diff options
Diffstat (limited to 'grc')
-rw-r--r-- | grc/CMakeLists.txt | 7 | ||||
-rw-r--r-- | grc/core/FlowGraph.py | 7 | ||||
-rw-r--r-- | grc/core/ParseXML.py | 185 | ||||
-rw-r--r-- | grc/gui/Application.py | 228 |
4 files changed, 121 insertions, 306 deletions
diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index 77c8d4c00d..9e5341bc17 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -45,12 +45,6 @@ GR_PYTHON_CHECK_MODULE_RAW( ) GR_PYTHON_CHECK_MODULE_RAW( - "lxml >= 1.3.6" - "import lxml.etree; assert lxml.etree.LXML_VERSION >= (1, 3, 6, 0)" - LXML_FOUND -) - -GR_PYTHON_CHECK_MODULE_RAW( "pygobject >= 2.28.6" "import gi; assert gi.version_info >= (2, 28, 6)" PYGI_FOUND @@ -90,7 +84,6 @@ if(NOT CMAKE_CROSSCOMPILING) PYTHON_MIN_VER_FOUND PYYAML_FOUND MAKO_FOUND - LXML_FOUND PYGI_FOUND GTK_GI_FOUND CAIRO_GI_FOUND diff --git a/grc/core/FlowGraph.py b/grc/core/FlowGraph.py index 6786bbee30..bf26225e48 100644 --- a/grc/core/FlowGraph.py +++ b/grc/core/FlowGraph.py @@ -191,8 +191,13 @@ class FlowGraph(Element): for expr in self.imports(): try: exec(expr, namespace) + except ImportError: + # We do not have a good way right now to determine if an import is for a + # hier block, these imports will fail as they are not in the search path + # this is ok behavior, unfortunately we could be hiding other import bugs + pass except Exception: - log.exception('Failed to evaluate expression in namespace', exc_info=True) + log.exception('Failed to evaluate import expression "{0}"'.format(expr), exc_info=True) pass for id, expr in self.get_python_modules(): diff --git a/grc/core/ParseXML.py b/grc/core/ParseXML.py deleted file mode 100644 index 430ba5b474..0000000000 --- a/grc/core/ParseXML.py +++ /dev/null @@ -1,185 +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 -""" - -from __future__ import absolute_import - -from lxml import etree - -import six -from six.moves import map - - -xml_failures = {} -etree.set_default_parser(etree.XMLParser(remove_comments=True)) - - -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) - - tag, nested_data = _from_file(xml.getroot()) - nested_data = {tag: nested_data, '_instructions': {}} - - # Get the embedded instructions and build a dictionary item - xml_instructions = xml.xpath('/processing-instruction()') - for inst in xml_instructions: - if inst.target != 'grc': - continue - nested_data['_instructions'] = dict(inst.attrib) - return nested_data - - -WANT_A_LIST = { - '/block': 'import callback param check sink source'.split(), - '/block/param_tab_order': 'tab'.split(), - '/block/param': 'option'.split(), - '/block/param/option': 'opt'.split(), - '/flow_graph': 'block connection'.split(), - '/flow_graph/block': 'param'.split(), - '/cat': 'cat block'.split(), - '/cat/cat': 'cat block'.split(), - '/cat/cat/cat': 'cat block'.split(), - '/cat/cat/cat/cat': 'cat block'.split(), - '/domain': 'connection'.split(), -} - - -def _from_file(xml, parent_tag=''): - """ - Recursively parse the xml tree into nested data format. - - Args: - xml: the xml tree - - Returns: - the nested data - """ - tag = xml.tag - tag_path = parent_tag + '/' + tag - - if not len(xml): - return tag, xml.text or '' # store empty tags (text is None) as empty string - - nested_data = {} - for elem in xml: - key, value = _from_file(elem, tag_path) - - if key in WANT_A_LIST.get(tag_path, []): - try: - nested_data[key].append(value) - except KeyError: - nested_data[key] = [value] - else: - nested_data[key] = value - - return 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) - # Create the processing instruction from the array - if instructions: - xml_data += etree.tostring(etree.ProcessingInstruction( - 'grc', ' '.join( - "{0}='{1}'".format(*item) for item in six.iteritems(instructions)) - ), 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, 'wb') 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 six.iteritems(nested_data): - # 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, six.text_type)): - node.text = six.text_type(value) - else: - node.extend(_to_file(value)) - nodes.append(node) - return nodes diff --git a/grc/gui/Application.py b/grc/gui/Application.py index 2a42a0b345..698f1f109d 100644 --- a/grc/gui/Application.py +++ b/grc/gui/Application.py @@ -213,10 +213,6 @@ class Application(Gtk.Application): main.update_panel_visibility(main.CONSOLE, Actions.TOGGLE_CONSOLE_WINDOW.get_active()) main.update_panel_visibility(main.VARIABLES, Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR.get_active()) - #if ParseXML.xml_failures: - # Messages.send_xml_errors_if_any(ParseXML.xml_failures) - # Actions.XML_PARSER_ERRORS_DISPLAY.set_enabled(True) - # Force an update on the current page to match loaded preferences. # In the future, change the __init__ order to load preferences first page = main.current_page @@ -264,132 +260,141 @@ class Application(Gtk.Application): flow_graph_update() page.state_cache.save_new_state(flow_graph.export_data()) page.saved = False - ################################################## - # Create heir block - ################################################## + ################################################## + # Create hier block + ################################################## elif action == Actions.BLOCK_CREATE_HIER: - # keeping track of coordinates for pasting later - coords = flow_graph.selected_blocks()[0].coordinate - x,y = coords - x_min = x - y_min = y - - pads = []; - params = []; - - # Save the state of the leaf blocks - for block in flow_graph.selected_blocks(): - - # Check for string variables within the blocks - for param in block.params.values(): - for variable in flow_graph.get_variables(): - # If a block parameter exists that is a variable, create a parameter for it - if param.get_value() == variable.name: - params.append(param.get_value()) - for flow_param in flow_graph.get_parameters(): - # If a block parameter exists that is a parameter, create a parameter for it - if param.get_value() == flow_param.name: - params.append(param.get_value()) - - - # keep track of x,y mins for pasting later - (x,y) = block.coordinate - if x < x_min: - x_min = x - if y < y_min: - y_min = y - - for connection in block.connections: - - # Get id of connected blocks - source_id = connection.source_block.name - sink_id = connection.sink_block.name - - # If connected block is not in the list of selected blocks create a pad for it - if flow_graph.get_block(source_id) not in flow_graph.selected_blocks(): - pads.append({'key': connection.sink_port.key, 'coord': connection.source_port.coordinate, 'block_id' : block.name, 'direction': 'source'}) - - if flow_graph.get_block(sink_id) not in flow_graph.selected_blocks(): - pads.append({'key': connection.source_port.key, 'coord': connection.sink_port.coordinate, 'block_id' : block.name, 'direction': 'sink'}) - - - # Copy the selected blocks and paste them into a new page - # then move the flowgraph to a reasonable position - Actions.BLOCK_COPY() - main.new_page() - Actions.BLOCK_PASTE() - coords = (x_min,y_min) - flow_graph.move_selected(coords) + # keeping track of coordinates for pasting later + coords = flow_graph.selected_blocks()[0].coordinate + x,y = coords + x_min = x + y_min = y + + pads = [] + params = [] + + # Save the state of the leaf blocks + for block in flow_graph.selected_blocks(): + + # Check for string variables within the blocks + for param in block.params.values(): + for variable in flow_graph.get_variables(): + # If a block parameter exists that is a variable, create a parameter for it + if param.get_value() == variable.name: + params.append(param.get_value()) + for flow_param in flow_graph.get_parameters(): + # If a block parameter exists that is a parameter, create a parameter for it + if param.get_value() == flow_param.name: + params.append(param.get_value()) + + # keep track of x,y mins for pasting later + (x,y) = block.coordinate + if x < x_min: + x_min = x + if y < y_min: + y_min = y + + for connection in block.connections: + + # Get id of connected blocks + source_id = connection.source_block.name + sink_id = connection.sink_block.name + + # If connected block is not in the list of selected blocks create a pad for it + if flow_graph.get_block( + source_id) not in flow_graph.selected_blocks(): + pads.append({ + 'key': + connection.sink_port.key, + 'coord': + connection.source_port.coordinate, + 'block_id': + block.name, + 'direction': + 'source' + }) + + if flow_graph.get_block(sink_id) not in flow_graph.selected_blocks(): + pads.append({'key': connection.source_port.key, 'coord': connection.sink_port.coordinate, 'block_id' : block.name, 'direction': 'sink'}) + + + # Copy the selected blocks and paste them into a new page + # then move the flowgraph to a reasonable position + Actions.BLOCK_COPY() + main.new_page() + Actions.BLOCK_PASTE() + coords = (x_min,y_min) + flow_graph.move_selected(coords) - # Set flow graph to heir block type - top_block = flow_graph.get_block("top_block") - top_block.params['generate_options'].set_value('hb') + # Set flow graph to heir block type + top_block = flow_graph.get_block("top_block") + top_block.params['generate_options'].set_value('hb') - # this needs to be a unique name - top_block.params['id'].set_value('new_heir') + # this needs to be a unique name + top_block.params['id'].set_value('new_heir') - # Remove the default samp_rate variable block that is created - remove_me = flow_graph.get_block("samp_rate") - flow_graph.remove_element(remove_me) + # Remove the default samp_rate variable block that is created + remove_me = flow_graph.get_block("samp_rate") + flow_graph.remove_element(remove_me) - # Add the param blocks along the top of the window - x_pos = 150 - for param in params: - param_id = flow_graph.add_new_block('parameter',(x_pos,10)) - param_block = flow_graph.get_block(param_id) - param_block.params['id'].set_value(param) - x_pos = x_pos + 100 + # Add the param blocks along the top of the window + x_pos = 150 + for param in params: + param_id = flow_graph.add_new_block('parameter',(x_pos,10)) + param_block = flow_graph.get_block(param_id) + param_block.params['id'].set_value(param) + x_pos = x_pos + 100 - for pad in pads: - # Add the pad sources and sinks within the new heir block - if pad['direction'] == 'sink': + for pad in pads: + # Add the pad sources and sinks within the new heir block + if pad['direction'] == 'sink': - # Add new PAD_SINK block to the canvas - pad_id = flow_graph.add_new_block('pad_sink', pad['coord']) + # Add new PAD_SINK block to the canvas + pad_id = flow_graph.add_new_block('pad_sink', pad['coord']) - # setup the references to the sink and source - pad_block = flow_graph.get_block(pad_id) - pad_sink = pad_block.sinks[0] + # setup the references to the sink and source + pad_block = flow_graph.get_block(pad_id) + pad_sink = pad_block.sinks[0] - source_block = flow_graph.get_block(pad['block_id']) - source = source_block.get_source(pad['key']) + source_block = flow_graph.get_block(pad['block_id']) + source = source_block.get_source(pad['key']) - # Ensure the port types match - while pad_sink.dtype != source.dtype: + # Ensure the port types match + while pad_sink.dtype != source.dtype: - # Special case for some blocks that have non-standard type names, e.g. uhd - if pad_sink.dtype == 'complex' and source.dtype == 'fc32': - break; - pad_block.type_controller_modify(1) + # Special case for some blocks that have non-standard type names, e.g. uhd + if pad_sink.dtype == 'complex' and source.dtype == 'fc32': + break; + pad_block.type_controller_modify(1) - # Connect the pad to the proper sinks - new_connection = flow_graph.connect(source,pad_sink) + # Connect the pad to the proper sinks + new_connection = flow_graph.connect(source,pad_sink) - elif pad['direction'] == 'source': - pad_id = flow_graph.add_new_block('pad_source', pad['coord']) + elif pad['direction'] == 'source': + pad_id = flow_graph.add_new_block('pad_source', pad['coord']) - # setup the references to the sink and source - pad_block = flow_graph.get_block(pad_id) - pad_source = pad_block.sources[0] + # setup the references to the sink and source + pad_block = flow_graph.get_block(pad_id) + pad_source = pad_block.sources[0] - sink_block = flow_graph.get_block(pad['block_id']) - sink = sink_block.get_sink(pad['key']) + sink_block = flow_graph.get_block(pad['block_id']) + sink = sink_block.get_sink(pad['key']) - # Ensure the port types match - while sink.dtype != pad_source.dtype: - # Special case for some blocks that have non-standard type names, e.g. uhd - if pad_source.dtype == 'complex' and sink.dtype == 'fc32': - break; - pad_block.type_controller_modify(1) + # Ensure the port types match + while sink.dtype != pad_source.dtype: + # Special case for some blocks that have non-standard type names, e.g. uhd + if pad_source.dtype == 'complex' and sink.dtype == 'fc32': + break + pad_block.type_controller_modify(1) - # Connect the pad to the proper sinks - new_connection = flow_graph.connect(pad_source,sink) + # Connect the pad to the proper sinks + new_connection = flow_graph.connect(pad_source, sink) - # update the new heir block flow graph - flow_graph_update() + # update the new heir block flow graph + flow_graph_update() ################################################## @@ -575,7 +580,6 @@ class Application(Gtk.Application): # View Parser Errors ################################################## elif action == Actions.XML_PARSER_ERRORS_DISPLAY: - # ParserErrorsDialog(ParseXML.xml_failures).run() pass ################################################## # Undo/Redo @@ -627,7 +631,7 @@ class Application(Gtk.Application): elif action == Actions.FLOW_GRAPH_OPEN_RECENT: file_path = str(args[0])[1:-1] main.new_page(file_path, show=True) - main.tool_bar.refresh_submenus() + main.tool_bar.refresh_submenus() elif action == Actions.FLOW_GRAPH_SAVE: #read-only or undefined file path, do save-as if page.get_read_only() or not page.file_path: @@ -730,8 +734,6 @@ class Application(Gtk.Application): main.btwin.repopulate() #todo: implement parser error dialog for YAML - #Actions.XML_PARSER_ERRORS_DISPLAY.set_enabled(bool(ParseXML.xml_failures)) - #Messages.send_xml_errors_if_any(ParseXML.xml_failures) # Force a redraw of the graph, by getting the current state and re-importing it main.update_pages() |