callbacks.py
124 lines
| 4.1 KiB
| text/x-python
|
PythonLexer
Thomas Kluyver
|
r15599 | """Infrastructure for registering and firing callbacks. | ||
Unlike :mod:`IPython.core.hooks`, which lets end users set single functions to | ||||
be called at specific times, or a collection of alternative methods to try, | ||||
callbacks are designed to be used by extension authors. A number of callbacks | ||||
can be registered for the same event without needing to be aware of one another. | ||||
The functions defined in this module are no-ops indicating the names of available | ||||
events and the arguments which will be passed to them. | ||||
""" | ||||
Thomas Kluyver
|
r15597 | from __future__ import print_function | ||
class CallbackManager(object): | ||||
Thomas Kluyver
|
r15599 | """Manage a collection of events and a sequence of callbacks for each. | ||
This is attached to :class:`~IPython.core.interactiveshell.InteractiveShell` | ||||
instances as a ``callbacks`` attribute. | ||||
""" | ||||
Thomas Kluyver
|
r15597 | def __init__(self, shell, available_callbacks): | ||
Thomas Kluyver
|
r15599 | """Initialise the :class:`CallbackManager`. | ||
Parameters | ||||
---------- | ||||
shell | ||||
The :class:`~IPython.core.interactiveshell.InteractiveShell` instance | ||||
available_callbacks | ||||
An iterable of names for callback events. | ||||
""" | ||||
Thomas Kluyver
|
r15597 | self.shell = shell | ||
self.callbacks = {n:[] for n in available_callbacks} | ||||
def register(self, name, function): | ||||
Thomas Kluyver
|
r15599 | """Register a new callback | ||
Parameters | ||||
---------- | ||||
name : str | ||||
The event for which to register this callback. | ||||
function : callable | ||||
A function to be called on the given event. It should take the same | ||||
parameters as the appropriate callback prototype. | ||||
Raises | ||||
------ | ||||
TypeError | ||||
If ``function`` is not callable. | ||||
KeyError | ||||
If ``name`` is not one of the known callback events. | ||||
""" | ||||
Thomas Kluyver
|
r15597 | if not callable(function): | ||
raise TypeError('Need a callable, got %r' % function) | ||||
self.callbacks[name].append(function) | ||||
def unregister(self, name, function): | ||||
Thomas Kluyver
|
r15599 | """Remove a callback from the given event.""" | ||
Thomas Kluyver
|
r15597 | self.callbacks[name].remove(function) | ||
def reset(self, name): | ||||
Thomas Kluyver
|
r15599 | """Clear all callbacks for the given event.""" | ||
Thomas Kluyver
|
r15597 | self.callbacks[name] = [] | ||
def reset_all(self): | ||||
Thomas Kluyver
|
r15599 | """Clear all callbacks for all events.""" | ||
Thomas Kluyver
|
r15597 | self.callbacks = {n:[] for n in self.callbacks} | ||
def fire(self, name, *args, **kwargs): | ||||
Thomas Kluyver
|
r15599 | """Call callbacks for the event ``name``. | ||
Any additional arguments are passed to all callbacks registered for this | ||||
event. Exceptions raised by callbacks are caught, and a message printed. | ||||
""" | ||||
Thomas Kluyver
|
r15597 | for func in self.callbacks[name]: | ||
try: | ||||
func(*args, **kwargs) | ||||
except Exception: | ||||
print("Error in callback {} (for {}):".format(func, name)) | ||||
self.shell.showtraceback() | ||||
Thomas Kluyver
|
r15599 | # event_name -> prototype mapping | ||
Thomas Kluyver
|
r15597 | available_callbacks = {} | ||
Thomas Kluyver
|
r15599 | |||
Thomas Kluyver
|
r15597 | def _collect(callback_proto): | ||
available_callbacks[callback_proto.__name__] = callback_proto | ||||
return callback_proto | ||||
Thomas Kluyver
|
r15599 | # ------------------------------------------------------------------------------ | ||
# Callback prototypes | ||||
# | ||||
# No-op functions which describe the names of available events and the | ||||
# signatures of callbacks for those events. | ||||
# ------------------------------------------------------------------------------ | ||||
Thomas Kluyver
|
r15597 | @_collect | ||
def pre_execute(): | ||||
"""Fires before code is executed in response to user/frontend action. | ||||
Thomas Kluyver
|
r15599 | This includes comm and widget messages as well as user code cells.""" | ||
Thomas Kluyver
|
r15597 | pass | ||
@_collect | ||||
def pre_execute_explicit(): | ||||
"""Fires before user-entered code runs.""" | ||||
pass | ||||
@_collect | ||||
def post_execute(): | ||||
"""Fires after code is executed in response to user/frontend action. | ||||
Thomas Kluyver
|
r15599 | This includes comm and widget messages as well as user code cells.""" | ||
Thomas Kluyver
|
r15597 | pass | ||
@_collect | ||||
def post_execute_explicit(): | ||||
"""Fires after user-entered code runs.""" | ||||
Thomas Kluyver
|
r15602 | pass | ||
@_collect | ||||
def shell_initialised(ip): | ||||
"""Fires after initialisation of :class:`~IPython.core.interactiveshell.InteractiveShell`. | ||||
This is before extensions and startup scripts are loaded, so it can only be | ||||
set by subclassing. | ||||
""" | ||||
pass | ||||