qpid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From g...@apache.org
Subject [2/9] qpid-proton git commit: Restructure the examples and install them all
Date Mon, 16 Feb 2015 19:20:30 GMT
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/reactor/global-logger.py
----------------------------------------------------------------------
diff --git a/examples/python/reactor/global-logger.py b/examples/python/reactor/global-logger.py
new file mode 100755
index 0000000..bc3bc56
--- /dev/null
+++ b/examples/python/reactor/global-logger.py
@@ -0,0 +1,58 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import time
+from proton.reactor import Reactor
+
+# Not every event goes to the reactor's event handler. If we have a
+# separate handler for something like a scheduled task, then those
+# events aren't logged by the logger associated with the reactor's
+# handler. Sometimes this is useful if you don't want to see them, but
+# sometimes you want the global picture.
+
+class Logger:
+
+    def on_unhandled(self, name, event):
+        print "LOG:", name, event
+
+class Task:
+
+    def on_timer_task(self, event):
+        print "Mission accomplished!"
+
+class Program:
+
+    def on_reactor_init(self, event):
+        print "Hello, World!"
+        event.reactor.schedule(0, Task())
+
+    def on_reactor_final(self, event):
+        print "Goodbye, World!"
+
+r = Reactor(Program())
+
+# In addition to having a regular handler, the reactor also has a
+# global handler that sees every event. By adding the Logger to the
+# global handler instead of the regular handler, we can log every
+# single event that occurs in the system regardless of whether or not
+# there are specific handlers associated with the objects that are the
+# target of those events.
+r.global_handler.add(Logger())
+r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/reactor/goodbye-world.py
----------------------------------------------------------------------
diff --git a/examples/python/reactor/goodbye-world.py b/examples/python/reactor/goodbye-world.py
new file mode 100755
index 0000000..44bcf7c
--- /dev/null
+++ b/examples/python/reactor/goodbye-world.py
@@ -0,0 +1,46 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from proton.reactor import Reactor
+
+# So far the reactive hello-world doesn't look too different from a
+# regular old non-reactive hello-world. The on_reactor_init method can
+# be used roughly as a 'main' method would. A program that only uses
+# that one event, however, isn't going to be very reactive. By using
+# other events, we can write a fully reactive program.
+
+class Program:
+
+    # As before we handle the reactor init event.
+    def on_reactor_init(self, event):
+        print "Hello, World!"
+
+    # In addition to an initial event, the reactor also produces an
+    # event when it is about to exit. This may not behave much
+    # differently than just putting the goodbye print statement inside
+    # on_reactor_init, but as we grow our program, this piece of it
+    # will always be what happens last, and will always happen
+    # regardless of what other paths the main logic of our program
+    # might take.
+    def on_reactor_final(self, event):
+        print "Goodbye, World!"
+
+r = Reactor(Program())
+r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/reactor/handlers.py
----------------------------------------------------------------------
diff --git a/examples/python/reactor/handlers.py b/examples/python/reactor/handlers.py
new file mode 100755
index 0000000..ed3a94d
--- /dev/null
+++ b/examples/python/reactor/handlers.py
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import time
+from proton.reactor import Reactor
+
+
+class World:
+
+    def on_reactor_init(self, event):
+        print "World!"
+
+class Goodbye:
+
+    def on_reactor_final(self, event):
+        print "Goodbye, World!"
+
+class Hello:
+
+    def __init__(self):
+        # When an event dispatches itself to a handler, it also checks
+        # if that handler has a "handlers" attribute and dispatches
+        # the event to any children.
+        self.handlers = [World(), Goodbye()]
+
+    # The parent handler always receives the event first.
+    def on_reactor_init(self, event):
+        print "Hello",
+
+r = Reactor(Hello())
+r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/reactor/hello-world.py
----------------------------------------------------------------------
diff --git a/examples/python/reactor/hello-world.py b/examples/python/reactor/hello-world.py
new file mode 100755
index 0000000..c685c73
--- /dev/null
+++ b/examples/python/reactor/hello-world.py
@@ -0,0 +1,42 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from proton.reactor import Reactor
+
+# The proton reactor provides a general purpose event processing
+# library for writing reactive programs. A reactive program is defined
+# by a set of event handlers. An event handler is just any class or
+# object that defines the "on_<event>" methods that it cares to
+# handle.
+
+class Program:
+
+    # The reactor init event is produced by the reactor itself when it
+    # starts.
+    def on_reactor_init(self, event):
+        print "Hello, World!"
+
+# When you construct a reactor, you give it a handler.
+r = Reactor(Program())
+
+# When you call run, the reactor will process events. The reactor init
+# event is what kicks off everything else. When the reactor has no
+# more events to process, it exits.
+r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/reactor/reactor-logger.py
----------------------------------------------------------------------
diff --git a/examples/python/reactor/reactor-logger.py b/examples/python/reactor/reactor-logger.py
new file mode 100755
index 0000000..c07e9b9
--- /dev/null
+++ b/examples/python/reactor/reactor-logger.py
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import time
+from proton.reactor import Reactor
+
+class Logger:
+
+    def on_unhandled(self, name, event):
+        print "LOG:", name, event
+
+class Program:
+
+    def on_reactor_init(self, event):
+        print "Hello, World!"
+
+    def on_reactor_final(self, event):
+        print "Goodbye, World!"
+
+# You can pass multiple handlers to a reactor when you construct it.
+# Each of these handlers will see every event the reactor sees. By
+# combining this with on_unhandled, you can log each event that goes
+# to the reactor.
+r = Reactor(Program(), Logger())
+r.run()
+
+# Note that if you wanted to add the logger later, you could also
+# write the above as below. All arguments to the reactor are just
+# added to the default handler for the reactor.
+
+def logging_enabled():
+    return False
+
+r = Reactor(Program())
+if logging_enabled():
+    r.handler.add(Logger())
+r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/reactor/recv.py
----------------------------------------------------------------------
diff --git a/examples/python/reactor/recv.py b/examples/python/reactor/recv.py
new file mode 100755
index 0000000..aa56472
--- /dev/null
+++ b/examples/python/reactor/recv.py
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from proton import Message
+from proton.reactor import Reactor
+from proton.handlers import CHandshaker, CFlowController
+
+class Program:
+
+    def __init__(self):
+        self.handlers = [CHandshaker(), CFlowController()]
+        self.message = Message()
+
+    def on_reactor_init(self, event):
+        # Create an amqp acceptor.
+        event.reactor.acceptor("0.0.0.0", 5672)
+        # There is an optional third argument to the Reactor.acceptor
+        # call. Using it, we could supply a handler here that would
+        # become the handler for all accepted connections. If we omit
+        # it, the reactor simply inherets all the connection events.
+
+    def on_delivery(self, event):
+        # XXX: we could make rcv.recv(self.message) work here to
+        # compliment the similar thing on send
+        rcv = event.receiver
+        if rcv and self.message.recv(rcv):
+            print self.message
+            event.delivery.settle()
+
+r = Reactor(Program())
+r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/reactor/scheduling.py
----------------------------------------------------------------------
diff --git a/examples/python/reactor/scheduling.py b/examples/python/reactor/scheduling.py
new file mode 100755
index 0000000..f822f68
--- /dev/null
+++ b/examples/python/reactor/scheduling.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import time
+from proton.reactor import Reactor
+
+class Program:
+
+    def on_reactor_init(self, event):
+        self.start = time.time()
+        print "Hello, World!"
+
+        # We can schedule a task event for some point in the future.
+        # This will cause the reactor to stick around until it has a
+        # chance to process the event.
+
+        # The first argument is the delay. The second argument is the
+        # handler for the event. We are just using self for now, but
+        # we could pass in another object if we wanted.
+        task = event.reactor.schedule(1.0, self)
+
+        # We can ignore the task if we want to, but we can also use it
+        # to pass stuff to the handler.
+        task.something_to_say = "Yay"
+
+    def on_timer_task(self, event):
+        task = event.context # xxx: don't have a task property on event yet
+        print task.something_to_say, "my task is complete!"
+
+    def on_reactor_final(self, event):
+        print "Goodbye, World! (after %s long seconds)" % (time.time() - self.start)
+
+r = Reactor(Program())
+r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/reactor/send.py
----------------------------------------------------------------------
diff --git a/examples/python/reactor/send.py b/examples/python/reactor/send.py
new file mode 100755
index 0000000..7b95502
--- /dev/null
+++ b/examples/python/reactor/send.py
@@ -0,0 +1,87 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import sys
+from proton import Message
+from proton.reactor import Reactor
+from proton.handlers import CHandshaker
+
+# This is a send in terms of low level AMQP events. There are handlers
+# that can streamline this significantly if you don't want to worry
+# about all the details, but it is useful to see how the AMQP engine
+# classes interact with handlers and events.
+
+class Send:
+
+    def __init__(self, host, message):
+        self.host = host
+        self.message = message
+        # Use the handlers property to add some default handshaking
+        # behaviour.
+        self.handlers = [CHandshaker()]
+
+    def on_connection_init(self, event):
+        conn = event.connection
+        conn.hostname = self.host
+
+        # Every session or link could have their own handler(s) if we
+        # wanted simply by setting the "handler" slot on the
+        # given session or link.
+        ssn = conn.session()
+
+        # If a link doesn't have an event handler, the events go to
+        # its parent session. If the session doesn't have a handler
+        # the events go to its parent connection. If the connection
+        # doesn't have a handler, the events go to the reactor.
+        snd = ssn.sender("sender")
+        conn.open()
+        ssn.open()
+        snd.open()
+
+    def on_link_flow(self, event):
+        snd = event.sender
+        if snd.credit > 0:
+            dlv = snd.send(self.message)
+            dlv.settle()
+            snd.close()
+            snd.session.close()
+            snd.connection.close()
+
+class Program:
+
+    def __init__(self, hostname, content):
+        self.hostname = hostname
+        self.content = content
+
+    def on_reactor_init(self, event):
+        # You can use the connection method to create AMQP connections.
+
+        # This connection's handler is the Send object. All the events
+        # for this connection will go to the Send object instead of
+        # going to the reactor. If you were to omit the Send object,
+        # all the events would go to the reactor.
+        event.reactor.connection(Send(self.hostname, Message(self.content)))
+
+args = sys.argv[1:]
+hostname = args.pop() if args else "localhost"
+content = args.pop() if args else "Hello World!"
+
+r = Reactor(Program(hostname, content))
+r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/reactor/tornado-hello-world.py
----------------------------------------------------------------------
diff --git a/examples/python/reactor/tornado-hello-world.py b/examples/python/reactor/tornado-hello-world.py
new file mode 100755
index 0000000..fa8ca83
--- /dev/null
+++ b/examples/python/reactor/tornado-hello-world.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import tornado.ioloop
+from tornado_app import TornadoApp
+
+# The proton reactor provides a general purpose event processing
+# library for writing reactive programs. A reactive program is defined
+# by a set of event handlers. An event handler is just any class or
+# object that defines the "on_<event>" methods that it cares to
+# handle.
+
+class Program:
+
+    # The reactor init event is produced by the reactor itself when it
+    # starts.
+    def on_reactor_init(self, event):
+        print "Hello, World!"
+
+# The TornadoApp integrates a Reactor into tornado's ioloop.
+TornadoApp(Program())
+
+# Now the tornado main loop will behave like the reactor's main loop.
+tornado.ioloop.IOLoop.instance().start()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/reactor/tornado-send.py
----------------------------------------------------------------------
diff --git a/examples/python/reactor/tornado-send.py b/examples/python/reactor/tornado-send.py
new file mode 100755
index 0000000..54b8618
--- /dev/null
+++ b/examples/python/reactor/tornado-send.py
@@ -0,0 +1,82 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import sys, tornado.ioloop
+from tornado_app import TornadoApp
+from proton import Message
+from proton.handlers import CHandshaker
+
+class Send:
+
+    def __init__(self, host, message):
+        self.host = host
+        self.message = message
+        # Use the handlers property to add some default handshaking
+        # behaviour.
+        self.handlers = [CHandshaker()]
+
+    def on_connection_init(self, event):
+        conn = event.connection
+        conn.hostname = self.host
+
+        # Every session or link could have their own handler(s) if we
+        # wanted simply by setting the "handler" slot on the
+        # given session or link.
+        ssn = conn.session()
+
+        # If a link doesn't have an event handler, the events go to
+        # its parent session. If the session doesn't have a handler
+        # the events go to its parent connection. If the connection
+        # doesn't have a handler, the events go to the reactor.
+        snd = ssn.sender("sender")
+        conn.open()
+        ssn.open()
+        snd.open()
+
+    def on_link_flow(self, event):
+        snd = event.sender
+        if snd.credit > 0:
+            dlv = snd.send(self.message)
+            dlv.settle()
+            snd.close()
+            snd.session.close()
+            snd.connection.close()
+
+class Program:
+
+    def __init__(self, hostname, content):
+        self.hostname = hostname
+        self.content = content
+
+    def on_reactor_init(self, event):
+        # You can use the connection method to create AMQP connections.
+
+        # This connection's handler is the Send object. All the events
+        # for this connection will go to the Send object instead of
+        # going to the reactor. If you were to omit the Send object,
+        # all the events would go to the reactor.
+        event.reactor.connection(Send(self.hostname, Message(self.content)))
+
+args = sys.argv[1:]
+hostname = args.pop() if args else "localhost"
+content = args.pop() if args else "Hello World!"
+
+TornadoApp(Program(hostname, content))
+tornado.ioloop.IOLoop.instance().start()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/reactor/tornado_app.py
----------------------------------------------------------------------
diff --git a/examples/python/reactor/tornado_app.py b/examples/python/reactor/tornado_app.py
new file mode 100644
index 0000000..966ac8b
--- /dev/null
+++ b/examples/python/reactor/tornado_app.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import tornado.ioloop
+from proton.reactor import Reactor
+from proton.handlers import IOHandler
+
+class TornadoApp:
+
+    def __init__(self, *args):
+        self.reactor = Reactor(*args)
+        self.reactor.global_handler = self
+        self.io = IOHandler()
+        self.loop = tornado.ioloop.IOLoop.instance()
+        self.count = 0
+        self.reactor.start()
+        self.reactor.process()
+
+    def on_reactor_quiesced(self, event):
+        event.reactor.yield_()
+
+    def on_unhandled(self, name, event):
+        event.dispatch(self.io)
+
+    def _events(self, sel):
+        events = self.loop.ERROR
+        if sel.reading:
+            events |= self.loop.READ
+        if sel.writing:
+            events |= self.loop.WRITE
+        return events
+
+    def _schedule(self, sel):
+        if sel.deadline:
+            self.loop.add_timeout(sel.deadline, lambda: self.expired(sel))
+
+    def _expired(self, sel):
+        sel.expired()
+
+    def _process(self):
+        self.reactor.process()
+        if not self.reactor.quiesced:
+            self.loop.add_callback(self._process)
+
+    def _callback(self, sel, events):
+        if self.loop.READ & events:
+            sel.readable()
+        if self.loop.WRITE & events:
+            sel.writable()
+        self._process()
+
+    def on_selectable_init(self, event):
+        sel = event.context
+        if sel.fileno() >= 0:
+            self.loop.add_handler(sel.fileno(), lambda fd, events: self._callback(sel, events), self._events(sel))
+        self._schedule(sel)
+        self.count += 1
+
+    def on_selectable_updated(self, event):
+        sel = event.context
+        if sel.fileno() > 0:
+            self.loop.update_handler(sel.fileno(), self._events(sel))
+        self._schedule(sel)
+
+    def on_selectable_final(self, event):
+        sel = event.context
+        if sel.fileno() > 0:
+            self.loop.remove_handler(sel.fileno())
+        sel.release()
+        self.count -= 1
+        if self.count == 0:
+            self.loop.add_callback(self._stop)
+
+    def _stop(self):
+        self.reactor.stop()
+        self.loop.stop()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/reactor/unhandled.py
----------------------------------------------------------------------
diff --git a/examples/python/reactor/unhandled.py b/examples/python/reactor/unhandled.py
new file mode 100755
index 0000000..3734a71
--- /dev/null
+++ b/examples/python/reactor/unhandled.py
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import time
+from proton.reactor import Reactor
+
+class Program:
+
+    # If an event occurs and its handler doesn't have an on_<event>
+    # method, the reactor will attempt to call the on_unhandled method
+    # if it exists. This can be useful not only for debugging, but for
+    # logging and for delegating/inheritance.
+    def on_unhandled(self, name, event):
+        print name, event
+
+r = Reactor(Program())
+r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/recurring_timer.py
----------------------------------------------------------------------
diff --git a/examples/python/recurring_timer.py b/examples/python/recurring_timer.py
new file mode 100755
index 0000000..a39791d
--- /dev/null
+++ b/examples/python/recurring_timer.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from proton.reactor import Container, Handler
+
+class Recurring(Handler):
+    def __init__(self, period):
+        self.period = period
+
+    def on_reactor_init(self, event):
+        self.container = event.reactor
+        self.container.schedule(self.period, self)
+
+    def on_timer_task(self, event):
+        print "Tick..."
+        self.container.schedule(self.period, self)
+
+try:
+    container = Container(Recurring(1.0))
+    container.run()
+except KeyboardInterrupt:
+    container.stop()
+    print
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/recurring_timer_tornado.py
----------------------------------------------------------------------
diff --git a/examples/python/recurring_timer_tornado.py b/examples/python/recurring_timer_tornado.py
new file mode 100755
index 0000000..1f1c0e7
--- /dev/null
+++ b/examples/python/recurring_timer_tornado.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import time
+from proton.reactor import Handler
+from proton_tornado import TornadoLoop
+
+class Recurring(Handler):
+    def __init__(self, period):
+        self.period = period
+
+    def on_start(self, event):
+        self.container = event.container
+        self.container.schedule(time.time() + self.period, subject=self)
+
+    def on_timer(self, event):
+        print "Tick..."
+        self.container.schedule(time.time() + self.period, subject=self)
+
+try:
+    container = TornadoLoop(Recurring(1.0))
+    container.run()
+except KeyboardInterrupt:
+    container.stop()
+    print
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/selected_recv.py
----------------------------------------------------------------------
diff --git a/examples/python/selected_recv.py b/examples/python/selected_recv.py
new file mode 100755
index 0000000..351d4ef
--- /dev/null
+++ b/examples/python/selected_recv.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from proton.reactor import Container, Selector
+from proton.handlers import MessagingHandler
+
+class Recv(MessagingHandler):
+    def __init__(self):
+        super(Recv, self).__init__()
+
+    def on_start(self, event):
+        conn = event.container.connect("localhost:5672")
+        event.container.create_receiver(conn, "examples", options=Selector(u"colour = 'green'"))
+
+    def on_message(self, event):
+        print event.message.body
+
+try:
+    Container(Recv()).run()
+except KeyboardInterrupt: pass
+
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/server.py
----------------------------------------------------------------------
diff --git a/examples/python/server.py b/examples/python/server.py
new file mode 100755
index 0000000..fc9ac8d
--- /dev/null
+++ b/examples/python/server.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from proton import Message
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+
+class Server(MessagingHandler):
+    def __init__(self, host, address):
+        super(Server, self).__init__()
+        self.host = host
+        self.address = address
+
+    def on_start(self, event):
+        self.container = event.container
+        self.conn = event.container.connect(self.host)
+        self.receiver = event.container.create_receiver(self.conn, self.address)
+        self.senders = {}
+        self.relay = None
+
+    def on_connection_opened(self, event):
+        if event.connection.remote_offered_capabilities and 'ANONYMOUS-RELAY' in event.connection.remote_offered_capabilities:
+            self.relay = self.container.create_sender(self.conn, None)
+
+    def on_message(self, event):
+        sender = self.relay
+        if not sender:
+            sender = self.senders.get(event.message.reply_to)
+        if not sender:
+            sender = self.container.create_sender(self.conn, event.message.reply_to)
+            self.senders[event.message.reply_to] = sender
+        sender.send(Message(address=event.message.reply_to, body=event.message.body.upper()))
+
+try:
+    Container(Server("localhost:5672", "examples")).run()
+except KeyboardInterrupt: pass
+
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/server_direct.py
----------------------------------------------------------------------
diff --git a/examples/python/server_direct.py b/examples/python/server_direct.py
new file mode 100755
index 0000000..605c755
--- /dev/null
+++ b/examples/python/server_direct.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from proton import generate_uuid, Message
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+
+class Server(MessagingHandler):
+    def __init__(self, url):
+        super(Server, self).__init__()
+        self.url = url
+        self.senders = {}
+
+    def on_start(self, event):
+        self.container = event.container
+        self.acceptor = event.container.listen(self.url)
+
+    def on_link_opening(self, event):
+        if event.link.is_sender:
+            if event.link.remote_source and event.link.remote_source.dynamic:
+                event.link.source.address = str(generate_uuid())
+                self.senders[event.link.source.address] = event.link
+            elif event.link.remote_target and event.link.remote_target.address:
+                event.link.target.address = event.link.remote_target.address
+                self.senders[event.link.remote_target.address] = event.link
+            elif event.link.remote_source:
+                event.link.source.address = event.link.remote_source.address
+        elif event.link.remote_target:
+            event.link.target.address = event.link.remote_target.address
+
+    def on_message(self, event):
+        sender = self.senders.get(event.message.reply_to)
+        if sender:
+            sender.send(Message(address=event.message.reply_to, body=event.message.body.upper()))
+
+try:
+    Container(Server("localhost:8888")).run()
+except KeyboardInterrupt: pass
+
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/server_tx.py
----------------------------------------------------------------------
diff --git a/examples/python/server_tx.py b/examples/python/server_tx.py
new file mode 100755
index 0000000..4a245e2
--- /dev/null
+++ b/examples/python/server_tx.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from proton import Message
+from proton.reactor import Container
+from proton.handlers import MessagingHandler, TransactionHandler
+
+class TxRequest(TransactionHandler):
+    def __init__(self, response, sender, request_delivery):
+        super(TxRequest, self).__init__()
+        self.response = response
+        self.sender = sender
+        self.request_delivery = request_delivery
+
+    def on_transaction_declared(self, event):
+        event.transaction.send(self.sender, self.response)
+        event.transaction.accept(self.request_delivery)
+        event.transaction.commit()
+
+    def on_transaction_committed(self, event):
+        print "Request processed successfully"
+
+    def on_transaction_aborted(self, event):
+        print "Request processing aborted"
+
+
+class TxServer(MessagingHandler):
+    def __init__(self, host, address):
+        super(TxServer, self).__init__(auto_accept=False)
+        self.host = host
+        self.address = address
+
+    def on_start(self, event):
+        self.container = event.container
+        self.conn = event.container.connect(self.host, reconnect=False)
+        self.receiver = event.container.create_receiver(self.conn, self.address)
+        self.senders = {}
+        self.relay = None
+
+    def on_message(self, event):
+        sender = self.relay
+        if not sender:
+            sender = self.senders.get(event.message.reply_to)
+        if not sender:
+            sender = self.container.create_sender(self.conn, event.message.reply_to)
+            self.senders[event.message.reply_to] = sender
+
+        response = Message(address=event.message.reply_to, body=event.message.body.upper())
+        self.container.declare_transaction(self.conn, handler=TxRequest(response, sender, event.delivery))
+
+    def on_connection_open(self, event):
+        if event.connection.remote_offered_capabilities and 'ANONYMOUS-RELAY' in event.connection.remote_offered_capabilities:
+            self.relay = self.container.create_sender(self.conn, None)
+
+try:
+    Container(TxServer("localhost:5672", "examples")).run()
+except KeyboardInterrupt: pass
+
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/simple_recv.py
----------------------------------------------------------------------
diff --git a/examples/python/simple_recv.py b/examples/python/simple_recv.py
new file mode 100755
index 0000000..2e42819
--- /dev/null
+++ b/examples/python/simple_recv.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import optparse
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+
+class Recv(MessagingHandler):
+    def __init__(self, url, count):
+        super(Recv, self).__init__()
+        self.url = url
+        self.expected = count
+        self.received = 0
+
+    def on_start(self, event):
+        event.container.create_receiver(self.url)
+
+    def on_message(self, event):
+        if self.expected == 0 or self.received < self.expected:
+            print event.message.body
+            self.received += 1
+            if self.received == self.expected:
+                event.connection.close()
+
+parser = optparse.OptionParser(usage="usage: %prog [options]")
+parser.add_option("-a", "--address", default="localhost:5672/examples",
+                  help="address from which messages are received (default %default)")
+parser.add_option("-m", "--messages", type="int", default=100,
+                  help="number of messages to receive; 0 receives indefinitely (default %default)")
+opts, args = parser.parse_args()
+
+try:
+    Container(Recv(opts.address, opts.messages)).run()
+except KeyboardInterrupt: pass
+
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/simple_send.py
----------------------------------------------------------------------
diff --git a/examples/python/simple_send.py b/examples/python/simple_send.py
new file mode 100755
index 0000000..551041c
--- /dev/null
+++ b/examples/python/simple_send.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import optparse
+from proton import Message
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+
+class Send(MessagingHandler):
+    def __init__(self, url, messages):
+        super(Send, self).__init__()
+        self.url = url
+        self.sent = 0
+        self.confirmed = 0
+        self.total = messages
+
+    def on_start(self, event):
+        event.container.create_sender(self.url)
+
+    def on_sendable(self, event):
+        while event.sender.credit and self.sent < self.total:
+            msg = Message(body={'sequence':(self.sent+1)})
+            event.sender.send(msg)
+            self.sent += 1
+
+    def on_accepted(self, event):
+        self.confirmed += 1
+        if self.confirmed == self.total:
+            print "all messages confirmed"
+            event.connection.close()
+
+    def on_disconnected(self, event):
+        self.sent = self.confirmed
+
+parser = optparse.OptionParser(usage="usage: %prog [options]",
+                               description="Send messages to the supplied address.")
+parser.add_option("-a", "--address", default="localhost:5672/examples",
+                  help="address to which messages are sent (default %default)")
+parser.add_option("-m", "--messages", type="int", default=100,
+                  help="number of messages to send (default %default)")
+opts, args = parser.parse_args()
+
+try:
+    Container(Send(opts.address, opts.messages)).run()
+except KeyboardInterrupt: pass

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/sync_client.py
----------------------------------------------------------------------
diff --git a/examples/python/sync_client.py b/examples/python/sync_client.py
new file mode 100755
index 0000000..86cd7c2
--- /dev/null
+++ b/examples/python/sync_client.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+"""
+Demonstrates the client side of the synchronous request-response pattern
+(also known as RPC or Remote Procecure Call) using proton.
+
+"""
+
+from proton import Message, Url, ConnectionException, Timeout
+from proton.utils import BlockingConnection
+from proton.handlers import IncomingMessageHandler
+import sys
+
+class SyncRequestClient(IncomingMessageHandler):
+    """
+    Implementation of the synchronous request-responce (aka RPC) pattern.
+    Create an instance and call invoke() to send a request and wait for a response.
+    """
+
+    def __init__(self, url, timeout=None):
+        """
+        @param url: a proton.Url or a URL string of the form 'host:port/path'
+            host:port is used to connect, path is used to identify the remote messaging endpoint.
+        """
+        super(SyncRequestClient, self).__init__()
+        self.connection = BlockingConnection(Url(url).defaults(), timeout=timeout)
+        self.sender = self.connection.create_sender(url.path)
+        # dynamic=true generates a unique address dynamically for this receiver.
+        # credit=1 because we want to receive 1 response message initially.
+        self.receiver = self.connection.create_receiver(None, dynamic=True, credit=1, handler=self)
+        self.response = None
+
+    def invoke(self, request):
+        """Send a request, wait for and return the response"""
+        request.reply_to = self.reply_to
+        self.sender.send(request)
+        self.connection.wait(lambda: self.response, msg="Waiting for response")
+        response = self.response
+        self.response = None    # Ready for next response.
+        self.receiver.flow(1)   # Set up credit for the next response.
+        return response
+
+    @property
+    def reply_to(self):
+        """Return the dynamic address of our receiver."""
+        return self.receiver.remote_source.address
+
+    def on_message(self, event):
+        """Called when we receive a message for our receiver."""
+        self.response = event.message # Store the response
+
+    def close(self):
+        self.connection.close()
+
+
+if __name__ == '__main__':
+    url = Url("0.0.0.0/examples")
+    if len(sys.argv) > 1: url = Url(sys.argv[1])
+
+    invoker = SyncRequestClient(url, timeout=2)
+    try:
+        REQUESTS= ["Twas brillig, and the slithy toves",
+                   "Did gire and gymble in the wabe.",
+                   "All mimsy were the borogroves,",
+                   "And the mome raths outgrabe."]
+        for request in REQUESTS:
+            response = invoker.invoke(Message(body=request))
+            print "%s => %s" % (request, response.body)
+    finally:
+        invoker.close()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/test_examples.py
----------------------------------------------------------------------
diff --git a/examples/python/test_examples.py b/examples/python/test_examples.py
new file mode 100644
index 0000000..b46b85b
--- /dev/null
+++ b/examples/python/test_examples.py
@@ -0,0 +1,109 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import subprocess
+import time
+import unittest
+
+class ExamplesTest(unittest.TestCase):
+    def test_helloworld(self, example="helloworld.py"):
+        p = subprocess.Popen([example], stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+        p.wait()
+        output = [l.strip() for l in p.stdout]
+        self.assertEqual(output, ['Hello World!'])
+
+    def test_helloworld_direct(self):
+        self.test_helloworld('helloworld_direct.py')
+
+    def test_helloworld_blocking(self):
+        self.test_helloworld('helloworld_blocking.py')
+
+    def test_helloworld_tornado(self):
+        self.test_helloworld('helloworld_tornado.py')
+
+    def test_helloworld_direct_tornado(self):
+        self.test_helloworld('helloworld_direct_tornado.py')
+
+    def test_simple_send_recv(self, recv='simple_recv.py', send='simple_send.py'):
+        r = subprocess.Popen([recv], stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+        s = subprocess.Popen([send], stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+        s.wait()
+        r.wait()
+        actual = [l.strip() for l in r.stdout]
+        expected = ["{'sequence': %iL}" % (i+1) for i in range(100)]
+        self.assertEqual(actual, expected)
+
+    def test_client_server(self, client=['client.py'], server=['server.py'], sleep=0):
+        s = subprocess.Popen(server, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+        if sleep:
+            time.sleep(sleep)
+        c = subprocess.Popen(client, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+        c.wait()
+        s.terminate()
+        actual = [l.strip() for l in c.stdout]
+        inputs = ["Twas brillig, and the slithy toves",
+                    "Did gire and gymble in the wabe.",
+                    "All mimsy were the borogroves,",
+                    "And the mome raths outgrabe."]
+        expected = ["%s => %s" % (l, l.upper()) for l in inputs]
+        self.assertEqual(actual, expected)
+
+    def test_sync_client_server(self):
+        self.test_client_server(client=['sync_client.py'])
+
+    def test_client_server_tx(self):
+        self.test_client_server(server=['server_tx.py'])
+
+    def test_sync_client_server_tx(self):
+        self.test_client_server(client=['sync_client.py'], server=['server_tx.py'])
+
+    def test_client_server_direct(self):
+        self.test_client_server(client=['client.py', '-a', 'localhost:8888/examples'], server=['server_direct.py'], sleep=0.5)
+
+    def test_sync_client_server_direct(self):
+        self.test_client_server(client=['sync_client.py', 'localhost:8888/examples'], server=['server_direct.py'], sleep=0.5)
+
+    def test_db_send_recv(self):
+        self.maxDiff = None
+        # setup databases
+        subprocess.check_call(['db_ctrl.py', 'init', './src_db'])
+        subprocess.check_call(['db_ctrl.py', 'init', './dst_db'])
+        fill = subprocess.Popen(['db_ctrl.py', 'insert', './src_db'], stdin=subprocess.PIPE, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+        for i in range(100):
+            fill.stdin.write("Message-%i\n" % (i+1))
+        fill.stdin.close()
+        fill.wait()
+        # run send and recv
+        r = subprocess.Popen(['db_recv.py', '-m', '100'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+        s = subprocess.Popen(['db_send.py', '-m', '100'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+        s.wait()
+        r.wait()
+        # verify output of receive
+        actual = [l.strip() for l in r.stdout]
+        expected = ["inserted message %i" % (i+1) for i in range(100)]
+        self.assertEqual(actual, expected)
+        # verify state of databases
+        v = subprocess.Popen(['db_ctrl.py', 'list', './dst_db'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+        v.wait()
+        expected = ["(%i, u'Message-%i')" % ((i+1), (i+1)) for i in range(100)]
+        actual = [l.strip() for l in v.stdout]
+        self.assertEqual(actual, expected)
+
+    def test_tx_send_tx_recv(self):
+        self.test_simple_send_recv(recv='tx_recv.py', send='tx_send.py')

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/tx_recv.py
----------------------------------------------------------------------
diff --git a/examples/python/tx_recv.py b/examples/python/tx_recv.py
new file mode 100755
index 0000000..641f0a2
--- /dev/null
+++ b/examples/python/tx_recv.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import optparse
+from proton import Url
+from proton.reactor import Container
+from proton.handlers import MessagingHandler, TransactionHandler
+
+class TxRecv(MessagingHandler, TransactionHandler):
+    def __init__(self, url, messages, batch_size):
+        super(TxRecv, self).__init__(prefetch=0, auto_accept=False)
+        self.url = Url(url)
+        self.expected = messages
+        self.batch_size = batch_size
+        self.current_batch = 0
+        self.committed = 0
+
+    def on_start(self, event):
+        self.container = event.container
+        self.conn = self.container.connect(self.url)
+        self.receiver = self.container.create_receiver(self.conn, self.url.path)
+        self.container.declare_transaction(self.conn, handler=self)
+        self.transaction = None
+
+    def on_message(self, event):
+        print event.message.body
+        self.transaction.accept(event.delivery)
+        self.current_batch += 1
+        if self.current_batch == self.batch_size:
+            self.transaction.commit()
+            self.transaction = None
+
+    def on_transaction_declared(self, event):
+        self.receiver.flow(self.batch_size)
+        self.transaction = event.transaction
+
+    def on_transaction_committed(self, event):
+        self.committed += self.current_batch
+        self.current_batch = 0
+        if self.expected == 0 or self.committed < self.expected:
+            self.container.declare_transaction(self.conn, handler=self)
+        else:
+            event.connection.close()
+
+    def on_disconnected(self, event):
+        self.current_batch = 0
+
+parser = optparse.OptionParser(usage="usage: %prog [options]")
+parser.add_option("-a", "--address", default="localhost:5672/examples",
+                  help="address from which messages are received (default %default)")
+parser.add_option("-m", "--messages", type="int", default=100,
+                  help="number of messages to receive; 0 receives indefinitely (default %default)")
+parser.add_option("-b", "--batch-size", type="int", default=10,
+                  help="number of messages in each transaction (default %default)")
+opts, args = parser.parse_args()
+
+try:
+    Container(TxRecv(opts.address, opts.messages, opts.batch_size)).run()
+except KeyboardInterrupt: pass
+
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/tx_recv_interactive.py
----------------------------------------------------------------------
diff --git a/examples/python/tx_recv_interactive.py b/examples/python/tx_recv_interactive.py
new file mode 100755
index 0000000..d08ff2b
--- /dev/null
+++ b/examples/python/tx_recv_interactive.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import sys
+import threading
+from proton.reactor import ApplicationEvent, Container
+from proton.handlers import MessagingHandler, TransactionHandler
+
+class TxRecv(MessagingHandler, TransactionHandler):
+    def __init__(self):
+        super(TxRecv, self).__init__(prefetch=0, auto_accept=False)
+
+    def on_start(self, event):
+        self.container = event.container
+        self.conn = self.container.connect("localhost:5672")
+        self.receiver = self.container.create_receiver(self.conn, "examples")
+        self.container.declare_transaction(self.conn, handler=self, settle_before_discharge=True)
+        self.transaction = None
+
+    def on_message(self, event):
+        print event.message.body
+        self.transaction.accept(event.delivery)
+
+    def on_transaction_declared(self, event):
+        self.transaction = event.transaction
+        print "transaction declared"
+
+    def on_transaction_committed(self, event):
+        print "transaction committed"
+        self.container.declare_transaction(self.conn, handler=self)
+
+    def on_transaction_aborted(self, event):
+        print "transaction aborted"
+        self.container.declare_transaction(self.conn, handler=self)
+
+    def on_commit(self, event):
+        self.transaction.commit()
+
+    def on_abort(self, event):
+        self.transaction.abort()
+
+    def on_fetch(self, event):
+        self.receiver.flow(1)
+
+    def on_quit(self, event):
+        c = self.receiver.connection
+        self.receiver.close()
+        c.close()
+
+try:
+    reactor = Container(TxRecv())
+    events = reactor.get_event_trigger()
+    thread = threading.Thread(target=reactor.run)
+    thread.daemon=True
+    thread.start()
+
+    print "Enter 'fetch', 'commit' or 'abort'"
+    while True:
+        line = sys.stdin.readline()
+        if line:
+            events.trigger(ApplicationEvent(line.strip()))
+        else:
+            break
+except KeyboardInterrupt: pass
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/python/tx_send.py
----------------------------------------------------------------------
diff --git a/examples/python/tx_send.py b/examples/python/tx_send.py
new file mode 100755
index 0000000..8c5420d
--- /dev/null
+++ b/examples/python/tx_send.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import optparse
+from proton import Message, Url
+from proton.reactor import Container
+from proton.handlers import MessagingHandler, TransactionHandler
+
+class TxSend(MessagingHandler, TransactionHandler):
+    def __init__(self, url, messages, batch_size):
+        super(TxSend, self).__init__()
+        self.url = Url(url)
+        self.current_batch = 0
+        self.committed = 0
+        self.confirmed = 0
+        self.total = messages
+        self.batch_size = batch_size
+
+    def on_start(self, event):
+        self.container = event.container
+        self.conn = self.container.connect(self.url)
+        self.sender = self.container.create_sender(self.conn, self.url.path)
+        self.container.declare_transaction(self.conn, handler=self)
+        self.transaction = None
+
+    def on_transaction_declared(self, event):
+        self.transaction = event.transaction
+        self.send()
+
+    def on_sendable(self, event):
+        self.send()
+
+    def send(self):
+        while self.transaction and self.sender.credit and (self.committed + self.current_batch) < self.total:
+            msg = Message(body={'sequence':(self.committed+self.current_batch+1)})
+            self.transaction.send(self.sender, msg)
+            self.current_batch += 1
+            if self.current_batch == self.batch_size:
+                self.transaction.commit()
+                self.transaction = None
+
+    def on_accepted(self, event):
+        if event.sender == self.sender:
+            self.confirmed += 1
+
+    def on_transaction_committed(self, event):
+        self.committed += self.current_batch
+        if self.committed == self.total:
+            print "all messages committed"
+            event.connection.close()
+        else:
+            self.current_batch = 0
+            self.container.declare_transaction(self.conn, handler=self)
+
+    def on_disconnected(self, event):
+        self.current_batch = 0
+
+parser = optparse.OptionParser(usage="usage: %prog [options]",
+                               description="Send messages transactionally to the supplied address.")
+parser.add_option("-a", "--address", default="localhost:5672/examples",
+                  help="address to which messages are sent (default %default)")
+parser.add_option("-m", "--messages", type="int", default=100,
+                  help="number of messages to send (default %default)")
+parser.add_option("-b", "--batch-size", type="int", default=10,
+                  help="number of messages in each transaction (default %default)")
+opts, args = parser.parse_args()
+
+try:
+    Container(TxSend(opts.address, opts.messages, opts.batch_size)).run()
+except KeyboardInterrupt: pass

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/reactor/py/README.md
----------------------------------------------------------------------
diff --git a/examples/reactor/py/README.md b/examples/reactor/py/README.md
deleted file mode 100644
index b08fdbd..0000000
--- a/examples/reactor/py/README.md
+++ /dev/null
@@ -1,34 +0,0 @@
-The examples in this directory provide a basic introduction to the
-proton reactor API and are best viewed in the order presented below.
-
-The examples contain comments that explain things in a tutorial-style
-manner. At some point soon this content will be pulled out into a
-proper tutorial that references the relevant code snippets from these
-examples. Until then please bear with this clumsy style of
-presentation.
-
-This API is present in C as well and most of these examples will
-transliterate into C in a fairly straightforward way.
-
-  - hello-world.py
-  - goodbye-world.py
-
-  - scheduling.py
-  - counter.py
-  - count-randomly.py
-
-  - unhandled.py
-  - reactor-logger.py
-  - global-logger.py
-  - delegates.py
-
-  - handlers.py
-
-  - echo.py
-  - cat.py
-
-  - send.py
-  - recv.py
-
-  - tornado-hello-world.py
-  - tornado-send.py

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/reactor/py/cat.py
----------------------------------------------------------------------
diff --git a/examples/reactor/py/cat.py b/examples/reactor/py/cat.py
deleted file mode 100755
index 57f4515..0000000
--- a/examples/reactor/py/cat.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import sys, os
-from proton.reactor import Reactor
-
-class Echo:
-
-    def __init__(self, source):
-        self.source = source
-
-    def on_selectable_init(self, event):
-        sel = event.context # XXX: no selectable property yet
-
-        # We can configure a selectable with any file descriptor we want.
-        sel.fileno(self.source.fileno())
-        # Ask to be notified when the file is readable.
-        sel.reading = True
-        event.reactor.update(sel)
-
-    def on_selectable_readable(self, event):
-        sel = event.context
-
-        # The on_selectable_readable event tells us that there is data
-        # to be read, or the end of stream has been reached.
-        data = os.read(sel.fileno(), 1024)
-        if data:
-            print data,
-        else:
-            sel.terminate()
-            event.reactor.update(sel)
-
-class Program:
-
-    def on_reactor_init(self, event):
-        event.reactor.selectable(Echo(open(sys.argv[1])))
-
-r = Reactor(Program())
-r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/reactor/py/count-randomly.py
----------------------------------------------------------------------
diff --git a/examples/reactor/py/count-randomly.py b/examples/reactor/py/count-randomly.py
deleted file mode 100755
index d9a32c6..0000000
--- a/examples/reactor/py/count-randomly.py
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import time, random
-from proton.reactor import Reactor
-
-# Let's try to modify our counter example. In addition to counting to
-# 10 in quarter second intervals, let's also print out a random number
-# every half second. This is not a super easy thing to express in a
-# purely sequential program, but not so difficult using events.
-
-class Counter:
-
-    def __init__(self, limit):
-        self.limit = limit
-        self.count = 0
-
-    def on_timer_task(self, event):
-        self.count += 1
-        print self.count
-        if not self.done():
-            event.reactor.schedule(0.25, self)
-
-    # add a public API to check for doneness
-    def done(self):
-        return self.count >= self.limit
-
-class Program:
-
-    def on_reactor_init(self, event):
-        self.start = time.time()
-        print "Hello, World!"
-
-        # Save the counter instance in an attribute so we can refer to
-        # it later.
-        self.counter = Counter(10)
-        event.reactor.schedule(0.25, self.counter)
-
-        # Now schedule another event with a different handler. Note
-        # that the timer tasks go to separate handlers, and they don't
-        # interfere with each other.
-        event.reactor.schedule(0.5, self)
-
-    def on_timer_task(self, event):
-        # keep on shouting until we are done counting
-        print "Yay, %s!" % random.randint(10, 100)
-        if not self.counter.done():
-            event.reactor.schedule(0.5, self)
-
-    def on_reactor_final(self, event):
-        print "Goodbye, World! (after %s long seconds)" % (time.time() - self.start)
-
-# In hello-world.py we said the reactor exits when there are no more
-# events to process. While this is true, it's not actually complete.
-# The reactor exits when there are no more events to process and no
-# possibility of future events arising. For that reason the reactor
-# will keep running until there are no more scheduled events and then
-# exit.
-r = Reactor(Program())
-r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/reactor/py/counter.py
----------------------------------------------------------------------
diff --git a/examples/reactor/py/counter.py b/examples/reactor/py/counter.py
deleted file mode 100755
index 1ef45f0..0000000
--- a/examples/reactor/py/counter.py
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import time
-from proton.reactor import Reactor
-
-class Counter:
-
-    def __init__(self, limit):
-        self.limit = limit
-        self.count = 0
-
-    def on_timer_task(self, event):
-        self.count += 1
-        print self.count
-        if self.count < self.limit:
-            # A recurring task can be acomplished by just scheduling
-            # another event.
-            event.reactor.schedule(0.25, self)
-
-class Program:
-
-    def on_reactor_init(self, event):
-        self.start = time.time()
-        print "Hello, World!"
-
-        # Note that unlike the previous scheduling example, we pass in
-        # a separate object for the handler. This means that the timer
-        # event we just scheduled will not be seen by Program as it is
-        # being handled by the Counter instance we create.
-        event.reactor.schedule(0.25, Counter(10))
-
-    def on_reactor_final(self, event):
-        print "Goodbye, World! (after %s long seconds)" % (time.time() - self.start)
-
-# In hello-world.py we said the reactor exits when there are no more
-# events to process. While this is true, it's not actually complete.
-# The reactor exits when there are no more events to process and no
-# possibility of future events arising. For that reason the reactor
-# will keep running until there are no more scheduled events and then
-# exit.
-r = Reactor(Program())
-r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/reactor/py/delegates.py
----------------------------------------------------------------------
diff --git a/examples/reactor/py/delegates.py b/examples/reactor/py/delegates.py
deleted file mode 100755
index 813ceba..0000000
--- a/examples/reactor/py/delegates.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import time
-from proton.reactor import Reactor
-
-# Events know how to dispatch themselves to handlers. By combining
-# this with on_unhandled, you can provide a kind of inheritance
-# between handlers using delegation.
-
-class Hello:
-
-    def on_reactor_init(self, event):
-        print "Hello, World!"
-
-class Goodbye:
-
-    def on_reactor_final(self, event):
-        print "Goodbye, World!"
-
-class Program:
-
-    def __init__(self, *delegates):
-        self.delegates = delegates
-
-    def on_unhandled(self, name, event):
-        for d in self.delegates:
-            event.dispatch(d)
-
-r = Reactor(Program(Hello(), Goodbye()))
-r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/reactor/py/echo.py
----------------------------------------------------------------------
diff --git a/examples/reactor/py/echo.py b/examples/reactor/py/echo.py
deleted file mode 100755
index 4675f5d..0000000
--- a/examples/reactor/py/echo.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import sys, os
-from proton.reactor import Reactor
-
-class Echo:
-
-    def __init__(self, source):
-        self.source = source
-
-    def on_selectable_init(self, event):
-        sel = event.context # XXX: no selectable property yet
-
-        # We can configure a selectable with any file descriptor we want.
-        sel.fileno(self.source.fileno())
-        # Ask to be notified when the file is readable.
-        sel.reading = True
-        event.reactor.update(sel)
-
-    def on_selectable_readable(self, event):
-        sel = event.context
-
-        # The on_selectable_readable event tells us that there is data
-        # to be read, or the end of stream has been reached.
-        data = os.read(sel.fileno(), 1024)
-        if data:
-            print data,
-        else:
-            sel.terminate()
-            event.reactor.update(sel)
-
-class Program:
-
-    def on_reactor_init(self, event):
-        # Every selectable is a possible source of future events. Our
-        # selectable stays alive until it reads the end of stream
-        # marker. This will keep the whole reactor running until we
-        # type Control-D.
-        print "Type whatever you want and then use Control-D to exit:"
-        event.reactor.selectable(Echo(sys.stdin))
-
-r = Reactor(Program())
-r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/reactor/py/global-logger.py
----------------------------------------------------------------------
diff --git a/examples/reactor/py/global-logger.py b/examples/reactor/py/global-logger.py
deleted file mode 100755
index bc3bc56..0000000
--- a/examples/reactor/py/global-logger.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import time
-from proton.reactor import Reactor
-
-# Not every event goes to the reactor's event handler. If we have a
-# separate handler for something like a scheduled task, then those
-# events aren't logged by the logger associated with the reactor's
-# handler. Sometimes this is useful if you don't want to see them, but
-# sometimes you want the global picture.
-
-class Logger:
-
-    def on_unhandled(self, name, event):
-        print "LOG:", name, event
-
-class Task:
-
-    def on_timer_task(self, event):
-        print "Mission accomplished!"
-
-class Program:
-
-    def on_reactor_init(self, event):
-        print "Hello, World!"
-        event.reactor.schedule(0, Task())
-
-    def on_reactor_final(self, event):
-        print "Goodbye, World!"
-
-r = Reactor(Program())
-
-# In addition to having a regular handler, the reactor also has a
-# global handler that sees every event. By adding the Logger to the
-# global handler instead of the regular handler, we can log every
-# single event that occurs in the system regardless of whether or not
-# there are specific handlers associated with the objects that are the
-# target of those events.
-r.global_handler.add(Logger())
-r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/reactor/py/goodbye-world.py
----------------------------------------------------------------------
diff --git a/examples/reactor/py/goodbye-world.py b/examples/reactor/py/goodbye-world.py
deleted file mode 100755
index 44bcf7c..0000000
--- a/examples/reactor/py/goodbye-world.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-from proton.reactor import Reactor
-
-# So far the reactive hello-world doesn't look too different from a
-# regular old non-reactive hello-world. The on_reactor_init method can
-# be used roughly as a 'main' method would. A program that only uses
-# that one event, however, isn't going to be very reactive. By using
-# other events, we can write a fully reactive program.
-
-class Program:
-
-    # As before we handle the reactor init event.
-    def on_reactor_init(self, event):
-        print "Hello, World!"
-
-    # In addition to an initial event, the reactor also produces an
-    # event when it is about to exit. This may not behave much
-    # differently than just putting the goodbye print statement inside
-    # on_reactor_init, but as we grow our program, this piece of it
-    # will always be what happens last, and will always happen
-    # regardless of what other paths the main logic of our program
-    # might take.
-    def on_reactor_final(self, event):
-        print "Goodbye, World!"
-
-r = Reactor(Program())
-r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/reactor/py/handlers.py
----------------------------------------------------------------------
diff --git a/examples/reactor/py/handlers.py b/examples/reactor/py/handlers.py
deleted file mode 100755
index ed3a94d..0000000
--- a/examples/reactor/py/handlers.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import time
-from proton.reactor import Reactor
-
-
-class World:
-
-    def on_reactor_init(self, event):
-        print "World!"
-
-class Goodbye:
-
-    def on_reactor_final(self, event):
-        print "Goodbye, World!"
-
-class Hello:
-
-    def __init__(self):
-        # When an event dispatches itself to a handler, it also checks
-        # if that handler has a "handlers" attribute and dispatches
-        # the event to any children.
-        self.handlers = [World(), Goodbye()]
-
-    # The parent handler always receives the event first.
-    def on_reactor_init(self, event):
-        print "Hello",
-
-r = Reactor(Hello())
-r.run()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/913a6fb6/examples/reactor/py/hello-world.py
----------------------------------------------------------------------
diff --git a/examples/reactor/py/hello-world.py b/examples/reactor/py/hello-world.py
deleted file mode 100755
index c685c73..0000000
--- a/examples/reactor/py/hello-world.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/python
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-from proton.reactor import Reactor
-
-# The proton reactor provides a general purpose event processing
-# library for writing reactive programs. A reactive program is defined
-# by a set of event handlers. An event handler is just any class or
-# object that defines the "on_<event>" methods that it cares to
-# handle.
-
-class Program:
-
-    # The reactor init event is produced by the reactor itself when it
-    # starts.
-    def on_reactor_init(self, event):
-        print "Hello, World!"
-
-# When you construct a reactor, you give it a handler.
-r = Reactor(Program())
-
-# When you call run, the reactor will process events. The reactor init
-# event is what kicks off everything else. When the reactor has no
-# more events to process, it exits.
-r.run()


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


Mime
View raw message