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