diff options
Diffstat (limited to 'grc/core')
-rw-r--r-- | grc/core/Block.py | 25 | ||||
-rw-r--r-- | grc/core/CMakeLists.txt | 2 | ||||
-rw-r--r-- | grc/core/Config.py | 4 | ||||
-rw-r--r-- | grc/core/Connection.py | 13 | ||||
-rw-r--r-- | grc/core/Constants.py | 3 | ||||
-rw-r--r-- | grc/core/Element.py | 2 | ||||
-rw-r--r-- | grc/core/Element.pyi | 54 | ||||
-rw-r--r-- | grc/core/FlowGraph.py | 22 | ||||
-rw-r--r-- | grc/core/Param.py | 128 | ||||
-rw-r--r-- | grc/core/Platform.py | 41 | ||||
-rw-r--r-- | grc/core/Port.py | 16 | ||||
-rw-r--r-- | grc/core/generator/CMakeLists.txt | 2 | ||||
-rw-r--r-- | grc/core/generator/Generator.py | 8 | ||||
-rw-r--r-- | grc/core/generator/flow_graph.tmpl | 80 | ||||
-rw-r--r-- | grc/core/utils/CMakeLists.txt | 1 | ||||
-rw-r--r-- | grc/core/utils/odict.py | 4 | ||||
-rw-r--r-- | grc/core/utils/shlex.py | 47 |
17 files changed, 225 insertions, 227 deletions
diff --git a/grc/core/Block.py b/grc/core/Block.py index f8179b113f..fba9371963 100644 --- a/grc/core/Block.py +++ b/grc/core/Block.py @@ -24,7 +24,7 @@ from Cheetah.Template import Template from .utils import epy_block_io, odict from . Constants import ( - BLOCK_FLAG_NEED_QT_GUI, BLOCK_FLAG_NEED_WX_GUI, + BLOCK_FLAG_NEED_QT_GUI, ADVANCED_PARAM_TAB, DEFAULT_PARAM_TAB, BLOCK_FLAG_THROTTLE, BLOCK_FLAG_DISABLE_BYPASS, BLOCK_FLAG_DEPRECATED, @@ -41,7 +41,7 @@ def _get_elem(lst, key): try: return lst[_get_keys(lst).index(key)] except ValueError: - raise ValueError('Key "{0}" not found in {1}.'.format(key, _get_keys(lst))) + raise ValueError('Key "{}" not found in {}.'.format(key, _get_keys(lst))) class Block(Element): @@ -121,7 +121,7 @@ class Block(Element): key = param.get_key() # Test against repeated keys if key in self.get_param_keys(): - raise Exception('Key "{0}" already exists in params'.format(key)) + raise Exception('Key "{}" already exists in params'.format(key)) # Store the param self.get_params().append(param) # Create the source objects @@ -130,7 +130,7 @@ class Block(Element): key = source.get_key() # Test against repeated keys if key in self.get_source_keys(): - raise Exception('Key "{0}" already exists in sources'.format(key)) + raise Exception('Key "{}" already exists in sources'.format(key)) # Store the port self.get_sources().append(source) self.back_ofthe_bus(self.get_sources()) @@ -140,7 +140,7 @@ class Block(Element): key = sink.get_key() # Test against repeated keys if key in self.get_sink_keys(): - raise Exception('Key "{0}" already exists in sinks'.format(key)) + raise Exception('Key "{}" already exists in sinks'.format(key)) # Store the port self.get_sinks().append(sink) self.back_ofthe_bus(self.get_sinks()) @@ -250,9 +250,9 @@ class Block(Element): check_res = self.resolve_dependencies(check) try: if not self.get_parent().evaluate(check_res): - self.add_error_message('Check "{0}" failed.'.format(check)) + self.add_error_message('Check "{}" failed.'.format(check)) except: - self.add_error_message('Check "{0}" did not evaluate.'.format(check)) + self.add_error_message('Check "{}" did not evaluate.'.format(check)) # For variables check the value (only if var_value is used if self.is_variable and self._var_value != '$value': @@ -261,7 +261,7 @@ class Block(Element): value = self.get_var_value() self.get_parent().evaluate(value) except Exception as err: - self.add_error_message('Value "{0}" cannot be evaluated:\n{1}'.format(value, err)) + self.add_error_message('Value "{}" cannot be evaluated:\n{}'.format(value, err)) # check if this is a GUI block and matches the selected generate option current_generate_option = self.get_parent().get_option('generate_options') @@ -272,10 +272,9 @@ class Block(Element): self.get_name().upper().startswith(label) ) if block_requires_mode and current_generate_option not in valid_options: - self.add_error_message("Can't generate this block in mode: {0} ".format( + self.add_error_message("Can't generate this block in mode: {} ".format( repr(current_generate_option))) - check_generate_mode('WX GUI', BLOCK_FLAG_NEED_WX_GUI, ('wx_gui',)) check_generate_mode('QT GUI', BLOCK_FLAG_NEED_QT_GUI, ('qt_gui', 'hb_qt_gui')) if self._epy_reload_error: self.get_param('_source_code').add_error_message(str(self._epy_reload_error)) @@ -390,7 +389,7 @@ class Block(Element): callback = self.resolve_dependencies(callback) if 'self.' in callback: return callback - return 'self.{0}.{1}'.format(self.get_id(), callback) + return 'self.{}.{}'.format(self.get_id(), callback) return map(make_callback, self._callbacks) def is_virtual_sink(self): @@ -587,7 +586,7 @@ class Block(Element): return True def __str__(self): - return 'Block - {0} - {1}({2})'.format(self.get_id(), self.get_name(), self.get_key()) + return 'Block - {} - {}({})'.format(self.get_id(), self.get_name(), self.get_key()) def get_id(self): return self.get_param('id').get_value() @@ -702,7 +701,7 @@ class Block(Element): try: return str(Template(tmpl, n)) except Exception as err: - return "Template error: {0}\n {1}".format(tmpl, err) + return "Template error: {}\n {}".format(tmpl, err) ############################################## # Controller Modify diff --git a/grc/core/CMakeLists.txt b/grc/core/CMakeLists.txt index 51b0dacba6..f340127873 100644 --- a/grc/core/CMakeLists.txt +++ b/grc/core/CMakeLists.txt @@ -22,7 +22,6 @@ file(GLOB py_files "*.py") GR_PYTHON_INSTALL( FILES ${py_files} DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core - COMPONENT "grc" ) file(GLOB dtd_files "*.dtd") @@ -30,7 +29,6 @@ file(GLOB dtd_files "*.dtd") install( FILES ${dtd_files} default_flow_graph.grc DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core - COMPONENT "grc" ) add_subdirectory(generator) diff --git a/grc/core/Config.py b/grc/core/Config.py index 78ff344998..744ad06ba9 100644 --- a/grc/core/Config.py +++ b/grc/core/Config.py @@ -32,10 +32,12 @@ class Config(object): hier_block_lib_dir = os.environ.get('GRC_HIER_PATH', Constants.DEFAULT_HIER_BLOCK_LIB_DIR) - def __init__(self, prefs_file, version, version_parts=None): + def __init__(self, prefs_file, version, version_parts=None, name=None): self.prefs = prefs_file self.version = version self.version_parts = version_parts or version[1:].split('-', 1)[0].split('.')[:3] + if name: + self.name = name @property def block_paths(self): diff --git a/grc/core/Connection.py b/grc/core/Connection.py index 49eae69c82..c028d89ddc 100644 --- a/grc/core/Connection.py +++ b/grc/core/Connection.py @@ -75,16 +75,13 @@ class Connection(Element): pass def __str__(self): - return 'Connection (\n\t{0}\n\t\t{1}\n\t{2}\n\t\t{3}\n)'.format( + return 'Connection (\n\t{}\n\t\t{}\n\t{}\n\t\t{}\n)'.format( self.get_source().get_parent(), self.get_source(), self.get_sink().get_parent(), self.get_sink(), ) - def is_msg(self): - return self.get_source().get_type() == self.get_sink().get_type() == 'msg' - def is_bus(self): return self.get_source().get_type() == self.get_sink().get_type() == 'bus' @@ -102,7 +99,7 @@ class Connection(Element): source_domain = self.get_source().get_domain() sink_domain = self.get_sink().get_domain() if (source_domain, sink_domain) not in platform.connection_templates: - self.add_error_message('No connection known for domains "{0}", "{1}"'.format( + self.add_error_message('No connection known for domains "{}", "{}"'.format( source_domain, sink_domain)) too_many_other_sinks = ( not platform.domains.get(source_domain, []).get('multiple_sinks', False) and @@ -114,15 +111,15 @@ class Connection(Element): ) if too_many_other_sinks: self.add_error_message( - 'Domain "{0}" can have only one downstream block'.format(source_domain)) + 'Domain "{}" can have only one downstream block'.format(source_domain)) if too_many_other_sources: self.add_error_message( - 'Domain "{0}" can have only one upstream block'.format(sink_domain)) + 'Domain "{}" can have only one upstream block'.format(sink_domain)) source_size = Constants.TYPE_TO_SIZEOF[self.get_source().get_type()] * self.get_source().get_vlen() sink_size = Constants.TYPE_TO_SIZEOF[self.get_sink().get_type()] * self.get_sink().get_vlen() if source_size != sink_size: - self.add_error_message('Source IO size "{0}" does not match sink IO size "{1}".'.format(source_size, sink_size)) + self.add_error_message('Source IO size "{}" does not match sink IO size "{}".'.format(source_size, sink_size)) def get_enabled(self): """ diff --git a/grc/core/Constants.py b/grc/core/Constants.py index 61a44d0c78..edd3442a94 100644 --- a/grc/core/Constants.py +++ b/grc/core/Constants.py @@ -48,7 +48,6 @@ DEFAULT_DOMAIN = GR_STREAM_DOMAIN BLOCK_FLAG_THROTTLE = 'throttle' BLOCK_FLAG_DISABLE_BYPASS = 'disable_bypass' BLOCK_FLAG_NEED_QT_GUI = 'need_qt_gui' -BLOCK_FLAG_NEED_WX_GUI = 'need_wx_gui' BLOCK_FLAG_DEPRECATED = 'deprecated' # Block States @@ -109,7 +108,6 @@ CORE_TYPES = ( # name, key, sizeof, color ('Integer 16', 's16', 2, GRC_COLOR_YELLOW), ('Integer 8', 's8', 1, GRC_COLOR_PURPLE_A400), ('Bits (unpacked byte)', 'bit', 1, GRC_COLOR_PURPLE_A100), - ('Message Queue', 'msg', 0, GRC_COLOR_DARK_GREY), ('Async Message', 'message', 0, GRC_COLOR_GREY), ('Bus Connection', 'bus', 0, GRC_COLOR_WHITE), ('Wildcard', '', 0, GRC_COLOR_WHITE), @@ -148,4 +146,3 @@ SHORT_VECTOR_COLOR_SPEC = '#CCCC33' BYTE_VECTOR_COLOR_SPEC = '#CC66CC' ID_COLOR_SPEC = '#DDDDDD' WILDCARD_COLOR_SPEC = '#FFFFFF' -MSG_COLOR_SPEC = '#777777' diff --git a/grc/core/Element.py b/grc/core/Element.py index d80753d8fa..67c36e12b4 100644 --- a/grc/core/Element.py +++ b/grc/core/Element.py @@ -66,7 +66,7 @@ class Element(object): error_messages = list(self._error_messages) # Make a copy for child in filter(lambda c: c.get_enabled() and not c.get_bypassed(), self.get_children()): for msg in child.get_error_messages(): - error_messages.append("{0}:\n\t{1}".format(child, msg.replace("\n", "\n\t"))) + error_messages.append("{}:\n\t{}".format(child, msg.replace("\n", "\n\t"))) return error_messages def rewrite(self): diff --git a/grc/core/Element.pyi b/grc/core/Element.pyi new file mode 100644 index 0000000000..c81180a33e --- /dev/null +++ b/grc/core/Element.pyi @@ -0,0 +1,54 @@ +# Copyright 2008, 2009, 2015, 2016 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +from . import Platform, FlowGraph, Block + +def lazy_property(func): + return func + + +class Element(object): + + def __init__(self, parent=None): + ... + + @property + def parent(self): + ... + + def get_parent_by_type(self, cls): + parent = self.parent + if parent is None: + return None + elif isinstance(parent, cls): + return parent + else: + return parent.get_parent_by_type(cls) + + @lazy_property + def parent_platform(self): -> Platform.Platform + ... + + @lazy_property + def parent_flowgraph(self): -> FlowGraph.FlowGraph + ... + + @lazy_property + def parent_block(self): -> Block.Block + ... + + diff --git a/grc/core/FlowGraph.py b/grc/core/FlowGraph.py index 48563eefb1..ecae11cf1a 100644 --- a/grc/core/FlowGraph.py +++ b/grc/core/FlowGraph.py @@ -16,16 +16,16 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import imp -import time from itertools import ifilter, chain from operator import methodcaller, attrgetter - import re +import sys +import time from . import Messages from .Constants import FLOW_GRAPH_FILE_FORMAT_VERSION from .Element import Element -from .utils import odict, expr_utils +from .utils import odict, expr_utils, shlex _parameter_matcher = re.compile('^(parameter)$') _monitors_searcher = re.compile('(ctrlport_monitor)') @@ -64,7 +64,7 @@ class FlowGraph(Element): self._options_block = self.new_block('options') def __str__(self): - return 'FlowGraph - {0}({1})'.format(self.get_option('title'), self.get_option('id')) + return 'FlowGraph - {}({})'.format(self.get_option('title'), self.get_option('id')) ############################################## # TODO: Move these to new generator package @@ -186,6 +186,16 @@ class FlowGraph(Element): """ return self._options_block.get_param(key).get_evaluated() + def get_run_command(self, file_path, split=False): + run_command = self.get_option('run_command') + try: + run_command = run_command.format( + python=shlex.quote(sys.executable), + filename=shlex.quote(file_path)) + return shlex.split(run_command) if split else run_command + except Exception as e: + raise ValueError("Can't parse run command {!r}: {}".format(run_command, e)) + ############################################## # Access Elements ############################################## @@ -410,7 +420,7 @@ class FlowGraph(Element): cwd=self.grc_file_path ) if file_path: # grc file found. load and get block - self.platform.load_and_generate_flow_graph(file_path) + self.platform.load_and_generate_flow_graph(file_path, hier_only=True) block = self.new_block(key) # can be None if not block: # looks like this block key cannot be found @@ -461,7 +471,7 @@ class FlowGraph(Element): self.connect(source_port, sink_port) except LookupError as e: Messages.send_error_load( - 'Connection between {0}({1}) and {2}({3}) could not be made.\n\t{4}'.format( + 'Connection between {}({}) and {}({}) could not be made.\n\t{}'.format( source_block_id, source_key, sink_block_id, sink_key, e)) errors = True diff --git a/grc/core/Param.py b/grc/core/Param.py index afa478b3a2..a9a664f74a 100644 --- a/grc/core/Param.py +++ b/grc/core/Param.py @@ -30,7 +30,7 @@ from .utils import odict import __builtin__ -ID_BLACKLIST = ['self', 'options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 'forms', 'firdes'] + dir(__builtin__) +ID_BLACKLIST = ['self', 'options', 'gr', 'math', 'firdes'] + dir(__builtin__) try: from gnuradio import gr ID_BLACKLIST.extend(attr for attr in dir(gr.top_block()) if not attr.startswith('_')) @@ -49,14 +49,14 @@ def _get_elem(lst, key): try: return lst[_get_keys(lst).index(key)] except ValueError: - raise ValueError('Key "{0}" not found in {1}.'.format(key, _get_keys(lst))) + raise ValueError('Key "{}" not found in {}.'.format(key, _get_keys(lst))) def num_to_str(num): """ Display logic for numbers """ def eng_notation(value, fmt='g'): """Convert a number to a string in engineering notation. E.g., 5e-9 -> 5n""" - template = '{0:' + fmt + '}{1}' + template = '{:' + fmt + '}{}' magnitude = abs(value) for exp, symbol in zip(range(9, -15-1, -3), 'GMk munpf'): factor = 10 ** exp @@ -92,15 +92,15 @@ class Option(Element): try: key, value = opt.split(':') except: - raise Exception('Error separating "{0}" into key:value'.format(opt)) + raise Exception('Error separating "{}" into key:value'.format(opt)) # Test against repeated keys if key in self._opts: - raise Exception('Key "{0}" already exists in option'.format(key)) + raise Exception('Key "{}" already exists in option'.format(key)) # Store the option self._opts[key] = value def __str__(self): - return 'Option {0}({1})'.format(self.get_name(), self.get_key()) + return 'Option {}({})'.format(self.get_name(), self.get_key()) def get_name(self): return self._name @@ -180,26 +180,26 @@ class Param(Element): key = option.get_key() # Test against repeated keys if key in self.get_option_keys(): - raise Exception('Key "{0}" already exists in options'.format(key)) + raise Exception('Key "{}" already exists in options'.format(key)) # Store the option self.get_options().append(option) # Test the enum options if self.is_enum(): # Test against options with identical keys if len(set(self.get_option_keys())) != len(self.get_options()): - raise Exception('Options keys "{0}" are not unique.'.format(self.get_option_keys())) + raise Exception('Options keys "{}" are not unique.'.format(self.get_option_keys())) # Test against inconsistent keys in options opt_keys = self.get_options()[0].get_opt_keys() for option in self.get_options(): if set(opt_keys) != set(option.get_opt_keys()): - raise Exception('Opt keys "{0}" are not identical across all options.'.format(opt_keys)) + raise Exception('Opt keys "{}" are not identical across all options.'.format(opt_keys)) # If a value is specified, it must be in the options keys if value or value in self.get_option_keys(): self._value = value else: self._value = self.get_option_keys()[0] if self.get_value() not in self.get_option_keys(): - raise Exception('The value "{0}" is not in the possible values of "{1}".'.format(self.get_value(), self.get_option_keys())) + raise Exception('The value "{}" is not in the possible values of "{}".'.format(self.get_value(), self.get_option_keys())) else: self._value = value or '' self._default = value @@ -215,7 +215,7 @@ class Param(Element): 'hex', 'string', 'bool', 'file_open', 'file_save', '_multiline', '_multiline_python_external', 'id', 'stream_id', - 'grid_pos', 'notebook', 'gui_hint', + 'gui_hint', 'import', ) @@ -290,7 +290,7 @@ class Param(Element): return self.get_value() def __str__(self): - return 'Param - {0}({1})'.format(self.get_name(), self.get_key()) + return 'Param - {}({})'.format(self.get_name(), self.get_key()) def get_color(self): """ @@ -317,8 +317,6 @@ class Param(Element): 'string': Constants.BYTE_VECTOR_COLOR_SPEC, 'id': Constants.ID_COLOR_SPEC, 'stream_id': Constants.ID_COLOR_SPEC, - 'grid_pos': Constants.INT_VECTOR_COLOR_SPEC, - 'notebook': Constants.INT_VECTOR_COLOR_SPEC, 'raw': Constants.WILDCARD_COLOR_SPEC, }[self.get_type()] except: @@ -354,9 +352,6 @@ class Param(Element): return 'part' except: pass - # Hide empty grid positions - if self.get_key() in ('grid_pos', 'notebook') and not self.get_value(): - return 'part' return hide def validate(self): @@ -366,7 +361,7 @@ class Param(Element): """ Element.validate(self) if self.get_type() not in self.get_types(): - self.add_error_message('Type "{0}" is not a possible type.'.format(self.get_type())) + self.add_error_message('Type "{}" is not a possible type.'.format(self.get_type())) self._evaluated = None try: @@ -405,30 +400,30 @@ class Param(Element): try: e = self.get_parent().get_parent().evaluate(v) except Exception, e: - raise Exception('Value "{0}" cannot be evaluated:\n{1}'.format(v, e)) + raise Exception('Value "{}" cannot be evaluated:\n{}'.format(v, e)) # Raise an exception if the data is invalid if t == 'raw': return e elif t == 'complex': if not isinstance(e, COMPLEX_TYPES): - raise Exception('Expression "{0}" is invalid for type complex.'.format(str(e))) + raise Exception('Expression "{}" is invalid for type complex.'.format(str(e))) return e elif t == 'real' or t == 'float': if not isinstance(e, REAL_TYPES): - raise Exception('Expression "{0}" is invalid for type float.'.format(str(e))) + raise Exception('Expression "{}" is invalid for type float.'.format(str(e))) return e elif t == 'int': if not isinstance(e, INT_TYPES): - raise Exception('Expression "{0}" is invalid for type integer.'.format(str(e))) + raise Exception('Expression "{}" is invalid for type integer.'.format(str(e))) return e elif t == 'hex': return hex(e) elif t == 'bool': if not isinstance(e, bool): - raise Exception('Expression "{0}" is invalid for type bool.'.format(str(e))) + raise Exception('Expression "{}" is invalid for type bool.'.format(str(e))) return e else: - raise TypeError('Type "{0}" not handled'.format(t)) + raise TypeError('Type "{}" not handled'.format(t)) ######################### # Numeric Vector Types ######################### @@ -440,28 +435,28 @@ class Param(Element): try: e = self.get_parent().get_parent().evaluate(v) except Exception, e: - raise Exception('Value "{0}" cannot be evaluated:\n{1}'.format(v, e)) + raise Exception('Value "{}" cannot be evaluated:\n{}'.format(v, e)) # Raise an exception if the data is invalid if t == 'complex_vector': if not isinstance(e, VECTOR_TYPES): self._lisitify_flag = True e = [e] if not all([isinstance(ei, COMPLEX_TYPES) for ei in e]): - raise Exception('Expression "{0}" is invalid for type complex vector.'.format(str(e))) + raise Exception('Expression "{}" is invalid for type complex vector.'.format(str(e))) return e elif t == 'real_vector' or t == 'float_vector': if not isinstance(e, VECTOR_TYPES): self._lisitify_flag = True e = [e] if not all([isinstance(ei, REAL_TYPES) for ei in e]): - raise Exception('Expression "{0}" is invalid for type float vector.'.format(str(e))) + raise Exception('Expression "{}" is invalid for type float vector.'.format(str(e))) return e elif t == 'int_vector': if not isinstance(e, VECTOR_TYPES): self._lisitify_flag = True e = [e] if not all([isinstance(ei, INT_TYPES) for ei in e]): - raise Exception('Expression "{0}" is invalid for type integer vector.'.format(str(e))) + raise Exception('Expression "{}" is invalid for type integer vector.'.format(str(e))) return e ######################### # String Types @@ -484,20 +479,20 @@ class Param(Element): elif t == 'id': # Can python use this as a variable? if not _check_id_matcher.match(v): - raise Exception('ID "{0}" must begin with a letter and may contain letters, numbers, and underscores.'.format(v)) + raise Exception('ID "{}" must begin with a letter and may contain letters, numbers, and underscores.'.format(v)) ids = [param.get_value() for param in self.get_all_params(t, 'id')] if v in ID_BLACKLIST: - raise Exception('ID "{0}" is blacklisted.'.format(v)) + raise Exception('ID "{}" is blacklisted.'.format(v)) if self._key == 'id': # Id should only appear once, or zero times if block is disabled if ids.count(v) > 1: - raise Exception('ID "{0}" is not unique.'.format(v)) + raise Exception('ID "{}" is not unique.'.format(v)) else: # Id should exist to be a reference if ids.count(v) < 1: - raise Exception('ID "{0}" does not exist.'.format(v)) + raise Exception('ID "{}" does not exist.'.format(v)) return v @@ -514,11 +509,11 @@ class Param(Element): if self.get_parent().is_virtual_sink(): # Id should only appear once, or zero times if block is disabled if ids.count(v) > 1: - raise Exception('Stream ID "{0}" is not unique.'.format(v)) + raise Exception('Stream ID "{}" is not unique.'.format(v)) # Check that the virtual source's steam id is found if self.get_parent().is_virtual_source(): if v not in ids: - raise Exception('Stream ID "{0}" is not found.'.format(v)) + raise Exception('Stream ID "{}" is not found.'.format(v)) return v ######################### @@ -558,65 +553,6 @@ class Param(Element): return self._ws return GuiHint(widget_str) ######################### - # Grid Position Type - ######################### - elif t == 'grid_pos': - if not v: - # Allow for empty grid pos - return '' - e = self.get_parent().get_parent().evaluate(v) - if not isinstance(e, (list, tuple)) or len(e) != 4 or not all([isinstance(ei, int) for ei in e]): - raise Exception('A grid position must be a list of 4 integers.') - row, col, row_span, col_span = e - # Check row, col - if row < 0 or col < 0: - raise Exception('Row and column must be non-negative.') - # Check row span, col span - if row_span <= 0 or col_span <= 0: - raise Exception('Row and column span must be greater than zero.') - # Get hostage cell parent - try: - my_parent = self.get_parent().get_param('notebook').evaluate() - except: - my_parent = '' - # Calculate hostage cells - for r in range(row_span): - for c in range(col_span): - self._hostage_cells.append((my_parent, (row+r, col+c))) - # Avoid collisions - params = filter(lambda p: p is not self, self.get_all_params('grid_pos')) - for param in params: - for parent, cell in param._hostage_cells: - if (parent, cell) in self._hostage_cells: - raise Exception('Another graphical element is using parent "{0}", cell "{1}".'.format(str(parent), str(cell))) - return e - ######################### - # Notebook Page Type - ######################### - elif t == 'notebook': - if not v: - # Allow for empty notebook - return '' - - # Get a list of all notebooks - notebook_blocks = filter(lambda b: b.get_key() == 'notebook', self.get_parent().get_parent().get_enabled_blocks()) - # Check for notebook param syntax - try: - notebook_id, page_index = map(str.strip, v.split(',')) - except: - raise Exception('Bad notebook page format.') - # Check that the notebook id is valid - try: - notebook_block = filter(lambda b: b.get_id() == notebook_id, notebook_blocks)[0] - except: - raise Exception('Notebook id "{0}" is not an existing notebook id.'.format(notebook_id)) - - # Check that page index exists - if int(page_index) not in range(len(notebook_block.get_param('labels').evaluate())): - raise Exception('Page index "{0}" is not a valid index number.'.format(page_index)) - return notebook_id, page_index - - ######################### # Import Type ######################### elif t == 'import': @@ -625,14 +561,14 @@ class Param(Element): try: exec v in n except ImportError: - raise Exception('Import "{0}" failed.'.format(v)) + raise Exception('Import "{}" failed.'.format(v)) except Exception: - raise Exception('Bad import syntax: "{0}".'.format(v)) + raise Exception('Bad import syntax: "{}".'.format(v)) return filter(lambda k: str(k) != '__builtins__', n.keys()) ######################### else: - raise TypeError('Type "{0}" not handled'.format(t)) + raise TypeError('Type "{}" not handled'.format(t)) def to_code(self): """ diff --git a/grc/core/Platform.py b/grc/core/Platform.py index 297e8b0ae5..b73dade2e8 100644 --- a/grc/core/Platform.py +++ b/grc/core/Platform.py @@ -75,7 +75,7 @@ class Platform(Element): self.build_block_library() def __str__(self): - return 'Platform - {0}({1})'.format(self.config.key, self.config.name) + return 'Platform - {}({})'.format(self.config.key, self.config.name) @staticmethod def find_file_in_paths(filename, paths, cwd): @@ -93,42 +93,43 @@ class Platform(Element): if os.path.exists(os.path.normpath(file_path)): return file_path - def load_and_generate_flow_graph(self, file_path): + def load_and_generate_flow_graph(self, file_path, out_path=None, hier_only=False): """Loads a flow graph from file and generates it""" Messages.set_indent(len(self._auto_hier_block_generate_chain)) - Messages.send('>>> Loading: %r\n' % file_path) + Messages.send('>>> Loading: {}\n'.format(file_path)) if file_path in self._auto_hier_block_generate_chain: Messages.send(' >>> Warning: cyclic hier_block dependency\n') - return False + return None, None self._auto_hier_block_generate_chain.add(file_path) try: flow_graph = self.get_new_flow_graph() flow_graph.grc_file_path = file_path - # Other, nested higiter_blocks might be auto-loaded here + # Other, nested hier_blocks might be auto-loaded here flow_graph.import_data(self.parse_flow_graph(file_path)) flow_graph.rewrite() flow_graph.validate() if not flow_graph.is_valid(): raise Exception('Flowgraph invalid') - if not flow_graph.get_option('generate_options').startswith('hb'): + if hier_only and not flow_graph.get_option('generate_options').startswith('hb'): raise Exception('Not a hier block') except Exception as e: - Messages.send('>>> Load Error: {0}: {1}\n'.format(file_path, str(e))) - return False + Messages.send('>>> Load Error: {}: {}\n'.format(file_path, str(e))) + return None, None finally: self._auto_hier_block_generate_chain.discard(file_path) Messages.set_indent(len(self._auto_hier_block_generate_chain)) try: - Messages.send('>>> Generating: {0}\n'.format(file_path)) - generator = self.Generator(flow_graph, file_path) + generator = self.Generator(flow_graph, out_path or file_path) + Messages.send('>>> Generating: {}\n'.format(generator.file_path)) generator.write() except Exception as e: - Messages.send('>>> Generate Error: {0}: {1}\n'.format(file_path, str(e))) - return False + Messages.send('>>> Generate Error: {}: {}\n'.format(file_path, str(e))) + return None, None - self.load_block_xml(generator.get_file_path_xml()) - return True + if flow_graph.get_option('generate_options').startswith('hb'): + self.load_block_xml(generator.get_file_path_xml()) + return flow_graph, generator.file_path def build_block_library(self): """load the blocks and block tree from the search paths""" @@ -192,7 +193,7 @@ class Platform(Element): block = self.Block(self._flow_graph, n) key = block.get_key() if key in self.blocks: - print >> sys.stderr, 'Warning: Block with key "{0}" already exists.\n\tIgnoring: {1}'.format(key, xml_file) + print >> sys.stderr, 'Warning: Block with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file) else: # Store the block self.blocks[key] = block self._blocks_n[key] = n @@ -227,10 +228,10 @@ class Platform(Element): key = n.find('key') if not key: - print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: {0}'.format(xml_file) + print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: {}'.format(xml_file) return if key in self.domains: # test against repeated keys - print >> sys.stderr, 'Warning: Domain with key "{0}" already exists.\n\tIgnoring: {1}'.format(key, xml_file) + print >> sys.stderr, 'Warning: Domain with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file) return #to_bool = lambda s, d: d if s is None else s.lower() not in ('false', 'off', '0', '') @@ -245,7 +246,7 @@ class Platform(Element): gtk.gdk.color_parse(color) except (ValueError, ImportError): if color: # no color is okay, default set in GUI - print >> sys.stderr, 'Warning: Can\'t parse color code "{0}" for domain "{1}" '.format(color, key) + print >> sys.stderr, 'Warning: Can\'t parse color code "{}" for domain "{}" '.format(color, key) color = None self.domains[key] = dict( @@ -257,9 +258,9 @@ class Platform(Element): for connection_n in n.findall('connection'): key = (connection_n.find('source_domain'), connection_n.find('sink_domain')) if not all(key): - print >> sys.stderr, 'Warning: Empty domain key(s) in connection template.\n\t{0}'.format(xml_file) + print >> sys.stderr, 'Warning: Empty domain key(s) in connection template.\n\t{}'.format(xml_file) elif key in self.connection_templates: - print >> sys.stderr, 'Warning: Connection template "{0}" already exists.\n\t{1}'.format(key, xml_file) + print >> sys.stderr, 'Warning: Connection template "{}" already exists.\n\t{}'.format(key, xml_file) else: self.connection_templates[key] = connection_n.find('make') or '' diff --git a/grc/core/Port.py b/grc/core/Port.py index acf4eea3d4..8549656c9b 100644 --- a/grc/core/Port.py +++ b/grc/core/Port.py @@ -150,8 +150,6 @@ class Port(Element): elif n['domain'] == GR_MESSAGE_DOMAIN: n['key'] = n['name'] n['type'] = 'message' # For port color - if n['type'] == 'msg': - n['key'] = 'msg' if not n.find('key'): n['key'] = str(next(block.port_counters[dir == 'source'])) @@ -174,9 +172,9 @@ class Port(Element): def __str__(self): if self.is_source: - return 'Source - {0}({1})'.format(self.get_name(), self.get_key()) + return 'Source - {}({})'.format(self.get_name(), self.get_key()) if self.is_sink: - return 'Sink - {0}({1})'.format(self.get_name(), self.get_key()) + return 'Sink - {}({})'.format(self.get_name(), self.get_key()) def get_types(self): return Constants.TYPE_TO_SIZEOF.keys() @@ -186,18 +184,12 @@ class Port(Element): def validate(self): if self.get_type() not in self.get_types(): - self.add_error_message('Type "{0}" is not a possible type.'.format(self.get_type())) + self.add_error_message('Type "{}" is not a possible type.'.format(self.get_type())) platform = self.get_parent().get_parent().get_parent() if self.get_domain() not in platform.domains: - self.add_error_message('Domain key "{0}" is not registered.'.format(self.get_domain())) + self.add_error_message('Domain key "{}" is not registered.'.format(self.get_domain())) if not self.get_enabled_connections() and not self.get_optional(): self.add_error_message('Port is not connected.') - # Message port logic - if self.get_type() == 'msg': - if self.get_nports(): - self.add_error_message('A port of type "msg" cannot have "nports" set.') - if self.get_vlen() != 1: - self.add_error_message('A port of type "msg" must have a "vlen" of 1.') def rewrite(self): """ diff --git a/grc/core/generator/CMakeLists.txt b/grc/core/generator/CMakeLists.txt index 4bdd59a7a2..492ad7c4ad 100644 --- a/grc/core/generator/CMakeLists.txt +++ b/grc/core/generator/CMakeLists.txt @@ -22,11 +22,9 @@ file(GLOB py_files "*.py") GR_PYTHON_INSTALL( FILES ${py_files} DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core/generator - COMPONENT "grc" ) install(FILES flow_graph.tmpl DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core/generator - COMPONENT "grc" ) diff --git a/grc/core/generator/Generator.py b/grc/core/generator/Generator.py index 8c1cd9a6b0..dda226c6b2 100644 --- a/grc/core/generator/Generator.py +++ b/grc/core/generator/Generator.py @@ -133,10 +133,6 @@ class TopBlockGenerator(object): def _get_block_sort_text(block): code = block.get_make().replace(block.get_id(), ' ') try: - code += block.get_param('notebook').get_value() # Older gui markup w/ wxgui - except: - pass - try: code += block.get_param('gui_hint').get_value() # Newer gui markup w/ qtgui except: pass @@ -165,7 +161,7 @@ class TopBlockGenerator(object): # Filter out virtual sink connections def cf(c): - return not (c.is_bus() or c.is_msg() or c.get_sink().get_parent().is_virtual_sink()) + return not (c.is_bus() or c.get_sink().get_parent().is_virtual_sink()) connections = filter(cf, fg.get_enabled_connections()) # Get the virtual blocks and resolve their connections @@ -214,7 +210,6 @@ class TopBlockGenerator(object): )) connection_templates = fg.get_parent().connection_templates - msgs = filter(lambda c: c.is_msg(), fg.get_enabled_connections()) # List of variable names var_ids = [var.get_id() for var in parameters + variables] @@ -243,7 +238,6 @@ class TopBlockGenerator(object): 'blocks': blocks, 'connections': connections, 'connection_templates': connection_templates, - 'msgs': msgs, 'generate_options': self._generate_options, 'callbacks': callbacks, } diff --git a/grc/core/generator/flow_graph.tmpl b/grc/core/generator/flow_graph.tmpl index 1ef251c46b..2adb555486 100644 --- a/grc/core/generator/flow_graph.tmpl +++ b/grc/core/generator/flow_graph.tmpl @@ -11,7 +11,6 @@ ##@param parameters the parameter blocks ##@param blocks the signal blocks ##@param connections the connections -##@param msgs the msg type connections ##@param generate_options the type of flow graph ##@param callbacks variable id map to callback strings ######################################################## @@ -36,9 +35,13 @@ $DIVIDER import threading #end if +#if $generate_options == 'qt_gui' +from distutils.version import StrictVersion +#end if + ## Call XInitThreads as the _very_ first thing. ## After some Qt import, it's too late -#if $generate_options in ('wx_gui', 'qt_gui') +#if $generate_options == 'qt_gui' if __name__ == '__main__': import ctypes import sys @@ -72,28 +75,13 @@ $imp ##Create Class ## Write the class declaration for a top or hier block. ## The parameter names are the arguments to __init__. -## Determine the absolute icon path (wx gui only). ## Setup the IO signature (hier block only). ######################################################## #set $class_name = $flow_graph.get_option('id') #set $param_str = ', '.join(['self'] + ['%s=%s'%(param.get_id(), param.get_make()) for param in $parameters]) -#if $generate_options == 'wx_gui' - #import gtk - #set $icon = gtk.IconTheme().lookup_icon('gnuradio-grc', 32, 0) - - -class $(class_name)(grc_wxgui.top_block_gui): - - def __init__($param_str): - grc_wxgui.top_block_gui.__init__(self, title="$title") - #if $icon - _icon_path = "$icon.get_filename()" - self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY)) - #end if -#elif $generate_options == 'qt_gui' +#if $generate_options == 'qt_gui' from gnuradio import qtgui - class $(class_name)(gr.top_block, Qt.QWidget): def __init__($param_str): @@ -118,7 +106,14 @@ class $(class_name)(gr.top_block, Qt.QWidget): self.top_layout.addLayout(self.top_grid_layout) self.settings = Qt.QSettings("GNU Radio", "$class_name") - self.restoreGeometry(self.settings.value("geometry").toByteArray()) + + try: + if StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"): + self.restoreGeometry(self.settings.value("geometry").toByteArray()) + else: + self.restoreGeometry(self.settings.value("geometry")) + except: + pass #elif $generate_options == 'no_gui' @@ -198,18 +193,6 @@ gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))]) $indent($var.get_var_make()) #end for ######################################################## -##Create Message Queues -######################################################## -#if $msgs - - $DIVIDER - # Message Queues - $DIVIDER -#end if -#for $msg in $msgs - $(msg.get_source().get_parent().get_id())_msgq_out = $(msg.get_sink().get_parent().get_id())_msgq_in = gr.msg_queue(2) -#end for -######################################################## ##Create Blocks ######################################################## #if $blocks @@ -338,19 +321,22 @@ $short_id#slurp def argument_parser(): - #set $desc_args = 'usage="%prog: [options]", option_class=eng_option' + #set $arg_parser_args = '' #if $flow_graph.get_option('description') - #set $desc_args += ', description=description' + #set $arg_parser_args = 'description=description' description = $repr($flow_graph.get_option('description')) #end if - parser = OptionParser($desc_args) + parser = ArgumentParser($arg_parser_args) #for $param in $parameters #set $type = $param.get_param('type').get_value() #if $type #silent $params_eq_list.append('%s=options.%s'%($param.get_id(), $param.get_id())) - parser.add_option( - "$make_short_id($param)", "--$param.get_id().replace('_', '-')", dest="$param.get_id()", type="$type", default=$make_default($type, $param), - help="Set $($param.get_param('label').get_evaluated() or $param.get_id()) [default=%default]") + parser.add_argument( + #if $make_short_id($param) + "$make_short_id($param)", #slurp + #end if + "--$param.get_id().replace('_', '-')", dest="$param.get_id()", type=$type, default=$make_default($type, $param), + help="Set $($param.get_param('label').get_evaluated() or $param.get_id()) [default=%(default)r]") #end if #end for return parser @@ -360,27 +346,15 @@ def argument_parser(): def main(top_block_cls=$(class_name), options=None): #if $parameters if options is None: - options, _ = argument_parser().parse_args() + options = argument_parser().parse_args() #end if #if $flow_graph.get_option('realtime_scheduling') if gr.enable_realtime_scheduling() != gr.RT_OK: print "Error: failed to enable real-time scheduling." #end if - #if $generate_options == 'wx_gui' - tb = top_block_cls($(', '.join($params_eq_list))) - #if $flow_graph.get_option('max_nouts') - tb.Run($flow_graph.get_option('run'), $flow_graph.get_option('max_nouts')) - #else - tb.Start($flow_graph.get_option('run')) - #for $m in $monitors - (tb.$m.get_id()).start() - #end for - tb.Wait() - #end if - #elif $generate_options == 'qt_gui' - from distutils.version import StrictVersion - if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"): + #if $generate_options == 'qt_gui' + if StrictVersion("4.5.0") <= StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"): style = gr.prefs().get_string('qtgui', 'style', 'raster') Qt.QApplication.setGraphicsSystem(style) qapp = Qt.QApplication(sys.argv) @@ -401,7 +375,7 @@ def main(top_block_cls=$(class_name), options=None): def quitting(): tb.stop() tb.wait() - qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting) + qapp.aboutToQuit.connect(quitting) #for $m in $monitors if $m.has_param('en'): if $m.get_param('en').get_value(): diff --git a/grc/core/utils/CMakeLists.txt b/grc/core/utils/CMakeLists.txt index 2528fbc43c..3ba65258a5 100644 --- a/grc/core/utils/CMakeLists.txt +++ b/grc/core/utils/CMakeLists.txt @@ -22,5 +22,4 @@ file(GLOB py_files "*.py") GR_PYTHON_INSTALL( FILES ${py_files} DESTINATION ${GR_PYTHON_DIR}/gnuradio/grc/core/utils - COMPONENT "grc" ) diff --git a/grc/core/utils/odict.py b/grc/core/utils/odict.py index 9d69082600..85927e869f 100644 --- a/grc/core/utils/odict.py +++ b/grc/core/utils/odict.py @@ -59,7 +59,7 @@ class odict(DictMixin): """ index = (pos_key is None) and len(self._keys) or self._keys.index(pos_key) if key in self._keys: - raise KeyError('Cannot insert, key "{0}" already exists'.format(str(key))) + raise KeyError('Cannot insert, key "{}" already exists'.format(str(key))) self._keys.insert(index+1, key) self._data[key] = val @@ -75,7 +75,7 @@ class odict(DictMixin): """ index = (pos_key is not None) and self._keys.index(pos_key) or 0 if key in self._keys: - raise KeyError('Cannot insert, key "{0}" already exists'.format(str(key))) + raise KeyError('Cannot insert, key "{}" already exists'.format(str(key))) self._keys.insert(index, key) self._data[key] = val diff --git a/grc/core/utils/shlex.py b/grc/core/utils/shlex.py new file mode 100644 index 0000000000..6b620fa396 --- /dev/null +++ b/grc/core/utils/shlex.py @@ -0,0 +1,47 @@ +# Copyright 2016 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. + +from __future__ import absolute_import + +import re +import shlex + +# back port from python3 + +_find_unsafe = re.compile(r'[^\w@%+=:,./-]').search + + +def _shlex_quote(s): + """Return a shell-escaped version of the string *s*.""" + if not s: + return "''" + if _find_unsafe(s) is None: + return s + + # use single quotes, and put single quotes into double quotes + # the string $'b is then quoted as '$'"'"'b' + return "'" + s.replace("'", "'\"'\"'") + "'" + + +if not hasattr(shlex, 'quote'): + quote = _shlex_quote +else: + quote = shlex.quote + +split = shlex.split |