summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcus Müller <mmueller@gnuradio.org>2023-11-17 18:20:26 +0100
committerJeff Long <willcode4@gmail.com>2023-11-29 09:21:51 -0500
commit04f079431bd6a613de113a377db53732785b4907 (patch)
treead554bc0d4780314dfdadcd3fdd70f11aee45bc0
parentgrc/core/FlowGraph: remove unused imports (diff)
downloadgnuradio-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.py72
-rw-r--r--grc/core/blocks/_build.py3
-rw-r--r--grc/core/blocks/block.py9
-rw-r--r--grc/core/params/dtypes.py23
-rw-r--r--grc/core/params/param.py11
-rw-r--r--grc/core/platform.py6
-rw-r--r--grc/core/utils/expr_utils.py2
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.