|
@@
-1,956
+1,960
|
|
1
|
# -*- coding: utf-8 -*-
|
|
1
|
# -*- coding: utf-8 -*-
|
|
2
|
"""IPython Shell classes.
|
|
2
|
"""IPython Shell classes.
|
|
3
|
|
|
3
|
|
|
4
|
All the matplotlib support code was co-developed with John Hunter,
|
|
4
|
All the matplotlib support code was co-developed with John Hunter,
|
|
5
|
matplotlib's author.
|
|
5
|
matplotlib's author.
|
|
6
|
|
|
6
|
|
|
7
|
$Id: Shell.py 1297 2006-05-13 19:14:48Z fperez $"""
|
|
7
|
$Id: Shell.py 1313 2006-05-19 17:48:41Z fperez $"""
|
|
8
|
|
|
8
|
|
|
9
|
#*****************************************************************************
|
|
9
|
#*****************************************************************************
|
|
10
|
# Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
|
|
10
|
# Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
|
|
11
|
#
|
|
11
|
#
|
|
12
|
# Distributed under the terms of the BSD License. The full license is in
|
|
12
|
# Distributed under the terms of the BSD License. The full license is in
|
|
13
|
# the file COPYING, distributed as part of this software.
|
|
13
|
# the file COPYING, distributed as part of this software.
|
|
14
|
#*****************************************************************************
|
|
14
|
#*****************************************************************************
|
|
15
|
|
|
15
|
|
|
16
|
from IPython import Release
|
|
16
|
from IPython import Release
|
|
17
|
__author__ = '%s <%s>' % Release.authors['Fernando']
|
|
17
|
__author__ = '%s <%s>' % Release.authors['Fernando']
|
|
18
|
__license__ = Release.license
|
|
18
|
__license__ = Release.license
|
|
19
|
|
|
19
|
|
|
20
|
# Code begins
|
|
20
|
# Code begins
|
|
21
|
import __builtin__
|
|
21
|
import __builtin__
|
|
22
|
import __main__
|
|
22
|
import __main__
|
|
23
|
import Queue
|
|
23
|
import Queue
|
|
24
|
import os
|
|
24
|
import os
|
|
25
|
import signal
|
|
25
|
import signal
|
|
26
|
import sys
|
|
26
|
import sys
|
|
27
|
import threading
|
|
27
|
import threading
|
|
28
|
import time
|
|
28
|
import time
|
|
29
|
|
|
29
|
|
|
30
|
import IPython
|
|
30
|
import IPython
|
|
31
|
from IPython import ultraTB
|
|
31
|
from IPython import ultraTB
|
|
32
|
from IPython.genutils import Term,warn,error,flag_calls
|
|
32
|
from IPython.genutils import Term,warn,error,flag_calls
|
|
33
|
from IPython.iplib import InteractiveShell
|
|
33
|
from IPython.iplib import InteractiveShell
|
|
34
|
from IPython.ipmaker import make_IPython
|
|
34
|
from IPython.ipmaker import make_IPython
|
|
35
|
from IPython.Magic import Magic
|
|
35
|
from IPython.Magic import Magic
|
|
36
|
from IPython.ipstruct import Struct
|
|
36
|
from IPython.ipstruct import Struct
|
|
37
|
|
|
37
|
|
|
38
|
# global flag to pass around information about Ctrl-C without exceptions
|
|
38
|
# global flag to pass around information about Ctrl-C without exceptions
|
|
39
|
KBINT = False
|
|
39
|
KBINT = False
|
|
40
|
|
|
40
|
|
|
41
|
# global flag to turn on/off Tk support.
|
|
41
|
# global flag to turn on/off Tk support.
|
|
42
|
USE_TK = False
|
|
42
|
USE_TK = False
|
|
43
|
|
|
43
|
|
|
44
|
#-----------------------------------------------------------------------------
|
|
44
|
#-----------------------------------------------------------------------------
|
|
45
|
# This class is trivial now, but I want to have it in to publish a clean
|
|
45
|
# This class is trivial now, but I want to have it in to publish a clean
|
|
46
|
# interface. Later when the internals are reorganized, code that uses this
|
|
46
|
# interface. Later when the internals are reorganized, code that uses this
|
|
47
|
# shouldn't have to change.
|
|
47
|
# shouldn't have to change.
|
|
48
|
|
|
48
|
|
|
49
|
class IPShell:
|
|
49
|
class IPShell:
|
|
50
|
"""Create an IPython instance."""
|
|
50
|
"""Create an IPython instance."""
|
|
51
|
|
|
51
|
|
|
52
|
def __init__(self,argv=None,user_ns=None,user_global_ns=None,
|
|
52
|
def __init__(self,argv=None,user_ns=None,user_global_ns=None,
|
|
53
|
debug=1,shell_class=InteractiveShell):
|
|
53
|
debug=1,shell_class=InteractiveShell):
|
|
54
|
self.IP = make_IPython(argv,user_ns=user_ns,user_global_ns=user_global_ns,
|
|
54
|
self.IP = make_IPython(argv,user_ns=user_ns,user_global_ns=user_global_ns,
|
|
55
|
debug=debug,shell_class=shell_class)
|
|
55
|
debug=debug,shell_class=shell_class)
|
|
56
|
|
|
56
|
|
|
57
|
def mainloop(self,sys_exit=0,banner=None):
|
|
57
|
def mainloop(self,sys_exit=0,banner=None):
|
|
58
|
self.IP.mainloop(banner)
|
|
58
|
self.IP.mainloop(banner)
|
|
59
|
if sys_exit:
|
|
59
|
if sys_exit:
|
|
60
|
sys.exit()
|
|
60
|
sys.exit()
|
|
61
|
|
|
61
|
|
|
62
|
#-----------------------------------------------------------------------------
|
|
62
|
#-----------------------------------------------------------------------------
|
|
63
|
class IPShellEmbed:
|
|
63
|
class IPShellEmbed:
|
|
64
|
"""Allow embedding an IPython shell into a running program.
|
|
64
|
"""Allow embedding an IPython shell into a running program.
|
|
65
|
|
|
65
|
|
|
66
|
Instances of this class are callable, with the __call__ method being an
|
|
66
|
Instances of this class are callable, with the __call__ method being an
|
|
67
|
alias to the embed() method of an InteractiveShell instance.
|
|
67
|
alias to the embed() method of an InteractiveShell instance.
|
|
68
|
|
|
68
|
|
|
69
|
Usage (see also the example-embed.py file for a running example):
|
|
69
|
Usage (see also the example-embed.py file for a running example):
|
|
70
|
|
|
70
|
|
|
71
|
ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
|
|
71
|
ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
|
|
72
|
|
|
72
|
|
|
73
|
- argv: list containing valid command-line options for IPython, as they
|
|
73
|
- argv: list containing valid command-line options for IPython, as they
|
|
74
|
would appear in sys.argv[1:].
|
|
74
|
would appear in sys.argv[1:].
|
|
75
|
|
|
75
|
|
|
76
|
For example, the following command-line options:
|
|
76
|
For example, the following command-line options:
|
|
77
|
|
|
77
|
|
|
78
|
$ ipython -prompt_in1 'Input <\\#>' -colors LightBG
|
|
78
|
$ ipython -prompt_in1 'Input <\\#>' -colors LightBG
|
|
79
|
|
|
79
|
|
|
80
|
would be passed in the argv list as:
|
|
80
|
would be passed in the argv list as:
|
|
81
|
|
|
81
|
|
|
82
|
['-prompt_in1','Input <\\#>','-colors','LightBG']
|
|
82
|
['-prompt_in1','Input <\\#>','-colors','LightBG']
|
|
83
|
|
|
83
|
|
|
84
|
- banner: string which gets printed every time the interpreter starts.
|
|
84
|
- banner: string which gets printed every time the interpreter starts.
|
|
85
|
|
|
85
|
|
|
86
|
- exit_msg: string which gets printed every time the interpreter exits.
|
|
86
|
- exit_msg: string which gets printed every time the interpreter exits.
|
|
87
|
|
|
87
|
|
|
88
|
- rc_override: a dict or Struct of configuration options such as those
|
|
88
|
- rc_override: a dict or Struct of configuration options such as those
|
|
89
|
used by IPython. These options are read from your ~/.ipython/ipythonrc
|
|
89
|
used by IPython. These options are read from your ~/.ipython/ipythonrc
|
|
90
|
file when the Shell object is created. Passing an explicit rc_override
|
|
90
|
file when the Shell object is created. Passing an explicit rc_override
|
|
91
|
dict with any options you want allows you to override those values at
|
|
91
|
dict with any options you want allows you to override those values at
|
|
92
|
creation time without having to modify the file. This way you can create
|
|
92
|
creation time without having to modify the file. This way you can create
|
|
93
|
embeddable instances configured in any way you want without editing any
|
|
93
|
embeddable instances configured in any way you want without editing any
|
|
94
|
global files (thus keeping your interactive IPython configuration
|
|
94
|
global files (thus keeping your interactive IPython configuration
|
|
95
|
unchanged).
|
|
95
|
unchanged).
|
|
96
|
|
|
96
|
|
|
97
|
Then the ipshell instance can be called anywhere inside your code:
|
|
97
|
Then the ipshell instance can be called anywhere inside your code:
|
|
98
|
|
|
98
|
|
|
99
|
ipshell(header='') -> Opens up an IPython shell.
|
|
99
|
ipshell(header='') -> Opens up an IPython shell.
|
|
100
|
|
|
100
|
|
|
101
|
- header: string printed by the IPython shell upon startup. This can let
|
|
101
|
- header: string printed by the IPython shell upon startup. This can let
|
|
102
|
you know where in your code you are when dropping into the shell. Note
|
|
102
|
you know where in your code you are when dropping into the shell. Note
|
|
103
|
that 'banner' gets prepended to all calls, so header is used for
|
|
103
|
that 'banner' gets prepended to all calls, so header is used for
|
|
104
|
location-specific information.
|
|
104
|
location-specific information.
|
|
105
|
|
|
105
|
|
|
106
|
For more details, see the __call__ method below.
|
|
106
|
For more details, see the __call__ method below.
|
|
107
|
|
|
107
|
|
|
108
|
When the IPython shell is exited with Ctrl-D, normal program execution
|
|
108
|
When the IPython shell is exited with Ctrl-D, normal program execution
|
|
109
|
resumes.
|
|
109
|
resumes.
|
|
110
|
|
|
110
|
|
|
111
|
This functionality was inspired by a posting on comp.lang.python by cmkl
|
|
111
|
This functionality was inspired by a posting on comp.lang.python by cmkl
|
|
112
|
<cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
|
|
112
|
<cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
|
|
113
|
by the IDL stop/continue commands."""
|
|
113
|
by the IDL stop/continue commands."""
|
|
114
|
|
|
114
|
|
|
115
|
def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None):
|
|
115
|
def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None):
|
|
116
|
"""Note that argv here is a string, NOT a list."""
|
|
116
|
"""Note that argv here is a string, NOT a list."""
|
|
117
|
self.set_banner(banner)
|
|
117
|
self.set_banner(banner)
|
|
118
|
self.set_exit_msg(exit_msg)
|
|
118
|
self.set_exit_msg(exit_msg)
|
|
119
|
self.set_dummy_mode(0)
|
|
119
|
self.set_dummy_mode(0)
|
|
120
|
|
|
120
|
|
|
121
|
# sys.displayhook is a global, we need to save the user's original
|
|
121
|
# sys.displayhook is a global, we need to save the user's original
|
|
122
|
# Don't rely on __displayhook__, as the user may have changed that.
|
|
122
|
# Don't rely on __displayhook__, as the user may have changed that.
|
|
123
|
self.sys_displayhook_ori = sys.displayhook
|
|
123
|
self.sys_displayhook_ori = sys.displayhook
|
|
124
|
|
|
124
|
|
|
125
|
# save readline completer status
|
|
125
|
# save readline completer status
|
|
126
|
try:
|
|
126
|
try:
|
|
127
|
#print 'Save completer',sys.ipcompleter # dbg
|
|
127
|
#print 'Save completer',sys.ipcompleter # dbg
|
|
128
|
self.sys_ipcompleter_ori = sys.ipcompleter
|
|
128
|
self.sys_ipcompleter_ori = sys.ipcompleter
|
|
129
|
except:
|
|
129
|
except:
|
|
130
|
pass # not nested with IPython
|
|
130
|
pass # not nested with IPython
|
|
131
|
|
|
131
|
|
|
132
|
# FIXME. Passing user_ns breaks namespace handling.
|
|
132
|
# FIXME. Passing user_ns breaks namespace handling.
|
|
133
|
#self.IP = make_IPython(argv,user_ns=__main__.__dict__)
|
|
133
|
#self.IP = make_IPython(argv,user_ns=__main__.__dict__)
|
|
134
|
self.IP = make_IPython(argv,rc_override=rc_override,embedded=True)
|
|
134
|
self.IP = make_IPython(argv,rc_override=rc_override,embedded=True)
|
|
135
|
|
|
135
|
|
|
136
|
# copy our own displayhook also
|
|
136
|
# copy our own displayhook also
|
|
137
|
self.sys_displayhook_embed = sys.displayhook
|
|
137
|
self.sys_displayhook_embed = sys.displayhook
|
|
138
|
# and leave the system's display hook clean
|
|
138
|
# and leave the system's display hook clean
|
|
139
|
sys.displayhook = self.sys_displayhook_ori
|
|
139
|
sys.displayhook = self.sys_displayhook_ori
|
|
140
|
# don't use the ipython crash handler so that user exceptions aren't
|
|
140
|
# don't use the ipython crash handler so that user exceptions aren't
|
|
141
|
# trapped
|
|
141
|
# trapped
|
|
142
|
sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
|
|
142
|
sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
|
|
143
|
mode = self.IP.rc.xmode,
|
|
143
|
mode = self.IP.rc.xmode,
|
|
144
|
call_pdb = self.IP.rc.pdb)
|
|
144
|
call_pdb = self.IP.rc.pdb)
|
|
145
|
self.restore_system_completer()
|
|
145
|
self.restore_system_completer()
|
|
146
|
|
|
146
|
|
|
147
|
def restore_system_completer(self):
|
|
147
|
def restore_system_completer(self):
|
|
148
|
"""Restores the readline completer which was in place.
|
|
148
|
"""Restores the readline completer which was in place.
|
|
149
|
|
|
149
|
|
|
150
|
This allows embedded IPython within IPython not to disrupt the
|
|
150
|
This allows embedded IPython within IPython not to disrupt the
|
|
151
|
parent's completion.
|
|
151
|
parent's completion.
|
|
152
|
"""
|
|
152
|
"""
|
|
153
|
|
|
153
|
|
|
154
|
try:
|
|
154
|
try:
|
|
155
|
self.IP.readline.set_completer(self.sys_ipcompleter_ori)
|
|
155
|
self.IP.readline.set_completer(self.sys_ipcompleter_ori)
|
|
156
|
sys.ipcompleter = self.sys_ipcompleter_ori
|
|
156
|
sys.ipcompleter = self.sys_ipcompleter_ori
|
|
157
|
except:
|
|
157
|
except:
|
|
158
|
pass
|
|
158
|
pass
|
|
159
|
|
|
159
|
|
|
160
|
def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
|
|
160
|
def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
|
|
161
|
"""Activate the interactive interpreter.
|
|
161
|
"""Activate the interactive interpreter.
|
|
162
|
|
|
162
|
|
|
163
|
__call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
|
|
163
|
__call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
|
|
164
|
the interpreter shell with the given local and global namespaces, and
|
|
164
|
the interpreter shell with the given local and global namespaces, and
|
|
165
|
optionally print a header string at startup.
|
|
165
|
optionally print a header string at startup.
|
|
166
|
|
|
166
|
|
|
167
|
The shell can be globally activated/deactivated using the
|
|
167
|
The shell can be globally activated/deactivated using the
|
|
168
|
set/get_dummy_mode methods. This allows you to turn off a shell used
|
|
168
|
set/get_dummy_mode methods. This allows you to turn off a shell used
|
|
169
|
for debugging globally.
|
|
169
|
for debugging globally.
|
|
170
|
|
|
170
|
|
|
171
|
However, *each* time you call the shell you can override the current
|
|
171
|
However, *each* time you call the shell you can override the current
|
|
172
|
state of dummy_mode with the optional keyword parameter 'dummy'. For
|
|
172
|
state of dummy_mode with the optional keyword parameter 'dummy'. For
|
|
173
|
example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
|
|
173
|
example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
|
|
174
|
can still have a specific call work by making it as IPShell(dummy=0).
|
|
174
|
can still have a specific call work by making it as IPShell(dummy=0).
|
|
175
|
|
|
175
|
|
|
176
|
The optional keyword parameter dummy controls whether the call
|
|
176
|
The optional keyword parameter dummy controls whether the call
|
|
177
|
actually does anything. """
|
|
177
|
actually does anything. """
|
|
178
|
|
|
178
|
|
|
179
|
# Allow the dummy parameter to override the global __dummy_mode
|
|
179
|
# Allow the dummy parameter to override the global __dummy_mode
|
|
180
|
if dummy or (dummy != 0 and self.__dummy_mode):
|
|
180
|
if dummy or (dummy != 0 and self.__dummy_mode):
|
|
181
|
return
|
|
181
|
return
|
|
182
|
|
|
182
|
|
|
183
|
# Set global subsystems (display,completions) to our values
|
|
183
|
# Set global subsystems (display,completions) to our values
|
|
184
|
sys.displayhook = self.sys_displayhook_embed
|
|
184
|
sys.displayhook = self.sys_displayhook_embed
|
|
185
|
if self.IP.has_readline:
|
|
185
|
if self.IP.has_readline:
|
|
186
|
self.IP.readline.set_completer(self.IP.Completer.complete)
|
|
186
|
self.IP.readline.set_completer(self.IP.Completer.complete)
|
|
187
|
|
|
187
|
|
|
188
|
if self.banner and header:
|
|
188
|
if self.banner and header:
|
|
189
|
format = '%s\n%s\n'
|
|
189
|
format = '%s\n%s\n'
|
|
190
|
else:
|
|
190
|
else:
|
|
191
|
format = '%s%s\n'
|
|
191
|
format = '%s%s\n'
|
|
192
|
banner = format % (self.banner,header)
|
|
192
|
banner = format % (self.banner,header)
|
|
193
|
|
|
193
|
|
|
194
|
# Call the embedding code with a stack depth of 1 so it can skip over
|
|
194
|
# Call the embedding code with a stack depth of 1 so it can skip over
|
|
195
|
# our call and get the original caller's namespaces.
|
|
195
|
# our call and get the original caller's namespaces.
|
|
196
|
self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
|
|
196
|
self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
|
|
197
|
|
|
197
|
|
|
198
|
if self.exit_msg:
|
|
198
|
if self.exit_msg:
|
|
199
|
print self.exit_msg
|
|
199
|
print self.exit_msg
|
|
200
|
|
|
200
|
|
|
201
|
# Restore global systems (display, completion)
|
|
201
|
# Restore global systems (display, completion)
|
|
202
|
sys.displayhook = self.sys_displayhook_ori
|
|
202
|
sys.displayhook = self.sys_displayhook_ori
|
|
203
|
self.restore_system_completer()
|
|
203
|
self.restore_system_completer()
|
|
204
|
|
|
204
|
|
|
205
|
def set_dummy_mode(self,dummy):
|
|
205
|
def set_dummy_mode(self,dummy):
|
|
206
|
"""Sets the embeddable shell's dummy mode parameter.
|
|
206
|
"""Sets the embeddable shell's dummy mode parameter.
|
|
207
|
|
|
207
|
|
|
208
|
set_dummy_mode(dummy): dummy = 0 or 1.
|
|
208
|
set_dummy_mode(dummy): dummy = 0 or 1.
|
|
209
|
|
|
209
|
|
|
210
|
This parameter is persistent and makes calls to the embeddable shell
|
|
210
|
This parameter is persistent and makes calls to the embeddable shell
|
|
211
|
silently return without performing any action. This allows you to
|
|
211
|
silently return without performing any action. This allows you to
|
|
212
|
globally activate or deactivate a shell you're using with a single call.
|
|
212
|
globally activate or deactivate a shell you're using with a single call.
|
|
213
|
|
|
213
|
|
|
214
|
If you need to manually"""
|
|
214
|
If you need to manually"""
|
|
215
|
|
|
215
|
|
|
216
|
if dummy not in [0,1,False,True]:
|
|
216
|
if dummy not in [0,1,False,True]:
|
|
217
|
raise ValueError,'dummy parameter must be boolean'
|
|
217
|
raise ValueError,'dummy parameter must be boolean'
|
|
218
|
self.__dummy_mode = dummy
|
|
218
|
self.__dummy_mode = dummy
|
|
219
|
|
|
219
|
|
|
220
|
def get_dummy_mode(self):
|
|
220
|
def get_dummy_mode(self):
|
|
221
|
"""Return the current value of the dummy mode parameter.
|
|
221
|
"""Return the current value of the dummy mode parameter.
|
|
222
|
"""
|
|
222
|
"""
|
|
223
|
return self.__dummy_mode
|
|
223
|
return self.__dummy_mode
|
|
224
|
|
|
224
|
|
|
225
|
def set_banner(self,banner):
|
|
225
|
def set_banner(self,banner):
|
|
226
|
"""Sets the global banner.
|
|
226
|
"""Sets the global banner.
|
|
227
|
|
|
227
|
|
|
228
|
This banner gets prepended to every header printed when the shell
|
|
228
|
This banner gets prepended to every header printed when the shell
|
|
229
|
instance is called."""
|
|
229
|
instance is called."""
|
|
230
|
|
|
230
|
|
|
231
|
self.banner = banner
|
|
231
|
self.banner = banner
|
|
232
|
|
|
232
|
|
|
233
|
def set_exit_msg(self,exit_msg):
|
|
233
|
def set_exit_msg(self,exit_msg):
|
|
234
|
"""Sets the global exit_msg.
|
|
234
|
"""Sets the global exit_msg.
|
|
235
|
|
|
235
|
|
|
236
|
This exit message gets printed upon exiting every time the embedded
|
|
236
|
This exit message gets printed upon exiting every time the embedded
|
|
237
|
shell is called. It is None by default. """
|
|
237
|
shell is called. It is None by default. """
|
|
238
|
|
|
238
|
|
|
239
|
self.exit_msg = exit_msg
|
|
239
|
self.exit_msg = exit_msg
|
|
240
|
|
|
240
|
|
|
241
|
#-----------------------------------------------------------------------------
|
|
241
|
#-----------------------------------------------------------------------------
|
|
242
|
def sigint_handler (signum,stack_frame):
|
|
242
|
def sigint_handler (signum,stack_frame):
|
|
243
|
"""Sigint handler for threaded apps.
|
|
243
|
"""Sigint handler for threaded apps.
|
|
244
|
|
|
244
|
|
|
245
|
This is a horrible hack to pass information about SIGINT _without_ using
|
|
245
|
This is a horrible hack to pass information about SIGINT _without_ using
|
|
246
|
exceptions, since I haven't been able to properly manage cross-thread
|
|
246
|
exceptions, since I haven't been able to properly manage cross-thread
|
|
247
|
exceptions in GTK/WX. In fact, I don't think it can be done (or at least
|
|
247
|
exceptions in GTK/WX. In fact, I don't think it can be done (or at least
|
|
248
|
that's my understanding from a c.l.py thread where this was discussed)."""
|
|
248
|
that's my understanding from a c.l.py thread where this was discussed)."""
|
|
249
|
|
|
249
|
|
|
250
|
global KBINT
|
|
250
|
global KBINT
|
|
251
|
|
|
251
|
|
|
252
|
print '\nKeyboardInterrupt - Press <Enter> to continue.',
|
|
252
|
print '\nKeyboardInterrupt - Press <Enter> to continue.',
|
|
253
|
Term.cout.flush()
|
|
253
|
Term.cout.flush()
|
|
254
|
# Set global flag so that runsource can know that Ctrl-C was hit
|
|
254
|
# Set global flag so that runsource can know that Ctrl-C was hit
|
|
255
|
KBINT = True
|
|
255
|
KBINT = True
|
|
256
|
|
|
256
|
|
|
257
|
class MTInteractiveShell(InteractiveShell):
|
|
257
|
class MTInteractiveShell(InteractiveShell):
|
|
258
|
"""Simple multi-threaded shell."""
|
|
258
|
"""Simple multi-threaded shell."""
|
|
259
|
|
|
259
|
|
|
260
|
# Threading strategy taken from:
|
|
260
|
# Threading strategy taken from:
|
|
261
|
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
|
|
261
|
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
|
|
262
|
# McErlean and John Finlay. Modified with corrections by Antoon Pardon,
|
|
262
|
# McErlean and John Finlay. Modified with corrections by Antoon Pardon,
|
|
263
|
# from the pygtk mailing list, to avoid lockups with system calls.
|
|
263
|
# from the pygtk mailing list, to avoid lockups with system calls.
|
|
264
|
|
|
264
|
|
|
265
|
# class attribute to indicate whether the class supports threads or not.
|
|
265
|
# class attribute to indicate whether the class supports threads or not.
|
|
266
|
# Subclasses with thread support should override this as needed.
|
|
266
|
# Subclasses with thread support should override this as needed.
|
|
267
|
isthreaded = True
|
|
267
|
isthreaded = True
|
|
268
|
|
|
268
|
|
|
269
|
def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
|
|
269
|
def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
|
|
270
|
user_ns=None,user_global_ns=None,banner2='',**kw):
|
|
270
|
user_ns=None,user_global_ns=None,banner2='',**kw):
|
|
271
|
"""Similar to the normal InteractiveShell, but with threading control"""
|
|
271
|
"""Similar to the normal InteractiveShell, but with threading control"""
|
|
272
|
|
|
272
|
|
|
273
|
InteractiveShell.__init__(self,name,usage,rc,user_ns,
|
|
273
|
InteractiveShell.__init__(self,name,usage,rc,user_ns,
|
|
274
|
user_global_ns,banner2)
|
|
274
|
user_global_ns,banner2)
|
|
275
|
|
|
275
|
|
|
276
|
# Locking control variable. We need to use a norma lock, not an RLock
|
|
276
|
# Locking control variable. We need to use a norma lock, not an RLock
|
|
277
|
# here. I'm not exactly sure why, it seems to me like it should be
|
|
277
|
# here. I'm not exactly sure why, it seems to me like it should be
|
|
278
|
# the opposite, but we deadlock with an RLock. Puzzled...
|
|
278
|
# the opposite, but we deadlock with an RLock. Puzzled...
|
|
279
|
self.thread_ready = threading.Condition(threading.Lock())
|
|
279
|
self.thread_ready = threading.Condition(threading.Lock())
|
|
280
|
|
|
280
|
|
|
281
|
# A queue to hold the code to be executed. A scalar variable is NOT
|
|
281
|
# A queue to hold the code to be executed. A scalar variable is NOT
|
|
282
|
# enough, because uses like macros cause reentrancy.
|
|
282
|
# enough, because uses like macros cause reentrancy.
|
|
283
|
self.code_queue = Queue.Queue()
|
|
283
|
self.code_queue = Queue.Queue()
|
|
284
|
|
|
284
|
|
|
285
|
# Stuff to do at closing time
|
|
285
|
# Stuff to do at closing time
|
|
286
|
self._kill = False
|
|
286
|
self._kill = False
|
|
287
|
on_kill = kw.get('on_kill')
|
|
287
|
on_kill = kw.get('on_kill')
|
|
288
|
if on_kill is None:
|
|
288
|
if on_kill is None:
|
|
289
|
on_kill = []
|
|
289
|
on_kill = []
|
|
290
|
# Check that all things to kill are callable:
|
|
290
|
# Check that all things to kill are callable:
|
|
291
|
for t in on_kill:
|
|
291
|
for t in on_kill:
|
|
292
|
if not callable(t):
|
|
292
|
if not callable(t):
|
|
293
|
raise TypeError,'on_kill must be a list of callables'
|
|
293
|
raise TypeError,'on_kill must be a list of callables'
|
|
294
|
self.on_kill = on_kill
|
|
294
|
self.on_kill = on_kill
|
|
295
|
|
|
295
|
|
|
296
|
def runsource(self, source, filename="<input>", symbol="single"):
|
|
296
|
def runsource(self, source, filename="<input>", symbol="single"):
|
|
297
|
"""Compile and run some source in the interpreter.
|
|
297
|
"""Compile and run some source in the interpreter.
|
|
298
|
|
|
298
|
|
|
299
|
Modified version of code.py's runsource(), to handle threading issues.
|
|
299
|
Modified version of code.py's runsource(), to handle threading issues.
|
|
300
|
See the original for full docstring details."""
|
|
300
|
See the original for full docstring details."""
|
|
301
|
|
|
301
|
|
|
302
|
global KBINT
|
|
302
|
global KBINT
|
|
303
|
|
|
303
|
|
|
304
|
# If Ctrl-C was typed, we reset the flag and return right away
|
|
304
|
# If Ctrl-C was typed, we reset the flag and return right away
|
|
305
|
if KBINT:
|
|
305
|
if KBINT:
|
|
306
|
KBINT = False
|
|
306
|
KBINT = False
|
|
307
|
return False
|
|
307
|
return False
|
|
308
|
|
|
308
|
|
|
309
|
try:
|
|
309
|
try:
|
|
310
|
code = self.compile(source, filename, symbol)
|
|
310
|
code = self.compile(source, filename, symbol)
|
|
311
|
except (OverflowError, SyntaxError, ValueError):
|
|
311
|
except (OverflowError, SyntaxError, ValueError):
|
|
312
|
# Case 1
|
|
312
|
# Case 1
|
|
313
|
self.showsyntaxerror(filename)
|
|
313
|
self.showsyntaxerror(filename)
|
|
314
|
return False
|
|
314
|
return False
|
|
315
|
|
|
315
|
|
|
316
|
if code is None:
|
|
316
|
if code is None:
|
|
317
|
# Case 2
|
|
317
|
# Case 2
|
|
318
|
return True
|
|
318
|
return True
|
|
319
|
|
|
319
|
|
|
320
|
# Case 3
|
|
320
|
# Case 3
|
|
321
|
# Store code in queue, so the execution thread can handle it.
|
|
321
|
# Store code in queue, so the execution thread can handle it.
|
|
322
|
|
|
322
|
|
|
323
|
# Note that with macros and other applications, we MAY re-enter this
|
|
323
|
# Note that with macros and other applications, we MAY re-enter this
|
|
324
|
# section, so we have to acquire the lock with non-blocking semantics,
|
|
324
|
# section, so we have to acquire the lock with non-blocking semantics,
|
|
325
|
# else we deadlock.
|
|
325
|
# else we deadlock.
|
|
326
|
got_lock = self.thread_ready.acquire(False)
|
|
326
|
got_lock = self.thread_ready.acquire(False)
|
|
327
|
self.code_queue.put(code)
|
|
327
|
self.code_queue.put(code)
|
|
328
|
if got_lock:
|
|
328
|
if got_lock:
|
|
329
|
self.thread_ready.wait() # Wait until processed in timeout interval
|
|
329
|
self.thread_ready.wait() # Wait until processed in timeout interval
|
|
330
|
self.thread_ready.release()
|
|
330
|
self.thread_ready.release()
|
|
331
|
|
|
331
|
|
|
332
|
return False
|
|
332
|
return False
|
|
333
|
|
|
333
|
|
|
334
|
def runcode(self):
|
|
334
|
def runcode(self):
|
|
335
|
"""Execute a code object.
|
|
335
|
"""Execute a code object.
|
|
336
|
|
|
336
|
|
|
337
|
Multithreaded wrapper around IPython's runcode()."""
|
|
337
|
Multithreaded wrapper around IPython's runcode()."""
|
|
338
|
|
|
338
|
|
|
339
|
# lock thread-protected stuff
|
|
339
|
# lock thread-protected stuff
|
|
340
|
got_lock = self.thread_ready.acquire(False)
|
|
340
|
got_lock = self.thread_ready.acquire(False)
|
|
341
|
|
|
341
|
|
|
342
|
# Install sigint handler
|
|
342
|
# Install sigint handler
|
|
343
|
try:
|
|
343
|
try:
|
|
344
|
signal.signal(signal.SIGINT, sigint_handler)
|
|
344
|
signal.signal(signal.SIGINT, sigint_handler)
|
|
345
|
except SystemError:
|
|
345
|
except SystemError:
|
|
346
|
# This happens under Windows, which seems to have all sorts
|
|
346
|
# This happens under Windows, which seems to have all sorts
|
|
347
|
# of problems with signal handling. Oh well...
|
|
347
|
# of problems with signal handling. Oh well...
|
|
348
|
pass
|
|
348
|
pass
|
|
349
|
|
|
349
|
|
|
350
|
if self._kill:
|
|
350
|
if self._kill:
|
|
351
|
print >>Term.cout, 'Closing threads...',
|
|
351
|
print >>Term.cout, 'Closing threads...',
|
|
352
|
Term.cout.flush()
|
|
352
|
Term.cout.flush()
|
|
353
|
for tokill in self.on_kill:
|
|
353
|
for tokill in self.on_kill:
|
|
354
|
tokill()
|
|
354
|
tokill()
|
|
355
|
print >>Term.cout, 'Done.'
|
|
355
|
print >>Term.cout, 'Done.'
|
|
356
|
|
|
356
|
|
|
357
|
# Flush queue of pending code by calling the run methood of the parent
|
|
357
|
# Flush queue of pending code by calling the run methood of the parent
|
|
358
|
# class with all items which may be in the queue.
|
|
358
|
# class with all items which may be in the queue.
|
|
359
|
while 1:
|
|
359
|
while 1:
|
|
360
|
try:
|
|
360
|
try:
|
|
361
|
code_to_run = self.code_queue.get_nowait()
|
|
361
|
code_to_run = self.code_queue.get_nowait()
|
|
362
|
except Queue.Empty:
|
|
362
|
except Queue.Empty:
|
|
363
|
break
|
|
363
|
break
|
|
364
|
self.thread_ready.notify()
|
|
364
|
if got_lock:
|
|
365
|
InteractiveShell.runcode(self,code_to_run)
|
|
365
|
self.thread_ready.notify()
|
|
|
|
|
366
|
InteractiveShell.runcode(self,code_to_run)
|
|
|
|
|
367
|
else:
|
|
|
|
|
368
|
break
|
|
366
|
|
|
369
|
|
|
367
|
# We're done with thread-protected variables
|
|
370
|
# We're done with thread-protected variables
|
|
368
|
if got_lock:
|
|
371
|
if got_lock:
|
|
369
|
self.thread_ready.release()
|
|
372
|
self.thread_ready.release()
|
|
370
|
# This MUST return true for gtk threading to work
|
|
373
|
# This MUST return true for gtk threading to work
|
|
371
|
return True
|
|
374
|
return True
|
|
372
|
|
|
375
|
|
|
373
|
def kill (self):
|
|
376
|
def kill(self):
|
|
374
|
"""Kill the thread, returning when it has been shut down."""
|
|
377
|
"""Kill the thread, returning when it has been shut down."""
|
|
375
|
self.thread_ready.acquire(False)
|
|
378
|
got_lock = self.thread_ready.acquire(False)
|
|
376
|
self._kill = True
|
|
379
|
self._kill = True
|
|
377
|
self.thread_ready.release()
|
|
380
|
if got_lock:
|
|
|
|
|
381
|
self.thread_ready.release()
|
|
378
|
|
|
382
|
|
|
379
|
class MatplotlibShellBase:
|
|
383
|
class MatplotlibShellBase:
|
|
380
|
"""Mixin class to provide the necessary modifications to regular IPython
|
|
384
|
"""Mixin class to provide the necessary modifications to regular IPython
|
|
381
|
shell classes for matplotlib support.
|
|
385
|
shell classes for matplotlib support.
|
|
382
|
|
|
386
|
|
|
383
|
Given Python's MRO, this should be used as the FIRST class in the
|
|
387
|
Given Python's MRO, this should be used as the FIRST class in the
|
|
384
|
inheritance hierarchy, so that it overrides the relevant methods."""
|
|
388
|
inheritance hierarchy, so that it overrides the relevant methods."""
|
|
385
|
|
|
389
|
|
|
386
|
def _matplotlib_config(self,name):
|
|
390
|
def _matplotlib_config(self,name):
|
|
387
|
"""Return items needed to setup the user's shell with matplotlib"""
|
|
391
|
"""Return items needed to setup the user's shell with matplotlib"""
|
|
388
|
|
|
392
|
|
|
389
|
# Initialize matplotlib to interactive mode always
|
|
393
|
# Initialize matplotlib to interactive mode always
|
|
390
|
import matplotlib
|
|
394
|
import matplotlib
|
|
391
|
from matplotlib import backends
|
|
395
|
from matplotlib import backends
|
|
392
|
matplotlib.interactive(True)
|
|
396
|
matplotlib.interactive(True)
|
|
393
|
|
|
397
|
|
|
394
|
def use(arg):
|
|
398
|
def use(arg):
|
|
395
|
"""IPython wrapper for matplotlib's backend switcher.
|
|
399
|
"""IPython wrapper for matplotlib's backend switcher.
|
|
396
|
|
|
400
|
|
|
397
|
In interactive use, we can not allow switching to a different
|
|
401
|
In interactive use, we can not allow switching to a different
|
|
398
|
interactive backend, since thread conflicts will most likely crash
|
|
402
|
interactive backend, since thread conflicts will most likely crash
|
|
399
|
the python interpreter. This routine does a safety check first,
|
|
403
|
the python interpreter. This routine does a safety check first,
|
|
400
|
and refuses to perform a dangerous switch. It still allows
|
|
404
|
and refuses to perform a dangerous switch. It still allows
|
|
401
|
switching to non-interactive backends."""
|
|
405
|
switching to non-interactive backends."""
|
|
402
|
|
|
406
|
|
|
403
|
if arg in backends.interactive_bk and arg != self.mpl_backend:
|
|
407
|
if arg in backends.interactive_bk and arg != self.mpl_backend:
|
|
404
|
m=('invalid matplotlib backend switch.\n'
|
|
408
|
m=('invalid matplotlib backend switch.\n'
|
|
405
|
'This script attempted to switch to the interactive '
|
|
409
|
'This script attempted to switch to the interactive '
|
|
406
|
'backend: `%s`\n'
|
|
410
|
'backend: `%s`\n'
|
|
407
|
'Your current choice of interactive backend is: `%s`\n\n'
|
|
411
|
'Your current choice of interactive backend is: `%s`\n\n'
|
|
408
|
'Switching interactive matplotlib backends at runtime\n'
|
|
412
|
'Switching interactive matplotlib backends at runtime\n'
|
|
409
|
'would crash the python interpreter, '
|
|
413
|
'would crash the python interpreter, '
|
|
410
|
'and IPython has blocked it.\n\n'
|
|
414
|
'and IPython has blocked it.\n\n'
|
|
411
|
'You need to either change your choice of matplotlib backend\n'
|
|
415
|
'You need to either change your choice of matplotlib backend\n'
|
|
412
|
'by editing your .matplotlibrc file, or run this script as a \n'
|
|
416
|
'by editing your .matplotlibrc file, or run this script as a \n'
|
|
413
|
'standalone file from the command line, not using IPython.\n' %
|
|
417
|
'standalone file from the command line, not using IPython.\n' %
|
|
414
|
(arg,self.mpl_backend) )
|
|
418
|
(arg,self.mpl_backend) )
|
|
415
|
raise RuntimeError, m
|
|
419
|
raise RuntimeError, m
|
|
416
|
else:
|
|
420
|
else:
|
|
417
|
self.mpl_use(arg)
|
|
421
|
self.mpl_use(arg)
|
|
418
|
self.mpl_use._called = True
|
|
422
|
self.mpl_use._called = True
|
|
419
|
|
|
423
|
|
|
420
|
self.matplotlib = matplotlib
|
|
424
|
self.matplotlib = matplotlib
|
|
421
|
self.mpl_backend = matplotlib.rcParams['backend']
|
|
425
|
self.mpl_backend = matplotlib.rcParams['backend']
|
|
422
|
|
|
426
|
|
|
423
|
# we also need to block switching of interactive backends by use()
|
|
427
|
# we also need to block switching of interactive backends by use()
|
|
424
|
self.mpl_use = matplotlib.use
|
|
428
|
self.mpl_use = matplotlib.use
|
|
425
|
self.mpl_use._called = False
|
|
429
|
self.mpl_use._called = False
|
|
426
|
# overwrite the original matplotlib.use with our wrapper
|
|
430
|
# overwrite the original matplotlib.use with our wrapper
|
|
427
|
matplotlib.use = use
|
|
431
|
matplotlib.use = use
|
|
428
|
|
|
432
|
|
|
429
|
# This must be imported last in the matplotlib series, after
|
|
433
|
# This must be imported last in the matplotlib series, after
|
|
430
|
# backend/interactivity choices have been made
|
|
434
|
# backend/interactivity choices have been made
|
|
431
|
try:
|
|
435
|
try:
|
|
432
|
import matplotlib.pylab as pylab
|
|
436
|
import matplotlib.pylab as pylab
|
|
433
|
self.pylab = pylab
|
|
437
|
self.pylab = pylab
|
|
434
|
self.pylab_name = 'pylab'
|
|
438
|
self.pylab_name = 'pylab'
|
|
435
|
except ImportError:
|
|
439
|
except ImportError:
|
|
436
|
import matplotlib.matlab as matlab
|
|
440
|
import matplotlib.matlab as matlab
|
|
437
|
self.pylab = matlab
|
|
441
|
self.pylab = matlab
|
|
438
|
self.pylab_name = 'matlab'
|
|
442
|
self.pylab_name = 'matlab'
|
|
439
|
|
|
443
|
|
|
440
|
self.pylab.show._needmain = False
|
|
444
|
self.pylab.show._needmain = False
|
|
441
|
# We need to detect at runtime whether show() is called by the user.
|
|
445
|
# We need to detect at runtime whether show() is called by the user.
|
|
442
|
# For this, we wrap it into a decorator which adds a 'called' flag.
|
|
446
|
# For this, we wrap it into a decorator which adds a 'called' flag.
|
|
443
|
self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
|
|
447
|
self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
|
|
444
|
|
|
448
|
|
|
445
|
# Build a user namespace initialized with matplotlib/matlab features.
|
|
449
|
# Build a user namespace initialized with matplotlib/matlab features.
|
|
446
|
user_ns = {'__name__':'__main__',
|
|
450
|
user_ns = {'__name__':'__main__',
|
|
447
|
'__builtins__' : __builtin__ }
|
|
451
|
'__builtins__' : __builtin__ }
|
|
448
|
|
|
452
|
|
|
449
|
# Be careful not to remove the final \n in the code string below, or
|
|
453
|
# Be careful not to remove the final \n in the code string below, or
|
|
450
|
# things will break badly with py22 (I think it's a python bug, 2.3 is
|
|
454
|
# things will break badly with py22 (I think it's a python bug, 2.3 is
|
|
451
|
# OK).
|
|
455
|
# OK).
|
|
452
|
pname = self.pylab_name # Python can't interpolate dotted var names
|
|
456
|
pname = self.pylab_name # Python can't interpolate dotted var names
|
|
453
|
exec ("import matplotlib\n"
|
|
457
|
exec ("import matplotlib\n"
|
|
454
|
"import matplotlib.%(pname)s as %(pname)s\n"
|
|
458
|
"import matplotlib.%(pname)s as %(pname)s\n"
|
|
455
|
"from matplotlib.%(pname)s import *\n" % locals()) in user_ns
|
|
459
|
"from matplotlib.%(pname)s import *\n" % locals()) in user_ns
|
|
456
|
|
|
460
|
|
|
457
|
# Build matplotlib info banner
|
|
461
|
# Build matplotlib info banner
|
|
458
|
b="""
|
|
462
|
b="""
|
|
459
|
Welcome to pylab, a matplotlib-based Python environment.
|
|
463
|
Welcome to pylab, a matplotlib-based Python environment.
|
|
460
|
For more information, type 'help(pylab)'.
|
|
464
|
For more information, type 'help(pylab)'.
|
|
461
|
"""
|
|
465
|
"""
|
|
462
|
return user_ns,b
|
|
466
|
return user_ns,b
|
|
463
|
|
|
467
|
|
|
464
|
def mplot_exec(self,fname,*where,**kw):
|
|
468
|
def mplot_exec(self,fname,*where,**kw):
|
|
465
|
"""Execute a matplotlib script.
|
|
469
|
"""Execute a matplotlib script.
|
|
466
|
|
|
470
|
|
|
467
|
This is a call to execfile(), but wrapped in safeties to properly
|
|
471
|
This is a call to execfile(), but wrapped in safeties to properly
|
|
468
|
handle interactive rendering and backend switching."""
|
|
472
|
handle interactive rendering and backend switching."""
|
|
469
|
|
|
473
|
|
|
470
|
#print '*** Matplotlib runner ***' # dbg
|
|
474
|
#print '*** Matplotlib runner ***' # dbg
|
|
471
|
# turn off rendering until end of script
|
|
475
|
# turn off rendering until end of script
|
|
472
|
isInteractive = self.matplotlib.rcParams['interactive']
|
|
476
|
isInteractive = self.matplotlib.rcParams['interactive']
|
|
473
|
self.matplotlib.interactive(False)
|
|
477
|
self.matplotlib.interactive(False)
|
|
474
|
self.safe_execfile(fname,*where,**kw)
|
|
478
|
self.safe_execfile(fname,*where,**kw)
|
|
475
|
self.matplotlib.interactive(isInteractive)
|
|
479
|
self.matplotlib.interactive(isInteractive)
|
|
476
|
# make rendering call now, if the user tried to do it
|
|
480
|
# make rendering call now, if the user tried to do it
|
|
477
|
if self.pylab.draw_if_interactive.called:
|
|
481
|
if self.pylab.draw_if_interactive.called:
|
|
478
|
self.pylab.draw()
|
|
482
|
self.pylab.draw()
|
|
479
|
self.pylab.draw_if_interactive.called = False
|
|
483
|
self.pylab.draw_if_interactive.called = False
|
|
480
|
|
|
484
|
|
|
481
|
# if a backend switch was performed, reverse it now
|
|
485
|
# if a backend switch was performed, reverse it now
|
|
482
|
if self.mpl_use._called:
|
|
486
|
if self.mpl_use._called:
|
|
483
|
self.matplotlib.rcParams['backend'] = self.mpl_backend
|
|
487
|
self.matplotlib.rcParams['backend'] = self.mpl_backend
|
|
484
|
|
|
488
|
|
|
485
|
def magic_run(self,parameter_s=''):
|
|
489
|
def magic_run(self,parameter_s=''):
|
|
486
|
Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
|
|
490
|
Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
|
|
487
|
|
|
491
|
|
|
488
|
# Fix the docstring so users see the original as well
|
|
492
|
# Fix the docstring so users see the original as well
|
|
489
|
magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
|
|
493
|
magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
|
|
490
|
"\n *** Modified %run for Matplotlib,"
|
|
494
|
"\n *** Modified %run for Matplotlib,"
|
|
491
|
" with proper interactive handling ***")
|
|
495
|
" with proper interactive handling ***")
|
|
492
|
|
|
496
|
|
|
493
|
# Now we provide 2 versions of a matplotlib-aware IPython base shells, single
|
|
497
|
# Now we provide 2 versions of a matplotlib-aware IPython base shells, single
|
|
494
|
# and multithreaded. Note that these are meant for internal use, the IPShell*
|
|
498
|
# and multithreaded. Note that these are meant for internal use, the IPShell*
|
|
495
|
# classes below are the ones meant for public consumption.
|
|
499
|
# classes below are the ones meant for public consumption.
|
|
496
|
|
|
500
|
|
|
497
|
class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
|
|
501
|
class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
|
|
498
|
"""Single-threaded shell with matplotlib support."""
|
|
502
|
"""Single-threaded shell with matplotlib support."""
|
|
499
|
|
|
503
|
|
|
500
|
def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
|
|
504
|
def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
|
|
501
|
user_ns=None,user_global_ns=None,**kw):
|
|
505
|
user_ns=None,user_global_ns=None,**kw):
|
|
502
|
user_ns,b2 = self._matplotlib_config(name)
|
|
506
|
user_ns,b2 = self._matplotlib_config(name)
|
|
503
|
InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
|
|
507
|
InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
|
|
504
|
banner2=b2,**kw)
|
|
508
|
banner2=b2,**kw)
|
|
505
|
|
|
509
|
|
|
506
|
class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
|
|
510
|
class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
|
|
507
|
"""Multi-threaded shell with matplotlib support."""
|
|
511
|
"""Multi-threaded shell with matplotlib support."""
|
|
508
|
|
|
512
|
|
|
509
|
def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
|
|
513
|
def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
|
|
510
|
user_ns=None,user_global_ns=None, **kw):
|
|
514
|
user_ns=None,user_global_ns=None, **kw):
|
|
511
|
user_ns,b2 = self._matplotlib_config(name)
|
|
515
|
user_ns,b2 = self._matplotlib_config(name)
|
|
512
|
MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
|
|
516
|
MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
|
|
513
|
banner2=b2,**kw)
|
|
517
|
banner2=b2,**kw)
|
|
514
|
|
|
518
|
|
|
515
|
#-----------------------------------------------------------------------------
|
|
519
|
#-----------------------------------------------------------------------------
|
|
516
|
# Utility functions for the different GUI enabled IPShell* classes.
|
|
520
|
# Utility functions for the different GUI enabled IPShell* classes.
|
|
517
|
|
|
521
|
|
|
518
|
def get_tk():
|
|
522
|
def get_tk():
|
|
519
|
"""Tries to import Tkinter and returns a withdrawn Tkinter root
|
|
523
|
"""Tries to import Tkinter and returns a withdrawn Tkinter root
|
|
520
|
window. If Tkinter is already imported or not available, this
|
|
524
|
window. If Tkinter is already imported or not available, this
|
|
521
|
returns None. This function calls `hijack_tk` underneath.
|
|
525
|
returns None. This function calls `hijack_tk` underneath.
|
|
522
|
"""
|
|
526
|
"""
|
|
523
|
if not USE_TK or sys.modules.has_key('Tkinter'):
|
|
527
|
if not USE_TK or sys.modules.has_key('Tkinter'):
|
|
524
|
return None
|
|
528
|
return None
|
|
525
|
else:
|
|
529
|
else:
|
|
526
|
try:
|
|
530
|
try:
|
|
527
|
import Tkinter
|
|
531
|
import Tkinter
|
|
528
|
except ImportError:
|
|
532
|
except ImportError:
|
|
529
|
return None
|
|
533
|
return None
|
|
530
|
else:
|
|
534
|
else:
|
|
531
|
hijack_tk()
|
|
535
|
hijack_tk()
|
|
532
|
r = Tkinter.Tk()
|
|
536
|
r = Tkinter.Tk()
|
|
533
|
r.withdraw()
|
|
537
|
r.withdraw()
|
|
534
|
return r
|
|
538
|
return r
|
|
535
|
|
|
539
|
|
|
536
|
def hijack_tk():
|
|
540
|
def hijack_tk():
|
|
537
|
"""Modifies Tkinter's mainloop with a dummy so when a module calls
|
|
541
|
"""Modifies Tkinter's mainloop with a dummy so when a module calls
|
|
538
|
mainloop, it does not block.
|
|
542
|
mainloop, it does not block.
|
|
539
|
|
|
543
|
|
|
540
|
"""
|
|
544
|
"""
|
|
541
|
def misc_mainloop(self, n=0):
|
|
545
|
def misc_mainloop(self, n=0):
|
|
542
|
pass
|
|
546
|
pass
|
|
543
|
def tkinter_mainloop(n=0):
|
|
547
|
def tkinter_mainloop(n=0):
|
|
544
|
pass
|
|
548
|
pass
|
|
545
|
|
|
549
|
|
|
546
|
import Tkinter
|
|
550
|
import Tkinter
|
|
547
|
Tkinter.Misc.mainloop = misc_mainloop
|
|
551
|
Tkinter.Misc.mainloop = misc_mainloop
|
|
548
|
Tkinter.mainloop = tkinter_mainloop
|
|
552
|
Tkinter.mainloop = tkinter_mainloop
|
|
549
|
|
|
553
|
|
|
550
|
def update_tk(tk):
|
|
554
|
def update_tk(tk):
|
|
551
|
"""Updates the Tkinter event loop. This is typically called from
|
|
555
|
"""Updates the Tkinter event loop. This is typically called from
|
|
552
|
the respective WX or GTK mainloops.
|
|
556
|
the respective WX or GTK mainloops.
|
|
553
|
"""
|
|
557
|
"""
|
|
554
|
if tk:
|
|
558
|
if tk:
|
|
555
|
tk.update()
|
|
559
|
tk.update()
|
|
556
|
|
|
560
|
|
|
557
|
def hijack_wx():
|
|
561
|
def hijack_wx():
|
|
558
|
"""Modifies wxPython's MainLoop with a dummy so user code does not
|
|
562
|
"""Modifies wxPython's MainLoop with a dummy so user code does not
|
|
559
|
block IPython. The hijacked mainloop function is returned.
|
|
563
|
block IPython. The hijacked mainloop function is returned.
|
|
560
|
"""
|
|
564
|
"""
|
|
561
|
def dummy_mainloop(*args, **kw):
|
|
565
|
def dummy_mainloop(*args, **kw):
|
|
562
|
pass
|
|
566
|
pass
|
|
563
|
import wxPython
|
|
567
|
import wxPython
|
|
564
|
ver = wxPython.__version__
|
|
568
|
ver = wxPython.__version__
|
|
565
|
orig_mainloop = None
|
|
569
|
orig_mainloop = None
|
|
566
|
if ver[:3] >= '2.5':
|
|
570
|
if ver[:3] >= '2.5':
|
|
567
|
import wx
|
|
571
|
import wx
|
|
568
|
if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
|
|
572
|
if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
|
|
569
|
elif hasattr(wx, '_core'): core = getattr(wx, '_core')
|
|
573
|
elif hasattr(wx, '_core'): core = getattr(wx, '_core')
|
|
570
|
else: raise AttributeError('Could not find wx core module')
|
|
574
|
else: raise AttributeError('Could not find wx core module')
|
|
571
|
orig_mainloop = core.PyApp_MainLoop
|
|
575
|
orig_mainloop = core.PyApp_MainLoop
|
|
572
|
core.PyApp_MainLoop = dummy_mainloop
|
|
576
|
core.PyApp_MainLoop = dummy_mainloop
|
|
573
|
elif ver[:3] == '2.4':
|
|
577
|
elif ver[:3] == '2.4':
|
|
574
|
orig_mainloop = wxPython.wxc.wxPyApp_MainLoop
|
|
578
|
orig_mainloop = wxPython.wxc.wxPyApp_MainLoop
|
|
575
|
wxPython.wxc.wxPyApp_MainLoop = dummy_mainloop
|
|
579
|
wxPython.wxc.wxPyApp_MainLoop = dummy_mainloop
|
|
576
|
else:
|
|
580
|
else:
|
|
577
|
warn("Unable to find either wxPython version 2.4 or >= 2.5.")
|
|
581
|
warn("Unable to find either wxPython version 2.4 or >= 2.5.")
|
|
578
|
return orig_mainloop
|
|
582
|
return orig_mainloop
|
|
579
|
|
|
583
|
|
|
580
|
def hijack_gtk():
|
|
584
|
def hijack_gtk():
|
|
581
|
"""Modifies pyGTK's mainloop with a dummy so user code does not
|
|
585
|
"""Modifies pyGTK's mainloop with a dummy so user code does not
|
|
582
|
block IPython. This function returns the original `gtk.mainloop`
|
|
586
|
block IPython. This function returns the original `gtk.mainloop`
|
|
583
|
function that has been hijacked.
|
|
587
|
function that has been hijacked.
|
|
584
|
"""
|
|
588
|
"""
|
|
585
|
def dummy_mainloop(*args, **kw):
|
|
589
|
def dummy_mainloop(*args, **kw):
|
|
586
|
pass
|
|
590
|
pass
|
|
587
|
import gtk
|
|
591
|
import gtk
|
|
588
|
if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
|
|
592
|
if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
|
|
589
|
else: orig_mainloop = gtk.mainloop
|
|
593
|
else: orig_mainloop = gtk.mainloop
|
|
590
|
gtk.mainloop = dummy_mainloop
|
|
594
|
gtk.mainloop = dummy_mainloop
|
|
591
|
gtk.main = dummy_mainloop
|
|
595
|
gtk.main = dummy_mainloop
|
|
592
|
return orig_mainloop
|
|
596
|
return orig_mainloop
|
|
593
|
|
|
597
|
|
|
594
|
#-----------------------------------------------------------------------------
|
|
598
|
#-----------------------------------------------------------------------------
|
|
595
|
# The IPShell* classes below are the ones meant to be run by external code as
|
|
599
|
# The IPShell* classes below are the ones meant to be run by external code as
|
|
596
|
# IPython instances. Note that unless a specific threading strategy is
|
|
600
|
# IPython instances. Note that unless a specific threading strategy is
|
|
597
|
# desired, the factory function start() below should be used instead (it
|
|
601
|
# desired, the factory function start() below should be used instead (it
|
|
598
|
# selects the proper threaded class).
|
|
602
|
# selects the proper threaded class).
|
|
599
|
|
|
603
|
|
|
600
|
class IPShellGTK(threading.Thread):
|
|
604
|
class IPShellGTK(threading.Thread):
|
|
601
|
"""Run a gtk mainloop() in a separate thread.
|
|
605
|
"""Run a gtk mainloop() in a separate thread.
|
|
602
|
|
|
606
|
|
|
603
|
Python commands can be passed to the thread where they will be executed.
|
|
607
|
Python commands can be passed to the thread where they will be executed.
|
|
604
|
This is implemented by periodically checking for passed code using a
|
|
608
|
This is implemented by periodically checking for passed code using a
|
|
605
|
GTK timeout callback."""
|
|
609
|
GTK timeout callback."""
|
|
606
|
|
|
610
|
|
|
607
|
TIMEOUT = 100 # Millisecond interval between timeouts.
|
|
611
|
TIMEOUT = 100 # Millisecond interval between timeouts.
|
|
608
|
|
|
612
|
|
|
609
|
def __init__(self,argv=None,user_ns=None,user_global_ns=None,
|
|
613
|
def __init__(self,argv=None,user_ns=None,user_global_ns=None,
|
|
610
|
debug=1,shell_class=MTInteractiveShell):
|
|
614
|
debug=1,shell_class=MTInteractiveShell):
|
|
611
|
|
|
615
|
|
|
612
|
import gtk
|
|
616
|
import gtk
|
|
613
|
|
|
617
|
|
|
614
|
self.gtk = gtk
|
|
618
|
self.gtk = gtk
|
|
615
|
self.gtk_mainloop = hijack_gtk()
|
|
619
|
self.gtk_mainloop = hijack_gtk()
|
|
616
|
|
|
620
|
|
|
617
|
# Allows us to use both Tk and GTK.
|
|
621
|
# Allows us to use both Tk and GTK.
|
|
618
|
self.tk = get_tk()
|
|
622
|