##// END OF EJS Templates
Merge pull request #3568 from minrk/pylab-no-import...
Paul Ivanov -
r11487:9e253ecd merge
parent child Browse files
Show More
@@ -55,7 +55,6 b' from IPython.core.macro import Macro'
55 55 from IPython.core.payload import PayloadManager
56 56 from IPython.core.prefilter import PrefilterManager
57 57 from IPython.core.profiledir import ProfileDir
58 from IPython.core.pylabtools import pylab_activate
59 58 from IPython.core.prompts import PromptManager
60 59 from IPython.lib.latextools import LaTeXTool
61 60 from IPython.testing.skipdoctest import skip_doctest
@@ -2838,6 +2837,51 b' class InteractiveShell(SingletonConfigurable):'
2838 2837
2839 2838 def enable_gui(self, gui=None):
2840 2839 raise NotImplementedError('Implement enable_gui in a subclass')
2840
2841 def enable_matplotlib(self, gui=None):
2842 """Enable interactive matplotlib and inline figure support.
2843
2844 This takes the following steps:
2845
2846 1. select the appropriate eventloop and matplotlib backend
2847 2. set up matplotlib for interactive use with that backend
2848 3. configure formatters for inline figure display
2849 4. enable the selected gui eventloop
2850
2851 Parameters
2852 ----------
2853 gui : optional, string
2854 If given, dictates the choice of matplotlib GUI backend to use
2855 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2856 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2857 matplotlib (as dictated by the matplotlib build-time options plus the
2858 user's matplotlibrc configuration file). Note that not all backends
2859 make sense in all contexts, for example a terminal ipython can't
2860 display figures inline.
2861 """
2862 from IPython.core import pylabtools as pt
2863 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
2864
2865 if gui != 'inline':
2866 # If we have our first gui selection, store it
2867 if self.pylab_gui_select is None:
2868 self.pylab_gui_select = gui
2869 # Otherwise if they are different
2870 elif gui != self.pylab_gui_select:
2871 print ('Warning: Cannot change to a different GUI toolkit: %s.'
2872 ' Using %s instead.' % (gui, self.pylab_gui_select))
2873 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
2874
2875 pt.activate_matplotlib(backend)
2876 pt.configure_inline_support(self, backend)
2877
2878 # Now we must activate the gui pylab wants to use, and fix %run to take
2879 # plot updates into account
2880 self.enable_gui(gui)
2881 self.magics_manager.registry['ExecutionMagics'].default_runner = \
2882 pt.mpl_runner(self.safe_execfile)
2883
2884 return gui, backend
2841 2885
2842 2886 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
2843 2887 """Activate pylab support at runtime.
@@ -2846,6 +2890,8 b' class InteractiveShell(SingletonConfigurable):'
2846 2890 namespace all of numpy and pylab, and configures IPython to correctly
2847 2891 interact with the GUI event loop. The GUI backend to be used can be
2848 2892 optionally selected with the optional ``gui`` argument.
2893
2894 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
2849 2895
2850 2896 Parameters
2851 2897 ----------
@@ -2857,30 +2903,29 b' class InteractiveShell(SingletonConfigurable):'
2857 2903 user's matplotlibrc configuration file). Note that not all backends
2858 2904 make sense in all contexts, for example a terminal ipython can't
2859 2905 display figures inline.
2906 import_all : optional, bool, default: True
2907 Whether to do `from numpy import *` and `from pylab import *`
2908 in addition to module imports.
2909 welcome_message : deprecated
2910 This argument is ignored, no welcome message will be displayed.
2860 2911 """
2861 from IPython.core.pylabtools import mpl_runner, backends
2912 from IPython.core.pylabtools import import_pylab
2913
2914 gui, backend = self.enable_matplotlib(gui)
2915
2862 2916 # We want to prevent the loading of pylab to pollute the user's
2863 2917 # namespace as shown by the %who* magics, so we execute the activation
2864 2918 # code in an empty namespace, and we update *both* user_ns and
2865 2919 # user_ns_hidden with this information.
2866 2920 ns = {}
2867 try:
2868 gui = pylab_activate(ns, gui, import_all, self, welcome_message=welcome_message)
2869 except KeyError:
2870 error("Backend '%s' not supported. Supported backends are: %s"
2871 % (gui, " ".join(sorted(backends.keys()))))
2872 return
2873 except ImportError:
2874 error("pylab mode doesn't work as matplotlib could not be found." + \
2875 "\nIs it installed on the system?")
2876 return
2921 import_pylab(ns, import_all)
2922 # warn about clobbered names
2923 ignored = set(["__builtins__"])
2924 both = set(ns).intersection(self.user_ns).difference(ignored)
2925 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
2877 2926 self.user_ns.update(ns)
2878 2927 self.user_ns_hidden.update(ns)
2879 # Now we must activate the gui pylab wants to use, and fix %run to take
2880 # plot updates into account
2881 self.enable_gui(gui)
2882 self.magics_manager.registry['ExecutionMagics'].default_runner = \
2883 mpl_runner(self.safe_execfile)
2928 return gui, backend, clobbered
2884 2929
2885 2930 #-------------------------------------------------------------------------
2886 2931 # Utilities
@@ -14,30 +14,41 b''
14 14
15 15 # Our own packages
16 16 from IPython.config.application import Application
17 from IPython.core import magic_arguments
17 18 from IPython.core.magic import Magics, magics_class, line_magic
18 19 from IPython.testing.skipdoctest import skip_doctest
20 from IPython.utils.warn import warn
21 from IPython.core.pylabtools import backends
19 22
20 23 #-----------------------------------------------------------------------------
21 24 # Magic implementation classes
22 25 #-----------------------------------------------------------------------------
23 26
27 magic_gui_arg = magic_arguments.argument(
28 'gui', nargs='?',
29 help="""Name of the matplotlib backend to use %s.
30 If given, the corresponding matplotlib backend is used,
31 otherwise it will be matplotlib's default
32 (which you can set in your matplotlib config file).
33 """ % str(tuple(sorted(backends.keys())))
34 )
35
36
24 37 @magics_class
25 38 class PylabMagics(Magics):
26 39 """Magics related to matplotlib's pylab support"""
27
40
28 41 @skip_doctest
29 42 @line_magic
30 def pylab(self, parameter_s=''):
31 """Load numpy and matplotlib to work interactively.
32
33 %pylab [GUINAME]
34
35 This function lets you activate pylab (matplotlib, numpy and
36 interactive support) at any point during an IPython session.
37
38 It will import at the top level numpy as np, pyplot as plt, matplotlib,
39 pylab and mlab, as well as all names from numpy and pylab.
40
43 @magic_arguments.magic_arguments()
44 @magic_gui_arg
45 def matplotlib(self, line=''):
46 """Set up matplotlib to work interactively.
47
48 This function lets you activate matplotlib interactive support
49 at any point during an IPython session.
50 It does not import anything into the interactive namespace.
51
41 52 If you are using the inline matplotlib backend for embedded figures,
42 53 you can adjust its behavior via the %config magic::
43 54
@@ -49,40 +60,82 b' class PylabMagics(Magics):'
49 60 # cells:
50 61 In [2]: %config InlineBackend.close_figures = False
51 62
52 Parameters
53 ----------
54 guiname : optional
55 One of the valid arguments to the %gui magic ('qt', 'wx', 'gtk',
56 'osx' or 'tk'). If given, the corresponding Matplotlib backend is
57 used, otherwise matplotlib's default (which you can override in your
58 matplotlib config file) is used.
59
60 63 Examples
61 64 --------
62 65 In this case, where the MPL default is TkAgg::
63 66
64 In [2]: %pylab
65
66 Welcome to pylab, a matplotlib-based Python environment.
67 Backend in use: TkAgg
68 For more information, type 'help(pylab)'.
67 In [2]: %matplotlib
68 Using matplotlib backend: TkAgg
69 69
70 70 But you can explicitly request a different backend::
71 71
72 In [3]: %pylab qt
72 In [3]: %matplotlib qt
73 """
74 args = magic_arguments.parse_argstring(self.matplotlib, line)
75 gui, backend = self.shell.enable_matplotlib(args.gui)
76 self._show_matplotlib_backend(args.gui, backend)
73 77
74 Welcome to pylab, a matplotlib-based Python environment.
75 Backend in use: Qt4Agg
76 For more information, type 'help(pylab)'.
78 @skip_doctest
79 @line_magic
80 @magic_arguments.magic_arguments()
81 @magic_arguments.argument(
82 '--no-import-all', action='store_true', default=None,
83 help="""Prevent IPython from performing ``import *`` into the interactive namespace.
84
85 The names that will still be added to the namespace if this flag is given::
86
87 numpy
88 matplotlib
89 np (numpy alias)
90 plt (matplotlib.pyplot alias)
91 pylab (from matplotlib)
92 pyplot (from matplotlib)
93 mlab (from matplotlib)
94 display (from IPython)
95 figsize (from IPython)
96 getfigs (from IPython)
97
98 You can govern the default behavior with the
99 InteractiveShellApp.pylab_import_all configurable.
77 100 """
101 )
102 @magic_gui_arg
103 def pylab(self, line=''):
104 """Load numpy and matplotlib to work interactively.
78 105
79 if Application.initialized():
80 app = Application.instance()
81 try:
82 import_all_status = app.pylab_import_all
83 except AttributeError:
84 import_all_status = True
85 else:
86 import_all_status = True
106 This function lets you activate pylab (matplotlib, numpy and
107 interactive support) at any point during an IPython session.
87 108
88 self.shell.enable_pylab(parameter_s, import_all=import_all_status, welcome_message=True)
109 It will import at the top level numpy as np, pyplot as plt, matplotlib,
110 pylab and mlab, as well as all names from numpy and pylab.
111
112 See the %matplotlib magic for more details.
113 """
114 args = magic_arguments.parse_argstring(self.pylab, line)
115 if args.no_import_all is None:
116 # get default from Application
117 if Application.initialized():
118 app = Application.instance()
119 try:
120 import_all = app.pylab_import_all
121 except AttributeError:
122 import_all = True
123 else:
124 # nothing specified, no app - default True
125 import_all = True
126 else:
127 # invert no-import flag
128 import_all = not args.no_import_all
129
130 gui, backend, clobbered = self.shell.enable_pylab(args.gui, import_all=import_all)
131 self._show_matplotlib_backend(args.gui, backend)
132 if clobbered:
133 warn("pylab import has clobbered these variables: %s" % clobbered +
134 "\n`%pylab --no-import-all` prevents importing * from pylab and numpy"
135 )
136
137 def _show_matplotlib_backend(self, gui, backend):
138 """show matplotlib message backend message"""
139 if not gui or gui == 'auto':
140 print ("using matplotlib backend: %s" % backend)
141
@@ -231,7 +231,7 b' def activate_matplotlib(backend):'
231 231
232 232 import matplotlib
233 233 matplotlib.interactive(True)
234
234
235 235 # Matplotlib had a bug where even switch_backend could not force
236 236 # the rcParam to update. This needs to be set *before* the module
237 237 # magic of switch_backend().
@@ -251,7 +251,13 b' def activate_matplotlib(backend):'
251 251
252 252
253 253 def import_pylab(user_ns, import_all=True):
254 """Import the standard pylab symbols into user_ns."""
254 """Populate the namespace with pylab-related values.
255
256 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
257
258 Also imports a few names from IPython (figsize, display, getfigs)
259
260 """
255 261
256 262 # Import numpy as np/pyplot as plt are conventions we're trying to
257 263 # somewhat standardize on. Making them available to users by default
@@ -263,14 +269,21 b' def import_pylab(user_ns, import_all=True):'
263 269 "plt = pyplot\n"
264 270 )
265 271 exec s in user_ns
266
272
267 273 if import_all:
268 274 s = ("from matplotlib.pylab import *\n"
269 275 "from numpy import *\n")
270 276 exec s in user_ns
277
278 # IPython symbols to add
279 user_ns['figsize'] = figsize
280 from IPython.core.display import display
281 # Add display and getfigs to the user's namespace
282 user_ns['display'] = display
283 user_ns['getfigs'] = getfigs
271 284
272 285
273 def configure_inline_support(shell, backend, user_ns=None):
286 def configure_inline_support(shell, backend):
274 287 """Configure an IPython shell object for matplotlib use.
275 288
276 289 Parameters
@@ -278,10 +291,6 b' def configure_inline_support(shell, backend, user_ns=None):'
278 291 shell : InteractiveShell instance
279 292
280 293 backend : matplotlib backend
281
282 user_ns : dict
283 A namespace where all configured variables will be placed. If not given,
284 the `user_ns` attribute of the shell object is used.
285 294 """
286 295 # If using our svg payload backend, register the post-execution
287 296 # function that will pick up the results for display. This can only be
@@ -296,8 +305,6 b' def configure_inline_support(shell, backend, user_ns=None):'
296 305 return
297 306 from matplotlib import pyplot
298 307
299 user_ns = shell.user_ns if user_ns is None else user_ns
300
301 308 cfg = InlineBackend.instance(parent=shell)
302 309 cfg.shell = shell
303 310 if cfg not in shell.configurables:
@@ -313,8 +320,6 b' def configure_inline_support(shell, backend, user_ns=None):'
313 320 shell._saved_rcParams[k] = pyplot.rcParams[k]
314 321 # load inline_rc
315 322 pyplot.rcParams.update(cfg.rc)
316 # Add 'figsize' to pyplot and to the user's namespace
317 user_ns['figsize'] = pyplot.figsize = figsize
318 323 else:
319 324 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
320 325 if flush_figures in shell._post_execute:
@@ -324,62 +329,5 b' def configure_inline_support(shell, backend, user_ns=None):'
324 329 del shell._saved_rcParams
325 330
326 331 # Setup the default figure format
327 fmt = cfg.figure_format
328 select_figure_format(shell, fmt)
329
330 # The old pastefig function has been replaced by display
331 from IPython.core.display import display
332 # Add display and getfigs to the user's namespace
333 user_ns['display'] = display
334 user_ns['getfigs'] = getfigs
335
336
337 def pylab_activate(user_ns, gui=None, import_all=True, shell=None, welcome_message=False):
338 """Activate pylab mode in the user's namespace.
339
340 Loads and initializes numpy, matplotlib and friends for interactive use.
341
342 Parameters
343 ----------
344 user_ns : dict
345 Namespace where the imports will occur.
346
347 gui : optional, string
348 A valid gui name following the conventions of the %gui magic.
349
350 import_all : optional, boolean
351 If true, an 'import *' is done from numpy and pylab.
332 select_figure_format(shell, cfg.figure_format)
352 333
353 welcome_message : optional, boolean
354 If true, print a welcome message about pylab, which includes the backend
355 being used.
356
357 Returns
358 -------
359 The actual gui used (if not given as input, it was obtained from matplotlib
360 itself, and will be needed next to configure IPython's gui integration.
361 """
362 pylab_gui_select = shell.pylab_gui_select if shell is not None else None
363 # Try to find the appropriate gui and backend for the settings
364 gui, backend = find_gui_and_backend(gui, pylab_gui_select)
365 if shell is not None and gui != 'inline':
366 # If we have our first gui selection, store it
367 if pylab_gui_select is None:
368 shell.pylab_gui_select = gui
369 # Otherwise if they are different
370 elif gui != pylab_gui_select:
371 print ('Warning: Cannot change to a different GUI toolkit: %s.'
372 ' Using %s instead.' % (gui, pylab_gui_select))
373 gui, backend = find_gui_and_backend(pylab_gui_select)
374 activate_matplotlib(backend)
375 import_pylab(user_ns, import_all)
376 if shell is not None:
377 configure_inline_support(shell, backend, user_ns)
378 if welcome_message:
379 print """
380 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
381 For more information, type 'help(pylab)'.""" % backend
382 # flush stdout, just to be safe
383 sys.stdout.flush()
384
385 return gui
@@ -176,8 +176,11 b' class InteractiveShellApp(Configurable):'
176 176 """
177 177 )
178 178 pylab_import_all = Bool(True, config=True,
179 help="""If true, an 'import *' is done from numpy and pylab,
180 when using pylab"""
179 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
180 and an 'import *' is done from numpy and pylab, when using pylab mode.
181
182 When False, pylab mode should not import any names into the user namespace.
183 """
181 184 )
182 185 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
183 186
@@ -198,7 +201,9 b' class InteractiveShellApp(Configurable):'
198 201 gui, backend = pylabtools.find_gui_and_backend(self.pylab)
199 202 self.log.info("Enabling GUI event loop integration, "
200 203 "toolkit=%s, pylab=%s" % (gui, self.pylab))
201 shell.enable_pylab(gui, import_all=self.pylab_import_all, welcome_message=True)
204 if self.pylab == "auto":
205 print ("using matplotlib backend: %s" % backend)
206 shell.enable_pylab(self.pylab, import_all=self.pylab_import_all)
202 207 else:
203 208 self.log.info("Enabling GUI event loop integration, "
204 209 "toolkit=%s" % self.gui)
@@ -23,6 +23,7 b' from matplotlib import pyplot as plt'
23 23 import numpy as np
24 24
25 25 # Our own imports
26 from IPython.core.interactiveshell import InteractiveShell
26 27 from IPython.testing import decorators as dec
27 28 from .. import pylabtools as pt
28 29
@@ -62,11 +63,11 b' def test_import_pylab():'
62 63 nt.assert_true('plt' in ns)
63 64 nt.assert_equal(ns['np'], np)
64 65
65
66 66 class TestPylabSwitch(object):
67 class Shell(object):
68 pylab_gui_select = None
69
67 class Shell(InteractiveShell):
68 def enable_gui(self, gui):
69 pass
70
70 71 def setup(self):
71 72 import matplotlib
72 73 def act_mpl(backend):
@@ -93,47 +94,47 b' class TestPylabSwitch(object):'
93 94
94 95 def test_qt(self):
95 96 s = self.Shell()
96 gui = pt.pylab_activate(dict(), None, False, s)
97 gui, backend = s.enable_matplotlib(None)
97 98 nt.assert_equal(gui, 'qt')
98 99 nt.assert_equal(s.pylab_gui_select, 'qt')
99 100
100 gui = pt.pylab_activate(dict(), 'inline', False, s)
101 gui, backend = s.enable_matplotlib('inline')
101 102 nt.assert_equal(gui, 'inline')
102 103 nt.assert_equal(s.pylab_gui_select, 'qt')
103 104
104 gui = pt.pylab_activate(dict(), 'qt', False, s)
105 gui, backend = s.enable_matplotlib('qt')
105 106 nt.assert_equal(gui, 'qt')
106 107 nt.assert_equal(s.pylab_gui_select, 'qt')
107 108
108 gui = pt.pylab_activate(dict(), 'inline', False, s)
109 gui, backend = s.enable_matplotlib('inline')
109 110 nt.assert_equal(gui, 'inline')
110 111 nt.assert_equal(s.pylab_gui_select, 'qt')
111 112
112 gui = pt.pylab_activate(dict(), None, False, s)
113 gui, backend = s.enable_matplotlib()
113 114 nt.assert_equal(gui, 'qt')
114 115 nt.assert_equal(s.pylab_gui_select, 'qt')
115 116
116 117 def test_inline(self):
117 118 s = self.Shell()
118 gui = pt.pylab_activate(dict(), 'inline', False, s)
119 gui, backend = s.enable_matplotlib('inline')
119 120 nt.assert_equal(gui, 'inline')
120 121 nt.assert_equal(s.pylab_gui_select, None)
121 122
122 gui = pt.pylab_activate(dict(), 'inline', False, s)
123 gui, backend = s.enable_matplotlib('inline')
123 124 nt.assert_equal(gui, 'inline')
124 125 nt.assert_equal(s.pylab_gui_select, None)
125 126
126 gui = pt.pylab_activate(dict(), 'qt', False, s)
127 gui, backend = s.enable_matplotlib('qt')
127 128 nt.assert_equal(gui, 'qt')
128 129 nt.assert_equal(s.pylab_gui_select, 'qt')
129 130
130 131 def test_qt_gtk(self):
131 132 s = self.Shell()
132 gui = pt.pylab_activate(dict(), 'qt', False, s)
133 gui, backend = s.enable_matplotlib('qt')
133 134 nt.assert_equal(gui, 'qt')
134 135 nt.assert_equal(s.pylab_gui_select, 'qt')
135 136
136 gui = pt.pylab_activate(dict(), 'gtk', False, s)
137 gui, backend = s.enable_matplotlib('gtk')
137 138 nt.assert_equal(gui, 'qt')
138 139 nt.assert_equal(s.pylab_gui_select, 'qt')
139 140
@@ -160,19 +160,23 b' class InProcessInteractiveShell(ZMQInteractiveShell):'
160 160 #-------------------------------------------------------------------------
161 161
162 162 def enable_gui(self, gui=None):
163 """ Enable GUI integration for the kernel.
164 """
163 """Enable GUI integration for the kernel."""
165 164 from IPython.kernel.zmq.eventloops import enable_gui
166 165 if not gui:
167 166 gui = self.kernel.gui
168 enable_gui(gui, kernel=self.kernel)
167 return enable_gui(gui, kernel=self.kernel)
168
169 def enable_matplotlib(self, gui=None):
170 """Enable matplotlib integration for the kernel."""
171 if not gui:
172 gui = self.kernel.gui
173 return super(InProcessInteractiveShell, self).enable_matplotlib(gui)
169 174
170 175 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
171 """ Activate pylab support at runtime.
172 """
176 """Activate pylab support at runtime."""
173 177 if not gui:
174 178 gui = self.kernel.gui
175 super(InProcessInteractiveShell, self).enable_pylab(gui, import_all,
179 return super(InProcessInteractiveShell, self).enable_pylab(gui, import_all,
176 180 welcome_message)
177 181
178 182 InteractiveShellABC.register(InProcessInteractiveShell)
@@ -42,7 +42,7 b' class InProcessKernelTestCase(unittest.TestCase):'
42 42 kc = self.kc
43 43 kc.execute('%pylab')
44 44 msg = get_stream_message(kc)
45 self.assert_('Welcome to pylab' in msg['content']['data'])
45 self.assert_('matplotlib' in msg['content']['data'])
46 46
47 47 def test_raw_input(self):
48 48 """ Does the in-process kernel handle raw_input correctly?
@@ -83,8 +83,7 b' In \\[1\\]: from IPython\\.config\\.application import Application'
83 83 In \[2\]: app = Application\.instance\(\)
84 84 In \[3\]: app\.pylab_import_all = True
85 85 In \[4\]: pylab
86 ^Welcome to pylab, a matplotlib-based Python environment
87 For more information, type 'help\(pylab\)'\.
86 ^using matplotlib backend:
88 87 In \[5\]: ip=get_ipython\(\)
89 88 In \[6\]: \'plot\' in ip\.user_ns
90 89 Out\[6\]: True
@@ -109,8 +108,7 b' In \\[1\\]: from IPython\\.config\\.application import Application'
109 108 In \[2\]: app = Application\.instance\(\)
110 109 In \[3\]: app\.pylab_import_all = False
111 110 In \[4\]: pylab
112 ^Welcome to pylab, a matplotlib-based Python environment
113 For more information, type 'help\(pylab\)'\.
111 ^using matplotlib backend:
114 112 In \[5\]: ip=get_ipython\(\)
115 113 In \[6\]: \'plot\' in ip\.user_ns
116 114 Out\[6\]: False
@@ -33,6 +33,10 b' def flag_calls(func):'
33 33
34 34 Testing for truth in wrapper.called allows you to determine if a call to
35 35 func() was attempted and succeeded."""
36
37 # don't wrap twice
38 if hasattr(func, 'called'):
39 return func
36 40
37 41 def wrapper(*args,**kw):
38 42 wrapper.called = False
General Comments 0
You need to be logged in to leave comments. Login now