##// END OF EJS Templates
Attempt to remove backcall....
Matthias Bussonnier -
Show More
@@ -1,166 +1,155 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
10
11 .. note::
11 .. note::
12
12
13 This API is experimental in IPython 2.0, and may be revised in future versions.
13 This API is experimental in IPython 2.0, and may be revised in future versions.
14 """
14 """
15
15
16 from backcall import callback_prototype
17
18
16
19 class EventManager(object):
17 class EventManager(object):
20 """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.
21
19
22 This is attached to :class:`~IPython.core.interactiveshell.InteractiveShell`
20 This is attached to :class:`~IPython.core.interactiveshell.InteractiveShell`
23 instances as an ``events`` attribute.
21 instances as an ``events`` attribute.
24
22
25 .. note::
23 .. note::
26
24
27 This API is experimental in IPython 2.0, and may be revised in future versions.
25 This API is experimental in IPython 2.0, and may be revised in future versions.
28 """
26 """
29
27
30 def __init__(self, shell, available_events, print_on_error=True):
28 def __init__(self, shell, available_events, print_on_error=True):
31 """Initialise the :class:`CallbackManager`.
29 """Initialise the :class:`CallbackManager`.
32
30
33 Parameters
31 Parameters
34 ----------
32 ----------
35 shell
33 shell
36 The :class:`~IPython.core.interactiveshell.InteractiveShell` instance
34 The :class:`~IPython.core.interactiveshell.InteractiveShell` instance
37 available_events
35 available_events
38 An iterable of names for callback events.
36 An iterable of names for callback events.
39 print_on_error:
37 print_on_error:
40 A boolean flag to set whether the EventManager will print a warning which a event errors.
38 A boolean flag to set whether the EventManager will print a warning which a event errors.
41 """
39 """
42 self.shell = shell
40 self.shell = shell
43 self.callbacks = {n:[] for n in available_events}
41 self.callbacks = {n:[] for n in available_events}
44 self.print_on_error = print_on_error
42 self.print_on_error = print_on_error
45
43
46 def register(self, event, function):
44 def register(self, event, function):
47 """Register a new event callback.
45 """Register a new event callback.
48
46
49 Parameters
47 Parameters
50 ----------
48 ----------
51 event : str
49 event : str
52 The event for which to register this callback.
50 The event for which to register this callback.
53 function : callable
51 function : callable
54 A function to be called on the given event. It should take the same
52 A function to be called on the given event. It should take the same
55 parameters as the appropriate callback prototype.
53 parameters as the appropriate callback prototype.
56
54
57 Raises
55 Raises
58 ------
56 ------
59 TypeError
57 TypeError
60 If ``function`` is not callable.
58 If ``function`` is not callable.
61 KeyError
59 KeyError
62 If ``event`` is not one of the known events.
60 If ``event`` is not one of the known events.
63 """
61 """
64 if not callable(function):
62 if not callable(function):
65 raise TypeError('Need a callable, got %r' % function)
63 raise TypeError('Need a callable, got %r' % function)
66 callback_proto = available_events.get(event)
67 if function not in self.callbacks[event]:
64 if function not in self.callbacks[event]:
68 self.callbacks[event].append(callback_proto.adapt(function))
65 self.callbacks[event].append(function)
69
66
70 def unregister(self, event, function):
67 def unregister(self, event, function):
71 """Remove a callback from the given event."""
68 """Remove a callback from the given event."""
72 if function in self.callbacks[event]:
69 if function in self.callbacks[event]:
73 return self.callbacks[event].remove(function)
70 return self.callbacks[event].remove(function)
74
71
75 # Remove callback in case ``function`` was adapted by `backcall`.
76 for callback in self.callbacks[event]:
77 try:
78 if callback.__wrapped__ is function:
79 return self.callbacks[event].remove(callback)
80 except AttributeError:
81 pass
82
83 raise ValueError('Function {!r} is not registered as a {} callback'.format(function, event))
72 raise ValueError('Function {!r} is not registered as a {} callback'.format(function, event))
84
73
85 def trigger(self, event, *args, **kwargs):
74 def trigger(self, event, *args, **kwargs):
86 """Call callbacks for ``event``.
75 """Call callbacks for ``event``.
87
76
88 Any additional arguments are passed to all callbacks registered for this
77 Any additional arguments are passed to all callbacks registered for this
89 event. Exceptions raised by callbacks are caught, and a message printed.
78 event. Exceptions raised by callbacks are caught, and a message printed.
90 """
79 """
91 for func in self.callbacks[event][:]:
80 for func in self.callbacks[event][:]:
92 try:
81 try:
93 func(*args, **kwargs)
82 func(*args, **kwargs)
94 except (Exception, KeyboardInterrupt):
83 except (Exception, KeyboardInterrupt):
95 if self.print_on_error:
84 if self.print_on_error:
96 print("Error in callback {} (for {}):".format(func, event))
85 print("Error in callback {} (for {}):".format(func, event))
97 self.shell.showtraceback()
86 self.shell.showtraceback()
98
87
99 # event_name -> prototype mapping
88 # event_name -> prototype mapping
100 available_events = {}
89 available_events = {}
101
90
102 def _define_event(callback_function):
91 def _define_event(callback_function):
103 callback_proto = callback_prototype(callback_function)
92 callback_proto = callback_prototype(callback_function)
104 available_events[callback_function.__name__] = callback_proto
93 available_events[callback_function.__name__] = callback_proto
105 return callback_proto
94 return callback_proto
106
95
107 # ------------------------------------------------------------------------------
96 # ------------------------------------------------------------------------------
108 # Callback prototypes
97 # Callback prototypes
109 #
98 #
110 # No-op functions which describe the names of available events and the
99 # No-op functions which describe the names of available events and the
111 # signatures of callbacks for those events.
100 # signatures of callbacks for those events.
112 # ------------------------------------------------------------------------------
101 # ------------------------------------------------------------------------------
113
102
114 @_define_event
103 @_define_event
115 def pre_execute():
104 def pre_execute():
116 """Fires before code is executed in response to user/frontend action.
105 """Fires before code is executed in response to user/frontend action.
117
106
118 This includes comm and widget messages and silent execution, as well as user
107 This includes comm and widget messages and silent execution, as well as user
119 code cells.
108 code cells.
120 """
109 """
121 pass
110 pass
122
111
123 @_define_event
112 @_define_event
124 def pre_run_cell(info):
113 def pre_run_cell(info):
125 """Fires before user-entered code runs.
114 """Fires before user-entered code runs.
126
115
127 Parameters
116 Parameters
128 ----------
117 ----------
129 info : :class:`~IPython.core.interactiveshell.ExecutionInfo`
118 info : :class:`~IPython.core.interactiveshell.ExecutionInfo`
130 An object containing information used for the code execution.
119 An object containing information used for the code execution.
131 """
120 """
132 pass
121 pass
133
122
134 @_define_event
123 @_define_event
135 def post_execute():
124 def post_execute():
136 """Fires after code is executed in response to user/frontend action.
125 """Fires after code is executed in response to user/frontend action.
137
126
138 This includes comm and widget messages and silent execution, as well as user
127 This includes comm and widget messages and silent execution, as well as user
139 code cells.
128 code cells.
140 """
129 """
141 pass
130 pass
142
131
143 @_define_event
132 @_define_event
144 def post_run_cell(result):
133 def post_run_cell(result):
145 """Fires after user-entered code runs.
134 """Fires after user-entered code runs.
146
135
147 Parameters
136 Parameters
148 ----------
137 ----------
149 result : :class:`~IPython.core.interactiveshell.ExecutionResult`
138 result : :class:`~IPython.core.interactiveshell.ExecutionResult`
150 The object which will be returned as the execution result.
139 The object which will be returned as the execution result.
151 """
140 """
152 pass
141 pass
153
142
154 @_define_event
143 @_define_event
155 def shell_initialized(ip):
144 def shell_initialized(ip):
156 """Fires after initialisation of :class:`~IPython.core.interactiveshell.InteractiveShell`.
145 """Fires after initialisation of :class:`~IPython.core.interactiveshell.InteractiveShell`.
157
146
158 This is before extensions and startup scripts are loaded, so it can only be
147 This is before extensions and startup scripts are loaded, so it can only be
159 set by subclassing.
148 set by subclassing.
160
149
161 Parameters
150 Parameters
162 ----------
151 ----------
163 ip : :class:`~IPython.core.interactiveshell.InteractiveShell`
152 ip : :class:`~IPython.core.interactiveshell.InteractiveShell`
164 The newly initialised shell.
153 The newly initialised shell.
165 """
154 """
166 pass
155 pass
@@ -1,118 +1,117 b''
1 [metadata]
1 [metadata]
2 name = ipython
2 name = ipython
3 version = attr: IPython.core.release.__version__
3 version = attr: IPython.core.release.__version__
4 url = https://ipython.org
4 url = https://ipython.org
5 description = IPython: Productive Interactive Computing
5 description = IPython: Productive Interactive Computing
6 long_description_content_type = text/x-rst
6 long_description_content_type = text/x-rst
7 long_description = file: long_description.rst
7 long_description = file: long_description.rst
8 license_file = LICENSE
8 license_file = LICENSE
9 project_urls =
9 project_urls =
10 Documentation = https://ipython.readthedocs.io/
10 Documentation = https://ipython.readthedocs.io/
11 Funding = https://numfocus.org/
11 Funding = https://numfocus.org/
12 Source = https://github.com/ipython/ipython
12 Source = https://github.com/ipython/ipython
13 Tracker = https://github.com/ipython/ipython/issues
13 Tracker = https://github.com/ipython/ipython/issues
14 keywords = Interactive, Interpreter, Shell, Embedding
14 keywords = Interactive, Interpreter, Shell, Embedding
15 platforms = Linux, Mac OSX, Windows
15 platforms = Linux, Mac OSX, Windows
16 classifiers =
16 classifiers =
17 Framework :: IPython
17 Framework :: IPython
18 Framework :: Jupyter
18 Framework :: Jupyter
19 Intended Audience :: Developers
19 Intended Audience :: Developers
20 Intended Audience :: Science/Research
20 Intended Audience :: Science/Research
21 License :: OSI Approved :: BSD License
21 License :: OSI Approved :: BSD License
22 Programming Language :: Python
22 Programming Language :: Python
23 Programming Language :: Python :: 3
23 Programming Language :: Python :: 3
24 Programming Language :: Python :: 3 :: Only
24 Programming Language :: Python :: 3 :: Only
25 Topic :: System :: Shells
25 Topic :: System :: Shells
26
26
27 [options]
27 [options]
28 packages = find:
28 packages = find:
29 python_requires = >=3.9
29 python_requires = >=3.9
30 zip_safe = False
30 zip_safe = False
31 install_requires =
31 install_requires =
32 appnope; sys_platform == "darwin"
32 appnope; sys_platform == "darwin"
33 backcall
34 colorama; sys_platform == "win32"
33 colorama; sys_platform == "win32"
35 decorator
34 decorator
36 exceptiongroup; python_version<'3.11'
35 exceptiongroup; python_version<'3.11'
37 jedi>=0.16
36 jedi>=0.16
38 matplotlib-inline
37 matplotlib-inline
39 pexpect>4.3; sys_platform != "win32"
38 pexpect>4.3; sys_platform != "win32"
40 pickleshare
39 pickleshare
41 prompt_toolkit>=3.0.30,<3.1.0,!=3.0.37
40 prompt_toolkit>=3.0.30,<3.1.0,!=3.0.37
42 pygments>=2.4.0
41 pygments>=2.4.0
43 stack_data
42 stack_data
44 traitlets>=5
43 traitlets>=5
45 typing_extensions ; python_version<'3.10'
44 typing_extensions ; python_version<'3.10'
46
45
47 [options.extras_require]
46 [options.extras_require]
48 black =
47 black =
49 black
48 black
50 doc =
49 doc =
51 ipykernel
50 ipykernel
52 setuptools>=18.5
51 setuptools>=18.5
53 sphinx>=1.3
52 sphinx>=1.3
54 sphinx-rtd-theme
53 sphinx-rtd-theme
55 docrepr
54 docrepr
56 matplotlib
55 matplotlib
57 stack_data
56 stack_data
58 pytest<7
57 pytest<7
59 typing_extensions
58 typing_extensions
60 exceptiongroup
59 exceptiongroup
61 %(test)s
60 %(test)s
62 kernel =
61 kernel =
63 ipykernel
62 ipykernel
64 nbconvert =
63 nbconvert =
65 nbconvert
64 nbconvert
66 nbformat =
65 nbformat =
67 nbformat
66 nbformat
68 notebook =
67 notebook =
69 ipywidgets
68 ipywidgets
70 notebook
69 notebook
71 parallel =
70 parallel =
72 ipyparallel
71 ipyparallel
73 qtconsole =
72 qtconsole =
74 qtconsole
73 qtconsole
75 terminal =
74 terminal =
76 test =
75 test =
77 pytest<7.1
76 pytest<7.1
78 pytest-asyncio
77 pytest-asyncio
79 testpath
78 testpath
80 test_extra =
79 test_extra =
81 %(test)s
80 %(test)s
82 curio
81 curio
83 matplotlib!=3.2.0
82 matplotlib!=3.2.0
84 nbformat
83 nbformat
85 numpy>=1.22
84 numpy>=1.22
86 pandas
85 pandas
87 trio
86 trio
88 all =
87 all =
89 %(black)s
88 %(black)s
90 %(doc)s
89 %(doc)s
91 %(kernel)s
90 %(kernel)s
92 %(nbconvert)s
91 %(nbconvert)s
93 %(nbformat)s
92 %(nbformat)s
94 %(notebook)s
93 %(notebook)s
95 %(parallel)s
94 %(parallel)s
96 %(qtconsole)s
95 %(qtconsole)s
97 %(terminal)s
96 %(terminal)s
98 %(test_extra)s
97 %(test_extra)s
99 %(test)s
98 %(test)s
100
99
101 [options.packages.find]
100 [options.packages.find]
102 exclude =
101 exclude =
103 setupext
102 setupext
104
103
105 [options.package_data]
104 [options.package_data]
106 IPython = py.typed
105 IPython = py.typed
107 IPython.core = profile/README*
106 IPython.core = profile/README*
108 IPython.core.tests = *.png, *.jpg, daft_extension/*.py
107 IPython.core.tests = *.png, *.jpg, daft_extension/*.py
109 IPython.lib.tests = *.wav
108 IPython.lib.tests = *.wav
110 IPython.testing.plugin = *.txt
109 IPython.testing.plugin = *.txt
111
110
112 [velin]
111 [velin]
113 ignore_patterns =
112 ignore_patterns =
114 IPython/core/tests
113 IPython/core/tests
115 IPython/testing
114 IPython/testing
116
115
117 [tool.black]
116 [tool.black]
118 exclude = 'timing\.py'
117 exclude = 'timing\.py'
General Comments 0
You need to be logged in to leave comments. Login now