##// END OF EJS Templates
Correctly handle "ipython --matplotlib=<whatever>"
Ian Thomas -
Show More
@@ -1,178 +1,173 b''
1 """Implementation of magic functions for matplotlib/pylab support.
1 """Implementation of magic functions for matplotlib/pylab support.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Our own packages
15 # Our own packages
16 from traitlets.config.application import Application
16 from traitlets.config.application import Application
17 from IPython.core import magic_arguments
17 from IPython.core import magic_arguments
18 from IPython.core.magic import Magics, magics_class, line_magic
18 from IPython.core.magic import Magics, magics_class, line_magic
19 from IPython.testing.skipdoctest import skip_doctest
19 from IPython.testing.skipdoctest import skip_doctest
20 from warnings import warn
20 from warnings import warn
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Magic implementation classes
23 # Magic implementation classes
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 magic_gui_arg = magic_arguments.argument(
26 magic_gui_arg = magic_arguments.argument(
27 "gui",
27 "gui",
28 nargs="?",
28 nargs="?",
29 help="""Name of the matplotlib backend to use such as 'qt' or 'widget'.
29 help="""Name of the matplotlib backend to use such as 'qt' or 'widget'.
30 If given, the corresponding matplotlib backend is used,
30 If given, the corresponding matplotlib backend is used,
31 otherwise it will be matplotlib's default
31 otherwise it will be matplotlib's default
32 (which you can set in your matplotlib config file).
32 (which you can set in your matplotlib config file).
33 """,
33 """,
34 )
34 )
35
35
36
36
37 @magics_class
37 @magics_class
38 class PylabMagics(Magics):
38 class PylabMagics(Magics):
39 """Magics related to matplotlib's pylab support"""
39 """Magics related to matplotlib's pylab support"""
40
40
41 @skip_doctest
41 @skip_doctest
42 @line_magic
42 @line_magic
43 @magic_arguments.magic_arguments()
43 @magic_arguments.magic_arguments()
44 @magic_arguments.argument('-l', '--list', action='store_true',
44 @magic_arguments.argument('-l', '--list', action='store_true',
45 help='Show available matplotlib backends')
45 help='Show available matplotlib backends')
46 @magic_gui_arg
46 @magic_gui_arg
47 def matplotlib(self, line=''):
47 def matplotlib(self, line=''):
48 """Set up matplotlib to work interactively.
48 """Set up matplotlib to work interactively.
49
49
50 This function lets you activate matplotlib interactive support
50 This function lets you activate matplotlib interactive support
51 at any point during an IPython session. It does not import anything
51 at any point during an IPython session. It does not import anything
52 into the interactive namespace.
52 into the interactive namespace.
53
53
54 If you are using the inline matplotlib backend in the IPython Notebook
54 If you are using the inline matplotlib backend in the IPython Notebook
55 you can set which figure formats are enabled using the following::
55 you can set which figure formats are enabled using the following::
56
56
57 In [1]: from matplotlib_inline.backend_inline import set_matplotlib_formats
57 In [1]: from matplotlib_inline.backend_inline import set_matplotlib_formats
58
58
59 In [2]: set_matplotlib_formats('pdf', 'svg')
59 In [2]: set_matplotlib_formats('pdf', 'svg')
60
60
61 The default for inline figures sets `bbox_inches` to 'tight'. This can
61 The default for inline figures sets `bbox_inches` to 'tight'. This can
62 cause discrepancies between the displayed image and the identical
62 cause discrepancies between the displayed image and the identical
63 image created using `savefig`. This behavior can be disabled using the
63 image created using `savefig`. This behavior can be disabled using the
64 `%config` magic::
64 `%config` magic::
65
65
66 In [3]: %config InlineBackend.print_figure_kwargs = {'bbox_inches':None}
66 In [3]: %config InlineBackend.print_figure_kwargs = {'bbox_inches':None}
67
67
68 In addition, see the docstrings of
68 In addition, see the docstrings of
69 `matplotlib_inline.backend_inline.set_matplotlib_formats` and
69 `matplotlib_inline.backend_inline.set_matplotlib_formats` and
70 `matplotlib_inline.backend_inline.set_matplotlib_close` for more information on
70 `matplotlib_inline.backend_inline.set_matplotlib_close` for more information on
71 changing additional behaviors of the inline backend.
71 changing additional behaviors of the inline backend.
72
72
73 Examples
73 Examples
74 --------
74 --------
75 To enable the inline backend for usage with the IPython Notebook::
75 To enable the inline backend for usage with the IPython Notebook::
76
76
77 In [1]: %matplotlib inline
77 In [1]: %matplotlib inline
78
78
79 In this case, where the matplotlib default is TkAgg::
79 In this case, where the matplotlib default is TkAgg::
80
80
81 In [2]: %matplotlib
81 In [2]: %matplotlib
82 Using matplotlib backend: TkAgg
82 Using matplotlib backend: TkAgg
83
83
84 But you can explicitly request a different GUI backend::
84 But you can explicitly request a different GUI backend::
85
85
86 In [3]: %matplotlib qt
86 In [3]: %matplotlib qt
87
87
88 You can list the available backends using the -l/--list option::
88 You can list the available backends using the -l/--list option::
89
89
90 In [4]: %matplotlib --list
90 In [4]: %matplotlib --list
91 Available matplotlib backends: ['osx', 'qt4', 'qt5', 'gtk3', 'gtk4', 'notebook', 'wx', 'qt', 'nbagg',
91 Available matplotlib backends: ['osx', 'qt4', 'qt5', 'gtk3', 'gtk4', 'notebook', 'wx', 'qt', 'nbagg',
92 'gtk', 'tk', 'inline']
92 'gtk', 'tk', 'inline']
93 """
93 """
94 args = magic_arguments.parse_argstring(self.matplotlib, line)
94 args = magic_arguments.parse_argstring(self.matplotlib, line)
95 if args.list:
95 if args.list:
96 from IPython.core.pylabtools import _matplotlib_manages_backends
96 from IPython.core.pylabtools import _list_matplotlib_backends_and_gui_loops
97
97
98 if _matplotlib_manages_backends():
98 print(
99 from matplotlib.backends.registry import backend_registry
99 "Available matplotlib backends: %s"
100
100 % _list_matplotlib_backends_and_gui_loops()
101 backends_list = backend_registry.list_all()
101 )
102 else:
103 from IPython.core.pylabtools import backends
104
105 backends_list = list(backends.keys())
106 print("Available matplotlib backends: %s" % backends_list)
107 else:
102 else:
108 gui, backend = self.shell.enable_matplotlib(args.gui.lower() if isinstance(args.gui, str) else args.gui)
103 gui, backend = self.shell.enable_matplotlib(args.gui.lower() if isinstance(args.gui, str) else args.gui)
109 self._show_matplotlib_backend(args.gui, backend)
104 self._show_matplotlib_backend(args.gui, backend)
110
105
111 @skip_doctest
106 @skip_doctest
112 @line_magic
107 @line_magic
113 @magic_arguments.magic_arguments()
108 @magic_arguments.magic_arguments()
114 @magic_arguments.argument(
109 @magic_arguments.argument(
115 '--no-import-all', action='store_true', default=None,
110 '--no-import-all', action='store_true', default=None,
116 help="""Prevent IPython from performing ``import *`` into the interactive namespace.
111 help="""Prevent IPython from performing ``import *`` into the interactive namespace.
117
112
118 You can govern the default behavior of this flag with the
113 You can govern the default behavior of this flag with the
119 InteractiveShellApp.pylab_import_all configurable.
114 InteractiveShellApp.pylab_import_all configurable.
120 """
115 """
121 )
116 )
122 @magic_gui_arg
117 @magic_gui_arg
123 def pylab(self, line=''):
118 def pylab(self, line=''):
124 """Load numpy and matplotlib to work interactively.
119 """Load numpy and matplotlib to work interactively.
125
120
126 This function lets you activate pylab (matplotlib, numpy and
121 This function lets you activate pylab (matplotlib, numpy and
127 interactive support) at any point during an IPython session.
122 interactive support) at any point during an IPython session.
128
123
129 %pylab makes the following imports::
124 %pylab makes the following imports::
130
125
131 import numpy
126 import numpy
132 import matplotlib
127 import matplotlib
133 from matplotlib import pylab, mlab, pyplot
128 from matplotlib import pylab, mlab, pyplot
134 np = numpy
129 np = numpy
135 plt = pyplot
130 plt = pyplot
136
131
137 from IPython.display import display
132 from IPython.display import display
138 from IPython.core.pylabtools import figsize, getfigs
133 from IPython.core.pylabtools import figsize, getfigs
139
134
140 from pylab import *
135 from pylab import *
141 from numpy import *
136 from numpy import *
142
137
143 If you pass `--no-import-all`, the last two `*` imports will be excluded.
138 If you pass `--no-import-all`, the last two `*` imports will be excluded.
144
139
145 See the %matplotlib magic for more details about activating matplotlib
140 See the %matplotlib magic for more details about activating matplotlib
146 without affecting the interactive namespace.
141 without affecting the interactive namespace.
147 """
142 """
148 args = magic_arguments.parse_argstring(self.pylab, line)
143 args = magic_arguments.parse_argstring(self.pylab, line)
149 if args.no_import_all is None:
144 if args.no_import_all is None:
150 # get default from Application
145 # get default from Application
151 if Application.initialized():
146 if Application.initialized():
152 app = Application.instance()
147 app = Application.instance()
153 try:
148 try:
154 import_all = app.pylab_import_all
149 import_all = app.pylab_import_all
155 except AttributeError:
150 except AttributeError:
156 import_all = True
151 import_all = True
157 else:
152 else:
158 # nothing specified, no app - default True
153 # nothing specified, no app - default True
159 import_all = True
154 import_all = True
160 else:
155 else:
161 # invert no-import flag
156 # invert no-import flag
162 import_all = not args.no_import_all
157 import_all = not args.no_import_all
163
158
164 gui, backend, clobbered = self.shell.enable_pylab(args.gui, import_all=import_all)
159 gui, backend, clobbered = self.shell.enable_pylab(args.gui, import_all=import_all)
165 self._show_matplotlib_backend(args.gui, backend)
160 self._show_matplotlib_backend(args.gui, backend)
166 print(
161 print(
167 "%pylab is deprecated, use %matplotlib inline and import the required libraries."
162 "%pylab is deprecated, use %matplotlib inline and import the required libraries."
168 )
163 )
169 print("Populating the interactive namespace from numpy and matplotlib")
164 print("Populating the interactive namespace from numpy and matplotlib")
170 if clobbered:
165 if clobbered:
171 warn("pylab import has clobbered these variables: %s" % clobbered +
166 warn("pylab import has clobbered these variables: %s" % clobbered +
172 "\n`%matplotlib` prevents importing * from pylab and numpy"
167 "\n`%matplotlib` prevents importing * from pylab and numpy"
173 )
168 )
174
169
175 def _show_matplotlib_backend(self, gui, backend):
170 def _show_matplotlib_backend(self, gui, backend):
176 """show matplotlib message backend message"""
171 """show matplotlib message backend message"""
177 if not gui or gui == 'auto':
172 if not gui or gui == 'auto':
178 print("Using matplotlib backend: %s" % backend)
173 print("Using matplotlib backend: %s" % backend)
@@ -1,499 +1,518 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities."""
2 """Pylab (matplotlib) support utilities."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from io import BytesIO
7 from io import BytesIO
8 from binascii import b2a_base64
8 from binascii import b2a_base64
9 from functools import partial
9 from functools import partial
10 import warnings
10 import warnings
11
11
12 from IPython.core.display import _pngxy
12 from IPython.core.display import _pngxy
13 from IPython.utils.decorators import flag_calls
13 from IPython.utils.decorators import flag_calls
14
14
15
15
16 # Matplotlib backend resolution functionality moved from IPython to Matplotlib
16 # Matplotlib backend resolution functionality moved from IPython to Matplotlib
17 # in IPython 8.24 and Matplotlib 3.9.1. Need to keep `backends` and `backend2gui`
17 # in IPython 8.24 and Matplotlib 3.9.1. Need to keep `backends` and `backend2gui`
18 # here for earlier Matplotlib and for external backend libraries such as
18 # here for earlier Matplotlib and for external backend libraries such as
19 # mplcairo that might rely upon it.
19 # mplcairo that might rely upon it.
20 _deprecated_backends = {
20 _deprecated_backends = {
21 "tk": "TkAgg",
21 "tk": "TkAgg",
22 "gtk": "GTKAgg",
22 "gtk": "GTKAgg",
23 "gtk3": "GTK3Agg",
23 "gtk3": "GTK3Agg",
24 "gtk4": "GTK4Agg",
24 "gtk4": "GTK4Agg",
25 "wx": "WXAgg",
25 "wx": "WXAgg",
26 "qt4": "Qt4Agg",
26 "qt4": "Qt4Agg",
27 "qt5": "Qt5Agg",
27 "qt5": "Qt5Agg",
28 "qt6": "QtAgg",
28 "qt6": "QtAgg",
29 "qt": "QtAgg",
29 "qt": "QtAgg",
30 "osx": "MacOSX",
30 "osx": "MacOSX",
31 "nbagg": "nbAgg",
31 "nbagg": "nbAgg",
32 "webagg": "WebAgg",
32 "webagg": "WebAgg",
33 "notebook": "nbAgg",
33 "notebook": "nbAgg",
34 "agg": "agg",
34 "agg": "agg",
35 "svg": "svg",
35 "svg": "svg",
36 "pdf": "pdf",
36 "pdf": "pdf",
37 "ps": "ps",
37 "ps": "ps",
38 "inline": "module://matplotlib_inline.backend_inline",
38 "inline": "module://matplotlib_inline.backend_inline",
39 "ipympl": "module://ipympl.backend_nbagg",
39 "ipympl": "module://ipympl.backend_nbagg",
40 "widget": "module://ipympl.backend_nbagg",
40 "widget": "module://ipympl.backend_nbagg",
41 }
41 }
42
42
43 # We also need a reverse backends2guis mapping that will properly choose which
43 # We also need a reverse backends2guis mapping that will properly choose which
44 # GUI support to activate based on the desired matplotlib backend. For the
44 # GUI support to activate based on the desired matplotlib backend. For the
45 # most part it's just a reverse of the above dict, but we also need to add a
45 # most part it's just a reverse of the above dict, but we also need to add a
46 # few others that map to the same GUI manually:
46 # few others that map to the same GUI manually:
47 _deprecated_backend2gui = dict(
47 _deprecated_backend2gui = dict(
48 zip(_deprecated_backends.values(), _deprecated_backends.keys())
48 zip(_deprecated_backends.values(), _deprecated_backends.keys())
49 )
49 )
50 # In the reverse mapping, there are a few extra valid matplotlib backends that
50 # In the reverse mapping, there are a few extra valid matplotlib backends that
51 # map to the same GUI support
51 # map to the same GUI support
52 _deprecated_backend2gui["GTK"] = _deprecated_backend2gui["GTKCairo"] = "gtk"
52 _deprecated_backend2gui["GTK"] = _deprecated_backend2gui["GTKCairo"] = "gtk"
53 _deprecated_backend2gui["GTK3Cairo"] = "gtk3"
53 _deprecated_backend2gui["GTK3Cairo"] = "gtk3"
54 _deprecated_backend2gui["GTK4Cairo"] = "gtk4"
54 _deprecated_backend2gui["GTK4Cairo"] = "gtk4"
55 _deprecated_backend2gui["WX"] = "wx"
55 _deprecated_backend2gui["WX"] = "wx"
56 _deprecated_backend2gui["CocoaAgg"] = "osx"
56 _deprecated_backend2gui["CocoaAgg"] = "osx"
57 # There needs to be a hysteresis here as the new QtAgg Matplotlib backend
57 # There needs to be a hysteresis here as the new QtAgg Matplotlib backend
58 # supports either Qt5 or Qt6 and the IPython qt event loop support Qt4, Qt5,
58 # supports either Qt5 or Qt6 and the IPython qt event loop support Qt4, Qt5,
59 # and Qt6.
59 # and Qt6.
60 _deprecated_backend2gui["QtAgg"] = "qt"
60 _deprecated_backend2gui["QtAgg"] = "qt"
61 _deprecated_backend2gui["Qt4Agg"] = "qt4"
61 _deprecated_backend2gui["Qt4Agg"] = "qt4"
62 _deprecated_backend2gui["Qt5Agg"] = "qt5"
62 _deprecated_backend2gui["Qt5Agg"] = "qt5"
63
63
64 # And some backends that don't need GUI integration
64 # And some backends that don't need GUI integration
65 del _deprecated_backend2gui["nbAgg"]
65 del _deprecated_backend2gui["nbAgg"]
66 del _deprecated_backend2gui["agg"]
66 del _deprecated_backend2gui["agg"]
67 del _deprecated_backend2gui["svg"]
67 del _deprecated_backend2gui["svg"]
68 del _deprecated_backend2gui["pdf"]
68 del _deprecated_backend2gui["pdf"]
69 del _deprecated_backend2gui["ps"]
69 del _deprecated_backend2gui["ps"]
70 del _deprecated_backend2gui["module://matplotlib_inline.backend_inline"]
70 del _deprecated_backend2gui["module://matplotlib_inline.backend_inline"]
71 del _deprecated_backend2gui["module://ipympl.backend_nbagg"]
71 del _deprecated_backend2gui["module://ipympl.backend_nbagg"]
72
72
73
73
74 # Deprecated attributes backends and backend2gui mostly following PEP 562.
74 # Deprecated attributes backends and backend2gui mostly following PEP 562.
75 def __getattr__(name):
75 def __getattr__(name):
76 if name in ("backends", "backend2gui"):
76 if name in ("backends", "backend2gui"):
77 warnings.warn(
77 warnings.warn(
78 f"{name} is deprecated since IPython 8.24, backends are managed "
78 f"{name} is deprecated since IPython 8.24, backends are managed "
79 "in matplotlib and can be externally registered.",
79 "in matplotlib and can be externally registered.",
80 DeprecationWarning,
80 DeprecationWarning,
81 )
81 )
82 return globals()[f"_deprecated_{name}"]
82 return globals()[f"_deprecated_{name}"]
83 raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
83 raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
84
84
85
85
86 #-----------------------------------------------------------------------------
86 #-----------------------------------------------------------------------------
87 # Matplotlib utilities
87 # Matplotlib utilities
88 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
89
89
90
90
91 def getfigs(*fig_nums):
91 def getfigs(*fig_nums):
92 """Get a list of matplotlib figures by figure numbers.
92 """Get a list of matplotlib figures by figure numbers.
93
93
94 If no arguments are given, all available figures are returned. If the
94 If no arguments are given, all available figures are returned. If the
95 argument list contains references to invalid figures, a warning is printed
95 argument list contains references to invalid figures, a warning is printed
96 but the function continues pasting further figures.
96 but the function continues pasting further figures.
97
97
98 Parameters
98 Parameters
99 ----------
99 ----------
100 figs : tuple
100 figs : tuple
101 A tuple of ints giving the figure numbers of the figures to return.
101 A tuple of ints giving the figure numbers of the figures to return.
102 """
102 """
103 from matplotlib._pylab_helpers import Gcf
103 from matplotlib._pylab_helpers import Gcf
104 if not fig_nums:
104 if not fig_nums:
105 fig_managers = Gcf.get_all_fig_managers()
105 fig_managers = Gcf.get_all_fig_managers()
106 return [fm.canvas.figure for fm in fig_managers]
106 return [fm.canvas.figure for fm in fig_managers]
107 else:
107 else:
108 figs = []
108 figs = []
109 for num in fig_nums:
109 for num in fig_nums:
110 f = Gcf.figs.get(num)
110 f = Gcf.figs.get(num)
111 if f is None:
111 if f is None:
112 print('Warning: figure %s not available.' % num)
112 print('Warning: figure %s not available.' % num)
113 else:
113 else:
114 figs.append(f.canvas.figure)
114 figs.append(f.canvas.figure)
115 return figs
115 return figs
116
116
117
117
118 def figsize(sizex, sizey):
118 def figsize(sizex, sizey):
119 """Set the default figure size to be [sizex, sizey].
119 """Set the default figure size to be [sizex, sizey].
120
120
121 This is just an easy to remember, convenience wrapper that sets::
121 This is just an easy to remember, convenience wrapper that sets::
122
122
123 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
123 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
124 """
124 """
125 import matplotlib
125 import matplotlib
126 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
126 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
127
127
128
128
129 def print_figure(fig, fmt="png", bbox_inches="tight", base64=False, **kwargs):
129 def print_figure(fig, fmt="png", bbox_inches="tight", base64=False, **kwargs):
130 """Print a figure to an image, and return the resulting file data
130 """Print a figure to an image, and return the resulting file data
131
131
132 Returned data will be bytes unless ``fmt='svg'``,
132 Returned data will be bytes unless ``fmt='svg'``,
133 in which case it will be unicode.
133 in which case it will be unicode.
134
134
135 Any keyword args are passed to fig.canvas.print_figure,
135 Any keyword args are passed to fig.canvas.print_figure,
136 such as ``quality`` or ``bbox_inches``.
136 such as ``quality`` or ``bbox_inches``.
137
137
138 If `base64` is True, return base64-encoded str instead of raw bytes
138 If `base64` is True, return base64-encoded str instead of raw bytes
139 for binary-encoded image formats
139 for binary-encoded image formats
140
140
141 .. versionadded:: 7.29
141 .. versionadded:: 7.29
142 base64 argument
142 base64 argument
143 """
143 """
144 # When there's an empty figure, we shouldn't return anything, otherwise we
144 # When there's an empty figure, we shouldn't return anything, otherwise we
145 # get big blank areas in the qt console.
145 # get big blank areas in the qt console.
146 if not fig.axes and not fig.lines:
146 if not fig.axes and not fig.lines:
147 return
147 return
148
148
149 dpi = fig.dpi
149 dpi = fig.dpi
150 if fmt == 'retina':
150 if fmt == 'retina':
151 dpi = dpi * 2
151 dpi = dpi * 2
152 fmt = 'png'
152 fmt = 'png'
153
153
154 # build keyword args
154 # build keyword args
155 kw = {
155 kw = {
156 "format":fmt,
156 "format":fmt,
157 "facecolor":fig.get_facecolor(),
157 "facecolor":fig.get_facecolor(),
158 "edgecolor":fig.get_edgecolor(),
158 "edgecolor":fig.get_edgecolor(),
159 "dpi":dpi,
159 "dpi":dpi,
160 "bbox_inches":bbox_inches,
160 "bbox_inches":bbox_inches,
161 }
161 }
162 # **kwargs get higher priority
162 # **kwargs get higher priority
163 kw.update(kwargs)
163 kw.update(kwargs)
164
164
165 bytes_io = BytesIO()
165 bytes_io = BytesIO()
166 if fig.canvas is None:
166 if fig.canvas is None:
167 from matplotlib.backend_bases import FigureCanvasBase
167 from matplotlib.backend_bases import FigureCanvasBase
168 FigureCanvasBase(fig)
168 FigureCanvasBase(fig)
169
169
170 fig.canvas.print_figure(bytes_io, **kw)
170 fig.canvas.print_figure(bytes_io, **kw)
171 data = bytes_io.getvalue()
171 data = bytes_io.getvalue()
172 if fmt == 'svg':
172 if fmt == 'svg':
173 data = data.decode('utf-8')
173 data = data.decode('utf-8')
174 elif base64:
174 elif base64:
175 data = b2a_base64(data, newline=False).decode("ascii")
175 data = b2a_base64(data, newline=False).decode("ascii")
176 return data
176 return data
177
177
178 def retina_figure(fig, base64=False, **kwargs):
178 def retina_figure(fig, base64=False, **kwargs):
179 """format a figure as a pixel-doubled (retina) PNG
179 """format a figure as a pixel-doubled (retina) PNG
180
180
181 If `base64` is True, return base64-encoded str instead of raw bytes
181 If `base64` is True, return base64-encoded str instead of raw bytes
182 for binary-encoded image formats
182 for binary-encoded image formats
183
183
184 .. versionadded:: 7.29
184 .. versionadded:: 7.29
185 base64 argument
185 base64 argument
186 """
186 """
187 pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs)
187 pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs)
188 # Make sure that retina_figure acts just like print_figure and returns
188 # Make sure that retina_figure acts just like print_figure and returns
189 # None when the figure is empty.
189 # None when the figure is empty.
190 if pngdata is None:
190 if pngdata is None:
191 return
191 return
192 w, h = _pngxy(pngdata)
192 w, h = _pngxy(pngdata)
193 metadata = {"width": w//2, "height":h//2}
193 metadata = {"width": w//2, "height":h//2}
194 if base64:
194 if base64:
195 pngdata = b2a_base64(pngdata, newline=False).decode("ascii")
195 pngdata = b2a_base64(pngdata, newline=False).decode("ascii")
196 return pngdata, metadata
196 return pngdata, metadata
197
197
198
198
199 # We need a little factory function here to create the closure where
199 # We need a little factory function here to create the closure where
200 # safe_execfile can live.
200 # safe_execfile can live.
201 def mpl_runner(safe_execfile):
201 def mpl_runner(safe_execfile):
202 """Factory to return a matplotlib-enabled runner for %run.
202 """Factory to return a matplotlib-enabled runner for %run.
203
203
204 Parameters
204 Parameters
205 ----------
205 ----------
206 safe_execfile : function
206 safe_execfile : function
207 This must be a function with the same interface as the
207 This must be a function with the same interface as the
208 :meth:`safe_execfile` method of IPython.
208 :meth:`safe_execfile` method of IPython.
209
209
210 Returns
210 Returns
211 -------
211 -------
212 A function suitable for use as the ``runner`` argument of the %run magic
212 A function suitable for use as the ``runner`` argument of the %run magic
213 function.
213 function.
214 """
214 """
215
215
216 def mpl_execfile(fname,*where,**kw):
216 def mpl_execfile(fname,*where,**kw):
217 """matplotlib-aware wrapper around safe_execfile.
217 """matplotlib-aware wrapper around safe_execfile.
218
218
219 Its interface is identical to that of the :func:`execfile` builtin.
219 Its interface is identical to that of the :func:`execfile` builtin.
220
220
221 This is ultimately a call to execfile(), but wrapped in safeties to
221 This is ultimately a call to execfile(), but wrapped in safeties to
222 properly handle interactive rendering."""
222 properly handle interactive rendering."""
223
223
224 import matplotlib
224 import matplotlib
225 import matplotlib.pyplot as plt
225 import matplotlib.pyplot as plt
226
226
227 #print '*** Matplotlib runner ***' # dbg
227 #print '*** Matplotlib runner ***' # dbg
228 # turn off rendering until end of script
228 # turn off rendering until end of script
229 with matplotlib.rc_context({"interactive": False}):
229 with matplotlib.rc_context({"interactive": False}):
230 safe_execfile(fname, *where, **kw)
230 safe_execfile(fname, *where, **kw)
231
231
232 if matplotlib.is_interactive():
232 if matplotlib.is_interactive():
233 plt.show()
233 plt.show()
234
234
235 # make rendering call now, if the user tried to do it
235 # make rendering call now, if the user tried to do it
236 if plt.draw_if_interactive.called:
236 if plt.draw_if_interactive.called:
237 plt.draw()
237 plt.draw()
238 plt.draw_if_interactive.called = False
238 plt.draw_if_interactive.called = False
239
239
240 # re-draw everything that is stale
240 # re-draw everything that is stale
241 try:
241 try:
242 da = plt.draw_all
242 da = plt.draw_all
243 except AttributeError:
243 except AttributeError:
244 pass
244 pass
245 else:
245 else:
246 da()
246 da()
247
247
248 return mpl_execfile
248 return mpl_execfile
249
249
250
250
251 def _reshow_nbagg_figure(fig):
251 def _reshow_nbagg_figure(fig):
252 """reshow an nbagg figure"""
252 """reshow an nbagg figure"""
253 try:
253 try:
254 reshow = fig.canvas.manager.reshow
254 reshow = fig.canvas.manager.reshow
255 except AttributeError as e:
255 except AttributeError as e:
256 raise NotImplementedError() from e
256 raise NotImplementedError() from e
257 else:
257 else:
258 reshow()
258 reshow()
259
259
260
260
261 def select_figure_formats(shell, formats, **kwargs):
261 def select_figure_formats(shell, formats, **kwargs):
262 """Select figure formats for the inline backend.
262 """Select figure formats for the inline backend.
263
263
264 Parameters
264 Parameters
265 ----------
265 ----------
266 shell : InteractiveShell
266 shell : InteractiveShell
267 The main IPython instance.
267 The main IPython instance.
268 formats : str or set
268 formats : str or set
269 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
269 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
270 **kwargs : any
270 **kwargs : any
271 Extra keyword arguments to be passed to fig.canvas.print_figure.
271 Extra keyword arguments to be passed to fig.canvas.print_figure.
272 """
272 """
273 import matplotlib
273 import matplotlib
274 from matplotlib.figure import Figure
274 from matplotlib.figure import Figure
275
275
276 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
276 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
277 png_formatter = shell.display_formatter.formatters['image/png']
277 png_formatter = shell.display_formatter.formatters['image/png']
278 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
278 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
279 pdf_formatter = shell.display_formatter.formatters['application/pdf']
279 pdf_formatter = shell.display_formatter.formatters['application/pdf']
280
280
281 if isinstance(formats, str):
281 if isinstance(formats, str):
282 formats = {formats}
282 formats = {formats}
283 # cast in case of list / tuple
283 # cast in case of list / tuple
284 formats = set(formats)
284 formats = set(formats)
285
285
286 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
286 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
287 mplbackend = matplotlib.get_backend().lower()
287 mplbackend = matplotlib.get_backend().lower()
288 if mplbackend in ("nbagg", "ipympl", "widget", "module://ipympl.backend_nbagg"):
288 if mplbackend in ("nbagg", "ipympl", "widget", "module://ipympl.backend_nbagg"):
289 formatter = shell.display_formatter.ipython_display_formatter
289 formatter = shell.display_formatter.ipython_display_formatter
290 formatter.for_type(Figure, _reshow_nbagg_figure)
290 formatter.for_type(Figure, _reshow_nbagg_figure)
291
291
292 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
292 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
293 bad = formats.difference(supported)
293 bad = formats.difference(supported)
294 if bad:
294 if bad:
295 bs = "%s" % ','.join([repr(f) for f in bad])
295 bs = "%s" % ','.join([repr(f) for f in bad])
296 gs = "%s" % ','.join([repr(f) for f in supported])
296 gs = "%s" % ','.join([repr(f) for f in supported])
297 raise ValueError("supported formats are: %s not %s" % (gs, bs))
297 raise ValueError("supported formats are: %s not %s" % (gs, bs))
298
298
299 if "png" in formats:
299 if "png" in formats:
300 png_formatter.for_type(
300 png_formatter.for_type(
301 Figure, partial(print_figure, fmt="png", base64=True, **kwargs)
301 Figure, partial(print_figure, fmt="png", base64=True, **kwargs)
302 )
302 )
303 if "retina" in formats or "png2x" in formats:
303 if "retina" in formats or "png2x" in formats:
304 png_formatter.for_type(Figure, partial(retina_figure, base64=True, **kwargs))
304 png_formatter.for_type(Figure, partial(retina_figure, base64=True, **kwargs))
305 if "jpg" in formats or "jpeg" in formats:
305 if "jpg" in formats or "jpeg" in formats:
306 jpg_formatter.for_type(
306 jpg_formatter.for_type(
307 Figure, partial(print_figure, fmt="jpg", base64=True, **kwargs)
307 Figure, partial(print_figure, fmt="jpg", base64=True, **kwargs)
308 )
308 )
309 if "svg" in formats:
309 if "svg" in formats:
310 svg_formatter.for_type(Figure, partial(print_figure, fmt="svg", **kwargs))
310 svg_formatter.for_type(Figure, partial(print_figure, fmt="svg", **kwargs))
311 if "pdf" in formats:
311 if "pdf" in formats:
312 pdf_formatter.for_type(
312 pdf_formatter.for_type(
313 Figure, partial(print_figure, fmt="pdf", base64=True, **kwargs)
313 Figure, partial(print_figure, fmt="pdf", base64=True, **kwargs)
314 )
314 )
315
315
316 #-----------------------------------------------------------------------------
316 #-----------------------------------------------------------------------------
317 # Code for initializing matplotlib and importing pylab
317 # Code for initializing matplotlib and importing pylab
318 #-----------------------------------------------------------------------------
318 #-----------------------------------------------------------------------------
319
319
320
320
321 def find_gui_and_backend(gui=None, gui_select=None):
321 def find_gui_and_backend(gui=None, gui_select=None):
322 """Given a gui string return the gui and mpl backend.
322 """Given a gui string return the gui and mpl backend.
323
323
324 Parameters
324 Parameters
325 ----------
325 ----------
326 gui : str
326 gui : str
327 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
327 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
328 gui_select : str
328 gui_select : str
329 Can be one of ('tk','gtk','wx','qt','qt4','inline').
329 Can be one of ('tk','gtk','wx','qt','qt4','inline').
330 This is any gui already selected by the shell.
330 This is any gui already selected by the shell.
331
331
332 Returns
332 Returns
333 -------
333 -------
334 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
334 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
335 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
335 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
336 """
336 """
337
337
338 import matplotlib
338 import matplotlib
339
339
340 if _matplotlib_manages_backends():
340 if _matplotlib_manages_backends():
341 backend_registry = matplotlib.backends.registry.backend_registry
341 backend_registry = matplotlib.backends.registry.backend_registry
342
342
343 # gui argument may be a gui event loop or may be a backend name.
343 # gui argument may be a gui event loop or may be a backend name.
344 if gui in ("auto", None):
344 if gui in ("auto", None):
345 backend = matplotlib.rcParamsOrig["backend"]
345 backend = matplotlib.rcParamsOrig["backend"]
346 backend, gui = backend_registry.resolve_backend(backend)
346 backend, gui = backend_registry.resolve_backend(backend)
347 else:
347 else:
348 backend, gui = backend_registry.resolve_gui_or_backend(gui)
348 backend, gui = backend_registry.resolve_gui_or_backend(gui)
349
349
350 return gui, backend
350 return gui, backend
351
351
352 # Fallback to previous behaviour (Matplotlib < 3.9)
352 # Fallback to previous behaviour (Matplotlib < 3.9)
353 mpl_version_info = getattr(matplotlib, "__version_info__", (0, 0))
353 mpl_version_info = getattr(matplotlib, "__version_info__", (0, 0))
354 has_unified_qt_backend = mpl_version_info >= (3, 5)
354 has_unified_qt_backend = mpl_version_info >= (3, 5)
355
355
356 from IPython.core.pylabtools import backends
356 from IPython.core.pylabtools import backends
357
357
358 backends_ = dict(backends)
358 backends_ = dict(backends)
359 if not has_unified_qt_backend:
359 if not has_unified_qt_backend:
360 backends_["qt"] = "qt5agg"
360 backends_["qt"] = "qt5agg"
361
361
362 if gui and gui != 'auto':
362 if gui and gui != 'auto':
363 # select backend based on requested gui
363 # select backend based on requested gui
364 backend = backends_[gui]
364 backend = backends_[gui]
365 if gui == 'agg':
365 if gui == 'agg':
366 gui = None
366 gui = None
367 else:
367 else:
368 # We need to read the backend from the original data structure, *not*
368 # We need to read the backend from the original data structure, *not*
369 # from mpl.rcParams, since a prior invocation of %matplotlib may have
369 # from mpl.rcParams, since a prior invocation of %matplotlib may have
370 # overwritten that.
370 # overwritten that.
371 # WARNING: this assumes matplotlib 1.1 or newer!!
371 # WARNING: this assumes matplotlib 1.1 or newer!!
372 backend = matplotlib.rcParamsOrig['backend']
372 backend = matplotlib.rcParamsOrig['backend']
373 # In this case, we need to find what the appropriate gui selection call
373 # In this case, we need to find what the appropriate gui selection call
374 # should be for IPython, so we can activate inputhook accordingly
374 # should be for IPython, so we can activate inputhook accordingly
375 from IPython.core.pylabtools import backend2gui
375 from IPython.core.pylabtools import backend2gui
376 gui = backend2gui.get(backend, None)
376 gui = backend2gui.get(backend, None)
377
377
378 # If we have already had a gui active, we need it and inline are the
378 # If we have already had a gui active, we need it and inline are the
379 # ones allowed.
379 # ones allowed.
380 if gui_select and gui != gui_select:
380 if gui_select and gui != gui_select:
381 gui = gui_select
381 gui = gui_select
382 backend = backends_[gui]
382 backend = backends_[gui]
383
383
384 # Matplotlib before _matplotlib_manages_backends() can return "inline" for
384 # Matplotlib before _matplotlib_manages_backends() can return "inline" for
385 # no gui event loop rather than the None that IPython >= 8.24.0 expects.
385 # no gui event loop rather than the None that IPython >= 8.24.0 expects.
386 if gui == "inline":
386 if gui == "inline":
387 gui = None
387 gui = None
388
388
389 return gui, backend
389 return gui, backend
390
390
391
391
392 def activate_matplotlib(backend):
392 def activate_matplotlib(backend):
393 """Activate the given backend and set interactive to True."""
393 """Activate the given backend and set interactive to True."""
394
394
395 import matplotlib
395 import matplotlib
396 matplotlib.interactive(True)
396 matplotlib.interactive(True)
397
397
398 # Matplotlib had a bug where even switch_backend could not force
398 # Matplotlib had a bug where even switch_backend could not force
399 # the rcParam to update. This needs to be set *before* the module
399 # the rcParam to update. This needs to be set *before* the module
400 # magic of switch_backend().
400 # magic of switch_backend().
401 matplotlib.rcParams['backend'] = backend
401 matplotlib.rcParams['backend'] = backend
402
402
403 # Due to circular imports, pyplot may be only partially initialised
403 # Due to circular imports, pyplot may be only partially initialised
404 # when this function runs.
404 # when this function runs.
405 # So avoid needing matplotlib attribute-lookup to access pyplot.
405 # So avoid needing matplotlib attribute-lookup to access pyplot.
406 from matplotlib import pyplot as plt
406 from matplotlib import pyplot as plt
407
407
408 plt.switch_backend(backend)
408 plt.switch_backend(backend)
409
409
410 plt.show._needmain = False
410 plt.show._needmain = False
411 # We need to detect at runtime whether show() is called by the user.
411 # We need to detect at runtime whether show() is called by the user.
412 # For this, we wrap it into a decorator which adds a 'called' flag.
412 # For this, we wrap it into a decorator which adds a 'called' flag.
413 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
413 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
414
414
415
415
416 def import_pylab(user_ns, import_all=True):
416 def import_pylab(user_ns, import_all=True):
417 """Populate the namespace with pylab-related values.
417 """Populate the namespace with pylab-related values.
418
418
419 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
419 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
420
420
421 Also imports a few names from IPython (figsize, display, getfigs)
421 Also imports a few names from IPython (figsize, display, getfigs)
422
422
423 """
423 """
424
424
425 # Import numpy as np/pyplot as plt are conventions we're trying to
425 # Import numpy as np/pyplot as plt are conventions we're trying to
426 # somewhat standardize on. Making them available to users by default
426 # somewhat standardize on. Making them available to users by default
427 # will greatly help this.
427 # will greatly help this.
428 s = ("import numpy\n"
428 s = ("import numpy\n"
429 "import matplotlib\n"
429 "import matplotlib\n"
430 "from matplotlib import pylab, mlab, pyplot\n"
430 "from matplotlib import pylab, mlab, pyplot\n"
431 "np = numpy\n"
431 "np = numpy\n"
432 "plt = pyplot\n"
432 "plt = pyplot\n"
433 )
433 )
434 exec(s, user_ns)
434 exec(s, user_ns)
435
435
436 if import_all:
436 if import_all:
437 s = ("from matplotlib.pylab import *\n"
437 s = ("from matplotlib.pylab import *\n"
438 "from numpy import *\n")
438 "from numpy import *\n")
439 exec(s, user_ns)
439 exec(s, user_ns)
440
440
441 # IPython symbols to add
441 # IPython symbols to add
442 user_ns['figsize'] = figsize
442 user_ns['figsize'] = figsize
443 from IPython.display import display
443 from IPython.display import display
444 # Add display and getfigs to the user's namespace
444 # Add display and getfigs to the user's namespace
445 user_ns['display'] = display
445 user_ns['display'] = display
446 user_ns['getfigs'] = getfigs
446 user_ns['getfigs'] = getfigs
447
447
448
448
449 def configure_inline_support(shell, backend):
449 def configure_inline_support(shell, backend):
450 """
450 """
451 .. deprecated:: 7.23
451 .. deprecated:: 7.23
452
452
453 use `matplotlib_inline.backend_inline.configure_inline_support()`
453 use `matplotlib_inline.backend_inline.configure_inline_support()`
454
454
455 Configure an IPython shell object for matplotlib use.
455 Configure an IPython shell object for matplotlib use.
456
456
457 Parameters
457 Parameters
458 ----------
458 ----------
459 shell : InteractiveShell instance
459 shell : InteractiveShell instance
460 backend : matplotlib backend
460 backend : matplotlib backend
461 """
461 """
462 warnings.warn(
462 warnings.warn(
463 "`configure_inline_support` is deprecated since IPython 7.23, directly "
463 "`configure_inline_support` is deprecated since IPython 7.23, directly "
464 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
464 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
465 DeprecationWarning,
465 DeprecationWarning,
466 stacklevel=2,
466 stacklevel=2,
467 )
467 )
468
468
469 from matplotlib_inline.backend_inline import (
469 from matplotlib_inline.backend_inline import (
470 configure_inline_support as configure_inline_support_orig,
470 configure_inline_support as configure_inline_support_orig,
471 )
471 )
472
472
473 configure_inline_support_orig(shell, backend)
473 configure_inline_support_orig(shell, backend)
474
474
475
475
476 # Determine if Matplotlib manages backends only if needed, and cache result.
476 # Determine if Matplotlib manages backends only if needed, and cache result.
477 # Do not read this directly, instead use _matplotlib_manages_backends().
477 # Do not read this directly, instead use _matplotlib_manages_backends().
478 _matplotlib_manages_backends_value: bool | None = None
478 _matplotlib_manages_backends_value: bool | None = None
479
479
480
480
481 def _matplotlib_manages_backends() -> bool:
481 def _matplotlib_manages_backends() -> bool:
482 """Return True if Matplotlib manages backends, False otherwise.
482 """Return True if Matplotlib manages backends, False otherwise.
483
483
484 If it returns True, the caller can be sure that
484 If it returns True, the caller can be sure that
485 matplotlib.backends.registry.backend_registry is available along with
485 matplotlib.backends.registry.backend_registry is available along with
486 member functions resolve_gui_or_backend, resolve_backend and list_all.
486 member functions resolve_gui_or_backend, resolve_backend, list_all, and
487 list_gui_frameworks.
487 """
488 """
488 global _matplotlib_manages_backends_value
489 global _matplotlib_manages_backends_value
489 if _matplotlib_manages_backends_value is None:
490 if _matplotlib_manages_backends_value is None:
490 try:
491 try:
491 from matplotlib.backends.registry import backend_registry
492 from matplotlib.backends.registry import backend_registry
492
493
493 _matplotlib_manages_backends_value = hasattr(
494 _matplotlib_manages_backends_value = hasattr(
494 backend_registry, "resolve_gui_or_backend"
495 backend_registry, "resolve_gui_or_backend"
495 )
496 )
496 except ImportError:
497 except ImportError:
497 _matplotlib_manages_backends_value = False
498 _matplotlib_manages_backends_value = False
498
499
499 return _matplotlib_manages_backends_value
500 return _matplotlib_manages_backends_value
501
502
503 def _list_matplotlib_backends_and_gui_loops() -> list[str]:
504 """Return list of all Matplotlib backends and GUI event loops.
505
506 This is the list returned by
507 %matplotlib --list
508 """
509 if _matplotlib_manages_backends():
510 from matplotlib.backends.registry import backend_registry
511
512 ret = backend_registry.list_all() + backend_registry.list_gui_frameworks()
513 else:
514 from IPython.core import pylabtools
515
516 ret = list(pylabtools.backends.keys())
517
518 return sorted(["auto"] + ret)
@@ -1,450 +1,491 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A mixin for :class:`~IPython.core.application.Application` classes that
3 A mixin for :class:`~IPython.core.application.Application` classes that
4 launch InteractiveShell instances, load extensions, etc.
4 launch InteractiveShell instances, load extensions, etc.
5 """
5 """
6
6
7 # Copyright (c) IPython Development Team.
7 # Copyright (c) IPython Development Team.
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9
9
10 import glob
10 import glob
11 from itertools import chain
11 from itertools import chain
12 import os
12 import os
13 import sys
13 import sys
14 import typing as t
14
15
15 from traitlets.config.application import boolean_flag
16 from traitlets.config.application import boolean_flag
16 from traitlets.config.configurable import Configurable
17 from traitlets.config.configurable import Configurable
17 from traitlets.config.loader import Config
18 from traitlets.config.loader import Config
18 from IPython.core.application import SYSTEM_CONFIG_DIRS, ENV_CONFIG_DIRS
19 from IPython.core.application import SYSTEM_CONFIG_DIRS, ENV_CONFIG_DIRS
19 from IPython.core import pylabtools
20 from IPython.utils.contexts import preserve_keys
20 from IPython.utils.contexts import preserve_keys
21 from IPython.utils.path import filefind
21 from IPython.utils.path import filefind
22 from traitlets import (
22 from traitlets import (
23 Unicode, Instance, List, Bool, CaselessStrEnum, observe,
23 Unicode,
24 Instance,
25 List,
26 Bool,
27 CaselessStrEnum,
28 observe,
24 DottedObjectName,
29 DottedObjectName,
30 Undefined,
25 )
31 )
26 from IPython.terminal import pt_inputhooks
32 from IPython.terminal import pt_inputhooks
27
33
28 #-----------------------------------------------------------------------------
34 # -----------------------------------------------------------------------------
29 # Aliases and Flags
35 # Aliases and Flags
30 #-----------------------------------------------------------------------------
36 # -----------------------------------------------------------------------------
31
37
32 gui_keys = tuple(sorted(pt_inputhooks.backends) + sorted(pt_inputhooks.aliases))
38 gui_keys = tuple(sorted(pt_inputhooks.backends) + sorted(pt_inputhooks.aliases))
33
39
34 backend_keys: list[str] = []
35
36 shell_flags = {}
40 shell_flags = {}
37
41
38 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
42 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
39 addflag('autoindent', 'InteractiveShell.autoindent',
43 addflag(
40 'Turn on autoindenting.', 'Turn off autoindenting.'
44 "autoindent",
45 "InteractiveShell.autoindent",
46 "Turn on autoindenting.",
47 "Turn off autoindenting.",
41 )
48 )
42 addflag('automagic', 'InteractiveShell.automagic',
49 addflag(
43 """Turn on the auto calling of magic commands. Type %%magic at the
50 "automagic",
51 "InteractiveShell.automagic",
52 """Turn on the auto calling of magic commands. Type %%magic at the
44 IPython prompt for more information.""",
53 IPython prompt for more information.""",
45 'Turn off the auto calling of magic commands.'
54 'Turn off the auto calling of magic commands.'
46 )
55 )
47 addflag('pdb', 'InteractiveShell.pdb',
56 addflag('pdb', 'InteractiveShell.pdb',
48 "Enable auto calling the pdb debugger after every exception.",
57 "Enable auto calling the pdb debugger after every exception.",
49 "Disable auto calling the pdb debugger after every exception."
58 "Disable auto calling the pdb debugger after every exception."
50 )
59 )
51 addflag('pprint', 'PlainTextFormatter.pprint',
60 addflag('pprint', 'PlainTextFormatter.pprint',
52 "Enable auto pretty printing of results.",
61 "Enable auto pretty printing of results.",
53 "Disable auto pretty printing of results."
62 "Disable auto pretty printing of results."
54 )
63 )
55 addflag('color-info', 'InteractiveShell.color_info',
64 addflag('color-info', 'InteractiveShell.color_info',
56 """IPython can display information about objects via a set of functions,
65 """IPython can display information about objects via a set of functions,
57 and optionally can use colors for this, syntax highlighting
66 and optionally can use colors for this, syntax highlighting
58 source code and various other elements. This is on by default, but can cause
67 source code and various other elements. This is on by default, but can cause
59 problems with some pagers. If you see such problems, you can disable the
68 problems with some pagers. If you see such problems, you can disable the
60 colours.""",
69 colours.""",
61 "Disable using colors for info related things."
70 "Disable using colors for info related things."
62 )
71 )
63 addflag('ignore-cwd', 'InteractiveShellApp.ignore_cwd',
72 addflag('ignore-cwd', 'InteractiveShellApp.ignore_cwd',
64 "Exclude the current working directory from sys.path",
73 "Exclude the current working directory from sys.path",
65 "Include the current working directory in sys.path",
74 "Include the current working directory in sys.path",
66 )
75 )
67 nosep_config = Config()
76 nosep_config = Config()
68 nosep_config.InteractiveShell.separate_in = ''
77 nosep_config.InteractiveShell.separate_in = ''
69 nosep_config.InteractiveShell.separate_out = ''
78 nosep_config.InteractiveShell.separate_out = ''
70 nosep_config.InteractiveShell.separate_out2 = ''
79 nosep_config.InteractiveShell.separate_out2 = ''
71
80
72 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
81 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
73 shell_flags['pylab'] = (
82 shell_flags['pylab'] = (
74 {'InteractiveShellApp' : {'pylab' : 'auto'}},
83 {'InteractiveShellApp' : {'pylab' : 'auto'}},
75 """Pre-load matplotlib and numpy for interactive use with
84 """Pre-load matplotlib and numpy for interactive use with
76 the default matplotlib backend."""
85 the default matplotlib backend."""
77 )
86 )
78 shell_flags['matplotlib'] = (
87 shell_flags['matplotlib'] = (
79 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
88 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
80 """Configure matplotlib for interactive use with
89 """Configure matplotlib for interactive use with
81 the default matplotlib backend."""
90 the default matplotlib backend."""
82 )
91 )
83
92
84 # it's possible we don't want short aliases for *all* of these:
93 # it's possible we don't want short aliases for *all* of these:
85 shell_aliases = dict(
94 shell_aliases = dict(
86 autocall='InteractiveShell.autocall',
95 autocall='InteractiveShell.autocall',
87 colors='InteractiveShell.colors',
96 colors='InteractiveShell.colors',
88 logfile='InteractiveShell.logfile',
97 logfile='InteractiveShell.logfile',
89 logappend='InteractiveShell.logappend',
98 logappend='InteractiveShell.logappend',
90 c='InteractiveShellApp.code_to_run',
99 c='InteractiveShellApp.code_to_run',
91 m='InteractiveShellApp.module_to_run',
100 m='InteractiveShellApp.module_to_run',
92 ext="InteractiveShellApp.extra_extensions",
101 ext="InteractiveShellApp.extra_extensions",
93 gui='InteractiveShellApp.gui',
102 gui='InteractiveShellApp.gui',
94 pylab='InteractiveShellApp.pylab',
103 pylab='InteractiveShellApp.pylab',
95 matplotlib='InteractiveShellApp.matplotlib',
104 matplotlib='InteractiveShellApp.matplotlib',
96 )
105 )
97 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
106 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
98
107
108
109 # -----------------------------------------------------------------------------
110 # Traitlets
111 # -----------------------------------------------------------------------------
112
113
114 class MatplotlibBackendCaselessStrEnum(CaselessStrEnum):
115 """An enum of Matplotlib backend strings where the case should be ignored.
116
117 Prior to Matplotlib 3.9.1 the list of valid backends is hardcoded in
118 pylabtools.backends. After that, Matplotlib manages backends.
119
120 The list of valid backends is determined when it is first needed to avoid
121 wasting unnecessary initialisation time.
122 """
123
124 def __init__(
125 self: CaselessStrEnum[t.Any],
126 default_value: t.Any = Undefined,
127 **kwargs: t.Any,
128 ) -> None:
129 super().__init__(None, default_value=default_value, **kwargs)
130
131 def __getattribute__(self, name):
132 if name == "values" and object.__getattribute__(self, name) is None:
133 from IPython.core.pylabtools import _list_matplotlib_backends_and_gui_loops
134
135 self.values = _list_matplotlib_backends_and_gui_loops()
136 return object.__getattribute__(self, name)
137
138
99 #-----------------------------------------------------------------------------
139 #-----------------------------------------------------------------------------
100 # Main classes and functions
140 # Main classes and functions
101 #-----------------------------------------------------------------------------
141 #-----------------------------------------------------------------------------
102
142
103 class InteractiveShellApp(Configurable):
143 class InteractiveShellApp(Configurable):
104 """A Mixin for applications that start InteractiveShell instances.
144 """A Mixin for applications that start InteractiveShell instances.
105
145
106 Provides configurables for loading extensions and executing files
146 Provides configurables for loading extensions and executing files
107 as part of configuring a Shell environment.
147 as part of configuring a Shell environment.
108
148
109 The following methods should be called by the :meth:`initialize` method
149 The following methods should be called by the :meth:`initialize` method
110 of the subclass:
150 of the subclass:
111
151
112 - :meth:`init_path`
152 - :meth:`init_path`
113 - :meth:`init_shell` (to be implemented by the subclass)
153 - :meth:`init_shell` (to be implemented by the subclass)
114 - :meth:`init_gui_pylab`
154 - :meth:`init_gui_pylab`
115 - :meth:`init_extensions`
155 - :meth:`init_extensions`
116 - :meth:`init_code`
156 - :meth:`init_code`
117 """
157 """
118 extensions = List(Unicode(),
158 extensions = List(Unicode(),
119 help="A list of dotted module names of IPython extensions to load."
159 help="A list of dotted module names of IPython extensions to load."
120 ).tag(config=True)
160 ).tag(config=True)
121
161
122 extra_extensions = List(
162 extra_extensions = List(
123 DottedObjectName(),
163 DottedObjectName(),
124 help="""
164 help="""
125 Dotted module name(s) of one or more IPython extensions to load.
165 Dotted module name(s) of one or more IPython extensions to load.
126
166
127 For specifying extra extensions to load on the command-line.
167 For specifying extra extensions to load on the command-line.
128
168
129 .. versionadded:: 7.10
169 .. versionadded:: 7.10
130 """,
170 """,
131 ).tag(config=True)
171 ).tag(config=True)
132
172
133 reraise_ipython_extension_failures = Bool(False,
173 reraise_ipython_extension_failures = Bool(False,
134 help="Reraise exceptions encountered loading IPython extensions?",
174 help="Reraise exceptions encountered loading IPython extensions?",
135 ).tag(config=True)
175 ).tag(config=True)
136
176
137 # Extensions that are always loaded (not configurable)
177 # Extensions that are always loaded (not configurable)
138 default_extensions = List(Unicode(), [u'storemagic']).tag(config=False)
178 default_extensions = List(Unicode(), [u'storemagic']).tag(config=False)
139
179
140 hide_initial_ns = Bool(True,
180 hide_initial_ns = Bool(True,
141 help="""Should variables loaded at startup (by startup files, exec_lines, etc.)
181 help="""Should variables loaded at startup (by startup files, exec_lines, etc.)
142 be hidden from tools like %who?"""
182 be hidden from tools like %who?"""
143 ).tag(config=True)
183 ).tag(config=True)
144
184
145 exec_files = List(Unicode(),
185 exec_files = List(Unicode(),
146 help="""List of files to run at IPython startup."""
186 help="""List of files to run at IPython startup."""
147 ).tag(config=True)
187 ).tag(config=True)
148 exec_PYTHONSTARTUP = Bool(True,
188 exec_PYTHONSTARTUP = Bool(True,
149 help="""Run the file referenced by the PYTHONSTARTUP environment
189 help="""Run the file referenced by the PYTHONSTARTUP environment
150 variable at IPython startup."""
190 variable at IPython startup."""
151 ).tag(config=True)
191 ).tag(config=True)
152 file_to_run = Unicode('',
192 file_to_run = Unicode('',
153 help="""A file to be run""").tag(config=True)
193 help="""A file to be run""").tag(config=True)
154
194
155 exec_lines = List(Unicode(),
195 exec_lines = List(Unicode(),
156 help="""lines of code to run at IPython startup."""
196 help="""lines of code to run at IPython startup."""
157 ).tag(config=True)
197 ).tag(config=True)
158 code_to_run = Unicode('',
198 code_to_run = Unicode("", help="Execute the given command string.").tag(config=True)
159 help="Execute the given command string."
199 module_to_run = Unicode("", help="Run the module as a script.").tag(config=True)
160 ).tag(config=True)
200 gui = CaselessStrEnum(
161 module_to_run = Unicode('',
201 gui_keys,
162 help="Run the module as a script."
202 allow_none=True,
203 help="Enable GUI event loop integration with any of {0}.".format(gui_keys),
163 ).tag(config=True)
204 ).tag(config=True)
164 gui = CaselessStrEnum(gui_keys, allow_none=True,
205 matplotlib = MatplotlibBackendCaselessStrEnum(
165 help="Enable GUI event loop integration with any of {0}.".format(gui_keys)
206 allow_none=True,
166 ).tag(config=True)
167 matplotlib = CaselessStrEnum(backend_keys, allow_none=True,
168 help="""Configure matplotlib for interactive use with
207 help="""Configure matplotlib for interactive use with
169 the default matplotlib backend."""
208 the default matplotlib backend.""",
170 ).tag(config=True)
209 ).tag(config=True)
171 pylab = CaselessStrEnum(backend_keys, allow_none=True,
210 pylab = MatplotlibBackendCaselessStrEnum(
211 allow_none=True,
172 help="""Pre-load matplotlib and numpy for interactive use,
212 help="""Pre-load matplotlib and numpy for interactive use,
173 selecting a particular matplotlib backend and loop integration.
213 selecting a particular matplotlib backend and loop integration.
174 """
214 """,
175 ).tag(config=True)
215 ).tag(config=True)
176 pylab_import_all = Bool(True,
216 pylab_import_all = Bool(
217 True,
177 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
218 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
178 and an ``import *`` is done from numpy and pylab, when using pylab mode.
219 and an ``import *`` is done from numpy and pylab, when using pylab mode.
179
220
180 When False, pylab mode should not import any names into the user namespace.
221 When False, pylab mode should not import any names into the user namespace.
181 """
222 """,
182 ).tag(config=True)
223 ).tag(config=True)
183 ignore_cwd = Bool(
224 ignore_cwd = Bool(
184 False,
225 False,
185 help="""If True, IPython will not add the current working directory to sys.path.
226 help="""If True, IPython will not add the current working directory to sys.path.
186 When False, the current working directory is added to sys.path, allowing imports
227 When False, the current working directory is added to sys.path, allowing imports
187 of modules defined in the current directory."""
228 of modules defined in the current directory."""
188 ).tag(config=True)
229 ).tag(config=True)
189 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
230 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
190 allow_none=True)
231 allow_none=True)
191 # whether interact-loop should start
232 # whether interact-loop should start
192 interact = Bool(True)
233 interact = Bool(True)
193
234
194 user_ns = Instance(dict, args=None, allow_none=True)
235 user_ns = Instance(dict, args=None, allow_none=True)
195 @observe('user_ns')
236 @observe('user_ns')
196 def _user_ns_changed(self, change):
237 def _user_ns_changed(self, change):
197 if self.shell is not None:
238 if self.shell is not None:
198 self.shell.user_ns = change['new']
239 self.shell.user_ns = change['new']
199 self.shell.init_user_ns()
240 self.shell.init_user_ns()
200
241
201 def init_path(self):
242 def init_path(self):
202 """Add current working directory, '', to sys.path
243 """Add current working directory, '', to sys.path
203
244
204 Unlike Python's default, we insert before the first `site-packages`
245 Unlike Python's default, we insert before the first `site-packages`
205 or `dist-packages` directory,
246 or `dist-packages` directory,
206 so that it is after the standard library.
247 so that it is after the standard library.
207
248
208 .. versionchanged:: 7.2
249 .. versionchanged:: 7.2
209 Try to insert after the standard library, instead of first.
250 Try to insert after the standard library, instead of first.
210 .. versionchanged:: 8.0
251 .. versionchanged:: 8.0
211 Allow optionally not including the current directory in sys.path
252 Allow optionally not including the current directory in sys.path
212 """
253 """
213 if '' in sys.path or self.ignore_cwd:
254 if '' in sys.path or self.ignore_cwd:
214 return
255 return
215 for idx, path in enumerate(sys.path):
256 for idx, path in enumerate(sys.path):
216 parent, last_part = os.path.split(path)
257 parent, last_part = os.path.split(path)
217 if last_part in {'site-packages', 'dist-packages'}:
258 if last_part in {'site-packages', 'dist-packages'}:
218 break
259 break
219 else:
260 else:
220 # no site-packages or dist-packages found (?!)
261 # no site-packages or dist-packages found (?!)
221 # back to original behavior of inserting at the front
262 # back to original behavior of inserting at the front
222 idx = 0
263 idx = 0
223 sys.path.insert(idx, '')
264 sys.path.insert(idx, '')
224
265
225 def init_shell(self):
266 def init_shell(self):
226 raise NotImplementedError("Override in subclasses")
267 raise NotImplementedError("Override in subclasses")
227
268
228 def init_gui_pylab(self):
269 def init_gui_pylab(self):
229 """Enable GUI event loop integration, taking pylab into account."""
270 """Enable GUI event loop integration, taking pylab into account."""
230 enable = False
271 enable = False
231 shell = self.shell
272 shell = self.shell
232 if self.pylab:
273 if self.pylab:
233 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
274 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
234 key = self.pylab
275 key = self.pylab
235 elif self.matplotlib:
276 elif self.matplotlib:
236 enable = shell.enable_matplotlib
277 enable = shell.enable_matplotlib
237 key = self.matplotlib
278 key = self.matplotlib
238 elif self.gui:
279 elif self.gui:
239 enable = shell.enable_gui
280 enable = shell.enable_gui
240 key = self.gui
281 key = self.gui
241
282
242 if not enable:
283 if not enable:
243 return
284 return
244
285
245 try:
286 try:
246 r = enable(key)
287 r = enable(key)
247 except ImportError:
288 except ImportError:
248 self.log.warning("Eventloop or matplotlib integration failed. Is matplotlib installed?")
289 self.log.warning("Eventloop or matplotlib integration failed. Is matplotlib installed?")
249 self.shell.showtraceback()
290 self.shell.showtraceback()
250 return
291 return
251 except Exception:
292 except Exception:
252 self.log.warning("GUI event loop or pylab initialization failed")
293 self.log.warning("GUI event loop or pylab initialization failed")
253 self.shell.showtraceback()
294 self.shell.showtraceback()
254 return
295 return
255
296
256 if isinstance(r, tuple):
297 if isinstance(r, tuple):
257 gui, backend = r[:2]
298 gui, backend = r[:2]
258 self.log.info("Enabling GUI event loop integration, "
299 self.log.info("Enabling GUI event loop integration, "
259 "eventloop=%s, matplotlib=%s", gui, backend)
300 "eventloop=%s, matplotlib=%s", gui, backend)
260 if key == "auto":
301 if key == "auto":
261 print("Using matplotlib backend: %s" % backend)
302 print("Using matplotlib backend: %s" % backend)
262 else:
303 else:
263 gui = r
304 gui = r
264 self.log.info("Enabling GUI event loop integration, "
305 self.log.info("Enabling GUI event loop integration, "
265 "eventloop=%s", gui)
306 "eventloop=%s", gui)
266
307
267 def init_extensions(self):
308 def init_extensions(self):
268 """Load all IPython extensions in IPythonApp.extensions.
309 """Load all IPython extensions in IPythonApp.extensions.
269
310
270 This uses the :meth:`ExtensionManager.load_extensions` to load all
311 This uses the :meth:`ExtensionManager.load_extensions` to load all
271 the extensions listed in ``self.extensions``.
312 the extensions listed in ``self.extensions``.
272 """
313 """
273 try:
314 try:
274 self.log.debug("Loading IPython extensions...")
315 self.log.debug("Loading IPython extensions...")
275 extensions = (
316 extensions = (
276 self.default_extensions + self.extensions + self.extra_extensions
317 self.default_extensions + self.extensions + self.extra_extensions
277 )
318 )
278 for ext in extensions:
319 for ext in extensions:
279 try:
320 try:
280 self.log.info("Loading IPython extension: %s", ext)
321 self.log.info("Loading IPython extension: %s", ext)
281 self.shell.extension_manager.load_extension(ext)
322 self.shell.extension_manager.load_extension(ext)
282 except:
323 except:
283 if self.reraise_ipython_extension_failures:
324 if self.reraise_ipython_extension_failures:
284 raise
325 raise
285 msg = ("Error in loading extension: {ext}\n"
326 msg = ("Error in loading extension: {ext}\n"
286 "Check your config files in {location}".format(
327 "Check your config files in {location}".format(
287 ext=ext,
328 ext=ext,
288 location=self.profile_dir.location
329 location=self.profile_dir.location
289 ))
330 ))
290 self.log.warning(msg, exc_info=True)
331 self.log.warning(msg, exc_info=True)
291 except:
332 except:
292 if self.reraise_ipython_extension_failures:
333 if self.reraise_ipython_extension_failures:
293 raise
334 raise
294 self.log.warning("Unknown error in loading extensions:", exc_info=True)
335 self.log.warning("Unknown error in loading extensions:", exc_info=True)
295
336
296 def init_code(self):
337 def init_code(self):
297 """run the pre-flight code, specified via exec_lines"""
338 """run the pre-flight code, specified via exec_lines"""
298 self._run_startup_files()
339 self._run_startup_files()
299 self._run_exec_lines()
340 self._run_exec_lines()
300 self._run_exec_files()
341 self._run_exec_files()
301
342
302 # Hide variables defined here from %who etc.
343 # Hide variables defined here from %who etc.
303 if self.hide_initial_ns:
344 if self.hide_initial_ns:
304 self.shell.user_ns_hidden.update(self.shell.user_ns)
345 self.shell.user_ns_hidden.update(self.shell.user_ns)
305
346
306 # command-line execution (ipython -i script.py, ipython -m module)
347 # command-line execution (ipython -i script.py, ipython -m module)
307 # should *not* be excluded from %whos
348 # should *not* be excluded from %whos
308 self._run_cmd_line_code()
349 self._run_cmd_line_code()
309 self._run_module()
350 self._run_module()
310
351
311 # flush output, so itwon't be attached to the first cell
352 # flush output, so itwon't be attached to the first cell
312 sys.stdout.flush()
353 sys.stdout.flush()
313 sys.stderr.flush()
354 sys.stderr.flush()
314 self.shell._sys_modules_keys = set(sys.modules.keys())
355 self.shell._sys_modules_keys = set(sys.modules.keys())
315
356
316 def _run_exec_lines(self):
357 def _run_exec_lines(self):
317 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
358 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
318 if not self.exec_lines:
359 if not self.exec_lines:
319 return
360 return
320 try:
361 try:
321 self.log.debug("Running code from IPythonApp.exec_lines...")
362 self.log.debug("Running code from IPythonApp.exec_lines...")
322 for line in self.exec_lines:
363 for line in self.exec_lines:
323 try:
364 try:
324 self.log.info("Running code in user namespace: %s" %
365 self.log.info("Running code in user namespace: %s" %
325 line)
366 line)
326 self.shell.run_cell(line, store_history=False)
367 self.shell.run_cell(line, store_history=False)
327 except:
368 except:
328 self.log.warning("Error in executing line in user "
369 self.log.warning("Error in executing line in user "
329 "namespace: %s" % line)
370 "namespace: %s" % line)
330 self.shell.showtraceback()
371 self.shell.showtraceback()
331 except:
372 except:
332 self.log.warning("Unknown error in handling IPythonApp.exec_lines:")
373 self.log.warning("Unknown error in handling IPythonApp.exec_lines:")
333 self.shell.showtraceback()
374 self.shell.showtraceback()
334
375
335 def _exec_file(self, fname, shell_futures=False):
376 def _exec_file(self, fname, shell_futures=False):
336 try:
377 try:
337 full_filename = filefind(fname, [u'.', self.ipython_dir])
378 full_filename = filefind(fname, [u'.', self.ipython_dir])
338 except IOError:
379 except IOError:
339 self.log.warning("File not found: %r"%fname)
380 self.log.warning("File not found: %r"%fname)
340 return
381 return
341 # Make sure that the running script gets a proper sys.argv as if it
382 # Make sure that the running script gets a proper sys.argv as if it
342 # were run from a system shell.
383 # were run from a system shell.
343 save_argv = sys.argv
384 save_argv = sys.argv
344 sys.argv = [full_filename] + self.extra_args[1:]
385 sys.argv = [full_filename] + self.extra_args[1:]
345 try:
386 try:
346 if os.path.isfile(full_filename):
387 if os.path.isfile(full_filename):
347 self.log.info("Running file in user namespace: %s" %
388 self.log.info("Running file in user namespace: %s" %
348 full_filename)
389 full_filename)
349 # Ensure that __file__ is always defined to match Python
390 # Ensure that __file__ is always defined to match Python
350 # behavior.
391 # behavior.
351 with preserve_keys(self.shell.user_ns, '__file__'):
392 with preserve_keys(self.shell.user_ns, '__file__'):
352 self.shell.user_ns['__file__'] = fname
393 self.shell.user_ns['__file__'] = fname
353 if full_filename.endswith('.ipy') or full_filename.endswith('.ipynb'):
394 if full_filename.endswith('.ipy') or full_filename.endswith('.ipynb'):
354 self.shell.safe_execfile_ipy(full_filename,
395 self.shell.safe_execfile_ipy(full_filename,
355 shell_futures=shell_futures)
396 shell_futures=shell_futures)
356 else:
397 else:
357 # default to python, even without extension
398 # default to python, even without extension
358 self.shell.safe_execfile(full_filename,
399 self.shell.safe_execfile(full_filename,
359 self.shell.user_ns,
400 self.shell.user_ns,
360 shell_futures=shell_futures,
401 shell_futures=shell_futures,
361 raise_exceptions=True)
402 raise_exceptions=True)
362 finally:
403 finally:
363 sys.argv = save_argv
404 sys.argv = save_argv
364
405
365 def _run_startup_files(self):
406 def _run_startup_files(self):
366 """Run files from profile startup directory"""
407 """Run files from profile startup directory"""
367 startup_dirs = [self.profile_dir.startup_dir] + [
408 startup_dirs = [self.profile_dir.startup_dir] + [
368 os.path.join(p, 'startup') for p in chain(ENV_CONFIG_DIRS, SYSTEM_CONFIG_DIRS)
409 os.path.join(p, 'startup') for p in chain(ENV_CONFIG_DIRS, SYSTEM_CONFIG_DIRS)
369 ]
410 ]
370 startup_files = []
411 startup_files = []
371
412
372 if self.exec_PYTHONSTARTUP and os.environ.get('PYTHONSTARTUP', False) and \
413 if self.exec_PYTHONSTARTUP and os.environ.get('PYTHONSTARTUP', False) and \
373 not (self.file_to_run or self.code_to_run or self.module_to_run):
414 not (self.file_to_run or self.code_to_run or self.module_to_run):
374 python_startup = os.environ['PYTHONSTARTUP']
415 python_startup = os.environ['PYTHONSTARTUP']
375 self.log.debug("Running PYTHONSTARTUP file %s...", python_startup)
416 self.log.debug("Running PYTHONSTARTUP file %s...", python_startup)
376 try:
417 try:
377 self._exec_file(python_startup)
418 self._exec_file(python_startup)
378 except:
419 except:
379 self.log.warning("Unknown error in handling PYTHONSTARTUP file %s:", python_startup)
420 self.log.warning("Unknown error in handling PYTHONSTARTUP file %s:", python_startup)
380 self.shell.showtraceback()
421 self.shell.showtraceback()
381 for startup_dir in startup_dirs[::-1]:
422 for startup_dir in startup_dirs[::-1]:
382 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
423 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
383 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
424 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
384 if not startup_files:
425 if not startup_files:
385 return
426 return
386
427
387 self.log.debug("Running startup files from %s...", startup_dir)
428 self.log.debug("Running startup files from %s...", startup_dir)
388 try:
429 try:
389 for fname in sorted(startup_files):
430 for fname in sorted(startup_files):
390 self._exec_file(fname)
431 self._exec_file(fname)
391 except:
432 except:
392 self.log.warning("Unknown error in handling startup files:")
433 self.log.warning("Unknown error in handling startup files:")
393 self.shell.showtraceback()
434 self.shell.showtraceback()
394
435
395 def _run_exec_files(self):
436 def _run_exec_files(self):
396 """Run files from IPythonApp.exec_files"""
437 """Run files from IPythonApp.exec_files"""
397 if not self.exec_files:
438 if not self.exec_files:
398 return
439 return
399
440
400 self.log.debug("Running files in IPythonApp.exec_files...")
441 self.log.debug("Running files in IPythonApp.exec_files...")
401 try:
442 try:
402 for fname in self.exec_files:
443 for fname in self.exec_files:
403 self._exec_file(fname)
444 self._exec_file(fname)
404 except:
445 except:
405 self.log.warning("Unknown error in handling IPythonApp.exec_files:")
446 self.log.warning("Unknown error in handling IPythonApp.exec_files:")
406 self.shell.showtraceback()
447 self.shell.showtraceback()
407
448
408 def _run_cmd_line_code(self):
449 def _run_cmd_line_code(self):
409 """Run code or file specified at the command-line"""
450 """Run code or file specified at the command-line"""
410 if self.code_to_run:
451 if self.code_to_run:
411 line = self.code_to_run
452 line = self.code_to_run
412 try:
453 try:
413 self.log.info("Running code given at command line (c=): %s" %
454 self.log.info("Running code given at command line (c=): %s" %
414 line)
455 line)
415 self.shell.run_cell(line, store_history=False)
456 self.shell.run_cell(line, store_history=False)
416 except:
457 except:
417 self.log.warning("Error in executing line in user namespace: %s" %
458 self.log.warning("Error in executing line in user namespace: %s" %
418 line)
459 line)
419 self.shell.showtraceback()
460 self.shell.showtraceback()
420 if not self.interact:
461 if not self.interact:
421 self.exit(1)
462 self.exit(1)
422
463
423 # Like Python itself, ignore the second if the first of these is present
464 # Like Python itself, ignore the second if the first of these is present
424 elif self.file_to_run:
465 elif self.file_to_run:
425 fname = self.file_to_run
466 fname = self.file_to_run
426 if os.path.isdir(fname):
467 if os.path.isdir(fname):
427 fname = os.path.join(fname, "__main__.py")
468 fname = os.path.join(fname, "__main__.py")
428 if not os.path.exists(fname):
469 if not os.path.exists(fname):
429 self.log.warning("File '%s' doesn't exist", fname)
470 self.log.warning("File '%s' doesn't exist", fname)
430 if not self.interact:
471 if not self.interact:
431 self.exit(2)
472 self.exit(2)
432 try:
473 try:
433 self._exec_file(fname, shell_futures=True)
474 self._exec_file(fname, shell_futures=True)
434 except:
475 except:
435 self.shell.showtraceback(tb_offset=4)
476 self.shell.showtraceback(tb_offset=4)
436 if not self.interact:
477 if not self.interact:
437 self.exit(1)
478 self.exit(1)
438
479
439 def _run_module(self):
480 def _run_module(self):
440 """Run module specified at the command-line."""
481 """Run module specified at the command-line."""
441 if self.module_to_run:
482 if self.module_to_run:
442 # Make sure that the module gets a proper sys.argv as if it were
483 # Make sure that the module gets a proper sys.argv as if it were
443 # run using `python -m`.
484 # run using `python -m`.
444 save_argv = sys.argv
485 save_argv = sys.argv
445 sys.argv = [sys.executable] + self.extra_args
486 sys.argv = [sys.executable] + self.extra_args
446 try:
487 try:
447 self.shell.safe_run_module(self.module_to_run,
488 self.shell.safe_run_module(self.module_to_run,
448 self.shell.user_ns)
489 self.shell.user_ns)
449 finally:
490 finally:
450 sys.argv = save_argv
491 sys.argv = save_argv
General Comments 0
You need to be logged in to leave comments. Login now