diff options
author | Sebastian Koslowski <koslowski@kit.edu> | 2016-07-15 23:25:54 +0200 |
---|---|---|
committer | Sebastian Koslowski <koslowski@kit.edu> | 2016-07-29 15:45:07 +0200 |
commit | 93ce3961a572da6ec3dbef1f24a22f4153acaa61 (patch) | |
tree | 274a78b5ce37f5305818c6ebab7ba495a2da4e12 /grc/core/Block.py | |
parent | 36f186bc46f528d95d9186955e91736d1fdb299e (diff) |
grc: refactor: Port, Param, Options init clean-up
Diffstat (limited to 'grc/core/Block.py')
-rw-r--r-- | grc/core/Block.py | 300 |
1 files changed, 145 insertions, 155 deletions
diff --git a/grc/core/Block.py b/grc/core/Block.py index 8ffb99b5bd..d37909b4b8 100644 --- a/grc/core/Block.py +++ b/grc/core/Block.py @@ -36,7 +36,7 @@ from . Constants import ( BLOCK_FLAG_THROTTLE, BLOCK_FLAG_DISABLE_BYPASS, BLOCK_FLAG_DEPRECATED, ) -from . Element import Element +from . Element import Element, lazy_property def _get_elem(iterable, key): @@ -53,21 +53,12 @@ class Block(Element): STATE_LABELS = ['disabled', 'enabled', 'bypassed'] - def __init__(self, flow_graph, n): - """ - Make a new block from nested data. - - Args: - flow_graph: the parent element - n: the nested odict + def __init__(self, parent, key, name, **n): + """Make a new block from nested data.""" + super(Block, self).__init__(parent) - Returns: - block a new block - """ - Element.__init__(self, parent=flow_graph) - - self.name = n['name'] - self.key = n['key'] + self.key = key + self.name = name self.category = [cat.strip() for cat in n.get('category', '').split('/') if cat.strip()] self.flags = n.get('flags', '') self._doc = n.get('doc', '').strip('\n').replace('\\\n', '') @@ -98,7 +89,6 @@ class Block(Element): has_sources=len(sources_n) ) - self.port_counters = [itertools.count(), itertools.count()] self.sources = self._init_ports(sources_n, direction='source') self.sinks = self._init_ports(sinks_n, direction='sink') self.active_sources = [] # on rewrite @@ -106,18 +96,15 @@ class Block(Element): self.states = {'_enabled': True} - self._epy_source_hash = -1 # for epy blocks - self._epy_reload_error = None - self._init_bus_ports(n) - def _add_param(self, key, name, value='', type='raw', **kwargs): - n = {'key': key, 'name': name, 'value': value, 'type': type} - n.update(kwargs) - self.params[key] = self.parent_platform.Param(block=self, n=n) - def _init_params(self, params_n, has_sources, has_sinks): - self._add_param(key='id', name='ID', type='id') + param_factory = self.parent_platform.get_new_param + + def add_param(key, **kwargs): + self.params[key] = param_factory(self, key=key, **kwargs) + + add_param(key='id', name='ID', type='id') # Virtual source/sink and pad source/sink blocks are # indistinguishable from normal GR blocks. Make explicit @@ -133,35 +120,40 @@ class Block(Element): self.flags += BLOCK_FLAG_DISABLE_BYPASS if not (is_virtual_or_pad or is_variable or self.key == 'options'): - self._add_param(key='alias', name='Block Alias', type='string', - hide='part', tab=ADVANCED_PARAM_TAB) + add_param(key='alias', name='Block Alias', type='string', + hide='part', tab=ADVANCED_PARAM_TAB) if not is_virtual_or_pad and (has_sources or has_sinks): - self._add_param(key='affinity', name='Core Affinity', type='int_vector', - hide='part', tab=ADVANCED_PARAM_TAB) + add_param(key='affinity', name='Core Affinity', type='int_vector', + hide='part', tab=ADVANCED_PARAM_TAB) if not is_virtual_or_pad and has_sources: - self._add_param(key='minoutbuf', name='Min Output Buffer', type='int', - hide='part', value='0', tab=ADVANCED_PARAM_TAB) - self._add_param(key='maxoutbuf', name='Max Output Buffer', type='int', - hide='part', value='0', tab=ADVANCED_PARAM_TAB) + add_param(key='minoutbuf', name='Min Output Buffer', type='int', + hide='part', value='0', tab=ADVANCED_PARAM_TAB) + add_param(key='maxoutbuf', name='Max Output Buffer', type='int', + hide='part', value='0', tab=ADVANCED_PARAM_TAB) + base_params_n = {n['key']: n for n in params_n} for param_n in params_n: - param = self.parent_platform.Param(block=self, n=param_n) - key = param.key + key = param_n['key'] if key in self.params: raise Exception('Key "{}" already exists in params'.format(key)) - self.params[key] = param - self._add_param(key='comment', name='Comment', type='_multiline', hide='part', - value='', tab=ADVANCED_PARAM_TAB) + extended_param_n = base_params_n.get(param_n.pop('base_key', None), {}) + extended_param_n.update(param_n) + self.params[key] = param_factory(self, **extended_param_n) + + add_param(key='comment', name='Comment', type='_multiline', hide='part', + value='', tab=ADVANCED_PARAM_TAB) def _init_ports(self, ports_n, direction): - port_cls = self.parent_platform.Port + port_factory = self.parent_platform.get_new_port ports = [] port_keys = set() - for port_n in ports_n: - port = port_cls(block=self, n=port_n, dir=direction) + stream_port_keys = itertools.count() + for i, port_n in enumerate(ports_n): + port_n.setdefault('key', str(next(stream_port_keys))) + port = port_factory(parent=self, direction=direction, **port_n) key = port.key if key in port_keys: raise Exception('Key "{}" already exists in {}'.format(key, direction)) @@ -169,61 +161,14 @@ class Block(Element): ports.append(port) return ports - def _run_checks(self): - """Evaluate the checks""" - for check in self._checks: - check_res = self.resolve_dependencies(check) - try: - if not self.parent.evaluate(check_res): - self.add_error_message('Check "{}" failed.'.format(check)) - except: - self.add_error_message('Check "{}" did not evaluate.'.format(check)) - - def _validate_generate_mode_compat(self): - """check if this is a GUI block and matches the selected generate option""" - current_generate_option = self.parent.get_option('generate_options') - - def check_generate_mode(label, flag, valid_options): - block_requires_mode = ( - flag in self.flags or self.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: {} ".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')) - - def _validate_var_value(self): - """or variables check the value (only if var_value is used)""" - if self.is_variable and self._var_value != '$value': - value = self._var_value - try: - value = self.get_var_value() - self.parent.evaluate(value) - except Exception as err: - self.add_error_message('Value "{}" cannot be evaluated:\n{}'.format(value, err)) - - def validate(self): - """ - Validate this block. - Call the base class validate. - Evaluate the checks: each check must evaluate to True. - """ - Element.validate(self) - self._run_checks() - self._validate_generate_mode_compat() - self._validate_var_value() - if self._epy_reload_error: - self.params['_source_code'].add_error_message(str(self._epy_reload_error)) - + ############################################## + # validation and rewrite + ############################################## def rewrite(self): """ Add and remove ports to adjust for the nports. """ Element.rewrite(self) - # Check and run any custom rewrite function for this block - getattr(self, 'rewrite_' + self.key, lambda: None)() # Adjust nports, disconnect hidden ports for ports in (self.sources, self.sinks): @@ -258,6 +203,55 @@ class Block(Element): self.active_sources = [p for p in self.get_sources_gui() if not p.get_hide()] self.active_sinks = [p for p in self.get_sinks_gui() if not p.get_hide()] + def validate(self): + """ + Validate this block. + Call the base class validate. + Evaluate the checks: each check must evaluate to True. + """ + Element.validate(self) + self._run_checks() + self._validate_generate_mode_compat() + self._validate_var_value() + + def _run_checks(self): + """Evaluate the checks""" + for check in self._checks: + check_res = self.resolve_dependencies(check) + try: + if not self.parent.evaluate(check_res): + self.add_error_message('Check "{}" failed.'.format(check)) + except: + self.add_error_message('Check "{}" did not evaluate.'.format(check)) + + def _validate_generate_mode_compat(self): + """check if this is a GUI block and matches the selected generate option""" + current_generate_option = self.parent.get_option('generate_options') + + def check_generate_mode(label, flag, valid_options): + block_requires_mode = ( + flag in self.flags or self.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: {} ".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')) + + def _validate_var_value(self): + """or variables check the value (only if var_value is used)""" + if self.is_variable and self._var_value != '$value': + value = self._var_value + try: + value = self.get_var_value() + self.parent.evaluate(value) + except Exception as err: + self.add_error_message('Value "{}" cannot be evaluated:\n{}'.format(value, err)) + + ############################################## + # Getters + ############################################## def get_imports(self, raw=False): """ Resolve all import statements. @@ -316,14 +310,7 @@ class Block(Element): # Also kept get_enabled and set_enabled to keep compatibility @property def state(self): - """ - Gets the block's current state. - - Returns: - ENABLED - 0 - BYPASSED - 1 - DISABLED - 2 - """ + """Gets the block's current state.""" try: return self.STATE_LABELS[int(self.states['_enabled'])] except ValueError: @@ -331,14 +318,7 @@ class Block(Element): @state.setter def state(self, value): - """ - Sets the state for the block. - - Args: - ENABLED - 0 - BYPASSED - 1 - DISABLED - 2 - """ + """Sets the state for the block.""" try: encoded = self.STATE_LABELS.index(value) except ValueError: @@ -425,11 +405,11 @@ class Block(Element): def get_comment(self): return self.params['comment'].get_value() - @property + @lazy_property def is_throtteling(self): return BLOCK_FLAG_THROTTLE in self.flags - @property + @lazy_property def is_deprecated(self): return BLOCK_FLAG_DEPRECATED in self.flags @@ -459,12 +439,11 @@ class Block(Element): return self.filter_bus_port(self.sources) def get_connections(self): - return sum([port.get_connections() for port in self.get_ports()], []) + return sum((port.get_connections() for port in self.get_ports()), []) ############################################## # Resolve ############################################## - def resolve_dependencies(self, tmpl): """ Resolve a paramater dependency with cheetah templates. @@ -515,7 +494,7 @@ class Block(Element): # Try to increment the enum by direction try: - keys = type_param.get_option_keys() + keys = list(type_param.options.keys()) old_index = keys.index(type_param.get_value()) new_index = (old_index + direction + len(keys)) % len(keys) type_param.set_value(keys[new_index]) @@ -693,7 +672,7 @@ class Block(Element): for i in range(len(struct)): n['key'] = str(len(ports)) n = dict(n) - port = self.parent.parent.Port(block=self, n=n, dir=direc) + port = self.parent_platform.get_new_port(self, direction=direc, **n) ports.append(port) elif any('bus' == p.get_type() for p in ports): for elt in get_p_gui(): @@ -716,15 +695,14 @@ class Block(Element): class EPyBlock(Block): - def __init__(self, flow_graph, n): - super(EPyBlock, self).__init__(flow_graph, n) + def __init__(self, flow_graph, **n): + super(EPyBlock, self).__init__(flow_graph, **n) self._epy_source_hash = -1 # for epy blocks self._epy_reload_error = None + def rewrite(self): + Element.rewrite(self) - def rewrite_epy_block(self): - flowgraph = self.parent_flowgraph - platform = self.parent_platform param_blk = self.params['_io_cache'] param_src = self.params['_source_code'] @@ -758,53 +736,65 @@ class EPyBlock(Block): self._make = '{0}.{1}({2})'.format(self.get_id(), blk_io.cls, ', '.join( '{0}=${{ {0} }}'.format(key) for key, _ in blk_io.params)) self._callbacks = ['{0} = ${{ {0} }}'.format(attr) for attr in blk_io.callbacks] + self._update_params(blk_io.params) + self._update_ports('in', self.sinks, blk_io.sinks, 'sink') + self._update_ports('out', self.sources, blk_io.sources, 'source') + + super(EPyBlock, self).rewrite() + def _update_params(self, params_in_src): + param_factory = self.parent_platform.get_new_param params = {} for param in list(self.params): if hasattr(param, '__epy_param__'): params[param.key] = param del self.params[param.key] - for key, value in blk_io.params: + for key, value in params_in_src: try: param = params[key] - param.set_default(value) + if param.default == param.value: + param.set_value(value) + param.default = str(value) except KeyError: # need to make a new param - name = key.replace('_', ' ').title() - n = dict(name=name, key=key, type='raw', value=value) - param = platform.Param(block=self, n=n) + param = param_factory( + parent=self, key=key, type='raw', value=value, + name=key.replace('_', ' ').title(), + ) setattr(param, '__epy_param__', True) self.params[key] = param - def update_ports(label, ports, port_specs, direction): - ports_to_remove = list(ports) - iter_ports = iter(ports) - ports_new = [] - port_current = next(iter_ports, None) - for key, port_type in port_specs: - reuse_port = ( - port_current is not None and - port_current.get_type() == port_type and - (key.isdigit() or port_current.key == key) - ) - if reuse_port: - ports_to_remove.remove(port_current) - port, port_current = port_current, next(iter_ports, None) - else: - n = dict(name=label + str(key), type=port_type, key=key) - if port_type == 'message': - n['name'] = key - n['optional'] = '1' - port = platform.Port(block=self, n=n, dir=direction) - ports_new.append(port) - # replace old port list with new one - del ports[:] - ports.extend(ports_new) - # remove excess port connections - for port in ports_to_remove: - for connection in port.get_connections(): - flowgraph.remove_element(connection) - - update_ports('in', self.sinks, blk_io.sinks, 'sink') - update_ports('out', self.sources, blk_io.sources, 'source') - self.rewrite() + def _update_ports(self, label, ports, port_specs, direction): + port_factory = self.parent_platform.get_new_port + ports_to_remove = list(ports) + iter_ports = iter(ports) + ports_new = [] + port_current = next(iter_ports, None) + for key, port_type in port_specs: + reuse_port = ( + port_current is not None and + port_current.get_type() == port_type and + (key.isdigit() or port_current.key == key) + ) + if reuse_port: + ports_to_remove.remove(port_current) + port, port_current = port_current, next(iter_ports, None) + else: + n = dict(name=label + str(key), type=port_type, key=key) + if port_type == 'message': + n['name'] = key + n['optional'] = '1' + port = port_factory(self, direction=direction, **n) + ports_new.append(port) + # replace old port list with new one + del ports[:] + ports.extend(ports_new) + # remove excess port connections + for port in ports_to_remove: + for connection in port.get_connections(): + self.parent_flowgraph.remove_element(connection) + + def validate(self): + super(EPyBlock, self).validate() + if self._epy_reload_error: + self.params['_source_code'].add_error_message(str(self._epy_reload_error)) |