##// END OF EJS Templates
shellglobals.py => core/shellglobals.py and imports updated.
Brian Granger -
Show More
1 NO CONTENT: file renamed from IPython/shellglobals.py to IPython/core/shellglobals.py
NO CONTENT: file renamed from IPython/shellglobals.py to IPython/core/shellglobals.py
@@ -1,62 +1,65 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3
3
4 def test_import_completer():
4 def test_import_completer():
5 from IPython.core import completer
5 from IPython.core import completer
6
6
7 def test_import_crashhandler():
7 def test_import_crashhandler():
8 from IPython.core import crashhandler
8 from IPython.core import crashhandler
9
9
10 def test_import_debugger():
10 def test_import_debugger():
11 from IPython.core import debugger
11 from IPython.core import debugger
12
12
13 def test_import_fakemodule():
13 def test_import_fakemodule():
14 from IPython.core import fakemodule
14 from IPython.core import fakemodule
15
15
16 def test_import_excolors():
16 def test_import_excolors():
17 from IPython.core import excolors
17 from IPython.core import excolors
18
18
19 def test_import_history():
19 def test_import_history():
20 from IPython.core import history
20 from IPython.core import history
21
21
22 def test_import_hooks():
22 def test_import_hooks():
23 from IPython.core import hooks
23 from IPython.core import hooks
24
24
25 def test_import_ipapi():
25 def test_import_ipapi():
26 from IPython.core import ipapi
26 from IPython.core import ipapi
27
27
28 def test_import_iplib():
28 def test_import_iplib():
29 from IPython.core import iplib
29 from IPython.core import iplib
30
30
31 def test_import_ipmaker():
31 def test_import_ipmaker():
32 from IPython.core import ipmaker
32 from IPython.core import ipmaker
33
33
34 def test_import_logger():
34 def test_import_logger():
35 from IPython.core import logger
35 from IPython.core import logger
36
36
37 def test_import_macro():
37 def test_import_macro():
38 from IPython.core import macro
38 from IPython.core import macro
39
39
40 def test_import_magic():
40 def test_import_magic():
41 from IPython.core import magic
41 from IPython.core import magic
42
42
43 def test_import_oinspect():
43 def test_import_oinspect():
44 from IPython.core import oinspect
44 from IPython.core import oinspect
45
45
46 def test_import_outputtrap():
46 def test_import_outputtrap():
47 from IPython.core import outputtrap
47 from IPython.core import outputtrap
48
48
49 def test_import_prefilter():
49 def test_import_prefilter():
50 from IPython.core import prefilter
50 from IPython.core import prefilter
51
51
52 def test_import_prompts():
52 def test_import_prompts():
53 from IPython.core import prompts
53 from IPython.core import prompts
54
54
55 def test_import_release():
55 def test_import_release():
56 from IPython.core import release
56 from IPython.core import release
57
57
58 def test_import_shadowns():
58 def test_import_shadowns():
59 from IPython.core import shadowns
59 from IPython.core import shadowns
60
60
61 def test_import_shell():
61 def test_import_shell():
62 from IPython.core import shell
62 from IPython.core import shell
63
64 def test_import_shellglobals():
65 from IPython.core import shellglobals
@@ -1,282 +1,282 b''
1 """Twisted shell support.
1 """Twisted shell support.
2
2
3 XXX - This module is missing proper docs.
3 XXX - This module is missing proper docs.
4 """
4 """
5 import sys
5 import sys
6
6
7 from twisted.internet import reactor, threads
7 from twisted.internet import reactor, threads
8
8
9 from IPython.core.ipmaker import make_IPython
9 from IPython.core.ipmaker import make_IPython
10 from IPython.core.iplib import InteractiveShell
10 from IPython.core.iplib import InteractiveShell
11 from IPython.utils.ipstruct import Struct
11 from IPython.utils.ipstruct import Struct
12 import Queue,thread,threading,signal
12 import Queue,thread,threading,signal
13 from signal import signal, SIGINT
13 from signal import signal, SIGINT
14 from IPython.utils.genutils import Term,warn,error,flag_calls, ask_yes_no
14 from IPython.utils.genutils import Term,warn,error,flag_calls, ask_yes_no
15 import shellglobals
15 from IPython.core import shellglobals
16
16
17 def install_gtk2():
17 def install_gtk2():
18 """ Install gtk2 reactor, needs to be called bef """
18 """ Install gtk2 reactor, needs to be called bef """
19 from twisted.internet import gtk2reactor
19 from twisted.internet import gtk2reactor
20 gtk2reactor.install()
20 gtk2reactor.install()
21
21
22
22
23 def hijack_reactor():
23 def hijack_reactor():
24 """Modifies Twisted's reactor with a dummy so user code does
24 """Modifies Twisted's reactor with a dummy so user code does
25 not block IPython. This function returns the original
25 not block IPython. This function returns the original
26 'twisted.internet.reactor' that has been hijacked.
26 'twisted.internet.reactor' that has been hijacked.
27
27
28 NOTE: Make sure you call this *AFTER* you've installed
28 NOTE: Make sure you call this *AFTER* you've installed
29 the reactor of your choice.
29 the reactor of your choice.
30 """
30 """
31 from twisted import internet
31 from twisted import internet
32 orig_reactor = internet.reactor
32 orig_reactor = internet.reactor
33
33
34 class DummyReactor(object):
34 class DummyReactor(object):
35 def run(self):
35 def run(self):
36 pass
36 pass
37 def __getattr__(self, name):
37 def __getattr__(self, name):
38 return getattr(orig_reactor, name)
38 return getattr(orig_reactor, name)
39 def __setattr__(self, name, value):
39 def __setattr__(self, name, value):
40 return setattr(orig_reactor, name, value)
40 return setattr(orig_reactor, name, value)
41
41
42 internet.reactor = DummyReactor()
42 internet.reactor = DummyReactor()
43 return orig_reactor
43 return orig_reactor
44
44
45 class TwistedInteractiveShell(InteractiveShell):
45 class TwistedInteractiveShell(InteractiveShell):
46 """Simple multi-threaded shell."""
46 """Simple multi-threaded shell."""
47
47
48 # Threading strategy taken from:
48 # Threading strategy taken from:
49 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
49 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
50 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
50 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
51 # from the pygtk mailing list, to avoid lockups with system calls.
51 # from the pygtk mailing list, to avoid lockups with system calls.
52
52
53 # class attribute to indicate whether the class supports threads or not.
53 # class attribute to indicate whether the class supports threads or not.
54 # Subclasses with thread support should override this as needed.
54 # Subclasses with thread support should override this as needed.
55 isthreaded = True
55 isthreaded = True
56
56
57 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
57 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
58 user_ns=None,user_global_ns=None,banner2='',**kw):
58 user_ns=None,user_global_ns=None,banner2='',**kw):
59 """Similar to the normal InteractiveShell, but with threading control"""
59 """Similar to the normal InteractiveShell, but with threading control"""
60
60
61 InteractiveShell.__init__(self,name,usage,rc,user_ns,
61 InteractiveShell.__init__(self,name,usage,rc,user_ns,
62 user_global_ns,banner2)
62 user_global_ns,banner2)
63
63
64
64
65 # A queue to hold the code to be executed.
65 # A queue to hold the code to be executed.
66 self.code_queue = Queue.Queue()
66 self.code_queue = Queue.Queue()
67
67
68 # Stuff to do at closing time
68 # Stuff to do at closing time
69 self._kill = None
69 self._kill = None
70 on_kill = kw.get('on_kill', [])
70 on_kill = kw.get('on_kill', [])
71 # Check that all things to kill are callable:
71 # Check that all things to kill are callable:
72 for t in on_kill:
72 for t in on_kill:
73 if not callable(t):
73 if not callable(t):
74 raise TypeError,'on_kill must be a list of callables'
74 raise TypeError,'on_kill must be a list of callables'
75 self.on_kill = on_kill
75 self.on_kill = on_kill
76 # thread identity of the "worker thread" (that may execute code directly)
76 # thread identity of the "worker thread" (that may execute code directly)
77 self.worker_ident = None
77 self.worker_ident = None
78 self.reactor_started = False
78 self.reactor_started = False
79 self.first_run = True
79 self.first_run = True
80
80
81 def runsource(self, source, filename="<input>", symbol="single"):
81 def runsource(self, source, filename="<input>", symbol="single"):
82 """Compile and run some source in the interpreter.
82 """Compile and run some source in the interpreter.
83
83
84 Modified version of code.py's runsource(), to handle threading issues.
84 Modified version of code.py's runsource(), to handle threading issues.
85 See the original for full docstring details."""
85 See the original for full docstring details."""
86
86
87 # If Ctrl-C was typed, we reset the flag and return right away
87 # If Ctrl-C was typed, we reset the flag and return right away
88 if shellglobals.KBINT:
88 if shellglobals.KBINT:
89 shellglobals.KBINT = False
89 shellglobals.KBINT = False
90 return False
90 return False
91
91
92 if self._kill:
92 if self._kill:
93 # can't queue new code if we are being killed
93 # can't queue new code if we are being killed
94 return True
94 return True
95
95
96 try:
96 try:
97 code = self.compile(source, filename, symbol)
97 code = self.compile(source, filename, symbol)
98 except (OverflowError, SyntaxError, ValueError):
98 except (OverflowError, SyntaxError, ValueError):
99 # Case 1
99 # Case 1
100 self.showsyntaxerror(filename)
100 self.showsyntaxerror(filename)
101 return False
101 return False
102
102
103 if code is None:
103 if code is None:
104 # Case 2
104 # Case 2
105 return True
105 return True
106
106
107 # shortcut - if we are in worker thread, or the worker thread is not running,
107 # shortcut - if we are in worker thread, or the worker thread is not running,
108 # execute directly (to allow recursion and prevent deadlock if code is run early
108 # execute directly (to allow recursion and prevent deadlock if code is run early
109 # in IPython construction)
109 # in IPython construction)
110
110
111 if (not self.reactor_started or (self.worker_ident is None and not self.first_run)
111 if (not self.reactor_started or (self.worker_ident is None and not self.first_run)
112 or self.worker_ident == thread.get_ident() or shellglobals.run_in_frontend(source)):
112 or self.worker_ident == thread.get_ident() or shellglobals.run_in_frontend(source)):
113 InteractiveShell.runcode(self,code)
113 InteractiveShell.runcode(self,code)
114 return
114 return
115
115
116 # Case 3
116 # Case 3
117 # Store code in queue, so the execution thread can handle it.
117 # Store code in queue, so the execution thread can handle it.
118
118
119 self.first_run = False
119 self.first_run = False
120 completed_ev, received_ev = threading.Event(), threading.Event()
120 completed_ev, received_ev = threading.Event(), threading.Event()
121
121
122 self.code_queue.put((code,completed_ev, received_ev))
122 self.code_queue.put((code,completed_ev, received_ev))
123
123
124 reactor.callLater(0.0,self.runcode)
124 reactor.callLater(0.0,self.runcode)
125 received_ev.wait(5)
125 received_ev.wait(5)
126 if not received_ev.isSet():
126 if not received_ev.isSet():
127 # the mainloop is dead, start executing code directly
127 # the mainloop is dead, start executing code directly
128 print "Warning: Timeout for mainloop thread exceeded"
128 print "Warning: Timeout for mainloop thread exceeded"
129 print "switching to nonthreaded mode (until mainloop wakes up again)"
129 print "switching to nonthreaded mode (until mainloop wakes up again)"
130 self.worker_ident = None
130 self.worker_ident = None
131 else:
131 else:
132 completed_ev.wait()
132 completed_ev.wait()
133
133
134 return False
134 return False
135
135
136 def runcode(self):
136 def runcode(self):
137 """Execute a code object.
137 """Execute a code object.
138
138
139 Multithreaded wrapper around IPython's runcode()."""
139 Multithreaded wrapper around IPython's runcode()."""
140
140
141
141
142 # we are in worker thread, stash out the id for runsource()
142 # we are in worker thread, stash out the id for runsource()
143 self.worker_ident = thread.get_ident()
143 self.worker_ident = thread.get_ident()
144
144
145 if self._kill:
145 if self._kill:
146 print >>Term.cout, 'Closing threads...',
146 print >>Term.cout, 'Closing threads...',
147 Term.cout.flush()
147 Term.cout.flush()
148 for tokill in self.on_kill:
148 for tokill in self.on_kill:
149 tokill()
149 tokill()
150 print >>Term.cout, 'Done.'
150 print >>Term.cout, 'Done.'
151 # allow kill() to return
151 # allow kill() to return
152 self._kill.set()
152 self._kill.set()
153 return True
153 return True
154
154
155 # Install SIGINT handler. We do it every time to ensure that if user
155 # Install SIGINT handler. We do it every time to ensure that if user
156 # code modifies it, we restore our own handling.
156 # code modifies it, we restore our own handling.
157 try:
157 try:
158 pass
158 pass
159 signal(SIGINT,shellglobals.sigint_handler)
159 signal(SIGINT,shellglobals.sigint_handler)
160 except SystemError:
160 except SystemError:
161 # This happens under Windows, which seems to have all sorts
161 # This happens under Windows, which seems to have all sorts
162 # of problems with signal handling. Oh well...
162 # of problems with signal handling. Oh well...
163 pass
163 pass
164
164
165 # Flush queue of pending code by calling the run methood of the parent
165 # Flush queue of pending code by calling the run methood of the parent
166 # class with all items which may be in the queue.
166 # class with all items which may be in the queue.
167 code_to_run = None
167 code_to_run = None
168 while 1:
168 while 1:
169 try:
169 try:
170 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
170 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
171 except Queue.Empty:
171 except Queue.Empty:
172 break
172 break
173 received_ev.set()
173 received_ev.set()
174
174
175
175
176 # Exceptions need to be raised differently depending on which
176 # Exceptions need to be raised differently depending on which
177 # thread is active. This convoluted try/except is only there to
177 # thread is active. This convoluted try/except is only there to
178 # protect against asynchronous exceptions, to ensure that a shellglobals.KBINT
178 # protect against asynchronous exceptions, to ensure that a shellglobals.KBINT
179 # at the wrong time doesn't deadlock everything. The global
179 # at the wrong time doesn't deadlock everything. The global
180 # CODE_TO_RUN is set to true/false as close as possible to the
180 # CODE_TO_RUN is set to true/false as close as possible to the
181 # runcode() call, so that the KBINT handler is correctly informed.
181 # runcode() call, so that the KBINT handler is correctly informed.
182 try:
182 try:
183 try:
183 try:
184 shellglobals.CODE_RUN = True
184 shellglobals.CODE_RUN = True
185 InteractiveShell.runcode(self,code_to_run)
185 InteractiveShell.runcode(self,code_to_run)
186 except KeyboardInterrupt:
186 except KeyboardInterrupt:
187 print "Keyboard interrupted in mainloop"
187 print "Keyboard interrupted in mainloop"
188 while not self.code_queue.empty():
188 while not self.code_queue.empty():
189 code = self.code_queue.get_nowait()
189 code = self.code_queue.get_nowait()
190 break
190 break
191 finally:
191 finally:
192 shellglobals.CODE_RUN = False
192 shellglobals.CODE_RUN = False
193 # allow runsource() return from wait
193 # allow runsource() return from wait
194 completed_ev.set()
194 completed_ev.set()
195
195
196 # This MUST return true for gtk threading to work
196 # This MUST return true for gtk threading to work
197 return True
197 return True
198
198
199 def kill(self):
199 def kill(self):
200 """Kill the thread, returning when it has been shut down."""
200 """Kill the thread, returning when it has been shut down."""
201 self._kill = threading.Event()
201 self._kill = threading.Event()
202 reactor.callLater(0.0,self.runcode)
202 reactor.callLater(0.0,self.runcode)
203 self._kill.wait()
203 self._kill.wait()
204
204
205
205
206
206
207 class IPShellTwisted:
207 class IPShellTwisted:
208 """Run a Twisted reactor while in an IPython session.
208 """Run a Twisted reactor while in an IPython session.
209
209
210 Python commands can be passed to the thread where they will be
210 Python commands can be passed to the thread where they will be
211 executed. This is implemented by periodically checking for
211 executed. This is implemented by periodically checking for
212 passed code using a Twisted reactor callback.
212 passed code using a Twisted reactor callback.
213 """
213 """
214
214
215 TIMEOUT = 0.01 # Millisecond interval between reactor runs.
215 TIMEOUT = 0.01 # Millisecond interval between reactor runs.
216
216
217 def __init__(self, argv=None, user_ns=None, debug=1,
217 def __init__(self, argv=None, user_ns=None, debug=1,
218 shell_class=TwistedInteractiveShell):
218 shell_class=TwistedInteractiveShell):
219
219
220 from twisted.internet import reactor
220 from twisted.internet import reactor
221 self.reactor = hijack_reactor()
221 self.reactor = hijack_reactor()
222
222
223 mainquit = self.reactor.stop
223 mainquit = self.reactor.stop
224
224
225 # Make sure IPython keeps going after reactor stop.
225 # Make sure IPython keeps going after reactor stop.
226 def reactorstop():
226 def reactorstop():
227 pass
227 pass
228 self.reactor.stop = reactorstop
228 self.reactor.stop = reactorstop
229 reactorrun_orig = self.reactor.run
229 reactorrun_orig = self.reactor.run
230 self.quitting = False
230 self.quitting = False
231 def reactorrun():
231 def reactorrun():
232 while True and not self.quitting:
232 while True and not self.quitting:
233 reactorrun_orig()
233 reactorrun_orig()
234 self.reactor.run = reactorrun
234 self.reactor.run = reactorrun
235
235
236 self.IP = make_IPython(argv, user_ns=user_ns, debug=debug,
236 self.IP = make_IPython(argv, user_ns=user_ns, debug=debug,
237 shell_class=shell_class,
237 shell_class=shell_class,
238 on_kill=[mainquit])
238 on_kill=[mainquit])
239
239
240 # threading.Thread.__init__(self)
240 # threading.Thread.__init__(self)
241
241
242 def run(self):
242 def run(self):
243 self.IP.mainloop()
243 self.IP.mainloop()
244 self.quitting = True
244 self.quitting = True
245 self.IP.kill()
245 self.IP.kill()
246
246
247 def mainloop(self):
247 def mainloop(self):
248 def mainLoopThreadDeath(r):
248 def mainLoopThreadDeath(r):
249 print "mainLoopThreadDeath: ", str(r)
249 print "mainLoopThreadDeath: ", str(r)
250 def spawnMainloopThread():
250 def spawnMainloopThread():
251 d=threads.deferToThread(self.run)
251 d=threads.deferToThread(self.run)
252 d.addBoth(mainLoopThreadDeath)
252 d.addBoth(mainLoopThreadDeath)
253 reactor.callWhenRunning(spawnMainloopThread)
253 reactor.callWhenRunning(spawnMainloopThread)
254 self.IP.reactor_started = True
254 self.IP.reactor_started = True
255 self.reactor.run()
255 self.reactor.run()
256 print "mainloop ending...."
256 print "mainloop ending...."
257
257
258 exists = True
258 exists = True
259
259
260
260
261 if __name__ == '__main__':
261 if __name__ == '__main__':
262 # Sample usage.
262 # Sample usage.
263
263
264 # Create the shell object. This steals twisted.internet.reactor
264 # Create the shell object. This steals twisted.internet.reactor
265 # for its own purposes, to make sure you've already installed a
265 # for its own purposes, to make sure you've already installed a
266 # reactor of your choice.
266 # reactor of your choice.
267 shell = IPShellTwisted(
267 shell = IPShellTwisted(
268 argv=[],
268 argv=[],
269 user_ns={'__name__': '__example__',
269 user_ns={'__name__': '__example__',
270 'hello': 'world',
270 'hello': 'world',
271 },
271 },
272 )
272 )
273
273
274 # Run the mainloop. This runs the actual reactor.run() method.
274 # Run the mainloop. This runs the actual reactor.run() method.
275 # The twisted.internet.reactor object at this point is a dummy
275 # The twisted.internet.reactor object at this point is a dummy
276 # object that passes through to the actual reactor, but prevents
276 # object that passes through to the actual reactor, but prevents
277 # run() from being called on it again.
277 # run() from being called on it again.
278 shell.mainloop()
278 shell.mainloop()
279
279
280 # You must exit IPython to terminate your program.
280 # You must exit IPython to terminate your program.
281 print 'Goodbye!'
281 print 'Goodbye!'
282
282
General Comments 0
You need to be logged in to leave comments. Login now