From 9f5ef34ac05de070a99fae07eb1a8087ba60a653 Mon Sep 17 00:00:00 2001
From: Sebastian Koslowski <koslowski@kit.edu>
Date: Fri, 20 Nov 2015 17:28:17 +0100
Subject: grc-refactor: move grc.base to grc.python.base

---
 grc/base/Block.py              | 542 -----------------------------------------
 grc/base/CMakeLists.txt        |  43 ----
 grc/base/Connection.py         | 138 -----------
 grc/base/Constants.py          |  50 ----
 grc/base/Element.py            |  97 --------
 grc/base/FlowGraph.py          | 482 ------------------------------------
 grc/base/Param.py              | 203 ---------------
 grc/base/ParseXML.py           | 155 ------------
 grc/base/Platform.py           | 271 ---------------------
 grc/base/Port.py               | 136 -----------
 grc/base/__init__.py           |  20 --
 grc/base/block_tree.dtd        |  26 --
 grc/base/domain.dtd            |  35 ---
 grc/base/flow_graph.dtd        |  38 ---
 grc/base/odict.py              | 105 --------
 grc/gui/ActionHandler.py       |   9 +-
 grc/gui/Block.py               |  25 +-
 grc/gui/Connection.py          |  16 +-
 grc/gui/Element.py             |  16 +-
 grc/gui/FlowGraph.py           |   7 +-
 grc/gui/Param.py               |   9 +-
 grc/gui/Platform.py            |  45 +++-
 grc/gui/Port.py                |  25 +-
 grc/python/Block.py            |  15 +-
 grc/python/Connection.py       |  14 +-
 grc/python/FlowGraph.py        |   6 +-
 grc/python/Generator.py        |  11 +-
 grc/python/Param.py            |  12 +-
 grc/python/Platform.py         |  32 +--
 grc/python/Port.py             |  15 +-
 grc/python/base/Block.py       | 542 +++++++++++++++++++++++++++++++++++++++++
 grc/python/base/CMakeLists.txt |  43 ++++
 grc/python/base/Connection.py  | 139 +++++++++++
 grc/python/base/Constants.py   |  50 ++++
 grc/python/base/Element.py     |  98 ++++++++
 grc/python/base/FlowGraph.py   | 482 ++++++++++++++++++++++++++++++++++++
 grc/python/base/Param.py       | 203 +++++++++++++++
 grc/python/base/ParseXML.py    | 155 ++++++++++++
 grc/python/base/Platform.py    | 274 +++++++++++++++++++++
 grc/python/base/Port.py        | 136 +++++++++++
 grc/python/base/__init__.py    |  20 ++
 grc/python/base/block_tree.dtd |  26 ++
 grc/python/base/domain.dtd     |  35 +++
 grc/python/base/flow_graph.dtd |  38 +++
 grc/python/base/odict.py       | 105 ++++++++
 grc/scripts/gnuradio-companion |   4 +-
 46 files changed, 2490 insertions(+), 2458 deletions(-)
 delete mode 100644 grc/base/Block.py
 delete mode 100644 grc/base/CMakeLists.txt
 delete mode 100644 grc/base/Connection.py
 delete mode 100644 grc/base/Constants.py
 delete mode 100644 grc/base/Element.py
 delete mode 100644 grc/base/FlowGraph.py
 delete mode 100644 grc/base/Param.py
 delete mode 100644 grc/base/ParseXML.py
 delete mode 100644 grc/base/Platform.py
 delete mode 100644 grc/base/Port.py
 delete mode 100644 grc/base/__init__.py
 delete mode 100644 grc/base/block_tree.dtd
 delete mode 100644 grc/base/domain.dtd
 delete mode 100644 grc/base/flow_graph.dtd
 delete mode 100644 grc/base/odict.py
 create mode 100644 grc/python/base/Block.py
 create mode 100644 grc/python/base/CMakeLists.txt
 create mode 100644 grc/python/base/Connection.py
 create mode 100644 grc/python/base/Constants.py
 create mode 100644 grc/python/base/Element.py
 create mode 100644 grc/python/base/FlowGraph.py
 create mode 100644 grc/python/base/Param.py
 create mode 100644 grc/python/base/ParseXML.py
 create mode 100644 grc/python/base/Platform.py
 create mode 100644 grc/python/base/Port.py
 create mode 100644 grc/python/base/__init__.py
 create mode 100644 grc/python/base/block_tree.dtd
 create mode 100644 grc/python/base/domain.dtd
 create mode 100644 grc/python/base/flow_graph.dtd
 create mode 100644 grc/python/base/odict.py

diff --git a/grc/base/Block.py b/grc/base/Block.py
deleted file mode 100644
index 77c3145173..0000000000
--- a/grc/base/Block.py
+++ /dev/null
@@ -1,542 +0,0 @@
-"""
-Copyright 2008-2011 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 . import odict
-from . Constants import ADVANCED_PARAM_TAB, DEFAULT_PARAM_TAB
-from . Constants import BLOCK_FLAG_THROTTLE, BLOCK_FLAG_DISABLE_BYPASS
-from . Constants import BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED
-from Element import Element
-
-from Cheetah.Template import Template
-from UserDict import UserDict
-from itertools import imap
-
-
-class TemplateArg(UserDict):
-    """
-    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):
-        UserDict.__init__(self)
-        self._param = param
-        if param.is_enum():
-            for key in param.get_opt_keys():
-                self[key] = str(param.get_opt(key))
-
-    def __str__(self):
-        return str(self._param.to_code())
-
-    def __call__(self):
-        return self._param.get_evaluated()
-
-
-def _get_keys(lst):
-    return [elem.get_key() for elem in lst]
-
-
-def _get_elem(lst, key):
-    try: return lst[_get_keys(lst).index(key)]
-    except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
-
-
-class Block(Element):
-
-    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
-        """
-        #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 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 "%s" already exists in params'%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 "%s" already exists in sources'%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 "%s" already exists in sinks'%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
-                         })
-                ))
-
-    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 - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key())
-
-    def get_id(self): return self.get_param('id').get_value()
-    def is_block(self): return True
-    def get_name(self): return self._name
-    def get_key(self): return self._key
-    def get_category(self): return self._category
-    def set_category(self, cat): self._category = cat
-    def get_doc(self): return ''
-    def get_ports(self): return self.get_sources() + self.get_sinks()
-    def get_ports_gui(self): return self.filter_bus_port(self.get_sources()) + self.filter_bus_port(self.get_sinks());
-    def get_children(self): return self.get_ports() + self.get_params()
-    def get_children_gui(self): return self.get_ports_gui() + self.get_params()
-    def get_block_wrapper_path(self): return self._block_wrapper_path
-    def get_comment(self): return self.get_param('comment').get_value()
-
-    def get_flags(self): return self._flags
-    def throtteling(self): return BLOCK_FLAG_THROTTLE in self._flags
-    def bypass_disabled(self): return BLOCK_FLAG_DISABLE_BYPASS in self._flags
-
-    ##############################################
-    # 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((p.get_key(), TemplateArg(p)) for p in self.get_params())
-        try:
-            return str(Template(tmpl, n))
-        except Exception as err:
-            return "Template error: %s\n    %s" % (tmpl, err)
-
-    ##############################################
-    # 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 port_controller_modify(self, direction):
-        """
-        Change the port controller.
-
-        Args:
-            direction: +1 or -1
-
-        Returns:
-            true for change
-        """
-        return False
-
-    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 (not 'bus' in map(lambda a: a.get_type(), get_p())) and len(get_p()) > 0:
-
-            struct = self.form_bus_structure(direc);
-            self.current_bus_structure[direc] = struct;
-            if 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 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
-        """
-        get_hash = lambda: hash(tuple(map(hash, self.get_params())))
-        my_hash = 0
-        while get_hash() != my_hash:
-            params_n = n.findall('param')
-            for param_n in params_n:
-                key = param_n.find('key')
-                value = param_n.find('value')
-                #the key must exist in this block's params
-                if key in self.get_param_keys():
-                    self.get_param(key).set_value(value)
-            #store hash and call rewrite
-            my_hash = get_hash()
-            self.rewrite()
-        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 --git a/grc/base/CMakeLists.txt b/grc/base/CMakeLists.txt
deleted file mode 100644
index bdc8a5006f..0000000000
--- a/grc/base/CMakeLists.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2011 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio 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 3, or (at your option)
-# any later version.
-#
-# GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-
-########################################################################
-GR_PYTHON_INSTALL(FILES
-    odict.py
-    ParseXML.py
-    Block.py
-    Connection.py
-    Constants.py
-    Element.py
-    FlowGraph.py
-    Param.py
-    Platform.py
-    Port.py
-    __init__.py
-    DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/base
-    COMPONENT "grc"
-)
-
-install(FILES
-    block_tree.dtd
-    domain.dtd
-    flow_graph.dtd
-    DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/base
-    COMPONENT "grc"
-)
diff --git a/grc/base/Connection.py b/grc/base/Connection.py
deleted file mode 100644
index bf3c75277c..0000000000
--- a/grc/base/Connection.py
+++ /dev/null
@@ -1,138 +0,0 @@
-"""
-Copyright 2008-2011 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 Element import Element
-from . import odict
-
-class Connection(Element):
-
-    def __init__(self, flow_graph, porta, portb):
-        """
-        Make a new connection given the parent and 2 ports.
-
-        Args:
-            flow_graph: the parent of this element
-            porta: a port (any direction)
-            portb: a port (any direction)
-        @throws Error cannot make connection
-
-        Returns:
-            a new connection
-        """
-        Element.__init__(self, flow_graph)
-        source = sink = None
-        #separate the source and sink
-        for port in (porta, portb):
-            if port.is_source(): source = port
-            if port.is_sink(): sink = port
-        if not source: raise ValueError('Connection could not isolate source')
-        if not sink: raise ValueError('Connection could not isolate sink')
-        busses = len(filter(lambda a: a.get_type() == 'bus', [source, sink]))%2
-        if not busses == 0: raise ValueError('busses must get with busses')
-
-        if not len(source.get_associated_ports()) == len(sink.get_associated_ports()):
-            raise ValueError('port connections must have same cardinality');
-        #ensure that this connection (source -> sink) is unique
-        for connection in self.get_parent().get_connections():
-            if connection.get_source() is source and connection.get_sink() is sink:
-                raise LookupError('This connection between source and sink is not unique.')
-        self._source = source
-        self._sink = sink
-        if source.get_type() == 'bus':
-
-            sources = source.get_associated_ports();
-            sinks = sink.get_associated_ports();
-
-            for i in range(len(sources)):
-                try:
-                    flow_graph.connect(sources[i], sinks[i]);
-                except:
-                    pass
-
-    def __str__(self):
-        return 'Connection (\n\t%s\n\t\t%s\n\t%s\n\t\t%s\n)'%(
-            self.get_source().get_parent(),
-            self.get_source(),
-            self.get_sink().get_parent(),
-            self.get_sink(),
-        )
-
-    def is_connection(self): return True
-
-    def validate(self):
-        """
-        Validate the connections.
-        The ports must match in type.
-        """
-        Element.validate(self)
-        platform = self.get_parent().get_parent()
-        source_domain = self.get_source().get_domain()
-        sink_domain = self.get_sink().get_domain()
-        if (source_domain, sink_domain) not in platform.get_connection_templates():
-            self.add_error_message('No connection known for domains "%s", "%s"'
-                                   % (source_domain, sink_domain))
-        too_many_other_sinks = (
-            source_domain in platform.get_domains() and
-            not platform.get_domain(key=source_domain)['multiple_sinks'] and
-            len(self.get_source().get_enabled_connections()) > 1
-        )
-        too_many_other_sources = (
-            sink_domain in platform.get_domains() and
-            not platform.get_domain(key=sink_domain)['multiple_sources'] and
-            len(self.get_sink().get_enabled_connections()) > 1
-        )
-        if too_many_other_sinks:
-            self.add_error_message(
-                'Domain "%s" can have only one downstream block' % source_domain)
-        if too_many_other_sources:
-            self.add_error_message(
-                'Domain "%s" can have only one upstream block' % sink_domain)
-
-    def get_enabled(self):
-        """
-        Get the enabled state of this connection.
-
-        Returns:
-            true if source and sink blocks are enabled
-        """
-        return self.get_source().get_parent().get_enabled() and \
-            self.get_sink().get_parent().get_enabled()
-
-    #############################
-    # Access Ports
-    #############################
-    def get_sink(self): return self._sink
-    def get_source(self): return self._source
-
-    ##############################################
-    ## Import/Export Methods
-    ##############################################
-    def export_data(self):
-        """
-        Export this connection's info.
-
-        Returns:
-            a nested data odict
-        """
-        n = odict()
-        n['source_block_id'] = self.get_source().get_parent().get_id()
-        n['sink_block_id'] = self.get_sink().get_parent().get_id()
-        n['source_key'] = self.get_source().get_key()
-        n['sink_key'] = self.get_sink().get_key()
-        return n
diff --git a/grc/base/Constants.py b/grc/base/Constants.py
deleted file mode 100644
index 1e83de63b5..0000000000
--- a/grc/base/Constants.py
+++ /dev/null
@@ -1,50 +0,0 @@
-"""
-Copyright 2008, 2009 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion is free software; you can redistribute it and/or
-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 os
-
-#data files
-DATA_DIR = os.path.dirname(__file__)
-FLOW_GRAPH_DTD = os.path.join(DATA_DIR, 'flow_graph.dtd')
-BLOCK_TREE_DTD = os.path.join(DATA_DIR, 'block_tree.dtd')
-
-# file format versions:
-#  0: undefined / legacy
-#  1: non-numeric message port keys (label is used instead)
-FLOW_GRAPH_FILE_FORMAT_VERSION = 1
-
-# Param tabs
-DEFAULT_PARAM_TAB = "General"
-ADVANCED_PARAM_TAB = "Advanced"
-
-# Port domains
-DOMAIN_DTD = os.path.join(DATA_DIR, 'domain.dtd')
-GR_STREAM_DOMAIN = "gr_stream"
-GR_MESSAGE_DOMAIN = "gr_message"
-DEFAULT_DOMAIN = GR_STREAM_DOMAIN
-
-BLOCK_FLAG_THROTTLE = 'throttle'
-BLOCK_FLAG_DISABLE_BYPASS = 'disable_bypass'
-BLOCK_FLAG_NEED_QT_GUI = 'need_qt_gui'
-BLOCK_FLAG_NEED_WX_GUI = 'need_ex_gui'
-
-# Block States
-BLOCK_DISABLED = 0
-BLOCK_ENABLED = 1
-BLOCK_BYPASSED = 2
diff --git a/grc/base/Element.py b/grc/base/Element.py
deleted file mode 100644
index 04a3690282..0000000000
--- a/grc/base/Element.py
+++ /dev/null
@@ -1,97 +0,0 @@
-"""
-Copyright 2008, 2009 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-GNU Radio Companion is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-"""
-
-class Element(object):
-
-    def __init__(self, parent=None):
-        self._parent = parent
-        self._error_messages = list()
-
-    ##################################################
-    # Element Validation API
-    ##################################################
-    def validate(self):
-        """
-        Validate this element and call validate on all children.
-        Call this base method before adding error messages in the subclass.
-        """
-        del self._error_messages[:]
-        for child in self.get_children(): child.validate()
-
-    def is_valid(self):
-        """
-        Is this element valid?
-
-        Returns:
-            true when the element is enabled and has no error messages
-        """
-        return not self.get_error_messages() or not self.get_enabled()
-
-    def add_error_message(self, msg):
-        """
-        Add an error message to the list of errors.
-
-        Args:
-            msg: the error message string
-        """
-        self._error_messages.append(msg)
-
-    def get_error_messages(self):
-        """
-        Get the list of error messages from this element and all of its children.
-        Do not include the error messages from disabled children.
-        Cleverly indent the children error messages for printing purposes.
-
-        Returns:
-            a list of error message strings
-        """
-        error_messages = list(self._error_messages) #make a copy
-        for child in filter(lambda c: c.get_enabled(), self.get_children()):
-            for msg in child.get_error_messages():
-                error_messages.append("%s:\n\t%s"%(child, msg.replace("\n", "\n\t")))
-        return error_messages
-
-    def rewrite(self):
-        """
-        Rewrite this element and call rewrite on all children.
-        Call this base method before rewriting the element.
-        """
-        for child in self.get_children(): child.rewrite()
-
-    def get_enabled(self): return True
-
-    ##############################################
-    ## Tree-like API
-    ##############################################
-    def get_parent(self): return self._parent
-    def get_children(self): return list()
-
-    ##############################################
-    ## Type testing methods
-    ##############################################
-    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
diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py
deleted file mode 100644
index 072414aa90..0000000000
--- a/grc/base/FlowGraph.py
+++ /dev/null
@@ -1,482 +0,0 @@
-"""
-Copyright 2008-2011 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 time
-from operator import methodcaller
-from itertools import ifilter
-
-from .. gui import Messages
-
-from . import odict
-from .Element import Element
-from .Constants import FLOW_GRAPH_FILE_FORMAT_VERSION
-
-
-class FlowGraph(Element):
-
-    def __init__(self, platform):
-        """
-        Make a flow graph from the arguments.
-
-        Args:
-            platform: a platforms with blocks and contrcutors
-
-        Returns:
-            the flow graph object
-        """
-        #initialize
-        Element.__init__(self, platform)
-        self._elements = []
-        self._timestamp = time.ctime()
-        #inital blank import
-        self.import_data()
-
-    def _get_unique_id(self, base_id=''):
-        """
-        Get a unique id starting with the base id.
-
-        Args:
-            base_id: the id starts with this and appends a count
-
-        Returns:
-            a unique id
-        """
-        index = 0
-        while True:
-            id = '%s_%d' % (base_id, index)
-            index += 1
-            #make sure that the id is not used by another block
-            if not filter(lambda b: b.get_id() == id, self.get_blocks()): return id
-
-    def __str__(self):
-        return 'FlowGraph - %s(%s)' % (self.get_option('title'), self.get_option('id'))
-
-    def get_complexity(self):
-        """
-        Determines the complexity of a flowgraph
-        """
-        dbal = 0
-        block_list = self.get_blocks()
-        for block in block_list:
-            # Skip options block
-            if block.get_key() == 'options':
-                continue
-
-            # Don't worry about optional sinks?
-            sink_list = filter(lambda c: not c.get_optional(), block.get_sinks())
-            source_list = filter(lambda c: not c.get_optional(), block.get_sources())
-            sinks = float(len(sink_list))
-            sources = float(len(source_list))
-            base = max(min(sinks, sources), 1)
-
-            # Port ratio multiplier
-            if min(sinks, sources) > 0:
-                multi = sinks / sources
-                multi = (1 / multi) if multi > 1 else multi
-            else:
-                multi = 1
-
-            # Connection ratio multiplier
-            sink_multi = max(float(sum(map(lambda c: len(c.get_connections()), sink_list)) / max(sinks, 1.0)), 1.0)
-            source_multi = max(float(sum(map(lambda c: len(c.get_connections()), source_list)) / max(sources, 1.0)), 1.0)
-            dbal = dbal + (base * multi * sink_multi * source_multi)
-
-        elements = float(len(self.get_elements()))
-        connections = float(len(self.get_connections()))
-        disabled_connections = len(filter(lambda c: not c.get_enabled(), self.get_connections()))
-        blocks = float(len(block_list))
-        variables = elements - blocks - connections
-        enabled = float(len(self.get_enabled_blocks()))
-
-        # Disabled multiplier
-        if enabled > 0:
-            disabled_multi = 1 / (max(1 - ((blocks - enabled) / max(blocks, 1)), 0.05))
-        else:
-            disabled_multi = 1
-
-        # Connection multiplier (How many connections )
-        if (connections - disabled_connections) > 0:
-            conn_multi = 1 / (max(1 - (disabled_connections / max(connections, 1)), 0.05))
-        else:
-            conn_multi = 1
-
-        final = round(max((dbal - 1) * disabled_multi * conn_multi * connections, 0.0) / 1000000, 6)
-        return final
-
-    def rewrite(self):
-        def refactor_bus_structure():
-
-            for block in self.get_blocks():
-                for direc in ['source', 'sink']:
-                    if direc == 'source':
-                        get_p = block.get_sources;
-                        get_p_gui = block.get_sources_gui;
-                        bus_structure = block.form_bus_structure('source');
-                    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);
-
-        for child in self.get_children(): child.rewrite()
-        refactor_bus_structure()
-
-    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()
-
-    def is_flow_graph(self): return True
-
-    ##############################################
-    ## Access Elements
-    ##############################################
-    def get_block(self, id):
-        for block in self.iter_blocks():
-            if block.get_id() == id:
-                return block
-        raise KeyError('No block with ID {0!r}'.format(id))
-
-    def iter_blocks(self):
-        return ifilter(methodcaller('is_block'), self.get_elements())
-
-    def get_blocks(self):
-        return list(self.iter_blocks())
-
-    def iter_connections(self):
-        return ifilter(methodcaller('is_connection'), self.get_elements())
-
-    def get_connections(self):
-        return list(self.iter_connections())
-
-    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._elements.count(self._options_block)
-        if not options_block_count:
-            self._elements.append(self._options_block)
-        for i in range(options_block_count-1):
-            self._elements.remove(self._options_block)
-        return self._elements
-
-    get_children = get_elements
-
-    def iter_enabled_blocks(self):
-        """
-        Get an iterator of all blocks that are enabled and not bypassed.
-        """
-        return ifilter(methodcaller('get_enabled'), self.iter_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.iter_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.get_connections())
-
-    def get_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
-        """
-        if key not in self.get_parent().get_block_keys(): return None
-        block = self.get_parent().get_new_block(self, key)
-        self.get_elements().append(block);
-        if block._bussify_sink:
-            block.bussify({'name':'bus','type':'bus'}, 'sink')
-        if block._bussify_source:
-            block.bussify({'name':'bus','type':'bus'}, 'source')
-        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.get_parent().Connection(flow_graph=self, porta=porta, portb=portb)
-        self.get_elements().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 not in self.get_elements(): return
-        #found a port, set to parent signal block
-        if element.is_port():
-            element = element.get_parent()
-        #remove block, remove all involved connections
-        if element.is_block():
-            for port in element.get_ports():
-                map(self.remove_element, port.get_connections())
-        if element.is_connection():
-            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.get_elements().remove(element)
-
-    def evaluate(self, expr):
-        """
-        Evaluate the expression.
-
-        Args:
-            expr: the string expression
-        @throw NotImplementedError
-        """
-        raise NotImplementedError
-
-    ##############################################
-    ## 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.iter_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.get_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': self.get_parent().get_version_short(),
-            'format': FLOW_GRAPH_FILE_FORMAT_VERSION,
-        })
-        return odict({'flow_graph': n, '_instructions': instructions})
-
-    def import_data(self, n=None):
-        """
-        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
-        """
-        errors = False
-        self._elements = list()  # remove previous elements
-        # 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.get_parent().get_new_block(self, 'options')
-        for block_n in fg_n.findall('block'):
-            key = block_n.find('key')
-            block = self._options_block if key == 'options' else self.get_new_block(key)
-
-            if not block:  # looks like this block key cannot be found
-                # create a dummy block instead
-                block = self.get_new_block('dummy_block')
-                # Ugly ugly ugly
-                _initialize_dummy_block(block, block_n)
-                Messages.send_error_msg_load('Block key "%s" not found' % key)
-
-            block.import_data(block_n)
-
-        # 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
-
-        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 %s(%s) and %s(%s) could not be made.\n\t%s' % (
-                        source_block_id, source_key, sink_block_id, sink_key, e))
-                errors = True
-
-        self.rewrite()  # global rewrite
-        return errors
-
-
-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'})
-            block.get_params().append(block.get_parent().get_parent().Param(block=block, n=new_param_n))
-
-
-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 --git a/grc/base/Param.py b/grc/base/Param.py
deleted file mode 100644
index b246d9f759..0000000000
--- a/grc/base/Param.py
+++ /dev/null
@@ -1,203 +0,0 @@
-"""
-Copyright 2008-2011 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 . import odict
-from Element import Element
-
-def _get_keys(lst): return [elem.get_key() for elem in lst]
-def _get_elem(lst, key):
-    try: return lst[_get_keys(lst).index(key)]
-    except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
-
-class Option(Element):
-
-    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 "%s" into key:value'%opt
-            #test against repeated keys
-            if self._opts.has_key(key):
-                raise Exception, 'Key "%s" already exists in option'%key
-            #store the option
-            self._opts[key] = value
-
-    def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key())
-    def get_name(self): return self._name
-    def get_key(self): return self._key
-
-    ##############################################
-    # 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 Param(Element):
-
-    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 not self._tab_label 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()
-        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 "%s" already exists in options'%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 "%s" are not unique.'%self.get_option_keys()
-            #test against inconsistent keys in options
-            opt_keys = self.get_options()[0].get_opt_keys()
-            for option in self.get_options():
-                if set(opt_keys) != set(option.get_opt_keys()):
-                    raise Exception, 'Opt keys "%s" are not identical across all options.'%opt_keys
-            #if a value is specified, it must be in the options keys
-            self._value = value if value or value in self.get_option_keys() else self.get_option_keys()[0]
-            if self.get_value() not in self.get_option_keys():
-                raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys())
-        else: self._value = value or ''
-        self._default = value
-
-    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 "%s" is not a possible type.'%self.get_type())
-
-    def get_evaluated(self): raise NotImplementedError
-
-    def to_code(self):
-        """
-        Convert the value to code.
-        @throw NotImplementedError
-        """
-        raise NotImplementedError
-
-    def get_types(self):
-        """
-        Get a list of all possible param types.
-        @throw NotImplementedError
-        """
-        raise NotImplementedError
-
-    def get_color(self): return '#FFFFFF'
-    def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())
-    def is_param(self): return True
-    def get_name(self): return self.get_parent().resolve_dependencies(self._name).strip()
-    def get_key(self): return self._key
-    def get_hide(self): return self.get_parent().resolve_dependencies(self._hide).strip()
-
-    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): self._value = str(value) #must be a string
-
-    def value_is_default(self):
-        return self._default == self._value
-
-    def get_type(self): return self.get_parent().resolve_dependencies(self._type)
-    def get_tab_label(self): return self._tab_label
-    def is_enum(self): return self._type == 'enum'
-
-    def __repr__(self):
-        """
-        Get the repr (nice string format) for this param.
-        Just return the value (special case enum).
-        Derived classes can handle complex formatting.
-
-        Returns:
-            the string representation
-        """
-        if self.is_enum(): return self.get_option(self.get_value()).get_name()
-        return self.get_value()
-
-    ##############################################
-    # 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 --git a/grc/base/ParseXML.py b/grc/base/ParseXML.py
deleted file mode 100644
index 2d5fed0862..0000000000
--- a/grc/base/ParseXML.py
+++ /dev/null
@@ -1,155 +0,0 @@
-"""
-Copyright 2008 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 lxml import etree
-from . import odict
-
-xml_failures = {}
-
-
-class XMLSyntaxError(Exception):
-    def __init__(self, error_log):
-        self._error_log = error_log
-        xml_failures[error_log.last_error.filename] = error_log
-
-    def __str__(self):
-        return '\n'.join(map(str, self._error_log.filter_from_errors()))
-
-
-def validate_dtd(xml_file, dtd_file=None):
-    """
-    Validate an xml file against its dtd.
-
-    Args:
-        xml_file: the xml file
-        dtd_file: the optional dtd file
-    @throws Exception validation fails
-    """
-    # perform parsing, use dtd validation if dtd file is not specified
-    parser = etree.XMLParser(dtd_validation=not dtd_file)
-    try:
-        xml = etree.parse(xml_file, parser=parser)
-    except etree.LxmlError:
-        pass
-    if parser.error_log:
-        raise XMLSyntaxError(parser.error_log)
-
-    # perform dtd validation if the dtd file is specified
-    if not dtd_file:
-        return
-    try:
-        dtd = etree.DTD(dtd_file)
-        if not dtd.validate(xml.getroot()):
-            raise XMLSyntaxError(dtd.error_log)
-    except etree.LxmlError:
-        raise XMLSyntaxError(dtd.error_log)
-
-
-def from_file(xml_file):
-    """
-    Create nested data from an xml file using the from xml helper.
-    Also get the grc version information.
-
-    Args:
-        xml_file: the xml file path
-
-    Returns:
-        the nested data with grc version information
-    """
-    xml = etree.parse(xml_file)
-    nested_data = _from_file(xml.getroot())
-
-    # Get the embedded instructions and build a dictionary item
-    nested_data['_instructions'] = {}
-    xml_instructions = xml.xpath('/processing-instruction()')
-    for inst in filter(lambda i: i.target == 'grc', xml_instructions):
-        nested_data['_instructions'] = odict(inst.attrib)
-    return nested_data
-
-
-def _from_file(xml):
-    """
-    Recursively parse the xml tree into nested data format.
-
-    Args:
-        xml: the xml tree
-
-    Returns:
-        the nested data
-    """
-    tag = xml.tag
-    if not len(xml):
-        return odict({tag: xml.text or ''})  # store empty tags (text is None) as empty string
-    nested_data = odict()
-    for elem in xml:
-        key, value = _from_file(elem).items()[0]
-        if nested_data.has_key(key): nested_data[key].append(value)
-        else: nested_data[key] = [value]
-    # delistify if the length of values is 1
-    for key, values in nested_data.iteritems():
-        if len(values) == 1:
-            nested_data[key] = values[0]
-
-    return odict({tag: nested_data})
-
-
-def to_file(nested_data, xml_file):
-    """
-    Write to an xml file and insert processing instructions for versioning
-
-    Args:
-        nested_data: the nested data
-        xml_file: the xml file path
-    """
-    xml_data = ""
-    instructions = nested_data.pop('_instructions', None)
-    if instructions:  # create the processing instruction from the array
-        xml_data += etree.tostring(etree.ProcessingInstruction(
-            'grc', ' '.join(
-                "{0}='{1}'".format(*item) for item in instructions.iteritems())
-        ), xml_declaration=True, pretty_print=True, encoding='utf-8')
-    xml_data += etree.tostring(_to_file(nested_data)[0],
-                               pretty_print=True, encoding='utf-8')
-    with open(xml_file, 'w') as fp:
-        fp.write(xml_data)
-
-
-def _to_file(nested_data):
-    """
-    Recursively parse the nested data into xml tree format.
-
-    Args:
-        nested_data: the nested data
-
-    Returns:
-        the xml tree filled with child nodes
-    """
-    nodes = list()
-    for key, values in nested_data.iteritems():
-        # listify the values if not a list
-        if not isinstance(values, (list, set, tuple)):
-            values = [values]
-        for value in values:
-            node = etree.Element(key)
-            if isinstance(value, (str, unicode)):
-                node.text = unicode(value)
-            else:
-                node.extend(_to_file(value))
-            nodes.append(node)
-    return nodes
diff --git a/grc/base/Platform.py b/grc/base/Platform.py
deleted file mode 100644
index 0cc3fcf1dd..0000000000
--- a/grc/base/Platform.py
+++ /dev/null
@@ -1,271 +0,0 @@
-"""
-Copyright 2008-2011 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 os
-import sys
-from .. base import ParseXML, odict
-from Element import Element as _Element
-from FlowGraph import FlowGraph as _FlowGraph
-from Connection import Connection as _Connection
-from Block import Block as _Block
-from Port import Port as _Port
-from Param import Param as _Param
-from Constants import BLOCK_TREE_DTD, FLOW_GRAPH_DTD, DOMAIN_DTD
-
-
-class Platform(_Element):
-    def __init__(self, name, version, key,
-                 block_paths, block_dtd, default_flow_graph, generator,
-                 license='', website=None, colors=None):
-        """
-        Make a platform from the arguments.
-
-        Args:
-            name: the platform name
-            version: the version string
-            key: the unique platform key
-            block_paths: the file paths to blocks in this platform
-            block_dtd: the dtd validator for xml block wrappers
-            default_flow_graph: the default flow graph file path
-            generator: the generator class for this platform
-            colors: a list of title, color_spec tuples
-            license: a multi-line license (first line is copyright)
-            website: the website url for this platform
-
-        Returns:
-            a platform object
-        """
-        _Element.__init__(self)
-        self._name = name
-        # Save the verion string to the first
-        self._version = version[0]
-        self._version_major = version[1]
-        self._version_api = version[2]
-        self._version_minor = version[3]
-        self._version_short = version[1] + "." + version[2] + "." + version[3]
-
-        self._key = key
-        self._license = license
-        self._website = website
-        self._block_paths = list(set(block_paths))
-        self._block_dtd = block_dtd
-        self._default_flow_graph = default_flow_graph
-        self._generator = generator
-        self._colors = colors or []
-        #create a dummy flow graph for the blocks
-        self._flow_graph = _Element(self)
-
-        self._blocks = None
-        self._blocks_n = None
-        self._category_trees_n = None
-        self._domains = dict()
-        self._connection_templates = dict()
-        self.load_blocks()
-
-    def load_blocks(self):
-        """load the blocks and block tree from the search paths"""
-        # reset
-        self._blocks = odict()
-        self._blocks_n = odict()
-        self._category_trees_n = list()
-        self._domains.clear()
-        self._connection_templates.clear()
-        ParseXML.xml_failures.clear()
-        # try to parse and load blocks
-        for xml_file in self.iter_xml_files():
-            try:
-                if xml_file.endswith("block_tree.xml"):
-                    self.load_category_tree_xml(xml_file)
-                elif xml_file.endswith('domain.xml'):
-                    self.load_domain_xml(xml_file)
-                else:
-                    self.load_block_xml(xml_file)
-            except ParseXML.XMLSyntaxError as e:
-                # print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s' % (e, xml_file)
-                pass
-            except Exception as e:
-                print >> sys.stderr, 'Warning: XML parsing failed:\n\t%s\n\tIgnoring: %s' % (e, xml_file)
-
-    def iter_xml_files(self):
-        """Iterator for block descriptions and category trees"""
-        get_path = lambda x: os.path.abspath(os.path.expanduser(x))
-        for block_path in map(get_path, self._block_paths):
-            if os.path.isfile(block_path):
-                yield block_path
-            elif os.path.isdir(block_path):
-                for dirpath, dirnames, filenames in os.walk(block_path):
-                    for filename in sorted(filter(lambda f: f.endswith('.xml'), filenames)):
-                        yield os.path.join(dirpath, filename)
-
-    def load_block_xml(self, xml_file):
-        """Load block description from xml file"""
-        # validate and import
-        ParseXML.validate_dtd(xml_file, self._block_dtd)
-        n = ParseXML.from_file(xml_file).find('block')
-        n['block_wrapper_path'] = xml_file  # inject block wrapper path
-        # get block instance and add it to the list of blocks
-        block = self.Block(self._flow_graph, n)
-        key = block.get_key()
-        if key in self._blocks:
-            print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s' % (key, xml_file)
-        else:  # store the block
-            self._blocks[key] = block
-            self._blocks_n[key] = n
-        return block
-
-    def load_category_tree_xml(self, xml_file):
-        """Validate and parse category tree file and add it to list"""
-        ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD)
-        n = ParseXML.from_file(xml_file).find('cat')
-        self._category_trees_n.append(n)
-
-    def load_domain_xml(self, xml_file):
-        """Load a domain properties and connection templates from XML"""
-        ParseXML.validate_dtd(xml_file, DOMAIN_DTD)
-        n = ParseXML.from_file(xml_file).find('domain')
-
-        key = n.find('key')
-        if not key:
-            print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: %s' % xml_file
-            return
-        if key in self.get_domains():  # test against repeated keys
-            print >> sys.stderr, 'Warning: Domain with key "%s" already exists.\n\tIgnoring: %s' % (key, xml_file)
-            return
-
-        to_bool = lambda s, d: d if s is None else \
-            s.lower() not in ('false', 'off', '0', '')
-
-        color = n.find('color') or ''
-        try:
-            import gtk  # ugly but handy
-            gtk.gdk.color_parse(color)
-        except (ValueError, ImportError):
-            if color:  # no color is okay, default set in GUI
-                print >> sys.stderr, 'Warning: Can\'t parse color code "%s" for domain "%s" ' % (color, key)
-                color = None
-
-        self._domains[key] = dict(
-            name=n.find('name') or key,
-            multiple_sinks=to_bool(n.find('multiple_sinks'), True),
-            multiple_sources=to_bool(n.find('multiple_sources'), False),
-            color=color
-        )
-        for connection_n in n.findall('connection'):
-            key = (connection_n.find('source_domain'), connection_n.find('sink_domain'))
-            if not all(key):
-                print >> sys.stderr, 'Warning: Empty domain key(s) in connection template.\n\t%s' % xml_file
-            elif key in self._connection_templates:
-                print >> sys.stderr, 'Warning: Connection template "%s" already exists.\n\t%s' % (key, xml_file)
-            else:
-                self._connection_templates[key] = connection_n.find('make') or ''
-
-    def parse_flow_graph(self, flow_graph_file):
-        """
-        Parse a saved flow graph file.
-        Ensure that the file exists, and passes the dtd check.
-
-        Args:
-            flow_graph_file: the flow graph file
-
-        Returns:
-            nested data
-        @throws exception if the validation fails
-        """
-        flow_graph_file = flow_graph_file or self._default_flow_graph
-        open(flow_graph_file, 'r')  # test open
-        ParseXML.validate_dtd(flow_graph_file, FLOW_GRAPH_DTD)
-        return ParseXML.from_file(flow_graph_file)
-
-    def load_block_tree(self, block_tree):
-        """
-        Load a block tree with categories and blocks.
-        Step 1: Load all blocks from the xml specification.
-        Step 2: Load blocks with builtin category specifications.
-
-        Args:
-            block_tree: the block tree object
-        """
-        #recursive function to load categories and blocks
-        def load_category(cat_n, parent=None):
-            #add this category
-            parent = (parent or []) + [cat_n.find('name')]
-            block_tree.add_block(parent)
-            #recursive call to load sub categories
-            map(lambda c: load_category(c, parent), cat_n.findall('cat'))
-            #add blocks in this category
-            for block_key in cat_n.findall('block'):
-                if block_key not in self.get_block_keys():
-                    print >> sys.stderr, 'Warning: Block key "%s" not found when loading category tree.' % (block_key)
-                    continue
-                block = self.get_block(block_key)
-                #if it exists, the block's category shall not be overridden by the xml tree
-                if not block.get_category():
-                    block.set_category(parent)
-
-        # recursively load the category trees and update the categories for each block
-        for category_tree_n in self._category_trees_n:
-            load_category(category_tree_n)
-
-        #add blocks to block tree
-        for block in self.get_blocks():
-            #blocks with empty categories are hidden
-            if not block.get_category(): continue
-            block_tree.add_block(block.get_category(), block)
-
-    def __str__(self): return 'Platform - %s(%s)'%(self.get_key(), self.get_name())
-
-    def is_platform(self): return True
-
-    def get_new_flow_graph(self): return self.FlowGraph(platform=self)
-
-    def get_generator(self): return self._generator
-
-    ##############################################
-    # Access Blocks
-    ##############################################
-    def get_block_keys(self): return self._blocks.keys()
-    def get_block(self, key): return self._blocks[key]
-    def get_blocks(self): return self._blocks.values()
-    def get_new_block(self, flow_graph, key): return self.Block(flow_graph, n=self._blocks_n[key])
-
-    def get_domains(self): return self._domains
-    def get_domain(self, key): return self._domains.get(key)
-    def get_connection_templates(self): return self._connection_templates
-
-    def get_name(self): return self._name
-    def get_version(self): return self._version
-    def get_version_major(self): return self._version_major
-    def get_version_api(self): return self._version_api
-    def get_version_minor(self): return self._version_minor
-    def get_version_short(self): return self._version_short
-
-    def get_key(self): return self._key
-    def get_license(self): return self._license
-    def get_website(self): return self._website
-    def get_colors(self): return self._colors
-    def get_block_paths(self): return self._block_paths
-
-    ##############################################
-    # Constructors
-    ##############################################
-    FlowGraph = _FlowGraph
-    Connection = _Connection
-    Block = _Block
-    Port = _Port
-    Param = _Param
diff --git a/grc/base/Port.py b/grc/base/Port.py
deleted file mode 100644
index 39166d18f7..0000000000
--- a/grc/base/Port.py
+++ /dev/null
@@ -1,136 +0,0 @@
-"""
-Copyright 2008-2011 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 Element import Element
-from . Constants import GR_STREAM_DOMAIN, GR_MESSAGE_DOMAIN
-
-class Port(Element):
-
-    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 source or sink
-        """
-        #build the port
-        Element.__init__(self, block)
-        #grab the data
-        self._name = n['name']
-        self._key = n['key']
-        self._type = n['type']
-        self._domain = n['domain']
-        self._hide = n.find('hide') or ''
-        self._dir = dir
-        self._hide_evaluated = False  # updated on rewrite()
-
-    def validate(self):
-        """
-        Validate the port.
-        The port must be non-empty and type must a possible type.
-        """
-        Element.validate(self)
-        if self.get_type() not in self.get_types():
-            self.add_error_message('Type "%s" is not a possible type.' % self.get_type())
-        platform = self.get_parent().get_parent().get_parent()
-        if self.get_domain() not in platform.get_domains():
-            self.add_error_message('Domain key "%s" is not registered.' % self.get_domain())
-
-    def rewrite(self):
-        """resolve dependencies in for type and hide"""
-        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 __str__(self):
-        if self.is_source():
-            return 'Source - %s(%s)'%(self.get_name(), self.get_key())
-        if self.is_sink():
-            return 'Sink - %s(%s)'%(self.get_name(), self.get_key())
-
-    def get_types(self):
-        """
-        Get a list of all possible port types.
-        @throw NotImplementedError
-        """
-        raise NotImplementedError
-
-    def is_port(self): return True
-    def get_color(self): return '#FFFFFF'
-    def get_name(self):
-        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
-    def is_sink(self): return self._dir == 'sink'
-    def is_source(self): return self._dir == 'source'
-    def get_type(self): return self.get_parent().resolve_dependencies(self._type)
-    def get_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().get_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 --git a/grc/base/__init__.py b/grc/base/__init__.py
deleted file mode 100644
index 2682db8125..0000000000
--- a/grc/base/__init__.py
+++ /dev/null
@@ -1,20 +0,0 @@
-"""
-Copyright 2009 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 odict import odict
diff --git a/grc/base/block_tree.dtd b/grc/base/block_tree.dtd
deleted file mode 100644
index 9e23576477..0000000000
--- a/grc/base/block_tree.dtd
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-Copyright 2008 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
--->
-<!--
-    block_tree.dtd
-    Josh Blum
-    The document type definition for a block tree category listing.
- -->
-<!ELEMENT cat (name, cat*, block*)>
-<!ELEMENT name (#PCDATA)>
-<!ELEMENT block (#PCDATA)>
diff --git a/grc/base/domain.dtd b/grc/base/domain.dtd
deleted file mode 100644
index b5b0b8bf39..0000000000
--- a/grc/base/domain.dtd
+++ /dev/null
@@ -1,35 +0,0 @@
-<!--
-Copyright 2014 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
--->
-<!ELEMENT domain (name, key, color?, multiple_sinks?, multiple_sources?, connection*)>
-<!--
-    Sub level elements.
- -->
-<!ELEMENT connection (source_domain, sink_domain, make)>
-<!--
-    Bottom level elements.
-    Character data only.
- -->
-<!ELEMENT name (#PCDATA)>
-<!ELEMENT key (#PCDATA)>
-<!ELEMENT multiple_sinks (#PCDATA)>
-<!ELEMENT multiple_sources (#PCDATA)>
-<!ELEMENT color (#PCDATA)>
-<!ELEMENT make (#PCDATA)>
-<!ELEMENT source_domain (#PCDATA)>
-<!ELEMENT sink_domain (#PCDATA)>
diff --git a/grc/base/flow_graph.dtd b/grc/base/flow_graph.dtd
deleted file mode 100644
index bdfe1dc059..0000000000
--- a/grc/base/flow_graph.dtd
+++ /dev/null
@@ -1,38 +0,0 @@
-<!--
-Copyright 2008 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
--->
-<!--
-    flow_graph.dtd
-    Josh Blum
-    The document type definition for flow graph xml files.
- -->
-<!ELEMENT flow_graph (timestamp?, block*, connection*)> <!-- optional timestamp -->
-<!ELEMENT timestamp (#PCDATA)>
-<!-- Block -->
-<!ELEMENT block (key, param*, bus_sink?, bus_source?)>
-<!ELEMENT param (key, value)>
-<!ELEMENT key (#PCDATA)>
-<!ELEMENT value (#PCDATA)>
-<!ELEMENT bus_sink (#PCDATA)>
-<!ELEMENT bus_source (#PCDATA)>
-<!-- Connection -->
-<!ELEMENT connection (source_block_id, sink_block_id, source_key, sink_key)>
-<!ELEMENT source_block_id (#PCDATA)>
-<!ELEMENT sink_block_id (#PCDATA)>
-<!ELEMENT source_key (#PCDATA)>
-<!ELEMENT sink_key (#PCDATA)>
diff --git a/grc/base/odict.py b/grc/base/odict.py
deleted file mode 100644
index 70ab67d053..0000000000
--- a/grc/base/odict.py
+++ /dev/null
@@ -1,105 +0,0 @@
-"""
-Copyright 2008-2011 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 UserDict import DictMixin
-
-class odict(DictMixin):
-
-    def __init__(self, d={}):
-        self._keys = list(d.keys())
-        self._data = dict(d.copy())
-
-    def __setitem__(self, key, value):
-        if key not in self._data:
-            self._keys.append(key)
-        self._data[key] = value
-
-    def __getitem__(self, key):
-        return self._data[key]
-
-    def __delitem__(self, key):
-        del self._data[key]
-        self._keys.remove(key)
-
-    def keys(self):
-        return list(self._keys)
-
-    def copy(self):
-        copy_dict = odict()
-        copy_dict._data = self._data.copy()
-        copy_dict._keys = list(self._keys)
-        return copy_dict
-
-    def insert_after(self, pos_key, key, val):
-        """
-        Insert the new key, value entry after the entry given by the position key.
-        If the positional key is None, insert at the end.
-
-        Args:
-            pos_key: the positional key
-            key: the key for the new entry
-            val: the value for the new entry
-        """
-        index = (pos_key is None) and len(self._keys) or self._keys.index(pos_key)
-        if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key))
-        self._keys.insert(index+1, key)
-        self._data[key] = val
-
-    def insert_before(self, pos_key, key, val):
-        """
-        Insert the new key, value entry before the entry given by the position key.
-        If the positional key is None, insert at the begining.
-
-        Args:
-            pos_key: the positional key
-            key: the key for the new entry
-            val: the value for the new entry
-        """
-        index = (pos_key is not None) and self._keys.index(pos_key) or 0
-        if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key))
-        self._keys.insert(index, key)
-        self._data[key] = val
-
-    def find(self, key):
-        """
-        Get the value for this key if exists.
-
-        Args:
-            key: the key to search for
-
-        Returns:
-            the value or None
-        """
-        if self.has_key(key): return self[key]
-        return None
-
-    def findall(self, key):
-        """
-        Get a list of values for this key.
-
-        Args:
-            key: the key to search for
-
-        Returns:
-            a list of values or empty list
-        """
-        obj = self.find(key)
-        if obj is None: obj = list()
-        if isinstance(obj, list): return obj
-        return [obj]
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py
index 0f227d08f5..726784f7cf 100644
--- a/grc/gui/ActionHandler.py
+++ b/grc/gui/ActionHandler.py
@@ -17,16 +17,18 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-import os
 import subprocess
 from threading import Thread
 
+import os
 import pygtk
+
 pygtk.require('2.0')
 import gtk
 import gobject
 
-from .. base import ParseXML, Constants
+from grc.python.base import Constants
+from grc.python.base import ParseXML
 from .. python.Constants import XTERM_EXECUTABLE
 
 from . import Dialogs, Messages, Preferences, Actions
@@ -560,7 +562,8 @@ class ActionHandler:
             self.platform.load_blocks()
             self.main_window.btwin.clear()
             self.platform.load_block_tree(self.main_window.btwin)
-            Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(bool(ParseXML.xml_failures))
+            Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(bool(
+                ParseXML.xml_failures))
             Messages.send_xml_errors_if_any(ParseXML.xml_failures)
             # Force a redraw of the graph, by getting the current state and re-importing it
             self.main_window.update_pages()
diff --git a/grc/gui/Block.py b/grc/gui/Block.py
index 67b80695fa..f961c2281e 100644
--- a/grc/gui/Block.py
+++ b/grc/gui/Block.py
@@ -17,22 +17,26 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-from Element import Element
-import Utils
+import pygtk
+
+import Actions
 import Colors
-from .. base import odict
-from .. python.Param import num_to_str
-from Constants import BORDER_PROXIMITY_SENSITIVITY
+import Utils
 from Constants import (
     BLOCK_LABEL_PADDING, PORT_SPACING, PORT_SEPARATION, LABEL_SEPARATION,
     PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS, BLOCK_FONT, PARAM_FONT
 )
-import Actions
-import pygtk
+from Constants import BORDER_PROXIMITY_SENSITIVITY
+from Element import Element
+from grc.python.base import odict
+from .. python.Param import num_to_str
+
 pygtk.require('2.0')
 import gtk
 import pango
 
+from ..python.Block import Block as _Block
+
 BLOCK_MARKUP_TMPL="""\
 #set $foreground = $block.is_valid() and 'black' or 'red'
 <span foreground="$foreground" font_desc="$font"><b>$encode($block.get_name())</b></span>"""
@@ -52,15 +56,16 @@ COMMENT_COMPLEXITY_MARKUP_TMPL="""\
 """
 
 
-
-class Block(Element):
+class Block(Element, _Block):
     """The graphical signal block."""
 
-    def __init__(self):
+    def __init__(self, flow_graph, n):
         """
         Block contructor.
         Add graphics related params to the block.
         """
+        _Block.__init__(self, flow_graph, n)
+
         self.W = 0
         self.H = 0
         #add the position param
diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py
index badf8e8a82..9a7777434d 100644
--- a/grc/gui/Connection.py
+++ b/grc/gui/Connection.py
@@ -17,15 +17,18 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-import Utils
-from Element import Element
+import gtk
+
 import Colors
+import Utils
 from Constants import CONNECTOR_ARROW_BASE, CONNECTOR_ARROW_HEIGHT
-import gtk
+from Element import Element
+
+from ..python.base.Constants import GR_MESSAGE_DOMAIN
+from ..python.Connection import Connection as _Connection
 
-from .. base.Constants import GR_MESSAGE_DOMAIN
 
-class Connection(Element):
+class Connection(Element, _Connection):
     """
     A graphical connection for ports.
     The connection has 2 parts, the arrow and the wire.
@@ -35,8 +38,9 @@ class Connection(Element):
     The arrow coloring exposes the enabled and valid states.
     """
 
-    def __init__(self):
+    def __init__(self, **kwargs):
         Element.__init__(self)
+        _Connection.__init__(self, **kwargs)
         # can't use Colors.CONNECTION_ENABLED_COLOR here, might not be defined (grcc)
         self._bg_color = self._arrow_color = self._color = None
 
diff --git a/grc/gui/Element.py b/grc/gui/Element.py
index 18fb321929..9385424772 100644
--- a/grc/gui/Element.py
+++ b/grc/gui/Element.py
@@ -132,14 +132,14 @@ class Element(object):
         """
         self.coor = coor
 
-    def get_parent(self):
-        """
-        Get the parent of this element.
-
-        Returns:
-            the parent
-        """
-        return self.parent
+    # def get_parent(self):
+    #     """
+    #     Get the parent of this element.
+    #
+    #     Returns:
+    #         the parent
+    #     """
+    #     return self.parent
 
     def set_highlighted(self, highlighted):
         """
diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py
index 867a7cd2e8..9cd8067966 100644
--- a/grc/gui/FlowGraph.py
+++ b/grc/gui/FlowGraph.py
@@ -30,20 +30,23 @@ from . Element import Element
 from . Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE
 from . external_editor import ExternalEditor
 
+from ..python.FlowGraph import FlowGraph as _Flowgraph
 
-class FlowGraph(Element):
+
+class FlowGraph(Element, _Flowgraph):
     """
     FlowGraph is the data structure to store graphical signal blocks,
     graphical inputs and outputs,
     and the connections between inputs and outputs.
     """
 
-    def __init__(self):
+    def __init__(self, **kwargs):
         """
         FlowGraph constructor.
         Create a list for signal blocks and connections. Connect mouse handlers.
         """
         Element.__init__(self)
+        _Flowgraph.__init__(self, **kwargs)
         #when is the flow graph selected? (used by keyboard event handler)
         self.is_selected = lambda: bool(self.get_selected_elements())
         #important vars dealing with mouse event tracking
diff --git a/grc/gui/Param.py b/grc/gui/Param.py
index 6884d6530a..ddfbdcbb1a 100644
--- a/grc/gui/Param.py
+++ b/grc/gui/Param.py
@@ -24,7 +24,9 @@ pygtk.require('2.0')
 import gtk
 
 from . import Colors, Utils, Constants, Dialogs
-from . Element import Element
+from .Element import Element
+
+from ..python.Param import Param as _Param
 
 
 class InputParam(gtk.HBox):
@@ -378,11 +380,12 @@ Error:
 #end if"""
 
 
-class Param(Element):
+class Param(Element, _Param):
     """The graphical parameter."""
 
-    def __init__(self):
+    def __init__(self, **kwargs):
         Element.__init__(self)
+        _Param.__init__(self, **kwargs)
 
     def get_input(self, *args, **kwargs):
         """
diff --git a/grc/gui/Platform.py b/grc/gui/Platform.py
index eda28a0e94..fa0bcf65ea 100644
--- a/grc/gui/Platform.py
+++ b/grc/gui/Platform.py
@@ -17,12 +17,47 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-from Element import Element
+import os
+import sys
+
+from .Element import Element
+
+from ..python.Platform import Platform as _Platform
+from ..python.Constants import PREFS_FILE, PREFS_FILE_OLD
+
+from .Block import Block as _Block
+from .FlowGraph import FlowGraph as _FlowGraph
+from .Param import Param as _Param
+from .Port import Port as _Port
+from .Connection import Connection as _Connection
 
-class Platform(Element):
-    def __init__(self, prefs_file):
-        Element.__init__(self)
 
-        self._prefs_file = prefs_file
+class Platform(Element, _Platform):
+
+    def __init__(self):
+        Element.__init__(self)
+        _Platform.__init__(self)
+        self._move_old_pref_file()
+        self._prefs_file = PREFS_FILE
 
     def get_prefs_file(self): return self._prefs_file
+
+    @staticmethod
+    def _move_old_pref_file():
+        if PREFS_FILE == PREFS_FILE_OLD:
+            return  # prefs file overridden with env var
+        if os.path.exists(PREFS_FILE_OLD) and not os.path.exists(PREFS_FILE):
+            try:
+                import shutil
+                shutil.move(PREFS_FILE_OLD, PREFS_FILE)
+            except Exception as e:
+                print >> sys.stderr, e
+
+    ##############################################
+    # Constructors
+    ##############################################
+    FlowGraph = _FlowGraph
+    Connection = _Connection
+    Block = _Block
+    Port = _Port
+    Param = _Param
diff --git a/grc/gui/Port.py b/grc/gui/Port.py
index ae1a1d223f..849465fc69 100644
--- a/grc/gui/Port.py
+++ b/grc/gui/Port.py
@@ -17,32 +17,33 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-from Element import Element
-from Constants import (
-    PORT_SEPARATION, PORT_SPACING, CONNECTOR_EXTENSION_MINIMAL,
-    CONNECTOR_EXTENSION_INCREMENT, CANVAS_GRID_SIZE,
-    PORT_LABEL_PADDING, PORT_MIN_WIDTH, PORT_LABEL_HIDDEN_WIDTH, PORT_FONT
-)
-from .. base.Constants import DEFAULT_DOMAIN, GR_MESSAGE_DOMAIN
-import Utils
-import Actions
-import Colors
 import pygtk
 pygtk.require('2.0')
 import gtk
 
+from . import Actions, Colors, Utils
+from .Constants import (
+    PORT_SEPARATION, PORT_SPACING, CONNECTOR_EXTENSION_MINIMAL,
+    CONNECTOR_EXTENSION_INCREMENT, PORT_LABEL_PADDING, PORT_MIN_WIDTH, PORT_LABEL_HIDDEN_WIDTH, PORT_FONT
+)
+from .Element import Element
+from ..python.base.Constants import DEFAULT_DOMAIN, GR_MESSAGE_DOMAIN
+
+from ..python.Port import Port as _Port
+
 PORT_MARKUP_TMPL="""\
 <span foreground="black" font_desc="$font">$encode($port.get_name())</span>"""
 
 
-class Port(Element):
+class Port(_Port, Element):
     """The graphical port."""
 
-    def __init__(self):
+    def __init__(self, block, n, dir):
         """
         Port contructor.
         Create list of connector coordinates.
         """
+        _Port.__init__(self, block, n, dir)
         Element.__init__(self)
         self.W = self.H = self.w = self.h = 0
         self._connector_coordinate = (0, 0)
diff --git a/grc/python/Block.py b/grc/python/Block.py
index f43b006e5f..aaf65fbddf 100644
--- a/grc/python/Block.py
+++ b/grc/python/Block.py
@@ -17,20 +17,18 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-import itertools
 import collections
+import itertools
 
-from .. base.Constants import BLOCK_FLAG_NEED_QT_GUI, BLOCK_FLAG_NEED_WX_GUI
-from .. base.odict import odict
-
-from .. base.Block import Block as _Block
-from .. gui.Block import Block as _GUIBlock
+from .base.Constants import BLOCK_FLAG_NEED_QT_GUI, BLOCK_FLAG_NEED_WX_GUI
+from .base.odict import odict
+from .base.Block import Block as _Block
 
-from . FlowGraph import _variable_matcher
 from . import epy_block_io
+from .FlowGraph import _variable_matcher
 
 
-class Block(_Block, _GUIBlock):
+class Block(_Block):
 
     def __init__(self, flow_graph, n):
         """
@@ -59,7 +57,6 @@ class Block(_Block, _GUIBlock):
             flow_graph=flow_graph,
             n=n,
         )
-        _GUIBlock.__init__(self)
 
         self._epy_source_hash = -1  # for epy blocks
         self._epy_reload_error = None
diff --git a/grc/python/Connection.py b/grc/python/Connection.py
index 822876a0ae..e5b4c2563b 100644
--- a/grc/python/Connection.py
+++ b/grc/python/Connection.py
@@ -17,15 +17,15 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-import Constants
-from .. base.Connection import Connection as _Connection
-from .. gui.Connection import Connection as _GUIConnection
+from . import Constants
 
-class Connection(_Connection, _GUIConnection):
+from .base.Connection import Connection as _Connection
 
-    def __init__(self, **kwargs):
-        _Connection.__init__(self, **kwargs)
-        _GUIConnection.__init__(self)
+
+class Connection(_Connection):
+
+    def __init__(self, flow_graph, porta, portb):
+        _Connection.__init__(self, flow_graph, porta, portb)
 
     def is_msg(self):
         return self.get_source().get_type() == self.get_sink().get_type() == 'msg'
diff --git a/grc/python/FlowGraph.py b/grc/python/FlowGraph.py
index b2a1d27859..002740ac9d 100644
--- a/grc/python/FlowGraph.py
+++ b/grc/python/FlowGraph.py
@@ -21,8 +21,7 @@ import imp
 from operator import methodcaller
 
 from . import expr_utils
-from .. base.FlowGraph import FlowGraph as _FlowGraph
-from .. gui.FlowGraph import FlowGraph as _GUIFlowGraph
+from .base.FlowGraph import FlowGraph as _FlowGraph
 
 _variable_matcher = re.compile('^(variable\w*)$')
 _parameter_matcher = re.compile('^(parameter)$')
@@ -33,12 +32,11 @@ _bus_struct_sink_searcher = re.compile('^(bus_structure_sink)$')
 _bus_struct_src_searcher = re.compile('^(bus_structure_source)$')
 
 
-class FlowGraph(_FlowGraph, _GUIFlowGraph):
+class FlowGraph(_FlowGraph):
 
     def __init__(self, **kwargs):
         self.grc_file_path = ''
         _FlowGraph.__init__(self, **kwargs)
-        _GUIFlowGraph.__init__(self)
         self.n = {}
         self.n_hash = -1
         self._renew_eval_ns = True
diff --git a/grc/python/Generator.py b/grc/python/Generator.py
index 56e3a6e78f..5d6de35077 100644
--- a/grc/python/Generator.py
+++ b/grc/python/Generator.py
@@ -27,15 +27,14 @@ import re  # for shlex_quote
 from distutils.spawn import find_executable
 
 from Cheetah.Template import Template
+from .base import odict
+from .base.Constants import BLOCK_FLAG_NEED_QT_GUI
 
-from .. gui import Messages
-from .. base import ParseXML
-from .. base import odict
-from .. base.Constants import BLOCK_FLAG_NEED_QT_GUI
-
+from .base import ParseXML
+from . import expr_utils
 from . Constants import TOP_BLOCK_FILE_MODE, FLOW_GRAPH_TEMPLATE, \
     XTERM_EXECUTABLE, HIER_BLOCK_FILE_MODE, HIER_BLOCKS_LIB_DIR, BLOCK_DTD
-from . import expr_utils
+from .. gui import Messages
 
 
 class Generator(object):
diff --git a/grc/python/Param.py b/grc/python/Param.py
index e60f613f00..b627e5eec8 100644
--- a/grc/python/Param.py
+++ b/grc/python/Param.py
@@ -18,17 +18,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
 import ast
-import re
 
+import re
+from gnuradio import eng_notation
 from gnuradio import gr
 
-from .. base.Param import Param as _Param
-from .. gui.Param import Param as _GUIParam
-
 import Constants
 from Constants import VECTOR_TYPES, COMPLEX_TYPES, REAL_TYPES, INT_TYPES
-
-from gnuradio import eng_notation
+from .base.Param import Param as _Param
 
 _check_id_matcher = re.compile('^[a-z|A-Z]\w*$')
 _show_id_matcher = re.compile('^(variable\w*|parameter|options|notebook|epy_module)$')
@@ -52,11 +49,10 @@ def num_to_str(num):
     else: return str(num)
 
 
-class Param(_Param, _GUIParam):
+class Param(_Param):
 
     def __init__(self, **kwargs):
         _Param.__init__(self, **kwargs)
-        _GUIParam.__init__(self)
         self._init = False
         self._hostage_cells = list()
 
diff --git a/grc/python/Platform.py b/grc/python/Platform.py
index 5932818c1e..e6b17fe3f7 100644
--- a/grc/python/Platform.py
+++ b/grc/python/Platform.py
@@ -19,27 +19,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
 import os
 import sys
-
 from gnuradio import gr
 
-from .. base.Platform import Platform as _Platform
-from .. gui.Platform import Platform as _GUIPlatform
-from .. gui import Messages
+from .base.Platform import Platform as _Platform
 
 from . import extract_docs
-from .FlowGraph import FlowGraph as _FlowGraph
-from .Connection import Connection as _Connection
-from .Block import Block as _Block
-from .Port import Port as _Port
-from .Param import Param as _Param
-from .Generator import Generator
 from .Constants import (
     HIER_BLOCKS_LIB_DIR, BLOCK_DTD, DEFAULT_FLOW_GRAPH, BLOCKS_DIRS,
-    PREFS_FILE, PREFS_FILE_OLD, CORE_TYPES
+    PREFS_FILE, CORE_TYPES, PREFS_FILE_OLD,
 )
+from .Generator import Generator
+from .. gui import Messages
 
 
-class Platform(_Platform, _GUIPlatform):
+class Platform(_Platform):
     def __init__(self):
         """
         Make a platform for gnuradio.
@@ -72,11 +65,7 @@ class Platform(_Platform, _GUIPlatform):
             generator=Generator,
             colors=[(name, color) for name, key, sizeof, color in CORE_TYPES],
         )
-        self._move_old_pref_file()
-        _GUIPlatform.__init__(
-            self,
-            prefs_file=PREFS_FILE
-        )
+
         self._auto_hier_block_generate_chain = set()
 
     def _save_docstring_extraction_result(self, key, docstrings):
@@ -164,12 +153,3 @@ class Platform(_Platform, _GUIPlatform):
 
         self.load_block_xml(generator.get_file_path_xml())
         return True
-
-    ##############################################
-    # Constructors
-    ##############################################
-    FlowGraph = _FlowGraph
-    Connection = _Connection
-    Block = _Block
-    Port = _Port
-    Param = _Param
diff --git a/grc/python/Port.py b/grc/python/Port.py
index 249d7aed71..8466f4f97c 100644
--- a/grc/python/Port.py
+++ b/grc/python/Port.py
@@ -17,10 +17,10 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-from .. base.Port import Port as _Port
-from .. base.Constants import DEFAULT_DOMAIN, GR_MESSAGE_DOMAIN
-from .. gui.Port import Port as _GUIPort
-import Constants
+from .base.Constants import DEFAULT_DOMAIN, GR_MESSAGE_DOMAIN
+from .base.Port import Port as _Port
+
+from . import Constants
 
 
 def _get_source_from_virtual_sink_port(vsp):
@@ -32,6 +32,7 @@ def _get_source_from_virtual_sink_port(vsp):
         vsp.get_enabled_connections()[0].get_source())
     except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp
 
+
 def _get_source_from_virtual_source_port(vsp, traversed=[]):
     """
     Recursively resolve source ports over the virtual connections.
@@ -52,6 +53,7 @@ def _get_source_from_virtual_source_port(vsp, traversed=[]):
     )
     except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp
 
+
 def _get_sink_from_virtual_source_port(vsp):
     """
     Resolve the sink port that is connected to the given virtual source port.
@@ -61,6 +63,7 @@ def _get_sink_from_virtual_source_port(vsp):
         vsp.get_enabled_connections()[0].get_sink())    # Could have many connections, but use first
     except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp
 
+
 def _get_sink_from_virtual_sink_port(vsp, traversed=[]):
     """
     Recursively resolve sink ports over the virtual connections.
@@ -81,7 +84,8 @@ def _get_sink_from_virtual_sink_port(vsp, traversed=[]):
     )
     except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp
 
-class Port(_Port, _GUIPort):
+
+class Port(_Port):
 
     def __init__(self, block, n, dir):
         """
@@ -111,7 +115,6 @@ class Port(_Port, _GUIPort):
             n=n,
             dir=dir,
         )
-        _GUIPort.__init__(self)
         self._nports = n.find('nports') or ''
         self._vlen = n.find('vlen') or ''
         self._optional = bool(n.find('optional'))
diff --git a/grc/python/base/Block.py b/grc/python/base/Block.py
new file mode 100644
index 0000000000..77c3145173
--- /dev/null
+++ b/grc/python/base/Block.py
@@ -0,0 +1,542 @@
+"""
+Copyright 2008-2011 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 . import odict
+from . Constants import ADVANCED_PARAM_TAB, DEFAULT_PARAM_TAB
+from . Constants import BLOCK_FLAG_THROTTLE, BLOCK_FLAG_DISABLE_BYPASS
+from . Constants import BLOCK_ENABLED, BLOCK_BYPASSED, BLOCK_DISABLED
+from Element import Element
+
+from Cheetah.Template import Template
+from UserDict import UserDict
+from itertools import imap
+
+
+class TemplateArg(UserDict):
+    """
+    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):
+        UserDict.__init__(self)
+        self._param = param
+        if param.is_enum():
+            for key in param.get_opt_keys():
+                self[key] = str(param.get_opt(key))
+
+    def __str__(self):
+        return str(self._param.to_code())
+
+    def __call__(self):
+        return self._param.get_evaluated()
+
+
+def _get_keys(lst):
+    return [elem.get_key() for elem in lst]
+
+
+def _get_elem(lst, key):
+    try: return lst[_get_keys(lst).index(key)]
+    except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
+
+
+class Block(Element):
+
+    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
+        """
+        #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 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 "%s" already exists in params'%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 "%s" already exists in sources'%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 "%s" already exists in sinks'%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
+                         })
+                ))
+
+    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 - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key())
+
+    def get_id(self): return self.get_param('id').get_value()
+    def is_block(self): return True
+    def get_name(self): return self._name
+    def get_key(self): return self._key
+    def get_category(self): return self._category
+    def set_category(self, cat): self._category = cat
+    def get_doc(self): return ''
+    def get_ports(self): return self.get_sources() + self.get_sinks()
+    def get_ports_gui(self): return self.filter_bus_port(self.get_sources()) + self.filter_bus_port(self.get_sinks());
+    def get_children(self): return self.get_ports() + self.get_params()
+    def get_children_gui(self): return self.get_ports_gui() + self.get_params()
+    def get_block_wrapper_path(self): return self._block_wrapper_path
+    def get_comment(self): return self.get_param('comment').get_value()
+
+    def get_flags(self): return self._flags
+    def throtteling(self): return BLOCK_FLAG_THROTTLE in self._flags
+    def bypass_disabled(self): return BLOCK_FLAG_DISABLE_BYPASS in self._flags
+
+    ##############################################
+    # 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((p.get_key(), TemplateArg(p)) for p in self.get_params())
+        try:
+            return str(Template(tmpl, n))
+        except Exception as err:
+            return "Template error: %s\n    %s" % (tmpl, err)
+
+    ##############################################
+    # 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 port_controller_modify(self, direction):
+        """
+        Change the port controller.
+
+        Args:
+            direction: +1 or -1
+
+        Returns:
+            true for change
+        """
+        return False
+
+    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 (not 'bus' in map(lambda a: a.get_type(), get_p())) and len(get_p()) > 0:
+
+            struct = self.form_bus_structure(direc);
+            self.current_bus_structure[direc] = struct;
+            if 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 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
+        """
+        get_hash = lambda: hash(tuple(map(hash, self.get_params())))
+        my_hash = 0
+        while get_hash() != my_hash:
+            params_n = n.findall('param')
+            for param_n in params_n:
+                key = param_n.find('key')
+                value = param_n.find('value')
+                #the key must exist in this block's params
+                if key in self.get_param_keys():
+                    self.get_param(key).set_value(value)
+            #store hash and call rewrite
+            my_hash = get_hash()
+            self.rewrite()
+        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 --git a/grc/python/base/CMakeLists.txt b/grc/python/base/CMakeLists.txt
new file mode 100644
index 0000000000..bdc8a5006f
--- /dev/null
+++ b/grc/python/base/CMakeLists.txt
@@ -0,0 +1,43 @@
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio 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 3, or (at your option)
+# any later version.
+#
+# GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+
+########################################################################
+GR_PYTHON_INSTALL(FILES
+    odict.py
+    ParseXML.py
+    Block.py
+    Connection.py
+    Constants.py
+    Element.py
+    FlowGraph.py
+    Param.py
+    Platform.py
+    Port.py
+    __init__.py
+    DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/base
+    COMPONENT "grc"
+)
+
+install(FILES
+    block_tree.dtd
+    domain.dtd
+    flow_graph.dtd
+    DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/base
+    COMPONENT "grc"
+)
diff --git a/grc/python/base/Connection.py b/grc/python/base/Connection.py
new file mode 100644
index 0000000000..8df0f5ad53
--- /dev/null
+++ b/grc/python/base/Connection.py
@@ -0,0 +1,139 @@
+"""
+Copyright 2008-2011 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 .Element import Element
+from . import odict
+
+
+class Connection(Element):
+
+    def __init__(self, flow_graph, porta, portb):
+        """
+        Make a new connection given the parent and 2 ports.
+
+        Args:
+            flow_graph: the parent of this element
+            porta: a port (any direction)
+            portb: a port (any direction)
+        @throws Error cannot make connection
+
+        Returns:
+            a new connection
+        """
+        Element.__init__(self, flow_graph)
+        source = sink = None
+        #separate the source and sink
+        for port in (porta, portb):
+            if port.is_source(): source = port
+            if port.is_sink(): sink = port
+        if not source: raise ValueError('Connection could not isolate source')
+        if not sink: raise ValueError('Connection could not isolate sink')
+        busses = len(filter(lambda a: a.get_type() == 'bus', [source, sink]))%2
+        if not busses == 0: raise ValueError('busses must get with busses')
+
+        if not len(source.get_associated_ports()) == len(sink.get_associated_ports()):
+            raise ValueError('port connections must have same cardinality');
+        #ensure that this connection (source -> sink) is unique
+        for connection in self.get_parent().get_connections():
+            if connection.get_source() is source and connection.get_sink() is sink:
+                raise LookupError('This connection between source and sink is not unique.')
+        self._source = source
+        self._sink = sink
+        if source.get_type() == 'bus':
+
+            sources = source.get_associated_ports();
+            sinks = sink.get_associated_ports();
+
+            for i in range(len(sources)):
+                try:
+                    flow_graph.connect(sources[i], sinks[i]);
+                except:
+                    pass
+
+    def __str__(self):
+        return 'Connection (\n\t%s\n\t\t%s\n\t%s\n\t\t%s\n)'%(
+            self.get_source().get_parent(),
+            self.get_source(),
+            self.get_sink().get_parent(),
+            self.get_sink(),
+        )
+
+    def is_connection(self): return True
+
+    def validate(self):
+        """
+        Validate the connections.
+        The ports must match in type.
+        """
+        Element.validate(self)
+        platform = self.get_parent().get_parent()
+        source_domain = self.get_source().get_domain()
+        sink_domain = self.get_sink().get_domain()
+        if (source_domain, sink_domain) not in platform.get_connection_templates():
+            self.add_error_message('No connection known for domains "%s", "%s"'
+                                   % (source_domain, sink_domain))
+        too_many_other_sinks = (
+            source_domain in platform.get_domains() and
+            not platform.get_domain(key=source_domain)['multiple_sinks'] and
+            len(self.get_source().get_enabled_connections()) > 1
+        )
+        too_many_other_sources = (
+            sink_domain in platform.get_domains() and
+            not platform.get_domain(key=sink_domain)['multiple_sources'] and
+            len(self.get_sink().get_enabled_connections()) > 1
+        )
+        if too_many_other_sinks:
+            self.add_error_message(
+                'Domain "%s" can have only one downstream block' % source_domain)
+        if too_many_other_sources:
+            self.add_error_message(
+                'Domain "%s" can have only one upstream block' % sink_domain)
+
+    def get_enabled(self):
+        """
+        Get the enabled state of this connection.
+
+        Returns:
+            true if source and sink blocks are enabled
+        """
+        return self.get_source().get_parent().get_enabled() and \
+            self.get_sink().get_parent().get_enabled()
+
+    #############################
+    # Access Ports
+    #############################
+    def get_sink(self): return self._sink
+    def get_source(self): return self._source
+
+    ##############################################
+    ## Import/Export Methods
+    ##############################################
+    def export_data(self):
+        """
+        Export this connection's info.
+
+        Returns:
+            a nested data odict
+        """
+        n = odict()
+        n['source_block_id'] = self.get_source().get_parent().get_id()
+        n['sink_block_id'] = self.get_sink().get_parent().get_id()
+        n['source_key'] = self.get_source().get_key()
+        n['sink_key'] = self.get_sink().get_key()
+        return n
diff --git a/grc/python/base/Constants.py b/grc/python/base/Constants.py
new file mode 100644
index 0000000000..1e83de63b5
--- /dev/null
+++ b/grc/python/base/Constants.py
@@ -0,0 +1,50 @@
+"""
+Copyright 2008, 2009 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion is free software; you can redistribute it and/or
+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 os
+
+#data files
+DATA_DIR = os.path.dirname(__file__)
+FLOW_GRAPH_DTD = os.path.join(DATA_DIR, 'flow_graph.dtd')
+BLOCK_TREE_DTD = os.path.join(DATA_DIR, 'block_tree.dtd')
+
+# file format versions:
+#  0: undefined / legacy
+#  1: non-numeric message port keys (label is used instead)
+FLOW_GRAPH_FILE_FORMAT_VERSION = 1
+
+# Param tabs
+DEFAULT_PARAM_TAB = "General"
+ADVANCED_PARAM_TAB = "Advanced"
+
+# Port domains
+DOMAIN_DTD = os.path.join(DATA_DIR, 'domain.dtd')
+GR_STREAM_DOMAIN = "gr_stream"
+GR_MESSAGE_DOMAIN = "gr_message"
+DEFAULT_DOMAIN = GR_STREAM_DOMAIN
+
+BLOCK_FLAG_THROTTLE = 'throttle'
+BLOCK_FLAG_DISABLE_BYPASS = 'disable_bypass'
+BLOCK_FLAG_NEED_QT_GUI = 'need_qt_gui'
+BLOCK_FLAG_NEED_WX_GUI = 'need_ex_gui'
+
+# Block States
+BLOCK_DISABLED = 0
+BLOCK_ENABLED = 1
+BLOCK_BYPASSED = 2
diff --git a/grc/python/base/Element.py b/grc/python/base/Element.py
new file mode 100644
index 0000000000..3b604a5340
--- /dev/null
+++ b/grc/python/base/Element.py
@@ -0,0 +1,98 @@
+"""
+Copyright 2008, 2009 Free Software Foundation, Inc.
+This file is part of GNU Radio
+
+GNU Radio Companion is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+GNU Radio Companion is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+"""
+
+
+class Element(object):
+
+    def __init__(self, parent=None):
+        self._parent = parent
+        self._error_messages = list()
+
+    ##################################################
+    # Element Validation API
+    ##################################################
+    def validate(self):
+        """
+        Validate this element and call validate on all children.
+        Call this base method before adding error messages in the subclass.
+        """
+        del self._error_messages[:]
+        for child in self.get_children(): child.validate()
+
+    def is_valid(self):
+        """
+        Is this element valid?
+
+        Returns:
+            true when the element is enabled and has no error messages
+        """
+        return not self.get_error_messages() or not self.get_enabled()
+
+    def add_error_message(self, msg):
+        """
+        Add an error message to the list of errors.
+
+        Args:
+            msg: the error message string
+        """
+        self._error_messages.append(msg)
+
+    def get_error_messages(self):
+        """
+        Get the list of error messages from this element and all of its children.
+        Do not include the error messages from disabled children.
+        Cleverly indent the children error messages for printing purposes.
+
+        Returns:
+            a list of error message strings
+        """
+        error_messages = list(self._error_messages) #make a copy
+        for child in filter(lambda c: c.get_enabled(), self.get_children()):
+            for msg in child.get_error_messages():
+                error_messages.append("%s:\n\t%s"%(child, msg.replace("\n", "\n\t")))
+        return error_messages
+
+    def rewrite(self):
+        """
+        Rewrite this element and call rewrite on all children.
+        Call this base method before rewriting the element.
+        """
+        for child in self.get_children(): child.rewrite()
+
+    def get_enabled(self): return True
+
+    ##############################################
+    ## Tree-like API
+    ##############################################
+    def get_parent(self): return self._parent
+    def get_children(self): return list()
+
+    ##############################################
+    ## Type testing methods
+    ##############################################
+    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
diff --git a/grc/python/base/FlowGraph.py b/grc/python/base/FlowGraph.py
new file mode 100644
index 0000000000..42faab6a16
--- /dev/null
+++ b/grc/python/base/FlowGraph.py
@@ -0,0 +1,482 @@
+"""
+Copyright 2008-2011 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 time
+from operator import methodcaller
+from itertools import ifilter
+
+from grc.gui import Messages
+
+from . import odict
+from .Element import Element
+from .Constants import FLOW_GRAPH_FILE_FORMAT_VERSION
+
+
+class FlowGraph(Element):
+
+    def __init__(self, platform):
+        """
+        Make a flow graph from the arguments.
+
+        Args:
+            platform: a platforms with blocks and contrcutors
+
+        Returns:
+            the flow graph object
+        """
+        #initialize
+        Element.__init__(self, platform)
+        self._elements = []
+        self._timestamp = time.ctime()
+        #inital blank import
+        self.import_data()
+
+    def _get_unique_id(self, base_id=''):
+        """
+        Get a unique id starting with the base id.
+
+        Args:
+            base_id: the id starts with this and appends a count
+
+        Returns:
+            a unique id
+        """
+        index = 0
+        while True:
+            id = '%s_%d' % (base_id, index)
+            index += 1
+            #make sure that the id is not used by another block
+            if not filter(lambda b: b.get_id() == id, self.get_blocks()): return id
+
+    def __str__(self):
+        return 'FlowGraph - %s(%s)' % (self.get_option('title'), self.get_option('id'))
+
+    def get_complexity(self):
+        """
+        Determines the complexity of a flowgraph
+        """
+        dbal = 0
+        block_list = self.get_blocks()
+        for block in block_list:
+            # Skip options block
+            if block.get_key() == 'options':
+                continue
+
+            # Don't worry about optional sinks?
+            sink_list = filter(lambda c: not c.get_optional(), block.get_sinks())
+            source_list = filter(lambda c: not c.get_optional(), block.get_sources())
+            sinks = float(len(sink_list))
+            sources = float(len(source_list))
+            base = max(min(sinks, sources), 1)
+
+            # Port ratio multiplier
+            if min(sinks, sources) > 0:
+                multi = sinks / sources
+                multi = (1 / multi) if multi > 1 else multi
+            else:
+                multi = 1
+
+            # Connection ratio multiplier
+            sink_multi = max(float(sum(map(lambda c: len(c.get_connections()), sink_list)) / max(sinks, 1.0)), 1.0)
+            source_multi = max(float(sum(map(lambda c: len(c.get_connections()), source_list)) / max(sources, 1.0)), 1.0)
+            dbal = dbal + (base * multi * sink_multi * source_multi)
+
+        elements = float(len(self.get_elements()))
+        connections = float(len(self.get_connections()))
+        disabled_connections = len(filter(lambda c: not c.get_enabled(), self.get_connections()))
+        blocks = float(len(block_list))
+        variables = elements - blocks - connections
+        enabled = float(len(self.get_enabled_blocks()))
+
+        # Disabled multiplier
+        if enabled > 0:
+            disabled_multi = 1 / (max(1 - ((blocks - enabled) / max(blocks, 1)), 0.05))
+        else:
+            disabled_multi = 1
+
+        # Connection multiplier (How many connections )
+        if (connections - disabled_connections) > 0:
+            conn_multi = 1 / (max(1 - (disabled_connections / max(connections, 1)), 0.05))
+        else:
+            conn_multi = 1
+
+        final = round(max((dbal - 1) * disabled_multi * conn_multi * connections, 0.0) / 1000000, 6)
+        return final
+
+    def rewrite(self):
+        def refactor_bus_structure():
+
+            for block in self.get_blocks():
+                for direc in ['source', 'sink']:
+                    if direc == 'source':
+                        get_p = block.get_sources;
+                        get_p_gui = block.get_sources_gui;
+                        bus_structure = block.form_bus_structure('source');
+                    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);
+
+        for child in self.get_children(): child.rewrite()
+        refactor_bus_structure()
+
+    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()
+
+    def is_flow_graph(self): return True
+
+    ##############################################
+    ## Access Elements
+    ##############################################
+    def get_block(self, id):
+        for block in self.iter_blocks():
+            if block.get_id() == id:
+                return block
+        raise KeyError('No block with ID {0!r}'.format(id))
+
+    def iter_blocks(self):
+        return ifilter(methodcaller('is_block'), self.get_elements())
+
+    def get_blocks(self):
+        return list(self.iter_blocks())
+
+    def iter_connections(self):
+        return ifilter(methodcaller('is_connection'), self.get_elements())
+
+    def get_connections(self):
+        return list(self.iter_connections())
+
+    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._elements.count(self._options_block)
+        if not options_block_count:
+            self._elements.append(self._options_block)
+        for i in range(options_block_count-1):
+            self._elements.remove(self._options_block)
+        return self._elements
+
+    get_children = get_elements
+
+    def iter_enabled_blocks(self):
+        """
+        Get an iterator of all blocks that are enabled and not bypassed.
+        """
+        return ifilter(methodcaller('get_enabled'), self.iter_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.iter_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.get_connections())
+
+    def get_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
+        """
+        if key not in self.get_parent().get_block_keys(): return None
+        block = self.get_parent().get_new_block(self, key)
+        self.get_elements().append(block);
+        if block._bussify_sink:
+            block.bussify({'name':'bus','type':'bus'}, 'sink')
+        if block._bussify_source:
+            block.bussify({'name':'bus','type':'bus'}, 'source')
+        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.get_parent().Connection(flow_graph=self, porta=porta, portb=portb)
+        self.get_elements().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 not in self.get_elements(): return
+        #found a port, set to parent signal block
+        if element.is_port():
+            element = element.get_parent()
+        #remove block, remove all involved connections
+        if element.is_block():
+            for port in element.get_ports():
+                map(self.remove_element, port.get_connections())
+        if element.is_connection():
+            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.get_elements().remove(element)
+
+    def evaluate(self, expr):
+        """
+        Evaluate the expression.
+
+        Args:
+            expr: the string expression
+        @throw NotImplementedError
+        """
+        raise NotImplementedError
+
+    ##############################################
+    ## 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.iter_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.get_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': self.get_parent().get_version_short(),
+            'format': FLOW_GRAPH_FILE_FORMAT_VERSION,
+        })
+        return odict({'flow_graph': n, '_instructions': instructions})
+
+    def import_data(self, n=None):
+        """
+        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
+        """
+        errors = False
+        self._elements = list()  # remove previous elements
+        # 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.get_parent().get_new_block(self, 'options')
+        for block_n in fg_n.findall('block'):
+            key = block_n.find('key')
+            block = self._options_block if key == 'options' else self.get_new_block(key)
+
+            if not block:  # looks like this block key cannot be found
+                # create a dummy block instead
+                block = self.get_new_block('dummy_block')
+                # Ugly ugly ugly
+                _initialize_dummy_block(block, block_n)
+                Messages.send_error_msg_load('Block key "%s" not found' % key)
+
+            block.import_data(block_n)
+
+        # 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
+
+        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 %s(%s) and %s(%s) could not be made.\n\t%s' % (
+                        source_block_id, source_key, sink_block_id, sink_key, e))
+                errors = True
+
+        self.rewrite()  # global rewrite
+        return errors
+
+
+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'})
+            block.get_params().append(block.get_parent().get_parent().Param(block=block, n=new_param_n))
+
+
+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 --git a/grc/python/base/Param.py b/grc/python/base/Param.py
new file mode 100644
index 0000000000..b246d9f759
--- /dev/null
+++ b/grc/python/base/Param.py
@@ -0,0 +1,203 @@
+"""
+Copyright 2008-2011 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 . import odict
+from Element import Element
+
+def _get_keys(lst): return [elem.get_key() for elem in lst]
+def _get_elem(lst, key):
+    try: return lst[_get_keys(lst).index(key)]
+    except ValueError: raise ValueError, 'Key "%s" not found in %s.'%(key, _get_keys(lst))
+
+class Option(Element):
+
+    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 "%s" into key:value'%opt
+            #test against repeated keys
+            if self._opts.has_key(key):
+                raise Exception, 'Key "%s" already exists in option'%key
+            #store the option
+            self._opts[key] = value
+
+    def __str__(self): return 'Option %s(%s)'%(self.get_name(), self.get_key())
+    def get_name(self): return self._name
+    def get_key(self): return self._key
+
+    ##############################################
+    # 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 Param(Element):
+
+    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 not self._tab_label 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()
+        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 "%s" already exists in options'%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 "%s" are not unique.'%self.get_option_keys()
+            #test against inconsistent keys in options
+            opt_keys = self.get_options()[0].get_opt_keys()
+            for option in self.get_options():
+                if set(opt_keys) != set(option.get_opt_keys()):
+                    raise Exception, 'Opt keys "%s" are not identical across all options.'%opt_keys
+            #if a value is specified, it must be in the options keys
+            self._value = value if value or value in self.get_option_keys() else self.get_option_keys()[0]
+            if self.get_value() not in self.get_option_keys():
+                raise Exception, 'The value "%s" is not in the possible values of "%s".'%(self.get_value(), self.get_option_keys())
+        else: self._value = value or ''
+        self._default = value
+
+    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 "%s" is not a possible type.'%self.get_type())
+
+    def get_evaluated(self): raise NotImplementedError
+
+    def to_code(self):
+        """
+        Convert the value to code.
+        @throw NotImplementedError
+        """
+        raise NotImplementedError
+
+    def get_types(self):
+        """
+        Get a list of all possible param types.
+        @throw NotImplementedError
+        """
+        raise NotImplementedError
+
+    def get_color(self): return '#FFFFFF'
+    def __str__(self): return 'Param - %s(%s)'%(self.get_name(), self.get_key())
+    def is_param(self): return True
+    def get_name(self): return self.get_parent().resolve_dependencies(self._name).strip()
+    def get_key(self): return self._key
+    def get_hide(self): return self.get_parent().resolve_dependencies(self._hide).strip()
+
+    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): self._value = str(value) #must be a string
+
+    def value_is_default(self):
+        return self._default == self._value
+
+    def get_type(self): return self.get_parent().resolve_dependencies(self._type)
+    def get_tab_label(self): return self._tab_label
+    def is_enum(self): return self._type == 'enum'
+
+    def __repr__(self):
+        """
+        Get the repr (nice string format) for this param.
+        Just return the value (special case enum).
+        Derived classes can handle complex formatting.
+
+        Returns:
+            the string representation
+        """
+        if self.is_enum(): return self.get_option(self.get_value()).get_name()
+        return self.get_value()
+
+    ##############################################
+    # 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 --git a/grc/python/base/ParseXML.py b/grc/python/base/ParseXML.py
new file mode 100644
index 0000000000..2d5fed0862
--- /dev/null
+++ b/grc/python/base/ParseXML.py
@@ -0,0 +1,155 @@
+"""
+Copyright 2008 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 lxml import etree
+from . import odict
+
+xml_failures = {}
+
+
+class XMLSyntaxError(Exception):
+    def __init__(self, error_log):
+        self._error_log = error_log
+        xml_failures[error_log.last_error.filename] = error_log
+
+    def __str__(self):
+        return '\n'.join(map(str, self._error_log.filter_from_errors()))
+
+
+def validate_dtd(xml_file, dtd_file=None):
+    """
+    Validate an xml file against its dtd.
+
+    Args:
+        xml_file: the xml file
+        dtd_file: the optional dtd file
+    @throws Exception validation fails
+    """
+    # perform parsing, use dtd validation if dtd file is not specified
+    parser = etree.XMLParser(dtd_validation=not dtd_file)
+    try:
+        xml = etree.parse(xml_file, parser=parser)
+    except etree.LxmlError:
+        pass
+    if parser.error_log:
+        raise XMLSyntaxError(parser.error_log)
+
+    # perform dtd validation if the dtd file is specified
+    if not dtd_file:
+        return
+    try:
+        dtd = etree.DTD(dtd_file)
+        if not dtd.validate(xml.getroot()):
+            raise XMLSyntaxError(dtd.error_log)
+    except etree.LxmlError:
+        raise XMLSyntaxError(dtd.error_log)
+
+
+def from_file(xml_file):
+    """
+    Create nested data from an xml file using the from xml helper.
+    Also get the grc version information.
+
+    Args:
+        xml_file: the xml file path
+
+    Returns:
+        the nested data with grc version information
+    """
+    xml = etree.parse(xml_file)
+    nested_data = _from_file(xml.getroot())
+
+    # Get the embedded instructions and build a dictionary item
+    nested_data['_instructions'] = {}
+    xml_instructions = xml.xpath('/processing-instruction()')
+    for inst in filter(lambda i: i.target == 'grc', xml_instructions):
+        nested_data['_instructions'] = odict(inst.attrib)
+    return nested_data
+
+
+def _from_file(xml):
+    """
+    Recursively parse the xml tree into nested data format.
+
+    Args:
+        xml: the xml tree
+
+    Returns:
+        the nested data
+    """
+    tag = xml.tag
+    if not len(xml):
+        return odict({tag: xml.text or ''})  # store empty tags (text is None) as empty string
+    nested_data = odict()
+    for elem in xml:
+        key, value = _from_file(elem).items()[0]
+        if nested_data.has_key(key): nested_data[key].append(value)
+        else: nested_data[key] = [value]
+    # delistify if the length of values is 1
+    for key, values in nested_data.iteritems():
+        if len(values) == 1:
+            nested_data[key] = values[0]
+
+    return odict({tag: nested_data})
+
+
+def to_file(nested_data, xml_file):
+    """
+    Write to an xml file and insert processing instructions for versioning
+
+    Args:
+        nested_data: the nested data
+        xml_file: the xml file path
+    """
+    xml_data = ""
+    instructions = nested_data.pop('_instructions', None)
+    if instructions:  # create the processing instruction from the array
+        xml_data += etree.tostring(etree.ProcessingInstruction(
+            'grc', ' '.join(
+                "{0}='{1}'".format(*item) for item in instructions.iteritems())
+        ), xml_declaration=True, pretty_print=True, encoding='utf-8')
+    xml_data += etree.tostring(_to_file(nested_data)[0],
+                               pretty_print=True, encoding='utf-8')
+    with open(xml_file, 'w') as fp:
+        fp.write(xml_data)
+
+
+def _to_file(nested_data):
+    """
+    Recursively parse the nested data into xml tree format.
+
+    Args:
+        nested_data: the nested data
+
+    Returns:
+        the xml tree filled with child nodes
+    """
+    nodes = list()
+    for key, values in nested_data.iteritems():
+        # listify the values if not a list
+        if not isinstance(values, (list, set, tuple)):
+            values = [values]
+        for value in values:
+            node = etree.Element(key)
+            if isinstance(value, (str, unicode)):
+                node.text = unicode(value)
+            else:
+                node.extend(_to_file(value))
+            nodes.append(node)
+    return nodes
diff --git a/grc/python/base/Platform.py b/grc/python/base/Platform.py
new file mode 100644
index 0000000000..367140f8ae
--- /dev/null
+++ b/grc/python/base/Platform.py
@@ -0,0 +1,274 @@
+"""
+Copyright 2008-2011 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 sys
+
+import os
+
+from .Block import Block as _Block
+from .Connection import Connection as _Connection
+from .Constants import BLOCK_TREE_DTD, FLOW_GRAPH_DTD, DOMAIN_DTD
+from .Element import Element as _Element
+from .FlowGraph import FlowGraph as _FlowGraph
+from .Param import Param as _Param
+from .Port import Port as _Port
+from . import ParseXML, odict
+
+
+class Platform(_Element):
+    def __init__(self, name, version, key,
+                 block_paths, block_dtd, default_flow_graph, generator,
+                 license='', website=None, colors=None):
+        """
+        Make a platform from the arguments.
+
+        Args:
+            name: the platform name
+            version: the version string
+            key: the unique platform key
+            block_paths: the file paths to blocks in this platform
+            block_dtd: the dtd validator for xml block wrappers
+            default_flow_graph: the default flow graph file path
+            generator: the generator class for this platform
+            colors: a list of title, color_spec tuples
+            license: a multi-line license (first line is copyright)
+            website: the website url for this platform
+
+        Returns:
+            a platform object
+        """
+        _Element.__init__(self)
+        self._name = name
+        # Save the verion string to the first
+        self._version = version[0]
+        self._version_major = version[1]
+        self._version_api = version[2]
+        self._version_minor = version[3]
+        self._version_short = version[1] + "." + version[2] + "." + version[3]
+
+        self._key = key
+        self._license = license
+        self._website = website
+        self._block_paths = list(set(block_paths))
+        self._block_dtd = block_dtd
+        self._default_flow_graph = default_flow_graph
+        self._generator = generator
+        self._colors = colors or []
+        #create a dummy flow graph for the blocks
+        self._flow_graph = _Element(self)
+
+        self._blocks = None
+        self._blocks_n = None
+        self._category_trees_n = None
+        self._domains = dict()
+        self._connection_templates = dict()
+        self.load_blocks()
+
+    def load_blocks(self):
+        """load the blocks and block tree from the search paths"""
+        # reset
+        self._blocks = odict()
+        self._blocks_n = odict()
+        self._category_trees_n = list()
+        self._domains.clear()
+        self._connection_templates.clear()
+        ParseXML.xml_failures.clear()
+        # try to parse and load blocks
+        for xml_file in self.iter_xml_files():
+            try:
+                if xml_file.endswith("block_tree.xml"):
+                    self.load_category_tree_xml(xml_file)
+                elif xml_file.endswith('domain.xml'):
+                    self.load_domain_xml(xml_file)
+                else:
+                    self.load_block_xml(xml_file)
+            except ParseXML.XMLSyntaxError as e:
+                # print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s' % (e, xml_file)
+                pass
+            except Exception as e:
+                print >> sys.stderr, 'Warning: XML parsing failed:\n\t%r\n\tIgnoring: %s' % (e, xml_file)
+
+    def iter_xml_files(self):
+        """Iterator for block descriptions and category trees"""
+        get_path = lambda x: os.path.abspath(os.path.expanduser(x))
+        for block_path in map(get_path, self._block_paths):
+            if os.path.isfile(block_path):
+                yield block_path
+            elif os.path.isdir(block_path):
+                for dirpath, dirnames, filenames in os.walk(block_path):
+                    for filename in sorted(filter(lambda f: f.endswith('.xml'), filenames)):
+                        yield os.path.join(dirpath, filename)
+
+    def load_block_xml(self, xml_file):
+        """Load block description from xml file"""
+        # validate and import
+        ParseXML.validate_dtd(xml_file, self._block_dtd)
+        n = ParseXML.from_file(xml_file).find('block')
+        n['block_wrapper_path'] = xml_file  # inject block wrapper path
+        # get block instance and add it to the list of blocks
+        block = self.Block(self._flow_graph, n)
+        key = block.get_key()
+        if key in self._blocks:
+            print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s' % (key, xml_file)
+        else:  # store the block
+            self._blocks[key] = block
+            self._blocks_n[key] = n
+        return block
+
+    def load_category_tree_xml(self, xml_file):
+        """Validate and parse category tree file and add it to list"""
+        ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD)
+        n = ParseXML.from_file(xml_file).find('cat')
+        self._category_trees_n.append(n)
+
+    def load_domain_xml(self, xml_file):
+        """Load a domain properties and connection templates from XML"""
+        ParseXML.validate_dtd(xml_file, DOMAIN_DTD)
+        n = ParseXML.from_file(xml_file).find('domain')
+
+        key = n.find('key')
+        if not key:
+            print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: %s' % xml_file
+            return
+        if key in self.get_domains():  # test against repeated keys
+            print >> sys.stderr, 'Warning: Domain with key "%s" already exists.\n\tIgnoring: %s' % (key, xml_file)
+            return
+
+        to_bool = lambda s, d: d if s is None else \
+            s.lower() not in ('false', 'off', '0', '')
+
+        color = n.find('color') or ''
+        try:
+            import gtk  # ugly but handy
+            gtk.gdk.color_parse(color)
+        except (ValueError, ImportError):
+            if color:  # no color is okay, default set in GUI
+                print >> sys.stderr, 'Warning: Can\'t parse color code "%s" for domain "%s" ' % (color, key)
+                color = None
+
+        self._domains[key] = dict(
+            name=n.find('name') or key,
+            multiple_sinks=to_bool(n.find('multiple_sinks'), True),
+            multiple_sources=to_bool(n.find('multiple_sources'), False),
+            color=color
+        )
+        for connection_n in n.findall('connection'):
+            key = (connection_n.find('source_domain'), connection_n.find('sink_domain'))
+            if not all(key):
+                print >> sys.stderr, 'Warning: Empty domain key(s) in connection template.\n\t%s' % xml_file
+            elif key in self._connection_templates:
+                print >> sys.stderr, 'Warning: Connection template "%s" already exists.\n\t%s' % (key, xml_file)
+            else:
+                self._connection_templates[key] = connection_n.find('make') or ''
+
+    def parse_flow_graph(self, flow_graph_file):
+        """
+        Parse a saved flow graph file.
+        Ensure that the file exists, and passes the dtd check.
+
+        Args:
+            flow_graph_file: the flow graph file
+
+        Returns:
+            nested data
+        @throws exception if the validation fails
+        """
+        flow_graph_file = flow_graph_file or self._default_flow_graph
+        open(flow_graph_file, 'r')  # test open
+        ParseXML.validate_dtd(flow_graph_file, FLOW_GRAPH_DTD)
+        return ParseXML.from_file(flow_graph_file)
+
+    def load_block_tree(self, block_tree):
+        """
+        Load a block tree with categories and blocks.
+        Step 1: Load all blocks from the xml specification.
+        Step 2: Load blocks with builtin category specifications.
+
+        Args:
+            block_tree: the block tree object
+        """
+        #recursive function to load categories and blocks
+        def load_category(cat_n, parent=None):
+            #add this category
+            parent = (parent or []) + [cat_n.find('name')]
+            block_tree.add_block(parent)
+            #recursive call to load sub categories
+            map(lambda c: load_category(c, parent), cat_n.findall('cat'))
+            #add blocks in this category
+            for block_key in cat_n.findall('block'):
+                if block_key not in self.get_block_keys():
+                    print >> sys.stderr, 'Warning: Block key "%s" not found when loading category tree.' % (block_key)
+                    continue
+                block = self.get_block(block_key)
+                #if it exists, the block's category shall not be overridden by the xml tree
+                if not block.get_category():
+                    block.set_category(parent)
+
+        # recursively load the category trees and update the categories for each block
+        for category_tree_n in self._category_trees_n:
+            load_category(category_tree_n)
+
+        #add blocks to block tree
+        for block in self.get_blocks():
+            #blocks with empty categories are hidden
+            if not block.get_category(): continue
+            block_tree.add_block(block.get_category(), block)
+
+    def __str__(self): return 'Platform - %s(%s)'%(self.get_key(), self.get_name())
+
+    def is_platform(self): return True
+
+    def get_new_flow_graph(self): return self.FlowGraph(platform=self)
+
+    def get_generator(self): return self._generator
+
+    ##############################################
+    # Access Blocks
+    ##############################################
+    def get_block_keys(self): return self._blocks.keys()
+    def get_block(self, key): return self._blocks[key]
+    def get_blocks(self): return self._blocks.values()
+    def get_new_block(self, flow_graph, key):
+        return self.Block(flow_graph, n=self._blocks_n[key])
+
+    def get_domains(self): return self._domains
+    def get_domain(self, key): return self._domains.get(key)
+    def get_connection_templates(self): return self._connection_templates
+
+    def get_name(self): return self._name
+    def get_version(self): return self._version
+    def get_version_major(self): return self._version_major
+    def get_version_api(self): return self._version_api
+    def get_version_minor(self): return self._version_minor
+    def get_version_short(self): return self._version_short
+
+    def get_key(self): return self._key
+    def get_license(self): return self._license
+    def get_website(self): return self._website
+    def get_colors(self): return self._colors
+    def get_block_paths(self): return self._block_paths
+
+    ##############################################
+    # Constructors
+    ##############################################
+    FlowGraph = _FlowGraph
+    Connection = _Connection
+    Block = _Block
+    Port = _Port
+    Param = _Param
diff --git a/grc/python/base/Port.py b/grc/python/base/Port.py
new file mode 100644
index 0000000000..39166d18f7
--- /dev/null
+++ b/grc/python/base/Port.py
@@ -0,0 +1,136 @@
+"""
+Copyright 2008-2011 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 Element import Element
+from . Constants import GR_STREAM_DOMAIN, GR_MESSAGE_DOMAIN
+
+class Port(Element):
+
+    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 source or sink
+        """
+        #build the port
+        Element.__init__(self, block)
+        #grab the data
+        self._name = n['name']
+        self._key = n['key']
+        self._type = n['type']
+        self._domain = n['domain']
+        self._hide = n.find('hide') or ''
+        self._dir = dir
+        self._hide_evaluated = False  # updated on rewrite()
+
+    def validate(self):
+        """
+        Validate the port.
+        The port must be non-empty and type must a possible type.
+        """
+        Element.validate(self)
+        if self.get_type() not in self.get_types():
+            self.add_error_message('Type "%s" is not a possible type.' % self.get_type())
+        platform = self.get_parent().get_parent().get_parent()
+        if self.get_domain() not in platform.get_domains():
+            self.add_error_message('Domain key "%s" is not registered.' % self.get_domain())
+
+    def rewrite(self):
+        """resolve dependencies in for type and hide"""
+        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 __str__(self):
+        if self.is_source():
+            return 'Source - %s(%s)'%(self.get_name(), self.get_key())
+        if self.is_sink():
+            return 'Sink - %s(%s)'%(self.get_name(), self.get_key())
+
+    def get_types(self):
+        """
+        Get a list of all possible port types.
+        @throw NotImplementedError
+        """
+        raise NotImplementedError
+
+    def is_port(self): return True
+    def get_color(self): return '#FFFFFF'
+    def get_name(self):
+        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
+    def is_sink(self): return self._dir == 'sink'
+    def is_source(self): return self._dir == 'source'
+    def get_type(self): return self.get_parent().resolve_dependencies(self._type)
+    def get_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().get_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 --git a/grc/python/base/__init__.py b/grc/python/base/__init__.py
new file mode 100644
index 0000000000..2682db8125
--- /dev/null
+++ b/grc/python/base/__init__.py
@@ -0,0 +1,20 @@
+"""
+Copyright 2009 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 odict import odict
diff --git a/grc/python/base/block_tree.dtd b/grc/python/base/block_tree.dtd
new file mode 100644
index 0000000000..9e23576477
--- /dev/null
+++ b/grc/python/base/block_tree.dtd
@@ -0,0 +1,26 @@
+<!--
+Copyright 2008 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
+-->
+<!--
+    block_tree.dtd
+    Josh Blum
+    The document type definition for a block tree category listing.
+ -->
+<!ELEMENT cat (name, cat*, block*)>
+<!ELEMENT name (#PCDATA)>
+<!ELEMENT block (#PCDATA)>
diff --git a/grc/python/base/domain.dtd b/grc/python/base/domain.dtd
new file mode 100644
index 0000000000..b5b0b8bf39
--- /dev/null
+++ b/grc/python/base/domain.dtd
@@ -0,0 +1,35 @@
+<!--
+Copyright 2014 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
+-->
+<!ELEMENT domain (name, key, color?, multiple_sinks?, multiple_sources?, connection*)>
+<!--
+    Sub level elements.
+ -->
+<!ELEMENT connection (source_domain, sink_domain, make)>
+<!--
+    Bottom level elements.
+    Character data only.
+ -->
+<!ELEMENT name (#PCDATA)>
+<!ELEMENT key (#PCDATA)>
+<!ELEMENT multiple_sinks (#PCDATA)>
+<!ELEMENT multiple_sources (#PCDATA)>
+<!ELEMENT color (#PCDATA)>
+<!ELEMENT make (#PCDATA)>
+<!ELEMENT source_domain (#PCDATA)>
+<!ELEMENT sink_domain (#PCDATA)>
diff --git a/grc/python/base/flow_graph.dtd b/grc/python/base/flow_graph.dtd
new file mode 100644
index 0000000000..bdfe1dc059
--- /dev/null
+++ b/grc/python/base/flow_graph.dtd
@@ -0,0 +1,38 @@
+<!--
+Copyright 2008 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
+-->
+<!--
+    flow_graph.dtd
+    Josh Blum
+    The document type definition for flow graph xml files.
+ -->
+<!ELEMENT flow_graph (timestamp?, block*, connection*)> <!-- optional timestamp -->
+<!ELEMENT timestamp (#PCDATA)>
+<!-- Block -->
+<!ELEMENT block (key, param*, bus_sink?, bus_source?)>
+<!ELEMENT param (key, value)>
+<!ELEMENT key (#PCDATA)>
+<!ELEMENT value (#PCDATA)>
+<!ELEMENT bus_sink (#PCDATA)>
+<!ELEMENT bus_source (#PCDATA)>
+<!-- Connection -->
+<!ELEMENT connection (source_block_id, sink_block_id, source_key, sink_key)>
+<!ELEMENT source_block_id (#PCDATA)>
+<!ELEMENT sink_block_id (#PCDATA)>
+<!ELEMENT source_key (#PCDATA)>
+<!ELEMENT sink_key (#PCDATA)>
diff --git a/grc/python/base/odict.py b/grc/python/base/odict.py
new file mode 100644
index 0000000000..70ab67d053
--- /dev/null
+++ b/grc/python/base/odict.py
@@ -0,0 +1,105 @@
+"""
+Copyright 2008-2011 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 UserDict import DictMixin
+
+class odict(DictMixin):
+
+    def __init__(self, d={}):
+        self._keys = list(d.keys())
+        self._data = dict(d.copy())
+
+    def __setitem__(self, key, value):
+        if key not in self._data:
+            self._keys.append(key)
+        self._data[key] = value
+
+    def __getitem__(self, key):
+        return self._data[key]
+
+    def __delitem__(self, key):
+        del self._data[key]
+        self._keys.remove(key)
+
+    def keys(self):
+        return list(self._keys)
+
+    def copy(self):
+        copy_dict = odict()
+        copy_dict._data = self._data.copy()
+        copy_dict._keys = list(self._keys)
+        return copy_dict
+
+    def insert_after(self, pos_key, key, val):
+        """
+        Insert the new key, value entry after the entry given by the position key.
+        If the positional key is None, insert at the end.
+
+        Args:
+            pos_key: the positional key
+            key: the key for the new entry
+            val: the value for the new entry
+        """
+        index = (pos_key is None) and len(self._keys) or self._keys.index(pos_key)
+        if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key))
+        self._keys.insert(index+1, key)
+        self._data[key] = val
+
+    def insert_before(self, pos_key, key, val):
+        """
+        Insert the new key, value entry before the entry given by the position key.
+        If the positional key is None, insert at the begining.
+
+        Args:
+            pos_key: the positional key
+            key: the key for the new entry
+            val: the value for the new entry
+        """
+        index = (pos_key is not None) and self._keys.index(pos_key) or 0
+        if key in self._keys: raise KeyError('Cannot insert, key "%s" already exists'%str(key))
+        self._keys.insert(index, key)
+        self._data[key] = val
+
+    def find(self, key):
+        """
+        Get the value for this key if exists.
+
+        Args:
+            key: the key to search for
+
+        Returns:
+            the value or None
+        """
+        if self.has_key(key): return self[key]
+        return None
+
+    def findall(self, key):
+        """
+        Get a list of values for this key.
+
+        Args:
+            key: the key to search for
+
+        Returns:
+            a list of values or empty list
+        """
+        obj = self.find(key)
+        if obj is None: obj = list()
+        if isinstance(obj, list): return obj
+        return [obj]
diff --git a/grc/scripts/gnuradio-companion b/grc/scripts/gnuradio-companion
index 203a8c773d..9eee8df7dd 100755
--- a/grc/scripts/gnuradio-companion
+++ b/grc/scripts/gnuradio-companion
@@ -108,13 +108,13 @@ def main():
     source_tree_root = get_source_tree_root()
     if not source_tree_root:
         # run the installed version
-        from gnuradio.grc.python.Platform import Platform
+        from gnuradio.grc.gui.Platform import Platform
         from gnuradio.grc.gui.ActionHandler import ActionHandler
 
     else:
         print("Running from source tree")
         sys.path.insert(1, source_tree_root)
-        from grc.python.Platform import Platform
+        from grc.gui.Platform import Platform
         from grc.gui.ActionHandler import ActionHandler
 
     try:
-- 
cgit v1.2.3