Show More
@@ -0,0 +1,286 b'' | |||||
|
1 | ======================================== | |||
|
2 | Design proposal for mod:`IPython.core` | |||
|
3 | ======================================== | |||
|
4 | ||||
|
5 | Currently mod:`IPython.core` is not well suited for use in GUI applications. | |||
|
6 | The purpose of this document is to describe a design that will resolve this | |||
|
7 | limitation. | |||
|
8 | ||||
|
9 | Process and thread model | |||
|
10 | ======================== | |||
|
11 | ||||
|
12 | The design described here is based on a two process model. These two processes | |||
|
13 | are: | |||
|
14 | ||||
|
15 | 1. The IPython engine/kernel. This process contains the user's namespace and | |||
|
16 | is responsible for executing user code. If user code uses | |||
|
17 | :mod:`enthought.traits` or uses a GUI toolkit to perform plotting, the GUI | |||
|
18 | event loop will run in this process. | |||
|
19 | ||||
|
20 | 2. The GUI application. The user facing GUI application will run in a second | |||
|
21 | process that communicates directly with the IPython engine using | |||
|
22 | asynchronous messaging. The GUI application will not execute any user code. | |||
|
23 | The canonical example of a GUI application that talks to the IPython | |||
|
24 | engine, would be a GUI based IPython terminal. However, the GUI application | |||
|
25 | could provide a more sophisticated interface such as a notebook. | |||
|
26 | ||||
|
27 | We now describe the threading model of the IPython engine. Two threads will be | |||
|
28 | used to implement the IPython engine: a main thread that executes user code | |||
|
29 | and a networking thread that communicates with the outside world. This | |||
|
30 | specific design is required by a number of different factors. | |||
|
31 | ||||
|
32 | First, The IPython engine must run the GUI event loop if the user wants to | |||
|
33 | perform interactive plotting. Because of the design of most GUIs, this means | |||
|
34 | that the user code (which will make GUI calls) must live in the main thread. | |||
|
35 | ||||
|
36 | Second, networking code in the engine (Twisted or otherwise) must be able to | |||
|
37 | communicate with the outside world while user code runs. An example would be | |||
|
38 | if user code does the following:: | |||
|
39 | ||||
|
40 | import time | |||
|
41 | for i in range(10): | |||
|
42 | print i | |||
|
43 | time.sleep(2) | |||
|
44 | ||||
|
45 | We would like to result of each ``print i`` to be seen by the GUI application | |||
|
46 | before the entire code block completes. We call this asynchronous printing. | |||
|
47 | For this to be possible, the networking code has to be able to be able to | |||
|
48 | communicate the current value of ``sys.stdout`` to the GUI application while | |||
|
49 | user code is run. Another example is using :mod:`IPython.kernel.client` in | |||
|
50 | user code to perform a parallel computation by talking to an IPython | |||
|
51 | controller and a set of engines (these engines are separate from the one we | |||
|
52 | are discussing here). This module requires the Twisted event loop to be run in | |||
|
53 | a different thread than user code. | |||
|
54 | ||||
|
55 | For the GUI application, threads are optional. However, the GUI application | |||
|
56 | does need to be able to perform network communications asynchronously (without | |||
|
57 | blocking the GUI itself). With this in mind, there are two options: | |||
|
58 | ||||
|
59 | * Use Twisted (or another non-blocking socket library) in the same thread as | |||
|
60 | the GUI event loop. | |||
|
61 | ||||
|
62 | * Don't use Twisted, but instead run networking code in the GUI application | |||
|
63 | using blocking sockets in threads. This would require the usage of polling | |||
|
64 | and queues to manage the networking in the GUI application. | |||
|
65 | ||||
|
66 | Thus, for the GUI application, there is a choice between non-blocking sockets | |||
|
67 | (Twisted) or threads. | |||
|
68 | ||||
|
69 | Asynchronous messaging | |||
|
70 | ====================== | |||
|
71 | ||||
|
72 | The GUI application will use asynchronous message queues to communicate with | |||
|
73 | the networking thread of the engine. Because this communication will typically | |||
|
74 | happen over localhost, a simple, one way, network protocol like XML-RPC or | |||
|
75 | JSON-RPC can be used to implement this messaging. These options will also make | |||
|
76 | it easy to implement the required networking in the GUI application using the | |||
|
77 | standard library. In applications where secure communications are required, | |||
|
78 | Twisted and Foolscap will probably be the best way to go for now, but HTTP is | |||
|
79 | also an option. | |||
|
80 | ||||
|
81 | There is some flexibility as to where the message queues are located. One | |||
|
82 | option is that we could create a third process (like the IPython controller) | |||
|
83 | that only manages the message queues. This is attractive, but does require | |||
|
84 | an additional process. | |||
|
85 | ||||
|
86 | Using this communication channel, the GUI application and kernel/engine will | |||
|
87 | be able to send messages back and forth. For the most part, these messages | |||
|
88 | will have a request/reply form, but it will be possible for the kernel/engine | |||
|
89 | to send multiple replies for a single request. | |||
|
90 | ||||
|
91 | The GUI application will use these messages to control the engine/kernel. | |||
|
92 | Examples of the types of things that will be possible are: | |||
|
93 | ||||
|
94 | * Pass code (as a string) to be executed by the engine in the user's namespace | |||
|
95 | as a string. | |||
|
96 | ||||
|
97 | * Get the current value of stdout and stderr. | |||
|
98 | ||||
|
99 | * Get the ``repr`` of an object returned (Out []:). | |||
|
100 | ||||
|
101 | * Pass a string to the engine to be completed when the GUI application | |||
|
102 | receives a tab completion event. | |||
|
103 | ||||
|
104 | * Get a list of all variable names in the user's namespace. | |||
|
105 | ||||
|
106 | The in memory format of a message should be a Python dictionary, as this | |||
|
107 | will be easy to serialize using virtually any network protocol. The | |||
|
108 | message dict should only contain basic types, such as strings, floats, | |||
|
109 | ints, lists, tuples and other dicts. | |||
|
110 | ||||
|
111 | Each message will have a unique id and will probably be determined by the | |||
|
112 | messaging system and returned when something is queued in the message | |||
|
113 | system. This unique id will be used to pair replies with requests. | |||
|
114 | ||||
|
115 | Each message should have a header of key value pairs that can be introspected | |||
|
116 | by the message system and a body, or payload, that is opaque. The queues | |||
|
117 | themselves will be purpose agnostic, so the purpose of the message will have | |||
|
118 | to be encoded in the message itself. While we are getting started, we | |||
|
119 | probably don't need to distinguish between the header and body. | |||
|
120 | ||||
|
121 | Here are some examples:: | |||
|
122 | ||||
|
123 | m1 = dict( | |||
|
124 | method='execute', | |||
|
125 | id=24, # added by the message system | |||
|
126 | parent=None # not a reply, | |||
|
127 | source_code='a=my_func()' | |||
|
128 | ) | |||
|
129 | ||||
|
130 | This single message could generate a number of reply messages:: | |||
|
131 | ||||
|
132 | m2 = dict( | |||
|
133 | method='stdout' | |||
|
134 | id=25, # my id, added by the message system | |||
|
135 | parent_id=24, # The message id of the request | |||
|
136 | value='This was printed by my_func()' | |||
|
137 | ) | |||
|
138 | ||||
|
139 | m3 = dict( | |||
|
140 | method='stdout' | |||
|
141 | id=26, # my id, added by the message system | |||
|
142 | parent_id=24, # The message id of the request | |||
|
143 | value='This too was printed by my_func() at a later time.' | |||
|
144 | ) | |||
|
145 | ||||
|
146 | m4 = dict( | |||
|
147 | method='execute_finished', | |||
|
148 | id=27, | |||
|
149 | parent_id=24 | |||
|
150 | # not sure what else should come back with this message, | |||
|
151 | # but we will need a way for the GUI app to tell that an execute | |||
|
152 | # is done. | |||
|
153 | ) | |||
|
154 | ||||
|
155 | We should probably use flags for the method and other purposes: | |||
|
156 | ||||
|
157 | EXECUTE='0' | |||
|
158 | EXECUTE_REPLY='1' | |||
|
159 | ||||
|
160 | This will keep out network traffic down and enable us to easily change the | |||
|
161 | actual value that is sent. | |||
|
162 | ||||
|
163 | Engine details | |||
|
164 | ============== | |||
|
165 | ||||
|
166 | As discussed above, the engine will consist of two threads: a main thread and | |||
|
167 | a networking thread. These two threads will communicate using a pair of | |||
|
168 | queues: one for data and requests passing to the main thread (the main | |||
|
169 | thread's "input queue") and another for data and requests passing out of the | |||
|
170 | main thread (the main thread's "output queue"). Both threads will have an | |||
|
171 | event loop that will enqueue elements on one queue and dequeue elements on the | |||
|
172 | other queue. | |||
|
173 | ||||
|
174 | The event loop of the main thread will be of a different nature depending on | |||
|
175 | if the user wants to perform interactive plotting. If they do want to perform | |||
|
176 | interactive plotting, the main threads event loop will simply be the GUI event | |||
|
177 | loop. In that case, GUI timers will be used to monitor the main threads input | |||
|
178 | queue. When elements appear on that queue, the main thread will respond | |||
|
179 | appropriately. For example, if the queue contains an element that consists of | |||
|
180 | user code to execute, the main thread will call the appropriate method of its | |||
|
181 | IPython instance. If the user does not want to perform interactive plotting, | |||
|
182 | the main thread will have a simpler event loop that will simply block on the | |||
|
183 | input queue. When something appears on that queue, the main thread will awake | |||
|
184 | and handle the request. | |||
|
185 | ||||
|
186 | The event loop of the networking thread will typically be the Twisted event | |||
|
187 | loop. While it is possible to implement the engine's networking without using | |||
|
188 | Twisted, at this point, Twisted provides the best solution. Note that the GUI | |||
|
189 | application does not need to use Twisted in this case. The Twisted event loop | |||
|
190 | will contain an XML-RPC or JSON-RPC server that takes requests over the | |||
|
191 | network and handles those requests by enqueing elements on the main thread's | |||
|
192 | input queue or dequeing elements on the main thread's output queue. | |||
|
193 | ||||
|
194 | Because of the asynchronous nature of the network communication, a single | |||
|
195 | input and output queue will be used to handle the interaction with the main | |||
|
196 | thread. It is also possible to use multiple queues to isolate the different | |||
|
197 | types of requests, but our feeling is that this is more complicated than it | |||
|
198 | needs to be. | |||
|
199 | ||||
|
200 | One of the main issues is how stdout/stderr will be handled. Our idea is to | |||
|
201 | replace sys.stdout/sys.stderr by custom classes that will immediately write | |||
|
202 | data to the main thread's output queue when user code writes to these streams | |||
|
203 | (by doing print). Once on the main thread's output queue, the networking | |||
|
204 | thread will make the data available to the GUI application over the network. | |||
|
205 | ||||
|
206 | One unavoidable limitation in this design is that if user code does a print | |||
|
207 | and then enters non-GIL-releasing extension code, the networking thread will | |||
|
208 | go silent until the GIL is again released. During this time, the networking | |||
|
209 | thread will not be able to process the GUI application's requests of the | |||
|
210 | engine. Thus, the values of stdout/stderr will be unavailable during this | |||
|
211 | time. This goes beyond stdout/stderr, however. Anytime the main thread is | |||
|
212 | holding the GIL, the networking thread will go silent and be unable to handle | |||
|
213 | requests. | |||
|
214 | ||||
|
215 | GUI Application details | |||
|
216 | ======================= | |||
|
217 | ||||
|
218 | The GUI application will also have two threads. While this is not a strict | |||
|
219 | requirement, it probably makes sense and is a good place to start. The main | |||
|
220 | thread will be the GUI tread. The other thread will be a networking thread and | |||
|
221 | will handle the messages that are sent to and from the engine process. | |||
|
222 | ||||
|
223 | Like the engine, we will use two queues to control the flow of messages | |||
|
224 | between the main thread and networking thread. One of these queues will be | |||
|
225 | used for messages sent from the GUI application to the engine. When the GUI | |||
|
226 | application needs to send a message to the engine, it will simply enque the | |||
|
227 | appropriate message on this queue. The networking thread will watch this queue | |||
|
228 | and forward messages to the engine using an appropriate network protocol. | |||
|
229 | ||||
|
230 | The other queue will be used for incoming messages from the engine. The | |||
|
231 | networking thread will poll for incoming messages from the engine. When it | |||
|
232 | receives any message, it will simply put that message on this other queue. The | |||
|
233 | GUI application will periodically see if there are any messages on this queue | |||
|
234 | and if there are it will handle them. | |||
|
235 | ||||
|
236 | The GUI application must be prepared to handle any incoming message at any | |||
|
237 | time. Due to a variety of reasons, the one or more reply messages associated | |||
|
238 | with a request, may appear at any time in the future and possible in different | |||
|
239 | orders. It is also possible that a reply might not appear. An example of this | |||
|
240 | would be a request for a tab completion event. If the engine is busy, it won't | |||
|
241 | be possible to fulfill the request for a while. While the tab completion | |||
|
242 | request will eventually be handled, the GUI application has to be prepared to | |||
|
243 | abandon waiting for the reply if the user moves on or a certain timeout | |||
|
244 | expires. | |||
|
245 | ||||
|
246 | Prototype details | |||
|
247 | ================= | |||
|
248 | ||||
|
249 | With this design, it should be possible to develop a relatively complete GUI | |||
|
250 | application, while using a mock engine. This prototype should use the two | |||
|
251 | process design described above, but instead of making actual network calls, | |||
|
252 | the network thread of the GUI application should have an object that fakes the | |||
|
253 | network traffic. This mock object will consume messages off of one queue, | |||
|
254 | pause for a short while (to model network and other latencies) and then place | |||
|
255 | reply messages on the other queue. | |||
|
256 | ||||
|
257 | This simple design will allow us to determine exactly what the message types | |||
|
258 | and formats should be as well as how the GUI application should interact with | |||
|
259 | the two message queues. Note, it is not required that the mock object actually | |||
|
260 | be able to execute Python code or actually complete strings in the users | |||
|
261 | namespace. All of these things can simply be faked. This will also help us to | |||
|
262 | understand what the interface needs to look like that handles the network | |||
|
263 | traffic. This will also help us to understand the design of the engine better. | |||
|
264 | ||||
|
265 | The GUI application should be developed using IPython's component, application | |||
|
266 | and configuration system. It may take some work to see what the best way of | |||
|
267 | integrating these things with PyQt are. | |||
|
268 | ||||
|
269 | After this stage is done, we can move onto creating a real IPython engine for | |||
|
270 | the GUI application to communicate with. This will likely be more work that | |||
|
271 | the GUI application itself, but having a working GUI application will make it | |||
|
272 | *much* easier to design and implement the engine. | |||
|
273 | ||||
|
274 | We also might want to introduce a third process into the mix. Basically, this | |||
|
275 | would be a central messaging hub that both the engine and GUI application | |||
|
276 | would use to send and retrieve messages. This is not required, but it might be | |||
|
277 | a really good idea. | |||
|
278 | ||||
|
279 | Also, I have some ideas on the best way to handle notebook saving and | |||
|
280 | persistence. | |||
|
281 | ||||
|
282 | Refactoring of IPython.core | |||
|
283 | =========================== | |||
|
284 | ||||
|
285 | We need to go through IPython.core and describe what specifically needs to be | |||
|
286 | done. |
@@ -0,0 +1,55 b'' | |||||
|
1 | ========================= | |||
|
2 | IPython GUI Support Notes | |||
|
3 | ========================= | |||
|
4 | ||||
|
5 | IPython allows GUI event loops to be run in an interactive IPython session. | |||
|
6 | This is done using Python's PyOS_InputHook hook which Python calls | |||
|
7 | when the :func:`raw_input` function is called and waiting for user input. | |||
|
8 | IPython has versions of this hook for wx, pyqt4 and pygtk. | |||
|
9 | ||||
|
10 | When a GUI program is used interactively within IPython, the event loop of | |||
|
11 | the GUI should *not* be started. This is because, the PyOS_Inputhook itself | |||
|
12 | is responsible for iterating the GUI event loop. | |||
|
13 | ||||
|
14 | IPython has facilities for installing the needed input hook for each GUI | |||
|
15 | toolkit and for creating the needed main GUI application object. Usually, | |||
|
16 | these main application objects should be created only once and for some | |||
|
17 | GUI toolkits, special options have to be passed to the application object | |||
|
18 | to enable it to function properly in IPython. | |||
|
19 | ||||
|
20 | We need to answer the following questions: | |||
|
21 | ||||
|
22 | * Who is responsible for creating the main GUI application object, IPython | |||
|
23 | or third parties (matplotlib, enthought.traits, etc.)? | |||
|
24 | ||||
|
25 | * What is the proper way for third party code to detect if a GUI application | |||
|
26 | object has already been created? If one has been created, how should | |||
|
27 | the existing instance be retrieved? | |||
|
28 | ||||
|
29 | * In a GUI application object has been created, how should third party code | |||
|
30 | detect if the GUI event loop is running. It is not sufficient to call the | |||
|
31 | relevant function methods in the GUI toolkits (like ``IsMainLoopRunning``) | |||
|
32 | because those don't know if the GUI event loop is running through the | |||
|
33 | input hook. | |||
|
34 | ||||
|
35 | * We might need a way for third party code to determine if it is running | |||
|
36 | in IPython or not. Currently, the only way of running GUI code in IPython | |||
|
37 | is by using the input hook, but eventually, GUI based versions of IPython | |||
|
38 | will allow the GUI event loop in the more traditional manner. We will need | |||
|
39 | a way for third party code to distinguish between these two cases. | |||
|
40 | ||||
|
41 | Here is some sample code I have been using to debug this issue:: | |||
|
42 | ||||
|
43 | from matplotlib import pyplot as plt | |||
|
44 | ||||
|
45 | from enthought.traits import api as traits | |||
|
46 | ||||
|
47 | class Foo(traits.HasTraits): | |||
|
48 | a = traits.Float() | |||
|
49 | ||||
|
50 | f = Foo() | |||
|
51 | f.configure_traits() | |||
|
52 | ||||
|
53 | plt.plot(range(10)) | |||
|
54 | ||||
|
55 |
@@ -0,0 +1,111 b'' | |||||
|
1 | =============================== | |||
|
2 | IPython session storage notes | |||
|
3 | =============================== | |||
|
4 | ||||
|
5 | This document serves as a sample/template for ideas on how to store session | |||
|
6 | data on disk. This stems from discussions we had on various mailing lists, and | |||
|
7 | should be considered a pure work in progress. We haven't settled these ideas | |||
|
8 | completely yet, and there's a lot to discuss; this document should just serve | |||
|
9 | as a reference of the distilled points from various conversations on multiple | |||
|
10 | mailing lists, and will congeal over time on a specific design we implement. | |||
|
11 | ||||
|
12 | The frontend would store, for now, 5 types of data: | |||
|
13 | ||||
|
14 | #. Input: this is python/ipython code to be executed. | |||
|
15 | ||||
|
16 | #. Output (python): result of executing Inputs. | |||
|
17 | ||||
|
18 | #. Standard output: from subprocesses. | |||
|
19 | ||||
|
20 | #. Standard error: from subprocesses. | |||
|
21 | ||||
|
22 | #. Text: arbitrary text. For now, we'll just store plain text and will defer | |||
|
23 | to the user on how to format it, though it should be valid reST if it is | |||
|
24 | later to be converted into html/pdf. | |||
|
25 | ||||
|
26 | The non-text cells would be stored on-disk as follows:: | |||
|
27 | ||||
|
28 | .. input-cell:: | |||
|
29 | :id: 1 | |||
|
30 | ||||
|
31 | 3+3 | |||
|
32 | ||||
|
33 | .. output-cell:: | |||
|
34 | :id: 1 | |||
|
35 | ||||
|
36 | 6 | |||
|
37 | ||||
|
38 | .. input-cell:: | |||
|
39 | :id: 2 | |||
|
40 | ||||
|
41 | ls | |||
|
42 | ||||
|
43 | .. stdout-cell:: | |||
|
44 | :id: 2 | |||
|
45 | ||||
|
46 | a.py b.py | |||
|
47 | ||||
|
48 | .. input-cell:: | |||
|
49 | :id: 3 | |||
|
50 | ||||
|
51 | !askdfj | |||
|
52 | ||||
|
53 | .. stderr-cell:: | |||
|
54 | :id: 3 | |||
|
55 | ||||
|
56 | sh: askdfj: command not found | |||
|
57 | ||||
|
58 | Brian made some interesting points on the mailing list inspired by the | |||
|
59 | Mathematica format, reproduced here for reference: | |||
|
60 | ||||
|
61 | The Mathematica notebook format is a plain text file that itself is *valid | |||
|
62 | Mathematica code*. This id documented here: | |||
|
63 | ||||
|
64 | http://reference.wolfram.com/mathematica/guide/LowLevelNotebookProgramming.html | |||
|
65 | ||||
|
66 | For examples a simple notebook with one text cell is just:: | |||
|
67 | ||||
|
68 | Notebook[{Cell['Here is my text', 'Text']}] | |||
|
69 | ||||
|
70 | Everything - input cells, output cells, static images and all are represented | |||
|
71 | in this way and embedded in the plain text notebook file. The Python | |||
|
72 | generalization of this would be the following: | |||
|
73 | ||||
|
74 | * A Python notebook is plain text, importable Python code. | |||
|
75 | ||||
|
76 | * That code is simply a tree of objects that declare the relevant parts of the | |||
|
77 | notebook. | |||
|
78 | ||||
|
79 | This has a number of advantages: | |||
|
80 | ||||
|
81 | * A notebook can be imported, manipulated and run by anyone who has the support | |||
|
82 | code (the notebook module that defines the relevant classes). | |||
|
83 | ||||
|
84 | * A notebook doesn't need to be parsed. It is valid Python and can be imported | |||
|
85 | or exec'd. Once that is done, you have the full notebook in memory. You can | |||
|
86 | immediately do anything you want with it. | |||
|
87 | ||||
|
88 | * The various Notebook, Cell, Image, etc. classes can know about how to output | |||
|
89 | to various formats, latex, html, reST, XML, etc:: | |||
|
90 | ||||
|
91 | import mynotebook | |||
|
92 | mynotebook.notebook.export('rest') | |||
|
93 | ||||
|
94 | * Each individual format (HTML, reST, latex) has weaknesses. If you pick any | |||
|
95 | one to be *the* notebook format, you are building those weaknesses into your | |||
|
96 | design. A pure python based notebook format won't suffer from that syndrome. | |||
|
97 | ||||
|
98 | * It is a clean separation of the model (Notebook, Cell, Image, etc.) and the | |||
|
99 | view (HTML, reST, etc.). Picking HTML or reST for the notebook format | |||
|
100 | confuses (at some level) the model and view... | |||
|
101 | ||||
|
102 | * Third party code can define new Notebook elements that specify how they can | |||
|
103 | be rendered in different contexts. For example, matplotlib could ship a | |||
|
104 | Figure element that knows how to render itself as a native PyQt GUI, a static | |||
|
105 | image, a web page, etc. | |||
|
106 | ||||
|
107 | * A notebook remains a single plain text file that anyone can edit - even if it | |||
|
108 | has embedded images. Neither HTML nor reST have the ability to inline | |||
|
109 | graphics in plain text files. While I love reST, it is a pain that I need an | |||
|
110 | entire directory of files to render a single Sphinx doc. | |||
|
111 | No newline at end of file |
@@ -21,9 +21,9 b" name = 'ipython'" | |||||
21 | # bdist_deb does not accept underscores (a Debian convention). |
|
21 | # bdist_deb does not accept underscores (a Debian convention). | |
22 |
|
22 | |||
23 | development = True # change this to False to do a release |
|
23 | development = True # change this to False to do a release | |
24 | version_base = '0.11' |
|
24 | version_base = '0.11.alpha1' | |
25 | branch = 'ipython' |
|
25 | branch = 'ipython' | |
26 |
revision = '1 |
|
26 | revision = '1223' | |
27 |
|
27 | |||
28 | if development: |
|
28 | if development: | |
29 | if branch == 'ipython': |
|
29 | if branch == 'ipython': |
@@ -24,15 +24,25 b' The main classes in this module are:' | |||||
24 | #----------------------------------------------------------------------------- |
|
24 | #----------------------------------------------------------------------------- | |
25 |
|
25 | |||
26 | #----------------------------------------------------------------------------- |
|
26 | #----------------------------------------------------------------------------- | |
27 | # Imports |
|
27 | # Warnings control | |
28 | #----------------------------------------------------------------------------- |
|
28 | #----------------------------------------------------------------------------- | |
29 |
|
29 | |||
30 | import sys |
|
|||
31 | import warnings |
|
30 | import warnings | |
32 |
|
31 | |||
33 | # from IPython.utils import growl |
|
32 | # Twisted generates annoying warnings with Python 2.6, as will do other code | |
34 | # growl.start("IPython1 Client") |
|
33 | # that imports 'sets' as of today | |
|
34 | warnings.filterwarnings('ignore', 'the sets module is deprecated', | |||
|
35 | DeprecationWarning ) | |||
|
36 | ||||
|
37 | # This one also comes from Twisted | |||
|
38 | warnings.filterwarnings('ignore', 'the sha module is deprecated', | |||
|
39 | DeprecationWarning) | |||
|
40 | ||||
|
41 | #----------------------------------------------------------------------------- | |||
|
42 | # Imports | |||
|
43 | #----------------------------------------------------------------------------- | |||
35 |
|
44 | |||
|
45 | import sys | |||
36 |
|
46 | |||
37 | from twisted.internet import reactor |
|
47 | from twisted.internet import reactor | |
38 | from twisted.internet.error import PotentialZombieWarning |
|
48 | from twisted.internet.error import PotentialZombieWarning | |
@@ -73,8 +83,6 b' rit.setDaemon(True)' | |||||
73 | rit.start() |
|
83 | rit.start() | |
74 |
|
84 | |||
75 |
|
85 | |||
76 |
|
||||
77 |
|
||||
78 | __all__ = [ |
|
86 | __all__ = [ | |
79 | 'MapTask', |
|
87 | 'MapTask', | |
80 | 'StringTask', |
|
88 | 'StringTask', |
@@ -23,7 +23,7 b' from IPython.core.component import Component' | |||||
23 | from IPython.external import Itpl |
|
23 | from IPython.external import Itpl | |
24 | from IPython.utils.traitlets import Str, Int, List, Unicode |
|
24 | from IPython.utils.traitlets import Str, Int, List, Unicode | |
25 | from IPython.utils.path import get_ipython_module_path |
|
25 | from IPython.utils.path import get_ipython_module_path | |
26 | from IPython.utils.process import find_cmd, pycmd2argv |
|
26 | from IPython.utils.process import find_cmd, pycmd2argv, FindCmdError | |
27 | from IPython.kernel.twistedutil import ( |
|
27 | from IPython.kernel.twistedutil import ( | |
28 | gatherBoth, |
|
28 | gatherBoth, | |
29 | make_deferred, |
|
29 | make_deferred, | |
@@ -538,7 +538,10 b' class SSHEngineSetLauncher(BaseLauncher):' | |||||
538 | # This is only used on Windows. |
|
538 | # This is only used on Windows. | |
539 | def find_job_cmd(): |
|
539 | def find_job_cmd(): | |
540 | if os.name=='nt': |
|
540 | if os.name=='nt': | |
541 | return find_cmd('job') |
|
541 | try: | |
|
542 | return find_cmd('job') | |||
|
543 | except FindCmdError: | |||
|
544 | return 'job' | |||
542 | else: |
|
545 | else: | |
543 | return 'job' |
|
546 | return 'job' | |
544 |
|
547 |
@@ -57,3 +57,5 b' methods in :class:`InteractiveShell` that manage code execution::' | |||||
57 | nx.draw_spectral(g, node_size=100, alpha=0.6, node_color='r', |
|
57 | nx.draw_spectral(g, node_size=100, alpha=0.6, node_color='r', | |
58 | font_size=10, node_shape='o') |
|
58 | font_size=10, node_shape='o') | |
59 | plt.show() |
|
59 | plt.show() | |
|
60 | ||||
|
61 |
General Comments 0
You need to be logged in to leave comments.
Login now