summaryrefslogtreecommitdiff
path: root/grc/python
diff options
context:
space:
mode:
authorSebastian Koslowski <koslowski@kit.edu>2015-11-20 17:39:59 +0100
committerSebastian Koslowski <koslowski@kit.edu>2016-02-17 19:55:16 +0100
commit36af320d43c726d9bf71eb871737bdd647ff60ef (patch)
tree389857d060e636e80efde53c7df1265e4e90ec3c /grc/python
parent9f5ef34ac05de070a99fae07eb1a8087ba60a653 (diff)
grc-refactor: clean-up grc directory
Diffstat (limited to 'grc/python')
-rw-r--r--grc/python/Block.py324
-rw-r--r--grc/python/CMakeLists.txt44
-rw-r--r--grc/python/Connection.py45
-rw-r--r--grc/python/Constants.py140
-rw-r--r--grc/python/FlowGraph.py336
-rw-r--r--grc/python/Generator.py446
-rw-r--r--grc/python/Param.py429
-rw-r--r--grc/python/Platform.py155
-rw-r--r--grc/python/Port.py271
-rw-r--r--grc/python/__init__.py1
-rw-r--r--grc/python/base/Block.py542
-rw-r--r--grc/python/base/CMakeLists.txt43
-rw-r--r--grc/python/base/Connection.py139
-rw-r--r--grc/python/base/Constants.py50
-rw-r--r--grc/python/base/Element.py98
-rw-r--r--grc/python/base/FlowGraph.py482
-rw-r--r--grc/python/base/Param.py203
-rw-r--r--grc/python/base/ParseXML.py155
-rw-r--r--grc/python/base/Platform.py274
-rw-r--r--grc/python/base/Port.py136
-rw-r--r--grc/python/base/__init__.py20
-rw-r--r--grc/python/base/block_tree.dtd26
-rw-r--r--grc/python/base/domain.dtd35
-rw-r--r--grc/python/base/flow_graph.dtd38
-rw-r--r--grc/python/base/odict.py105
-rw-r--r--grc/python/block.dtd69
-rw-r--r--grc/python/default_flow_graph.grc43
-rw-r--r--grc/python/epy_block_io.py95
-rw-r--r--grc/python/expr_utils.py177
-rw-r--r--grc/python/extract_docs.py296
-rw-r--r--grc/python/flow_graph.tmpl439
31 files changed, 0 insertions, 5656 deletions
diff --git a/grc/python/Block.py b/grc/python/Block.py
deleted file mode 100644
index aaf65fbddf..0000000000
--- a/grc/python/Block.py
+++ /dev/null
@@ -1,324 +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 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 . import epy_block_io
-from .FlowGraph import _variable_matcher
-
-
-class Block(_Block):
-
- def __init__(self, flow_graph, n):
- """
- Make a new block from nested data.
-
- Args:
- flow: graph the parent element
- n: the nested odict
-
- Returns:
- block a new block
- """
- #grab the data
- self._doc = (n.find('doc') or '').strip('\n').replace('\\\n', '')
- self._imports = map(lambda i: i.strip(), n.findall('import'))
- self._make = n.find('make')
- self._var_make = n.find('var_make')
- self._checks = n.findall('check')
- self._callbacks = n.findall('callback')
- self._bus_structure_source = n.find('bus_structure_source') or ''
- self._bus_structure_sink = n.find('bus_structure_sink') or ''
- self.port_counters = [itertools.count(), itertools.count()]
- #build the block
- _Block.__init__(
- self,
- flow_graph=flow_graph,
- n=n,
- )
-
- self._epy_source_hash = -1 # for epy blocks
- self._epy_reload_error = None
-
- def get_bus_structure(self, direction):
- if direction == 'source':
- bus_structure = self._bus_structure_source;
- else:
- bus_structure = self._bus_structure_sink;
-
- bus_structure = self.resolve_dependencies(bus_structure);
-
- if not bus_structure: return ''
- try:
- clean_bus_structure = self.get_parent().evaluate(bus_structure)
- return clean_bus_structure
-
- except: return ''
-
- def validate(self):
- """
- Validate this block.
- Call the base class validate.
- Evaluate the checks: each check must evaluate to True.
- """
- _Block.validate(self)
- #evaluate the checks
- for check in self._checks:
- check_res = self.resolve_dependencies(check)
- try:
- if not self.get_parent().evaluate(check_res):
- self.add_error_message('Check "%s" failed.'%check)
- except: self.add_error_message('Check "%s" did not evaluate.'%check)
- # for variables check the value (only if var_value is used
- if _variable_matcher.match(self.get_key()) and self._var_value != '$value':
- value = self._var_value
- try:
- value = self.get_var_value()
- self.get_parent().evaluate(value)
- except Exception as err:
- self.add_error_message('Value "%s" cannot be evaluated:\n%s' % (value, err))
-
- # check if this is a GUI block and matches the selected generate option
- current_generate_option = self.get_parent().get_option('generate_options')
-
- def check_generate_mode(label, flag, valid_options):
- block_requires_mode = (
- flag in self.get_flags() or
- self.get_name().upper().startswith(label)
- )
- if block_requires_mode and current_generate_option not in valid_options:
- self.add_error_message("Can't generate this block in mode " +
- repr(current_generate_option))
-
- check_generate_mode('WX GUI', BLOCK_FLAG_NEED_WX_GUI, ('wx_gui',))
- check_generate_mode('QT GUI', BLOCK_FLAG_NEED_QT_GUI, ('qt_gui', 'hb_qt_gui'))
- if self._epy_reload_error:
- self.get_param('_source_code').add_error_message(str(self._epy_reload_error))
-
- def rewrite(self):
- """
- Add and remove ports to adjust for the nports.
- """
- _Block.rewrite(self)
- # Check and run any custom rewrite function for this block
- getattr(self, 'rewrite_' + self._key, lambda: None)()
-
- # adjust nports, disconnect hidden ports
- for ports in (self.get_sources(), self.get_sinks()):
- for i, master_port in enumerate(ports):
- nports = master_port.get_nports() or 1
- num_ports = 1 + len(master_port.get_clones())
- if master_port.get_hide():
- for connection in master_port.get_connections():
- self.get_parent().remove_element(connection)
- if not nports and num_ports == 1: # not a master port and no left-over clones
- continue
- # remove excess cloned ports
- for port in master_port.get_clones()[nports-1:]:
- # remove excess connections
- for connection in port.get_connections():
- self.get_parent().remove_element(connection)
- master_port.remove_clone(port)
- ports.remove(port)
- # add more cloned ports
- for j in range(num_ports, nports):
- port = master_port.add_clone()
- ports.insert(ports.index(master_port) + j, port)
-
- self.back_ofthe_bus(ports)
- # renumber non-message/-msg ports
- domain_specific_port_index = collections.defaultdict(int)
- for port in filter(lambda p: p.get_key().isdigit(), ports):
- domain = port.get_domain()
- port._key = str(domain_specific_port_index[domain])
- domain_specific_port_index[domain] += 1
-
- def port_controller_modify(self, direction):
- """
- Change the port controller.
-
- Args:
- direction: +1 or -1
-
- Returns:
- true for change
- """
- changed = False
- #concat the nports string from the private nports settings of all ports
- nports_str = ' '.join([port._nports for port in self.get_ports()])
- #modify all params whose keys appear in the nports string
- for param in self.get_params():
- if param.is_enum() or param.get_key() not in nports_str: continue
- #try to increment the port controller by direction
- try:
- value = param.get_evaluated()
- value = value + direction
- if 0 < value:
- param.set_value(value)
- changed = True
- except: pass
- return changed
-
- def get_doc(self):
- platform = self.get_parent().get_parent()
- documentation = platform.block_docstrings.get(self._key, {})
- from_xml = self._doc.strip()
- if from_xml:
- documentation[''] = from_xml
- return documentation
-
- def get_category(self):
- return _Block.get_category(self)
-
- def get_imports(self, raw=False):
- """
- Resolve all import statements.
- Split each import statement at newlines.
- Combine all import statments into a list.
- Filter empty imports.
-
- Returns:
- a list of import statements
- """
- if raw:
- return self._imports
- return filter(lambda i: i, sum(map(lambda i: self.resolve_dependencies(i).split('\n'), self._imports), []))
-
- def get_make(self, raw=False):
- if raw:
- return self._make
- return self.resolve_dependencies(self._make)
-
- def get_var_make(self):
- return self.resolve_dependencies(self._var_make)
-
- def get_var_value(self):
- return self.resolve_dependencies(self._var_value)
-
- def get_callbacks(self):
- """
- Get a list of function callbacks for this block.
-
- Returns:
- a list of strings
- """
- def make_callback(callback):
- callback = self.resolve_dependencies(callback)
- if 'self.' in callback: return callback
- return 'self.%s.%s'%(self.get_id(), callback)
- return map(make_callback, self._callbacks)
-
- def is_virtual_sink(self):
- return self.get_key() == 'virtual_sink'
-
- def is_virtual_source(self):
- return self.get_key() == 'virtual_source'
-
- ###########################################################################
- # Custom rewrite functions
- ###########################################################################
-
- def rewrite_epy_block(self):
- flowgraph = self.get_parent()
- platform = flowgraph.get_parent()
- param_blk = self.get_param('_io_cache')
- param_src = self.get_param('_source_code')
-
- src = param_src.get_value()
- src_hash = hash(src)
- if src_hash == self._epy_source_hash:
- return
-
- try:
- blk_io = epy_block_io.extract(src)
-
- except Exception as e:
- self._epy_reload_error = ValueError(str(e))
- try: # load last working block io
- blk_io = epy_block_io.BlockIO(*eval(param_blk.get_value()))
- except:
- return
- else:
- self._epy_reload_error = None # clear previous errors
- param_blk.set_value(repr(tuple(blk_io)))
-
- # print "Rewriting embedded python block {!r}".format(self.get_id())
-
- self._epy_source_hash = src_hash
- self._name = blk_io.name or blk_io.cls
- self._doc = blk_io.doc
- self._imports[0] = 'from {} import {}'.format(self.get_id(), blk_io.cls)
- self._make = '{}({})'.format(blk_io.cls, ', '.join(
- '{0}=${0}'.format(key) for key, _ in blk_io.params))
-
- params = {}
- for param in list(self._params):
- if hasattr(param, '__epy_param__'):
- params[param.get_key()] = param
- self._params.remove(param)
-
- for key, value in blk_io.params:
- if key in params:
- param = params[key]
- if not param.value_is_default():
- param.set_value(value)
- else:
- name = key.replace('_', ' ').title()
- n = odict(dict(name=name, key=key, type='raw', value=value))
- param = platform.Param(block=self, n=n)
- setattr(param, '__epy_param__', True)
- self._params.append(param)
-
- def update_ports(label, ports, port_specs, direction):
- ports_to_remove = list(ports)
- iter_ports = iter(ports)
- ports_new = []
- port_current = next(iter_ports, None)
- for key, port_type in port_specs:
- reuse_port = (
- port_current is not None and
- port_current.get_type() == port_type and
- (key.isdigit() or port_current.get_key() == key)
- )
- if reuse_port:
- ports_to_remove.remove(port_current)
- port, port_current = port_current, next(iter_ports, None)
- else:
- n = odict(dict(name=label + str(key), type=port_type, key=key))
- if port_type == 'message':
- n['name'] = key
- n['optional'] = '1'
- port = platform.Port(block=self, n=n, dir=direction)
- ports_new.append(port)
- # replace old port list with new one
- del ports[:]
- ports.extend(ports_new)
- # remove excess port connections
- for port in ports_to_remove:
- for connection in port.get_connections():
- flowgraph.remove_element(connection)
-
- update_ports('in', self.get_sinks(), blk_io.sinks, 'sink')
- update_ports('out', self.get_sources(), blk_io.sources, 'source')
- _Block.rewrite(self)
diff --git a/grc/python/CMakeLists.txt b/grc/python/CMakeLists.txt
deleted file mode 100644
index 3f9e273146..0000000000
--- a/grc/python/CMakeLists.txt
+++ /dev/null
@@ -1,44 +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
- expr_utils.py
- extract_docs.py
- epy_block_io.py
- Block.py
- Connection.py
- Constants.py
- FlowGraph.py
- Generator.py
- Param.py
- Platform.py
- Port.py
- __init__.py
- DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/python
- COMPONENT "grc"
-)
-
-install(FILES
- block.dtd
- default_flow_graph.grc
- flow_graph.tmpl
- DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/python
- COMPONENT "grc"
-)
diff --git a/grc/python/Connection.py b/grc/python/Connection.py
deleted file mode 100644
index e5b4c2563b..0000000000
--- a/grc/python/Connection.py
+++ /dev/null
@@ -1,45 +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 Constants
-
-from .base.Connection import Connection as _Connection
-
-
-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'
-
- def is_bus(self):
- return self.get_source().get_type() == self.get_sink().get_type() == 'bus'
-
- def validate(self):
- """
- Validate the connections.
- The ports must match in io size.
- """
- _Connection.validate(self)
- source_size = Constants.TYPE_TO_SIZEOF[self.get_source().get_type()] * self.get_source().get_vlen()
- sink_size = Constants.TYPE_TO_SIZEOF[self.get_sink().get_type()] * self.get_sink().get_vlen()
- if source_size != sink_size:
- self.add_error_message('Source IO size "%s" does not match sink IO size "%s".'%(source_size, sink_size))
diff --git a/grc/python/Constants.py b/grc/python/Constants.py
deleted file mode 100644
index b7a370cad7..0000000000
--- a/grc/python/Constants.py
+++ /dev/null
@@ -1,140 +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
-from os.path import expanduser
-import numpy
-import stat
-from gnuradio import gr
-
-_gr_prefs = gr.prefs()
-
-# setup paths
-PATH_SEP = {'/': ':', '\\': ';'}[os.path.sep]
-
-HIER_BLOCKS_LIB_DIR = os.environ.get('GRC_HIER_PATH', expanduser('~/.grc_gnuradio'))
-
-PREFS_FILE = os.environ.get('GRC_PREFS_PATH', expanduser('~/.gnuradio/grc.conf'))
-PREFS_FILE_OLD = os.environ.get('GRC_PREFS_PATH', expanduser('~/.grc'))
-
-BLOCKS_DIRS = filter( # filter blank strings
- lambda x: x, PATH_SEP.join([
- os.environ.get('GRC_BLOCKS_PATH', ''),
- _gr_prefs.get_string('grc', 'local_blocks_path', ''),
- _gr_prefs.get_string('grc', 'global_blocks_path', ''),
- ]).split(PATH_SEP),
-) + [HIER_BLOCKS_LIB_DIR]
-
-# user settings
-XTERM_EXECUTABLE = _gr_prefs.get_string('grc', 'xterm_executable', 'xterm')
-
-# file creation modes
-TOP_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH
-HIER_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH
-
-# data files
-DATA_DIR = os.path.dirname(__file__)
-FLOW_GRAPH_TEMPLATE = os.path.join(DATA_DIR, 'flow_graph.tmpl')
-BLOCK_DTD = os.path.join(DATA_DIR, 'block.dtd')
-DEFAULT_FLOW_GRAPH = os.path.join(DATA_DIR, 'default_flow_graph.grc')
-
-#define types, native python + numpy
-VECTOR_TYPES = (tuple, list, set, numpy.ndarray)
-COMPLEX_TYPES = [complex, numpy.complex, numpy.complex64, numpy.complex128]
-REAL_TYPES = [float, numpy.float, numpy.float32, numpy.float64]
-INT_TYPES = [int, long, numpy.int, numpy.int8, numpy.int16, numpy.int32, numpy.uint64,
- numpy.uint, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64]
-#cast to tuple for isinstance, concat subtypes
-COMPLEX_TYPES = tuple(COMPLEX_TYPES + REAL_TYPES + INT_TYPES)
-REAL_TYPES = tuple(REAL_TYPES + INT_TYPES)
-INT_TYPES = tuple(INT_TYPES)
-
-# Updating colors. Using the standard color pallette from:
-# http://www.google.com/design/spec/style/color.html#color-color-palette
-# Most are based on the main, primary color standard. Some are within
-# that color's spectrum when it was deemed necessary.
-GRC_COLOR_BROWN = '#795548'
-GRC_COLOR_BLUE = '#2196F3'
-GRC_COLOR_LIGHT_GREEN = '#8BC34A'
-GRC_COLOR_GREEN = '#4CAF50'
-GRC_COLOR_AMBER = '#FFC107'
-GRC_COLOR_PURPLE = '#9C27B0'
-GRC_COLOR_CYAN = '#00BCD4'
-GRC_COLOR_GR_ORANGE = '#FF6905'
-GRC_COLOR_ORANGE = '#F57C00'
-GRC_COLOR_LIME = '#CDDC39'
-GRC_COLOR_TEAL = '#009688'
-GRC_COLOR_YELLOW = '#FFEB3B'
-GRC_COLOR_PINK = '#F50057'
-GRC_COLOR_LIGHT_PURPLE = '#E040FB'
-GRC_COLOR_DARK_GREY = '#72706F'
-GRC_COLOR_GREY = '#BDBDBD'
-GRC_COLOR_WHITE = '#FFFFFF'
-
-
-CORE_TYPES = ( # name, key, sizeof, color
- ('Complex Float 64', 'fc64', 16, GRC_COLOR_BROWN),
- ('Complex Float 32', 'fc32', 8, GRC_COLOR_BLUE),
- ('Complex Integer 64', 'sc64', 16, GRC_COLOR_LIGHT_GREEN),
- ('Complex Integer 32', 'sc32', 8, GRC_COLOR_GREEN),
- ('Complex Integer 16', 'sc16', 4, GRC_COLOR_AMBER),
- ('Complex Integer 8', 'sc8', 2, GRC_COLOR_PURPLE),
- ('Float 64', 'f64', 8, GRC_COLOR_CYAN),
- ('Float 32', 'f32', 4, GRC_COLOR_ORANGE),
- ('Integer 64', 's64', 8, GRC_COLOR_LIME),
- ('Integer 32', 's32', 4, GRC_COLOR_TEAL),
- ('Integer 16', 's16', 2, GRC_COLOR_YELLOW),
- ('Integer 8', 's8', 1, GRC_COLOR_LIGHT_PURPLE),
- ('Message Queue', 'msg', 0, GRC_COLOR_DARK_GREY),
- ('Async Message', 'message', 0, GRC_COLOR_GREY),
- ('Bus Connection', 'bus', 0, GRC_COLOR_WHITE),
- ('Wildcard', '', 0, GRC_COLOR_WHITE),
-)
-
-ALIAS_TYPES = {
- 'complex' : (8, GRC_COLOR_BLUE),
- 'float' : (4, GRC_COLOR_ORANGE),
- 'int' : (4, GRC_COLOR_TEAL),
- 'short' : (2, GRC_COLOR_YELLOW),
- 'byte' : (1, GRC_COLOR_LIGHT_PURPLE),
-}
-
-TYPE_TO_COLOR = dict()
-TYPE_TO_SIZEOF = dict()
-for name, key, sizeof, color in CORE_TYPES:
- TYPE_TO_COLOR[key] = color
- TYPE_TO_SIZEOF[key] = sizeof
-for key, (sizeof, color) in ALIAS_TYPES.iteritems():
- TYPE_TO_COLOR[key] = color
- TYPE_TO_SIZEOF[key] = sizeof
-
-#coloring
-COMPLEX_COLOR_SPEC = '#3399FF'
-FLOAT_COLOR_SPEC = '#FF8C69'
-INT_COLOR_SPEC = '#00FF99'
-SHORT_COLOR_SPEC = '#FFFF66'
-BYTE_COLOR_SPEC = '#FF66FF'
-COMPLEX_VECTOR_COLOR_SPEC = '#3399AA'
-FLOAT_VECTOR_COLOR_SPEC = '#CC8C69'
-INT_VECTOR_COLOR_SPEC = '#00CC99'
-SHORT_VECTOR_COLOR_SPEC = '#CCCC33'
-BYTE_VECTOR_COLOR_SPEC = '#CC66CC'
-ID_COLOR_SPEC = '#DDDDDD'
-WILDCARD_COLOR_SPEC = '#FFFFFF'
-MSG_COLOR_SPEC = '#777777'
diff --git a/grc/python/FlowGraph.py b/grc/python/FlowGraph.py
deleted file mode 100644
index 002740ac9d..0000000000
--- a/grc/python/FlowGraph.py
+++ /dev/null
@@ -1,336 +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 re
-import imp
-from operator import methodcaller
-
-from . import expr_utils
-from .base.FlowGraph import FlowGraph as _FlowGraph
-
-_variable_matcher = re.compile('^(variable\w*)$')
-_parameter_matcher = re.compile('^(parameter)$')
-_monitors_searcher = re.compile('(ctrlport_monitor)')
-_bussink_searcher = re.compile('^(bus_sink)$')
-_bussrc_searcher = re.compile('^(bus_source)$')
-_bus_struct_sink_searcher = re.compile('^(bus_structure_sink)$')
-_bus_struct_src_searcher = re.compile('^(bus_structure_source)$')
-
-
-class FlowGraph(_FlowGraph):
-
- def __init__(self, **kwargs):
- self.grc_file_path = ''
- _FlowGraph.__init__(self, **kwargs)
- self.n = {}
- self.n_hash = -1
- self._renew_eval_ns = True
- self._eval_cache = {}
-
- def _eval(self, code, namespace, namespace_hash):
- """
- Evaluate the code with the given namespace.
-
- Args:
- code: a string with python code
- namespace: a dict representing the namespace
- namespace_hash: a unique hash for the namespace
-
- Returns:
- the resultant object
- """
- if not code: raise Exception, 'Cannot evaluate empty statement.'
- my_hash = hash(code) ^ namespace_hash
- #cache if does not exist
- if not self._eval_cache.has_key(my_hash):
- self._eval_cache[my_hash] = eval(code, namespace, namespace)
- #return from cache
- return self._eval_cache[my_hash]
-
- def get_hier_block_stream_io(self, direction):
- """
- Get a list of stream io signatures for this flow graph.
-
- Args:
- direction: a string of 'in' or 'out'
-
- Returns:
- a list of dicts with: type, label, vlen, size, optional
- """
- return filter(lambda p: p['type'] != "message",
- self.get_hier_block_io(direction))
-
- def get_hier_block_message_io(self, direction):
- """
- Get a list of message io signatures for this flow graph.
-
- Args:
- direction: a string of 'in' or 'out'
-
- Returns:
- a list of dicts with: type, label, vlen, size, optional
- """
- return filter(lambda p: p['type'] == "message",
- self.get_hier_block_io(direction))
-
- def get_hier_block_io(self, direction):
- """
- Get a list of io ports for this flow graph.
-
- Args:
- direction: a string of 'in' or 'out'
-
- Returns:
- a list of dicts with: type, label, vlen, size, optional
- """
- pads = self.get_pad_sources() if direction in ('sink', 'in') else \
- self.get_pad_sinks() if direction in ('source', 'out') else []
- ports = []
- for pad in pads:
- master = {
- 'label': str(pad.get_param('label').get_evaluated()),
- 'type': str(pad.get_param('type').get_evaluated()),
- 'vlen': str(pad.get_param('vlen').get_value()),
- 'size': pad.get_param('type').get_opt('size'),
- 'optional': bool(pad.get_param('optional').get_evaluated()),
- }
- num_ports = pad.get_param('num_streams').get_evaluated()
- if num_ports > 1:
- for i in xrange(num_ports):
- clone = master.copy()
- clone['label'] += str(i)
- ports.append(clone)
- else:
- ports.append(master)
- return ports
-
- def get_pad_sources(self):
- """
- Get a list of pad source blocks sorted by id order.
-
- Returns:
- a list of pad source blocks in this flow graph
- """
- pads = filter(lambda b: b.get_key() == 'pad_source', self.get_enabled_blocks())
- return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id()))
-
- def get_pad_sinks(self):
- """
- Get a list of pad sink blocks sorted by id order.
-
- Returns:
- a list of pad sink blocks in this flow graph
- """
- pads = filter(lambda b: b.get_key() == 'pad_sink', self.get_enabled_blocks())
- return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id()))
-
- def get_pad_port_global_key(self, port):
- """
- Get the key for a port of a pad source/sink to use in connect()
- This takes into account that pad blocks may have multiple ports
-
- Returns:
- the key (str)
- """
- key_offset = 0
- pads = self.get_pad_sources() if port.is_source() else self.get_pad_sinks()
- for pad in pads:
- # using the block param 'type' instead of the port domain here
- # to emphasize that hier block generation is domain agnostic
- is_message_pad = pad.get_param('type').get_evaluated() == "message"
- if port.get_parent() == pad:
- if is_message_pad:
- key = pad.get_param('label').get_value()
- else:
- key = str(key_offset + int(port.get_key()))
- return key
- else:
- # assuming we have either only sources or sinks
- if not is_message_pad:
- key_offset += len(pad.get_ports())
- return -1
-
- def get_imports(self):
- """
- Get a set of all import statments in this flow graph namespace.
-
- Returns:
- a set of import statements
- """
- imports = sum([block.get_imports() for block in self.get_enabled_blocks()], [])
- imports = sorted(set(imports))
- return imports
-
- def get_variables(self):
- """
- Get a list of all variables in this flow graph namespace.
- Exclude paramterized variables.
-
- Returns:
- a sorted list of variable blocks in order of dependency (indep -> dep)
- """
- variables = filter(lambda b: _variable_matcher.match(b.get_key()), self.iter_enabled_blocks())
- return expr_utils.sort_objects(variables, methodcaller('get_id'), methodcaller('get_var_make'))
-
- def get_parameters(self):
- """
- Get a list of all paramterized variables in this flow graph namespace.
-
- Returns:
- a list of paramterized variables
- """
- parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), self.iter_enabled_blocks())
- return parameters
-
- def get_monitors(self):
- """
- Get a list of all ControlPort monitors
- """
- monitors = filter(lambda b: _monitors_searcher.search(b.get_key()),
- self.iter_enabled_blocks())
- return monitors
-
- def get_python_modules(self):
- """Iterate over custom code block ID and Source"""
- for block in self.iter_enabled_blocks():
- if block.get_key() == 'epy_module':
- yield block.get_id(), block.get_param('source_code').get_value()
-
- def get_bussink(self):
- bussink = filter(lambda b: _bussink_searcher.search(b.get_key()), self.get_enabled_blocks())
-
- for i in bussink:
- for j in i.get_params():
- if j.get_name() == 'On/Off' and j.get_value() == 'on':
- return True;
-
- return False
-
- def get_bussrc(self):
- bussrc = filter(lambda b: _bussrc_searcher.search(b.get_key()), self.get_enabled_blocks())
-
- for i in bussrc:
- for j in i.get_params():
- if j.get_name() == 'On/Off' and j.get_value() == 'on':
- return True;
-
- return False
-
- def get_bus_structure_sink(self):
- bussink = filter(lambda b: _bus_struct_sink_searcher.search(b.get_key()), self.get_enabled_blocks())
-
- return bussink
-
- def get_bus_structure_src(self):
- bussrc = filter(lambda b: _bus_struct_src_searcher.search(b.get_key()), self.get_enabled_blocks())
-
- return bussrc
-
- def rewrite(self):
- """
- Flag the namespace to be renewed.
- """
- def reconnect_bus_blocks():
- for block in self.get_blocks():
-
- if 'bus' in map(lambda a: a.get_type(), block.get_sources_gui()):
-
-
- for i in range(len(block.get_sources_gui())):
- if len(block.get_sources_gui()[i].get_connections()) > 0:
- source = block.get_sources_gui()[i]
- sink = []
-
- for j in range(len(source.get_connections())):
- sink.append(source.get_connections()[j].get_sink());
-
-
- for elt in source.get_connections():
- self.remove_element(elt);
- for j in sink:
- self.connect(source, j);
- self._renew_eval_ns = True
- _FlowGraph.rewrite(self);
- reconnect_bus_blocks();
-
- def evaluate(self, expr):
- """
- Evaluate the expression.
-
- Args:
- expr: the string expression
- @throw Exception bad expression
-
- Returns:
- the evaluated data
- """
- if self._renew_eval_ns:
- self._renew_eval_ns = False
- #reload namespace
- n = dict()
- #load imports
- for code in self.get_imports():
- try: exec code in n
- except: pass
-
- for id, code in self.get_python_modules():
- try:
- module = imp.new_module(id)
- exec code in module.__dict__
- n[id] = module
- except:
- pass
-
- #load parameters
- np = dict()
- for parameter in self.get_parameters():
- try:
- e = eval(parameter.get_param('value').to_code(), n, n)
- np[parameter.get_id()] = e
- except: pass
- n.update(np) #merge param namespace
- #load variables
- for variable in self.get_variables():
- try:
- e = eval(variable.get_var_value(), n, n)
- n[variable.get_id()] = e
- except: pass
- #make namespace public
- self.n = n
- self.n_hash = hash(str(n))
- #evaluate
- e = self._eval(expr, self.n, self.n_hash)
- return e
-
- def get_new_block(self, key):
- """Try to auto-generate the block from file if missing"""
- block = _FlowGraph.get_new_block(self, key)
- if not block:
- platform = self.get_parent()
- # we're before the initial fg rewrite(), so no evaluated values!
- # --> use raw value instead
- path_param = self._options_block.get_param('hier_block_src_path')
- file_path = platform.find_file_in_paths(
- filename=key + '.' + platform.get_key(),
- paths=path_param.get_value(),
- cwd=self.grc_file_path
- )
- if file_path: # grc file found. load and get block
- platform.load_and_generate_flow_graph(file_path)
- block = _FlowGraph.get_new_block(self, key) # can be None
- return block
diff --git a/grc/python/Generator.py b/grc/python/Generator.py
deleted file mode 100644
index 5d6de35077..0000000000
--- a/grc/python/Generator.py
+++ /dev/null
@@ -1,446 +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
-import subprocess
-import tempfile
-import shlex
-import codecs
-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 .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 .. gui import Messages
-
-
-class Generator(object):
- """Adaptor for various generators (uses generate_options)"""
-
- def __init__(self, flow_graph, file_path):
- """
- Initialize the generator object.
- Determine the file to generate.
-
- Args:
- flow_graph: the flow graph object
- file_path: the path to the grc file
- """
- self._generate_options = flow_graph.get_option('generate_options')
- if self._generate_options == 'hb':
- generator_cls = HierBlockGenerator
- elif self._generate_options == 'hb_qt_gui':
- generator_cls = QtHierBlockGenerator
- else:
- generator_cls = TopBlockGenerator
-
- self._generator = generator_cls(flow_graph, file_path)
-
- def get_generate_options(self):
- return self._generate_options
-
- def __getattr__(self, item):
- """get all other attrib from actual generator object"""
- return getattr(self._generator, item)
-
-
-class TopBlockGenerator(object):
-
- def __init__(self, flow_graph, file_path):
- """
- Initialize the top block generator object.
-
- Args:
- flow_graph: the flow graph object
- file_path: the path to write the file to
- """
- self._flow_graph = flow_graph
- self._generate_options = self._flow_graph.get_option('generate_options')
- self._mode = TOP_BLOCK_FILE_MODE
- dirname = self._dirname = os.path.dirname(file_path)
- # handle the case where the directory is read-only
- # in this case, use the system's temp directory
- if not os.access(dirname, os.W_OK):
- dirname = tempfile.gettempdir()
- filename = self._flow_graph.get_option('id') + '.py'
- self._file_path = os.path.join(dirname, filename)
-
- def get_file_path(self):
- return self._file_path
-
- def write(self):
- """generate output and write it to files"""
- # do throttle warning
- throttling_blocks = filter(lambda b: b.throtteling(), self._flow_graph.get_enabled_blocks())
- if not throttling_blocks and not self._generate_options.startswith('hb'):
- Messages.send_warning("This flow graph may not have flow control: "
- "no audio or RF hardware blocks found. "
- "Add a Misc->Throttle block to your flow "
- "graph to avoid CPU congestion.")
- if len(throttling_blocks) > 1:
- keys = set(map(lambda b: b.get_key(), throttling_blocks))
- if len(keys) > 1 and 'blocks_throttle' in keys:
- Messages.send_warning("This flow graph contains a throttle "
- "block and another rate limiting block, "
- "e.g. a hardware source or sink. "
- "This is usually undesired. Consider "
- "removing the throttle block.")
- # generate
- for filename, data in self._build_python_code_from_template():
- with codecs.open(filename, 'w', encoding='utf-8') as fp:
- fp.write(data)
- if filename == self.get_file_path():
- try:
- os.chmod(filename, self._mode)
- except:
- pass
-
- def get_popen(self):
- """
- Execute this python flow graph.
-
- Returns:
- a popen object
- """
- run_command = self._flow_graph.get_option('run_command')
- try:
- run_command = run_command.format(
- python=shlex_quote(sys.executable),
- filename=shlex_quote(self.get_file_path()))
- run_command_args = shlex.split(run_command)
- except Exception as e:
- raise ValueError("Can't parse run command {!r}: {}".format(run_command, e))
-
- # when in no gui mode on linux, use a graphical terminal (looks nice)
- xterm_executable = find_executable(XTERM_EXECUTABLE)
- if self._generate_options == 'no_gui' and xterm_executable:
- run_command_args = [xterm_executable, '-e', run_command]
-
- # this does not reproduce a shell executable command string, if a graphical
- # terminal is used. Passing run_command though shlex_quote would do it but
- # it looks really ugly and confusing in the console panel.
- Messages.send_start_exec(' '.join(run_command_args))
-
- return subprocess.Popen(
- args=run_command_args,
- stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
- shell=False, universal_newlines=True
- )
-
- def _build_python_code_from_template(self):
- """
- Convert the flow graph to python code.
-
- Returns:
- a string of python code
- """
- output = list()
-
- fg = self._flow_graph
- title = fg.get_option('title') or fg.get_option('id').replace('_', ' ').title()
- imports = fg.get_imports()
- variables = fg.get_variables()
- parameters = fg.get_parameters()
- monitors = fg.get_monitors()
-
- # list of blocks not including variables and imports and parameters and disabled
- def _get_block_sort_text(block):
- code = block.get_make().replace(block.get_id(), ' ')
- try:
- code += block.get_param('notebook').get_value() # older gui markup w/ wxgui
- except:
- pass
- try:
- code += block.get_param('gui_hint').get_value() # newer gui markup w/ qtgui
- except:
- pass
- return code
-
- blocks = expr_utils.sort_objects(
- filter(lambda b: b.get_enabled() and not b.get_bypassed(), fg.iter_blocks()),
- lambda b: b.get_id(), _get_block_sort_text
- )
- # List of regular blocks (all blocks minus the special ones)
- blocks = filter(lambda b: b not in (imports + parameters), blocks)
-
- for block in blocks:
- key = block.get_key()
- file_path = os.path.join(self._dirname, block.get_id() + '.py')
- if key == 'epy_block':
- src = block.get_param('_source_code').get_value()
- output.append((file_path, src))
- elif key == 'epy_module':
- src = block.get_param('source_code').get_value()
- output.append((file_path, src))
-
- # Filter out virtual sink connections
- cf = lambda c: not (c.is_bus() or c.is_msg() or c.get_sink().get_parent().is_virtual_sink())
- connections = filter(cf, fg.get_enabled_connections())
-
- # Get the virtual blocks and resolve their connections
- virtual = filter(lambda c: c.get_source().get_parent().is_virtual_source(), connections)
- for connection in virtual:
- source = connection.get_source().resolve_virtual_source()
- sink = connection.get_sink()
- resolved = fg.get_parent().Connection(flow_graph=fg, porta=source, portb=sink)
- connections.append(resolved)
- # Remove the virtual connection
- connections.remove(connection)
-
- # Bypassing blocks: Need to find all the enabled connections for the block using
- # the *connections* object rather than get_connections(). Create new connections
- # that bypass the selected block and remove the existing ones. This allows adjacent
- # bypassed blocks to see the newly created connections to downstream blocks,
- # allowing them to correctly construct bypass connections.
- bypassed_blocks = fg.get_bypassed_blocks()
- for block in bypassed_blocks:
- # Get the upstream connection (off of the sink ports)
- # Use *connections* not get_connections()
- get_source_connection = lambda c: c.get_sink() == block.get_sinks()[0]
- source_connection = filter(get_source_connection, connections)
- # The source connection should never have more than one element.
- assert (len(source_connection) == 1)
-
- # Get the source of the connection.
- source_port = source_connection[0].get_source()
-
- # Loop through all the downstream connections
- get_sink_connections = lambda c: c.get_source() == block.get_sources()[0]
- for sink in filter(get_sink_connections, connections):
- if not sink.get_enabled():
- # Ignore disabled connections
- continue
- sink_port = sink.get_sink()
- connection = fg.get_parent().Connection(flow_graph=fg, porta=source_port, portb=sink_port)
- connections.append(connection)
- # Remove this sink connection
- connections.remove(sink)
- # Remove the source connection
- connections.remove(source_connection[0])
-
- # List of connections where each endpoint is enabled (sorted by domains, block names)
- connections.sort(key=lambda c: (
- c.get_source().get_domain(), c.get_sink().get_domain(),
- c.get_source().get_parent().get_id(), c.get_sink().get_parent().get_id()
- ))
-
- connection_templates = fg.get_parent().get_connection_templates()
- msgs = filter(lambda c: c.is_msg(), fg.get_enabled_connections())
- # list of variable names
- var_ids = [var.get_id() for var in parameters + variables]
- # prepend self.
- replace_dict = dict([(var_id, 'self.%s' % var_id) for var_id in var_ids])
- # list of callbacks
- callbacks = [
- expr_utils.expr_replace(cb, replace_dict)
- for cb in sum([block.get_callbacks() for block in fg.get_enabled_blocks()], [])
- ]
- # map var id to callbacks
- var_id2cbs = dict([
- (var_id, filter(lambda c: expr_utils.get_variable_dependencies(c, [var_id]), callbacks))
- for var_id in var_ids
- ])
- # load the namespace
- namespace = {
- 'title': title,
- 'imports': imports,
- 'flow_graph': fg,
- 'variables': variables,
- 'parameters': parameters,
- 'monitors': monitors,
- 'blocks': blocks,
- 'connections': connections,
- 'connection_templates': connection_templates,
- 'msgs': msgs,
- 'generate_options': self._generate_options,
- 'var_id2cbs': var_id2cbs,
- }
- # build the template
- t = Template(open(FLOW_GRAPH_TEMPLATE, 'r').read(), namespace)
- output.append((self.get_file_path(), str(t)))
- return output
-
-
-class HierBlockGenerator(TopBlockGenerator):
- """Extends the top block generator to also generate a block XML file"""
-
- def __init__(self, flow_graph, file_path):
- """
- Initialize the hier block generator object.
-
- Args:
- flow_graph: the flow graph object
- file_path: where to write the py file (the xml goes into HIER_BLOCK_LIB_DIR)
- """
- TopBlockGenerator.__init__(self, flow_graph, file_path)
- self._mode = HIER_BLOCK_FILE_MODE
- self._file_path = os.path.join(HIER_BLOCKS_LIB_DIR,
- self._flow_graph.get_option('id') + '.py')
- self._file_path_xml = self._file_path + '.xml'
-
- def get_file_path_xml(self):
- return self._file_path_xml
-
- def write(self):
- """generate output and write it to files"""
- TopBlockGenerator.write(self)
- ParseXML.to_file(self._build_block_n_from_flow_graph_io(), self.get_file_path_xml())
- ParseXML.validate_dtd(self.get_file_path_xml(), BLOCK_DTD)
- try:
- os.chmod(self.get_file_path_xml(), self._mode)
- except:
- pass
-
- def _build_block_n_from_flow_graph_io(self):
- """
- Generate a block XML nested data from the flow graph IO
-
- Returns:
- a xml node tree
- """
- # extract info from the flow graph
- block_key = self._flow_graph.get_option('id')
- parameters = self._flow_graph.get_parameters()
-
- def var_or_value(name):
- if name in map(lambda p: p.get_id(), parameters):
- return "$"+name
- return name
-
- # build the nested data
- block_n = odict()
- block_n['name'] = self._flow_graph.get_option('title') or \
- self._flow_graph.get_option('id').replace('_', ' ').title()
- block_n['key'] = block_key
- block_n['category'] = self._flow_graph.get_option('category')
- block_n['import'] = "from {0} import {0} # grc-generated hier_block".format(
- self._flow_graph.get_option('id'))
- # make data
- if parameters:
- block_n['make'] = '{cls}(\n {kwargs},\n)'.format(
- cls=block_key,
- kwargs=',\n '.join(
- '{key}=${key}'.format(key=param.get_id()) for param in parameters
- ),
- )
- else:
- block_n['make'] = '{cls}()'.format(cls=block_key)
- # callback data
- block_n['callback'] = [
- 'set_{key}(${key})'.format(key=param.get_id()) for param in parameters
- ]
-
- # Parameters
- block_n['param'] = list()
- for param in parameters:
- param_n = odict()
- param_n['name'] = param.get_param('label').get_value() or param.get_id()
- param_n['key'] = param.get_id()
- param_n['value'] = param.get_param('value').get_value()
- param_n['type'] = 'raw'
- block_n['param'].append(param_n)
-
- # bus stuff
- if self._flow_graph.get_bussink():
- block_n['bus_sink'] = '1'
- if self._flow_graph.get_bussrc():
- block_n['bus_source'] = '1'
-
- # sink/source ports
- for direction in ('sink', 'source'):
- block_n[direction] = list()
- for port in self._flow_graph.get_hier_block_io(direction):
- port_n = odict()
- port_n['name'] = port['label']
- port_n['type'] = port['type']
- if port['type'] != "message":
- port_n['vlen'] = var_or_value(port['vlen'])
- if port['optional']:
- port_n['optional'] = '1'
- block_n[direction].append(port_n)
-
- # more bus stuff
- bus_struct_sink = self._flow_graph.get_bus_structure_sink()
- if bus_struct_sink:
- block_n['bus_structure_sink'] = bus_struct_sink[0].get_param('struct').get_value()
- bus_struct_src = self._flow_graph.get_bus_structure_src()
- if bus_struct_src:
- block_n['bus_structure_source'] = bus_struct_src[0].get_param('struct').get_value()
-
- # documentation
- block_n['doc'] = "\n".join(field for field in (
- self._flow_graph.get_option('author'),
- self._flow_graph.get_option('description'),
- self.get_file_path()
- ) if field)
- block_n['grc_source'] = str(self._flow_graph.grc_file_path)
-
- n = {'block': block_n}
- return n
-
-
-class QtHierBlockGenerator(HierBlockGenerator):
-
- def _build_block_n_from_flow_graph_io(self):
- n = HierBlockGenerator._build_block_n_from_flow_graph_io(self)
- block_n = n['block']
-
- if not block_n['name'].upper().startswith('QT GUI'):
- block_n['name'] = 'QT GUI ' + block_n['name']
-
- block_n.insert_after('category', 'flags', BLOCK_FLAG_NEED_QT_GUI)
-
- gui_hint_param = odict()
- gui_hint_param['name'] = 'GUI Hint'
- gui_hint_param['key'] = 'gui_hint'
- gui_hint_param['value'] = ''
- gui_hint_param['type'] = 'gui_hint'
- gui_hint_param['hide'] = 'part'
- block_n['param'].append(gui_hint_param)
-
- block_n['make'] += (
- "\n#set $win = 'self.%s' % $id"
- "\n${gui_hint()($win)}"
- )
- return n
-
-
-###########################################################
-# back-port from python3
-###########################################################
-_find_unsafe = re.compile(r'[^\w@%+=:,./-]').search
-
-
-def shlex_quote(s):
- """Return a shell-escaped version of the string *s*."""
- if not s:
- return "''"
- if _find_unsafe(s) is None:
- return s
-
- # use single quotes, and put single quotes into double quotes
- # the string $'b is then quoted as '$'"'"'b'
- return "'" + s.replace("'", "'\"'\"'") + "'"
diff --git a/grc/python/Param.py b/grc/python/Param.py
deleted file mode 100644
index b627e5eec8..0000000000
--- a/grc/python/Param.py
+++ /dev/null
@@ -1,429 +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 ast
-
-import re
-from gnuradio import eng_notation
-from gnuradio import gr
-
-import Constants
-from Constants import VECTOR_TYPES, COMPLEX_TYPES, REAL_TYPES, INT_TYPES
-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)$')
-
-
-#blacklist certain ids, its not complete, but should help
-import __builtin__
-ID_BLACKLIST = ['self', 'options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 'forms', 'firdes'] + \
- filter(lambda x: not x.startswith('_'), dir(gr.top_block())) + dir(__builtin__)
-
-
-def num_to_str(num):
- """ Display logic for numbers """
- if isinstance(num, COMPLEX_TYPES):
- num = complex(num) #cast to python complex
- if num == 0: return '0' #value is zero
- elif num.imag == 0: return '%s'%eng_notation.num_to_str(num.real) #value is real
- elif num.real == 0: return '%sj'%eng_notation.num_to_str(num.imag) #value is imaginary
- elif num.imag < 0: return '%s-%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(abs(num.imag)))
- else: return '%s+%sj'%(eng_notation.num_to_str(num.real), eng_notation.num_to_str(num.imag))
- else: return str(num)
-
-
-class Param(_Param):
-
- def __init__(self, **kwargs):
- _Param.__init__(self, **kwargs)
- self._init = False
- self._hostage_cells = list()
-
- def get_types(self): return (
- 'raw', 'enum',
- 'complex', 'real', 'float', 'int',
- 'complex_vector', 'real_vector', 'float_vector', 'int_vector',
- 'hex', 'string', 'bool',
- 'file_open', 'file_save', '_multiline', '_multiline_python_external',
- 'id', 'stream_id',
- 'grid_pos', 'notebook', 'gui_hint',
- 'import',
- )
-
- def __repr__(self):
- """
- Get the repr (nice string format) for this param.
-
- Returns:
- the string representation
- """
- ##################################################
- # truncate helper method
- ##################################################
- def _truncate(string, style=0):
- max_len = max(27 - len(self.get_name()), 3)
- if len(string) > max_len:
- if style < 0: #front truncate
- string = '...' + string[3-max_len:]
- elif style == 0: #center truncate
- string = string[:max_len/2 -3] + '...' + string[-max_len/2:]
- elif style > 0: #rear truncate
- string = string[:max_len-3] + '...'
- return string
- ##################################################
- # simple conditions
- ##################################################
- if not self.is_valid(): return _truncate(self.get_value())
- if self.get_value() in self.get_option_keys(): return self.get_option(self.get_value()).get_name()
-
- ##################################################
- # split up formatting by type
- ##################################################
- truncate = 0 #default center truncate
- e = self.get_evaluated()
- t = self.get_type()
- if isinstance(e, bool): return str(e)
- elif isinstance(e, COMPLEX_TYPES): dt_str = num_to_str(e)
- elif isinstance(e, VECTOR_TYPES): #vector types
- if len(e) > 8:
- dt_str = self.get_value() #large vectors use code
- truncate = 1
- else: dt_str = ', '.join(map(num_to_str, e)) #small vectors use eval
- elif t in ('file_open', 'file_save'):
- dt_str = self.get_value()
- truncate = -1
- else: dt_str = str(e) #other types
- ##################################################
- # done
- ##################################################
- return _truncate(dt_str, truncate)
-
- def get_color(self):
- """
- Get the color that represents this param's type.
-
- Returns:
- a hex color code.
- """
- try:
- return {
- #number types
- 'complex': Constants.COMPLEX_COLOR_SPEC,
- 'real': Constants.FLOAT_COLOR_SPEC,
- 'float': Constants.FLOAT_COLOR_SPEC,
- 'int': Constants.INT_COLOR_SPEC,
- #vector types
- 'complex_vector': Constants.COMPLEX_VECTOR_COLOR_SPEC,
- 'real_vector': Constants.FLOAT_VECTOR_COLOR_SPEC,
- 'float_vector': Constants.FLOAT_VECTOR_COLOR_SPEC,
- 'int_vector': Constants.INT_VECTOR_COLOR_SPEC,
- #special
- 'bool': Constants.INT_COLOR_SPEC,
- 'hex': Constants.INT_COLOR_SPEC,
- 'string': Constants.BYTE_VECTOR_COLOR_SPEC,
- 'id': Constants.ID_COLOR_SPEC,
- 'stream_id': Constants.ID_COLOR_SPEC,
- 'grid_pos': Constants.INT_VECTOR_COLOR_SPEC,
- 'notebook': Constants.INT_VECTOR_COLOR_SPEC,
- 'raw': Constants.WILDCARD_COLOR_SPEC,
- }[self.get_type()]
- except: return _Param.get_color(self)
-
- def get_hide(self):
- """
- Get the hide value from the base class.
- Hide the ID parameter for most blocks. Exceptions below.
- If the parameter controls a port type, vlen, or nports, return part.
- If the parameter is an empty grid position, return part.
- These parameters are redundant to display in the flow graph view.
-
- Returns:
- hide the hide property string
- """
- hide = _Param.get_hide(self)
- if hide: return hide
- #hide ID in non variable blocks
- if self.get_key() == 'id' and not _show_id_matcher.match(self.get_parent().get_key()): return 'part'
- #hide port controllers for type and nports
- if self.get_key() in ' '.join(map(
- lambda p: ' '.join([p._type, p._nports]), self.get_parent().get_ports())
- ): return 'part'
- #hide port controllers for vlen, when == 1
- if self.get_key() in ' '.join(map(
- lambda p: p._vlen, self.get_parent().get_ports())
- ):
- try:
- if int(self.get_evaluated()) == 1: return 'part'
- except: pass
- #hide empty grid positions
- if self.get_key() in ('grid_pos', 'notebook') and not self.get_value(): return 'part'
- return hide
-
- def validate(self):
- """
- Validate the param.
- A test evaluation is performed
- """
- _Param.validate(self) #checks type
- self._evaluated = None
- try: self._evaluated = self.evaluate()
- except Exception, e: self.add_error_message(str(e))
-
- def get_evaluated(self): return self._evaluated
-
- def evaluate(self):
- """
- Evaluate the value.
-
- Returns:
- evaluated type
- """
- self._init = True
- self._lisitify_flag = False
- self._stringify_flag = False
- self._hostage_cells = list()
- t = self.get_type()
- v = self.get_value()
- #########################
- # Enum Type
- #########################
- if self.is_enum(): return v
- #########################
- # Numeric Types
- #########################
- elif t in ('raw', 'complex', 'real', 'float', 'int', 'hex', 'bool'):
- #raise exception if python cannot evaluate this value
- try: e = self.get_parent().get_parent().evaluate(v)
- except Exception, e: raise Exception, 'Value "%s" cannot be evaluated:\n%s'%(v, e)
- #raise an exception if the data is invalid
- if t == 'raw': return e
- elif t == 'complex':
- if not isinstance(e, COMPLEX_TYPES):
- raise Exception, 'Expression "%s" is invalid for type complex.'%str(e)
- return e
- elif t == 'real' or t == 'float':
- if not isinstance(e, REAL_TYPES):
- raise Exception, 'Expression "%s" is invalid for type float.'%str(e)
- return e
- elif t == 'int':
- if not isinstance(e, INT_TYPES):
- raise Exception, 'Expression "%s" is invalid for type integer.'%str(e)
- return e
- elif t == 'hex': return hex(e)
- elif t == 'bool':
- if not isinstance(e, bool):
- raise Exception, 'Expression "%s" is invalid for type bool.'%str(e)
- return e
- else: raise TypeError, 'Type "%s" not handled'%t
- #########################
- # Numeric Vector Types
- #########################
- elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'):
- if not v: v = '()' #turn a blank string into an empty list, so it will eval
- #raise exception if python cannot evaluate this value
- try: e = self.get_parent().get_parent().evaluate(v)
- except Exception, e: raise Exception, 'Value "%s" cannot be evaluated:\n%s'%(v, e)
- #raise an exception if the data is invalid
- if t == 'complex_vector':
- if not isinstance(e, VECTOR_TYPES):
- self._lisitify_flag = True
- e = [e]
- if not all([isinstance(ei, COMPLEX_TYPES) for ei in e]):
- raise Exception, 'Expression "%s" is invalid for type complex vector.'%str(e)
- return e
- elif t == 'real_vector' or t == 'float_vector':
- if not isinstance(e, VECTOR_TYPES):
- self._lisitify_flag = True
- e = [e]
- if not all([isinstance(ei, REAL_TYPES) for ei in e]):
- raise Exception, 'Expression "%s" is invalid for type float vector.'%str(e)
- return e
- elif t == 'int_vector':
- if not isinstance(e, VECTOR_TYPES):
- self._lisitify_flag = True
- e = [e]
- if not all([isinstance(ei, INT_TYPES) for ei in e]):
- raise Exception, 'Expression "%s" is invalid for type integer vector.'%str(e)
- return e
- #########################
- # String Types
- #########################
- elif t in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'):
- #do not check if file/directory exists, that is a runtime issue
- try:
- e = self.get_parent().get_parent().evaluate(v)
- if not isinstance(e, str):
- raise Exception()
- except:
- self._stringify_flag = True
- e = str(v)
- if t == '_multiline_python_external':
- ast.parse(e) # raises SyntaxError
- return e
- #########################
- # Unique ID Type
- #########################
- elif t == 'id':
- #can python use this as a variable?
- if not _check_id_matcher.match(v):
- raise Exception, 'ID "%s" must begin with a letter and may contain letters, numbers, and underscores.'%v
- ids = [param.get_value() for param in self.get_all_params(t)]
- if ids.count(v) > 1: #id should only appear once, or zero times if block is disabled
- raise Exception, 'ID "%s" is not unique.'%v
- if v in ID_BLACKLIST:
- raise Exception, 'ID "%s" is blacklisted.'%v
- return v
- #########################
- # Stream ID Type
- #########################
- elif t == 'stream_id':
- #get a list of all stream ids used in the virtual sinks
- ids = [param.get_value() for param in filter(
- lambda p: p.get_parent().is_virtual_sink(),
- self.get_all_params(t),
- )]
- #check that the virtual sink's stream id is unique
- if self.get_parent().is_virtual_sink():
- if ids.count(v) > 1: #id should only appear once, or zero times if block is disabled
- raise Exception, 'Stream ID "%s" is not unique.'%v
- #check that the virtual source's steam id is found
- if self.get_parent().is_virtual_source():
- if v not in ids:
- raise Exception, 'Stream ID "%s" is not found.'%v
- return v
- #########################
- # GUI Position/Hint
- #########################
- elif t == 'gui_hint':
- if ':' in v: tab, pos = v.split(':')
- elif '@' in v: tab, pos = v, ''
- else: tab, pos = '', v
-
- if '@' in tab: tab, index = tab.split('@')
- else: index = '?'
-
- widget_str = ({
- (True, True): 'self.%(tab)s_grid_layout_%(index)s.addWidget(%(widget)s, %(pos)s)',
- (True, False): 'self.%(tab)s_layout_%(index)s.addWidget(%(widget)s)',
- (False, True): 'self.top_grid_layout.addWidget(%(widget)s, %(pos)s)',
- (False, False): 'self.top_layout.addWidget(%(widget)s)',
- }[bool(tab), bool(pos)])%{'tab': tab, 'index': index, 'widget': '%s', 'pos': pos}
-
- # FIXME: Move replace(...) into the make template of the qtgui blocks and return a string here
- class GuiHint(object):
- def __init__(self, ws):
- self._ws = ws
-
- def __call__(self, w):
- return (self._ws.replace('addWidget', 'addLayout') if 'layout' in w else self._ws) % w
-
- def __str__(self):
- return self._ws
- return GuiHint(widget_str)
- #########################
- # Grid Position Type
- #########################
- elif t == 'grid_pos':
- if not v: return '' #allow for empty grid pos
- e = self.get_parent().get_parent().evaluate(v)
- if not isinstance(e, (list, tuple)) or len(e) != 4 or not all([isinstance(ei, int) for ei in e]):
- raise Exception, 'A grid position must be a list of 4 integers.'
- row, col, row_span, col_span = e
- #check row, col
- if row < 0 or col < 0:
- raise Exception, 'Row and column must be non-negative.'
- #check row span, col span
- if row_span <= 0 or col_span <= 0:
- raise Exception, 'Row and column span must be greater than zero.'
- #get hostage cell parent
- try: my_parent = self.get_parent().get_param('notebook').evaluate()
- except: my_parent = ''
- #calculate hostage cells
- for r in range(row_span):
- for c in range(col_span):
- self._hostage_cells.append((my_parent, (row+r, col+c)))
- #avoid collisions
- params = filter(lambda p: p is not self, self.get_all_params('grid_pos'))
- for param in params:
- for parent, cell in param._hostage_cells:
- if (parent, cell) in self._hostage_cells:
- raise Exception, 'Another graphical element is using parent "%s", cell "%s".'%(str(parent), str(cell))
- return e
- #########################
- # Notebook Page Type
- #########################
- elif t == 'notebook':
- if not v: return '' #allow for empty notebook
- #get a list of all notebooks
- notebook_blocks = filter(lambda b: b.get_key() == 'notebook', self.get_parent().get_parent().get_enabled_blocks())
- #check for notebook param syntax
- try: notebook_id, page_index = map(str.strip, v.split(','))
- except: raise Exception, 'Bad notebook page format.'
- #check that the notebook id is valid
- try: notebook_block = filter(lambda b: b.get_id() == notebook_id, notebook_blocks)[0]
- except: raise Exception, 'Notebook id "%s" is not an existing notebook id.'%notebook_id
- #check that page index exists
- if int(page_index) not in range(len(notebook_block.get_param('labels').evaluate())):
- raise Exception, 'Page index "%s" is not a valid index number.'%page_index
- return notebook_id, page_index
- #########################
- # Import Type
- #########################
- elif t == 'import':
- n = dict() #new namespace
- try: exec v in n
- except ImportError: raise Exception, 'Import "%s" failed.'%v
- except Exception: raise Exception, 'Bad import syntax: "%s".'%v
- return filter(lambda k: str(k) != '__builtins__', n.keys())
- #########################
- else: raise TypeError, 'Type "%s" not handled'%t
-
- def to_code(self):
- """
- Convert the value to code.
- For string and list types, check the init flag, call evaluate().
- This ensures that evaluate() was called to set the xxxify_flags.
-
- Returns:
- a string representing the code
- """
- v = self.get_value()
- t = self.get_type()
- if t in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'): # string types
- if not self._init: self.evaluate()
- if self._stringify_flag: return '"%s"'%v.replace('"', '\"')
- else: return v
- elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'): #vector types
- if not self._init: self.evaluate()
- if self._lisitify_flag: return '(%s, )'%v
- else: return '(%s)'%v
- else: return v
-
- def get_all_params(self, type):
- """
- Get all the params from the flowgraph that have the given type.
-
- Args:
- type: the specified type
-
- Returns:
- a list of params
- """
- return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_enabled_blocks()], [])
diff --git a/grc/python/Platform.py b/grc/python/Platform.py
deleted file mode 100644
index e6b17fe3f7..0000000000
--- a/grc/python/Platform.py
+++ /dev/null
@@ -1,155 +0,0 @@
-"""
-Copyright 2008-2015 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-GNU Radio Companion is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-import os
-import sys
-from gnuradio import gr
-
-from .base.Platform import Platform as _Platform
-
-from . import extract_docs
-from .Constants import (
- HIER_BLOCKS_LIB_DIR, BLOCK_DTD, DEFAULT_FLOW_GRAPH, BLOCKS_DIRS,
- PREFS_FILE, CORE_TYPES, PREFS_FILE_OLD,
-)
-from .Generator import Generator
-from .. gui import Messages
-
-
-class Platform(_Platform):
- def __init__(self):
- """
- Make a platform for gnuradio.
- """
- # ensure hier and conf directories
- if not os.path.exists(HIER_BLOCKS_LIB_DIR):
- os.mkdir(HIER_BLOCKS_LIB_DIR)
- if not os.path.exists(os.path.dirname(PREFS_FILE)):
- os.mkdir(os.path.dirname(PREFS_FILE))
-
- self.block_docstrings = {}
- self.block_docstrings_loaded_callback = lambda: None # dummy to be replaced by BlockTreeWindow
-
- self._docstring_extractor = extract_docs.SubprocessLoader(
- callback_query_result=self._save_docstring_extraction_result,
- callback_finished=lambda: self.block_docstrings_loaded_callback()
- )
-
- # init
- _Platform.__init__(
- self,
- name='GNU Radio Companion',
- version=(gr.version(), gr.major_version(), gr.api_version(), gr.minor_version()),
- key='grc',
- license=__doc__.strip(),
- website='http://gnuradio.org/',
- block_paths=BLOCKS_DIRS,
- block_dtd=BLOCK_DTD,
- default_flow_graph=DEFAULT_FLOW_GRAPH,
- generator=Generator,
- colors=[(name, color) for name, key, sizeof, color in CORE_TYPES],
- )
-
- self._auto_hier_block_generate_chain = set()
-
- def _save_docstring_extraction_result(self, key, docstrings):
- docs = {}
- for match, docstring in docstrings.iteritems():
- if not docstring or match.endswith('_sptr'):
- continue
- docstring = docstring.replace('\n\n', '\n').strip()
- docs[match] = docstring
- self.block_docstrings[key] = docs
-
- @staticmethod
- def _move_old_pref_file():
- if PREFS_FILE == PREFS_FILE_OLD:
- return # prefs file overridden with env var
- if os.path.exists(PREFS_FILE_OLD) and not os.path.exists(PREFS_FILE):
- try:
- import shutil
- shutil.move(PREFS_FILE_OLD, PREFS_FILE)
- except Exception as e:
- print >> sys.stderr, e
-
- def load_blocks(self):
- self._docstring_extractor.start()
- _Platform.load_blocks(self)
- self._docstring_extractor.finish()
- # self._docstring_extractor.wait()
-
- def load_block_xml(self, xml_file):
- block = _Platform.load_block_xml(self, xml_file)
- self._docstring_extractor.query(
- block.get_key(),
- block.get_imports(raw=True),
- block.get_make(raw=True)
- )
- return block
-
- @staticmethod
- def find_file_in_paths(filename, paths, cwd):
- """Checks the provided paths relative to cwd for a certain filename"""
- if not os.path.isdir(cwd):
- cwd = os.path.dirname(cwd)
- if isinstance(paths, str):
- paths = (p for p in paths.split(':') if p)
-
- for path in paths:
- path = os.path.expanduser(path)
- if not os.path.isabs(path):
- path = os.path.normpath(os.path.join(cwd, path))
- file_path = os.path.join(path, filename)
- if os.path.exists(os.path.normpath(file_path)):
- return file_path
-
- def load_and_generate_flow_graph(self, file_path):
- """Loads a flowgraph from file and generates it"""
- Messages.set_indent(len(self._auto_hier_block_generate_chain))
- Messages.send('>>> Loading: %r\n' % file_path)
- if file_path in self._auto_hier_block_generate_chain:
- Messages.send(' >>> Warning: cyclic hier_block dependency\n')
- return False
- self._auto_hier_block_generate_chain.add(file_path)
- try:
- flow_graph = self.get_new_flow_graph()
- flow_graph.grc_file_path = file_path
- # other, nested higiter_blocks might be auto-loaded here
- flow_graph.import_data(self.parse_flow_graph(file_path))
- flow_graph.rewrite()
- flow_graph.validate()
- if not flow_graph.is_valid():
- raise Exception('Flowgraph invalid')
- except Exception as e:
- Messages.send('>>> Load Error: %r: %s\n' % (file_path, str(e)))
- return False
- finally:
- self._auto_hier_block_generate_chain.discard(file_path)
- Messages.set_indent(len(self._auto_hier_block_generate_chain))
-
- try:
- Messages.send('>>> Generating: %r\n' % file_path)
- generator = self.get_generator()(flow_graph, file_path)
- generator.write()
- except Exception as e:
- Messages.send('>>> Generate Error: %r: %s\n' % (file_path, str(e)))
- return False
-
- self.load_block_xml(generator.get_file_path_xml())
- return True
diff --git a/grc/python/Port.py b/grc/python/Port.py
deleted file mode 100644
index 8466f4f97c..0000000000
--- a/grc/python/Port.py
+++ /dev/null
@@ -1,271 +0,0 @@
-"""
-Copyright 2008-2012 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 .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):
- """
- Resolve the source port that is connected to the given virtual sink port.
- Use the get source from virtual source to recursively resolve subsequent ports.
- """
- try: return _get_source_from_virtual_source_port(
- vsp.get_enabled_connections()[0].get_source())
- except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp
-
-
-def _get_source_from_virtual_source_port(vsp, traversed=[]):
- """
- Recursively resolve source ports over the virtual connections.
- Keep track of traversed sources to avoid recursive loops.
- """
- if not vsp.get_parent().is_virtual_source(): return vsp
- if vsp in traversed: raise Exception, 'Loop found when resolving virtual source %s'%vsp
- try: return _get_source_from_virtual_source_port(
- _get_source_from_virtual_sink_port(
- filter(#get all virtual sinks with a matching stream id
- lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(),
- filter(#get all enabled blocks that are also virtual sinks
- lambda b: b.is_virtual_sink(),
- vsp.get_parent().get_parent().get_enabled_blocks(),
- ),
- )[0].get_sinks()[0]
- ), traversed + [vsp],
- )
- except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp
-
-
-def _get_sink_from_virtual_source_port(vsp):
- """
- Resolve the sink port that is connected to the given virtual source port.
- Use the get sink from virtual sink to recursively resolve subsequent ports.
- """
- try: return _get_sink_from_virtual_sink_port(
- vsp.get_enabled_connections()[0].get_sink()) # Could have many connections, but use first
- except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp
-
-
-def _get_sink_from_virtual_sink_port(vsp, traversed=[]):
- """
- Recursively resolve sink ports over the virtual connections.
- Keep track of traversed sinks to avoid recursive loops.
- """
- if not vsp.get_parent().is_virtual_sink(): return vsp
- if vsp in traversed: raise Exception, 'Loop found when resolving virtual sink %s'%vsp
- try: return _get_sink_from_virtual_sink_port(
- _get_sink_from_virtual_source_port(
- filter(#get all virtual source with a matching stream id
- lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(),
- filter(#get all enabled blocks that are also virtual sinks
- lambda b: b.is_virtual_source(),
- vsp.get_parent().get_parent().get_enabled_blocks(),
- ),
- )[0].get_sources()[0]
- ), traversed + [vsp],
- )
- except: raise Exception, 'Could not resolve source for virtual sink port %s'%vsp
-
-
-class Port(_Port):
-
- def __init__(self, block, n, dir):
- """
- Make a new port from nested data.
-
- Args:
- block: the parent element
- n: the nested odict
- dir: the direction
- """
- self._n = n
- if n['type'] == 'message':
- n['domain'] = GR_MESSAGE_DOMAIN
- if 'domain' not in n:
- n['domain'] = DEFAULT_DOMAIN
- elif n['domain'] == GR_MESSAGE_DOMAIN:
- n['key'] = n['name']
- n['type'] = 'message' # for port color
- if n['type'] == 'msg':
- n['key'] = 'msg'
- if not n.find('key'):
- n['key'] = str(next(block.port_counters[dir == 'source']))
- # build the port
- _Port.__init__(
- self,
- block=block,
- n=n,
- dir=dir,
- )
- self._nports = n.find('nports') or ''
- self._vlen = n.find('vlen') or ''
- self._optional = bool(n.find('optional'))
- self._clones = [] # references to cloned ports (for nports > 1)
-
- def get_types(self): return Constants.TYPE_TO_SIZEOF.keys()
-
- def is_type_empty(self): return not self._n['type']
-
- def validate(self):
- _Port.validate(self)
- if not self.get_enabled_connections() and not self.get_optional():
- self.add_error_message('Port is not connected.')
- #message port logic
- if self.get_type() == 'msg':
- if self.get_nports():
- self.add_error_message('A port of type "msg" cannot have "nports" set.')
- if self.get_vlen() != 1:
- self.add_error_message('A port of type "msg" must have a "vlen" of 1.')
-
- def rewrite(self):
- """
- Handle the port cloning for virtual blocks.
- """
- if self.is_type_empty():
- try: #clone type and vlen
- source = self.resolve_empty_type()
- self._type = str(source.get_type())
- self._vlen = str(source.get_vlen())
- except: #reset type and vlen
- self._type = ''
- self._vlen = ''
- _Port.rewrite(self)
-
- def resolve_virtual_source(self):
- if self.get_parent().is_virtual_sink(): return _get_source_from_virtual_sink_port(self)
- if self.get_parent().is_virtual_source(): return _get_source_from_virtual_source_port(self)
-
- def resolve_empty_type(self):
- if self.is_sink():
- try:
- src = _get_source_from_virtual_sink_port(self)
- if not src.is_type_empty(): return src
- except: pass
- sink = _get_sink_from_virtual_sink_port(self)
- if not sink.is_type_empty(): return sink
- if self.is_source():
- try:
- src = _get_source_from_virtual_source_port(self)
- if not src.is_type_empty(): return src
- except: pass
- sink = _get_sink_from_virtual_source_port(self)
- if not sink.is_type_empty(): return sink
-
- def get_vlen(self):
- """
- Get the vector length.
- If the evaluation of vlen cannot be cast to an integer, return 1.
-
- Returns:
- the vector length or 1
- """
- vlen = self.get_parent().resolve_dependencies(self._vlen)
- try: return int(self.get_parent().get_parent().evaluate(vlen))
- except: return 1
-
- def get_nports(self):
- """
- Get the number of ports.
- If already blank, return a blank
- If the evaluation of nports cannot be cast to a positive integer, return 1.
-
- Returns:
- the number of ports or 1
- """
- if self._nports == '': return ''
-
- nports = self.get_parent().resolve_dependencies(self._nports)
- try:
- return max(1, int(self.get_parent().get_parent().evaluate(nports)))
- except:
- return 1
-
- def get_optional(self): return bool(self._optional)
-
- def get_color(self):
- """
- Get the color that represents this port's type.
- Codes differ for ports where the vec length is 1 or greater than 1.
-
- Returns:
- a hex color code.
- """
- try:
- color = Constants.TYPE_TO_COLOR[self.get_type()]
- vlen = self.get_vlen()
- if vlen == 1: return color
- color_val = int(color[1:], 16)
- r = (color_val >> 16) & 0xff
- g = (color_val >> 8) & 0xff
- b = (color_val >> 0) & 0xff
- dark = (0, 0, 30, 50, 70)[min(4, vlen)]
- r = max(r-dark, 0)
- g = max(g-dark, 0)
- b = max(b-dark, 0)
- return '#%.2x%.2x%.2x'%(r, g, b)
- except: return _Port.get_color(self)
-
- def get_clones(self):
- """
- Get the clones of this master port (nports > 1)
-
- Returns:
- a list of ports
- """
- return self._clones
-
- def add_clone(self):
- """
- Create a clone of this (master) port and store a reference in self._clones.
-
- The new port name (and key for message ports) will have index 1... appended.
- If this is the first clone, this (master) port will get a 0 appended to its name (and key)
-
- Returns:
- the cloned port
- """
- # add index to master port name if there are no clones yet
- if not self._clones:
- self._name = self._n['name'] + '0'
- if not self._key.isdigit(): # also update key for none stream ports
- self._key = self._name
-
- # Prepare a copy of the odict for the clone
- n = self._n.copy()
- if 'nports' in n: n.pop('nports') # remove nports from the key so the copy cannot be a duplicator
- n['name'] = self._n['name'] + str(len(self._clones) + 1)
- n['key'] = '99999' if self._key.isdigit() else n['name'] # dummy value 99999 will be fixed later
-
- port = self.__class__(self.get_parent(), n, self._dir) # clone
- self._clones.append(port)
- return port
-
- def remove_clone(self, port):
- """
- Remove a cloned port (from the list of clones only)
- Remove the index 0 of the master port name (and key9 if there are no more clones left
- """
- self._clones.remove(port)
- # remove index from master port name if there are no more clones
- if not self._clones:
- self._name = self._n['name']
- if not self._key.isdigit(): # also update key for none stream ports
- self._key = self._name
diff --git a/grc/python/__init__.py b/grc/python/__init__.py
deleted file mode 100644
index 8b13789179..0000000000
--- a/grc/python/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/grc/python/base/Block.py b/grc/python/base/Block.py
deleted file mode 100644
index 77c3145173..0000000000
--- a/grc/python/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/python/base/CMakeLists.txt b/grc/python/base/CMakeLists.txt
deleted file mode 100644
index bdc8a5006f..0000000000
--- a/grc/python/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/python/base/Connection.py b/grc/python/base/Connection.py
deleted file mode 100644
index 8df0f5ad53..0000000000
--- a/grc/python/base/Connection.py
+++ /dev/null
@@ -1,139 +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/python/base/Constants.py b/grc/python/base/Constants.py
deleted file mode 100644
index 1e83de63b5..0000000000
--- a/grc/python/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/python/base/Element.py b/grc/python/base/Element.py
deleted file mode 100644
index 3b604a5340..0000000000
--- a/grc/python/base/Element.py
+++ /dev/null
@@ -1,98 +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/python/base/FlowGraph.py b/grc/python/base/FlowGraph.py
deleted file mode 100644
index 42faab6a16..0000000000
--- a/grc/python/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 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
deleted file mode 100644
index b246d9f759..0000000000
--- a/grc/python/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/python/base/ParseXML.py b/grc/python/base/ParseXML.py
deleted file mode 100644
index 2d5fed0862..0000000000
--- a/grc/python/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/python/base/Platform.py b/grc/python/base/Platform.py
deleted file mode 100644
index 367140f8ae..0000000000
--- a/grc/python/base/Platform.py
+++ /dev/null
@@ -1,274 +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 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
deleted file mode 100644
index 39166d18f7..0000000000
--- a/grc/python/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/python/base/__init__.py b/grc/python/base/__init__.py
deleted file mode 100644
index 2682db8125..0000000000
--- a/grc/python/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/python/base/block_tree.dtd b/grc/python/base/block_tree.dtd
deleted file mode 100644
index 9e23576477..0000000000
--- a/grc/python/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/python/base/domain.dtd b/grc/python/base/domain.dtd
deleted file mode 100644
index b5b0b8bf39..0000000000
--- a/grc/python/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/python/base/flow_graph.dtd b/grc/python/base/flow_graph.dtd
deleted file mode 100644
index bdfe1dc059..0000000000
--- a/grc/python/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/python/base/odict.py b/grc/python/base/odict.py
deleted file mode 100644
index 70ab67d053..0000000000
--- a/grc/python/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/python/block.dtd b/grc/python/block.dtd
deleted file mode 100644
index 145f4d8610..0000000000
--- a/grc/python/block.dtd
+++ /dev/null
@@ -1,69 +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
--->
-<!--
- gnuradio_python.blocks.dtd
- Josh Blum
- The document type definition for blocks.
- -->
-<!--
- Top level element.
- A block contains a name, ...parameters list, and list of IO ports.
- -->
-<!ELEMENT block (name, key, category?, throttle?, flags?, import*, var_make?, var_value?,
- make, callback*, param_tab_order?, param*, bus_sink?, bus_source?, check*,
- sink*, source*, bus_structure_sink?, bus_structure_source?, doc?, grc_source?)>
-<!--
- Sub level elements.
- -->
-<!ELEMENT param_tab_order (tab+)>
-<!ELEMENT param (base_key?, name, key, value?, type?, hide?, option*, tab?)>
-<!ELEMENT option (name, key, opt*)>
-<!ELEMENT sink (name, type, vlen?, domain?, nports?, optional?, hide?)>
-<!ELEMENT source (name, type, vlen?, domain?, nports?, optional?, hide?)>
-<!--
- Bottom level elements.
- Character data only.
- -->
-<!ELEMENT category (#PCDATA)>
-<!ELEMENT import (#PCDATA)>
-<!ELEMENT doc (#PCDATA)>
-<!ELEMENT grc_source (#PCDATA)>
-<!ELEMENT tab (#PCDATA)>
-<!ELEMENT name (#PCDATA)>
-<!ELEMENT base_key (#PCDATA)>
-<!ELEMENT key (#PCDATA)>
-<!ELEMENT check (#PCDATA)>
-<!ELEMENT bus_sink (#PCDATA)>
-<!ELEMENT bus_source (#PCDATA)>
-<!ELEMENT opt (#PCDATA)>
-<!ELEMENT type (#PCDATA)>
-<!ELEMENT hide (#PCDATA)>
-<!ELEMENT vlen (#PCDATA)>
-<!ELEMENT domain (#PCDATA)>
-<!ELEMENT nports (#PCDATA)>
-<!ELEMENT bus_structure_sink (#PCDATA)>
-<!ELEMENT bus_structure_source (#PCDATA)>
-<!ELEMENT var_make (#PCDATA)>
-<!ELEMENT var_value (#PCDATA)>
-<!ELEMENT make (#PCDATA)>
-<!ELEMENT value (#PCDATA)>
-<!ELEMENT callback (#PCDATA)>
-<!ELEMENT optional (#PCDATA)>
-<!ELEMENT throttle (#PCDATA)>
-<!ELEMENT flags (#PCDATA)>
diff --git a/grc/python/default_flow_graph.grc b/grc/python/default_flow_graph.grc
deleted file mode 100644
index 059509d34b..0000000000
--- a/grc/python/default_flow_graph.grc
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0"?>
-<!--
-###################################################
-##Default Flow Graph:
-## include an options block and a variable for sample rate
-###################################################
- -->
-<flow_graph>
- <block>
- <key>options</key>
- <param>
- <key>id</key>
- <value>top_block</value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(8, 8)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
- <block>
- <key>variable</key>
- <param>
- <key>id</key>
- <value>samp_rate</value>
- </param>
- <param>
- <key>value</key>
- <value>32000</value>
- </param>
- <param>
- <key>_coordinate</key>
- <value>(8, 160)</value>
- </param>
- <param>
- <key>_rotation</key>
- <value>0</value>
- </param>
- </block>
-</flow_graph>
diff --git a/grc/python/epy_block_io.py b/grc/python/epy_block_io.py
deleted file mode 100644
index e089908a01..0000000000
--- a/grc/python/epy_block_io.py
+++ /dev/null
@@ -1,95 +0,0 @@
-
-import inspect
-import collections
-
-from gnuradio import gr
-import pmt
-
-
-TYPE_MAP = {
- 'complex64': 'complex', 'complex': 'complex',
- 'float32': 'float', 'float': 'float',
- 'int32': 'int', 'uint32': 'int',
- 'int16': 'short', 'uint16': 'short',
- 'int8': 'byte', 'uint8': 'byte',
-}
-
-BlockIO = collections.namedtuple('BlockIO', 'name cls params sinks sources doc')
-
-
-def _ports(sigs, msgs):
- ports = list()
- for i, dtype in enumerate(sigs):
- port_type = TYPE_MAP.get(dtype.name, None)
- if not port_type:
- raise ValueError("Can't map {0:!r} to GRC port type".format(dtype))
- ports.append((str(i), port_type))
- for msg_key in msgs:
- if msg_key == 'system':
- continue
- ports.append((msg_key, 'message'))
- return ports
-
-
-def _blk_class(source_code):
- ns = {}
- try:
- exec source_code in ns
- except Exception as e:
- raise ValueError("Can't interpret source code: " + str(e))
- for var in ns.itervalues():
- if inspect.isclass(var)and issubclass(var, gr.gateway.gateway_block):
- return var
- raise ValueError('No python block class found in code')
-
-
-def extract(cls):
- if not inspect.isclass(cls):
- cls = _blk_class(cls)
-
- spec = inspect.getargspec(cls.__init__)
- defaults = map(repr, spec.defaults or ())
- doc = cls.__doc__ or cls.__init__.__doc__ or ''
- cls_name = cls.__name__
-
- if len(defaults) + 1 != len(spec.args):
- raise ValueError("Need all __init__ arguments to have default values")
-
- try:
- instance = cls()
- except Exception as e:
- raise RuntimeError("Can't create an instance of your block: " + str(e))
-
- name = instance.name()
- params = list(zip(spec.args[1:], defaults))
-
- sinks = _ports(instance.in_sig(),
- pmt.to_python(instance.message_ports_in()))
- sources = _ports(instance.out_sig(),
- pmt.to_python(instance.message_ports_out()))
-
- return BlockIO(name, cls_name, params, sinks, sources, doc)
-
-
-if __name__ == '__main__':
- blk_code = """
-import numpy as np
-from gnuradio import gr
-import pmt
-
-class blk(gr.sync_block):
- def __init__(self, param1=None, param2=None):
- "Test Docu"
- gr.sync_block.__init__(
- self,
- name='Embedded Python Block',
- in_sig = (np.float32,),
- out_sig = (np.float32,np.complex64,),
- )
- self.message_port_register_in(pmt.intern('msg_in'))
- self.message_port_register_out(pmt.intern('msg_out'))
-
- def work(self, inputs_items, output_items):
- return 10
- """
- print extract(blk_code)
diff --git a/grc/python/expr_utils.py b/grc/python/expr_utils.py
deleted file mode 100644
index 9e0b2a4a0a..0000000000
--- a/grc/python/expr_utils.py
+++ /dev/null
@@ -1,177 +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 string
-VAR_CHARS = string.letters + string.digits + '_'
-
-class graph(object):
- """
- Simple graph structure held in a dictionary.
- """
-
- def __init__(self): self._graph = dict()
-
- def __str__(self): return str(self._graph)
-
- def add_node(self, node_key):
- if self._graph.has_key(node_key): return
- self._graph[node_key] = set()
-
- def remove_node(self, node_key):
- if not self._graph.has_key(node_key): return
- for edges in self._graph.values():
- if node_key in edges: edges.remove(node_key)
- self._graph.pop(node_key)
-
- def add_edge(self, src_node_key, dest_node_key):
- self._graph[src_node_key].add(dest_node_key)
-
- def remove_edge(self, src_node_key, dest_node_key):
- self._graph[src_node_key].remove(dest_node_key)
-
- def get_nodes(self): return self._graph.keys()
-
- def get_edges(self, node_key): return self._graph[node_key]
-
-def expr_split(expr):
- """
- Split up an expression by non alphanumeric characters, including underscore.
- Leave strings in-tact.
- #TODO ignore escaped quotes, use raw strings.
-
- Args:
- expr: an expression string
-
- Returns:
- a list of string tokens that form expr
- """
- toks = list()
- tok = ''
- quote = ''
- for char in expr:
- if quote or char in VAR_CHARS:
- if char == quote: quote = ''
- tok += char
- elif char in ("'", '"'):
- toks.append(tok)
- tok = char
- quote = char
- else:
- toks.append(tok)
- toks.append(char)
- tok = ''
- toks.append(tok)
- return filter(lambda t: t, toks)
-
-def expr_replace(expr, replace_dict):
- """
- Search for vars in the expression and add the prepend.
-
- Args:
- expr: an expression string
- replace_dict: a dict of find:replace
-
- Returns:
- a new expression with the prepend
- """
- expr_splits = expr_split(expr)
- for i, es in enumerate(expr_splits):
- if es in replace_dict.keys():
- expr_splits[i] = replace_dict[es]
- return ''.join(expr_splits)
-
-def get_variable_dependencies(expr, vars):
- """
- Return a set of variables used in this expression.
-
- Args:
- expr: an expression string
- vars: a list of variable names
-
- Returns:
- a subset of vars used in the expression
- """
- expr_toks = expr_split(expr)
- return set(filter(lambda v: v in expr_toks, vars))
-
-def get_graph(exprs):
- """
- Get a graph representing the variable dependencies
-
- Args:
- exprs: a mapping of variable name to expression
-
- Returns:
- a graph of variable deps
- """
- vars = exprs.keys()
- #get dependencies for each expression, load into graph
- var_graph = graph()
- for var in vars: var_graph.add_node(var)
- for var, expr in exprs.iteritems():
- for dep in get_variable_dependencies(expr, vars):
- if dep != var: var_graph.add_edge(dep, var)
- return var_graph
-
-def sort_variables(exprs):
- """
- Get a list of variables in order of dependencies.
-
- Args:
- exprs: a mapping of variable name to expression
-
- Returns:
- a list of variable names
- @throws Exception circular dependencies
- """
- var_graph = get_graph(exprs)
- sorted_vars = list()
- #determine dependency order
- while var_graph.get_nodes():
- #get a list of nodes with no edges
- indep_vars = filter(lambda var: not var_graph.get_edges(var), var_graph.get_nodes())
- if not indep_vars: raise Exception('circular dependency caught in sort_variables')
- #add the indep vars to the end of the list
- sorted_vars.extend(sorted(indep_vars))
- #remove each edge-less node from the graph
- for var in indep_vars: var_graph.remove_node(var)
- return reversed(sorted_vars)
-
-def sort_objects(objects, get_id, get_expr):
- """
- Sort a list of objects according to their expressions.
-
- Args:
- objects: the list of objects to sort
- get_id: the function to extract an id from the object
- get_expr: the function to extract an expression from the object
-
- Returns:
- a list of sorted objects
- """
- id2obj = dict([(get_id(obj), obj) for obj in objects])
- #map obj id to expression code
- id2expr = dict([(get_id(obj), get_expr(obj)) for obj in objects])
- #sort according to dependency
- sorted_ids = sort_variables(id2expr)
- #return list of sorted objects
- return [id2obj[id] for id in sorted_ids]
-
-if __name__ == '__main__':
- for i in sort_variables({'x':'1', 'y':'x+1', 'a':'x+y', 'b':'y+1', 'c':'a+b+x+y'}): print i
diff --git a/grc/python/extract_docs.py b/grc/python/extract_docs.py
deleted file mode 100644
index 7c149ce593..0000000000
--- a/grc/python/extract_docs.py
+++ /dev/null
@@ -1,296 +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 sys
-import re
-import subprocess
-import threading
-import json
-import Queue
-import random
-import itertools
-
-
-###############################################################################
-# The docstring extraction
-###############################################################################
-
-def docstring_guess_from_key(key):
- """Extract the documentation from the python __doc__ strings
-
- By guessing module and constructor names from key
-
- Args:
- key: the block key
-
- Returns:
- a dict (block_name --> doc string)
- """
- doc_strings = dict()
-
- in_tree = [key.partition('_')[::2] + (
- lambda package: getattr(__import__('gnuradio.' + package), package),
- )]
-
- key_parts = key.split('_')
- oot = [
- ('_'.join(key_parts[:i]), '_'.join(key_parts[i:]), __import__)
- for i in range(1, len(key_parts))
- ]
-
- for module_name, init_name, importer in itertools.chain(in_tree, oot):
- if not module_name or not init_name:
- continue
- try:
- module = importer(module_name)
- break
- except ImportError:
- continue
- else:
- return doc_strings
-
- pattern = re.compile(
- '^' + init_name.replace('_', '_*').replace('x', r'\w') + r'\w*$'
- )
- for match in filter(pattern.match, dir(module)):
- try:
- doc_strings[match] = getattr(module, match).__doc__
- except AttributeError:
- continue
-
- return doc_strings
-
-
-def docstring_from_make(key, imports, make):
- """Extract the documentation from the python __doc__ strings
-
- By importing it and checking a truncated make
-
- Args:
- key: the block key
- imports: a list of import statements (string) to execute
- make: block constructor template
-
- Returns:
- a list of tuples (block_name, doc string)
- """
-
- try:
- blk_cls = make.partition('(')[0].strip()
- if '$' in blk_cls:
- raise ValueError('Not an identifier')
-
- ns = dict()
- for _import in imports:
- exec(_import.strip(), ns)
- blk = eval(blk_cls, ns)
-
- doc_strings = {key: blk.__doc__}
-
- except (ImportError, AttributeError, SyntaxError, ValueError):
- doc_strings = docstring_guess_from_key(key)
-
- return doc_strings
-
-
-###############################################################################
-# Manage docstring extraction in separate process
-###############################################################################
-
-class SubprocessLoader(object):
- """Start and manage docstring extraction process
-
- Manages subprocess and handles RPC.
- """
- BOOTSTRAP = "import runpy; runpy.run_path({!r}, run_name='__worker__')"
- AUTH_CODE = random.random() # sort out unwanted output of worker process
- RESTART = 5 # number of worker restarts before giving up
- DONE = object() # sentinel value to signal end-of-queue
-
- def __init__(self, callback_query_result, callback_finished=None):
- self.callback_query_result = callback_query_result
- self.callback_finished = callback_finished or (lambda: None)
-
- self._queue = Queue.Queue()
- self._thread = None
- self._worker = None
- self._shutdown = threading.Event()
- self._last_cmd = None
-
- def start(self):
- """Start the worker process handler thread"""
- if self._thread is not None:
- return
- self._shutdown.clear()
- thread = self._thread = threading.Thread(target=self.run_worker)
- thread.daemon = True
- thread.start()
-
- def run_worker(self):
- """Read docstring back from worker stdout and execute callback."""
- for _ in range(self.RESTART):
- if self._shutdown.is_set():
- break
- try:
- self._worker = subprocess.Popen(
- args=(sys.executable, '-uc', self.BOOTSTRAP.format(__file__)),
- stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE
- )
- self._handle_worker()
-
- except (OSError, IOError):
- msg = "Warning: restarting the docstring loader"
- cmd, args = self._last_cmd
- if cmd == 'query':
- msg += " (crashed while loading {0!r})".format(args[0])
- print >> sys.stderr, msg
- continue # restart
- else:
- break # normal termination, return
- finally:
- self._worker.terminate()
- else:
- print >> sys.stderr, "Warning: docstring loader crashed too often"
- self._thread = None
- self._worker = None
- self.callback_finished()
-
- def _handle_worker(self):
- """Send commands and responses back from worker."""
- assert '1' == self._worker.stdout.read(1)
- for cmd, args in iter(self._queue.get, self.DONE):
- self._last_cmd = cmd, args
- self._send(cmd, args)
- cmd, args = self._receive()
- self._handle_response(cmd, args)
-
- def _send(self, cmd, args):
- """send a command to worker's stdin"""
- fd = self._worker.stdin
- json.dump((self.AUTH_CODE, cmd, args), fd)
- fd.write('\n'.encode())
-
- def _receive(self):
- """receive response from worker's stdout"""
- for line in iter(self._worker.stdout.readline, ''):
- try:
- key, cmd, args = json.loads(line, encoding='utf-8')
- if key != self.AUTH_CODE:
- raise ValueError('Got wrong auth code')
- return cmd, args
- except ValueError:
- continue # ignore invalid output from worker
- else:
- raise IOError("Can't read worker response")
-
- def _handle_response(self, cmd, args):
- """Handle response from worker, call the callback"""
- if cmd == 'result':
- key, docs = args
- self.callback_query_result(key, docs)
- elif cmd == 'error':
- print args
- else:
- print >> sys.stderr, "Unknown response:", cmd, args
-
- def query(self, key, imports=None, make=None):
- """request docstring extraction for a certain key"""
- if self._thread is None:
- self.start()
- if imports and make:
- self._queue.put(('query', (key, imports, make)))
- else:
- self._queue.put(('query_key_only', (key,)))
-
- def finish(self):
- """signal end of requests"""
- self._queue.put(self.DONE)
-
- def wait(self):
- """Wait for the handler thread to die"""
- if self._thread:
- self._thread.join()
-
- def terminate(self):
- """Terminate the worker and wait"""
- self._shutdown.set()
- try:
- self._worker.terminate()
- self.wait()
- except (OSError, AttributeError):
- pass
-
-
-###############################################################################
-# Main worker entry point
-###############################################################################
-
-def worker_main():
- """Main entry point for the docstring extraction process.
-
- Manages RPC with main process through.
- Runs a docstring extraction for each key it read on stdin.
- """
- def send(cmd, args):
- json.dump((code, cmd, args), sys.stdout)
- sys.stdout.write('\n'.encode())
-
- sys.stdout.write('1')
- for line in iter(sys.stdin.readline, ''):
- code, cmd, args = json.loads(line, encoding='utf-8')
- try:
- if cmd == 'query':
- key, imports, make = args
- send('result', (key, docstring_from_make(key, imports, make)))
- elif cmd == 'query_key_only':
- key, = args
- send('result', (key, docstring_guess_from_key(key)))
- elif cmd == 'exit':
- break
- except Exception as e:
- send('error', repr(e))
-
-
-if __name__ == '__worker__':
- worker_main()
-
-elif __name__ == '__main__':
- def callback(key, docs):
- print key
- for match, doc in docs.iteritems():
- print '-->', match
- print doc.strip()
- print
- print
-
- r = SubprocessLoader(callback)
-
- # r.query('analog_feedforward_agc_cc')
- # r.query('uhd_source')
- r.query('expr_utils_graph')
- r.query('blocks_add_cc')
- r.query('blocks_add_cc', ['import gnuradio.blocks'], 'gnuradio.blocks.add_cc(')
- # r.query('analog_feedforward_agc_cc')
- # r.query('uhd_source')
- # r.query('uhd_source')
- # r.query('analog_feedforward_agc_cc')
- r.finish()
- # r.terminate()
- r.wait()
diff --git a/grc/python/flow_graph.tmpl b/grc/python/flow_graph.tmpl
deleted file mode 100644
index bd8025b676..0000000000
--- a/grc/python/flow_graph.tmpl
+++ /dev/null
@@ -1,439 +0,0 @@
-#if not $generate_options.startswith('hb')
-#!/usr/bin/env python2
-#end if
-# -*- coding: utf-8 -*-
-########################################################
-##Cheetah template - gnuradio_python
-##
-##@param imports the import statements
-##@param flow_graph the flow_graph
-##@param variables the variable blocks
-##@param parameters the parameter blocks
-##@param blocks the signal blocks
-##@param connections the connections
-##@param msgs the msg type connections
-##@param generate_options the type of flow graph
-##@param var_id2cbs variable id map to callback strings
-########################################################
-#def indent($code)
-#set $code = '\n '.join(str($code).splitlines())
-$code#slurp
-#end def
-#import time
-#set $DIVIDER = '#'*50
-$DIVIDER
-# GNU Radio Python Flow Graph
-# Title: $title
-#if $flow_graph.get_option('author')
-# Author: $flow_graph.get_option('author')
-#end if
-#if $flow_graph.get_option('description')
-# Description: $flow_graph.get_option('description')
-#end if
-# Generated: $time.ctime()
-$DIVIDER
-#if $flow_graph.get_option('thread_safe_setters')
-import threading
-#end if
-
-## Call XInitThreads as the _very_ first thing.
-## After some Qt import, it's too late
-#if $generate_options in ('wx_gui', 'qt_gui')
-if __name__ == '__main__':
- import ctypes
- import sys
- if sys.platform.startswith('linux'):
- try:
- x11 = ctypes.cdll.LoadLibrary('libX11.so')
- x11.XInitThreads()
- except:
- print "Warning: failed to XInitThreads()"
-
-#end if
-#
-########################################################
-##Create Imports
-########################################################
-#if $flow_graph.get_option('qt_qss_theme')
-#set imports = $sorted(set($imports + ["import os", "import sys"]))
-#end if
-#if any(imp.endswith("# grc-generated hier_block") for imp in $imports)
-import os
-import sys
-#set imports = $filter(lambda i: i not in ("import os", "import sys"), $imports)
-sys.path.append(os.environ.get('GRC_HIER_PATH', os.path.expanduser('~/.grc_gnuradio')))
-
-#end if
-#for $imp in $imports
-##$(imp.replace(" # grc-generated hier_block", ""))
-$imp
-#end for
-########################################################
-##Create Class
-## Write the class declaration for a top or hier block.
-## The parameter names are the arguments to __init__.
-## Determine the absolute icon path (wx gui only).
-## Setup the IO signature (hier block only).
-########################################################
-#set $class_name = $flow_graph.get_option('id')
-#set $param_str = ', '.join(['self'] + ['%s=%s'%(param.get_id(), param.get_make()) for param in $parameters])
-#if $generate_options == 'wx_gui'
- #import gtk
- #set $icon = gtk.IconTheme().lookup_icon('gnuradio-grc', 32, 0)
-
-
-class $(class_name)(grc_wxgui.top_block_gui):
-
- def __init__($param_str):
- grc_wxgui.top_block_gui.__init__(self, title="$title")
- #if $icon
- _icon_path = "$icon.get_filename()"
- self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY))
- #end if
-#elif $generate_options == 'qt_gui'
-
-
-class $(class_name)(gr.top_block, Qt.QWidget):
-
- def __init__($param_str):
- gr.top_block.__init__(self, "$title")
- Qt.QWidget.__init__(self)
- self.setWindowTitle("$title")
- try:
- self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
- except:
- pass
- self.top_scroll_layout = Qt.QVBoxLayout()
- self.setLayout(self.top_scroll_layout)
- self.top_scroll = Qt.QScrollArea()
- self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
- self.top_scroll_layout.addWidget(self.top_scroll)
- self.top_scroll.setWidgetResizable(True)
- self.top_widget = Qt.QWidget()
- self.top_scroll.setWidget(self.top_widget)
- self.top_layout = Qt.QVBoxLayout(self.top_widget)
- self.top_grid_layout = Qt.QGridLayout()
- self.top_layout.addLayout(self.top_grid_layout)
-
- self.settings = Qt.QSettings("GNU Radio", "$class_name")
- self.restoreGeometry(self.settings.value("geometry").toByteArray())
-#elif $generate_options == 'no_gui'
-
-
-class $(class_name)(gr.top_block):
-
- def __init__($param_str):
- gr.top_block.__init__(self, "$title")
-#elif $generate_options.startswith('hb')
- #set $in_sigs = $flow_graph.get_hier_block_stream_io('in')
- #set $out_sigs = $flow_graph.get_hier_block_stream_io('out')
-
-
-#if $generate_options == 'hb_qt_gui'
-class $(class_name)(gr.hier_block2, Qt.QWidget):
-#else
-class $(class_name)(gr.hier_block2):
-#end if
-#def make_io_sig($io_sigs)
- #set $size_strs = ['%s*%s'%(io_sig['size'], io_sig['vlen']) for io_sig in $io_sigs]
- #if len($io_sigs) == 0
-gr.io_signature(0, 0, 0)#slurp
- #elif len($io_sigs) == 1
-gr.io_signature(1, 1, $size_strs[0])#slurp
- #else
-gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))])#slurp
- #end if
-#end def
-
- def __init__($param_str):
- gr.hier_block2.__init__(
- self, "$title",
- $make_io_sig($in_sigs),
- $make_io_sig($out_sigs),
- )
- #for $pad in $flow_graph.get_hier_block_message_io('in')
- self.message_port_register_hier_in("$pad['label']")
- #end for
- #for $pad in $flow_graph.get_hier_block_message_io('out')
- self.message_port_register_hier_out("$pad['label']")
- #end for
- #if $generate_options == 'hb_qt_gui'
-
- Qt.QWidget.__init__(self)
- self.top_layout = Qt.QVBoxLayout()
- self.top_grid_layout = Qt.QGridLayout()
- self.top_layout.addLayout(self.top_grid_layout)
- self.setLayout(self.top_layout)
- #end if
-#end if
-#if $flow_graph.get_option('thread_safe_setters')
-
- self._lock = threading.RLock()
-#end if
-########################################################
-##Create Parameters
-## Set the parameter to a property of self.
-########################################################
-#if $parameters
-
- $DIVIDER
- # Parameters
- $DIVIDER
-#end if
-#for $param in $parameters
- $indent($param.get_var_make())
-#end for
-########################################################
-##Create Variables
-########################################################
-#if $variables
-
- $DIVIDER
- # Variables
- $DIVIDER
-#end if
-#for $var in $variables
- $indent($var.get_var_make())
-#end for
-########################################################
-##Create Message Queues
-########################################################
-#if $msgs
-
- $DIVIDER
- # Message Queues
- $DIVIDER
-#end if
-#for $msg in $msgs
- $(msg.get_source().get_parent().get_id())_msgq_out = $(msg.get_sink().get_parent().get_id())_msgq_in = gr.msg_queue(2)
-#end for
-########################################################
-##Create Blocks
-########################################################
-#if $blocks
-
- $DIVIDER
- # Blocks
- $DIVIDER
-#end if
-#for $blk in filter(lambda b: b.get_make(), $blocks)
- #if $blk in $variables
- $indent($blk.get_make())
- #else
- self.$blk.get_id() = $indent($blk.get_make())
- #if $blk.has_param('alias') and $blk.get_param('alias').get_evaluated()
- (self.$blk.get_id()).set_block_alias("$blk.get_param('alias').get_evaluated()")
- #end if
- #if $blk.has_param('affinity') and $blk.get_param('affinity').get_evaluated()
- (self.$blk.get_id()).set_processor_affinity($blk.get_param('affinity').get_evaluated())
- #end if
- #if (len($blk.get_sources())>0) and $blk.has_param('minoutbuf') and (int($blk.get_param('minoutbuf').get_evaluated()) > 0)
- (self.$blk.get_id()).set_min_output_buffer($blk.get_param('minoutbuf').get_evaluated())
- #end if
- #if (len($blk.get_sources())>0) and $blk.has_param('maxoutbuf') and (int($blk.get_param('maxoutbuf').get_evaluated()) > 0)
- (self.$blk.get_id()).set_max_output_buffer($blk.get_param('maxoutbuf').get_evaluated())
- #end if
- #end if
-#end for
-########################################################
-##Create Connections
-## The port name should be the id of the parent block.
-## However, port names for IO pads should be self.
-########################################################
-#def make_port_sig($port)
- #if $port.get_parent().get_key() in ('pad_source', 'pad_sink')
- #set block = 'self'
- #set key = $flow_graph.get_pad_port_global_key($port)
- #else
- #set block = 'self.' + $port.get_parent().get_id()
- #set key = $port.get_key()
- #end if
- #if not $key.isdigit()
- #set key = repr($key)
- #end if
-($block, $key)#slurp
-#end def
-#if $connections
-
- $DIVIDER
- # Connections
- $DIVIDER
-#end if
-#for $con in $connections
- #set global $source = $con.get_source()
- #set global $sink = $con.get_sink()
- #include source=$connection_templates[($source.get_domain(), $sink.get_domain())]
-
-#end for
-########################################################
-## QT sink close method reimplementation
-########################################################
-#if $generate_options == 'qt_gui'
-
- def closeEvent(self, event):
- self.settings = Qt.QSettings("GNU Radio", "$class_name")
- self.settings.setValue("geometry", self.saveGeometry())
- event.accept()
-
- #if $flow_graph.get_option('qt_qss_theme')
- def setStyleSheetFromFile(self, filename):
- try:
- if not os.path.exists(filename):
- filename = os.path.join(
- gr.prefix(), "share", "gnuradio", "themes", filename)
- with open(filename) as ss:
- self.setStyleSheet(ss.read())
- except Exception as e:
- print >> sys.stderr, e
- #end if
-#end if
-########################################################
-##Create Callbacks
-## Write a set method for this variable that calls the callbacks
-########################################################
-#for $var in $parameters + $variables
-
- #set $id = $var.get_id()
- def get_$(id)(self):
- return self.$id
-
- def set_$(id)(self, $id):
- #if $flow_graph.get_option('thread_safe_setters')
- with self._lock:
- self.$id = $id
- #for $callback in $var_id2cbs[$id]
- $indent($callback)
- #end for
- #else
- self.$id = $id
- #for $callback in $var_id2cbs[$id]
- $indent($callback)
- #end for
- #end if
-#end for
-########################################################
-##Create Main
-## For top block code, generate a main routine.
-## Instantiate the top block and run as gui or cli.
-########################################################
-#def make_default($type, $param)
- #if $type == 'eng_float'
-eng_notation.num_to_str($param.get_make())#slurp
- #else
-$param.get_make()#slurp
- #end if
-#end def
-#def make_short_id($param)
- #set $short_id = $param.get_param('short_id').get_evaluated()
- #if $short_id
- #set $short_id = '-' + $short_id
- #end if
-$short_id#slurp
-#end def
-#if not $generate_options.startswith('hb')
-#set $params_eq_list = list()
-#if $parameters
-
-
-def argument_parser():
- parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
- #for $param in $parameters
- #set $type = $param.get_param('type').get_value()
- #if $type
- #silent $params_eq_list.append('%s=options.%s'%($param.get_id(), $param.get_id()))
- parser.add_option(
- "$make_short_id($param)", "--$param.get_id().replace('_', '-')", dest="$param.get_id()", type="$type", default=$make_default($type, $param),
- help="Set $($param.get_param('label').get_evaluated() or $param.get_id()) [default=%default]")
- #end if
- #end for
- return parser
-#end if
-
-
-def main(top_block_cls=$(class_name), options=None):
- #if $parameters
- if options is None:
- options, _ = argument_parser().parse_args()
- #end if
- #if $flow_graph.get_option('realtime_scheduling')
- if gr.enable_realtime_scheduling() != gr.RT_OK:
- print "Error: failed to enable real-time scheduling."
- #end if
-
- #if $generate_options == 'wx_gui'
- tb = top_block_cls($(', '.join($params_eq_list)))
- #if $flow_graph.get_option('max_nouts')
- tb.Run($flow_graph.get_option('run'), $flow_graph.get_option('max_nouts'))
- #else
- tb.Start($flow_graph.get_option('run'))
- #for $m in $monitors
- (tb.$m.get_id()).start()
- #end for
- tb.Wait()
- #end if
- #elif $generate_options == 'qt_gui'
- from distutils.version import StrictVersion
- if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"):
- style = gr.prefs().get_string('qtgui', 'style', 'raster')
- Qt.QApplication.setGraphicsSystem(style)
- qapp = Qt.QApplication(sys.argv)
-
- tb = top_block_cls($(', '.join($params_eq_list)))
- #if $flow_graph.get_option('run')
- #if $flow_graph.get_option('max_nouts')
- tb.start($flow_graph.get_option('max_nouts'))
- #else
- tb.start()
- #end if
- #end if
- #if $flow_graph.get_option('qt_qss_theme')
- tb.setStyleSheetFromFile($repr($flow_graph.get_option('qt_qss_theme')))
- #end if
- tb.show()
-
- def quitting():
- tb.stop()
- tb.wait()
- qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting)
- #for $m in $monitors
- if $m.has_param('en'):
- if $m.get_param('en').get_value():
- (tb.$m.get_id()).start()
- else:
- sys.stderr.write("Monitor '{0}' does not have an enable ('en') parameter.".format("tb.$m.get_id()"))
- #end for
- qapp.exec_()
- #elif $generate_options == 'no_gui'
- tb = top_block_cls($(', '.join($params_eq_list)))
- #set $run_options = $flow_graph.get_option('run_options')
- #if $run_options == 'prompt'
- #if $flow_graph.get_option('max_nouts')
- tb.start($flow_graph.get_option('max_nouts'))
- #else
- tb.start()
- #end if
- #for $m in $monitors
- (tb.$m.get_id()).start()
- #end for
- try:
- raw_input('Press Enter to quit: ')
- except EOFError:
- pass
- tb.stop()
- #elif $run_options == 'run'
- #if $flow_graph.get_option('max_nouts')
- tb.start($flow_graph.get_option('max_nouts'))
- #else
- tb.start()
- #end if
- #end if
- #for $m in $monitors
- (tb.$m.get_id()).start()
- #end for
- tb.wait()
- #end if
-
-
-if __name__ == '__main__':
- main()
-#end if