commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] [gnuradio] 14/22: runtime: refactor top/hier block pyt


From: git
Subject: [Commit-gnuradio] [gnuradio] 14/22: runtime: refactor top/hier block python wrappers
Date: Tue, 23 Dec 2014 09:38:58 +0000 (UTC)

This is an automated email from the git hooks/post-receive script.

jcorgan pushed a commit to branch master
in repository gnuradio.

commit 94a93636ea33685a22e673934006f96cff0c29aa
Author: Sebastian Koslowski <address@hidden>
Date:   Wed Dec 10 15:42:46 2014 +0100

    runtime: refactor top/hier block python wrappers
---
 gnuradio-runtime/python/gnuradio/gr/hier_block2.py | 131 ++++++++++--------
 gnuradio-runtime/python/gnuradio/gr/top_block.py   | 149 +++++++--------------
 2 files changed, 129 insertions(+), 151 deletions(-)

diff --git a/gnuradio-runtime/python/gnuradio/gr/hier_block2.py 
b/gnuradio-runtime/python/gnuradio/gr/hier_block2.py
index a7879a6..602e5f7 100644
--- a/gnuradio-runtime/python/gnuradio/gr/hier_block2.py
+++ b/gnuradio-runtime/python/gnuradio/gr/hier_block2.py
@@ -1,5 +1,5 @@
 """
-Copyright 2006, 2007 Free Software Foundation, Inc.
+Copyright 2006, 2007, 2014 Free Software Foundation, Inc.
 This file is part of GNU Radio
 
 GNU Radio Companion is free software; you can redistribute it and/or
@@ -17,11 +17,45 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
+from functools import wraps
+
 from runtime_swig import hier_block2_swig, dot_graph
 import pmt
 
-#
-# This hack forces a 'has-a' relationship to look like an 'is-a' one.
+
+def _multiple_endpoints(func):
+    def coerce_endpoint(endp, default_port=0):
+        if hasattr(endp, 'to_basic_block'):
+            return endp.to_basic_block(), default_port
+        try:
+            block, port = endp
+            return block.to_basic_block(), port
+        except ValueError:
+            raise ValueError("unable to coerce endpoint")
+    @wraps(func)
+    def wrapped(self, *points):
+        if not points:
+            raise ValueError("At least one endpoint required for " + 
func.__name__)
+        elif len(points) == 1:
+            func(points[0].to_basic_block())
+        else:
+            for src, dst in map(lambda i: points[i:i + 2], range(len(points) - 
1)):
+                func(self, *(coerce_endpoint(src) + coerce_endpoint(dst)))
+    return wrapped
+
+
+def _optional_endpoints(func):
+    @wraps(func)
+    def wrapped(self, src, srcport, dst=None, dstport=None):
+        if dst is None and dstport is None:
+            (src, srcport), (dst, dstport) = src, srcport
+        return func(self,
+                    src.to_basic_block(), srcport,
+                    dst.to_basic_block(), dstport)
+    return wrapped
+
+
+# This makes a 'has-a' relationship to look like an 'is-a' one.
 #
 # It allows Python classes to subclass this one, while passing through
 # method calls to the C++ class shared pointer from SWIG.
@@ -40,17 +74,23 @@ class hier_block2(object):
         """
         Create a hierarchical block with a given name and I/O signatures.
         """
-        self._hb = hier_block2_swig(name, input_signature, output_signature)
+        self._impl = hier_block2_swig(name, input_signature, output_signature)
 
     def __getattr__(self, name):
         """
         Pass-through member requests to the C++ object.
         """
-        if not hasattr(self, "_hb"):
-            raise RuntimeError("hier_block2: invalid state--did you forget to 
call gr.hier_block2.__init__ in a derived class?")
-        return getattr(self._hb, name)
+        if not hasattr(self, "_impl"):
+            raise RuntimeError(
+                "{0}: invalid state -- did you forget to call {0}.__init__ in "
+                "a derived class?".format(self.__class__.__name__))
+        return getattr(self._impl, name)
+
+    # FIXME: these should really be implemented
+    # in the original C++ class (gr_hier_block2), then they would all be 
inherited here
 
-    def connect(self, *points):
+    @_multiple_endpoints
+    def connect(self, *args):
         """
         Connect two or more block endpoints.  An endpoint is either a (block, 
port)
         tuple or a block instance.  In the latter case, the port number is 
assumed
@@ -62,69 +102,52 @@ class hier_block2(object):
         If multiple arguments are provided, connect will attempt to wire them 
in series,
         interpreting the endpoints as inputs or outputs as appropriate.
         """
+        self.primitive_connect(*args)
 
-        if len (points) < 1:
-            raise ValueError, ("connect requires at least one endpoint; %d 
provided." % (len (points),))
-        else:
-            if len(points) == 1:
-                self._hb.primitive_connect(points[0].to_basic_block())
-            else:
-                for i in range (1, len (points)):
-                    self._connect(points[i-1], points[i])
-
-    def _connect(self, src, dst):
-        (src_block, src_port) = self._coerce_endpoint(src)
-        (dst_block, dst_port) = self._coerce_endpoint(dst)
-        self._hb.primitive_connect(src_block.to_basic_block(), src_port,
-                                   dst_block.to_basic_block(), dst_port)
-
-    def _coerce_endpoint(self, endp):
-        if hasattr(endp, 'to_basic_block'):
-            return (endp, 0)
-        else:
-            if hasattr(endp, "__getitem__") and len(endp) == 2:
-                return endp # Assume user put (block, port)
-            else:
-                raise ValueError("unable to coerce endpoint")
-
-    def disconnect(self, *points):
+    @_multiple_endpoints
+    def disconnect(self, *args):
         """
-        Disconnect two endpoints in the flowgraph.
+        Disconnect two or more endpoints in the flowgraph.
 
         To disconnect the hierarchical block external inputs or outputs to 
internal block
         inputs or outputs, use 'self' in the connect call.
 
         If more than two arguments are provided, they are disconnected 
successively.
         """
+        self.primitive_disconnect(*args)
 
-        if len (points) < 1:
-            raise ValueError, ("disconnect requires at least one endpoint; %d 
provided." % (len (points),))
-        else:
-            if len (points) == 1:
-                self._hb.primitive_disconnect(points[0].to_basic_block())
-            else:
-                for i in range (1, len (points)):
-                    self._disconnect(points[i-1], points[i])
+    @_optional_endpoints
+    def msg_connect(self, *args):
+        """
+        Connect two message ports in the flowgraph.
 
-    def _disconnect(self, src, dst):
-        (src_block, src_port) = self._coerce_endpoint(src)
-        (dst_block, dst_port) = self._coerce_endpoint(dst)
-        self._hb.primitive_disconnect(src_block.to_basic_block(), src_port,
-                                      dst_block.to_basic_block(), dst_port)
+        If only two arguments are provided, they must be endpoints (block, 
port)
+        """
+        self.primitive_msg_connect(*args)
 
-    def msg_connect(self, src, srcport, dst, dstport):
-        self.primitive_msg_connect(src.to_basic_block(), srcport, 
dst.to_basic_block(), dstport);
+    @_optional_endpoints
+    def msg_disconnect(self, *args):
+        """
+        Disconnect two message ports in the flowgraph.
 
-    def msg_disconnect(self, src, srcport, dst, dstport):
-        self.primitive_msg_disconnect(src.to_basic_block(), srcport, 
dst.to_basic_block(), dstport);
+        If only two arguments are provided, they must be endpoints (block, 
port)
+        """
+        self.primitive_msg_disconnect(*args)
 
     def message_port_register_hier_in(self, portname):
+        """
+        Register a message port for this hier block
+        """
         self.primitive_message_port_register_hier_in(pmt.intern(portname))
 
     def message_port_register_hier_out(self, portname):
+        """
+        Register a message port for this hier block
+        """
         self.primitive_message_port_register_hier_out(pmt.intern(portname))
 
     def dot_graph(self):
-        '''Return graph representation in dot language'''
-        return dot_graph(self._hb)
-
+        """
+        Return graph representation in dot language
+        """
+        return dot_graph(self._impl)
diff --git a/gnuradio-runtime/python/gnuradio/gr/top_block.py 
b/gnuradio-runtime/python/gnuradio/gr/top_block.py
index 51d0ad5..8d81065 100644
--- a/gnuradio-runtime/python/gnuradio/gr/top_block.py
+++ b/gnuradio-runtime/python/gnuradio/gr/top_block.py
@@ -1,5 +1,5 @@
 """
-Copyright 2007 Free Software Foundation, Inc.
+Copyright 2007, 2014 Free Software Foundation, Inc.
 This file is part of GNU Radio
 
 GNU Radio Companion is free software; you can redistribute it and/or
@@ -17,7 +17,6 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-
 from runtime_swig import top_block_swig, \
     top_block_wait_unlocked, top_block_run_unlocked, \
     top_block_start_unlocked, top_block_stop_unlocked, \
@@ -26,32 +25,31 @@ from runtime_swig import top_block_swig, \
 #import gnuradio.gr.gr_threading as _threading
 import gr_threading as _threading
 
-#
-# There is no problem that can't be solved with an additional
-# level of indirection...
-#
-# This kludge allows ^C to interrupt top_block.run and top_block.wait
-#
-# The problem that we are working around is that Python only services
-# signals (e.g., KeyboardInterrupt) in its main thread.  If the main
-# thread is blocked in our C++ version of wait, even though Python's
-# SIGINT handler fires, and even though there may be other python
-# threads running, no one will know.  Thus instead of directly waiting
-# in the thread that calls wait (which is likely to be the Python main
-# thread), we create a separate thread that does the blocking wait,
-# and then use the thread that called wait to do a slow poll of an
-# event queue.  That thread, which is executing "wait" below is
-# interruptable, and if it sees a KeyboardInterrupt, executes a stop
-# on the top_block, then goes back to waiting for it to complete.
-# This ensures that the unlocked wait that was in progress (in the
-# _top_block_waiter thread) can complete, release its mutex and back
-# out.  If we don't do that, we are never able to clean up, and nasty
-# things occur like leaving the USRP transmitter sending a carrier.
-#
-# See also top_block.wait (below), which uses this class to implement
-# the interruptable wait.
-#
+from hier_block2 import hier_block2
+
 class _top_block_waiter(_threading.Thread):
+    """
+    This kludge allows ^C to interrupt top_block.run and top_block.wait
+
+    The problem that we are working around is that Python only services
+    signals (e.g., KeyboardInterrupt) in its main thread.  If the main
+    thread is blocked in our C++ version of wait, even though Python's
+    SIGINT handler fires, and even though there may be other python
+    threads running, no one will know.  Thus instead of directly waiting
+    in the thread that calls wait (which is likely to be the Python main
+    thread), we create a separate thread that does the blocking wait,
+    and then use the thread that called wait to do a slow poll of an
+    event queue.  That thread, which is executing "wait" below is
+    interruptable, and if it sees a KeyboardInterrupt, executes a stop
+    on the top_block, then goes back to waiting for it to complete.
+    This ensures that the unlocked wait that was in progress (in the
+    _top_block_waiter thread) can complete, release its mutex and back
+    out.  If we don't do that, we are never able to clean up, and nasty
+    things occur like leaving the USRP transmitter sending a carrier.
+
+    See also top_block.wait (below), which uses this class to implement
+    the interruptable wait.
+    """
     def __init__(self, tb):
         _threading.Thread.__init__(self)
         self.setDaemon(1)
@@ -73,7 +71,7 @@ class _top_block_waiter(_threading.Thread):
 
 
 #
-# This hack forces a 'has-a' relationship to look like an 'is-a' one.
+# This makes a 'has-a' relationship to look like an 'is-a' one.
 #
 # It allows Python classes to subclass this one, while passing through
 # method calls to the C++ class shared pointer from SWIG.
@@ -84,91 +82,48 @@ class _top_block_waiter(_threading.Thread):
 # to release the Python global interpreter lock before calling the actual
 # method in gr_top_block
 #
-class top_block(object):
+class top_block(hier_block2):
     """
     Top-level hierarchical block representing a flow-graph.
 
     This is a python wrapper around the C++ implementation to allow
     python subclassing.
     """
-    def __init__(self, name="top_block"):
-        self._tb = top_block_swig(name)
 
-    def __getattr__(self, name):
-        if not hasattr(self, "_tb"):
-            raise RuntimeError("top_block: invalid state--did you forget to 
call gr.top_block.__init__ in a derived class?")
-        return getattr(self._tb, name)
+    def __init__(self, name="top_block"):
+        """
+        Create a top block with a given name.
+        """
+        # not calling hier_block2.__init__, we set our own _impl
+        self._impl = top_block_swig(name)
 
     def start(self, max_noutput_items=10000000):
-        top_block_start_unlocked(self._tb, max_noutput_items)
+        """
+        Start the flowgraph with the given number of output items and return.
+        """
+        top_block_start_unlocked(self._impl, max_noutput_items)
 
     def stop(self):
-        top_block_stop_unlocked(self._tb)
+        """
+        Stop the flowgraph
+        """
+        top_block_stop_unlocked(self._impl)
 
     def run(self, max_noutput_items=10000000):
+        """
+        Start the flowgraph with the given number of output items and wait.
+        """
         self.start(max_noutput_items)
         self.wait()
 
     def wait(self):
-        _top_block_waiter(self._tb).wait()
-
-
-    # FIXME: these are duplicated from hier_block2.py; they should really be 
implemented
-    # in the original C++ class (gr_hier_block2), then they would all be 
inherited here
-
-    def connect(self, *points):
-        '''connect requires one or more arguments that can be coerced to 
endpoints.
-        If more than two arguments are provided, they are connected together 
successively.
-        '''
-        if len (points) < 1:
-            raise ValueError, ("connect requires at least one endpoint; %d 
provided." % (len (points),))
-        else:
-            if len(points) == 1:
-                self._tb.primitive_connect(points[0].to_basic_block())
-            else:
-                for i in range (1, len (points)):
-                    self._connect(points[i-1], points[i])
-
-    def msg_connect(self, src, srcport, dst, dstport):
-        self.primitive_msg_connect(src.to_basic_block(), srcport, 
dst.to_basic_block(), dstport);
-
-    def msg_disconnect(self, src, srcport, dst, dstport):
-        self.primitive_msg_disconnect(src.to_basic_block(), srcport, 
dst.to_basic_block(), dstport);
-
-    def _connect(self, src, dst):
-        (src_block, src_port) = self._coerce_endpoint(src)
-        (dst_block, dst_port) = self._coerce_endpoint(dst)
-        self._tb.primitive_connect(src_block.to_basic_block(), src_port,
-                                   dst_block.to_basic_block(), dst_port)
-
-    def _coerce_endpoint(self, endp):
-        if hasattr(endp, 'to_basic_block'):
-            return (endp, 0)
-        else:
-            if hasattr(endp, "__getitem__") and len(endp) == 2:
-                return endp # Assume user put (block, port)
-            else:
-                raise ValueError("unable to coerce endpoint")
-
-    def disconnect(self, *points):
-        '''disconnect requires one or more arguments that can be coerced to 
endpoints.
-        If more than two arguments are provided, they are disconnected 
successively.
-        '''
-        if len (points) < 1:
-            raise ValueError, ("disconnect requires at least one endpoint; %d 
provided." % (len (points),))
-        else:
-            if len(points) == 1:
-                self._tb.primitive_disconnect(points[0].to_basic_block())
-            else:
-                for i in range (1, len (points)):
-                    self._disconnect(points[i-1], points[i])
-
-    def _disconnect(self, src, dst):
-        (src_block, src_port) = self._coerce_endpoint(src)
-        (dst_block, dst_port) = self._coerce_endpoint(dst)
-        self._tb.primitive_disconnect(src_block.to_basic_block(), src_port,
-                                      dst_block.to_basic_block(), dst_port)
+        """
+        Wait for the flowgraph to finish running
+        """
+        _top_block_waiter(self._impl).wait()
 
     def dot_graph(self):
-        '''Return graph representation in dot language'''
-        return dot_graph_tb(self._tb)
+        """
+        Return graph representation in dot language
+        """
+        return dot_graph_tb(self._impl)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]