Show More
@@ -0,0 +1,140 b'' | |||||
|
1 | #!/usr/bin/env python | |||
|
2 | # coding: utf-8 | |||
|
3 | """ | |||
|
4 | Support for creating GUI apps and starting event loops. | |||
|
5 | ||||
|
6 | IPython's GUI integration allows interative plotting and GUI usage in IPython | |||
|
7 | session. IPython has two different types of GUI integration: | |||
|
8 | ||||
|
9 | 1. The terminal based IPython supports GUI event loops through Python's | |||
|
10 | PyOS_InputHook. PyOS_InputHook is a hook that Python calls periodically | |||
|
11 | whenever raw_input is waiting for a user to type code. We implement GUI | |||
|
12 | support in the terminal by setting PyOS_InputHook to a function that | |||
|
13 | iterates the event loop for a short while. It is important to note that | |||
|
14 | in this situation, the real GUI event loop is NOT run in the normal | |||
|
15 | manner, so you can't use the normal means to detect that it is running. | |||
|
16 | 2. In the two process IPython kernel/frontend, the GUI event loop is run in | |||
|
17 | the kernel. In this case, the event loop is run in the normal manner by | |||
|
18 | calling the function or method of the GUI toolkit that starts the event | |||
|
19 | loop. | |||
|
20 | ||||
|
21 | In addition to starting the GUI event loops in one of these two ways, IPython | |||
|
22 | will *always* create an appropriate GUI application object when GUi | |||
|
23 | integration is enabled. | |||
|
24 | ||||
|
25 | If you want your GUI apps to run in IPython you need to do two things: | |||
|
26 | ||||
|
27 | 1. Test to see if there is already an existing main application object. If | |||
|
28 | there is, you should use it. If there is not an existing application object | |||
|
29 | you should create one. | |||
|
30 | 2. Test to see if the GUI event loop is running. If it is, you should not | |||
|
31 | start it. If the event loop is not running you may start it. | |||
|
32 | ||||
|
33 | This module contains functions for each toolkit that perform these things | |||
|
34 | in a consistent manner. Because of how PyOS_InputHook runs the event loop | |||
|
35 | you cannot detect if the event loop is running using the traditional calls | |||
|
36 | (such as ``wx.GetApp.IsMainLoopRunning()`` in wxPython). If PyOS_InputHook is | |||
|
37 | set These methods will return a false negative. That is, they will say the | |||
|
38 | event loop is not running, when is actually is. To work around this limitation | |||
|
39 | we proposed the following informal protocol: | |||
|
40 | ||||
|
41 | * Whenever someone starts the event loop, they *must* set the ``_in_event_loop`` | |||
|
42 | attribute of the main application object to ``True``. This should be done | |||
|
43 | regardless of how the event loop is actually run. | |||
|
44 | * Whenever someone stops the event loop, they *must* set the ``_in_event_loop`` | |||
|
45 | attribute of the main application object to ``False``. | |||
|
46 | * If you want to see if the event loop is running, you *must* use ``hasattr`` | |||
|
47 | to see if ``_in_event_loop`` attribute has been set. If it is set, you | |||
|
48 | *must* use its value. If it has not been set, you can query the toolkit | |||
|
49 | in the normal manner. | |||
|
50 | ||||
|
51 | The functions below implement this logic for each GUI toolkit. If you need | |||
|
52 | to create custom application subclasses, you will likely have to modify this | |||
|
53 | code for your own purposes. This code can be copied into your own project | |||
|
54 | so you don't have to depend on IPython. | |||
|
55 | ||||
|
56 | """ | |||
|
57 | ||||
|
58 | #----------------------------------------------------------------------------- | |||
|
59 | # Copyright (C) 2008-2010 The IPython Development Team | |||
|
60 | # | |||
|
61 | # Distributed under the terms of the BSD License. The full license is in | |||
|
62 | # the file COPYING, distributed as part of this software. | |||
|
63 | #----------------------------------------------------------------------------- | |||
|
64 | ||||
|
65 | #----------------------------------------------------------------------------- | |||
|
66 | # Imports | |||
|
67 | #----------------------------------------------------------------------------- | |||
|
68 | ||||
|
69 | #----------------------------------------------------------------------------- | |||
|
70 | # wx | |||
|
71 | #----------------------------------------------------------------------------- | |||
|
72 | ||||
|
73 | def get_app_wx(*args, **kwargs): | |||
|
74 | """Create a new wx app or return an exiting one.""" | |||
|
75 | import wx | |||
|
76 | app = wx.GetApp() | |||
|
77 | if app is None: | |||
|
78 | app = wx.PySimpleApp(*args, **kwargs) | |||
|
79 | return app | |||
|
80 | ||||
|
81 | def is_event_loop_running_wx(app=None): | |||
|
82 | """Is the wx event loop running.""" | |||
|
83 | if app is None: | |||
|
84 | app = get_app_wx() | |||
|
85 | if hasattr(app, '_in_event_loop'): | |||
|
86 | return app._in_event_loop | |||
|
87 | else: | |||
|
88 | return app.IsMainLoopRunning() | |||
|
89 | ||||
|
90 | def start_event_loop_wx(app=None): | |||
|
91 | """Start the wx event loop in a consistent manner.""" | |||
|
92 | if app is None: | |||
|
93 | app = get_app_wx() | |||
|
94 | if not is_event_loop_running_wx(app): | |||
|
95 | app._in_event_loop = True | |||
|
96 | app.MainLoop() | |||
|
97 | app._in_event_loop = False | |||
|
98 | else: | |||
|
99 | app._in_event_loop = True | |||
|
100 | ||||
|
101 | #----------------------------------------------------------------------------- | |||
|
102 | # qt4 | |||
|
103 | #----------------------------------------------------------------------------- | |||
|
104 | ||||
|
105 | def get_app_qt4(*args, **kwargs): | |||
|
106 | """Create a new qt4 app or return an existing one.""" | |||
|
107 | from PyQt4 import QtGui | |||
|
108 | app = QtGui.QApplication.instance() | |||
|
109 | if app is None: | |||
|
110 | app = QtGui.QApplication(*args, **kwargs) | |||
|
111 | return app | |||
|
112 | ||||
|
113 | def is_event_loop_running_qt4(app=None): | |||
|
114 | """Is the qt4 event loop running.""" | |||
|
115 | if app is None: | |||
|
116 | app = get_app_qt4() | |||
|
117 | if hasattr(app, '_in_event_loop'): | |||
|
118 | return app._in_event_loop | |||
|
119 | else: | |||
|
120 | # Does qt4 provide a other way to detect this? | |||
|
121 | return False | |||
|
122 | ||||
|
123 | def start_event_loop_qt4(app=None): | |||
|
124 | """Start the qt4 event loop in a consistent manner.""" | |||
|
125 | if app is None: | |||
|
126 | app = get_app_qt4() | |||
|
127 | if not is_event_loop_running_qt4(app): | |||
|
128 | app._in_event_loop = True | |||
|
129 | app.exec_() | |||
|
130 | app._in_event_loop = False | |||
|
131 | else: | |||
|
132 | app._in_event_loop = True | |||
|
133 | ||||
|
134 | #----------------------------------------------------------------------------- | |||
|
135 | # Tk | |||
|
136 | #----------------------------------------------------------------------------- | |||
|
137 | ||||
|
138 | #----------------------------------------------------------------------------- | |||
|
139 | # gtk | |||
|
140 | #----------------------------------------------------------------------------- |
@@ -1,3 +1,9 b'' | |||||
|
1 | """Produce SVG versions of active plots for display by the rich Qt frontend. | |||
|
2 | """ | |||
|
3 | #----------------------------------------------------------------------------- | |||
|
4 | # Imports | |||
|
5 | #----------------------------------------------------------------------------- | |||
|
6 | ||||
1 | # Standard library imports |
|
7 | # Standard library imports | |
2 | from cStringIO import StringIO |
|
8 | from cStringIO import StringIO | |
3 |
|
9 | |||
@@ -8,12 +14,14 b' from matplotlib._pylab_helpers import Gcf' | |||||
8 | # Local imports. |
|
14 | # Local imports. | |
9 | from backend_payload import add_plot_payload |
|
15 | from backend_payload import add_plot_payload | |
10 |
|
16 | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | # Functions | |||
|
19 | #----------------------------------------------------------------------------- | |||
11 |
|
20 | |||
12 | def show(): |
|
21 | def show(): | |
13 | """ Deliver a SVG payload. |
|
22 | """ Deliver a SVG payload. | |
14 | """ |
|
23 | """ | |
15 |
figure_manager |
|
24 | for figure_manager in Gcf.get_all_fig_managers(): | |
16 | if figure_manager is not None: |
|
|||
17 | # Make the background transparent. |
|
25 | # Make the background transparent. | |
18 | # figure_manager.canvas.figure.patch.set_alpha(0.0) |
|
26 | # figure_manager.canvas.figure.patch.set_alpha(0.0) | |
19 | # Set the background to white instead so it looks good on black. |
|
27 | # Set the background to white instead so it looks good on black. | |
@@ -22,6 +30,7 b' def show():' | |||||
22 | data = svg_from_canvas(figure_manager.canvas) |
|
30 | data = svg_from_canvas(figure_manager.canvas) | |
23 | add_plot_payload('svg', data) |
|
31 | add_plot_payload('svg', data) | |
24 |
|
32 | |||
|
33 | ||||
25 | def svg_from_canvas(canvas): |
|
34 | def svg_from_canvas(canvas): | |
26 | """ Return a string containing the SVG representation of a FigureCanvasSvg. |
|
35 | """ Return a string containing the SVG representation of a FigureCanvasSvg. | |
27 | """ |
|
36 | """ |
@@ -1,8 +1,29 b'' | |||||
|
1 | """A ZMQ-based subclass of InteractiveShell. | |||
|
2 | ||||
|
3 | This code is meant to ease the refactoring of the base InteractiveShell into | |||
|
4 | something with a cleaner architecture for 2-process use, without actually | |||
|
5 | breaking InteractiveShell itself. So we're doing something a bit ugly, where | |||
|
6 | we subclass and override what we want to fix. Once this is working well, we | |||
|
7 | can go back to the base class and refactor the code for a cleaner inheritance | |||
|
8 | implementation that doesn't rely on so much monkeypatching. | |||
|
9 | ||||
|
10 | But this lets us maintain a fully working IPython as we develop the new | |||
|
11 | machinery. This should thus be thought of as scaffolding. | |||
|
12 | """ | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | # Imports | |||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | from __future__ import print_function | |||
|
17 | ||||
|
18 | # Stdlib | |||
1 | import inspect |
|
19 | import inspect | |
|
20 | import os | |||
2 | import re |
|
21 | import re | |
3 | import sys |
|
22 | import sys | |
|
23 | ||||
4 | from subprocess import Popen, PIPE |
|
24 | from subprocess import Popen, PIPE | |
5 |
|
25 | |||
|
26 | # Our own | |||
6 | from IPython.core.interactiveshell import ( |
|
27 | from IPython.core.interactiveshell import ( | |
7 | InteractiveShell, InteractiveShellABC |
|
28 | InteractiveShell, InteractiveShellABC | |
8 | ) |
|
29 | ) | |
@@ -16,9 +37,16 b' from IPython.zmq.session import extract_header' | |||||
16 | from IPython.core.payloadpage import install_payload_page |
|
37 | from IPython.core.payloadpage import install_payload_page | |
17 | from session import Session |
|
38 | from session import Session | |
18 |
|
39 | |||
|
40 | #----------------------------------------------------------------------------- | |||
|
41 | # Globals and side-effects | |||
|
42 | #----------------------------------------------------------------------------- | |||
|
43 | ||||
19 | # Install the payload version of page. |
|
44 | # Install the payload version of page. | |
20 | install_payload_page() |
|
45 | install_payload_page() | |
21 |
|
46 | |||
|
47 | #----------------------------------------------------------------------------- | |||
|
48 | # Functions and classes | |||
|
49 | #----------------------------------------------------------------------------- | |||
22 |
|
50 | |||
23 | class ZMQDisplayHook(DisplayHook): |
|
51 | class ZMQDisplayHook(DisplayHook): | |
24 |
|
52 | |||
@@ -56,16 +84,23 b' class ZMQInteractiveShell(InteractiveShell):' | |||||
56 | displayhook_class = Type(ZMQDisplayHook) |
|
84 | displayhook_class = Type(ZMQDisplayHook) | |
57 |
|
85 | |||
58 | def system(self, cmd): |
|
86 | def system(self, cmd): | |
59 | cmd = self.var_expand(cmd, depth=2) |
|
87 | cmd = self.var_expand(cmd, depth=2).strip() | |
|
88 | ||||
|
89 | # Runnning a bacgkrounded process from within the gui isn't supported | |||
|
90 | # because we do p.wait() at the end. So instead of silently blocking | |||
|
91 | # we simply refuse to run in this mode, to avoid surprising the user. | |||
|
92 | if cmd.endswith('&'): | |||
|
93 | raise OSError("Background processes not supported.") | |||
|
94 | ||||
60 | sys.stdout.flush() |
|
95 | sys.stdout.flush() | |
61 | sys.stderr.flush() |
|
96 | sys.stderr.flush() | |
62 | p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) |
|
97 | p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) | |
63 | for line in p.stdout.read().split('\n'): |
|
98 | for line in p.stdout.read().split('\n'): | |
64 | if len(line) > 0: |
|
99 | if len(line) > 0: | |
65 |
print |
|
100 | print(line) | |
66 | for line in p.stderr.read().split('\n'): |
|
101 | for line in p.stderr.read().split('\n'): | |
67 | if len(line) > 0: |
|
102 | if len(line) > 0: | |
68 |
print |
|
103 | print(line, file=sys.stderr) | |
69 | p.wait() |
|
104 | p.wait() | |
70 |
|
105 | |||
71 | def init_io(self): |
|
106 | def init_io(self): | |
@@ -349,7 +384,11 b' class ZMQInteractiveShell(InteractiveShell):' | |||||
349 |
|
384 | |||
350 | if use_temp: |
|
385 | if use_temp: | |
351 | filename = self.shell.mktempfile(data) |
|
386 | filename = self.shell.mktempfile(data) | |
352 |
print |
|
387 | print('IPython will make a temporary file named:', filename) | |
|
388 | ||||
|
389 | # Make sure we send to the client an absolute path, in case the working | |||
|
390 | # directory of client and kernel don't match | |||
|
391 | filename = os.path.abspath(filename) | |||
353 |
|
392 | |||
354 | payload = { |
|
393 | payload = { | |
355 | 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic', |
|
394 | 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic', |
@@ -101,4 +101,4 b' gitwash-update:' | |||||
101 | cd source/development/gitwash && rename 's/.rst/.txt/' *.rst |
|
101 | cd source/development/gitwash && rename 's/.rst/.txt/' *.rst | |
102 |
|
102 | |||
103 | nightly: dist |
|
103 | nightly: dist | |
104 | rsync -avH --delete dist/ ipython:www/doc/nightly No newline at end of file |
|
104 | rsync -avH --delete dist/ ipython:www/doc/nightly |
@@ -130,15 +130,9 b' Messages on the XREP/XREQ socket' | |||||
130 | Execute |
|
130 | Execute | |
131 | ------- |
|
131 | ------- | |
132 |
|
132 | |||
133 | The execution request contains a single string, but this may be a multiline |
|
133 | This message type is used by frontends to ask the kernel to execute code on | |
134 | string. The kernel is responsible for splitting this into possibly more than |
|
134 | behalf of the user, in a namespace reserved to the user's variables (and thus | |
135 | one block and deciding whether to compile these in 'single' or 'exec' mode. |
|
135 | separate from the kernel's own internal code and variables). | |
136 | We're still sorting out this policy. The current inputsplitter is capable of |
|
|||
137 | splitting the input for blocks that can all be run as 'single', but in the long |
|
|||
138 | run it may prove cleaner to only use 'single' mode for truly single-line |
|
|||
139 | inputs, and run all multiline input in 'exec' mode. This would preserve the |
|
|||
140 | natural behavior of single-line inputs while allowing long cells to behave more |
|
|||
141 | likea a script. This design will be refined as we complete the implementation. |
|
|||
142 |
|
136 | |||
143 | Message type: ``execute_request``:: |
|
137 | Message type: ``execute_request``:: | |
144 |
|
138 | |||
@@ -148,17 +142,94 b' Message type: ``execute_request``::' | |||||
148 |
|
142 | |||
149 | # A boolean flag which, if True, signals the kernel to execute this |
|
143 | # A boolean flag which, if True, signals the kernel to execute this | |
150 | # code as quietly as possible. This means that the kernel will compile |
|
144 | # code as quietly as possible. This means that the kernel will compile | |
151 |
# the code with 'exec' instead of 'single' (so |
|
145 | # the code witIPython/core/tests/h 'exec' instead of 'single' (so | |
152 | # fire), and will *not*: |
|
146 | # sys.displayhook will not fire), and will *not*: | |
153 | # - broadcast exceptions on the PUB socket |
|
147 | # - broadcast exceptions on the PUB socket | |
154 | # - do any logging |
|
148 | # - do any logging | |
155 | # - populate any history |
|
149 | # - populate any history | |
|
150 | # | |||
156 | # The default is False. |
|
151 | # The default is False. | |
157 | 'silent' : bool, |
|
152 | 'silent' : bool, | |
|
153 | ||||
|
154 | # A list of variable names from the user's namespace to be retrieved. What | |||
|
155 | # returns is a JSON string of the variable's repr(), not a python object. | |||
|
156 | 'user_variables' : list, | |||
|
157 | ||||
|
158 | # Similarly, a dict mapping names to expressions to be evaluated in the | |||
|
159 | # user's dict. | |||
|
160 | 'user_expressions' : dict, | |||
158 | } |
|
161 | } | |
159 |
|
162 | |||
160 | Upon execution, the kernel *always* sends a reply, with a status code |
|
163 | The ``code`` field contains a single string, but this may be a multiline | |
161 | indicating what happened and additional data depending on the outcome. |
|
164 | string. The kernel is responsible for splitting this into possibly more than | |
|
165 | one block and deciding whether to compile these in 'single' or 'exec' mode. | |||
|
166 | We're still sorting out this policy. The current inputsplitter is capable of | |||
|
167 | splitting the input for blocks that can all be run as 'single', but in the long | |||
|
168 | run it may prove cleaner to only use 'single' mode for truly single-line | |||
|
169 | inputs, and run all multiline input in 'exec' mode. This would preserve the | |||
|
170 | natural behavior of single-line inputs while allowing long cells to behave more | |||
|
171 | likea a script. This design will be refined as we complete the implementation. | |||
|
172 | ||||
|
173 | The ``user_`` fields deserve a detailed explanation. In the past, IPython had | |||
|
174 | the notion of a prompt string that allowed arbitrary code to be evaluated, and | |||
|
175 | this was put to good use by many in creating prompts that displayed system | |||
|
176 | status, path information, and even more esoteric uses like remote instrument | |||
|
177 | status aqcuired over the network. But now that IPython has a clean separation | |||
|
178 | between the kernel and the clients, the notion of embedding 'prompt' | |||
|
179 | maninpulations into the kernel itself feels awkward. Prompts should be a | |||
|
180 | frontend-side feature, and it should be even possible for different frontends | |||
|
181 | to display different prompts while interacting with the same kernel. | |||
|
182 | ||||
|
183 | We have therefore abandoned the idea of a 'prompt string' to be evaluated by | |||
|
184 | the kernel, and instead provide the ability to retrieve from the user's | |||
|
185 | namespace information after the execution of the main ``code``, with two fields | |||
|
186 | of the execution request: | |||
|
187 | ||||
|
188 | - ``user_variables``: If only variables from the user's namespace are needed, a | |||
|
189 | list of variable names can be passed and a dict with these names as keys and | |||
|
190 | their :func:`repr()` as values will be returned. | |||
|
191 | ||||
|
192 | - ``user_expressions``: For more complex expressions that require function | |||
|
193 | evaluations, a dict can be provided with string keys and arbitrary python | |||
|
194 | expressions as values. The return message will contain also a dict with the | |||
|
195 | same keys and the :func:`repr()` of the evaluated expressions as value. | |||
|
196 | ||||
|
197 | With this information, frontends can display any status information they wish | |||
|
198 | in the form that best suits each frontend (a status line, a popup, inline for a | |||
|
199 | terminal, etc). | |||
|
200 | ||||
|
201 | .. Note:: | |||
|
202 | ||||
|
203 | In order to obtain the current execution counter for the purposes of | |||
|
204 | displaying input prompts, frontends simply make an execution request with an | |||
|
205 | empty code string and ``silent=True``. | |||
|
206 | ||||
|
207 | Execution semantics | |||
|
208 | Upon completion of the execution request, the kernel *always* sends a | |||
|
209 | reply, with a status code indicating what happened and additional data | |||
|
210 | depending on the outcome. | |||
|
211 | ||||
|
212 | The ``code`` field is executed first, and then the ``user_variables`` and | |||
|
213 | ``user_expressions`` are computed. This ensures that any error in the | |||
|
214 | latter don't harm the main code execution. | |||
|
215 | ||||
|
216 | Any error in retrieving the ``user_variables`` or evaluating the | |||
|
217 | ``user_expressions`` will result in a simple error message in the return | |||
|
218 | fields of the form:: | |||
|
219 | ||||
|
220 | [ERROR] ExceptionType: Exception message | |||
|
221 | ||||
|
222 | The user can simply send the same variable name or expression for | |||
|
223 | evaluation to see a regular traceback. | |||
|
224 | ||||
|
225 | Execution counter (old prompt number) | |||
|
226 | The kernel has a single, monotonically increasing counter of all execution | |||
|
227 | requests that are made with ``silent=False``. This counter is used to | |||
|
228 | populate the ``In[n]``, ``Out[n]`` and ``_n`` variables, so clients will | |||
|
229 | likely want to display it in some form to the user, which will typically | |||
|
230 | (but not necessarily) be done in the prompts. The value of this counter | |||
|
231 | will be returned as the ``execution_count`` field of all ``execute_reply``` | |||
|
232 | messages. | |||
162 |
|
233 | |||
163 | Message type: ``execute_reply``:: |
|
234 | Message type: ``execute_reply``:: | |
164 |
|
235 | |||
@@ -166,30 +237,25 b' Message type: ``execute_reply``::' | |||||
166 | # One of: 'ok' OR 'error' OR 'abort' |
|
237 | # One of: 'ok' OR 'error' OR 'abort' | |
167 | 'status' : str, |
|
238 | 'status' : str, | |
168 |
|
239 | |||
169 | # This has the same structure as the output of a prompt request, but is |
|
240 | # The global kernel counter that increases by one with each non-silent | |
170 | # for the client to set up the *next* prompt (with identical limitations |
|
241 | # executed request. This will typically be used by clients to display | |
171 | # to a prompt request) |
|
242 | # prompt numbers to the user. If the request was a silent one, this will | |
172 | 'next_prompt' : { |
|
243 | # be the current value of the counter in the kernel. | |
173 | 'prompt_string' : str, |
|
244 | 'execution_count' : int, | |
174 | 'prompt_number' : int, |
|
245 | ||
175 | 'input_sep' : str |
|
246 | # If the state_template was provided, this will contain the evaluated | |
176 | }, |
|
247 | # form of the template. | |
177 |
|
248 | 'state' : str, | ||
178 | # The prompt number of the actual execution for this code, which may be |
|
|||
179 | # different from the one used when the code was typed, which was the |
|
|||
180 | # 'next_prompt' field of the *previous* request. They will differ in the |
|
|||
181 | # case where there is more than one client talking simultaneously to a |
|
|||
182 | # kernel, since the numbers can go out of sync. GUI clients can use this |
|
|||
183 | # to correct the previously written number in-place, terminal ones may |
|
|||
184 | # re-print a corrected one if desired. |
|
|||
185 | 'prompt_number' : int, |
|
|||
186 | } |
|
249 | } | |
187 |
|
250 | |||
188 | When status is 'ok', the following extra fields are present:: |
|
251 | When status is 'ok', the following extra fields are present:: | |
189 |
|
252 | |||
190 | { |
|
253 | { | |
191 |
# The kernel will often transform the input provided to it. |
|
254 | # The kernel will often transform the input provided to it. If the | |
192 | # contains the transformed code, which is what was actually executed. |
|
255 | # '---->' transform had been applied, this is filled, otherwise it's the | |
|
256 | # empty string. So transformations like magics don't appear here, only | |||
|
257 | # autocall ones. | |||
|
258 | ||||
193 | 'transformed_code' : str, |
|
259 | 'transformed_code' : str, | |
194 |
|
260 | |||
195 | # The execution payload is a dict with string keys that may have been |
|
261 | # The execution payload is a dict with string keys that may have been | |
@@ -235,31 +301,65 b" When status is 'error', the following extra fields are present::" | |||||
235 | When status is 'abort', there are for now no additional data fields. This |
|
301 | When status is 'abort', there are for now no additional data fields. This | |
236 | happens when the kernel was interrupted by a signal. |
|
302 | happens when the kernel was interrupted by a signal. | |
237 |
|
303 | |||
|
304 | Kernel attribute access | |||
|
305 | ----------------------- | |||
238 |
|
306 | |||
239 | Prompt |
|
307 | While this protocol does not specify full RPC access to arbitrary methods of | |
240 | ------ |
|
308 | the kernel object, the kernel does allow read (and in some cases write) access | |
|
309 | to certain attributes. | |||
241 |
|
310 | |||
242 | A simple request for a current prompt string. |
|
311 | The policy for which attributes can be read is: any attribute of the kernel, or | |
|
312 | its sub-objects, that belongs to a :class:`Configurable` object and has been | |||
|
313 | declared at the class-level with Traits validation, is in principle accessible | |||
|
314 | as long as its name does not begin with a leading underscore. The attribute | |||
|
315 | itself will have metadata indicating whether it allows remote read and/or write | |||
|
316 | access. The message spec follows for attribute read and write requests. | |||
243 |
|
317 | |||
244 |
Message type: `` |
|
318 | Message type: ``getattr_request``:: | |
245 |
|
319 | |||
246 |
content = { |
|
320 | content = { | |
|
321 | # The (possibly dotted) name of the attribute | |||
|
322 | 'name' : str, | |||
|
323 | } | |||
|
324 | ||||
|
325 | When a ``getattr_request`` fails, there are two possible error types: | |||
|
326 | ||||
|
327 | - AttributeError: this type of error was raised when trying to access the | |||
|
328 | given name by the kernel itself. This means that the attribute likely | |||
|
329 | doesn't exist. | |||
|
330 | ||||
|
331 | - AccessError: the attribute exists but its value is not readable remotely. | |||
247 |
|
332 | |||
248 | In the reply, the prompt string comes back with the prompt number placeholder |
|
333 | ||
249 | *unevaluated*. The message format is: |
|
334 | Message type: ``getattr_reply``:: | |
250 |
|
335 | |||
251 | Message type: ``prompt_reply``:: |
|
336 | content = { | |
|
337 | # One of ['ok', 'AttributeError', 'AccessError']. | |||
|
338 | 'status' : str, | |||
|
339 | # If status is 'ok', a JSON object. | |||
|
340 | 'value' : object, | |||
|
341 | } | |||
|
342 | ||||
|
343 | Message type: ``setattr_request``:: | |||
252 |
|
344 | |||
253 | content = { |
|
345 | content = { | |
254 | 'prompt_string' : str, |
|
346 | # The (possibly dotted) name of the attribute | |
255 | 'prompt_number' : int, |
|
347 | 'name' : str, | |
256 | 'input_sep' : str |
|
348 | ||
|
349 | # A JSON-encoded object, that will be validated by the Traits | |||
|
350 | # information in the kernel | |||
|
351 | 'value' : object, | |||
257 | } |
|
352 | } | |
258 |
|
353 | |||
259 | Clients can produce a prompt with ``prompt_string.format(prompt_number)``, but |
|
354 | When a ``setattr_request`` fails, there are also two possible error types with | |
260 | they should be aware that the actual prompt number for that input could change |
|
355 | similar meanings as those of the ``getattr_request`` case, but for writing. | |
261 | later, in the case where multiple clients are interacting with a single |
|
356 | ||
262 | kernel. |
|
357 | Message type: ``setattr_reply``:: | |
|
358 | ||||
|
359 | content = { | |||
|
360 | # One of ['ok', 'AttributeError', 'AccessError']. | |||
|
361 | 'status' : str, | |||
|
362 | } | |||
263 |
|
363 | |||
264 |
|
364 | |||
265 | Object information |
|
365 | Object information | |
@@ -276,12 +376,12 b' Message type: ``object_info_request``::' | |||||
276 |
|
376 | |||
277 | content = { |
|
377 | content = { | |
278 | # The (possibly dotted) name of the object to be searched in all |
|
378 | # The (possibly dotted) name of the object to be searched in all | |
279 |
|
|
379 | # relevant namespaces | |
280 | 'name' : str, |
|
380 | 'name' : str, | |
281 |
|
381 | |||
282 | # The level of detail desired. The default (0) is equivalent to typing |
|
382 | # The level of detail desired. The default (0) is equivalent to typing | |
283 |
|
|
383 | # 'x?' at the prompt, 1 is equivalent to 'x??'. | |
284 |
|
|
384 | 'detail_level' : int, | |
285 | } |
|
385 | } | |
286 |
|
386 | |||
287 | The returned information will be a dictionary with keys very similar to the |
|
387 | The returned information will be a dictionary with keys very similar to the | |
@@ -315,9 +415,29 b' Message type: ``object_info_reply``::' | |||||
315 | 'file' : str, |
|
415 | 'file' : str, | |
316 |
|
416 | |||
317 | # For pure Python callable objects, we can reconstruct the object |
|
417 | # For pure Python callable objects, we can reconstruct the object | |
318 | # definition line which provides its call signature |
|
418 | # definition line which provides its call signature. For convenience this | |
|
419 | # is returned as a single 'definition' field, but below the raw parts that | |||
|
420 | # compose it are also returned as the argspec field. | |||
319 | 'definition' : str, |
|
421 | 'definition' : str, | |
320 |
|
422 | |||
|
423 | # The individual parts that together form the definition string. Clients | |||
|
424 | # with rich display capabilities may use this to provide a richer and more | |||
|
425 | # precise representation of the definition line (e.g. by highlighting | |||
|
426 | # arguments based on the user's cursor position). For non-callable | |||
|
427 | # objects, this field is empty. | |||
|
428 | 'argspec' : { # The names of all the arguments | |||
|
429 | args : list, | |||
|
430 | # The name of the varargs (*args), if any | |||
|
431 | varargs : str, | |||
|
432 | # The name of the varkw (**kw), if any | |||
|
433 | varkw : str, | |||
|
434 | # The values (as strings) of all default arguments. Note | |||
|
435 | # that these must be matched *in reverse* with the 'args' | |||
|
436 | # list above, since the first positional args have no default | |||
|
437 | # value at all. | |||
|
438 | func_defaults : list, | |||
|
439 | }, | |||
|
440 | ||||
321 | # For instances, provide the constructor signature (the definition of |
|
441 | # For instances, provide the constructor signature (the definition of | |
322 | # the __init__ method): |
|
442 | # the __init__ method): | |
323 | 'init_definition' : str, |
|
443 | 'init_definition' : str, | |
@@ -406,6 +526,7 b' Message type: ``history_reply``::' | |||||
406 | # respectively. |
|
526 | # respectively. | |
407 | 'history' : dict, |
|
527 | 'history' : dict, | |
408 | } |
|
528 | } | |
|
529 | ||||
409 | Messages on the PUB/SUB socket |
|
530 | Messages on the PUB/SUB socket | |
410 | ============================== |
|
531 | ============================== | |
411 |
|
532 | |||
@@ -458,10 +579,10 b' Message type: ``pyout``::' | |||||
458 | # The data is typically the repr() of the object. |
|
579 | # The data is typically the repr() of the object. | |
459 | 'data' : str, |
|
580 | 'data' : str, | |
460 |
|
581 | |||
461 |
# The |
|
582 | # The counter for this execution is also provided so that clients can | |
462 |
# |
|
583 | # display it, since IPython automatically creates variables called _N (for | |
463 |
# |
|
584 | # prompt N). | |
464 | 'prompt_number' : int, |
|
585 | 'execution_count' : int, | |
465 | } |
|
586 | } | |
466 |
|
587 | |||
467 | Python errors |
|
588 | Python errors |
General Comments 0
You need to be logged in to leave comments.
Login now