diff options
Diffstat (limited to 'grc/core/Param.py')
-rw-r--r-- | grc/core/Param.py | 413 |
1 files changed, 0 insertions, 413 deletions
diff --git a/grc/core/Param.py b/grc/core/Param.py deleted file mode 100644 index 56855908ea..0000000000 --- a/grc/core/Param.py +++ /dev/null @@ -1,413 +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 - -import ast -import numbers -import re -import collections - -import six -from six.moves import builtins, filter, map, range, zip - -from . import Constants, blocks -from .base import Element -from .utils.descriptors import Evaluated, EvaluatedEnum, setup_names - -# Blacklist certain ids, its not complete, but should help -ID_BLACKLIST = ['self', 'options', 'gr', 'math', 'firdes'] + dir(builtins) -try: - from gnuradio import gr - ID_BLACKLIST.extend(attr for attr in dir(gr.top_block()) if not attr.startswith('_')) -except (ImportError, AttributeError): - pass - - -class TemplateArg(str): - """ - A cheetah template argument created from a param. - The str of this class evaluates to the param's to code method. - The use of this class as a dictionary (enum only) will reveal the enum opts. - The __call__ or () method can return the param evaluated to a raw python data type. - """ - - def __new__(cls, param): - value = param.to_code() - instance = str.__new__(cls, value) - setattr(instance, '_param', param) - return instance - - def __getitem__(self, item): - return str(self._param.get_opt(item)) if self._param.is_enum() else NotImplemented - - def __getattr__(self, item): - if not self._param.is_enum(): - raise AttributeError() - try: - return str(self._param.get_opt(item)) - except KeyError: - raise AttributeError() - - def __str__(self): - return str(self._param.to_code()) - - def __call__(self): - return self._param.get_evaluated() - - -@setup_names -class Param(Element): - - is_param = True - - name = Evaluated(str, default='no name') - dtype = EvaluatedEnum(Constants.PARAM_TYPE_NAMES, default='raw') - hide = EvaluatedEnum('none all part') - - # region init - def __init__(self, parent, id, label='', dtype='raw', default='', - options=None, option_labels=None, option_attributes=None, - category='', hide='none', **_): - """Make a new param from nested data""" - super(Param, self).__init__(parent) - self.key = id - self.name = label.strip() or id.title() - self.category = category or Constants.DEFAULT_PARAM_TAB - - self.dtype = dtype - self.value = self.default = str(default) - - self.options = self._init_options(options or [], option_labels or [], - option_attributes or {}) - self.hide = hide or 'none' - # end of args ######################################################## - - self._evaluated = None - self._stringify_flag = False - self._lisitify_flag = False - self._init = False - - @property - def template_arg(self): - return TemplateArg(self) - - def _init_options(self, values, labels, attributes): - """parse option and option attributes""" - options = collections.OrderedDict() - options.attributes = collections.defaultdict(dict) - - padding = [''] * max(len(values), len(labels)) - attributes = {key: value + padding for key, value in six.iteritems(attributes)} - - for i, option in enumerate(values): - # Test against repeated keys - if option in options: - raise KeyError('Value "{}" already exists in options'.format(option)) - # get label - try: - label = str(labels[i]) - except IndexError: - label = str(option) - # Store the option - options[option] = label - options.attributes[option] = {attrib: values[i] for attrib, values in six.iteritems(attributes)} - - default = next(iter(options)) if options else '' - if not self.value: - self.value = self.default = default - - if self.is_enum() and self.value not in options: - self.value = self.default = default # TODO: warn - # raise ValueError('The value {!r} is not in the possible values of {}.' - # ''.format(self.get_value(), ', '.join(self.options))) - return options - # endregion - - def __str__(self): - return 'Param - {}({})'.format(self.name, self.key) - - def __repr__(self): - return '{!r}.param[{}]'.format(self.parent, self.key) - - def is_enum(self): - return self.get_raw('dtype') == 'enum' - - def get_value(self): - value = self.value - if self.is_enum() and value not in self.options: - value = self.default - self.set_value(value) - return value - - def set_value(self, value): - # Must be a string - self.value = str(value) - - def set_default(self, value): - if self.default == self.value: - self.set_value(value) - self.default = str(value) - - def rewrite(self): - Element.rewrite(self) - del self.name - del self.dtype - del self.hide - - self._evaluated = None - try: - self._evaluated = self.evaluate() - except Exception as e: - self.add_error_message(str(e)) - - def validate(self): - """ - Validate the param. - The value must be evaluated and type must a possible type. - """ - Element.validate(self) - if self.dtype not in Constants.PARAM_TYPE_NAMES: - self.add_error_message('Type "{}" is not a possible type.'.format(self.dtype)) - - def get_evaluated(self): - return self._evaluated - - def evaluate(self): - """ - Evaluate the value. - - Returns: - evaluated type - """ - self._init = True - self._lisitify_flag = False - self._stringify_flag = False - dtype = self.dtype - expr = self.get_value() - - ######################### - # Enum Type - ######################### - if self.is_enum(): - return expr - - ######################### - # Numeric Types - ######################### - elif dtype in ('raw', 'complex', 'real', 'float', 'int', 'hex', 'bool'): - # Raise exception if python cannot evaluate this value - try: - value = self.parent_flowgraph.evaluate(expr) - except Exception as value: - raise Exception('Value "{}" cannot be evaluated:\n{}'.format(expr, value)) - # Raise an exception if the data is invalid - if dtype == 'raw': - return value - elif dtype == 'complex': - if not isinstance(value, Constants.COMPLEX_TYPES): - raise Exception('Expression "{}" is invalid for type complex.'.format(str(value))) - return value - elif dtype in ('real', 'float'): - if not isinstance(value, Constants.REAL_TYPES): - raise Exception('Expression "{}" is invalid for type float.'.format(str(value))) - return value - elif dtype == 'int': - if not isinstance(value, Constants.INT_TYPES): - raise Exception('Expression "{}" is invalid for type integer.'.format(str(value))) - return value - elif dtype == 'hex': - return hex(value) - elif dtype == 'bool': - if not isinstance(value, bool): - raise Exception('Expression "{}" is invalid for type bool.'.format(str(value))) - return value - else: - raise TypeError('Type "{}" not handled'.format(dtype)) - ######################### - # Numeric Vector Types - ######################### - elif dtype in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'): - default = [] - - if not expr: - return default # Turn a blank string into an empty list, so it will eval - - try: - value = self.parent.parent.evaluate(expr) - except Exception as value: - raise Exception('Value "{}" cannot be evaluated:\n{}'.format(expr, value)) - - if not isinstance(value, Constants.VECTOR_TYPES): - self._lisitify_flag = True - value = [value] - - # Raise an exception if the data is invalid - if dtype == 'complex_vector' and not all(isinstance(item, numbers.Complex) for item in value): - raise Exception('Expression "{}" is invalid for type complex vector.'.format(value)) - elif dtype in ('real_vector', 'float_vector') and not all(isinstance(item, numbers.Real) for item in value): - raise Exception('Expression "{}" is invalid for type float vector.'.format(value)) - elif dtype == 'int_vector' and not all(isinstance(item, Constants.INT_TYPES) for item in value): - raise Exception('Expression "{}" is invalid for type integer vector.'.format(str(value))) - return value - ######################### - # String Types - ######################### - elif dtype in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'): - # Do not check if file/directory exists, that is a runtime issue - try: - value = self.parent.parent.evaluate(expr) - if not isinstance(value, str): - raise Exception() - except: - self._stringify_flag = True - value = str(expr) - if dtype == '_multiline_python_external': - ast.parse(value) # Raises SyntaxError - return value - ######################### - # Unique ID Type - ######################### - elif dtype == 'id': - self.validate_block_id() - return expr - - ######################### - # Stream ID Type - ######################### - elif dtype == 'stream_id': - self.validate_stream_id() - return expr - - ######################### - # GUI Position/Hint - ######################### - elif dtype == 'gui_hint': - 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 = '?' - - # 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 - ######################### - elif dtype == 'import': - # New namespace - n = dict() - try: - exec(expr, n) - except ImportError: - raise Exception('Import "{}" failed.'.format(expr)) - except Exception: - raise Exception('Bad import syntax: "{}".'.format(expr)) - return [k for k in list(n.keys()) if str(k) != '__builtins__'] - - ######################### - else: - raise TypeError('Type "{}" not handled'.format(dtype)) - - def validate_block_id(self): - value = self.value - # Can python use this as a variable? - if not re.match(r'^[a-z|A-Z]\w*$', value): - raise Exception('ID "{}" must begin with a letter and may contain letters, numbers, ' - 'and underscores.'.format(value)) - if value in ID_BLACKLIST: - raise Exception('ID "{}" is blacklisted.'.format(value)) - block_names = [block.name for block in self.parent_flowgraph.iter_enabled_blocks()] - # Id should only appear once, or zero times if block is disabled - if self.key == 'id' and block_names.count(value) > 1: - raise Exception('ID "{}" is not unique.'.format(value)) - elif value not in block_names: - raise Exception('ID "{}" does not exist.'.format(value)) - return value - - def validate_stream_id(self): - value = self.value - stream_ids = [ - block.params['stream_id'].value - for block in self.parent_flowgraph.iter_enabled_blocks() - if isinstance(block, blocks.VirtualSink) - ] - # Check that the virtual sink's stream id is unique - if isinstance(self.parent_block, blocks.VirtualSink) and stream_ids.count(value) >= 2: - # Id should only appear once, or zero times if block is disabled - raise Exception('Stream ID "{}" is not unique.'.format(value)) - # Check that the virtual source's steam id is found - elif isinstance(self.parent_block, blocks.VirtualSource) and value not in stream_ids: - raise Exception('Stream ID "{}" is not found.'.format(value)) - - def to_code(self): - """ - Convert the value to code. - For string and list types, check the init flag, call evaluate(). - This ensures that evaluate() was called to set the xxxify_flags. - - Returns: - a string representing the code - """ - self._init = True - v = self.get_value() - t = self.dtype - # String types - if t in ('string', 'file_open', 'file_save', '_multiline', '_multiline_python_external'): - if not self._init: - self.evaluate() - return repr(v) if self._stringify_flag else v - - # Vector types - elif t in ('complex_vector', 'real_vector', 'float_vector', 'int_vector'): - if not self._init: - self.evaluate() - if self._lisitify_flag: - return '(%s, )' % v - else: - return '(%s)' % v - else: - return v - - def get_opt(self, item): - return self.options.attributes[self.get_value()][item] |