diff options
author | Marcus Müller <mmueller@gnuradio.org> | 2023-11-17 18:20:26 +0100 |
---|---|---|
committer | Jeff Long <willcode4@gmail.com> | 2023-11-29 09:21:51 -0500 |
commit | 04f079431bd6a613de113a377db53732785b4907 (patch) | |
tree | ad554bc0d4780314dfdadcd3fdd70f11aee45bc0 | |
parent | grc/core/FlowGraph: remove unused imports (diff) | |
download | gnuradio-04f079431bd6a613de113a377db53732785b4907.tar.xz gnuradio-04f079431bd6a613de113a377db53732785b4907.zip |
grc/core: Type annotations, so I can somewhat sensibly work in my editor
Signed-off-by: Marcus Müller <mmueller@gnuradio.org>
(cherry picked from commit 14ba5eb076ab3b7dc4844e60f8dc880d558c9a43)
Signed-off-by: Jeff Long <willcode4@gmail.com>
-rw-r--r-- | grc/core/FlowGraph.py | 72 | ||||
-rw-r--r-- | grc/core/blocks/_build.py | 3 | ||||
-rw-r--r-- | grc/core/blocks/block.py | 9 | ||||
-rw-r--r-- | grc/core/params/dtypes.py | 23 | ||||
-rw-r--r-- | grc/core/params/param.py | 11 | ||||
-rw-r--r-- | grc/core/platform.py | 6 | ||||
-rw-r--r-- | grc/core/utils/expr_utils.py | 2 |
7 files changed, 68 insertions, 58 deletions
diff --git a/grc/core/FlowGraph.py b/grc/core/FlowGraph.py index 9542c7582..778683eee 100644 --- a/grc/core/FlowGraph.py +++ b/grc/core/FlowGraph.py @@ -12,10 +12,13 @@ import types import logging import shlex from operator import methodcaller, attrgetter +from typing import (List, Set, Optional, Iterator, Iterable, Tuple, Union, OrderedDict) from . import Messages from .base import Element +from .blocks import Block from .utils import expr_utils +from .params import Param log = logging.getLogger(__name__) @@ -24,7 +27,7 @@ class FlowGraph(Element): is_flow_graph = True - def __init__(self, parent): + def __init__(self, parent: Element): """ Make a flow graph from the arguments. @@ -35,7 +38,7 @@ class FlowGraph(Element): the flow graph object """ Element.__init__(self, parent) - self.options_block = self.parent_platform.make_block(self, 'options') + self.options_block: Block = self.parent_platform.make_block(self, 'options') self.blocks = [self.options_block] self.connections = set() @@ -46,10 +49,10 @@ class FlowGraph(Element): self.grc_file_path = '' - def __str__(self): + def __str__(self) -> str: return 'FlowGraph - {}({})'.format(self.get_option('title'), self.get_option('id')) - def imports(self): + def imports(self) -> List[str]: """ Get a set of all import statements (Python) in this flow graph namespace. @@ -58,7 +61,7 @@ class FlowGraph(Element): """ return [block.templates.render('imports') for block in self.iter_enabled_blocks()] - def get_variables(self): + def get_variables(self) -> List[str]: """ Get a list of all variables (Python) in this flow graph namespace. Exclude parameterized variables. @@ -70,7 +73,7 @@ class FlowGraph(Element): if block.is_variable] return expr_utils.sort_objects(variables, attrgetter('name'), methodcaller('get_var_make')) - def get_parameters(self): + def get_parameters(self) -> List[Element]: """ Get a list of all parameterized variables in this flow graph namespace. @@ -81,7 +84,7 @@ class FlowGraph(Element): if b.key == 'parameter'] return parameters - def get_snippets(self): + def _get_snippets(self) -> List[Element]: """ Get a set of all code snippets (Python) in this flow graph namespace. @@ -90,7 +93,7 @@ class FlowGraph(Element): """ return [b for b in self.iter_enabled_blocks() if b.key == 'snippet'] - def get_snippets_dict(self, section=None): + def get_snippets_dict(self, section=None) -> List[dict]: """ Get a dictionary of code snippet information for a particular section. @@ -100,7 +103,7 @@ class FlowGraph(Element): Returns: a list of code snippets dicts """ - snippets = self.get_snippets() + snippets = self._get_snippets() if not snippets: return [] @@ -125,7 +128,7 @@ class FlowGraph(Element): return output - def get_monitors(self): + def get_monitors(self) -> List[Element]: """ Get a list of all ControlPort monitors """ @@ -133,19 +136,19 @@ class FlowGraph(Element): if 'ctrlport_monitor' in b.key] return monitors - def get_python_modules(self): + def get_python_modules(self) -> Iterator[Tuple[str, str]]: """Iterate over custom code block ID and Source""" for block in self.iter_enabled_blocks(): if block.key == 'epy_module': yield block.name, block.params['source_code'].get_value() - def iter_enabled_blocks(self): + def iter_enabled_blocks(self) -> Iterator[Element]: """ Get an iterator of all blocks that are enabled and not bypassed. """ return (block for block in self.blocks if block.enabled) - def get_enabled_blocks(self): + def get_enabled_blocks(self) -> List[Element]: """ Get a list of all blocks that are enabled and not bypassed. @@ -154,7 +157,7 @@ class FlowGraph(Element): """ return list(self.iter_enabled_blocks()) - def get_bypassed_blocks(self): + def get_bypassed_blocks(self) -> List[Element]: """ Get a list of all blocks that are bypassed. @@ -163,7 +166,7 @@ class FlowGraph(Element): """ return [block for block in self.blocks if block.get_bypassed()] - def get_enabled_connections(self): + def get_enabled_connections(self) -> List[Element]: """ Get a list of all connections that are enabled. @@ -172,7 +175,7 @@ class FlowGraph(Element): """ return [connection for connection in self.connections if connection.enabled] - def get_option(self, key): + def get_option(self, key) -> Param.EvaluationType: """ Get the option for a given key. The option comes from the special options block. @@ -185,7 +188,7 @@ class FlowGraph(Element): """ return self.options_block.params[key].get_evaluated() - def get_run_command(self, file_path, split=False): + def get_run_command(self, file_path, split=False) -> Union[str, List[str]]: run_command = self.get_option('run_command') try: run_command = run_command.format( @@ -196,9 +199,9 @@ class FlowGraph(Element): raise ValueError( "Can't parse run command {!r}: {}".format(run_command, e)) - def get_imported_names(self): + def get_imported_names(self) -> Set[str]: """ - Get a lis of imported names. + Get a list of imported names. These names may not be used as id's Returns: @@ -209,18 +212,18 @@ class FlowGraph(Element): ############################################## # Access Elements ############################################## - def get_block(self, name): + def get_block(self, name) -> Block: for block in self.blocks: if block.name == name: return block raise KeyError('No block with name {!r}'.format(name)) - def get_elements(self): + def get_elements(self) -> List[Element]: elements = list(self.blocks) elements.extend(self.connections) return elements - def children(self): + def children(self) -> Iterable[Element]: return itertools.chain(self.blocks, self.connections) def rewrite(self): @@ -313,9 +316,9 @@ class FlowGraph(Element): namespace = self._reload_variables(namespace) self._eval_cache.clear() - def evaluate(self, expr, namespace=None, local_namespace=None): + def evaluate(self, expr: str, namespace: Optional[dict] = None, local_namespace: Optional[dict] = None): """ - Evaluate the expression. + Evaluate the expression within the specified global and local namespaces """ # Evaluate if not expr: @@ -329,7 +332,7 @@ class FlowGraph(Element): # Add/remove stuff ############################################## - def new_block(self, block_id, **kwargs): + def new_block(self, block_id, **kwargs) -> Block: """ Get a new block of the specified key. Add the block to the list of elements. @@ -369,13 +372,13 @@ class FlowGraph(Element): return connection - def disconnect(self, *ports): + def disconnect(self, *ports) -> None: to_be_removed = [con for con in self.connections if any(port in con for port in ports)] for con in to_be_removed: self.remove_element(con) - def remove_element(self, element): + def remove_element(self, element) -> None: """ Remove the element from the list of elements. If the element is a port, remove the whole block. @@ -399,7 +402,7 @@ class FlowGraph(Element): ############################################## # Import/Export Methods ############################################## - def export_data(self): + def export_data(self) -> OrderedDict[str, str]: """ Export this flow graph to nested data. Export all block and connection data. @@ -410,13 +413,13 @@ class FlowGraph(Element): def block_order(b): return not b.is_variable, b.name # todo: vars still first ?!? - def get_file_format_version(data): + def get_file_format_version(data) -> int: """Determine file format version based on available data""" if any(isinstance(c, dict) for c in data['connections']): return 2 return 1 - def sort_connection_key(connection_info): + def sort_connection_key(connection_info) -> List[str]: if isinstance(connection_info, dict): return [ connection_info.get('src_blk_id'), @@ -439,7 +442,7 @@ class FlowGraph(Element): } return data - def _build_depending_hier_block(self, block_id): + def _build_depending_hier_block(self, block_id) -> Optional[Block]: # we're before the initial fg update(), so no evaluated values! # --> use raw value instead path_param = self.options_block.params['hier_block_src_path'] @@ -453,7 +456,7 @@ class FlowGraph(Element): file_path, hier_only=True) return self.new_block(block_id) # can be None - def import_data(self, data): + def import_data(self, data) -> bool: """ Import blocks and connections into this flow graph. Clear this flow graph of all previous blocks and connections. @@ -461,6 +464,9 @@ class FlowGraph(Element): Args: data: the nested data odict + + Returns: + connection_error bool signifying whether a connection error happened. """ # Remove previous elements del self.blocks[:] @@ -558,7 +564,7 @@ class FlowGraph(Element): return had_connect_errors -def _update_old_message_port_keys(source_key, sink_key, source_block, sink_block): +def _update_old_message_port_keys(source_key, sink_key, source_block, sink_block) -> Tuple[str, str]: """ Backward compatibility for message port keys diff --git a/grc/core/blocks/_build.py b/grc/core/blocks/_build.py index 91ebef1a4..6fd917118 100644 --- a/grc/core/blocks/_build.py +++ b/grc/core/blocks/_build.py @@ -7,6 +7,7 @@ import itertools import re +from typing import Type from ..Constants import ADVANCED_PARAM_TAB from ..utils import to_list @@ -19,7 +20,7 @@ from ._templates import MakoTemplates def build(id, label='', category='', flags='', documentation='', value=None, asserts=None, - parameters=None, inputs=None, outputs=None, templates=None, cpp_templates=None, **kwargs): + parameters=None, inputs=None, outputs=None, templates=None, cpp_templates=None, **kwargs) -> Type[Block]: block_id = id cls = type(str(block_id), (Block,), {}) diff --git a/grc/core/blocks/block.py b/grc/core/blocks/block.py index 4abf63b17..4b36057a6 100644 --- a/grc/core/blocks/block.py +++ b/grc/core/blocks/block.py @@ -11,9 +11,7 @@ SPDX-License-Identifier: GPL-2.0-or-later import collections import itertools import copy - import re - import ast import typing @@ -21,6 +19,7 @@ from ._templates import MakoTemplates from ._flags import Flags from ..base import Element +from ..params import Param from ..utils.descriptors import lazy_property @@ -62,10 +61,8 @@ class Block(Element): param_factory = self.parent_platform.make_param port_factory = self.parent_platform.make_port - self.params = collections.OrderedDict( - (data['id'], param_factory(parent=self, **data)) - for data in self.parameters_data - ) + self.params: typing.OrderedDict[str, Param] = collections.OrderedDict( + (data['id'], param_factory(parent=self, **data)) for data in self.parameters_data) if self.key == 'options': self.params['id'].hide = 'part' diff --git a/grc/core/params/dtypes.py b/grc/core/params/dtypes.py index b93a6b83b..889c7b523 100644 --- a/grc/core/params/dtypes.py +++ b/grc/core/params/dtypes.py @@ -7,6 +7,8 @@ import re import builtins +import keyword +from typing import List, Callable from .. import blocks from .. import Constants @@ -25,7 +27,10 @@ except (ImportError, AttributeError): validators = {} -def validates(*dtypes): +def validates(*dtypes) -> Callable: + """ + Registers a function as validator for the type of element give as strings + """ def decorator(func): for dtype in dtypes: assert dtype in Constants.PARAM_TYPE_NAMES @@ -39,10 +44,9 @@ class ValidateError(Exception): @validates('id') -def validate_block_id(param, black_listed_ids): +def validate_block_id(param, black_listed_ids: List[str]) -> None: value = param.value # Can python use this as a variable? - if not re.match(r'^[a-z|A-Z]\w*$', value): raise ValidateError('ID "{}" must begin with a letter and may contain letters, numbers, ' 'and underscores.'.format(value)) @@ -57,24 +61,21 @@ def validate_block_id(param, black_listed_ids): raise ValidateError('ID "{}" is not unique.'.format(value)) elif value not in block_names: raise ValidateError('ID "{}" does not exist.'.format(value)) - return value @validates('name') -def validate_name(param, black_listed_ids): +def validate_name(param, _) -> None: # Name of a function or other block that will be generated literally not as a string value = param.value - # Allow blank to pass validation # Can python use this as a variable? if not re.match(r'^([a-z|A-Z]\w*)?$', value): raise ValidateError('ID "{}" must begin with a letter and may contain letters, numbers, ' 'and underscores.'.format(value)) - return value @validates('stream_id') -def validate_stream_id(param, black_listed_ids): +def validate_stream_id(param, _) -> None: value = param.value stream_ids = [ block.params['stream_id'].value @@ -91,7 +92,7 @@ def validate_stream_id(param, black_listed_ids): @validates('complex', 'real', 'float', 'int') -def validate_scalar(param, black_listed_ids): +def validate_scalar(param, _) -> None: valid_types = Constants.PARAM_TYPE_MAP[param.dtype] if not isinstance(param.get_evaluated(), valid_types): raise ValidateError('Expression {!r} is invalid for type {!r}.'.format( @@ -99,7 +100,7 @@ def validate_scalar(param, black_listed_ids): @validates('complex_vector', 'real_vector', 'float_vector', 'int_vector') -def validate_vector(param, black_listed_ids): +def validate_vector(param, _) -> None: # todo: check vector types if param.get_evaluated() is None: @@ -113,7 +114,7 @@ def validate_vector(param, black_listed_ids): @validates('gui_hint') -def validate_gui_hint(param, black_listed_ids): +def validate_gui_hint(param, _) -> None: try: # Only parse the param if there are no errors if len(param.get_error_messages()) > 0: diff --git a/grc/core/params/param.py b/grc/core/params/param.py index a4bcebcd8..7422a6019 100644 --- a/grc/core/params/param.py +++ b/grc/core/params/param.py @@ -8,6 +8,7 @@ import ast import collections import textwrap +from typing import Union, List from .. import Constants from ..base import Element @@ -22,6 +23,8 @@ attributed_str = type('attributed_str', (str,), {}) @setup_names class Param(Element): + EvaluationType = Union[None, str, complex, float, int, bool, List[str], List[complex], List[float], List[int]] + is_param = True name = Evaluated(str, default='no name') @@ -46,7 +49,7 @@ class Param(Element): self.hide = hide or 'none' # end of args ######################################################## - self._evaluated = None + self._evaluated: Param.EvaluationType = None self._stringify_flag = False self._lisitify_flag = False self.hostage_cells = set() @@ -165,7 +168,7 @@ class Param(Element): except dtypes.ValidateError as e: self.add_error_message(str(e)) - def get_evaluated(self): + def get_evaluated(self) -> EvaluationType: return self._evaluated def is_float(self, num): @@ -181,7 +184,7 @@ class Param(Element): except ValueError: return False - def evaluate(self): + def evaluate(self) -> EvaluationType: """ Evaluate the value. @@ -318,7 +321,7 @@ class Param(Element): ############################################## # GUI Hint ############################################## - def parse_gui_hint(self, expr): + def parse_gui_hint(self, expr: str) -> str: """ Parse/validate gui hint value. diff --git a/grc/core/platform.py b/grc/core/platform.py index 313947adc..fa8922a3b 100644 --- a/grc/core/platform.py +++ b/grc/core/platform.py @@ -11,11 +11,13 @@ from collections import ChainMap import os import logging from itertools import chain +from typing import Type from . import ( Messages, Constants, blocks, params, ports, errors, utils, schema_checker ) +from .blocks import Block from .Config import Config from .cache import Cache @@ -437,10 +439,10 @@ class Platform(Element): fg.import_data(data) return fg - def new_block_class(self, **data): + def new_block_class(self, **data) -> Type[Block]: return blocks.build(**data) - def make_block(self, parent, block_id, **kwargs): + def make_block(self, parent, block_id, **kwargs) -> Block: cls = self.block_classes[block_id] return cls(parent, **kwargs) diff --git a/grc/core/utils/expr_utils.py b/grc/core/utils/expr_utils.py index cfb127404..77483440e 100644 --- a/grc/core/utils/expr_utils.py +++ b/grc/core/utils/expr_utils.py @@ -44,7 +44,7 @@ def get_variable_dependencies(expr, vars): return set(v for v in vars if v in expr_toks) -def sort_objects(objects, get_id, get_expr): +def sort_objects(objects, get_id, get_expr) -> list: """ Sort a list of objects according to their expressions. |