##// END OF EJS Templates
Add note about experimental API
Thomas Kluyver -
Show More
@@ -1,129 +1,137 b''
1 """Infrastructure for registering and firing callbacks on application events.
1 """Infrastructure for registering and firing callbacks on application events.
2
2
3 Unlike :mod:`IPython.core.hooks`, which lets end users set single functions to
3 Unlike :mod:`IPython.core.hooks`, which lets end users set single functions to
4 be called at specific times, or a collection of alternative methods to try,
4 be called at specific times, or a collection of alternative methods to try,
5 callbacks are designed to be used by extension authors. A number of callbacks
5 callbacks are designed to be used by extension authors. A number of callbacks
6 can be registered for the same event without needing to be aware of one another.
6 can be registered for the same event without needing to be aware of one another.
7
7
8 The functions defined in this module are no-ops indicating the names of available
8 The functions defined in this module are no-ops indicating the names of available
9 events and the arguments which will be passed to them.
9 events and the arguments which will be passed to them.
10
11 .. note::
12
13 This API is experimental in IPython 2.0, and may be revised in future versions.
10 """
14 """
11 from __future__ import print_function
15 from __future__ import print_function
12
16
13 class EventManager(object):
17 class EventManager(object):
14 """Manage a collection of events and a sequence of callbacks for each.
18 """Manage a collection of events and a sequence of callbacks for each.
15
19
16 This is attached to :class:`~IPython.core.interactiveshell.InteractiveShell`
20 This is attached to :class:`~IPython.core.interactiveshell.InteractiveShell`
17 instances as a ``callbacks`` attribute.
21 instances as a ``callbacks`` attribute.
22
23 .. note::
24
25 This API is experimental in IPython 2.0, and may be revised in future versions.
18 """
26 """
19 def __init__(self, shell, available_events):
27 def __init__(self, shell, available_events):
20 """Initialise the :class:`CallbackManager`.
28 """Initialise the :class:`CallbackManager`.
21
29
22 Parameters
30 Parameters
23 ----------
31 ----------
24 shell
32 shell
25 The :class:`~IPython.core.interactiveshell.InteractiveShell` instance
33 The :class:`~IPython.core.interactiveshell.InteractiveShell` instance
26 available_callbacks
34 available_callbacks
27 An iterable of names for callback events.
35 An iterable of names for callback events.
28 """
36 """
29 self.shell = shell
37 self.shell = shell
30 self.callbacks = {n:[] for n in available_events}
38 self.callbacks = {n:[] for n in available_events}
31
39
32 def register(self, event, function):
40 def register(self, event, function):
33 """Register a new callback
41 """Register a new callback
34
42
35 Parameters
43 Parameters
36 ----------
44 ----------
37 event : str
45 event : str
38 The event for which to register this callback.
46 The event for which to register this callback.
39 function : callable
47 function : callable
40 A function to be called on the given event. It should take the same
48 A function to be called on the given event. It should take the same
41 parameters as the appropriate callback prototype.
49 parameters as the appropriate callback prototype.
42
50
43 Raises
51 Raises
44 ------
52 ------
45 TypeError
53 TypeError
46 If ``function`` is not callable.
54 If ``function`` is not callable.
47 KeyError
55 KeyError
48 If ``event`` is not one of the known events.
56 If ``event`` is not one of the known events.
49 """
57 """
50 if not callable(function):
58 if not callable(function):
51 raise TypeError('Need a callable, got %r' % function)
59 raise TypeError('Need a callable, got %r' % function)
52 self.callbacks[event].append(function)
60 self.callbacks[event].append(function)
53
61
54 def unregister(self, event, function):
62 def unregister(self, event, function):
55 """Remove a callback from the given event."""
63 """Remove a callback from the given event."""
56 self.callbacks[event].remove(function)
64 self.callbacks[event].remove(function)
57
65
58 def reset(self, event):
66 def reset(self, event):
59 """Clear all callbacks for the given event."""
67 """Clear all callbacks for the given event."""
60 self.callbacks[event] = []
68 self.callbacks[event] = []
61
69
62 def reset_all(self):
70 def reset_all(self):
63 """Clear all callbacks for all events."""
71 """Clear all callbacks for all events."""
64 self.callbacks = {n:[] for n in self.callbacks}
72 self.callbacks = {n:[] for n in self.callbacks}
65
73
66 def trigger(self, event, *args, **kwargs):
74 def trigger(self, event, *args, **kwargs):
67 """Call callbacks for ``event``.
75 """Call callbacks for ``event``.
68
76
69 Any additional arguments are passed to all callbacks registered for this
77 Any additional arguments are passed to all callbacks registered for this
70 event. Exceptions raised by callbacks are caught, and a message printed.
78 event. Exceptions raised by callbacks are caught, and a message printed.
71 """
79 """
72 for func in self.callbacks[event]:
80 for func in self.callbacks[event]:
73 try:
81 try:
74 func(*args, **kwargs)
82 func(*args, **kwargs)
75 except Exception:
83 except Exception:
76 print("Error in callback {} (for {}):".format(func, event))
84 print("Error in callback {} (for {}):".format(func, event))
77 self.shell.showtraceback()
85 self.shell.showtraceback()
78
86
79 # event_name -> prototype mapping
87 # event_name -> prototype mapping
80 available_events = {}
88 available_events = {}
81
89
82 def _collect(callback_proto):
90 def _collect(callback_proto):
83 available_events[callback_proto.__name__] = callback_proto
91 available_events[callback_proto.__name__] = callback_proto
84 return callback_proto
92 return callback_proto
85
93
86 # ------------------------------------------------------------------------------
94 # ------------------------------------------------------------------------------
87 # Callback prototypes
95 # Callback prototypes
88 #
96 #
89 # No-op functions which describe the names of available events and the
97 # No-op functions which describe the names of available events and the
90 # signatures of callbacks for those events.
98 # signatures of callbacks for those events.
91 # ------------------------------------------------------------------------------
99 # ------------------------------------------------------------------------------
92
100
93 @_collect
101 @_collect
94 def pre_execute():
102 def pre_execute():
95 """Fires before code is executed in response to user/frontend action.
103 """Fires before code is executed in response to user/frontend action.
96
104
97 This includes comm and widget messages as well as user code cells."""
105 This includes comm and widget messages as well as user code cells."""
98 pass
106 pass
99
107
100 @_collect
108 @_collect
101 def pre_execute_explicit():
109 def pre_execute_explicit():
102 """Fires before user-entered code runs."""
110 """Fires before user-entered code runs."""
103 pass
111 pass
104
112
105 @_collect
113 @_collect
106 def post_execute():
114 def post_execute():
107 """Fires after code is executed in response to user/frontend action.
115 """Fires after code is executed in response to user/frontend action.
108
116
109 This includes comm and widget messages as well as user code cells."""
117 This includes comm and widget messages as well as user code cells."""
110 pass
118 pass
111
119
112 @_collect
120 @_collect
113 def post_execute_explicit():
121 def post_execute_explicit():
114 """Fires after user-entered code runs."""
122 """Fires after user-entered code runs."""
115 pass
123 pass
116
124
117 @_collect
125 @_collect
118 def shell_initialised(ip):
126 def shell_initialised(ip):
119 """Fires after initialisation of :class:`~IPython.core.interactiveshell.InteractiveShell`.
127 """Fires after initialisation of :class:`~IPython.core.interactiveshell.InteractiveShell`.
120
128
121 This is before extensions and startup scripts are loaded, so it can only be
129 This is before extensions and startup scripts are loaded, so it can only be
122 set by subclassing.
130 set by subclassing.
123
131
124 Parameters
132 Parameters
125 ----------
133 ----------
126 ip : :class:`~IPython.core.interactiveshell.InteractiveShell`
134 ip : :class:`~IPython.core.interactiveshell.InteractiveShell`
127 The newly initialised shell.
135 The newly initialised shell.
128 """
136 """
129 pass
137 pass
@@ -1,38 +1,42 b''
1 =====================
1 =====================
2 Registering callbacks
2 Registering callbacks
3 =====================
3 =====================
4
4
5 Extension code can register callbacks functions which will be called on specific
5 Extension code can register callbacks functions which will be called on specific
6 events within the IPython code. You can see the current list of available
6 events within the IPython code. You can see the current list of available
7 callbacks, and the parameters that will be passed with each, in the callback
7 callbacks, and the parameters that will be passed with each, in the callback
8 prototype functions defined in :mod:`IPython.core.callbacks`.
8 prototype functions defined in :mod:`IPython.core.callbacks`.
9
9
10 To register callbacks, use :meth:`IPython.core.callbacks.CallbackManager.register`.
10 To register callbacks, use :meth:`IPython.core.callbacks.CallbackManager.register`.
11 For example::
11 For example::
12
12
13 class VarWatcher(object):
13 class VarWatcher(object):
14 def __init__(self, ip):
14 def __init__(self, ip):
15 self.shell = ip
15 self.shell = ip
16 self.last_x = None
16 self.last_x = None
17
17
18 def pre_execute(self):
18 def pre_execute(self):
19 self.last_x = self.shell.user_ns.get('x', None)
19 self.last_x = self.shell.user_ns.get('x', None)
20
20
21 def post_execute(self):
21 def post_execute(self):
22 if self.shell.user_ns.get('x', None) != self.last_x:
22 if self.shell.user_ns.get('x', None) != self.last_x:
23 print("x changed!")
23 print("x changed!")
24
24
25 def load_ipython_extension(ip):
25 def load_ipython_extension(ip):
26 vw = VarWatcher(ip)
26 vw = VarWatcher(ip)
27 ip.callbacks.register('pre_execute', vw.pre_execute)
27 ip.callbacks.register('pre_execute', vw.pre_execute)
28 ip.callbacks.register('post_execute', vw.post_execute)
28 ip.callbacks.register('post_execute', vw.post_execute)
29
29
30 .. note::
31
32 This API is experimental in IPython 2.0, and may be revised in future versions.
33
30 .. seealso::
34 .. seealso::
31
35
32 Module :mod:`IPython.core.hooks`
36 Module :mod:`IPython.core.hooks`
33 The older 'hooks' system allows end users to customise some parts of
37 The older 'hooks' system allows end users to customise some parts of
34 IPython's behaviour.
38 IPython's behaviour.
35
39
36 :doc:`inputtransforms`
40 :doc:`inputtransforms`
37 By registering input transformers that don't change code, you can monitor
41 By registering input transformers that don't change code, you can monitor
38 what is being executed.
42 what is being executed.
General Comments 0
You need to be logged in to leave comments. Login now