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