##// END OF EJS Templates
Backport PR #4158: generate choices for `--gui` configurable from real mapping...
MinRK -
Show More
@@ -1,406 +1,409 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A mixin for :class:`~IPython.core.application.Application` classes that
3 A mixin for :class:`~IPython.core.application.Application` classes that
4 launch InteractiveShell instances, load extensions, etc.
4 launch InteractiveShell instances, load extensions, etc.
5
5
6 Authors
6 Authors
7 -------
7 -------
8
8
9 * Min Ragan-Kelley
9 * Min Ragan-Kelley
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2011 The IPython Development Team
13 # Copyright (C) 2008-2011 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 from __future__ import absolute_import
23 from __future__ import absolute_import
24
24
25 import glob
25 import glob
26 import os
26 import os
27 import sys
27 import sys
28
28
29 from IPython.config.application import boolean_flag
29 from IPython.config.application import boolean_flag
30 from IPython.config.configurable import Configurable
30 from IPython.config.configurable import Configurable
31 from IPython.config.loader import Config
31 from IPython.config.loader import Config
32 from IPython.core import pylabtools
32 from IPython.core import pylabtools
33 from IPython.utils import py3compat
33 from IPython.utils import py3compat
34 from IPython.utils.contexts import preserve_keys
34 from IPython.utils.contexts import preserve_keys
35 from IPython.utils.path import filefind
35 from IPython.utils.path import filefind
36 from IPython.utils.traitlets import (
36 from IPython.utils.traitlets import (
37 Unicode, Instance, List, Bool, CaselessStrEnum, Dict
37 Unicode, Instance, List, Bool, CaselessStrEnum, Dict
38 )
38 )
39 from IPython.lib.inputhook import guis
39
40
40 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
41 # Aliases and Flags
42 # Aliases and Flags
42 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
43
44
45 gui_keys = tuple(sorted([ key for key in guis if key is not None ]))
46
44 backend_keys = sorted(pylabtools.backends.keys())
47 backend_keys = sorted(pylabtools.backends.keys())
45 backend_keys.insert(0, 'auto')
48 backend_keys.insert(0, 'auto')
46
49
47 shell_flags = {}
50 shell_flags = {}
48
51
49 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
52 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
50 addflag('autoindent', 'InteractiveShell.autoindent',
53 addflag('autoindent', 'InteractiveShell.autoindent',
51 'Turn on autoindenting.', 'Turn off autoindenting.'
54 'Turn on autoindenting.', 'Turn off autoindenting.'
52 )
55 )
53 addflag('automagic', 'InteractiveShell.automagic',
56 addflag('automagic', 'InteractiveShell.automagic',
54 """Turn on the auto calling of magic commands. Type %%magic at the
57 """Turn on the auto calling of magic commands. Type %%magic at the
55 IPython prompt for more information.""",
58 IPython prompt for more information.""",
56 'Turn off the auto calling of magic commands.'
59 'Turn off the auto calling of magic commands.'
57 )
60 )
58 addflag('pdb', 'InteractiveShell.pdb',
61 addflag('pdb', 'InteractiveShell.pdb',
59 "Enable auto calling the pdb debugger after every exception.",
62 "Enable auto calling the pdb debugger after every exception.",
60 "Disable auto calling the pdb debugger after every exception."
63 "Disable auto calling the pdb debugger after every exception."
61 )
64 )
62 # pydb flag doesn't do any config, as core.debugger switches on import,
65 # pydb flag doesn't do any config, as core.debugger switches on import,
63 # which is before parsing. This just allows the flag to be passed.
66 # which is before parsing. This just allows the flag to be passed.
64 shell_flags.update(dict(
67 shell_flags.update(dict(
65 pydb = ({},
68 pydb = ({},
66 """Use the third party 'pydb' package as debugger, instead of pdb.
69 """Use the third party 'pydb' package as debugger, instead of pdb.
67 Requires that pydb is installed."""
70 Requires that pydb is installed."""
68 )
71 )
69 ))
72 ))
70 addflag('pprint', 'PlainTextFormatter.pprint',
73 addflag('pprint', 'PlainTextFormatter.pprint',
71 "Enable auto pretty printing of results.",
74 "Enable auto pretty printing of results.",
72 "Disable auto pretty printing of results."
75 "Disable auto pretty printing of results."
73 )
76 )
74 addflag('color-info', 'InteractiveShell.color_info',
77 addflag('color-info', 'InteractiveShell.color_info',
75 """IPython can display information about objects via a set of func-
78 """IPython can display information about objects via a set of func-
76 tions, and optionally can use colors for this, syntax highlighting
79 tions, and optionally can use colors for this, syntax highlighting
77 source code and various other elements. However, because this
80 source code and various other elements. However, because this
78 information is passed through a pager (like 'less') and many pagers get
81 information is passed through a pager (like 'less') and many pagers get
79 confused with color codes, this option is off by default. You can test
82 confused with color codes, this option is off by default. You can test
80 it and turn it on permanently in your ipython_config.py file if it
83 it and turn it on permanently in your ipython_config.py file if it
81 works for you. Test it and turn it on permanently if it works with
84 works for you. Test it and turn it on permanently if it works with
82 your system. The magic function %%color_info allows you to toggle this
85 your system. The magic function %%color_info allows you to toggle this
83 interactively for testing.""",
86 interactively for testing.""",
84 "Disable using colors for info related things."
87 "Disable using colors for info related things."
85 )
88 )
86 addflag('deep-reload', 'InteractiveShell.deep_reload',
89 addflag('deep-reload', 'InteractiveShell.deep_reload',
87 """Enable deep (recursive) reloading by default. IPython can use the
90 """Enable deep (recursive) reloading by default. IPython can use the
88 deep_reload module which reloads changes in modules recursively (it
91 deep_reload module which reloads changes in modules recursively (it
89 replaces the reload() function, so you don't need to change anything to
92 replaces the reload() function, so you don't need to change anything to
90 use it). deep_reload() forces a full reload of modules whose code may
93 use it). deep_reload() forces a full reload of modules whose code may
91 have changed, which the default reload() function does not. When
94 have changed, which the default reload() function does not. When
92 deep_reload is off, IPython will use the normal reload(), but
95 deep_reload is off, IPython will use the normal reload(), but
93 deep_reload will still be available as dreload(). This feature is off
96 deep_reload will still be available as dreload(). This feature is off
94 by default [which means that you have both normal reload() and
97 by default [which means that you have both normal reload() and
95 dreload()].""",
98 dreload()].""",
96 "Disable deep (recursive) reloading by default."
99 "Disable deep (recursive) reloading by default."
97 )
100 )
98 nosep_config = Config()
101 nosep_config = Config()
99 nosep_config.InteractiveShell.separate_in = ''
102 nosep_config.InteractiveShell.separate_in = ''
100 nosep_config.InteractiveShell.separate_out = ''
103 nosep_config.InteractiveShell.separate_out = ''
101 nosep_config.InteractiveShell.separate_out2 = ''
104 nosep_config.InteractiveShell.separate_out2 = ''
102
105
103 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
106 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
104 shell_flags['pylab'] = (
107 shell_flags['pylab'] = (
105 {'InteractiveShellApp' : {'pylab' : 'auto'}},
108 {'InteractiveShellApp' : {'pylab' : 'auto'}},
106 """Pre-load matplotlib and numpy for interactive use with
109 """Pre-load matplotlib and numpy for interactive use with
107 the default matplotlib backend."""
110 the default matplotlib backend."""
108 )
111 )
109 shell_flags['matplotlib'] = (
112 shell_flags['matplotlib'] = (
110 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
113 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
111 """Configure matplotlib for interactive use with
114 """Configure matplotlib for interactive use with
112 the default matplotlib backend."""
115 the default matplotlib backend."""
113 )
116 )
114
117
115 # it's possible we don't want short aliases for *all* of these:
118 # it's possible we don't want short aliases for *all* of these:
116 shell_aliases = dict(
119 shell_aliases = dict(
117 autocall='InteractiveShell.autocall',
120 autocall='InteractiveShell.autocall',
118 colors='InteractiveShell.colors',
121 colors='InteractiveShell.colors',
119 logfile='InteractiveShell.logfile',
122 logfile='InteractiveShell.logfile',
120 logappend='InteractiveShell.logappend',
123 logappend='InteractiveShell.logappend',
121 c='InteractiveShellApp.code_to_run',
124 c='InteractiveShellApp.code_to_run',
122 m='InteractiveShellApp.module_to_run',
125 m='InteractiveShellApp.module_to_run',
123 ext='InteractiveShellApp.extra_extension',
126 ext='InteractiveShellApp.extra_extension',
124 gui='InteractiveShellApp.gui',
127 gui='InteractiveShellApp.gui',
125 pylab='InteractiveShellApp.pylab',
128 pylab='InteractiveShellApp.pylab',
126 matplotlib='InteractiveShellApp.matplotlib',
129 matplotlib='InteractiveShellApp.matplotlib',
127 )
130 )
128 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
131 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
129
132
130 #-----------------------------------------------------------------------------
133 #-----------------------------------------------------------------------------
131 # Main classes and functions
134 # Main classes and functions
132 #-----------------------------------------------------------------------------
135 #-----------------------------------------------------------------------------
133
136
134 class InteractiveShellApp(Configurable):
137 class InteractiveShellApp(Configurable):
135 """A Mixin for applications that start InteractiveShell instances.
138 """A Mixin for applications that start InteractiveShell instances.
136
139
137 Provides configurables for loading extensions and executing files
140 Provides configurables for loading extensions and executing files
138 as part of configuring a Shell environment.
141 as part of configuring a Shell environment.
139
142
140 The following methods should be called by the :meth:`initialize` method
143 The following methods should be called by the :meth:`initialize` method
141 of the subclass:
144 of the subclass:
142
145
143 - :meth:`init_path`
146 - :meth:`init_path`
144 - :meth:`init_shell` (to be implemented by the subclass)
147 - :meth:`init_shell` (to be implemented by the subclass)
145 - :meth:`init_gui_pylab`
148 - :meth:`init_gui_pylab`
146 - :meth:`init_extensions`
149 - :meth:`init_extensions`
147 - :meth:`init_code`
150 - :meth:`init_code`
148 """
151 """
149 extensions = List(Unicode, config=True,
152 extensions = List(Unicode, config=True,
150 help="A list of dotted module names of IPython extensions to load."
153 help="A list of dotted module names of IPython extensions to load."
151 )
154 )
152 extra_extension = Unicode('', config=True,
155 extra_extension = Unicode('', config=True,
153 help="dotted module name of an IPython extension to load."
156 help="dotted module name of an IPython extension to load."
154 )
157 )
155 def _extra_extension_changed(self, name, old, new):
158 def _extra_extension_changed(self, name, old, new):
156 if new:
159 if new:
157 # add to self.extensions
160 # add to self.extensions
158 self.extensions.append(new)
161 self.extensions.append(new)
159
162
160 # Extensions that are always loaded (not configurable)
163 # Extensions that are always loaded (not configurable)
161 default_extensions = List(Unicode, [u'storemagic'], config=False)
164 default_extensions = List(Unicode, [u'storemagic'], config=False)
162
165
163 exec_files = List(Unicode, config=True,
166 exec_files = List(Unicode, config=True,
164 help="""List of files to run at IPython startup."""
167 help="""List of files to run at IPython startup."""
165 )
168 )
166 file_to_run = Unicode('', config=True,
169 file_to_run = Unicode('', config=True,
167 help="""A file to be run""")
170 help="""A file to be run""")
168
171
169 exec_lines = List(Unicode, config=True,
172 exec_lines = List(Unicode, config=True,
170 help="""lines of code to run at IPython startup."""
173 help="""lines of code to run at IPython startup."""
171 )
174 )
172 code_to_run = Unicode('', config=True,
175 code_to_run = Unicode('', config=True,
173 help="Execute the given command string."
176 help="Execute the given command string."
174 )
177 )
175 module_to_run = Unicode('', config=True,
178 module_to_run = Unicode('', config=True,
176 help="Run the module as a script."
179 help="Run the module as a script."
177 )
180 )
178 gui = CaselessStrEnum(('qt', 'wx', 'gtk', 'glut', 'pyglet', 'osx'), config=True,
181 gui = CaselessStrEnum(gui_keys, config=True,
179 help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'glut', 'pyglet', 'osx')."
182 help="Enable GUI event loop integration with any of {0}.".format(gui_keys)
180 )
183 )
181 matplotlib = CaselessStrEnum(backend_keys,
184 matplotlib = CaselessStrEnum(backend_keys,
182 config=True,
185 config=True,
183 help="""Configure matplotlib for interactive use with
186 help="""Configure matplotlib for interactive use with
184 the default matplotlib backend."""
187 the default matplotlib backend."""
185 )
188 )
186 pylab = CaselessStrEnum(backend_keys,
189 pylab = CaselessStrEnum(backend_keys,
187 config=True,
190 config=True,
188 help="""Pre-load matplotlib and numpy for interactive use,
191 help="""Pre-load matplotlib and numpy for interactive use,
189 selecting a particular matplotlib backend and loop integration.
192 selecting a particular matplotlib backend and loop integration.
190 """
193 """
191 )
194 )
192 pylab_import_all = Bool(True, config=True,
195 pylab_import_all = Bool(True, config=True,
193 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
196 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
194 and an 'import *' is done from numpy and pylab, when using pylab mode.
197 and an 'import *' is done from numpy and pylab, when using pylab mode.
195
198
196 When False, pylab mode should not import any names into the user namespace.
199 When False, pylab mode should not import any names into the user namespace.
197 """
200 """
198 )
201 )
199 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
202 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
200
203
201 user_ns = Dict(default_value=None)
204 user_ns = Dict(default_value=None)
202 def _user_ns_changed(self, name, old, new):
205 def _user_ns_changed(self, name, old, new):
203 if self.shell is not None:
206 if self.shell is not None:
204 self.shell.user_ns = new
207 self.shell.user_ns = new
205 self.shell.init_user_ns()
208 self.shell.init_user_ns()
206
209
207 def init_path(self):
210 def init_path(self):
208 """Add current working directory, '', to sys.path"""
211 """Add current working directory, '', to sys.path"""
209 if sys.path[0] != '':
212 if sys.path[0] != '':
210 sys.path.insert(0, '')
213 sys.path.insert(0, '')
211
214
212 def init_shell(self):
215 def init_shell(self):
213 raise NotImplementedError("Override in subclasses")
216 raise NotImplementedError("Override in subclasses")
214
217
215 def init_gui_pylab(self):
218 def init_gui_pylab(self):
216 """Enable GUI event loop integration, taking pylab into account."""
219 """Enable GUI event loop integration, taking pylab into account."""
217 enable = False
220 enable = False
218 shell = self.shell
221 shell = self.shell
219 if self.pylab:
222 if self.pylab:
220 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
223 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
221 key = self.pylab
224 key = self.pylab
222 elif self.matplotlib:
225 elif self.matplotlib:
223 enable = shell.enable_matplotlib
226 enable = shell.enable_matplotlib
224 key = self.matplotlib
227 key = self.matplotlib
225 elif self.gui:
228 elif self.gui:
226 enable = shell.enable_gui
229 enable = shell.enable_gui
227 key = self.gui
230 key = self.gui
228
231
229 if not enable:
232 if not enable:
230 return
233 return
231
234
232 try:
235 try:
233 r = enable(key)
236 r = enable(key)
234 except ImportError:
237 except ImportError:
235 self.log.warn("Eventloop or matplotlib integration failed. Is matplotlib installed?")
238 self.log.warn("Eventloop or matplotlib integration failed. Is matplotlib installed?")
236 self.shell.showtraceback()
239 self.shell.showtraceback()
237 return
240 return
238 except Exception:
241 except Exception:
239 self.log.warn("GUI event loop or pylab initialization failed")
242 self.log.warn("GUI event loop or pylab initialization failed")
240 self.shell.showtraceback()
243 self.shell.showtraceback()
241 return
244 return
242
245
243 if isinstance(r, tuple):
246 if isinstance(r, tuple):
244 gui, backend = r[:2]
247 gui, backend = r[:2]
245 self.log.info("Enabling GUI event loop integration, "
248 self.log.info("Enabling GUI event loop integration, "
246 "eventloop=%s, matplotlib=%s", gui, backend)
249 "eventloop=%s, matplotlib=%s", gui, backend)
247 if key == "auto":
250 if key == "auto":
248 print ("Using matplotlib backend: %s" % backend)
251 print ("Using matplotlib backend: %s" % backend)
249 else:
252 else:
250 gui = r
253 gui = r
251 self.log.info("Enabling GUI event loop integration, "
254 self.log.info("Enabling GUI event loop integration, "
252 "eventloop=%s", gui)
255 "eventloop=%s", gui)
253
256
254 def init_extensions(self):
257 def init_extensions(self):
255 """Load all IPython extensions in IPythonApp.extensions.
258 """Load all IPython extensions in IPythonApp.extensions.
256
259
257 This uses the :meth:`ExtensionManager.load_extensions` to load all
260 This uses the :meth:`ExtensionManager.load_extensions` to load all
258 the extensions listed in ``self.extensions``.
261 the extensions listed in ``self.extensions``.
259 """
262 """
260 try:
263 try:
261 self.log.debug("Loading IPython extensions...")
264 self.log.debug("Loading IPython extensions...")
262 extensions = self.default_extensions + self.extensions
265 extensions = self.default_extensions + self.extensions
263 for ext in extensions:
266 for ext in extensions:
264 try:
267 try:
265 self.log.info("Loading IPython extension: %s" % ext)
268 self.log.info("Loading IPython extension: %s" % ext)
266 self.shell.extension_manager.load_extension(ext)
269 self.shell.extension_manager.load_extension(ext)
267 except:
270 except:
268 self.log.warn("Error in loading extension: %s" % ext +
271 self.log.warn("Error in loading extension: %s" % ext +
269 "\nCheck your config files in %s" % self.profile_dir.location
272 "\nCheck your config files in %s" % self.profile_dir.location
270 )
273 )
271 self.shell.showtraceback()
274 self.shell.showtraceback()
272 except:
275 except:
273 self.log.warn("Unknown error in loading extensions:")
276 self.log.warn("Unknown error in loading extensions:")
274 self.shell.showtraceback()
277 self.shell.showtraceback()
275
278
276 def init_code(self):
279 def init_code(self):
277 """run the pre-flight code, specified via exec_lines"""
280 """run the pre-flight code, specified via exec_lines"""
278 self._run_startup_files()
281 self._run_startup_files()
279 self._run_exec_lines()
282 self._run_exec_lines()
280 self._run_exec_files()
283 self._run_exec_files()
281 self._run_cmd_line_code()
284 self._run_cmd_line_code()
282 self._run_module()
285 self._run_module()
283
286
284 # flush output, so itwon't be attached to the first cell
287 # flush output, so itwon't be attached to the first cell
285 sys.stdout.flush()
288 sys.stdout.flush()
286 sys.stderr.flush()
289 sys.stderr.flush()
287
290
288 # Hide variables defined here from %who etc.
291 # Hide variables defined here from %who etc.
289 self.shell.user_ns_hidden.update(self.shell.user_ns)
292 self.shell.user_ns_hidden.update(self.shell.user_ns)
290
293
291 def _run_exec_lines(self):
294 def _run_exec_lines(self):
292 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
295 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
293 if not self.exec_lines:
296 if not self.exec_lines:
294 return
297 return
295 try:
298 try:
296 self.log.debug("Running code from IPythonApp.exec_lines...")
299 self.log.debug("Running code from IPythonApp.exec_lines...")
297 for line in self.exec_lines:
300 for line in self.exec_lines:
298 try:
301 try:
299 self.log.info("Running code in user namespace: %s" %
302 self.log.info("Running code in user namespace: %s" %
300 line)
303 line)
301 self.shell.run_cell(line, store_history=False)
304 self.shell.run_cell(line, store_history=False)
302 except:
305 except:
303 self.log.warn("Error in executing line in user "
306 self.log.warn("Error in executing line in user "
304 "namespace: %s" % line)
307 "namespace: %s" % line)
305 self.shell.showtraceback()
308 self.shell.showtraceback()
306 except:
309 except:
307 self.log.warn("Unknown error in handling IPythonApp.exec_lines:")
310 self.log.warn("Unknown error in handling IPythonApp.exec_lines:")
308 self.shell.showtraceback()
311 self.shell.showtraceback()
309
312
310 def _exec_file(self, fname):
313 def _exec_file(self, fname):
311 try:
314 try:
312 full_filename = filefind(fname, [u'.', self.ipython_dir])
315 full_filename = filefind(fname, [u'.', self.ipython_dir])
313 except IOError as e:
316 except IOError as e:
314 self.log.warn("File not found: %r"%fname)
317 self.log.warn("File not found: %r"%fname)
315 return
318 return
316 # Make sure that the running script gets a proper sys.argv as if it
319 # Make sure that the running script gets a proper sys.argv as if it
317 # were run from a system shell.
320 # were run from a system shell.
318 save_argv = sys.argv
321 save_argv = sys.argv
319 sys.argv = [full_filename] + self.extra_args[1:]
322 sys.argv = [full_filename] + self.extra_args[1:]
320 # protect sys.argv from potential unicode strings on Python 2:
323 # protect sys.argv from potential unicode strings on Python 2:
321 if not py3compat.PY3:
324 if not py3compat.PY3:
322 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
325 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
323 try:
326 try:
324 if os.path.isfile(full_filename):
327 if os.path.isfile(full_filename):
325 self.log.info("Running file in user namespace: %s" %
328 self.log.info("Running file in user namespace: %s" %
326 full_filename)
329 full_filename)
327 # Ensure that __file__ is always defined to match Python
330 # Ensure that __file__ is always defined to match Python
328 # behavior.
331 # behavior.
329 with preserve_keys(self.shell.user_ns, '__file__'):
332 with preserve_keys(self.shell.user_ns, '__file__'):
330 self.shell.user_ns['__file__'] = fname
333 self.shell.user_ns['__file__'] = fname
331 if full_filename.endswith('.ipy'):
334 if full_filename.endswith('.ipy'):
332 self.shell.safe_execfile_ipy(full_filename)
335 self.shell.safe_execfile_ipy(full_filename)
333 else:
336 else:
334 # default to python, even without extension
337 # default to python, even without extension
335 self.shell.safe_execfile(full_filename,
338 self.shell.safe_execfile(full_filename,
336 self.shell.user_ns)
339 self.shell.user_ns)
337 finally:
340 finally:
338 sys.argv = save_argv
341 sys.argv = save_argv
339
342
340 def _run_startup_files(self):
343 def _run_startup_files(self):
341 """Run files from profile startup directory"""
344 """Run files from profile startup directory"""
342 startup_dir = self.profile_dir.startup_dir
345 startup_dir = self.profile_dir.startup_dir
343 startup_files = []
346 startup_files = []
344 if os.environ.get('PYTHONSTARTUP', False):
347 if os.environ.get('PYTHONSTARTUP', False):
345 startup_files.append(os.environ['PYTHONSTARTUP'])
348 startup_files.append(os.environ['PYTHONSTARTUP'])
346 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
349 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
347 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
350 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
348 if not startup_files:
351 if not startup_files:
349 return
352 return
350
353
351 self.log.debug("Running startup files from %s...", startup_dir)
354 self.log.debug("Running startup files from %s...", startup_dir)
352 try:
355 try:
353 for fname in sorted(startup_files):
356 for fname in sorted(startup_files):
354 self._exec_file(fname)
357 self._exec_file(fname)
355 except:
358 except:
356 self.log.warn("Unknown error in handling startup files:")
359 self.log.warn("Unknown error in handling startup files:")
357 self.shell.showtraceback()
360 self.shell.showtraceback()
358
361
359 def _run_exec_files(self):
362 def _run_exec_files(self):
360 """Run files from IPythonApp.exec_files"""
363 """Run files from IPythonApp.exec_files"""
361 if not self.exec_files:
364 if not self.exec_files:
362 return
365 return
363
366
364 self.log.debug("Running files in IPythonApp.exec_files...")
367 self.log.debug("Running files in IPythonApp.exec_files...")
365 try:
368 try:
366 for fname in self.exec_files:
369 for fname in self.exec_files:
367 self._exec_file(fname)
370 self._exec_file(fname)
368 except:
371 except:
369 self.log.warn("Unknown error in handling IPythonApp.exec_files:")
372 self.log.warn("Unknown error in handling IPythonApp.exec_files:")
370 self.shell.showtraceback()
373 self.shell.showtraceback()
371
374
372 def _run_cmd_line_code(self):
375 def _run_cmd_line_code(self):
373 """Run code or file specified at the command-line"""
376 """Run code or file specified at the command-line"""
374 if self.code_to_run:
377 if self.code_to_run:
375 line = self.code_to_run
378 line = self.code_to_run
376 try:
379 try:
377 self.log.info("Running code given at command line (c=): %s" %
380 self.log.info("Running code given at command line (c=): %s" %
378 line)
381 line)
379 self.shell.run_cell(line, store_history=False)
382 self.shell.run_cell(line, store_history=False)
380 except:
383 except:
381 self.log.warn("Error in executing line in user namespace: %s" %
384 self.log.warn("Error in executing line in user namespace: %s" %
382 line)
385 line)
383 self.shell.showtraceback()
386 self.shell.showtraceback()
384
387
385 # Like Python itself, ignore the second if the first of these is present
388 # Like Python itself, ignore the second if the first of these is present
386 elif self.file_to_run:
389 elif self.file_to_run:
387 fname = self.file_to_run
390 fname = self.file_to_run
388 try:
391 try:
389 self._exec_file(fname)
392 self._exec_file(fname)
390 except:
393 except:
391 self.log.warn("Error in executing file in user namespace: %s" %
394 self.log.warn("Error in executing file in user namespace: %s" %
392 fname)
395 fname)
393 self.shell.showtraceback()
396 self.shell.showtraceback()
394
397
395 def _run_module(self):
398 def _run_module(self):
396 """Run module specified at the command-line."""
399 """Run module specified at the command-line."""
397 if self.module_to_run:
400 if self.module_to_run:
398 # Make sure that the module gets a proper sys.argv as if it were
401 # Make sure that the module gets a proper sys.argv as if it were
399 # run using `python -m`.
402 # run using `python -m`.
400 save_argv = sys.argv
403 save_argv = sys.argv
401 sys.argv = [sys.executable] + self.extra_args
404 sys.argv = [sys.executable] + self.extra_args
402 try:
405 try:
403 self.shell.safe_run_module(self.module_to_run,
406 self.shell.safe_run_module(self.module_to_run,
404 self.shell.user_ns)
407 self.shell.user_ns)
405 finally:
408 finally:
406 sys.argv = save_argv
409 sys.argv = save_argv
@@ -1,528 +1,529 b''
1 # coding: utf-8
1 # coding: utf-8
2 """
2 """
3 Inputhook management for GUI event loop integration.
3 Inputhook management for GUI event loop integration.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 try:
17 try:
18 import ctypes
18 import ctypes
19 except ImportError:
19 except ImportError:
20 ctypes = None
20 ctypes = None
21 import os
21 import os
22 import sys
22 import sys
23 from distutils.version import LooseVersion as V
23 from distutils.version import LooseVersion as V
24
24
25 from IPython.utils.warn import warn
25 from IPython.utils.warn import warn
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Constants
28 # Constants
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 # Constants for identifying the GUI toolkits.
31 # Constants for identifying the GUI toolkits.
32 GUI_WX = 'wx'
32 GUI_WX = 'wx'
33 GUI_QT = 'qt'
33 GUI_QT = 'qt'
34 GUI_QT4 = 'qt4'
34 GUI_QT4 = 'qt4'
35 GUI_GTK = 'gtk'
35 GUI_GTK = 'gtk'
36 GUI_TK = 'tk'
36 GUI_TK = 'tk'
37 GUI_OSX = 'osx'
37 GUI_OSX = 'osx'
38 GUI_GLUT = 'glut'
38 GUI_GLUT = 'glut'
39 GUI_PYGLET = 'pyglet'
39 GUI_PYGLET = 'pyglet'
40 GUI_GTK3 = 'gtk3'
40 GUI_GTK3 = 'gtk3'
41 GUI_NONE = 'none' # i.e. disable
41 GUI_NONE = 'none' # i.e. disable
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Utilities
44 # Utilities
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 def _stdin_ready_posix():
47 def _stdin_ready_posix():
48 """Return True if there's something to read on stdin (posix version)."""
48 """Return True if there's something to read on stdin (posix version)."""
49 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
49 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
50 return bool(infds)
50 return bool(infds)
51
51
52 def _stdin_ready_nt():
52 def _stdin_ready_nt():
53 """Return True if there's something to read on stdin (nt version)."""
53 """Return True if there's something to read on stdin (nt version)."""
54 return msvcrt.kbhit()
54 return msvcrt.kbhit()
55
55
56 def _stdin_ready_other():
56 def _stdin_ready_other():
57 """Return True, assuming there's something to read on stdin."""
57 """Return True, assuming there's something to read on stdin."""
58 return True #
58 return True #
59
59
60
60
61 def _ignore_CTRL_C_posix():
61 def _ignore_CTRL_C_posix():
62 """Ignore CTRL+C (SIGINT)."""
62 """Ignore CTRL+C (SIGINT)."""
63 signal.signal(signal.SIGINT, signal.SIG_IGN)
63 signal.signal(signal.SIGINT, signal.SIG_IGN)
64
64
65 def _allow_CTRL_C_posix():
65 def _allow_CTRL_C_posix():
66 """Take CTRL+C into account (SIGINT)."""
66 """Take CTRL+C into account (SIGINT)."""
67 signal.signal(signal.SIGINT, signal.default_int_handler)
67 signal.signal(signal.SIGINT, signal.default_int_handler)
68
68
69 def _ignore_CTRL_C_other():
69 def _ignore_CTRL_C_other():
70 """Ignore CTRL+C (not implemented)."""
70 """Ignore CTRL+C (not implemented)."""
71 pass
71 pass
72
72
73 def _allow_CTRL_C_other():
73 def _allow_CTRL_C_other():
74 """Take CTRL+C into account (not implemented)."""
74 """Take CTRL+C into account (not implemented)."""
75 pass
75 pass
76
76
77 if os.name == 'posix':
77 if os.name == 'posix':
78 import select
78 import select
79 import signal
79 import signal
80 stdin_ready = _stdin_ready_posix
80 stdin_ready = _stdin_ready_posix
81 ignore_CTRL_C = _ignore_CTRL_C_posix
81 ignore_CTRL_C = _ignore_CTRL_C_posix
82 allow_CTRL_C = _allow_CTRL_C_posix
82 allow_CTRL_C = _allow_CTRL_C_posix
83 elif os.name == 'nt':
83 elif os.name == 'nt':
84 import msvcrt
84 import msvcrt
85 stdin_ready = _stdin_ready_nt
85 stdin_ready = _stdin_ready_nt
86 ignore_CTRL_C = _ignore_CTRL_C_other
86 ignore_CTRL_C = _ignore_CTRL_C_other
87 allow_CTRL_C = _allow_CTRL_C_other
87 allow_CTRL_C = _allow_CTRL_C_other
88 else:
88 else:
89 stdin_ready = _stdin_ready_other
89 stdin_ready = _stdin_ready_other
90 ignore_CTRL_C = _ignore_CTRL_C_other
90 ignore_CTRL_C = _ignore_CTRL_C_other
91 allow_CTRL_C = _allow_CTRL_C_other
91 allow_CTRL_C = _allow_CTRL_C_other
92
92
93
93
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95 # Main InputHookManager class
95 # Main InputHookManager class
96 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
97
97
98
98
99 class InputHookManager(object):
99 class InputHookManager(object):
100 """Manage PyOS_InputHook for different GUI toolkits.
100 """Manage PyOS_InputHook for different GUI toolkits.
101
101
102 This class installs various hooks under ``PyOSInputHook`` to handle
102 This class installs various hooks under ``PyOSInputHook`` to handle
103 GUI event loop integration.
103 GUI event loop integration.
104 """
104 """
105
105
106 def __init__(self):
106 def __init__(self):
107 if ctypes is None:
107 if ctypes is None:
108 warn("IPython GUI event loop requires ctypes, %gui will not be available")
108 warn("IPython GUI event loop requires ctypes, %gui will not be available")
109 return
109 return
110 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
110 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
111 self._apps = {}
111 self._apps = {}
112 self._reset()
112 self._reset()
113
113
114 def _reset(self):
114 def _reset(self):
115 self._callback_pyfunctype = None
115 self._callback_pyfunctype = None
116 self._callback = None
116 self._callback = None
117 self._installed = False
117 self._installed = False
118 self._current_gui = None
118 self._current_gui = None
119
119
120 def get_pyos_inputhook(self):
120 def get_pyos_inputhook(self):
121 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
121 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
122 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
122 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
123
123
124 def get_pyos_inputhook_as_func(self):
124 def get_pyos_inputhook_as_func(self):
125 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
125 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
126 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
126 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
127
127
128 def set_inputhook(self, callback):
128 def set_inputhook(self, callback):
129 """Set PyOS_InputHook to callback and return the previous one."""
129 """Set PyOS_InputHook to callback and return the previous one."""
130 # On platforms with 'readline' support, it's all too likely to
130 # On platforms with 'readline' support, it's all too likely to
131 # have a KeyboardInterrupt signal delivered *even before* an
131 # have a KeyboardInterrupt signal delivered *even before* an
132 # initial ``try:`` clause in the callback can be executed, so
132 # initial ``try:`` clause in the callback can be executed, so
133 # we need to disable CTRL+C in this situation.
133 # we need to disable CTRL+C in this situation.
134 ignore_CTRL_C()
134 ignore_CTRL_C()
135 self._callback = callback
135 self._callback = callback
136 self._callback_pyfunctype = self.PYFUNC(callback)
136 self._callback_pyfunctype = self.PYFUNC(callback)
137 pyos_inputhook_ptr = self.get_pyos_inputhook()
137 pyos_inputhook_ptr = self.get_pyos_inputhook()
138 original = self.get_pyos_inputhook_as_func()
138 original = self.get_pyos_inputhook_as_func()
139 pyos_inputhook_ptr.value = \
139 pyos_inputhook_ptr.value = \
140 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
140 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
141 self._installed = True
141 self._installed = True
142 return original
142 return original
143
143
144 def clear_inputhook(self, app=None):
144 def clear_inputhook(self, app=None):
145 """Set PyOS_InputHook to NULL and return the previous one.
145 """Set PyOS_InputHook to NULL and return the previous one.
146
146
147 Parameters
147 Parameters
148 ----------
148 ----------
149 app : optional, ignored
149 app : optional, ignored
150 This parameter is allowed only so that clear_inputhook() can be
150 This parameter is allowed only so that clear_inputhook() can be
151 called with a similar interface as all the ``enable_*`` methods. But
151 called with a similar interface as all the ``enable_*`` methods. But
152 the actual value of the parameter is ignored. This uniform interface
152 the actual value of the parameter is ignored. This uniform interface
153 makes it easier to have user-level entry points in the main IPython
153 makes it easier to have user-level entry points in the main IPython
154 app like :meth:`enable_gui`."""
154 app like :meth:`enable_gui`."""
155 pyos_inputhook_ptr = self.get_pyos_inputhook()
155 pyos_inputhook_ptr = self.get_pyos_inputhook()
156 original = self.get_pyos_inputhook_as_func()
156 original = self.get_pyos_inputhook_as_func()
157 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
157 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
158 allow_CTRL_C()
158 allow_CTRL_C()
159 self._reset()
159 self._reset()
160 return original
160 return original
161
161
162 def clear_app_refs(self, gui=None):
162 def clear_app_refs(self, gui=None):
163 """Clear IPython's internal reference to an application instance.
163 """Clear IPython's internal reference to an application instance.
164
164
165 Whenever we create an app for a user on qt4 or wx, we hold a
165 Whenever we create an app for a user on qt4 or wx, we hold a
166 reference to the app. This is needed because in some cases bad things
166 reference to the app. This is needed because in some cases bad things
167 can happen if a user doesn't hold a reference themselves. This
167 can happen if a user doesn't hold a reference themselves. This
168 method is provided to clear the references we are holding.
168 method is provided to clear the references we are holding.
169
169
170 Parameters
170 Parameters
171 ----------
171 ----------
172 gui : None or str
172 gui : None or str
173 If None, clear all app references. If ('wx', 'qt4') clear
173 If None, clear all app references. If ('wx', 'qt4') clear
174 the app for that toolkit. References are not held for gtk or tk
174 the app for that toolkit. References are not held for gtk or tk
175 as those toolkits don't have the notion of an app.
175 as those toolkits don't have the notion of an app.
176 """
176 """
177 if gui is None:
177 if gui is None:
178 self._apps = {}
178 self._apps = {}
179 elif gui in self._apps:
179 elif gui in self._apps:
180 del self._apps[gui]
180 del self._apps[gui]
181
181
182 def enable_wx(self, app=None):
182 def enable_wx(self, app=None):
183 """Enable event loop integration with wxPython.
183 """Enable event loop integration with wxPython.
184
184
185 Parameters
185 Parameters
186 ----------
186 ----------
187 app : WX Application, optional.
187 app : WX Application, optional.
188 Running application to use. If not given, we probe WX for an
188 Running application to use. If not given, we probe WX for an
189 existing application object, and create a new one if none is found.
189 existing application object, and create a new one if none is found.
190
190
191 Notes
191 Notes
192 -----
192 -----
193 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
193 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
194 the wxPython to integrate with terminal based applications like
194 the wxPython to integrate with terminal based applications like
195 IPython.
195 IPython.
196
196
197 If ``app`` is not given we probe for an existing one, and return it if
197 If ``app`` is not given we probe for an existing one, and return it if
198 found. If no existing app is found, we create an :class:`wx.App` as
198 found. If no existing app is found, we create an :class:`wx.App` as
199 follows::
199 follows::
200
200
201 import wx
201 import wx
202 app = wx.App(redirect=False, clearSigInt=False)
202 app = wx.App(redirect=False, clearSigInt=False)
203 """
203 """
204 import wx
204 import wx
205
205
206 wx_version = V(wx.__version__).version
206 wx_version = V(wx.__version__).version
207
207
208 if wx_version < [2, 8]:
208 if wx_version < [2, 8]:
209 raise ValueError("requires wxPython >= 2.8, but you have %s" % wx.__version__)
209 raise ValueError("requires wxPython >= 2.8, but you have %s" % wx.__version__)
210
210
211 from IPython.lib.inputhookwx import inputhook_wx
211 from IPython.lib.inputhookwx import inputhook_wx
212 self.set_inputhook(inputhook_wx)
212 self.set_inputhook(inputhook_wx)
213 self._current_gui = GUI_WX
213 self._current_gui = GUI_WX
214 import wx
214 import wx
215 if app is None:
215 if app is None:
216 app = wx.GetApp()
216 app = wx.GetApp()
217 if app is None:
217 if app is None:
218 app = wx.App(redirect=False, clearSigInt=False)
218 app = wx.App(redirect=False, clearSigInt=False)
219 app._in_event_loop = True
219 app._in_event_loop = True
220 self._apps[GUI_WX] = app
220 self._apps[GUI_WX] = app
221 return app
221 return app
222
222
223 def disable_wx(self):
223 def disable_wx(self):
224 """Disable event loop integration with wxPython.
224 """Disable event loop integration with wxPython.
225
225
226 This merely sets PyOS_InputHook to NULL.
226 This merely sets PyOS_InputHook to NULL.
227 """
227 """
228 if GUI_WX in self._apps:
228 if GUI_WX in self._apps:
229 self._apps[GUI_WX]._in_event_loop = False
229 self._apps[GUI_WX]._in_event_loop = False
230 self.clear_inputhook()
230 self.clear_inputhook()
231
231
232 def enable_qt4(self, app=None):
232 def enable_qt4(self, app=None):
233 """Enable event loop integration with PyQt4.
233 """Enable event loop integration with PyQt4.
234
234
235 Parameters
235 Parameters
236 ----------
236 ----------
237 app : Qt Application, optional.
237 app : Qt Application, optional.
238 Running application to use. If not given, we probe Qt for an
238 Running application to use. If not given, we probe Qt for an
239 existing application object, and create a new one if none is found.
239 existing application object, and create a new one if none is found.
240
240
241 Notes
241 Notes
242 -----
242 -----
243 This methods sets the PyOS_InputHook for PyQt4, which allows
243 This methods sets the PyOS_InputHook for PyQt4, which allows
244 the PyQt4 to integrate with terminal based applications like
244 the PyQt4 to integrate with terminal based applications like
245 IPython.
245 IPython.
246
246
247 If ``app`` is not given we probe for an existing one, and return it if
247 If ``app`` is not given we probe for an existing one, and return it if
248 found. If no existing app is found, we create an :class:`QApplication`
248 found. If no existing app is found, we create an :class:`QApplication`
249 as follows::
249 as follows::
250
250
251 from PyQt4 import QtCore
251 from PyQt4 import QtCore
252 app = QtGui.QApplication(sys.argv)
252 app = QtGui.QApplication(sys.argv)
253 """
253 """
254 from IPython.lib.inputhookqt4 import create_inputhook_qt4
254 from IPython.lib.inputhookqt4 import create_inputhook_qt4
255 app, inputhook_qt4 = create_inputhook_qt4(self, app)
255 app, inputhook_qt4 = create_inputhook_qt4(self, app)
256 self.set_inputhook(inputhook_qt4)
256 self.set_inputhook(inputhook_qt4)
257
257
258 self._current_gui = GUI_QT4
258 self._current_gui = GUI_QT4
259 app._in_event_loop = True
259 app._in_event_loop = True
260 self._apps[GUI_QT4] = app
260 self._apps[GUI_QT4] = app
261 return app
261 return app
262
262
263 def disable_qt4(self):
263 def disable_qt4(self):
264 """Disable event loop integration with PyQt4.
264 """Disable event loop integration with PyQt4.
265
265
266 This merely sets PyOS_InputHook to NULL.
266 This merely sets PyOS_InputHook to NULL.
267 """
267 """
268 if GUI_QT4 in self._apps:
268 if GUI_QT4 in self._apps:
269 self._apps[GUI_QT4]._in_event_loop = False
269 self._apps[GUI_QT4]._in_event_loop = False
270 self.clear_inputhook()
270 self.clear_inputhook()
271
271
272 def enable_gtk(self, app=None):
272 def enable_gtk(self, app=None):
273 """Enable event loop integration with PyGTK.
273 """Enable event loop integration with PyGTK.
274
274
275 Parameters
275 Parameters
276 ----------
276 ----------
277 app : ignored
277 app : ignored
278 Ignored, it's only a placeholder to keep the call signature of all
278 Ignored, it's only a placeholder to keep the call signature of all
279 gui activation methods consistent, which simplifies the logic of
279 gui activation methods consistent, which simplifies the logic of
280 supporting magics.
280 supporting magics.
281
281
282 Notes
282 Notes
283 -----
283 -----
284 This methods sets the PyOS_InputHook for PyGTK, which allows
284 This methods sets the PyOS_InputHook for PyGTK, which allows
285 the PyGTK to integrate with terminal based applications like
285 the PyGTK to integrate with terminal based applications like
286 IPython.
286 IPython.
287 """
287 """
288 import gtk
288 import gtk
289 try:
289 try:
290 gtk.set_interactive(True)
290 gtk.set_interactive(True)
291 self._current_gui = GUI_GTK
291 self._current_gui = GUI_GTK
292 except AttributeError:
292 except AttributeError:
293 # For older versions of gtk, use our own ctypes version
293 # For older versions of gtk, use our own ctypes version
294 from IPython.lib.inputhookgtk import inputhook_gtk
294 from IPython.lib.inputhookgtk import inputhook_gtk
295 self.set_inputhook(inputhook_gtk)
295 self.set_inputhook(inputhook_gtk)
296 self._current_gui = GUI_GTK
296 self._current_gui = GUI_GTK
297
297
298 def disable_gtk(self):
298 def disable_gtk(self):
299 """Disable event loop integration with PyGTK.
299 """Disable event loop integration with PyGTK.
300
300
301 This merely sets PyOS_InputHook to NULL.
301 This merely sets PyOS_InputHook to NULL.
302 """
302 """
303 self.clear_inputhook()
303 self.clear_inputhook()
304
304
305 def enable_tk(self, app=None):
305 def enable_tk(self, app=None):
306 """Enable event loop integration with Tk.
306 """Enable event loop integration with Tk.
307
307
308 Parameters
308 Parameters
309 ----------
309 ----------
310 app : toplevel :class:`Tkinter.Tk` widget, optional.
310 app : toplevel :class:`Tkinter.Tk` widget, optional.
311 Running toplevel widget to use. If not given, we probe Tk for an
311 Running toplevel widget to use. If not given, we probe Tk for an
312 existing one, and create a new one if none is found.
312 existing one, and create a new one if none is found.
313
313
314 Notes
314 Notes
315 -----
315 -----
316 If you have already created a :class:`Tkinter.Tk` object, the only
316 If you have already created a :class:`Tkinter.Tk` object, the only
317 thing done by this method is to register with the
317 thing done by this method is to register with the
318 :class:`InputHookManager`, since creating that object automatically
318 :class:`InputHookManager`, since creating that object automatically
319 sets ``PyOS_InputHook``.
319 sets ``PyOS_InputHook``.
320 """
320 """
321 self._current_gui = GUI_TK
321 self._current_gui = GUI_TK
322 if app is None:
322 if app is None:
323 import Tkinter
323 import Tkinter
324 app = Tkinter.Tk()
324 app = Tkinter.Tk()
325 app.withdraw()
325 app.withdraw()
326 self._apps[GUI_TK] = app
326 self._apps[GUI_TK] = app
327 return app
327 return app
328
328
329 def disable_tk(self):
329 def disable_tk(self):
330 """Disable event loop integration with Tkinter.
330 """Disable event loop integration with Tkinter.
331
331
332 This merely sets PyOS_InputHook to NULL.
332 This merely sets PyOS_InputHook to NULL.
333 """
333 """
334 self.clear_inputhook()
334 self.clear_inputhook()
335
335
336
336
337 def enable_glut(self, app=None):
337 def enable_glut(self, app=None):
338 """ Enable event loop integration with GLUT.
338 """ Enable event loop integration with GLUT.
339
339
340 Parameters
340 Parameters
341 ----------
341 ----------
342
342
343 app : ignored
343 app : ignored
344 Ignored, it's only a placeholder to keep the call signature of all
344 Ignored, it's only a placeholder to keep the call signature of all
345 gui activation methods consistent, which simplifies the logic of
345 gui activation methods consistent, which simplifies the logic of
346 supporting magics.
346 supporting magics.
347
347
348 Notes
348 Notes
349 -----
349 -----
350
350
351 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
351 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
352 integrate with terminal based applications like IPython. Due to GLUT
352 integrate with terminal based applications like IPython. Due to GLUT
353 limitations, it is currently not possible to start the event loop
353 limitations, it is currently not possible to start the event loop
354 without first creating a window. You should thus not create another
354 without first creating a window. You should thus not create another
355 window but use instead the created one. See 'gui-glut.py' in the
355 window but use instead the created one. See 'gui-glut.py' in the
356 docs/examples/lib directory.
356 docs/examples/lib directory.
357
357
358 The default screen mode is set to:
358 The default screen mode is set to:
359 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
359 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
360 """
360 """
361
361
362 import OpenGL.GLUT as glut
362 import OpenGL.GLUT as glut
363 from IPython.lib.inputhookglut import glut_display_mode, \
363 from IPython.lib.inputhookglut import glut_display_mode, \
364 glut_close, glut_display, \
364 glut_close, glut_display, \
365 glut_idle, inputhook_glut
365 glut_idle, inputhook_glut
366
366
367 if GUI_GLUT not in self._apps:
367 if GUI_GLUT not in self._apps:
368 glut.glutInit( sys.argv )
368 glut.glutInit( sys.argv )
369 glut.glutInitDisplayMode( glut_display_mode )
369 glut.glutInitDisplayMode( glut_display_mode )
370 # This is specific to freeglut
370 # This is specific to freeglut
371 if bool(glut.glutSetOption):
371 if bool(glut.glutSetOption):
372 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
372 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
373 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
373 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
374 glut.glutCreateWindow( sys.argv[0] )
374 glut.glutCreateWindow( sys.argv[0] )
375 glut.glutReshapeWindow( 1, 1 )
375 glut.glutReshapeWindow( 1, 1 )
376 glut.glutHideWindow( )
376 glut.glutHideWindow( )
377 glut.glutWMCloseFunc( glut_close )
377 glut.glutWMCloseFunc( glut_close )
378 glut.glutDisplayFunc( glut_display )
378 glut.glutDisplayFunc( glut_display )
379 glut.glutIdleFunc( glut_idle )
379 glut.glutIdleFunc( glut_idle )
380 else:
380 else:
381 glut.glutWMCloseFunc( glut_close )
381 glut.glutWMCloseFunc( glut_close )
382 glut.glutDisplayFunc( glut_display )
382 glut.glutDisplayFunc( glut_display )
383 glut.glutIdleFunc( glut_idle)
383 glut.glutIdleFunc( glut_idle)
384 self.set_inputhook( inputhook_glut )
384 self.set_inputhook( inputhook_glut )
385 self._current_gui = GUI_GLUT
385 self._current_gui = GUI_GLUT
386 self._apps[GUI_GLUT] = True
386 self._apps[GUI_GLUT] = True
387
387
388
388
389 def disable_glut(self):
389 def disable_glut(self):
390 """Disable event loop integration with glut.
390 """Disable event loop integration with glut.
391
391
392 This sets PyOS_InputHook to NULL and set the display function to a
392 This sets PyOS_InputHook to NULL and set the display function to a
393 dummy one and set the timer to a dummy timer that will be triggered
393 dummy one and set the timer to a dummy timer that will be triggered
394 very far in the future.
394 very far in the future.
395 """
395 """
396 import OpenGL.GLUT as glut
396 import OpenGL.GLUT as glut
397 from glut_support import glutMainLoopEvent
397 from glut_support import glutMainLoopEvent
398
398
399 glut.glutHideWindow() # This is an event to be processed below
399 glut.glutHideWindow() # This is an event to be processed below
400 glutMainLoopEvent()
400 glutMainLoopEvent()
401 self.clear_inputhook()
401 self.clear_inputhook()
402
402
403 def enable_pyglet(self, app=None):
403 def enable_pyglet(self, app=None):
404 """Enable event loop integration with pyglet.
404 """Enable event loop integration with pyglet.
405
405
406 Parameters
406 Parameters
407 ----------
407 ----------
408 app : ignored
408 app : ignored
409 Ignored, it's only a placeholder to keep the call signature of all
409 Ignored, it's only a placeholder to keep the call signature of all
410 gui activation methods consistent, which simplifies the logic of
410 gui activation methods consistent, which simplifies the logic of
411 supporting magics.
411 supporting magics.
412
412
413 Notes
413 Notes
414 -----
414 -----
415 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
415 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
416 pyglet to integrate with terminal based applications like
416 pyglet to integrate with terminal based applications like
417 IPython.
417 IPython.
418
418
419 """
419 """
420 from IPython.lib.inputhookpyglet import inputhook_pyglet
420 from IPython.lib.inputhookpyglet import inputhook_pyglet
421 self.set_inputhook(inputhook_pyglet)
421 self.set_inputhook(inputhook_pyglet)
422 self._current_gui = GUI_PYGLET
422 self._current_gui = GUI_PYGLET
423 return app
423 return app
424
424
425 def disable_pyglet(self):
425 def disable_pyglet(self):
426 """Disable event loop integration with pyglet.
426 """Disable event loop integration with pyglet.
427
427
428 This merely sets PyOS_InputHook to NULL.
428 This merely sets PyOS_InputHook to NULL.
429 """
429 """
430 self.clear_inputhook()
430 self.clear_inputhook()
431
431
432 def enable_gtk3(self, app=None):
432 def enable_gtk3(self, app=None):
433 """Enable event loop integration with Gtk3 (gir bindings).
433 """Enable event loop integration with Gtk3 (gir bindings).
434
434
435 Parameters
435 Parameters
436 ----------
436 ----------
437 app : ignored
437 app : ignored
438 Ignored, it's only a placeholder to keep the call signature of all
438 Ignored, it's only a placeholder to keep the call signature of all
439 gui activation methods consistent, which simplifies the logic of
439 gui activation methods consistent, which simplifies the logic of
440 supporting magics.
440 supporting magics.
441
441
442 Notes
442 Notes
443 -----
443 -----
444 This methods sets the PyOS_InputHook for Gtk3, which allows
444 This methods sets the PyOS_InputHook for Gtk3, which allows
445 the Gtk3 to integrate with terminal based applications like
445 the Gtk3 to integrate with terminal based applications like
446 IPython.
446 IPython.
447 """
447 """
448 from IPython.lib.inputhookgtk3 import inputhook_gtk3
448 from IPython.lib.inputhookgtk3 import inputhook_gtk3
449 self.set_inputhook(inputhook_gtk3)
449 self.set_inputhook(inputhook_gtk3)
450 self._current_gui = GUI_GTK
450 self._current_gui = GUI_GTK
451
451
452 def disable_gtk3(self):
452 def disable_gtk3(self):
453 """Disable event loop integration with PyGTK.
453 """Disable event loop integration with PyGTK.
454
454
455 This merely sets PyOS_InputHook to NULL.
455 This merely sets PyOS_InputHook to NULL.
456 """
456 """
457 self.clear_inputhook()
457 self.clear_inputhook()
458
458
459 def current_gui(self):
459 def current_gui(self):
460 """Return a string indicating the currently active GUI or None."""
460 """Return a string indicating the currently active GUI or None."""
461 return self._current_gui
461 return self._current_gui
462
462
463 inputhook_manager = InputHookManager()
463 inputhook_manager = InputHookManager()
464
464
465 enable_wx = inputhook_manager.enable_wx
465 enable_wx = inputhook_manager.enable_wx
466 disable_wx = inputhook_manager.disable_wx
466 disable_wx = inputhook_manager.disable_wx
467 enable_qt4 = inputhook_manager.enable_qt4
467 enable_qt4 = inputhook_manager.enable_qt4
468 disable_qt4 = inputhook_manager.disable_qt4
468 disable_qt4 = inputhook_manager.disable_qt4
469 enable_gtk = inputhook_manager.enable_gtk
469 enable_gtk = inputhook_manager.enable_gtk
470 disable_gtk = inputhook_manager.disable_gtk
470 disable_gtk = inputhook_manager.disable_gtk
471 enable_tk = inputhook_manager.enable_tk
471 enable_tk = inputhook_manager.enable_tk
472 disable_tk = inputhook_manager.disable_tk
472 disable_tk = inputhook_manager.disable_tk
473 enable_glut = inputhook_manager.enable_glut
473 enable_glut = inputhook_manager.enable_glut
474 disable_glut = inputhook_manager.disable_glut
474 disable_glut = inputhook_manager.disable_glut
475 enable_pyglet = inputhook_manager.enable_pyglet
475 enable_pyglet = inputhook_manager.enable_pyglet
476 disable_pyglet = inputhook_manager.disable_pyglet
476 disable_pyglet = inputhook_manager.disable_pyglet
477 enable_gtk3 = inputhook_manager.enable_gtk3
477 enable_gtk3 = inputhook_manager.enable_gtk3
478 disable_gtk3 = inputhook_manager.disable_gtk3
478 disable_gtk3 = inputhook_manager.disable_gtk3
479 clear_inputhook = inputhook_manager.clear_inputhook
479 clear_inputhook = inputhook_manager.clear_inputhook
480 set_inputhook = inputhook_manager.set_inputhook
480 set_inputhook = inputhook_manager.set_inputhook
481 current_gui = inputhook_manager.current_gui
481 current_gui = inputhook_manager.current_gui
482 clear_app_refs = inputhook_manager.clear_app_refs
482 clear_app_refs = inputhook_manager.clear_app_refs
483
483
484 guis = {None: clear_inputhook,
485 GUI_NONE: clear_inputhook,
486 GUI_OSX: lambda app=False: None,
487 GUI_TK: enable_tk,
488 GUI_GTK: enable_gtk,
489 GUI_WX: enable_wx,
490 GUI_QT: enable_qt4, # qt3 not supported
491 GUI_QT4: enable_qt4,
492 GUI_GLUT: enable_glut,
493 GUI_PYGLET: enable_pyglet,
494 GUI_GTK3: enable_gtk3,
495 }
496
484
497
485 # Convenience function to switch amongst them
498 # Convenience function to switch amongst them
486 def enable_gui(gui=None, app=None):
499 def enable_gui(gui=None, app=None):
487 """Switch amongst GUI input hooks by name.
500 """Switch amongst GUI input hooks by name.
488
501
489 This is just a utility wrapper around the methods of the InputHookManager
502 This is just a utility wrapper around the methods of the InputHookManager
490 object.
503 object.
491
504
492 Parameters
505 Parameters
493 ----------
506 ----------
494 gui : optional, string or None
507 gui : optional, string or None
495 If None (or 'none'), clears input hook, otherwise it must be one
508 If None (or 'none'), clears input hook, otherwise it must be one
496 of the recognized GUI names (see ``GUI_*`` constants in module).
509 of the recognized GUI names (see ``GUI_*`` constants in module).
497
510
498 app : optional, existing application object.
511 app : optional, existing application object.
499 For toolkits that have the concept of a global app, you can supply an
512 For toolkits that have the concept of a global app, you can supply an
500 existing one. If not given, the toolkit will be probed for one, and if
513 existing one. If not given, the toolkit will be probed for one, and if
501 none is found, a new one will be created. Note that GTK does not have
514 none is found, a new one will be created. Note that GTK does not have
502 this concept, and passing an app if ``gui=="GTK"`` will raise an error.
515 this concept, and passing an app if ``gui=="GTK"`` will raise an error.
503
516
504 Returns
517 Returns
505 -------
518 -------
506 The output of the underlying gui switch routine, typically the actual
519 The output of the underlying gui switch routine, typically the actual
507 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
520 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
508 one.
521 one.
509 """
522 """
510 guis = {None: clear_inputhook,
511 GUI_NONE: clear_inputhook,
512 GUI_OSX: lambda app=False: None,
513 GUI_TK: enable_tk,
514 GUI_GTK: enable_gtk,
515 GUI_WX: enable_wx,
516 GUI_QT: enable_qt4, # qt3 not supported
517 GUI_QT4: enable_qt4,
518 GUI_GLUT: enable_glut,
519 GUI_PYGLET: enable_pyglet,
520 GUI_GTK3: enable_gtk3,
521 }
522 try:
523 try:
523 gui_hook = guis[gui]
524 gui_hook = guis[gui]
524 except KeyError:
525 except KeyError:
525 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
526 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
526 raise ValueError(e)
527 raise ValueError(e)
527 return gui_hook(app)
528 return gui_hook(app)
528
529
General Comments 0
You need to be logged in to leave comments. Login now