##// END OF EJS Templates
Do not generate output for empty figures in Qt console....
Fernando Perez -
Show More
@@ -1,295 +1,299
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities.
2 """Pylab (matplotlib) support utilities.
3
3
4 Authors
4 Authors
5 -------
5 -------
6
6
7 * Fernando Perez.
7 * Fernando Perez.
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2009 The IPython Development Team
12 # Copyright (C) 2009 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 from cStringIO import StringIO
22 from cStringIO import StringIO
23
23
24 from IPython.utils.decorators import flag_calls
24 from IPython.utils.decorators import flag_calls
25
25
26 # If user specifies a GUI, that dictates the backend, otherwise we read the
26 # If user specifies a GUI, that dictates the backend, otherwise we read the
27 # user's mpl default from the mpl rc structure
27 # user's mpl default from the mpl rc structure
28 backends = {'tk': 'TkAgg',
28 backends = {'tk': 'TkAgg',
29 'gtk': 'GTKAgg',
29 'gtk': 'GTKAgg',
30 'wx': 'WXAgg',
30 'wx': 'WXAgg',
31 'qt': 'Qt4Agg', # qt3 not supported
31 'qt': 'Qt4Agg', # qt3 not supported
32 'qt4': 'Qt4Agg',
32 'qt4': 'Qt4Agg',
33 'osx': 'MacOSX',
33 'osx': 'MacOSX',
34 'inline' : 'module://IPython.zmq.pylab.backend_inline'}
34 'inline' : 'module://IPython.zmq.pylab.backend_inline'}
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Matplotlib utilities
37 # Matplotlib utilities
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40
40
41 def getfigs(*fig_nums):
41 def getfigs(*fig_nums):
42 """Get a list of matplotlib figures by figure numbers.
42 """Get a list of matplotlib figures by figure numbers.
43
43
44 If no arguments are given, all available figures are returned. If the
44 If no arguments are given, all available figures are returned. If the
45 argument list contains references to invalid figures, a warning is printed
45 argument list contains references to invalid figures, a warning is printed
46 but the function continues pasting further figures.
46 but the function continues pasting further figures.
47
47
48 Parameters
48 Parameters
49 ----------
49 ----------
50 figs : tuple
50 figs : tuple
51 A tuple of ints giving the figure numbers of the figures to return.
51 A tuple of ints giving the figure numbers of the figures to return.
52 """
52 """
53 from matplotlib._pylab_helpers import Gcf
53 from matplotlib._pylab_helpers import Gcf
54 if not fig_nums:
54 if not fig_nums:
55 fig_managers = Gcf.get_all_fig_managers()
55 fig_managers = Gcf.get_all_fig_managers()
56 return [fm.canvas.figure for fm in fig_managers]
56 return [fm.canvas.figure for fm in fig_managers]
57 else:
57 else:
58 figs = []
58 figs = []
59 for num in fig_nums:
59 for num in fig_nums:
60 f = Gcf.figs.get(num)
60 f = Gcf.figs.get(num)
61 if f is None:
61 if f is None:
62 print('Warning: figure %s not available.' % num)
62 print('Warning: figure %s not available.' % num)
63 figs.append(f.canvas.figure)
63 figs.append(f.canvas.figure)
64 return figs
64 return figs
65
65
66
66
67 def figsize(sizex, sizey):
67 def figsize(sizex, sizey):
68 """Set the default figure size to be [sizex, sizey].
68 """Set the default figure size to be [sizex, sizey].
69
69
70 This is just an easy to remember, convenience wrapper that sets::
70 This is just an easy to remember, convenience wrapper that sets::
71
71
72 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
72 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
73 """
73 """
74 import matplotlib
74 import matplotlib
75 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
75 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
76
76
77
77
78 def figure_to_svg(fig):
78 def figure_to_svg(fig):
79 """Convert a figure to svg for inline display."""
79 """Convert a figure to svg for inline display."""
80 # When there's an empty figure, we shouldn't return anything, otherwise we
81 # get big blank areas in the qt console.
82 if not fig.axes:
83 return
84
80 fc = fig.get_facecolor()
85 fc = fig.get_facecolor()
81 ec = fig.get_edgecolor()
86 ec = fig.get_edgecolor()
82 fig.set_facecolor('white')
87 fig.set_facecolor('white')
83 fig.set_edgecolor('white')
88 fig.set_edgecolor('white')
84 try:
89 try:
85 string_io = StringIO()
90 string_io = StringIO()
86 fig.canvas.print_figure(string_io, format='svg')
91 fig.canvas.print_figure(string_io, format='svg')
87 svg = string_io.getvalue()
92 svg = string_io.getvalue()
88 finally:
93 finally:
89 fig.set_facecolor(fc)
94 fig.set_facecolor(fc)
90 fig.set_edgecolor(ec)
95 fig.set_edgecolor(ec)
91 return svg
96 return svg
92
97
93
98
94 # We need a little factory function here to create the closure where
99 # We need a little factory function here to create the closure where
95 # safe_execfile can live.
100 # safe_execfile can live.
96 def mpl_runner(safe_execfile):
101 def mpl_runner(safe_execfile):
97 """Factory to return a matplotlib-enabled runner for %run.
102 """Factory to return a matplotlib-enabled runner for %run.
98
103
99 Parameters
104 Parameters
100 ----------
105 ----------
101 safe_execfile : function
106 safe_execfile : function
102 This must be a function with the same interface as the
107 This must be a function with the same interface as the
103 :meth:`safe_execfile` method of IPython.
108 :meth:`safe_execfile` method of IPython.
104
109
105 Returns
110 Returns
106 -------
111 -------
107 A function suitable for use as the ``runner`` argument of the %run magic
112 A function suitable for use as the ``runner`` argument of the %run magic
108 function.
113 function.
109 """
114 """
110
115
111 def mpl_execfile(fname,*where,**kw):
116 def mpl_execfile(fname,*where,**kw):
112 """matplotlib-aware wrapper around safe_execfile.
117 """matplotlib-aware wrapper around safe_execfile.
113
118
114 Its interface is identical to that of the :func:`execfile` builtin.
119 Its interface is identical to that of the :func:`execfile` builtin.
115
120
116 This is ultimately a call to execfile(), but wrapped in safeties to
121 This is ultimately a call to execfile(), but wrapped in safeties to
117 properly handle interactive rendering."""
122 properly handle interactive rendering."""
118
123
119 import matplotlib
124 import matplotlib
120 import matplotlib.pylab as pylab
125 import matplotlib.pylab as pylab
121
126
122 #print '*** Matplotlib runner ***' # dbg
127 #print '*** Matplotlib runner ***' # dbg
123 # turn off rendering until end of script
128 # turn off rendering until end of script
124 is_interactive = matplotlib.rcParams['interactive']
129 is_interactive = matplotlib.rcParams['interactive']
125 matplotlib.interactive(False)
130 matplotlib.interactive(False)
126 safe_execfile(fname,*where,**kw)
131 safe_execfile(fname,*where,**kw)
127 matplotlib.interactive(is_interactive)
132 matplotlib.interactive(is_interactive)
128 # make rendering call now, if the user tried to do it
133 # make rendering call now, if the user tried to do it
129 if pylab.draw_if_interactive.called:
134 if pylab.draw_if_interactive.called:
130 pylab.draw()
135 pylab.draw()
131 pylab.draw_if_interactive.called = False
136 pylab.draw_if_interactive.called = False
132
137
133 return mpl_execfile
138 return mpl_execfile
134
139
135
140
136 #-----------------------------------------------------------------------------
141 #-----------------------------------------------------------------------------
137 # Code for initializing matplotlib and importing pylab
142 # Code for initializing matplotlib and importing pylab
138 #-----------------------------------------------------------------------------
143 #-----------------------------------------------------------------------------
139
144
140
145
141 def find_gui_and_backend(gui=None):
146 def find_gui_and_backend(gui=None):
142 """Given a gui string return the gui and mpl backend.
147 """Given a gui string return the gui and mpl backend.
143
148
144 Parameters
149 Parameters
145 ----------
150 ----------
146 gui : str
151 gui : str
147 Can be one of ('tk','gtk','wx','qt','qt4','inline').
152 Can be one of ('tk','gtk','wx','qt','qt4','inline').
148
153
149 Returns
154 Returns
150 -------
155 -------
151 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
156 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
152 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline').
157 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline').
153 """
158 """
154
159
155 import matplotlib
160 import matplotlib
156
161
157 if gui:
162 if gui:
158 # select backend based on requested gui
163 # select backend based on requested gui
159 backend = backends[gui]
164 backend = backends[gui]
160 else:
165 else:
161 backend = matplotlib.rcParams['backend']
166 backend = matplotlib.rcParams['backend']
162 # In this case, we need to find what the appropriate gui selection call
167 # In this case, we need to find what the appropriate gui selection call
163 # should be for IPython, so we can activate inputhook accordingly
168 # should be for IPython, so we can activate inputhook accordingly
164 g2b = backends # maps gui names to mpl backend names
169 g2b = backends # maps gui names to mpl backend names
165 b2g = dict(zip(g2b.values(), g2b.keys())) # reverse dict
170 b2g = dict(zip(g2b.values(), g2b.keys())) # reverse dict
166 gui = b2g.get(backend, None)
171 gui = b2g.get(backend, None)
167 return gui, backend
172 return gui, backend
168
173
169
174
170 def activate_matplotlib(backend):
175 def activate_matplotlib(backend):
171 """Activate the given backend and set interactive to True."""
176 """Activate the given backend and set interactive to True."""
172
177
173 import matplotlib
178 import matplotlib
174 if backend.startswith('module://'):
179 if backend.startswith('module://'):
175 # Work around bug in matplotlib: matplotlib.use converts the
180 # Work around bug in matplotlib: matplotlib.use converts the
176 # backend_id to lowercase even if a module name is specified!
181 # backend_id to lowercase even if a module name is specified!
177 matplotlib.rcParams['backend'] = backend
182 matplotlib.rcParams['backend'] = backend
178 else:
183 else:
179 matplotlib.use(backend)
184 matplotlib.use(backend)
180 matplotlib.interactive(True)
185 matplotlib.interactive(True)
181
186
182 # This must be imported last in the matplotlib series, after
187 # This must be imported last in the matplotlib series, after
183 # backend/interactivity choices have been made
188 # backend/interactivity choices have been made
184 import matplotlib.pylab as pylab
189 import matplotlib.pylab as pylab
185
190
186 # XXX For now leave this commented out, but depending on discussions with
191 # XXX For now leave this commented out, but depending on discussions with
187 # mpl-dev, we may be able to allow interactive switching...
192 # mpl-dev, we may be able to allow interactive switching...
188 #import matplotlib.pyplot
193 #import matplotlib.pyplot
189 #matplotlib.pyplot.switch_backend(backend)
194 #matplotlib.pyplot.switch_backend(backend)
190
195
191 pylab.show._needmain = False
196 pylab.show._needmain = False
192 # We need to detect at runtime whether show() is called by the user.
197 # We need to detect at runtime whether show() is called by the user.
193 # For this, we wrap it into a decorator which adds a 'called' flag.
198 # For this, we wrap it into a decorator which adds a 'called' flag.
194 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
199 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
195
200
196
201
197 def import_pylab(user_ns, backend, import_all=True, shell=None):
202 def import_pylab(user_ns, backend, import_all=True, shell=None):
198 """Import the standard pylab symbols into user_ns."""
203 """Import the standard pylab symbols into user_ns."""
199
204
200 # Import numpy as np/pyplot as plt are conventions we're trying to
205 # Import numpy as np/pyplot as plt are conventions we're trying to
201 # somewhat standardize on. Making them available to users by default
206 # somewhat standardize on. Making them available to users by default
202 # will greatly help this.
207 # will greatly help this.
203 s = ("import numpy\n"
208 s = ("import numpy\n"
204 "import matplotlib\n"
209 "import matplotlib\n"
205 "from matplotlib import pylab, mlab, pyplot\n"
210 "from matplotlib import pylab, mlab, pyplot\n"
206 "np = numpy\n"
211 "np = numpy\n"
207 "plt = pyplot\n"
212 "plt = pyplot\n"
208 )
213 )
209 exec s in user_ns
214 exec s in user_ns
210
215
211 if shell is not None:
216 if shell is not None:
212 exec s in shell.user_ns_hidden
217 exec s in shell.user_ns_hidden
213 # If using our svg payload backend, register the post-execution
218 # If using our svg payload backend, register the post-execution
214 # function that will pick up the results for display. This can only be
219 # function that will pick up the results for display. This can only be
215 # done with access to the real shell object.
220 # done with access to the real shell object.
216 if backend == backends['inline']:
221 if backend == backends['inline']:
217 from IPython.zmq.pylab.backend_inline import flush_svg
222 from IPython.zmq.pylab.backend_inline import flush_svg
218 from matplotlib import pyplot
223 from matplotlib import pyplot
219 shell.register_post_execute(flush_svg)
224 shell.register_post_execute(flush_svg)
220 # The typical default figure size is too large for inline use,
225 # The typical default figure size is too large for inline use,
221 # so we shrink the figure size to 6x4, and tweak fonts to
226 # so we shrink the figure size to 6x4, and tweak fonts to
222 # make that fit. This is configurable via Global.pylab_inline_rc,
227 # make that fit. This is configurable via Global.pylab_inline_rc,
223 # or rather it will be once the zmq kernel is hooked up to
228 # or rather it will be once the zmq kernel is hooked up to
224 # the config system.
229 # the config system.
225
230
226 default_rc = {
231 default_rc = {
227 'figure.figsize': (6.0,4.0),
232 'figure.figsize': (6.0,4.0),
228 # 12pt labels get cutoff on 6x4 logplots, so use 10pt.
233 # 12pt labels get cutoff on 6x4 logplots, so use 10pt.
229 'font.size': 10,
234 'font.size': 10,
230 # 10pt still needs a little more room on the xlabel:
235 # 10pt still needs a little more room on the xlabel:
231 'figure.subplot.bottom' : .125
236 'figure.subplot.bottom' : .125
232 }
237 }
233 rc = getattr(shell.config.Global, 'pylab_inline_rc', default_rc)
238 rc = getattr(shell.config.Global, 'pylab_inline_rc', default_rc)
234 pyplot.rcParams.update(rc)
239 pyplot.rcParams.update(rc)
235 shell.config.Global.pylab_inline_rc = rc
240 shell.config.Global.pylab_inline_rc = rc
236
241
237 # Add 'figsize' to pyplot and to the user's namespace
242 # Add 'figsize' to pyplot and to the user's namespace
238 user_ns['figsize'] = pyplot.figsize = figsize
243 user_ns['figsize'] = pyplot.figsize = figsize
239 shell.user_ns_hidden['figsize'] = figsize
244 shell.user_ns_hidden['figsize'] = figsize
240
245
241 # The old pastefig function has been replaced by display
246 # The old pastefig function has been replaced by display
242 # Always add this svg formatter so display works.
247 # Always add this svg formatter so display works.
243 from IPython.zmq.pylab.backend_inline import figure_to_svg
244 from IPython.core.display import display, display_svg
248 from IPython.core.display import display, display_svg
245 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
249 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
246 svg_formatter.for_type_by_name(
250 svg_formatter.for_type_by_name(
247 'matplotlib.figure','Figure',figure_to_svg
251 'matplotlib.figure','Figure',figure_to_svg
248 )
252 )
249 # Add display and display_png to the user's namespace
253 # Add display and display_png to the user's namespace
250 user_ns['display'] = display
254 user_ns['display'] = display
251 shell.user_ns_hidden['display'] = display
255 shell.user_ns_hidden['display'] = display
252 user_ns['display_svg'] = display_svg
256 user_ns['display_svg'] = display_svg
253 shell.user_ns_hidden['display_svg'] = display_svg
257 shell.user_ns_hidden['display_svg'] = display_svg
254 user_ns['getfigs'] = getfigs
258 user_ns['getfigs'] = getfigs
255 shell.user_ns_hidden['getfigs'] = getfigs
259 shell.user_ns_hidden['getfigs'] = getfigs
256
260
257 if import_all:
261 if import_all:
258 s = ("from matplotlib.pylab import *\n"
262 s = ("from matplotlib.pylab import *\n"
259 "from numpy import *\n")
263 "from numpy import *\n")
260 exec s in user_ns
264 exec s in user_ns
261 if shell is not None:
265 if shell is not None:
262 exec s in shell.user_ns_hidden
266 exec s in shell.user_ns_hidden
263
267
264
268
265 def pylab_activate(user_ns, gui=None, import_all=True):
269 def pylab_activate(user_ns, gui=None, import_all=True):
266 """Activate pylab mode in the user's namespace.
270 """Activate pylab mode in the user's namespace.
267
271
268 Loads and initializes numpy, matplotlib and friends for interactive use.
272 Loads and initializes numpy, matplotlib and friends for interactive use.
269
273
270 Parameters
274 Parameters
271 ----------
275 ----------
272 user_ns : dict
276 user_ns : dict
273 Namespace where the imports will occur.
277 Namespace where the imports will occur.
274
278
275 gui : optional, string
279 gui : optional, string
276 A valid gui name following the conventions of the %gui magic.
280 A valid gui name following the conventions of the %gui magic.
277
281
278 import_all : optional, boolean
282 import_all : optional, boolean
279 If true, an 'import *' is done from numpy and pylab.
283 If true, an 'import *' is done from numpy and pylab.
280
284
281 Returns
285 Returns
282 -------
286 -------
283 The actual gui used (if not given as input, it was obtained from matplotlib
287 The actual gui used (if not given as input, it was obtained from matplotlib
284 itself, and will be needed next to configure IPython's gui integration.
288 itself, and will be needed next to configure IPython's gui integration.
285 """
289 """
286 gui, backend = find_gui_and_backend(gui)
290 gui, backend = find_gui_and_backend(gui)
287 activate_matplotlib(backend)
291 activate_matplotlib(backend)
288 import_pylab(user_ns, backend)
292 import_pylab(user_ns, backend)
289
293
290 print """
294 print """
291 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
295 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
292 For more information, type 'help(pylab)'.""" % backend
296 For more information, type 'help(pylab)'.""" % backend
293
297
294 return gui
298 return gui
295
299
@@ -1,427 +1,433
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Test Suite Runner.
2 """IPython Test Suite Runner.
3
3
4 This module provides a main entry point to a user script to test IPython
4 This module provides a main entry point to a user script to test IPython
5 itself from the command line. There are two ways of running this script:
5 itself from the command line. There are two ways of running this script:
6
6
7 1. With the syntax `iptest all`. This runs our entire test suite by
7 1. With the syntax `iptest all`. This runs our entire test suite by
8 calling this script (with different arguments) recursively. This
8 calling this script (with different arguments) recursively. This
9 causes modules and package to be tested in different processes, using nose
9 causes modules and package to be tested in different processes, using nose
10 or trial where appropriate.
10 or trial where appropriate.
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 the script simply calls nose, but with special command line flags and
12 the script simply calls nose, but with special command line flags and
13 plugins loaded.
13 plugins loaded.
14
14
15 """
15 """
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2009 The IPython Development Team
18 # Copyright (C) 2009 The IPython Development Team
19 #
19 #
20 # Distributed under the terms of the BSD License. The full license is in
20 # Distributed under the terms of the BSD License. The full license is in
21 # the file COPYING, distributed as part of this software.
21 # the file COPYING, distributed as part of this software.
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Imports
25 # Imports
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 # Stdlib
28 # Stdlib
29 import os
29 import os
30 import os.path as path
30 import os.path as path
31 import signal
31 import signal
32 import sys
32 import sys
33 import subprocess
33 import subprocess
34 import tempfile
34 import tempfile
35 import time
35 import time
36 import warnings
36 import warnings
37
37
38 # Note: monkeypatch!
38 # Note: monkeypatch!
39 # We need to monkeypatch a small problem in nose itself first, before importing
39 # We need to monkeypatch a small problem in nose itself first, before importing
40 # it for actual use. This should get into nose upstream, but its release cycle
40 # it for actual use. This should get into nose upstream, but its release cycle
41 # is slow and we need it for our parametric tests to work correctly.
41 # is slow and we need it for our parametric tests to work correctly.
42 from IPython.testing import nosepatch
42 from IPython.testing import nosepatch
43 # Now, proceed to import nose itself
43 # Now, proceed to import nose itself
44 import nose.plugins.builtin
44 import nose.plugins.builtin
45 from nose.core import TestProgram
45 from nose.core import TestProgram
46
46
47 # Our own imports
47 # Our own imports
48 from IPython.utils.path import get_ipython_module_path
48 from IPython.utils.path import get_ipython_module_path
49 from IPython.utils.process import find_cmd, pycmd2argv
49 from IPython.utils.process import find_cmd, pycmd2argv
50 from IPython.utils.sysinfo import sys_info
50 from IPython.utils.sysinfo import sys_info
51
51
52 from IPython.testing import globalipapp
52 from IPython.testing import globalipapp
53 from IPython.testing.plugin.ipdoctest import IPythonDoctest
53 from IPython.testing.plugin.ipdoctest import IPythonDoctest
54 from IPython.external.decorators import KnownFailure
54 from IPython.external.decorators import KnownFailure
55
55
56 pjoin = path.join
56 pjoin = path.join
57
57
58
58
59 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
60 # Globals
60 # Globals
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62
62
63
63
64 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
65 # Warnings control
65 # Warnings control
66 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
67
67
68 # Twisted generates annoying warnings with Python 2.6, as will do other code
68 # Twisted generates annoying warnings with Python 2.6, as will do other code
69 # that imports 'sets' as of today
69 # that imports 'sets' as of today
70 warnings.filterwarnings('ignore', 'the sets module is deprecated',
70 warnings.filterwarnings('ignore', 'the sets module is deprecated',
71 DeprecationWarning )
71 DeprecationWarning )
72
72
73 # This one also comes from Twisted
73 # This one also comes from Twisted
74 warnings.filterwarnings('ignore', 'the sha module is deprecated',
74 warnings.filterwarnings('ignore', 'the sha module is deprecated',
75 DeprecationWarning)
75 DeprecationWarning)
76
76
77 # Wx on Fedora11 spits these out
77 # Wx on Fedora11 spits these out
78 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
78 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
79 UserWarning)
79 UserWarning)
80
80
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 # Logic for skipping doctests
82 # Logic for skipping doctests
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84
84
85 def test_for(mod, min_version=None):
85 def test_for(mod, min_version=None):
86 """Test to see if mod is importable."""
86 """Test to see if mod is importable."""
87 try:
87 try:
88 __import__(mod)
88 __import__(mod)
89 except (ImportError, RuntimeError):
89 except (ImportError, RuntimeError):
90 # GTK reports Runtime error if it can't be initialized even if it's
90 # GTK reports Runtime error if it can't be initialized even if it's
91 # importable.
91 # importable.
92 return False
92 return False
93 else:
93 else:
94 if min_version:
94 if min_version:
95 return sys.modules[mod].__version__ >= min_version
95 return sys.modules[mod].__version__ >= min_version
96 else:
96 else:
97 return True
97 return True
98
98
99 # Global dict where we can store information on what we have and what we don't
99 # Global dict where we can store information on what we have and what we don't
100 # have available at test run time
100 # have available at test run time
101 have = {}
101 have = {}
102
102
103 have['curses'] = test_for('_curses')
103 have['curses'] = test_for('_curses')
104 have['matplotlib'] = test_for('matplotlib')
105 have['pexpect'] = test_for('pexpect')
106 have['pymongo'] = test_for('pymongo')
104 have['wx'] = test_for('wx')
107 have['wx'] = test_for('wx')
105 have['wx.aui'] = test_for('wx.aui')
108 have['wx.aui'] = test_for('wx.aui')
106 have['pexpect'] = test_for('pexpect')
107 have['zmq'] = test_for('zmq', '2.1.4')
109 have['zmq'] = test_for('zmq', '2.1.4')
108 have['pymongo'] = test_for('pymongo')
109
110
110 #-----------------------------------------------------------------------------
111 #-----------------------------------------------------------------------------
111 # Functions and classes
112 # Functions and classes
112 #-----------------------------------------------------------------------------
113 #-----------------------------------------------------------------------------
113
114
114 def report():
115 def report():
115 """Return a string with a summary report of test-related variables."""
116 """Return a string with a summary report of test-related variables."""
116
117
117 out = [ sys_info(), '\n']
118 out = [ sys_info(), '\n']
118
119
119 avail = []
120 avail = []
120 not_avail = []
121 not_avail = []
121
122
122 for k, is_avail in have.items():
123 for k, is_avail in have.items():
123 if is_avail:
124 if is_avail:
124 avail.append(k)
125 avail.append(k)
125 else:
126 else:
126 not_avail.append(k)
127 not_avail.append(k)
127
128
128 if avail:
129 if avail:
129 out.append('\nTools and libraries available at test time:\n')
130 out.append('\nTools and libraries available at test time:\n')
130 avail.sort()
131 avail.sort()
131 out.append(' ' + ' '.join(avail)+'\n')
132 out.append(' ' + ' '.join(avail)+'\n')
132
133
133 if not_avail:
134 if not_avail:
134 out.append('\nTools and libraries NOT available at test time:\n')
135 out.append('\nTools and libraries NOT available at test time:\n')
135 not_avail.sort()
136 not_avail.sort()
136 out.append(' ' + ' '.join(not_avail)+'\n')
137 out.append(' ' + ' '.join(not_avail)+'\n')
137
138
138 return ''.join(out)
139 return ''.join(out)
139
140
140
141
141 def make_exclude():
142 def make_exclude():
142 """Make patterns of modules and packages to exclude from testing.
143 """Make patterns of modules and packages to exclude from testing.
143
144
144 For the IPythonDoctest plugin, we need to exclude certain patterns that
145 For the IPythonDoctest plugin, we need to exclude certain patterns that
145 cause testing problems. We should strive to minimize the number of
146 cause testing problems. We should strive to minimize the number of
146 skipped modules, since this means untested code.
147 skipped modules, since this means untested code.
147
148
148 These modules and packages will NOT get scanned by nose at all for tests.
149 These modules and packages will NOT get scanned by nose at all for tests.
149 """
150 """
150 # Simple utility to make IPython paths more readably, we need a lot of
151 # Simple utility to make IPython paths more readably, we need a lot of
151 # these below
152 # these below
152 ipjoin = lambda *paths: pjoin('IPython', *paths)
153 ipjoin = lambda *paths: pjoin('IPython', *paths)
153
154
154 exclusions = [ipjoin('external'),
155 exclusions = [ipjoin('external'),
155 pjoin('IPython_doctest_plugin'),
156 pjoin('IPython_doctest_plugin'),
156 ipjoin('quarantine'),
157 ipjoin('quarantine'),
157 ipjoin('deathrow'),
158 ipjoin('deathrow'),
158 ipjoin('testing', 'attic'),
159 ipjoin('testing', 'attic'),
159 # This guy is probably attic material
160 # This guy is probably attic material
160 ipjoin('testing', 'mkdoctests'),
161 ipjoin('testing', 'mkdoctests'),
161 # Testing inputhook will need a lot of thought, to figure out
162 # Testing inputhook will need a lot of thought, to figure out
162 # how to have tests that don't lock up with the gui event
163 # how to have tests that don't lock up with the gui event
163 # loops in the picture
164 # loops in the picture
164 ipjoin('lib', 'inputhook'),
165 ipjoin('lib', 'inputhook'),
165 # Config files aren't really importable stand-alone
166 # Config files aren't really importable stand-alone
166 ipjoin('config', 'default'),
167 ipjoin('config', 'default'),
167 ipjoin('config', 'profile'),
168 ipjoin('config', 'profile'),
168 ]
169 ]
169
170
170 if not have['wx']:
171 if not have['wx']:
171 exclusions.append(ipjoin('lib', 'inputhookwx'))
172 exclusions.append(ipjoin('lib', 'inputhookwx'))
172
173
173 # We do this unconditionally, so that the test suite doesn't import
174 # We do this unconditionally, so that the test suite doesn't import
174 # gtk, changing the default encoding and masking some unicode bugs.
175 # gtk, changing the default encoding and masking some unicode bugs.
175 exclusions.append(ipjoin('lib', 'inputhookgtk'))
176 exclusions.append(ipjoin('lib', 'inputhookgtk'))
176
177
177 # These have to be skipped on win32 because the use echo, rm, cd, etc.
178 # These have to be skipped on win32 because the use echo, rm, cd, etc.
178 # See ticket https://bugs.launchpad.net/bugs/366982
179 # See ticket https://bugs.launchpad.net/bugs/366982
179 if sys.platform == 'win32':
180 if sys.platform == 'win32':
180 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
181 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
181 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
182 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
182
183
183 if not have['pexpect']:
184 if not have['pexpect']:
184 exclusions.extend([ipjoin('scripts', 'irunner'),
185 exclusions.extend([ipjoin('scripts', 'irunner'),
185 ipjoin('lib', 'irunner')])
186 ipjoin('lib', 'irunner')])
186
187
187 if not have['zmq']:
188 if not have['zmq']:
188 exclusions.append(ipjoin('zmq'))
189 exclusions.append(ipjoin('zmq'))
189 exclusions.append(ipjoin('parallel'))
190 exclusions.append(ipjoin('parallel'))
190
191
191 if not have['pymongo']:
192 if not have['pymongo']:
192 exclusions.append(ipjoin('parallel', 'controller', 'mongodb'))
193 exclusions.append(ipjoin('parallel', 'controller', 'mongodb'))
193
194
195 if not have['matplotlib']:
196 exclusions.extend([ipjoin('lib', 'pylabtools'),
197 ipjoin('lib', 'pylabtools',
198 'tests', 'test_pylabtools')])
199
194 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
200 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
195 if sys.platform == 'win32':
201 if sys.platform == 'win32':
196 exclusions = [s.replace('\\','\\\\') for s in exclusions]
202 exclusions = [s.replace('\\','\\\\') for s in exclusions]
197
203
198 return exclusions
204 return exclusions
199
205
200
206
201 class IPTester(object):
207 class IPTester(object):
202 """Call that calls iptest or trial in a subprocess.
208 """Call that calls iptest or trial in a subprocess.
203 """
209 """
204 #: string, name of test runner that will be called
210 #: string, name of test runner that will be called
205 runner = None
211 runner = None
206 #: list, parameters for test runner
212 #: list, parameters for test runner
207 params = None
213 params = None
208 #: list, arguments of system call to be made to call test runner
214 #: list, arguments of system call to be made to call test runner
209 call_args = None
215 call_args = None
210 #: list, process ids of subprocesses we start (for cleanup)
216 #: list, process ids of subprocesses we start (for cleanup)
211 pids = None
217 pids = None
212
218
213 def __init__(self, runner='iptest', params=None):
219 def __init__(self, runner='iptest', params=None):
214 """Create new test runner."""
220 """Create new test runner."""
215 p = os.path
221 p = os.path
216 if runner == 'iptest':
222 if runner == 'iptest':
217 iptest_app = get_ipython_module_path('IPython.testing.iptest')
223 iptest_app = get_ipython_module_path('IPython.testing.iptest')
218 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
224 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
219 else:
225 else:
220 raise Exception('Not a valid test runner: %s' % repr(runner))
226 raise Exception('Not a valid test runner: %s' % repr(runner))
221 if params is None:
227 if params is None:
222 params = []
228 params = []
223 if isinstance(params, str):
229 if isinstance(params, str):
224 params = [params]
230 params = [params]
225 self.params = params
231 self.params = params
226
232
227 # Assemble call
233 # Assemble call
228 self.call_args = self.runner+self.params
234 self.call_args = self.runner+self.params
229
235
230 # Store pids of anything we start to clean up on deletion, if possible
236 # Store pids of anything we start to clean up on deletion, if possible
231 # (on posix only, since win32 has no os.kill)
237 # (on posix only, since win32 has no os.kill)
232 self.pids = []
238 self.pids = []
233
239
234 if sys.platform == 'win32':
240 if sys.platform == 'win32':
235 def _run_cmd(self):
241 def _run_cmd(self):
236 # On Windows, use os.system instead of subprocess.call, because I
242 # On Windows, use os.system instead of subprocess.call, because I
237 # was having problems with subprocess and I just don't know enough
243 # was having problems with subprocess and I just don't know enough
238 # about win32 to debug this reliably. Os.system may be the 'old
244 # about win32 to debug this reliably. Os.system may be the 'old
239 # fashioned' way to do it, but it works just fine. If someone
245 # fashioned' way to do it, but it works just fine. If someone
240 # later can clean this up that's fine, as long as the tests run
246 # later can clean this up that's fine, as long as the tests run
241 # reliably in win32.
247 # reliably in win32.
242 # What types of problems are you having. They may be related to
248 # What types of problems are you having. They may be related to
243 # running Python in unboffered mode. BG.
249 # running Python in unboffered mode. BG.
244 return os.system(' '.join(self.call_args))
250 return os.system(' '.join(self.call_args))
245 else:
251 else:
246 def _run_cmd(self):
252 def _run_cmd(self):
247 # print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
253 # print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
248 subp = subprocess.Popen(self.call_args)
254 subp = subprocess.Popen(self.call_args)
249 self.pids.append(subp.pid)
255 self.pids.append(subp.pid)
250 # If this fails, the pid will be left in self.pids and cleaned up
256 # If this fails, the pid will be left in self.pids and cleaned up
251 # later, but if the wait call succeeds, then we can clear the
257 # later, but if the wait call succeeds, then we can clear the
252 # stored pid.
258 # stored pid.
253 retcode = subp.wait()
259 retcode = subp.wait()
254 self.pids.pop()
260 self.pids.pop()
255 return retcode
261 return retcode
256
262
257 def run(self):
263 def run(self):
258 """Run the stored commands"""
264 """Run the stored commands"""
259 try:
265 try:
260 return self._run_cmd()
266 return self._run_cmd()
261 except:
267 except:
262 import traceback
268 import traceback
263 traceback.print_exc()
269 traceback.print_exc()
264 return 1 # signal failure
270 return 1 # signal failure
265
271
266 def __del__(self):
272 def __del__(self):
267 """Cleanup on exit by killing any leftover processes."""
273 """Cleanup on exit by killing any leftover processes."""
268
274
269 if not hasattr(os, 'kill'):
275 if not hasattr(os, 'kill'):
270 return
276 return
271
277
272 for pid in self.pids:
278 for pid in self.pids:
273 try:
279 try:
274 print 'Cleaning stale PID:', pid
280 print 'Cleaning stale PID:', pid
275 os.kill(pid, signal.SIGKILL)
281 os.kill(pid, signal.SIGKILL)
276 except OSError:
282 except OSError:
277 # This is just a best effort, if we fail or the process was
283 # This is just a best effort, if we fail or the process was
278 # really gone, ignore it.
284 # really gone, ignore it.
279 pass
285 pass
280
286
281
287
282 def make_runners():
288 def make_runners():
283 """Define the top-level packages that need to be tested.
289 """Define the top-level packages that need to be tested.
284 """
290 """
285
291
286 # Packages to be tested via nose, that only depend on the stdlib
292 # Packages to be tested via nose, that only depend on the stdlib
287 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
293 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
288 'scripts', 'testing', 'utils' ]
294 'scripts', 'testing', 'utils' ]
289
295
290 if have['zmq']:
296 if have['zmq']:
291 nose_pkg_names.append('parallel')
297 nose_pkg_names.append('parallel')
292
298
293 # For debugging this code, only load quick stuff
299 # For debugging this code, only load quick stuff
294 #nose_pkg_names = ['core', 'extensions'] # dbg
300 #nose_pkg_names = ['core', 'extensions'] # dbg
295
301
296 # Make fully qualified package names prepending 'IPython.' to our name lists
302 # Make fully qualified package names prepending 'IPython.' to our name lists
297 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
303 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
298
304
299 # Make runners
305 # Make runners
300 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
306 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
301
307
302 return runners
308 return runners
303
309
304
310
305 def run_iptest():
311 def run_iptest():
306 """Run the IPython test suite using nose.
312 """Run the IPython test suite using nose.
307
313
308 This function is called when this script is **not** called with the form
314 This function is called when this script is **not** called with the form
309 `iptest all`. It simply calls nose with appropriate command line flags
315 `iptest all`. It simply calls nose with appropriate command line flags
310 and accepts all of the standard nose arguments.
316 and accepts all of the standard nose arguments.
311 """
317 """
312
318
313 warnings.filterwarnings('ignore',
319 warnings.filterwarnings('ignore',
314 'This will be removed soon. Use IPython.testing.util instead')
320 'This will be removed soon. Use IPython.testing.util instead')
315
321
316 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
322 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
317
323
318 # Loading ipdoctest causes problems with Twisted, but
324 # Loading ipdoctest causes problems with Twisted, but
319 # our test suite runner now separates things and runs
325 # our test suite runner now separates things and runs
320 # all Twisted tests with trial.
326 # all Twisted tests with trial.
321 '--with-ipdoctest',
327 '--with-ipdoctest',
322 '--ipdoctest-tests','--ipdoctest-extension=txt',
328 '--ipdoctest-tests','--ipdoctest-extension=txt',
323
329
324 # We add --exe because of setuptools' imbecility (it
330 # We add --exe because of setuptools' imbecility (it
325 # blindly does chmod +x on ALL files). Nose does the
331 # blindly does chmod +x on ALL files). Nose does the
326 # right thing and it tries to avoid executables,
332 # right thing and it tries to avoid executables,
327 # setuptools unfortunately forces our hand here. This
333 # setuptools unfortunately forces our hand here. This
328 # has been discussed on the distutils list and the
334 # has been discussed on the distutils list and the
329 # setuptools devs refuse to fix this problem!
335 # setuptools devs refuse to fix this problem!
330 '--exe',
336 '--exe',
331 ]
337 ]
332
338
333 if nose.__version__ >= '0.11':
339 if nose.__version__ >= '0.11':
334 # I don't fully understand why we need this one, but depending on what
340 # I don't fully understand why we need this one, but depending on what
335 # directory the test suite is run from, if we don't give it, 0 tests
341 # directory the test suite is run from, if we don't give it, 0 tests
336 # get run. Specifically, if the test suite is run from the source dir
342 # get run. Specifically, if the test suite is run from the source dir
337 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
343 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
338 # even if the same call done in this directory works fine). It appears
344 # even if the same call done in this directory works fine). It appears
339 # that if the requested package is in the current dir, nose bails early
345 # that if the requested package is in the current dir, nose bails early
340 # by default. Since it's otherwise harmless, leave it in by default
346 # by default. Since it's otherwise harmless, leave it in by default
341 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
347 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
342 argv.append('--traverse-namespace')
348 argv.append('--traverse-namespace')
343
349
344 # Construct list of plugins, omitting the existing doctest plugin, which
350 # Construct list of plugins, omitting the existing doctest plugin, which
345 # ours replaces (and extends).
351 # ours replaces (and extends).
346 plugins = [IPythonDoctest(make_exclude()), KnownFailure()]
352 plugins = [IPythonDoctest(make_exclude()), KnownFailure()]
347 for p in nose.plugins.builtin.plugins:
353 for p in nose.plugins.builtin.plugins:
348 plug = p()
354 plug = p()
349 if plug.name == 'doctest':
355 if plug.name == 'doctest':
350 continue
356 continue
351 plugins.append(plug)
357 plugins.append(plug)
352
358
353 # We need a global ipython running in this process
359 # We need a global ipython running in this process
354 globalipapp.start_ipython()
360 globalipapp.start_ipython()
355 # Now nose can run
361 # Now nose can run
356 TestProgram(argv=argv, plugins=plugins)
362 TestProgram(argv=argv, plugins=plugins)
357
363
358
364
359 def run_iptestall():
365 def run_iptestall():
360 """Run the entire IPython test suite by calling nose and trial.
366 """Run the entire IPython test suite by calling nose and trial.
361
367
362 This function constructs :class:`IPTester` instances for all IPython
368 This function constructs :class:`IPTester` instances for all IPython
363 modules and package and then runs each of them. This causes the modules
369 modules and package and then runs each of them. This causes the modules
364 and packages of IPython to be tested each in their own subprocess using
370 and packages of IPython to be tested each in their own subprocess using
365 nose or twisted.trial appropriately.
371 nose or twisted.trial appropriately.
366 """
372 """
367
373
368 runners = make_runners()
374 runners = make_runners()
369
375
370 # Run the test runners in a temporary dir so we can nuke it when finished
376 # Run the test runners in a temporary dir so we can nuke it when finished
371 # to clean up any junk files left over by accident. This also makes it
377 # to clean up any junk files left over by accident. This also makes it
372 # robust against being run in non-writeable directories by mistake, as the
378 # robust against being run in non-writeable directories by mistake, as the
373 # temp dir will always be user-writeable.
379 # temp dir will always be user-writeable.
374 curdir = os.getcwd()
380 curdir = os.getcwd()
375 testdir = tempfile.gettempdir()
381 testdir = tempfile.gettempdir()
376 os.chdir(testdir)
382 os.chdir(testdir)
377
383
378 # Run all test runners, tracking execution time
384 # Run all test runners, tracking execution time
379 failed = []
385 failed = []
380 t_start = time.time()
386 t_start = time.time()
381 try:
387 try:
382 for (name, runner) in runners:
388 for (name, runner) in runners:
383 print '*'*70
389 print '*'*70
384 print 'IPython test group:',name
390 print 'IPython test group:',name
385 res = runner.run()
391 res = runner.run()
386 if res:
392 if res:
387 failed.append( (name, runner) )
393 failed.append( (name, runner) )
388 finally:
394 finally:
389 os.chdir(curdir)
395 os.chdir(curdir)
390 t_end = time.time()
396 t_end = time.time()
391 t_tests = t_end - t_start
397 t_tests = t_end - t_start
392 nrunners = len(runners)
398 nrunners = len(runners)
393 nfail = len(failed)
399 nfail = len(failed)
394 # summarize results
400 # summarize results
395 print
401 print
396 print '*'*70
402 print '*'*70
397 print 'Test suite completed for system with the following information:'
403 print 'Test suite completed for system with the following information:'
398 print report()
404 print report()
399 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
405 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
400 print
406 print
401 print 'Status:'
407 print 'Status:'
402 if not failed:
408 if not failed:
403 print 'OK'
409 print 'OK'
404 else:
410 else:
405 # If anything went wrong, point out what command to rerun manually to
411 # If anything went wrong, point out what command to rerun manually to
406 # see the actual errors and individual summary
412 # see the actual errors and individual summary
407 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
413 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
408 for name, failed_runner in failed:
414 for name, failed_runner in failed:
409 print '-'*40
415 print '-'*40
410 print 'Runner failed:',name
416 print 'Runner failed:',name
411 print 'You may wish to rerun this one individually, with:'
417 print 'You may wish to rerun this one individually, with:'
412 print ' '.join(failed_runner.call_args)
418 print ' '.join(failed_runner.call_args)
413 print
419 print
414
420
415
421
416 def main():
422 def main():
417 for arg in sys.argv[1:]:
423 for arg in sys.argv[1:]:
418 if arg.startswith('IPython'):
424 if arg.startswith('IPython'):
419 # This is in-process
425 # This is in-process
420 run_iptest()
426 run_iptest()
421 else:
427 else:
422 # This starts subprocesses
428 # This starts subprocesses
423 run_iptestall()
429 run_iptestall()
424
430
425
431
426 if __name__ == '__main__':
432 if __name__ == '__main__':
427 main()
433 main()
@@ -1,73 +1,83
1 """Produce SVG versions of active plots for display by the rich Qt frontend.
1 """Produce SVG versions of active plots for display by the rich Qt frontend.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Imports
4 # Imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 from __future__ import print_function
6 from __future__ import print_function
7
7
8 # Standard library imports
8 # Standard library imports
9 import sys
9
10
11 # Third-party imports
10 import matplotlib
12 import matplotlib
11 from matplotlib.backends.backend_svg import new_figure_manager
13 from matplotlib.backends.backend_svg import new_figure_manager
12 from matplotlib._pylab_helpers import Gcf
14 from matplotlib._pylab_helpers import Gcf
13
15
14 # Local imports.
16 # Local imports.
15 from IPython.core.displaypub import publish_display_data
17 from IPython.core.displaypub import publish_display_data
16 from IPython.lib.pylabtools import figure_to_svg
18 from IPython.lib.pylabtools import figure_to_svg
17
19
18 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
19 # Functions
21 # Functions
20 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
21
23
22 def show(close=False):
24 def show(close=False):
23 """Show all figures as SVG payloads sent to the IPython clients.
25 """Show all figures as SVG payloads sent to the IPython clients.
24
26
25 Parameters
27 Parameters
26 ----------
28 ----------
27 close : bool, optional
29 close : bool, optional
28 If true, a ``plt.close('all')`` call is automatically issued after
30 If true, a ``plt.close('all')`` call is automatically issued after
29 sending all the SVG figures. If this is set, the figures will entirely
31 sending all the SVG figures. If this is set, the figures will entirely
30 removed from the internal list of figures.
32 removed from the internal list of figures.
31 """
33 """
32 for figure_manager in Gcf.get_all_fig_managers():
34 for figure_manager in Gcf.get_all_fig_managers():
33 send_svg_figure(figure_manager.canvas.figure)
35 send_svg_figure(figure_manager.canvas.figure)
34 if close:
36 if close:
35 matplotlib.pyplot.close('all')
37 matplotlib.pyplot.close('all')
36
38
37
39
38 # This flag will be reset by draw_if_interactive when called
40 # This flag will be reset by draw_if_interactive when called
39 show._draw_called = False
41 show._draw_called = False
40
42
41
43
42 def draw_if_interactive():
44 def draw_if_interactive():
43 """
45 """
44 Is called after every pylab drawing command
46 Is called after every pylab drawing command
45 """
47 """
46 # We simply flag we were called and otherwise do nothing. At the end of
48 # We simply flag we were called and otherwise do nothing. At the end of
47 # the code execution, a separate call to show_close() will act upon this.
49 # the code execution, a separate call to show_close() will act upon this.
48 show._draw_called = True
50 show._draw_called = True
49
51
50
52
51 def flush_svg():
53 def flush_svg():
52 """Call show, close all open figures, sending all SVG images.
54 """Call show, close all open figures, sending all SVG images.
53
55
54 This is meant to be called automatically and will call show() if, during
56 This is meant to be called automatically and will call show() if, during
55 prior code execution, there had been any calls to draw_if_interactive.
57 prior code execution, there had been any calls to draw_if_interactive.
56 """
58 """
57 if show._draw_called:
59 if show._draw_called:
58 # Show is called with the default close=False here, otherwise, the
60 # Show is called with the default close=False here, otherwise, the
59 # Figure will be closed and not available for future plotting.
61 # Figure will be closed and not available for future plotting.
60 show()
62 show()
61 show._draw_called = False
63 show._draw_called = False
62
64
63
65
64 def send_svg_figure(fig):
66 def send_svg_figure(fig):
65 """Draw the current figure and send it as an SVG payload.
67 """Draw the current figure and send it as an SVG payload.
66 """
68 """
69 # For an empty figure, don't even bother calling figure_to_svg, to avoid
70 # big blank spaces in the qt console
71 if not fig.axes:
72 return
73
67 svg = figure_to_svg(fig)
74 svg = figure_to_svg(fig)
75 # flush text streams before sending figures, helps a little with output
76 # synchronization in the console (though it's a bandaid, not a real sln)
77 sys.stdout.flush(); sys.stderr.flush()
68 publish_display_data(
78 publish_display_data(
69 'IPython.zmq.pylab.backend_inline.send_svg_figure',
79 'IPython.zmq.pylab.backend_inline.send_svg_figure',
70 'Matplotlib Plot',
80 'Matplotlib Plot',
71 {'image/svg+xml' : svg}
81 {'image/svg+xml' : svg}
72 )
82 )
73
83
General Comments 0
You need to be logged in to leave comments. Login now