events.py
158 lines
| 5.1 KiB
| text/x-python
|
PythonLexer
Thomas Kluyver
|
r15605 | """Infrastructure for registering and firing callbacks on application events. | ||
Thomas Kluyver
|
r15599 | |||
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
|
r15606 | |||
.. note:: | ||||
This API is experimental in IPython 2.0, and may be revised in future versions. | ||||
Thomas Kluyver
|
r15599 | """ | ||
Thomas Kluyver
|
r15597 | |||
Fabio Niephaus
|
r23982 | |||
Thomas Kluyver
|
r15605 | class EventManager(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` | ||||
Thomas Kluyver
|
r15609 | instances as an ``events`` attribute. | ||
Thomas Kluyver
|
r15606 | |||
.. note:: | ||||
This API is experimental in IPython 2.0, and may be revised in future versions. | ||||
Thomas Kluyver
|
r15599 | """ | ||
Tim Nonet
|
r28312 | |||
def __init__(self, shell, available_events, print_on_error=True): | ||||
Thomas Kluyver
|
r15599 | """Initialise the :class:`CallbackManager`. | ||
Matthias Bussonnier
|
r26498 | |||
Thomas Kluyver
|
r15599 | Parameters | ||
---------- | ||||
shell | ||||
Matthias Bussonnier
|
r26498 | The :class:`~IPython.core.interactiveshell.InteractiveShell` instance | ||
available_events | ||||
An iterable of names for callback events. | ||||
Tim Nonet
|
r28312 | print_on_error: | ||
A boolean flag to set whether the EventManager will print a warning which a event errors. | ||||
Thomas Kluyver
|
r15599 | """ | ||
Thomas Kluyver
|
r15597 | self.shell = shell | ||
Thomas Kluyver
|
r15605 | self.callbacks = {n:[] for n in available_events} | ||
Tim Nonet
|
r28312 | self.print_on_error = print_on_error | ||
Thomas Kluyver
|
r15597 | |||
Thomas Kluyver
|
r15605 | def register(self, event, function): | ||
Fabio Niephaus
|
r23997 | """Register a new event callback. | ||
Matthias Bussonnier
|
r26498 | |||
Thomas Kluyver
|
r15599 | Parameters | ||
---------- | ||||
Thomas Kluyver
|
r15605 | event : str | ||
Matthias Bussonnier
|
r26498 | The event for which to register this callback. | ||
Thomas Kluyver
|
r15599 | function : callable | ||
Matthias Bussonnier
|
r26498 | A function to be called on the given event. It should take the same | ||
parameters as the appropriate callback prototype. | ||||
Thomas Kluyver
|
r15599 | Raises | ||
------ | ||||
TypeError | ||||
Matthias Bussonnier
|
r26498 | If ``function`` is not callable. | ||
Thomas Kluyver
|
r15599 | KeyError | ||
Matthias Bussonnier
|
r26498 | If ``event`` is not one of the known events. | ||
Thomas Kluyver
|
r15599 | """ | ||
Thomas Kluyver
|
r15597 | if not callable(function): | ||
raise TypeError('Need a callable, got %r' % function) | ||||
Quentin Peter
|
r26114 | if function not in self.callbacks[event]: | ||
Matthias Bussonnier
|
r28468 | self.callbacks[event].append(function) | ||
Thomas Kluyver
|
r15597 | |||
Thomas Kluyver
|
r15605 | def unregister(self, event, function): | ||
Thomas Kluyver
|
r15599 | """Remove a callback from the given event.""" | ||
Fabio Niephaus
|
r23997 | if function in self.callbacks[event]: | ||
return self.callbacks[event].remove(function) | ||||
raise ValueError('Function {!r} is not registered as a {} callback'.format(function, event)) | ||||
Thomas Kluyver
|
r15605 | def trigger(self, event, *args, **kwargs): | ||
"""Call callbacks for ``event``. | ||||
Matthias Bussonnier
|
r26498 | |||
Thomas Kluyver
|
r15599 | Any additional arguments are passed to all callbacks registered for this | ||
event. Exceptions raised by callbacks are caught, and a message printed. | ||||
""" | ||||
Craig Citro
|
r22317 | for func in self.callbacks[event][:]: | ||
Thomas Kluyver
|
r15597 | try: | ||
func(*args, **kwargs) | ||||
jsnydes
|
r24961 | except (Exception, KeyboardInterrupt): | ||
Tim Nonet
|
r28312 | if self.print_on_error: | ||
Matthias Bussonnier
|
r28501 | print( | ||
"Error in callback {} (for {}), with arguments args {},kwargs {}:".format( | ||||
func, event, args, kwargs | ||||
) | ||||
) | ||||
Thomas Kluyver
|
r15597 | self.shell.showtraceback() | ||
Thomas Kluyver
|
r15599 | # event_name -> prototype mapping | ||
Thomas Kluyver
|
r15605 | available_events = {} | ||
Thomas Kluyver
|
r15599 | |||
Fabio Niephaus
|
r23997 | def _define_event(callback_function): | ||
Matthias Bussonnier
|
r28469 | available_events[callback_function.__name__] = callback_function | ||
return callback_function | ||||
Thomas Kluyver
|
r15597 | |||
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
|
r15609 | @_define_event | ||
Fabio Niephaus
|
r23997 | def pre_execute(): | ||
Thomas Kluyver
|
r15597 | """Fires before code is executed in response to user/frontend action. | ||
Matthias Bussonnier
|
r26498 | |||
Thomas Kluyver
|
r15627 | This includes comm and widget messages and silent execution, as well as user | ||
Fabio Niephaus
|
r23982 | code cells. | ||
""" | ||||
Thomas Kluyver
|
r15597 | pass | ||
Thomas Kluyver
|
r15609 | @_define_event | ||
Fabio Niephaus
|
r23997 | def pre_run_cell(info): | ||
Fabio Niephaus
|
r23982 | """Fires before user-entered code runs. | ||
Thomas Kluyver
|
r15597 | |||
Fabio Niephaus
|
r23982 | Parameters | ||
---------- | ||||
Fabio Niephaus
|
r23997 | info : :class:`~IPython.core.interactiveshell.ExecutionInfo` | ||
Matthias Bussonnier
|
r26498 | An object containing information used for the code execution. | ||
Fabio Niephaus
|
r23982 | """ | ||
Thomas Kluyver
|
r15602 | pass | ||
Thomas Kluyver
|
r15609 | @_define_event | ||
Fabio Niephaus
|
r23997 | def post_execute(): | ||
Fabio Niephaus
|
r23982 | """Fires after code is executed in response to user/frontend action. | ||
Matthias Bussonnier
|
r26498 | |||
Fabio Niephaus
|
r23909 | This includes comm and widget messages and silent execution, as well as user | ||
code cells. | ||||
""" | ||||
pass | ||||
@_define_event | ||||
Fabio Niephaus
|
r23982 | def post_run_cell(result): | ||
"""Fires after user-entered code runs. | ||||
Fabio Niephaus
|
r23909 | |||
Parameters | ||||
---------- | ||||
result : :class:`~IPython.core.interactiveshell.ExecutionResult` | ||||
Matthias Bussonnier
|
r26498 | The object which will be returned as the execution result. | ||
Fabio Niephaus
|
r23909 | """ | ||
pass | ||||
@_define_event | ||||
Thomas Kluyver
|
r15612 | def shell_initialized(ip): | ||
Thomas Kluyver
|
r15602 | """Fires after initialisation of :class:`~IPython.core.interactiveshell.InteractiveShell`. | ||
Matthias Bussonnier
|
r26498 | |||
Thomas Kluyver
|
r15602 | This is before extensions and startup scripts are loaded, so it can only be | ||
set by subclassing. | ||||
Matthias Bussonnier
|
r26498 | |||
Thomas Kluyver
|
r15604 | Parameters | ||
---------- | ||||
ip : :class:`~IPython.core.interactiveshell.InteractiveShell` | ||||
Matthias Bussonnier
|
r26498 | The newly initialised shell. | ||
Thomas Kluyver
|
r15602 | """ | ||
pass | ||||