summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gr-qtgui/grc/qtgui_ber_sink_b.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_check_box.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_chooser.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_const_sink_x.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_edit_box_msg.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_entry.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_histogram_sink_x.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_label.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_number_sink.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_push_button.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_range.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_tab_widget.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_time_raster_x.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_time_sink_x.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_vector_sink_f.block.yml2
-rw-r--r--gr-qtgui/grc/qtgui_waterfall_sink_x.block.yml2
-rw-r--r--grc/converter/block.py6
-rw-r--r--grc/core/Param.py166
-rw-r--r--grc/core/blocks/_build.py4
-rw-r--r--grc/core/blocks/block.py19
-rw-r--r--grc/core/generator/flow_graph.py.mako24
-rw-r--r--grc/core/generator/hier_block.py4
-rw-r--r--grc/core/generator/top_block.py12
-rw-r--r--grc/core/schema_checker/block.py2
-rw-r--r--grc/core/utils/hide_bokeh_gui_options_if_not_installed.py7
-rw-r--r--grc/gui/MainWindow.py2
-rw-r--r--grc/gui/Notebook.py2
27 files changed, 192 insertions, 88 deletions
diff --git a/gr-qtgui/grc/qtgui_ber_sink_b.block.yml b/gr-qtgui/grc/qtgui_ber_sink_b.block.yml
index 3060862299..ddf28cf1e5 100644
--- a/gr-qtgui/grc/qtgui_ber_sink_b.block.yml
+++ b/gr-qtgui/grc/qtgui_ber_sink_b.block.yml
@@ -358,7 +358,7 @@ templates:
self.${id}.set_line_alpha(i, alphas[i])
${win} = sip.wrapinstance(self.${id}.pyqwidget(), Qt.QWidget)
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
The GUI hint can be used to position the widget within the application. The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. Both the tab specification and the grid position are optional.
diff --git a/gr-qtgui/grc/qtgui_check_box.block.yml b/gr-qtgui/grc/qtgui_check_box.block.yml
index 3f58b3cc78..dc67237e4f 100644
--- a/gr-qtgui/grc/qtgui_check_box.block.yml
+++ b/gr-qtgui/grc/qtgui_check_box.block.yml
@@ -54,7 +54,7 @@ templates:
self._${id}_callback = lambda i: Qt.QMetaObject.invokeMethod(${win}, "setChecked", Qt.Q_ARG("bool", self._${id}_choices_inv[i]))
self._${id}_callback(self.${id})
${win}.stateChanged.connect(lambda i: self.set_${id}(self._${id}_choices[bool(i)]))
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
This block creates a variable check box. Leave the label blank to use the variable id as the label.
diff --git a/gr-qtgui/grc/qtgui_chooser.block.yml b/gr-qtgui/grc/qtgui_chooser.block.yml
index 12087d8b94..a342beccc0 100644
--- a/gr-qtgui/grc/qtgui_chooser.block.yml
+++ b/gr-qtgui/grc/qtgui_chooser.block.yml
@@ -179,7 +179,7 @@ templates:
self._${id}_button_group.buttonClicked[int].connect(
lambda i: self.set_${id}(self._${id}_options[i]))
% endif
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
This block creates a variable with enumerated options. The gui widget is implemented as a combo box or radio button group. Leave the label blank to use the variable id as the label.
diff --git a/gr-qtgui/grc/qtgui_const_sink_x.block.yml b/gr-qtgui/grc/qtgui_const_sink_x.block.yml
index af6b166df1..1019393d6b 100644
--- a/gr-qtgui/grc/qtgui_const_sink_x.block.yml
+++ b/gr-qtgui/grc/qtgui_const_sink_x.block.yml
@@ -449,7 +449,7 @@ templates:
self.${id}.set_line_alpha(i, alphas[i])
self._${id}_win = sip.wrapinstance(self.${id}.pyqwidget(), Qt.QWidget)
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
The GUI hint can be used to position the widget within the application. The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. Both the tab specification and the grid position are optional.
diff --git a/gr-qtgui/grc/qtgui_edit_box_msg.block.yml b/gr-qtgui/grc/qtgui_edit_box_msg.block.yml
index 37aa0ce071..ac867bfcef 100644
--- a/gr-qtgui/grc/qtgui_edit_box_msg.block.yml
+++ b/gr-qtgui/grc/qtgui_edit_box_msg.block.yml
@@ -61,7 +61,7 @@ templates:
%>\
qtgui.edit_box_msg(${type.t)}, ${value}, ${label}, ${is_pair}, ${is_static}, ${key})
${win} = sip.wrapinstance(self.${id}.pyqwidget(), Qt.QWidget)
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
The GUI hint can be used to position the widget within the application. The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. Both the tab specification and the grid position are optional.
diff --git a/gr-qtgui/grc/qtgui_entry.block.yml b/gr-qtgui/grc/qtgui_entry.block.yml
index 25b7bcf33f..8a430b2874 100644
--- a/gr-qtgui/grc/qtgui_entry.block.yml
+++ b/gr-qtgui/grc/qtgui_entry.block.yml
@@ -47,7 +47,7 @@ templates:
self._${id}_tool_bar.addWidget(self._${id}_line_edit)
self._${id}_line_edit.returnPressed.connect(
lambda: self.set_${id}(${type.conv}(str(self._${id}_line_edit.text().toAscii()))))
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
This block creates a variable with a text entry box. Leave the label blank to use the variable id as the label.
diff --git a/gr-qtgui/grc/qtgui_histogram_sink_x.block.yml b/gr-qtgui/grc/qtgui_histogram_sink_x.block.yml
index e1451144c2..f71c2edb94 100644
--- a/gr-qtgui/grc/qtgui_histogram_sink_x.block.yml
+++ b/gr-qtgui/grc/qtgui_histogram_sink_x.block.yml
@@ -411,7 +411,7 @@ templates:
self.${id}.set_line_alpha(i, alphas[i])
${win} = sip.wrapinstance(self.${id}.pyqwidget(), Qt.QWidget)
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
The GUI hint can be used to position the widget within the application. The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. Both the tab specification and the grid position are optional.
diff --git a/gr-qtgui/grc/qtgui_label.block.yml b/gr-qtgui/grc/qtgui_label.block.yml
index 68a46acb27..e86aa20727 100644
--- a/gr-qtgui/grc/qtgui_label.block.yml
+++ b/gr-qtgui/grc/qtgui_label.block.yml
@@ -56,7 +56,7 @@ templates:
${win}.addWidget(Qt.QLabel(${label}+": "))
self._${id}_label = Qt.QLabel(str(self._${id}_formatter(self.${id})))
self._${id}_tool_bar.addWidget(self._${id}_label)
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
This block creates a variable with a label widget for text. Leave the label blank to use the variable id as the label.
diff --git a/gr-qtgui/grc/qtgui_number_sink.block.yml b/gr-qtgui/grc/qtgui_number_sink.block.yml
index 559958a9ae..05adc13d3c 100644
--- a/gr-qtgui/grc/qtgui_number_sink.block.yml
+++ b/gr-qtgui/grc/qtgui_number_sink.block.yml
@@ -275,7 +275,7 @@ templates:
self.${id}.enable_autoscale(${autoscale})
${win} = sip.wrapinstance(self.${id}.pyqwidget(), Qt.QWidget)
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
The GUI hint can be used to position the widget within the application. The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. Both the tab specification and the grid position are optional.
diff --git a/gr-qtgui/grc/qtgui_push_button.block.yml b/gr-qtgui/grc/qtgui_push_button.block.yml
index 8c62e92f08..20e4593404 100644
--- a/gr-qtgui/grc/qtgui_push_button.block.yml
+++ b/gr-qtgui/grc/qtgui_push_button.block.yml
@@ -48,7 +48,7 @@ templates:
self._${id}_choices = {'Pressed': ${pressed}, 'Released': ${released}}
${win}.pressed.connect(lambda: self.set_${id}(self._${id}_choices['Pressed']))
${win}.released.connect(lambda: self.set_${id}(self._${id}_choices['Released']))
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
This block creates a variable push button. Leave the label blank to use the variable id as the label.
diff --git a/gr-qtgui/grc/qtgui_range.block.yml b/gr-qtgui/grc/qtgui_range.block.yml
index 0c75489533..a4aaa5925c 100644
--- a/gr-qtgui/grc/qtgui_range.block.yml
+++ b/gr-qtgui/grc/qtgui_range.block.yml
@@ -76,7 +76,7 @@ templates:
%>\
${range} = Range(${start}, ${stop}, ${step}, ${value}, ${min_len})
${win} = RangeWidget(${range}, self.set_${id}, ${label}, "${widget}", ${rangeType})
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
This block creates a variable with a slider. Leave the label blank to use the variable id as the label. The value must be a real number. The value must be between the start and the stop.
diff --git a/gr-qtgui/grc/qtgui_tab_widget.block.yml b/gr-qtgui/grc/qtgui_tab_widget.block.yml
index 79cbf70cae..12a902eac2 100644
--- a/gr-qtgui/grc/qtgui_tab_widget.block.yml
+++ b/gr-qtgui/grc/qtgui_tab_widget.block.yml
@@ -131,7 +131,7 @@ templates:
self.${id}_layout_${i}.addLayout(self.${id}_grid_layout_${i})
${win}.addTab(self.${id}_widget_${i}, ${label})
% endfor
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
This block creates a tabbed widget to organize other widgets. The ID of this block can be used as the tab_id in the GUI hints of other widgets.
diff --git a/gr-qtgui/grc/qtgui_time_raster_x.block.yml b/gr-qtgui/grc/qtgui_time_raster_x.block.yml
index 77ae0a4ad1..6ffaf1934a 100644
--- a/gr-qtgui/grc/qtgui_time_raster_x.block.yml
+++ b/gr-qtgui/grc/qtgui_time_raster_x.block.yml
@@ -258,7 +258,7 @@ templates:
self.${id}.set_line_alpha(i, alphas[i])
${win} = sip.wrapinstance(self.${id}.pyqwidget(), Qt.QWidget)
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
The GUI hint can be used to position the widget within the application. The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. Both the tab specification and the grid position are optional.
diff --git a/gr-qtgui/grc/qtgui_time_sink_x.block.yml b/gr-qtgui/grc/qtgui_time_sink_x.block.yml
index dfe53527eb..4da2d3ec66 100644
--- a/gr-qtgui/grc/qtgui_time_sink_x.block.yml
+++ b/gr-qtgui/grc/qtgui_time_sink_x.block.yml
@@ -551,7 +551,7 @@ templates:
% endif
${win} = sip.wrapinstance(self.${id}.pyqwidget(), Qt.QWidget)
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
The GUI hint can be used to position the widget within the application. The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. Both the tab specification and the grid position are optional.
diff --git a/gr-qtgui/grc/qtgui_vector_sink_f.block.yml b/gr-qtgui/grc/qtgui_vector_sink_f.block.yml
index d30349dceb..d2fb1a7d5d 100644
--- a/gr-qtgui/grc/qtgui_vector_sink_f.block.yml
+++ b/gr-qtgui/grc/qtgui_vector_sink_f.block.yml
@@ -344,7 +344,7 @@ templates:
self.${id}.set_line_alpha(i, alphas[i])
${win} = sip.wrapinstance(self.${id}.pyqwidget(), Qt.QWidget)
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
The GUI hint can be used to position the widget within the application. The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. Both the tab specification and the grid position are optional.
diff --git a/gr-qtgui/grc/qtgui_waterfall_sink_x.block.yml b/gr-qtgui/grc/qtgui_waterfall_sink_x.block.yml
index 4b1cc055bc..45fc6c41fd 100644
--- a/gr-qtgui/grc/qtgui_waterfall_sink_x.block.yml
+++ b/gr-qtgui/grc/qtgui_waterfall_sink_x.block.yml
@@ -295,7 +295,7 @@ templates:
self.${id}.set_intensity_range(${int_min}, ${int_max})
${win} = sip.wrapinstance(self.${id}.pyqwidget(), Qt.QWidget)
- ${gui_hint()(win)}
+ ${gui_hint() % win}
documentation: |-
The GUI hint can be used to position the widget within the application. The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. Both the tab specification and the grid position are optional.
diff --git a/grc/converter/block.py b/grc/converter/block.py
index 04e5c905a0..0e362d97c0 100644
--- a/grc/converter/block.py
+++ b/grc/converter/block.py
@@ -95,14 +95,14 @@ def convert_block_xml(node):
data['outputs'] = [convert_port_xml(port_node, converter.to_python_dec)
for port_node in node.iterfind('source')] or no_value
-
- data['checks'] = [converter.to_python_dec(check_node.text)
- for check_node in node.iterfind('checks')] or no_value
data['value'] = (
converter.to_python_dec(node.findtext('var_value')) or
('${ value }' if block_id.startswith('variable') else no_value)
)
+ data['asserts'] = [converter.to_python_dec(check_node.text)
+ for check_node in node.iterfind('check')] or no_value
+
data['templates'] = convert_templates(node, converter.to_mako, block_id) or no_value
docs = node.findtext('doc')
diff --git a/grc/core/Param.py b/grc/core/Param.py
index 56855908ea..13439f43b4 100644
--- a/grc/core/Param.py
+++ b/grc/core/Param.py
@@ -23,9 +23,10 @@ import ast
import numbers
import re
import collections
+import textwrap
import six
-from six.moves import builtins, filter, map, range, zip
+from six.moves import builtins, range
from . import Constants, blocks
from .base import Element
@@ -102,6 +103,7 @@ class Param(Element):
self._evaluated = None
self._stringify_flag = False
self._lisitify_flag = False
+ self.hostage_cells = set()
self._init = False
@property
@@ -299,38 +301,11 @@ class Param(Element):
# GUI Position/Hint
#########################
elif dtype == 'gui_hint':
- if ':' in expr:
- tab, pos = expr.split(':')
- elif '@' in expr:
- tab, pos = expr, ''
+ if self.parent_block.state == 'disabled':
+ return ''
else:
- tab, pos = '', expr
+ return self.parse_gui_hint(expr)
- if '@' in tab:
- tab, index = tab.split('@')
- else:
- index = '?'
-
- # TODO: Problem with this code. Produces bad tabs
- 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
- # 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)
#########################
# Import Type
#########################
@@ -411,3 +386,132 @@ class Param(Element):
def get_opt(self, item):
return self.options.attributes[self.get_value()][item]
+
+ ##############################################
+ # GUI Hint
+ ##############################################
+ def parse_gui_hint(self, expr):
+ """
+ Parse/validate gui hint value.
+
+ Args:
+ expr: gui_hint string from a block's 'gui_hint' param
+
+ Returns:
+ string of python code for positioning GUI elements in pyQT
+ """
+ self.hostage_cells.clear()
+
+ # Parsing
+ if ':' in expr:
+ tab, pos = expr.split(':')
+ elif ',' in expr:
+ tab, pos = '', expr
+ else:
+ tab, pos = expr, ''
+
+ if '@' in tab:
+ tab, index = tab.split('@')
+ else:
+ index = '0'
+ index = int(index)
+
+ # Validation
+ def parse_pos():
+ e = self.parent_flowgraph.evaluate(pos)
+
+ if not isinstance(e, (list, tuple)) or len(e) not in (2, 4) or not all(isinstance(ei, int) for ei in e):
+ raise Exception('Invalid GUI Hint entered: {e!r} (Must be a list of {{2,4}} non-negative integers).'.format(e=e))
+
+ if len(e) == 2:
+ row, col = e
+ row_span = col_span = 1
+ else:
+ row, col, row_span, col_span = e
+
+ if (row < 0) or (col < 0):
+ raise Exception('Invalid GUI Hint entered: {e!r} (non-negative integers only).'.format(e=e))
+
+ if (row_span < 1) or (col_span < 1):
+ raise Exception('Invalid GUI Hint entered: {e!r} (positive row/column span required).'.format(e=e))
+
+ return row, col, row_span, col_span
+
+ def validate_tab():
+ tabs = (block for block in self.parent_flowgraph.iter_enabled_blocks()
+ if block.key == 'qtgui_tab_widget' and block.name == tab)
+ tab_block = next(iter(tabs), None)
+ if not tab_block:
+ raise Exception('Invalid tab name entered: {tab} (Tab name not found).'.format(tab=tab))
+
+ tab_index_size = int(tab_block.params['num_tabs'].value)
+ if index >= tab_index_size:
+ raise Exception('Invalid tab index entered: {tab}@{index} (Index out of range).'.format(
+ tab=tab, index=index))
+
+ # Collision Detection
+ def collision_detection(row, col, row_span, col_span):
+ my_parent = '{tab}@{index}'.format(tab=tab, index=index) if tab else 'main'
+ # Calculate hostage cells
+ for r in range(row, row + row_span):
+ for c in range(col, col + col_span):
+ self.hostage_cells.add((my_parent, (r, c)))
+
+ for other in self.get_all_params('gui_hint'):
+ if other is self:
+ continue
+ collision = next(iter(self.hostage_cells & other.hostage_cells), None)
+ if collision:
+ raise Exception('Block {block!r} is also using parent {parent!r}, cell {cell!r}.'.format(
+ block=other.parent_block.name, parent=collision[0], cell=collision[1]
+ ))
+
+ # Code Generation
+ if tab:
+ validate_tab()
+ layout = '{tab}_grid_layout_{index}'.format(tab=tab, index=index)
+ else:
+ layout = 'top_grid_layout'
+
+ widget = '%s' # to be fill-out in the mail template
+
+ if pos:
+ row, col, row_span, col_span = parse_pos()
+ collision_detection(row, col, row_span, col_span)
+
+ widget_str = textwrap.dedent("""
+ self.{layout}.addWidget({widget}, {row}, {col}, {row_span}, {col_span})
+ for r in range({row}, {row_end}):
+ self.{layout}.setRowStretch(r, 1)
+ for c in range({col}, {col_end}):
+ self.{layout}.setColumnStretch(c, 1)
+ """.strip('\n')).format(
+ layout=layout, widget=widget,
+ row=row, row_span=row_span, row_end=row+row_span,
+ col=col, col_span=col_span, col_end=col+col_span,
+ )
+
+ else:
+ widget_str = 'self.{layout}.addWidget({widget})'.format(layout=layout, widget=widget)
+
+ return widget_str
+
+ def get_all_params(self, dtype, key=None):
+ """
+ Get all the params from the flowgraph that have the given type and
+ optionally a given key
+
+ Args:
+ type: the specified type
+ key: the key to match against
+
+ Returns:
+ a list of params
+ """
+ params = []
+ for block in self.parent_flowgraph.iter_enabled_blocks():
+ params.extend(
+ param for param in block.params.values()
+ if param.dtype == dtype and (key is None or key == param.name)
+ )
+ return params
diff --git a/grc/core/blocks/_build.py b/grc/core/blocks/_build.py
index 9a50086cea..9221433387 100644
--- a/grc/core/blocks/_build.py
+++ b/grc/core/blocks/_build.py
@@ -25,7 +25,7 @@ from ._templates import MakoTemplates
def build(id, label='', category='', flags='', documentation='',
- checks=None, value=None,
+ value=None, asserts=None,
parameters=None, inputs=None, outputs=None, templates=None, **kwargs):
block_id = id
@@ -41,7 +41,7 @@ def build(id, label='', category='', flags='', documentation='',
cls.documentation = {'': documentation.strip('\n\t ').replace('\\\n', '')}
- cls.checks = [_single_mako_expr(check, block_id) for check in (checks or [])]
+ cls.asserts = [_single_mako_expr(a, block_id) for a in (asserts or [])]
cls.parameters_data = parameters or []
cls.inputs_data = inputs or []
diff --git a/grc/core/blocks/block.py b/grc/core/blocks/block.py
index e0858957ab..adc046936d 100644
--- a/grc/core/blocks/block.py
+++ b/grc/core/blocks/block.py
@@ -55,7 +55,7 @@ class Block(Element):
documentation = {'': ''}
value = None
- checks = []
+ asserts = []
templates = MakoTemplates()
parameters_data = []
@@ -127,11 +127,10 @@ class Block(Element):
port_factory = self.parent_platform.make_port
port_ids = set()
- def make_stream_port_id(_pool=itertools.count()):
- return {'sink': 'in', 'source': 'out'}[direction] + str(next(_pool))
+ stream_port_ids = itertools.count()
for i, port_data in enumerate(ports_n):
- port_id = port_data.setdefault('id', make_stream_port_id())
+ port_id = port_data.setdefault('id', str(next(stream_port_ids)))
if port_id in port_ids:
raise Exception('Port id "{}" already exists in {}s'.format(port_id, direction))
port_ids.add(port_id)
@@ -191,18 +190,18 @@ class Block(Element):
Evaluate the checks: each check must evaluate to True.
"""
Element.validate(self)
- self._run_checks()
+ self._run_asserts()
self._validate_generate_mode_compat()
self._validate_var_value()
- def _run_checks(self):
+ def _run_asserts(self):
"""Evaluate the checks"""
- for check in self.checks:
+ for expr in self.asserts:
try:
- if not self.evaluate(check):
- self.add_error_message('Check "{}" failed.'.format(check))
+ if not self.evaluate(expr):
+ self.add_error_message('Assertion "{}" failed.'.format(expr))
except:
- self.add_error_message('Check "{}" did not evaluate.'.format(check))
+ self.add_error_message('Assertion "{}" did not evaluate.'.format(expr))
def _validate_generate_mode_compat(self):
"""check if this is a GUI block and matches the selected generate option"""
diff --git a/grc/core/generator/flow_graph.py.mako b/grc/core/generator/flow_graph.py.mako
index b054f7aebf..877c9eee9d 100644
--- a/grc/core/generator/flow_graph.py.mako
+++ b/grc/core/generator/flow_graph.py.mako
@@ -90,9 +90,9 @@ class ${class_name}(gr.top_block, Qt.QWidget):
self.restoreGeometry(self.settings.value("geometry"))
except:
pass
-#elif $generate_options == 'bokeh_gui'
+% elif generate_options == 'bokeh_gui':
-class $(class_name)(gr.top_block):
+class ${class_name}(gr.top_block):
def __init__(self, doc):
gr.top_block.__init__(self, "${title}")
self.doc = doc
@@ -117,8 +117,8 @@ class ${class_name}(gr.hier_block2):
<%def name="make_io_sig(io_sigs)">
<% 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)\
- #elif len(${io_sigs}) == 1
+gr.io_signature(0, 0, 0)
+ % elif len(io_sigs) == 1:
gr.io_signature(1, 1, ${size_strs[0]})
% else:
gr.io_signaturev(${len(io_sigs)}, ${len(io_sigs)}, [${', '.join(ize_strs)}])
@@ -200,7 +200,7 @@ gr.io_signaturev(${len(io_sigs)}, ${len(io_sigs)}, [${', '.join(ize_strs)}])
##########################################################
## Create a layout entry if not manually done for BokehGUI
##########################################################
-%if generate_options == 'bokeh_gui'
+% if generate_options == 'bokeh_gui':
if self.widget_lst:
input_t = bokehgui.BokehLayout.widgetbox(self.widget_lst)
widgetbox = bokehgui.BokehLayout.WidgetLayout(input_t)
@@ -357,7 +357,7 @@ def main(top_block_cls=${class_name}, options=None):
sys.stderr.write("Monitor '{0}' does not have an enable ('en') parameter.".format("tb.${m.name}"))
% endfor
qapp.exec_()
- #elif $generate_options == 'bokeh_gui'
+ % elif generate_options == 'bokeh_gui':
serverProc, port = bokehgui.utils.create_server()
def killProc(signum, frame, tb):
tb.stop()
@@ -366,16 +366,16 @@ def main(top_block_cls=${class_name}, options=None):
serverProc.kill()
time.sleep(1)
try:
- ${'#'} Define the document instance
+ # Define the document instance
doc = curdoc()
- #if ${flow_graph.get_option('author')}
- doc.title = "$title - ${flow_graph.get_option('author')}"
- #else
+ % if flow_graph.get_option('author'):
+ doc.title = "${title} - ${flow_graph.get_option('author')}"
+ % else:
doc.title = "${title}"
- #end if
+ % endif
session = push_session(doc, session_id="${flow_graph.get_option('id')}",
url = "http://localhost:" + port + "/bokehgui")
- ${'#'} Create Top Block instance
+ # Create Top Block instance
tb = top_block_cls(doc)
try:
tb.start()
diff --git a/grc/core/generator/hier_block.py b/grc/core/generator/hier_block.py
index 237fd71377..31cd198c01 100644
--- a/grc/core/generator/hier_block.py
+++ b/grc/core/generator/hier_block.py
@@ -149,8 +149,8 @@ class QtHierBlockGenerator(HierBlockGenerator):
block_n['param'].append(gui_hint_param)
block_n['make'] += (
- "\n#set $win = 'self.%s' % $id"
- "\n${gui_hint()($win)}"
+ "\n<% win = 'self.' + id %>"
+ "\n${ gui_hint % win }"
)
return {'block': block_n}
diff --git a/grc/core/generator/top_block.py b/grc/core/generator/top_block.py
index d6a7e35575..799ebb1076 100644
--- a/grc/core/generator/top_block.py
+++ b/grc/core/generator/top_block.py
@@ -4,7 +4,6 @@ import os
import tempfile
import textwrap
import time
-import re
from mako.template import Template
@@ -33,14 +32,13 @@ class TopBlockGenerator(object):
self._generate_options = self._flow_graph.get_option('generate_options')
self._mode = TOP_BLOCK_FILE_MODE
- 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()
+ if not os.access(file_path, os.W_OK):
+ file_path = tempfile.gettempdir()
filename = self._flow_graph.get_option('id') + '.py'
- self.file_path = os.path.join(dirname, filename)
- self._dirname = dirname
+ self.file_path = os.path.join(file_path, filename)
+ self._dirname = file_path
def _warnings(self):
throttling_blocks = [b for b in self._flow_graph.get_enabled_blocks()
@@ -228,7 +226,7 @@ class TopBlockGenerator(object):
key = port.key
if not key.isdigit():
- key = re.findall(r'\d+', key)[0]
+ key.repr(key)
return '({block}, {key})'.format(block=block, key=key)
diff --git a/grc/core/schema_checker/block.py b/grc/core/schema_checker/block.py
index db8830fddf..ea079b4276 100644
--- a/grc/core/schema_checker/block.py
+++ b/grc/core/schema_checker/block.py
@@ -44,7 +44,7 @@ BLOCK_SCHEME = expand(
inputs=Spec(types=list, required=False, item_scheme=PORT_SCHEME),
outputs=Spec(types=list, required=False, item_scheme=PORT_SCHEME),
- checks=(list, str_),
+ asserts=(list, str_),
value=str_,
templates=Spec(types=dict, required=False, item_scheme=TEMPLATES_SCHEME),
diff --git a/grc/core/utils/hide_bokeh_gui_options_if_not_installed.py b/grc/core/utils/hide_bokeh_gui_options_if_not_installed.py
index f209e515a8..ab4a42b2e7 100644
--- a/grc/core/utils/hide_bokeh_gui_options_if_not_installed.py
+++ b/grc/core/utils/hide_bokeh_gui_options_if_not_installed.py
@@ -20,5 +20,8 @@ def hide_bokeh_gui_options_if_not_installed(options_blk):
try:
import bokehgui
except ImportError:
- generate_options = options_blk.params['generate_options']
- del generate_options.options['bokeh_gui']
+ for param in options_blk.parameters_data:
+ if param['id'] == 'generate_options':
+ ind = param['options'].index('bokeh_gui')
+ del param['options'][ind]
+ del param['option_labels'][ind]
diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py
index ec927a4777..e737610a79 100644
--- a/grc/gui/MainWindow.py
+++ b/grc/gui/MainWindow.py
@@ -71,7 +71,7 @@ class MainWindow(Gtk.ApplicationWindow):
vbox = Gtk.VBox()
self.add(vbox)
- icon_theme = gtk.icon_theme_get_default()
+ icon_theme = Gtk.IconTheme.get_default()
icon = icon_theme.lookup_icon("gnuradio-grc", 48, 0)
if not icon:
# Set window icon
diff --git a/grc/gui/Notebook.py b/grc/gui/Notebook.py
index 21db913c0e..9f63190b31 100644
--- a/grc/gui/Notebook.py
+++ b/grc/gui/Notebook.py
@@ -151,7 +151,7 @@ class Page(Gtk.HBox):
generator
"""
platform = self.flow_graph.parent_platform
- return platform.Generator(self.flow_graph, self.file_path)
+ return platform.Generator(self.flow_graph, os.path.dirname(self.file_path))
def _handle_button(self, button):
"""