diff options
Diffstat (limited to 'grc/src/platforms/python')
-rw-r--r-- | grc/src/platforms/python/Block.py | 152 | ||||
-rw-r--r-- | grc/src/platforms/python/Connection.py | 34 | ||||
-rw-r--r-- | grc/src/platforms/python/Constants.py.in | 54 | ||||
-rw-r--r-- | grc/src/platforms/python/FlowGraph.py | 162 | ||||
-rw-r--r-- | grc/src/platforms/python/Generator.py | 142 | ||||
-rw-r--r-- | grc/src/platforms/python/Makefile.am | 48 | ||||
-rw-r--r-- | grc/src/platforms/python/Param.py | 402 | ||||
-rw-r--r-- | grc/src/platforms/python/Platform.py | 69 | ||||
-rw-r--r-- | grc/src/platforms/python/Port.py | 129 | ||||
-rw-r--r-- | grc/src/platforms/python/__init__.py | 1 | ||||
-rw-r--r-- | grc/src/platforms/python/utils/Makefile.am | 30 | ||||
-rw-r--r-- | grc/src/platforms/python/utils/__init__.py | 1 | ||||
-rw-r--r-- | grc/src/platforms/python/utils/convert_hier.py | 78 | ||||
-rw-r--r-- | grc/src/platforms/python/utils/expr_utils.py | 137 | ||||
-rw-r--r-- | grc/src/platforms/python/utils/extract_docs.py | 92 |
15 files changed, 0 insertions, 1531 deletions
diff --git a/grc/src/platforms/python/Block.py b/grc/src/platforms/python/Block.py deleted file mode 100644 index 341e5fdc3..000000000 --- a/grc/src/platforms/python/Block.py +++ /dev/null @@ -1,152 +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 .. base.Block import Block as _Block -from utils import extract_docs - -class Block(_Block): - - ##for make source to keep track of indexes - _source_count = 0 - ##for make sink to keep track of indexes - _sink_count = 0 - - def __init__(self, flow_graph, n): - """ - Make a new block from nested data. - @param flow graph the parent element - @param n the nested odict - @return block a new block - """ - #grab the data - doc = n.find('doc') or '' - imports = map(lambda i: i.strip(), n.findall('import')) - make = n.find('make') - checks = n.findall('check') - callbacks = n.findall('callback') - #build the block - _Block.__init__( - self, - flow_graph=flow_graph, - n=n, - ) - self._doc = doc - self._imports = imports - self._make = make - self._callbacks = callbacks - self._checks = checks - - def validate(self): - """ - Validate this block. - Call the base class validate. - Evaluate the checks: each check must evaluate to True. - Adjust the nports. - """ - _Block.validate(self) - #evaluate the checks - for check in self._checks: - check_res = self.resolve_dependencies(check) - try: - check_eval = self.get_parent().evaluate(check_res) - try: assert check_eval - except AssertionError: self._add_error_message('Check "%s" failed.'%check) - except: self._add_error_message('Check "%s" did not evaluate.'%check) - #adjust nports - for ports, Port in ( - (self._sources, self.get_parent().get_parent().Source), - (self._sinks, self.get_parent().get_parent().Sink), - ): - #how many ports? - num_ports = len(ports) - #do nothing for 0 ports - if not num_ports: continue - #get the nports setting - port0 = ports[str(0)] - nports = port0.get_nports() - #do nothing for no nports - if not nports: continue - #do nothing if nports is already num ports - if nports == num_ports: continue - #remove excess ports and connections - if nports < num_ports: - #remove the connections - for key in map(str, range(nports, num_ports)): - port = ports[key] - for connection in port.get_connections(): - self.get_parent().remove_element(connection) - #remove the ports - for key in map(str, range(nports, num_ports)): ports.pop(key) - continue - #add more ports - if nports > num_ports: - for key in map(str, range(num_ports, nports)): - n = port0._n - n['key'] = key - port = Port(self, n) - ports[key] = port - continue - - def port_controller_modify(self, direction): - """ - Change the port controller. - @param direction +1 or -1 - @return true for change - """ - changed = False - #concat the nports string from the private nports settings of both port0 - nports_str = \ - (self.get_sinks() and self.get_sinks()[0]._nports or '') + \ - (self.get_sources() and self.get_sources()[0]._nports or '') - #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.evaluate() - value = value + direction - assert 0 < value - param.set_value(value) - changed = True - except: pass - return changed - - def get_doc(self): - doc = self._doc.strip('\n').replace('\\\n', '') - #merge custom doc with doxygen docs - return '\n'.join([doc, extract_docs.extract(self.get_key())]).strip('\n') - - def get_imports(self): - """ - Resolve all import statements. - Split each import statement at newlines. - Combine all import statments into a list. - Filter empty imports. - @return a list of import statements - """ - return filter(lambda i: i, sum(map(lambda i: self.resolve_dependencies(i).split('\n'), self._imports), [])) - - def get_make(self): return self.resolve_dependencies(self._make) - - def get_callbacks(self): - """ - Get a list of function callbacks for this block. - @return a list of strings - """ - return map(lambda c: self.get_id() + '.' + self.resolve_dependencies(c), self._callbacks) diff --git a/grc/src/platforms/python/Connection.py b/grc/src/platforms/python/Connection.py deleted file mode 100644 index f742ff63d..000000000 --- a/grc/src/platforms/python/Connection.py +++ /dev/null @@ -1,34 +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 .. base.Connection import Connection as _Connection - -class Connection(_Connection): - - def validate(self): - """ - Validate the connections. - The ports must match in type and vector length. - """ - _Connection.validate(self) #checks type - #check vector length - source_vlen = self.get_source().get_vlen() - sink_vlen = self.get_sink().get_vlen() - try: assert(source_vlen == sink_vlen) - except AssertionError: self._add_error_message('Source vector length "%s" does not match sink vector length "%s".'%(source_vlen, sink_vlen)) diff --git a/grc/src/platforms/python/Constants.py.in b/grc/src/platforms/python/Constants.py.in deleted file mode 100644 index 4a43147fa..000000000 --- a/grc/src/platforms/python/Constants.py.in +++ /dev/null @@ -1,54 +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 -""" - -import os -import sys -import stat -from .. base.Constants import PKG_DIR - -PYEXEC = '@PYTHONW@' - -#setup paths -DOCS_DIR = os.path.join(os.environ.get('GR_DOCDIR', '@docdir@'), 'xml') -DATA_DIR = os.path.join(PKG_DIR, '@reldatadir@') -BLOCKS_DIR = os.path.join(PKG_DIR, '@relblocksdir@') -HIER_BLOCKS_LIB_DIR = os.path.join(os.path.expanduser('~'), '.grc_gnuradio') - -#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 -FLOW_GRAPH_TEMPLATE = os.path.join(DATA_DIR, 'flow_graph.tmpl') -BLOCK_DTD = os.path.join(DATA_DIR, 'block.dtd') -BLOCK_TREE = os.path.join(DATA_DIR, 'block_tree.xml') -DEFAULT_FLOW_GRAPH = os.path.join(DATA_DIR, 'default_flow_graph.grc') - -#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' diff --git a/grc/src/platforms/python/FlowGraph.py b/grc/src/platforms/python/FlowGraph.py deleted file mode 100644 index d0b997a58..000000000 --- a/grc/src/platforms/python/FlowGraph.py +++ /dev/null @@ -1,162 +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 -""" - -from utils import expr_utils -from .. base.FlowGraph import FlowGraph as _FlowGraph -from Block import Block -from Connection import Connection - -def _get_value_expr(variable_block): - """ - Get the expression to evaluate from the value param. - Parameter blocks need to be evaluated so the stringify flag can be determined. - @param variable_block the variable or parameter block - @return the expression string - """ - value_param = variable_block.get_param('value') - if variable_block.get_key() == 'parameter': value_param.evaluate() - return value_param.to_code() - -class FlowGraph(_FlowGraph): - - _eval_cache = dict() - def _eval(self, code, namespace): - """ - Evaluate the code with the given namespace. - @param code a string with python code - @param namespace a dict representing the namespace - @return the resultant object - """ - my_hash = hash(code + str(namespace)) - #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_io_signature(self, pad_key): - """ - Get an io signature for this flow graph. - The pad key determines the directionality of the io signature. - @param pad_key a string of pad_source or pad_sink - @return a dict with: type, nports, vlen, size - """ - pads = filter(lambda b: b.get_key() == pad_key, self.get_enabled_blocks()) - if not pads: return { - 'nports': '0', - 'type': '', - 'vlen': '0', - 'size': '0', - } - pad = pads[0] #take only the first, user should not have more than 1 - #load io signature - return { - 'nports': str(pad.get_param('nports').evaluate()), - 'type': str(pad.get_param('type').evaluate()), - 'vlen': str(pad.get_param('vlen').evaluate()), - 'size': pad.get_param('type').get_opt('size'), - } - - def get_input_signature(self): - """ - Get the io signature for the input side of this flow graph. - The io signature with be "0", "0" if no pad source is present. - @return a string tuple of type, num_ports, port_size - """ - return self._get_io_signature('pad_source') - - def get_output_signature(self): - """ - Get the io signature for the output side of this flow graph. - The io signature with be "0", "0" if no pad sink is present. - @return a string tuple of type, num_ports, port_size - """ - return self._get_io_signature('pad_sink') - - def get_imports(self): - """ - Get a set of all import statments in this flow graph namespace. - @return 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. - @return a sorted list of variable blocks in order of dependency (indep -> dep) - """ - variables = filter(lambda b: b.get_key() in ( - 'variable', 'variable_slider', 'variable_chooser', 'variable_text_box' - ), self.get_enabled_blocks()) - #map var id to variable block - id2var = dict([(var.get_id(), var) for var in variables]) - #map var id to variable code - #variable code is a concatenation of all param code (without the id param) - id2expr = dict([(var.get_id(), var.get_param('value').get_value()) for var in variables]) - #sort according to dependency - sorted_ids = expr_utils.sort_variables(id2expr) - #create list of sorted variable blocks - variables = [id2var[id] for id in sorted_ids] - return variables - - def get_parameters(self): - """ - Get a list of all paramterized variables in this flow graph namespace. - @return a list of paramterized variables - """ - parameters = filter(lambda b: b.get_key() == 'parameter', self.get_enabled_blocks()) - return parameters - - def evaluate(self, expr): - """ - Evaluate the expression. - @param expr the string expression - @throw Exception bad expression - @return the evaluated data - """ - if self.is_flagged(): - self.deflag() - #reload namespace - n = dict() - #load imports - for imp in self.get_imports(): - try: exec imp in n - except: pass - #load parameters - np = dict() - for parameter in self.get_parameters(): - try: - e = self._eval(_get_value_expr(parameter), n) - np[parameter.get_id()] = e - except: pass - n.update(np) #merge param namespace - #load variables - for variable in self.get_variables(): - try: - e = self._eval(_get_value_expr(variable), n) - n[variable.get_id()] = e - except: pass - #make namespace public - self.n = n - #evaluate - e = self._eval(expr, self.n) - return e diff --git a/grc/src/platforms/python/Generator.py b/grc/src/platforms/python/Generator.py deleted file mode 100644 index 93321404a..000000000 --- a/grc/src/platforms/python/Generator.py +++ /dev/null @@ -1,142 +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 -""" - -import os -import subprocess -from Cheetah.Template import Template -from utils import expr_utils -from Constants import \ - TOP_BLOCK_FILE_MODE, HIER_BLOCK_FILE_MODE, \ - HIER_BLOCKS_LIB_DIR, PYEXEC, \ - FLOW_GRAPH_TEMPLATE -from utils import convert_hier -from ... gui import Messages - -class Generator(object): - - def __init__(self, flow_graph, file_path): - """ - Initialize the generator object. - Determine the file to generate. - @param flow_graph the flow graph object - @param file_path the path to write the file to - """ - self._flow_graph = flow_graph - self._generate_options = self._flow_graph.get_option('generate_options') - if self._generate_options == 'hb': - self._mode = HIER_BLOCK_FILE_MODE - dirname = HIER_BLOCKS_LIB_DIR - else: - self._mode = TOP_BLOCK_FILE_MODE - dirname = os.path.dirname(file_path) - 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): - #do throttle warning - all_keys = ' '.join(map(lambda b: b.get_key(), self._flow_graph.get_enabled_blocks())) - if ('usrp' not in all_keys) and ('audio' not in all_keys) and ('throttle' not in all_keys) and self._generate_options != 'hb': - Messages.send_warning('''\ -This flow graph may not have flow control: no audio or usrp blocks found. \ -Add a Misc->Throttle block to your flow graph to avoid CPU congestion.''') - #generate - open(self.get_file_path(), 'w').write(str(self)) - if self._generate_options == 'hb': - #convert hier block to xml wrapper - convert_hier.convert_hier(self._flow_graph, self.get_file_path()) - os.chmod(self.get_file_path(), self._mode) - - def get_popen(self): - """ - Execute this python flow graph. - @return a popen object - """ - #execute - cmds = [PYEXEC, '-u', self.get_file_path()] #-u is unbuffered stdio - if self._generate_options == 'no_gui': - cmds = ['xterm', '-e'] + cmds - p = subprocess.Popen(args=cmds, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False, universal_newlines=True) - return p - - def __str__(self): - """ - Convert the flow graph to python code. - @return a string of python code - """ - imports = self._flow_graph.get_imports() - variables = self._flow_graph.get_variables() - parameters = self._flow_graph.get_parameters() - #list of variables with controls - controls = filter(lambda v: v.get_key().startswith('variable_'), variables) - #list of blocks not including variables and imports and parameters and disabled - blocks = sorted(self._flow_graph.get_enabled_blocks(), lambda x, y: cmp(x.get_id(), y.get_id())) - probes = filter(lambda b: b.get_key().startswith('probe_'), blocks) #ensure probes are last in the block list - blocks = filter(lambda b: b not in (imports + parameters + variables + probes), blocks) + probes - #list of connections where each endpoint is enabled - connections = self._flow_graph.get_enabled_connections() - #list of variable names - var_ids = [var.get_id() for var in parameters + variables] - #list of callbacks (prepend self.) - callbacks = [ - expr_utils.expr_prepend(cb, var_ids, 'self.') - for cb in sum([block.get_callbacks() for block in self._flow_graph.get_enabled_blocks()], []) - ] - #map var id to the expression (prepend self.) - var_id2expr = dict( - [(var.get_id(), expr_utils.expr_prepend(var.get_make().split('\n')[0], var_ids, 'self.')) - for var in parameters + variables] - ) - #create graph structure for variables - variable_graph = expr_utils.get_graph(var_id2expr) - #map var id to direct dependents - #for each var id, make a list of all 2nd order edges - #use all edges of that id that are not also 2nd order edges - #meaning: list variables the ONLY depend directly on this variable - #and not variables that also depend indirectly on this variable - var_id2deps = dict( - [(var_id, filter(lambda e: e not in sum([list(variable_graph.get_edges(edge)) - for edge in variable_graph.get_edges(var_id)], []), variable_graph.get_edges(var_id) - ) - ) - for var_id in var_ids] - ) - #map var id to callbacks - var_id2cbs = dict( - [(var_id, filter(lambda c: var_id in expr_utils.expr_split(c), callbacks)) - for var_id in var_ids] - ) - #load the namespace - namespace = { - 'imports': imports, - 'flow_graph': self._flow_graph, - 'variables': variables, - 'controls': controls, - 'parameters': parameters, - 'blocks': blocks, - 'connections': connections, - 'generate_options': self._generate_options, - 'var_id2expr': var_id2expr, - 'var_id2deps': var_id2deps, - 'var_id2cbs': var_id2cbs, - } - #build the template - t = Template(open(FLOW_GRAPH_TEMPLATE, 'r').read(), namespace) - return str(t) diff --git a/grc/src/platforms/python/Makefile.am b/grc/src/platforms/python/Makefile.am deleted file mode 100644 index c23d14792..000000000 --- a/grc/src/platforms/python/Makefile.am +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright 2008,2009 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. -# - -include $(top_srcdir)/grc/Makefile.inc - -SUBDIRS = utils - -ourpythondir = $(grc_src_prefix)/platforms/python - -ourpython_PYTHON = \ - Block.py \ - Connection.py \ - Constants.py \ - FlowGraph.py \ - Generator.py \ - Param.py \ - Platform.py \ - Port.py \ - __init__.py - -Constants.py: $(srcdir)/Constants.py.in Makefile - sed \ - -e 's|@PYTHONW[@]|$(PYTHONW)|g' \ - -e 's|@reldatadir[@]|$(grc_python_data_reldir)|g' \ - -e 's|@relblocksdir[@]|$(grc_blocks_data_reldir)|g' \ - -e 's|@docdir[@]|$(gr_docdir)|g' \ - $< > $@ - -EXTRA_DIST = $(srcdir)/Constants.py.in -BUILT_SOURCES = Constants.py diff --git a/grc/src/platforms/python/Param.py b/grc/src/platforms/python/Param.py deleted file mode 100644 index e5ac1dcf6..000000000 --- a/grc/src/platforms/python/Param.py +++ /dev/null @@ -1,402 +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 -""" - -from utils import expr_utils -from .. base.Param import Param as _Param, EntryParam -import Constants -import numpy -import os -import pygtk -pygtk.require('2.0') -import gtk -from gnuradio import eng_notation - -class FileParam(EntryParam): - """Provide an entry box for filename and a button to browse for a file.""" - - def __init__(self, *args, **kwargs): - EntryParam.__init__(self, *args, **kwargs) - input = gtk.Button('...') - input.connect('clicked', self._handle_clicked) - self.pack_start(input, False) - - def _handle_clicked(self, widget=None): - """ - If the button was clicked, open a file dialog in open/save format. - Replace the text in the entry with the new filename from the file dialog. - """ - #get the paths - file_path = self.param.is_valid() and self.param.evaluate() or '' - (dirname, basename) = os.path.isfile(file_path) and os.path.split(file_path) or (file_path, '') - if not os.path.exists(dirname): dirname = os.getcwd() #fix bad paths - #build the dialog - if self.param.get_type() == 'file_open': - file_dialog = gtk.FileChooserDialog('Open a Data File...', None, - gtk.FILE_CHOOSER_ACTION_OPEN, ('gtk-cancel',gtk.RESPONSE_CANCEL,'gtk-open',gtk.RESPONSE_OK)) - elif self.param.get_type() == 'file_save': - file_dialog = gtk.FileChooserDialog('Save a Data File...', None, - gtk.FILE_CHOOSER_ACTION_SAVE, ('gtk-cancel',gtk.RESPONSE_CANCEL, 'gtk-save',gtk.RESPONSE_OK)) - file_dialog.set_do_overwrite_confirmation(True) - file_dialog.set_current_name(basename) #show the current filename - file_dialog.set_current_folder(dirname) #current directory - file_dialog.set_select_multiple(False) - file_dialog.set_local_only(True) - if gtk.RESPONSE_OK == file_dialog.run(): #run the dialog - file_path = file_dialog.get_filename() #get the file path - self.entry.set_text(file_path) - self._handle_changed() - file_dialog.destroy() #destroy the dialog - -#blacklist certain ids, its not complete, but should help -import __builtin__ -ID_BLACKLIST = ['options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 'forms', 'firdes'] + dir(__builtin__) -#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) - -class Param(_Param): - - _init = False - _hostage_cells = list() - - ##possible param types - TYPES = _Param.TYPES + [ - 'complex', 'real', 'int', - 'complex_vector', 'real_vector', 'int_vector', - 'hex', 'string', - 'file_open', 'file_save', - 'id', - 'grid_pos', 'import', - ] - - def __repr__(self): - """ - Get the repr (nice string format) for this param. - @return the string representation - """ - if self.get_value() in self.get_option_keys(): return self.get_option(self.get_value()).get_name() - ################################################## - # display logic for numbers - ################################################## - def num_to_str(num): - 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) - ################################################## - # split up formatting by type - ################################################## - truncate = 0 #default center truncate - max_len = max(27 - len(self.get_name()), 3) - e = self.evaluate() - t = self.get_type() - if 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 - ################################################## - # truncate - ################################################## - if len(dt_str) > max_len: - if truncate < 0: #front truncate - dt_str = '...' + dt_str[3-max_len:] - elif truncate == 0: #center truncate - dt_str = dt_str[:max_len/2 -3] + '...' + dt_str[-max_len/2:] - elif truncate > 0: #rear truncate - dt_str = dt_str[:max_len-3] + '...' - return dt_str - - def get_input_class(self): - if self.get_type() in ('file_open', 'file_save'): return FileParam - return _Param.get_input_class(self) - - def get_color(self): - """ - Get the color that represents this param's type. - @return a hex color code. - """ - try: - return { - #number types - 'complex': Constants.COMPLEX_COLOR_SPEC, - 'real': 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, - 'int_vector': Constants.INT_VECTOR_COLOR_SPEC, - #special - 'hex': Constants.INT_COLOR_SPEC, - 'string': Constants.BYTE_VECTOR_COLOR_SPEC, - 'id': Constants.ID_COLOR_SPEC, - 'grid_pos': Constants.INT_VECTOR_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. - @return 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 self.get_parent().get_key() not in ( - 'variable', 'variable_slider', 'variable_chooser', 'variable_text_box', 'parameter', 'options' - ): 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: - assert int(self.evaluate()) == 1 - return 'part' - except: pass - #hide empty grid positions - if self.get_key() == 'grid_pos' and not self.get_value(): return 'part' - return hide - - def evaluate(self): - """ - Evaluate the value. - @return evaluated type - """ - self._lisitify_flag = False - self._stringify_flag = False - self._hostage_cells = list() - def eval_string(v): - try: - e = self.get_parent().get_parent().evaluate(v) - assert isinstance(e, str) - return e - except: - self._stringify_flag = True - return v - t = self.get_type() - v = self.get_value() - ######################### - # Enum Type - ######################### - if self.is_enum(): return v - ######################### - # Numeric Types - ######################### - elif t in ('raw', 'complex', 'real', 'int', 'complex_vector', 'real_vector', 'int_vector', 'hex'): - #raise exception if python cannot evaluate this value - try: e = self.get_parent().get_parent().evaluate(v) - except Exception, e: - self._add_error_message('Value "%s" cannot be evaluated: %s'%(v, e)) - raise Exception - #raise an exception if the data is invalid - if t == 'raw': return e - elif t == 'complex': - try: assert(isinstance(e, COMPLEX_TYPES)) - except AssertionError: - self._add_error_message('Expression "%s" is invalid for type complex.'%str(e)) - raise Exception - return e - elif t == 'real': - try: assert(isinstance(e, REAL_TYPES)) - except AssertionError: - self._add_error_message('Expression "%s" is invalid for type real.'%str(e)) - raise Exception - return e - elif t == 'int': - try: assert(isinstance(e, INT_TYPES)) - except AssertionError: - self._add_error_message('Expression "%s" is invalid for type integer.'%str(e)) - raise Exception - return e - ######################### - # Numeric Vector Types - ######################### - elif t == 'complex_vector': - if not isinstance(e, VECTOR_TYPES): - self._lisitify_flag = True - e = [e] - try: - for ei in e: - assert(isinstance(ei, COMPLEX_TYPES)) - except AssertionError: - self._add_error_message('Expression "%s" is invalid for type complex vector.'%str(e)) - raise Exception - return e - elif t == 'real_vector': - if not isinstance(e, VECTOR_TYPES): - self._lisitify_flag = True - e = [e] - try: - for ei in e: - assert(isinstance(ei, REAL_TYPES)) - except AssertionError: - self._add_error_message('Expression "%s" is invalid for type real vector.'%str(e)) - raise Exception - return e - elif t == 'int_vector': - if not isinstance(e, VECTOR_TYPES): - self._lisitify_flag = True - e = [e] - try: - for ei in e: - assert(isinstance(ei, INT_TYPES)) - except AssertionError: - self._add_error_message('Expression "%s" is invalid for type integer vector.'%str(e)) - raise Exception - return e - elif t == 'hex': - return hex(e) - else: raise TypeError, 'Type "%s" not handled'%t - ######################### - # String Types - ######################### - elif t in ('string', 'file_open', 'file_save'): - #do not check if file/directory exists, that is a runtime issue - e = eval_string(v) - return str(e) - ######################### - # Unique ID Type - ######################### - elif t == 'id': - #can python use this as a variable? - try: - assert(len(v) > 0) - assert(v[0].isalpha()) - for c in v: assert(c.isalnum() or c in ('_',)) - except AssertionError: - self._add_error_message('ID "%s" must be alpha-numeric or underscored, and begin with a letter.'%v) - raise Exception - params = self.get_all_params('id') - keys = [param.get_value() for param in params] - try: assert keys.count(v) <= 1 #id should only appear once, or zero times if block is disabled - except: - self._add_error_message('ID "%s" is not unique.'%v) - raise Exception - try: assert v not in ID_BLACKLIST - except: - self._add_error_message('ID "%s" is blacklisted.'%v) - raise Exception - return v - ######################### - # Grid Position Type - ######################### - elif t == 'grid_pos': - if not v: return '' #allow for empty grid pos - e = self.get_parent().get_parent().evaluate(v) - try: - assert(isinstance(e, (list, tuple)) and len(e) == 4) - for ei in e: assert(isinstance(ei, int)) - except AssertionError: - self._add_error_message('A grid position must be a list of 4 integers.') - raise Exception - row, col, row_span, col_span = e - #check row, col - try: assert(row >= 0 and col >= 0) - except AssertionError: - self._add_error_message('Row and column must be non-negative.') - raise Exception - #check row span, col span - try: assert(row_span > 0 and col_span > 0) - except AssertionError: - self._add_error_message('Row and column span must be greater than zero.') - raise Exception - #calculate hostage cells - for r in range(row_span): - for c in range(col_span): - self._hostage_cells.append((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 cell in param._hostage_cells: - if cell in self._hostage_cells: - self._add_error_message('Another graphical element is using cell "%s".'%str(cell)) - raise Exception - return e - ######################### - # Import Type - ######################### - elif t == 'import': - n = dict() #new namespace - try: exec v in n - except ImportError: - self._add_error_message('Import "%s" failed.'%v) - raise Exception - except Exception: - self._add_error_message('Bad import syntax: "%s".'%v) - raise Exception - 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. - @return a string representing the code - """ - #run init tasks in evaluate - #such as setting flags - if not self._init: - self.evaluate() - self._init = True - v = self.get_value() - t = self.get_type() - if t in ('string', 'file_open', 'file_save'): #string types - if self._stringify_flag: - return '"%s"'%v.replace('"', '\"') - else: - return v - elif t in ('complex_vector', 'real_vector', 'int_vector'): #vector types - 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. - @param type the specified type - @return 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/src/platforms/python/Platform.py b/grc/src/platforms/python/Platform.py deleted file mode 100644 index d2bb4627e..000000000 --- a/grc/src/platforms/python/Platform.py +++ /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 -""" - -import os -from .. base.Platform import Platform as _Platform -from FlowGraph import FlowGraph as _FlowGraph -from Connection import Connection as _Connection -from Block import Block as _Block -from Port import Source,Sink -from Param import Param as _Param -from Generator import Generator -from Constants import \ - HIER_BLOCKS_LIB_DIR, BLOCK_DTD, \ - BLOCK_TREE, DEFAULT_FLOW_GRAPH, \ - BLOCKS_DIR - -_critical_blocks_only = map(lambda b: os.path.join(BLOCKS_DIR, b), ['options.xml', 'usrp_probe.xml', 'usrp2_probe.xml']) - -class Platform(_Platform): - - def __init__(self, extra_blocks=[], critical_only=False): - """ - Make a platform for gnuradio. - @param extra_blocks a list of block paths to load in addition to main block library - @param critical_only only load critical blocks (used only for usrp probe scripts to speed up load time) - """ - #ensure hier dir - if not os.path.exists(HIER_BLOCKS_LIB_DIR): os.mkdir(HIER_BLOCKS_LIB_DIR) - if critical_only: block_paths = _critical_blocks_only - else: block_paths = extra_blocks + [HIER_BLOCKS_LIB_DIR, BLOCKS_DIR] - #convert block paths to absolute paths, ensure uniqueness - block_paths = set(map(os.path.abspath, block_paths)) - #init - _Platform.__init__( - self, - name='GRC', - key='grc', - block_paths=block_paths, - block_dtd=BLOCK_DTD, - block_tree=BLOCK_TREE, - default_flow_graph=DEFAULT_FLOW_GRAPH, - generator=Generator, - ) - - ############################################## - # Constructors - ############################################## - FlowGraph = _FlowGraph - Connection = _Connection - Block = _Block - Source = Source - Sink = Sink - Param = _Param diff --git a/grc/src/platforms/python/Port.py b/grc/src/platforms/python/Port.py deleted file mode 100644 index b5bc9696b..000000000 --- a/grc/src/platforms/python/Port.py +++ /dev/null @@ -1,129 +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 -""" - -from .. base.Port import Port as _Port -import Constants - -class Port(_Port): - - ##possible port types - TYPES = ['complex', 'float', 'int', 'short', 'byte'] - - def __init__(self, block, n): - """ - Make a new port from nested data. - @param block the parent element - @param n the nested odict - @return a new port - """ - vlen = n.find('vlen') or '1' - nports = n.find('nports') or '' - optional = n.find('optional') or '' - #build the port - _Port.__init__( - self, - block=block, - n=n, - ) - self._nports = nports - self._vlen = vlen - self._optional = bool(optional) - - def validate(self): - _Port.validate(self) - try: assert(self.get_enabled_connections() or self.get_optional()) - except AssertionError: self._add_error_message('Port is not connected.') - try: assert(self.is_source() or len(self.get_enabled_connections()) <= 1) - except AssertionError: self._add_error_message('Port has too many connections.') - - def get_vlen(self): - """ - Get the vector length. - If the evaluation of vlen cannot be cast to an integer, return 1. - @return 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 an integer, return 1. - @return the number of ports or 1 - """ - nports = self.get_parent().resolve_dependencies(self._nports) - #return blank if nports is blank - if not nports: return '' - try: - nports = int(self.get_parent().get_parent().evaluate(nports)) - assert 0 < nports - return 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. - @return a hex color code. - """ - try: - if self.get_vlen() == 1: - return {#vlen is 1 - 'complex': Constants.COMPLEX_COLOR_SPEC, - 'float': Constants.FLOAT_COLOR_SPEC, - 'int': Constants.INT_COLOR_SPEC, - 'short': Constants.SHORT_COLOR_SPEC, - 'byte': Constants.BYTE_COLOR_SPEC, - }[self.get_type()] - return {#vlen is non 1 - 'complex': Constants.COMPLEX_VECTOR_COLOR_SPEC, - 'float': Constants.FLOAT_VECTOR_COLOR_SPEC, - 'int': Constants.INT_VECTOR_COLOR_SPEC, - 'short': Constants.SHORT_VECTOR_COLOR_SPEC, - 'byte': Constants.BYTE_VECTOR_COLOR_SPEC, - }[self.get_type()] - except: return _Port.get_color(self) - -class Source(Port): - - def __init__(self, block, n): - self._n = n #save n - #key is port index - n['key'] = str(block._source_count) - block._source_count = block._source_count + 1 - Port.__init__(self, block, n) - - def __del__(self): - self.get_parent()._source_count = self.get_parent()._source_count - 1 - -class Sink(Port): - - def __init__(self, block, n): - self._n = n #save n - #key is port index - n['key'] = str(block._sink_count) - block._sink_count = block._sink_count + 1 - Port.__init__(self, block, n) - - def __del__(self): - self.get_parent()._sink_count = self.get_parent()._sink_count - 1 diff --git a/grc/src/platforms/python/__init__.py b/grc/src/platforms/python/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/grc/src/platforms/python/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/grc/src/platforms/python/utils/Makefile.am b/grc/src/platforms/python/utils/Makefile.am deleted file mode 100644 index b12e51d8e..000000000 --- a/grc/src/platforms/python/utils/Makefile.am +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright 2008 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. -# - -include $(top_srcdir)/grc/Makefile.inc - -ourpythondir = $(grc_src_prefix)/platforms/python/utils - -ourpython_PYTHON = \ - convert_hier.py \ - expr_utils.py \ - extract_docs.py \ - __init__.py diff --git a/grc/src/platforms/python/utils/__init__.py b/grc/src/platforms/python/utils/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/grc/src/platforms/python/utils/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/grc/src/platforms/python/utils/convert_hier.py b/grc/src/platforms/python/utils/convert_hier.py deleted file mode 100644 index 495358984..000000000 --- a/grc/src/platforms/python/utils/convert_hier.py +++ /dev/null @@ -1,78 +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 .. Constants import BLOCK_DTD -from .... utils import ParseXML -from .... utils import odict - -def convert_hier(flow_graph, python_file): - #extract info from the flow graph - input_sig = flow_graph.get_input_signature() - output_sig = flow_graph.get_output_signature() - parameters = flow_graph.get_parameters() - block_key = flow_graph.get_option('id') - block_name = flow_graph.get_option('title') - block_category = flow_graph.get_option('category') - block_desc = flow_graph.get_option('description') - block_author = flow_graph.get_option('author') - #build the nested data - block_n = odict() - block_n['name'] = block_name - block_n['key'] = block_key - block_n['category'] = block_category - block_n['import'] = 'execfile("%s")'%python_file - #make data - block_n['make'] = '%s(\n\t%s,\n)'%( - block_key, - ',\n\t'.join(['%s=$%s'%(param.get_id(), param.get_id()) for param in parameters]), - ) - #callback data - block_n['callback'] = ['set_%s($%s)'%(param.get_id(), param.get_id()) for param in parameters] - #param data - params_n = 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' - params_n.append(param_n) - block_n['param'] = params_n - #sink data - if int(input_sig['nports']): - sink_n = odict() - sink_n['name'] = 'in' - sink_n['type'] = input_sig['type'] - sink_n['vlen'] = input_sig['vlen'] - sink_n['nports'] = input_sig['nports'] - block_n['sink'] = sink_n - #source data - if int(output_sig['nports']): - source_n = odict() - source_n['name'] = 'out' - source_n['type'] = output_sig['type'] - source_n['vlen'] = output_sig['vlen'] - source_n['nports'] = output_sig['nports'] - block_n['source'] = source_n - #doc data - block_n['doc'] = "%s\n%s\n%s"%(block_author, block_desc, python_file) - #write the block_n to file - xml_file = python_file + '.xml' - ParseXML.to_file({'block': block_n}, xml_file) - ParseXML.validate_dtd(xml_file, BLOCK_DTD) diff --git a/grc/src/platforms/python/utils/expr_utils.py b/grc/src/platforms/python/utils/expr_utils.py deleted file mode 100644 index 40700993d..000000000 --- a/grc/src/platforms/python/utils/expr_utils.py +++ /dev/null @@ -1,137 +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 -""" - -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. - @param expr an expression string - @return 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_prepend(expr, vars, prepend): - """ - Search for vars in the expression and add the prepend. - @param expr an expression string - @param vars a list of variable names - @param prepend the prepend string - @return a new expression with the prepend - """ - expr_splits = expr_split(expr) - for i, es in enumerate(expr_splits): - if es in vars: expr_splits[i] = prepend + es - return ''.join(expr_splits) - -def get_variable_dependencies(expr, vars): - """ - Return a set of variables used in this expression. - @param expr an expression string - @param vars a list of variable names - @return 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 - @param exprs a mapping of variable name to expression - @return 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): - var_graph.add_edge(dep, var) - return var_graph - -def sort_variables(exprs): - """ - Get a list of variables in order of dependencies. - @param exprs a mapping of variable name to expression - @return a list of variable names - @throws AssertionError 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()) - assert indep_vars - #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) - -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/src/platforms/python/utils/extract_docs.py b/grc/src/platforms/python/utils/extract_docs.py deleted file mode 100644 index 523519f97..000000000 --- a/grc/src/platforms/python/utils/extract_docs.py +++ /dev/null @@ -1,92 +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 -""" - -from .. Constants import DOCS_DIR -from lxml import etree -import os -import re - -DOXYGEN_NAME_XPATH = '/doxygen/compounddef/compoundname' -DOXYGEN_BRIEFDESC_GR_XPATH = '/doxygen/compounddef/briefdescription' -DOXYGEN_DETAILDESC_GR_XPATH = '/doxygen/compounddef/detaileddescription' - -def extract_txt(xml): - """ - Recursivly pull the text out of an xml tree. - @param xml the xml tree - @return a string - """ - text = (xml.text or '').replace('\n', '') - tail = (xml.tail or '').replace('\n', '') - if xml.tag == 'para': tail += '\n\n' - if xml.tag == 'linebreak': text += '\n' - if xml.tag == 'parametername': text += ': ' - return text + ''.join( - map(lambda x: extract_txt(x), xml) - ) + tail - -def _extract(key): - """ - Extract the documentation from the doxygen generated xml files. - If multiple files match, combine the docs. - @param key the block key - @return a string with documentation - """ - UBUNTU_DOCS_DIR = '/usr/share/doc/gnuradio-doc/xml' - if os.path.exists(DOCS_DIR): docs_dir = DOCS_DIR - elif os.path.exists(UBUNTU_DOCS_DIR): docs_dir = UBUNTU_DOCS_DIR - else: return '' - #extract matches - pattern = key.replace('_', '_*').replace('x', '\w') - prog = re.compile('^class%s\..*$'%pattern) - matches = filter(lambda f: prog.match(f), os.listdir(docs_dir)) - #combine all matches - doc_strs = list() - for match in matches: - try: - xml_file = os.path.join(docs_dir, match) - xml = etree.parse(xml_file) - #extract descriptions - comp_name = extract_txt(xml.xpath(DOXYGEN_NAME_XPATH)[0]).strip() - comp_name = ' --- ' + comp_name + ' --- ' - if re.match('(gr|usrp2|trellis)_.*', key): - brief_desc = extract_txt(xml.xpath(DOXYGEN_BRIEFDESC_GR_XPATH)[0]).strip() - detailed_desc = extract_txt(xml.xpath(DOXYGEN_DETAILDESC_GR_XPATH)[0]).strip() - else: - brief_desc = '' - detailed_desc = '' - #combine - doc_strs.append('\n\n'.join([comp_name, brief_desc, detailed_desc]).strip()) - except IndexError: pass #bad format - return '\n\n'.join(doc_strs) - -_docs_cache = dict() -def extract(key): - """ - Call the private extract and cache the result. - @param key the block key - @return a string with documentation - """ - try: assert _docs_cache.has_key(key) - except: _docs_cache[key] = _extract(key) - return _docs_cache[key] - -if __name__ == '__main__': - import sys - print extract(sys.argv[1]) |