##// END OF EJS Templates
Initial GUI support in kernel.
Brian Granger -
Show More
@@ -194,8 +194,8 b' class InteractiveShell(Configurable, Magic):'
194 194 # TODO: this part of prompt management should be moved to the frontends.
195 195 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
196 196 separate_in = SeparateStr('\n', config=True)
197 separate_out = SeparateStr('\n', config=True)
198 separate_out2 = SeparateStr('\n', config=True)
197 separate_out = SeparateStr('', config=True)
198 separate_out2 = SeparateStr('', config=True)
199 199 system_header = Str('IPython system call: ', config=True)
200 200 system_verbose = CBool(False, config=True)
201 201 wildcards_case_sensitive = CBool(True, config=True)
@@ -23,29 +23,21 b' from IPython.utils.decorators import flag_calls'
23 23 # Main classes and functions
24 24 #-----------------------------------------------------------------------------
25 25
26 def pylab_activate(user_ns, gui=None, import_all=True):
27 """Activate pylab mode in the user's namespace.
28 26
29 Loads and initializes numpy, matplotlib and friends for interactive use.
27 def find_gui_and_backend(gui=None):
28 """Given a gui string return the gui and mpl backend.
30 29
31 30 Parameters
32 31 ----------
33 user_ns : dict
34 Namespace where the imports will occur.
35
36 gui : optional, string
37 A valid gui name following the conventions of the %gui magic.
38
39 import_all : optional, boolean
40 If true, an 'import *' is done from numpy and pylab.
32 gui : str
33 Can be one of ('tk','gtk','wx','qt','qt4','payload-svg').
41 34
42 35 Returns
43 36 -------
44 The actual gui used (if not given as input, it was obtained from matplotlib
45 itself, and will be needed next to configure IPython's gui integration.
37 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
38 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_payload_svg').
46 39 """
47 40
48 # Initialize matplotlib to interactive mode always
49 41 import matplotlib
50 42
51 43 # If user specifies a GUI, that dictates the backend, otherwise we read the
@@ -54,7 +46,9 b' def pylab_activate(user_ns, gui=None, import_all=True):'
54 46 'gtk': 'GTKAgg',
55 47 'wx': 'WXAgg',
56 48 'qt': 'Qt4Agg', # qt3 not supported
57 'qt4': 'Qt4Agg' }
49 'qt4': 'Qt4Agg',
50 'payload-svg' : \
51 'module://IPython.zmq.pylab.backend_payload_svg'}
58 52
59 53 if gui:
60 54 # select backend based on requested gui
@@ -65,23 +59,25 b' def pylab_activate(user_ns, gui=None, import_all=True):'
65 59 # should be for IPython, so we can activate inputhook accordingly
66 60 b2g = dict(zip(g2b.values(),g2b.keys()))
67 61 gui = b2g.get(backend, None)
62 return gui, backend
68 63
69 # We must set the desired backend before importing pylab
70 matplotlib.use(backend)
71
72 # This must be imported last in the matplotlib series, after
73 # backend/interactivity choices have been made
64
65 def activate_matplotlib(backend):
66 """Activate the given backend and set interactive to True."""
67
68 import matplotlib
69 if backend.startswith('module://'):
70 # Work around bug in matplotlib: matplotlib.use converts the
71 # backend_id to lowercase even if a module name is specified!
72 matplotlib.rcParams['backend'] = backend
73 else:
74 matplotlib.use(backend)
75 matplotlib.interactive(True)
74 76 import matplotlib.pylab as pylab
75 77
76 # XXX For now leave this commented out, but depending on discussions with
77 # mpl-dev, we may be able to allow interactive switching...
78 #import matplotlib.pyplot
79 #matplotlib.pyplot.switch_backend(backend)
80 78
81 pylab.show._needmain = False
82 # We need to detect at runtime whether show() is called by the user.
83 # For this, we wrap it into a decorator which adds a 'called' flag.
84 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
79 def import_pylab(user_ns, import_all=True):
80 """Import the standard pylab symbols into user_ns."""
85 81
86 82 # Import numpy as np/pyplot as plt are conventions we're trying to
87 83 # somewhat standardize on. Making them available to users by default
@@ -97,7 +93,47 b' def pylab_activate(user_ns, gui=None, import_all=True):'
97 93 exec("from matplotlib.pylab import *\n"
98 94 "from numpy import *\n") in user_ns
99 95
100 matplotlib.interactive(True)
96
97 def pylab_activate(user_ns, gui=None, import_all=True):
98 """Activate pylab mode in the user's namespace.
99
100 Loads and initializes numpy, matplotlib and friends for interactive use.
101
102 Parameters
103 ----------
104 user_ns : dict
105 Namespace where the imports will occur.
106
107 gui : optional, string
108 A valid gui name following the conventions of the %gui magic.
109
110 import_all : optional, boolean
111 If true, an 'import *' is done from numpy and pylab.
112
113 Returns
114 -------
115 The actual gui used (if not given as input, it was obtained from matplotlib
116 itself, and will be needed next to configure IPython's gui integration.
117 """
118
119 gui, backend = find_gui_and_backend(gui)
120 activate_matplotlib(backend)
121
122 # This must be imported last in the matplotlib series, after
123 # backend/interactivity choices have been made
124 import matplotlib.pylab as pylab
125
126 # XXX For now leave this commented out, but depending on discussions with
127 # mpl-dev, we may be able to allow interactive switching...
128 #import matplotlib.pyplot
129 #matplotlib.pyplot.switch_backend(backend)
130
131 pylab.show._needmain = False
132 # We need to detect at runtime whether show() is called by the user.
133 # For this, we wrap it into a decorator which adds a 'called' flag.
134 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
135
136 import_pylab(user_ns)
101 137
102 138 print """
103 139 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
@@ -79,6 +79,7 b' def make_kernel(namespace, kernel_factory,'
79 79
80 80 # Redirect input streams and set a display hook.
81 81 if out_stream_factory:
82 pass
82 83 sys.stdout = out_stream_factory(session, pub_socket, u'stdout')
83 84 sys.stderr = out_stream_factory(session, pub_socket, u'stderr')
84 85 if display_hook_factory:
@@ -25,8 +25,8 b' import zmq'
25 25
26 26 # Local imports.
27 27 from IPython.config.configurable import Configurable
28 from IPython.lib import pylabtools
28 29 from IPython.utils.traitlets import Instance
29 from completer import KernelCompleter
30 30 from entry_point import base_launch_kernel, make_argument_parser, make_kernel, \
31 31 start_kernel
32 32 from iostream import OutStream
@@ -49,15 +49,6 b' class Kernel(Configurable):'
49 49 pub_socket = Instance('zmq.Socket')
50 50 req_socket = Instance('zmq.Socket')
51 51
52 # Maps user-friendly backend names to matplotlib backend identifiers.
53 _pylab_map = { 'tk': 'TkAgg',
54 'gtk': 'GTKAgg',
55 'wx': 'WXAgg',
56 'qt': 'Qt4Agg', # qt3 not supported
57 'qt4': 'Qt4Agg',
58 'payload-svg' : \
59 'module://IPython.zmq.pylab.backend_payload_svg' }
60
61 52 def __init__(self, **kwargs):
62 53 super(Kernel, self).__init__(**kwargs)
63 54
@@ -77,62 +68,32 b' class Kernel(Configurable):'
77 68 for msg_type in msg_types:
78 69 self.handlers[msg_type] = getattr(self, msg_type)
79 70
80 def activate_pylab(self, backend=None, import_all=True):
81 """ Activates pylab in this kernel's namespace.
82
83 Parameters:
84 -----------
85 backend : str, optional
86 A valid backend name.
87
88 import_all : bool, optional
89 If true, an 'import *' is done from numpy and pylab.
90 """
91 # FIXME: This is adapted from IPython.lib.pylabtools.pylab_activate.
92 # Common functionality should be refactored.
93
94 # We must set the desired backend before importing pylab.
95 import matplotlib
96 if backend:
97 backend_id = self._pylab_map[backend]
98 if backend_id.startswith('module://'):
99 # Work around bug in matplotlib: matplotlib.use converts the
100 # backend_id to lowercase even if a module name is specified!
101 matplotlib.rcParams['backend'] = backend_id
71 def do_one_iteration(self):
72 try:
73 ident = self.reply_socket.recv(zmq.NOBLOCK)
74 except zmq.ZMQError, e:
75 if e.errno == zmq.EAGAIN:
76 return
102 77 else:
103 matplotlib.use(backend_id)
104
105 # Import numpy as np/pyplot as plt are conventions we're trying to
106 # somewhat standardize on. Making them available to users by default
107 # will greatly help this.
108 exec ("import numpy\n"
109 "import matplotlib\n"
110 "from matplotlib import pylab, mlab, pyplot\n"
111 "np = numpy\n"
112 "plt = pyplot\n"
113 ) in self.shell.user_ns
114
115 if import_all:
116 exec("from matplotlib.pylab import *\n"
117 "from numpy import *\n") in self.shell.user_ns
118
119 matplotlib.interactive(True)
78 raise
79 # FIXME: Bug in pyzmq/zmq?
80 # assert self.reply_socket.rcvmore(), "Missing message part."
81 msg = self.reply_socket.recv_json()
82 omsg = Message(msg)
83 print>>sys.__stdout__
84 print>>sys.__stdout__, omsg
85 handler = self.handlers.get(omsg.msg_type, None)
86 if handler is None:
87 print >> sys.__stderr__, "UNKNOWN MESSAGE TYPE:", omsg
88 else:
89 handler(ident, omsg)
120 90
121 91 def start(self):
122 92 """ Start the kernel main loop.
123 93 """
124 94 while True:
125 ident = self.reply_socket.recv()
126 assert self.reply_socket.rcvmore(), "Missing message part."
127 msg = self.reply_socket.recv_json()
128 omsg = Message(msg)
129 print>>sys.__stdout__
130 print>>sys.__stdout__, omsg
131 handler = self.handlers.get(omsg.msg_type, None)
132 if handler is None:
133 print >> sys.__stderr__, "UNKNOWN MESSAGE TYPE:", omsg
134 else:
135 handler(ident, omsg)
95 time.sleep(0.05)
96 self.do_one_iteration()
136 97
137 98 #---------------------------------------------------------------------------
138 99 # Kernel request handlers
@@ -330,6 +291,19 b' class Kernel(Configurable):'
330 291
331 292 return symbol, []
332 293
294
295 class QtKernel(Kernel):
296
297 def start(self):
298 """Start a kernel with QtPy4 event loop integration."""
299 from PyQt4 import QtGui, QtCore
300 self.qapp = app = QtGui.QApplication([])
301 self.qtimer = QtCore.QTimer()
302 self.qtimer.timeout.connect(self.do_one_iteration)
303 self.qtimer.start(50)
304 self.qapp.exec_()
305
306
333 307 #-----------------------------------------------------------------------------
334 308 # Kernel main and launch functions
335 309 #-----------------------------------------------------------------------------
@@ -386,13 +360,31 b" given, the GUI backend is matplotlib's, otherwise use one of: \\"
386 360 ['tk', 'gtk', 'qt', 'wx', 'payload-svg'].")
387 361 namespace = parser.parse_args()
388 362
389 kernel = make_kernel(namespace, Kernel, OutStream)
363 kernel_class = Kernel
364
365 _kernel_classes = {
366 'qt' : QtKernel,
367 'qt4' : QtKernel,
368 'payload-svg':Kernel
369 }
390 370 if namespace.pylab:
391 371 if namespace.pylab == 'auto':
392 kernel.activate_pylab()
372 gui, backend = pylabtools.find_gui_and_backend()
393 373 else:
394 kernel.activate_pylab(namespace.pylab)
395
374 gui, backend = pylabtools.find_gui_and_backend(namespace.pylab)
375 print gui, backend
376 kernel_class = _kernel_classes.get(gui)
377 if kernel_class is None:
378 raise ValueError('GUI is not supported: %r' % gui)
379 pylabtools.activate_matplotlib(backend)
380
381 print>>sys.__stdout__, kernel_class
382 kernel = make_kernel(namespace, kernel_class, OutStream)
383 print >>sys.__stdout__, kernel
384
385 if namespace.pylab:
386 pylabtools.import_pylab(kernel.shell.user_ns)
387
396 388 start_kernel(namespace, kernel)
397 389
398 390 if __name__ == '__main__':
@@ -15,7 +15,7 b' from IPython.utils.traitlets import Instance, Type, Dict'
15 15 from IPython.utils.warn import warn
16 16 from IPython.zmq.session import extract_header
17 17 from IPython.core.payloadpage import install_payload_page
18
18 from session import Session
19 19
20 20 # Install the payload version of page.
21 21 install_payload_page()
@@ -23,7 +23,7 b' install_payload_page()'
23 23
24 24 class ZMQDisplayHook(DisplayHook):
25 25
26 session = Instance('IPython.zmq.session.Session')
26 session = Instance(Session)
27 27 pub_socket = Instance('zmq.Socket')
28 28 parent_header = Dict({})
29 29
General Comments 0
You need to be logged in to leave comments. Login now