|
|
.. _notification:
|
|
|
|
|
|
==========================================
|
|
|
IPython.kernel.core.notification blueprint
|
|
|
==========================================
|
|
|
|
|
|
Overview
|
|
|
========
|
|
|
|
|
|
The :mod:`IPython.kernel.core.notification` module will provide a simple
|
|
|
implementation of a notification center and support for the observer pattern
|
|
|
within the :mod:`IPython.kernel.core`. The main intended use case is to
|
|
|
provide notification of Interpreter events to an observing frontend during the
|
|
|
execution of a single block of code.
|
|
|
|
|
|
Functional Requirements
|
|
|
=======================
|
|
|
|
|
|
The notification center must:
|
|
|
|
|
|
* Provide synchronous notification of events to all registered observers.
|
|
|
|
|
|
* Provide typed or labeled notification types.
|
|
|
|
|
|
* Allow observers to register callbacks for individual or all notification
|
|
|
types.
|
|
|
|
|
|
* Allow observers to register callbacks for events from individual or all
|
|
|
notifying objects.
|
|
|
|
|
|
* Notification to the observer consists of the notification type, notifying
|
|
|
object and user-supplied extra information [implementation: as keyword
|
|
|
parameters to the registered callback].
|
|
|
|
|
|
* Perform as O(1) in the case of no registered observers.
|
|
|
|
|
|
* Permit out-of-process or cross-network extension.
|
|
|
|
|
|
What's not included
|
|
|
===================
|
|
|
|
|
|
As written, the :mod:`IPython.kernel.core.notification` module does not:
|
|
|
|
|
|
* Provide out-of-process or network notifications (these should be handled by
|
|
|
a separate, Twisted aware module in :mod:`IPython.kernel`).
|
|
|
|
|
|
* Provide zope.interface style interfaces for the notification system (these
|
|
|
should also be provided by the :mod:`IPython.kernel` module).
|
|
|
|
|
|
Use Cases
|
|
|
=========
|
|
|
|
|
|
The following use cases describe the main intended uses of the notification
|
|
|
module and illustrate the main success scenario for each use case:
|
|
|
|
|
|
Scenario 1
|
|
|
----------
|
|
|
|
|
|
Dwight Schroot is writing a frontend for the IPython project. His frontend is
|
|
|
stuck in the stone age and must communicate synchronously with an
|
|
|
:mod:`IPython.kernel.core.Interpreter` instance. Because code is executed in blocks
|
|
|
by the Interpreter, Dwight's UI freezes every time he executes a long block of
|
|
|
code. To keep track of the progress of his long running block, Dwight adds the
|
|
|
following code to his frontend's set-up code::
|
|
|
|
|
|
from IPython.kernel.core.notification import NotificationCenter
|
|
|
center = NotificationCenter.sharedNotificationCenter
|
|
|
center.registerObserver(self, type=IPython.kernel.core.Interpreter.STDOUT_NOTIFICATION_TYPE, notifying_object=self.interpreter, callback=self.stdout_notification)
|
|
|
|
|
|
and elsewhere in his front end::
|
|
|
|
|
|
def stdout_notification(self, type, notifying_object, out_string=None):
|
|
|
self.writeStdOut(out_string)
|
|
|
|
|
|
If everything works, the Interpreter will (according to its published API)
|
|
|
fire a notification via the
|
|
|
:data:`IPython.kernel.core.notification.sharedCenter` of type
|
|
|
:const:`STD_OUT_NOTIFICATION_TYPE` before writing anything to stdout [it's up
|
|
|
to the Intereter implementation to figure out when to do this]. The
|
|
|
notificaiton center will then call the registered callbacks for that event
|
|
|
type (in this case, Dwight's frontend's stdout_notification method). Again,
|
|
|
according to its API, the Interpreter provides an additional keyword argument
|
|
|
when firing the notificaiton of out_string, a copy of the string it will write
|
|
|
to stdout.
|
|
|
|
|
|
Like magic, Dwight's frontend is able to provide output, even during
|
|
|
long-running calculations. Now if Jim could just convince Dwight to use
|
|
|
Twisted...
|
|
|
|
|
|
Scenario 2
|
|
|
----------
|
|
|
|
|
|
Boss Hog is writing a frontend for the IPython project. Because Boss Hog is
|
|
|
stuck in the stone age, his frontend will be written in a new Fortran-like
|
|
|
dialect of python and will run only from the command line. Because he doesn't
|
|
|
need any fancy notification system and is used to worrying about every cycle
|
|
|
on his rat-wheel powered mini, Boss Hog is adamant that the new notification
|
|
|
system not produce any performance penalty. As they say in Hazard county,
|
|
|
there's no such thing as a free lunch. If he wanted zero overhead, he should
|
|
|
have kept using IPython 0.8. Instead, those tricky Duke boys slide in a
|
|
|
suped-up bridge-out jumpin' awkwardly confederate-lovin' notification module
|
|
|
that imparts only a constant (and small) performance penalty when the
|
|
|
Interpreter (or any other object) fires an event for which there are no
|
|
|
registered observers. Of course, the same notificaiton-enabled Interpreter can
|
|
|
then be used in frontends that require notifications, thus saving the IPython
|
|
|
project from a nasty civil war.
|
|
|
|
|
|
Scenario 3
|
|
|
----------
|
|
|
|
|
|
Barry is wrting a frontend for the IPython project. Because Barry's front end
|
|
|
is the *new hotness*, it uses an asynchronous event model to communicate with
|
|
|
a Twisted :mod:`IPython.kernel.engineservice` that communicates with the
|
|
|
IPython :class:`IPython.kernel.core.interpreter.Interpreter`. Using the
|
|
|
:mod:`IPython.kernel.notification` module, an asynchronous wrapper on the
|
|
|
:mod:`IPython.kernel.core.notification` module, Barry's frontend can register
|
|
|
for notifications from the interpreter that are delivered asynchronously. Even
|
|
|
if Barry's frontend is running on a separate process or even host from the
|
|
|
Interpreter, the notifications are delivered, as if by dark and twisted magic.
|
|
|
Just like Dwight's frontend, Barry's frontend can now receive notifications of
|
|
|
e.g. writing to stdout/stderr, opening/closing an external file, an exception
|
|
|
in the executing code, etc.
|
|
|
|
|
|
|