summaryrefslogtreecommitdiff
path: root/grc
diff options
context:
space:
mode:
Diffstat (limited to 'grc')
-rw-r--r--grc/CMakeLists.txt7
-rw-r--r--grc/core/FlowGraph.py7
-rw-r--r--grc/core/ParseXML.py185
-rw-r--r--grc/gui/Application.py228
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()