gnuradio-companion/core/blocks/embedded_python.py
Oleksandr Kravchuk 43e6a43e3d python: Remove unnecessary 'from __future__ import'
All of the removed `from __future__ import` were needed in older
versions of Python (mostly 2.5.x and below) but later became mandatory
in most versions of Python 3 hence are not necessary anymore.

More specifically, according to __future__.py[1]:
- unicode_literals is part of Python since versions 2.6.0 and 3.0.0;
- print_function is part of Python since versions 2.6.0 and 3.0.0;
- absolute_import is part of Python since versions 2.5.0 and 3.0.0;
- division is part of Python since versions 2.2.0 and 3.0.0;

Get rid of those unnecessary imports to slightly clean up the codebase.

[1] https://github.com/python/cpython/blob/master/Lib/__future__.py
2020-08-03 11:40:27 +02:00

235 lines
7.7 KiB
Python

# Copyright 2015-16 Free Software Foundation, Inc.
# This file is part of GNU Radio
#
# SPDX-License-Identifier: GPL-2.0-or-later
#
from ast import literal_eval
from textwrap import dedent
from . import Block, register_build_in
from ._templates import MakoTemplates
from .. import utils
from ..base import Element
from ._build import build_params
DEFAULT_CODE = '''\
"""
Embedded Python Blocks:
Each time this file is saved, GRC will instantiate the first class it finds
to get ports and parameters of your block. The arguments to __init__ will
be the parameters. All of them are required to have default values!
"""
import numpy as np
from gnuradio import gr
class blk(gr.sync_block): # other base classes are basic_block, decim_block, interp_block
"""Embedded Python Block example - a simple multiply const"""
def __init__(self, example_param=1.0): # only default arguments here
"""arguments to this function show up as parameters in GRC"""
gr.sync_block.__init__(
self,
name='Embedded Python Block', # will show up in GRC
in_sig=[np.complex64],
out_sig=[np.complex64]
)
# if an attribute with the same name as a parameter is found,
# a callback is registered (properties work, too).
self.example_param = example_param
def work(self, input_items, output_items):
"""example: multiply with constant"""
output_items[0][:] = input_items[0] * self.example_param
return len(output_items[0])
'''
DOC = """
This block represents an arbitrary GNU Radio Python Block.
Its source code can be accessed through the parameter 'Code' which opens your editor. \
Each time you save changes in the editor, GRC will update the block. \
This includes the number, names and defaults of the parameters, \
the ports (stream and message) and the block name and documentation.
Block Documentation:
(will be replaced the docstring of your block class)
"""
@register_build_in
class EPyBlock(Block):
key = 'epy_block'
label = 'Python Block'
documentation = {'': DOC}
parameters_data = build_params(
params_raw=[
dict(label='Code', id='_source_code', dtype='_multiline_python_external',
default=DEFAULT_CODE, hide='part')
], have_inputs=True, have_outputs=True, flags=Block.flags, block_id=key
)
inputs_data = []
outputs_data = []
def __init__(self, flow_graph, **kwargs):
super(EPyBlock, self).__init__(flow_graph, **kwargs)
self.states['_io_cache'] = ''
self._epy_source_hash = -1
self._epy_reload_error = None
def rewrite(self):
Element.rewrite(self)
param_src = self.params['_source_code']
src = param_src.get_value()
src_hash = hash((self.name, src))
if src_hash == self._epy_source_hash:
return
try:
blk_io = utils.epy_block_io.extract(src)
except Exception as e:
self._epy_reload_error = ValueError(str(e))
try: # Load last working block io
blk_io_args = literal_eval(self.states['_io_cache'])
if len(blk_io_args) == 6:
blk_io_args += ([],) # add empty callbacks
blk_io = utils.epy_block_io.BlockIO(*blk_io_args)
except Exception:
return
else:
self._epy_reload_error = None # Clear previous errors
self.states['_io_cache'] = repr(tuple(blk_io))
# print "Rewriting embedded python block {!r}".format(self.name)
self._epy_source_hash = src_hash
self.label = blk_io.name or blk_io.cls
self.documentation = {'': blk_io.doc}
self.templates['imports'] = 'import ' + self.name
self.templates['make'] = '{mod}.{cls}({args})'.format(
mod=self.name,
cls=blk_io.cls,
args=', '.join('{0}=${{ {0} }}'.format(key) for key, _ in blk_io.params))
self.templates['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.make_param
params = {}
for key, value in self.params.copy().items():
if hasattr(value, '__epy_param__'):
params[key] = value
del self.params[key]
for id_, value in params_in_src:
try:
param = params[id_]
if param.default == param.value:
param.set_value(value)
param.default = str(value)
except KeyError: # need to make a new param
param = param_factory(
parent=self, id=id_, dtype='raw', value=value,
name=id_.replace('_', ' ').title(),
)
setattr(param, '__epy_param__', True)
self.params[id_] = param
def _update_ports(self, label, ports, port_specs, direction):
port_factory = self.parent_platform.make_port
ports_to_remove = list(ports)
iter_ports = iter(ports)
ports_new = []
port_current = next(iter_ports, None)
for key, port_type, vlen in port_specs:
reuse_port = (
port_current is not None and
port_current.dtype == port_type and
port_current.vlen == vlen 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), dtype=port_type, id=key)
if port_type == 'message':
n['name'] = key
n['optional'] = '1'
if vlen > 1:
n['vlen'] = str(vlen)
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
self.parent_flowgraph.disconnect(*ports_to_remove)
def validate(self):
super(EPyBlock, self).validate()
if self._epy_reload_error:
self.params['_source_code'].add_error_message(str(self._epy_reload_error))
@register_build_in
class EPyModule(Block):
key = 'epy_module'
label = 'Python Module'
documentation = {'': dedent("""
This block lets you embed a python module in your flowgraph.
Code you put in this module is accessible in other blocks using the ID of this
block. Example:
If you put
a = 2
def double(arg):
return 2 * arg
in a Python Module Block with the ID 'stuff' you can use code like
stuff.a # evals to 2
stuff.double(3) # evals to 6
to set parameters of other blocks in your flowgraph.
""")}
epy_flags=Block.flags
epy_flags.set(epy_flags.SHOW_ID)
parameters_data = build_params(
params_raw=[
dict(label='Code', id='source_code', dtype='_multiline_python_external',
default='# this module will be imported in the into your flowgraph',
hide='part')
], have_inputs=False, have_outputs=False, flags=epy_flags, block_id=key
)
templates = MakoTemplates(
imports='import ${ id } # embedded python module',
)