##// END OF EJS Templates
MAINT: refactor/please mypy....
Matthias Bussonnier -
Show More
@@ -1,41 +1,38 b''
1 name: Run MyPy
1 name: Run MyPy
2
2
3 on:
3 on:
4 push:
4 push:
5 branches: [ main, 7.x]
5 branches: [ main, 7.x]
6 pull_request:
6 pull_request:
7 branches: [ main, 7.x]
7 branches: [ main, 7.x]
8
8
9 permissions:
9 permissions:
10 contents: read
10 contents: read
11
11
12 jobs:
12 jobs:
13 build:
13 build:
14
14
15 runs-on: ubuntu-latest
15 runs-on: ubuntu-latest
16 strategy:
16 strategy:
17 matrix:
17 matrix:
18 python-version: ["3.x"]
18 python-version: ["3.x"]
19
19
20 steps:
20 steps:
21 - uses: actions/checkout@v3
21 - uses: actions/checkout@v3
22 - name: Set up Python ${{ matrix.python-version }}
22 - name: Set up Python ${{ matrix.python-version }}
23 uses: actions/setup-python@v4
23 uses: actions/setup-python@v4
24 with:
24 with:
25 python-version: ${{ matrix.python-version }}
25 python-version: ${{ matrix.python-version }}
26 - name: Install dependencies
26 - name: Install dependencies
27 run: |
27 run: |
28 python -m pip install --upgrade pip
28 python -m pip install --upgrade pip
29 pip install mypy pyflakes flake8
29 pip install mypy pyflakes flake8 types-decorator
30 - name: Lint with mypy
30 - name: Lint with mypy
31 run: |
31 run: |
32 set -e
32 set -e
33 mypy -p IPython.terminal
33 mypy IPython
34 mypy -p IPython.core.magics
35 mypy -p IPython.core.guarded_eval
36 mypy -p IPython.core.completer
37 - name: Lint with pyflakes
34 - name: Lint with pyflakes
38 run: |
35 run: |
39 set -e
36 set -e
40 flake8 IPython/core/magics/script.py
37 flake8 IPython/core/magics/script.py
41 flake8 IPython/core/magics/packaging.py
38 flake8 IPython/core/magics/packaging.py
@@ -1,1026 +1,1028 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Display formatters.
2 """Display formatters.
3
3
4 Inheritance diagram:
4 Inheritance diagram:
5
5
6 .. inheritance-diagram:: IPython.core.formatters
6 .. inheritance-diagram:: IPython.core.formatters
7 :parts: 3
7 :parts: 3
8 """
8 """
9
9
10 # Copyright (c) IPython Development Team.
10 # Copyright (c) IPython Development Team.
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12
12
13 import abc
13 import abc
14 import sys
14 import sys
15 import traceback
15 import traceback
16 import warnings
16 import warnings
17 from io import StringIO
17 from io import StringIO
18
18
19 from decorator import decorator
19 from decorator import decorator
20
20
21 from traitlets.config.configurable import Configurable
21 from traitlets.config.configurable import Configurable
22 from .getipython import get_ipython
22 from .getipython import get_ipython
23 from ..utils.sentinel import Sentinel
23 from ..utils.sentinel import Sentinel
24 from ..utils.dir2 import get_real_method
24 from ..utils.dir2 import get_real_method
25 from ..lib import pretty
25 from ..lib import pretty
26 from traitlets import (
26 from traitlets import (
27 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
27 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
28 ForwardDeclaredInstance,
28 ForwardDeclaredInstance,
29 default, observe,
29 default, observe,
30 )
30 )
31
31
32 from typing import Any
33
32
34
33 class DisplayFormatter(Configurable):
35 class DisplayFormatter(Configurable):
34
36
35 active_types = List(Unicode(),
37 active_types = List(Unicode(),
36 help="""List of currently active mime-types to display.
38 help="""List of currently active mime-types to display.
37 You can use this to set a white-list for formats to display.
39 You can use this to set a white-list for formats to display.
38
40
39 Most users will not need to change this value.
41 Most users will not need to change this value.
40 """).tag(config=True)
42 """).tag(config=True)
41
43
42 @default('active_types')
44 @default('active_types')
43 def _active_types_default(self):
45 def _active_types_default(self):
44 return self.format_types
46 return self.format_types
45
47
46 @observe('active_types')
48 @observe('active_types')
47 def _active_types_changed(self, change):
49 def _active_types_changed(self, change):
48 for key, formatter in self.formatters.items():
50 for key, formatter in self.formatters.items():
49 if key in change['new']:
51 if key in change['new']:
50 formatter.enabled = True
52 formatter.enabled = True
51 else:
53 else:
52 formatter.enabled = False
54 formatter.enabled = False
53
55
54 ipython_display_formatter = ForwardDeclaredInstance('FormatterABC')
56 ipython_display_formatter = ForwardDeclaredInstance('FormatterABC')
55 @default('ipython_display_formatter')
57 @default('ipython_display_formatter')
56 def _default_formatter(self):
58 def _default_formatter(self):
57 return IPythonDisplayFormatter(parent=self)
59 return IPythonDisplayFormatter(parent=self)
58
60
59 mimebundle_formatter = ForwardDeclaredInstance('FormatterABC')
61 mimebundle_formatter = ForwardDeclaredInstance('FormatterABC')
60 @default('mimebundle_formatter')
62 @default('mimebundle_formatter')
61 def _default_mime_formatter(self):
63 def _default_mime_formatter(self):
62 return MimeBundleFormatter(parent=self)
64 return MimeBundleFormatter(parent=self)
63
65
64 # A dict of formatter whose keys are format types (MIME types) and whose
66 # A dict of formatter whose keys are format types (MIME types) and whose
65 # values are subclasses of BaseFormatter.
67 # values are subclasses of BaseFormatter.
66 formatters = Dict()
68 formatters = Dict()
67 @default('formatters')
69 @default('formatters')
68 def _formatters_default(self):
70 def _formatters_default(self):
69 """Activate the default formatters."""
71 """Activate the default formatters."""
70 formatter_classes = [
72 formatter_classes = [
71 PlainTextFormatter,
73 PlainTextFormatter,
72 HTMLFormatter,
74 HTMLFormatter,
73 MarkdownFormatter,
75 MarkdownFormatter,
74 SVGFormatter,
76 SVGFormatter,
75 PNGFormatter,
77 PNGFormatter,
76 PDFFormatter,
78 PDFFormatter,
77 JPEGFormatter,
79 JPEGFormatter,
78 LatexFormatter,
80 LatexFormatter,
79 JSONFormatter,
81 JSONFormatter,
80 JavascriptFormatter
82 JavascriptFormatter
81 ]
83 ]
82 d = {}
84 d = {}
83 for cls in formatter_classes:
85 for cls in formatter_classes:
84 f = cls(parent=self)
86 f = cls(parent=self)
85 d[f.format_type] = f
87 d[f.format_type] = f
86 return d
88 return d
87
89
88 def format(self, obj, include=None, exclude=None):
90 def format(self, obj, include=None, exclude=None):
89 """Return a format data dict for an object.
91 """Return a format data dict for an object.
90
92
91 By default all format types will be computed.
93 By default all format types will be computed.
92
94
93 The following MIME types are usually implemented:
95 The following MIME types are usually implemented:
94
96
95 * text/plain
97 * text/plain
96 * text/html
98 * text/html
97 * text/markdown
99 * text/markdown
98 * text/latex
100 * text/latex
99 * application/json
101 * application/json
100 * application/javascript
102 * application/javascript
101 * application/pdf
103 * application/pdf
102 * image/png
104 * image/png
103 * image/jpeg
105 * image/jpeg
104 * image/svg+xml
106 * image/svg+xml
105
107
106 Parameters
108 Parameters
107 ----------
109 ----------
108 obj : object
110 obj : object
109 The Python object whose format data will be computed.
111 The Python object whose format data will be computed.
110 include : list, tuple or set; optional
112 include : list, tuple or set; optional
111 A list of format type strings (MIME types) to include in the
113 A list of format type strings (MIME types) to include in the
112 format data dict. If this is set *only* the format types included
114 format data dict. If this is set *only* the format types included
113 in this list will be computed.
115 in this list will be computed.
114 exclude : list, tuple or set; optional
116 exclude : list, tuple or set; optional
115 A list of format type string (MIME types) to exclude in the format
117 A list of format type string (MIME types) to exclude in the format
116 data dict. If this is set all format types will be computed,
118 data dict. If this is set all format types will be computed,
117 except for those included in this argument.
119 except for those included in this argument.
118 Mimetypes present in exclude will take precedence over the ones in include
120 Mimetypes present in exclude will take precedence over the ones in include
119
121
120 Returns
122 Returns
121 -------
123 -------
122 (format_dict, metadata_dict) : tuple of two dicts
124 (format_dict, metadata_dict) : tuple of two dicts
123 format_dict is a dictionary of key/value pairs, one of each format that was
125 format_dict is a dictionary of key/value pairs, one of each format that was
124 generated for the object. The keys are the format types, which
126 generated for the object. The keys are the format types, which
125 will usually be MIME type strings and the values and JSON'able
127 will usually be MIME type strings and the values and JSON'able
126 data structure containing the raw data for the representation in
128 data structure containing the raw data for the representation in
127 that format.
129 that format.
128
130
129 metadata_dict is a dictionary of metadata about each mime-type output.
131 metadata_dict is a dictionary of metadata about each mime-type output.
130 Its keys will be a strict subset of the keys in format_dict.
132 Its keys will be a strict subset of the keys in format_dict.
131
133
132 Notes
134 Notes
133 -----
135 -----
134 If an object implement `_repr_mimebundle_` as well as various
136 If an object implement `_repr_mimebundle_` as well as various
135 `_repr_*_`, the data returned by `_repr_mimebundle_` will take
137 `_repr_*_`, the data returned by `_repr_mimebundle_` will take
136 precedence and the corresponding `_repr_*_` for this mimetype will
138 precedence and the corresponding `_repr_*_` for this mimetype will
137 not be called.
139 not be called.
138
140
139 """
141 """
140 format_dict = {}
142 format_dict = {}
141 md_dict = {}
143 md_dict = {}
142
144
143 if self.ipython_display_formatter(obj):
145 if self.ipython_display_formatter(obj):
144 # object handled itself, don't proceed
146 # object handled itself, don't proceed
145 return {}, {}
147 return {}, {}
146
148
147 format_dict, md_dict = self.mimebundle_formatter(obj, include=include, exclude=exclude)
149 format_dict, md_dict = self.mimebundle_formatter(obj, include=include, exclude=exclude)
148
150
149 if format_dict or md_dict:
151 if format_dict or md_dict:
150 if include:
152 if include:
151 format_dict = {k:v for k,v in format_dict.items() if k in include}
153 format_dict = {k:v for k,v in format_dict.items() if k in include}
152 md_dict = {k:v for k,v in md_dict.items() if k in include}
154 md_dict = {k:v for k,v in md_dict.items() if k in include}
153 if exclude:
155 if exclude:
154 format_dict = {k:v for k,v in format_dict.items() if k not in exclude}
156 format_dict = {k:v for k,v in format_dict.items() if k not in exclude}
155 md_dict = {k:v for k,v in md_dict.items() if k not in exclude}
157 md_dict = {k:v for k,v in md_dict.items() if k not in exclude}
156
158
157 for format_type, formatter in self.formatters.items():
159 for format_type, formatter in self.formatters.items():
158 if format_type in format_dict:
160 if format_type in format_dict:
159 # already got it from mimebundle, maybe don't render again.
161 # already got it from mimebundle, maybe don't render again.
160 # exception: manually registered per-mime renderer
162 # exception: manually registered per-mime renderer
161 # check priority:
163 # check priority:
162 # 1. user-registered per-mime formatter
164 # 1. user-registered per-mime formatter
163 # 2. mime-bundle (user-registered or repr method)
165 # 2. mime-bundle (user-registered or repr method)
164 # 3. default per-mime formatter (e.g. repr method)
166 # 3. default per-mime formatter (e.g. repr method)
165 try:
167 try:
166 formatter.lookup(obj)
168 formatter.lookup(obj)
167 except KeyError:
169 except KeyError:
168 # no special formatter, use mime-bundle-provided value
170 # no special formatter, use mime-bundle-provided value
169 continue
171 continue
170 if include and format_type not in include:
172 if include and format_type not in include:
171 continue
173 continue
172 if exclude and format_type in exclude:
174 if exclude and format_type in exclude:
173 continue
175 continue
174
176
175 md = None
177 md = None
176 try:
178 try:
177 data = formatter(obj)
179 data = formatter(obj)
178 except:
180 except:
179 # FIXME: log the exception
181 # FIXME: log the exception
180 raise
182 raise
181
183
182 # formatters can return raw data or (data, metadata)
184 # formatters can return raw data or (data, metadata)
183 if isinstance(data, tuple) and len(data) == 2:
185 if isinstance(data, tuple) and len(data) == 2:
184 data, md = data
186 data, md = data
185
187
186 if data is not None:
188 if data is not None:
187 format_dict[format_type] = data
189 format_dict[format_type] = data
188 if md is not None:
190 if md is not None:
189 md_dict[format_type] = md
191 md_dict[format_type] = md
190 return format_dict, md_dict
192 return format_dict, md_dict
191
193
192 @property
194 @property
193 def format_types(self):
195 def format_types(self):
194 """Return the format types (MIME types) of the active formatters."""
196 """Return the format types (MIME types) of the active formatters."""
195 return list(self.formatters.keys())
197 return list(self.formatters.keys())
196
198
197
199
198 #-----------------------------------------------------------------------------
200 #-----------------------------------------------------------------------------
199 # Formatters for specific format types (text, html, svg, etc.)
201 # Formatters for specific format types (text, html, svg, etc.)
200 #-----------------------------------------------------------------------------
202 #-----------------------------------------------------------------------------
201
203
202
204
203 def _safe_repr(obj):
205 def _safe_repr(obj):
204 """Try to return a repr of an object
206 """Try to return a repr of an object
205
207
206 always returns a string, at least.
208 always returns a string, at least.
207 """
209 """
208 try:
210 try:
209 return repr(obj)
211 return repr(obj)
210 except Exception as e:
212 except Exception as e:
211 return "un-repr-able object (%r)" % e
213 return "un-repr-able object (%r)" % e
212
214
213
215
214 class FormatterWarning(UserWarning):
216 class FormatterWarning(UserWarning):
215 """Warning class for errors in formatters"""
217 """Warning class for errors in formatters"""
216
218
217 @decorator
219 @decorator
218 def catch_format_error(method, self, *args, **kwargs):
220 def catch_format_error(method, self, *args, **kwargs):
219 """show traceback on failed format call"""
221 """show traceback on failed format call"""
220 try:
222 try:
221 r = method(self, *args, **kwargs)
223 r = method(self, *args, **kwargs)
222 except NotImplementedError:
224 except NotImplementedError:
223 # don't warn on NotImplementedErrors
225 # don't warn on NotImplementedErrors
224 return self._check_return(None, args[0])
226 return self._check_return(None, args[0])
225 except Exception:
227 except Exception:
226 exc_info = sys.exc_info()
228 exc_info = sys.exc_info()
227 ip = get_ipython()
229 ip = get_ipython()
228 if ip is not None:
230 if ip is not None:
229 ip.showtraceback(exc_info)
231 ip.showtraceback(exc_info)
230 else:
232 else:
231 traceback.print_exception(*exc_info)
233 traceback.print_exception(*exc_info)
232 return self._check_return(None, args[0])
234 return self._check_return(None, args[0])
233 return self._check_return(r, args[0])
235 return self._check_return(r, args[0])
234
236
235
237
236 class FormatterABC(metaclass=abc.ABCMeta):
238 class FormatterABC(metaclass=abc.ABCMeta):
237 """ Abstract base class for Formatters.
239 """ Abstract base class for Formatters.
238
240
239 A formatter is a callable class that is responsible for computing the
241 A formatter is a callable class that is responsible for computing the
240 raw format data for a particular format type (MIME type). For example,
242 raw format data for a particular format type (MIME type). For example,
241 an HTML formatter would have a format type of `text/html` and would return
243 an HTML formatter would have a format type of `text/html` and would return
242 the HTML representation of the object when called.
244 the HTML representation of the object when called.
243 """
245 """
244
246
245 # The format type of the data returned, usually a MIME type.
247 # The format type of the data returned, usually a MIME type.
246 format_type = 'text/plain'
248 format_type = 'text/plain'
247
249
248 # Is the formatter enabled...
250 # Is the formatter enabled...
249 enabled = True
251 enabled = True
250
252
251 @abc.abstractmethod
253 @abc.abstractmethod
252 def __call__(self, obj):
254 def __call__(self, obj):
253 """Return a JSON'able representation of the object.
255 """Return a JSON'able representation of the object.
254
256
255 If the object cannot be formatted by this formatter,
257 If the object cannot be formatted by this formatter,
256 warn and return None.
258 warn and return None.
257 """
259 """
258 return repr(obj)
260 return repr(obj)
259
261
260
262
261 def _mod_name_key(typ):
263 def _mod_name_key(typ):
262 """Return a (__module__, __name__) tuple for a type.
264 """Return a (__module__, __name__) tuple for a type.
263
265
264 Used as key in Formatter.deferred_printers.
266 Used as key in Formatter.deferred_printers.
265 """
267 """
266 module = getattr(typ, '__module__', None)
268 module = getattr(typ, '__module__', None)
267 name = getattr(typ, '__name__', None)
269 name = getattr(typ, '__name__', None)
268 return (module, name)
270 return (module, name)
269
271
270
272
271 def _get_type(obj):
273 def _get_type(obj):
272 """Return the type of an instance (old and new-style)"""
274 """Return the type of an instance (old and new-style)"""
273 return getattr(obj, '__class__', None) or type(obj)
275 return getattr(obj, '__class__', None) or type(obj)
274
276
275
277
276 _raise_key_error = Sentinel('_raise_key_error', __name__,
278 _raise_key_error = Sentinel('_raise_key_error', __name__,
277 """
279 """
278 Special value to raise a KeyError
280 Special value to raise a KeyError
279
281
280 Raise KeyError in `BaseFormatter.pop` if passed as the default value to `pop`
282 Raise KeyError in `BaseFormatter.pop` if passed as the default value to `pop`
281 """)
283 """)
282
284
283
285
284 class BaseFormatter(Configurable):
286 class BaseFormatter(Configurable):
285 """A base formatter class that is configurable.
287 """A base formatter class that is configurable.
286
288
287 This formatter should usually be used as the base class of all formatters.
289 This formatter should usually be used as the base class of all formatters.
288 It is a traited :class:`Configurable` class and includes an extensible
290 It is a traited :class:`Configurable` class and includes an extensible
289 API for users to determine how their objects are formatted. The following
291 API for users to determine how their objects are formatted. The following
290 logic is used to find a function to format an given object.
292 logic is used to find a function to format an given object.
291
293
292 1. The object is introspected to see if it has a method with the name
294 1. The object is introspected to see if it has a method with the name
293 :attr:`print_method`. If is does, that object is passed to that method
295 :attr:`print_method`. If is does, that object is passed to that method
294 for formatting.
296 for formatting.
295 2. If no print method is found, three internal dictionaries are consulted
297 2. If no print method is found, three internal dictionaries are consulted
296 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
298 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
297 and :attr:`deferred_printers`.
299 and :attr:`deferred_printers`.
298
300
299 Users should use these dictionaries to register functions that will be
301 Users should use these dictionaries to register functions that will be
300 used to compute the format data for their objects (if those objects don't
302 used to compute the format data for their objects (if those objects don't
301 have the special print methods). The easiest way of using these
303 have the special print methods). The easiest way of using these
302 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
304 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
303 methods.
305 methods.
304
306
305 If no function/callable is found to compute the format data, ``None`` is
307 If no function/callable is found to compute the format data, ``None`` is
306 returned and this format type is not used.
308 returned and this format type is not used.
307 """
309 """
308
310
309 format_type = Unicode('text/plain')
311 format_type = Unicode("text/plain")
310 _return_type = str
312 _return_type: Any = str
311
313
312 enabled = Bool(True).tag(config=True)
314 enabled = Bool(True).tag(config=True)
313
315
314 print_method = ObjectName('__repr__')
316 print_method = ObjectName('__repr__')
315
317
316 # The singleton printers.
318 # The singleton printers.
317 # Maps the IDs of the builtin singleton objects to the format functions.
319 # Maps the IDs of the builtin singleton objects to the format functions.
318 singleton_printers = Dict().tag(config=True)
320 singleton_printers = Dict().tag(config=True)
319
321
320 # The type-specific printers.
322 # The type-specific printers.
321 # Map type objects to the format functions.
323 # Map type objects to the format functions.
322 type_printers = Dict().tag(config=True)
324 type_printers = Dict().tag(config=True)
323
325
324 # The deferred-import type-specific printers.
326 # The deferred-import type-specific printers.
325 # Map (modulename, classname) pairs to the format functions.
327 # Map (modulename, classname) pairs to the format functions.
326 deferred_printers = Dict().tag(config=True)
328 deferred_printers = Dict().tag(config=True)
327
329
328 @catch_format_error
330 @catch_format_error
329 def __call__(self, obj):
331 def __call__(self, obj):
330 """Compute the format for an object."""
332 """Compute the format for an object."""
331 if self.enabled:
333 if self.enabled:
332 # lookup registered printer
334 # lookup registered printer
333 try:
335 try:
334 printer = self.lookup(obj)
336 printer = self.lookup(obj)
335 except KeyError:
337 except KeyError:
336 pass
338 pass
337 else:
339 else:
338 return printer(obj)
340 return printer(obj)
339 # Finally look for special method names
341 # Finally look for special method names
340 method = get_real_method(obj, self.print_method)
342 method = get_real_method(obj, self.print_method)
341 if method is not None:
343 if method is not None:
342 return method()
344 return method()
343 return None
345 return None
344 else:
346 else:
345 return None
347 return None
346
348
347 def __contains__(self, typ):
349 def __contains__(self, typ):
348 """map in to lookup_by_type"""
350 """map in to lookup_by_type"""
349 try:
351 try:
350 self.lookup_by_type(typ)
352 self.lookup_by_type(typ)
351 except KeyError:
353 except KeyError:
352 return False
354 return False
353 else:
355 else:
354 return True
356 return True
355
357
356 def _check_return(self, r, obj):
358 def _check_return(self, r, obj):
357 """Check that a return value is appropriate
359 """Check that a return value is appropriate
358
360
359 Return the value if so, None otherwise, warning if invalid.
361 Return the value if so, None otherwise, warning if invalid.
360 """
362 """
361 if r is None or isinstance(r, self._return_type) or \
363 if r is None or isinstance(r, self._return_type) or \
362 (isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
364 (isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
363 return r
365 return r
364 else:
366 else:
365 warnings.warn(
367 warnings.warn(
366 "%s formatter returned invalid type %s (expected %s) for object: %s" % \
368 "%s formatter returned invalid type %s (expected %s) for object: %s" % \
367 (self.format_type, type(r), self._return_type, _safe_repr(obj)),
369 (self.format_type, type(r), self._return_type, _safe_repr(obj)),
368 FormatterWarning
370 FormatterWarning
369 )
371 )
370
372
371 def lookup(self, obj):
373 def lookup(self, obj):
372 """Look up the formatter for a given instance.
374 """Look up the formatter for a given instance.
373
375
374 Parameters
376 Parameters
375 ----------
377 ----------
376 obj : object instance
378 obj : object instance
377
379
378 Returns
380 Returns
379 -------
381 -------
380 f : callable
382 f : callable
381 The registered formatting callable for the type.
383 The registered formatting callable for the type.
382
384
383 Raises
385 Raises
384 ------
386 ------
385 KeyError if the type has not been registered.
387 KeyError if the type has not been registered.
386 """
388 """
387 # look for singleton first
389 # look for singleton first
388 obj_id = id(obj)
390 obj_id = id(obj)
389 if obj_id in self.singleton_printers:
391 if obj_id in self.singleton_printers:
390 return self.singleton_printers[obj_id]
392 return self.singleton_printers[obj_id]
391 # then lookup by type
393 # then lookup by type
392 return self.lookup_by_type(_get_type(obj))
394 return self.lookup_by_type(_get_type(obj))
393
395
394 def lookup_by_type(self, typ):
396 def lookup_by_type(self, typ):
395 """Look up the registered formatter for a type.
397 """Look up the registered formatter for a type.
396
398
397 Parameters
399 Parameters
398 ----------
400 ----------
399 typ : type or '__module__.__name__' string for a type
401 typ : type or '__module__.__name__' string for a type
400
402
401 Returns
403 Returns
402 -------
404 -------
403 f : callable
405 f : callable
404 The registered formatting callable for the type.
406 The registered formatting callable for the type.
405
407
406 Raises
408 Raises
407 ------
409 ------
408 KeyError if the type has not been registered.
410 KeyError if the type has not been registered.
409 """
411 """
410 if isinstance(typ, str):
412 if isinstance(typ, str):
411 typ_key = tuple(typ.rsplit('.',1))
413 typ_key = tuple(typ.rsplit('.',1))
412 if typ_key not in self.deferred_printers:
414 if typ_key not in self.deferred_printers:
413 # We may have it cached in the type map. We will have to
415 # We may have it cached in the type map. We will have to
414 # iterate over all of the types to check.
416 # iterate over all of the types to check.
415 for cls in self.type_printers:
417 for cls in self.type_printers:
416 if _mod_name_key(cls) == typ_key:
418 if _mod_name_key(cls) == typ_key:
417 return self.type_printers[cls]
419 return self.type_printers[cls]
418 else:
420 else:
419 return self.deferred_printers[typ_key]
421 return self.deferred_printers[typ_key]
420 else:
422 else:
421 for cls in pretty._get_mro(typ):
423 for cls in pretty._get_mro(typ):
422 if cls in self.type_printers or self._in_deferred_types(cls):
424 if cls in self.type_printers or self._in_deferred_types(cls):
423 return self.type_printers[cls]
425 return self.type_printers[cls]
424
426
425 # If we have reached here, the lookup failed.
427 # If we have reached here, the lookup failed.
426 raise KeyError("No registered printer for {0!r}".format(typ))
428 raise KeyError("No registered printer for {0!r}".format(typ))
427
429
428 def for_type(self, typ, func=None):
430 def for_type(self, typ, func=None):
429 """Add a format function for a given type.
431 """Add a format function for a given type.
430
432
431 Parameters
433 Parameters
432 ----------
434 ----------
433 typ : type or '__module__.__name__' string for a type
435 typ : type or '__module__.__name__' string for a type
434 The class of the object that will be formatted using `func`.
436 The class of the object that will be formatted using `func`.
435
437
436 func : callable
438 func : callable
437 A callable for computing the format data.
439 A callable for computing the format data.
438 `func` will be called with the object to be formatted,
440 `func` will be called with the object to be formatted,
439 and will return the raw data in this formatter's format.
441 and will return the raw data in this formatter's format.
440 Subclasses may use a different call signature for the
442 Subclasses may use a different call signature for the
441 `func` argument.
443 `func` argument.
442
444
443 If `func` is None or not specified, there will be no change,
445 If `func` is None or not specified, there will be no change,
444 only returning the current value.
446 only returning the current value.
445
447
446 Returns
448 Returns
447 -------
449 -------
448 oldfunc : callable
450 oldfunc : callable
449 The currently registered callable.
451 The currently registered callable.
450 If you are registering a new formatter,
452 If you are registering a new formatter,
451 this will be the previous value (to enable restoring later).
453 this will be the previous value (to enable restoring later).
452 """
454 """
453 # if string given, interpret as 'pkg.module.class_name'
455 # if string given, interpret as 'pkg.module.class_name'
454 if isinstance(typ, str):
456 if isinstance(typ, str):
455 type_module, type_name = typ.rsplit('.', 1)
457 type_module, type_name = typ.rsplit('.', 1)
456 return self.for_type_by_name(type_module, type_name, func)
458 return self.for_type_by_name(type_module, type_name, func)
457
459
458 try:
460 try:
459 oldfunc = self.lookup_by_type(typ)
461 oldfunc = self.lookup_by_type(typ)
460 except KeyError:
462 except KeyError:
461 oldfunc = None
463 oldfunc = None
462
464
463 if func is not None:
465 if func is not None:
464 self.type_printers[typ] = func
466 self.type_printers[typ] = func
465
467
466 return oldfunc
468 return oldfunc
467
469
468 def for_type_by_name(self, type_module, type_name, func=None):
470 def for_type_by_name(self, type_module, type_name, func=None):
469 """Add a format function for a type specified by the full dotted
471 """Add a format function for a type specified by the full dotted
470 module and name of the type, rather than the type of the object.
472 module and name of the type, rather than the type of the object.
471
473
472 Parameters
474 Parameters
473 ----------
475 ----------
474 type_module : str
476 type_module : str
475 The full dotted name of the module the type is defined in, like
477 The full dotted name of the module the type is defined in, like
476 ``numpy``.
478 ``numpy``.
477
479
478 type_name : str
480 type_name : str
479 The name of the type (the class name), like ``dtype``
481 The name of the type (the class name), like ``dtype``
480
482
481 func : callable
483 func : callable
482 A callable for computing the format data.
484 A callable for computing the format data.
483 `func` will be called with the object to be formatted,
485 `func` will be called with the object to be formatted,
484 and will return the raw data in this formatter's format.
486 and will return the raw data in this formatter's format.
485 Subclasses may use a different call signature for the
487 Subclasses may use a different call signature for the
486 `func` argument.
488 `func` argument.
487
489
488 If `func` is None or unspecified, there will be no change,
490 If `func` is None or unspecified, there will be no change,
489 only returning the current value.
491 only returning the current value.
490
492
491 Returns
493 Returns
492 -------
494 -------
493 oldfunc : callable
495 oldfunc : callable
494 The currently registered callable.
496 The currently registered callable.
495 If you are registering a new formatter,
497 If you are registering a new formatter,
496 this will be the previous value (to enable restoring later).
498 this will be the previous value (to enable restoring later).
497 """
499 """
498 key = (type_module, type_name)
500 key = (type_module, type_name)
499
501
500 try:
502 try:
501 oldfunc = self.lookup_by_type("%s.%s" % key)
503 oldfunc = self.lookup_by_type("%s.%s" % key)
502 except KeyError:
504 except KeyError:
503 oldfunc = None
505 oldfunc = None
504
506
505 if func is not None:
507 if func is not None:
506 self.deferred_printers[key] = func
508 self.deferred_printers[key] = func
507 return oldfunc
509 return oldfunc
508
510
509 def pop(self, typ, default=_raise_key_error):
511 def pop(self, typ, default=_raise_key_error):
510 """Pop a formatter for the given type.
512 """Pop a formatter for the given type.
511
513
512 Parameters
514 Parameters
513 ----------
515 ----------
514 typ : type or '__module__.__name__' string for a type
516 typ : type or '__module__.__name__' string for a type
515 default : object
517 default : object
516 value to be returned if no formatter is registered for typ.
518 value to be returned if no formatter is registered for typ.
517
519
518 Returns
520 Returns
519 -------
521 -------
520 obj : object
522 obj : object
521 The last registered object for the type.
523 The last registered object for the type.
522
524
523 Raises
525 Raises
524 ------
526 ------
525 KeyError if the type is not registered and default is not specified.
527 KeyError if the type is not registered and default is not specified.
526 """
528 """
527
529
528 if isinstance(typ, str):
530 if isinstance(typ, str):
529 typ_key = tuple(typ.rsplit('.',1))
531 typ_key = tuple(typ.rsplit('.',1))
530 if typ_key not in self.deferred_printers:
532 if typ_key not in self.deferred_printers:
531 # We may have it cached in the type map. We will have to
533 # We may have it cached in the type map. We will have to
532 # iterate over all of the types to check.
534 # iterate over all of the types to check.
533 for cls in self.type_printers:
535 for cls in self.type_printers:
534 if _mod_name_key(cls) == typ_key:
536 if _mod_name_key(cls) == typ_key:
535 old = self.type_printers.pop(cls)
537 old = self.type_printers.pop(cls)
536 break
538 break
537 else:
539 else:
538 old = default
540 old = default
539 else:
541 else:
540 old = self.deferred_printers.pop(typ_key)
542 old = self.deferred_printers.pop(typ_key)
541 else:
543 else:
542 if typ in self.type_printers:
544 if typ in self.type_printers:
543 old = self.type_printers.pop(typ)
545 old = self.type_printers.pop(typ)
544 else:
546 else:
545 old = self.deferred_printers.pop(_mod_name_key(typ), default)
547 old = self.deferred_printers.pop(_mod_name_key(typ), default)
546 if old is _raise_key_error:
548 if old is _raise_key_error:
547 raise KeyError("No registered value for {0!r}".format(typ))
549 raise KeyError("No registered value for {0!r}".format(typ))
548 return old
550 return old
549
551
550 def _in_deferred_types(self, cls):
552 def _in_deferred_types(self, cls):
551 """
553 """
552 Check if the given class is specified in the deferred type registry.
554 Check if the given class is specified in the deferred type registry.
553
555
554 Successful matches will be moved to the regular type registry for future use.
556 Successful matches will be moved to the regular type registry for future use.
555 """
557 """
556 mod = getattr(cls, '__module__', None)
558 mod = getattr(cls, '__module__', None)
557 name = getattr(cls, '__name__', None)
559 name = getattr(cls, '__name__', None)
558 key = (mod, name)
560 key = (mod, name)
559 if key in self.deferred_printers:
561 if key in self.deferred_printers:
560 # Move the printer over to the regular registry.
562 # Move the printer over to the regular registry.
561 printer = self.deferred_printers.pop(key)
563 printer = self.deferred_printers.pop(key)
562 self.type_printers[cls] = printer
564 self.type_printers[cls] = printer
563 return True
565 return True
564 return False
566 return False
565
567
566
568
567 class PlainTextFormatter(BaseFormatter):
569 class PlainTextFormatter(BaseFormatter):
568 """The default pretty-printer.
570 """The default pretty-printer.
569
571
570 This uses :mod:`IPython.lib.pretty` to compute the format data of
572 This uses :mod:`IPython.lib.pretty` to compute the format data of
571 the object. If the object cannot be pretty printed, :func:`repr` is used.
573 the object. If the object cannot be pretty printed, :func:`repr` is used.
572 See the documentation of :mod:`IPython.lib.pretty` for details on
574 See the documentation of :mod:`IPython.lib.pretty` for details on
573 how to write pretty printers. Here is a simple example::
575 how to write pretty printers. Here is a simple example::
574
576
575 def dtype_pprinter(obj, p, cycle):
577 def dtype_pprinter(obj, p, cycle):
576 if cycle:
578 if cycle:
577 return p.text('dtype(...)')
579 return p.text('dtype(...)')
578 if hasattr(obj, 'fields'):
580 if hasattr(obj, 'fields'):
579 if obj.fields is None:
581 if obj.fields is None:
580 p.text(repr(obj))
582 p.text(repr(obj))
581 else:
583 else:
582 p.begin_group(7, 'dtype([')
584 p.begin_group(7, 'dtype([')
583 for i, field in enumerate(obj.descr):
585 for i, field in enumerate(obj.descr):
584 if i > 0:
586 if i > 0:
585 p.text(',')
587 p.text(',')
586 p.breakable()
588 p.breakable()
587 p.pretty(field)
589 p.pretty(field)
588 p.end_group(7, '])')
590 p.end_group(7, '])')
589 """
591 """
590
592
591 # The format type of data returned.
593 # The format type of data returned.
592 format_type = Unicode('text/plain')
594 format_type = Unicode('text/plain')
593
595
594 # This subclass ignores this attribute as it always need to return
596 # This subclass ignores this attribute as it always need to return
595 # something.
597 # something.
596 enabled = Bool(True).tag(config=False)
598 enabled = Bool(True).tag(config=False)
597
599
598 max_seq_length = Integer(pretty.MAX_SEQ_LENGTH,
600 max_seq_length = Integer(pretty.MAX_SEQ_LENGTH,
599 help="""Truncate large collections (lists, dicts, tuples, sets) to this size.
601 help="""Truncate large collections (lists, dicts, tuples, sets) to this size.
600
602
601 Set to 0 to disable truncation.
603 Set to 0 to disable truncation.
602 """
604 """
603 ).tag(config=True)
605 ).tag(config=True)
604
606
605 # Look for a _repr_pretty_ methods to use for pretty printing.
607 # Look for a _repr_pretty_ methods to use for pretty printing.
606 print_method = ObjectName('_repr_pretty_')
608 print_method = ObjectName('_repr_pretty_')
607
609
608 # Whether to pretty-print or not.
610 # Whether to pretty-print or not.
609 pprint = Bool(True).tag(config=True)
611 pprint = Bool(True).tag(config=True)
610
612
611 # Whether to be verbose or not.
613 # Whether to be verbose or not.
612 verbose = Bool(False).tag(config=True)
614 verbose = Bool(False).tag(config=True)
613
615
614 # The maximum width.
616 # The maximum width.
615 max_width = Integer(79).tag(config=True)
617 max_width = Integer(79).tag(config=True)
616
618
617 # The newline character.
619 # The newline character.
618 newline = Unicode('\n').tag(config=True)
620 newline = Unicode('\n').tag(config=True)
619
621
620 # format-string for pprinting floats
622 # format-string for pprinting floats
621 float_format = Unicode('%r')
623 float_format = Unicode('%r')
622 # setter for float precision, either int or direct format-string
624 # setter for float precision, either int or direct format-string
623 float_precision = CUnicode('').tag(config=True)
625 float_precision = CUnicode('').tag(config=True)
624
626
625 @observe('float_precision')
627 @observe('float_precision')
626 def _float_precision_changed(self, change):
628 def _float_precision_changed(self, change):
627 """float_precision changed, set float_format accordingly.
629 """float_precision changed, set float_format accordingly.
628
630
629 float_precision can be set by int or str.
631 float_precision can be set by int or str.
630 This will set float_format, after interpreting input.
632 This will set float_format, after interpreting input.
631 If numpy has been imported, numpy print precision will also be set.
633 If numpy has been imported, numpy print precision will also be set.
632
634
633 integer `n` sets format to '%.nf', otherwise, format set directly.
635 integer `n` sets format to '%.nf', otherwise, format set directly.
634
636
635 An empty string returns to defaults (repr for float, 8 for numpy).
637 An empty string returns to defaults (repr for float, 8 for numpy).
636
638
637 This parameter can be set via the '%precision' magic.
639 This parameter can be set via the '%precision' magic.
638 """
640 """
639 new = change['new']
641 new = change['new']
640 if '%' in new:
642 if '%' in new:
641 # got explicit format string
643 # got explicit format string
642 fmt = new
644 fmt = new
643 try:
645 try:
644 fmt%3.14159
646 fmt%3.14159
645 except Exception as e:
647 except Exception as e:
646 raise ValueError("Precision must be int or format string, not %r"%new) from e
648 raise ValueError("Precision must be int or format string, not %r"%new) from e
647 elif new:
649 elif new:
648 # otherwise, should be an int
650 # otherwise, should be an int
649 try:
651 try:
650 i = int(new)
652 i = int(new)
651 assert i >= 0
653 assert i >= 0
652 except ValueError as e:
654 except ValueError as e:
653 raise ValueError("Precision must be int or format string, not %r"%new) from e
655 raise ValueError("Precision must be int or format string, not %r"%new) from e
654 except AssertionError as e:
656 except AssertionError as e:
655 raise ValueError("int precision must be non-negative, not %r"%i) from e
657 raise ValueError("int precision must be non-negative, not %r"%i) from e
656
658
657 fmt = '%%.%if'%i
659 fmt = '%%.%if'%i
658 if 'numpy' in sys.modules:
660 if 'numpy' in sys.modules:
659 # set numpy precision if it has been imported
661 # set numpy precision if it has been imported
660 import numpy
662 import numpy
661 numpy.set_printoptions(precision=i)
663 numpy.set_printoptions(precision=i)
662 else:
664 else:
663 # default back to repr
665 # default back to repr
664 fmt = '%r'
666 fmt = '%r'
665 if 'numpy' in sys.modules:
667 if 'numpy' in sys.modules:
666 import numpy
668 import numpy
667 # numpy default is 8
669 # numpy default is 8
668 numpy.set_printoptions(precision=8)
670 numpy.set_printoptions(precision=8)
669 self.float_format = fmt
671 self.float_format = fmt
670
672
671 # Use the default pretty printers from IPython.lib.pretty.
673 # Use the default pretty printers from IPython.lib.pretty.
672 @default('singleton_printers')
674 @default('singleton_printers')
673 def _singleton_printers_default(self):
675 def _singleton_printers_default(self):
674 return pretty._singleton_pprinters.copy()
676 return pretty._singleton_pprinters.copy()
675
677
676 @default('type_printers')
678 @default('type_printers')
677 def _type_printers_default(self):
679 def _type_printers_default(self):
678 d = pretty._type_pprinters.copy()
680 d = pretty._type_pprinters.copy()
679 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
681 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
680 # if NumPy is used, set precision for its float64 type
682 # if NumPy is used, set precision for its float64 type
681 if "numpy" in sys.modules:
683 if "numpy" in sys.modules:
682 import numpy
684 import numpy
683
685
684 d[numpy.float64] = lambda obj, p, cycle: p.text(self.float_format % obj)
686 d[numpy.float64] = lambda obj, p, cycle: p.text(self.float_format % obj)
685 return d
687 return d
686
688
687 @default('deferred_printers')
689 @default('deferred_printers')
688 def _deferred_printers_default(self):
690 def _deferred_printers_default(self):
689 return pretty._deferred_type_pprinters.copy()
691 return pretty._deferred_type_pprinters.copy()
690
692
691 #### FormatterABC interface ####
693 #### FormatterABC interface ####
692
694
693 @catch_format_error
695 @catch_format_error
694 def __call__(self, obj):
696 def __call__(self, obj):
695 """Compute the pretty representation of the object."""
697 """Compute the pretty representation of the object."""
696 if not self.pprint:
698 if not self.pprint:
697 return repr(obj)
699 return repr(obj)
698 else:
700 else:
699 stream = StringIO()
701 stream = StringIO()
700 printer = pretty.RepresentationPrinter(stream, self.verbose,
702 printer = pretty.RepresentationPrinter(stream, self.verbose,
701 self.max_width, self.newline,
703 self.max_width, self.newline,
702 max_seq_length=self.max_seq_length,
704 max_seq_length=self.max_seq_length,
703 singleton_pprinters=self.singleton_printers,
705 singleton_pprinters=self.singleton_printers,
704 type_pprinters=self.type_printers,
706 type_pprinters=self.type_printers,
705 deferred_pprinters=self.deferred_printers)
707 deferred_pprinters=self.deferred_printers)
706 printer.pretty(obj)
708 printer.pretty(obj)
707 printer.flush()
709 printer.flush()
708 return stream.getvalue()
710 return stream.getvalue()
709
711
710
712
711 class HTMLFormatter(BaseFormatter):
713 class HTMLFormatter(BaseFormatter):
712 """An HTML formatter.
714 """An HTML formatter.
713
715
714 To define the callables that compute the HTML representation of your
716 To define the callables that compute the HTML representation of your
715 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
717 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
716 or :meth:`for_type_by_name` methods to register functions that handle
718 or :meth:`for_type_by_name` methods to register functions that handle
717 this.
719 this.
718
720
719 The return value of this formatter should be a valid HTML snippet that
721 The return value of this formatter should be a valid HTML snippet that
720 could be injected into an existing DOM. It should *not* include the
722 could be injected into an existing DOM. It should *not* include the
721 ```<html>`` or ```<body>`` tags.
723 ```<html>`` or ```<body>`` tags.
722 """
724 """
723 format_type = Unicode('text/html')
725 format_type = Unicode('text/html')
724
726
725 print_method = ObjectName('_repr_html_')
727 print_method = ObjectName('_repr_html_')
726
728
727
729
728 class MarkdownFormatter(BaseFormatter):
730 class MarkdownFormatter(BaseFormatter):
729 """A Markdown formatter.
731 """A Markdown formatter.
730
732
731 To define the callables that compute the Markdown representation of your
733 To define the callables that compute the Markdown representation of your
732 objects, define a :meth:`_repr_markdown_` method or use the :meth:`for_type`
734 objects, define a :meth:`_repr_markdown_` method or use the :meth:`for_type`
733 or :meth:`for_type_by_name` methods to register functions that handle
735 or :meth:`for_type_by_name` methods to register functions that handle
734 this.
736 this.
735
737
736 The return value of this formatter should be a valid Markdown.
738 The return value of this formatter should be a valid Markdown.
737 """
739 """
738 format_type = Unicode('text/markdown')
740 format_type = Unicode('text/markdown')
739
741
740 print_method = ObjectName('_repr_markdown_')
742 print_method = ObjectName('_repr_markdown_')
741
743
742 class SVGFormatter(BaseFormatter):
744 class SVGFormatter(BaseFormatter):
743 """An SVG formatter.
745 """An SVG formatter.
744
746
745 To define the callables that compute the SVG representation of your
747 To define the callables that compute the SVG representation of your
746 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
748 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
747 or :meth:`for_type_by_name` methods to register functions that handle
749 or :meth:`for_type_by_name` methods to register functions that handle
748 this.
750 this.
749
751
750 The return value of this formatter should be valid SVG enclosed in
752 The return value of this formatter should be valid SVG enclosed in
751 ```<svg>``` tags, that could be injected into an existing DOM. It should
753 ```<svg>``` tags, that could be injected into an existing DOM. It should
752 *not* include the ```<html>`` or ```<body>`` tags.
754 *not* include the ```<html>`` or ```<body>`` tags.
753 """
755 """
754 format_type = Unicode('image/svg+xml')
756 format_type = Unicode('image/svg+xml')
755
757
756 print_method = ObjectName('_repr_svg_')
758 print_method = ObjectName('_repr_svg_')
757
759
758
760
759 class PNGFormatter(BaseFormatter):
761 class PNGFormatter(BaseFormatter):
760 """A PNG formatter.
762 """A PNG formatter.
761
763
762 To define the callables that compute the PNG representation of your
764 To define the callables that compute the PNG representation of your
763 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
765 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
764 or :meth:`for_type_by_name` methods to register functions that handle
766 or :meth:`for_type_by_name` methods to register functions that handle
765 this.
767 this.
766
768
767 The return value of this formatter should be raw PNG data, *not*
769 The return value of this formatter should be raw PNG data, *not*
768 base64 encoded.
770 base64 encoded.
769 """
771 """
770 format_type = Unicode('image/png')
772 format_type = Unicode('image/png')
771
773
772 print_method = ObjectName('_repr_png_')
774 print_method = ObjectName('_repr_png_')
773
775
774 _return_type = (bytes, str)
776 _return_type = (bytes, str)
775
777
776
778
777 class JPEGFormatter(BaseFormatter):
779 class JPEGFormatter(BaseFormatter):
778 """A JPEG formatter.
780 """A JPEG formatter.
779
781
780 To define the callables that compute the JPEG representation of your
782 To define the callables that compute the JPEG representation of your
781 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
783 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
782 or :meth:`for_type_by_name` methods to register functions that handle
784 or :meth:`for_type_by_name` methods to register functions that handle
783 this.
785 this.
784
786
785 The return value of this formatter should be raw JPEG data, *not*
787 The return value of this formatter should be raw JPEG data, *not*
786 base64 encoded.
788 base64 encoded.
787 """
789 """
788 format_type = Unicode('image/jpeg')
790 format_type = Unicode('image/jpeg')
789
791
790 print_method = ObjectName('_repr_jpeg_')
792 print_method = ObjectName('_repr_jpeg_')
791
793
792 _return_type = (bytes, str)
794 _return_type = (bytes, str)
793
795
794
796
795 class LatexFormatter(BaseFormatter):
797 class LatexFormatter(BaseFormatter):
796 """A LaTeX formatter.
798 """A LaTeX formatter.
797
799
798 To define the callables that compute the LaTeX representation of your
800 To define the callables that compute the LaTeX representation of your
799 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
801 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
800 or :meth:`for_type_by_name` methods to register functions that handle
802 or :meth:`for_type_by_name` methods to register functions that handle
801 this.
803 this.
802
804
803 The return value of this formatter should be a valid LaTeX equation,
805 The return value of this formatter should be a valid LaTeX equation,
804 enclosed in either ```$```, ```$$``` or another LaTeX equation
806 enclosed in either ```$```, ```$$``` or another LaTeX equation
805 environment.
807 environment.
806 """
808 """
807 format_type = Unicode('text/latex')
809 format_type = Unicode('text/latex')
808
810
809 print_method = ObjectName('_repr_latex_')
811 print_method = ObjectName('_repr_latex_')
810
812
811
813
812 class JSONFormatter(BaseFormatter):
814 class JSONFormatter(BaseFormatter):
813 """A JSON string formatter.
815 """A JSON string formatter.
814
816
815 To define the callables that compute the JSONable representation of
817 To define the callables that compute the JSONable representation of
816 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
818 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
817 or :meth:`for_type_by_name` methods to register functions that handle
819 or :meth:`for_type_by_name` methods to register functions that handle
818 this.
820 this.
819
821
820 The return value of this formatter should be a JSONable list or dict.
822 The return value of this formatter should be a JSONable list or dict.
821 JSON scalars (None, number, string) are not allowed, only dict or list containers.
823 JSON scalars (None, number, string) are not allowed, only dict or list containers.
822 """
824 """
823 format_type = Unicode('application/json')
825 format_type = Unicode('application/json')
824 _return_type = (list, dict)
826 _return_type = (list, dict)
825
827
826 print_method = ObjectName('_repr_json_')
828 print_method = ObjectName('_repr_json_')
827
829
828 def _check_return(self, r, obj):
830 def _check_return(self, r, obj):
829 """Check that a return value is appropriate
831 """Check that a return value is appropriate
830
832
831 Return the value if so, None otherwise, warning if invalid.
833 Return the value if so, None otherwise, warning if invalid.
832 """
834 """
833 if r is None:
835 if r is None:
834 return
836 return
835 md = None
837 md = None
836 if isinstance(r, tuple):
838 if isinstance(r, tuple):
837 # unpack data, metadata tuple for type checking on first element
839 # unpack data, metadata tuple for type checking on first element
838 r, md = r
840 r, md = r
839
841
840 assert not isinstance(
842 assert not isinstance(
841 r, str
843 r, str
842 ), "JSON-as-string has been deprecated since IPython < 3"
844 ), "JSON-as-string has been deprecated since IPython < 3"
843
845
844 if md is not None:
846 if md is not None:
845 # put the tuple back together
847 # put the tuple back together
846 r = (r, md)
848 r = (r, md)
847 return super(JSONFormatter, self)._check_return(r, obj)
849 return super(JSONFormatter, self)._check_return(r, obj)
848
850
849
851
850 class JavascriptFormatter(BaseFormatter):
852 class JavascriptFormatter(BaseFormatter):
851 """A Javascript formatter.
853 """A Javascript formatter.
852
854
853 To define the callables that compute the Javascript representation of
855 To define the callables that compute the Javascript representation of
854 your objects, define a :meth:`_repr_javascript_` method or use the
856 your objects, define a :meth:`_repr_javascript_` method or use the
855 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
857 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
856 that handle this.
858 that handle this.
857
859
858 The return value of this formatter should be valid Javascript code and
860 The return value of this formatter should be valid Javascript code and
859 should *not* be enclosed in ```<script>``` tags.
861 should *not* be enclosed in ```<script>``` tags.
860 """
862 """
861 format_type = Unicode('application/javascript')
863 format_type = Unicode('application/javascript')
862
864
863 print_method = ObjectName('_repr_javascript_')
865 print_method = ObjectName('_repr_javascript_')
864
866
865
867
866 class PDFFormatter(BaseFormatter):
868 class PDFFormatter(BaseFormatter):
867 """A PDF formatter.
869 """A PDF formatter.
868
870
869 To define the callables that compute the PDF representation of your
871 To define the callables that compute the PDF representation of your
870 objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type`
872 objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type`
871 or :meth:`for_type_by_name` methods to register functions that handle
873 or :meth:`for_type_by_name` methods to register functions that handle
872 this.
874 this.
873
875
874 The return value of this formatter should be raw PDF data, *not*
876 The return value of this formatter should be raw PDF data, *not*
875 base64 encoded.
877 base64 encoded.
876 """
878 """
877 format_type = Unicode('application/pdf')
879 format_type = Unicode('application/pdf')
878
880
879 print_method = ObjectName('_repr_pdf_')
881 print_method = ObjectName('_repr_pdf_')
880
882
881 _return_type = (bytes, str)
883 _return_type = (bytes, str)
882
884
883 class IPythonDisplayFormatter(BaseFormatter):
885 class IPythonDisplayFormatter(BaseFormatter):
884 """An escape-hatch Formatter for objects that know how to display themselves.
886 """An escape-hatch Formatter for objects that know how to display themselves.
885
887
886 To define the callables that compute the representation of your
888 To define the callables that compute the representation of your
887 objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type`
889 objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type`
888 or :meth:`for_type_by_name` methods to register functions that handle
890 or :meth:`for_type_by_name` methods to register functions that handle
889 this. Unlike mime-type displays, this method should not return anything,
891 this. Unlike mime-type displays, this method should not return anything,
890 instead calling any appropriate display methods itself.
892 instead calling any appropriate display methods itself.
891
893
892 This display formatter has highest priority.
894 This display formatter has highest priority.
893 If it fires, no other display formatter will be called.
895 If it fires, no other display formatter will be called.
894
896
895 Prior to IPython 6.1, `_ipython_display_` was the only way to display custom mime-types
897 Prior to IPython 6.1, `_ipython_display_` was the only way to display custom mime-types
896 without registering a new Formatter.
898 without registering a new Formatter.
897
899
898 IPython 6.1 introduces `_repr_mimebundle_` for displaying custom mime-types,
900 IPython 6.1 introduces `_repr_mimebundle_` for displaying custom mime-types,
899 so `_ipython_display_` should only be used for objects that require unusual
901 so `_ipython_display_` should only be used for objects that require unusual
900 display patterns, such as multiple display calls.
902 display patterns, such as multiple display calls.
901 """
903 """
902 print_method = ObjectName('_ipython_display_')
904 print_method = ObjectName('_ipython_display_')
903 _return_type = (type(None), bool)
905 _return_type = (type(None), bool)
904
906
905 @catch_format_error
907 @catch_format_error
906 def __call__(self, obj):
908 def __call__(self, obj):
907 """Compute the format for an object."""
909 """Compute the format for an object."""
908 if self.enabled:
910 if self.enabled:
909 # lookup registered printer
911 # lookup registered printer
910 try:
912 try:
911 printer = self.lookup(obj)
913 printer = self.lookup(obj)
912 except KeyError:
914 except KeyError:
913 pass
915 pass
914 else:
916 else:
915 printer(obj)
917 printer(obj)
916 return True
918 return True
917 # Finally look for special method names
919 # Finally look for special method names
918 method = get_real_method(obj, self.print_method)
920 method = get_real_method(obj, self.print_method)
919 if method is not None:
921 if method is not None:
920 method()
922 method()
921 return True
923 return True
922
924
923
925
924 class MimeBundleFormatter(BaseFormatter):
926 class MimeBundleFormatter(BaseFormatter):
925 """A Formatter for arbitrary mime-types.
927 """A Formatter for arbitrary mime-types.
926
928
927 Unlike other `_repr_<mimetype>_` methods,
929 Unlike other `_repr_<mimetype>_` methods,
928 `_repr_mimebundle_` should return mime-bundle data,
930 `_repr_mimebundle_` should return mime-bundle data,
929 either the mime-keyed `data` dictionary or the tuple `(data, metadata)`.
931 either the mime-keyed `data` dictionary or the tuple `(data, metadata)`.
930 Any mime-type is valid.
932 Any mime-type is valid.
931
933
932 To define the callables that compute the mime-bundle representation of your
934 To define the callables that compute the mime-bundle representation of your
933 objects, define a :meth:`_repr_mimebundle_` method or use the :meth:`for_type`
935 objects, define a :meth:`_repr_mimebundle_` method or use the :meth:`for_type`
934 or :meth:`for_type_by_name` methods to register functions that handle
936 or :meth:`for_type_by_name` methods to register functions that handle
935 this.
937 this.
936
938
937 .. versionadded:: 6.1
939 .. versionadded:: 6.1
938 """
940 """
939 print_method = ObjectName('_repr_mimebundle_')
941 print_method = ObjectName('_repr_mimebundle_')
940 _return_type = dict
942 _return_type = dict
941
943
942 def _check_return(self, r, obj):
944 def _check_return(self, r, obj):
943 r = super(MimeBundleFormatter, self)._check_return(r, obj)
945 r = super(MimeBundleFormatter, self)._check_return(r, obj)
944 # always return (data, metadata):
946 # always return (data, metadata):
945 if r is None:
947 if r is None:
946 return {}, {}
948 return {}, {}
947 if not isinstance(r, tuple):
949 if not isinstance(r, tuple):
948 return r, {}
950 return r, {}
949 return r
951 return r
950
952
951 @catch_format_error
953 @catch_format_error
952 def __call__(self, obj, include=None, exclude=None):
954 def __call__(self, obj, include=None, exclude=None):
953 """Compute the format for an object.
955 """Compute the format for an object.
954
956
955 Identical to parent's method but we pass extra parameters to the method.
957 Identical to parent's method but we pass extra parameters to the method.
956
958
957 Unlike other _repr_*_ `_repr_mimebundle_` should allow extra kwargs, in
959 Unlike other _repr_*_ `_repr_mimebundle_` should allow extra kwargs, in
958 particular `include` and `exclude`.
960 particular `include` and `exclude`.
959 """
961 """
960 if self.enabled:
962 if self.enabled:
961 # lookup registered printer
963 # lookup registered printer
962 try:
964 try:
963 printer = self.lookup(obj)
965 printer = self.lookup(obj)
964 except KeyError:
966 except KeyError:
965 pass
967 pass
966 else:
968 else:
967 return printer(obj)
969 return printer(obj)
968 # Finally look for special method names
970 # Finally look for special method names
969 method = get_real_method(obj, self.print_method)
971 method = get_real_method(obj, self.print_method)
970
972
971 if method is not None:
973 if method is not None:
972 return method(include=include, exclude=exclude)
974 return method(include=include, exclude=exclude)
973 return None
975 return None
974 else:
976 else:
975 return None
977 return None
976
978
977
979
978 FormatterABC.register(BaseFormatter)
980 FormatterABC.register(BaseFormatter)
979 FormatterABC.register(PlainTextFormatter)
981 FormatterABC.register(PlainTextFormatter)
980 FormatterABC.register(HTMLFormatter)
982 FormatterABC.register(HTMLFormatter)
981 FormatterABC.register(MarkdownFormatter)
983 FormatterABC.register(MarkdownFormatter)
982 FormatterABC.register(SVGFormatter)
984 FormatterABC.register(SVGFormatter)
983 FormatterABC.register(PNGFormatter)
985 FormatterABC.register(PNGFormatter)
984 FormatterABC.register(PDFFormatter)
986 FormatterABC.register(PDFFormatter)
985 FormatterABC.register(JPEGFormatter)
987 FormatterABC.register(JPEGFormatter)
986 FormatterABC.register(LatexFormatter)
988 FormatterABC.register(LatexFormatter)
987 FormatterABC.register(JSONFormatter)
989 FormatterABC.register(JSONFormatter)
988 FormatterABC.register(JavascriptFormatter)
990 FormatterABC.register(JavascriptFormatter)
989 FormatterABC.register(IPythonDisplayFormatter)
991 FormatterABC.register(IPythonDisplayFormatter)
990 FormatterABC.register(MimeBundleFormatter)
992 FormatterABC.register(MimeBundleFormatter)
991
993
992
994
993 def format_display_data(obj, include=None, exclude=None):
995 def format_display_data(obj, include=None, exclude=None):
994 """Return a format data dict for an object.
996 """Return a format data dict for an object.
995
997
996 By default all format types will be computed.
998 By default all format types will be computed.
997
999
998 Parameters
1000 Parameters
999 ----------
1001 ----------
1000 obj : object
1002 obj : object
1001 The Python object whose format data will be computed.
1003 The Python object whose format data will be computed.
1002
1004
1003 Returns
1005 Returns
1004 -------
1006 -------
1005 format_dict : dict
1007 format_dict : dict
1006 A dictionary of key/value pairs, one or each format that was
1008 A dictionary of key/value pairs, one or each format that was
1007 generated for the object. The keys are the format types, which
1009 generated for the object. The keys are the format types, which
1008 will usually be MIME type strings and the values and JSON'able
1010 will usually be MIME type strings and the values and JSON'able
1009 data structure containing the raw data for the representation in
1011 data structure containing the raw data for the representation in
1010 that format.
1012 that format.
1011 include : list or tuple, optional
1013 include : list or tuple, optional
1012 A list of format type strings (MIME types) to include in the
1014 A list of format type strings (MIME types) to include in the
1013 format data dict. If this is set *only* the format types included
1015 format data dict. If this is set *only* the format types included
1014 in this list will be computed.
1016 in this list will be computed.
1015 exclude : list or tuple, optional
1017 exclude : list or tuple, optional
1016 A list of format type string (MIME types) to exclude in the format
1018 A list of format type string (MIME types) to exclude in the format
1017 data dict. If this is set all format types will be computed,
1019 data dict. If this is set all format types will be computed,
1018 except for those included in this argument.
1020 except for those included in this argument.
1019 """
1021 """
1020 from .interactiveshell import InteractiveShell
1022 from .interactiveshell import InteractiveShell
1021
1023
1022 return InteractiveShell.instance().display_formatter.format(
1024 return InteractiveShell.instance().display_formatter.format(
1023 obj,
1025 obj,
1024 include,
1026 include,
1025 exclude
1027 exclude
1026 )
1028 )
@@ -1,772 +1,773 b''
1 """DEPRECATED: Input handling and transformation machinery.
1 """DEPRECATED: Input handling and transformation machinery.
2
2
3 This module was deprecated in IPython 7.0, in favour of inputtransformer2.
3 This module was deprecated in IPython 7.0, in favour of inputtransformer2.
4
4
5 The first class in this module, :class:`InputSplitter`, is designed to tell when
5 The first class in this module, :class:`InputSplitter`, is designed to tell when
6 input from a line-oriented frontend is complete and should be executed, and when
6 input from a line-oriented frontend is complete and should be executed, and when
7 the user should be prompted for another line of code instead. The name 'input
7 the user should be prompted for another line of code instead. The name 'input
8 splitter' is largely for historical reasons.
8 splitter' is largely for historical reasons.
9
9
10 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
10 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
11 with full support for the extended IPython syntax (magics, system calls, etc).
11 with full support for the extended IPython syntax (magics, system calls, etc).
12 The code to actually do these transformations is in :mod:`IPython.core.inputtransformer`.
12 The code to actually do these transformations is in :mod:`IPython.core.inputtransformer`.
13 :class:`IPythonInputSplitter` feeds the raw code to the transformers in order
13 :class:`IPythonInputSplitter` feeds the raw code to the transformers in order
14 and stores the results.
14 and stores the results.
15
15
16 For more details, see the class docstrings below.
16 For more details, see the class docstrings below.
17 """
17 """
18
18
19 from warnings import warn
19 from warnings import warn
20
20
21 warn('IPython.core.inputsplitter is deprecated since IPython 7 in favor of `IPython.core.inputtransformer2`',
21 warn('IPython.core.inputsplitter is deprecated since IPython 7 in favor of `IPython.core.inputtransformer2`',
22 DeprecationWarning)
22 DeprecationWarning)
23
23
24 # Copyright (c) IPython Development Team.
24 # Copyright (c) IPython Development Team.
25 # Distributed under the terms of the Modified BSD License.
25 # Distributed under the terms of the Modified BSD License.
26 import ast
26 import ast
27 import codeop
27 import codeop
28 import io
28 import io
29 import re
29 import re
30 import sys
30 import sys
31 import tokenize
31 import tokenize
32 import warnings
32 import warnings
33
33
34 from typing import List
35
34 from IPython.core.inputtransformer import (leading_indent,
36 from IPython.core.inputtransformer import (leading_indent,
35 classic_prompt,
37 classic_prompt,
36 ipy_prompt,
38 ipy_prompt,
37 cellmagic,
39 cellmagic,
38 assemble_logical_lines,
40 assemble_logical_lines,
39 help_end,
41 help_end,
40 escaped_commands,
42 escaped_commands,
41 assign_from_magic,
43 assign_from_magic,
42 assign_from_system,
44 assign_from_system,
43 assemble_python_lines,
45 assemble_python_lines,
44 )
46 )
45
47
46 # These are available in this module for backwards compatibility.
48 # These are available in this module for backwards compatibility.
47 from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
49 from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
48 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
50 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
49 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
51 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
50
52
51 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
52 # Utilities
54 # Utilities
53 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
54
56
55 # FIXME: These are general-purpose utilities that later can be moved to the
57 # FIXME: These are general-purpose utilities that later can be moved to the
56 # general ward. Kept here for now because we're being very strict about test
58 # general ward. Kept here for now because we're being very strict about test
57 # coverage with this code, and this lets us ensure that we keep 100% coverage
59 # coverage with this code, and this lets us ensure that we keep 100% coverage
58 # while developing.
60 # while developing.
59
61
60 # compiled regexps for autoindent management
62 # compiled regexps for autoindent management
61 dedent_re = re.compile('|'.join([
63 dedent_re = re.compile('|'.join([
62 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
64 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
63 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
65 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
64 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
66 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
65 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
67 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
66 r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
68 r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
67 r'^\s+break\s*$', # break (optionally followed by trailing spaces)
69 r'^\s+break\s*$', # break (optionally followed by trailing spaces)
68 r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
70 r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
69 ]))
71 ]))
70 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
72 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
71
73
72 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
74 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
73 # before pure comments
75 # before pure comments
74 comment_line_re = re.compile(r'^\s*\#')
76 comment_line_re = re.compile(r'^\s*\#')
75
77
76
78
77 def num_ini_spaces(s):
79 def num_ini_spaces(s):
78 """Return the number of initial spaces in a string.
80 """Return the number of initial spaces in a string.
79
81
80 Note that tabs are counted as a single space. For now, we do *not* support
82 Note that tabs are counted as a single space. For now, we do *not* support
81 mixing of tabs and spaces in the user's input.
83 mixing of tabs and spaces in the user's input.
82
84
83 Parameters
85 Parameters
84 ----------
86 ----------
85 s : string
87 s : string
86
88
87 Returns
89 Returns
88 -------
90 -------
89 n : int
91 n : int
90 """
92 """
91
93
92 ini_spaces = ini_spaces_re.match(s)
94 ini_spaces = ini_spaces_re.match(s)
93 if ini_spaces:
95 if ini_spaces:
94 return ini_spaces.end()
96 return ini_spaces.end()
95 else:
97 else:
96 return 0
98 return 0
97
99
98 # Fake token types for partial_tokenize:
100 # Fake token types for partial_tokenize:
99 INCOMPLETE_STRING = tokenize.N_TOKENS
101 INCOMPLETE_STRING = tokenize.N_TOKENS
100 IN_MULTILINE_STATEMENT = tokenize.N_TOKENS + 1
102 IN_MULTILINE_STATEMENT = tokenize.N_TOKENS + 1
101
103
102 # The 2 classes below have the same API as TokenInfo, but don't try to look up
104 # The 2 classes below have the same API as TokenInfo, but don't try to look up
103 # a token type name that they won't find.
105 # a token type name that they won't find.
104 class IncompleteString:
106 class IncompleteString:
105 type = exact_type = INCOMPLETE_STRING
107 type = exact_type = INCOMPLETE_STRING
106 def __init__(self, s, start, end, line):
108 def __init__(self, s, start, end, line):
107 self.s = s
109 self.s = s
108 self.start = start
110 self.start = start
109 self.end = end
111 self.end = end
110 self.line = line
112 self.line = line
111
113
112 class InMultilineStatement:
114 class InMultilineStatement:
113 type = exact_type = IN_MULTILINE_STATEMENT
115 type = exact_type = IN_MULTILINE_STATEMENT
114 def __init__(self, pos, line):
116 def __init__(self, pos, line):
115 self.s = ''
117 self.s = ''
116 self.start = self.end = pos
118 self.start = self.end = pos
117 self.line = line
119 self.line = line
118
120
119 def partial_tokens(s):
121 def partial_tokens(s):
120 """Iterate over tokens from a possibly-incomplete string of code.
122 """Iterate over tokens from a possibly-incomplete string of code.
121
123
122 This adds two special token types: INCOMPLETE_STRING and
124 This adds two special token types: INCOMPLETE_STRING and
123 IN_MULTILINE_STATEMENT. These can only occur as the last token yielded, and
125 IN_MULTILINE_STATEMENT. These can only occur as the last token yielded, and
124 represent the two main ways for code to be incomplete.
126 represent the two main ways for code to be incomplete.
125 """
127 """
126 readline = io.StringIO(s).readline
128 readline = io.StringIO(s).readline
127 token = tokenize.TokenInfo(tokenize.NEWLINE, '', (1, 0), (1, 0), '')
129 token = tokenize.TokenInfo(tokenize.NEWLINE, '', (1, 0), (1, 0), '')
128 try:
130 try:
129 for token in tokenize.generate_tokens(readline):
131 for token in tokenize.generate_tokens(readline):
130 yield token
132 yield token
131 except tokenize.TokenError as e:
133 except tokenize.TokenError as e:
132 # catch EOF error
134 # catch EOF error
133 lines = s.splitlines(keepends=True)
135 lines = s.splitlines(keepends=True)
134 end = len(lines), len(lines[-1])
136 end = len(lines), len(lines[-1])
135 if 'multi-line string' in e.args[0]:
137 if 'multi-line string' in e.args[0]:
136 l, c = start = token.end
138 l, c = start = token.end
137 s = lines[l-1][c:] + ''.join(lines[l:])
139 s = lines[l-1][c:] + ''.join(lines[l:])
138 yield IncompleteString(s, start, end, lines[-1])
140 yield IncompleteString(s, start, end, lines[-1])
139 elif 'multi-line statement' in e.args[0]:
141 elif 'multi-line statement' in e.args[0]:
140 yield InMultilineStatement(end, lines[-1])
142 yield InMultilineStatement(end, lines[-1])
141 else:
143 else:
142 raise
144 raise
143
145
144 def find_next_indent(code):
146 def find_next_indent(code):
145 """Find the number of spaces for the next line of indentation"""
147 """Find the number of spaces for the next line of indentation"""
146 tokens = list(partial_tokens(code))
148 tokens = list(partial_tokens(code))
147 if tokens[-1].type == tokenize.ENDMARKER:
149 if tokens[-1].type == tokenize.ENDMARKER:
148 tokens.pop()
150 tokens.pop()
149 if not tokens:
151 if not tokens:
150 return 0
152 return 0
151 while (tokens[-1].type in {tokenize.DEDENT, tokenize.NEWLINE, tokenize.COMMENT}):
153 while (tokens[-1].type in {tokenize.DEDENT, tokenize.NEWLINE, tokenize.COMMENT}):
152 tokens.pop()
154 tokens.pop()
153
155
154 if tokens[-1].type == INCOMPLETE_STRING:
156 if tokens[-1].type == INCOMPLETE_STRING:
155 # Inside a multiline string
157 # Inside a multiline string
156 return 0
158 return 0
157
159
158 # Find the indents used before
160 # Find the indents used before
159 prev_indents = [0]
161 prev_indents = [0]
160 def _add_indent(n):
162 def _add_indent(n):
161 if n != prev_indents[-1]:
163 if n != prev_indents[-1]:
162 prev_indents.append(n)
164 prev_indents.append(n)
163
165
164 tokiter = iter(tokens)
166 tokiter = iter(tokens)
165 for tok in tokiter:
167 for tok in tokiter:
166 if tok.type in {tokenize.INDENT, tokenize.DEDENT}:
168 if tok.type in {tokenize.INDENT, tokenize.DEDENT}:
167 _add_indent(tok.end[1])
169 _add_indent(tok.end[1])
168 elif (tok.type == tokenize.NL):
170 elif (tok.type == tokenize.NL):
169 try:
171 try:
170 _add_indent(next(tokiter).start[1])
172 _add_indent(next(tokiter).start[1])
171 except StopIteration:
173 except StopIteration:
172 break
174 break
173
175
174 last_indent = prev_indents.pop()
176 last_indent = prev_indents.pop()
175
177
176 # If we've just opened a multiline statement (e.g. 'a = ['), indent more
178 # If we've just opened a multiline statement (e.g. 'a = ['), indent more
177 if tokens[-1].type == IN_MULTILINE_STATEMENT:
179 if tokens[-1].type == IN_MULTILINE_STATEMENT:
178 if tokens[-2].exact_type in {tokenize.LPAR, tokenize.LSQB, tokenize.LBRACE}:
180 if tokens[-2].exact_type in {tokenize.LPAR, tokenize.LSQB, tokenize.LBRACE}:
179 return last_indent + 4
181 return last_indent + 4
180 return last_indent
182 return last_indent
181
183
182 if tokens[-1].exact_type == tokenize.COLON:
184 if tokens[-1].exact_type == tokenize.COLON:
183 # Line ends with colon - indent
185 # Line ends with colon - indent
184 return last_indent + 4
186 return last_indent + 4
185
187
186 if last_indent:
188 if last_indent:
187 # Examine the last line for dedent cues - statements like return or
189 # Examine the last line for dedent cues - statements like return or
188 # raise which normally end a block of code.
190 # raise which normally end a block of code.
189 last_line_starts = 0
191 last_line_starts = 0
190 for i, tok in enumerate(tokens):
192 for i, tok in enumerate(tokens):
191 if tok.type == tokenize.NEWLINE:
193 if tok.type == tokenize.NEWLINE:
192 last_line_starts = i + 1
194 last_line_starts = i + 1
193
195
194 last_line_tokens = tokens[last_line_starts:]
196 last_line_tokens = tokens[last_line_starts:]
195 names = [t.string for t in last_line_tokens if t.type == tokenize.NAME]
197 names = [t.string for t in last_line_tokens if t.type == tokenize.NAME]
196 if names and names[0] in {'raise', 'return', 'pass', 'break', 'continue'}:
198 if names and names[0] in {'raise', 'return', 'pass', 'break', 'continue'}:
197 # Find the most recent indentation less than the current level
199 # Find the most recent indentation less than the current level
198 for indent in reversed(prev_indents):
200 for indent in reversed(prev_indents):
199 if indent < last_indent:
201 if indent < last_indent:
200 return indent
202 return indent
201
203
202 return last_indent
204 return last_indent
203
205
204
206
205 def last_blank(src):
207 def last_blank(src):
206 """Determine if the input source ends in a blank.
208 """Determine if the input source ends in a blank.
207
209
208 A blank is either a newline or a line consisting of whitespace.
210 A blank is either a newline or a line consisting of whitespace.
209
211
210 Parameters
212 Parameters
211 ----------
213 ----------
212 src : string
214 src : string
213 A single or multiline string.
215 A single or multiline string.
214 """
216 """
215 if not src: return False
217 if not src: return False
216 ll = src.splitlines()[-1]
218 ll = src.splitlines()[-1]
217 return (ll == '') or ll.isspace()
219 return (ll == '') or ll.isspace()
218
220
219
221
220 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
222 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
221 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
223 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
222
224
223 def last_two_blanks(src):
225 def last_two_blanks(src):
224 """Determine if the input source ends in two blanks.
226 """Determine if the input source ends in two blanks.
225
227
226 A blank is either a newline or a line consisting of whitespace.
228 A blank is either a newline or a line consisting of whitespace.
227
229
228 Parameters
230 Parameters
229 ----------
231 ----------
230 src : string
232 src : string
231 A single or multiline string.
233 A single or multiline string.
232 """
234 """
233 if not src: return False
235 if not src: return False
234 # The logic here is tricky: I couldn't get a regexp to work and pass all
236 # The logic here is tricky: I couldn't get a regexp to work and pass all
235 # the tests, so I took a different approach: split the source by lines,
237 # the tests, so I took a different approach: split the source by lines,
236 # grab the last two and prepend '###\n' as a stand-in for whatever was in
238 # grab the last two and prepend '###\n' as a stand-in for whatever was in
237 # the body before the last two lines. Then, with that structure, it's
239 # the body before the last two lines. Then, with that structure, it's
238 # possible to analyze with two regexps. Not the most elegant solution, but
240 # possible to analyze with two regexps. Not the most elegant solution, but
239 # it works. If anyone tries to change this logic, make sure to validate
241 # it works. If anyone tries to change this logic, make sure to validate
240 # the whole test suite first!
242 # the whole test suite first!
241 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
243 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
242 return (bool(last_two_blanks_re.match(new_src)) or
244 return (bool(last_two_blanks_re.match(new_src)) or
243 bool(last_two_blanks_re2.match(new_src)) )
245 bool(last_two_blanks_re2.match(new_src)) )
244
246
245
247
246 def remove_comments(src):
248 def remove_comments(src):
247 """Remove all comments from input source.
249 """Remove all comments from input source.
248
250
249 Note: comments are NOT recognized inside of strings!
251 Note: comments are NOT recognized inside of strings!
250
252
251 Parameters
253 Parameters
252 ----------
254 ----------
253 src : string
255 src : string
254 A single or multiline input string.
256 A single or multiline input string.
255
257
256 Returns
258 Returns
257 -------
259 -------
258 String with all Python comments removed.
260 String with all Python comments removed.
259 """
261 """
260
262
261 return re.sub('#.*', '', src)
263 return re.sub('#.*', '', src)
262
264
263
265
264 def get_input_encoding():
266 def get_input_encoding():
265 """Return the default standard input encoding.
267 """Return the default standard input encoding.
266
268
267 If sys.stdin has no encoding, 'ascii' is returned."""
269 If sys.stdin has no encoding, 'ascii' is returned."""
268 # There are strange environments for which sys.stdin.encoding is None. We
270 # There are strange environments for which sys.stdin.encoding is None. We
269 # ensure that a valid encoding is returned.
271 # ensure that a valid encoding is returned.
270 encoding = getattr(sys.stdin, 'encoding', None)
272 encoding = getattr(sys.stdin, 'encoding', None)
271 if encoding is None:
273 if encoding is None:
272 encoding = 'ascii'
274 encoding = 'ascii'
273 return encoding
275 return encoding
274
276
275 #-----------------------------------------------------------------------------
277 #-----------------------------------------------------------------------------
276 # Classes and functions for normal Python syntax handling
278 # Classes and functions for normal Python syntax handling
277 #-----------------------------------------------------------------------------
279 #-----------------------------------------------------------------------------
278
280
279 class InputSplitter(object):
281 class InputSplitter(object):
280 r"""An object that can accumulate lines of Python source before execution.
282 r"""An object that can accumulate lines of Python source before execution.
281
283
282 This object is designed to be fed python source line-by-line, using
284 This object is designed to be fed python source line-by-line, using
283 :meth:`push`. It will return on each push whether the currently pushed
285 :meth:`push`. It will return on each push whether the currently pushed
284 code could be executed already. In addition, it provides a method called
286 code could be executed already. In addition, it provides a method called
285 :meth:`push_accepts_more` that can be used to query whether more input
287 :meth:`push_accepts_more` that can be used to query whether more input
286 can be pushed into a single interactive block.
288 can be pushed into a single interactive block.
287
289
288 This is a simple example of how an interactive terminal-based client can use
290 This is a simple example of how an interactive terminal-based client can use
289 this tool::
291 this tool::
290
292
291 isp = InputSplitter()
293 isp = InputSplitter()
292 while isp.push_accepts_more():
294 while isp.push_accepts_more():
293 indent = ' '*isp.indent_spaces
295 indent = ' '*isp.indent_spaces
294 prompt = '>>> ' + indent
296 prompt = '>>> ' + indent
295 line = indent + raw_input(prompt)
297 line = indent + raw_input(prompt)
296 isp.push(line)
298 isp.push(line)
297 print 'Input source was:\n', isp.source_reset(),
299 print 'Input source was:\n', isp.source_reset(),
298 """
300 """
299 # A cache for storing the current indentation
301 # A cache for storing the current indentation
300 # The first value stores the most recently processed source input
302 # The first value stores the most recently processed source input
301 # The second value is the number of spaces for the current indentation
303 # The second value is the number of spaces for the current indentation
302 # If self.source matches the first value, the second value is a valid
304 # If self.source matches the first value, the second value is a valid
303 # current indentation. Otherwise, the cache is invalid and the indentation
305 # current indentation. Otherwise, the cache is invalid and the indentation
304 # must be recalculated.
306 # must be recalculated.
305 _indent_spaces_cache = None, None
307 _indent_spaces_cache = None, None
306 # String, indicating the default input encoding. It is computed by default
308 # String, indicating the default input encoding. It is computed by default
307 # at initialization time via get_input_encoding(), but it can be reset by a
309 # at initialization time via get_input_encoding(), but it can be reset by a
308 # client with specific knowledge of the encoding.
310 # client with specific knowledge of the encoding.
309 encoding = ''
311 encoding = ''
310 # String where the current full source input is stored, properly encoded.
312 # String where the current full source input is stored, properly encoded.
311 # Reading this attribute is the normal way of querying the currently pushed
313 # Reading this attribute is the normal way of querying the currently pushed
312 # source code, that has been properly encoded.
314 # source code, that has been properly encoded.
313 source = ''
315 source = ''
314 # Code object corresponding to the current source. It is automatically
316 # Code object corresponding to the current source. It is automatically
315 # synced to the source, so it can be queried at any time to obtain the code
317 # synced to the source, so it can be queried at any time to obtain the code
316 # object; it will be None if the source doesn't compile to valid Python.
318 # object; it will be None if the source doesn't compile to valid Python.
317 code = None
319 code = None
318
320
319 # Private attributes
321 # Private attributes
320
322
321 # List with lines of input accumulated so far
323 # List with lines of input accumulated so far
322 _buffer = None
324 _buffer: List[str]
323 # Command compiler
325 # Command compiler
324 _compile = None
326 _compile: codeop.CommandCompiler
325 # Boolean indicating whether the current block is complete
327 # Boolean indicating whether the current block is complete
326 _is_complete = None
328 _is_complete = None
327 # Boolean indicating whether the current block has an unrecoverable syntax error
329 # Boolean indicating whether the current block has an unrecoverable syntax error
328 _is_invalid = False
330 _is_invalid = False
329
331
330 def __init__(self):
332 def __init__(self) -> None:
331 """Create a new InputSplitter instance.
333 """Create a new InputSplitter instance."""
332 """
333 self._buffer = []
334 self._buffer = []
334 self._compile = codeop.CommandCompiler()
335 self._compile = codeop.CommandCompiler()
335 self.encoding = get_input_encoding()
336 self.encoding = get_input_encoding()
336
337
337 def reset(self):
338 def reset(self):
338 """Reset the input buffer and associated state."""
339 """Reset the input buffer and associated state."""
339 self._buffer[:] = []
340 self._buffer[:] = []
340 self.source = ''
341 self.source = ''
341 self.code = None
342 self.code = None
342 self._is_complete = False
343 self._is_complete = False
343 self._is_invalid = False
344 self._is_invalid = False
344
345
345 def source_reset(self):
346 def source_reset(self):
346 """Return the input source and perform a full reset.
347 """Return the input source and perform a full reset.
347 """
348 """
348 out = self.source
349 out = self.source
349 self.reset()
350 self.reset()
350 return out
351 return out
351
352
352 def check_complete(self, source):
353 def check_complete(self, source):
353 """Return whether a block of code is ready to execute, or should be continued
354 """Return whether a block of code is ready to execute, or should be continued
354
355
355 This is a non-stateful API, and will reset the state of this InputSplitter.
356 This is a non-stateful API, and will reset the state of this InputSplitter.
356
357
357 Parameters
358 Parameters
358 ----------
359 ----------
359 source : string
360 source : string
360 Python input code, which can be multiline.
361 Python input code, which can be multiline.
361
362
362 Returns
363 Returns
363 -------
364 -------
364 status : str
365 status : str
365 One of 'complete', 'incomplete', or 'invalid' if source is not a
366 One of 'complete', 'incomplete', or 'invalid' if source is not a
366 prefix of valid code.
367 prefix of valid code.
367 indent_spaces : int or None
368 indent_spaces : int or None
368 The number of spaces by which to indent the next line of code. If
369 The number of spaces by which to indent the next line of code. If
369 status is not 'incomplete', this is None.
370 status is not 'incomplete', this is None.
370 """
371 """
371 self.reset()
372 self.reset()
372 try:
373 try:
373 self.push(source)
374 self.push(source)
374 except SyntaxError:
375 except SyntaxError:
375 # Transformers in IPythonInputSplitter can raise SyntaxError,
376 # Transformers in IPythonInputSplitter can raise SyntaxError,
376 # which push() will not catch.
377 # which push() will not catch.
377 return 'invalid', None
378 return 'invalid', None
378 else:
379 else:
379 if self._is_invalid:
380 if self._is_invalid:
380 return 'invalid', None
381 return 'invalid', None
381 elif self.push_accepts_more():
382 elif self.push_accepts_more():
382 return 'incomplete', self.get_indent_spaces()
383 return 'incomplete', self.get_indent_spaces()
383 else:
384 else:
384 return 'complete', None
385 return 'complete', None
385 finally:
386 finally:
386 self.reset()
387 self.reset()
387
388
388 def push(self, lines:str) -> bool:
389 def push(self, lines:str) -> bool:
389 """Push one or more lines of input.
390 """Push one or more lines of input.
390
391
391 This stores the given lines and returns a status code indicating
392 This stores the given lines and returns a status code indicating
392 whether the code forms a complete Python block or not.
393 whether the code forms a complete Python block or not.
393
394
394 Any exceptions generated in compilation are swallowed, but if an
395 Any exceptions generated in compilation are swallowed, but if an
395 exception was produced, the method returns True.
396 exception was produced, the method returns True.
396
397
397 Parameters
398 Parameters
398 ----------
399 ----------
399 lines : string
400 lines : string
400 One or more lines of Python input.
401 One or more lines of Python input.
401
402
402 Returns
403 Returns
403 -------
404 -------
404 is_complete : boolean
405 is_complete : boolean
405 True if the current input source (the result of the current input
406 True if the current input source (the result of the current input
406 plus prior inputs) forms a complete Python execution block. Note that
407 plus prior inputs) forms a complete Python execution block. Note that
407 this value is also stored as a private attribute (``_is_complete``), so it
408 this value is also stored as a private attribute (``_is_complete``), so it
408 can be queried at any time.
409 can be queried at any time.
409 """
410 """
410 assert isinstance(lines, str)
411 assert isinstance(lines, str)
411 self._store(lines)
412 self._store(lines)
412 source = self.source
413 source = self.source
413
414
414 # Before calling _compile(), reset the code object to None so that if an
415 # Before calling _compile(), reset the code object to None so that if an
415 # exception is raised in compilation, we don't mislead by having
416 # exception is raised in compilation, we don't mislead by having
416 # inconsistent code/source attributes.
417 # inconsistent code/source attributes.
417 self.code, self._is_complete = None, None
418 self.code, self._is_complete = None, None
418 self._is_invalid = False
419 self._is_invalid = False
419
420
420 # Honor termination lines properly
421 # Honor termination lines properly
421 if source.endswith('\\\n'):
422 if source.endswith('\\\n'):
422 return False
423 return False
423
424
424 try:
425 try:
425 with warnings.catch_warnings():
426 with warnings.catch_warnings():
426 warnings.simplefilter('error', SyntaxWarning)
427 warnings.simplefilter('error', SyntaxWarning)
427 self.code = self._compile(source, symbol="exec")
428 self.code = self._compile(source, symbol="exec")
428 # Invalid syntax can produce any of a number of different errors from
429 # Invalid syntax can produce any of a number of different errors from
429 # inside the compiler, so we have to catch them all. Syntax errors
430 # inside the compiler, so we have to catch them all. Syntax errors
430 # immediately produce a 'ready' block, so the invalid Python can be
431 # immediately produce a 'ready' block, so the invalid Python can be
431 # sent to the kernel for evaluation with possible ipython
432 # sent to the kernel for evaluation with possible ipython
432 # special-syntax conversion.
433 # special-syntax conversion.
433 except (SyntaxError, OverflowError, ValueError, TypeError,
434 except (SyntaxError, OverflowError, ValueError, TypeError,
434 MemoryError, SyntaxWarning):
435 MemoryError, SyntaxWarning):
435 self._is_complete = True
436 self._is_complete = True
436 self._is_invalid = True
437 self._is_invalid = True
437 else:
438 else:
438 # Compilation didn't produce any exceptions (though it may not have
439 # Compilation didn't produce any exceptions (though it may not have
439 # given a complete code object)
440 # given a complete code object)
440 self._is_complete = self.code is not None
441 self._is_complete = self.code is not None
441
442
442 return self._is_complete
443 return self._is_complete
443
444
444 def push_accepts_more(self):
445 def push_accepts_more(self):
445 """Return whether a block of interactive input can accept more input.
446 """Return whether a block of interactive input can accept more input.
446
447
447 This method is meant to be used by line-oriented frontends, who need to
448 This method is meant to be used by line-oriented frontends, who need to
448 guess whether a block is complete or not based solely on prior and
449 guess whether a block is complete or not based solely on prior and
449 current input lines. The InputSplitter considers it has a complete
450 current input lines. The InputSplitter considers it has a complete
450 interactive block and will not accept more input when either:
451 interactive block and will not accept more input when either:
451
452
452 * A SyntaxError is raised
453 * A SyntaxError is raised
453
454
454 * The code is complete and consists of a single line or a single
455 * The code is complete and consists of a single line or a single
455 non-compound statement
456 non-compound statement
456
457
457 * The code is complete and has a blank line at the end
458 * The code is complete and has a blank line at the end
458
459
459 If the current input produces a syntax error, this method immediately
460 If the current input produces a syntax error, this method immediately
460 returns False but does *not* raise the syntax error exception, as
461 returns False but does *not* raise the syntax error exception, as
461 typically clients will want to send invalid syntax to an execution
462 typically clients will want to send invalid syntax to an execution
462 backend which might convert the invalid syntax into valid Python via
463 backend which might convert the invalid syntax into valid Python via
463 one of the dynamic IPython mechanisms.
464 one of the dynamic IPython mechanisms.
464 """
465 """
465
466
466 # With incomplete input, unconditionally accept more
467 # With incomplete input, unconditionally accept more
467 # A syntax error also sets _is_complete to True - see push()
468 # A syntax error also sets _is_complete to True - see push()
468 if not self._is_complete:
469 if not self._is_complete:
469 #print("Not complete") # debug
470 #print("Not complete") # debug
470 return True
471 return True
471
472
472 # The user can make any (complete) input execute by leaving a blank line
473 # The user can make any (complete) input execute by leaving a blank line
473 last_line = self.source.splitlines()[-1]
474 last_line = self.source.splitlines()[-1]
474 if (not last_line) or last_line.isspace():
475 if (not last_line) or last_line.isspace():
475 #print("Blank line") # debug
476 #print("Blank line") # debug
476 return False
477 return False
477
478
478 # If there's just a single line or AST node, and we're flush left, as is
479 # If there's just a single line or AST node, and we're flush left, as is
479 # the case after a simple statement such as 'a=1', we want to execute it
480 # the case after a simple statement such as 'a=1', we want to execute it
480 # straight away.
481 # straight away.
481 if self.get_indent_spaces() == 0:
482 if self.get_indent_spaces() == 0:
482 if len(self.source.splitlines()) <= 1:
483 if len(self.source.splitlines()) <= 1:
483 return False
484 return False
484
485
485 try:
486 try:
486 code_ast = ast.parse(u''.join(self._buffer))
487 code_ast = ast.parse("".join(self._buffer))
487 except Exception:
488 except Exception:
488 #print("Can't parse AST") # debug
489 #print("Can't parse AST") # debug
489 return False
490 return False
490 else:
491 else:
491 if len(code_ast.body) == 1 and \
492 if len(code_ast.body) == 1 and \
492 not hasattr(code_ast.body[0], 'body'):
493 not hasattr(code_ast.body[0], 'body'):
493 #print("Simple statement") # debug
494 #print("Simple statement") # debug
494 return False
495 return False
495
496
496 # General fallback - accept more code
497 # General fallback - accept more code
497 return True
498 return True
498
499
499 def get_indent_spaces(self):
500 def get_indent_spaces(self):
500 sourcefor, n = self._indent_spaces_cache
501 sourcefor, n = self._indent_spaces_cache
501 if sourcefor == self.source:
502 if sourcefor == self.source:
502 return n
503 return n
503
504
504 # self.source always has a trailing newline
505 # self.source always has a trailing newline
505 n = find_next_indent(self.source[:-1])
506 n = find_next_indent(self.source[:-1])
506 self._indent_spaces_cache = (self.source, n)
507 self._indent_spaces_cache = (self.source, n)
507 return n
508 return n
508
509
509 # Backwards compatibility. I think all code that used .indent_spaces was
510 # Backwards compatibility. I think all code that used .indent_spaces was
510 # inside IPython, but we can leave this here until IPython 7 in case any
511 # inside IPython, but we can leave this here until IPython 7 in case any
511 # other modules are using it. -TK, November 2017
512 # other modules are using it. -TK, November 2017
512 indent_spaces = property(get_indent_spaces)
513 indent_spaces = property(get_indent_spaces)
513
514
514 def _store(self, lines, buffer=None, store='source'):
515 def _store(self, lines, buffer=None, store='source'):
515 """Store one or more lines of input.
516 """Store one or more lines of input.
516
517
517 If input lines are not newline-terminated, a newline is automatically
518 If input lines are not newline-terminated, a newline is automatically
518 appended."""
519 appended."""
519
520
520 if buffer is None:
521 if buffer is None:
521 buffer = self._buffer
522 buffer = self._buffer
522
523
523 if lines.endswith('\n'):
524 if lines.endswith('\n'):
524 buffer.append(lines)
525 buffer.append(lines)
525 else:
526 else:
526 buffer.append(lines+'\n')
527 buffer.append(lines+'\n')
527 setattr(self, store, self._set_source(buffer))
528 setattr(self, store, self._set_source(buffer))
528
529
529 def _set_source(self, buffer):
530 def _set_source(self, buffer):
530 return u''.join(buffer)
531 return u''.join(buffer)
531
532
532
533
533 class IPythonInputSplitter(InputSplitter):
534 class IPythonInputSplitter(InputSplitter):
534 """An input splitter that recognizes all of IPython's special syntax."""
535 """An input splitter that recognizes all of IPython's special syntax."""
535
536
536 # String with raw, untransformed input.
537 # String with raw, untransformed input.
537 source_raw = ''
538 source_raw = ''
538
539
539 # Flag to track when a transformer has stored input that it hasn't given
540 # Flag to track when a transformer has stored input that it hasn't given
540 # back yet.
541 # back yet.
541 transformer_accumulating = False
542 transformer_accumulating = False
542
543
543 # Flag to track when assemble_python_lines has stored input that it hasn't
544 # Flag to track when assemble_python_lines has stored input that it hasn't
544 # given back yet.
545 # given back yet.
545 within_python_line = False
546 within_python_line = False
546
547
547 # Private attributes
548 # Private attributes
548
549
549 # List with lines of raw input accumulated so far.
550 # List with lines of raw input accumulated so far.
550 _buffer_raw = None
551 _buffer_raw = None
551
552
552 def __init__(self, line_input_checker=True, physical_line_transforms=None,
553 def __init__(self, line_input_checker=True, physical_line_transforms=None,
553 logical_line_transforms=None, python_line_transforms=None):
554 logical_line_transforms=None, python_line_transforms=None):
554 super(IPythonInputSplitter, self).__init__()
555 super(IPythonInputSplitter, self).__init__()
555 self._buffer_raw = []
556 self._buffer_raw = []
556 self._validate = True
557 self._validate = True
557
558
558 if physical_line_transforms is not None:
559 if physical_line_transforms is not None:
559 self.physical_line_transforms = physical_line_transforms
560 self.physical_line_transforms = physical_line_transforms
560 else:
561 else:
561 self.physical_line_transforms = [
562 self.physical_line_transforms = [
562 leading_indent(),
563 leading_indent(),
563 classic_prompt(),
564 classic_prompt(),
564 ipy_prompt(),
565 ipy_prompt(),
565 cellmagic(end_on_blank_line=line_input_checker),
566 cellmagic(end_on_blank_line=line_input_checker),
566 ]
567 ]
567
568
568 self.assemble_logical_lines = assemble_logical_lines()
569 self.assemble_logical_lines = assemble_logical_lines()
569 if logical_line_transforms is not None:
570 if logical_line_transforms is not None:
570 self.logical_line_transforms = logical_line_transforms
571 self.logical_line_transforms = logical_line_transforms
571 else:
572 else:
572 self.logical_line_transforms = [
573 self.logical_line_transforms = [
573 help_end(),
574 help_end(),
574 escaped_commands(),
575 escaped_commands(),
575 assign_from_magic(),
576 assign_from_magic(),
576 assign_from_system(),
577 assign_from_system(),
577 ]
578 ]
578
579
579 self.assemble_python_lines = assemble_python_lines()
580 self.assemble_python_lines = assemble_python_lines()
580 if python_line_transforms is not None:
581 if python_line_transforms is not None:
581 self.python_line_transforms = python_line_transforms
582 self.python_line_transforms = python_line_transforms
582 else:
583 else:
583 # We don't use any of these at present
584 # We don't use any of these at present
584 self.python_line_transforms = []
585 self.python_line_transforms = []
585
586
586 @property
587 @property
587 def transforms(self):
588 def transforms(self):
588 "Quick access to all transformers."
589 "Quick access to all transformers."
589 return self.physical_line_transforms + \
590 return self.physical_line_transforms + \
590 [self.assemble_logical_lines] + self.logical_line_transforms + \
591 [self.assemble_logical_lines] + self.logical_line_transforms + \
591 [self.assemble_python_lines] + self.python_line_transforms
592 [self.assemble_python_lines] + self.python_line_transforms
592
593
593 @property
594 @property
594 def transforms_in_use(self):
595 def transforms_in_use(self):
595 """Transformers, excluding logical line transformers if we're in a
596 """Transformers, excluding logical line transformers if we're in a
596 Python line."""
597 Python line."""
597 t = self.physical_line_transforms[:]
598 t = self.physical_line_transforms[:]
598 if not self.within_python_line:
599 if not self.within_python_line:
599 t += [self.assemble_logical_lines] + self.logical_line_transforms
600 t += [self.assemble_logical_lines] + self.logical_line_transforms
600 return t + [self.assemble_python_lines] + self.python_line_transforms
601 return t + [self.assemble_python_lines] + self.python_line_transforms
601
602
602 def reset(self):
603 def reset(self):
603 """Reset the input buffer and associated state."""
604 """Reset the input buffer and associated state."""
604 super(IPythonInputSplitter, self).reset()
605 super(IPythonInputSplitter, self).reset()
605 self._buffer_raw[:] = []
606 self._buffer_raw[:] = []
606 self.source_raw = ''
607 self.source_raw = ''
607 self.transformer_accumulating = False
608 self.transformer_accumulating = False
608 self.within_python_line = False
609 self.within_python_line = False
609
610
610 for t in self.transforms:
611 for t in self.transforms:
611 try:
612 try:
612 t.reset()
613 t.reset()
613 except SyntaxError:
614 except SyntaxError:
614 # Nothing that calls reset() expects to handle transformer
615 # Nothing that calls reset() expects to handle transformer
615 # errors
616 # errors
616 pass
617 pass
617
618
618 def flush_transformers(self):
619 def flush_transformers(self):
619 def _flush(transform, outs):
620 def _flush(transform, outs):
620 """yield transformed lines
621 """yield transformed lines
621
622
622 always strings, never None
623 always strings, never None
623
624
624 transform: the current transform
625 transform: the current transform
625 outs: an iterable of previously transformed inputs.
626 outs: an iterable of previously transformed inputs.
626 Each may be multiline, which will be passed
627 Each may be multiline, which will be passed
627 one line at a time to transform.
628 one line at a time to transform.
628 """
629 """
629 for out in outs:
630 for out in outs:
630 for line in out.splitlines():
631 for line in out.splitlines():
631 # push one line at a time
632 # push one line at a time
632 tmp = transform.push(line)
633 tmp = transform.push(line)
633 if tmp is not None:
634 if tmp is not None:
634 yield tmp
635 yield tmp
635
636
636 # reset the transform
637 # reset the transform
637 tmp = transform.reset()
638 tmp = transform.reset()
638 if tmp is not None:
639 if tmp is not None:
639 yield tmp
640 yield tmp
640
641
641 out = []
642 out = []
642 for t in self.transforms_in_use:
643 for t in self.transforms_in_use:
643 out = _flush(t, out)
644 out = _flush(t, out)
644
645
645 out = list(out)
646 out = list(out)
646 if out:
647 if out:
647 self._store('\n'.join(out))
648 self._store('\n'.join(out))
648
649
649 def raw_reset(self):
650 def raw_reset(self):
650 """Return raw input only and perform a full reset.
651 """Return raw input only and perform a full reset.
651 """
652 """
652 out = self.source_raw
653 out = self.source_raw
653 self.reset()
654 self.reset()
654 return out
655 return out
655
656
656 def source_reset(self):
657 def source_reset(self):
657 try:
658 try:
658 self.flush_transformers()
659 self.flush_transformers()
659 return self.source
660 return self.source
660 finally:
661 finally:
661 self.reset()
662 self.reset()
662
663
663 def push_accepts_more(self):
664 def push_accepts_more(self):
664 if self.transformer_accumulating:
665 if self.transformer_accumulating:
665 return True
666 return True
666 else:
667 else:
667 return super(IPythonInputSplitter, self).push_accepts_more()
668 return super(IPythonInputSplitter, self).push_accepts_more()
668
669
669 def transform_cell(self, cell):
670 def transform_cell(self, cell):
670 """Process and translate a cell of input.
671 """Process and translate a cell of input.
671 """
672 """
672 self.reset()
673 self.reset()
673 try:
674 try:
674 self.push(cell)
675 self.push(cell)
675 self.flush_transformers()
676 self.flush_transformers()
676 return self.source
677 return self.source
677 finally:
678 finally:
678 self.reset()
679 self.reset()
679
680
680 def push(self, lines:str) -> bool:
681 def push(self, lines:str) -> bool:
681 """Push one or more lines of IPython input.
682 """Push one or more lines of IPython input.
682
683
683 This stores the given lines and returns a status code indicating
684 This stores the given lines and returns a status code indicating
684 whether the code forms a complete Python block or not, after processing
685 whether the code forms a complete Python block or not, after processing
685 all input lines for special IPython syntax.
686 all input lines for special IPython syntax.
686
687
687 Any exceptions generated in compilation are swallowed, but if an
688 Any exceptions generated in compilation are swallowed, but if an
688 exception was produced, the method returns True.
689 exception was produced, the method returns True.
689
690
690 Parameters
691 Parameters
691 ----------
692 ----------
692 lines : string
693 lines : string
693 One or more lines of Python input.
694 One or more lines of Python input.
694
695
695 Returns
696 Returns
696 -------
697 -------
697 is_complete : boolean
698 is_complete : boolean
698 True if the current input source (the result of the current input
699 True if the current input source (the result of the current input
699 plus prior inputs) forms a complete Python execution block. Note that
700 plus prior inputs) forms a complete Python execution block. Note that
700 this value is also stored as a private attribute (_is_complete), so it
701 this value is also stored as a private attribute (_is_complete), so it
701 can be queried at any time.
702 can be queried at any time.
702 """
703 """
703 assert isinstance(lines, str)
704 assert isinstance(lines, str)
704 # We must ensure all input is pure unicode
705 # We must ensure all input is pure unicode
705 # ''.splitlines() --> [], but we need to push the empty line to transformers
706 # ''.splitlines() --> [], but we need to push the empty line to transformers
706 lines_list = lines.splitlines()
707 lines_list = lines.splitlines()
707 if not lines_list:
708 if not lines_list:
708 lines_list = ['']
709 lines_list = ['']
709
710
710 # Store raw source before applying any transformations to it. Note
711 # Store raw source before applying any transformations to it. Note
711 # that this must be done *after* the reset() call that would otherwise
712 # that this must be done *after* the reset() call that would otherwise
712 # flush the buffer.
713 # flush the buffer.
713 self._store(lines, self._buffer_raw, 'source_raw')
714 self._store(lines, self._buffer_raw, 'source_raw')
714
715
715 transformed_lines_list = []
716 transformed_lines_list = []
716 for line in lines_list:
717 for line in lines_list:
717 transformed = self._transform_line(line)
718 transformed = self._transform_line(line)
718 if transformed is not None:
719 if transformed is not None:
719 transformed_lines_list.append(transformed)
720 transformed_lines_list.append(transformed)
720
721
721 if transformed_lines_list:
722 if transformed_lines_list:
722 transformed_lines = '\n'.join(transformed_lines_list)
723 transformed_lines = '\n'.join(transformed_lines_list)
723 return super(IPythonInputSplitter, self).push(transformed_lines)
724 return super(IPythonInputSplitter, self).push(transformed_lines)
724 else:
725 else:
725 # Got nothing back from transformers - they must be waiting for
726 # Got nothing back from transformers - they must be waiting for
726 # more input.
727 # more input.
727 return False
728 return False
728
729
729 def _transform_line(self, line):
730 def _transform_line(self, line):
730 """Push a line of input code through the various transformers.
731 """Push a line of input code through the various transformers.
731
732
732 Returns any output from the transformers, or None if a transformer
733 Returns any output from the transformers, or None if a transformer
733 is accumulating lines.
734 is accumulating lines.
734
735
735 Sets self.transformer_accumulating as a side effect.
736 Sets self.transformer_accumulating as a side effect.
736 """
737 """
737 def _accumulating(dbg):
738 def _accumulating(dbg):
738 #print(dbg)
739 #print(dbg)
739 self.transformer_accumulating = True
740 self.transformer_accumulating = True
740 return None
741 return None
741
742
742 for transformer in self.physical_line_transforms:
743 for transformer in self.physical_line_transforms:
743 line = transformer.push(line)
744 line = transformer.push(line)
744 if line is None:
745 if line is None:
745 return _accumulating(transformer)
746 return _accumulating(transformer)
746
747
747 if not self.within_python_line:
748 if not self.within_python_line:
748 line = self.assemble_logical_lines.push(line)
749 line = self.assemble_logical_lines.push(line)
749 if line is None:
750 if line is None:
750 return _accumulating('acc logical line')
751 return _accumulating('acc logical line')
751
752
752 for transformer in self.logical_line_transforms:
753 for transformer in self.logical_line_transforms:
753 line = transformer.push(line)
754 line = transformer.push(line)
754 if line is None:
755 if line is None:
755 return _accumulating(transformer)
756 return _accumulating(transformer)
756
757
757 line = self.assemble_python_lines.push(line)
758 line = self.assemble_python_lines.push(line)
758 if line is None:
759 if line is None:
759 self.within_python_line = True
760 self.within_python_line = True
760 return _accumulating('acc python line')
761 return _accumulating('acc python line')
761 else:
762 else:
762 self.within_python_line = False
763 self.within_python_line = False
763
764
764 for transformer in self.python_line_transforms:
765 for transformer in self.python_line_transforms:
765 line = transformer.push(line)
766 line = transformer.push(line)
766 if line is None:
767 if line is None:
767 return _accumulating(transformer)
768 return _accumulating(transformer)
768
769
769 #print("transformers clear") #debug
770 #print("transformers clear") #debug
770 self.transformer_accumulating = False
771 self.transformer_accumulating = False
771 return line
772 return line
772
773
@@ -1,3898 +1,3898 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Main IPython class."""
2 """Main IPython class."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13
13
14 import abc
14 import abc
15 import ast
15 import ast
16 import atexit
16 import atexit
17 import bdb
17 import bdb
18 import builtins as builtin_mod
18 import builtins as builtin_mod
19 import functools
19 import functools
20 import inspect
20 import inspect
21 import os
21 import os
22 import re
22 import re
23 import runpy
23 import runpy
24 import subprocess
24 import subprocess
25 import sys
25 import sys
26 import tempfile
26 import tempfile
27 import traceback
27 import traceback
28 import types
28 import types
29 import warnings
29 import warnings
30 from ast import stmt
30 from ast import stmt
31 from io import open as io_open
31 from io import open as io_open
32 from logging import error
32 from logging import error
33 from pathlib import Path
33 from pathlib import Path
34 from typing import Callable
34 from typing import Callable
35 from typing import List as ListType, Dict as DictType, Any as AnyType
35 from typing import List as ListType, Dict as DictType, Any as AnyType
36 from typing import Optional, Tuple
36 from typing import Optional, Sequence, Tuple
37 from warnings import warn
37 from warnings import warn
38
38
39 from pickleshare import PickleShareDB
39 from pickleshare import PickleShareDB
40 from tempfile import TemporaryDirectory
40 from tempfile import TemporaryDirectory
41 from traitlets import (
41 from traitlets import (
42 Any,
42 Any,
43 Bool,
43 Bool,
44 CaselessStrEnum,
44 CaselessStrEnum,
45 Dict,
45 Dict,
46 Enum,
46 Enum,
47 Instance,
47 Instance,
48 Integer,
48 Integer,
49 List,
49 List,
50 Type,
50 Type,
51 Unicode,
51 Unicode,
52 default,
52 default,
53 observe,
53 observe,
54 validate,
54 validate,
55 )
55 )
56 from traitlets.config.configurable import SingletonConfigurable
56 from traitlets.config.configurable import SingletonConfigurable
57 from traitlets.utils.importstring import import_item
57 from traitlets.utils.importstring import import_item
58
58
59 import IPython.core.hooks
59 import IPython.core.hooks
60 from IPython.core import magic, oinspect, page, prefilter, ultratb
60 from IPython.core import magic, oinspect, page, prefilter, ultratb
61 from IPython.core.alias import Alias, AliasManager
61 from IPython.core.alias import Alias, AliasManager
62 from IPython.core.autocall import ExitAutocall
62 from IPython.core.autocall import ExitAutocall
63 from IPython.core.builtin_trap import BuiltinTrap
63 from IPython.core.builtin_trap import BuiltinTrap
64 from IPython.core.compilerop import CachingCompiler
64 from IPython.core.compilerop import CachingCompiler
65 from IPython.core.debugger import InterruptiblePdb
65 from IPython.core.debugger import InterruptiblePdb
66 from IPython.core.display_trap import DisplayTrap
66 from IPython.core.display_trap import DisplayTrap
67 from IPython.core.displayhook import DisplayHook
67 from IPython.core.displayhook import DisplayHook
68 from IPython.core.displaypub import DisplayPublisher
68 from IPython.core.displaypub import DisplayPublisher
69 from IPython.core.error import InputRejected, UsageError
69 from IPython.core.error import InputRejected, UsageError
70 from IPython.core.events import EventManager, available_events
70 from IPython.core.events import EventManager, available_events
71 from IPython.core.extensions import ExtensionManager
71 from IPython.core.extensions import ExtensionManager
72 from IPython.core.formatters import DisplayFormatter
72 from IPython.core.formatters import DisplayFormatter
73 from IPython.core.history import HistoryManager
73 from IPython.core.history import HistoryManager
74 from IPython.core.inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
74 from IPython.core.inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
75 from IPython.core.logger import Logger
75 from IPython.core.logger import Logger
76 from IPython.core.macro import Macro
76 from IPython.core.macro import Macro
77 from IPython.core.payload import PayloadManager
77 from IPython.core.payload import PayloadManager
78 from IPython.core.prefilter import PrefilterManager
78 from IPython.core.prefilter import PrefilterManager
79 from IPython.core.profiledir import ProfileDir
79 from IPython.core.profiledir import ProfileDir
80 from IPython.core.usage import default_banner
80 from IPython.core.usage import default_banner
81 from IPython.display import display
81 from IPython.display import display
82 from IPython.paths import get_ipython_dir
82 from IPython.paths import get_ipython_dir
83 from IPython.testing.skipdoctest import skip_doctest
83 from IPython.testing.skipdoctest import skip_doctest
84 from IPython.utils import PyColorize, io, openpy, py3compat
84 from IPython.utils import PyColorize, io, openpy, py3compat
85 from IPython.utils.decorators import undoc
85 from IPython.utils.decorators import undoc
86 from IPython.utils.io import ask_yes_no
86 from IPython.utils.io import ask_yes_no
87 from IPython.utils.ipstruct import Struct
87 from IPython.utils.ipstruct import Struct
88 from IPython.utils.path import ensure_dir_exists, get_home_dir, get_py_filename
88 from IPython.utils.path import ensure_dir_exists, get_home_dir, get_py_filename
89 from IPython.utils.process import getoutput, system
89 from IPython.utils.process import getoutput, system
90 from IPython.utils.strdispatch import StrDispatch
90 from IPython.utils.strdispatch import StrDispatch
91 from IPython.utils.syspathcontext import prepended_to_syspath
91 from IPython.utils.syspathcontext import prepended_to_syspath
92 from IPython.utils.text import DollarFormatter, LSString, SList, format_screen
92 from IPython.utils.text import DollarFormatter, LSString, SList, format_screen
93 from IPython.core.oinspect import OInfo
93 from IPython.core.oinspect import OInfo
94
94
95
95
96 sphinxify: Optional[Callable]
96 sphinxify: Optional[Callable]
97
97
98 try:
98 try:
99 import docrepr.sphinxify as sphx
99 import docrepr.sphinxify as sphx
100
100
101 def sphinxify(oinfo):
101 def sphinxify(oinfo):
102 wrapped_docstring = sphx.wrap_main_docstring(oinfo)
102 wrapped_docstring = sphx.wrap_main_docstring(oinfo)
103
103
104 def sphinxify_docstring(docstring):
104 def sphinxify_docstring(docstring):
105 with TemporaryDirectory() as dirname:
105 with TemporaryDirectory() as dirname:
106 return {
106 return {
107 "text/html": sphx.sphinxify(wrapped_docstring, dirname),
107 "text/html": sphx.sphinxify(wrapped_docstring, dirname),
108 "text/plain": docstring,
108 "text/plain": docstring,
109 }
109 }
110
110
111 return sphinxify_docstring
111 return sphinxify_docstring
112 except ImportError:
112 except ImportError:
113 sphinxify = None
113 sphinxify = None
114
114
115
115
116 class ProvisionalWarning(DeprecationWarning):
116 class ProvisionalWarning(DeprecationWarning):
117 """
117 """
118 Warning class for unstable features
118 Warning class for unstable features
119 """
119 """
120 pass
120 pass
121
121
122 from ast import Module
122 from ast import Module
123
123
124 _assign_nodes = (ast.AugAssign, ast.AnnAssign, ast.Assign)
124 _assign_nodes = (ast.AugAssign, ast.AnnAssign, ast.Assign)
125 _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)
125 _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)
126
126
127 #-----------------------------------------------------------------------------
127 #-----------------------------------------------------------------------------
128 # Await Helpers
128 # Await Helpers
129 #-----------------------------------------------------------------------------
129 #-----------------------------------------------------------------------------
130
130
131 # we still need to run things using the asyncio eventloop, but there is no
131 # we still need to run things using the asyncio eventloop, but there is no
132 # async integration
132 # async integration
133 from .async_helpers import (
133 from .async_helpers import (
134 _asyncio_runner,
134 _asyncio_runner,
135 _curio_runner,
135 _curio_runner,
136 _pseudo_sync_runner,
136 _pseudo_sync_runner,
137 _should_be_async,
137 _should_be_async,
138 _trio_runner,
138 _trio_runner,
139 )
139 )
140
140
141 #-----------------------------------------------------------------------------
141 #-----------------------------------------------------------------------------
142 # Globals
142 # Globals
143 #-----------------------------------------------------------------------------
143 #-----------------------------------------------------------------------------
144
144
145 # compiled regexps for autoindent management
145 # compiled regexps for autoindent management
146 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
146 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
147
147
148 #-----------------------------------------------------------------------------
148 #-----------------------------------------------------------------------------
149 # Utilities
149 # Utilities
150 #-----------------------------------------------------------------------------
150 #-----------------------------------------------------------------------------
151
151
152
152
153 def is_integer_string(s: str):
153 def is_integer_string(s: str):
154 """
154 """
155 Variant of "str.isnumeric()" that allow negative values and other ints.
155 Variant of "str.isnumeric()" that allow negative values and other ints.
156 """
156 """
157 try:
157 try:
158 int(s)
158 int(s)
159 return True
159 return True
160 except ValueError:
160 except ValueError:
161 return False
161 return False
162 raise ValueError("Unexpected error")
162 raise ValueError("Unexpected error")
163
163
164
164
165 @undoc
165 @undoc
166 def softspace(file, newvalue):
166 def softspace(file, newvalue):
167 """Copied from code.py, to remove the dependency"""
167 """Copied from code.py, to remove the dependency"""
168
168
169 oldvalue = 0
169 oldvalue = 0
170 try:
170 try:
171 oldvalue = file.softspace
171 oldvalue = file.softspace
172 except AttributeError:
172 except AttributeError:
173 pass
173 pass
174 try:
174 try:
175 file.softspace = newvalue
175 file.softspace = newvalue
176 except (AttributeError, TypeError):
176 except (AttributeError, TypeError):
177 # "attribute-less object" or "read-only attributes"
177 # "attribute-less object" or "read-only attributes"
178 pass
178 pass
179 return oldvalue
179 return oldvalue
180
180
181 @undoc
181 @undoc
182 def no_op(*a, **kw):
182 def no_op(*a, **kw):
183 pass
183 pass
184
184
185
185
186 class SpaceInInput(Exception): pass
186 class SpaceInInput(Exception): pass
187
187
188
188
189 class SeparateUnicode(Unicode):
189 class SeparateUnicode(Unicode):
190 r"""A Unicode subclass to validate separate_in, separate_out, etc.
190 r"""A Unicode subclass to validate separate_in, separate_out, etc.
191
191
192 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
192 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
193 """
193 """
194
194
195 def validate(self, obj, value):
195 def validate(self, obj, value):
196 if value == '0': value = ''
196 if value == '0': value = ''
197 value = value.replace('\\n','\n')
197 value = value.replace('\\n','\n')
198 return super(SeparateUnicode, self).validate(obj, value)
198 return super(SeparateUnicode, self).validate(obj, value)
199
199
200
200
201 @undoc
201 @undoc
202 class DummyMod(object):
202 class DummyMod(object):
203 """A dummy module used for IPython's interactive module when
203 """A dummy module used for IPython's interactive module when
204 a namespace must be assigned to the module's __dict__."""
204 a namespace must be assigned to the module's __dict__."""
205 __spec__ = None
205 __spec__ = None
206
206
207
207
208 class ExecutionInfo(object):
208 class ExecutionInfo(object):
209 """The arguments used for a call to :meth:`InteractiveShell.run_cell`
209 """The arguments used for a call to :meth:`InteractiveShell.run_cell`
210
210
211 Stores information about what is going to happen.
211 Stores information about what is going to happen.
212 """
212 """
213 raw_cell = None
213 raw_cell = None
214 store_history = False
214 store_history = False
215 silent = False
215 silent = False
216 shell_futures = True
216 shell_futures = True
217 cell_id = None
217 cell_id = None
218
218
219 def __init__(self, raw_cell, store_history, silent, shell_futures, cell_id):
219 def __init__(self, raw_cell, store_history, silent, shell_futures, cell_id):
220 self.raw_cell = raw_cell
220 self.raw_cell = raw_cell
221 self.store_history = store_history
221 self.store_history = store_history
222 self.silent = silent
222 self.silent = silent
223 self.shell_futures = shell_futures
223 self.shell_futures = shell_futures
224 self.cell_id = cell_id
224 self.cell_id = cell_id
225
225
226 def __repr__(self):
226 def __repr__(self):
227 name = self.__class__.__qualname__
227 name = self.__class__.__qualname__
228 raw_cell = (
228 raw_cell = (
229 (self.raw_cell[:50] + "..") if len(self.raw_cell) > 50 else self.raw_cell
229 (self.raw_cell[:50] + "..") if len(self.raw_cell) > 50 else self.raw_cell
230 )
230 )
231 return (
231 return (
232 '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s cell_id=%s>'
232 '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s cell_id=%s>'
233 % (
233 % (
234 name,
234 name,
235 id(self),
235 id(self),
236 raw_cell,
236 raw_cell,
237 self.store_history,
237 self.store_history,
238 self.silent,
238 self.silent,
239 self.shell_futures,
239 self.shell_futures,
240 self.cell_id,
240 self.cell_id,
241 )
241 )
242 )
242 )
243
243
244
244
245 class ExecutionResult(object):
245 class ExecutionResult(object):
246 """The result of a call to :meth:`InteractiveShell.run_cell`
246 """The result of a call to :meth:`InteractiveShell.run_cell`
247
247
248 Stores information about what took place.
248 Stores information about what took place.
249 """
249 """
250 execution_count = None
250 execution_count = None
251 error_before_exec = None
251 error_before_exec = None
252 error_in_exec: Optional[BaseException] = None
252 error_in_exec: Optional[BaseException] = None
253 info = None
253 info = None
254 result = None
254 result = None
255
255
256 def __init__(self, info):
256 def __init__(self, info):
257 self.info = info
257 self.info = info
258
258
259 @property
259 @property
260 def success(self):
260 def success(self):
261 return (self.error_before_exec is None) and (self.error_in_exec is None)
261 return (self.error_before_exec is None) and (self.error_in_exec is None)
262
262
263 def raise_error(self):
263 def raise_error(self):
264 """Reraises error if `success` is `False`, otherwise does nothing"""
264 """Reraises error if `success` is `False`, otherwise does nothing"""
265 if self.error_before_exec is not None:
265 if self.error_before_exec is not None:
266 raise self.error_before_exec
266 raise self.error_before_exec
267 if self.error_in_exec is not None:
267 if self.error_in_exec is not None:
268 raise self.error_in_exec
268 raise self.error_in_exec
269
269
270 def __repr__(self):
270 def __repr__(self):
271 name = self.__class__.__qualname__
271 name = self.__class__.__qualname__
272 return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s info=%s result=%s>' %\
272 return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s info=%s result=%s>' %\
273 (name, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.info), repr(self.result))
273 (name, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.info), repr(self.result))
274
274
275 @functools.wraps(io_open)
275 @functools.wraps(io_open)
276 def _modified_open(file, *args, **kwargs):
276 def _modified_open(file, *args, **kwargs):
277 if file in {0, 1, 2}:
277 if file in {0, 1, 2}:
278 raise ValueError(
278 raise ValueError(
279 f"IPython won't let you open fd={file} by default "
279 f"IPython won't let you open fd={file} by default "
280 "as it is likely to crash IPython. If you know what you are doing, "
280 "as it is likely to crash IPython. If you know what you are doing, "
281 "you can use builtins' open."
281 "you can use builtins' open."
282 )
282 )
283
283
284 return io_open(file, *args, **kwargs)
284 return io_open(file, *args, **kwargs)
285
285
286 class InteractiveShell(SingletonConfigurable):
286 class InteractiveShell(SingletonConfigurable):
287 """An enhanced, interactive shell for Python."""
287 """An enhanced, interactive shell for Python."""
288
288
289 _instance = None
289 _instance = None
290
290
291 ast_transformers = List([], help=
291 ast_transformers = List([], help=
292 """
292 """
293 A list of ast.NodeTransformer subclass instances, which will be applied
293 A list of ast.NodeTransformer subclass instances, which will be applied
294 to user input before code is run.
294 to user input before code is run.
295 """
295 """
296 ).tag(config=True)
296 ).tag(config=True)
297
297
298 autocall = Enum((0,1,2), default_value=0, help=
298 autocall = Enum((0,1,2), default_value=0, help=
299 """
299 """
300 Make IPython automatically call any callable object even if you didn't
300 Make IPython automatically call any callable object even if you didn't
301 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
301 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
302 automatically. The value can be '0' to disable the feature, '1' for
302 automatically. The value can be '0' to disable the feature, '1' for
303 'smart' autocall, where it is not applied if there are no more
303 'smart' autocall, where it is not applied if there are no more
304 arguments on the line, and '2' for 'full' autocall, where all callable
304 arguments on the line, and '2' for 'full' autocall, where all callable
305 objects are automatically called (even if no arguments are present).
305 objects are automatically called (even if no arguments are present).
306 """
306 """
307 ).tag(config=True)
307 ).tag(config=True)
308
308
309 autoindent = Bool(True, help=
309 autoindent = Bool(True, help=
310 """
310 """
311 Autoindent IPython code entered interactively.
311 Autoindent IPython code entered interactively.
312 """
312 """
313 ).tag(config=True)
313 ).tag(config=True)
314
314
315 autoawait = Bool(True, help=
315 autoawait = Bool(True, help=
316 """
316 """
317 Automatically run await statement in the top level repl.
317 Automatically run await statement in the top level repl.
318 """
318 """
319 ).tag(config=True)
319 ).tag(config=True)
320
320
321 loop_runner_map ={
321 loop_runner_map ={
322 'asyncio':(_asyncio_runner, True),
322 'asyncio':(_asyncio_runner, True),
323 'curio':(_curio_runner, True),
323 'curio':(_curio_runner, True),
324 'trio':(_trio_runner, True),
324 'trio':(_trio_runner, True),
325 'sync': (_pseudo_sync_runner, False)
325 'sync': (_pseudo_sync_runner, False)
326 }
326 }
327
327
328 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
328 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
329 allow_none=True,
329 allow_none=True,
330 help="""Select the loop runner that will be used to execute top-level asynchronous code"""
330 help="""Select the loop runner that will be used to execute top-level asynchronous code"""
331 ).tag(config=True)
331 ).tag(config=True)
332
332
333 @default('loop_runner')
333 @default('loop_runner')
334 def _default_loop_runner(self):
334 def _default_loop_runner(self):
335 return import_item("IPython.core.interactiveshell._asyncio_runner")
335 return import_item("IPython.core.interactiveshell._asyncio_runner")
336
336
337 @validate('loop_runner')
337 @validate('loop_runner')
338 def _import_runner(self, proposal):
338 def _import_runner(self, proposal):
339 if isinstance(proposal.value, str):
339 if isinstance(proposal.value, str):
340 if proposal.value in self.loop_runner_map:
340 if proposal.value in self.loop_runner_map:
341 runner, autoawait = self.loop_runner_map[proposal.value]
341 runner, autoawait = self.loop_runner_map[proposal.value]
342 self.autoawait = autoawait
342 self.autoawait = autoawait
343 return runner
343 return runner
344 runner = import_item(proposal.value)
344 runner = import_item(proposal.value)
345 if not callable(runner):
345 if not callable(runner):
346 raise ValueError('loop_runner must be callable')
346 raise ValueError('loop_runner must be callable')
347 return runner
347 return runner
348 if not callable(proposal.value):
348 if not callable(proposal.value):
349 raise ValueError('loop_runner must be callable')
349 raise ValueError('loop_runner must be callable')
350 return proposal.value
350 return proposal.value
351
351
352 automagic = Bool(True, help=
352 automagic = Bool(True, help=
353 """
353 """
354 Enable magic commands to be called without the leading %.
354 Enable magic commands to be called without the leading %.
355 """
355 """
356 ).tag(config=True)
356 ).tag(config=True)
357
357
358 banner1 = Unicode(default_banner,
358 banner1 = Unicode(default_banner,
359 help="""The part of the banner to be printed before the profile"""
359 help="""The part of the banner to be printed before the profile"""
360 ).tag(config=True)
360 ).tag(config=True)
361 banner2 = Unicode('',
361 banner2 = Unicode('',
362 help="""The part of the banner to be printed after the profile"""
362 help="""The part of the banner to be printed after the profile"""
363 ).tag(config=True)
363 ).tag(config=True)
364
364
365 cache_size = Integer(1000, help=
365 cache_size = Integer(1000, help=
366 """
366 """
367 Set the size of the output cache. The default is 1000, you can
367 Set the size of the output cache. The default is 1000, you can
368 change it permanently in your config file. Setting it to 0 completely
368 change it permanently in your config file. Setting it to 0 completely
369 disables the caching system, and the minimum value accepted is 3 (if
369 disables the caching system, and the minimum value accepted is 3 (if
370 you provide a value less than 3, it is reset to 0 and a warning is
370 you provide a value less than 3, it is reset to 0 and a warning is
371 issued). This limit is defined because otherwise you'll spend more
371 issued). This limit is defined because otherwise you'll spend more
372 time re-flushing a too small cache than working
372 time re-flushing a too small cache than working
373 """
373 """
374 ).tag(config=True)
374 ).tag(config=True)
375 color_info = Bool(True, help=
375 color_info = Bool(True, help=
376 """
376 """
377 Use colors for displaying information about objects. Because this
377 Use colors for displaying information about objects. Because this
378 information is passed through a pager (like 'less'), and some pagers
378 information is passed through a pager (like 'less'), and some pagers
379 get confused with color codes, this capability can be turned off.
379 get confused with color codes, this capability can be turned off.
380 """
380 """
381 ).tag(config=True)
381 ).tag(config=True)
382 colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'),
382 colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'),
383 default_value='Neutral',
383 default_value='Neutral',
384 help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)."
384 help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)."
385 ).tag(config=True)
385 ).tag(config=True)
386 debug = Bool(False).tag(config=True)
386 debug = Bool(False).tag(config=True)
387 disable_failing_post_execute = Bool(False,
387 disable_failing_post_execute = Bool(False,
388 help="Don't call post-execute functions that have failed in the past."
388 help="Don't call post-execute functions that have failed in the past."
389 ).tag(config=True)
389 ).tag(config=True)
390 display_formatter = Instance(DisplayFormatter, allow_none=True)
390 display_formatter = Instance(DisplayFormatter, allow_none=True)
391 displayhook_class = Type(DisplayHook)
391 displayhook_class = Type(DisplayHook)
392 display_pub_class = Type(DisplayPublisher)
392 display_pub_class = Type(DisplayPublisher)
393 compiler_class = Type(CachingCompiler)
393 compiler_class = Type(CachingCompiler)
394 inspector_class = Type(
394 inspector_class = Type(
395 oinspect.Inspector, help="Class to use to instantiate the shell inspector"
395 oinspect.Inspector, help="Class to use to instantiate the shell inspector"
396 ).tag(config=True)
396 ).tag(config=True)
397
397
398 sphinxify_docstring = Bool(False, help=
398 sphinxify_docstring = Bool(False, help=
399 """
399 """
400 Enables rich html representation of docstrings. (This requires the
400 Enables rich html representation of docstrings. (This requires the
401 docrepr module).
401 docrepr module).
402 """).tag(config=True)
402 """).tag(config=True)
403
403
404 @observe("sphinxify_docstring")
404 @observe("sphinxify_docstring")
405 def _sphinxify_docstring_changed(self, change):
405 def _sphinxify_docstring_changed(self, change):
406 if change['new']:
406 if change['new']:
407 warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning)
407 warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning)
408
408
409 enable_html_pager = Bool(False, help=
409 enable_html_pager = Bool(False, help=
410 """
410 """
411 (Provisional API) enables html representation in mime bundles sent
411 (Provisional API) enables html representation in mime bundles sent
412 to pagers.
412 to pagers.
413 """).tag(config=True)
413 """).tag(config=True)
414
414
415 @observe("enable_html_pager")
415 @observe("enable_html_pager")
416 def _enable_html_pager_changed(self, change):
416 def _enable_html_pager_changed(self, change):
417 if change['new']:
417 if change['new']:
418 warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning)
418 warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning)
419
419
420 data_pub_class = None
420 data_pub_class = None
421
421
422 exit_now = Bool(False)
422 exit_now = Bool(False)
423 exiter = Instance(ExitAutocall)
423 exiter = Instance(ExitAutocall)
424 @default('exiter')
424 @default('exiter')
425 def _exiter_default(self):
425 def _exiter_default(self):
426 return ExitAutocall(self)
426 return ExitAutocall(self)
427 # Monotonically increasing execution counter
427 # Monotonically increasing execution counter
428 execution_count = Integer(1)
428 execution_count = Integer(1)
429 filename = Unicode("<ipython console>")
429 filename = Unicode("<ipython console>")
430 ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__
430 ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__
431
431
432 # Used to transform cells before running them, and check whether code is complete
432 # Used to transform cells before running them, and check whether code is complete
433 input_transformer_manager = Instance('IPython.core.inputtransformer2.TransformerManager',
433 input_transformer_manager = Instance('IPython.core.inputtransformer2.TransformerManager',
434 ())
434 ())
435
435
436 @property
436 @property
437 def input_transformers_cleanup(self):
437 def input_transformers_cleanup(self):
438 return self.input_transformer_manager.cleanup_transforms
438 return self.input_transformer_manager.cleanup_transforms
439
439
440 input_transformers_post = List([],
440 input_transformers_post = List([],
441 help="A list of string input transformers, to be applied after IPython's "
441 help="A list of string input transformers, to be applied after IPython's "
442 "own input transformations."
442 "own input transformations."
443 )
443 )
444
444
445 @property
445 @property
446 def input_splitter(self):
446 def input_splitter(self):
447 """Make this available for backward compatibility (pre-7.0 release) with existing code.
447 """Make this available for backward compatibility (pre-7.0 release) with existing code.
448
448
449 For example, ipykernel ipykernel currently uses
449 For example, ipykernel ipykernel currently uses
450 `shell.input_splitter.check_complete`
450 `shell.input_splitter.check_complete`
451 """
451 """
452 from warnings import warn
452 from warnings import warn
453 warn("`input_splitter` is deprecated since IPython 7.0, prefer `input_transformer_manager`.",
453 warn("`input_splitter` is deprecated since IPython 7.0, prefer `input_transformer_manager`.",
454 DeprecationWarning, stacklevel=2
454 DeprecationWarning, stacklevel=2
455 )
455 )
456 return self.input_transformer_manager
456 return self.input_transformer_manager
457
457
458 logstart = Bool(False, help=
458 logstart = Bool(False, help=
459 """
459 """
460 Start logging to the default log file in overwrite mode.
460 Start logging to the default log file in overwrite mode.
461 Use `logappend` to specify a log file to **append** logs to.
461 Use `logappend` to specify a log file to **append** logs to.
462 """
462 """
463 ).tag(config=True)
463 ).tag(config=True)
464 logfile = Unicode('', help=
464 logfile = Unicode('', help=
465 """
465 """
466 The name of the logfile to use.
466 The name of the logfile to use.
467 """
467 """
468 ).tag(config=True)
468 ).tag(config=True)
469 logappend = Unicode('', help=
469 logappend = Unicode('', help=
470 """
470 """
471 Start logging to the given file in append mode.
471 Start logging to the given file in append mode.
472 Use `logfile` to specify a log file to **overwrite** logs to.
472 Use `logfile` to specify a log file to **overwrite** logs to.
473 """
473 """
474 ).tag(config=True)
474 ).tag(config=True)
475 object_info_string_level = Enum((0,1,2), default_value=0,
475 object_info_string_level = Enum((0,1,2), default_value=0,
476 ).tag(config=True)
476 ).tag(config=True)
477 pdb = Bool(False, help=
477 pdb = Bool(False, help=
478 """
478 """
479 Automatically call the pdb debugger after every exception.
479 Automatically call the pdb debugger after every exception.
480 """
480 """
481 ).tag(config=True)
481 ).tag(config=True)
482 display_page = Bool(False,
482 display_page = Bool(False,
483 help="""If True, anything that would be passed to the pager
483 help="""If True, anything that would be passed to the pager
484 will be displayed as regular output instead."""
484 will be displayed as regular output instead."""
485 ).tag(config=True)
485 ).tag(config=True)
486
486
487
487
488 show_rewritten_input = Bool(True,
488 show_rewritten_input = Bool(True,
489 help="Show rewritten input, e.g. for autocall."
489 help="Show rewritten input, e.g. for autocall."
490 ).tag(config=True)
490 ).tag(config=True)
491
491
492 quiet = Bool(False).tag(config=True)
492 quiet = Bool(False).tag(config=True)
493
493
494 history_length = Integer(10000,
494 history_length = Integer(10000,
495 help='Total length of command history'
495 help='Total length of command history'
496 ).tag(config=True)
496 ).tag(config=True)
497
497
498 history_load_length = Integer(1000, help=
498 history_load_length = Integer(1000, help=
499 """
499 """
500 The number of saved history entries to be loaded
500 The number of saved history entries to be loaded
501 into the history buffer at startup.
501 into the history buffer at startup.
502 """
502 """
503 ).tag(config=True)
503 ).tag(config=True)
504
504
505 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'],
505 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'],
506 default_value='last_expr',
506 default_value='last_expr',
507 help="""
507 help="""
508 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying
508 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying
509 which nodes should be run interactively (displaying output from expressions).
509 which nodes should be run interactively (displaying output from expressions).
510 """
510 """
511 ).tag(config=True)
511 ).tag(config=True)
512
512
513 warn_venv = Bool(
513 warn_venv = Bool(
514 True,
514 True,
515 help="Warn if running in a virtual environment with no IPython installed (so IPython from the global environment is used).",
515 help="Warn if running in a virtual environment with no IPython installed (so IPython from the global environment is used).",
516 ).tag(config=True)
516 ).tag(config=True)
517
517
518 # TODO: this part of prompt management should be moved to the frontends.
518 # TODO: this part of prompt management should be moved to the frontends.
519 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
519 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
520 separate_in = SeparateUnicode('\n').tag(config=True)
520 separate_in = SeparateUnicode('\n').tag(config=True)
521 separate_out = SeparateUnicode('').tag(config=True)
521 separate_out = SeparateUnicode('').tag(config=True)
522 separate_out2 = SeparateUnicode('').tag(config=True)
522 separate_out2 = SeparateUnicode('').tag(config=True)
523 wildcards_case_sensitive = Bool(True).tag(config=True)
523 wildcards_case_sensitive = Bool(True).tag(config=True)
524 xmode = CaselessStrEnum(('Context', 'Plain', 'Verbose', 'Minimal'),
524 xmode = CaselessStrEnum(('Context', 'Plain', 'Verbose', 'Minimal'),
525 default_value='Context',
525 default_value='Context',
526 help="Switch modes for the IPython exception handlers."
526 help="Switch modes for the IPython exception handlers."
527 ).tag(config=True)
527 ).tag(config=True)
528
528
529 # Subcomponents of InteractiveShell
529 # Subcomponents of InteractiveShell
530 alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True)
530 alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True)
531 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
531 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
532 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap', allow_none=True)
532 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap', allow_none=True)
533 display_trap = Instance('IPython.core.display_trap.DisplayTrap', allow_none=True)
533 display_trap = Instance('IPython.core.display_trap.DisplayTrap', allow_none=True)
534 extension_manager = Instance('IPython.core.extensions.ExtensionManager', allow_none=True)
534 extension_manager = Instance('IPython.core.extensions.ExtensionManager', allow_none=True)
535 payload_manager = Instance('IPython.core.payload.PayloadManager', allow_none=True)
535 payload_manager = Instance('IPython.core.payload.PayloadManager', allow_none=True)
536 history_manager = Instance('IPython.core.history.HistoryAccessorBase', allow_none=True)
536 history_manager = Instance('IPython.core.history.HistoryAccessorBase', allow_none=True)
537 magics_manager = Instance('IPython.core.magic.MagicsManager', allow_none=True)
537 magics_manager = Instance('IPython.core.magic.MagicsManager', allow_none=True)
538
538
539 profile_dir = Instance('IPython.core.application.ProfileDir', allow_none=True)
539 profile_dir = Instance('IPython.core.application.ProfileDir', allow_none=True)
540 @property
540 @property
541 def profile(self):
541 def profile(self):
542 if self.profile_dir is not None:
542 if self.profile_dir is not None:
543 name = os.path.basename(self.profile_dir.location)
543 name = os.path.basename(self.profile_dir.location)
544 return name.replace('profile_','')
544 return name.replace('profile_','')
545
545
546
546
547 # Private interface
547 # Private interface
548 _post_execute = Dict()
548 _post_execute = Dict()
549
549
550 # Tracks any GUI loop loaded for pylab
550 # Tracks any GUI loop loaded for pylab
551 pylab_gui_select = None
551 pylab_gui_select = None
552
552
553 last_execution_succeeded = Bool(True, help='Did last executed command succeeded')
553 last_execution_succeeded = Bool(True, help='Did last executed command succeeded')
554
554
555 last_execution_result = Instance('IPython.core.interactiveshell.ExecutionResult', help='Result of executing the last command', allow_none=True)
555 last_execution_result = Instance('IPython.core.interactiveshell.ExecutionResult', help='Result of executing the last command', allow_none=True)
556
556
557 def __init__(self, ipython_dir=None, profile_dir=None,
557 def __init__(self, ipython_dir=None, profile_dir=None,
558 user_module=None, user_ns=None,
558 user_module=None, user_ns=None,
559 custom_exceptions=((), None), **kwargs):
559 custom_exceptions=((), None), **kwargs):
560 # This is where traits with a config_key argument are updated
560 # This is where traits with a config_key argument are updated
561 # from the values on config.
561 # from the values on config.
562 super(InteractiveShell, self).__init__(**kwargs)
562 super(InteractiveShell, self).__init__(**kwargs)
563 if 'PromptManager' in self.config:
563 if 'PromptManager' in self.config:
564 warn('As of IPython 5.0 `PromptManager` config will have no effect'
564 warn('As of IPython 5.0 `PromptManager` config will have no effect'
565 ' and has been replaced by TerminalInteractiveShell.prompts_class')
565 ' and has been replaced by TerminalInteractiveShell.prompts_class')
566 self.configurables = [self]
566 self.configurables = [self]
567
567
568 # These are relatively independent and stateless
568 # These are relatively independent and stateless
569 self.init_ipython_dir(ipython_dir)
569 self.init_ipython_dir(ipython_dir)
570 self.init_profile_dir(profile_dir)
570 self.init_profile_dir(profile_dir)
571 self.init_instance_attrs()
571 self.init_instance_attrs()
572 self.init_environment()
572 self.init_environment()
573
573
574 # Check if we're in a virtualenv, and set up sys.path.
574 # Check if we're in a virtualenv, and set up sys.path.
575 self.init_virtualenv()
575 self.init_virtualenv()
576
576
577 # Create namespaces (user_ns, user_global_ns, etc.)
577 # Create namespaces (user_ns, user_global_ns, etc.)
578 self.init_create_namespaces(user_module, user_ns)
578 self.init_create_namespaces(user_module, user_ns)
579 # This has to be done after init_create_namespaces because it uses
579 # This has to be done after init_create_namespaces because it uses
580 # something in self.user_ns, but before init_sys_modules, which
580 # something in self.user_ns, but before init_sys_modules, which
581 # is the first thing to modify sys.
581 # is the first thing to modify sys.
582 # TODO: When we override sys.stdout and sys.stderr before this class
582 # TODO: When we override sys.stdout and sys.stderr before this class
583 # is created, we are saving the overridden ones here. Not sure if this
583 # is created, we are saving the overridden ones here. Not sure if this
584 # is what we want to do.
584 # is what we want to do.
585 self.save_sys_module_state()
585 self.save_sys_module_state()
586 self.init_sys_modules()
586 self.init_sys_modules()
587
587
588 # While we're trying to have each part of the code directly access what
588 # While we're trying to have each part of the code directly access what
589 # it needs without keeping redundant references to objects, we have too
589 # it needs without keeping redundant references to objects, we have too
590 # much legacy code that expects ip.db to exist.
590 # much legacy code that expects ip.db to exist.
591 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
591 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
592
592
593 self.init_history()
593 self.init_history()
594 self.init_encoding()
594 self.init_encoding()
595 self.init_prefilter()
595 self.init_prefilter()
596
596
597 self.init_syntax_highlighting()
597 self.init_syntax_highlighting()
598 self.init_hooks()
598 self.init_hooks()
599 self.init_events()
599 self.init_events()
600 self.init_pushd_popd_magic()
600 self.init_pushd_popd_magic()
601 self.init_user_ns()
601 self.init_user_ns()
602 self.init_logger()
602 self.init_logger()
603 self.init_builtins()
603 self.init_builtins()
604
604
605 # The following was in post_config_initialization
605 # The following was in post_config_initialization
606 self.init_inspector()
606 self.init_inspector()
607 self.raw_input_original = input
607 self.raw_input_original = input
608 self.init_completer()
608 self.init_completer()
609 # TODO: init_io() needs to happen before init_traceback handlers
609 # TODO: init_io() needs to happen before init_traceback handlers
610 # because the traceback handlers hardcode the stdout/stderr streams.
610 # because the traceback handlers hardcode the stdout/stderr streams.
611 # This logic in in debugger.Pdb and should eventually be changed.
611 # This logic in in debugger.Pdb and should eventually be changed.
612 self.init_io()
612 self.init_io()
613 self.init_traceback_handlers(custom_exceptions)
613 self.init_traceback_handlers(custom_exceptions)
614 self.init_prompts()
614 self.init_prompts()
615 self.init_display_formatter()
615 self.init_display_formatter()
616 self.init_display_pub()
616 self.init_display_pub()
617 self.init_data_pub()
617 self.init_data_pub()
618 self.init_displayhook()
618 self.init_displayhook()
619 self.init_magics()
619 self.init_magics()
620 self.init_alias()
620 self.init_alias()
621 self.init_logstart()
621 self.init_logstart()
622 self.init_pdb()
622 self.init_pdb()
623 self.init_extension_manager()
623 self.init_extension_manager()
624 self.init_payload()
624 self.init_payload()
625 self.events.trigger('shell_initialized', self)
625 self.events.trigger('shell_initialized', self)
626 atexit.register(self.atexit_operations)
626 atexit.register(self.atexit_operations)
627
627
628 # The trio runner is used for running Trio in the foreground thread. It
628 # The trio runner is used for running Trio in the foreground thread. It
629 # is different from `_trio_runner(async_fn)` in `async_helpers.py`
629 # is different from `_trio_runner(async_fn)` in `async_helpers.py`
630 # which calls `trio.run()` for every cell. This runner runs all cells
630 # which calls `trio.run()` for every cell. This runner runs all cells
631 # inside a single Trio event loop. If used, it is set from
631 # inside a single Trio event loop. If used, it is set from
632 # `ipykernel.kernelapp`.
632 # `ipykernel.kernelapp`.
633 self.trio_runner = None
633 self.trio_runner = None
634
634
635 def get_ipython(self):
635 def get_ipython(self):
636 """Return the currently running IPython instance."""
636 """Return the currently running IPython instance."""
637 return self
637 return self
638
638
639 #-------------------------------------------------------------------------
639 #-------------------------------------------------------------------------
640 # Trait changed handlers
640 # Trait changed handlers
641 #-------------------------------------------------------------------------
641 #-------------------------------------------------------------------------
642 @observe('ipython_dir')
642 @observe('ipython_dir')
643 def _ipython_dir_changed(self, change):
643 def _ipython_dir_changed(self, change):
644 ensure_dir_exists(change['new'])
644 ensure_dir_exists(change['new'])
645
645
646 def set_autoindent(self,value=None):
646 def set_autoindent(self,value=None):
647 """Set the autoindent flag.
647 """Set the autoindent flag.
648
648
649 If called with no arguments, it acts as a toggle."""
649 If called with no arguments, it acts as a toggle."""
650 if value is None:
650 if value is None:
651 self.autoindent = not self.autoindent
651 self.autoindent = not self.autoindent
652 else:
652 else:
653 self.autoindent = value
653 self.autoindent = value
654
654
655 def set_trio_runner(self, tr):
655 def set_trio_runner(self, tr):
656 self.trio_runner = tr
656 self.trio_runner = tr
657
657
658 #-------------------------------------------------------------------------
658 #-------------------------------------------------------------------------
659 # init_* methods called by __init__
659 # init_* methods called by __init__
660 #-------------------------------------------------------------------------
660 #-------------------------------------------------------------------------
661
661
662 def init_ipython_dir(self, ipython_dir):
662 def init_ipython_dir(self, ipython_dir):
663 if ipython_dir is not None:
663 if ipython_dir is not None:
664 self.ipython_dir = ipython_dir
664 self.ipython_dir = ipython_dir
665 return
665 return
666
666
667 self.ipython_dir = get_ipython_dir()
667 self.ipython_dir = get_ipython_dir()
668
668
669 def init_profile_dir(self, profile_dir):
669 def init_profile_dir(self, profile_dir):
670 if profile_dir is not None:
670 if profile_dir is not None:
671 self.profile_dir = profile_dir
671 self.profile_dir = profile_dir
672 return
672 return
673 self.profile_dir = ProfileDir.create_profile_dir_by_name(
673 self.profile_dir = ProfileDir.create_profile_dir_by_name(
674 self.ipython_dir, "default"
674 self.ipython_dir, "default"
675 )
675 )
676
676
677 def init_instance_attrs(self):
677 def init_instance_attrs(self):
678 self.more = False
678 self.more = False
679
679
680 # command compiler
680 # command compiler
681 self.compile = self.compiler_class()
681 self.compile = self.compiler_class()
682
682
683 # Make an empty namespace, which extension writers can rely on both
683 # Make an empty namespace, which extension writers can rely on both
684 # existing and NEVER being used by ipython itself. This gives them a
684 # existing and NEVER being used by ipython itself. This gives them a
685 # convenient location for storing additional information and state
685 # convenient location for storing additional information and state
686 # their extensions may require, without fear of collisions with other
686 # their extensions may require, without fear of collisions with other
687 # ipython names that may develop later.
687 # ipython names that may develop later.
688 self.meta = Struct()
688 self.meta = Struct()
689
689
690 # Temporary files used for various purposes. Deleted at exit.
690 # Temporary files used for various purposes. Deleted at exit.
691 # The files here are stored with Path from Pathlib
691 # The files here are stored with Path from Pathlib
692 self.tempfiles = []
692 self.tempfiles = []
693 self.tempdirs = []
693 self.tempdirs = []
694
694
695 # keep track of where we started running (mainly for crash post-mortem)
695 # keep track of where we started running (mainly for crash post-mortem)
696 # This is not being used anywhere currently.
696 # This is not being used anywhere currently.
697 self.starting_dir = os.getcwd()
697 self.starting_dir = os.getcwd()
698
698
699 # Indentation management
699 # Indentation management
700 self.indent_current_nsp = 0
700 self.indent_current_nsp = 0
701
701
702 # Dict to track post-execution functions that have been registered
702 # Dict to track post-execution functions that have been registered
703 self._post_execute = {}
703 self._post_execute = {}
704
704
705 def init_environment(self):
705 def init_environment(self):
706 """Any changes we need to make to the user's environment."""
706 """Any changes we need to make to the user's environment."""
707 pass
707 pass
708
708
709 def init_encoding(self):
709 def init_encoding(self):
710 # Get system encoding at startup time. Certain terminals (like Emacs
710 # Get system encoding at startup time. Certain terminals (like Emacs
711 # under Win32 have it set to None, and we need to have a known valid
711 # under Win32 have it set to None, and we need to have a known valid
712 # encoding to use in the raw_input() method
712 # encoding to use in the raw_input() method
713 try:
713 try:
714 self.stdin_encoding = sys.stdin.encoding or 'ascii'
714 self.stdin_encoding = sys.stdin.encoding or 'ascii'
715 except AttributeError:
715 except AttributeError:
716 self.stdin_encoding = 'ascii'
716 self.stdin_encoding = 'ascii'
717
717
718
718
719 @observe('colors')
719 @observe('colors')
720 def init_syntax_highlighting(self, changes=None):
720 def init_syntax_highlighting(self, changes=None):
721 # Python source parser/formatter for syntax highlighting
721 # Python source parser/formatter for syntax highlighting
722 pyformat = PyColorize.Parser(style=self.colors, parent=self).format
722 pyformat = PyColorize.Parser(style=self.colors, parent=self).format
723 self.pycolorize = lambda src: pyformat(src,'str')
723 self.pycolorize = lambda src: pyformat(src,'str')
724
724
725 def refresh_style(self):
725 def refresh_style(self):
726 # No-op here, used in subclass
726 # No-op here, used in subclass
727 pass
727 pass
728
728
729 def init_pushd_popd_magic(self):
729 def init_pushd_popd_magic(self):
730 # for pushd/popd management
730 # for pushd/popd management
731 self.home_dir = get_home_dir()
731 self.home_dir = get_home_dir()
732
732
733 self.dir_stack = []
733 self.dir_stack = []
734
734
735 def init_logger(self):
735 def init_logger(self):
736 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
736 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
737 logmode='rotate')
737 logmode='rotate')
738
738
739 def init_logstart(self):
739 def init_logstart(self):
740 """Initialize logging in case it was requested at the command line.
740 """Initialize logging in case it was requested at the command line.
741 """
741 """
742 if self.logappend:
742 if self.logappend:
743 self.magic('logstart %s append' % self.logappend)
743 self.magic('logstart %s append' % self.logappend)
744 elif self.logfile:
744 elif self.logfile:
745 self.magic('logstart %s' % self.logfile)
745 self.magic('logstart %s' % self.logfile)
746 elif self.logstart:
746 elif self.logstart:
747 self.magic('logstart')
747 self.magic('logstart')
748
748
749
749
750 def init_builtins(self):
750 def init_builtins(self):
751 # A single, static flag that we set to True. Its presence indicates
751 # A single, static flag that we set to True. Its presence indicates
752 # that an IPython shell has been created, and we make no attempts at
752 # that an IPython shell has been created, and we make no attempts at
753 # removing on exit or representing the existence of more than one
753 # removing on exit or representing the existence of more than one
754 # IPython at a time.
754 # IPython at a time.
755 builtin_mod.__dict__['__IPYTHON__'] = True
755 builtin_mod.__dict__['__IPYTHON__'] = True
756 builtin_mod.__dict__['display'] = display
756 builtin_mod.__dict__['display'] = display
757
757
758 self.builtin_trap = BuiltinTrap(shell=self)
758 self.builtin_trap = BuiltinTrap(shell=self)
759
759
760 @observe('colors')
760 @observe('colors')
761 def init_inspector(self, changes=None):
761 def init_inspector(self, changes=None):
762 # Object inspector
762 # Object inspector
763 self.inspector = self.inspector_class(
763 self.inspector = self.inspector_class(
764 oinspect.InspectColors,
764 oinspect.InspectColors,
765 PyColorize.ANSICodeColors,
765 PyColorize.ANSICodeColors,
766 self.colors,
766 self.colors,
767 self.object_info_string_level,
767 self.object_info_string_level,
768 )
768 )
769
769
770 def init_io(self):
770 def init_io(self):
771 # implemented in subclasses, TerminalInteractiveShell does call
771 # implemented in subclasses, TerminalInteractiveShell does call
772 # colorama.init().
772 # colorama.init().
773 pass
773 pass
774
774
775 def init_prompts(self):
775 def init_prompts(self):
776 # Set system prompts, so that scripts can decide if they are running
776 # Set system prompts, so that scripts can decide if they are running
777 # interactively.
777 # interactively.
778 sys.ps1 = 'In : '
778 sys.ps1 = 'In : '
779 sys.ps2 = '...: '
779 sys.ps2 = '...: '
780 sys.ps3 = 'Out: '
780 sys.ps3 = 'Out: '
781
781
782 def init_display_formatter(self):
782 def init_display_formatter(self):
783 self.display_formatter = DisplayFormatter(parent=self)
783 self.display_formatter = DisplayFormatter(parent=self)
784 self.configurables.append(self.display_formatter)
784 self.configurables.append(self.display_formatter)
785
785
786 def init_display_pub(self):
786 def init_display_pub(self):
787 self.display_pub = self.display_pub_class(parent=self, shell=self)
787 self.display_pub = self.display_pub_class(parent=self, shell=self)
788 self.configurables.append(self.display_pub)
788 self.configurables.append(self.display_pub)
789
789
790 def init_data_pub(self):
790 def init_data_pub(self):
791 if not self.data_pub_class:
791 if not self.data_pub_class:
792 self.data_pub = None
792 self.data_pub = None
793 return
793 return
794 self.data_pub = self.data_pub_class(parent=self)
794 self.data_pub = self.data_pub_class(parent=self)
795 self.configurables.append(self.data_pub)
795 self.configurables.append(self.data_pub)
796
796
797 def init_displayhook(self):
797 def init_displayhook(self):
798 # Initialize displayhook, set in/out prompts and printing system
798 # Initialize displayhook, set in/out prompts and printing system
799 self.displayhook = self.displayhook_class(
799 self.displayhook = self.displayhook_class(
800 parent=self,
800 parent=self,
801 shell=self,
801 shell=self,
802 cache_size=self.cache_size,
802 cache_size=self.cache_size,
803 )
803 )
804 self.configurables.append(self.displayhook)
804 self.configurables.append(self.displayhook)
805 # This is a context manager that installs/revmoes the displayhook at
805 # This is a context manager that installs/revmoes the displayhook at
806 # the appropriate time.
806 # the appropriate time.
807 self.display_trap = DisplayTrap(hook=self.displayhook)
807 self.display_trap = DisplayTrap(hook=self.displayhook)
808
808
809 @staticmethod
809 @staticmethod
810 def get_path_links(p: Path):
810 def get_path_links(p: Path):
811 """Gets path links including all symlinks
811 """Gets path links including all symlinks
812
812
813 Examples
813 Examples
814 --------
814 --------
815 In [1]: from IPython.core.interactiveshell import InteractiveShell
815 In [1]: from IPython.core.interactiveshell import InteractiveShell
816
816
817 In [2]: import sys, pathlib
817 In [2]: import sys, pathlib
818
818
819 In [3]: paths = InteractiveShell.get_path_links(pathlib.Path(sys.executable))
819 In [3]: paths = InteractiveShell.get_path_links(pathlib.Path(sys.executable))
820
820
821 In [4]: len(paths) == len(set(paths))
821 In [4]: len(paths) == len(set(paths))
822 Out[4]: True
822 Out[4]: True
823
823
824 In [5]: bool(paths)
824 In [5]: bool(paths)
825 Out[5]: True
825 Out[5]: True
826 """
826 """
827 paths = [p]
827 paths = [p]
828 while p.is_symlink():
828 while p.is_symlink():
829 new_path = Path(os.readlink(p))
829 new_path = Path(os.readlink(p))
830 if not new_path.is_absolute():
830 if not new_path.is_absolute():
831 new_path = p.parent / new_path
831 new_path = p.parent / new_path
832 p = new_path
832 p = new_path
833 paths.append(p)
833 paths.append(p)
834 return paths
834 return paths
835
835
836 def init_virtualenv(self):
836 def init_virtualenv(self):
837 """Add the current virtualenv to sys.path so the user can import modules from it.
837 """Add the current virtualenv to sys.path so the user can import modules from it.
838 This isn't perfect: it doesn't use the Python interpreter with which the
838 This isn't perfect: it doesn't use the Python interpreter with which the
839 virtualenv was built, and it ignores the --no-site-packages option. A
839 virtualenv was built, and it ignores the --no-site-packages option. A
840 warning will appear suggesting the user installs IPython in the
840 warning will appear suggesting the user installs IPython in the
841 virtualenv, but for many cases, it probably works well enough.
841 virtualenv, but for many cases, it probably works well enough.
842
842
843 Adapted from code snippets online.
843 Adapted from code snippets online.
844
844
845 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
845 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
846 """
846 """
847 if 'VIRTUAL_ENV' not in os.environ:
847 if 'VIRTUAL_ENV' not in os.environ:
848 # Not in a virtualenv
848 # Not in a virtualenv
849 return
849 return
850 elif os.environ["VIRTUAL_ENV"] == "":
850 elif os.environ["VIRTUAL_ENV"] == "":
851 warn("Virtual env path set to '', please check if this is intended.")
851 warn("Virtual env path set to '', please check if this is intended.")
852 return
852 return
853
853
854 p = Path(sys.executable)
854 p = Path(sys.executable)
855 p_venv = Path(os.environ["VIRTUAL_ENV"])
855 p_venv = Path(os.environ["VIRTUAL_ENV"])
856
856
857 # fallback venv detection:
857 # fallback venv detection:
858 # stdlib venv may symlink sys.executable, so we can't use realpath.
858 # stdlib venv may symlink sys.executable, so we can't use realpath.
859 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
859 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
860 # So we just check every item in the symlink tree (generally <= 3)
860 # So we just check every item in the symlink tree (generally <= 3)
861 paths = self.get_path_links(p)
861 paths = self.get_path_links(p)
862
862
863 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
863 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
864 if p_venv.parts[1] == "cygdrive":
864 if p_venv.parts[1] == "cygdrive":
865 drive_name = p_venv.parts[2]
865 drive_name = p_venv.parts[2]
866 p_venv = (drive_name + ":/") / Path(*p_venv.parts[3:])
866 p_venv = (drive_name + ":/") / Path(*p_venv.parts[3:])
867
867
868 if any(p_venv == p.parents[1] for p in paths):
868 if any(p_venv == p.parents[1] for p in paths):
869 # Our exe is inside or has access to the virtualenv, don't need to do anything.
869 # Our exe is inside or has access to the virtualenv, don't need to do anything.
870 return
870 return
871
871
872 if sys.platform == "win32":
872 if sys.platform == "win32":
873 virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages"))
873 virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages"))
874 else:
874 else:
875 virtual_env_path = Path(
875 virtual_env_path = Path(
876 os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
876 os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
877 )
877 )
878 p_ver = sys.version_info[:2]
878 p_ver = sys.version_info[:2]
879
879
880 # Predict version from py[thon]-x.x in the $VIRTUAL_ENV
880 # Predict version from py[thon]-x.x in the $VIRTUAL_ENV
881 re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
881 re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
882 if re_m:
882 if re_m:
883 predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
883 predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
884 if predicted_path.exists():
884 if predicted_path.exists():
885 p_ver = re_m.groups()
885 p_ver = re_m.groups()
886
886
887 virtual_env = str(virtual_env_path).format(*p_ver)
887 virtual_env = str(virtual_env_path).format(*p_ver)
888 if self.warn_venv:
888 if self.warn_venv:
889 warn(
889 warn(
890 "Attempting to work in a virtualenv. If you encounter problems, "
890 "Attempting to work in a virtualenv. If you encounter problems, "
891 "please install IPython inside the virtualenv."
891 "please install IPython inside the virtualenv."
892 )
892 )
893 import site
893 import site
894 sys.path.insert(0, virtual_env)
894 sys.path.insert(0, virtual_env)
895 site.addsitedir(virtual_env)
895 site.addsitedir(virtual_env)
896
896
897 #-------------------------------------------------------------------------
897 #-------------------------------------------------------------------------
898 # Things related to injections into the sys module
898 # Things related to injections into the sys module
899 #-------------------------------------------------------------------------
899 #-------------------------------------------------------------------------
900
900
901 def save_sys_module_state(self):
901 def save_sys_module_state(self):
902 """Save the state of hooks in the sys module.
902 """Save the state of hooks in the sys module.
903
903
904 This has to be called after self.user_module is created.
904 This has to be called after self.user_module is created.
905 """
905 """
906 self._orig_sys_module_state = {'stdin': sys.stdin,
906 self._orig_sys_module_state = {'stdin': sys.stdin,
907 'stdout': sys.stdout,
907 'stdout': sys.stdout,
908 'stderr': sys.stderr,
908 'stderr': sys.stderr,
909 'excepthook': sys.excepthook}
909 'excepthook': sys.excepthook}
910 self._orig_sys_modules_main_name = self.user_module.__name__
910 self._orig_sys_modules_main_name = self.user_module.__name__
911 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
911 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
912
912
913 def restore_sys_module_state(self):
913 def restore_sys_module_state(self):
914 """Restore the state of the sys module."""
914 """Restore the state of the sys module."""
915 try:
915 try:
916 for k, v in self._orig_sys_module_state.items():
916 for k, v in self._orig_sys_module_state.items():
917 setattr(sys, k, v)
917 setattr(sys, k, v)
918 except AttributeError:
918 except AttributeError:
919 pass
919 pass
920 # Reset what what done in self.init_sys_modules
920 # Reset what what done in self.init_sys_modules
921 if self._orig_sys_modules_main_mod is not None:
921 if self._orig_sys_modules_main_mod is not None:
922 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
922 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
923
923
924 #-------------------------------------------------------------------------
924 #-------------------------------------------------------------------------
925 # Things related to the banner
925 # Things related to the banner
926 #-------------------------------------------------------------------------
926 #-------------------------------------------------------------------------
927
927
928 @property
928 @property
929 def banner(self):
929 def banner(self):
930 banner = self.banner1
930 banner = self.banner1
931 if self.profile and self.profile != 'default':
931 if self.profile and self.profile != 'default':
932 banner += '\nIPython profile: %s\n' % self.profile
932 banner += '\nIPython profile: %s\n' % self.profile
933 if self.banner2:
933 if self.banner2:
934 banner += '\n' + self.banner2
934 banner += '\n' + self.banner2
935 return banner
935 return banner
936
936
937 def show_banner(self, banner=None):
937 def show_banner(self, banner=None):
938 if banner is None:
938 if banner is None:
939 banner = self.banner
939 banner = self.banner
940 sys.stdout.write(banner)
940 sys.stdout.write(banner)
941
941
942 #-------------------------------------------------------------------------
942 #-------------------------------------------------------------------------
943 # Things related to hooks
943 # Things related to hooks
944 #-------------------------------------------------------------------------
944 #-------------------------------------------------------------------------
945
945
946 def init_hooks(self):
946 def init_hooks(self):
947 # hooks holds pointers used for user-side customizations
947 # hooks holds pointers used for user-side customizations
948 self.hooks = Struct()
948 self.hooks = Struct()
949
949
950 self.strdispatchers = {}
950 self.strdispatchers = {}
951
951
952 # Set all default hooks, defined in the IPython.hooks module.
952 # Set all default hooks, defined in the IPython.hooks module.
953 hooks = IPython.core.hooks
953 hooks = IPython.core.hooks
954 for hook_name in hooks.__all__:
954 for hook_name in hooks.__all__:
955 # default hooks have priority 100, i.e. low; user hooks should have
955 # default hooks have priority 100, i.e. low; user hooks should have
956 # 0-100 priority
956 # 0-100 priority
957 self.set_hook(hook_name, getattr(hooks, hook_name), 100)
957 self.set_hook(hook_name, getattr(hooks, hook_name), 100)
958
958
959 if self.display_page:
959 if self.display_page:
960 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
960 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
961
961
962 def set_hook(self, name, hook, priority=50, str_key=None, re_key=None):
962 def set_hook(self, name, hook, priority=50, str_key=None, re_key=None):
963 """set_hook(name,hook) -> sets an internal IPython hook.
963 """set_hook(name,hook) -> sets an internal IPython hook.
964
964
965 IPython exposes some of its internal API as user-modifiable hooks. By
965 IPython exposes some of its internal API as user-modifiable hooks. By
966 adding your function to one of these hooks, you can modify IPython's
966 adding your function to one of these hooks, you can modify IPython's
967 behavior to call at runtime your own routines."""
967 behavior to call at runtime your own routines."""
968
968
969 # At some point in the future, this should validate the hook before it
969 # At some point in the future, this should validate the hook before it
970 # accepts it. Probably at least check that the hook takes the number
970 # accepts it. Probably at least check that the hook takes the number
971 # of args it's supposed to.
971 # of args it's supposed to.
972
972
973 f = types.MethodType(hook,self)
973 f = types.MethodType(hook,self)
974
974
975 # check if the hook is for strdispatcher first
975 # check if the hook is for strdispatcher first
976 if str_key is not None:
976 if str_key is not None:
977 sdp = self.strdispatchers.get(name, StrDispatch())
977 sdp = self.strdispatchers.get(name, StrDispatch())
978 sdp.add_s(str_key, f, priority )
978 sdp.add_s(str_key, f, priority )
979 self.strdispatchers[name] = sdp
979 self.strdispatchers[name] = sdp
980 return
980 return
981 if re_key is not None:
981 if re_key is not None:
982 sdp = self.strdispatchers.get(name, StrDispatch())
982 sdp = self.strdispatchers.get(name, StrDispatch())
983 sdp.add_re(re.compile(re_key), f, priority )
983 sdp.add_re(re.compile(re_key), f, priority )
984 self.strdispatchers[name] = sdp
984 self.strdispatchers[name] = sdp
985 return
985 return
986
986
987 dp = getattr(self.hooks, name, None)
987 dp = getattr(self.hooks, name, None)
988 if name not in IPython.core.hooks.__all__:
988 if name not in IPython.core.hooks.__all__:
989 print("Warning! Hook '%s' is not one of %s" % \
989 print("Warning! Hook '%s' is not one of %s" % \
990 (name, IPython.core.hooks.__all__ ))
990 (name, IPython.core.hooks.__all__ ))
991
991
992 if name in IPython.core.hooks.deprecated:
992 if name in IPython.core.hooks.deprecated:
993 alternative = IPython.core.hooks.deprecated[name]
993 alternative = IPython.core.hooks.deprecated[name]
994 raise ValueError(
994 raise ValueError(
995 "Hook {} has been deprecated since IPython 5.0. Use {} instead.".format(
995 "Hook {} has been deprecated since IPython 5.0. Use {} instead.".format(
996 name, alternative
996 name, alternative
997 )
997 )
998 )
998 )
999
999
1000 if not dp:
1000 if not dp:
1001 dp = IPython.core.hooks.CommandChainDispatcher()
1001 dp = IPython.core.hooks.CommandChainDispatcher()
1002
1002
1003 try:
1003 try:
1004 dp.add(f,priority)
1004 dp.add(f,priority)
1005 except AttributeError:
1005 except AttributeError:
1006 # it was not commandchain, plain old func - replace
1006 # it was not commandchain, plain old func - replace
1007 dp = f
1007 dp = f
1008
1008
1009 setattr(self.hooks,name, dp)
1009 setattr(self.hooks,name, dp)
1010
1010
1011 #-------------------------------------------------------------------------
1011 #-------------------------------------------------------------------------
1012 # Things related to events
1012 # Things related to events
1013 #-------------------------------------------------------------------------
1013 #-------------------------------------------------------------------------
1014
1014
1015 def init_events(self):
1015 def init_events(self):
1016 self.events = EventManager(self, available_events)
1016 self.events = EventManager(self, available_events)
1017
1017
1018 self.events.register("pre_execute", self._clear_warning_registry)
1018 self.events.register("pre_execute", self._clear_warning_registry)
1019
1019
1020 def register_post_execute(self, func):
1020 def register_post_execute(self, func):
1021 """DEPRECATED: Use ip.events.register('post_run_cell', func)
1021 """DEPRECATED: Use ip.events.register('post_run_cell', func)
1022
1022
1023 Register a function for calling after code execution.
1023 Register a function for calling after code execution.
1024 """
1024 """
1025 raise ValueError(
1025 raise ValueError(
1026 "ip.register_post_execute is deprecated since IPython 1.0, use "
1026 "ip.register_post_execute is deprecated since IPython 1.0, use "
1027 "ip.events.register('post_run_cell', func) instead."
1027 "ip.events.register('post_run_cell', func) instead."
1028 )
1028 )
1029
1029
1030 def _clear_warning_registry(self):
1030 def _clear_warning_registry(self):
1031 # clear the warning registry, so that different code blocks with
1031 # clear the warning registry, so that different code blocks with
1032 # overlapping line number ranges don't cause spurious suppression of
1032 # overlapping line number ranges don't cause spurious suppression of
1033 # warnings (see gh-6611 for details)
1033 # warnings (see gh-6611 for details)
1034 if "__warningregistry__" in self.user_global_ns:
1034 if "__warningregistry__" in self.user_global_ns:
1035 del self.user_global_ns["__warningregistry__"]
1035 del self.user_global_ns["__warningregistry__"]
1036
1036
1037 #-------------------------------------------------------------------------
1037 #-------------------------------------------------------------------------
1038 # Things related to the "main" module
1038 # Things related to the "main" module
1039 #-------------------------------------------------------------------------
1039 #-------------------------------------------------------------------------
1040
1040
1041 def new_main_mod(self, filename, modname):
1041 def new_main_mod(self, filename, modname):
1042 """Return a new 'main' module object for user code execution.
1042 """Return a new 'main' module object for user code execution.
1043
1043
1044 ``filename`` should be the path of the script which will be run in the
1044 ``filename`` should be the path of the script which will be run in the
1045 module. Requests with the same filename will get the same module, with
1045 module. Requests with the same filename will get the same module, with
1046 its namespace cleared.
1046 its namespace cleared.
1047
1047
1048 ``modname`` should be the module name - normally either '__main__' or
1048 ``modname`` should be the module name - normally either '__main__' or
1049 the basename of the file without the extension.
1049 the basename of the file without the extension.
1050
1050
1051 When scripts are executed via %run, we must keep a reference to their
1051 When scripts are executed via %run, we must keep a reference to their
1052 __main__ module around so that Python doesn't
1052 __main__ module around so that Python doesn't
1053 clear it, rendering references to module globals useless.
1053 clear it, rendering references to module globals useless.
1054
1054
1055 This method keeps said reference in a private dict, keyed by the
1055 This method keeps said reference in a private dict, keyed by the
1056 absolute path of the script. This way, for multiple executions of the
1056 absolute path of the script. This way, for multiple executions of the
1057 same script we only keep one copy of the namespace (the last one),
1057 same script we only keep one copy of the namespace (the last one),
1058 thus preventing memory leaks from old references while allowing the
1058 thus preventing memory leaks from old references while allowing the
1059 objects from the last execution to be accessible.
1059 objects from the last execution to be accessible.
1060 """
1060 """
1061 filename = os.path.abspath(filename)
1061 filename = os.path.abspath(filename)
1062 try:
1062 try:
1063 main_mod = self._main_mod_cache[filename]
1063 main_mod = self._main_mod_cache[filename]
1064 except KeyError:
1064 except KeyError:
1065 main_mod = self._main_mod_cache[filename] = types.ModuleType(
1065 main_mod = self._main_mod_cache[filename] = types.ModuleType(
1066 modname,
1066 modname,
1067 doc="Module created for script run in IPython")
1067 doc="Module created for script run in IPython")
1068 else:
1068 else:
1069 main_mod.__dict__.clear()
1069 main_mod.__dict__.clear()
1070 main_mod.__name__ = modname
1070 main_mod.__name__ = modname
1071
1071
1072 main_mod.__file__ = filename
1072 main_mod.__file__ = filename
1073 # It seems pydoc (and perhaps others) needs any module instance to
1073 # It seems pydoc (and perhaps others) needs any module instance to
1074 # implement a __nonzero__ method
1074 # implement a __nonzero__ method
1075 main_mod.__nonzero__ = lambda : True
1075 main_mod.__nonzero__ = lambda : True
1076
1076
1077 return main_mod
1077 return main_mod
1078
1078
1079 def clear_main_mod_cache(self):
1079 def clear_main_mod_cache(self):
1080 """Clear the cache of main modules.
1080 """Clear the cache of main modules.
1081
1081
1082 Mainly for use by utilities like %reset.
1082 Mainly for use by utilities like %reset.
1083
1083
1084 Examples
1084 Examples
1085 --------
1085 --------
1086 In [15]: import IPython
1086 In [15]: import IPython
1087
1087
1088 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
1088 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
1089
1089
1090 In [17]: len(_ip._main_mod_cache) > 0
1090 In [17]: len(_ip._main_mod_cache) > 0
1091 Out[17]: True
1091 Out[17]: True
1092
1092
1093 In [18]: _ip.clear_main_mod_cache()
1093 In [18]: _ip.clear_main_mod_cache()
1094
1094
1095 In [19]: len(_ip._main_mod_cache) == 0
1095 In [19]: len(_ip._main_mod_cache) == 0
1096 Out[19]: True
1096 Out[19]: True
1097 """
1097 """
1098 self._main_mod_cache.clear()
1098 self._main_mod_cache.clear()
1099
1099
1100 #-------------------------------------------------------------------------
1100 #-------------------------------------------------------------------------
1101 # Things related to debugging
1101 # Things related to debugging
1102 #-------------------------------------------------------------------------
1102 #-------------------------------------------------------------------------
1103
1103
1104 def init_pdb(self):
1104 def init_pdb(self):
1105 # Set calling of pdb on exceptions
1105 # Set calling of pdb on exceptions
1106 # self.call_pdb is a property
1106 # self.call_pdb is a property
1107 self.call_pdb = self.pdb
1107 self.call_pdb = self.pdb
1108
1108
1109 def _get_call_pdb(self):
1109 def _get_call_pdb(self):
1110 return self._call_pdb
1110 return self._call_pdb
1111
1111
1112 def _set_call_pdb(self,val):
1112 def _set_call_pdb(self,val):
1113
1113
1114 if val not in (0,1,False,True):
1114 if val not in (0,1,False,True):
1115 raise ValueError('new call_pdb value must be boolean')
1115 raise ValueError('new call_pdb value must be boolean')
1116
1116
1117 # store value in instance
1117 # store value in instance
1118 self._call_pdb = val
1118 self._call_pdb = val
1119
1119
1120 # notify the actual exception handlers
1120 # notify the actual exception handlers
1121 self.InteractiveTB.call_pdb = val
1121 self.InteractiveTB.call_pdb = val
1122
1122
1123 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
1123 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
1124 'Control auto-activation of pdb at exceptions')
1124 'Control auto-activation of pdb at exceptions')
1125
1125
1126 def debugger(self,force=False):
1126 def debugger(self,force=False):
1127 """Call the pdb debugger.
1127 """Call the pdb debugger.
1128
1128
1129 Keywords:
1129 Keywords:
1130
1130
1131 - force(False): by default, this routine checks the instance call_pdb
1131 - force(False): by default, this routine checks the instance call_pdb
1132 flag and does not actually invoke the debugger if the flag is false.
1132 flag and does not actually invoke the debugger if the flag is false.
1133 The 'force' option forces the debugger to activate even if the flag
1133 The 'force' option forces the debugger to activate even if the flag
1134 is false.
1134 is false.
1135 """
1135 """
1136
1136
1137 if not (force or self.call_pdb):
1137 if not (force or self.call_pdb):
1138 return
1138 return
1139
1139
1140 if not hasattr(sys,'last_traceback'):
1140 if not hasattr(sys,'last_traceback'):
1141 error('No traceback has been produced, nothing to debug.')
1141 error('No traceback has been produced, nothing to debug.')
1142 return
1142 return
1143
1143
1144 self.InteractiveTB.debugger(force=True)
1144 self.InteractiveTB.debugger(force=True)
1145
1145
1146 #-------------------------------------------------------------------------
1146 #-------------------------------------------------------------------------
1147 # Things related to IPython's various namespaces
1147 # Things related to IPython's various namespaces
1148 #-------------------------------------------------------------------------
1148 #-------------------------------------------------------------------------
1149 default_user_namespaces = True
1149 default_user_namespaces = True
1150
1150
1151 def init_create_namespaces(self, user_module=None, user_ns=None):
1151 def init_create_namespaces(self, user_module=None, user_ns=None):
1152 # Create the namespace where the user will operate. user_ns is
1152 # Create the namespace where the user will operate. user_ns is
1153 # normally the only one used, and it is passed to the exec calls as
1153 # normally the only one used, and it is passed to the exec calls as
1154 # the locals argument. But we do carry a user_global_ns namespace
1154 # the locals argument. But we do carry a user_global_ns namespace
1155 # given as the exec 'globals' argument, This is useful in embedding
1155 # given as the exec 'globals' argument, This is useful in embedding
1156 # situations where the ipython shell opens in a context where the
1156 # situations where the ipython shell opens in a context where the
1157 # distinction between locals and globals is meaningful. For
1157 # distinction between locals and globals is meaningful. For
1158 # non-embedded contexts, it is just the same object as the user_ns dict.
1158 # non-embedded contexts, it is just the same object as the user_ns dict.
1159
1159
1160 # FIXME. For some strange reason, __builtins__ is showing up at user
1160 # FIXME. For some strange reason, __builtins__ is showing up at user
1161 # level as a dict instead of a module. This is a manual fix, but I
1161 # level as a dict instead of a module. This is a manual fix, but I
1162 # should really track down where the problem is coming from. Alex
1162 # should really track down where the problem is coming from. Alex
1163 # Schmolck reported this problem first.
1163 # Schmolck reported this problem first.
1164
1164
1165 # A useful post by Alex Martelli on this topic:
1165 # A useful post by Alex Martelli on this topic:
1166 # Re: inconsistent value from __builtins__
1166 # Re: inconsistent value from __builtins__
1167 # Von: Alex Martelli <aleaxit@yahoo.com>
1167 # Von: Alex Martelli <aleaxit@yahoo.com>
1168 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1168 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1169 # Gruppen: comp.lang.python
1169 # Gruppen: comp.lang.python
1170
1170
1171 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1171 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1172 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1172 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1173 # > <type 'dict'>
1173 # > <type 'dict'>
1174 # > >>> print type(__builtins__)
1174 # > >>> print type(__builtins__)
1175 # > <type 'module'>
1175 # > <type 'module'>
1176 # > Is this difference in return value intentional?
1176 # > Is this difference in return value intentional?
1177
1177
1178 # Well, it's documented that '__builtins__' can be either a dictionary
1178 # Well, it's documented that '__builtins__' can be either a dictionary
1179 # or a module, and it's been that way for a long time. Whether it's
1179 # or a module, and it's been that way for a long time. Whether it's
1180 # intentional (or sensible), I don't know. In any case, the idea is
1180 # intentional (or sensible), I don't know. In any case, the idea is
1181 # that if you need to access the built-in namespace directly, you
1181 # that if you need to access the built-in namespace directly, you
1182 # should start with "import __builtin__" (note, no 's') which will
1182 # should start with "import __builtin__" (note, no 's') which will
1183 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1183 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1184
1184
1185 # These routines return a properly built module and dict as needed by
1185 # These routines return a properly built module and dict as needed by
1186 # the rest of the code, and can also be used by extension writers to
1186 # the rest of the code, and can also be used by extension writers to
1187 # generate properly initialized namespaces.
1187 # generate properly initialized namespaces.
1188 if (user_ns is not None) or (user_module is not None):
1188 if (user_ns is not None) or (user_module is not None):
1189 self.default_user_namespaces = False
1189 self.default_user_namespaces = False
1190 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1190 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1191
1191
1192 # A record of hidden variables we have added to the user namespace, so
1192 # A record of hidden variables we have added to the user namespace, so
1193 # we can list later only variables defined in actual interactive use.
1193 # we can list later only variables defined in actual interactive use.
1194 self.user_ns_hidden = {}
1194 self.user_ns_hidden = {}
1195
1195
1196 # Now that FakeModule produces a real module, we've run into a nasty
1196 # Now that FakeModule produces a real module, we've run into a nasty
1197 # problem: after script execution (via %run), the module where the user
1197 # problem: after script execution (via %run), the module where the user
1198 # code ran is deleted. Now that this object is a true module (needed
1198 # code ran is deleted. Now that this object is a true module (needed
1199 # so doctest and other tools work correctly), the Python module
1199 # so doctest and other tools work correctly), the Python module
1200 # teardown mechanism runs over it, and sets to None every variable
1200 # teardown mechanism runs over it, and sets to None every variable
1201 # present in that module. Top-level references to objects from the
1201 # present in that module. Top-level references to objects from the
1202 # script survive, because the user_ns is updated with them. However,
1202 # script survive, because the user_ns is updated with them. However,
1203 # calling functions defined in the script that use other things from
1203 # calling functions defined in the script that use other things from
1204 # the script will fail, because the function's closure had references
1204 # the script will fail, because the function's closure had references
1205 # to the original objects, which are now all None. So we must protect
1205 # to the original objects, which are now all None. So we must protect
1206 # these modules from deletion by keeping a cache.
1206 # these modules from deletion by keeping a cache.
1207 #
1207 #
1208 # To avoid keeping stale modules around (we only need the one from the
1208 # To avoid keeping stale modules around (we only need the one from the
1209 # last run), we use a dict keyed with the full path to the script, so
1209 # last run), we use a dict keyed with the full path to the script, so
1210 # only the last version of the module is held in the cache. Note,
1210 # only the last version of the module is held in the cache. Note,
1211 # however, that we must cache the module *namespace contents* (their
1211 # however, that we must cache the module *namespace contents* (their
1212 # __dict__). Because if we try to cache the actual modules, old ones
1212 # __dict__). Because if we try to cache the actual modules, old ones
1213 # (uncached) could be destroyed while still holding references (such as
1213 # (uncached) could be destroyed while still holding references (such as
1214 # those held by GUI objects that tend to be long-lived)>
1214 # those held by GUI objects that tend to be long-lived)>
1215 #
1215 #
1216 # The %reset command will flush this cache. See the cache_main_mod()
1216 # The %reset command will flush this cache. See the cache_main_mod()
1217 # and clear_main_mod_cache() methods for details on use.
1217 # and clear_main_mod_cache() methods for details on use.
1218
1218
1219 # This is the cache used for 'main' namespaces
1219 # This is the cache used for 'main' namespaces
1220 self._main_mod_cache = {}
1220 self._main_mod_cache = {}
1221
1221
1222 # A table holding all the namespaces IPython deals with, so that
1222 # A table holding all the namespaces IPython deals with, so that
1223 # introspection facilities can search easily.
1223 # introspection facilities can search easily.
1224 self.ns_table = {'user_global':self.user_module.__dict__,
1224 self.ns_table = {'user_global':self.user_module.__dict__,
1225 'user_local':self.user_ns,
1225 'user_local':self.user_ns,
1226 'builtin':builtin_mod.__dict__
1226 'builtin':builtin_mod.__dict__
1227 }
1227 }
1228
1228
1229 @property
1229 @property
1230 def user_global_ns(self):
1230 def user_global_ns(self):
1231 return self.user_module.__dict__
1231 return self.user_module.__dict__
1232
1232
1233 def prepare_user_module(self, user_module=None, user_ns=None):
1233 def prepare_user_module(self, user_module=None, user_ns=None):
1234 """Prepare the module and namespace in which user code will be run.
1234 """Prepare the module and namespace in which user code will be run.
1235
1235
1236 When IPython is started normally, both parameters are None: a new module
1236 When IPython is started normally, both parameters are None: a new module
1237 is created automatically, and its __dict__ used as the namespace.
1237 is created automatically, and its __dict__ used as the namespace.
1238
1238
1239 If only user_module is provided, its __dict__ is used as the namespace.
1239 If only user_module is provided, its __dict__ is used as the namespace.
1240 If only user_ns is provided, a dummy module is created, and user_ns
1240 If only user_ns is provided, a dummy module is created, and user_ns
1241 becomes the global namespace. If both are provided (as they may be
1241 becomes the global namespace. If both are provided (as they may be
1242 when embedding), user_ns is the local namespace, and user_module
1242 when embedding), user_ns is the local namespace, and user_module
1243 provides the global namespace.
1243 provides the global namespace.
1244
1244
1245 Parameters
1245 Parameters
1246 ----------
1246 ----------
1247 user_module : module, optional
1247 user_module : module, optional
1248 The current user module in which IPython is being run. If None,
1248 The current user module in which IPython is being run. If None,
1249 a clean module will be created.
1249 a clean module will be created.
1250 user_ns : dict, optional
1250 user_ns : dict, optional
1251 A namespace in which to run interactive commands.
1251 A namespace in which to run interactive commands.
1252
1252
1253 Returns
1253 Returns
1254 -------
1254 -------
1255 A tuple of user_module and user_ns, each properly initialised.
1255 A tuple of user_module and user_ns, each properly initialised.
1256 """
1256 """
1257 if user_module is None and user_ns is not None:
1257 if user_module is None and user_ns is not None:
1258 user_ns.setdefault("__name__", "__main__")
1258 user_ns.setdefault("__name__", "__main__")
1259 user_module = DummyMod()
1259 user_module = DummyMod()
1260 user_module.__dict__ = user_ns
1260 user_module.__dict__ = user_ns
1261
1261
1262 if user_module is None:
1262 if user_module is None:
1263 user_module = types.ModuleType("__main__",
1263 user_module = types.ModuleType("__main__",
1264 doc="Automatically created module for IPython interactive environment")
1264 doc="Automatically created module for IPython interactive environment")
1265
1265
1266 # We must ensure that __builtin__ (without the final 's') is always
1266 # We must ensure that __builtin__ (without the final 's') is always
1267 # available and pointing to the __builtin__ *module*. For more details:
1267 # available and pointing to the __builtin__ *module*. For more details:
1268 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1268 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1269 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1269 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1270 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1270 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1271
1271
1272 if user_ns is None:
1272 if user_ns is None:
1273 user_ns = user_module.__dict__
1273 user_ns = user_module.__dict__
1274
1274
1275 return user_module, user_ns
1275 return user_module, user_ns
1276
1276
1277 def init_sys_modules(self):
1277 def init_sys_modules(self):
1278 # We need to insert into sys.modules something that looks like a
1278 # We need to insert into sys.modules something that looks like a
1279 # module but which accesses the IPython namespace, for shelve and
1279 # module but which accesses the IPython namespace, for shelve and
1280 # pickle to work interactively. Normally they rely on getting
1280 # pickle to work interactively. Normally they rely on getting
1281 # everything out of __main__, but for embedding purposes each IPython
1281 # everything out of __main__, but for embedding purposes each IPython
1282 # instance has its own private namespace, so we can't go shoving
1282 # instance has its own private namespace, so we can't go shoving
1283 # everything into __main__.
1283 # everything into __main__.
1284
1284
1285 # note, however, that we should only do this for non-embedded
1285 # note, however, that we should only do this for non-embedded
1286 # ipythons, which really mimic the __main__.__dict__ with their own
1286 # ipythons, which really mimic the __main__.__dict__ with their own
1287 # namespace. Embedded instances, on the other hand, should not do
1287 # namespace. Embedded instances, on the other hand, should not do
1288 # this because they need to manage the user local/global namespaces
1288 # this because they need to manage the user local/global namespaces
1289 # only, but they live within a 'normal' __main__ (meaning, they
1289 # only, but they live within a 'normal' __main__ (meaning, they
1290 # shouldn't overtake the execution environment of the script they're
1290 # shouldn't overtake the execution environment of the script they're
1291 # embedded in).
1291 # embedded in).
1292
1292
1293 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1293 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1294 main_name = self.user_module.__name__
1294 main_name = self.user_module.__name__
1295 sys.modules[main_name] = self.user_module
1295 sys.modules[main_name] = self.user_module
1296
1296
1297 def init_user_ns(self):
1297 def init_user_ns(self):
1298 """Initialize all user-visible namespaces to their minimum defaults.
1298 """Initialize all user-visible namespaces to their minimum defaults.
1299
1299
1300 Certain history lists are also initialized here, as they effectively
1300 Certain history lists are also initialized here, as they effectively
1301 act as user namespaces.
1301 act as user namespaces.
1302
1302
1303 Notes
1303 Notes
1304 -----
1304 -----
1305 All data structures here are only filled in, they are NOT reset by this
1305 All data structures here are only filled in, they are NOT reset by this
1306 method. If they were not empty before, data will simply be added to
1306 method. If they were not empty before, data will simply be added to
1307 them.
1307 them.
1308 """
1308 """
1309 # This function works in two parts: first we put a few things in
1309 # This function works in two parts: first we put a few things in
1310 # user_ns, and we sync that contents into user_ns_hidden so that these
1310 # user_ns, and we sync that contents into user_ns_hidden so that these
1311 # initial variables aren't shown by %who. After the sync, we add the
1311 # initial variables aren't shown by %who. After the sync, we add the
1312 # rest of what we *do* want the user to see with %who even on a new
1312 # rest of what we *do* want the user to see with %who even on a new
1313 # session (probably nothing, so they really only see their own stuff)
1313 # session (probably nothing, so they really only see their own stuff)
1314
1314
1315 # The user dict must *always* have a __builtin__ reference to the
1315 # The user dict must *always* have a __builtin__ reference to the
1316 # Python standard __builtin__ namespace, which must be imported.
1316 # Python standard __builtin__ namespace, which must be imported.
1317 # This is so that certain operations in prompt evaluation can be
1317 # This is so that certain operations in prompt evaluation can be
1318 # reliably executed with builtins. Note that we can NOT use
1318 # reliably executed with builtins. Note that we can NOT use
1319 # __builtins__ (note the 's'), because that can either be a dict or a
1319 # __builtins__ (note the 's'), because that can either be a dict or a
1320 # module, and can even mutate at runtime, depending on the context
1320 # module, and can even mutate at runtime, depending on the context
1321 # (Python makes no guarantees on it). In contrast, __builtin__ is
1321 # (Python makes no guarantees on it). In contrast, __builtin__ is
1322 # always a module object, though it must be explicitly imported.
1322 # always a module object, though it must be explicitly imported.
1323
1323
1324 # For more details:
1324 # For more details:
1325 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1325 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1326 ns = {}
1326 ns = {}
1327
1327
1328 # make global variables for user access to the histories
1328 # make global variables for user access to the histories
1329 ns['_ih'] = self.history_manager.input_hist_parsed
1329 ns['_ih'] = self.history_manager.input_hist_parsed
1330 ns['_oh'] = self.history_manager.output_hist
1330 ns['_oh'] = self.history_manager.output_hist
1331 ns['_dh'] = self.history_manager.dir_hist
1331 ns['_dh'] = self.history_manager.dir_hist
1332
1332
1333 # user aliases to input and output histories. These shouldn't show up
1333 # user aliases to input and output histories. These shouldn't show up
1334 # in %who, as they can have very large reprs.
1334 # in %who, as they can have very large reprs.
1335 ns['In'] = self.history_manager.input_hist_parsed
1335 ns['In'] = self.history_manager.input_hist_parsed
1336 ns['Out'] = self.history_manager.output_hist
1336 ns['Out'] = self.history_manager.output_hist
1337
1337
1338 # Store myself as the public api!!!
1338 # Store myself as the public api!!!
1339 ns['get_ipython'] = self.get_ipython
1339 ns['get_ipython'] = self.get_ipython
1340
1340
1341 ns['exit'] = self.exiter
1341 ns['exit'] = self.exiter
1342 ns['quit'] = self.exiter
1342 ns['quit'] = self.exiter
1343 ns["open"] = _modified_open
1343 ns["open"] = _modified_open
1344
1344
1345 # Sync what we've added so far to user_ns_hidden so these aren't seen
1345 # Sync what we've added so far to user_ns_hidden so these aren't seen
1346 # by %who
1346 # by %who
1347 self.user_ns_hidden.update(ns)
1347 self.user_ns_hidden.update(ns)
1348
1348
1349 # Anything put into ns now would show up in %who. Think twice before
1349 # Anything put into ns now would show up in %who. Think twice before
1350 # putting anything here, as we really want %who to show the user their
1350 # putting anything here, as we really want %who to show the user their
1351 # stuff, not our variables.
1351 # stuff, not our variables.
1352
1352
1353 # Finally, update the real user's namespace
1353 # Finally, update the real user's namespace
1354 self.user_ns.update(ns)
1354 self.user_ns.update(ns)
1355
1355
1356 @property
1356 @property
1357 def all_ns_refs(self):
1357 def all_ns_refs(self):
1358 """Get a list of references to all the namespace dictionaries in which
1358 """Get a list of references to all the namespace dictionaries in which
1359 IPython might store a user-created object.
1359 IPython might store a user-created object.
1360
1360
1361 Note that this does not include the displayhook, which also caches
1361 Note that this does not include the displayhook, which also caches
1362 objects from the output."""
1362 objects from the output."""
1363 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1363 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1364 [m.__dict__ for m in self._main_mod_cache.values()]
1364 [m.__dict__ for m in self._main_mod_cache.values()]
1365
1365
1366 def reset(self, new_session=True, aggressive=False):
1366 def reset(self, new_session=True, aggressive=False):
1367 """Clear all internal namespaces, and attempt to release references to
1367 """Clear all internal namespaces, and attempt to release references to
1368 user objects.
1368 user objects.
1369
1369
1370 If new_session is True, a new history session will be opened.
1370 If new_session is True, a new history session will be opened.
1371 """
1371 """
1372 # Clear histories
1372 # Clear histories
1373 self.history_manager.reset(new_session)
1373 self.history_manager.reset(new_session)
1374 # Reset counter used to index all histories
1374 # Reset counter used to index all histories
1375 if new_session:
1375 if new_session:
1376 self.execution_count = 1
1376 self.execution_count = 1
1377
1377
1378 # Reset last execution result
1378 # Reset last execution result
1379 self.last_execution_succeeded = True
1379 self.last_execution_succeeded = True
1380 self.last_execution_result = None
1380 self.last_execution_result = None
1381
1381
1382 # Flush cached output items
1382 # Flush cached output items
1383 if self.displayhook.do_full_cache:
1383 if self.displayhook.do_full_cache:
1384 self.displayhook.flush()
1384 self.displayhook.flush()
1385
1385
1386 # The main execution namespaces must be cleared very carefully,
1386 # The main execution namespaces must be cleared very carefully,
1387 # skipping the deletion of the builtin-related keys, because doing so
1387 # skipping the deletion of the builtin-related keys, because doing so
1388 # would cause errors in many object's __del__ methods.
1388 # would cause errors in many object's __del__ methods.
1389 if self.user_ns is not self.user_global_ns:
1389 if self.user_ns is not self.user_global_ns:
1390 self.user_ns.clear()
1390 self.user_ns.clear()
1391 ns = self.user_global_ns
1391 ns = self.user_global_ns
1392 drop_keys = set(ns.keys())
1392 drop_keys = set(ns.keys())
1393 drop_keys.discard('__builtin__')
1393 drop_keys.discard('__builtin__')
1394 drop_keys.discard('__builtins__')
1394 drop_keys.discard('__builtins__')
1395 drop_keys.discard('__name__')
1395 drop_keys.discard('__name__')
1396 for k in drop_keys:
1396 for k in drop_keys:
1397 del ns[k]
1397 del ns[k]
1398
1398
1399 self.user_ns_hidden.clear()
1399 self.user_ns_hidden.clear()
1400
1400
1401 # Restore the user namespaces to minimal usability
1401 # Restore the user namespaces to minimal usability
1402 self.init_user_ns()
1402 self.init_user_ns()
1403 if aggressive and not hasattr(self, "_sys_modules_keys"):
1403 if aggressive and not hasattr(self, "_sys_modules_keys"):
1404 print("Cannot restore sys.module, no snapshot")
1404 print("Cannot restore sys.module, no snapshot")
1405 elif aggressive:
1405 elif aggressive:
1406 print("culling sys module...")
1406 print("culling sys module...")
1407 current_keys = set(sys.modules.keys())
1407 current_keys = set(sys.modules.keys())
1408 for k in current_keys - self._sys_modules_keys:
1408 for k in current_keys - self._sys_modules_keys:
1409 if k.startswith("multiprocessing"):
1409 if k.startswith("multiprocessing"):
1410 continue
1410 continue
1411 del sys.modules[k]
1411 del sys.modules[k]
1412
1412
1413 # Restore the default and user aliases
1413 # Restore the default and user aliases
1414 self.alias_manager.clear_aliases()
1414 self.alias_manager.clear_aliases()
1415 self.alias_manager.init_aliases()
1415 self.alias_manager.init_aliases()
1416
1416
1417 # Now define aliases that only make sense on the terminal, because they
1417 # Now define aliases that only make sense on the terminal, because they
1418 # need direct access to the console in a way that we can't emulate in
1418 # need direct access to the console in a way that we can't emulate in
1419 # GUI or web frontend
1419 # GUI or web frontend
1420 if os.name == 'posix':
1420 if os.name == 'posix':
1421 for cmd in ('clear', 'more', 'less', 'man'):
1421 for cmd in ('clear', 'more', 'less', 'man'):
1422 if cmd not in self.magics_manager.magics['line']:
1422 if cmd not in self.magics_manager.magics['line']:
1423 self.alias_manager.soft_define_alias(cmd, cmd)
1423 self.alias_manager.soft_define_alias(cmd, cmd)
1424
1424
1425 # Flush the private list of module references kept for script
1425 # Flush the private list of module references kept for script
1426 # execution protection
1426 # execution protection
1427 self.clear_main_mod_cache()
1427 self.clear_main_mod_cache()
1428
1428
1429 def del_var(self, varname, by_name=False):
1429 def del_var(self, varname, by_name=False):
1430 """Delete a variable from the various namespaces, so that, as
1430 """Delete a variable from the various namespaces, so that, as
1431 far as possible, we're not keeping any hidden references to it.
1431 far as possible, we're not keeping any hidden references to it.
1432
1432
1433 Parameters
1433 Parameters
1434 ----------
1434 ----------
1435 varname : str
1435 varname : str
1436 The name of the variable to delete.
1436 The name of the variable to delete.
1437 by_name : bool
1437 by_name : bool
1438 If True, delete variables with the given name in each
1438 If True, delete variables with the given name in each
1439 namespace. If False (default), find the variable in the user
1439 namespace. If False (default), find the variable in the user
1440 namespace, and delete references to it.
1440 namespace, and delete references to it.
1441 """
1441 """
1442 if varname in ('__builtin__', '__builtins__'):
1442 if varname in ('__builtin__', '__builtins__'):
1443 raise ValueError("Refusing to delete %s" % varname)
1443 raise ValueError("Refusing to delete %s" % varname)
1444
1444
1445 ns_refs = self.all_ns_refs
1445 ns_refs = self.all_ns_refs
1446
1446
1447 if by_name: # Delete by name
1447 if by_name: # Delete by name
1448 for ns in ns_refs:
1448 for ns in ns_refs:
1449 try:
1449 try:
1450 del ns[varname]
1450 del ns[varname]
1451 except KeyError:
1451 except KeyError:
1452 pass
1452 pass
1453 else: # Delete by object
1453 else: # Delete by object
1454 try:
1454 try:
1455 obj = self.user_ns[varname]
1455 obj = self.user_ns[varname]
1456 except KeyError as e:
1456 except KeyError as e:
1457 raise NameError("name '%s' is not defined" % varname) from e
1457 raise NameError("name '%s' is not defined" % varname) from e
1458 # Also check in output history
1458 # Also check in output history
1459 ns_refs.append(self.history_manager.output_hist)
1459 ns_refs.append(self.history_manager.output_hist)
1460 for ns in ns_refs:
1460 for ns in ns_refs:
1461 to_delete = [n for n, o in ns.items() if o is obj]
1461 to_delete = [n for n, o in ns.items() if o is obj]
1462 for name in to_delete:
1462 for name in to_delete:
1463 del ns[name]
1463 del ns[name]
1464
1464
1465 # Ensure it is removed from the last execution result
1465 # Ensure it is removed from the last execution result
1466 if self.last_execution_result.result is obj:
1466 if self.last_execution_result.result is obj:
1467 self.last_execution_result = None
1467 self.last_execution_result = None
1468
1468
1469 # displayhook keeps extra references, but not in a dictionary
1469 # displayhook keeps extra references, but not in a dictionary
1470 for name in ('_', '__', '___'):
1470 for name in ('_', '__', '___'):
1471 if getattr(self.displayhook, name) is obj:
1471 if getattr(self.displayhook, name) is obj:
1472 setattr(self.displayhook, name, None)
1472 setattr(self.displayhook, name, None)
1473
1473
1474 def reset_selective(self, regex=None):
1474 def reset_selective(self, regex=None):
1475 """Clear selective variables from internal namespaces based on a
1475 """Clear selective variables from internal namespaces based on a
1476 specified regular expression.
1476 specified regular expression.
1477
1477
1478 Parameters
1478 Parameters
1479 ----------
1479 ----------
1480 regex : string or compiled pattern, optional
1480 regex : string or compiled pattern, optional
1481 A regular expression pattern that will be used in searching
1481 A regular expression pattern that will be used in searching
1482 variable names in the users namespaces.
1482 variable names in the users namespaces.
1483 """
1483 """
1484 if regex is not None:
1484 if regex is not None:
1485 try:
1485 try:
1486 m = re.compile(regex)
1486 m = re.compile(regex)
1487 except TypeError as e:
1487 except TypeError as e:
1488 raise TypeError('regex must be a string or compiled pattern') from e
1488 raise TypeError('regex must be a string or compiled pattern') from e
1489 # Search for keys in each namespace that match the given regex
1489 # Search for keys in each namespace that match the given regex
1490 # If a match is found, delete the key/value pair.
1490 # If a match is found, delete the key/value pair.
1491 for ns in self.all_ns_refs:
1491 for ns in self.all_ns_refs:
1492 for var in ns:
1492 for var in ns:
1493 if m.search(var):
1493 if m.search(var):
1494 del ns[var]
1494 del ns[var]
1495
1495
1496 def push(self, variables, interactive=True):
1496 def push(self, variables, interactive=True):
1497 """Inject a group of variables into the IPython user namespace.
1497 """Inject a group of variables into the IPython user namespace.
1498
1498
1499 Parameters
1499 Parameters
1500 ----------
1500 ----------
1501 variables : dict, str or list/tuple of str
1501 variables : dict, str or list/tuple of str
1502 The variables to inject into the user's namespace. If a dict, a
1502 The variables to inject into the user's namespace. If a dict, a
1503 simple update is done. If a str, the string is assumed to have
1503 simple update is done. If a str, the string is assumed to have
1504 variable names separated by spaces. A list/tuple of str can also
1504 variable names separated by spaces. A list/tuple of str can also
1505 be used to give the variable names. If just the variable names are
1505 be used to give the variable names. If just the variable names are
1506 give (list/tuple/str) then the variable values looked up in the
1506 give (list/tuple/str) then the variable values looked up in the
1507 callers frame.
1507 callers frame.
1508 interactive : bool
1508 interactive : bool
1509 If True (default), the variables will be listed with the ``who``
1509 If True (default), the variables will be listed with the ``who``
1510 magic.
1510 magic.
1511 """
1511 """
1512 vdict = None
1512 vdict = None
1513
1513
1514 # We need a dict of name/value pairs to do namespace updates.
1514 # We need a dict of name/value pairs to do namespace updates.
1515 if isinstance(variables, dict):
1515 if isinstance(variables, dict):
1516 vdict = variables
1516 vdict = variables
1517 elif isinstance(variables, (str, list, tuple)):
1517 elif isinstance(variables, (str, list, tuple)):
1518 if isinstance(variables, str):
1518 if isinstance(variables, str):
1519 vlist = variables.split()
1519 vlist = variables.split()
1520 else:
1520 else:
1521 vlist = variables
1521 vlist = variables
1522 vdict = {}
1522 vdict = {}
1523 cf = sys._getframe(1)
1523 cf = sys._getframe(1)
1524 for name in vlist:
1524 for name in vlist:
1525 try:
1525 try:
1526 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1526 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1527 except:
1527 except:
1528 print('Could not get variable %s from %s' %
1528 print('Could not get variable %s from %s' %
1529 (name,cf.f_code.co_name))
1529 (name,cf.f_code.co_name))
1530 else:
1530 else:
1531 raise ValueError('variables must be a dict/str/list/tuple')
1531 raise ValueError('variables must be a dict/str/list/tuple')
1532
1532
1533 # Propagate variables to user namespace
1533 # Propagate variables to user namespace
1534 self.user_ns.update(vdict)
1534 self.user_ns.update(vdict)
1535
1535
1536 # And configure interactive visibility
1536 # And configure interactive visibility
1537 user_ns_hidden = self.user_ns_hidden
1537 user_ns_hidden = self.user_ns_hidden
1538 if interactive:
1538 if interactive:
1539 for name in vdict:
1539 for name in vdict:
1540 user_ns_hidden.pop(name, None)
1540 user_ns_hidden.pop(name, None)
1541 else:
1541 else:
1542 user_ns_hidden.update(vdict)
1542 user_ns_hidden.update(vdict)
1543
1543
1544 def drop_by_id(self, variables):
1544 def drop_by_id(self, variables):
1545 """Remove a dict of variables from the user namespace, if they are the
1545 """Remove a dict of variables from the user namespace, if they are the
1546 same as the values in the dictionary.
1546 same as the values in the dictionary.
1547
1547
1548 This is intended for use by extensions: variables that they've added can
1548 This is intended for use by extensions: variables that they've added can
1549 be taken back out if they are unloaded, without removing any that the
1549 be taken back out if they are unloaded, without removing any that the
1550 user has overwritten.
1550 user has overwritten.
1551
1551
1552 Parameters
1552 Parameters
1553 ----------
1553 ----------
1554 variables : dict
1554 variables : dict
1555 A dictionary mapping object names (as strings) to the objects.
1555 A dictionary mapping object names (as strings) to the objects.
1556 """
1556 """
1557 for name, obj in variables.items():
1557 for name, obj in variables.items():
1558 if name in self.user_ns and self.user_ns[name] is obj:
1558 if name in self.user_ns and self.user_ns[name] is obj:
1559 del self.user_ns[name]
1559 del self.user_ns[name]
1560 self.user_ns_hidden.pop(name, None)
1560 self.user_ns_hidden.pop(name, None)
1561
1561
1562 #-------------------------------------------------------------------------
1562 #-------------------------------------------------------------------------
1563 # Things related to object introspection
1563 # Things related to object introspection
1564 #-------------------------------------------------------------------------
1564 #-------------------------------------------------------------------------
1565 @staticmethod
1565 @staticmethod
1566 def _find_parts(oname: str) -> ListType[str]:
1566 def _find_parts(oname: str) -> Tuple[bool, ListType[str]]:
1567 """
1567 """
1568 Given an object name, return a list of parts of this object name.
1568 Given an object name, return a list of parts of this object name.
1569
1569
1570 Basically split on docs when using attribute access,
1570 Basically split on docs when using attribute access,
1571 and extract the value when using square bracket.
1571 and extract the value when using square bracket.
1572
1572
1573
1573
1574 For example foo.bar[3].baz[x] -> foo, bar, 3, baz, x
1574 For example foo.bar[3].baz[x] -> foo, bar, 3, baz, x
1575
1575
1576
1576
1577 Returns
1577 Returns
1578 -------
1578 -------
1579 parts_ok: bool
1579 parts_ok: bool
1580 wether we were properly able to parse parts.
1580 wether we were properly able to parse parts.
1581 parts: list of str
1581 parts: list of str
1582 extracted parts
1582 extracted parts
1583
1583
1584
1584
1585
1585
1586 """
1586 """
1587 raw_parts = oname.split(".")
1587 raw_parts = oname.split(".")
1588 parts = []
1588 parts = []
1589 parts_ok = True
1589 parts_ok = True
1590 for p in raw_parts:
1590 for p in raw_parts:
1591 if p.endswith("]"):
1591 if p.endswith("]"):
1592 var, *indices = p.split("[")
1592 var, *indices = p.split("[")
1593 if not var.isidentifier():
1593 if not var.isidentifier():
1594 parts_ok = False
1594 parts_ok = False
1595 break
1595 break
1596 parts.append(var)
1596 parts.append(var)
1597 for ind in indices:
1597 for ind in indices:
1598 if ind[-1] != "]" and not is_integer_string(ind[:-1]):
1598 if ind[-1] != "]" and not is_integer_string(ind[:-1]):
1599 parts_ok = False
1599 parts_ok = False
1600 break
1600 break
1601 parts.append(ind[:-1])
1601 parts.append(ind[:-1])
1602 continue
1602 continue
1603
1603
1604 if not p.isidentifier():
1604 if not p.isidentifier():
1605 parts_ok = False
1605 parts_ok = False
1606 parts.append(p)
1606 parts.append(p)
1607
1607
1608 return parts_ok, parts
1608 return parts_ok, parts
1609
1609
1610 def _ofind(self, oname: str, namespaces: DictType[str, AnyType] = None):
1610 def _ofind(
1611 self, oname: str, namespaces: Optional[Sequence[Tuple[str, AnyType]]] = None
1612 ):
1611 """Find an object in the available namespaces.
1613 """Find an object in the available namespaces.
1612
1614
1613 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1615 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1614
1616
1615 Has special code to detect magic functions.
1617 Has special code to detect magic functions.
1616 """
1618 """
1617 oname = oname.strip()
1619 oname = oname.strip()
1618 parts_ok, parts = self._find_parts(oname)
1620 parts_ok, parts = self._find_parts(oname)
1619
1621
1620 if (
1622 if (
1621 not oname.startswith(ESC_MAGIC)
1623 not oname.startswith(ESC_MAGIC)
1622 and not oname.startswith(ESC_MAGIC2)
1624 and not oname.startswith(ESC_MAGIC2)
1623 and not parts_ok
1625 and not parts_ok
1624 ):
1626 ):
1625 return OInfo(
1627 return OInfo(
1626 ismagic=False,
1628 ismagic=False,
1627 isalias=False,
1629 isalias=False,
1628 found=False,
1630 found=False,
1629 obj=None,
1631 obj=None,
1630 namespace="",
1632 namespace=None,
1631 parent=None,
1633 parent=None,
1632 )
1634 )
1633
1635
1634 if namespaces is None:
1636 if namespaces is None:
1635 # Namespaces to search in:
1637 # Namespaces to search in:
1636 # Put them in a list. The order is important so that we
1638 # Put them in a list. The order is important so that we
1637 # find things in the same order that Python finds them.
1639 # find things in the same order that Python finds them.
1638 namespaces = [ ('Interactive', self.user_ns),
1640 namespaces = [ ('Interactive', self.user_ns),
1639 ('Interactive (global)', self.user_global_ns),
1641 ('Interactive (global)', self.user_global_ns),
1640 ('Python builtin', builtin_mod.__dict__),
1642 ('Python builtin', builtin_mod.__dict__),
1641 ]
1643 ]
1642
1644
1643 ismagic = False
1645 ismagic = False
1644 isalias = False
1646 isalias = False
1645 found = False
1647 found = False
1646 ospace = None
1648 ospace = None
1647 parent = None
1649 parent = None
1648 obj = None
1650 obj = None
1649
1651
1650
1652
1651 # Look for the given name by splitting it in parts. If the head is
1653 # Look for the given name by splitting it in parts. If the head is
1652 # found, then we look for all the remaining parts as members, and only
1654 # found, then we look for all the remaining parts as members, and only
1653 # declare success if we can find them all.
1655 # declare success if we can find them all.
1654 oname_parts = parts
1656 oname_parts = parts
1655 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1657 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1656 for nsname,ns in namespaces:
1658 for nsname,ns in namespaces:
1657 try:
1659 try:
1658 obj = ns[oname_head]
1660 obj = ns[oname_head]
1659 except KeyError:
1661 except KeyError:
1660 continue
1662 continue
1661 else:
1663 else:
1662 for idx, part in enumerate(oname_rest):
1664 for idx, part in enumerate(oname_rest):
1663 try:
1665 try:
1664 parent = obj
1666 parent = obj
1665 # The last part is looked up in a special way to avoid
1667 # The last part is looked up in a special way to avoid
1666 # descriptor invocation as it may raise or have side
1668 # descriptor invocation as it may raise or have side
1667 # effects.
1669 # effects.
1668 if idx == len(oname_rest) - 1:
1670 if idx == len(oname_rest) - 1:
1669 obj = self._getattr_property(obj, part)
1671 obj = self._getattr_property(obj, part)
1670 else:
1672 else:
1671 if is_integer_string(part):
1673 if is_integer_string(part):
1672 obj = obj[int(part)]
1674 obj = obj[int(part)]
1673 else:
1675 else:
1674 obj = getattr(obj, part)
1676 obj = getattr(obj, part)
1675 except:
1677 except:
1676 # Blanket except b/c some badly implemented objects
1678 # Blanket except b/c some badly implemented objects
1677 # allow __getattr__ to raise exceptions other than
1679 # allow __getattr__ to raise exceptions other than
1678 # AttributeError, which then crashes IPython.
1680 # AttributeError, which then crashes IPython.
1679 break
1681 break
1680 else:
1682 else:
1681 # If we finish the for loop (no break), we got all members
1683 # If we finish the for loop (no break), we got all members
1682 found = True
1684 found = True
1683 ospace = nsname
1685 ospace = nsname
1684 break # namespace loop
1686 break # namespace loop
1685
1687
1686 # Try to see if it's magic
1688 # Try to see if it's magic
1687 if not found:
1689 if not found:
1688 obj = None
1690 obj = None
1689 if oname.startswith(ESC_MAGIC2):
1691 if oname.startswith(ESC_MAGIC2):
1690 oname = oname.lstrip(ESC_MAGIC2)
1692 oname = oname.lstrip(ESC_MAGIC2)
1691 obj = self.find_cell_magic(oname)
1693 obj = self.find_cell_magic(oname)
1692 elif oname.startswith(ESC_MAGIC):
1694 elif oname.startswith(ESC_MAGIC):
1693 oname = oname.lstrip(ESC_MAGIC)
1695 oname = oname.lstrip(ESC_MAGIC)
1694 obj = self.find_line_magic(oname)
1696 obj = self.find_line_magic(oname)
1695 else:
1697 else:
1696 # search without prefix, so run? will find %run?
1698 # search without prefix, so run? will find %run?
1697 obj = self.find_line_magic(oname)
1699 obj = self.find_line_magic(oname)
1698 if obj is None:
1700 if obj is None:
1699 obj = self.find_cell_magic(oname)
1701 obj = self.find_cell_magic(oname)
1700 if obj is not None:
1702 if obj is not None:
1701 found = True
1703 found = True
1702 ospace = 'IPython internal'
1704 ospace = 'IPython internal'
1703 ismagic = True
1705 ismagic = True
1704 isalias = isinstance(obj, Alias)
1706 isalias = isinstance(obj, Alias)
1705
1707
1706 # Last try: special-case some literals like '', [], {}, etc:
1708 # Last try: special-case some literals like '', [], {}, etc:
1707 if not found and oname_head in ["''",'""','[]','{}','()']:
1709 if not found and oname_head in ["''",'""','[]','{}','()']:
1708 obj = eval(oname_head)
1710 obj = eval(oname_head)
1709 found = True
1711 found = True
1710 ospace = 'Interactive'
1712 ospace = 'Interactive'
1711
1713
1712 return OInfo(
1714 return OInfo(
1713 **{
1715 obj=obj,
1714 "obj": obj,
1716 found=found,
1715 "found": found,
1717 parent=parent,
1716 "parent": parent,
1718 ismagic=ismagic,
1717 "ismagic": ismagic,
1719 isalias=isalias,
1718 "isalias": isalias,
1720 namespace=ospace,
1719 "namespace": ospace,
1720 }
1721 )
1721 )
1722
1722
1723 @staticmethod
1723 @staticmethod
1724 def _getattr_property(obj, attrname):
1724 def _getattr_property(obj, attrname):
1725 """Property-aware getattr to use in object finding.
1725 """Property-aware getattr to use in object finding.
1726
1726
1727 If attrname represents a property, return it unevaluated (in case it has
1727 If attrname represents a property, return it unevaluated (in case it has
1728 side effects or raises an error.
1728 side effects or raises an error.
1729
1729
1730 """
1730 """
1731 if not isinstance(obj, type):
1731 if not isinstance(obj, type):
1732 try:
1732 try:
1733 # `getattr(type(obj), attrname)` is not guaranteed to return
1733 # `getattr(type(obj), attrname)` is not guaranteed to return
1734 # `obj`, but does so for property:
1734 # `obj`, but does so for property:
1735 #
1735 #
1736 # property.__get__(self, None, cls) -> self
1736 # property.__get__(self, None, cls) -> self
1737 #
1737 #
1738 # The universal alternative is to traverse the mro manually
1738 # The universal alternative is to traverse the mro manually
1739 # searching for attrname in class dicts.
1739 # searching for attrname in class dicts.
1740 if is_integer_string(attrname):
1740 if is_integer_string(attrname):
1741 return obj[int(attrname)]
1741 return obj[int(attrname)]
1742 else:
1742 else:
1743 attr = getattr(type(obj), attrname)
1743 attr = getattr(type(obj), attrname)
1744 except AttributeError:
1744 except AttributeError:
1745 pass
1745 pass
1746 else:
1746 else:
1747 # This relies on the fact that data descriptors (with both
1747 # This relies on the fact that data descriptors (with both
1748 # __get__ & __set__ magic methods) take precedence over
1748 # __get__ & __set__ magic methods) take precedence over
1749 # instance-level attributes:
1749 # instance-level attributes:
1750 #
1750 #
1751 # class A(object):
1751 # class A(object):
1752 # @property
1752 # @property
1753 # def foobar(self): return 123
1753 # def foobar(self): return 123
1754 # a = A()
1754 # a = A()
1755 # a.__dict__['foobar'] = 345
1755 # a.__dict__['foobar'] = 345
1756 # a.foobar # == 123
1756 # a.foobar # == 123
1757 #
1757 #
1758 # So, a property may be returned right away.
1758 # So, a property may be returned right away.
1759 if isinstance(attr, property):
1759 if isinstance(attr, property):
1760 return attr
1760 return attr
1761
1761
1762 # Nothing helped, fall back.
1762 # Nothing helped, fall back.
1763 return getattr(obj, attrname)
1763 return getattr(obj, attrname)
1764
1764
1765 def _object_find(self, oname, namespaces=None) -> OInfo:
1765 def _object_find(self, oname, namespaces=None) -> OInfo:
1766 """Find an object and return a struct with info about it."""
1766 """Find an object and return a struct with info about it."""
1767 return self._ofind(oname, namespaces)
1767 return self._ofind(oname, namespaces)
1768
1768
1769 def _inspect(self, meth, oname, namespaces=None, **kw):
1769 def _inspect(self, meth, oname, namespaces=None, **kw):
1770 """Generic interface to the inspector system.
1770 """Generic interface to the inspector system.
1771
1771
1772 This function is meant to be called by pdef, pdoc & friends.
1772 This function is meant to be called by pdef, pdoc & friends.
1773 """
1773 """
1774 info = self._object_find(oname, namespaces)
1774 info = self._object_find(oname, namespaces)
1775 docformat = (
1775 docformat = (
1776 sphinxify(self.object_inspect(oname)) if self.sphinxify_docstring else None
1776 sphinxify(self.object_inspect(oname)) if self.sphinxify_docstring else None
1777 )
1777 )
1778 if info.found:
1778 if info.found:
1779 pmethod = getattr(self.inspector, meth)
1779 pmethod = getattr(self.inspector, meth)
1780 # TODO: only apply format_screen to the plain/text repr of the mime
1780 # TODO: only apply format_screen to the plain/text repr of the mime
1781 # bundle.
1781 # bundle.
1782 formatter = format_screen if info.ismagic else docformat
1782 formatter = format_screen if info.ismagic else docformat
1783 if meth == 'pdoc':
1783 if meth == 'pdoc':
1784 pmethod(info.obj, oname, formatter)
1784 pmethod(info.obj, oname, formatter)
1785 elif meth == 'pinfo':
1785 elif meth == 'pinfo':
1786 pmethod(
1786 pmethod(
1787 info.obj,
1787 info.obj,
1788 oname,
1788 oname,
1789 formatter,
1789 formatter,
1790 info,
1790 info,
1791 enable_html_pager=self.enable_html_pager,
1791 enable_html_pager=self.enable_html_pager,
1792 **kw,
1792 **kw,
1793 )
1793 )
1794 else:
1794 else:
1795 pmethod(info.obj, oname)
1795 pmethod(info.obj, oname)
1796 else:
1796 else:
1797 print('Object `%s` not found.' % oname)
1797 print('Object `%s` not found.' % oname)
1798 return 'not found' # so callers can take other action
1798 return 'not found' # so callers can take other action
1799
1799
1800 def object_inspect(self, oname, detail_level=0):
1800 def object_inspect(self, oname, detail_level=0):
1801 """Get object info about oname"""
1801 """Get object info about oname"""
1802 with self.builtin_trap:
1802 with self.builtin_trap:
1803 info = self._object_find(oname)
1803 info = self._object_find(oname)
1804 if info.found:
1804 if info.found:
1805 return self.inspector.info(info.obj, oname, info=info,
1805 return self.inspector.info(info.obj, oname, info=info,
1806 detail_level=detail_level
1806 detail_level=detail_level
1807 )
1807 )
1808 else:
1808 else:
1809 return oinspect.object_info(name=oname, found=False)
1809 return oinspect.object_info(name=oname, found=False)
1810
1810
1811 def object_inspect_text(self, oname, detail_level=0):
1811 def object_inspect_text(self, oname, detail_level=0):
1812 """Get object info as formatted text"""
1812 """Get object info as formatted text"""
1813 return self.object_inspect_mime(oname, detail_level)['text/plain']
1813 return self.object_inspect_mime(oname, detail_level)['text/plain']
1814
1814
1815 def object_inspect_mime(self, oname, detail_level=0, omit_sections=()):
1815 def object_inspect_mime(self, oname, detail_level=0, omit_sections=()):
1816 """Get object info as a mimebundle of formatted representations.
1816 """Get object info as a mimebundle of formatted representations.
1817
1817
1818 A mimebundle is a dictionary, keyed by mime-type.
1818 A mimebundle is a dictionary, keyed by mime-type.
1819 It must always have the key `'text/plain'`.
1819 It must always have the key `'text/plain'`.
1820 """
1820 """
1821 with self.builtin_trap:
1821 with self.builtin_trap:
1822 info = self._object_find(oname)
1822 info = self._object_find(oname)
1823 if info.found:
1823 if info.found:
1824 docformat = (
1824 docformat = (
1825 sphinxify(self.object_inspect(oname))
1825 sphinxify(self.object_inspect(oname))
1826 if self.sphinxify_docstring
1826 if self.sphinxify_docstring
1827 else None
1827 else None
1828 )
1828 )
1829 return self.inspector._get_info(
1829 return self.inspector._get_info(
1830 info.obj,
1830 info.obj,
1831 oname,
1831 oname,
1832 info=info,
1832 info=info,
1833 detail_level=detail_level,
1833 detail_level=detail_level,
1834 formatter=docformat,
1834 formatter=docformat,
1835 omit_sections=omit_sections,
1835 omit_sections=omit_sections,
1836 )
1836 )
1837 else:
1837 else:
1838 raise KeyError(oname)
1838 raise KeyError(oname)
1839
1839
1840 #-------------------------------------------------------------------------
1840 #-------------------------------------------------------------------------
1841 # Things related to history management
1841 # Things related to history management
1842 #-------------------------------------------------------------------------
1842 #-------------------------------------------------------------------------
1843
1843
1844 def init_history(self):
1844 def init_history(self):
1845 """Sets up the command history, and starts regular autosaves."""
1845 """Sets up the command history, and starts regular autosaves."""
1846 self.history_manager = HistoryManager(shell=self, parent=self)
1846 self.history_manager = HistoryManager(shell=self, parent=self)
1847 self.configurables.append(self.history_manager)
1847 self.configurables.append(self.history_manager)
1848
1848
1849 #-------------------------------------------------------------------------
1849 #-------------------------------------------------------------------------
1850 # Things related to exception handling and tracebacks (not debugging)
1850 # Things related to exception handling and tracebacks (not debugging)
1851 #-------------------------------------------------------------------------
1851 #-------------------------------------------------------------------------
1852
1852
1853 debugger_cls = InterruptiblePdb
1853 debugger_cls = InterruptiblePdb
1854
1854
1855 def init_traceback_handlers(self, custom_exceptions):
1855 def init_traceback_handlers(self, custom_exceptions):
1856 # Syntax error handler.
1856 # Syntax error handler.
1857 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor', parent=self)
1857 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor', parent=self)
1858
1858
1859 # The interactive one is initialized with an offset, meaning we always
1859 # The interactive one is initialized with an offset, meaning we always
1860 # want to remove the topmost item in the traceback, which is our own
1860 # want to remove the topmost item in the traceback, which is our own
1861 # internal code. Valid modes: ['Plain','Context','Verbose','Minimal']
1861 # internal code. Valid modes: ['Plain','Context','Verbose','Minimal']
1862 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1862 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1863 color_scheme='NoColor',
1863 color_scheme='NoColor',
1864 tb_offset = 1,
1864 tb_offset = 1,
1865 debugger_cls=self.debugger_cls, parent=self)
1865 debugger_cls=self.debugger_cls, parent=self)
1866
1866
1867 # The instance will store a pointer to the system-wide exception hook,
1867 # The instance will store a pointer to the system-wide exception hook,
1868 # so that runtime code (such as magics) can access it. This is because
1868 # so that runtime code (such as magics) can access it. This is because
1869 # during the read-eval loop, it may get temporarily overwritten.
1869 # during the read-eval loop, it may get temporarily overwritten.
1870 self.sys_excepthook = sys.excepthook
1870 self.sys_excepthook = sys.excepthook
1871
1871
1872 # and add any custom exception handlers the user may have specified
1872 # and add any custom exception handlers the user may have specified
1873 self.set_custom_exc(*custom_exceptions)
1873 self.set_custom_exc(*custom_exceptions)
1874
1874
1875 # Set the exception mode
1875 # Set the exception mode
1876 self.InteractiveTB.set_mode(mode=self.xmode)
1876 self.InteractiveTB.set_mode(mode=self.xmode)
1877
1877
1878 def set_custom_exc(self, exc_tuple, handler):
1878 def set_custom_exc(self, exc_tuple, handler):
1879 """set_custom_exc(exc_tuple, handler)
1879 """set_custom_exc(exc_tuple, handler)
1880
1880
1881 Set a custom exception handler, which will be called if any of the
1881 Set a custom exception handler, which will be called if any of the
1882 exceptions in exc_tuple occur in the mainloop (specifically, in the
1882 exceptions in exc_tuple occur in the mainloop (specifically, in the
1883 run_code() method).
1883 run_code() method).
1884
1884
1885 Parameters
1885 Parameters
1886 ----------
1886 ----------
1887 exc_tuple : tuple of exception classes
1887 exc_tuple : tuple of exception classes
1888 A *tuple* of exception classes, for which to call the defined
1888 A *tuple* of exception classes, for which to call the defined
1889 handler. It is very important that you use a tuple, and NOT A
1889 handler. It is very important that you use a tuple, and NOT A
1890 LIST here, because of the way Python's except statement works. If
1890 LIST here, because of the way Python's except statement works. If
1891 you only want to trap a single exception, use a singleton tuple::
1891 you only want to trap a single exception, use a singleton tuple::
1892
1892
1893 exc_tuple == (MyCustomException,)
1893 exc_tuple == (MyCustomException,)
1894
1894
1895 handler : callable
1895 handler : callable
1896 handler must have the following signature::
1896 handler must have the following signature::
1897
1897
1898 def my_handler(self, etype, value, tb, tb_offset=None):
1898 def my_handler(self, etype, value, tb, tb_offset=None):
1899 ...
1899 ...
1900 return structured_traceback
1900 return structured_traceback
1901
1901
1902 Your handler must return a structured traceback (a list of strings),
1902 Your handler must return a structured traceback (a list of strings),
1903 or None.
1903 or None.
1904
1904
1905 This will be made into an instance method (via types.MethodType)
1905 This will be made into an instance method (via types.MethodType)
1906 of IPython itself, and it will be called if any of the exceptions
1906 of IPython itself, and it will be called if any of the exceptions
1907 listed in the exc_tuple are caught. If the handler is None, an
1907 listed in the exc_tuple are caught. If the handler is None, an
1908 internal basic one is used, which just prints basic info.
1908 internal basic one is used, which just prints basic info.
1909
1909
1910 To protect IPython from crashes, if your handler ever raises an
1910 To protect IPython from crashes, if your handler ever raises an
1911 exception or returns an invalid result, it will be immediately
1911 exception or returns an invalid result, it will be immediately
1912 disabled.
1912 disabled.
1913
1913
1914 Notes
1914 Notes
1915 -----
1915 -----
1916 WARNING: by putting in your own exception handler into IPython's main
1916 WARNING: by putting in your own exception handler into IPython's main
1917 execution loop, you run a very good chance of nasty crashes. This
1917 execution loop, you run a very good chance of nasty crashes. This
1918 facility should only be used if you really know what you are doing.
1918 facility should only be used if you really know what you are doing.
1919 """
1919 """
1920
1920
1921 if not isinstance(exc_tuple, tuple):
1921 if not isinstance(exc_tuple, tuple):
1922 raise TypeError("The custom exceptions must be given as a tuple.")
1922 raise TypeError("The custom exceptions must be given as a tuple.")
1923
1923
1924 def dummy_handler(self, etype, value, tb, tb_offset=None):
1924 def dummy_handler(self, etype, value, tb, tb_offset=None):
1925 print('*** Simple custom exception handler ***')
1925 print('*** Simple custom exception handler ***')
1926 print('Exception type :', etype)
1926 print('Exception type :', etype)
1927 print('Exception value:', value)
1927 print('Exception value:', value)
1928 print('Traceback :', tb)
1928 print('Traceback :', tb)
1929
1929
1930 def validate_stb(stb):
1930 def validate_stb(stb):
1931 """validate structured traceback return type
1931 """validate structured traceback return type
1932
1932
1933 return type of CustomTB *should* be a list of strings, but allow
1933 return type of CustomTB *should* be a list of strings, but allow
1934 single strings or None, which are harmless.
1934 single strings or None, which are harmless.
1935
1935
1936 This function will *always* return a list of strings,
1936 This function will *always* return a list of strings,
1937 and will raise a TypeError if stb is inappropriate.
1937 and will raise a TypeError if stb is inappropriate.
1938 """
1938 """
1939 msg = "CustomTB must return list of strings, not %r" % stb
1939 msg = "CustomTB must return list of strings, not %r" % stb
1940 if stb is None:
1940 if stb is None:
1941 return []
1941 return []
1942 elif isinstance(stb, str):
1942 elif isinstance(stb, str):
1943 return [stb]
1943 return [stb]
1944 elif not isinstance(stb, list):
1944 elif not isinstance(stb, list):
1945 raise TypeError(msg)
1945 raise TypeError(msg)
1946 # it's a list
1946 # it's a list
1947 for line in stb:
1947 for line in stb:
1948 # check every element
1948 # check every element
1949 if not isinstance(line, str):
1949 if not isinstance(line, str):
1950 raise TypeError(msg)
1950 raise TypeError(msg)
1951 return stb
1951 return stb
1952
1952
1953 if handler is None:
1953 if handler is None:
1954 wrapped = dummy_handler
1954 wrapped = dummy_handler
1955 else:
1955 else:
1956 def wrapped(self,etype,value,tb,tb_offset=None):
1956 def wrapped(self,etype,value,tb,tb_offset=None):
1957 """wrap CustomTB handler, to protect IPython from user code
1957 """wrap CustomTB handler, to protect IPython from user code
1958
1958
1959 This makes it harder (but not impossible) for custom exception
1959 This makes it harder (but not impossible) for custom exception
1960 handlers to crash IPython.
1960 handlers to crash IPython.
1961 """
1961 """
1962 try:
1962 try:
1963 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1963 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1964 return validate_stb(stb)
1964 return validate_stb(stb)
1965 except:
1965 except:
1966 # clear custom handler immediately
1966 # clear custom handler immediately
1967 self.set_custom_exc((), None)
1967 self.set_custom_exc((), None)
1968 print("Custom TB Handler failed, unregistering", file=sys.stderr)
1968 print("Custom TB Handler failed, unregistering", file=sys.stderr)
1969 # show the exception in handler first
1969 # show the exception in handler first
1970 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1970 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1971 print(self.InteractiveTB.stb2text(stb))
1971 print(self.InteractiveTB.stb2text(stb))
1972 print("The original exception:")
1972 print("The original exception:")
1973 stb = self.InteractiveTB.structured_traceback(
1973 stb = self.InteractiveTB.structured_traceback(
1974 (etype,value,tb), tb_offset=tb_offset
1974 (etype,value,tb), tb_offset=tb_offset
1975 )
1975 )
1976 return stb
1976 return stb
1977
1977
1978 self.CustomTB = types.MethodType(wrapped,self)
1978 self.CustomTB = types.MethodType(wrapped,self)
1979 self.custom_exceptions = exc_tuple
1979 self.custom_exceptions = exc_tuple
1980
1980
1981 def excepthook(self, etype, value, tb):
1981 def excepthook(self, etype, value, tb):
1982 """One more defense for GUI apps that call sys.excepthook.
1982 """One more defense for GUI apps that call sys.excepthook.
1983
1983
1984 GUI frameworks like wxPython trap exceptions and call
1984 GUI frameworks like wxPython trap exceptions and call
1985 sys.excepthook themselves. I guess this is a feature that
1985 sys.excepthook themselves. I guess this is a feature that
1986 enables them to keep running after exceptions that would
1986 enables them to keep running after exceptions that would
1987 otherwise kill their mainloop. This is a bother for IPython
1987 otherwise kill their mainloop. This is a bother for IPython
1988 which expects to catch all of the program exceptions with a try:
1988 which expects to catch all of the program exceptions with a try:
1989 except: statement.
1989 except: statement.
1990
1990
1991 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1991 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1992 any app directly invokes sys.excepthook, it will look to the user like
1992 any app directly invokes sys.excepthook, it will look to the user like
1993 IPython crashed. In order to work around this, we can disable the
1993 IPython crashed. In order to work around this, we can disable the
1994 CrashHandler and replace it with this excepthook instead, which prints a
1994 CrashHandler and replace it with this excepthook instead, which prints a
1995 regular traceback using our InteractiveTB. In this fashion, apps which
1995 regular traceback using our InteractiveTB. In this fashion, apps which
1996 call sys.excepthook will generate a regular-looking exception from
1996 call sys.excepthook will generate a regular-looking exception from
1997 IPython, and the CrashHandler will only be triggered by real IPython
1997 IPython, and the CrashHandler will only be triggered by real IPython
1998 crashes.
1998 crashes.
1999
1999
2000 This hook should be used sparingly, only in places which are not likely
2000 This hook should be used sparingly, only in places which are not likely
2001 to be true IPython errors.
2001 to be true IPython errors.
2002 """
2002 """
2003 self.showtraceback((etype, value, tb), tb_offset=0)
2003 self.showtraceback((etype, value, tb), tb_offset=0)
2004
2004
2005 def _get_exc_info(self, exc_tuple=None):
2005 def _get_exc_info(self, exc_tuple=None):
2006 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
2006 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
2007
2007
2008 Ensures sys.last_type,value,traceback hold the exc_info we found,
2008 Ensures sys.last_type,value,traceback hold the exc_info we found,
2009 from whichever source.
2009 from whichever source.
2010
2010
2011 raises ValueError if none of these contain any information
2011 raises ValueError if none of these contain any information
2012 """
2012 """
2013 if exc_tuple is None:
2013 if exc_tuple is None:
2014 etype, value, tb = sys.exc_info()
2014 etype, value, tb = sys.exc_info()
2015 else:
2015 else:
2016 etype, value, tb = exc_tuple
2016 etype, value, tb = exc_tuple
2017
2017
2018 if etype is None:
2018 if etype is None:
2019 if hasattr(sys, 'last_type'):
2019 if hasattr(sys, 'last_type'):
2020 etype, value, tb = sys.last_type, sys.last_value, \
2020 etype, value, tb = sys.last_type, sys.last_value, \
2021 sys.last_traceback
2021 sys.last_traceback
2022
2022
2023 if etype is None:
2023 if etype is None:
2024 raise ValueError("No exception to find")
2024 raise ValueError("No exception to find")
2025
2025
2026 # Now store the exception info in sys.last_type etc.
2026 # Now store the exception info in sys.last_type etc.
2027 # WARNING: these variables are somewhat deprecated and not
2027 # WARNING: these variables are somewhat deprecated and not
2028 # necessarily safe to use in a threaded environment, but tools
2028 # necessarily safe to use in a threaded environment, but tools
2029 # like pdb depend on their existence, so let's set them. If we
2029 # like pdb depend on their existence, so let's set them. If we
2030 # find problems in the field, we'll need to revisit their use.
2030 # find problems in the field, we'll need to revisit their use.
2031 sys.last_type = etype
2031 sys.last_type = etype
2032 sys.last_value = value
2032 sys.last_value = value
2033 sys.last_traceback = tb
2033 sys.last_traceback = tb
2034
2034
2035 return etype, value, tb
2035 return etype, value, tb
2036
2036
2037 def show_usage_error(self, exc):
2037 def show_usage_error(self, exc):
2038 """Show a short message for UsageErrors
2038 """Show a short message for UsageErrors
2039
2039
2040 These are special exceptions that shouldn't show a traceback.
2040 These are special exceptions that shouldn't show a traceback.
2041 """
2041 """
2042 print("UsageError: %s" % exc, file=sys.stderr)
2042 print("UsageError: %s" % exc, file=sys.stderr)
2043
2043
2044 def get_exception_only(self, exc_tuple=None):
2044 def get_exception_only(self, exc_tuple=None):
2045 """
2045 """
2046 Return as a string (ending with a newline) the exception that
2046 Return as a string (ending with a newline) the exception that
2047 just occurred, without any traceback.
2047 just occurred, without any traceback.
2048 """
2048 """
2049 etype, value, tb = self._get_exc_info(exc_tuple)
2049 etype, value, tb = self._get_exc_info(exc_tuple)
2050 msg = traceback.format_exception_only(etype, value)
2050 msg = traceback.format_exception_only(etype, value)
2051 return ''.join(msg)
2051 return ''.join(msg)
2052
2052
2053 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
2053 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
2054 exception_only=False, running_compiled_code=False):
2054 exception_only=False, running_compiled_code=False):
2055 """Display the exception that just occurred.
2055 """Display the exception that just occurred.
2056
2056
2057 If nothing is known about the exception, this is the method which
2057 If nothing is known about the exception, this is the method which
2058 should be used throughout the code for presenting user tracebacks,
2058 should be used throughout the code for presenting user tracebacks,
2059 rather than directly invoking the InteractiveTB object.
2059 rather than directly invoking the InteractiveTB object.
2060
2060
2061 A specific showsyntaxerror() also exists, but this method can take
2061 A specific showsyntaxerror() also exists, but this method can take
2062 care of calling it if needed, so unless you are explicitly catching a
2062 care of calling it if needed, so unless you are explicitly catching a
2063 SyntaxError exception, don't try to analyze the stack manually and
2063 SyntaxError exception, don't try to analyze the stack manually and
2064 simply call this method."""
2064 simply call this method."""
2065
2065
2066 try:
2066 try:
2067 try:
2067 try:
2068 etype, value, tb = self._get_exc_info(exc_tuple)
2068 etype, value, tb = self._get_exc_info(exc_tuple)
2069 except ValueError:
2069 except ValueError:
2070 print('No traceback available to show.', file=sys.stderr)
2070 print('No traceback available to show.', file=sys.stderr)
2071 return
2071 return
2072
2072
2073 if issubclass(etype, SyntaxError):
2073 if issubclass(etype, SyntaxError):
2074 # Though this won't be called by syntax errors in the input
2074 # Though this won't be called by syntax errors in the input
2075 # line, there may be SyntaxError cases with imported code.
2075 # line, there may be SyntaxError cases with imported code.
2076 self.showsyntaxerror(filename, running_compiled_code)
2076 self.showsyntaxerror(filename, running_compiled_code)
2077 elif etype is UsageError:
2077 elif etype is UsageError:
2078 self.show_usage_error(value)
2078 self.show_usage_error(value)
2079 else:
2079 else:
2080 if exception_only:
2080 if exception_only:
2081 stb = ['An exception has occurred, use %tb to see '
2081 stb = ['An exception has occurred, use %tb to see '
2082 'the full traceback.\n']
2082 'the full traceback.\n']
2083 stb.extend(self.InteractiveTB.get_exception_only(etype,
2083 stb.extend(self.InteractiveTB.get_exception_only(etype,
2084 value))
2084 value))
2085 else:
2085 else:
2086 try:
2086 try:
2087 # Exception classes can customise their traceback - we
2087 # Exception classes can customise their traceback - we
2088 # use this in IPython.parallel for exceptions occurring
2088 # use this in IPython.parallel for exceptions occurring
2089 # in the engines. This should return a list of strings.
2089 # in the engines. This should return a list of strings.
2090 if hasattr(value, "_render_traceback_"):
2090 if hasattr(value, "_render_traceback_"):
2091 stb = value._render_traceback_()
2091 stb = value._render_traceback_()
2092 else:
2092 else:
2093 stb = self.InteractiveTB.structured_traceback(
2093 stb = self.InteractiveTB.structured_traceback(
2094 etype, value, tb, tb_offset=tb_offset
2094 etype, value, tb, tb_offset=tb_offset
2095 )
2095 )
2096
2096
2097 except Exception:
2097 except Exception:
2098 print(
2098 print(
2099 "Unexpected exception formatting exception. Falling back to standard exception"
2099 "Unexpected exception formatting exception. Falling back to standard exception"
2100 )
2100 )
2101 traceback.print_exc()
2101 traceback.print_exc()
2102 return None
2102 return None
2103
2103
2104 self._showtraceback(etype, value, stb)
2104 self._showtraceback(etype, value, stb)
2105 if self.call_pdb:
2105 if self.call_pdb:
2106 # drop into debugger
2106 # drop into debugger
2107 self.debugger(force=True)
2107 self.debugger(force=True)
2108 return
2108 return
2109
2109
2110 # Actually show the traceback
2110 # Actually show the traceback
2111 self._showtraceback(etype, value, stb)
2111 self._showtraceback(etype, value, stb)
2112
2112
2113 except KeyboardInterrupt:
2113 except KeyboardInterrupt:
2114 print('\n' + self.get_exception_only(), file=sys.stderr)
2114 print('\n' + self.get_exception_only(), file=sys.stderr)
2115
2115
2116 def _showtraceback(self, etype, evalue, stb: str):
2116 def _showtraceback(self, etype, evalue, stb: str):
2117 """Actually show a traceback.
2117 """Actually show a traceback.
2118
2118
2119 Subclasses may override this method to put the traceback on a different
2119 Subclasses may override this method to put the traceback on a different
2120 place, like a side channel.
2120 place, like a side channel.
2121 """
2121 """
2122 val = self.InteractiveTB.stb2text(stb)
2122 val = self.InteractiveTB.stb2text(stb)
2123 try:
2123 try:
2124 print(val)
2124 print(val)
2125 except UnicodeEncodeError:
2125 except UnicodeEncodeError:
2126 print(val.encode("utf-8", "backslashreplace").decode())
2126 print(val.encode("utf-8", "backslashreplace").decode())
2127
2127
2128 def showsyntaxerror(self, filename=None, running_compiled_code=False):
2128 def showsyntaxerror(self, filename=None, running_compiled_code=False):
2129 """Display the syntax error that just occurred.
2129 """Display the syntax error that just occurred.
2130
2130
2131 This doesn't display a stack trace because there isn't one.
2131 This doesn't display a stack trace because there isn't one.
2132
2132
2133 If a filename is given, it is stuffed in the exception instead
2133 If a filename is given, it is stuffed in the exception instead
2134 of what was there before (because Python's parser always uses
2134 of what was there before (because Python's parser always uses
2135 "<string>" when reading from a string).
2135 "<string>" when reading from a string).
2136
2136
2137 If the syntax error occurred when running a compiled code (i.e. running_compile_code=True),
2137 If the syntax error occurred when running a compiled code (i.e. running_compile_code=True),
2138 longer stack trace will be displayed.
2138 longer stack trace will be displayed.
2139 """
2139 """
2140 etype, value, last_traceback = self._get_exc_info()
2140 etype, value, last_traceback = self._get_exc_info()
2141
2141
2142 if filename and issubclass(etype, SyntaxError):
2142 if filename and issubclass(etype, SyntaxError):
2143 try:
2143 try:
2144 value.filename = filename
2144 value.filename = filename
2145 except:
2145 except:
2146 # Not the format we expect; leave it alone
2146 # Not the format we expect; leave it alone
2147 pass
2147 pass
2148
2148
2149 # If the error occurred when executing compiled code, we should provide full stacktrace.
2149 # If the error occurred when executing compiled code, we should provide full stacktrace.
2150 elist = traceback.extract_tb(last_traceback) if running_compiled_code else []
2150 elist = traceback.extract_tb(last_traceback) if running_compiled_code else []
2151 stb = self.SyntaxTB.structured_traceback(etype, value, elist)
2151 stb = self.SyntaxTB.structured_traceback(etype, value, elist)
2152 self._showtraceback(etype, value, stb)
2152 self._showtraceback(etype, value, stb)
2153
2153
2154 # This is overridden in TerminalInteractiveShell to show a message about
2154 # This is overridden in TerminalInteractiveShell to show a message about
2155 # the %paste magic.
2155 # the %paste magic.
2156 def showindentationerror(self):
2156 def showindentationerror(self):
2157 """Called by _run_cell when there's an IndentationError in code entered
2157 """Called by _run_cell when there's an IndentationError in code entered
2158 at the prompt.
2158 at the prompt.
2159
2159
2160 This is overridden in TerminalInteractiveShell to show a message about
2160 This is overridden in TerminalInteractiveShell to show a message about
2161 the %paste magic."""
2161 the %paste magic."""
2162 self.showsyntaxerror()
2162 self.showsyntaxerror()
2163
2163
2164 @skip_doctest
2164 @skip_doctest
2165 def set_next_input(self, s, replace=False):
2165 def set_next_input(self, s, replace=False):
2166 """ Sets the 'default' input string for the next command line.
2166 """ Sets the 'default' input string for the next command line.
2167
2167
2168 Example::
2168 Example::
2169
2169
2170 In [1]: _ip.set_next_input("Hello Word")
2170 In [1]: _ip.set_next_input("Hello Word")
2171 In [2]: Hello Word_ # cursor is here
2171 In [2]: Hello Word_ # cursor is here
2172 """
2172 """
2173 self.rl_next_input = s
2173 self.rl_next_input = s
2174
2174
2175 def _indent_current_str(self):
2175 def _indent_current_str(self):
2176 """return the current level of indentation as a string"""
2176 """return the current level of indentation as a string"""
2177 return self.input_splitter.get_indent_spaces() * ' '
2177 return self.input_splitter.get_indent_spaces() * ' '
2178
2178
2179 #-------------------------------------------------------------------------
2179 #-------------------------------------------------------------------------
2180 # Things related to text completion
2180 # Things related to text completion
2181 #-------------------------------------------------------------------------
2181 #-------------------------------------------------------------------------
2182
2182
2183 def init_completer(self):
2183 def init_completer(self):
2184 """Initialize the completion machinery.
2184 """Initialize the completion machinery.
2185
2185
2186 This creates completion machinery that can be used by client code,
2186 This creates completion machinery that can be used by client code,
2187 either interactively in-process (typically triggered by the readline
2187 either interactively in-process (typically triggered by the readline
2188 library), programmatically (such as in test suites) or out-of-process
2188 library), programmatically (such as in test suites) or out-of-process
2189 (typically over the network by remote frontends).
2189 (typically over the network by remote frontends).
2190 """
2190 """
2191 from IPython.core.completer import IPCompleter
2191 from IPython.core.completer import IPCompleter
2192 from IPython.core.completerlib import (
2192 from IPython.core.completerlib import (
2193 cd_completer,
2193 cd_completer,
2194 magic_run_completer,
2194 magic_run_completer,
2195 module_completer,
2195 module_completer,
2196 reset_completer,
2196 reset_completer,
2197 )
2197 )
2198
2198
2199 self.Completer = IPCompleter(shell=self,
2199 self.Completer = IPCompleter(shell=self,
2200 namespace=self.user_ns,
2200 namespace=self.user_ns,
2201 global_namespace=self.user_global_ns,
2201 global_namespace=self.user_global_ns,
2202 parent=self,
2202 parent=self,
2203 )
2203 )
2204 self.configurables.append(self.Completer)
2204 self.configurables.append(self.Completer)
2205
2205
2206 # Add custom completers to the basic ones built into IPCompleter
2206 # Add custom completers to the basic ones built into IPCompleter
2207 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2207 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2208 self.strdispatchers['complete_command'] = sdisp
2208 self.strdispatchers['complete_command'] = sdisp
2209 self.Completer.custom_completers = sdisp
2209 self.Completer.custom_completers = sdisp
2210
2210
2211 self.set_hook('complete_command', module_completer, str_key = 'import')
2211 self.set_hook('complete_command', module_completer, str_key = 'import')
2212 self.set_hook('complete_command', module_completer, str_key = 'from')
2212 self.set_hook('complete_command', module_completer, str_key = 'from')
2213 self.set_hook('complete_command', module_completer, str_key = '%aimport')
2213 self.set_hook('complete_command', module_completer, str_key = '%aimport')
2214 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2214 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2215 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2215 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2216 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2216 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2217
2217
2218 @skip_doctest
2218 @skip_doctest
2219 def complete(self, text, line=None, cursor_pos=None):
2219 def complete(self, text, line=None, cursor_pos=None):
2220 """Return the completed text and a list of completions.
2220 """Return the completed text and a list of completions.
2221
2221
2222 Parameters
2222 Parameters
2223 ----------
2223 ----------
2224 text : string
2224 text : string
2225 A string of text to be completed on. It can be given as empty and
2225 A string of text to be completed on. It can be given as empty and
2226 instead a line/position pair are given. In this case, the
2226 instead a line/position pair are given. In this case, the
2227 completer itself will split the line like readline does.
2227 completer itself will split the line like readline does.
2228 line : string, optional
2228 line : string, optional
2229 The complete line that text is part of.
2229 The complete line that text is part of.
2230 cursor_pos : int, optional
2230 cursor_pos : int, optional
2231 The position of the cursor on the input line.
2231 The position of the cursor on the input line.
2232
2232
2233 Returns
2233 Returns
2234 -------
2234 -------
2235 text : string
2235 text : string
2236 The actual text that was completed.
2236 The actual text that was completed.
2237 matches : list
2237 matches : list
2238 A sorted list with all possible completions.
2238 A sorted list with all possible completions.
2239
2239
2240 Notes
2240 Notes
2241 -----
2241 -----
2242 The optional arguments allow the completion to take more context into
2242 The optional arguments allow the completion to take more context into
2243 account, and are part of the low-level completion API.
2243 account, and are part of the low-level completion API.
2244
2244
2245 This is a wrapper around the completion mechanism, similar to what
2245 This is a wrapper around the completion mechanism, similar to what
2246 readline does at the command line when the TAB key is hit. By
2246 readline does at the command line when the TAB key is hit. By
2247 exposing it as a method, it can be used by other non-readline
2247 exposing it as a method, it can be used by other non-readline
2248 environments (such as GUIs) for text completion.
2248 environments (such as GUIs) for text completion.
2249
2249
2250 Examples
2250 Examples
2251 --------
2251 --------
2252 In [1]: x = 'hello'
2252 In [1]: x = 'hello'
2253
2253
2254 In [2]: _ip.complete('x.l')
2254 In [2]: _ip.complete('x.l')
2255 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2255 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2256 """
2256 """
2257
2257
2258 # Inject names into __builtin__ so we can complete on the added names.
2258 # Inject names into __builtin__ so we can complete on the added names.
2259 with self.builtin_trap:
2259 with self.builtin_trap:
2260 return self.Completer.complete(text, line, cursor_pos)
2260 return self.Completer.complete(text, line, cursor_pos)
2261
2261
2262 def set_custom_completer(self, completer, pos=0) -> None:
2262 def set_custom_completer(self, completer, pos=0) -> None:
2263 """Adds a new custom completer function.
2263 """Adds a new custom completer function.
2264
2264
2265 The position argument (defaults to 0) is the index in the completers
2265 The position argument (defaults to 0) is the index in the completers
2266 list where you want the completer to be inserted.
2266 list where you want the completer to be inserted.
2267
2267
2268 `completer` should have the following signature::
2268 `completer` should have the following signature::
2269
2269
2270 def completion(self: Completer, text: string) -> List[str]:
2270 def completion(self: Completer, text: string) -> List[str]:
2271 raise NotImplementedError
2271 raise NotImplementedError
2272
2272
2273 It will be bound to the current Completer instance and pass some text
2273 It will be bound to the current Completer instance and pass some text
2274 and return a list with current completions to suggest to the user.
2274 and return a list with current completions to suggest to the user.
2275 """
2275 """
2276
2276
2277 newcomp = types.MethodType(completer, self.Completer)
2277 newcomp = types.MethodType(completer, self.Completer)
2278 self.Completer.custom_matchers.insert(pos,newcomp)
2278 self.Completer.custom_matchers.insert(pos,newcomp)
2279
2279
2280 def set_completer_frame(self, frame=None):
2280 def set_completer_frame(self, frame=None):
2281 """Set the frame of the completer."""
2281 """Set the frame of the completer."""
2282 if frame:
2282 if frame:
2283 self.Completer.namespace = frame.f_locals
2283 self.Completer.namespace = frame.f_locals
2284 self.Completer.global_namespace = frame.f_globals
2284 self.Completer.global_namespace = frame.f_globals
2285 else:
2285 else:
2286 self.Completer.namespace = self.user_ns
2286 self.Completer.namespace = self.user_ns
2287 self.Completer.global_namespace = self.user_global_ns
2287 self.Completer.global_namespace = self.user_global_ns
2288
2288
2289 #-------------------------------------------------------------------------
2289 #-------------------------------------------------------------------------
2290 # Things related to magics
2290 # Things related to magics
2291 #-------------------------------------------------------------------------
2291 #-------------------------------------------------------------------------
2292
2292
2293 def init_magics(self):
2293 def init_magics(self):
2294 from IPython.core import magics as m
2294 from IPython.core import magics as m
2295 self.magics_manager = magic.MagicsManager(shell=self,
2295 self.magics_manager = magic.MagicsManager(shell=self,
2296 parent=self,
2296 parent=self,
2297 user_magics=m.UserMagics(self))
2297 user_magics=m.UserMagics(self))
2298 self.configurables.append(self.magics_manager)
2298 self.configurables.append(self.magics_manager)
2299
2299
2300 # Expose as public API from the magics manager
2300 # Expose as public API from the magics manager
2301 self.register_magics = self.magics_manager.register
2301 self.register_magics = self.magics_manager.register
2302
2302
2303 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2303 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2304 m.ConfigMagics, m.DisplayMagics, m.ExecutionMagics,
2304 m.ConfigMagics, m.DisplayMagics, m.ExecutionMagics,
2305 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2305 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2306 m.NamespaceMagics, m.OSMagics, m.PackagingMagics,
2306 m.NamespaceMagics, m.OSMagics, m.PackagingMagics,
2307 m.PylabMagics, m.ScriptMagics,
2307 m.PylabMagics, m.ScriptMagics,
2308 )
2308 )
2309 self.register_magics(m.AsyncMagics)
2309 self.register_magics(m.AsyncMagics)
2310
2310
2311 # Register Magic Aliases
2311 # Register Magic Aliases
2312 mman = self.magics_manager
2312 mman = self.magics_manager
2313 # FIXME: magic aliases should be defined by the Magics classes
2313 # FIXME: magic aliases should be defined by the Magics classes
2314 # or in MagicsManager, not here
2314 # or in MagicsManager, not here
2315 mman.register_alias('ed', 'edit')
2315 mman.register_alias('ed', 'edit')
2316 mman.register_alias('hist', 'history')
2316 mman.register_alias('hist', 'history')
2317 mman.register_alias('rep', 'recall')
2317 mman.register_alias('rep', 'recall')
2318 mman.register_alias('SVG', 'svg', 'cell')
2318 mman.register_alias('SVG', 'svg', 'cell')
2319 mman.register_alias('HTML', 'html', 'cell')
2319 mman.register_alias('HTML', 'html', 'cell')
2320 mman.register_alias('file', 'writefile', 'cell')
2320 mman.register_alias('file', 'writefile', 'cell')
2321
2321
2322 # FIXME: Move the color initialization to the DisplayHook, which
2322 # FIXME: Move the color initialization to the DisplayHook, which
2323 # should be split into a prompt manager and displayhook. We probably
2323 # should be split into a prompt manager and displayhook. We probably
2324 # even need a centralize colors management object.
2324 # even need a centralize colors management object.
2325 self.run_line_magic('colors', self.colors)
2325 self.run_line_magic('colors', self.colors)
2326
2326
2327 # Defined here so that it's included in the documentation
2327 # Defined here so that it's included in the documentation
2328 @functools.wraps(magic.MagicsManager.register_function)
2328 @functools.wraps(magic.MagicsManager.register_function)
2329 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2329 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2330 self.magics_manager.register_function(
2330 self.magics_manager.register_function(
2331 func, magic_kind=magic_kind, magic_name=magic_name
2331 func, magic_kind=magic_kind, magic_name=magic_name
2332 )
2332 )
2333
2333
2334 def _find_with_lazy_load(self, /, type_, magic_name: str):
2334 def _find_with_lazy_load(self, /, type_, magic_name: str):
2335 """
2335 """
2336 Try to find a magic potentially lazy-loading it.
2336 Try to find a magic potentially lazy-loading it.
2337
2337
2338 Parameters
2338 Parameters
2339 ----------
2339 ----------
2340
2340
2341 type_: "line"|"cell"
2341 type_: "line"|"cell"
2342 the type of magics we are trying to find/lazy load.
2342 the type of magics we are trying to find/lazy load.
2343 magic_name: str
2343 magic_name: str
2344 The name of the magic we are trying to find/lazy load
2344 The name of the magic we are trying to find/lazy load
2345
2345
2346
2346
2347 Note that this may have any side effects
2347 Note that this may have any side effects
2348 """
2348 """
2349 finder = {"line": self.find_line_magic, "cell": self.find_cell_magic}[type_]
2349 finder = {"line": self.find_line_magic, "cell": self.find_cell_magic}[type_]
2350 fn = finder(magic_name)
2350 fn = finder(magic_name)
2351 if fn is not None:
2351 if fn is not None:
2352 return fn
2352 return fn
2353 lazy = self.magics_manager.lazy_magics.get(magic_name)
2353 lazy = self.magics_manager.lazy_magics.get(magic_name)
2354 if lazy is None:
2354 if lazy is None:
2355 return None
2355 return None
2356
2356
2357 self.run_line_magic("load_ext", lazy)
2357 self.run_line_magic("load_ext", lazy)
2358 res = finder(magic_name)
2358 res = finder(magic_name)
2359 return res
2359 return res
2360
2360
2361 def run_line_magic(self, magic_name: str, line, _stack_depth=1):
2361 def run_line_magic(self, magic_name: str, line, _stack_depth=1):
2362 """Execute the given line magic.
2362 """Execute the given line magic.
2363
2363
2364 Parameters
2364 Parameters
2365 ----------
2365 ----------
2366 magic_name : str
2366 magic_name : str
2367 Name of the desired magic function, without '%' prefix.
2367 Name of the desired magic function, without '%' prefix.
2368 line : str
2368 line : str
2369 The rest of the input line as a single string.
2369 The rest of the input line as a single string.
2370 _stack_depth : int
2370 _stack_depth : int
2371 If run_line_magic() is called from magic() then _stack_depth=2.
2371 If run_line_magic() is called from magic() then _stack_depth=2.
2372 This is added to ensure backward compatibility for use of 'get_ipython().magic()'
2372 This is added to ensure backward compatibility for use of 'get_ipython().magic()'
2373 """
2373 """
2374 fn = self._find_with_lazy_load("line", magic_name)
2374 fn = self._find_with_lazy_load("line", magic_name)
2375 if fn is None:
2375 if fn is None:
2376 lazy = self.magics_manager.lazy_magics.get(magic_name)
2376 lazy = self.magics_manager.lazy_magics.get(magic_name)
2377 if lazy:
2377 if lazy:
2378 self.run_line_magic("load_ext", lazy)
2378 self.run_line_magic("load_ext", lazy)
2379 fn = self.find_line_magic(magic_name)
2379 fn = self.find_line_magic(magic_name)
2380 if fn is None:
2380 if fn is None:
2381 cm = self.find_cell_magic(magic_name)
2381 cm = self.find_cell_magic(magic_name)
2382 etpl = "Line magic function `%%%s` not found%s."
2382 etpl = "Line magic function `%%%s` not found%s."
2383 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2383 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2384 'did you mean that instead?)' % magic_name )
2384 'did you mean that instead?)' % magic_name )
2385 raise UsageError(etpl % (magic_name, extra))
2385 raise UsageError(etpl % (magic_name, extra))
2386 else:
2386 else:
2387 # Note: this is the distance in the stack to the user's frame.
2387 # Note: this is the distance in the stack to the user's frame.
2388 # This will need to be updated if the internal calling logic gets
2388 # This will need to be updated if the internal calling logic gets
2389 # refactored, or else we'll be expanding the wrong variables.
2389 # refactored, or else we'll be expanding the wrong variables.
2390
2390
2391 # Determine stack_depth depending on where run_line_magic() has been called
2391 # Determine stack_depth depending on where run_line_magic() has been called
2392 stack_depth = _stack_depth
2392 stack_depth = _stack_depth
2393 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2393 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2394 # magic has opted out of var_expand
2394 # magic has opted out of var_expand
2395 magic_arg_s = line
2395 magic_arg_s = line
2396 else:
2396 else:
2397 magic_arg_s = self.var_expand(line, stack_depth)
2397 magic_arg_s = self.var_expand(line, stack_depth)
2398 # Put magic args in a list so we can call with f(*a) syntax
2398 # Put magic args in a list so we can call with f(*a) syntax
2399 args = [magic_arg_s]
2399 args = [magic_arg_s]
2400 kwargs = {}
2400 kwargs = {}
2401 # Grab local namespace if we need it:
2401 # Grab local namespace if we need it:
2402 if getattr(fn, "needs_local_scope", False):
2402 if getattr(fn, "needs_local_scope", False):
2403 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2403 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2404 with self.builtin_trap:
2404 with self.builtin_trap:
2405 result = fn(*args, **kwargs)
2405 result = fn(*args, **kwargs)
2406
2406
2407 # The code below prevents the output from being displayed
2407 # The code below prevents the output from being displayed
2408 # when using magics with decodator @output_can_be_silenced
2408 # when using magics with decodator @output_can_be_silenced
2409 # when the last Python token in the expression is a ';'.
2409 # when the last Python token in the expression is a ';'.
2410 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):
2410 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):
2411 if DisplayHook.semicolon_at_end_of_expression(magic_arg_s):
2411 if DisplayHook.semicolon_at_end_of_expression(magic_arg_s):
2412 return None
2412 return None
2413
2413
2414 return result
2414 return result
2415
2415
2416 def get_local_scope(self, stack_depth):
2416 def get_local_scope(self, stack_depth):
2417 """Get local scope at given stack depth.
2417 """Get local scope at given stack depth.
2418
2418
2419 Parameters
2419 Parameters
2420 ----------
2420 ----------
2421 stack_depth : int
2421 stack_depth : int
2422 Depth relative to calling frame
2422 Depth relative to calling frame
2423 """
2423 """
2424 return sys._getframe(stack_depth + 1).f_locals
2424 return sys._getframe(stack_depth + 1).f_locals
2425
2425
2426 def run_cell_magic(self, magic_name, line, cell):
2426 def run_cell_magic(self, magic_name, line, cell):
2427 """Execute the given cell magic.
2427 """Execute the given cell magic.
2428
2428
2429 Parameters
2429 Parameters
2430 ----------
2430 ----------
2431 magic_name : str
2431 magic_name : str
2432 Name of the desired magic function, without '%' prefix.
2432 Name of the desired magic function, without '%' prefix.
2433 line : str
2433 line : str
2434 The rest of the first input line as a single string.
2434 The rest of the first input line as a single string.
2435 cell : str
2435 cell : str
2436 The body of the cell as a (possibly multiline) string.
2436 The body of the cell as a (possibly multiline) string.
2437 """
2437 """
2438 fn = self._find_with_lazy_load("cell", magic_name)
2438 fn = self._find_with_lazy_load("cell", magic_name)
2439 if fn is None:
2439 if fn is None:
2440 lm = self.find_line_magic(magic_name)
2440 lm = self.find_line_magic(magic_name)
2441 etpl = "Cell magic `%%{0}` not found{1}."
2441 etpl = "Cell magic `%%{0}` not found{1}."
2442 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2442 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2443 'did you mean that instead?)'.format(magic_name))
2443 'did you mean that instead?)'.format(magic_name))
2444 raise UsageError(etpl.format(magic_name, extra))
2444 raise UsageError(etpl.format(magic_name, extra))
2445 elif cell == '':
2445 elif cell == '':
2446 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2446 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2447 if self.find_line_magic(magic_name) is not None:
2447 if self.find_line_magic(magic_name) is not None:
2448 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2448 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2449 raise UsageError(message)
2449 raise UsageError(message)
2450 else:
2450 else:
2451 # Note: this is the distance in the stack to the user's frame.
2451 # Note: this is the distance in the stack to the user's frame.
2452 # This will need to be updated if the internal calling logic gets
2452 # This will need to be updated if the internal calling logic gets
2453 # refactored, or else we'll be expanding the wrong variables.
2453 # refactored, or else we'll be expanding the wrong variables.
2454 stack_depth = 2
2454 stack_depth = 2
2455 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2455 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2456 # magic has opted out of var_expand
2456 # magic has opted out of var_expand
2457 magic_arg_s = line
2457 magic_arg_s = line
2458 else:
2458 else:
2459 magic_arg_s = self.var_expand(line, stack_depth)
2459 magic_arg_s = self.var_expand(line, stack_depth)
2460 kwargs = {}
2460 kwargs = {}
2461 if getattr(fn, "needs_local_scope", False):
2461 if getattr(fn, "needs_local_scope", False):
2462 kwargs['local_ns'] = self.user_ns
2462 kwargs['local_ns'] = self.user_ns
2463
2463
2464 with self.builtin_trap:
2464 with self.builtin_trap:
2465 args = (magic_arg_s, cell)
2465 args = (magic_arg_s, cell)
2466 result = fn(*args, **kwargs)
2466 result = fn(*args, **kwargs)
2467
2467
2468 # The code below prevents the output from being displayed
2468 # The code below prevents the output from being displayed
2469 # when using magics with decodator @output_can_be_silenced
2469 # when using magics with decodator @output_can_be_silenced
2470 # when the last Python token in the expression is a ';'.
2470 # when the last Python token in the expression is a ';'.
2471 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):
2471 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):
2472 if DisplayHook.semicolon_at_end_of_expression(cell):
2472 if DisplayHook.semicolon_at_end_of_expression(cell):
2473 return None
2473 return None
2474
2474
2475 return result
2475 return result
2476
2476
2477 def find_line_magic(self, magic_name):
2477 def find_line_magic(self, magic_name):
2478 """Find and return a line magic by name.
2478 """Find and return a line magic by name.
2479
2479
2480 Returns None if the magic isn't found."""
2480 Returns None if the magic isn't found."""
2481 return self.magics_manager.magics['line'].get(magic_name)
2481 return self.magics_manager.magics['line'].get(magic_name)
2482
2482
2483 def find_cell_magic(self, magic_name):
2483 def find_cell_magic(self, magic_name):
2484 """Find and return a cell magic by name.
2484 """Find and return a cell magic by name.
2485
2485
2486 Returns None if the magic isn't found."""
2486 Returns None if the magic isn't found."""
2487 return self.magics_manager.magics['cell'].get(magic_name)
2487 return self.magics_manager.magics['cell'].get(magic_name)
2488
2488
2489 def find_magic(self, magic_name, magic_kind='line'):
2489 def find_magic(self, magic_name, magic_kind='line'):
2490 """Find and return a magic of the given type by name.
2490 """Find and return a magic of the given type by name.
2491
2491
2492 Returns None if the magic isn't found."""
2492 Returns None if the magic isn't found."""
2493 return self.magics_manager.magics[magic_kind].get(magic_name)
2493 return self.magics_manager.magics[magic_kind].get(magic_name)
2494
2494
2495 def magic(self, arg_s):
2495 def magic(self, arg_s):
2496 """
2496 """
2497 DEPRECATED
2497 DEPRECATED
2498
2498
2499 Deprecated since IPython 0.13 (warning added in
2499 Deprecated since IPython 0.13 (warning added in
2500 8.1), use run_line_magic(magic_name, parameter_s).
2500 8.1), use run_line_magic(magic_name, parameter_s).
2501
2501
2502 Call a magic function by name.
2502 Call a magic function by name.
2503
2503
2504 Input: a string containing the name of the magic function to call and
2504 Input: a string containing the name of the magic function to call and
2505 any additional arguments to be passed to the magic.
2505 any additional arguments to be passed to the magic.
2506
2506
2507 magic('name -opt foo bar') is equivalent to typing at the ipython
2507 magic('name -opt foo bar') is equivalent to typing at the ipython
2508 prompt:
2508 prompt:
2509
2509
2510 In[1]: %name -opt foo bar
2510 In[1]: %name -opt foo bar
2511
2511
2512 To call a magic without arguments, simply use magic('name').
2512 To call a magic without arguments, simply use magic('name').
2513
2513
2514 This provides a proper Python function to call IPython's magics in any
2514 This provides a proper Python function to call IPython's magics in any
2515 valid Python code you can type at the interpreter, including loops and
2515 valid Python code you can type at the interpreter, including loops and
2516 compound statements.
2516 compound statements.
2517 """
2517 """
2518 warnings.warn(
2518 warnings.warn(
2519 "`magic(...)` is deprecated since IPython 0.13 (warning added in "
2519 "`magic(...)` is deprecated since IPython 0.13 (warning added in "
2520 "8.1), use run_line_magic(magic_name, parameter_s).",
2520 "8.1), use run_line_magic(magic_name, parameter_s).",
2521 DeprecationWarning,
2521 DeprecationWarning,
2522 stacklevel=2,
2522 stacklevel=2,
2523 )
2523 )
2524 # TODO: should we issue a loud deprecation warning here?
2524 # TODO: should we issue a loud deprecation warning here?
2525 magic_name, _, magic_arg_s = arg_s.partition(' ')
2525 magic_name, _, magic_arg_s = arg_s.partition(' ')
2526 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2526 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2527 return self.run_line_magic(magic_name, magic_arg_s, _stack_depth=2)
2527 return self.run_line_magic(magic_name, magic_arg_s, _stack_depth=2)
2528
2528
2529 #-------------------------------------------------------------------------
2529 #-------------------------------------------------------------------------
2530 # Things related to macros
2530 # Things related to macros
2531 #-------------------------------------------------------------------------
2531 #-------------------------------------------------------------------------
2532
2532
2533 def define_macro(self, name, themacro):
2533 def define_macro(self, name, themacro):
2534 """Define a new macro
2534 """Define a new macro
2535
2535
2536 Parameters
2536 Parameters
2537 ----------
2537 ----------
2538 name : str
2538 name : str
2539 The name of the macro.
2539 The name of the macro.
2540 themacro : str or Macro
2540 themacro : str or Macro
2541 The action to do upon invoking the macro. If a string, a new
2541 The action to do upon invoking the macro. If a string, a new
2542 Macro object is created by passing the string to it.
2542 Macro object is created by passing the string to it.
2543 """
2543 """
2544
2544
2545 from IPython.core import macro
2545 from IPython.core import macro
2546
2546
2547 if isinstance(themacro, str):
2547 if isinstance(themacro, str):
2548 themacro = macro.Macro(themacro)
2548 themacro = macro.Macro(themacro)
2549 if not isinstance(themacro, macro.Macro):
2549 if not isinstance(themacro, macro.Macro):
2550 raise ValueError('A macro must be a string or a Macro instance.')
2550 raise ValueError('A macro must be a string or a Macro instance.')
2551 self.user_ns[name] = themacro
2551 self.user_ns[name] = themacro
2552
2552
2553 #-------------------------------------------------------------------------
2553 #-------------------------------------------------------------------------
2554 # Things related to the running of system commands
2554 # Things related to the running of system commands
2555 #-------------------------------------------------------------------------
2555 #-------------------------------------------------------------------------
2556
2556
2557 def system_piped(self, cmd):
2557 def system_piped(self, cmd):
2558 """Call the given cmd in a subprocess, piping stdout/err
2558 """Call the given cmd in a subprocess, piping stdout/err
2559
2559
2560 Parameters
2560 Parameters
2561 ----------
2561 ----------
2562 cmd : str
2562 cmd : str
2563 Command to execute (can not end in '&', as background processes are
2563 Command to execute (can not end in '&', as background processes are
2564 not supported. Should not be a command that expects input
2564 not supported. Should not be a command that expects input
2565 other than simple text.
2565 other than simple text.
2566 """
2566 """
2567 if cmd.rstrip().endswith('&'):
2567 if cmd.rstrip().endswith('&'):
2568 # this is *far* from a rigorous test
2568 # this is *far* from a rigorous test
2569 # We do not support backgrounding processes because we either use
2569 # We do not support backgrounding processes because we either use
2570 # pexpect or pipes to read from. Users can always just call
2570 # pexpect or pipes to read from. Users can always just call
2571 # os.system() or use ip.system=ip.system_raw
2571 # os.system() or use ip.system=ip.system_raw
2572 # if they really want a background process.
2572 # if they really want a background process.
2573 raise OSError("Background processes not supported.")
2573 raise OSError("Background processes not supported.")
2574
2574
2575 # we explicitly do NOT return the subprocess status code, because
2575 # we explicitly do NOT return the subprocess status code, because
2576 # a non-None value would trigger :func:`sys.displayhook` calls.
2576 # a non-None value would trigger :func:`sys.displayhook` calls.
2577 # Instead, we store the exit_code in user_ns.
2577 # Instead, we store the exit_code in user_ns.
2578 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2578 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2579
2579
2580 def system_raw(self, cmd):
2580 def system_raw(self, cmd):
2581 """Call the given cmd in a subprocess using os.system on Windows or
2581 """Call the given cmd in a subprocess using os.system on Windows or
2582 subprocess.call using the system shell on other platforms.
2582 subprocess.call using the system shell on other platforms.
2583
2583
2584 Parameters
2584 Parameters
2585 ----------
2585 ----------
2586 cmd : str
2586 cmd : str
2587 Command to execute.
2587 Command to execute.
2588 """
2588 """
2589 cmd = self.var_expand(cmd, depth=1)
2589 cmd = self.var_expand(cmd, depth=1)
2590 # warn if there is an IPython magic alternative.
2590 # warn if there is an IPython magic alternative.
2591 main_cmd = cmd.split()[0]
2591 main_cmd = cmd.split()[0]
2592 has_magic_alternatives = ("pip", "conda", "cd")
2592 has_magic_alternatives = ("pip", "conda", "cd")
2593
2593
2594 if main_cmd in has_magic_alternatives:
2594 if main_cmd in has_magic_alternatives:
2595 warnings.warn(
2595 warnings.warn(
2596 (
2596 (
2597 "You executed the system command !{0} which may not work "
2597 "You executed the system command !{0} which may not work "
2598 "as expected. Try the IPython magic %{0} instead."
2598 "as expected. Try the IPython magic %{0} instead."
2599 ).format(main_cmd)
2599 ).format(main_cmd)
2600 )
2600 )
2601
2601
2602 # protect os.system from UNC paths on Windows, which it can't handle:
2602 # protect os.system from UNC paths on Windows, which it can't handle:
2603 if sys.platform == 'win32':
2603 if sys.platform == 'win32':
2604 from IPython.utils._process_win32 import AvoidUNCPath
2604 from IPython.utils._process_win32 import AvoidUNCPath
2605 with AvoidUNCPath() as path:
2605 with AvoidUNCPath() as path:
2606 if path is not None:
2606 if path is not None:
2607 cmd = '"pushd %s &&"%s' % (path, cmd)
2607 cmd = '"pushd %s &&"%s' % (path, cmd)
2608 try:
2608 try:
2609 ec = os.system(cmd)
2609 ec = os.system(cmd)
2610 except KeyboardInterrupt:
2610 except KeyboardInterrupt:
2611 print('\n' + self.get_exception_only(), file=sys.stderr)
2611 print('\n' + self.get_exception_only(), file=sys.stderr)
2612 ec = -2
2612 ec = -2
2613 else:
2613 else:
2614 # For posix the result of the subprocess.call() below is an exit
2614 # For posix the result of the subprocess.call() below is an exit
2615 # code, which by convention is zero for success, positive for
2615 # code, which by convention is zero for success, positive for
2616 # program failure. Exit codes above 128 are reserved for signals,
2616 # program failure. Exit codes above 128 are reserved for signals,
2617 # and the formula for converting a signal to an exit code is usually
2617 # and the formula for converting a signal to an exit code is usually
2618 # signal_number+128. To more easily differentiate between exit
2618 # signal_number+128. To more easily differentiate between exit
2619 # codes and signals, ipython uses negative numbers. For instance
2619 # codes and signals, ipython uses negative numbers. For instance
2620 # since control-c is signal 2 but exit code 130, ipython's
2620 # since control-c is signal 2 but exit code 130, ipython's
2621 # _exit_code variable will read -2. Note that some shells like
2621 # _exit_code variable will read -2. Note that some shells like
2622 # csh and fish don't follow sh/bash conventions for exit codes.
2622 # csh and fish don't follow sh/bash conventions for exit codes.
2623 executable = os.environ.get('SHELL', None)
2623 executable = os.environ.get('SHELL', None)
2624 try:
2624 try:
2625 # Use env shell instead of default /bin/sh
2625 # Use env shell instead of default /bin/sh
2626 ec = subprocess.call(cmd, shell=True, executable=executable)
2626 ec = subprocess.call(cmd, shell=True, executable=executable)
2627 except KeyboardInterrupt:
2627 except KeyboardInterrupt:
2628 # intercept control-C; a long traceback is not useful here
2628 # intercept control-C; a long traceback is not useful here
2629 print('\n' + self.get_exception_only(), file=sys.stderr)
2629 print('\n' + self.get_exception_only(), file=sys.stderr)
2630 ec = 130
2630 ec = 130
2631 if ec > 128:
2631 if ec > 128:
2632 ec = -(ec - 128)
2632 ec = -(ec - 128)
2633
2633
2634 # We explicitly do NOT return the subprocess status code, because
2634 # We explicitly do NOT return the subprocess status code, because
2635 # a non-None value would trigger :func:`sys.displayhook` calls.
2635 # a non-None value would trigger :func:`sys.displayhook` calls.
2636 # Instead, we store the exit_code in user_ns. Note the semantics
2636 # Instead, we store the exit_code in user_ns. Note the semantics
2637 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2637 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2638 # but raising SystemExit(_exit_code) will give status 254!
2638 # but raising SystemExit(_exit_code) will give status 254!
2639 self.user_ns['_exit_code'] = ec
2639 self.user_ns['_exit_code'] = ec
2640
2640
2641 # use piped system by default, because it is better behaved
2641 # use piped system by default, because it is better behaved
2642 system = system_piped
2642 system = system_piped
2643
2643
2644 def getoutput(self, cmd, split=True, depth=0):
2644 def getoutput(self, cmd, split=True, depth=0):
2645 """Get output (possibly including stderr) from a subprocess.
2645 """Get output (possibly including stderr) from a subprocess.
2646
2646
2647 Parameters
2647 Parameters
2648 ----------
2648 ----------
2649 cmd : str
2649 cmd : str
2650 Command to execute (can not end in '&', as background processes are
2650 Command to execute (can not end in '&', as background processes are
2651 not supported.
2651 not supported.
2652 split : bool, optional
2652 split : bool, optional
2653 If True, split the output into an IPython SList. Otherwise, an
2653 If True, split the output into an IPython SList. Otherwise, an
2654 IPython LSString is returned. These are objects similar to normal
2654 IPython LSString is returned. These are objects similar to normal
2655 lists and strings, with a few convenience attributes for easier
2655 lists and strings, with a few convenience attributes for easier
2656 manipulation of line-based output. You can use '?' on them for
2656 manipulation of line-based output. You can use '?' on them for
2657 details.
2657 details.
2658 depth : int, optional
2658 depth : int, optional
2659 How many frames above the caller are the local variables which should
2659 How many frames above the caller are the local variables which should
2660 be expanded in the command string? The default (0) assumes that the
2660 be expanded in the command string? The default (0) assumes that the
2661 expansion variables are in the stack frame calling this function.
2661 expansion variables are in the stack frame calling this function.
2662 """
2662 """
2663 if cmd.rstrip().endswith('&'):
2663 if cmd.rstrip().endswith('&'):
2664 # this is *far* from a rigorous test
2664 # this is *far* from a rigorous test
2665 raise OSError("Background processes not supported.")
2665 raise OSError("Background processes not supported.")
2666 out = getoutput(self.var_expand(cmd, depth=depth+1))
2666 out = getoutput(self.var_expand(cmd, depth=depth+1))
2667 if split:
2667 if split:
2668 out = SList(out.splitlines())
2668 out = SList(out.splitlines())
2669 else:
2669 else:
2670 out = LSString(out)
2670 out = LSString(out)
2671 return out
2671 return out
2672
2672
2673 #-------------------------------------------------------------------------
2673 #-------------------------------------------------------------------------
2674 # Things related to aliases
2674 # Things related to aliases
2675 #-------------------------------------------------------------------------
2675 #-------------------------------------------------------------------------
2676
2676
2677 def init_alias(self):
2677 def init_alias(self):
2678 self.alias_manager = AliasManager(shell=self, parent=self)
2678 self.alias_manager = AliasManager(shell=self, parent=self)
2679 self.configurables.append(self.alias_manager)
2679 self.configurables.append(self.alias_manager)
2680
2680
2681 #-------------------------------------------------------------------------
2681 #-------------------------------------------------------------------------
2682 # Things related to extensions
2682 # Things related to extensions
2683 #-------------------------------------------------------------------------
2683 #-------------------------------------------------------------------------
2684
2684
2685 def init_extension_manager(self):
2685 def init_extension_manager(self):
2686 self.extension_manager = ExtensionManager(shell=self, parent=self)
2686 self.extension_manager = ExtensionManager(shell=self, parent=self)
2687 self.configurables.append(self.extension_manager)
2687 self.configurables.append(self.extension_manager)
2688
2688
2689 #-------------------------------------------------------------------------
2689 #-------------------------------------------------------------------------
2690 # Things related to payloads
2690 # Things related to payloads
2691 #-------------------------------------------------------------------------
2691 #-------------------------------------------------------------------------
2692
2692
2693 def init_payload(self):
2693 def init_payload(self):
2694 self.payload_manager = PayloadManager(parent=self)
2694 self.payload_manager = PayloadManager(parent=self)
2695 self.configurables.append(self.payload_manager)
2695 self.configurables.append(self.payload_manager)
2696
2696
2697 #-------------------------------------------------------------------------
2697 #-------------------------------------------------------------------------
2698 # Things related to the prefilter
2698 # Things related to the prefilter
2699 #-------------------------------------------------------------------------
2699 #-------------------------------------------------------------------------
2700
2700
2701 def init_prefilter(self):
2701 def init_prefilter(self):
2702 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2702 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2703 self.configurables.append(self.prefilter_manager)
2703 self.configurables.append(self.prefilter_manager)
2704 # Ultimately this will be refactored in the new interpreter code, but
2704 # Ultimately this will be refactored in the new interpreter code, but
2705 # for now, we should expose the main prefilter method (there's legacy
2705 # for now, we should expose the main prefilter method (there's legacy
2706 # code out there that may rely on this).
2706 # code out there that may rely on this).
2707 self.prefilter = self.prefilter_manager.prefilter_lines
2707 self.prefilter = self.prefilter_manager.prefilter_lines
2708
2708
2709 def auto_rewrite_input(self, cmd):
2709 def auto_rewrite_input(self, cmd):
2710 """Print to the screen the rewritten form of the user's command.
2710 """Print to the screen the rewritten form of the user's command.
2711
2711
2712 This shows visual feedback by rewriting input lines that cause
2712 This shows visual feedback by rewriting input lines that cause
2713 automatic calling to kick in, like::
2713 automatic calling to kick in, like::
2714
2714
2715 /f x
2715 /f x
2716
2716
2717 into::
2717 into::
2718
2718
2719 ------> f(x)
2719 ------> f(x)
2720
2720
2721 after the user's input prompt. This helps the user understand that the
2721 after the user's input prompt. This helps the user understand that the
2722 input line was transformed automatically by IPython.
2722 input line was transformed automatically by IPython.
2723 """
2723 """
2724 if not self.show_rewritten_input:
2724 if not self.show_rewritten_input:
2725 return
2725 return
2726
2726
2727 # This is overridden in TerminalInteractiveShell to use fancy prompts
2727 # This is overridden in TerminalInteractiveShell to use fancy prompts
2728 print("------> " + cmd)
2728 print("------> " + cmd)
2729
2729
2730 #-------------------------------------------------------------------------
2730 #-------------------------------------------------------------------------
2731 # Things related to extracting values/expressions from kernel and user_ns
2731 # Things related to extracting values/expressions from kernel and user_ns
2732 #-------------------------------------------------------------------------
2732 #-------------------------------------------------------------------------
2733
2733
2734 def _user_obj_error(self):
2734 def _user_obj_error(self):
2735 """return simple exception dict
2735 """return simple exception dict
2736
2736
2737 for use in user_expressions
2737 for use in user_expressions
2738 """
2738 """
2739
2739
2740 etype, evalue, tb = self._get_exc_info()
2740 etype, evalue, tb = self._get_exc_info()
2741 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2741 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2742
2742
2743 exc_info = {
2743 exc_info = {
2744 "status": "error",
2744 "status": "error",
2745 "traceback": stb,
2745 "traceback": stb,
2746 "ename": etype.__name__,
2746 "ename": etype.__name__,
2747 "evalue": py3compat.safe_unicode(evalue),
2747 "evalue": py3compat.safe_unicode(evalue),
2748 }
2748 }
2749
2749
2750 return exc_info
2750 return exc_info
2751
2751
2752 def _format_user_obj(self, obj):
2752 def _format_user_obj(self, obj):
2753 """format a user object to display dict
2753 """format a user object to display dict
2754
2754
2755 for use in user_expressions
2755 for use in user_expressions
2756 """
2756 """
2757
2757
2758 data, md = self.display_formatter.format(obj)
2758 data, md = self.display_formatter.format(obj)
2759 value = {
2759 value = {
2760 'status' : 'ok',
2760 'status' : 'ok',
2761 'data' : data,
2761 'data' : data,
2762 'metadata' : md,
2762 'metadata' : md,
2763 }
2763 }
2764 return value
2764 return value
2765
2765
2766 def user_expressions(self, expressions):
2766 def user_expressions(self, expressions):
2767 """Evaluate a dict of expressions in the user's namespace.
2767 """Evaluate a dict of expressions in the user's namespace.
2768
2768
2769 Parameters
2769 Parameters
2770 ----------
2770 ----------
2771 expressions : dict
2771 expressions : dict
2772 A dict with string keys and string values. The expression values
2772 A dict with string keys and string values. The expression values
2773 should be valid Python expressions, each of which will be evaluated
2773 should be valid Python expressions, each of which will be evaluated
2774 in the user namespace.
2774 in the user namespace.
2775
2775
2776 Returns
2776 Returns
2777 -------
2777 -------
2778 A dict, keyed like the input expressions dict, with the rich mime-typed
2778 A dict, keyed like the input expressions dict, with the rich mime-typed
2779 display_data of each value.
2779 display_data of each value.
2780 """
2780 """
2781 out = {}
2781 out = {}
2782 user_ns = self.user_ns
2782 user_ns = self.user_ns
2783 global_ns = self.user_global_ns
2783 global_ns = self.user_global_ns
2784
2784
2785 for key, expr in expressions.items():
2785 for key, expr in expressions.items():
2786 try:
2786 try:
2787 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2787 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2788 except:
2788 except:
2789 value = self._user_obj_error()
2789 value = self._user_obj_error()
2790 out[key] = value
2790 out[key] = value
2791 return out
2791 return out
2792
2792
2793 #-------------------------------------------------------------------------
2793 #-------------------------------------------------------------------------
2794 # Things related to the running of code
2794 # Things related to the running of code
2795 #-------------------------------------------------------------------------
2795 #-------------------------------------------------------------------------
2796
2796
2797 def ex(self, cmd):
2797 def ex(self, cmd):
2798 """Execute a normal python statement in user namespace."""
2798 """Execute a normal python statement in user namespace."""
2799 with self.builtin_trap:
2799 with self.builtin_trap:
2800 exec(cmd, self.user_global_ns, self.user_ns)
2800 exec(cmd, self.user_global_ns, self.user_ns)
2801
2801
2802 def ev(self, expr):
2802 def ev(self, expr):
2803 """Evaluate python expression expr in user namespace.
2803 """Evaluate python expression expr in user namespace.
2804
2804
2805 Returns the result of evaluation
2805 Returns the result of evaluation
2806 """
2806 """
2807 with self.builtin_trap:
2807 with self.builtin_trap:
2808 return eval(expr, self.user_global_ns, self.user_ns)
2808 return eval(expr, self.user_global_ns, self.user_ns)
2809
2809
2810 def safe_execfile(self, fname, *where, exit_ignore=False, raise_exceptions=False, shell_futures=False):
2810 def safe_execfile(self, fname, *where, exit_ignore=False, raise_exceptions=False, shell_futures=False):
2811 """A safe version of the builtin execfile().
2811 """A safe version of the builtin execfile().
2812
2812
2813 This version will never throw an exception, but instead print
2813 This version will never throw an exception, but instead print
2814 helpful error messages to the screen. This only works on pure
2814 helpful error messages to the screen. This only works on pure
2815 Python files with the .py extension.
2815 Python files with the .py extension.
2816
2816
2817 Parameters
2817 Parameters
2818 ----------
2818 ----------
2819 fname : string
2819 fname : string
2820 The name of the file to be executed.
2820 The name of the file to be executed.
2821 *where : tuple
2821 *where : tuple
2822 One or two namespaces, passed to execfile() as (globals,locals).
2822 One or two namespaces, passed to execfile() as (globals,locals).
2823 If only one is given, it is passed as both.
2823 If only one is given, it is passed as both.
2824 exit_ignore : bool (False)
2824 exit_ignore : bool (False)
2825 If True, then silence SystemExit for non-zero status (it is always
2825 If True, then silence SystemExit for non-zero status (it is always
2826 silenced for zero status, as it is so common).
2826 silenced for zero status, as it is so common).
2827 raise_exceptions : bool (False)
2827 raise_exceptions : bool (False)
2828 If True raise exceptions everywhere. Meant for testing.
2828 If True raise exceptions everywhere. Meant for testing.
2829 shell_futures : bool (False)
2829 shell_futures : bool (False)
2830 If True, the code will share future statements with the interactive
2830 If True, the code will share future statements with the interactive
2831 shell. It will both be affected by previous __future__ imports, and
2831 shell. It will both be affected by previous __future__ imports, and
2832 any __future__ imports in the code will affect the shell. If False,
2832 any __future__ imports in the code will affect the shell. If False,
2833 __future__ imports are not shared in either direction.
2833 __future__ imports are not shared in either direction.
2834
2834
2835 """
2835 """
2836 fname = Path(fname).expanduser().resolve()
2836 fname = Path(fname).expanduser().resolve()
2837
2837
2838 # Make sure we can open the file
2838 # Make sure we can open the file
2839 try:
2839 try:
2840 with fname.open("rb"):
2840 with fname.open("rb"):
2841 pass
2841 pass
2842 except:
2842 except:
2843 warn('Could not open file <%s> for safe execution.' % fname)
2843 warn('Could not open file <%s> for safe execution.' % fname)
2844 return
2844 return
2845
2845
2846 # Find things also in current directory. This is needed to mimic the
2846 # Find things also in current directory. This is needed to mimic the
2847 # behavior of running a script from the system command line, where
2847 # behavior of running a script from the system command line, where
2848 # Python inserts the script's directory into sys.path
2848 # Python inserts the script's directory into sys.path
2849 dname = str(fname.parent)
2849 dname = str(fname.parent)
2850
2850
2851 with prepended_to_syspath(dname), self.builtin_trap:
2851 with prepended_to_syspath(dname), self.builtin_trap:
2852 try:
2852 try:
2853 glob, loc = (where + (None, ))[:2]
2853 glob, loc = (where + (None, ))[:2]
2854 py3compat.execfile(
2854 py3compat.execfile(
2855 fname, glob, loc,
2855 fname, glob, loc,
2856 self.compile if shell_futures else None)
2856 self.compile if shell_futures else None)
2857 except SystemExit as status:
2857 except SystemExit as status:
2858 # If the call was made with 0 or None exit status (sys.exit(0)
2858 # If the call was made with 0 or None exit status (sys.exit(0)
2859 # or sys.exit() ), don't bother showing a traceback, as both of
2859 # or sys.exit() ), don't bother showing a traceback, as both of
2860 # these are considered normal by the OS:
2860 # these are considered normal by the OS:
2861 # > python -c'import sys;sys.exit(0)'; echo $?
2861 # > python -c'import sys;sys.exit(0)'; echo $?
2862 # 0
2862 # 0
2863 # > python -c'import sys;sys.exit()'; echo $?
2863 # > python -c'import sys;sys.exit()'; echo $?
2864 # 0
2864 # 0
2865 # For other exit status, we show the exception unless
2865 # For other exit status, we show the exception unless
2866 # explicitly silenced, but only in short form.
2866 # explicitly silenced, but only in short form.
2867 if status.code:
2867 if status.code:
2868 if raise_exceptions:
2868 if raise_exceptions:
2869 raise
2869 raise
2870 if not exit_ignore:
2870 if not exit_ignore:
2871 self.showtraceback(exception_only=True)
2871 self.showtraceback(exception_only=True)
2872 except:
2872 except:
2873 if raise_exceptions:
2873 if raise_exceptions:
2874 raise
2874 raise
2875 # tb offset is 2 because we wrap execfile
2875 # tb offset is 2 because we wrap execfile
2876 self.showtraceback(tb_offset=2)
2876 self.showtraceback(tb_offset=2)
2877
2877
2878 def safe_execfile_ipy(self, fname, shell_futures=False, raise_exceptions=False):
2878 def safe_execfile_ipy(self, fname, shell_futures=False, raise_exceptions=False):
2879 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2879 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2880
2880
2881 Parameters
2881 Parameters
2882 ----------
2882 ----------
2883 fname : str
2883 fname : str
2884 The name of the file to execute. The filename must have a
2884 The name of the file to execute. The filename must have a
2885 .ipy or .ipynb extension.
2885 .ipy or .ipynb extension.
2886 shell_futures : bool (False)
2886 shell_futures : bool (False)
2887 If True, the code will share future statements with the interactive
2887 If True, the code will share future statements with the interactive
2888 shell. It will both be affected by previous __future__ imports, and
2888 shell. It will both be affected by previous __future__ imports, and
2889 any __future__ imports in the code will affect the shell. If False,
2889 any __future__ imports in the code will affect the shell. If False,
2890 __future__ imports are not shared in either direction.
2890 __future__ imports are not shared in either direction.
2891 raise_exceptions : bool (False)
2891 raise_exceptions : bool (False)
2892 If True raise exceptions everywhere. Meant for testing.
2892 If True raise exceptions everywhere. Meant for testing.
2893 """
2893 """
2894 fname = Path(fname).expanduser().resolve()
2894 fname = Path(fname).expanduser().resolve()
2895
2895
2896 # Make sure we can open the file
2896 # Make sure we can open the file
2897 try:
2897 try:
2898 with fname.open("rb"):
2898 with fname.open("rb"):
2899 pass
2899 pass
2900 except:
2900 except:
2901 warn('Could not open file <%s> for safe execution.' % fname)
2901 warn('Could not open file <%s> for safe execution.' % fname)
2902 return
2902 return
2903
2903
2904 # Find things also in current directory. This is needed to mimic the
2904 # Find things also in current directory. This is needed to mimic the
2905 # behavior of running a script from the system command line, where
2905 # behavior of running a script from the system command line, where
2906 # Python inserts the script's directory into sys.path
2906 # Python inserts the script's directory into sys.path
2907 dname = str(fname.parent)
2907 dname = str(fname.parent)
2908
2908
2909 def get_cells():
2909 def get_cells():
2910 """generator for sequence of code blocks to run"""
2910 """generator for sequence of code blocks to run"""
2911 if fname.suffix == ".ipynb":
2911 if fname.suffix == ".ipynb":
2912 from nbformat import read
2912 from nbformat import read
2913 nb = read(fname, as_version=4)
2913 nb = read(fname, as_version=4)
2914 if not nb.cells:
2914 if not nb.cells:
2915 return
2915 return
2916 for cell in nb.cells:
2916 for cell in nb.cells:
2917 if cell.cell_type == 'code':
2917 if cell.cell_type == 'code':
2918 yield cell.source
2918 yield cell.source
2919 else:
2919 else:
2920 yield fname.read_text(encoding="utf-8")
2920 yield fname.read_text(encoding="utf-8")
2921
2921
2922 with prepended_to_syspath(dname):
2922 with prepended_to_syspath(dname):
2923 try:
2923 try:
2924 for cell in get_cells():
2924 for cell in get_cells():
2925 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2925 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2926 if raise_exceptions:
2926 if raise_exceptions:
2927 result.raise_error()
2927 result.raise_error()
2928 elif not result.success:
2928 elif not result.success:
2929 break
2929 break
2930 except:
2930 except:
2931 if raise_exceptions:
2931 if raise_exceptions:
2932 raise
2932 raise
2933 self.showtraceback()
2933 self.showtraceback()
2934 warn('Unknown failure executing file: <%s>' % fname)
2934 warn('Unknown failure executing file: <%s>' % fname)
2935
2935
2936 def safe_run_module(self, mod_name, where):
2936 def safe_run_module(self, mod_name, where):
2937 """A safe version of runpy.run_module().
2937 """A safe version of runpy.run_module().
2938
2938
2939 This version will never throw an exception, but instead print
2939 This version will never throw an exception, but instead print
2940 helpful error messages to the screen.
2940 helpful error messages to the screen.
2941
2941
2942 `SystemExit` exceptions with status code 0 or None are ignored.
2942 `SystemExit` exceptions with status code 0 or None are ignored.
2943
2943
2944 Parameters
2944 Parameters
2945 ----------
2945 ----------
2946 mod_name : string
2946 mod_name : string
2947 The name of the module to be executed.
2947 The name of the module to be executed.
2948 where : dict
2948 where : dict
2949 The globals namespace.
2949 The globals namespace.
2950 """
2950 """
2951 try:
2951 try:
2952 try:
2952 try:
2953 where.update(
2953 where.update(
2954 runpy.run_module(str(mod_name), run_name="__main__",
2954 runpy.run_module(str(mod_name), run_name="__main__",
2955 alter_sys=True)
2955 alter_sys=True)
2956 )
2956 )
2957 except SystemExit as status:
2957 except SystemExit as status:
2958 if status.code:
2958 if status.code:
2959 raise
2959 raise
2960 except:
2960 except:
2961 self.showtraceback()
2961 self.showtraceback()
2962 warn('Unknown failure executing module: <%s>' % mod_name)
2962 warn('Unknown failure executing module: <%s>' % mod_name)
2963
2963
2964 def run_cell(
2964 def run_cell(
2965 self,
2965 self,
2966 raw_cell,
2966 raw_cell,
2967 store_history=False,
2967 store_history=False,
2968 silent=False,
2968 silent=False,
2969 shell_futures=True,
2969 shell_futures=True,
2970 cell_id=None,
2970 cell_id=None,
2971 ):
2971 ):
2972 """Run a complete IPython cell.
2972 """Run a complete IPython cell.
2973
2973
2974 Parameters
2974 Parameters
2975 ----------
2975 ----------
2976 raw_cell : str
2976 raw_cell : str
2977 The code (including IPython code such as %magic functions) to run.
2977 The code (including IPython code such as %magic functions) to run.
2978 store_history : bool
2978 store_history : bool
2979 If True, the raw and translated cell will be stored in IPython's
2979 If True, the raw and translated cell will be stored in IPython's
2980 history. For user code calling back into IPython's machinery, this
2980 history. For user code calling back into IPython's machinery, this
2981 should be set to False.
2981 should be set to False.
2982 silent : bool
2982 silent : bool
2983 If True, avoid side-effects, such as implicit displayhooks and
2983 If True, avoid side-effects, such as implicit displayhooks and
2984 and logging. silent=True forces store_history=False.
2984 and logging. silent=True forces store_history=False.
2985 shell_futures : bool
2985 shell_futures : bool
2986 If True, the code will share future statements with the interactive
2986 If True, the code will share future statements with the interactive
2987 shell. It will both be affected by previous __future__ imports, and
2987 shell. It will both be affected by previous __future__ imports, and
2988 any __future__ imports in the code will affect the shell. If False,
2988 any __future__ imports in the code will affect the shell. If False,
2989 __future__ imports are not shared in either direction.
2989 __future__ imports are not shared in either direction.
2990
2990
2991 Returns
2991 Returns
2992 -------
2992 -------
2993 result : :class:`ExecutionResult`
2993 result : :class:`ExecutionResult`
2994 """
2994 """
2995 result = None
2995 result = None
2996 try:
2996 try:
2997 result = self._run_cell(
2997 result = self._run_cell(
2998 raw_cell, store_history, silent, shell_futures, cell_id
2998 raw_cell, store_history, silent, shell_futures, cell_id
2999 )
2999 )
3000 finally:
3000 finally:
3001 self.events.trigger('post_execute')
3001 self.events.trigger('post_execute')
3002 if not silent:
3002 if not silent:
3003 self.events.trigger('post_run_cell', result)
3003 self.events.trigger('post_run_cell', result)
3004 return result
3004 return result
3005
3005
3006 def _run_cell(
3006 def _run_cell(
3007 self,
3007 self,
3008 raw_cell: str,
3008 raw_cell: str,
3009 store_history: bool,
3009 store_history: bool,
3010 silent: bool,
3010 silent: bool,
3011 shell_futures: bool,
3011 shell_futures: bool,
3012 cell_id: str,
3012 cell_id: str,
3013 ) -> ExecutionResult:
3013 ) -> ExecutionResult:
3014 """Internal method to run a complete IPython cell."""
3014 """Internal method to run a complete IPython cell."""
3015
3015
3016 # we need to avoid calling self.transform_cell multiple time on the same thing
3016 # we need to avoid calling self.transform_cell multiple time on the same thing
3017 # so we need to store some results:
3017 # so we need to store some results:
3018 preprocessing_exc_tuple = None
3018 preprocessing_exc_tuple = None
3019 try:
3019 try:
3020 transformed_cell = self.transform_cell(raw_cell)
3020 transformed_cell = self.transform_cell(raw_cell)
3021 except Exception:
3021 except Exception:
3022 transformed_cell = raw_cell
3022 transformed_cell = raw_cell
3023 preprocessing_exc_tuple = sys.exc_info()
3023 preprocessing_exc_tuple = sys.exc_info()
3024
3024
3025 assert transformed_cell is not None
3025 assert transformed_cell is not None
3026 coro = self.run_cell_async(
3026 coro = self.run_cell_async(
3027 raw_cell,
3027 raw_cell,
3028 store_history=store_history,
3028 store_history=store_history,
3029 silent=silent,
3029 silent=silent,
3030 shell_futures=shell_futures,
3030 shell_futures=shell_futures,
3031 transformed_cell=transformed_cell,
3031 transformed_cell=transformed_cell,
3032 preprocessing_exc_tuple=preprocessing_exc_tuple,
3032 preprocessing_exc_tuple=preprocessing_exc_tuple,
3033 cell_id=cell_id,
3033 cell_id=cell_id,
3034 )
3034 )
3035
3035
3036 # run_cell_async is async, but may not actually need an eventloop.
3036 # run_cell_async is async, but may not actually need an eventloop.
3037 # when this is the case, we want to run it using the pseudo_sync_runner
3037 # when this is the case, we want to run it using the pseudo_sync_runner
3038 # so that code can invoke eventloops (for example via the %run , and
3038 # so that code can invoke eventloops (for example via the %run , and
3039 # `%paste` magic.
3039 # `%paste` magic.
3040 if self.trio_runner:
3040 if self.trio_runner:
3041 runner = self.trio_runner
3041 runner = self.trio_runner
3042 elif self.should_run_async(
3042 elif self.should_run_async(
3043 raw_cell,
3043 raw_cell,
3044 transformed_cell=transformed_cell,
3044 transformed_cell=transformed_cell,
3045 preprocessing_exc_tuple=preprocessing_exc_tuple,
3045 preprocessing_exc_tuple=preprocessing_exc_tuple,
3046 ):
3046 ):
3047 runner = self.loop_runner
3047 runner = self.loop_runner
3048 else:
3048 else:
3049 runner = _pseudo_sync_runner
3049 runner = _pseudo_sync_runner
3050
3050
3051 try:
3051 try:
3052 result = runner(coro)
3052 result = runner(coro)
3053 except BaseException as e:
3053 except BaseException as e:
3054 info = ExecutionInfo(
3054 info = ExecutionInfo(
3055 raw_cell, store_history, silent, shell_futures, cell_id
3055 raw_cell, store_history, silent, shell_futures, cell_id
3056 )
3056 )
3057 result = ExecutionResult(info)
3057 result = ExecutionResult(info)
3058 result.error_in_exec = e
3058 result.error_in_exec = e
3059 self.showtraceback(running_compiled_code=True)
3059 self.showtraceback(running_compiled_code=True)
3060 finally:
3060 finally:
3061 return result
3061 return result
3062
3062
3063 def should_run_async(
3063 def should_run_async(
3064 self, raw_cell: str, *, transformed_cell=None, preprocessing_exc_tuple=None
3064 self, raw_cell: str, *, transformed_cell=None, preprocessing_exc_tuple=None
3065 ) -> bool:
3065 ) -> bool:
3066 """Return whether a cell should be run asynchronously via a coroutine runner
3066 """Return whether a cell should be run asynchronously via a coroutine runner
3067
3067
3068 Parameters
3068 Parameters
3069 ----------
3069 ----------
3070 raw_cell : str
3070 raw_cell : str
3071 The code to be executed
3071 The code to be executed
3072
3072
3073 Returns
3073 Returns
3074 -------
3074 -------
3075 result: bool
3075 result: bool
3076 Whether the code needs to be run with a coroutine runner or not
3076 Whether the code needs to be run with a coroutine runner or not
3077 .. versionadded:: 7.0
3077 .. versionadded:: 7.0
3078 """
3078 """
3079 if not self.autoawait:
3079 if not self.autoawait:
3080 return False
3080 return False
3081 if preprocessing_exc_tuple is not None:
3081 if preprocessing_exc_tuple is not None:
3082 return False
3082 return False
3083 assert preprocessing_exc_tuple is None
3083 assert preprocessing_exc_tuple is None
3084 if transformed_cell is None:
3084 if transformed_cell is None:
3085 warnings.warn(
3085 warnings.warn(
3086 "`should_run_async` will not call `transform_cell`"
3086 "`should_run_async` will not call `transform_cell`"
3087 " automatically in the future. Please pass the result to"
3087 " automatically in the future. Please pass the result to"
3088 " `transformed_cell` argument and any exception that happen"
3088 " `transformed_cell` argument and any exception that happen"
3089 " during the"
3089 " during the"
3090 "transform in `preprocessing_exc_tuple` in"
3090 "transform in `preprocessing_exc_tuple` in"
3091 " IPython 7.17 and above.",
3091 " IPython 7.17 and above.",
3092 DeprecationWarning,
3092 DeprecationWarning,
3093 stacklevel=2,
3093 stacklevel=2,
3094 )
3094 )
3095 try:
3095 try:
3096 cell = self.transform_cell(raw_cell)
3096 cell = self.transform_cell(raw_cell)
3097 except Exception:
3097 except Exception:
3098 # any exception during transform will be raised
3098 # any exception during transform will be raised
3099 # prior to execution
3099 # prior to execution
3100 return False
3100 return False
3101 else:
3101 else:
3102 cell = transformed_cell
3102 cell = transformed_cell
3103 return _should_be_async(cell)
3103 return _should_be_async(cell)
3104
3104
3105 async def run_cell_async(
3105 async def run_cell_async(
3106 self,
3106 self,
3107 raw_cell: str,
3107 raw_cell: str,
3108 store_history=False,
3108 store_history=False,
3109 silent=False,
3109 silent=False,
3110 shell_futures=True,
3110 shell_futures=True,
3111 *,
3111 *,
3112 transformed_cell: Optional[str] = None,
3112 transformed_cell: Optional[str] = None,
3113 preprocessing_exc_tuple: Optional[Any] = None,
3113 preprocessing_exc_tuple: Optional[AnyType] = None,
3114 cell_id=None,
3114 cell_id=None,
3115 ) -> ExecutionResult:
3115 ) -> ExecutionResult:
3116 """Run a complete IPython cell asynchronously.
3116 """Run a complete IPython cell asynchronously.
3117
3117
3118 Parameters
3118 Parameters
3119 ----------
3119 ----------
3120 raw_cell : str
3120 raw_cell : str
3121 The code (including IPython code such as %magic functions) to run.
3121 The code (including IPython code such as %magic functions) to run.
3122 store_history : bool
3122 store_history : bool
3123 If True, the raw and translated cell will be stored in IPython's
3123 If True, the raw and translated cell will be stored in IPython's
3124 history. For user code calling back into IPython's machinery, this
3124 history. For user code calling back into IPython's machinery, this
3125 should be set to False.
3125 should be set to False.
3126 silent : bool
3126 silent : bool
3127 If True, avoid side-effects, such as implicit displayhooks and
3127 If True, avoid side-effects, such as implicit displayhooks and
3128 and logging. silent=True forces store_history=False.
3128 and logging. silent=True forces store_history=False.
3129 shell_futures : bool
3129 shell_futures : bool
3130 If True, the code will share future statements with the interactive
3130 If True, the code will share future statements with the interactive
3131 shell. It will both be affected by previous __future__ imports, and
3131 shell. It will both be affected by previous __future__ imports, and
3132 any __future__ imports in the code will affect the shell. If False,
3132 any __future__ imports in the code will affect the shell. If False,
3133 __future__ imports are not shared in either direction.
3133 __future__ imports are not shared in either direction.
3134 transformed_cell: str
3134 transformed_cell: str
3135 cell that was passed through transformers
3135 cell that was passed through transformers
3136 preprocessing_exc_tuple:
3136 preprocessing_exc_tuple:
3137 trace if the transformation failed.
3137 trace if the transformation failed.
3138
3138
3139 Returns
3139 Returns
3140 -------
3140 -------
3141 result : :class:`ExecutionResult`
3141 result : :class:`ExecutionResult`
3142
3142
3143 .. versionadded:: 7.0
3143 .. versionadded:: 7.0
3144 """
3144 """
3145 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures, cell_id)
3145 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures, cell_id)
3146 result = ExecutionResult(info)
3146 result = ExecutionResult(info)
3147
3147
3148 if (not raw_cell) or raw_cell.isspace():
3148 if (not raw_cell) or raw_cell.isspace():
3149 self.last_execution_succeeded = True
3149 self.last_execution_succeeded = True
3150 self.last_execution_result = result
3150 self.last_execution_result = result
3151 return result
3151 return result
3152
3152
3153 if silent:
3153 if silent:
3154 store_history = False
3154 store_history = False
3155
3155
3156 if store_history:
3156 if store_history:
3157 result.execution_count = self.execution_count
3157 result.execution_count = self.execution_count
3158
3158
3159 def error_before_exec(value):
3159 def error_before_exec(value):
3160 if store_history:
3160 if store_history:
3161 self.execution_count += 1
3161 self.execution_count += 1
3162 result.error_before_exec = value
3162 result.error_before_exec = value
3163 self.last_execution_succeeded = False
3163 self.last_execution_succeeded = False
3164 self.last_execution_result = result
3164 self.last_execution_result = result
3165 return result
3165 return result
3166
3166
3167 self.events.trigger('pre_execute')
3167 self.events.trigger('pre_execute')
3168 if not silent:
3168 if not silent:
3169 self.events.trigger('pre_run_cell', info)
3169 self.events.trigger('pre_run_cell', info)
3170
3170
3171 if transformed_cell is None:
3171 if transformed_cell is None:
3172 warnings.warn(
3172 warnings.warn(
3173 "`run_cell_async` will not call `transform_cell`"
3173 "`run_cell_async` will not call `transform_cell`"
3174 " automatically in the future. Please pass the result to"
3174 " automatically in the future. Please pass the result to"
3175 " `transformed_cell` argument and any exception that happen"
3175 " `transformed_cell` argument and any exception that happen"
3176 " during the"
3176 " during the"
3177 "transform in `preprocessing_exc_tuple` in"
3177 "transform in `preprocessing_exc_tuple` in"
3178 " IPython 7.17 and above.",
3178 " IPython 7.17 and above.",
3179 DeprecationWarning,
3179 DeprecationWarning,
3180 stacklevel=2,
3180 stacklevel=2,
3181 )
3181 )
3182 # If any of our input transformation (input_transformer_manager or
3182 # If any of our input transformation (input_transformer_manager or
3183 # prefilter_manager) raises an exception, we store it in this variable
3183 # prefilter_manager) raises an exception, we store it in this variable
3184 # so that we can display the error after logging the input and storing
3184 # so that we can display the error after logging the input and storing
3185 # it in the history.
3185 # it in the history.
3186 try:
3186 try:
3187 cell = self.transform_cell(raw_cell)
3187 cell = self.transform_cell(raw_cell)
3188 except Exception:
3188 except Exception:
3189 preprocessing_exc_tuple = sys.exc_info()
3189 preprocessing_exc_tuple = sys.exc_info()
3190 cell = raw_cell # cell has to exist so it can be stored/logged
3190 cell = raw_cell # cell has to exist so it can be stored/logged
3191 else:
3191 else:
3192 preprocessing_exc_tuple = None
3192 preprocessing_exc_tuple = None
3193 else:
3193 else:
3194 if preprocessing_exc_tuple is None:
3194 if preprocessing_exc_tuple is None:
3195 cell = transformed_cell
3195 cell = transformed_cell
3196 else:
3196 else:
3197 cell = raw_cell
3197 cell = raw_cell
3198
3198
3199 # Do NOT store paste/cpaste magic history
3199 # Do NOT store paste/cpaste magic history
3200 if "get_ipython().run_line_magic(" in cell and "paste" in cell:
3200 if "get_ipython().run_line_magic(" in cell and "paste" in cell:
3201 store_history = False
3201 store_history = False
3202
3202
3203 # Store raw and processed history
3203 # Store raw and processed history
3204 if store_history:
3204 if store_history:
3205 self.history_manager.store_inputs(self.execution_count, cell, raw_cell)
3205 self.history_manager.store_inputs(self.execution_count, cell, raw_cell)
3206 if not silent:
3206 if not silent:
3207 self.logger.log(cell, raw_cell)
3207 self.logger.log(cell, raw_cell)
3208
3208
3209 # Display the exception if input processing failed.
3209 # Display the exception if input processing failed.
3210 if preprocessing_exc_tuple is not None:
3210 if preprocessing_exc_tuple is not None:
3211 self.showtraceback(preprocessing_exc_tuple)
3211 self.showtraceback(preprocessing_exc_tuple)
3212 if store_history:
3212 if store_history:
3213 self.execution_count += 1
3213 self.execution_count += 1
3214 return error_before_exec(preprocessing_exc_tuple[1])
3214 return error_before_exec(preprocessing_exc_tuple[1])
3215
3215
3216 # Our own compiler remembers the __future__ environment. If we want to
3216 # Our own compiler remembers the __future__ environment. If we want to
3217 # run code with a separate __future__ environment, use the default
3217 # run code with a separate __future__ environment, use the default
3218 # compiler
3218 # compiler
3219 compiler = self.compile if shell_futures else self.compiler_class()
3219 compiler = self.compile if shell_futures else self.compiler_class()
3220
3220
3221 _run_async = False
3221 _run_async = False
3222
3222
3223 with self.builtin_trap:
3223 with self.builtin_trap:
3224 cell_name = compiler.cache(cell, self.execution_count, raw_code=raw_cell)
3224 cell_name = compiler.cache(cell, self.execution_count, raw_code=raw_cell)
3225
3225
3226 with self.display_trap:
3226 with self.display_trap:
3227 # Compile to bytecode
3227 # Compile to bytecode
3228 try:
3228 try:
3229 code_ast = compiler.ast_parse(cell, filename=cell_name)
3229 code_ast = compiler.ast_parse(cell, filename=cell_name)
3230 except self.custom_exceptions as e:
3230 except self.custom_exceptions as e:
3231 etype, value, tb = sys.exc_info()
3231 etype, value, tb = sys.exc_info()
3232 self.CustomTB(etype, value, tb)
3232 self.CustomTB(etype, value, tb)
3233 return error_before_exec(e)
3233 return error_before_exec(e)
3234 except IndentationError as e:
3234 except IndentationError as e:
3235 self.showindentationerror()
3235 self.showindentationerror()
3236 return error_before_exec(e)
3236 return error_before_exec(e)
3237 except (OverflowError, SyntaxError, ValueError, TypeError,
3237 except (OverflowError, SyntaxError, ValueError, TypeError,
3238 MemoryError) as e:
3238 MemoryError) as e:
3239 self.showsyntaxerror()
3239 self.showsyntaxerror()
3240 return error_before_exec(e)
3240 return error_before_exec(e)
3241
3241
3242 # Apply AST transformations
3242 # Apply AST transformations
3243 try:
3243 try:
3244 code_ast = self.transform_ast(code_ast)
3244 code_ast = self.transform_ast(code_ast)
3245 except InputRejected as e:
3245 except InputRejected as e:
3246 self.showtraceback()
3246 self.showtraceback()
3247 return error_before_exec(e)
3247 return error_before_exec(e)
3248
3248
3249 # Give the displayhook a reference to our ExecutionResult so it
3249 # Give the displayhook a reference to our ExecutionResult so it
3250 # can fill in the output value.
3250 # can fill in the output value.
3251 self.displayhook.exec_result = result
3251 self.displayhook.exec_result = result
3252
3252
3253 # Execute the user code
3253 # Execute the user code
3254 interactivity = "none" if silent else self.ast_node_interactivity
3254 interactivity = "none" if silent else self.ast_node_interactivity
3255
3255
3256
3256
3257 has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
3257 has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
3258 interactivity=interactivity, compiler=compiler, result=result)
3258 interactivity=interactivity, compiler=compiler, result=result)
3259
3259
3260 self.last_execution_succeeded = not has_raised
3260 self.last_execution_succeeded = not has_raised
3261 self.last_execution_result = result
3261 self.last_execution_result = result
3262
3262
3263 # Reset this so later displayed values do not modify the
3263 # Reset this so later displayed values do not modify the
3264 # ExecutionResult
3264 # ExecutionResult
3265 self.displayhook.exec_result = None
3265 self.displayhook.exec_result = None
3266
3266
3267 if store_history:
3267 if store_history:
3268 # Write output to the database. Does nothing unless
3268 # Write output to the database. Does nothing unless
3269 # history output logging is enabled.
3269 # history output logging is enabled.
3270 self.history_manager.store_output(self.execution_count)
3270 self.history_manager.store_output(self.execution_count)
3271 # Each cell is a *single* input, regardless of how many lines it has
3271 # Each cell is a *single* input, regardless of how many lines it has
3272 self.execution_count += 1
3272 self.execution_count += 1
3273
3273
3274 return result
3274 return result
3275
3275
3276 def transform_cell(self, raw_cell):
3276 def transform_cell(self, raw_cell):
3277 """Transform an input cell before parsing it.
3277 """Transform an input cell before parsing it.
3278
3278
3279 Static transformations, implemented in IPython.core.inputtransformer2,
3279 Static transformations, implemented in IPython.core.inputtransformer2,
3280 deal with things like ``%magic`` and ``!system`` commands.
3280 deal with things like ``%magic`` and ``!system`` commands.
3281 These run on all input.
3281 These run on all input.
3282 Dynamic transformations, for things like unescaped magics and the exit
3282 Dynamic transformations, for things like unescaped magics and the exit
3283 autocall, depend on the state of the interpreter.
3283 autocall, depend on the state of the interpreter.
3284 These only apply to single line inputs.
3284 These only apply to single line inputs.
3285
3285
3286 These string-based transformations are followed by AST transformations;
3286 These string-based transformations are followed by AST transformations;
3287 see :meth:`transform_ast`.
3287 see :meth:`transform_ast`.
3288 """
3288 """
3289 # Static input transformations
3289 # Static input transformations
3290 cell = self.input_transformer_manager.transform_cell(raw_cell)
3290 cell = self.input_transformer_manager.transform_cell(raw_cell)
3291
3291
3292 if len(cell.splitlines()) == 1:
3292 if len(cell.splitlines()) == 1:
3293 # Dynamic transformations - only applied for single line commands
3293 # Dynamic transformations - only applied for single line commands
3294 with self.builtin_trap:
3294 with self.builtin_trap:
3295 # use prefilter_lines to handle trailing newlines
3295 # use prefilter_lines to handle trailing newlines
3296 # restore trailing newline for ast.parse
3296 # restore trailing newline for ast.parse
3297 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
3297 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
3298
3298
3299 lines = cell.splitlines(keepends=True)
3299 lines = cell.splitlines(keepends=True)
3300 for transform in self.input_transformers_post:
3300 for transform in self.input_transformers_post:
3301 lines = transform(lines)
3301 lines = transform(lines)
3302 cell = ''.join(lines)
3302 cell = ''.join(lines)
3303
3303
3304 return cell
3304 return cell
3305
3305
3306 def transform_ast(self, node):
3306 def transform_ast(self, node):
3307 """Apply the AST transformations from self.ast_transformers
3307 """Apply the AST transformations from self.ast_transformers
3308
3308
3309 Parameters
3309 Parameters
3310 ----------
3310 ----------
3311 node : ast.Node
3311 node : ast.Node
3312 The root node to be transformed. Typically called with the ast.Module
3312 The root node to be transformed. Typically called with the ast.Module
3313 produced by parsing user input.
3313 produced by parsing user input.
3314
3314
3315 Returns
3315 Returns
3316 -------
3316 -------
3317 An ast.Node corresponding to the node it was called with. Note that it
3317 An ast.Node corresponding to the node it was called with. Note that it
3318 may also modify the passed object, so don't rely on references to the
3318 may also modify the passed object, so don't rely on references to the
3319 original AST.
3319 original AST.
3320 """
3320 """
3321 for transformer in self.ast_transformers:
3321 for transformer in self.ast_transformers:
3322 try:
3322 try:
3323 node = transformer.visit(node)
3323 node = transformer.visit(node)
3324 except InputRejected:
3324 except InputRejected:
3325 # User-supplied AST transformers can reject an input by raising
3325 # User-supplied AST transformers can reject an input by raising
3326 # an InputRejected. Short-circuit in this case so that we
3326 # an InputRejected. Short-circuit in this case so that we
3327 # don't unregister the transform.
3327 # don't unregister the transform.
3328 raise
3328 raise
3329 except Exception:
3329 except Exception:
3330 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
3330 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
3331 self.ast_transformers.remove(transformer)
3331 self.ast_transformers.remove(transformer)
3332
3332
3333 if self.ast_transformers:
3333 if self.ast_transformers:
3334 ast.fix_missing_locations(node)
3334 ast.fix_missing_locations(node)
3335 return node
3335 return node
3336
3336
3337 async def run_ast_nodes(
3337 async def run_ast_nodes(
3338 self,
3338 self,
3339 nodelist: ListType[stmt],
3339 nodelist: ListType[stmt],
3340 cell_name: str,
3340 cell_name: str,
3341 interactivity="last_expr",
3341 interactivity="last_expr",
3342 compiler=compile,
3342 compiler=compile,
3343 result=None,
3343 result=None,
3344 ):
3344 ):
3345 """Run a sequence of AST nodes. The execution mode depends on the
3345 """Run a sequence of AST nodes. The execution mode depends on the
3346 interactivity parameter.
3346 interactivity parameter.
3347
3347
3348 Parameters
3348 Parameters
3349 ----------
3349 ----------
3350 nodelist : list
3350 nodelist : list
3351 A sequence of AST nodes to run.
3351 A sequence of AST nodes to run.
3352 cell_name : str
3352 cell_name : str
3353 Will be passed to the compiler as the filename of the cell. Typically
3353 Will be passed to the compiler as the filename of the cell. Typically
3354 the value returned by ip.compile.cache(cell).
3354 the value returned by ip.compile.cache(cell).
3355 interactivity : str
3355 interactivity : str
3356 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none',
3356 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none',
3357 specifying which nodes should be run interactively (displaying output
3357 specifying which nodes should be run interactively (displaying output
3358 from expressions). 'last_expr' will run the last node interactively
3358 from expressions). 'last_expr' will run the last node interactively
3359 only if it is an expression (i.e. expressions in loops or other blocks
3359 only if it is an expression (i.e. expressions in loops or other blocks
3360 are not displayed) 'last_expr_or_assign' will run the last expression
3360 are not displayed) 'last_expr_or_assign' will run the last expression
3361 or the last assignment. Other values for this parameter will raise a
3361 or the last assignment. Other values for this parameter will raise a
3362 ValueError.
3362 ValueError.
3363
3363
3364 compiler : callable
3364 compiler : callable
3365 A function with the same interface as the built-in compile(), to turn
3365 A function with the same interface as the built-in compile(), to turn
3366 the AST nodes into code objects. Default is the built-in compile().
3366 the AST nodes into code objects. Default is the built-in compile().
3367 result : ExecutionResult, optional
3367 result : ExecutionResult, optional
3368 An object to store exceptions that occur during execution.
3368 An object to store exceptions that occur during execution.
3369
3369
3370 Returns
3370 Returns
3371 -------
3371 -------
3372 True if an exception occurred while running code, False if it finished
3372 True if an exception occurred while running code, False if it finished
3373 running.
3373 running.
3374 """
3374 """
3375 if not nodelist:
3375 if not nodelist:
3376 return
3376 return
3377
3377
3378
3378
3379 if interactivity == 'last_expr_or_assign':
3379 if interactivity == 'last_expr_or_assign':
3380 if isinstance(nodelist[-1], _assign_nodes):
3380 if isinstance(nodelist[-1], _assign_nodes):
3381 asg = nodelist[-1]
3381 asg = nodelist[-1]
3382 if isinstance(asg, ast.Assign) and len(asg.targets) == 1:
3382 if isinstance(asg, ast.Assign) and len(asg.targets) == 1:
3383 target = asg.targets[0]
3383 target = asg.targets[0]
3384 elif isinstance(asg, _single_targets_nodes):
3384 elif isinstance(asg, _single_targets_nodes):
3385 target = asg.target
3385 target = asg.target
3386 else:
3386 else:
3387 target = None
3387 target = None
3388 if isinstance(target, ast.Name):
3388 if isinstance(target, ast.Name):
3389 nnode = ast.Expr(ast.Name(target.id, ast.Load()))
3389 nnode = ast.Expr(ast.Name(target.id, ast.Load()))
3390 ast.fix_missing_locations(nnode)
3390 ast.fix_missing_locations(nnode)
3391 nodelist.append(nnode)
3391 nodelist.append(nnode)
3392 interactivity = 'last_expr'
3392 interactivity = 'last_expr'
3393
3393
3394 _async = False
3394 _async = False
3395 if interactivity == 'last_expr':
3395 if interactivity == 'last_expr':
3396 if isinstance(nodelist[-1], ast.Expr):
3396 if isinstance(nodelist[-1], ast.Expr):
3397 interactivity = "last"
3397 interactivity = "last"
3398 else:
3398 else:
3399 interactivity = "none"
3399 interactivity = "none"
3400
3400
3401 if interactivity == 'none':
3401 if interactivity == 'none':
3402 to_run_exec, to_run_interactive = nodelist, []
3402 to_run_exec, to_run_interactive = nodelist, []
3403 elif interactivity == 'last':
3403 elif interactivity == 'last':
3404 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
3404 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
3405 elif interactivity == 'all':
3405 elif interactivity == 'all':
3406 to_run_exec, to_run_interactive = [], nodelist
3406 to_run_exec, to_run_interactive = [], nodelist
3407 else:
3407 else:
3408 raise ValueError("Interactivity was %r" % interactivity)
3408 raise ValueError("Interactivity was %r" % interactivity)
3409
3409
3410 try:
3410 try:
3411
3411
3412 def compare(code):
3412 def compare(code):
3413 is_async = inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE
3413 is_async = inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE
3414 return is_async
3414 return is_async
3415
3415
3416 # refactor that to just change the mod constructor.
3416 # refactor that to just change the mod constructor.
3417 to_run = []
3417 to_run = []
3418 for node in to_run_exec:
3418 for node in to_run_exec:
3419 to_run.append((node, "exec"))
3419 to_run.append((node, "exec"))
3420
3420
3421 for node in to_run_interactive:
3421 for node in to_run_interactive:
3422 to_run.append((node, "single"))
3422 to_run.append((node, "single"))
3423
3423
3424 for node, mode in to_run:
3424 for node, mode in to_run:
3425 if mode == "exec":
3425 if mode == "exec":
3426 mod = Module([node], [])
3426 mod = Module([node], [])
3427 elif mode == "single":
3427 elif mode == "single":
3428 mod = ast.Interactive([node])
3428 mod = ast.Interactive([node]) # type: ignore
3429 with compiler.extra_flags(
3429 with compiler.extra_flags(
3430 getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
3430 getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
3431 if self.autoawait
3431 if self.autoawait
3432 else 0x0
3432 else 0x0
3433 ):
3433 ):
3434 code = compiler(mod, cell_name, mode)
3434 code = compiler(mod, cell_name, mode)
3435 asy = compare(code)
3435 asy = compare(code)
3436 if await self.run_code(code, result, async_=asy):
3436 if await self.run_code(code, result, async_=asy):
3437 return True
3437 return True
3438
3438
3439 # Flush softspace
3439 # Flush softspace
3440 if softspace(sys.stdout, 0):
3440 if softspace(sys.stdout, 0):
3441 print()
3441 print()
3442
3442
3443 except:
3443 except:
3444 # It's possible to have exceptions raised here, typically by
3444 # It's possible to have exceptions raised here, typically by
3445 # compilation of odd code (such as a naked 'return' outside a
3445 # compilation of odd code (such as a naked 'return' outside a
3446 # function) that did parse but isn't valid. Typically the exception
3446 # function) that did parse but isn't valid. Typically the exception
3447 # is a SyntaxError, but it's safest just to catch anything and show
3447 # is a SyntaxError, but it's safest just to catch anything and show
3448 # the user a traceback.
3448 # the user a traceback.
3449
3449
3450 # We do only one try/except outside the loop to minimize the impact
3450 # We do only one try/except outside the loop to minimize the impact
3451 # on runtime, and also because if any node in the node list is
3451 # on runtime, and also because if any node in the node list is
3452 # broken, we should stop execution completely.
3452 # broken, we should stop execution completely.
3453 if result:
3453 if result:
3454 result.error_before_exec = sys.exc_info()[1]
3454 result.error_before_exec = sys.exc_info()[1]
3455 self.showtraceback()
3455 self.showtraceback()
3456 return True
3456 return True
3457
3457
3458 return False
3458 return False
3459
3459
3460 async def run_code(self, code_obj, result=None, *, async_=False):
3460 async def run_code(self, code_obj, result=None, *, async_=False):
3461 """Execute a code object.
3461 """Execute a code object.
3462
3462
3463 When an exception occurs, self.showtraceback() is called to display a
3463 When an exception occurs, self.showtraceback() is called to display a
3464 traceback.
3464 traceback.
3465
3465
3466 Parameters
3466 Parameters
3467 ----------
3467 ----------
3468 code_obj : code object
3468 code_obj : code object
3469 A compiled code object, to be executed
3469 A compiled code object, to be executed
3470 result : ExecutionResult, optional
3470 result : ExecutionResult, optional
3471 An object to store exceptions that occur during execution.
3471 An object to store exceptions that occur during execution.
3472 async_ : Bool (Experimental)
3472 async_ : Bool (Experimental)
3473 Attempt to run top-level asynchronous code in a default loop.
3473 Attempt to run top-level asynchronous code in a default loop.
3474
3474
3475 Returns
3475 Returns
3476 -------
3476 -------
3477 False : successful execution.
3477 False : successful execution.
3478 True : an error occurred.
3478 True : an error occurred.
3479 """
3479 """
3480 # special value to say that anything above is IPython and should be
3480 # special value to say that anything above is IPython and should be
3481 # hidden.
3481 # hidden.
3482 __tracebackhide__ = "__ipython_bottom__"
3482 __tracebackhide__ = "__ipython_bottom__"
3483 # Set our own excepthook in case the user code tries to call it
3483 # Set our own excepthook in case the user code tries to call it
3484 # directly, so that the IPython crash handler doesn't get triggered
3484 # directly, so that the IPython crash handler doesn't get triggered
3485 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3485 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3486
3486
3487 # we save the original sys.excepthook in the instance, in case config
3487 # we save the original sys.excepthook in the instance, in case config
3488 # code (such as magics) needs access to it.
3488 # code (such as magics) needs access to it.
3489 self.sys_excepthook = old_excepthook
3489 self.sys_excepthook = old_excepthook
3490 outflag = True # happens in more places, so it's easier as default
3490 outflag = True # happens in more places, so it's easier as default
3491 try:
3491 try:
3492 try:
3492 try:
3493 if async_:
3493 if async_:
3494 await eval(code_obj, self.user_global_ns, self.user_ns)
3494 await eval(code_obj, self.user_global_ns, self.user_ns)
3495 else:
3495 else:
3496 exec(code_obj, self.user_global_ns, self.user_ns)
3496 exec(code_obj, self.user_global_ns, self.user_ns)
3497 finally:
3497 finally:
3498 # Reset our crash handler in place
3498 # Reset our crash handler in place
3499 sys.excepthook = old_excepthook
3499 sys.excepthook = old_excepthook
3500 except SystemExit as e:
3500 except SystemExit as e:
3501 if result is not None:
3501 if result is not None:
3502 result.error_in_exec = e
3502 result.error_in_exec = e
3503 self.showtraceback(exception_only=True)
3503 self.showtraceback(exception_only=True)
3504 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3504 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3505 except bdb.BdbQuit:
3505 except bdb.BdbQuit:
3506 etype, value, tb = sys.exc_info()
3506 etype, value, tb = sys.exc_info()
3507 if result is not None:
3507 if result is not None:
3508 result.error_in_exec = value
3508 result.error_in_exec = value
3509 # the BdbQuit stops here
3509 # the BdbQuit stops here
3510 except self.custom_exceptions:
3510 except self.custom_exceptions:
3511 etype, value, tb = sys.exc_info()
3511 etype, value, tb = sys.exc_info()
3512 if result is not None:
3512 if result is not None:
3513 result.error_in_exec = value
3513 result.error_in_exec = value
3514 self.CustomTB(etype, value, tb)
3514 self.CustomTB(etype, value, tb)
3515 except:
3515 except:
3516 if result is not None:
3516 if result is not None:
3517 result.error_in_exec = sys.exc_info()[1]
3517 result.error_in_exec = sys.exc_info()[1]
3518 self.showtraceback(running_compiled_code=True)
3518 self.showtraceback(running_compiled_code=True)
3519 else:
3519 else:
3520 outflag = False
3520 outflag = False
3521 return outflag
3521 return outflag
3522
3522
3523 # For backwards compatibility
3523 # For backwards compatibility
3524 runcode = run_code
3524 runcode = run_code
3525
3525
3526 def check_complete(self, code: str) -> Tuple[str, str]:
3526 def check_complete(self, code: str) -> Tuple[str, str]:
3527 """Return whether a block of code is ready to execute, or should be continued
3527 """Return whether a block of code is ready to execute, or should be continued
3528
3528
3529 Parameters
3529 Parameters
3530 ----------
3530 ----------
3531 code : string
3531 code : string
3532 Python input code, which can be multiline.
3532 Python input code, which can be multiline.
3533
3533
3534 Returns
3534 Returns
3535 -------
3535 -------
3536 status : str
3536 status : str
3537 One of 'complete', 'incomplete', or 'invalid' if source is not a
3537 One of 'complete', 'incomplete', or 'invalid' if source is not a
3538 prefix of valid code.
3538 prefix of valid code.
3539 indent : str
3539 indent : str
3540 When status is 'incomplete', this is some whitespace to insert on
3540 When status is 'incomplete', this is some whitespace to insert on
3541 the next line of the prompt.
3541 the next line of the prompt.
3542 """
3542 """
3543 status, nspaces = self.input_transformer_manager.check_complete(code)
3543 status, nspaces = self.input_transformer_manager.check_complete(code)
3544 return status, ' ' * (nspaces or 0)
3544 return status, ' ' * (nspaces or 0)
3545
3545
3546 #-------------------------------------------------------------------------
3546 #-------------------------------------------------------------------------
3547 # Things related to GUI support and pylab
3547 # Things related to GUI support and pylab
3548 #-------------------------------------------------------------------------
3548 #-------------------------------------------------------------------------
3549
3549
3550 active_eventloop = None
3550 active_eventloop = None
3551
3551
3552 def enable_gui(self, gui=None):
3552 def enable_gui(self, gui=None):
3553 raise NotImplementedError('Implement enable_gui in a subclass')
3553 raise NotImplementedError('Implement enable_gui in a subclass')
3554
3554
3555 def enable_matplotlib(self, gui=None):
3555 def enable_matplotlib(self, gui=None):
3556 """Enable interactive matplotlib and inline figure support.
3556 """Enable interactive matplotlib and inline figure support.
3557
3557
3558 This takes the following steps:
3558 This takes the following steps:
3559
3559
3560 1. select the appropriate eventloop and matplotlib backend
3560 1. select the appropriate eventloop and matplotlib backend
3561 2. set up matplotlib for interactive use with that backend
3561 2. set up matplotlib for interactive use with that backend
3562 3. configure formatters for inline figure display
3562 3. configure formatters for inline figure display
3563 4. enable the selected gui eventloop
3563 4. enable the selected gui eventloop
3564
3564
3565 Parameters
3565 Parameters
3566 ----------
3566 ----------
3567 gui : optional, string
3567 gui : optional, string
3568 If given, dictates the choice of matplotlib GUI backend to use
3568 If given, dictates the choice of matplotlib GUI backend to use
3569 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3569 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3570 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3570 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3571 matplotlib (as dictated by the matplotlib build-time options plus the
3571 matplotlib (as dictated by the matplotlib build-time options plus the
3572 user's matplotlibrc configuration file). Note that not all backends
3572 user's matplotlibrc configuration file). Note that not all backends
3573 make sense in all contexts, for example a terminal ipython can't
3573 make sense in all contexts, for example a terminal ipython can't
3574 display figures inline.
3574 display figures inline.
3575 """
3575 """
3576 from matplotlib_inline.backend_inline import configure_inline_support
3576 from matplotlib_inline.backend_inline import configure_inline_support
3577
3577
3578 from IPython.core import pylabtools as pt
3578 from IPython.core import pylabtools as pt
3579 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3579 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3580
3580
3581 if gui != 'inline':
3581 if gui != 'inline':
3582 # If we have our first gui selection, store it
3582 # If we have our first gui selection, store it
3583 if self.pylab_gui_select is None:
3583 if self.pylab_gui_select is None:
3584 self.pylab_gui_select = gui
3584 self.pylab_gui_select = gui
3585 # Otherwise if they are different
3585 # Otherwise if they are different
3586 elif gui != self.pylab_gui_select:
3586 elif gui != self.pylab_gui_select:
3587 print('Warning: Cannot change to a different GUI toolkit: %s.'
3587 print('Warning: Cannot change to a different GUI toolkit: %s.'
3588 ' Using %s instead.' % (gui, self.pylab_gui_select))
3588 ' Using %s instead.' % (gui, self.pylab_gui_select))
3589 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3589 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3590
3590
3591 pt.activate_matplotlib(backend)
3591 pt.activate_matplotlib(backend)
3592 configure_inline_support(self, backend)
3592 configure_inline_support(self, backend)
3593
3593
3594 # Now we must activate the gui pylab wants to use, and fix %run to take
3594 # Now we must activate the gui pylab wants to use, and fix %run to take
3595 # plot updates into account
3595 # plot updates into account
3596 self.enable_gui(gui)
3596 self.enable_gui(gui)
3597 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3597 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3598 pt.mpl_runner(self.safe_execfile)
3598 pt.mpl_runner(self.safe_execfile)
3599
3599
3600 return gui, backend
3600 return gui, backend
3601
3601
3602 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3602 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3603 """Activate pylab support at runtime.
3603 """Activate pylab support at runtime.
3604
3604
3605 This turns on support for matplotlib, preloads into the interactive
3605 This turns on support for matplotlib, preloads into the interactive
3606 namespace all of numpy and pylab, and configures IPython to correctly
3606 namespace all of numpy and pylab, and configures IPython to correctly
3607 interact with the GUI event loop. The GUI backend to be used can be
3607 interact with the GUI event loop. The GUI backend to be used can be
3608 optionally selected with the optional ``gui`` argument.
3608 optionally selected with the optional ``gui`` argument.
3609
3609
3610 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3610 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3611
3611
3612 Parameters
3612 Parameters
3613 ----------
3613 ----------
3614 gui : optional, string
3614 gui : optional, string
3615 If given, dictates the choice of matplotlib GUI backend to use
3615 If given, dictates the choice of matplotlib GUI backend to use
3616 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3616 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3617 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3617 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3618 matplotlib (as dictated by the matplotlib build-time options plus the
3618 matplotlib (as dictated by the matplotlib build-time options plus the
3619 user's matplotlibrc configuration file). Note that not all backends
3619 user's matplotlibrc configuration file). Note that not all backends
3620 make sense in all contexts, for example a terminal ipython can't
3620 make sense in all contexts, for example a terminal ipython can't
3621 display figures inline.
3621 display figures inline.
3622 import_all : optional, bool, default: True
3622 import_all : optional, bool, default: True
3623 Whether to do `from numpy import *` and `from pylab import *`
3623 Whether to do `from numpy import *` and `from pylab import *`
3624 in addition to module imports.
3624 in addition to module imports.
3625 welcome_message : deprecated
3625 welcome_message : deprecated
3626 This argument is ignored, no welcome message will be displayed.
3626 This argument is ignored, no welcome message will be displayed.
3627 """
3627 """
3628 from IPython.core.pylabtools import import_pylab
3628 from IPython.core.pylabtools import import_pylab
3629
3629
3630 gui, backend = self.enable_matplotlib(gui)
3630 gui, backend = self.enable_matplotlib(gui)
3631
3631
3632 # We want to prevent the loading of pylab to pollute the user's
3632 # We want to prevent the loading of pylab to pollute the user's
3633 # namespace as shown by the %who* magics, so we execute the activation
3633 # namespace as shown by the %who* magics, so we execute the activation
3634 # code in an empty namespace, and we update *both* user_ns and
3634 # code in an empty namespace, and we update *both* user_ns and
3635 # user_ns_hidden with this information.
3635 # user_ns_hidden with this information.
3636 ns = {}
3636 ns = {}
3637 import_pylab(ns, import_all)
3637 import_pylab(ns, import_all)
3638 # warn about clobbered names
3638 # warn about clobbered names
3639 ignored = {"__builtins__"}
3639 ignored = {"__builtins__"}
3640 both = set(ns).intersection(self.user_ns).difference(ignored)
3640 both = set(ns).intersection(self.user_ns).difference(ignored)
3641 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3641 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3642 self.user_ns.update(ns)
3642 self.user_ns.update(ns)
3643 self.user_ns_hidden.update(ns)
3643 self.user_ns_hidden.update(ns)
3644 return gui, backend, clobbered
3644 return gui, backend, clobbered
3645
3645
3646 #-------------------------------------------------------------------------
3646 #-------------------------------------------------------------------------
3647 # Utilities
3647 # Utilities
3648 #-------------------------------------------------------------------------
3648 #-------------------------------------------------------------------------
3649
3649
3650 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3650 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3651 """Expand python variables in a string.
3651 """Expand python variables in a string.
3652
3652
3653 The depth argument indicates how many frames above the caller should
3653 The depth argument indicates how many frames above the caller should
3654 be walked to look for the local namespace where to expand variables.
3654 be walked to look for the local namespace where to expand variables.
3655
3655
3656 The global namespace for expansion is always the user's interactive
3656 The global namespace for expansion is always the user's interactive
3657 namespace.
3657 namespace.
3658 """
3658 """
3659 ns = self.user_ns.copy()
3659 ns = self.user_ns.copy()
3660 try:
3660 try:
3661 frame = sys._getframe(depth+1)
3661 frame = sys._getframe(depth+1)
3662 except ValueError:
3662 except ValueError:
3663 # This is thrown if there aren't that many frames on the stack,
3663 # This is thrown if there aren't that many frames on the stack,
3664 # e.g. if a script called run_line_magic() directly.
3664 # e.g. if a script called run_line_magic() directly.
3665 pass
3665 pass
3666 else:
3666 else:
3667 ns.update(frame.f_locals)
3667 ns.update(frame.f_locals)
3668
3668
3669 try:
3669 try:
3670 # We have to use .vformat() here, because 'self' is a valid and common
3670 # We have to use .vformat() here, because 'self' is a valid and common
3671 # name, and expanding **ns for .format() would make it collide with
3671 # name, and expanding **ns for .format() would make it collide with
3672 # the 'self' argument of the method.
3672 # the 'self' argument of the method.
3673 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3673 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3674 except Exception:
3674 except Exception:
3675 # if formatter couldn't format, just let it go untransformed
3675 # if formatter couldn't format, just let it go untransformed
3676 pass
3676 pass
3677 return cmd
3677 return cmd
3678
3678
3679 def mktempfile(self, data=None, prefix='ipython_edit_'):
3679 def mktempfile(self, data=None, prefix='ipython_edit_'):
3680 """Make a new tempfile and return its filename.
3680 """Make a new tempfile and return its filename.
3681
3681
3682 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3682 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3683 but it registers the created filename internally so ipython cleans it up
3683 but it registers the created filename internally so ipython cleans it up
3684 at exit time.
3684 at exit time.
3685
3685
3686 Optional inputs:
3686 Optional inputs:
3687
3687
3688 - data(None): if data is given, it gets written out to the temp file
3688 - data(None): if data is given, it gets written out to the temp file
3689 immediately, and the file is closed again."""
3689 immediately, and the file is closed again."""
3690
3690
3691 dir_path = Path(tempfile.mkdtemp(prefix=prefix))
3691 dir_path = Path(tempfile.mkdtemp(prefix=prefix))
3692 self.tempdirs.append(dir_path)
3692 self.tempdirs.append(dir_path)
3693
3693
3694 handle, filename = tempfile.mkstemp(".py", prefix, dir=str(dir_path))
3694 handle, filename = tempfile.mkstemp(".py", prefix, dir=str(dir_path))
3695 os.close(handle) # On Windows, there can only be one open handle on a file
3695 os.close(handle) # On Windows, there can only be one open handle on a file
3696
3696
3697 file_path = Path(filename)
3697 file_path = Path(filename)
3698 self.tempfiles.append(file_path)
3698 self.tempfiles.append(file_path)
3699
3699
3700 if data:
3700 if data:
3701 file_path.write_text(data, encoding="utf-8")
3701 file_path.write_text(data, encoding="utf-8")
3702 return filename
3702 return filename
3703
3703
3704 def ask_yes_no(self, prompt, default=None, interrupt=None):
3704 def ask_yes_no(self, prompt, default=None, interrupt=None):
3705 if self.quiet:
3705 if self.quiet:
3706 return True
3706 return True
3707 return ask_yes_no(prompt,default,interrupt)
3707 return ask_yes_no(prompt,default,interrupt)
3708
3708
3709 def show_usage(self):
3709 def show_usage(self):
3710 """Show a usage message"""
3710 """Show a usage message"""
3711 page.page(IPython.core.usage.interactive_usage)
3711 page.page(IPython.core.usage.interactive_usage)
3712
3712
3713 def extract_input_lines(self, range_str, raw=False):
3713 def extract_input_lines(self, range_str, raw=False):
3714 """Return as a string a set of input history slices.
3714 """Return as a string a set of input history slices.
3715
3715
3716 Parameters
3716 Parameters
3717 ----------
3717 ----------
3718 range_str : str
3718 range_str : str
3719 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3719 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3720 since this function is for use by magic functions which get their
3720 since this function is for use by magic functions which get their
3721 arguments as strings. The number before the / is the session
3721 arguments as strings. The number before the / is the session
3722 number: ~n goes n back from the current session.
3722 number: ~n goes n back from the current session.
3723
3723
3724 If empty string is given, returns history of current session
3724 If empty string is given, returns history of current session
3725 without the last input.
3725 without the last input.
3726
3726
3727 raw : bool, optional
3727 raw : bool, optional
3728 By default, the processed input is used. If this is true, the raw
3728 By default, the processed input is used. If this is true, the raw
3729 input history is used instead.
3729 input history is used instead.
3730
3730
3731 Notes
3731 Notes
3732 -----
3732 -----
3733 Slices can be described with two notations:
3733 Slices can be described with two notations:
3734
3734
3735 * ``N:M`` -> standard python form, means including items N...(M-1).
3735 * ``N:M`` -> standard python form, means including items N...(M-1).
3736 * ``N-M`` -> include items N..M (closed endpoint).
3736 * ``N-M`` -> include items N..M (closed endpoint).
3737 """
3737 """
3738 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3738 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3739 text = "\n".join(x for _, _, x in lines)
3739 text = "\n".join(x for _, _, x in lines)
3740
3740
3741 # Skip the last line, as it's probably the magic that called this
3741 # Skip the last line, as it's probably the magic that called this
3742 if not range_str:
3742 if not range_str:
3743 if "\n" not in text:
3743 if "\n" not in text:
3744 text = ""
3744 text = ""
3745 else:
3745 else:
3746 text = text[: text.rfind("\n")]
3746 text = text[: text.rfind("\n")]
3747
3747
3748 return text
3748 return text
3749
3749
3750 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3750 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3751 """Get a code string from history, file, url, or a string or macro.
3751 """Get a code string from history, file, url, or a string or macro.
3752
3752
3753 This is mainly used by magic functions.
3753 This is mainly used by magic functions.
3754
3754
3755 Parameters
3755 Parameters
3756 ----------
3756 ----------
3757 target : str
3757 target : str
3758 A string specifying code to retrieve. This will be tried respectively
3758 A string specifying code to retrieve. This will be tried respectively
3759 as: ranges of input history (see %history for syntax), url,
3759 as: ranges of input history (see %history for syntax), url,
3760 corresponding .py file, filename, or an expression evaluating to a
3760 corresponding .py file, filename, or an expression evaluating to a
3761 string or Macro in the user namespace.
3761 string or Macro in the user namespace.
3762
3762
3763 If empty string is given, returns complete history of current
3763 If empty string is given, returns complete history of current
3764 session, without the last line.
3764 session, without the last line.
3765
3765
3766 raw : bool
3766 raw : bool
3767 If true (default), retrieve raw history. Has no effect on the other
3767 If true (default), retrieve raw history. Has no effect on the other
3768 retrieval mechanisms.
3768 retrieval mechanisms.
3769
3769
3770 py_only : bool (default False)
3770 py_only : bool (default False)
3771 Only try to fetch python code, do not try alternative methods to decode file
3771 Only try to fetch python code, do not try alternative methods to decode file
3772 if unicode fails.
3772 if unicode fails.
3773
3773
3774 Returns
3774 Returns
3775 -------
3775 -------
3776 A string of code.
3776 A string of code.
3777 ValueError is raised if nothing is found, and TypeError if it evaluates
3777 ValueError is raised if nothing is found, and TypeError if it evaluates
3778 to an object of another type. In each case, .args[0] is a printable
3778 to an object of another type. In each case, .args[0] is a printable
3779 message.
3779 message.
3780 """
3780 """
3781 code = self.extract_input_lines(target, raw=raw) # Grab history
3781 code = self.extract_input_lines(target, raw=raw) # Grab history
3782 if code:
3782 if code:
3783 return code
3783 return code
3784 try:
3784 try:
3785 if target.startswith(('http://', 'https://')):
3785 if target.startswith(('http://', 'https://')):
3786 return openpy.read_py_url(target, skip_encoding_cookie=skip_encoding_cookie)
3786 return openpy.read_py_url(target, skip_encoding_cookie=skip_encoding_cookie)
3787 except UnicodeDecodeError as e:
3787 except UnicodeDecodeError as e:
3788 if not py_only :
3788 if not py_only :
3789 # Deferred import
3789 # Deferred import
3790 from urllib.request import urlopen
3790 from urllib.request import urlopen
3791 response = urlopen(target)
3791 response = urlopen(target)
3792 return response.read().decode('latin1')
3792 return response.read().decode('latin1')
3793 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3793 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3794
3794
3795 potential_target = [target]
3795 potential_target = [target]
3796 try :
3796 try :
3797 potential_target.insert(0,get_py_filename(target))
3797 potential_target.insert(0,get_py_filename(target))
3798 except IOError:
3798 except IOError:
3799 pass
3799 pass
3800
3800
3801 for tgt in potential_target :
3801 for tgt in potential_target :
3802 if os.path.isfile(tgt): # Read file
3802 if os.path.isfile(tgt): # Read file
3803 try :
3803 try :
3804 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3804 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3805 except UnicodeDecodeError as e:
3805 except UnicodeDecodeError as e:
3806 if not py_only :
3806 if not py_only :
3807 with io_open(tgt,'r', encoding='latin1') as f :
3807 with io_open(tgt,'r', encoding='latin1') as f :
3808 return f.read()
3808 return f.read()
3809 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3809 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3810 elif os.path.isdir(os.path.expanduser(tgt)):
3810 elif os.path.isdir(os.path.expanduser(tgt)):
3811 raise ValueError("'%s' is a directory, not a regular file." % target)
3811 raise ValueError("'%s' is a directory, not a regular file." % target)
3812
3812
3813 if search_ns:
3813 if search_ns:
3814 # Inspect namespace to load object source
3814 # Inspect namespace to load object source
3815 object_info = self.object_inspect(target, detail_level=1)
3815 object_info = self.object_inspect(target, detail_level=1)
3816 if object_info['found'] and object_info['source']:
3816 if object_info['found'] and object_info['source']:
3817 return object_info['source']
3817 return object_info['source']
3818
3818
3819 try: # User namespace
3819 try: # User namespace
3820 codeobj = eval(target, self.user_ns)
3820 codeobj = eval(target, self.user_ns)
3821 except Exception as e:
3821 except Exception as e:
3822 raise ValueError(("'%s' was not found in history, as a file, url, "
3822 raise ValueError(("'%s' was not found in history, as a file, url, "
3823 "nor in the user namespace.") % target) from e
3823 "nor in the user namespace.") % target) from e
3824
3824
3825 if isinstance(codeobj, str):
3825 if isinstance(codeobj, str):
3826 return codeobj
3826 return codeobj
3827 elif isinstance(codeobj, Macro):
3827 elif isinstance(codeobj, Macro):
3828 return codeobj.value
3828 return codeobj.value
3829
3829
3830 raise TypeError("%s is neither a string nor a macro." % target,
3830 raise TypeError("%s is neither a string nor a macro." % target,
3831 codeobj)
3831 codeobj)
3832
3832
3833 def _atexit_once(self):
3833 def _atexit_once(self):
3834 """
3834 """
3835 At exist operation that need to be called at most once.
3835 At exist operation that need to be called at most once.
3836 Second call to this function per instance will do nothing.
3836 Second call to this function per instance will do nothing.
3837 """
3837 """
3838
3838
3839 if not getattr(self, "_atexit_once_called", False):
3839 if not getattr(self, "_atexit_once_called", False):
3840 self._atexit_once_called = True
3840 self._atexit_once_called = True
3841 # Clear all user namespaces to release all references cleanly.
3841 # Clear all user namespaces to release all references cleanly.
3842 self.reset(new_session=False)
3842 self.reset(new_session=False)
3843 # Close the history session (this stores the end time and line count)
3843 # Close the history session (this stores the end time and line count)
3844 # this must be *before* the tempfile cleanup, in case of temporary
3844 # this must be *before* the tempfile cleanup, in case of temporary
3845 # history db
3845 # history db
3846 self.history_manager.end_session()
3846 self.history_manager.end_session()
3847 self.history_manager = None
3847 self.history_manager = None
3848
3848
3849 #-------------------------------------------------------------------------
3849 #-------------------------------------------------------------------------
3850 # Things related to IPython exiting
3850 # Things related to IPython exiting
3851 #-------------------------------------------------------------------------
3851 #-------------------------------------------------------------------------
3852 def atexit_operations(self):
3852 def atexit_operations(self):
3853 """This will be executed at the time of exit.
3853 """This will be executed at the time of exit.
3854
3854
3855 Cleanup operations and saving of persistent data that is done
3855 Cleanup operations and saving of persistent data that is done
3856 unconditionally by IPython should be performed here.
3856 unconditionally by IPython should be performed here.
3857
3857
3858 For things that may depend on startup flags or platform specifics (such
3858 For things that may depend on startup flags or platform specifics (such
3859 as having readline or not), register a separate atexit function in the
3859 as having readline or not), register a separate atexit function in the
3860 code that has the appropriate information, rather than trying to
3860 code that has the appropriate information, rather than trying to
3861 clutter
3861 clutter
3862 """
3862 """
3863 self._atexit_once()
3863 self._atexit_once()
3864
3864
3865 # Cleanup all tempfiles and folders left around
3865 # Cleanup all tempfiles and folders left around
3866 for tfile in self.tempfiles:
3866 for tfile in self.tempfiles:
3867 try:
3867 try:
3868 tfile.unlink()
3868 tfile.unlink()
3869 self.tempfiles.remove(tfile)
3869 self.tempfiles.remove(tfile)
3870 except FileNotFoundError:
3870 except FileNotFoundError:
3871 pass
3871 pass
3872 del self.tempfiles
3872 del self.tempfiles
3873 for tdir in self.tempdirs:
3873 for tdir in self.tempdirs:
3874 try:
3874 try:
3875 tdir.rmdir()
3875 tdir.rmdir()
3876 self.tempdirs.remove(tdir)
3876 self.tempdirs.remove(tdir)
3877 except FileNotFoundError:
3877 except FileNotFoundError:
3878 pass
3878 pass
3879 del self.tempdirs
3879 del self.tempdirs
3880
3880
3881 # Restore user's cursor
3881 # Restore user's cursor
3882 if hasattr(self, "editing_mode") and self.editing_mode == "vi":
3882 if hasattr(self, "editing_mode") and self.editing_mode == "vi":
3883 sys.stdout.write("\x1b[0 q")
3883 sys.stdout.write("\x1b[0 q")
3884 sys.stdout.flush()
3884 sys.stdout.flush()
3885
3885
3886 def cleanup(self):
3886 def cleanup(self):
3887 self.restore_sys_module_state()
3887 self.restore_sys_module_state()
3888
3888
3889
3889
3890 # Overridden in terminal subclass to change prompts
3890 # Overridden in terminal subclass to change prompts
3891 def switch_doctest_mode(self, mode):
3891 def switch_doctest_mode(self, mode):
3892 pass
3892 pass
3893
3893
3894
3894
3895 class InteractiveShellABC(metaclass=abc.ABCMeta):
3895 class InteractiveShellABC(metaclass=abc.ABCMeta):
3896 """An abstract base class for InteractiveShell."""
3896 """An abstract base class for InteractiveShell."""
3897
3897
3898 InteractiveShellABC.register(InteractiveShell)
3898 InteractiveShellABC.register(InteractiveShell)
@@ -1,310 +1,310 b''
1 ''' A decorator-based method of constructing IPython magics with `argparse`
1 ''' A decorator-based method of constructing IPython magics with `argparse`
2 option handling.
2 option handling.
3
3
4 New magic functions can be defined like so::
4 New magic functions can be defined like so::
5
5
6 from IPython.core.magic_arguments import (argument, magic_arguments,
6 from IPython.core.magic_arguments import (argument, magic_arguments,
7 parse_argstring)
7 parse_argstring)
8
8
9 @magic_arguments()
9 @magic_arguments()
10 @argument('-o', '--option', help='An optional argument.')
10 @argument('-o', '--option', help='An optional argument.')
11 @argument('arg', type=int, help='An integer positional argument.')
11 @argument('arg', type=int, help='An integer positional argument.')
12 def magic_cool(self, arg):
12 def magic_cool(self, arg):
13 """ A really cool magic command.
13 """ A really cool magic command.
14
14
15 """
15 """
16 args = parse_argstring(magic_cool, arg)
16 args = parse_argstring(magic_cool, arg)
17 ...
17 ...
18
18
19 The `@magic_arguments` decorator marks the function as having argparse arguments.
19 The `@magic_arguments` decorator marks the function as having argparse arguments.
20 The `@argument` decorator adds an argument using the same syntax as argparse's
20 The `@argument` decorator adds an argument using the same syntax as argparse's
21 `add_argument()` method. More sophisticated uses may also require the
21 `add_argument()` method. More sophisticated uses may also require the
22 `@argument_group` or `@kwds` decorator to customize the formatting and the
22 `@argument_group` or `@kwds` decorator to customize the formatting and the
23 parsing.
23 parsing.
24
24
25 Help text for the magic is automatically generated from the docstring and the
25 Help text for the magic is automatically generated from the docstring and the
26 arguments::
26 arguments::
27
27
28 In[1]: %cool?
28 In[1]: %cool?
29 %cool [-o OPTION] arg
29 %cool [-o OPTION] arg
30
30
31 A really cool magic command.
31 A really cool magic command.
32
32
33 positional arguments:
33 positional arguments:
34 arg An integer positional argument.
34 arg An integer positional argument.
35
35
36 optional arguments:
36 optional arguments:
37 -o OPTION, --option OPTION
37 -o OPTION, --option OPTION
38 An optional argument.
38 An optional argument.
39
39
40 Here is an elaborated example that uses default parameters in `argument` and calls the `args` in the cell magic::
40 Here is an elaborated example that uses default parameters in `argument` and calls the `args` in the cell magic::
41
41
42 from IPython.core.magic import register_cell_magic
42 from IPython.core.magic import register_cell_magic
43 from IPython.core.magic_arguments import (argument, magic_arguments,
43 from IPython.core.magic_arguments import (argument, magic_arguments,
44 parse_argstring)
44 parse_argstring)
45
45
46
46
47 @magic_arguments()
47 @magic_arguments()
48 @argument(
48 @argument(
49 "--option",
49 "--option",
50 "-o",
50 "-o",
51 help=("Add an option here"),
51 help=("Add an option here"),
52 )
52 )
53 @argument(
53 @argument(
54 "--style",
54 "--style",
55 "-s",
55 "-s",
56 default="foo",
56 default="foo",
57 help=("Add some style arguments"),
57 help=("Add some style arguments"),
58 )
58 )
59 @register_cell_magic
59 @register_cell_magic
60 def my_cell_magic(line, cell):
60 def my_cell_magic(line, cell):
61 args = parse_argstring(my_cell_magic, line)
61 args = parse_argstring(my_cell_magic, line)
62 print(f"{args.option=}")
62 print(f"{args.option=}")
63 print(f"{args.style=}")
63 print(f"{args.style=}")
64 print(f"{cell=}")
64 print(f"{cell=}")
65
65
66 In a jupyter notebook, this cell magic can be executed like this::
66 In a jupyter notebook, this cell magic can be executed like this::
67
67
68 %%my_cell_magic -o Hello
68 %%my_cell_magic -o Hello
69 print("bar")
69 print("bar")
70 i = 42
70 i = 42
71
71
72 Inheritance diagram:
72 Inheritance diagram:
73
73
74 .. inheritance-diagram:: IPython.core.magic_arguments
74 .. inheritance-diagram:: IPython.core.magic_arguments
75 :parts: 3
75 :parts: 3
76
76
77 '''
77 '''
78 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
79 # Copyright (C) 2010-2011, IPython Development Team.
79 # Copyright (C) 2010-2011, IPython Development Team.
80 #
80 #
81 # Distributed under the terms of the Modified BSD License.
81 # Distributed under the terms of the Modified BSD License.
82 #
82 #
83 # The full license is in the file COPYING.txt, distributed with this software.
83 # The full license is in the file COPYING.txt, distributed with this software.
84 #-----------------------------------------------------------------------------
84 #-----------------------------------------------------------------------------
85 import argparse
85 import argparse
86 import re
86 import re
87
87
88 # Our own imports
88 # Our own imports
89 from IPython.core.error import UsageError
89 from IPython.core.error import UsageError
90 from IPython.utils.decorators import undoc
90 from IPython.utils.decorators import undoc
91 from IPython.utils.process import arg_split
91 from IPython.utils.process import arg_split
92 from IPython.utils.text import dedent
92 from IPython.utils.text import dedent
93
93
94 NAME_RE = re.compile(r"[a-zA-Z][a-zA-Z0-9_-]*$")
94 NAME_RE = re.compile(r"[a-zA-Z][a-zA-Z0-9_-]*$")
95
95
96 @undoc
96 @undoc
97 class MagicHelpFormatter(argparse.RawDescriptionHelpFormatter):
97 class MagicHelpFormatter(argparse.RawDescriptionHelpFormatter):
98 """A HelpFormatter with a couple of changes to meet our needs.
98 """A HelpFormatter with a couple of changes to meet our needs.
99 """
99 """
100 # Modified to dedent text.
100 # Modified to dedent text.
101 def _fill_text(self, text, width, indent):
101 def _fill_text(self, text, width, indent):
102 return argparse.RawDescriptionHelpFormatter._fill_text(self, dedent(text), width, indent)
102 return argparse.RawDescriptionHelpFormatter._fill_text(self, dedent(text), width, indent)
103
103
104 # Modified to wrap argument placeholders in <> where necessary.
104 # Modified to wrap argument placeholders in <> where necessary.
105 def _format_action_invocation(self, action):
105 def _format_action_invocation(self, action):
106 if not action.option_strings:
106 if not action.option_strings:
107 metavar, = self._metavar_formatter(action, action.dest)(1)
107 metavar, = self._metavar_formatter(action, action.dest)(1)
108 return metavar
108 return metavar
109
109
110 else:
110 else:
111 parts = []
111 parts = []
112
112
113 # if the Optional doesn't take a value, format is:
113 # if the Optional doesn't take a value, format is:
114 # -s, --long
114 # -s, --long
115 if action.nargs == 0:
115 if action.nargs == 0:
116 parts.extend(action.option_strings)
116 parts.extend(action.option_strings)
117
117
118 # if the Optional takes a value, format is:
118 # if the Optional takes a value, format is:
119 # -s ARGS, --long ARGS
119 # -s ARGS, --long ARGS
120 else:
120 else:
121 default = action.dest.upper()
121 default = action.dest.upper()
122 args_string = self._format_args(action, default)
122 args_string = self._format_args(action, default)
123 # IPYTHON MODIFICATION: If args_string is not a plain name, wrap
123 # IPYTHON MODIFICATION: If args_string is not a plain name, wrap
124 # it in <> so it's valid RST.
124 # it in <> so it's valid RST.
125 if not NAME_RE.match(args_string):
125 if not NAME_RE.match(args_string):
126 args_string = "<%s>" % args_string
126 args_string = "<%s>" % args_string
127 for option_string in action.option_strings:
127 for option_string in action.option_strings:
128 parts.append('%s %s' % (option_string, args_string))
128 parts.append('%s %s' % (option_string, args_string))
129
129
130 return ', '.join(parts)
130 return ', '.join(parts)
131
131
132 # Override the default prefix ('usage') to our % magic escape,
132 # Override the default prefix ('usage') to our % magic escape,
133 # in a code block.
133 # in a code block.
134 def add_usage(self, usage, actions, groups, prefix="::\n\n %"):
134 def add_usage(self, usage, actions, groups, prefix="::\n\n %"):
135 super(MagicHelpFormatter, self).add_usage(usage, actions, groups, prefix)
135 super(MagicHelpFormatter, self).add_usage(usage, actions, groups, prefix)
136
136
137 class MagicArgumentParser(argparse.ArgumentParser):
137 class MagicArgumentParser(argparse.ArgumentParser):
138 """ An ArgumentParser tweaked for use by IPython magics.
138 """ An ArgumentParser tweaked for use by IPython magics.
139 """
139 """
140 def __init__(self,
140 def __init__(self,
141 prog=None,
141 prog=None,
142 usage=None,
142 usage=None,
143 description=None,
143 description=None,
144 epilog=None,
144 epilog=None,
145 parents=None,
145 parents=None,
146 formatter_class=MagicHelpFormatter,
146 formatter_class=MagicHelpFormatter,
147 prefix_chars='-',
147 prefix_chars='-',
148 argument_default=None,
148 argument_default=None,
149 conflict_handler='error',
149 conflict_handler='error',
150 add_help=False):
150 add_help=False):
151 if parents is None:
151 if parents is None:
152 parents = []
152 parents = []
153 super(MagicArgumentParser, self).__init__(prog=prog, usage=usage,
153 super(MagicArgumentParser, self).__init__(prog=prog, usage=usage,
154 description=description, epilog=epilog,
154 description=description, epilog=epilog,
155 parents=parents, formatter_class=formatter_class,
155 parents=parents, formatter_class=formatter_class,
156 prefix_chars=prefix_chars, argument_default=argument_default,
156 prefix_chars=prefix_chars, argument_default=argument_default,
157 conflict_handler=conflict_handler, add_help=add_help)
157 conflict_handler=conflict_handler, add_help=add_help)
158
158
159 def error(self, message):
159 def error(self, message):
160 """ Raise a catchable error instead of exiting.
160 """ Raise a catchable error instead of exiting.
161 """
161 """
162 raise UsageError(message)
162 raise UsageError(message)
163
163
164 def parse_argstring(self, argstring):
164 def parse_argstring(self, argstring):
165 """ Split a string into an argument list and parse that argument list.
165 """ Split a string into an argument list and parse that argument list.
166 """
166 """
167 argv = arg_split(argstring)
167 argv = arg_split(argstring)
168 return self.parse_args(argv)
168 return self.parse_args(argv)
169
169
170
170
171 def construct_parser(magic_func):
171 def construct_parser(magic_func):
172 """ Construct an argument parser using the function decorations.
172 """ Construct an argument parser using the function decorations.
173 """
173 """
174 kwds = getattr(magic_func, 'argcmd_kwds', {})
174 kwds = getattr(magic_func, 'argcmd_kwds', {})
175 if 'description' not in kwds:
175 if 'description' not in kwds:
176 kwds['description'] = getattr(magic_func, '__doc__', None)
176 kwds['description'] = getattr(magic_func, '__doc__', None)
177 arg_name = real_name(magic_func)
177 arg_name = real_name(magic_func)
178 parser = MagicArgumentParser(arg_name, **kwds)
178 parser = MagicArgumentParser(arg_name, **kwds)
179 # Reverse the list of decorators in order to apply them in the
179 # Reverse the list of decorators in order to apply them in the
180 # order in which they appear in the source.
180 # order in which they appear in the source.
181 group = None
181 group = None
182 for deco in magic_func.decorators[::-1]:
182 for deco in magic_func.decorators[::-1]:
183 result = deco.add_to_parser(parser, group)
183 result = deco.add_to_parser(parser, group)
184 if result is not None:
184 if result is not None:
185 group = result
185 group = result
186
186
187 # Replace the magic function's docstring with the full help text.
187 # Replace the magic function's docstring with the full help text.
188 magic_func.__doc__ = parser.format_help()
188 magic_func.__doc__ = parser.format_help()
189
189
190 return parser
190 return parser
191
191
192
192
193 def parse_argstring(magic_func, argstring):
193 def parse_argstring(magic_func, argstring):
194 """ Parse the string of arguments for the given magic function.
194 """ Parse the string of arguments for the given magic function.
195 """
195 """
196 return magic_func.parser.parse_argstring(argstring)
196 return magic_func.parser.parse_argstring(argstring)
197
197
198
198
199 def real_name(magic_func):
199 def real_name(magic_func):
200 """ Find the real name of the magic.
200 """ Find the real name of the magic.
201 """
201 """
202 magic_name = magic_func.__name__
202 magic_name = magic_func.__name__
203 if magic_name.startswith('magic_'):
203 if magic_name.startswith('magic_'):
204 magic_name = magic_name[len('magic_'):]
204 magic_name = magic_name[len('magic_'):]
205 return getattr(magic_func, 'argcmd_name', magic_name)
205 return getattr(magic_func, 'argcmd_name', magic_name)
206
206
207
207
208 class ArgDecorator(object):
208 class ArgDecorator(object):
209 """ Base class for decorators to add ArgumentParser information to a method.
209 """ Base class for decorators to add ArgumentParser information to a method.
210 """
210 """
211
211
212 def __call__(self, func):
212 def __call__(self, func):
213 if not getattr(func, 'has_arguments', False):
213 if not getattr(func, 'has_arguments', False):
214 func.has_arguments = True
214 func.has_arguments = True
215 func.decorators = []
215 func.decorators = []
216 func.decorators.append(self)
216 func.decorators.append(self)
217 return func
217 return func
218
218
219 def add_to_parser(self, parser, group):
219 def add_to_parser(self, parser, group):
220 """ Add this object's information to the parser, if necessary.
220 """ Add this object's information to the parser, if necessary.
221 """
221 """
222 pass
222 pass
223
223
224
224
225 class magic_arguments(ArgDecorator):
225 class magic_arguments(ArgDecorator):
226 """ Mark the magic as having argparse arguments and possibly adjust the
226 """ Mark the magic as having argparse arguments and possibly adjust the
227 name.
227 name.
228 """
228 """
229
229
230 def __init__(self, name=None):
230 def __init__(self, name=None):
231 self.name = name
231 self.name = name
232
232
233 def __call__(self, func):
233 def __call__(self, func):
234 if not getattr(func, 'has_arguments', False):
234 if not getattr(func, 'has_arguments', False):
235 func.has_arguments = True
235 func.has_arguments = True
236 func.decorators = []
236 func.decorators = []
237 if self.name is not None:
237 if self.name is not None:
238 func.argcmd_name = self.name
238 func.argcmd_name = self.name
239 # This should be the first decorator in the list of decorators, thus the
239 # This should be the first decorator in the list of decorators, thus the
240 # last to execute. Build the parser.
240 # last to execute. Build the parser.
241 func.parser = construct_parser(func)
241 func.parser = construct_parser(func)
242 return func
242 return func
243
243
244
244
245 class ArgMethodWrapper(ArgDecorator):
245 class ArgMethodWrapper(ArgDecorator):
246
246
247 """
247 """
248 Base class to define a wrapper for ArgumentParser method.
248 Base class to define a wrapper for ArgumentParser method.
249
249
250 Child class must define either `_method_name` or `add_to_parser`.
250 Child class must define either `_method_name` or `add_to_parser`.
251
251
252 """
252 """
253
253
254 _method_name = None
254 _method_name: str
255
255
256 def __init__(self, *args, **kwds):
256 def __init__(self, *args, **kwds):
257 self.args = args
257 self.args = args
258 self.kwds = kwds
258 self.kwds = kwds
259
259
260 def add_to_parser(self, parser, group):
260 def add_to_parser(self, parser, group):
261 """ Add this object's information to the parser.
261 """ Add this object's information to the parser.
262 """
262 """
263 if group is not None:
263 if group is not None:
264 parser = group
264 parser = group
265 getattr(parser, self._method_name)(*self.args, **self.kwds)
265 getattr(parser, self._method_name)(*self.args, **self.kwds)
266 return None
266 return None
267
267
268
268
269 class argument(ArgMethodWrapper):
269 class argument(ArgMethodWrapper):
270 """ Store arguments and keywords to pass to add_argument().
270 """ Store arguments and keywords to pass to add_argument().
271
271
272 Instances also serve to decorate command methods.
272 Instances also serve to decorate command methods.
273 """
273 """
274 _method_name = 'add_argument'
274 _method_name = 'add_argument'
275
275
276
276
277 class defaults(ArgMethodWrapper):
277 class defaults(ArgMethodWrapper):
278 """ Store arguments and keywords to pass to set_defaults().
278 """ Store arguments and keywords to pass to set_defaults().
279
279
280 Instances also serve to decorate command methods.
280 Instances also serve to decorate command methods.
281 """
281 """
282 _method_name = 'set_defaults'
282 _method_name = 'set_defaults'
283
283
284
284
285 class argument_group(ArgMethodWrapper):
285 class argument_group(ArgMethodWrapper):
286 """ Store arguments and keywords to pass to add_argument_group().
286 """ Store arguments and keywords to pass to add_argument_group().
287
287
288 Instances also serve to decorate command methods.
288 Instances also serve to decorate command methods.
289 """
289 """
290
290
291 def add_to_parser(self, parser, group):
291 def add_to_parser(self, parser, group):
292 """ Add this object's information to the parser.
292 """ Add this object's information to the parser.
293 """
293 """
294 return parser.add_argument_group(*self.args, **self.kwds)
294 return parser.add_argument_group(*self.args, **self.kwds)
295
295
296
296
297 class kwds(ArgDecorator):
297 class kwds(ArgDecorator):
298 """ Provide other keywords to the sub-parser constructor.
298 """ Provide other keywords to the sub-parser constructor.
299 """
299 """
300 def __init__(self, **kwds):
300 def __init__(self, **kwds):
301 self.kwds = kwds
301 self.kwds = kwds
302
302
303 def __call__(self, func):
303 def __call__(self, func):
304 func = super(kwds, self).__call__(func)
304 func = super(kwds, self).__call__(func)
305 func.argcmd_kwds = self.kwds
305 func.argcmd_kwds = self.kwds
306 return func
306 return func
307
307
308
308
309 __all__ = ['magic_arguments', 'argument', 'argument_group', 'kwds',
309 __all__ = ['magic_arguments', 'argument', 'argument_group', 'kwds',
310 'parse_argstring']
310 'parse_argstring']
@@ -1,1093 +1,1098 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tools for inspecting Python objects.
2 """Tools for inspecting Python objects.
3
3
4 Uses syntax highlighting for presenting the various information elements.
4 Uses syntax highlighting for presenting the various information elements.
5
5
6 Similar in spirit to the inspect module, but all calls take a name argument to
6 Similar in spirit to the inspect module, but all calls take a name argument to
7 reference the name under which an object is being read.
7 reference the name under which an object is being read.
8 """
8 """
9
9
10 # Copyright (c) IPython Development Team.
10 # Copyright (c) IPython Development Team.
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12
12
13 __all__ = ['Inspector','InspectColors']
13 __all__ = ['Inspector','InspectColors']
14
14
15 # stdlib modules
15 # stdlib modules
16 import ast
16 import ast
17 import inspect
17 import inspect
18 from inspect import signature
18 from inspect import signature
19 import html
19 import html
20 import linecache
20 import linecache
21 import warnings
21 import warnings
22 import os
22 import os
23 from textwrap import dedent
23 from textwrap import dedent
24 import types
24 import types
25 import io as stdlib_io
25 import io as stdlib_io
26
26
27 from typing import Union
27 from typing import Union
28
28
29 # IPython's own
29 # IPython's own
30 from IPython.core import page
30 from IPython.core import page
31 from IPython.lib.pretty import pretty
31 from IPython.lib.pretty import pretty
32 from IPython.testing.skipdoctest import skip_doctest
32 from IPython.testing.skipdoctest import skip_doctest
33 from IPython.utils import PyColorize
33 from IPython.utils import PyColorize
34 from IPython.utils import openpy
34 from IPython.utils import openpy
35 from IPython.utils.dir2 import safe_hasattr
35 from IPython.utils.dir2 import safe_hasattr
36 from IPython.utils.path import compress_user
36 from IPython.utils.path import compress_user
37 from IPython.utils.text import indent
37 from IPython.utils.text import indent
38 from IPython.utils.wildcard import list_namespace
38 from IPython.utils.wildcard import list_namespace
39 from IPython.utils.wildcard import typestr2type
39 from IPython.utils.wildcard import typestr2type
40 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
40 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
41 from IPython.utils.py3compat import cast_unicode
41 from IPython.utils.py3compat import cast_unicode
42 from IPython.utils.colorable import Colorable
42 from IPython.utils.colorable import Colorable
43 from IPython.utils.decorators import undoc
43 from IPython.utils.decorators import undoc
44
44
45 from pygments import highlight
45 from pygments import highlight
46 from pygments.lexers import PythonLexer
46 from pygments.lexers import PythonLexer
47 from pygments.formatters import HtmlFormatter
47 from pygments.formatters import HtmlFormatter
48
48
49 from typing import Any
49 from typing import Any, Optional
50 from dataclasses import dataclass
50 from dataclasses import dataclass
51
51
52
52
53 @dataclass
53 @dataclass
54 class OInfo:
54 class OInfo:
55 ismagic: bool
55 ismagic: bool
56 isalias: bool
56 isalias: bool
57 found: bool
57 found: bool
58 namespace: str
58 namespace: Optional[str]
59 parent: Any
59 parent: Any
60 obj: Any
60 obj: Any
61
61
62 def pylight(code):
62 def pylight(code):
63 return highlight(code, PythonLexer(), HtmlFormatter(noclasses=True))
63 return highlight(code, PythonLexer(), HtmlFormatter(noclasses=True))
64
64
65 # builtin docstrings to ignore
65 # builtin docstrings to ignore
66 _func_call_docstring = types.FunctionType.__call__.__doc__
66 _func_call_docstring = types.FunctionType.__call__.__doc__
67 _object_init_docstring = object.__init__.__doc__
67 _object_init_docstring = object.__init__.__doc__
68 _builtin_type_docstrings = {
68 _builtin_type_docstrings = {
69 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
69 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
70 types.FunctionType, property)
70 types.FunctionType, property)
71 }
71 }
72
72
73 _builtin_func_type = type(all)
73 _builtin_func_type = type(all)
74 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
74 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
75 #****************************************************************************
75 #****************************************************************************
76 # Builtin color schemes
76 # Builtin color schemes
77
77
78 Colors = TermColors # just a shorthand
78 Colors = TermColors # just a shorthand
79
79
80 InspectColors = PyColorize.ANSICodeColors
80 InspectColors = PyColorize.ANSICodeColors
81
81
82 #****************************************************************************
82 #****************************************************************************
83 # Auxiliary functions and objects
83 # Auxiliary functions and objects
84
84
85 # See the messaging spec for the definition of all these fields. This list
85 # See the messaging spec for the definition of all these fields. This list
86 # effectively defines the order of display
86 # effectively defines the order of display
87 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
87 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
88 'length', 'file', 'definition', 'docstring', 'source',
88 'length', 'file', 'definition', 'docstring', 'source',
89 'init_definition', 'class_docstring', 'init_docstring',
89 'init_definition', 'class_docstring', 'init_docstring',
90 'call_def', 'call_docstring',
90 'call_def', 'call_docstring',
91 # These won't be printed but will be used to determine how to
91 # These won't be printed but will be used to determine how to
92 # format the object
92 # format the object
93 'ismagic', 'isalias', 'isclass', 'found', 'name'
93 'ismagic', 'isalias', 'isclass', 'found', 'name'
94 ]
94 ]
95
95
96
96
97 def object_info(**kw):
97 def object_info(**kw):
98 """Make an object info dict with all fields present."""
98 """Make an object info dict with all fields present."""
99 infodict = {k:None for k in info_fields}
99 infodict = {k:None for k in info_fields}
100 infodict.update(kw)
100 infodict.update(kw)
101 return infodict
101 return infodict
102
102
103
103
104 def get_encoding(obj):
104 def get_encoding(obj):
105 """Get encoding for python source file defining obj
105 """Get encoding for python source file defining obj
106
106
107 Returns None if obj is not defined in a sourcefile.
107 Returns None if obj is not defined in a sourcefile.
108 """
108 """
109 ofile = find_file(obj)
109 ofile = find_file(obj)
110 # run contents of file through pager starting at line where the object
110 # run contents of file through pager starting at line where the object
111 # is defined, as long as the file isn't binary and is actually on the
111 # is defined, as long as the file isn't binary and is actually on the
112 # filesystem.
112 # filesystem.
113 if ofile is None:
113 if ofile is None:
114 return None
114 return None
115 elif ofile.endswith(('.so', '.dll', '.pyd')):
115 elif ofile.endswith(('.so', '.dll', '.pyd')):
116 return None
116 return None
117 elif not os.path.isfile(ofile):
117 elif not os.path.isfile(ofile):
118 return None
118 return None
119 else:
119 else:
120 # Print only text files, not extension binaries. Note that
120 # Print only text files, not extension binaries. Note that
121 # getsourcelines returns lineno with 1-offset and page() uses
121 # getsourcelines returns lineno with 1-offset and page() uses
122 # 0-offset, so we must adjust.
122 # 0-offset, so we must adjust.
123 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
123 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
124 encoding, lines = openpy.detect_encoding(buffer.readline)
124 encoding, lines = openpy.detect_encoding(buffer.readline)
125 return encoding
125 return encoding
126
126
127 def getdoc(obj) -> Union[str,None]:
127 def getdoc(obj) -> Union[str,None]:
128 """Stable wrapper around inspect.getdoc.
128 """Stable wrapper around inspect.getdoc.
129
129
130 This can't crash because of attribute problems.
130 This can't crash because of attribute problems.
131
131
132 It also attempts to call a getdoc() method on the given object. This
132 It also attempts to call a getdoc() method on the given object. This
133 allows objects which provide their docstrings via non-standard mechanisms
133 allows objects which provide their docstrings via non-standard mechanisms
134 (like Pyro proxies) to still be inspected by ipython's ? system.
134 (like Pyro proxies) to still be inspected by ipython's ? system.
135 """
135 """
136 # Allow objects to offer customized documentation via a getdoc method:
136 # Allow objects to offer customized documentation via a getdoc method:
137 try:
137 try:
138 ds = obj.getdoc()
138 ds = obj.getdoc()
139 except Exception:
139 except Exception:
140 pass
140 pass
141 else:
141 else:
142 if isinstance(ds, str):
142 if isinstance(ds, str):
143 return inspect.cleandoc(ds)
143 return inspect.cleandoc(ds)
144 docstr = inspect.getdoc(obj)
144 docstr = inspect.getdoc(obj)
145 return docstr
145 return docstr
146
146
147
147
148 def getsource(obj, oname='') -> Union[str,None]:
148 def getsource(obj, oname='') -> Union[str,None]:
149 """Wrapper around inspect.getsource.
149 """Wrapper around inspect.getsource.
150
150
151 This can be modified by other projects to provide customized source
151 This can be modified by other projects to provide customized source
152 extraction.
152 extraction.
153
153
154 Parameters
154 Parameters
155 ----------
155 ----------
156 obj : object
156 obj : object
157 an object whose source code we will attempt to extract
157 an object whose source code we will attempt to extract
158 oname : str
158 oname : str
159 (optional) a name under which the object is known
159 (optional) a name under which the object is known
160
160
161 Returns
161 Returns
162 -------
162 -------
163 src : unicode or None
163 src : unicode or None
164
164
165 """
165 """
166
166
167 if isinstance(obj, property):
167 if isinstance(obj, property):
168 sources = []
168 sources = []
169 for attrname in ['fget', 'fset', 'fdel']:
169 for attrname in ['fget', 'fset', 'fdel']:
170 fn = getattr(obj, attrname)
170 fn = getattr(obj, attrname)
171 if fn is not None:
171 if fn is not None:
172 encoding = get_encoding(fn)
172 encoding = get_encoding(fn)
173 oname_prefix = ('%s.' % oname) if oname else ''
173 oname_prefix = ('%s.' % oname) if oname else ''
174 sources.append(''.join(('# ', oname_prefix, attrname)))
174 sources.append(''.join(('# ', oname_prefix, attrname)))
175 if inspect.isfunction(fn):
175 if inspect.isfunction(fn):
176 sources.append(dedent(getsource(fn)))
176 _src = getsource(fn)
177 if _src:
178 # assert _src is not None, "please mypy"
179 sources.append(dedent(_src))
177 else:
180 else:
178 # Default str/repr only prints function name,
181 # Default str/repr only prints function name,
179 # pretty.pretty prints module name too.
182 # pretty.pretty prints module name too.
180 sources.append(
183 sources.append(
181 '%s%s = %s\n' % (oname_prefix, attrname, pretty(fn))
184 '%s%s = %s\n' % (oname_prefix, attrname, pretty(fn))
182 )
185 )
183 if sources:
186 if sources:
184 return '\n'.join(sources)
187 return '\n'.join(sources)
185 else:
188 else:
186 return None
189 return None
187
190
188 else:
191 else:
189 # Get source for non-property objects.
192 # Get source for non-property objects.
190
193
191 obj = _get_wrapped(obj)
194 obj = _get_wrapped(obj)
192
195
193 try:
196 try:
194 src = inspect.getsource(obj)
197 src = inspect.getsource(obj)
195 except TypeError:
198 except TypeError:
196 # The object itself provided no meaningful source, try looking for
199 # The object itself provided no meaningful source, try looking for
197 # its class definition instead.
200 # its class definition instead.
198 try:
201 try:
199 src = inspect.getsource(obj.__class__)
202 src = inspect.getsource(obj.__class__)
200 except (OSError, TypeError):
203 except (OSError, TypeError):
201 return None
204 return None
202 except OSError:
205 except OSError:
203 return None
206 return None
204
207
205 return src
208 return src
206
209
207
210
208 def is_simple_callable(obj):
211 def is_simple_callable(obj):
209 """True if obj is a function ()"""
212 """True if obj is a function ()"""
210 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
213 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
211 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
214 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
212
215
213 @undoc
216 @undoc
214 def getargspec(obj):
217 def getargspec(obj):
215 """Wrapper around :func:`inspect.getfullargspec`
218 """Wrapper around :func:`inspect.getfullargspec`
216
219
217 In addition to functions and methods, this can also handle objects with a
220 In addition to functions and methods, this can also handle objects with a
218 ``__call__`` attribute.
221 ``__call__`` attribute.
219
222
220 DEPRECATED: Deprecated since 7.10. Do not use, will be removed.
223 DEPRECATED: Deprecated since 7.10. Do not use, will be removed.
221 """
224 """
222
225
223 warnings.warn('`getargspec` function is deprecated as of IPython 7.10'
226 warnings.warn('`getargspec` function is deprecated as of IPython 7.10'
224 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
227 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
225
228
226 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
229 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
227 obj = obj.__call__
230 obj = obj.__call__
228
231
229 return inspect.getfullargspec(obj)
232 return inspect.getfullargspec(obj)
230
233
231 @undoc
234 @undoc
232 def format_argspec(argspec):
235 def format_argspec(argspec):
233 """Format argspect, convenience wrapper around inspect's.
236 """Format argspect, convenience wrapper around inspect's.
234
237
235 This takes a dict instead of ordered arguments and calls
238 This takes a dict instead of ordered arguments and calls
236 inspect.format_argspec with the arguments in the necessary order.
239 inspect.format_argspec with the arguments in the necessary order.
237
240
238 DEPRECATED (since 7.10): Do not use; will be removed in future versions.
241 DEPRECATED (since 7.10): Do not use; will be removed in future versions.
239 """
242 """
240
243
241 warnings.warn('`format_argspec` function is deprecated as of IPython 7.10'
244 warnings.warn('`format_argspec` function is deprecated as of IPython 7.10'
242 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
245 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
243
246
244
247
245 return inspect.formatargspec(argspec['args'], argspec['varargs'],
248 return inspect.formatargspec(argspec['args'], argspec['varargs'],
246 argspec['varkw'], argspec['defaults'])
249 argspec['varkw'], argspec['defaults'])
247
250
248 @undoc
251 @undoc
249 def call_tip(oinfo, format_call=True):
252 def call_tip(oinfo, format_call=True):
250 """DEPRECATED since 6.0. Extract call tip data from an oinfo dict."""
253 """DEPRECATED since 6.0. Extract call tip data from an oinfo dict."""
251 warnings.warn(
254 warnings.warn(
252 "`call_tip` function is deprecated as of IPython 6.0"
255 "`call_tip` function is deprecated as of IPython 6.0"
253 "and will be removed in future versions.",
256 "and will be removed in future versions.",
254 DeprecationWarning,
257 DeprecationWarning,
255 stacklevel=2,
258 stacklevel=2,
256 )
259 )
257 # Get call definition
260 # Get call definition
258 argspec = oinfo.get('argspec')
261 argspec = oinfo.get('argspec')
259 if argspec is None:
262 if argspec is None:
260 call_line = None
263 call_line = None
261 else:
264 else:
262 # Callable objects will have 'self' as their first argument, prune
265 # Callable objects will have 'self' as their first argument, prune
263 # it out if it's there for clarity (since users do *not* pass an
266 # it out if it's there for clarity (since users do *not* pass an
264 # extra first argument explicitly).
267 # extra first argument explicitly).
265 try:
268 try:
266 has_self = argspec['args'][0] == 'self'
269 has_self = argspec['args'][0] == 'self'
267 except (KeyError, IndexError):
270 except (KeyError, IndexError):
268 pass
271 pass
269 else:
272 else:
270 if has_self:
273 if has_self:
271 argspec['args'] = argspec['args'][1:]
274 argspec['args'] = argspec['args'][1:]
272
275
273 call_line = oinfo['name']+format_argspec(argspec)
276 call_line = oinfo['name']+format_argspec(argspec)
274
277
275 # Now get docstring.
278 # Now get docstring.
276 # The priority is: call docstring, constructor docstring, main one.
279 # The priority is: call docstring, constructor docstring, main one.
277 doc = oinfo.get('call_docstring')
280 doc = oinfo.get('call_docstring')
278 if doc is None:
281 if doc is None:
279 doc = oinfo.get('init_docstring')
282 doc = oinfo.get('init_docstring')
280 if doc is None:
283 if doc is None:
281 doc = oinfo.get('docstring','')
284 doc = oinfo.get('docstring','')
282
285
283 return call_line, doc
286 return call_line, doc
284
287
285
288
286 def _get_wrapped(obj):
289 def _get_wrapped(obj):
287 """Get the original object if wrapped in one or more @decorators
290 """Get the original object if wrapped in one or more @decorators
288
291
289 Some objects automatically construct similar objects on any unrecognised
292 Some objects automatically construct similar objects on any unrecognised
290 attribute access (e.g. unittest.mock.call). To protect against infinite loops,
293 attribute access (e.g. unittest.mock.call). To protect against infinite loops,
291 this will arbitrarily cut off after 100 levels of obj.__wrapped__
294 this will arbitrarily cut off after 100 levels of obj.__wrapped__
292 attribute access. --TK, Jan 2016
295 attribute access. --TK, Jan 2016
293 """
296 """
294 orig_obj = obj
297 orig_obj = obj
295 i = 0
298 i = 0
296 while safe_hasattr(obj, '__wrapped__'):
299 while safe_hasattr(obj, '__wrapped__'):
297 obj = obj.__wrapped__
300 obj = obj.__wrapped__
298 i += 1
301 i += 1
299 if i > 100:
302 if i > 100:
300 # __wrapped__ is probably a lie, so return the thing we started with
303 # __wrapped__ is probably a lie, so return the thing we started with
301 return orig_obj
304 return orig_obj
302 return obj
305 return obj
303
306
304 def find_file(obj) -> str:
307 def find_file(obj) -> str:
305 """Find the absolute path to the file where an object was defined.
308 """Find the absolute path to the file where an object was defined.
306
309
307 This is essentially a robust wrapper around `inspect.getabsfile`.
310 This is essentially a robust wrapper around `inspect.getabsfile`.
308
311
309 Returns None if no file can be found.
312 Returns None if no file can be found.
310
313
311 Parameters
314 Parameters
312 ----------
315 ----------
313 obj : any Python object
316 obj : any Python object
314
317
315 Returns
318 Returns
316 -------
319 -------
317 fname : str
320 fname : str
318 The absolute path to the file where the object was defined.
321 The absolute path to the file where the object was defined.
319 """
322 """
320 obj = _get_wrapped(obj)
323 obj = _get_wrapped(obj)
321
324
322 fname = None
325 fname = None
323 try:
326 try:
324 fname = inspect.getabsfile(obj)
327 fname = inspect.getabsfile(obj)
325 except TypeError:
328 except TypeError:
326 # For an instance, the file that matters is where its class was
329 # For an instance, the file that matters is where its class was
327 # declared.
330 # declared.
328 try:
331 try:
329 fname = inspect.getabsfile(obj.__class__)
332 fname = inspect.getabsfile(obj.__class__)
330 except (OSError, TypeError):
333 except (OSError, TypeError):
331 # Can happen for builtins
334 # Can happen for builtins
332 pass
335 pass
333 except OSError:
336 except OSError:
334 pass
337 pass
335
338
336 return cast_unicode(fname)
339 return cast_unicode(fname)
337
340
338
341
339 def find_source_lines(obj):
342 def find_source_lines(obj):
340 """Find the line number in a file where an object was defined.
343 """Find the line number in a file where an object was defined.
341
344
342 This is essentially a robust wrapper around `inspect.getsourcelines`.
345 This is essentially a robust wrapper around `inspect.getsourcelines`.
343
346
344 Returns None if no file can be found.
347 Returns None if no file can be found.
345
348
346 Parameters
349 Parameters
347 ----------
350 ----------
348 obj : any Python object
351 obj : any Python object
349
352
350 Returns
353 Returns
351 -------
354 -------
352 lineno : int
355 lineno : int
353 The line number where the object definition starts.
356 The line number where the object definition starts.
354 """
357 """
355 obj = _get_wrapped(obj)
358 obj = _get_wrapped(obj)
356
359
357 try:
360 try:
358 lineno = inspect.getsourcelines(obj)[1]
361 lineno = inspect.getsourcelines(obj)[1]
359 except TypeError:
362 except TypeError:
360 # For instances, try the class object like getsource() does
363 # For instances, try the class object like getsource() does
361 try:
364 try:
362 lineno = inspect.getsourcelines(obj.__class__)[1]
365 lineno = inspect.getsourcelines(obj.__class__)[1]
363 except (OSError, TypeError):
366 except (OSError, TypeError):
364 return None
367 return None
365 except OSError:
368 except OSError:
366 return None
369 return None
367
370
368 return lineno
371 return lineno
369
372
370 class Inspector(Colorable):
373 class Inspector(Colorable):
371
374
372 def __init__(self, color_table=InspectColors,
375 def __init__(self, color_table=InspectColors,
373 code_color_table=PyColorize.ANSICodeColors,
376 code_color_table=PyColorize.ANSICodeColors,
374 scheme=None,
377 scheme=None,
375 str_detail_level=0,
378 str_detail_level=0,
376 parent=None, config=None):
379 parent=None, config=None):
377 super(Inspector, self).__init__(parent=parent, config=config)
380 super(Inspector, self).__init__(parent=parent, config=config)
378 self.color_table = color_table
381 self.color_table = color_table
379 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
382 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
380 self.format = self.parser.format
383 self.format = self.parser.format
381 self.str_detail_level = str_detail_level
384 self.str_detail_level = str_detail_level
382 self.set_active_scheme(scheme)
385 self.set_active_scheme(scheme)
383
386
384 def _getdef(self,obj,oname='') -> Union[str,None]:
387 def _getdef(self,obj,oname='') -> Union[str,None]:
385 """Return the call signature for any callable object.
388 """Return the call signature for any callable object.
386
389
387 If any exception is generated, None is returned instead and the
390 If any exception is generated, None is returned instead and the
388 exception is suppressed."""
391 exception is suppressed."""
389 try:
392 try:
390 return _render_signature(signature(obj), oname)
393 return _render_signature(signature(obj), oname)
391 except:
394 except:
392 return None
395 return None
393
396
394 def __head(self,h) -> str:
397 def __head(self,h) -> str:
395 """Return a header string with proper colors."""
398 """Return a header string with proper colors."""
396 return '%s%s%s' % (self.color_table.active_colors.header,h,
399 return '%s%s%s' % (self.color_table.active_colors.header,h,
397 self.color_table.active_colors.normal)
400 self.color_table.active_colors.normal)
398
401
399 def set_active_scheme(self, scheme):
402 def set_active_scheme(self, scheme):
400 if scheme is not None:
403 if scheme is not None:
401 self.color_table.set_active_scheme(scheme)
404 self.color_table.set_active_scheme(scheme)
402 self.parser.color_table.set_active_scheme(scheme)
405 self.parser.color_table.set_active_scheme(scheme)
403
406
404 def noinfo(self, msg, oname):
407 def noinfo(self, msg, oname):
405 """Generic message when no information is found."""
408 """Generic message when no information is found."""
406 print('No %s found' % msg, end=' ')
409 print('No %s found' % msg, end=' ')
407 if oname:
410 if oname:
408 print('for %s' % oname)
411 print('for %s' % oname)
409 else:
412 else:
410 print()
413 print()
411
414
412 def pdef(self, obj, oname=''):
415 def pdef(self, obj, oname=''):
413 """Print the call signature for any callable object.
416 """Print the call signature for any callable object.
414
417
415 If the object is a class, print the constructor information."""
418 If the object is a class, print the constructor information."""
416
419
417 if not callable(obj):
420 if not callable(obj):
418 print('Object is not callable.')
421 print('Object is not callable.')
419 return
422 return
420
423
421 header = ''
424 header = ''
422
425
423 if inspect.isclass(obj):
426 if inspect.isclass(obj):
424 header = self.__head('Class constructor information:\n')
427 header = self.__head('Class constructor information:\n')
425
428
426
429
427 output = self._getdef(obj,oname)
430 output = self._getdef(obj,oname)
428 if output is None:
431 if output is None:
429 self.noinfo('definition header',oname)
432 self.noinfo('definition header',oname)
430 else:
433 else:
431 print(header,self.format(output), end=' ')
434 print(header,self.format(output), end=' ')
432
435
433 # In Python 3, all classes are new-style, so they all have __init__.
436 # In Python 3, all classes are new-style, so they all have __init__.
434 @skip_doctest
437 @skip_doctest
435 def pdoc(self, obj, oname='', formatter=None):
438 def pdoc(self, obj, oname='', formatter=None):
436 """Print the docstring for any object.
439 """Print the docstring for any object.
437
440
438 Optional:
441 Optional:
439 -formatter: a function to run the docstring through for specially
442 -formatter: a function to run the docstring through for specially
440 formatted docstrings.
443 formatted docstrings.
441
444
442 Examples
445 Examples
443 --------
446 --------
444 In [1]: class NoInit:
447 In [1]: class NoInit:
445 ...: pass
448 ...: pass
446
449
447 In [2]: class NoDoc:
450 In [2]: class NoDoc:
448 ...: def __init__(self):
451 ...: def __init__(self):
449 ...: pass
452 ...: pass
450
453
451 In [3]: %pdoc NoDoc
454 In [3]: %pdoc NoDoc
452 No documentation found for NoDoc
455 No documentation found for NoDoc
453
456
454 In [4]: %pdoc NoInit
457 In [4]: %pdoc NoInit
455 No documentation found for NoInit
458 No documentation found for NoInit
456
459
457 In [5]: obj = NoInit()
460 In [5]: obj = NoInit()
458
461
459 In [6]: %pdoc obj
462 In [6]: %pdoc obj
460 No documentation found for obj
463 No documentation found for obj
461
464
462 In [5]: obj2 = NoDoc()
465 In [5]: obj2 = NoDoc()
463
466
464 In [6]: %pdoc obj2
467 In [6]: %pdoc obj2
465 No documentation found for obj2
468 No documentation found for obj2
466 """
469 """
467
470
468 head = self.__head # For convenience
471 head = self.__head # For convenience
469 lines = []
472 lines = []
470 ds = getdoc(obj)
473 ds = getdoc(obj)
471 if formatter:
474 if formatter:
472 ds = formatter(ds).get('plain/text', ds)
475 ds = formatter(ds).get('plain/text', ds)
473 if ds:
476 if ds:
474 lines.append(head("Class docstring:"))
477 lines.append(head("Class docstring:"))
475 lines.append(indent(ds))
478 lines.append(indent(ds))
476 if inspect.isclass(obj) and hasattr(obj, '__init__'):
479 if inspect.isclass(obj) and hasattr(obj, '__init__'):
477 init_ds = getdoc(obj.__init__)
480 init_ds = getdoc(obj.__init__)
478 if init_ds is not None:
481 if init_ds is not None:
479 lines.append(head("Init docstring:"))
482 lines.append(head("Init docstring:"))
480 lines.append(indent(init_ds))
483 lines.append(indent(init_ds))
481 elif hasattr(obj,'__call__'):
484 elif hasattr(obj,'__call__'):
482 call_ds = getdoc(obj.__call__)
485 call_ds = getdoc(obj.__call__)
483 if call_ds:
486 if call_ds:
484 lines.append(head("Call docstring:"))
487 lines.append(head("Call docstring:"))
485 lines.append(indent(call_ds))
488 lines.append(indent(call_ds))
486
489
487 if not lines:
490 if not lines:
488 self.noinfo('documentation',oname)
491 self.noinfo('documentation',oname)
489 else:
492 else:
490 page.page('\n'.join(lines))
493 page.page('\n'.join(lines))
491
494
492 def psource(self, obj, oname=''):
495 def psource(self, obj, oname=''):
493 """Print the source code for an object."""
496 """Print the source code for an object."""
494
497
495 # Flush the source cache because inspect can return out-of-date source
498 # Flush the source cache because inspect can return out-of-date source
496 linecache.checkcache()
499 linecache.checkcache()
497 try:
500 try:
498 src = getsource(obj, oname=oname)
501 src = getsource(obj, oname=oname)
499 except Exception:
502 except Exception:
500 src = None
503 src = None
501
504
502 if src is None:
505 if src is None:
503 self.noinfo('source', oname)
506 self.noinfo('source', oname)
504 else:
507 else:
505 page.page(self.format(src))
508 page.page(self.format(src))
506
509
507 def pfile(self, obj, oname=''):
510 def pfile(self, obj, oname=''):
508 """Show the whole file where an object was defined."""
511 """Show the whole file where an object was defined."""
509
512
510 lineno = find_source_lines(obj)
513 lineno = find_source_lines(obj)
511 if lineno is None:
514 if lineno is None:
512 self.noinfo('file', oname)
515 self.noinfo('file', oname)
513 return
516 return
514
517
515 ofile = find_file(obj)
518 ofile = find_file(obj)
516 # run contents of file through pager starting at line where the object
519 # run contents of file through pager starting at line where the object
517 # is defined, as long as the file isn't binary and is actually on the
520 # is defined, as long as the file isn't binary and is actually on the
518 # filesystem.
521 # filesystem.
519 if ofile.endswith(('.so', '.dll', '.pyd')):
522 if ofile.endswith(('.so', '.dll', '.pyd')):
520 print('File %r is binary, not printing.' % ofile)
523 print('File %r is binary, not printing.' % ofile)
521 elif not os.path.isfile(ofile):
524 elif not os.path.isfile(ofile):
522 print('File %r does not exist, not printing.' % ofile)
525 print('File %r does not exist, not printing.' % ofile)
523 else:
526 else:
524 # Print only text files, not extension binaries. Note that
527 # Print only text files, not extension binaries. Note that
525 # getsourcelines returns lineno with 1-offset and page() uses
528 # getsourcelines returns lineno with 1-offset and page() uses
526 # 0-offset, so we must adjust.
529 # 0-offset, so we must adjust.
527 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
530 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
528
531
529
532
530 def _mime_format(self, text:str, formatter=None) -> dict:
533 def _mime_format(self, text:str, formatter=None) -> dict:
531 """Return a mime bundle representation of the input text.
534 """Return a mime bundle representation of the input text.
532
535
533 - if `formatter` is None, the returned mime bundle has
536 - if `formatter` is None, the returned mime bundle has
534 a ``text/plain`` field, with the input text.
537 a ``text/plain`` field, with the input text.
535 a ``text/html`` field with a ``<pre>`` tag containing the input text.
538 a ``text/html`` field with a ``<pre>`` tag containing the input text.
536
539
537 - if ``formatter`` is not None, it must be a callable transforming the
540 - if ``formatter`` is not None, it must be a callable transforming the
538 input text into a mime bundle. Default values for ``text/plain`` and
541 input text into a mime bundle. Default values for ``text/plain`` and
539 ``text/html`` representations are the ones described above.
542 ``text/html`` representations are the ones described above.
540
543
541 Note:
544 Note:
542
545
543 Formatters returning strings are supported but this behavior is deprecated.
546 Formatters returning strings are supported but this behavior is deprecated.
544
547
545 """
548 """
546 defaults = {
549 defaults = {
547 "text/plain": text,
550 "text/plain": text,
548 "text/html": f"<pre>{html.escape(text)}</pre>",
551 "text/html": f"<pre>{html.escape(text)}</pre>",
549 }
552 }
550
553
551 if formatter is None:
554 if formatter is None:
552 return defaults
555 return defaults
553 else:
556 else:
554 formatted = formatter(text)
557 formatted = formatter(text)
555
558
556 if not isinstance(formatted, dict):
559 if not isinstance(formatted, dict):
557 # Handle the deprecated behavior of a formatter returning
560 # Handle the deprecated behavior of a formatter returning
558 # a string instead of a mime bundle.
561 # a string instead of a mime bundle.
559 return {"text/plain": formatted, "text/html": f"<pre>{formatted}</pre>"}
562 return {"text/plain": formatted, "text/html": f"<pre>{formatted}</pre>"}
560
563
561 else:
564 else:
562 return dict(defaults, **formatted)
565 return dict(defaults, **formatted)
563
566
564
567
565 def format_mime(self, bundle):
568 def format_mime(self, bundle):
566 """Format a mimebundle being created by _make_info_unformatted into a real mimebundle"""
569 """Format a mimebundle being created by _make_info_unformatted into a real mimebundle"""
567 # Format text/plain mimetype
570 # Format text/plain mimetype
568 if isinstance(bundle["text/plain"], (list, tuple)):
571 if isinstance(bundle["text/plain"], (list, tuple)):
569 # bundle['text/plain'] is a list of (head, formatted body) pairs
572 # bundle['text/plain'] is a list of (head, formatted body) pairs
570 lines = []
573 lines = []
571 _len = max(len(h) for h, _ in bundle["text/plain"])
574 _len = max(len(h) for h, _ in bundle["text/plain"])
572
575
573 for head, body in bundle["text/plain"]:
576 for head, body in bundle["text/plain"]:
574 body = body.strip("\n")
577 body = body.strip("\n")
575 delim = "\n" if "\n" in body else " "
578 delim = "\n" if "\n" in body else " "
576 lines.append(
579 lines.append(
577 f"{self.__head(head+':')}{(_len - len(head))*' '}{delim}{body}"
580 f"{self.__head(head+':')}{(_len - len(head))*' '}{delim}{body}"
578 )
581 )
579
582
580 bundle["text/plain"] = "\n".join(lines)
583 bundle["text/plain"] = "\n".join(lines)
581
584
582 # Format the text/html mimetype
585 # Format the text/html mimetype
583 if isinstance(bundle["text/html"], (list, tuple)):
586 if isinstance(bundle["text/html"], (list, tuple)):
584 # bundle['text/html'] is a list of (head, formatted body) pairs
587 # bundle['text/html'] is a list of (head, formatted body) pairs
585 bundle["text/html"] = "\n".join(
588 bundle["text/html"] = "\n".join(
586 (f"<h1>{head}</h1>\n{body}" for (head, body) in bundle["text/html"])
589 (f"<h1>{head}</h1>\n{body}" for (head, body) in bundle["text/html"])
587 )
590 )
588 return bundle
591 return bundle
589
592
590 def _append_info_field(
593 def _append_info_field(
591 self, bundle, title: str, key: str, info, omit_sections, formatter
594 self, bundle, title: str, key: str, info, omit_sections, formatter
592 ):
595 ):
593 """Append an info value to the unformatted mimebundle being constructed by _make_info_unformatted"""
596 """Append an info value to the unformatted mimebundle being constructed by _make_info_unformatted"""
594 if title in omit_sections or key in omit_sections:
597 if title in omit_sections or key in omit_sections:
595 return
598 return
596 field = info[key]
599 field = info[key]
597 if field is not None:
600 if field is not None:
598 formatted_field = self._mime_format(field, formatter)
601 formatted_field = self._mime_format(field, formatter)
599 bundle["text/plain"].append((title, formatted_field["text/plain"]))
602 bundle["text/plain"].append((title, formatted_field["text/plain"]))
600 bundle["text/html"].append((title, formatted_field["text/html"]))
603 bundle["text/html"].append((title, formatted_field["text/html"]))
601
604
602 def _make_info_unformatted(self, obj, info, formatter, detail_level, omit_sections):
605 def _make_info_unformatted(self, obj, info, formatter, detail_level, omit_sections):
603 """Assemble the mimebundle as unformatted lists of information"""
606 """Assemble the mimebundle as unformatted lists of information"""
604 bundle = {
607 bundle = {
605 "text/plain": [],
608 "text/plain": [],
606 "text/html": [],
609 "text/html": [],
607 }
610 }
608
611
609 # A convenience function to simplify calls below
612 # A convenience function to simplify calls below
610 def append_field(bundle, title: str, key: str, formatter=None):
613 def append_field(bundle, title: str, key: str, formatter=None):
611 self._append_info_field(
614 self._append_info_field(
612 bundle,
615 bundle,
613 title=title,
616 title=title,
614 key=key,
617 key=key,
615 info=info,
618 info=info,
616 omit_sections=omit_sections,
619 omit_sections=omit_sections,
617 formatter=formatter,
620 formatter=formatter,
618 )
621 )
619
622
620 def code_formatter(text):
623 def code_formatter(text):
621 return {
624 return {
622 'text/plain': self.format(text),
625 'text/plain': self.format(text),
623 'text/html': pylight(text)
626 'text/html': pylight(text)
624 }
627 }
625
628
626 if info["isalias"]:
629 if info["isalias"]:
627 append_field(bundle, "Repr", "string_form")
630 append_field(bundle, "Repr", "string_form")
628
631
629 elif info['ismagic']:
632 elif info['ismagic']:
630 if detail_level > 0:
633 if detail_level > 0:
631 append_field(bundle, "Source", "source", code_formatter)
634 append_field(bundle, "Source", "source", code_formatter)
632 else:
635 else:
633 append_field(bundle, "Docstring", "docstring", formatter)
636 append_field(bundle, "Docstring", "docstring", formatter)
634 append_field(bundle, "File", "file")
637 append_field(bundle, "File", "file")
635
638
636 elif info['isclass'] or is_simple_callable(obj):
639 elif info['isclass'] or is_simple_callable(obj):
637 # Functions, methods, classes
640 # Functions, methods, classes
638 append_field(bundle, "Signature", "definition", code_formatter)
641 append_field(bundle, "Signature", "definition", code_formatter)
639 append_field(bundle, "Init signature", "init_definition", code_formatter)
642 append_field(bundle, "Init signature", "init_definition", code_formatter)
640 append_field(bundle, "Docstring", "docstring", formatter)
643 append_field(bundle, "Docstring", "docstring", formatter)
641 if detail_level > 0 and info["source"]:
644 if detail_level > 0 and info["source"]:
642 append_field(bundle, "Source", "source", code_formatter)
645 append_field(bundle, "Source", "source", code_formatter)
643 else:
646 else:
644 append_field(bundle, "Init docstring", "init_docstring", formatter)
647 append_field(bundle, "Init docstring", "init_docstring", formatter)
645
648
646 append_field(bundle, "File", "file")
649 append_field(bundle, "File", "file")
647 append_field(bundle, "Type", "type_name")
650 append_field(bundle, "Type", "type_name")
648 append_field(bundle, "Subclasses", "subclasses")
651 append_field(bundle, "Subclasses", "subclasses")
649
652
650 else:
653 else:
651 # General Python objects
654 # General Python objects
652 append_field(bundle, "Signature", "definition", code_formatter)
655 append_field(bundle, "Signature", "definition", code_formatter)
653 append_field(bundle, "Call signature", "call_def", code_formatter)
656 append_field(bundle, "Call signature", "call_def", code_formatter)
654 append_field(bundle, "Type", "type_name")
657 append_field(bundle, "Type", "type_name")
655 append_field(bundle, "String form", "string_form")
658 append_field(bundle, "String form", "string_form")
656
659
657 # Namespace
660 # Namespace
658 if info["namespace"] != "Interactive":
661 if info["namespace"] != "Interactive":
659 append_field(bundle, "Namespace", "namespace")
662 append_field(bundle, "Namespace", "namespace")
660
663
661 append_field(bundle, "Length", "length")
664 append_field(bundle, "Length", "length")
662 append_field(bundle, "File", "file")
665 append_field(bundle, "File", "file")
663
666
664 # Source or docstring, depending on detail level and whether
667 # Source or docstring, depending on detail level and whether
665 # source found.
668 # source found.
666 if detail_level > 0 and info["source"]:
669 if detail_level > 0 and info["source"]:
667 append_field(bundle, "Source", "source", code_formatter)
670 append_field(bundle, "Source", "source", code_formatter)
668 else:
671 else:
669 append_field(bundle, "Docstring", "docstring", formatter)
672 append_field(bundle, "Docstring", "docstring", formatter)
670
673
671 append_field(bundle, "Class docstring", "class_docstring", formatter)
674 append_field(bundle, "Class docstring", "class_docstring", formatter)
672 append_field(bundle, "Init docstring", "init_docstring", formatter)
675 append_field(bundle, "Init docstring", "init_docstring", formatter)
673 append_field(bundle, "Call docstring", "call_docstring", formatter)
676 append_field(bundle, "Call docstring", "call_docstring", formatter)
674 return bundle
677 return bundle
675
678
676
679
677 def _get_info(
680 def _get_info(
678 self, obj, oname="", formatter=None, info=None, detail_level=0, omit_sections=()
681 self, obj, oname="", formatter=None, info=None, detail_level=0, omit_sections=()
679 ):
682 ):
680 """Retrieve an info dict and format it.
683 """Retrieve an info dict and format it.
681
684
682 Parameters
685 Parameters
683 ----------
686 ----------
684 obj : any
687 obj : any
685 Object to inspect and return info from
688 Object to inspect and return info from
686 oname : str (default: ''):
689 oname : str (default: ''):
687 Name of the variable pointing to `obj`.
690 Name of the variable pointing to `obj`.
688 formatter : callable
691 formatter : callable
689 info
692 info
690 already computed information
693 already computed information
691 detail_level : integer
694 detail_level : integer
692 Granularity of detail level, if set to 1, give more information.
695 Granularity of detail level, if set to 1, give more information.
693 omit_sections : container[str]
696 omit_sections : container[str]
694 Titles or keys to omit from output (can be set, tuple, etc., anything supporting `in`)
697 Titles or keys to omit from output (can be set, tuple, etc., anything supporting `in`)
695 """
698 """
696
699
697 info = self.info(obj, oname=oname, info=info, detail_level=detail_level)
700 info = self.info(obj, oname=oname, info=info, detail_level=detail_level)
698 bundle = self._make_info_unformatted(
701 bundle = self._make_info_unformatted(
699 obj, info, formatter, detail_level=detail_level, omit_sections=omit_sections
702 obj, info, formatter, detail_level=detail_level, omit_sections=omit_sections
700 )
703 )
701 return self.format_mime(bundle)
704 return self.format_mime(bundle)
702
705
703 def pinfo(
706 def pinfo(
704 self,
707 self,
705 obj,
708 obj,
706 oname="",
709 oname="",
707 formatter=None,
710 formatter=None,
708 info=None,
711 info=None,
709 detail_level=0,
712 detail_level=0,
710 enable_html_pager=True,
713 enable_html_pager=True,
711 omit_sections=(),
714 omit_sections=(),
712 ):
715 ):
713 """Show detailed information about an object.
716 """Show detailed information about an object.
714
717
715 Optional arguments:
718 Optional arguments:
716
719
717 - oname: name of the variable pointing to the object.
720 - oname: name of the variable pointing to the object.
718
721
719 - formatter: callable (optional)
722 - formatter: callable (optional)
720 A special formatter for docstrings.
723 A special formatter for docstrings.
721
724
722 The formatter is a callable that takes a string as an input
725 The formatter is a callable that takes a string as an input
723 and returns either a formatted string or a mime type bundle
726 and returns either a formatted string or a mime type bundle
724 in the form of a dictionary.
727 in the form of a dictionary.
725
728
726 Although the support of custom formatter returning a string
729 Although the support of custom formatter returning a string
727 instead of a mime type bundle is deprecated.
730 instead of a mime type bundle is deprecated.
728
731
729 - info: a structure with some information fields which may have been
732 - info: a structure with some information fields which may have been
730 precomputed already.
733 precomputed already.
731
734
732 - detail_level: if set to 1, more information is given.
735 - detail_level: if set to 1, more information is given.
733
736
734 - omit_sections: set of section keys and titles to omit
737 - omit_sections: set of section keys and titles to omit
735 """
738 """
736 info = self._get_info(
739 info = self._get_info(
737 obj, oname, formatter, info, detail_level, omit_sections=omit_sections
740 obj, oname, formatter, info, detail_level, omit_sections=omit_sections
738 )
741 )
739 if not enable_html_pager:
742 if not enable_html_pager:
740 del info['text/html']
743 del info['text/html']
741 page.page(info)
744 page.page(info)
742
745
743 def _info(self, obj, oname="", info=None, detail_level=0):
746 def _info(self, obj, oname="", info=None, detail_level=0):
744 """
747 """
745 Inspector.info() was likely improperly marked as deprecated
748 Inspector.info() was likely improperly marked as deprecated
746 while only a parameter was deprecated. We "un-deprecate" it.
749 while only a parameter was deprecated. We "un-deprecate" it.
747 """
750 """
748
751
749 warnings.warn(
752 warnings.warn(
750 "The `Inspector.info()` method has been un-deprecated as of 8.0 "
753 "The `Inspector.info()` method has been un-deprecated as of 8.0 "
751 "and the `formatter=` keyword removed. `Inspector._info` is now "
754 "and the `formatter=` keyword removed. `Inspector._info` is now "
752 "an alias, and you can just call `.info()` directly.",
755 "an alias, and you can just call `.info()` directly.",
753 DeprecationWarning,
756 DeprecationWarning,
754 stacklevel=2,
757 stacklevel=2,
755 )
758 )
756 return self.info(obj, oname=oname, info=info, detail_level=detail_level)
759 return self.info(obj, oname=oname, info=info, detail_level=detail_level)
757
760
758 def info(self, obj, oname="", info=None, detail_level=0) -> dict:
761 def info(self, obj, oname="", info=None, detail_level=0) -> dict:
759 """Compute a dict with detailed information about an object.
762 """Compute a dict with detailed information about an object.
760
763
761 Parameters
764 Parameters
762 ----------
765 ----------
763 obj : any
766 obj : any
764 An object to find information about
767 An object to find information about
765 oname : str (default: '')
768 oname : str (default: '')
766 Name of the variable pointing to `obj`.
769 Name of the variable pointing to `obj`.
767 info : (default: None)
770 info : (default: None)
768 A struct (dict like with attr access) with some information fields
771 A struct (dict like with attr access) with some information fields
769 which may have been precomputed already.
772 which may have been precomputed already.
770 detail_level : int (default:0)
773 detail_level : int (default:0)
771 If set to 1, more information is given.
774 If set to 1, more information is given.
772
775
773 Returns
776 Returns
774 -------
777 -------
775 An object info dict with known fields from `info_fields`. Keys are
778 An object info dict with known fields from `info_fields`. Keys are
776 strings, values are string or None.
779 strings, values are string or None.
777 """
780 """
778
781
779 if info is None:
782 if info is None:
780 ismagic = False
783 ismagic = False
781 isalias = False
784 isalias = False
782 ospace = ''
785 ospace = ''
783 else:
786 else:
784 ismagic = info.ismagic
787 ismagic = info.ismagic
785 isalias = info.isalias
788 isalias = info.isalias
786 ospace = info.namespace
789 ospace = info.namespace
787
790
788 # Get docstring, special-casing aliases:
791 # Get docstring, special-casing aliases:
789 if isalias:
792 if isalias:
790 if not callable(obj):
793 if not callable(obj):
791 try:
794 try:
792 ds = "Alias to the system command:\n %s" % obj[1]
795 ds = "Alias to the system command:\n %s" % obj[1]
793 except:
796 except:
794 ds = "Alias: " + str(obj)
797 ds = "Alias: " + str(obj)
795 else:
798 else:
796 ds = "Alias to " + str(obj)
799 ds = "Alias to " + str(obj)
797 if obj.__doc__:
800 if obj.__doc__:
798 ds += "\nDocstring:\n" + obj.__doc__
801 ds += "\nDocstring:\n" + obj.__doc__
799 else:
802 else:
800 ds = getdoc(obj)
803 ds_or_None = getdoc(obj)
801 if ds is None:
804 if ds_or_None is None:
802 ds = '<no docstring>'
805 ds = '<no docstring>'
806 else:
807 ds = ds_or_None
803
808
804 # store output in a dict, we initialize it here and fill it as we go
809 # store output in a dict, we initialize it here and fill it as we go
805 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic, subclasses=None)
810 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic, subclasses=None)
806
811
807 string_max = 200 # max size of strings to show (snipped if longer)
812 string_max = 200 # max size of strings to show (snipped if longer)
808 shalf = int((string_max - 5) / 2)
813 shalf = int((string_max - 5) / 2)
809
814
810 if ismagic:
815 if ismagic:
811 out['type_name'] = 'Magic function'
816 out['type_name'] = 'Magic function'
812 elif isalias:
817 elif isalias:
813 out['type_name'] = 'System alias'
818 out['type_name'] = 'System alias'
814 else:
819 else:
815 out['type_name'] = type(obj).__name__
820 out['type_name'] = type(obj).__name__
816
821
817 try:
822 try:
818 bclass = obj.__class__
823 bclass = obj.__class__
819 out['base_class'] = str(bclass)
824 out['base_class'] = str(bclass)
820 except:
825 except:
821 pass
826 pass
822
827
823 # String form, but snip if too long in ? form (full in ??)
828 # String form, but snip if too long in ? form (full in ??)
824 if detail_level >= self.str_detail_level:
829 if detail_level >= self.str_detail_level:
825 try:
830 try:
826 ostr = str(obj)
831 ostr = str(obj)
827 str_head = 'string_form'
832 str_head = 'string_form'
828 if not detail_level and len(ostr)>string_max:
833 if not detail_level and len(ostr)>string_max:
829 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
834 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
830 ostr = ("\n" + " " * len(str_head.expandtabs())).\
835 ostr = ("\n" + " " * len(str_head.expandtabs())).\
831 join(q.strip() for q in ostr.split("\n"))
836 join(q.strip() for q in ostr.split("\n"))
832 out[str_head] = ostr
837 out[str_head] = ostr
833 except:
838 except:
834 pass
839 pass
835
840
836 if ospace:
841 if ospace:
837 out['namespace'] = ospace
842 out['namespace'] = ospace
838
843
839 # Length (for strings and lists)
844 # Length (for strings and lists)
840 try:
845 try:
841 out['length'] = str(len(obj))
846 out['length'] = str(len(obj))
842 except Exception:
847 except Exception:
843 pass
848 pass
844
849
845 # Filename where object was defined
850 # Filename where object was defined
846 binary_file = False
851 binary_file = False
847 fname = find_file(obj)
852 fname = find_file(obj)
848 if fname is None:
853 if fname is None:
849 # if anything goes wrong, we don't want to show source, so it's as
854 # if anything goes wrong, we don't want to show source, so it's as
850 # if the file was binary
855 # if the file was binary
851 binary_file = True
856 binary_file = True
852 else:
857 else:
853 if fname.endswith(('.so', '.dll', '.pyd')):
858 if fname.endswith(('.so', '.dll', '.pyd')):
854 binary_file = True
859 binary_file = True
855 elif fname.endswith('<string>'):
860 elif fname.endswith('<string>'):
856 fname = 'Dynamically generated function. No source code available.'
861 fname = 'Dynamically generated function. No source code available.'
857 out['file'] = compress_user(fname)
862 out['file'] = compress_user(fname)
858
863
859 # Original source code for a callable, class or property.
864 # Original source code for a callable, class or property.
860 if detail_level:
865 if detail_level:
861 # Flush the source cache because inspect can return out-of-date
866 # Flush the source cache because inspect can return out-of-date
862 # source
867 # source
863 linecache.checkcache()
868 linecache.checkcache()
864 try:
869 try:
865 if isinstance(obj, property) or not binary_file:
870 if isinstance(obj, property) or not binary_file:
866 src = getsource(obj, oname)
871 src = getsource(obj, oname)
867 if src is not None:
872 if src is not None:
868 src = src.rstrip()
873 src = src.rstrip()
869 out['source'] = src
874 out['source'] = src
870
875
871 except Exception:
876 except Exception:
872 pass
877 pass
873
878
874 # Add docstring only if no source is to be shown (avoid repetitions).
879 # Add docstring only if no source is to be shown (avoid repetitions).
875 if ds and not self._source_contains_docstring(out.get('source'), ds):
880 if ds and not self._source_contains_docstring(out.get('source'), ds):
876 out['docstring'] = ds
881 out['docstring'] = ds
877
882
878 # Constructor docstring for classes
883 # Constructor docstring for classes
879 if inspect.isclass(obj):
884 if inspect.isclass(obj):
880 out['isclass'] = True
885 out['isclass'] = True
881
886
882 # get the init signature:
887 # get the init signature:
883 try:
888 try:
884 init_def = self._getdef(obj, oname)
889 init_def = self._getdef(obj, oname)
885 except AttributeError:
890 except AttributeError:
886 init_def = None
891 init_def = None
887
892
888 # get the __init__ docstring
893 # get the __init__ docstring
889 try:
894 try:
890 obj_init = obj.__init__
895 obj_init = obj.__init__
891 except AttributeError:
896 except AttributeError:
892 init_ds = None
897 init_ds = None
893 else:
898 else:
894 if init_def is None:
899 if init_def is None:
895 # Get signature from init if top-level sig failed.
900 # Get signature from init if top-level sig failed.
896 # Can happen for built-in types (list, etc.).
901 # Can happen for built-in types (list, etc.).
897 try:
902 try:
898 init_def = self._getdef(obj_init, oname)
903 init_def = self._getdef(obj_init, oname)
899 except AttributeError:
904 except AttributeError:
900 pass
905 pass
901 init_ds = getdoc(obj_init)
906 init_ds = getdoc(obj_init)
902 # Skip Python's auto-generated docstrings
907 # Skip Python's auto-generated docstrings
903 if init_ds == _object_init_docstring:
908 if init_ds == _object_init_docstring:
904 init_ds = None
909 init_ds = None
905
910
906 if init_def:
911 if init_def:
907 out['init_definition'] = init_def
912 out['init_definition'] = init_def
908
913
909 if init_ds:
914 if init_ds:
910 out['init_docstring'] = init_ds
915 out['init_docstring'] = init_ds
911
916
912 names = [sub.__name__ for sub in type.__subclasses__(obj)]
917 names = [sub.__name__ for sub in type.__subclasses__(obj)]
913 if len(names) < 10:
918 if len(names) < 10:
914 all_names = ', '.join(names)
919 all_names = ', '.join(names)
915 else:
920 else:
916 all_names = ', '.join(names[:10]+['...'])
921 all_names = ', '.join(names[:10]+['...'])
917 out['subclasses'] = all_names
922 out['subclasses'] = all_names
918 # and class docstring for instances:
923 # and class docstring for instances:
919 else:
924 else:
920 # reconstruct the function definition and print it:
925 # reconstruct the function definition and print it:
921 defln = self._getdef(obj, oname)
926 defln = self._getdef(obj, oname)
922 if defln:
927 if defln:
923 out['definition'] = defln
928 out['definition'] = defln
924
929
925 # First, check whether the instance docstring is identical to the
930 # First, check whether the instance docstring is identical to the
926 # class one, and print it separately if they don't coincide. In
931 # class one, and print it separately if they don't coincide. In
927 # most cases they will, but it's nice to print all the info for
932 # most cases they will, but it's nice to print all the info for
928 # objects which use instance-customized docstrings.
933 # objects which use instance-customized docstrings.
929 if ds:
934 if ds:
930 try:
935 try:
931 cls = getattr(obj,'__class__')
936 cls = getattr(obj,'__class__')
932 except:
937 except:
933 class_ds = None
938 class_ds = None
934 else:
939 else:
935 class_ds = getdoc(cls)
940 class_ds = getdoc(cls)
936 # Skip Python's auto-generated docstrings
941 # Skip Python's auto-generated docstrings
937 if class_ds in _builtin_type_docstrings:
942 if class_ds in _builtin_type_docstrings:
938 class_ds = None
943 class_ds = None
939 if class_ds and ds != class_ds:
944 if class_ds and ds != class_ds:
940 out['class_docstring'] = class_ds
945 out['class_docstring'] = class_ds
941
946
942 # Next, try to show constructor docstrings
947 # Next, try to show constructor docstrings
943 try:
948 try:
944 init_ds = getdoc(obj.__init__)
949 init_ds = getdoc(obj.__init__)
945 # Skip Python's auto-generated docstrings
950 # Skip Python's auto-generated docstrings
946 if init_ds == _object_init_docstring:
951 if init_ds == _object_init_docstring:
947 init_ds = None
952 init_ds = None
948 except AttributeError:
953 except AttributeError:
949 init_ds = None
954 init_ds = None
950 if init_ds:
955 if init_ds:
951 out['init_docstring'] = init_ds
956 out['init_docstring'] = init_ds
952
957
953 # Call form docstring for callable instances
958 # Call form docstring for callable instances
954 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
959 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
955 call_def = self._getdef(obj.__call__, oname)
960 call_def = self._getdef(obj.__call__, oname)
956 if call_def and (call_def != out.get('definition')):
961 if call_def and (call_def != out.get('definition')):
957 # it may never be the case that call def and definition differ,
962 # it may never be the case that call def and definition differ,
958 # but don't include the same signature twice
963 # but don't include the same signature twice
959 out['call_def'] = call_def
964 out['call_def'] = call_def
960 call_ds = getdoc(obj.__call__)
965 call_ds = getdoc(obj.__call__)
961 # Skip Python's auto-generated docstrings
966 # Skip Python's auto-generated docstrings
962 if call_ds == _func_call_docstring:
967 if call_ds == _func_call_docstring:
963 call_ds = None
968 call_ds = None
964 if call_ds:
969 if call_ds:
965 out['call_docstring'] = call_ds
970 out['call_docstring'] = call_ds
966
971
967 return object_info(**out)
972 return object_info(**out)
968
973
969 @staticmethod
974 @staticmethod
970 def _source_contains_docstring(src, doc):
975 def _source_contains_docstring(src, doc):
971 """
976 """
972 Check whether the source *src* contains the docstring *doc*.
977 Check whether the source *src* contains the docstring *doc*.
973
978
974 This is is helper function to skip displaying the docstring if the
979 This is is helper function to skip displaying the docstring if the
975 source already contains it, avoiding repetition of information.
980 source already contains it, avoiding repetition of information.
976 """
981 """
977 try:
982 try:
978 def_node, = ast.parse(dedent(src)).body
983 def_node, = ast.parse(dedent(src)).body
979 return ast.get_docstring(def_node) == doc
984 return ast.get_docstring(def_node) == doc
980 except Exception:
985 except Exception:
981 # The source can become invalid or even non-existent (because it
986 # The source can become invalid or even non-existent (because it
982 # is re-fetched from the source file) so the above code fail in
987 # is re-fetched from the source file) so the above code fail in
983 # arbitrary ways.
988 # arbitrary ways.
984 return False
989 return False
985
990
986 def psearch(self,pattern,ns_table,ns_search=[],
991 def psearch(self,pattern,ns_table,ns_search=[],
987 ignore_case=False,show_all=False, *, list_types=False):
992 ignore_case=False,show_all=False, *, list_types=False):
988 """Search namespaces with wildcards for objects.
993 """Search namespaces with wildcards for objects.
989
994
990 Arguments:
995 Arguments:
991
996
992 - pattern: string containing shell-like wildcards to use in namespace
997 - pattern: string containing shell-like wildcards to use in namespace
993 searches and optionally a type specification to narrow the search to
998 searches and optionally a type specification to narrow the search to
994 objects of that type.
999 objects of that type.
995
1000
996 - ns_table: dict of name->namespaces for search.
1001 - ns_table: dict of name->namespaces for search.
997
1002
998 Optional arguments:
1003 Optional arguments:
999
1004
1000 - ns_search: list of namespace names to include in search.
1005 - ns_search: list of namespace names to include in search.
1001
1006
1002 - ignore_case(False): make the search case-insensitive.
1007 - ignore_case(False): make the search case-insensitive.
1003
1008
1004 - show_all(False): show all names, including those starting with
1009 - show_all(False): show all names, including those starting with
1005 underscores.
1010 underscores.
1006
1011
1007 - list_types(False): list all available object types for object matching.
1012 - list_types(False): list all available object types for object matching.
1008 """
1013 """
1009 #print 'ps pattern:<%r>' % pattern # dbg
1014 #print 'ps pattern:<%r>' % pattern # dbg
1010
1015
1011 # defaults
1016 # defaults
1012 type_pattern = 'all'
1017 type_pattern = 'all'
1013 filter = ''
1018 filter = ''
1014
1019
1015 # list all object types
1020 # list all object types
1016 if list_types:
1021 if list_types:
1017 page.page('\n'.join(sorted(typestr2type)))
1022 page.page('\n'.join(sorted(typestr2type)))
1018 return
1023 return
1019
1024
1020 cmds = pattern.split()
1025 cmds = pattern.split()
1021 len_cmds = len(cmds)
1026 len_cmds = len(cmds)
1022 if len_cmds == 1:
1027 if len_cmds == 1:
1023 # Only filter pattern given
1028 # Only filter pattern given
1024 filter = cmds[0]
1029 filter = cmds[0]
1025 elif len_cmds == 2:
1030 elif len_cmds == 2:
1026 # Both filter and type specified
1031 # Both filter and type specified
1027 filter,type_pattern = cmds
1032 filter,type_pattern = cmds
1028 else:
1033 else:
1029 raise ValueError('invalid argument string for psearch: <%s>' %
1034 raise ValueError('invalid argument string for psearch: <%s>' %
1030 pattern)
1035 pattern)
1031
1036
1032 # filter search namespaces
1037 # filter search namespaces
1033 for name in ns_search:
1038 for name in ns_search:
1034 if name not in ns_table:
1039 if name not in ns_table:
1035 raise ValueError('invalid namespace <%s>. Valid names: %s' %
1040 raise ValueError('invalid namespace <%s>. Valid names: %s' %
1036 (name,ns_table.keys()))
1041 (name,ns_table.keys()))
1037
1042
1038 #print 'type_pattern:',type_pattern # dbg
1043 #print 'type_pattern:',type_pattern # dbg
1039 search_result, namespaces_seen = set(), set()
1044 search_result, namespaces_seen = set(), set()
1040 for ns_name in ns_search:
1045 for ns_name in ns_search:
1041 ns = ns_table[ns_name]
1046 ns = ns_table[ns_name]
1042 # Normally, locals and globals are the same, so we just check one.
1047 # Normally, locals and globals are the same, so we just check one.
1043 if id(ns) in namespaces_seen:
1048 if id(ns) in namespaces_seen:
1044 continue
1049 continue
1045 namespaces_seen.add(id(ns))
1050 namespaces_seen.add(id(ns))
1046 tmp_res = list_namespace(ns, type_pattern, filter,
1051 tmp_res = list_namespace(ns, type_pattern, filter,
1047 ignore_case=ignore_case, show_all=show_all)
1052 ignore_case=ignore_case, show_all=show_all)
1048 search_result.update(tmp_res)
1053 search_result.update(tmp_res)
1049
1054
1050 page.page('\n'.join(sorted(search_result)))
1055 page.page('\n'.join(sorted(search_result)))
1051
1056
1052
1057
1053 def _render_signature(obj_signature, obj_name) -> str:
1058 def _render_signature(obj_signature, obj_name) -> str:
1054 """
1059 """
1055 This was mostly taken from inspect.Signature.__str__.
1060 This was mostly taken from inspect.Signature.__str__.
1056 Look there for the comments.
1061 Look there for the comments.
1057 The only change is to add linebreaks when this gets too long.
1062 The only change is to add linebreaks when this gets too long.
1058 """
1063 """
1059 result = []
1064 result = []
1060 pos_only = False
1065 pos_only = False
1061 kw_only = True
1066 kw_only = True
1062 for param in obj_signature.parameters.values():
1067 for param in obj_signature.parameters.values():
1063 if param.kind == inspect._POSITIONAL_ONLY:
1068 if param.kind == inspect.Parameter.POSITIONAL_ONLY:
1064 pos_only = True
1069 pos_only = True
1065 elif pos_only:
1070 elif pos_only:
1066 result.append('/')
1071 result.append('/')
1067 pos_only = False
1072 pos_only = False
1068
1073
1069 if param.kind == inspect._VAR_POSITIONAL:
1074 if param.kind == inspect.Parameter.VAR_POSITIONAL:
1070 kw_only = False
1075 kw_only = False
1071 elif param.kind == inspect._KEYWORD_ONLY and kw_only:
1076 elif param.kind == inspect.Parameter.KEYWORD_ONLY and kw_only:
1072 result.append('*')
1077 result.append('*')
1073 kw_only = False
1078 kw_only = False
1074
1079
1075 result.append(str(param))
1080 result.append(str(param))
1076
1081
1077 if pos_only:
1082 if pos_only:
1078 result.append('/')
1083 result.append('/')
1079
1084
1080 # add up name, parameters, braces (2), and commas
1085 # add up name, parameters, braces (2), and commas
1081 if len(obj_name) + sum(len(r) + 2 for r in result) > 75:
1086 if len(obj_name) + sum(len(r) + 2 for r in result) > 75:
1082 # This doesn’t fit behind “Signature: ” in an inspect window.
1087 # This doesn’t fit behind “Signature: ” in an inspect window.
1083 rendered = '{}(\n{})'.format(obj_name, ''.join(
1088 rendered = '{}(\n{})'.format(obj_name, ''.join(
1084 ' {},\n'.format(r) for r in result)
1089 ' {},\n'.format(r) for r in result)
1085 )
1090 )
1086 else:
1091 else:
1087 rendered = '{}({})'.format(obj_name, ', '.join(result))
1092 rendered = '{}({})'.format(obj_name, ', '.join(result))
1088
1093
1089 if obj_signature.return_annotation is not inspect._empty:
1094 if obj_signature.return_annotation is not inspect._empty:
1090 anno = inspect.formatannotation(obj_signature.return_annotation)
1095 anno = inspect.formatannotation(obj_signature.return_annotation)
1091 rendered += ' -> {}'.format(anno)
1096 rendered += ' -> {}'.format(anno)
1092
1097
1093 return rendered
1098 return rendered
@@ -1,1200 +1,1200 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the key interactiveshell module.
2 """Tests for the key interactiveshell module.
3
3
4 Historically the main classes in interactiveshell have been under-tested. This
4 Historically the main classes in interactiveshell have been under-tested. This
5 module should grow as many single-method tests as possible to trap many of the
5 module should grow as many single-method tests as possible to trap many of the
6 recurring bugs we seem to encounter with high-level interaction.
6 recurring bugs we seem to encounter with high-level interaction.
7 """
7 """
8
8
9 # Copyright (c) IPython Development Team.
9 # Copyright (c) IPython Development Team.
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11
11
12 import asyncio
12 import asyncio
13 import ast
13 import ast
14 import os
14 import os
15 import signal
15 import signal
16 import shutil
16 import shutil
17 import sys
17 import sys
18 import tempfile
18 import tempfile
19 import unittest
19 import unittest
20 import pytest
20 import pytest
21 from unittest import mock
21 from unittest import mock
22
22
23 from os.path import join
23 from os.path import join
24
24
25 from IPython.core.error import InputRejected
25 from IPython.core.error import InputRejected
26 from IPython.core.inputtransformer import InputTransformer
26 from IPython.core.inputtransformer import InputTransformer
27 from IPython.core import interactiveshell
27 from IPython.core import interactiveshell
28 from IPython.core.oinspect import OInfo
28 from IPython.core.oinspect import OInfo
29 from IPython.testing.decorators import (
29 from IPython.testing.decorators import (
30 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
30 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
31 )
31 )
32 from IPython.testing import tools as tt
32 from IPython.testing import tools as tt
33 from IPython.utils.process import find_cmd
33 from IPython.utils.process import find_cmd
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Globals
36 # Globals
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # This is used by every single test, no point repeating it ad nauseam
38 # This is used by every single test, no point repeating it ad nauseam
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Tests
41 # Tests
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 class DerivedInterrupt(KeyboardInterrupt):
44 class DerivedInterrupt(KeyboardInterrupt):
45 pass
45 pass
46
46
47 class InteractiveShellTestCase(unittest.TestCase):
47 class InteractiveShellTestCase(unittest.TestCase):
48 def test_naked_string_cells(self):
48 def test_naked_string_cells(self):
49 """Test that cells with only naked strings are fully executed"""
49 """Test that cells with only naked strings are fully executed"""
50 # First, single-line inputs
50 # First, single-line inputs
51 ip.run_cell('"a"\n')
51 ip.run_cell('"a"\n')
52 self.assertEqual(ip.user_ns['_'], 'a')
52 self.assertEqual(ip.user_ns['_'], 'a')
53 # And also multi-line cells
53 # And also multi-line cells
54 ip.run_cell('"""a\nb"""\n')
54 ip.run_cell('"""a\nb"""\n')
55 self.assertEqual(ip.user_ns['_'], 'a\nb')
55 self.assertEqual(ip.user_ns['_'], 'a\nb')
56
56
57 def test_run_empty_cell(self):
57 def test_run_empty_cell(self):
58 """Just make sure we don't get a horrible error with a blank
58 """Just make sure we don't get a horrible error with a blank
59 cell of input. Yes, I did overlook that."""
59 cell of input. Yes, I did overlook that."""
60 old_xc = ip.execution_count
60 old_xc = ip.execution_count
61 res = ip.run_cell('')
61 res = ip.run_cell('')
62 self.assertEqual(ip.execution_count, old_xc)
62 self.assertEqual(ip.execution_count, old_xc)
63 self.assertEqual(res.execution_count, None)
63 self.assertEqual(res.execution_count, None)
64
64
65 def test_run_cell_multiline(self):
65 def test_run_cell_multiline(self):
66 """Multi-block, multi-line cells must execute correctly.
66 """Multi-block, multi-line cells must execute correctly.
67 """
67 """
68 src = '\n'.join(["x=1",
68 src = '\n'.join(["x=1",
69 "y=2",
69 "y=2",
70 "if 1:",
70 "if 1:",
71 " x += 1",
71 " x += 1",
72 " y += 1",])
72 " y += 1",])
73 res = ip.run_cell(src)
73 res = ip.run_cell(src)
74 self.assertEqual(ip.user_ns['x'], 2)
74 self.assertEqual(ip.user_ns['x'], 2)
75 self.assertEqual(ip.user_ns['y'], 3)
75 self.assertEqual(ip.user_ns['y'], 3)
76 self.assertEqual(res.success, True)
76 self.assertEqual(res.success, True)
77 self.assertEqual(res.result, None)
77 self.assertEqual(res.result, None)
78
78
79 def test_multiline_string_cells(self):
79 def test_multiline_string_cells(self):
80 "Code sprinkled with multiline strings should execute (GH-306)"
80 "Code sprinkled with multiline strings should execute (GH-306)"
81 ip.run_cell('tmp=0')
81 ip.run_cell('tmp=0')
82 self.assertEqual(ip.user_ns['tmp'], 0)
82 self.assertEqual(ip.user_ns['tmp'], 0)
83 res = ip.run_cell('tmp=1;"""a\nb"""\n')
83 res = ip.run_cell('tmp=1;"""a\nb"""\n')
84 self.assertEqual(ip.user_ns['tmp'], 1)
84 self.assertEqual(ip.user_ns['tmp'], 1)
85 self.assertEqual(res.success, True)
85 self.assertEqual(res.success, True)
86 self.assertEqual(res.result, "a\nb")
86 self.assertEqual(res.result, "a\nb")
87
87
88 def test_dont_cache_with_semicolon(self):
88 def test_dont_cache_with_semicolon(self):
89 "Ending a line with semicolon should not cache the returned object (GH-307)"
89 "Ending a line with semicolon should not cache the returned object (GH-307)"
90 oldlen = len(ip.user_ns['Out'])
90 oldlen = len(ip.user_ns['Out'])
91 for cell in ['1;', '1;1;']:
91 for cell in ['1;', '1;1;']:
92 res = ip.run_cell(cell, store_history=True)
92 res = ip.run_cell(cell, store_history=True)
93 newlen = len(ip.user_ns['Out'])
93 newlen = len(ip.user_ns['Out'])
94 self.assertEqual(oldlen, newlen)
94 self.assertEqual(oldlen, newlen)
95 self.assertIsNone(res.result)
95 self.assertIsNone(res.result)
96 i = 0
96 i = 0
97 #also test the default caching behavior
97 #also test the default caching behavior
98 for cell in ['1', '1;1']:
98 for cell in ['1', '1;1']:
99 ip.run_cell(cell, store_history=True)
99 ip.run_cell(cell, store_history=True)
100 newlen = len(ip.user_ns['Out'])
100 newlen = len(ip.user_ns['Out'])
101 i += 1
101 i += 1
102 self.assertEqual(oldlen+i, newlen)
102 self.assertEqual(oldlen+i, newlen)
103
103
104 def test_syntax_error(self):
104 def test_syntax_error(self):
105 res = ip.run_cell("raise = 3")
105 res = ip.run_cell("raise = 3")
106 self.assertIsInstance(res.error_before_exec, SyntaxError)
106 self.assertIsInstance(res.error_before_exec, SyntaxError)
107
107
108 def test_open_standard_input_stream(self):
108 def test_open_standard_input_stream(self):
109 res = ip.run_cell("open(0)")
109 res = ip.run_cell("open(0)")
110 self.assertIsInstance(res.error_in_exec, ValueError)
110 self.assertIsInstance(res.error_in_exec, ValueError)
111
111
112 def test_open_standard_output_stream(self):
112 def test_open_standard_output_stream(self):
113 res = ip.run_cell("open(1)")
113 res = ip.run_cell("open(1)")
114 self.assertIsInstance(res.error_in_exec, ValueError)
114 self.assertIsInstance(res.error_in_exec, ValueError)
115
115
116 def test_open_standard_error_stream(self):
116 def test_open_standard_error_stream(self):
117 res = ip.run_cell("open(2)")
117 res = ip.run_cell("open(2)")
118 self.assertIsInstance(res.error_in_exec, ValueError)
118 self.assertIsInstance(res.error_in_exec, ValueError)
119
119
120 def test_In_variable(self):
120 def test_In_variable(self):
121 "Verify that In variable grows with user input (GH-284)"
121 "Verify that In variable grows with user input (GH-284)"
122 oldlen = len(ip.user_ns['In'])
122 oldlen = len(ip.user_ns['In'])
123 ip.run_cell('1;', store_history=True)
123 ip.run_cell('1;', store_history=True)
124 newlen = len(ip.user_ns['In'])
124 newlen = len(ip.user_ns['In'])
125 self.assertEqual(oldlen+1, newlen)
125 self.assertEqual(oldlen+1, newlen)
126 self.assertEqual(ip.user_ns['In'][-1],'1;')
126 self.assertEqual(ip.user_ns['In'][-1],'1;')
127
127
128 def test_magic_names_in_string(self):
128 def test_magic_names_in_string(self):
129 ip.run_cell('a = """\n%exit\n"""')
129 ip.run_cell('a = """\n%exit\n"""')
130 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
130 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
131
131
132 def test_trailing_newline(self):
132 def test_trailing_newline(self):
133 """test that running !(command) does not raise a SyntaxError"""
133 """test that running !(command) does not raise a SyntaxError"""
134 ip.run_cell('!(true)\n', False)
134 ip.run_cell('!(true)\n', False)
135 ip.run_cell('!(true)\n\n\n', False)
135 ip.run_cell('!(true)\n\n\n', False)
136
136
137 def test_gh_597(self):
137 def test_gh_597(self):
138 """Pretty-printing lists of objects with non-ascii reprs may cause
138 """Pretty-printing lists of objects with non-ascii reprs may cause
139 problems."""
139 problems."""
140 class Spam(object):
140 class Spam(object):
141 def __repr__(self):
141 def __repr__(self):
142 return "\xe9"*50
142 return "\xe9"*50
143 import IPython.core.formatters
143 import IPython.core.formatters
144 f = IPython.core.formatters.PlainTextFormatter()
144 f = IPython.core.formatters.PlainTextFormatter()
145 f([Spam(),Spam()])
145 f([Spam(),Spam()])
146
146
147
147
148 def test_future_flags(self):
148 def test_future_flags(self):
149 """Check that future flags are used for parsing code (gh-777)"""
149 """Check that future flags are used for parsing code (gh-777)"""
150 ip.run_cell('from __future__ import barry_as_FLUFL')
150 ip.run_cell('from __future__ import barry_as_FLUFL')
151 try:
151 try:
152 ip.run_cell('prfunc_return_val = 1 <> 2')
152 ip.run_cell('prfunc_return_val = 1 <> 2')
153 assert 'prfunc_return_val' in ip.user_ns
153 assert 'prfunc_return_val' in ip.user_ns
154 finally:
154 finally:
155 # Reset compiler flags so we don't mess up other tests.
155 # Reset compiler flags so we don't mess up other tests.
156 ip.compile.reset_compiler_flags()
156 ip.compile.reset_compiler_flags()
157
157
158 def test_can_pickle(self):
158 def test_can_pickle(self):
159 "Can we pickle objects defined interactively (GH-29)"
159 "Can we pickle objects defined interactively (GH-29)"
160 ip = get_ipython()
160 ip = get_ipython()
161 ip.reset()
161 ip.reset()
162 ip.run_cell(("class Mylist(list):\n"
162 ip.run_cell(("class Mylist(list):\n"
163 " def __init__(self,x=[]):\n"
163 " def __init__(self,x=[]):\n"
164 " list.__init__(self,x)"))
164 " list.__init__(self,x)"))
165 ip.run_cell("w=Mylist([1,2,3])")
165 ip.run_cell("w=Mylist([1,2,3])")
166
166
167 from pickle import dumps
167 from pickle import dumps
168
168
169 # We need to swap in our main module - this is only necessary
169 # We need to swap in our main module - this is only necessary
170 # inside the test framework, because IPython puts the interactive module
170 # inside the test framework, because IPython puts the interactive module
171 # in place (but the test framework undoes this).
171 # in place (but the test framework undoes this).
172 _main = sys.modules['__main__']
172 _main = sys.modules['__main__']
173 sys.modules['__main__'] = ip.user_module
173 sys.modules['__main__'] = ip.user_module
174 try:
174 try:
175 res = dumps(ip.user_ns["w"])
175 res = dumps(ip.user_ns["w"])
176 finally:
176 finally:
177 sys.modules['__main__'] = _main
177 sys.modules['__main__'] = _main
178 self.assertTrue(isinstance(res, bytes))
178 self.assertTrue(isinstance(res, bytes))
179
179
180 def test_global_ns(self):
180 def test_global_ns(self):
181 "Code in functions must be able to access variables outside them."
181 "Code in functions must be able to access variables outside them."
182 ip = get_ipython()
182 ip = get_ipython()
183 ip.run_cell("a = 10")
183 ip.run_cell("a = 10")
184 ip.run_cell(("def f(x):\n"
184 ip.run_cell(("def f(x):\n"
185 " return x + a"))
185 " return x + a"))
186 ip.run_cell("b = f(12)")
186 ip.run_cell("b = f(12)")
187 self.assertEqual(ip.user_ns["b"], 22)
187 self.assertEqual(ip.user_ns["b"], 22)
188
188
189 def test_bad_custom_tb(self):
189 def test_bad_custom_tb(self):
190 """Check that InteractiveShell is protected from bad custom exception handlers"""
190 """Check that InteractiveShell is protected from bad custom exception handlers"""
191 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
191 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
192 self.assertEqual(ip.custom_exceptions, (IOError,))
192 self.assertEqual(ip.custom_exceptions, (IOError,))
193 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
193 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
194 ip.run_cell(u'raise IOError("foo")')
194 ip.run_cell(u'raise IOError("foo")')
195 self.assertEqual(ip.custom_exceptions, ())
195 self.assertEqual(ip.custom_exceptions, ())
196
196
197 def test_bad_custom_tb_return(self):
197 def test_bad_custom_tb_return(self):
198 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
198 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
199 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
199 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
200 self.assertEqual(ip.custom_exceptions, (NameError,))
200 self.assertEqual(ip.custom_exceptions, (NameError,))
201 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
201 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
202 ip.run_cell(u'a=abracadabra')
202 ip.run_cell(u'a=abracadabra')
203 self.assertEqual(ip.custom_exceptions, ())
203 self.assertEqual(ip.custom_exceptions, ())
204
204
205 def test_drop_by_id(self):
205 def test_drop_by_id(self):
206 myvars = {"a":object(), "b":object(), "c": object()}
206 myvars = {"a":object(), "b":object(), "c": object()}
207 ip.push(myvars, interactive=False)
207 ip.push(myvars, interactive=False)
208 for name in myvars:
208 for name in myvars:
209 assert name in ip.user_ns, name
209 assert name in ip.user_ns, name
210 assert name in ip.user_ns_hidden, name
210 assert name in ip.user_ns_hidden, name
211 ip.user_ns['b'] = 12
211 ip.user_ns['b'] = 12
212 ip.drop_by_id(myvars)
212 ip.drop_by_id(myvars)
213 for name in ["a", "c"]:
213 for name in ["a", "c"]:
214 assert name not in ip.user_ns, name
214 assert name not in ip.user_ns, name
215 assert name not in ip.user_ns_hidden, name
215 assert name not in ip.user_ns_hidden, name
216 assert ip.user_ns['b'] == 12
216 assert ip.user_ns['b'] == 12
217 ip.reset()
217 ip.reset()
218
218
219 def test_var_expand(self):
219 def test_var_expand(self):
220 ip.user_ns['f'] = u'Ca\xf1o'
220 ip.user_ns['f'] = u'Ca\xf1o'
221 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
221 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
222 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
222 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
223 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
223 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
224 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
224 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
225
225
226 self.assertEqual(ip.var_expand(u"grep x | awk '{print $1}'"), u"grep x | awk '{print $1}'")
226 self.assertEqual(ip.var_expand(u"grep x | awk '{print $1}'"), u"grep x | awk '{print $1}'")
227
227
228 ip.user_ns['f'] = b'Ca\xc3\xb1o'
228 ip.user_ns['f'] = b'Ca\xc3\xb1o'
229 # This should not raise any exception:
229 # This should not raise any exception:
230 ip.var_expand(u'echo $f')
230 ip.var_expand(u'echo $f')
231
231
232 def test_var_expand_local(self):
232 def test_var_expand_local(self):
233 """Test local variable expansion in !system and %magic calls"""
233 """Test local variable expansion in !system and %magic calls"""
234 # !system
234 # !system
235 ip.run_cell(
235 ip.run_cell(
236 "def test():\n"
236 "def test():\n"
237 ' lvar = "ttt"\n'
237 ' lvar = "ttt"\n'
238 " ret = !echo {lvar}\n"
238 " ret = !echo {lvar}\n"
239 " return ret[0]\n"
239 " return ret[0]\n"
240 )
240 )
241 res = ip.user_ns["test"]()
241 res = ip.user_ns["test"]()
242 self.assertIn("ttt", res)
242 self.assertIn("ttt", res)
243
243
244 # %magic
244 # %magic
245 ip.run_cell(
245 ip.run_cell(
246 "def makemacro():\n"
246 "def makemacro():\n"
247 ' macroname = "macro_var_expand_locals"\n'
247 ' macroname = "macro_var_expand_locals"\n'
248 " %macro {macroname} codestr\n"
248 " %macro {macroname} codestr\n"
249 )
249 )
250 ip.user_ns["codestr"] = "str(12)"
250 ip.user_ns["codestr"] = "str(12)"
251 ip.run_cell("makemacro()")
251 ip.run_cell("makemacro()")
252 self.assertIn("macro_var_expand_locals", ip.user_ns)
252 self.assertIn("macro_var_expand_locals", ip.user_ns)
253
253
254 def test_var_expand_self(self):
254 def test_var_expand_self(self):
255 """Test variable expansion with the name 'self', which was failing.
255 """Test variable expansion with the name 'self', which was failing.
256
256
257 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
257 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
258 """
258 """
259 ip.run_cell(
259 ip.run_cell(
260 "class cTest:\n"
260 "class cTest:\n"
261 ' classvar="see me"\n'
261 ' classvar="see me"\n'
262 " def test(self):\n"
262 " def test(self):\n"
263 " res = !echo Variable: {self.classvar}\n"
263 " res = !echo Variable: {self.classvar}\n"
264 " return res[0]\n"
264 " return res[0]\n"
265 )
265 )
266 self.assertIn("see me", ip.user_ns["cTest"]().test())
266 self.assertIn("see me", ip.user_ns["cTest"]().test())
267
267
268 def test_bad_var_expand(self):
268 def test_bad_var_expand(self):
269 """var_expand on invalid formats shouldn't raise"""
269 """var_expand on invalid formats shouldn't raise"""
270 # SyntaxError
270 # SyntaxError
271 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
271 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
272 # NameError
272 # NameError
273 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
273 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
274 # ZeroDivisionError
274 # ZeroDivisionError
275 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
275 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
276
276
277 def test_silent_postexec(self):
277 def test_silent_postexec(self):
278 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
278 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
279 pre_explicit = mock.Mock()
279 pre_explicit = mock.Mock()
280 pre_always = mock.Mock()
280 pre_always = mock.Mock()
281 post_explicit = mock.Mock()
281 post_explicit = mock.Mock()
282 post_always = mock.Mock()
282 post_always = mock.Mock()
283 all_mocks = [pre_explicit, pre_always, post_explicit, post_always]
283 all_mocks = [pre_explicit, pre_always, post_explicit, post_always]
284
284
285 ip.events.register('pre_run_cell', pre_explicit)
285 ip.events.register('pre_run_cell', pre_explicit)
286 ip.events.register('pre_execute', pre_always)
286 ip.events.register('pre_execute', pre_always)
287 ip.events.register('post_run_cell', post_explicit)
287 ip.events.register('post_run_cell', post_explicit)
288 ip.events.register('post_execute', post_always)
288 ip.events.register('post_execute', post_always)
289
289
290 try:
290 try:
291 ip.run_cell("1", silent=True)
291 ip.run_cell("1", silent=True)
292 assert pre_always.called
292 assert pre_always.called
293 assert not pre_explicit.called
293 assert not pre_explicit.called
294 assert post_always.called
294 assert post_always.called
295 assert not post_explicit.called
295 assert not post_explicit.called
296 # double-check that non-silent exec did what we expected
296 # double-check that non-silent exec did what we expected
297 # silent to avoid
297 # silent to avoid
298 ip.run_cell("1")
298 ip.run_cell("1")
299 assert pre_explicit.called
299 assert pre_explicit.called
300 assert post_explicit.called
300 assert post_explicit.called
301 info, = pre_explicit.call_args[0]
301 info, = pre_explicit.call_args[0]
302 result, = post_explicit.call_args[0]
302 result, = post_explicit.call_args[0]
303 self.assertEqual(info, result.info)
303 self.assertEqual(info, result.info)
304 # check that post hooks are always called
304 # check that post hooks are always called
305 [m.reset_mock() for m in all_mocks]
305 [m.reset_mock() for m in all_mocks]
306 ip.run_cell("syntax error")
306 ip.run_cell("syntax error")
307 assert pre_always.called
307 assert pre_always.called
308 assert pre_explicit.called
308 assert pre_explicit.called
309 assert post_always.called
309 assert post_always.called
310 assert post_explicit.called
310 assert post_explicit.called
311 info, = pre_explicit.call_args[0]
311 info, = pre_explicit.call_args[0]
312 result, = post_explicit.call_args[0]
312 result, = post_explicit.call_args[0]
313 self.assertEqual(info, result.info)
313 self.assertEqual(info, result.info)
314 finally:
314 finally:
315 # remove post-exec
315 # remove post-exec
316 ip.events.unregister('pre_run_cell', pre_explicit)
316 ip.events.unregister('pre_run_cell', pre_explicit)
317 ip.events.unregister('pre_execute', pre_always)
317 ip.events.unregister('pre_execute', pre_always)
318 ip.events.unregister('post_run_cell', post_explicit)
318 ip.events.unregister('post_run_cell', post_explicit)
319 ip.events.unregister('post_execute', post_always)
319 ip.events.unregister('post_execute', post_always)
320
320
321 def test_silent_noadvance(self):
321 def test_silent_noadvance(self):
322 """run_cell(silent=True) doesn't advance execution_count"""
322 """run_cell(silent=True) doesn't advance execution_count"""
323 ec = ip.execution_count
323 ec = ip.execution_count
324 # silent should force store_history=False
324 # silent should force store_history=False
325 ip.run_cell("1", store_history=True, silent=True)
325 ip.run_cell("1", store_history=True, silent=True)
326
326
327 self.assertEqual(ec, ip.execution_count)
327 self.assertEqual(ec, ip.execution_count)
328 # double-check that non-silent exec did what we expected
328 # double-check that non-silent exec did what we expected
329 # silent to avoid
329 # silent to avoid
330 ip.run_cell("1", store_history=True)
330 ip.run_cell("1", store_history=True)
331 self.assertEqual(ec+1, ip.execution_count)
331 self.assertEqual(ec+1, ip.execution_count)
332
332
333 def test_silent_nodisplayhook(self):
333 def test_silent_nodisplayhook(self):
334 """run_cell(silent=True) doesn't trigger displayhook"""
334 """run_cell(silent=True) doesn't trigger displayhook"""
335 d = dict(called=False)
335 d = dict(called=False)
336
336
337 trap = ip.display_trap
337 trap = ip.display_trap
338 save_hook = trap.hook
338 save_hook = trap.hook
339
339
340 def failing_hook(*args, **kwargs):
340 def failing_hook(*args, **kwargs):
341 d['called'] = True
341 d['called'] = True
342
342
343 try:
343 try:
344 trap.hook = failing_hook
344 trap.hook = failing_hook
345 res = ip.run_cell("1", silent=True)
345 res = ip.run_cell("1", silent=True)
346 self.assertFalse(d['called'])
346 self.assertFalse(d['called'])
347 self.assertIsNone(res.result)
347 self.assertIsNone(res.result)
348 # double-check that non-silent exec did what we expected
348 # double-check that non-silent exec did what we expected
349 # silent to avoid
349 # silent to avoid
350 ip.run_cell("1")
350 ip.run_cell("1")
351 self.assertTrue(d['called'])
351 self.assertTrue(d['called'])
352 finally:
352 finally:
353 trap.hook = save_hook
353 trap.hook = save_hook
354
354
355 def test_ofind_line_magic(self):
355 def test_ofind_line_magic(self):
356 from IPython.core.magic import register_line_magic
356 from IPython.core.magic import register_line_magic
357
357
358 @register_line_magic
358 @register_line_magic
359 def lmagic(line):
359 def lmagic(line):
360 "A line magic"
360 "A line magic"
361
361
362 # Get info on line magic
362 # Get info on line magic
363 lfind = ip._ofind("lmagic")
363 lfind = ip._ofind("lmagic")
364 info = OInfo(
364 info = OInfo(
365 found=True,
365 found=True,
366 isalias=False,
366 isalias=False,
367 ismagic=True,
367 ismagic=True,
368 namespace="IPython internal",
368 namespace="IPython internal",
369 obj=lmagic,
369 obj=lmagic,
370 parent=None,
370 parent=None,
371 )
371 )
372 self.assertEqual(lfind, info)
372 self.assertEqual(lfind, info)
373
373
374 def test_ofind_cell_magic(self):
374 def test_ofind_cell_magic(self):
375 from IPython.core.magic import register_cell_magic
375 from IPython.core.magic import register_cell_magic
376
376
377 @register_cell_magic
377 @register_cell_magic
378 def cmagic(line, cell):
378 def cmagic(line, cell):
379 "A cell magic"
379 "A cell magic"
380
380
381 # Get info on cell magic
381 # Get info on cell magic
382 find = ip._ofind("cmagic")
382 find = ip._ofind("cmagic")
383 info = OInfo(
383 info = OInfo(
384 found=True,
384 found=True,
385 isalias=False,
385 isalias=False,
386 ismagic=True,
386 ismagic=True,
387 namespace="IPython internal",
387 namespace="IPython internal",
388 obj=cmagic,
388 obj=cmagic,
389 parent=None,
389 parent=None,
390 )
390 )
391 self.assertEqual(find, info)
391 self.assertEqual(find, info)
392
392
393 def test_ofind_property_with_error(self):
393 def test_ofind_property_with_error(self):
394 class A(object):
394 class A(object):
395 @property
395 @property
396 def foo(self):
396 def foo(self):
397 raise NotImplementedError() # pragma: no cover
397 raise NotImplementedError() # pragma: no cover
398
398
399 a = A()
399 a = A()
400
400
401 found = ip._ofind("a.foo", [("locals", locals())])
401 found = ip._ofind("a.foo", [("locals", locals())])
402 info = OInfo(
402 info = OInfo(
403 found=True,
403 found=True,
404 isalias=False,
404 isalias=False,
405 ismagic=False,
405 ismagic=False,
406 namespace="locals",
406 namespace="locals",
407 obj=A.foo,
407 obj=A.foo,
408 parent=a,
408 parent=a,
409 )
409 )
410 self.assertEqual(found, info)
410 self.assertEqual(found, info)
411
411
412 def test_ofind_multiple_attribute_lookups(self):
412 def test_ofind_multiple_attribute_lookups(self):
413 class A(object):
413 class A(object):
414 @property
414 @property
415 def foo(self):
415 def foo(self):
416 raise NotImplementedError() # pragma: no cover
416 raise NotImplementedError() # pragma: no cover
417
417
418 a = A()
418 a = A()
419 a.a = A()
419 a.a = A()
420 a.a.a = A()
420 a.a.a = A()
421
421
422 found = ip._ofind("a.a.a.foo", [("locals", locals())])
422 found = ip._ofind("a.a.a.foo", [("locals", locals())])
423 info = OInfo(
423 info = OInfo(
424 found=True,
424 found=True,
425 isalias=False,
425 isalias=False,
426 ismagic=False,
426 ismagic=False,
427 namespace="locals",
427 namespace="locals",
428 obj=A.foo,
428 obj=A.foo,
429 parent=a.a.a,
429 parent=a.a.a,
430 )
430 )
431 self.assertEqual(found, info)
431 self.assertEqual(found, info)
432
432
433 def test_ofind_slotted_attributes(self):
433 def test_ofind_slotted_attributes(self):
434 class A(object):
434 class A(object):
435 __slots__ = ['foo']
435 __slots__ = ['foo']
436 def __init__(self):
436 def __init__(self):
437 self.foo = 'bar'
437 self.foo = 'bar'
438
438
439 a = A()
439 a = A()
440 found = ip._ofind("a.foo", [("locals", locals())])
440 found = ip._ofind("a.foo", [("locals", locals())])
441 info = OInfo(
441 info = OInfo(
442 found=True,
442 found=True,
443 isalias=False,
443 isalias=False,
444 ismagic=False,
444 ismagic=False,
445 namespace="locals",
445 namespace="locals",
446 obj=a.foo,
446 obj=a.foo,
447 parent=a,
447 parent=a,
448 )
448 )
449 self.assertEqual(found, info)
449 self.assertEqual(found, info)
450
450
451 found = ip._ofind("a.bar", [("locals", locals())])
451 found = ip._ofind("a.bar", [("locals", locals())])
452 info = OInfo(
452 expected = OInfo(
453 found=False,
453 found=False,
454 isalias=False,
454 isalias=False,
455 ismagic=False,
455 ismagic=False,
456 namespace=None,
456 namespace=None,
457 obj=None,
457 obj=None,
458 parent=a,
458 parent=a,
459 )
459 )
460 self.assertEqual(found, info)
460 assert found == expected
461
461
462 def test_ofind_prefers_property_to_instance_level_attribute(self):
462 def test_ofind_prefers_property_to_instance_level_attribute(self):
463 class A(object):
463 class A(object):
464 @property
464 @property
465 def foo(self):
465 def foo(self):
466 return 'bar'
466 return 'bar'
467 a = A()
467 a = A()
468 a.__dict__["foo"] = "baz"
468 a.__dict__["foo"] = "baz"
469 self.assertEqual(a.foo, "bar")
469 self.assertEqual(a.foo, "bar")
470 found = ip._ofind("a.foo", [("locals", locals())])
470 found = ip._ofind("a.foo", [("locals", locals())])
471 self.assertIs(found.obj, A.foo)
471 self.assertIs(found.obj, A.foo)
472
472
473 def test_custom_syntaxerror_exception(self):
473 def test_custom_syntaxerror_exception(self):
474 called = []
474 called = []
475 def my_handler(shell, etype, value, tb, tb_offset=None):
475 def my_handler(shell, etype, value, tb, tb_offset=None):
476 called.append(etype)
476 called.append(etype)
477 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
477 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
478
478
479 ip.set_custom_exc((SyntaxError,), my_handler)
479 ip.set_custom_exc((SyntaxError,), my_handler)
480 try:
480 try:
481 ip.run_cell("1f")
481 ip.run_cell("1f")
482 # Check that this was called, and only once.
482 # Check that this was called, and only once.
483 self.assertEqual(called, [SyntaxError])
483 self.assertEqual(called, [SyntaxError])
484 finally:
484 finally:
485 # Reset the custom exception hook
485 # Reset the custom exception hook
486 ip.set_custom_exc((), None)
486 ip.set_custom_exc((), None)
487
487
488 def test_custom_exception(self):
488 def test_custom_exception(self):
489 called = []
489 called = []
490 def my_handler(shell, etype, value, tb, tb_offset=None):
490 def my_handler(shell, etype, value, tb, tb_offset=None):
491 called.append(etype)
491 called.append(etype)
492 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
492 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
493
493
494 ip.set_custom_exc((ValueError,), my_handler)
494 ip.set_custom_exc((ValueError,), my_handler)
495 try:
495 try:
496 res = ip.run_cell("raise ValueError('test')")
496 res = ip.run_cell("raise ValueError('test')")
497 # Check that this was called, and only once.
497 # Check that this was called, and only once.
498 self.assertEqual(called, [ValueError])
498 self.assertEqual(called, [ValueError])
499 # Check that the error is on the result object
499 # Check that the error is on the result object
500 self.assertIsInstance(res.error_in_exec, ValueError)
500 self.assertIsInstance(res.error_in_exec, ValueError)
501 finally:
501 finally:
502 # Reset the custom exception hook
502 # Reset the custom exception hook
503 ip.set_custom_exc((), None)
503 ip.set_custom_exc((), None)
504
504
505 @mock.patch("builtins.print")
505 @mock.patch("builtins.print")
506 def test_showtraceback_with_surrogates(self, mocked_print):
506 def test_showtraceback_with_surrogates(self, mocked_print):
507 values = []
507 values = []
508
508
509 def mock_print_func(value, sep=" ", end="\n", file=sys.stdout, flush=False):
509 def mock_print_func(value, sep=" ", end="\n", file=sys.stdout, flush=False):
510 values.append(value)
510 values.append(value)
511 if value == chr(0xD8FF):
511 if value == chr(0xD8FF):
512 raise UnicodeEncodeError("utf-8", chr(0xD8FF), 0, 1, "")
512 raise UnicodeEncodeError("utf-8", chr(0xD8FF), 0, 1, "")
513
513
514 # mock builtins.print
514 # mock builtins.print
515 mocked_print.side_effect = mock_print_func
515 mocked_print.side_effect = mock_print_func
516
516
517 # ip._showtraceback() is replaced in globalipapp.py.
517 # ip._showtraceback() is replaced in globalipapp.py.
518 # Call original method to test.
518 # Call original method to test.
519 interactiveshell.InteractiveShell._showtraceback(ip, None, None, chr(0xD8FF))
519 interactiveshell.InteractiveShell._showtraceback(ip, None, None, chr(0xD8FF))
520
520
521 self.assertEqual(mocked_print.call_count, 2)
521 self.assertEqual(mocked_print.call_count, 2)
522 self.assertEqual(values, [chr(0xD8FF), "\\ud8ff"])
522 self.assertEqual(values, [chr(0xD8FF), "\\ud8ff"])
523
523
524 def test_mktempfile(self):
524 def test_mktempfile(self):
525 filename = ip.mktempfile()
525 filename = ip.mktempfile()
526 # Check that we can open the file again on Windows
526 # Check that we can open the file again on Windows
527 with open(filename, "w", encoding="utf-8") as f:
527 with open(filename, "w", encoding="utf-8") as f:
528 f.write("abc")
528 f.write("abc")
529
529
530 filename = ip.mktempfile(data="blah")
530 filename = ip.mktempfile(data="blah")
531 with open(filename, "r", encoding="utf-8") as f:
531 with open(filename, "r", encoding="utf-8") as f:
532 self.assertEqual(f.read(), "blah")
532 self.assertEqual(f.read(), "blah")
533
533
534 def test_new_main_mod(self):
534 def test_new_main_mod(self):
535 # Smoketest to check that this accepts a unicode module name
535 # Smoketest to check that this accepts a unicode module name
536 name = u'jiefmw'
536 name = u'jiefmw'
537 mod = ip.new_main_mod(u'%s.py' % name, name)
537 mod = ip.new_main_mod(u'%s.py' % name, name)
538 self.assertEqual(mod.__name__, name)
538 self.assertEqual(mod.__name__, name)
539
539
540 def test_get_exception_only(self):
540 def test_get_exception_only(self):
541 try:
541 try:
542 raise KeyboardInterrupt
542 raise KeyboardInterrupt
543 except KeyboardInterrupt:
543 except KeyboardInterrupt:
544 msg = ip.get_exception_only()
544 msg = ip.get_exception_only()
545 self.assertEqual(msg, 'KeyboardInterrupt\n')
545 self.assertEqual(msg, 'KeyboardInterrupt\n')
546
546
547 try:
547 try:
548 raise DerivedInterrupt("foo")
548 raise DerivedInterrupt("foo")
549 except KeyboardInterrupt:
549 except KeyboardInterrupt:
550 msg = ip.get_exception_only()
550 msg = ip.get_exception_only()
551 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
551 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
552
552
553 def test_inspect_text(self):
553 def test_inspect_text(self):
554 ip.run_cell('a = 5')
554 ip.run_cell('a = 5')
555 text = ip.object_inspect_text('a')
555 text = ip.object_inspect_text('a')
556 self.assertIsInstance(text, str)
556 self.assertIsInstance(text, str)
557
557
558 def test_last_execution_result(self):
558 def test_last_execution_result(self):
559 """ Check that last execution result gets set correctly (GH-10702) """
559 """ Check that last execution result gets set correctly (GH-10702) """
560 result = ip.run_cell('a = 5; a')
560 result = ip.run_cell('a = 5; a')
561 self.assertTrue(ip.last_execution_succeeded)
561 self.assertTrue(ip.last_execution_succeeded)
562 self.assertEqual(ip.last_execution_result.result, 5)
562 self.assertEqual(ip.last_execution_result.result, 5)
563
563
564 result = ip.run_cell('a = x_invalid_id_x')
564 result = ip.run_cell('a = x_invalid_id_x')
565 self.assertFalse(ip.last_execution_succeeded)
565 self.assertFalse(ip.last_execution_succeeded)
566 self.assertFalse(ip.last_execution_result.success)
566 self.assertFalse(ip.last_execution_result.success)
567 self.assertIsInstance(ip.last_execution_result.error_in_exec, NameError)
567 self.assertIsInstance(ip.last_execution_result.error_in_exec, NameError)
568
568
569 def test_reset_aliasing(self):
569 def test_reset_aliasing(self):
570 """ Check that standard posix aliases work after %reset. """
570 """ Check that standard posix aliases work after %reset. """
571 if os.name != 'posix':
571 if os.name != 'posix':
572 return
572 return
573
573
574 ip.reset()
574 ip.reset()
575 for cmd in ('clear', 'more', 'less', 'man'):
575 for cmd in ('clear', 'more', 'less', 'man'):
576 res = ip.run_cell('%' + cmd)
576 res = ip.run_cell('%' + cmd)
577 self.assertEqual(res.success, True)
577 self.assertEqual(res.success, True)
578
578
579
579
580 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
580 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
581
581
582 @onlyif_unicode_paths
582 @onlyif_unicode_paths
583 def setUp(self):
583 def setUp(self):
584 self.BASETESTDIR = tempfile.mkdtemp()
584 self.BASETESTDIR = tempfile.mkdtemp()
585 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
585 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
586 os.mkdir(self.TESTDIR)
586 os.mkdir(self.TESTDIR)
587 with open(
587 with open(
588 join(self.TESTDIR, "åäötestscript.py"), "w", encoding="utf-8"
588 join(self.TESTDIR, "åäötestscript.py"), "w", encoding="utf-8"
589 ) as sfile:
589 ) as sfile:
590 sfile.write("pass\n")
590 sfile.write("pass\n")
591 self.oldpath = os.getcwd()
591 self.oldpath = os.getcwd()
592 os.chdir(self.TESTDIR)
592 os.chdir(self.TESTDIR)
593 self.fname = u"åäötestscript.py"
593 self.fname = u"åäötestscript.py"
594
594
595 def tearDown(self):
595 def tearDown(self):
596 os.chdir(self.oldpath)
596 os.chdir(self.oldpath)
597 shutil.rmtree(self.BASETESTDIR)
597 shutil.rmtree(self.BASETESTDIR)
598
598
599 @onlyif_unicode_paths
599 @onlyif_unicode_paths
600 def test_1(self):
600 def test_1(self):
601 """Test safe_execfile with non-ascii path
601 """Test safe_execfile with non-ascii path
602 """
602 """
603 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
603 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
604
604
605 class ExitCodeChecks(tt.TempFileMixin):
605 class ExitCodeChecks(tt.TempFileMixin):
606
606
607 def setUp(self):
607 def setUp(self):
608 self.system = ip.system_raw
608 self.system = ip.system_raw
609
609
610 def test_exit_code_ok(self):
610 def test_exit_code_ok(self):
611 self.system('exit 0')
611 self.system('exit 0')
612 self.assertEqual(ip.user_ns['_exit_code'], 0)
612 self.assertEqual(ip.user_ns['_exit_code'], 0)
613
613
614 def test_exit_code_error(self):
614 def test_exit_code_error(self):
615 self.system('exit 1')
615 self.system('exit 1')
616 self.assertEqual(ip.user_ns['_exit_code'], 1)
616 self.assertEqual(ip.user_ns['_exit_code'], 1)
617
617
618 @skipif(not hasattr(signal, 'SIGALRM'))
618 @skipif(not hasattr(signal, 'SIGALRM'))
619 def test_exit_code_signal(self):
619 def test_exit_code_signal(self):
620 self.mktmp("import signal, time\n"
620 self.mktmp("import signal, time\n"
621 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
621 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
622 "time.sleep(1)\n")
622 "time.sleep(1)\n")
623 self.system("%s %s" % (sys.executable, self.fname))
623 self.system("%s %s" % (sys.executable, self.fname))
624 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
624 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
625
625
626 @onlyif_cmds_exist("csh")
626 @onlyif_cmds_exist("csh")
627 def test_exit_code_signal_csh(self): # pragma: no cover
627 def test_exit_code_signal_csh(self): # pragma: no cover
628 SHELL = os.environ.get("SHELL", None)
628 SHELL = os.environ.get("SHELL", None)
629 os.environ["SHELL"] = find_cmd("csh")
629 os.environ["SHELL"] = find_cmd("csh")
630 try:
630 try:
631 self.test_exit_code_signal()
631 self.test_exit_code_signal()
632 finally:
632 finally:
633 if SHELL is not None:
633 if SHELL is not None:
634 os.environ['SHELL'] = SHELL
634 os.environ['SHELL'] = SHELL
635 else:
635 else:
636 del os.environ['SHELL']
636 del os.environ['SHELL']
637
637
638
638
639 class TestSystemRaw(ExitCodeChecks):
639 class TestSystemRaw(ExitCodeChecks):
640
640
641 def setUp(self):
641 def setUp(self):
642 super().setUp()
642 super().setUp()
643 self.system = ip.system_raw
643 self.system = ip.system_raw
644
644
645 @onlyif_unicode_paths
645 @onlyif_unicode_paths
646 def test_1(self):
646 def test_1(self):
647 """Test system_raw with non-ascii cmd
647 """Test system_raw with non-ascii cmd
648 """
648 """
649 cmd = u'''python -c "'åäö'" '''
649 cmd = u'''python -c "'åäö'" '''
650 ip.system_raw(cmd)
650 ip.system_raw(cmd)
651
651
652 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
652 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
653 @mock.patch('os.system', side_effect=KeyboardInterrupt)
653 @mock.patch('os.system', side_effect=KeyboardInterrupt)
654 def test_control_c(self, *mocks):
654 def test_control_c(self, *mocks):
655 try:
655 try:
656 self.system("sleep 1 # wont happen")
656 self.system("sleep 1 # wont happen")
657 except KeyboardInterrupt: # pragma: no cove
657 except KeyboardInterrupt: # pragma: no cove
658 self.fail(
658 self.fail(
659 "system call should intercept "
659 "system call should intercept "
660 "keyboard interrupt from subprocess.call"
660 "keyboard interrupt from subprocess.call"
661 )
661 )
662 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
662 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
663
663
664
664
665 @pytest.mark.parametrize("magic_cmd", ["pip", "conda", "cd"])
665 @pytest.mark.parametrize("magic_cmd", ["pip", "conda", "cd"])
666 def test_magic_warnings(magic_cmd):
666 def test_magic_warnings(magic_cmd):
667 if sys.platform == "win32":
667 if sys.platform == "win32":
668 to_mock = "os.system"
668 to_mock = "os.system"
669 expected_arg, expected_kwargs = magic_cmd, dict()
669 expected_arg, expected_kwargs = magic_cmd, dict()
670 else:
670 else:
671 to_mock = "subprocess.call"
671 to_mock = "subprocess.call"
672 expected_arg, expected_kwargs = magic_cmd, dict(
672 expected_arg, expected_kwargs = magic_cmd, dict(
673 shell=True, executable=os.environ.get("SHELL", None)
673 shell=True, executable=os.environ.get("SHELL", None)
674 )
674 )
675
675
676 with mock.patch(to_mock, return_value=0) as mock_sub:
676 with mock.patch(to_mock, return_value=0) as mock_sub:
677 with pytest.warns(Warning, match=r"You executed the system command"):
677 with pytest.warns(Warning, match=r"You executed the system command"):
678 ip.system_raw(magic_cmd)
678 ip.system_raw(magic_cmd)
679 mock_sub.assert_called_once_with(expected_arg, **expected_kwargs)
679 mock_sub.assert_called_once_with(expected_arg, **expected_kwargs)
680
680
681
681
682 # TODO: Exit codes are currently ignored on Windows.
682 # TODO: Exit codes are currently ignored on Windows.
683 class TestSystemPipedExitCode(ExitCodeChecks):
683 class TestSystemPipedExitCode(ExitCodeChecks):
684
684
685 def setUp(self):
685 def setUp(self):
686 super().setUp()
686 super().setUp()
687 self.system = ip.system_piped
687 self.system = ip.system_piped
688
688
689 @skip_win32
689 @skip_win32
690 def test_exit_code_ok(self):
690 def test_exit_code_ok(self):
691 ExitCodeChecks.test_exit_code_ok(self)
691 ExitCodeChecks.test_exit_code_ok(self)
692
692
693 @skip_win32
693 @skip_win32
694 def test_exit_code_error(self):
694 def test_exit_code_error(self):
695 ExitCodeChecks.test_exit_code_error(self)
695 ExitCodeChecks.test_exit_code_error(self)
696
696
697 @skip_win32
697 @skip_win32
698 def test_exit_code_signal(self):
698 def test_exit_code_signal(self):
699 ExitCodeChecks.test_exit_code_signal(self)
699 ExitCodeChecks.test_exit_code_signal(self)
700
700
701 class TestModules(tt.TempFileMixin):
701 class TestModules(tt.TempFileMixin):
702 def test_extraneous_loads(self):
702 def test_extraneous_loads(self):
703 """Test we're not loading modules on startup that we shouldn't.
703 """Test we're not loading modules on startup that we shouldn't.
704 """
704 """
705 self.mktmp("import sys\n"
705 self.mktmp("import sys\n"
706 "print('numpy' in sys.modules)\n"
706 "print('numpy' in sys.modules)\n"
707 "print('ipyparallel' in sys.modules)\n"
707 "print('ipyparallel' in sys.modules)\n"
708 "print('ipykernel' in sys.modules)\n"
708 "print('ipykernel' in sys.modules)\n"
709 )
709 )
710 out = "False\nFalse\nFalse\n"
710 out = "False\nFalse\nFalse\n"
711 tt.ipexec_validate(self.fname, out)
711 tt.ipexec_validate(self.fname, out)
712
712
713 class Negator(ast.NodeTransformer):
713 class Negator(ast.NodeTransformer):
714 """Negates all number literals in an AST."""
714 """Negates all number literals in an AST."""
715
715
716 # for python 3.7 and earlier
716 # for python 3.7 and earlier
717 def visit_Num(self, node):
717 def visit_Num(self, node):
718 node.n = -node.n
718 node.n = -node.n
719 return node
719 return node
720
720
721 # for python 3.8+
721 # for python 3.8+
722 def visit_Constant(self, node):
722 def visit_Constant(self, node):
723 if isinstance(node.value, int):
723 if isinstance(node.value, int):
724 return self.visit_Num(node)
724 return self.visit_Num(node)
725 return node
725 return node
726
726
727 class TestAstTransform(unittest.TestCase):
727 class TestAstTransform(unittest.TestCase):
728 def setUp(self):
728 def setUp(self):
729 self.negator = Negator()
729 self.negator = Negator()
730 ip.ast_transformers.append(self.negator)
730 ip.ast_transformers.append(self.negator)
731
731
732 def tearDown(self):
732 def tearDown(self):
733 ip.ast_transformers.remove(self.negator)
733 ip.ast_transformers.remove(self.negator)
734
734
735 def test_non_int_const(self):
735 def test_non_int_const(self):
736 with tt.AssertPrints("hello"):
736 with tt.AssertPrints("hello"):
737 ip.run_cell('print("hello")')
737 ip.run_cell('print("hello")')
738
738
739 def test_run_cell(self):
739 def test_run_cell(self):
740 with tt.AssertPrints("-34"):
740 with tt.AssertPrints("-34"):
741 ip.run_cell("print(12 + 22)")
741 ip.run_cell("print(12 + 22)")
742
742
743 # A named reference to a number shouldn't be transformed.
743 # A named reference to a number shouldn't be transformed.
744 ip.user_ns["n"] = 55
744 ip.user_ns["n"] = 55
745 with tt.AssertNotPrints("-55"):
745 with tt.AssertNotPrints("-55"):
746 ip.run_cell("print(n)")
746 ip.run_cell("print(n)")
747
747
748 def test_timeit(self):
748 def test_timeit(self):
749 called = set()
749 called = set()
750 def f(x):
750 def f(x):
751 called.add(x)
751 called.add(x)
752 ip.push({'f':f})
752 ip.push({'f':f})
753
753
754 with tt.AssertPrints("std. dev. of"):
754 with tt.AssertPrints("std. dev. of"):
755 ip.run_line_magic("timeit", "-n1 f(1)")
755 ip.run_line_magic("timeit", "-n1 f(1)")
756 self.assertEqual(called, {-1})
756 self.assertEqual(called, {-1})
757 called.clear()
757 called.clear()
758
758
759 with tt.AssertPrints("std. dev. of"):
759 with tt.AssertPrints("std. dev. of"):
760 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
760 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
761 self.assertEqual(called, {-2, -3})
761 self.assertEqual(called, {-2, -3})
762
762
763 def test_time(self):
763 def test_time(self):
764 called = []
764 called = []
765 def f(x):
765 def f(x):
766 called.append(x)
766 called.append(x)
767 ip.push({'f':f})
767 ip.push({'f':f})
768
768
769 # Test with an expression
769 # Test with an expression
770 with tt.AssertPrints("Wall time: "):
770 with tt.AssertPrints("Wall time: "):
771 ip.run_line_magic("time", "f(5+9)")
771 ip.run_line_magic("time", "f(5+9)")
772 self.assertEqual(called, [-14])
772 self.assertEqual(called, [-14])
773 called[:] = []
773 called[:] = []
774
774
775 # Test with a statement (different code path)
775 # Test with a statement (different code path)
776 with tt.AssertPrints("Wall time: "):
776 with tt.AssertPrints("Wall time: "):
777 ip.run_line_magic("time", "a = f(-3 + -2)")
777 ip.run_line_magic("time", "a = f(-3 + -2)")
778 self.assertEqual(called, [5])
778 self.assertEqual(called, [5])
779
779
780 def test_macro(self):
780 def test_macro(self):
781 ip.push({'a':10})
781 ip.push({'a':10})
782 # The AST transformation makes this do a+=-1
782 # The AST transformation makes this do a+=-1
783 ip.define_macro("amacro", "a+=1\nprint(a)")
783 ip.define_macro("amacro", "a+=1\nprint(a)")
784
784
785 with tt.AssertPrints("9"):
785 with tt.AssertPrints("9"):
786 ip.run_cell("amacro")
786 ip.run_cell("amacro")
787 with tt.AssertPrints("8"):
787 with tt.AssertPrints("8"):
788 ip.run_cell("amacro")
788 ip.run_cell("amacro")
789
789
790 class TestMiscTransform(unittest.TestCase):
790 class TestMiscTransform(unittest.TestCase):
791
791
792
792
793 def test_transform_only_once(self):
793 def test_transform_only_once(self):
794 cleanup = 0
794 cleanup = 0
795 line_t = 0
795 line_t = 0
796 def count_cleanup(lines):
796 def count_cleanup(lines):
797 nonlocal cleanup
797 nonlocal cleanup
798 cleanup += 1
798 cleanup += 1
799 return lines
799 return lines
800
800
801 def count_line_t(lines):
801 def count_line_t(lines):
802 nonlocal line_t
802 nonlocal line_t
803 line_t += 1
803 line_t += 1
804 return lines
804 return lines
805
805
806 ip.input_transformer_manager.cleanup_transforms.append(count_cleanup)
806 ip.input_transformer_manager.cleanup_transforms.append(count_cleanup)
807 ip.input_transformer_manager.line_transforms.append(count_line_t)
807 ip.input_transformer_manager.line_transforms.append(count_line_t)
808
808
809 ip.run_cell('1')
809 ip.run_cell('1')
810
810
811 assert cleanup == 1
811 assert cleanup == 1
812 assert line_t == 1
812 assert line_t == 1
813
813
814 class IntegerWrapper(ast.NodeTransformer):
814 class IntegerWrapper(ast.NodeTransformer):
815 """Wraps all integers in a call to Integer()"""
815 """Wraps all integers in a call to Integer()"""
816
816
817 # for Python 3.7 and earlier
817 # for Python 3.7 and earlier
818
818
819 # for Python 3.7 and earlier
819 # for Python 3.7 and earlier
820 def visit_Num(self, node):
820 def visit_Num(self, node):
821 if isinstance(node.n, int):
821 if isinstance(node.n, int):
822 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
822 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
823 args=[node], keywords=[])
823 args=[node], keywords=[])
824 return node
824 return node
825
825
826 # For Python 3.8+
826 # For Python 3.8+
827 def visit_Constant(self, node):
827 def visit_Constant(self, node):
828 if isinstance(node.value, int):
828 if isinstance(node.value, int):
829 return self.visit_Num(node)
829 return self.visit_Num(node)
830 return node
830 return node
831
831
832
832
833 class TestAstTransform2(unittest.TestCase):
833 class TestAstTransform2(unittest.TestCase):
834 def setUp(self):
834 def setUp(self):
835 self.intwrapper = IntegerWrapper()
835 self.intwrapper = IntegerWrapper()
836 ip.ast_transformers.append(self.intwrapper)
836 ip.ast_transformers.append(self.intwrapper)
837
837
838 self.calls = []
838 self.calls = []
839 def Integer(*args):
839 def Integer(*args):
840 self.calls.append(args)
840 self.calls.append(args)
841 return args
841 return args
842 ip.push({"Integer": Integer})
842 ip.push({"Integer": Integer})
843
843
844 def tearDown(self):
844 def tearDown(self):
845 ip.ast_transformers.remove(self.intwrapper)
845 ip.ast_transformers.remove(self.intwrapper)
846 del ip.user_ns['Integer']
846 del ip.user_ns['Integer']
847
847
848 def test_run_cell(self):
848 def test_run_cell(self):
849 ip.run_cell("n = 2")
849 ip.run_cell("n = 2")
850 self.assertEqual(self.calls, [(2,)])
850 self.assertEqual(self.calls, [(2,)])
851
851
852 # This shouldn't throw an error
852 # This shouldn't throw an error
853 ip.run_cell("o = 2.0")
853 ip.run_cell("o = 2.0")
854 self.assertEqual(ip.user_ns['o'], 2.0)
854 self.assertEqual(ip.user_ns['o'], 2.0)
855
855
856 def test_run_cell_non_int(self):
856 def test_run_cell_non_int(self):
857 ip.run_cell("n = 'a'")
857 ip.run_cell("n = 'a'")
858 assert self.calls == []
858 assert self.calls == []
859
859
860 def test_timeit(self):
860 def test_timeit(self):
861 called = set()
861 called = set()
862 def f(x):
862 def f(x):
863 called.add(x)
863 called.add(x)
864 ip.push({'f':f})
864 ip.push({'f':f})
865
865
866 with tt.AssertPrints("std. dev. of"):
866 with tt.AssertPrints("std. dev. of"):
867 ip.run_line_magic("timeit", "-n1 f(1)")
867 ip.run_line_magic("timeit", "-n1 f(1)")
868 self.assertEqual(called, {(1,)})
868 self.assertEqual(called, {(1,)})
869 called.clear()
869 called.clear()
870
870
871 with tt.AssertPrints("std. dev. of"):
871 with tt.AssertPrints("std. dev. of"):
872 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
872 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
873 self.assertEqual(called, {(2,), (3,)})
873 self.assertEqual(called, {(2,), (3,)})
874
874
875 class ErrorTransformer(ast.NodeTransformer):
875 class ErrorTransformer(ast.NodeTransformer):
876 """Throws an error when it sees a number."""
876 """Throws an error when it sees a number."""
877
877
878 def visit_Constant(self, node):
878 def visit_Constant(self, node):
879 if isinstance(node.value, int):
879 if isinstance(node.value, int):
880 raise ValueError("test")
880 raise ValueError("test")
881 return node
881 return node
882
882
883
883
884 class TestAstTransformError(unittest.TestCase):
884 class TestAstTransformError(unittest.TestCase):
885 def test_unregistering(self):
885 def test_unregistering(self):
886 err_transformer = ErrorTransformer()
886 err_transformer = ErrorTransformer()
887 ip.ast_transformers.append(err_transformer)
887 ip.ast_transformers.append(err_transformer)
888
888
889 with self.assertWarnsRegex(UserWarning, "It will be unregistered"):
889 with self.assertWarnsRegex(UserWarning, "It will be unregistered"):
890 ip.run_cell("1 + 2")
890 ip.run_cell("1 + 2")
891
891
892 # This should have been removed.
892 # This should have been removed.
893 self.assertNotIn(err_transformer, ip.ast_transformers)
893 self.assertNotIn(err_transformer, ip.ast_transformers)
894
894
895
895
896 class StringRejector(ast.NodeTransformer):
896 class StringRejector(ast.NodeTransformer):
897 """Throws an InputRejected when it sees a string literal.
897 """Throws an InputRejected when it sees a string literal.
898
898
899 Used to verify that NodeTransformers can signal that a piece of code should
899 Used to verify that NodeTransformers can signal that a piece of code should
900 not be executed by throwing an InputRejected.
900 not be executed by throwing an InputRejected.
901 """
901 """
902
902
903 # 3.8 only
903 # 3.8 only
904 def visit_Constant(self, node):
904 def visit_Constant(self, node):
905 if isinstance(node.value, str):
905 if isinstance(node.value, str):
906 raise InputRejected("test")
906 raise InputRejected("test")
907 return node
907 return node
908
908
909
909
910 class TestAstTransformInputRejection(unittest.TestCase):
910 class TestAstTransformInputRejection(unittest.TestCase):
911
911
912 def setUp(self):
912 def setUp(self):
913 self.transformer = StringRejector()
913 self.transformer = StringRejector()
914 ip.ast_transformers.append(self.transformer)
914 ip.ast_transformers.append(self.transformer)
915
915
916 def tearDown(self):
916 def tearDown(self):
917 ip.ast_transformers.remove(self.transformer)
917 ip.ast_transformers.remove(self.transformer)
918
918
919 def test_input_rejection(self):
919 def test_input_rejection(self):
920 """Check that NodeTransformers can reject input."""
920 """Check that NodeTransformers can reject input."""
921
921
922 expect_exception_tb = tt.AssertPrints("InputRejected: test")
922 expect_exception_tb = tt.AssertPrints("InputRejected: test")
923 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
923 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
924
924
925 # Run the same check twice to verify that the transformer is not
925 # Run the same check twice to verify that the transformer is not
926 # disabled after raising.
926 # disabled after raising.
927 with expect_exception_tb, expect_no_cell_output:
927 with expect_exception_tb, expect_no_cell_output:
928 ip.run_cell("'unsafe'")
928 ip.run_cell("'unsafe'")
929
929
930 with expect_exception_tb, expect_no_cell_output:
930 with expect_exception_tb, expect_no_cell_output:
931 res = ip.run_cell("'unsafe'")
931 res = ip.run_cell("'unsafe'")
932
932
933 self.assertIsInstance(res.error_before_exec, InputRejected)
933 self.assertIsInstance(res.error_before_exec, InputRejected)
934
934
935 def test__IPYTHON__():
935 def test__IPYTHON__():
936 # This shouldn't raise a NameError, that's all
936 # This shouldn't raise a NameError, that's all
937 __IPYTHON__
937 __IPYTHON__
938
938
939
939
940 class DummyRepr(object):
940 class DummyRepr(object):
941 def __repr__(self):
941 def __repr__(self):
942 return "DummyRepr"
942 return "DummyRepr"
943
943
944 def _repr_html_(self):
944 def _repr_html_(self):
945 return "<b>dummy</b>"
945 return "<b>dummy</b>"
946
946
947 def _repr_javascript_(self):
947 def _repr_javascript_(self):
948 return "console.log('hi');", {'key': 'value'}
948 return "console.log('hi');", {'key': 'value'}
949
949
950
950
951 def test_user_variables():
951 def test_user_variables():
952 # enable all formatters
952 # enable all formatters
953 ip.display_formatter.active_types = ip.display_formatter.format_types
953 ip.display_formatter.active_types = ip.display_formatter.format_types
954
954
955 ip.user_ns['dummy'] = d = DummyRepr()
955 ip.user_ns['dummy'] = d = DummyRepr()
956 keys = {'dummy', 'doesnotexist'}
956 keys = {'dummy', 'doesnotexist'}
957 r = ip.user_expressions({ key:key for key in keys})
957 r = ip.user_expressions({ key:key for key in keys})
958
958
959 assert keys == set(r.keys())
959 assert keys == set(r.keys())
960 dummy = r["dummy"]
960 dummy = r["dummy"]
961 assert {"status", "data", "metadata"} == set(dummy.keys())
961 assert {"status", "data", "metadata"} == set(dummy.keys())
962 assert dummy["status"] == "ok"
962 assert dummy["status"] == "ok"
963 data = dummy["data"]
963 data = dummy["data"]
964 metadata = dummy["metadata"]
964 metadata = dummy["metadata"]
965 assert data.get("text/html") == d._repr_html_()
965 assert data.get("text/html") == d._repr_html_()
966 js, jsmd = d._repr_javascript_()
966 js, jsmd = d._repr_javascript_()
967 assert data.get("application/javascript") == js
967 assert data.get("application/javascript") == js
968 assert metadata.get("application/javascript") == jsmd
968 assert metadata.get("application/javascript") == jsmd
969
969
970 dne = r["doesnotexist"]
970 dne = r["doesnotexist"]
971 assert dne["status"] == "error"
971 assert dne["status"] == "error"
972 assert dne["ename"] == "NameError"
972 assert dne["ename"] == "NameError"
973
973
974 # back to text only
974 # back to text only
975 ip.display_formatter.active_types = ['text/plain']
975 ip.display_formatter.active_types = ['text/plain']
976
976
977 def test_user_expression():
977 def test_user_expression():
978 # enable all formatters
978 # enable all formatters
979 ip.display_formatter.active_types = ip.display_formatter.format_types
979 ip.display_formatter.active_types = ip.display_formatter.format_types
980 query = {
980 query = {
981 'a' : '1 + 2',
981 'a' : '1 + 2',
982 'b' : '1/0',
982 'b' : '1/0',
983 }
983 }
984 r = ip.user_expressions(query)
984 r = ip.user_expressions(query)
985 import pprint
985 import pprint
986 pprint.pprint(r)
986 pprint.pprint(r)
987 assert set(r.keys()) == set(query.keys())
987 assert set(r.keys()) == set(query.keys())
988 a = r["a"]
988 a = r["a"]
989 assert {"status", "data", "metadata"} == set(a.keys())
989 assert {"status", "data", "metadata"} == set(a.keys())
990 assert a["status"] == "ok"
990 assert a["status"] == "ok"
991 data = a["data"]
991 data = a["data"]
992 metadata = a["metadata"]
992 metadata = a["metadata"]
993 assert data.get("text/plain") == "3"
993 assert data.get("text/plain") == "3"
994
994
995 b = r["b"]
995 b = r["b"]
996 assert b["status"] == "error"
996 assert b["status"] == "error"
997 assert b["ename"] == "ZeroDivisionError"
997 assert b["ename"] == "ZeroDivisionError"
998
998
999 # back to text only
999 # back to text only
1000 ip.display_formatter.active_types = ['text/plain']
1000 ip.display_formatter.active_types = ['text/plain']
1001
1001
1002
1002
1003 class TestSyntaxErrorTransformer(unittest.TestCase):
1003 class TestSyntaxErrorTransformer(unittest.TestCase):
1004 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
1004 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
1005
1005
1006 @staticmethod
1006 @staticmethod
1007 def transformer(lines):
1007 def transformer(lines):
1008 for line in lines:
1008 for line in lines:
1009 pos = line.find('syntaxerror')
1009 pos = line.find('syntaxerror')
1010 if pos >= 0:
1010 if pos >= 0:
1011 e = SyntaxError('input contains "syntaxerror"')
1011 e = SyntaxError('input contains "syntaxerror"')
1012 e.text = line
1012 e.text = line
1013 e.offset = pos + 1
1013 e.offset = pos + 1
1014 raise e
1014 raise e
1015 return lines
1015 return lines
1016
1016
1017 def setUp(self):
1017 def setUp(self):
1018 ip.input_transformers_post.append(self.transformer)
1018 ip.input_transformers_post.append(self.transformer)
1019
1019
1020 def tearDown(self):
1020 def tearDown(self):
1021 ip.input_transformers_post.remove(self.transformer)
1021 ip.input_transformers_post.remove(self.transformer)
1022
1022
1023 def test_syntaxerror_input_transformer(self):
1023 def test_syntaxerror_input_transformer(self):
1024 with tt.AssertPrints('1234'):
1024 with tt.AssertPrints('1234'):
1025 ip.run_cell('1234')
1025 ip.run_cell('1234')
1026 with tt.AssertPrints('SyntaxError: invalid syntax'):
1026 with tt.AssertPrints('SyntaxError: invalid syntax'):
1027 ip.run_cell('1 2 3') # plain python syntax error
1027 ip.run_cell('1 2 3') # plain python syntax error
1028 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
1028 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
1029 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
1029 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
1030 with tt.AssertPrints('3456'):
1030 with tt.AssertPrints('3456'):
1031 ip.run_cell('3456')
1031 ip.run_cell('3456')
1032
1032
1033
1033
1034 class TestWarningSuppression(unittest.TestCase):
1034 class TestWarningSuppression(unittest.TestCase):
1035 def test_warning_suppression(self):
1035 def test_warning_suppression(self):
1036 ip.run_cell("import warnings")
1036 ip.run_cell("import warnings")
1037 try:
1037 try:
1038 with self.assertWarnsRegex(UserWarning, "asdf"):
1038 with self.assertWarnsRegex(UserWarning, "asdf"):
1039 ip.run_cell("warnings.warn('asdf')")
1039 ip.run_cell("warnings.warn('asdf')")
1040 # Here's the real test -- if we run that again, we should get the
1040 # Here's the real test -- if we run that again, we should get the
1041 # warning again. Traditionally, each warning was only issued once per
1041 # warning again. Traditionally, each warning was only issued once per
1042 # IPython session (approximately), even if the user typed in new and
1042 # IPython session (approximately), even if the user typed in new and
1043 # different code that should have also triggered the warning, leading
1043 # different code that should have also triggered the warning, leading
1044 # to much confusion.
1044 # to much confusion.
1045 with self.assertWarnsRegex(UserWarning, "asdf"):
1045 with self.assertWarnsRegex(UserWarning, "asdf"):
1046 ip.run_cell("warnings.warn('asdf')")
1046 ip.run_cell("warnings.warn('asdf')")
1047 finally:
1047 finally:
1048 ip.run_cell("del warnings")
1048 ip.run_cell("del warnings")
1049
1049
1050
1050
1051 def test_deprecation_warning(self):
1051 def test_deprecation_warning(self):
1052 ip.run_cell("""
1052 ip.run_cell("""
1053 import warnings
1053 import warnings
1054 def wrn():
1054 def wrn():
1055 warnings.warn(
1055 warnings.warn(
1056 "I AM A WARNING",
1056 "I AM A WARNING",
1057 DeprecationWarning
1057 DeprecationWarning
1058 )
1058 )
1059 """)
1059 """)
1060 try:
1060 try:
1061 with self.assertWarnsRegex(DeprecationWarning, "I AM A WARNING"):
1061 with self.assertWarnsRegex(DeprecationWarning, "I AM A WARNING"):
1062 ip.run_cell("wrn()")
1062 ip.run_cell("wrn()")
1063 finally:
1063 finally:
1064 ip.run_cell("del warnings")
1064 ip.run_cell("del warnings")
1065 ip.run_cell("del wrn")
1065 ip.run_cell("del wrn")
1066
1066
1067
1067
1068 class TestImportNoDeprecate(tt.TempFileMixin):
1068 class TestImportNoDeprecate(tt.TempFileMixin):
1069
1069
1070 def setUp(self):
1070 def setUp(self):
1071 """Make a valid python temp file."""
1071 """Make a valid python temp file."""
1072 self.mktmp("""
1072 self.mktmp("""
1073 import warnings
1073 import warnings
1074 def wrn():
1074 def wrn():
1075 warnings.warn(
1075 warnings.warn(
1076 "I AM A WARNING",
1076 "I AM A WARNING",
1077 DeprecationWarning
1077 DeprecationWarning
1078 )
1078 )
1079 """)
1079 """)
1080 super().setUp()
1080 super().setUp()
1081
1081
1082 def test_no_dep(self):
1082 def test_no_dep(self):
1083 """
1083 """
1084 No deprecation warning should be raised from imported functions
1084 No deprecation warning should be raised from imported functions
1085 """
1085 """
1086 ip.run_cell("from {} import wrn".format(self.fname))
1086 ip.run_cell("from {} import wrn".format(self.fname))
1087
1087
1088 with tt.AssertNotPrints("I AM A WARNING"):
1088 with tt.AssertNotPrints("I AM A WARNING"):
1089 ip.run_cell("wrn()")
1089 ip.run_cell("wrn()")
1090 ip.run_cell("del wrn")
1090 ip.run_cell("del wrn")
1091
1091
1092
1092
1093 def test_custom_exc_count():
1093 def test_custom_exc_count():
1094 hook = mock.Mock(return_value=None)
1094 hook = mock.Mock(return_value=None)
1095 ip.set_custom_exc((SyntaxError,), hook)
1095 ip.set_custom_exc((SyntaxError,), hook)
1096 before = ip.execution_count
1096 before = ip.execution_count
1097 ip.run_cell("def foo()", store_history=True)
1097 ip.run_cell("def foo()", store_history=True)
1098 # restore default excepthook
1098 # restore default excepthook
1099 ip.set_custom_exc((), None)
1099 ip.set_custom_exc((), None)
1100 assert hook.call_count == 1
1100 assert hook.call_count == 1
1101 assert ip.execution_count == before + 1
1101 assert ip.execution_count == before + 1
1102
1102
1103
1103
1104 def test_run_cell_async():
1104 def test_run_cell_async():
1105 ip.run_cell("import asyncio")
1105 ip.run_cell("import asyncio")
1106 coro = ip.run_cell_async("await asyncio.sleep(0.01)\n5")
1106 coro = ip.run_cell_async("await asyncio.sleep(0.01)\n5")
1107 assert asyncio.iscoroutine(coro)
1107 assert asyncio.iscoroutine(coro)
1108 loop = asyncio.new_event_loop()
1108 loop = asyncio.new_event_loop()
1109 result = loop.run_until_complete(coro)
1109 result = loop.run_until_complete(coro)
1110 assert isinstance(result, interactiveshell.ExecutionResult)
1110 assert isinstance(result, interactiveshell.ExecutionResult)
1111 assert result.result == 5
1111 assert result.result == 5
1112
1112
1113
1113
1114 def test_run_cell_await():
1114 def test_run_cell_await():
1115 ip.run_cell("import asyncio")
1115 ip.run_cell("import asyncio")
1116 result = ip.run_cell("await asyncio.sleep(0.01); 10")
1116 result = ip.run_cell("await asyncio.sleep(0.01); 10")
1117 assert ip.user_ns["_"] == 10
1117 assert ip.user_ns["_"] == 10
1118
1118
1119
1119
1120 def test_run_cell_asyncio_run():
1120 def test_run_cell_asyncio_run():
1121 ip.run_cell("import asyncio")
1121 ip.run_cell("import asyncio")
1122 result = ip.run_cell("await asyncio.sleep(0.01); 1")
1122 result = ip.run_cell("await asyncio.sleep(0.01); 1")
1123 assert ip.user_ns["_"] == 1
1123 assert ip.user_ns["_"] == 1
1124 result = ip.run_cell("asyncio.run(asyncio.sleep(0.01)); 2")
1124 result = ip.run_cell("asyncio.run(asyncio.sleep(0.01)); 2")
1125 assert ip.user_ns["_"] == 2
1125 assert ip.user_ns["_"] == 2
1126 result = ip.run_cell("await asyncio.sleep(0.01); 3")
1126 result = ip.run_cell("await asyncio.sleep(0.01); 3")
1127 assert ip.user_ns["_"] == 3
1127 assert ip.user_ns["_"] == 3
1128
1128
1129
1129
1130 def test_should_run_async():
1130 def test_should_run_async():
1131 assert not ip.should_run_async("a = 5", transformed_cell="a = 5")
1131 assert not ip.should_run_async("a = 5", transformed_cell="a = 5")
1132 assert ip.should_run_async("await x", transformed_cell="await x")
1132 assert ip.should_run_async("await x", transformed_cell="await x")
1133 assert ip.should_run_async(
1133 assert ip.should_run_async(
1134 "import asyncio; await asyncio.sleep(1)",
1134 "import asyncio; await asyncio.sleep(1)",
1135 transformed_cell="import asyncio; await asyncio.sleep(1)",
1135 transformed_cell="import asyncio; await asyncio.sleep(1)",
1136 )
1136 )
1137
1137
1138
1138
1139 def test_set_custom_completer():
1139 def test_set_custom_completer():
1140 num_completers = len(ip.Completer.matchers)
1140 num_completers = len(ip.Completer.matchers)
1141
1141
1142 def foo(*args, **kwargs):
1142 def foo(*args, **kwargs):
1143 return "I'm a completer!"
1143 return "I'm a completer!"
1144
1144
1145 ip.set_custom_completer(foo, 0)
1145 ip.set_custom_completer(foo, 0)
1146
1146
1147 # check that we've really added a new completer
1147 # check that we've really added a new completer
1148 assert len(ip.Completer.matchers) == num_completers + 1
1148 assert len(ip.Completer.matchers) == num_completers + 1
1149
1149
1150 # check that the first completer is the function we defined
1150 # check that the first completer is the function we defined
1151 assert ip.Completer.matchers[0]() == "I'm a completer!"
1151 assert ip.Completer.matchers[0]() == "I'm a completer!"
1152
1152
1153 # clean up
1153 # clean up
1154 ip.Completer.custom_matchers.pop()
1154 ip.Completer.custom_matchers.pop()
1155
1155
1156
1156
1157 class TestShowTracebackAttack(unittest.TestCase):
1157 class TestShowTracebackAttack(unittest.TestCase):
1158 """Test that the interactive shell is resilient against the client attack of
1158 """Test that the interactive shell is resilient against the client attack of
1159 manipulating the showtracebacks method. These attacks shouldn't result in an
1159 manipulating the showtracebacks method. These attacks shouldn't result in an
1160 unhandled exception in the kernel."""
1160 unhandled exception in the kernel."""
1161
1161
1162 def setUp(self):
1162 def setUp(self):
1163 self.orig_showtraceback = interactiveshell.InteractiveShell.showtraceback
1163 self.orig_showtraceback = interactiveshell.InteractiveShell.showtraceback
1164
1164
1165 def tearDown(self):
1165 def tearDown(self):
1166 interactiveshell.InteractiveShell.showtraceback = self.orig_showtraceback
1166 interactiveshell.InteractiveShell.showtraceback = self.orig_showtraceback
1167
1167
1168 def test_set_show_tracebacks_none(self):
1168 def test_set_show_tracebacks_none(self):
1169 """Test the case of the client setting showtracebacks to None"""
1169 """Test the case of the client setting showtracebacks to None"""
1170
1170
1171 result = ip.run_cell(
1171 result = ip.run_cell(
1172 """
1172 """
1173 import IPython.core.interactiveshell
1173 import IPython.core.interactiveshell
1174 IPython.core.interactiveshell.InteractiveShell.showtraceback = None
1174 IPython.core.interactiveshell.InteractiveShell.showtraceback = None
1175
1175
1176 assert False, "This should not raise an exception"
1176 assert False, "This should not raise an exception"
1177 """
1177 """
1178 )
1178 )
1179 print(result)
1179 print(result)
1180
1180
1181 assert result.result is None
1181 assert result.result is None
1182 assert isinstance(result.error_in_exec, TypeError)
1182 assert isinstance(result.error_in_exec, TypeError)
1183 assert str(result.error_in_exec) == "'NoneType' object is not callable"
1183 assert str(result.error_in_exec) == "'NoneType' object is not callable"
1184
1184
1185 def test_set_show_tracebacks_noop(self):
1185 def test_set_show_tracebacks_noop(self):
1186 """Test the case of the client setting showtracebacks to a no op lambda"""
1186 """Test the case of the client setting showtracebacks to a no op lambda"""
1187
1187
1188 result = ip.run_cell(
1188 result = ip.run_cell(
1189 """
1189 """
1190 import IPython.core.interactiveshell
1190 import IPython.core.interactiveshell
1191 IPython.core.interactiveshell.InteractiveShell.showtraceback = lambda *args, **kwargs: None
1191 IPython.core.interactiveshell.InteractiveShell.showtraceback = lambda *args, **kwargs: None
1192
1192
1193 assert False, "This should not raise an exception"
1193 assert False, "This should not raise an exception"
1194 """
1194 """
1195 )
1195 )
1196 print(result)
1196 print(result)
1197
1197
1198 assert result.result is None
1198 assert result.result is None
1199 assert isinstance(result.error_in_exec, AssertionError)
1199 assert isinstance(result.error_in_exec, AssertionError)
1200 assert str(result.error_in_exec) == "This should not raise an exception"
1200 assert str(result.error_in_exec) == "This should not raise an exception"
@@ -1,1377 +1,1395 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Verbose and colourful traceback formatting.
3 Verbose and colourful traceback formatting.
4
4
5 **ColorTB**
5 **ColorTB**
6
6
7 I've always found it a bit hard to visually parse tracebacks in Python. The
7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 ColorTB class is a solution to that problem. It colors the different parts of a
8 ColorTB class is a solution to that problem. It colors the different parts of a
9 traceback in a manner similar to what you would expect from a syntax-highlighting
9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 text editor.
10 text editor.
11
11
12 Installation instructions for ColorTB::
12 Installation instructions for ColorTB::
13
13
14 import sys,ultratb
14 import sys,ultratb
15 sys.excepthook = ultratb.ColorTB()
15 sys.excepthook = ultratb.ColorTB()
16
16
17 **VerboseTB**
17 **VerboseTB**
18
18
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 and intended it for CGI programmers, but why should they have all the fun? I
21 and intended it for CGI programmers, but why should they have all the fun? I
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 but kind of neat, and maybe useful for long-running programs that you believe
23 but kind of neat, and maybe useful for long-running programs that you believe
24 are bug-free. If a crash *does* occur in that type of program you want details.
24 are bug-free. If a crash *does* occur in that type of program you want details.
25 Give it a shot--you'll love it or you'll hate it.
25 Give it a shot--you'll love it or you'll hate it.
26
26
27 .. note::
27 .. note::
28
28
29 The Verbose mode prints the variables currently visible where the exception
29 The Verbose mode prints the variables currently visible where the exception
30 happened (shortening their strings if too long). This can potentially be
30 happened (shortening their strings if too long). This can potentially be
31 very slow, if you happen to have a huge data structure whose string
31 very slow, if you happen to have a huge data structure whose string
32 representation is complex to compute. Your computer may appear to freeze for
32 representation is complex to compute. Your computer may appear to freeze for
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 with Ctrl-C (maybe hitting it more than once).
34 with Ctrl-C (maybe hitting it more than once).
35
35
36 If you encounter this kind of situation often, you may want to use the
36 If you encounter this kind of situation often, you may want to use the
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 variables (but otherwise includes the information and context given by
38 variables (but otherwise includes the information and context given by
39 Verbose).
39 Verbose).
40
40
41 .. note::
41 .. note::
42
42
43 The verbose mode print all variables in the stack, which means it can
43 The verbose mode print all variables in the stack, which means it can
44 potentially leak sensitive information like access keys, or unencrypted
44 potentially leak sensitive information like access keys, or unencrypted
45 password.
45 password.
46
46
47 Installation instructions for VerboseTB::
47 Installation instructions for VerboseTB::
48
48
49 import sys,ultratb
49 import sys,ultratb
50 sys.excepthook = ultratb.VerboseTB()
50 sys.excepthook = ultratb.VerboseTB()
51
51
52 Note: Much of the code in this module was lifted verbatim from the standard
52 Note: Much of the code in this module was lifted verbatim from the standard
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54
54
55 Color schemes
55 Color schemes
56 -------------
56 -------------
57
57
58 The colors are defined in the class TBTools through the use of the
58 The colors are defined in the class TBTools through the use of the
59 ColorSchemeTable class. Currently the following exist:
59 ColorSchemeTable class. Currently the following exist:
60
60
61 - NoColor: allows all of this module to be used in any terminal (the color
61 - NoColor: allows all of this module to be used in any terminal (the color
62 escapes are just dummy blank strings).
62 escapes are just dummy blank strings).
63
63
64 - Linux: is meant to look good in a terminal like the Linux console (black
64 - Linux: is meant to look good in a terminal like the Linux console (black
65 or very dark background).
65 or very dark background).
66
66
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 in light background terminals.
68 in light background terminals.
69
69
70 - Neutral: a neutral color scheme that should be readable on both light and
70 - Neutral: a neutral color scheme that should be readable on both light and
71 dark background
71 dark background
72
72
73 You can implement other color schemes easily, the syntax is fairly
73 You can implement other color schemes easily, the syntax is fairly
74 self-explanatory. Please send back new schemes you develop to the author for
74 self-explanatory. Please send back new schemes you develop to the author for
75 possible inclusion in future releases.
75 possible inclusion in future releases.
76
76
77 Inheritance diagram:
77 Inheritance diagram:
78
78
79 .. inheritance-diagram:: IPython.core.ultratb
79 .. inheritance-diagram:: IPython.core.ultratb
80 :parts: 3
80 :parts: 3
81 """
81 """
82
82
83 #*****************************************************************************
83 #*****************************************************************************
84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
86 #
86 #
87 # Distributed under the terms of the BSD License. The full license is in
87 # Distributed under the terms of the BSD License. The full license is in
88 # the file COPYING, distributed as part of this software.
88 # the file COPYING, distributed as part of this software.
89 #*****************************************************************************
89 #*****************************************************************************
90
90
91
91
92 import inspect
92 import inspect
93 import linecache
93 import linecache
94 import pydoc
94 import pydoc
95 import sys
95 import sys
96 import time
96 import time
97 import traceback
97 import traceback
98 from types import TracebackType
98 from types import TracebackType
99 from typing import Tuple, List, Any, Optional
99 from typing import Tuple, List, Any, Optional
100
100
101 import stack_data
101 import stack_data
102 from stack_data import FrameInfo as SDFrameInfo
102 from stack_data import FrameInfo as SDFrameInfo
103 from pygments.formatters.terminal256 import Terminal256Formatter
103 from pygments.formatters.terminal256 import Terminal256Formatter
104 from pygments.styles import get_style_by_name
104 from pygments.styles import get_style_by_name
105
105
106 # IPython's own modules
106 # IPython's own modules
107 from IPython import get_ipython
107 from IPython import get_ipython
108 from IPython.core import debugger
108 from IPython.core import debugger
109 from IPython.core.display_trap import DisplayTrap
109 from IPython.core.display_trap import DisplayTrap
110 from IPython.core.excolors import exception_colors
110 from IPython.core.excolors import exception_colors
111 from IPython.utils import PyColorize
111 from IPython.utils import PyColorize
112 from IPython.utils import path as util_path
112 from IPython.utils import path as util_path
113 from IPython.utils import py3compat
113 from IPython.utils import py3compat
114 from IPython.utils.terminal import get_terminal_size
114 from IPython.utils.terminal import get_terminal_size
115
115
116 import IPython.utils.colorable as colorable
116 import IPython.utils.colorable as colorable
117
117
118 # Globals
118 # Globals
119 # amount of space to put line numbers before verbose tracebacks
119 # amount of space to put line numbers before verbose tracebacks
120 INDENT_SIZE = 8
120 INDENT_SIZE = 8
121
121
122 # Default color scheme. This is used, for example, by the traceback
122 # Default color scheme. This is used, for example, by the traceback
123 # formatter. When running in an actual IPython instance, the user's rc.colors
123 # formatter. When running in an actual IPython instance, the user's rc.colors
124 # value is used, but having a module global makes this functionality available
124 # value is used, but having a module global makes this functionality available
125 # to users of ultratb who are NOT running inside ipython.
125 # to users of ultratb who are NOT running inside ipython.
126 DEFAULT_SCHEME = 'NoColor'
126 DEFAULT_SCHEME = 'NoColor'
127 FAST_THRESHOLD = 10_000
127 FAST_THRESHOLD = 10_000
128
128
129 # ---------------------------------------------------------------------------
129 # ---------------------------------------------------------------------------
130 # Code begins
130 # Code begins
131
131
132 # Helper function -- largely belongs to VerboseTB, but we need the same
132 # Helper function -- largely belongs to VerboseTB, but we need the same
133 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
133 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
134 # can be recognized properly by ipython.el's py-traceback-line-re
134 # can be recognized properly by ipython.el's py-traceback-line-re
135 # (SyntaxErrors have to be treated specially because they have no traceback)
135 # (SyntaxErrors have to be treated specially because they have no traceback)
136
136
137
137
138 def _format_traceback_lines(lines, Colors, has_colors: bool, lvals):
138 def _format_traceback_lines(lines, Colors, has_colors: bool, lvals):
139 """
139 """
140 Format tracebacks lines with pointing arrow, leading numbers...
140 Format tracebacks lines with pointing arrow, leading numbers...
141
141
142 Parameters
142 Parameters
143 ----------
143 ----------
144 lines : list[Line]
144 lines : list[Line]
145 Colors
145 Colors
146 ColorScheme used.
146 ColorScheme used.
147 lvals : str
147 lvals : str
148 Values of local variables, already colored, to inject just after the error line.
148 Values of local variables, already colored, to inject just after the error line.
149 """
149 """
150 numbers_width = INDENT_SIZE - 1
150 numbers_width = INDENT_SIZE - 1
151 res = []
151 res = []
152
152
153 for stack_line in lines:
153 for stack_line in lines:
154 if stack_line is stack_data.LINE_GAP:
154 if stack_line is stack_data.LINE_GAP:
155 res.append('%s (...)%s\n' % (Colors.linenoEm, Colors.Normal))
155 res.append('%s (...)%s\n' % (Colors.linenoEm, Colors.Normal))
156 continue
156 continue
157
157
158 line = stack_line.render(pygmented=has_colors).rstrip('\n') + '\n'
158 line = stack_line.render(pygmented=has_colors).rstrip('\n') + '\n'
159 lineno = stack_line.lineno
159 lineno = stack_line.lineno
160 if stack_line.is_current:
160 if stack_line.is_current:
161 # This is the line with the error
161 # This is the line with the error
162 pad = numbers_width - len(str(lineno))
162 pad = numbers_width - len(str(lineno))
163 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
163 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
164 start_color = Colors.linenoEm
164 start_color = Colors.linenoEm
165 else:
165 else:
166 num = '%*s' % (numbers_width, lineno)
166 num = '%*s' % (numbers_width, lineno)
167 start_color = Colors.lineno
167 start_color = Colors.lineno
168
168
169 line = '%s%s%s %s' % (start_color, num, Colors.Normal, line)
169 line = '%s%s%s %s' % (start_color, num, Colors.Normal, line)
170
170
171 res.append(line)
171 res.append(line)
172 if lvals and stack_line.is_current:
172 if lvals and stack_line.is_current:
173 res.append(lvals + '\n')
173 res.append(lvals + '\n')
174 return res
174 return res
175
175
176 def _simple_format_traceback_lines(lnum, index, lines, Colors, lvals, _line_format):
176 def _simple_format_traceback_lines(lnum, index, lines, Colors, lvals, _line_format):
177 """
177 """
178 Format tracebacks lines with pointing arrow, leading numbers...
178 Format tracebacks lines with pointing arrow, leading numbers...
179
179
180 Parameters
180 Parameters
181 ==========
181 ==========
182
182
183 lnum: int
183 lnum: int
184 number of the target line of code.
184 number of the target line of code.
185 index: int
185 index: int
186 which line in the list should be highlighted.
186 which line in the list should be highlighted.
187 lines: list[string]
187 lines: list[string]
188 Colors:
188 Colors:
189 ColorScheme used.
189 ColorScheme used.
190 lvals: bytes
190 lvals: bytes
191 Values of local variables, already colored, to inject just after the error line.
191 Values of local variables, already colored, to inject just after the error line.
192 _line_format: f (str) -> (str, bool)
192 _line_format: f (str) -> (str, bool)
193 return (colorized version of str, failure to do so)
193 return (colorized version of str, failure to do so)
194 """
194 """
195 numbers_width = INDENT_SIZE - 1
195 numbers_width = INDENT_SIZE - 1
196 res = []
196 res = []
197
197
198 for i, line in enumerate(lines, lnum - index):
198 for i, line in enumerate(lines, lnum - index):
199 line = py3compat.cast_unicode(line)
199 line = py3compat.cast_unicode(line)
200
200
201 new_line, err = _line_format(line, "str")
201 new_line, err = _line_format(line, "str")
202 if not err:
202 if not err:
203 line = new_line
203 line = new_line
204
204
205 if i == lnum:
205 if i == lnum:
206 # This is the line with the error
206 # This is the line with the error
207 pad = numbers_width - len(str(i))
207 pad = numbers_width - len(str(i))
208 num = "%s%s" % (debugger.make_arrow(pad), str(lnum))
208 num = "%s%s" % (debugger.make_arrow(pad), str(lnum))
209 line = "%s%s%s %s%s" % (
209 line = "%s%s%s %s%s" % (
210 Colors.linenoEm,
210 Colors.linenoEm,
211 num,
211 num,
212 Colors.line,
212 Colors.line,
213 line,
213 line,
214 Colors.Normal,
214 Colors.Normal,
215 )
215 )
216 else:
216 else:
217 num = "%*s" % (numbers_width, i)
217 num = "%*s" % (numbers_width, i)
218 line = "%s%s%s %s" % (Colors.lineno, num, Colors.Normal, line)
218 line = "%s%s%s %s" % (Colors.lineno, num, Colors.Normal, line)
219
219
220 res.append(line)
220 res.append(line)
221 if lvals and i == lnum:
221 if lvals and i == lnum:
222 res.append(lvals + "\n")
222 res.append(lvals + "\n")
223 return res
223 return res
224
224
225
225
226 def _format_filename(file, ColorFilename, ColorNormal, *, lineno=None):
226 def _format_filename(file, ColorFilename, ColorNormal, *, lineno=None):
227 """
227 """
228 Format filename lines with custom formatting from caching compiler or `File *.py` by default
228 Format filename lines with custom formatting from caching compiler or `File *.py` by default
229
229
230 Parameters
230 Parameters
231 ----------
231 ----------
232 file : str
232 file : str
233 ColorFilename
233 ColorFilename
234 ColorScheme's filename coloring to be used.
234 ColorScheme's filename coloring to be used.
235 ColorNormal
235 ColorNormal
236 ColorScheme's normal coloring to be used.
236 ColorScheme's normal coloring to be used.
237 """
237 """
238 ipinst = get_ipython()
238 ipinst = get_ipython()
239 if (
239 if (
240 ipinst is not None
240 ipinst is not None
241 and (data := ipinst.compile.format_code_name(file)) is not None
241 and (data := ipinst.compile.format_code_name(file)) is not None
242 ):
242 ):
243 label, name = data
243 label, name = data
244 if lineno is None:
244 if lineno is None:
245 tpl_link = f"{{label}} {ColorFilename}{{name}}{ColorNormal}"
245 tpl_link = f"{{label}} {ColorFilename}{{name}}{ColorNormal}"
246 else:
246 else:
247 tpl_link = (
247 tpl_link = (
248 f"{{label}} {ColorFilename}{{name}}, line {{lineno}}{ColorNormal}"
248 f"{{label}} {ColorFilename}{{name}}, line {{lineno}}{ColorNormal}"
249 )
249 )
250 else:
250 else:
251 label = "File"
251 label = "File"
252 name = util_path.compress_user(
252 name = util_path.compress_user(
253 py3compat.cast_unicode(file, util_path.fs_encoding)
253 py3compat.cast_unicode(file, util_path.fs_encoding)
254 )
254 )
255 if lineno is None:
255 if lineno is None:
256 tpl_link = f"{{label}} {ColorFilename}{{name}}{ColorNormal}"
256 tpl_link = f"{{label}} {ColorFilename}{{name}}{ColorNormal}"
257 else:
257 else:
258 # can we make this the more friendly ", line {{lineno}}", or do we need to preserve the formatting with the colon?
258 # can we make this the more friendly ", line {{lineno}}", or do we need to preserve the formatting with the colon?
259 tpl_link = f"{{label}} {ColorFilename}{{name}}:{{lineno}}{ColorNormal}"
259 tpl_link = f"{{label}} {ColorFilename}{{name}}:{{lineno}}{ColorNormal}"
260
260
261 return tpl_link.format(label=label, name=name, lineno=lineno)
261 return tpl_link.format(label=label, name=name, lineno=lineno)
262
262
263 #---------------------------------------------------------------------------
263 #---------------------------------------------------------------------------
264 # Module classes
264 # Module classes
265 class TBTools(colorable.Colorable):
265 class TBTools(colorable.Colorable):
266 """Basic tools used by all traceback printer classes."""
266 """Basic tools used by all traceback printer classes."""
267
267
268 # Number of frames to skip when reporting tracebacks
268 # Number of frames to skip when reporting tracebacks
269 tb_offset = 0
269 tb_offset = 0
270
270
271 def __init__(
271 def __init__(
272 self,
272 self,
273 color_scheme="NoColor",
273 color_scheme="NoColor",
274 call_pdb=False,
274 call_pdb=False,
275 ostream=None,
275 ostream=None,
276 parent=None,
276 parent=None,
277 config=None,
277 config=None,
278 *,
278 *,
279 debugger_cls=None,
279 debugger_cls=None,
280 ):
280 ):
281 # Whether to call the interactive pdb debugger after printing
281 # Whether to call the interactive pdb debugger after printing
282 # tracebacks or not
282 # tracebacks or not
283 super(TBTools, self).__init__(parent=parent, config=config)
283 super(TBTools, self).__init__(parent=parent, config=config)
284 self.call_pdb = call_pdb
284 self.call_pdb = call_pdb
285
285
286 # Output stream to write to. Note that we store the original value in
286 # Output stream to write to. Note that we store the original value in
287 # a private attribute and then make the public ostream a property, so
287 # a private attribute and then make the public ostream a property, so
288 # that we can delay accessing sys.stdout until runtime. The way
288 # that we can delay accessing sys.stdout until runtime. The way
289 # things are written now, the sys.stdout object is dynamically managed
289 # things are written now, the sys.stdout object is dynamically managed
290 # so a reference to it should NEVER be stored statically. This
290 # so a reference to it should NEVER be stored statically. This
291 # property approach confines this detail to a single location, and all
291 # property approach confines this detail to a single location, and all
292 # subclasses can simply access self.ostream for writing.
292 # subclasses can simply access self.ostream for writing.
293 self._ostream = ostream
293 self._ostream = ostream
294
294
295 # Create color table
295 # Create color table
296 self.color_scheme_table = exception_colors()
296 self.color_scheme_table = exception_colors()
297
297
298 self.set_colors(color_scheme)
298 self.set_colors(color_scheme)
299 self.old_scheme = color_scheme # save initial value for toggles
299 self.old_scheme = color_scheme # save initial value for toggles
300 self.debugger_cls = debugger_cls or debugger.Pdb
300 self.debugger_cls = debugger_cls or debugger.Pdb
301
301
302 if call_pdb:
302 if call_pdb:
303 self.pdb = self.debugger_cls()
303 self.pdb = self.debugger_cls()
304 else:
304 else:
305 self.pdb = None
305 self.pdb = None
306
306
307 def _get_ostream(self):
307 def _get_ostream(self):
308 """Output stream that exceptions are written to.
308 """Output stream that exceptions are written to.
309
309
310 Valid values are:
310 Valid values are:
311
311
312 - None: the default, which means that IPython will dynamically resolve
312 - None: the default, which means that IPython will dynamically resolve
313 to sys.stdout. This ensures compatibility with most tools, including
313 to sys.stdout. This ensures compatibility with most tools, including
314 Windows (where plain stdout doesn't recognize ANSI escapes).
314 Windows (where plain stdout doesn't recognize ANSI escapes).
315
315
316 - Any object with 'write' and 'flush' attributes.
316 - Any object with 'write' and 'flush' attributes.
317 """
317 """
318 return sys.stdout if self._ostream is None else self._ostream
318 return sys.stdout if self._ostream is None else self._ostream
319
319
320 def _set_ostream(self, val):
320 def _set_ostream(self, val):
321 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
321 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
322 self._ostream = val
322 self._ostream = val
323
323
324 ostream = property(_get_ostream, _set_ostream)
324 ostream = property(_get_ostream, _set_ostream)
325
325
326 @staticmethod
326 @staticmethod
327 def _get_chained_exception(exception_value):
327 def _get_chained_exception(exception_value):
328 cause = getattr(exception_value, "__cause__", None)
328 cause = getattr(exception_value, "__cause__", None)
329 if cause:
329 if cause:
330 return cause
330 return cause
331 if getattr(exception_value, "__suppress_context__", False):
331 if getattr(exception_value, "__suppress_context__", False):
332 return None
332 return None
333 return getattr(exception_value, "__context__", None)
333 return getattr(exception_value, "__context__", None)
334
334
335 def get_parts_of_chained_exception(
335 def get_parts_of_chained_exception(
336 self, evalue
336 self, evalue
337 ) -> Optional[Tuple[type, BaseException, TracebackType]]:
337 ) -> Optional[Tuple[type, BaseException, TracebackType]]:
338 chained_evalue = self._get_chained_exception(evalue)
338 chained_evalue = self._get_chained_exception(evalue)
339
339
340 if chained_evalue:
340 if chained_evalue:
341 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
341 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
342 return None
342 return None
343
343
344 def prepare_chained_exception_message(self, cause) -> List[Any]:
344 def prepare_chained_exception_message(self, cause) -> List[Any]:
345 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
345 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
346 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
346 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
347
347
348 if cause:
348 if cause:
349 message = [[direct_cause]]
349 message = [[direct_cause]]
350 else:
350 else:
351 message = [[exception_during_handling]]
351 message = [[exception_during_handling]]
352 return message
352 return message
353
353
354 @property
354 @property
355 def has_colors(self) -> bool:
355 def has_colors(self) -> bool:
356 return self.color_scheme_table.active_scheme_name.lower() != "nocolor"
356 return self.color_scheme_table.active_scheme_name.lower() != "nocolor"
357
357
358 def set_colors(self, *args, **kw):
358 def set_colors(self, *args, **kw):
359 """Shorthand access to the color table scheme selector method."""
359 """Shorthand access to the color table scheme selector method."""
360
360
361 # Set own color table
361 # Set own color table
362 self.color_scheme_table.set_active_scheme(*args, **kw)
362 self.color_scheme_table.set_active_scheme(*args, **kw)
363 # for convenience, set Colors to the active scheme
363 # for convenience, set Colors to the active scheme
364 self.Colors = self.color_scheme_table.active_colors
364 self.Colors = self.color_scheme_table.active_colors
365 # Also set colors of debugger
365 # Also set colors of debugger
366 if hasattr(self, 'pdb') and self.pdb is not None:
366 if hasattr(self, 'pdb') and self.pdb is not None:
367 self.pdb.set_colors(*args, **kw)
367 self.pdb.set_colors(*args, **kw)
368
368
369 def color_toggle(self):
369 def color_toggle(self):
370 """Toggle between the currently active color scheme and NoColor."""
370 """Toggle between the currently active color scheme and NoColor."""
371
371
372 if self.color_scheme_table.active_scheme_name == 'NoColor':
372 if self.color_scheme_table.active_scheme_name == 'NoColor':
373 self.color_scheme_table.set_active_scheme(self.old_scheme)
373 self.color_scheme_table.set_active_scheme(self.old_scheme)
374 self.Colors = self.color_scheme_table.active_colors
374 self.Colors = self.color_scheme_table.active_colors
375 else:
375 else:
376 self.old_scheme = self.color_scheme_table.active_scheme_name
376 self.old_scheme = self.color_scheme_table.active_scheme_name
377 self.color_scheme_table.set_active_scheme('NoColor')
377 self.color_scheme_table.set_active_scheme('NoColor')
378 self.Colors = self.color_scheme_table.active_colors
378 self.Colors = self.color_scheme_table.active_colors
379
379
380 def stb2text(self, stb):
380 def stb2text(self, stb):
381 """Convert a structured traceback (a list) to a string."""
381 """Convert a structured traceback (a list) to a string."""
382 return '\n'.join(stb)
382 return '\n'.join(stb)
383
383
384 def text(self, etype, value, tb, tb_offset: Optional[int] = None, context=5):
384 def text(self, etype, value, tb, tb_offset: Optional[int] = None, context=5):
385 """Return formatted traceback.
385 """Return formatted traceback.
386
386
387 Subclasses may override this if they add extra arguments.
387 Subclasses may override this if they add extra arguments.
388 """
388 """
389 tb_list = self.structured_traceback(etype, value, tb,
389 tb_list = self.structured_traceback(etype, value, tb,
390 tb_offset, context)
390 tb_offset, context)
391 return self.stb2text(tb_list)
391 return self.stb2text(tb_list)
392
392
393 def structured_traceback(
393 def structured_traceback(
394 self, etype, evalue, tb, tb_offset: Optional[int] = None, context=5, mode=None
394 self,
395 etype: type,
396 evalue: Optional[BaseException],
397 etb: Optional[TracebackType] = None,
398 tb_offset: Optional[int] = None,
399 context=5,
395 ):
400 ):
396 """Return a list of traceback frames.
401 """Return a list of traceback frames.
397
402
398 Must be implemented by each class.
403 Must be implemented by each class.
399 """
404 """
400 raise NotImplementedError()
405 raise NotImplementedError()
401
406
402
407
403 #---------------------------------------------------------------------------
408 #---------------------------------------------------------------------------
404 class ListTB(TBTools):
409 class ListTB(TBTools):
405 """Print traceback information from a traceback list, with optional color.
410 """Print traceback information from a traceback list, with optional color.
406
411
407 Calling requires 3 arguments: (etype, evalue, elist)
412 Calling requires 3 arguments: (etype, evalue, elist)
408 as would be obtained by::
413 as would be obtained by::
409
414
410 etype, evalue, tb = sys.exc_info()
415 etype, evalue, tb = sys.exc_info()
411 if tb:
416 if tb:
412 elist = traceback.extract_tb(tb)
417 elist = traceback.extract_tb(tb)
413 else:
418 else:
414 elist = None
419 elist = None
415
420
416 It can thus be used by programs which need to process the traceback before
421 It can thus be used by programs which need to process the traceback before
417 printing (such as console replacements based on the code module from the
422 printing (such as console replacements based on the code module from the
418 standard library).
423 standard library).
419
424
420 Because they are meant to be called without a full traceback (only a
425 Because they are meant to be called without a full traceback (only a
421 list), instances of this class can't call the interactive pdb debugger."""
426 list), instances of this class can't call the interactive pdb debugger."""
422
427
423
428
424 def __call__(self, etype, value, elist):
429 def __call__(self, etype, value, elist):
425 self.ostream.flush()
430 self.ostream.flush()
426 self.ostream.write(self.text(etype, value, elist))
431 self.ostream.write(self.text(etype, value, elist))
427 self.ostream.write('\n')
432 self.ostream.write('\n')
428
433
429 def _extract_tb(self, tb):
434 def _extract_tb(self, tb):
430 if tb:
435 if tb:
431 return traceback.extract_tb(tb)
436 return traceback.extract_tb(tb)
432 else:
437 else:
433 return None
438 return None
434
439
435 def structured_traceback(
440 def structured_traceback(
436 self,
441 self,
437 etype: type,
442 etype: type,
438 evalue: BaseException,
443 evalue: Optional[BaseException],
439 etb: Optional[TracebackType] = None,
444 etb: Optional[TracebackType] = None,
440 tb_offset: Optional[int] = None,
445 tb_offset: Optional[int] = None,
441 context=5,
446 context=5,
442 ):
447 ):
443 """Return a color formatted string with the traceback info.
448 """Return a color formatted string with the traceback info.
444
449
445 Parameters
450 Parameters
446 ----------
451 ----------
447 etype : exception type
452 etype : exception type
448 Type of the exception raised.
453 Type of the exception raised.
449 evalue : object
454 evalue : object
450 Data stored in the exception
455 Data stored in the exception
451 etb : list | TracebackType | None
456 etb : list | TracebackType | None
452 If list: List of frames, see class docstring for details.
457 If list: List of frames, see class docstring for details.
453 If Traceback: Traceback of the exception.
458 If Traceback: Traceback of the exception.
454 tb_offset : int, optional
459 tb_offset : int, optional
455 Number of frames in the traceback to skip. If not given, the
460 Number of frames in the traceback to skip. If not given, the
456 instance evalue is used (set in constructor).
461 instance evalue is used (set in constructor).
457 context : int, optional
462 context : int, optional
458 Number of lines of context information to print.
463 Number of lines of context information to print.
459
464
460 Returns
465 Returns
461 -------
466 -------
462 String with formatted exception.
467 String with formatted exception.
463 """
468 """
464 # This is a workaround to get chained_exc_ids in recursive calls
469 # This is a workaround to get chained_exc_ids in recursive calls
465 # etb should not be a tuple if structured_traceback is not recursive
470 # etb should not be a tuple if structured_traceback is not recursive
466 if isinstance(etb, tuple):
471 if isinstance(etb, tuple):
467 etb, chained_exc_ids = etb
472 etb, chained_exc_ids = etb
468 else:
473 else:
469 chained_exc_ids = set()
474 chained_exc_ids = set()
470
475
471 if isinstance(etb, list):
476 if isinstance(etb, list):
472 elist = etb
477 elist = etb
473 elif etb is not None:
478 elif etb is not None:
474 elist = self._extract_tb(etb)
479 elist = self._extract_tb(etb)
475 else:
480 else:
476 elist = []
481 elist = []
477 tb_offset = self.tb_offset if tb_offset is None else tb_offset
482 tb_offset = self.tb_offset if tb_offset is None else tb_offset
478 assert isinstance(tb_offset, int)
483 assert isinstance(tb_offset, int)
479 Colors = self.Colors
484 Colors = self.Colors
480 out_list = []
485 out_list = []
481 if elist:
486 if elist:
482
487
483 if tb_offset and len(elist) > tb_offset:
488 if tb_offset and len(elist) > tb_offset:
484 elist = elist[tb_offset:]
489 elist = elist[tb_offset:]
485
490
486 out_list.append('Traceback %s(most recent call last)%s:' %
491 out_list.append('Traceback %s(most recent call last)%s:' %
487 (Colors.normalEm, Colors.Normal) + '\n')
492 (Colors.normalEm, Colors.Normal) + '\n')
488 out_list.extend(self._format_list(elist))
493 out_list.extend(self._format_list(elist))
489 # The exception info should be a single entry in the list.
494 # The exception info should be a single entry in the list.
490 lines = ''.join(self._format_exception_only(etype, evalue))
495 lines = ''.join(self._format_exception_only(etype, evalue))
491 out_list.append(lines)
496 out_list.append(lines)
492
497
493 exception = self.get_parts_of_chained_exception(evalue)
498 exception = self.get_parts_of_chained_exception(evalue)
494
499
495 if exception and not id(exception[1]) in chained_exc_ids:
500 if exception and not id(exception[1]) in chained_exc_ids:
496 chained_exception_message = self.prepare_chained_exception_message(
501 chained_exception_message = (
497 evalue.__cause__)[0]
502 self.prepare_chained_exception_message(evalue.__cause__)[0]
503 if evalue is not None
504 else ""
505 )
498 etype, evalue, etb = exception
506 etype, evalue, etb = exception
499 # Trace exception to avoid infinite 'cause' loop
507 # Trace exception to avoid infinite 'cause' loop
500 chained_exc_ids.add(id(exception[1]))
508 chained_exc_ids.add(id(exception[1]))
501 chained_exceptions_tb_offset = 0
509 chained_exceptions_tb_offset = 0
502 out_list = (
510 out_list = (
503 self.structured_traceback(
511 self.structured_traceback(
504 etype, evalue, (etb, chained_exc_ids),
512 etype, evalue, (etb, chained_exc_ids),
505 chained_exceptions_tb_offset, context)
513 chained_exceptions_tb_offset, context)
506 + chained_exception_message
514 + chained_exception_message
507 + out_list)
515 + out_list)
508
516
509 return out_list
517 return out_list
510
518
511 def _format_list(self, extracted_list):
519 def _format_list(self, extracted_list):
512 """Format a list of traceback entry tuples for printing.
520 """Format a list of traceback entry tuples for printing.
513
521
514 Given a list of tuples as returned by extract_tb() or
522 Given a list of tuples as returned by extract_tb() or
515 extract_stack(), return a list of strings ready for printing.
523 extract_stack(), return a list of strings ready for printing.
516 Each string in the resulting list corresponds to the item with the
524 Each string in the resulting list corresponds to the item with the
517 same index in the argument list. Each string ends in a newline;
525 same index in the argument list. Each string ends in a newline;
518 the strings may contain internal newlines as well, for those items
526 the strings may contain internal newlines as well, for those items
519 whose source text line is not None.
527 whose source text line is not None.
520
528
521 Lifted almost verbatim from traceback.py
529 Lifted almost verbatim from traceback.py
522 """
530 """
523
531
524 Colors = self.Colors
532 Colors = self.Colors
525 list = []
533 list = []
526 for ind, (filename, lineno, name, line) in enumerate(extracted_list):
534 for ind, (filename, lineno, name, line) in enumerate(extracted_list):
527 normalCol, nameCol, fileCol, lineCol = (
535 normalCol, nameCol, fileCol, lineCol = (
528 # Emphasize the last entry
536 # Emphasize the last entry
529 (Colors.normalEm, Colors.nameEm, Colors.filenameEm, Colors.line)
537 (Colors.normalEm, Colors.nameEm, Colors.filenameEm, Colors.line)
530 if ind == len(extracted_list) - 1
538 if ind == len(extracted_list) - 1
531 else (Colors.Normal, Colors.name, Colors.filename, "")
539 else (Colors.Normal, Colors.name, Colors.filename, "")
532 )
540 )
533
541
534 fns = _format_filename(filename, fileCol, normalCol, lineno=lineno)
542 fns = _format_filename(filename, fileCol, normalCol, lineno=lineno)
535 item = f"{normalCol} {fns}"
543 item = f"{normalCol} {fns}"
536
544
537 if name != "<module>":
545 if name != "<module>":
538 item += f" in {nameCol}{name}{normalCol}\n"
546 item += f" in {nameCol}{name}{normalCol}\n"
539 else:
547 else:
540 item += "\n"
548 item += "\n"
541 if line:
549 if line:
542 item += f"{lineCol} {line.strip()}{normalCol}\n"
550 item += f"{lineCol} {line.strip()}{normalCol}\n"
543 list.append(item)
551 list.append(item)
544
552
545 return list
553 return list
546
554
547 def _format_exception_only(self, etype, value):
555 def _format_exception_only(self, etype, value):
548 """Format the exception part of a traceback.
556 """Format the exception part of a traceback.
549
557
550 The arguments are the exception type and value such as given by
558 The arguments are the exception type and value such as given by
551 sys.exc_info()[:2]. The return value is a list of strings, each ending
559 sys.exc_info()[:2]. The return value is a list of strings, each ending
552 in a newline. Normally, the list contains a single string; however,
560 in a newline. Normally, the list contains a single string; however,
553 for SyntaxError exceptions, it contains several lines that (when
561 for SyntaxError exceptions, it contains several lines that (when
554 printed) display detailed information about where the syntax error
562 printed) display detailed information about where the syntax error
555 occurred. The message indicating which exception occurred is the
563 occurred. The message indicating which exception occurred is the
556 always last string in the list.
564 always last string in the list.
557
565
558 Also lifted nearly verbatim from traceback.py
566 Also lifted nearly verbatim from traceback.py
559 """
567 """
560 have_filedata = False
568 have_filedata = False
561 Colors = self.Colors
569 Colors = self.Colors
562 list = []
570 list = []
563 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
571 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
564 if value is None:
572 if value is None:
565 # Not sure if this can still happen in Python 2.6 and above
573 # Not sure if this can still happen in Python 2.6 and above
566 list.append(stype + '\n')
574 list.append(stype + '\n')
567 else:
575 else:
568 if issubclass(etype, SyntaxError):
576 if issubclass(etype, SyntaxError):
569 have_filedata = True
577 have_filedata = True
570 if not value.filename: value.filename = "<string>"
578 if not value.filename: value.filename = "<string>"
571 if value.lineno:
579 if value.lineno:
572 lineno = value.lineno
580 lineno = value.lineno
573 textline = linecache.getline(value.filename, value.lineno)
581 textline = linecache.getline(value.filename, value.lineno)
574 else:
582 else:
575 lineno = "unknown"
583 lineno = "unknown"
576 textline = ""
584 textline = ""
577 list.append(
585 list.append(
578 "%s %s%s\n"
586 "%s %s%s\n"
579 % (
587 % (
580 Colors.normalEm,
588 Colors.normalEm,
581 _format_filename(
589 _format_filename(
582 value.filename,
590 value.filename,
583 Colors.filenameEm,
591 Colors.filenameEm,
584 Colors.normalEm,
592 Colors.normalEm,
585 lineno=(None if lineno == "unknown" else lineno),
593 lineno=(None if lineno == "unknown" else lineno),
586 ),
594 ),
587 Colors.Normal,
595 Colors.Normal,
588 )
596 )
589 )
597 )
590 if textline == "":
598 if textline == "":
591 textline = py3compat.cast_unicode(value.text, "utf-8")
599 textline = py3compat.cast_unicode(value.text, "utf-8")
592
600
593 if textline is not None:
601 if textline is not None:
594 i = 0
602 i = 0
595 while i < len(textline) and textline[i].isspace():
603 while i < len(textline) and textline[i].isspace():
596 i += 1
604 i += 1
597 list.append('%s %s%s\n' % (Colors.line,
605 list.append('%s %s%s\n' % (Colors.line,
598 textline.strip(),
606 textline.strip(),
599 Colors.Normal))
607 Colors.Normal))
600 if value.offset is not None:
608 if value.offset is not None:
601 s = ' '
609 s = ' '
602 for c in textline[i:value.offset - 1]:
610 for c in textline[i:value.offset - 1]:
603 if c.isspace():
611 if c.isspace():
604 s += c
612 s += c
605 else:
613 else:
606 s += ' '
614 s += ' '
607 list.append('%s%s^%s\n' % (Colors.caret, s,
615 list.append('%s%s^%s\n' % (Colors.caret, s,
608 Colors.Normal))
616 Colors.Normal))
609
617
610 try:
618 try:
611 s = value.msg
619 s = value.msg
612 except Exception:
620 except Exception:
613 s = self._some_str(value)
621 s = self._some_str(value)
614 if s:
622 if s:
615 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
623 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
616 Colors.Normal, s))
624 Colors.Normal, s))
617 else:
625 else:
618 list.append('%s\n' % stype)
626 list.append('%s\n' % stype)
619
627
620 # sync with user hooks
628 # sync with user hooks
621 if have_filedata:
629 if have_filedata:
622 ipinst = get_ipython()
630 ipinst = get_ipython()
623 if ipinst is not None:
631 if ipinst is not None:
624 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
632 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
625
633
626 return list
634 return list
627
635
628 def get_exception_only(self, etype, value):
636 def get_exception_only(self, etype, value):
629 """Only print the exception type and message, without a traceback.
637 """Only print the exception type and message, without a traceback.
630
638
631 Parameters
639 Parameters
632 ----------
640 ----------
633 etype : exception type
641 etype : exception type
634 value : exception value
642 value : exception value
635 """
643 """
636 return ListTB.structured_traceback(self, etype, value)
644 return ListTB.structured_traceback(self, etype, value)
637
645
638 def show_exception_only(self, etype, evalue):
646 def show_exception_only(self, etype, evalue):
639 """Only print the exception type and message, without a traceback.
647 """Only print the exception type and message, without a traceback.
640
648
641 Parameters
649 Parameters
642 ----------
650 ----------
643 etype : exception type
651 etype : exception type
644 evalue : exception value
652 evalue : exception value
645 """
653 """
646 # This method needs to use __call__ from *this* class, not the one from
654 # This method needs to use __call__ from *this* class, not the one from
647 # a subclass whose signature or behavior may be different
655 # a subclass whose signature or behavior may be different
648 ostream = self.ostream
656 ostream = self.ostream
649 ostream.flush()
657 ostream.flush()
650 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
658 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
651 ostream.flush()
659 ostream.flush()
652
660
653 def _some_str(self, value):
661 def _some_str(self, value):
654 # Lifted from traceback.py
662 # Lifted from traceback.py
655 try:
663 try:
656 return py3compat.cast_unicode(str(value))
664 return py3compat.cast_unicode(str(value))
657 except:
665 except:
658 return u'<unprintable %s object>' % type(value).__name__
666 return u'<unprintable %s object>' % type(value).__name__
659
667
660
668
661 class FrameInfo:
669 class FrameInfo:
662 """
670 """
663 Mirror of stack data's FrameInfo, but so that we can bypass highlighting on
671 Mirror of stack data's FrameInfo, but so that we can bypass highlighting on
664 really long frames.
672 really long frames.
665 """
673 """
666
674
667 description: Optional[str]
675 description: Optional[str]
668 filename: str
676 filename: str
669 lineno: int
677 lineno: int
670
678
671 @classmethod
679 @classmethod
672 def _from_stack_data_FrameInfo(cls, frame_info):
680 def _from_stack_data_FrameInfo(cls, frame_info):
673 return cls(
681 return cls(
674 getattr(frame_info, "description", None),
682 getattr(frame_info, "description", None),
675 getattr(frame_info, "filename", None),
683 getattr(frame_info, "filename", None),
676 getattr(frame_info, "lineno", None),
684 getattr(frame_info, "lineno", None),
677 getattr(frame_info, "frame", None),
685 getattr(frame_info, "frame", None),
678 getattr(frame_info, "code", None),
686 getattr(frame_info, "code", None),
679 sd=frame_info,
687 sd=frame_info,
680 )
688 )
681
689
682 def __init__(self, description, filename, lineno, frame, code, sd=None):
690 def __init__(self, description, filename, lineno, frame, code, sd=None):
683 self.description = description
691 self.description = description
684 self.filename = filename
692 self.filename = filename
685 self.lineno = lineno
693 self.lineno = lineno
686 self.frame = frame
694 self.frame = frame
687 self.code = code
695 self.code = code
688 self._sd = sd
696 self._sd = sd
689
697
690 # self.lines = []
698 # self.lines = []
691 if sd is None:
699 if sd is None:
692 ix = inspect.getsourcelines(frame)
700 ix = inspect.getsourcelines(frame)
693 self.raw_lines = ix[0]
701 self.raw_lines = ix[0]
694
702
695 @property
703 @property
696 def variables_in_executing_piece(self):
704 def variables_in_executing_piece(self):
697 if self._sd:
705 if self._sd:
698 return self._sd.variables_in_executing_piece
706 return self._sd.variables_in_executing_piece
699 else:
707 else:
700 return []
708 return []
701
709
702 @property
710 @property
703 def lines(self):
711 def lines(self):
704 return self._sd.lines
712 return self._sd.lines
705
713
706 @property
714 @property
707 def executing(self):
715 def executing(self):
708 if self._sd:
716 if self._sd:
709 return self._sd.executing
717 return self._sd.executing
710 else:
718 else:
711 return None
719 return None
712
720
713
721
714 # ----------------------------------------------------------------------------
722 # ----------------------------------------------------------------------------
715 class VerboseTB(TBTools):
723 class VerboseTB(TBTools):
716 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
724 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
717 of HTML. Requires inspect and pydoc. Crazy, man.
725 of HTML. Requires inspect and pydoc. Crazy, man.
718
726
719 Modified version which optionally strips the topmost entries from the
727 Modified version which optionally strips the topmost entries from the
720 traceback, to be used with alternate interpreters (because their own code
728 traceback, to be used with alternate interpreters (because their own code
721 would appear in the traceback)."""
729 would appear in the traceback)."""
722
730
723 _tb_highlight = "bg:ansiyellow"
731 _tb_highlight = "bg:ansiyellow"
724
732
725 def __init__(
733 def __init__(
726 self,
734 self,
727 color_scheme: str = "Linux",
735 color_scheme: str = "Linux",
728 call_pdb: bool = False,
736 call_pdb: bool = False,
729 ostream=None,
737 ostream=None,
730 tb_offset: int = 0,
738 tb_offset: int = 0,
731 long_header: bool = False,
739 long_header: bool = False,
732 include_vars: bool = True,
740 include_vars: bool = True,
733 check_cache=None,
741 check_cache=None,
734 debugger_cls=None,
742 debugger_cls=None,
735 parent=None,
743 parent=None,
736 config=None,
744 config=None,
737 ):
745 ):
738 """Specify traceback offset, headers and color scheme.
746 """Specify traceback offset, headers and color scheme.
739
747
740 Define how many frames to drop from the tracebacks. Calling it with
748 Define how many frames to drop from the tracebacks. Calling it with
741 tb_offset=1 allows use of this handler in interpreters which will have
749 tb_offset=1 allows use of this handler in interpreters which will have
742 their own code at the top of the traceback (VerboseTB will first
750 their own code at the top of the traceback (VerboseTB will first
743 remove that frame before printing the traceback info)."""
751 remove that frame before printing the traceback info)."""
744 TBTools.__init__(
752 TBTools.__init__(
745 self,
753 self,
746 color_scheme=color_scheme,
754 color_scheme=color_scheme,
747 call_pdb=call_pdb,
755 call_pdb=call_pdb,
748 ostream=ostream,
756 ostream=ostream,
749 parent=parent,
757 parent=parent,
750 config=config,
758 config=config,
751 debugger_cls=debugger_cls,
759 debugger_cls=debugger_cls,
752 )
760 )
753 self.tb_offset = tb_offset
761 self.tb_offset = tb_offset
754 self.long_header = long_header
762 self.long_header = long_header
755 self.include_vars = include_vars
763 self.include_vars = include_vars
756 # By default we use linecache.checkcache, but the user can provide a
764 # By default we use linecache.checkcache, but the user can provide a
757 # different check_cache implementation. This was formerly used by the
765 # different check_cache implementation. This was formerly used by the
758 # IPython kernel for interactive code, but is no longer necessary.
766 # IPython kernel for interactive code, but is no longer necessary.
759 if check_cache is None:
767 if check_cache is None:
760 check_cache = linecache.checkcache
768 check_cache = linecache.checkcache
761 self.check_cache = check_cache
769 self.check_cache = check_cache
762
770
763 self.skip_hidden = True
771 self.skip_hidden = True
764
772
765 def format_record(self, frame_info: FrameInfo):
773 def format_record(self, frame_info: FrameInfo):
766 """Format a single stack frame"""
774 """Format a single stack frame"""
767 assert isinstance(frame_info, FrameInfo)
775 assert isinstance(frame_info, FrameInfo)
768 Colors = self.Colors # just a shorthand + quicker name lookup
776 Colors = self.Colors # just a shorthand + quicker name lookup
769 ColorsNormal = Colors.Normal # used a lot
777 ColorsNormal = Colors.Normal # used a lot
770
778
771 if isinstance(frame_info._sd, stack_data.RepeatedFrames):
779 if isinstance(frame_info._sd, stack_data.RepeatedFrames):
772 return ' %s[... skipping similar frames: %s]%s\n' % (
780 return ' %s[... skipping similar frames: %s]%s\n' % (
773 Colors.excName, frame_info.description, ColorsNormal)
781 Colors.excName, frame_info.description, ColorsNormal)
774
782
775 indent = " " * INDENT_SIZE
783 indent = " " * INDENT_SIZE
776 em_normal = "%s\n%s%s" % (Colors.valEm, indent, ColorsNormal)
784 em_normal = "%s\n%s%s" % (Colors.valEm, indent, ColorsNormal)
777 tpl_call = f"in {Colors.vName}{{file}}{Colors.valEm}{{scope}}{ColorsNormal}"
785 tpl_call = f"in {Colors.vName}{{file}}{Colors.valEm}{{scope}}{ColorsNormal}"
778 tpl_call_fail = "in %s%%s%s(***failed resolving arguments***)%s" % (
786 tpl_call_fail = "in %s%%s%s(***failed resolving arguments***)%s" % (
779 Colors.vName,
787 Colors.vName,
780 Colors.valEm,
788 Colors.valEm,
781 ColorsNormal,
789 ColorsNormal,
782 )
790 )
783 tpl_name_val = "%%s %s= %%s%s" % (Colors.valEm, ColorsNormal)
791 tpl_name_val = "%%s %s= %%s%s" % (Colors.valEm, ColorsNormal)
784
792
785 link = _format_filename(
793 link = _format_filename(
786 frame_info.filename,
794 frame_info.filename,
787 Colors.filenameEm,
795 Colors.filenameEm,
788 ColorsNormal,
796 ColorsNormal,
789 lineno=frame_info.lineno,
797 lineno=frame_info.lineno,
790 )
798 )
791 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
799 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
792 if frame_info.executing is not None:
800 if frame_info.executing is not None:
793 func = frame_info.executing.code_qualname()
801 func = frame_info.executing.code_qualname()
794 else:
802 else:
795 func = "?"
803 func = "?"
796 if func == "<module>":
804 if func == "<module>":
797 call = ""
805 call = ""
798 else:
806 else:
799 # Decide whether to include variable details or not
807 # Decide whether to include variable details or not
800 var_repr = eqrepr if self.include_vars else nullrepr
808 var_repr = eqrepr if self.include_vars else nullrepr
801 try:
809 try:
802 scope = inspect.formatargvalues(
810 scope = inspect.formatargvalues(
803 args, varargs, varkw, locals_, formatvalue=var_repr
811 args, varargs, varkw, locals_, formatvalue=var_repr
804 )
812 )
805 call = tpl_call.format(file=func, scope=scope)
813 call = tpl_call.format(file=func, scope=scope)
806 except KeyError:
814 except KeyError:
807 # This happens in situations like errors inside generator
815 # This happens in situations like errors inside generator
808 # expressions, where local variables are listed in the
816 # expressions, where local variables are listed in the
809 # line, but can't be extracted from the frame. I'm not
817 # line, but can't be extracted from the frame. I'm not
810 # 100% sure this isn't actually a bug in inspect itself,
818 # 100% sure this isn't actually a bug in inspect itself,
811 # but since there's no info for us to compute with, the
819 # but since there's no info for us to compute with, the
812 # best we can do is report the failure and move on. Here
820 # best we can do is report the failure and move on. Here
813 # we must *not* call any traceback construction again,
821 # we must *not* call any traceback construction again,
814 # because that would mess up use of %debug later on. So we
822 # because that would mess up use of %debug later on. So we
815 # simply report the failure and move on. The only
823 # simply report the failure and move on. The only
816 # limitation will be that this frame won't have locals
824 # limitation will be that this frame won't have locals
817 # listed in the call signature. Quite subtle problem...
825 # listed in the call signature. Quite subtle problem...
818 # I can't think of a good way to validate this in a unit
826 # I can't think of a good way to validate this in a unit
819 # test, but running a script consisting of:
827 # test, but running a script consisting of:
820 # dict( (k,v.strip()) for (k,v) in range(10) )
828 # dict( (k,v.strip()) for (k,v) in range(10) )
821 # will illustrate the error, if this exception catch is
829 # will illustrate the error, if this exception catch is
822 # disabled.
830 # disabled.
823 call = tpl_call_fail % func
831 call = tpl_call_fail % func
824
832
825 lvals = ''
833 lvals = ''
826 lvals_list = []
834 lvals_list = []
827 if self.include_vars:
835 if self.include_vars:
828 try:
836 try:
829 # we likely want to fix stackdata at some point, but
837 # we likely want to fix stackdata at some point, but
830 # still need a workaround.
838 # still need a workaround.
831 fibp = frame_info.variables_in_executing_piece
839 fibp = frame_info.variables_in_executing_piece
832 for var in fibp:
840 for var in fibp:
833 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
841 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
834 except Exception:
842 except Exception:
835 lvals_list.append(
843 lvals_list.append(
836 "Exception trying to inspect frame. No more locals available."
844 "Exception trying to inspect frame. No more locals available."
837 )
845 )
838 if lvals_list:
846 if lvals_list:
839 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
847 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
840
848
841 result = f'{link}{", " if call else ""}{call}\n'
849 result = f'{link}{", " if call else ""}{call}\n'
842 if frame_info._sd is None:
850 if frame_info._sd is None:
843 assert False
851 assert False
844 # fast fallback if file is too long
852 # fast fallback if file is too long
845 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
853 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
846 link = tpl_link % util_path.compress_user(frame_info.filename)
854 link = tpl_link % util_path.compress_user(frame_info.filename)
847 level = "%s %s\n" % (link, call)
855 level = "%s %s\n" % (link, call)
848 _line_format = PyColorize.Parser(
856 _line_format = PyColorize.Parser(
849 style=self.color_scheme_table.active_scheme_name, parent=self
857 style=self.color_scheme_table.active_scheme_name, parent=self
850 ).format2
858 ).format2
851 first_line = frame_info.code.co_firstlineno
859 first_line = frame_info.code.co_firstlineno
852 current_line = frame_info.lineno[0]
860 current_line = frame_info.lineno[0]
853 return "%s%s" % (
861 return "%s%s" % (
854 level,
862 level,
855 "".join(
863 "".join(
856 _simple_format_traceback_lines(
864 _simple_format_traceback_lines(
857 current_line,
865 current_line,
858 current_line - first_line,
866 current_line - first_line,
859 frame_info.raw_lines,
867 frame_info.raw_lines,
860 Colors,
868 Colors,
861 lvals,
869 lvals,
862 _line_format,
870 _line_format,
863 )
871 )
864 ),
872 ),
865 )
873 )
866 # result += "\n".join(frame_info.raw_lines)
874 # result += "\n".join(frame_info.raw_lines)
867 else:
875 else:
868 result += "".join(
876 result += "".join(
869 _format_traceback_lines(
877 _format_traceback_lines(
870 frame_info.lines, Colors, self.has_colors, lvals
878 frame_info.lines, Colors, self.has_colors, lvals
871 )
879 )
872 )
880 )
873 return result
881 return result
874
882
875 def prepare_header(self, etype, long_version=False):
883 def prepare_header(self, etype: str, long_version: bool = False):
876 colors = self.Colors # just a shorthand + quicker name lookup
884 colors = self.Colors # just a shorthand + quicker name lookup
877 colorsnormal = colors.Normal # used a lot
885 colorsnormal = colors.Normal # used a lot
878 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
886 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
879 width = min(75, get_terminal_size()[0])
887 width = min(75, get_terminal_size()[0])
880 if long_version:
888 if long_version:
881 # Header with the exception type, python version, and date
889 # Header with the exception type, python version, and date
882 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
890 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
883 date = time.ctime(time.time())
891 date = time.ctime(time.time())
884
892
885 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
893 head = "%s%s%s\n%s%s%s\n%s" % (
886 exc, ' ' * (width - len(str(etype)) - len(pyver)),
894 colors.topline,
887 pyver, date.rjust(width) )
895 "-" * width,
888 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
896 colorsnormal,
889 "\ncalls leading up to the error, with the most recent (innermost) call last."
897 exc,
898 " " * (width - len(etype) - len(pyver)),
899 pyver,
900 date.rjust(width),
901 )
902 head += (
903 "\nA problem occurred executing Python code. Here is the sequence of function"
904 "\ncalls leading up to the error, with the most recent (innermost) call last."
905 )
890 else:
906 else:
891 # Simplified header
907 # Simplified header
892 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
908 head = "%s%s" % (
893 rjust(width - len(str(etype))) )
909 exc,
910 "Traceback (most recent call last)".rjust(width - len(etype)),
911 )
894
912
895 return head
913 return head
896
914
897 def format_exception(self, etype, evalue):
915 def format_exception(self, etype, evalue):
898 colors = self.Colors # just a shorthand + quicker name lookup
916 colors = self.Colors # just a shorthand + quicker name lookup
899 colorsnormal = colors.Normal # used a lot
917 colorsnormal = colors.Normal # used a lot
900 # Get (safely) a string form of the exception info
918 # Get (safely) a string form of the exception info
901 try:
919 try:
902 etype_str, evalue_str = map(str, (etype, evalue))
920 etype_str, evalue_str = map(str, (etype, evalue))
903 except:
921 except:
904 # User exception is improperly defined.
922 # User exception is improperly defined.
905 etype, evalue = str, sys.exc_info()[:2]
923 etype, evalue = str, sys.exc_info()[:2]
906 etype_str, evalue_str = map(str, (etype, evalue))
924 etype_str, evalue_str = map(str, (etype, evalue))
907 # ... and format it
925 # ... and format it
908 return ['%s%s%s: %s' % (colors.excName, etype_str,
926 return ['%s%s%s: %s' % (colors.excName, etype_str,
909 colorsnormal, py3compat.cast_unicode(evalue_str))]
927 colorsnormal, py3compat.cast_unicode(evalue_str))]
910
928
911 def format_exception_as_a_whole(
929 def format_exception_as_a_whole(
912 self,
930 self,
913 etype: type,
931 etype: type,
914 evalue: BaseException,
932 evalue: Optional[BaseException],
915 etb: Optional[TracebackType],
933 etb: Optional[TracebackType],
916 number_of_lines_of_context,
934 number_of_lines_of_context,
917 tb_offset: Optional[int],
935 tb_offset: Optional[int],
918 ):
936 ):
919 """Formats the header, traceback and exception message for a single exception.
937 """Formats the header, traceback and exception message for a single exception.
920
938
921 This may be called multiple times by Python 3 exception chaining
939 This may be called multiple times by Python 3 exception chaining
922 (PEP 3134).
940 (PEP 3134).
923 """
941 """
924 # some locals
942 # some locals
925 orig_etype = etype
943 orig_etype = etype
926 try:
944 try:
927 etype = etype.__name__
945 etype = etype.__name__
928 except AttributeError:
946 except AttributeError:
929 pass
947 pass
930
948
931 tb_offset = self.tb_offset if tb_offset is None else tb_offset
949 tb_offset = self.tb_offset if tb_offset is None else tb_offset
932 assert isinstance(tb_offset, int)
950 assert isinstance(tb_offset, int)
933 head = self.prepare_header(etype, self.long_header)
951 head = self.prepare_header(etype, self.long_header)
934 records = (
952 records = (
935 self.get_records(etb, number_of_lines_of_context, tb_offset) if etb else []
953 self.get_records(etb, number_of_lines_of_context, tb_offset) if etb else []
936 )
954 )
937
955
938 frames = []
956 frames = []
939 skipped = 0
957 skipped = 0
940 lastrecord = len(records) - 1
958 lastrecord = len(records) - 1
941 for i, record in enumerate(records):
959 for i, record in enumerate(records):
942 if (
960 if (
943 not isinstance(record._sd, stack_data.RepeatedFrames)
961 not isinstance(record._sd, stack_data.RepeatedFrames)
944 and self.skip_hidden
962 and self.skip_hidden
945 ):
963 ):
946 if (
964 if (
947 record.frame.f_locals.get("__tracebackhide__", 0)
965 record.frame.f_locals.get("__tracebackhide__", 0)
948 and i != lastrecord
966 and i != lastrecord
949 ):
967 ):
950 skipped += 1
968 skipped += 1
951 continue
969 continue
952 if skipped:
970 if skipped:
953 Colors = self.Colors # just a shorthand + quicker name lookup
971 Colors = self.Colors # just a shorthand + quicker name lookup
954 ColorsNormal = Colors.Normal # used a lot
972 ColorsNormal = Colors.Normal # used a lot
955 frames.append(
973 frames.append(
956 " %s[... skipping hidden %s frame]%s\n"
974 " %s[... skipping hidden %s frame]%s\n"
957 % (Colors.excName, skipped, ColorsNormal)
975 % (Colors.excName, skipped, ColorsNormal)
958 )
976 )
959 skipped = 0
977 skipped = 0
960 frames.append(self.format_record(record))
978 frames.append(self.format_record(record))
961 if skipped:
979 if skipped:
962 Colors = self.Colors # just a shorthand + quicker name lookup
980 Colors = self.Colors # just a shorthand + quicker name lookup
963 ColorsNormal = Colors.Normal # used a lot
981 ColorsNormal = Colors.Normal # used a lot
964 frames.append(
982 frames.append(
965 " %s[... skipping hidden %s frame]%s\n"
983 " %s[... skipping hidden %s frame]%s\n"
966 % (Colors.excName, skipped, ColorsNormal)
984 % (Colors.excName, skipped, ColorsNormal)
967 )
985 )
968
986
969 formatted_exception = self.format_exception(etype, evalue)
987 formatted_exception = self.format_exception(etype, evalue)
970 if records:
988 if records:
971 frame_info = records[-1]
989 frame_info = records[-1]
972 ipinst = get_ipython()
990 ipinst = get_ipython()
973 if ipinst is not None:
991 if ipinst is not None:
974 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
992 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
975
993
976 return [[head] + frames + [''.join(formatted_exception[0])]]
994 return [[head] + frames + [''.join(formatted_exception[0])]]
977
995
978 def get_records(
996 def get_records(
979 self, etb: TracebackType, number_of_lines_of_context: int, tb_offset: int
997 self, etb: TracebackType, number_of_lines_of_context: int, tb_offset: int
980 ):
998 ):
981 assert etb is not None
999 assert etb is not None
982 context = number_of_lines_of_context - 1
1000 context = number_of_lines_of_context - 1
983 after = context // 2
1001 after = context // 2
984 before = context - after
1002 before = context - after
985 if self.has_colors:
1003 if self.has_colors:
986 style = get_style_by_name("default")
1004 style = get_style_by_name("default")
987 style = stack_data.style_with_executing_node(style, self._tb_highlight)
1005 style = stack_data.style_with_executing_node(style, self._tb_highlight)
988 formatter = Terminal256Formatter(style=style)
1006 formatter = Terminal256Formatter(style=style)
989 else:
1007 else:
990 formatter = None
1008 formatter = None
991 options = stack_data.Options(
1009 options = stack_data.Options(
992 before=before,
1010 before=before,
993 after=after,
1011 after=after,
994 pygments_formatter=formatter,
1012 pygments_formatter=formatter,
995 )
1013 )
996
1014
997 # Let's estimate the amount of code we will have to parse/highlight.
1015 # Let's estimate the amount of code we will have to parse/highlight.
998 cf = etb
1016 cf: Optional[TracebackType] = etb
999 max_len = 0
1017 max_len = 0
1000 tbs = []
1018 tbs = []
1001 while cf is not None:
1019 while cf is not None:
1002 source_file = inspect.getsourcefile(etb.tb_frame)
1020 source_file = inspect.getsourcefile(etb.tb_frame)
1003 lines, first = inspect.getsourcelines(etb.tb_frame)
1021 lines, first = inspect.getsourcelines(etb.tb_frame)
1004 max_len = max(max_len, first + len(lines))
1022 max_len = max(max_len, first + len(lines))
1005 tbs.append(cf)
1023 tbs.append(cf)
1006 cf = cf.tb_next
1024 cf = cf.tb_next
1007
1025
1008 if max_len > FAST_THRESHOLD:
1026 if max_len > FAST_THRESHOLD:
1009 FIs = []
1027 FIs = []
1010 for tb in tbs:
1028 for tb in tbs:
1011 frame = tb.tb_frame
1029 frame = tb.tb_frame
1012 lineno = (frame.f_lineno,)
1030 lineno = (frame.f_lineno,)
1013 code = frame.f_code
1031 code = frame.f_code
1014 filename = code.co_filename
1032 filename = code.co_filename
1015 FIs.append(FrameInfo("Raw frame", filename, lineno, frame, code))
1033 FIs.append(FrameInfo("Raw frame", filename, lineno, frame, code))
1016 return FIs
1034 return FIs
1017 res = list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
1035 res = list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
1018 res = [FrameInfo._from_stack_data_FrameInfo(r) for r in res]
1036 res = [FrameInfo._from_stack_data_FrameInfo(r) for r in res]
1019 return res
1037 return res
1020
1038
1021 def structured_traceback(
1039 def structured_traceback(
1022 self,
1040 self,
1023 etype: type,
1041 etype: type,
1024 evalue: Optional[BaseException],
1042 evalue: Optional[BaseException],
1025 etb: Optional[TracebackType],
1043 etb: Optional[TracebackType],
1026 tb_offset: Optional[int] = None,
1044 tb_offset: Optional[int] = None,
1027 number_of_lines_of_context: int = 5,
1045 number_of_lines_of_context: int = 5,
1028 ):
1046 ):
1029 """Return a nice text document describing the traceback."""
1047 """Return a nice text document describing the traceback."""
1030 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1048 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1031 tb_offset)
1049 tb_offset)
1032
1050
1033 colors = self.Colors # just a shorthand + quicker name lookup
1051 colors = self.Colors # just a shorthand + quicker name lookup
1034 colorsnormal = colors.Normal # used a lot
1052 colorsnormal = colors.Normal # used a lot
1035 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1053 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1036 structured_traceback_parts = [head]
1054 structured_traceback_parts = [head]
1037 chained_exceptions_tb_offset = 0
1055 chained_exceptions_tb_offset = 0
1038 lines_of_context = 3
1056 lines_of_context = 3
1039 formatted_exceptions = formatted_exception
1057 formatted_exceptions = formatted_exception
1040 exception = self.get_parts_of_chained_exception(evalue)
1058 exception = self.get_parts_of_chained_exception(evalue)
1041 if exception:
1059 if exception:
1042 assert evalue is not None
1060 assert evalue is not None
1043 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1061 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1044 etype, evalue, etb = exception
1062 etype, evalue, etb = exception
1045 else:
1063 else:
1046 evalue = None
1064 evalue = None
1047 chained_exc_ids = set()
1065 chained_exc_ids = set()
1048 while evalue:
1066 while evalue:
1049 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1067 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1050 chained_exceptions_tb_offset)
1068 chained_exceptions_tb_offset)
1051 exception = self.get_parts_of_chained_exception(evalue)
1069 exception = self.get_parts_of_chained_exception(evalue)
1052
1070
1053 if exception and not id(exception[1]) in chained_exc_ids:
1071 if exception and not id(exception[1]) in chained_exc_ids:
1054 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1072 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1055 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1073 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1056 etype, evalue, etb = exception
1074 etype, evalue, etb = exception
1057 else:
1075 else:
1058 evalue = None
1076 evalue = None
1059
1077
1060 # we want to see exceptions in a reversed order:
1078 # we want to see exceptions in a reversed order:
1061 # the first exception should be on top
1079 # the first exception should be on top
1062 for formatted_exception in reversed(formatted_exceptions):
1080 for formatted_exception in reversed(formatted_exceptions):
1063 structured_traceback_parts += formatted_exception
1081 structured_traceback_parts += formatted_exception
1064
1082
1065 return structured_traceback_parts
1083 return structured_traceback_parts
1066
1084
1067 def debugger(self, force: bool = False):
1085 def debugger(self, force: bool = False):
1068 """Call up the pdb debugger if desired, always clean up the tb
1086 """Call up the pdb debugger if desired, always clean up the tb
1069 reference.
1087 reference.
1070
1088
1071 Keywords:
1089 Keywords:
1072
1090
1073 - force(False): by default, this routine checks the instance call_pdb
1091 - force(False): by default, this routine checks the instance call_pdb
1074 flag and does not actually invoke the debugger if the flag is false.
1092 flag and does not actually invoke the debugger if the flag is false.
1075 The 'force' option forces the debugger to activate even if the flag
1093 The 'force' option forces the debugger to activate even if the flag
1076 is false.
1094 is false.
1077
1095
1078 If the call_pdb flag is set, the pdb interactive debugger is
1096 If the call_pdb flag is set, the pdb interactive debugger is
1079 invoked. In all cases, the self.tb reference to the current traceback
1097 invoked. In all cases, the self.tb reference to the current traceback
1080 is deleted to prevent lingering references which hamper memory
1098 is deleted to prevent lingering references which hamper memory
1081 management.
1099 management.
1082
1100
1083 Note that each call to pdb() does an 'import readline', so if your app
1101 Note that each call to pdb() does an 'import readline', so if your app
1084 requires a special setup for the readline completers, you'll have to
1102 requires a special setup for the readline completers, you'll have to
1085 fix that by hand after invoking the exception handler."""
1103 fix that by hand after invoking the exception handler."""
1086
1104
1087 if force or self.call_pdb:
1105 if force or self.call_pdb:
1088 if self.pdb is None:
1106 if self.pdb is None:
1089 self.pdb = self.debugger_cls()
1107 self.pdb = self.debugger_cls()
1090 # the system displayhook may have changed, restore the original
1108 # the system displayhook may have changed, restore the original
1091 # for pdb
1109 # for pdb
1092 display_trap = DisplayTrap(hook=sys.__displayhook__)
1110 display_trap = DisplayTrap(hook=sys.__displayhook__)
1093 with display_trap:
1111 with display_trap:
1094 self.pdb.reset()
1112 self.pdb.reset()
1095 # Find the right frame so we don't pop up inside ipython itself
1113 # Find the right frame so we don't pop up inside ipython itself
1096 if hasattr(self, 'tb') and self.tb is not None:
1114 if hasattr(self, 'tb') and self.tb is not None:
1097 etb = self.tb
1115 etb = self.tb
1098 else:
1116 else:
1099 etb = self.tb = sys.last_traceback
1117 etb = self.tb = sys.last_traceback
1100 while self.tb is not None and self.tb.tb_next is not None:
1118 while self.tb is not None and self.tb.tb_next is not None:
1101 assert self.tb.tb_next is not None
1119 assert self.tb.tb_next is not None
1102 self.tb = self.tb.tb_next
1120 self.tb = self.tb.tb_next
1103 if etb and etb.tb_next:
1121 if etb and etb.tb_next:
1104 etb = etb.tb_next
1122 etb = etb.tb_next
1105 self.pdb.botframe = etb.tb_frame
1123 self.pdb.botframe = etb.tb_frame
1106 self.pdb.interaction(None, etb)
1124 self.pdb.interaction(None, etb)
1107
1125
1108 if hasattr(self, 'tb'):
1126 if hasattr(self, 'tb'):
1109 del self.tb
1127 del self.tb
1110
1128
1111 def handler(self, info=None):
1129 def handler(self, info=None):
1112 (etype, evalue, etb) = info or sys.exc_info()
1130 (etype, evalue, etb) = info or sys.exc_info()
1113 self.tb = etb
1131 self.tb = etb
1114 ostream = self.ostream
1132 ostream = self.ostream
1115 ostream.flush()
1133 ostream.flush()
1116 ostream.write(self.text(etype, evalue, etb))
1134 ostream.write(self.text(etype, evalue, etb))
1117 ostream.write('\n')
1135 ostream.write('\n')
1118 ostream.flush()
1136 ostream.flush()
1119
1137
1120 # Changed so an instance can just be called as VerboseTB_inst() and print
1138 # Changed so an instance can just be called as VerboseTB_inst() and print
1121 # out the right info on its own.
1139 # out the right info on its own.
1122 def __call__(self, etype=None, evalue=None, etb=None):
1140 def __call__(self, etype=None, evalue=None, etb=None):
1123 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1141 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1124 if etb is None:
1142 if etb is None:
1125 self.handler()
1143 self.handler()
1126 else:
1144 else:
1127 self.handler((etype, evalue, etb))
1145 self.handler((etype, evalue, etb))
1128 try:
1146 try:
1129 self.debugger()
1147 self.debugger()
1130 except KeyboardInterrupt:
1148 except KeyboardInterrupt:
1131 print("\nKeyboardInterrupt")
1149 print("\nKeyboardInterrupt")
1132
1150
1133
1151
1134 #----------------------------------------------------------------------------
1152 #----------------------------------------------------------------------------
1135 class FormattedTB(VerboseTB, ListTB):
1153 class FormattedTB(VerboseTB, ListTB):
1136 """Subclass ListTB but allow calling with a traceback.
1154 """Subclass ListTB but allow calling with a traceback.
1137
1155
1138 It can thus be used as a sys.excepthook for Python > 2.1.
1156 It can thus be used as a sys.excepthook for Python > 2.1.
1139
1157
1140 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1158 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1141
1159
1142 Allows a tb_offset to be specified. This is useful for situations where
1160 Allows a tb_offset to be specified. This is useful for situations where
1143 one needs to remove a number of topmost frames from the traceback (such as
1161 one needs to remove a number of topmost frames from the traceback (such as
1144 occurs with python programs that themselves execute other python code,
1162 occurs with python programs that themselves execute other python code,
1145 like Python shells). """
1163 like Python shells). """
1146
1164
1147 mode: str
1165 mode: str
1148
1166
1149 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1167 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1150 ostream=None,
1168 ostream=None,
1151 tb_offset=0, long_header=False, include_vars=False,
1169 tb_offset=0, long_header=False, include_vars=False,
1152 check_cache=None, debugger_cls=None,
1170 check_cache=None, debugger_cls=None,
1153 parent=None, config=None):
1171 parent=None, config=None):
1154
1172
1155 # NEVER change the order of this list. Put new modes at the end:
1173 # NEVER change the order of this list. Put new modes at the end:
1156 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
1174 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
1157 self.verbose_modes = self.valid_modes[1:3]
1175 self.verbose_modes = self.valid_modes[1:3]
1158
1176
1159 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1177 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1160 ostream=ostream, tb_offset=tb_offset,
1178 ostream=ostream, tb_offset=tb_offset,
1161 long_header=long_header, include_vars=include_vars,
1179 long_header=long_header, include_vars=include_vars,
1162 check_cache=check_cache, debugger_cls=debugger_cls,
1180 check_cache=check_cache, debugger_cls=debugger_cls,
1163 parent=parent, config=config)
1181 parent=parent, config=config)
1164
1182
1165 # Different types of tracebacks are joined with different separators to
1183 # Different types of tracebacks are joined with different separators to
1166 # form a single string. They are taken from this dict
1184 # form a single string. They are taken from this dict
1167 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
1185 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
1168 Minimal='')
1186 Minimal='')
1169 # set_mode also sets the tb_join_char attribute
1187 # set_mode also sets the tb_join_char attribute
1170 self.set_mode(mode)
1188 self.set_mode(mode)
1171
1189
1172 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1190 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1173 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1191 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1174 mode = self.mode
1192 mode = self.mode
1175 if mode in self.verbose_modes:
1193 if mode in self.verbose_modes:
1176 # Verbose modes need a full traceback
1194 # Verbose modes need a full traceback
1177 return VerboseTB.structured_traceback(
1195 return VerboseTB.structured_traceback(
1178 self, etype, value, tb, tb_offset, number_of_lines_of_context
1196 self, etype, value, tb, tb_offset, number_of_lines_of_context
1179 )
1197 )
1180 elif mode == 'Minimal':
1198 elif mode == 'Minimal':
1181 return ListTB.get_exception_only(self, etype, value)
1199 return ListTB.get_exception_only(self, etype, value)
1182 else:
1200 else:
1183 # We must check the source cache because otherwise we can print
1201 # We must check the source cache because otherwise we can print
1184 # out-of-date source code.
1202 # out-of-date source code.
1185 self.check_cache()
1203 self.check_cache()
1186 # Now we can extract and format the exception
1204 # Now we can extract and format the exception
1187 return ListTB.structured_traceback(
1205 return ListTB.structured_traceback(
1188 self, etype, value, tb, tb_offset, number_of_lines_of_context
1206 self, etype, value, tb, tb_offset, number_of_lines_of_context
1189 )
1207 )
1190
1208
1191 def stb2text(self, stb):
1209 def stb2text(self, stb):
1192 """Convert a structured traceback (a list) to a string."""
1210 """Convert a structured traceback (a list) to a string."""
1193 return self.tb_join_char.join(stb)
1211 return self.tb_join_char.join(stb)
1194
1212
1195 def set_mode(self, mode: Optional[str] = None):
1213 def set_mode(self, mode: Optional[str] = None):
1196 """Switch to the desired mode.
1214 """Switch to the desired mode.
1197
1215
1198 If mode is not specified, cycles through the available modes."""
1216 If mode is not specified, cycles through the available modes."""
1199
1217
1200 if not mode:
1218 if not mode:
1201 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1219 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1202 len(self.valid_modes)
1220 len(self.valid_modes)
1203 self.mode = self.valid_modes[new_idx]
1221 self.mode = self.valid_modes[new_idx]
1204 elif mode not in self.valid_modes:
1222 elif mode not in self.valid_modes:
1205 raise ValueError(
1223 raise ValueError(
1206 "Unrecognized mode in FormattedTB: <" + mode + ">\n"
1224 "Unrecognized mode in FormattedTB: <" + mode + ">\n"
1207 "Valid modes: " + str(self.valid_modes)
1225 "Valid modes: " + str(self.valid_modes)
1208 )
1226 )
1209 else:
1227 else:
1210 assert isinstance(mode, str)
1228 assert isinstance(mode, str)
1211 self.mode = mode
1229 self.mode = mode
1212 # include variable details only in 'Verbose' mode
1230 # include variable details only in 'Verbose' mode
1213 self.include_vars = (self.mode == self.valid_modes[2])
1231 self.include_vars = (self.mode == self.valid_modes[2])
1214 # Set the join character for generating text tracebacks
1232 # Set the join character for generating text tracebacks
1215 self.tb_join_char = self._join_chars[self.mode]
1233 self.tb_join_char = self._join_chars[self.mode]
1216
1234
1217 # some convenient shortcuts
1235 # some convenient shortcuts
1218 def plain(self):
1236 def plain(self):
1219 self.set_mode(self.valid_modes[0])
1237 self.set_mode(self.valid_modes[0])
1220
1238
1221 def context(self):
1239 def context(self):
1222 self.set_mode(self.valid_modes[1])
1240 self.set_mode(self.valid_modes[1])
1223
1241
1224 def verbose(self):
1242 def verbose(self):
1225 self.set_mode(self.valid_modes[2])
1243 self.set_mode(self.valid_modes[2])
1226
1244
1227 def minimal(self):
1245 def minimal(self):
1228 self.set_mode(self.valid_modes[3])
1246 self.set_mode(self.valid_modes[3])
1229
1247
1230
1248
1231 #----------------------------------------------------------------------------
1249 #----------------------------------------------------------------------------
1232 class AutoFormattedTB(FormattedTB):
1250 class AutoFormattedTB(FormattedTB):
1233 """A traceback printer which can be called on the fly.
1251 """A traceback printer which can be called on the fly.
1234
1252
1235 It will find out about exceptions by itself.
1253 It will find out about exceptions by itself.
1236
1254
1237 A brief example::
1255 A brief example::
1238
1256
1239 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1257 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1240 try:
1258 try:
1241 ...
1259 ...
1242 except:
1260 except:
1243 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1261 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1244 """
1262 """
1245
1263
1246 def __call__(self, etype=None, evalue=None, etb=None,
1264 def __call__(self, etype=None, evalue=None, etb=None,
1247 out=None, tb_offset=None):
1265 out=None, tb_offset=None):
1248 """Print out a formatted exception traceback.
1266 """Print out a formatted exception traceback.
1249
1267
1250 Optional arguments:
1268 Optional arguments:
1251 - out: an open file-like object to direct output to.
1269 - out: an open file-like object to direct output to.
1252
1270
1253 - tb_offset: the number of frames to skip over in the stack, on a
1271 - tb_offset: the number of frames to skip over in the stack, on a
1254 per-call basis (this overrides temporarily the instance's tb_offset
1272 per-call basis (this overrides temporarily the instance's tb_offset
1255 given at initialization time."""
1273 given at initialization time."""
1256
1274
1257 if out is None:
1275 if out is None:
1258 out = self.ostream
1276 out = self.ostream
1259 out.flush()
1277 out.flush()
1260 out.write(self.text(etype, evalue, etb, tb_offset))
1278 out.write(self.text(etype, evalue, etb, tb_offset))
1261 out.write('\n')
1279 out.write('\n')
1262 out.flush()
1280 out.flush()
1263 # FIXME: we should remove the auto pdb behavior from here and leave
1281 # FIXME: we should remove the auto pdb behavior from here and leave
1264 # that to the clients.
1282 # that to the clients.
1265 try:
1283 try:
1266 self.debugger()
1284 self.debugger()
1267 except KeyboardInterrupt:
1285 except KeyboardInterrupt:
1268 print("\nKeyboardInterrupt")
1286 print("\nKeyboardInterrupt")
1269
1287
1270 def structured_traceback(
1288 def structured_traceback(
1271 self,
1289 self,
1272 etype=None,
1290 etype=None,
1273 value=None,
1291 value=None,
1274 tb=None,
1292 tb=None,
1275 tb_offset=None,
1293 tb_offset=None,
1276 number_of_lines_of_context=5,
1294 number_of_lines_of_context=5,
1277 ):
1295 ):
1278 etype: type
1296 etype: type
1279 value: BaseException
1297 value: BaseException
1280 # tb: TracebackType or tupleof tb types ?
1298 # tb: TracebackType or tupleof tb types ?
1281 if etype is None:
1299 if etype is None:
1282 etype, value, tb = sys.exc_info()
1300 etype, value, tb = sys.exc_info()
1283 if isinstance(tb, tuple):
1301 if isinstance(tb, tuple):
1284 # tb is a tuple if this is a chained exception.
1302 # tb is a tuple if this is a chained exception.
1285 self.tb = tb[0]
1303 self.tb = tb[0]
1286 else:
1304 else:
1287 self.tb = tb
1305 self.tb = tb
1288 return FormattedTB.structured_traceback(
1306 return FormattedTB.structured_traceback(
1289 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1307 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1290
1308
1291
1309
1292 #---------------------------------------------------------------------------
1310 #---------------------------------------------------------------------------
1293
1311
1294 # A simple class to preserve Nathan's original functionality.
1312 # A simple class to preserve Nathan's original functionality.
1295 class ColorTB(FormattedTB):
1313 class ColorTB(FormattedTB):
1296 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1314 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1297
1315
1298 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1316 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1299 FormattedTB.__init__(self, color_scheme=color_scheme,
1317 FormattedTB.__init__(self, color_scheme=color_scheme,
1300 call_pdb=call_pdb, **kwargs)
1318 call_pdb=call_pdb, **kwargs)
1301
1319
1302
1320
1303 class SyntaxTB(ListTB):
1321 class SyntaxTB(ListTB):
1304 """Extension which holds some state: the last exception value"""
1322 """Extension which holds some state: the last exception value"""
1305
1323
1306 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1324 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1307 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1325 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1308 self.last_syntax_error = None
1326 self.last_syntax_error = None
1309
1327
1310 def __call__(self, etype, value, elist):
1328 def __call__(self, etype, value, elist):
1311 self.last_syntax_error = value
1329 self.last_syntax_error = value
1312
1330
1313 ListTB.__call__(self, etype, value, elist)
1331 ListTB.__call__(self, etype, value, elist)
1314
1332
1315 def structured_traceback(self, etype, value, elist, tb_offset=None,
1333 def structured_traceback(self, etype, value, elist, tb_offset=None,
1316 context=5):
1334 context=5):
1317 # If the source file has been edited, the line in the syntax error can
1335 # If the source file has been edited, the line in the syntax error can
1318 # be wrong (retrieved from an outdated cache). This replaces it with
1336 # be wrong (retrieved from an outdated cache). This replaces it with
1319 # the current value.
1337 # the current value.
1320 if isinstance(value, SyntaxError) \
1338 if isinstance(value, SyntaxError) \
1321 and isinstance(value.filename, str) \
1339 and isinstance(value.filename, str) \
1322 and isinstance(value.lineno, int):
1340 and isinstance(value.lineno, int):
1323 linecache.checkcache(value.filename)
1341 linecache.checkcache(value.filename)
1324 newtext = linecache.getline(value.filename, value.lineno)
1342 newtext = linecache.getline(value.filename, value.lineno)
1325 if newtext:
1343 if newtext:
1326 value.text = newtext
1344 value.text = newtext
1327 self.last_syntax_error = value
1345 self.last_syntax_error = value
1328 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1346 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1329 tb_offset=tb_offset, context=context)
1347 tb_offset=tb_offset, context=context)
1330
1348
1331 def clear_err_state(self):
1349 def clear_err_state(self):
1332 """Return the current error state and clear it"""
1350 """Return the current error state and clear it"""
1333 e = self.last_syntax_error
1351 e = self.last_syntax_error
1334 self.last_syntax_error = None
1352 self.last_syntax_error = None
1335 return e
1353 return e
1336
1354
1337 def stb2text(self, stb):
1355 def stb2text(self, stb):
1338 """Convert a structured traceback (a list) to a string."""
1356 """Convert a structured traceback (a list) to a string."""
1339 return ''.join(stb)
1357 return ''.join(stb)
1340
1358
1341
1359
1342 # some internal-use functions
1360 # some internal-use functions
1343 def text_repr(value):
1361 def text_repr(value):
1344 """Hopefully pretty robust repr equivalent."""
1362 """Hopefully pretty robust repr equivalent."""
1345 # this is pretty horrible but should always return *something*
1363 # this is pretty horrible but should always return *something*
1346 try:
1364 try:
1347 return pydoc.text.repr(value)
1365 return pydoc.text.repr(value)
1348 except KeyboardInterrupt:
1366 except KeyboardInterrupt:
1349 raise
1367 raise
1350 except:
1368 except:
1351 try:
1369 try:
1352 return repr(value)
1370 return repr(value)
1353 except KeyboardInterrupt:
1371 except KeyboardInterrupt:
1354 raise
1372 raise
1355 except:
1373 except:
1356 try:
1374 try:
1357 # all still in an except block so we catch
1375 # all still in an except block so we catch
1358 # getattr raising
1376 # getattr raising
1359 name = getattr(value, '__name__', None)
1377 name = getattr(value, '__name__', None)
1360 if name:
1378 if name:
1361 # ick, recursion
1379 # ick, recursion
1362 return text_repr(name)
1380 return text_repr(name)
1363 klass = getattr(value, '__class__', None)
1381 klass = getattr(value, '__class__', None)
1364 if klass:
1382 if klass:
1365 return '%s instance' % text_repr(klass)
1383 return '%s instance' % text_repr(klass)
1366 except KeyboardInterrupt:
1384 except KeyboardInterrupt:
1367 raise
1385 raise
1368 except:
1386 except:
1369 return 'UNRECOVERABLE REPR FAILURE'
1387 return 'UNRECOVERABLE REPR FAILURE'
1370
1388
1371
1389
1372 def eqrepr(value, repr=text_repr):
1390 def eqrepr(value, repr=text_repr):
1373 return '=%s' % repr(value)
1391 return '=%s' % repr(value)
1374
1392
1375
1393
1376 def nullrepr(value, repr=text_repr):
1394 def nullrepr(value, repr=text_repr):
1377 return ''
1395 return ''
@@ -1,675 +1,677 b''
1 """Various display related classes.
1 """Various display related classes.
2
2
3 Authors : MinRK, gregcaporaso, dannystaple
3 Authors : MinRK, gregcaporaso, dannystaple
4 """
4 """
5 from html import escape as html_escape
5 from html import escape as html_escape
6 from os.path import exists, isfile, splitext, abspath, join, isdir
6 from os.path import exists, isfile, splitext, abspath, join, isdir
7 from os import walk, sep, fsdecode
7 from os import walk, sep, fsdecode
8
8
9 from IPython.core.display import DisplayObject, TextDisplayObject
9 from IPython.core.display import DisplayObject, TextDisplayObject
10
10
11 from typing import Tuple, Iterable
11 from typing import Tuple, Iterable, Optional
12
12
13 __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument',
13 __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument',
14 'FileLink', 'FileLinks', 'Code']
14 'FileLink', 'FileLinks', 'Code']
15
15
16
16
17 class Audio(DisplayObject):
17 class Audio(DisplayObject):
18 """Create an audio object.
18 """Create an audio object.
19
19
20 When this object is returned by an input cell or passed to the
20 When this object is returned by an input cell or passed to the
21 display function, it will result in Audio controls being displayed
21 display function, it will result in Audio controls being displayed
22 in the frontend (only works in the notebook).
22 in the frontend (only works in the notebook).
23
23
24 Parameters
24 Parameters
25 ----------
25 ----------
26 data : numpy array, list, unicode, str or bytes
26 data : numpy array, list, unicode, str or bytes
27 Can be one of
27 Can be one of
28
28
29 * Numpy 1d array containing the desired waveform (mono)
29 * Numpy 1d array containing the desired waveform (mono)
30 * Numpy 2d array containing waveforms for each channel.
30 * Numpy 2d array containing waveforms for each channel.
31 Shape=(NCHAN, NSAMPLES). For the standard channel order, see
31 Shape=(NCHAN, NSAMPLES). For the standard channel order, see
32 http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
32 http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
33 * List of float or integer representing the waveform (mono)
33 * List of float or integer representing the waveform (mono)
34 * String containing the filename
34 * String containing the filename
35 * Bytestring containing raw PCM data or
35 * Bytestring containing raw PCM data or
36 * URL pointing to a file on the web.
36 * URL pointing to a file on the web.
37
37
38 If the array option is used, the waveform will be normalized.
38 If the array option is used, the waveform will be normalized.
39
39
40 If a filename or url is used, the format support will be browser
40 If a filename or url is used, the format support will be browser
41 dependent.
41 dependent.
42 url : unicode
42 url : unicode
43 A URL to download the data from.
43 A URL to download the data from.
44 filename : unicode
44 filename : unicode
45 Path to a local file to load the data from.
45 Path to a local file to load the data from.
46 embed : boolean
46 embed : boolean
47 Should the audio data be embedded using a data URI (True) or should
47 Should the audio data be embedded using a data URI (True) or should
48 the original source be referenced. Set this to True if you want the
48 the original source be referenced. Set this to True if you want the
49 audio to playable later with no internet connection in the notebook.
49 audio to playable later with no internet connection in the notebook.
50
50
51 Default is `True`, unless the keyword argument `url` is set, then
51 Default is `True`, unless the keyword argument `url` is set, then
52 default value is `False`.
52 default value is `False`.
53 rate : integer
53 rate : integer
54 The sampling rate of the raw data.
54 The sampling rate of the raw data.
55 Only required when data parameter is being used as an array
55 Only required when data parameter is being used as an array
56 autoplay : bool
56 autoplay : bool
57 Set to True if the audio should immediately start playing.
57 Set to True if the audio should immediately start playing.
58 Default is `False`.
58 Default is `False`.
59 normalize : bool
59 normalize : bool
60 Whether audio should be normalized (rescaled) to the maximum possible
60 Whether audio should be normalized (rescaled) to the maximum possible
61 range. Default is `True`. When set to `False`, `data` must be between
61 range. Default is `True`. When set to `False`, `data` must be between
62 -1 and 1 (inclusive), otherwise an error is raised.
62 -1 and 1 (inclusive), otherwise an error is raised.
63 Applies only when `data` is a list or array of samples; other types of
63 Applies only when `data` is a list or array of samples; other types of
64 audio are never normalized.
64 audio are never normalized.
65
65
66 Examples
66 Examples
67 --------
67 --------
68
68
69 >>> import pytest
69 >>> import pytest
70 >>> np = pytest.importorskip("numpy")
70 >>> np = pytest.importorskip("numpy")
71
71
72 Generate a sound
72 Generate a sound
73
73
74 >>> import numpy as np
74 >>> import numpy as np
75 >>> framerate = 44100
75 >>> framerate = 44100
76 >>> t = np.linspace(0,5,framerate*5)
76 >>> t = np.linspace(0,5,framerate*5)
77 >>> data = np.sin(2*np.pi*220*t) + np.sin(2*np.pi*224*t)
77 >>> data = np.sin(2*np.pi*220*t) + np.sin(2*np.pi*224*t)
78 >>> Audio(data, rate=framerate)
78 >>> Audio(data, rate=framerate)
79 <IPython.lib.display.Audio object>
79 <IPython.lib.display.Audio object>
80
80
81 Can also do stereo or more channels
81 Can also do stereo or more channels
82
82
83 >>> dataleft = np.sin(2*np.pi*220*t)
83 >>> dataleft = np.sin(2*np.pi*220*t)
84 >>> dataright = np.sin(2*np.pi*224*t)
84 >>> dataright = np.sin(2*np.pi*224*t)
85 >>> Audio([dataleft, dataright], rate=framerate)
85 >>> Audio([dataleft, dataright], rate=framerate)
86 <IPython.lib.display.Audio object>
86 <IPython.lib.display.Audio object>
87
87
88 From URL:
88 From URL:
89
89
90 >>> Audio("http://www.nch.com.au/acm/8k16bitpcm.wav") # doctest: +SKIP
90 >>> Audio("http://www.nch.com.au/acm/8k16bitpcm.wav") # doctest: +SKIP
91 >>> Audio(url="http://www.w3schools.com/html/horse.ogg") # doctest: +SKIP
91 >>> Audio(url="http://www.w3schools.com/html/horse.ogg") # doctest: +SKIP
92
92
93 From a File:
93 From a File:
94
94
95 >>> Audio('IPython/lib/tests/test.wav') # doctest: +SKIP
95 >>> Audio('IPython/lib/tests/test.wav') # doctest: +SKIP
96 >>> Audio(filename='IPython/lib/tests/test.wav') # doctest: +SKIP
96 >>> Audio(filename='IPython/lib/tests/test.wav') # doctest: +SKIP
97
97
98 From Bytes:
98 From Bytes:
99
99
100 >>> Audio(b'RAW_WAV_DATA..') # doctest: +SKIP
100 >>> Audio(b'RAW_WAV_DATA..') # doctest: +SKIP
101 >>> Audio(data=b'RAW_WAV_DATA..') # doctest: +SKIP
101 >>> Audio(data=b'RAW_WAV_DATA..') # doctest: +SKIP
102
102
103 See Also
103 See Also
104 --------
104 --------
105 ipywidgets.Audio
105 ipywidgets.Audio
106
106
107 Audio widget with more more flexibility and options.
107 Audio widget with more more flexibility and options.
108
108
109 """
109 """
110 _read_flags = 'rb'
110 _read_flags = 'rb'
111
111
112 def __init__(self, data=None, filename=None, url=None, embed=None, rate=None, autoplay=False, normalize=True, *,
112 def __init__(self, data=None, filename=None, url=None, embed=None, rate=None, autoplay=False, normalize=True, *,
113 element_id=None):
113 element_id=None):
114 if filename is None and url is None and data is None:
114 if filename is None and url is None and data is None:
115 raise ValueError("No audio data found. Expecting filename, url, or data.")
115 raise ValueError("No audio data found. Expecting filename, url, or data.")
116 if embed is False and url is None:
116 if embed is False and url is None:
117 raise ValueError("No url found. Expecting url when embed=False")
117 raise ValueError("No url found. Expecting url when embed=False")
118
118
119 if url is not None and embed is not True:
119 if url is not None and embed is not True:
120 self.embed = False
120 self.embed = False
121 else:
121 else:
122 self.embed = True
122 self.embed = True
123 self.autoplay = autoplay
123 self.autoplay = autoplay
124 self.element_id = element_id
124 self.element_id = element_id
125 super(Audio, self).__init__(data=data, url=url, filename=filename)
125 super(Audio, self).__init__(data=data, url=url, filename=filename)
126
126
127 if self.data is not None and not isinstance(self.data, bytes):
127 if self.data is not None and not isinstance(self.data, bytes):
128 if rate is None:
128 if rate is None:
129 raise ValueError("rate must be specified when data is a numpy array or list of audio samples.")
129 raise ValueError("rate must be specified when data is a numpy array or list of audio samples.")
130 self.data = Audio._make_wav(data, rate, normalize)
130 self.data = Audio._make_wav(data, rate, normalize)
131
131
132 def reload(self):
132 def reload(self):
133 """Reload the raw data from file or URL."""
133 """Reload the raw data from file or URL."""
134 import mimetypes
134 import mimetypes
135 if self.embed:
135 if self.embed:
136 super(Audio, self).reload()
136 super(Audio, self).reload()
137
137
138 if self.filename is not None:
138 if self.filename is not None:
139 self.mimetype = mimetypes.guess_type(self.filename)[0]
139 self.mimetype = mimetypes.guess_type(self.filename)[0]
140 elif self.url is not None:
140 elif self.url is not None:
141 self.mimetype = mimetypes.guess_type(self.url)[0]
141 self.mimetype = mimetypes.guess_type(self.url)[0]
142 else:
142 else:
143 self.mimetype = "audio/wav"
143 self.mimetype = "audio/wav"
144
144
145 @staticmethod
145 @staticmethod
146 def _make_wav(data, rate, normalize):
146 def _make_wav(data, rate, normalize):
147 """ Transform a numpy array to a PCM bytestring """
147 """ Transform a numpy array to a PCM bytestring """
148 from io import BytesIO
148 from io import BytesIO
149 import wave
149 import wave
150
150
151 try:
151 try:
152 scaled, nchan = Audio._validate_and_normalize_with_numpy(data, normalize)
152 scaled, nchan = Audio._validate_and_normalize_with_numpy(data, normalize)
153 except ImportError:
153 except ImportError:
154 scaled, nchan = Audio._validate_and_normalize_without_numpy(data, normalize)
154 scaled, nchan = Audio._validate_and_normalize_without_numpy(data, normalize)
155
155
156 fp = BytesIO()
156 fp = BytesIO()
157 waveobj = wave.open(fp,mode='wb')
157 waveobj = wave.open(fp,mode='wb')
158 waveobj.setnchannels(nchan)
158 waveobj.setnchannels(nchan)
159 waveobj.setframerate(rate)
159 waveobj.setframerate(rate)
160 waveobj.setsampwidth(2)
160 waveobj.setsampwidth(2)
161 waveobj.setcomptype('NONE','NONE')
161 waveobj.setcomptype('NONE','NONE')
162 waveobj.writeframes(scaled)
162 waveobj.writeframes(scaled)
163 val = fp.getvalue()
163 val = fp.getvalue()
164 waveobj.close()
164 waveobj.close()
165
165
166 return val
166 return val
167
167
168 @staticmethod
168 @staticmethod
169 def _validate_and_normalize_with_numpy(data, normalize) -> Tuple[bytes, int]:
169 def _validate_and_normalize_with_numpy(data, normalize) -> Tuple[bytes, int]:
170 import numpy as np
170 import numpy as np
171
171
172 data = np.array(data, dtype=float)
172 data = np.array(data, dtype=float)
173 if len(data.shape) == 1:
173 if len(data.shape) == 1:
174 nchan = 1
174 nchan = 1
175 elif len(data.shape) == 2:
175 elif len(data.shape) == 2:
176 # In wave files,channels are interleaved. E.g.,
176 # In wave files,channels are interleaved. E.g.,
177 # "L1R1L2R2..." for stereo. See
177 # "L1R1L2R2..." for stereo. See
178 # http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
178 # http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
179 # for channel ordering
179 # for channel ordering
180 nchan = data.shape[0]
180 nchan = data.shape[0]
181 data = data.T.ravel()
181 data = data.T.ravel()
182 else:
182 else:
183 raise ValueError('Array audio input must be a 1D or 2D array')
183 raise ValueError('Array audio input must be a 1D or 2D array')
184
184
185 max_abs_value = np.max(np.abs(data))
185 max_abs_value = np.max(np.abs(data))
186 normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize)
186 normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize)
187 scaled = data / normalization_factor * 32767
187 scaled = data / normalization_factor * 32767
188 return scaled.astype("<h").tobytes(), nchan
188 return scaled.astype("<h").tobytes(), nchan
189
189
190 @staticmethod
190 @staticmethod
191 def _validate_and_normalize_without_numpy(data, normalize):
191 def _validate_and_normalize_without_numpy(data, normalize):
192 import array
192 import array
193 import sys
193 import sys
194
194
195 data = array.array('f', data)
195 data = array.array('f', data)
196
196
197 try:
197 try:
198 max_abs_value = float(max([abs(x) for x in data]))
198 max_abs_value = float(max([abs(x) for x in data]))
199 except TypeError as e:
199 except TypeError as e:
200 raise TypeError('Only lists of mono audio are '
200 raise TypeError('Only lists of mono audio are '
201 'supported if numpy is not installed') from e
201 'supported if numpy is not installed') from e
202
202
203 normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize)
203 normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize)
204 scaled = array.array('h', [int(x / normalization_factor * 32767) for x in data])
204 scaled = array.array('h', [int(x / normalization_factor * 32767) for x in data])
205 if sys.byteorder == 'big':
205 if sys.byteorder == 'big':
206 scaled.byteswap()
206 scaled.byteswap()
207 nchan = 1
207 nchan = 1
208 return scaled.tobytes(), nchan
208 return scaled.tobytes(), nchan
209
209
210 @staticmethod
210 @staticmethod
211 def _get_normalization_factor(max_abs_value, normalize):
211 def _get_normalization_factor(max_abs_value, normalize):
212 if not normalize and max_abs_value > 1:
212 if not normalize and max_abs_value > 1:
213 raise ValueError('Audio data must be between -1 and 1 when normalize=False.')
213 raise ValueError('Audio data must be between -1 and 1 when normalize=False.')
214 return max_abs_value if normalize else 1
214 return max_abs_value if normalize else 1
215
215
216 def _data_and_metadata(self):
216 def _data_and_metadata(self):
217 """shortcut for returning metadata with url information, if defined"""
217 """shortcut for returning metadata with url information, if defined"""
218 md = {}
218 md = {}
219 if self.url:
219 if self.url:
220 md['url'] = self.url
220 md['url'] = self.url
221 if md:
221 if md:
222 return self.data, md
222 return self.data, md
223 else:
223 else:
224 return self.data
224 return self.data
225
225
226 def _repr_html_(self):
226 def _repr_html_(self):
227 src = """
227 src = """
228 <audio {element_id} controls="controls" {autoplay}>
228 <audio {element_id} controls="controls" {autoplay}>
229 <source src="{src}" type="{type}" />
229 <source src="{src}" type="{type}" />
230 Your browser does not support the audio element.
230 Your browser does not support the audio element.
231 </audio>
231 </audio>
232 """
232 """
233 return src.format(src=self.src_attr(), type=self.mimetype, autoplay=self.autoplay_attr(),
233 return src.format(src=self.src_attr(), type=self.mimetype, autoplay=self.autoplay_attr(),
234 element_id=self.element_id_attr())
234 element_id=self.element_id_attr())
235
235
236 def src_attr(self):
236 def src_attr(self):
237 import base64
237 import base64
238 if self.embed and (self.data is not None):
238 if self.embed and (self.data is not None):
239 data = base64=base64.b64encode(self.data).decode('ascii')
239 data = base64=base64.b64encode(self.data).decode('ascii')
240 return """data:{type};base64,{base64}""".format(type=self.mimetype,
240 return """data:{type};base64,{base64}""".format(type=self.mimetype,
241 base64=data)
241 base64=data)
242 elif self.url is not None:
242 elif self.url is not None:
243 return self.url
243 return self.url
244 else:
244 else:
245 return ""
245 return ""
246
246
247 def autoplay_attr(self):
247 def autoplay_attr(self):
248 if(self.autoplay):
248 if(self.autoplay):
249 return 'autoplay="autoplay"'
249 return 'autoplay="autoplay"'
250 else:
250 else:
251 return ''
251 return ''
252
252
253 def element_id_attr(self):
253 def element_id_attr(self):
254 if (self.element_id):
254 if (self.element_id):
255 return 'id="{element_id}"'.format(element_id=self.element_id)
255 return 'id="{element_id}"'.format(element_id=self.element_id)
256 else:
256 else:
257 return ''
257 return ''
258
258
259 class IFrame(object):
259 class IFrame(object):
260 """
260 """
261 Generic class to embed an iframe in an IPython notebook
261 Generic class to embed an iframe in an IPython notebook
262 """
262 """
263
263
264 iframe = """
264 iframe = """
265 <iframe
265 <iframe
266 width="{width}"
266 width="{width}"
267 height="{height}"
267 height="{height}"
268 src="{src}{params}"
268 src="{src}{params}"
269 frameborder="0"
269 frameborder="0"
270 allowfullscreen
270 allowfullscreen
271 {extras}
271 {extras}
272 ></iframe>
272 ></iframe>
273 """
273 """
274
274
275 def __init__(self, src, width, height, extras: Iterable[str] = None, **kwargs):
275 def __init__(
276 self, src, width, height, extras: Optional[Iterable[str]] = None, **kwargs
277 ):
276 if extras is None:
278 if extras is None:
277 extras = []
279 extras = []
278
280
279 self.src = src
281 self.src = src
280 self.width = width
282 self.width = width
281 self.height = height
283 self.height = height
282 self.extras = extras
284 self.extras = extras
283 self.params = kwargs
285 self.params = kwargs
284
286
285 def _repr_html_(self):
287 def _repr_html_(self):
286 """return the embed iframe"""
288 """return the embed iframe"""
287 if self.params:
289 if self.params:
288 from urllib.parse import urlencode
290 from urllib.parse import urlencode
289 params = "?" + urlencode(self.params)
291 params = "?" + urlencode(self.params)
290 else:
292 else:
291 params = ""
293 params = ""
292 return self.iframe.format(
294 return self.iframe.format(
293 src=self.src,
295 src=self.src,
294 width=self.width,
296 width=self.width,
295 height=self.height,
297 height=self.height,
296 params=params,
298 params=params,
297 extras=" ".join(self.extras),
299 extras=" ".join(self.extras),
298 )
300 )
299
301
300
302
301 class YouTubeVideo(IFrame):
303 class YouTubeVideo(IFrame):
302 """Class for embedding a YouTube Video in an IPython session, based on its video id.
304 """Class for embedding a YouTube Video in an IPython session, based on its video id.
303
305
304 e.g. to embed the video from https://www.youtube.com/watch?v=foo , you would
306 e.g. to embed the video from https://www.youtube.com/watch?v=foo , you would
305 do::
307 do::
306
308
307 vid = YouTubeVideo("foo")
309 vid = YouTubeVideo("foo")
308 display(vid)
310 display(vid)
309
311
310 To start from 30 seconds::
312 To start from 30 seconds::
311
313
312 vid = YouTubeVideo("abc", start=30)
314 vid = YouTubeVideo("abc", start=30)
313 display(vid)
315 display(vid)
314
316
315 To calculate seconds from time as hours, minutes, seconds use
317 To calculate seconds from time as hours, minutes, seconds use
316 :class:`datetime.timedelta`::
318 :class:`datetime.timedelta`::
317
319
318 start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds())
320 start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds())
319
321
320 Other parameters can be provided as documented at
322 Other parameters can be provided as documented at
321 https://developers.google.com/youtube/player_parameters#Parameters
323 https://developers.google.com/youtube/player_parameters#Parameters
322
324
323 When converting the notebook using nbconvert, a jpeg representation of the video
325 When converting the notebook using nbconvert, a jpeg representation of the video
324 will be inserted in the document.
326 will be inserted in the document.
325 """
327 """
326
328
327 def __init__(self, id, width=400, height=300, allow_autoplay=False, **kwargs):
329 def __init__(self, id, width=400, height=300, allow_autoplay=False, **kwargs):
328 self.id=id
330 self.id=id
329 src = "https://www.youtube.com/embed/{0}".format(id)
331 src = "https://www.youtube.com/embed/{0}".format(id)
330 if allow_autoplay:
332 if allow_autoplay:
331 extras = list(kwargs.get("extras", [])) + ['allow="autoplay"']
333 extras = list(kwargs.get("extras", [])) + ['allow="autoplay"']
332 kwargs.update(autoplay=1, extras=extras)
334 kwargs.update(autoplay=1, extras=extras)
333 super(YouTubeVideo, self).__init__(src, width, height, **kwargs)
335 super(YouTubeVideo, self).__init__(src, width, height, **kwargs)
334
336
335 def _repr_jpeg_(self):
337 def _repr_jpeg_(self):
336 # Deferred import
338 # Deferred import
337 from urllib.request import urlopen
339 from urllib.request import urlopen
338
340
339 try:
341 try:
340 return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read()
342 return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read()
341 except IOError:
343 except IOError:
342 return None
344 return None
343
345
344 class VimeoVideo(IFrame):
346 class VimeoVideo(IFrame):
345 """
347 """
346 Class for embedding a Vimeo video in an IPython session, based on its video id.
348 Class for embedding a Vimeo video in an IPython session, based on its video id.
347 """
349 """
348
350
349 def __init__(self, id, width=400, height=300, **kwargs):
351 def __init__(self, id, width=400, height=300, **kwargs):
350 src="https://player.vimeo.com/video/{0}".format(id)
352 src="https://player.vimeo.com/video/{0}".format(id)
351 super(VimeoVideo, self).__init__(src, width, height, **kwargs)
353 super(VimeoVideo, self).__init__(src, width, height, **kwargs)
352
354
353 class ScribdDocument(IFrame):
355 class ScribdDocument(IFrame):
354 """
356 """
355 Class for embedding a Scribd document in an IPython session
357 Class for embedding a Scribd document in an IPython session
356
358
357 Use the start_page params to specify a starting point in the document
359 Use the start_page params to specify a starting point in the document
358 Use the view_mode params to specify display type one off scroll | slideshow | book
360 Use the view_mode params to specify display type one off scroll | slideshow | book
359
361
360 e.g to Display Wes' foundational paper about PANDAS in book mode from page 3
362 e.g to Display Wes' foundational paper about PANDAS in book mode from page 3
361
363
362 ScribdDocument(71048089, width=800, height=400, start_page=3, view_mode="book")
364 ScribdDocument(71048089, width=800, height=400, start_page=3, view_mode="book")
363 """
365 """
364
366
365 def __init__(self, id, width=400, height=300, **kwargs):
367 def __init__(self, id, width=400, height=300, **kwargs):
366 src="https://www.scribd.com/embeds/{0}/content".format(id)
368 src="https://www.scribd.com/embeds/{0}/content".format(id)
367 super(ScribdDocument, self).__init__(src, width, height, **kwargs)
369 super(ScribdDocument, self).__init__(src, width, height, **kwargs)
368
370
369 class FileLink(object):
371 class FileLink(object):
370 """Class for embedding a local file link in an IPython session, based on path
372 """Class for embedding a local file link in an IPython session, based on path
371
373
372 e.g. to embed a link that was generated in the IPython notebook as my/data.txt
374 e.g. to embed a link that was generated in the IPython notebook as my/data.txt
373
375
374 you would do::
376 you would do::
375
377
376 local_file = FileLink("my/data.txt")
378 local_file = FileLink("my/data.txt")
377 display(local_file)
379 display(local_file)
378
380
379 or in the HTML notebook, just::
381 or in the HTML notebook, just::
380
382
381 FileLink("my/data.txt")
383 FileLink("my/data.txt")
382 """
384 """
383
385
384 html_link_str = "<a href='%s' target='_blank'>%s</a>"
386 html_link_str = "<a href='%s' target='_blank'>%s</a>"
385
387
386 def __init__(self,
388 def __init__(self,
387 path,
389 path,
388 url_prefix='',
390 url_prefix='',
389 result_html_prefix='',
391 result_html_prefix='',
390 result_html_suffix='<br>'):
392 result_html_suffix='<br>'):
391 """
393 """
392 Parameters
394 Parameters
393 ----------
395 ----------
394 path : str
396 path : str
395 path to the file or directory that should be formatted
397 path to the file or directory that should be formatted
396 url_prefix : str
398 url_prefix : str
397 prefix to be prepended to all files to form a working link [default:
399 prefix to be prepended to all files to form a working link [default:
398 '']
400 '']
399 result_html_prefix : str
401 result_html_prefix : str
400 text to append to beginning to link [default: '']
402 text to append to beginning to link [default: '']
401 result_html_suffix : str
403 result_html_suffix : str
402 text to append at the end of link [default: '<br>']
404 text to append at the end of link [default: '<br>']
403 """
405 """
404 if isdir(path):
406 if isdir(path):
405 raise ValueError("Cannot display a directory using FileLink. "
407 raise ValueError("Cannot display a directory using FileLink. "
406 "Use FileLinks to display '%s'." % path)
408 "Use FileLinks to display '%s'." % path)
407 self.path = fsdecode(path)
409 self.path = fsdecode(path)
408 self.url_prefix = url_prefix
410 self.url_prefix = url_prefix
409 self.result_html_prefix = result_html_prefix
411 self.result_html_prefix = result_html_prefix
410 self.result_html_suffix = result_html_suffix
412 self.result_html_suffix = result_html_suffix
411
413
412 def _format_path(self):
414 def _format_path(self):
413 fp = ''.join([self.url_prefix, html_escape(self.path)])
415 fp = ''.join([self.url_prefix, html_escape(self.path)])
414 return ''.join([self.result_html_prefix,
416 return ''.join([self.result_html_prefix,
415 self.html_link_str % \
417 self.html_link_str % \
416 (fp, html_escape(self.path, quote=False)),
418 (fp, html_escape(self.path, quote=False)),
417 self.result_html_suffix])
419 self.result_html_suffix])
418
420
419 def _repr_html_(self):
421 def _repr_html_(self):
420 """return html link to file
422 """return html link to file
421 """
423 """
422 if not exists(self.path):
424 if not exists(self.path):
423 return ("Path (<tt>%s</tt>) doesn't exist. "
425 return ("Path (<tt>%s</tt>) doesn't exist. "
424 "It may still be in the process of "
426 "It may still be in the process of "
425 "being generated, or you may have the "
427 "being generated, or you may have the "
426 "incorrect path." % self.path)
428 "incorrect path." % self.path)
427
429
428 return self._format_path()
430 return self._format_path()
429
431
430 def __repr__(self):
432 def __repr__(self):
431 """return absolute path to file
433 """return absolute path to file
432 """
434 """
433 return abspath(self.path)
435 return abspath(self.path)
434
436
435 class FileLinks(FileLink):
437 class FileLinks(FileLink):
436 """Class for embedding local file links in an IPython session, based on path
438 """Class for embedding local file links in an IPython session, based on path
437
439
438 e.g. to embed links to files that were generated in the IPython notebook
440 e.g. to embed links to files that were generated in the IPython notebook
439 under ``my/data``, you would do::
441 under ``my/data``, you would do::
440
442
441 local_files = FileLinks("my/data")
443 local_files = FileLinks("my/data")
442 display(local_files)
444 display(local_files)
443
445
444 or in the HTML notebook, just::
446 or in the HTML notebook, just::
445
447
446 FileLinks("my/data")
448 FileLinks("my/data")
447 """
449 """
448 def __init__(self,
450 def __init__(self,
449 path,
451 path,
450 url_prefix='',
452 url_prefix='',
451 included_suffixes=None,
453 included_suffixes=None,
452 result_html_prefix='',
454 result_html_prefix='',
453 result_html_suffix='<br>',
455 result_html_suffix='<br>',
454 notebook_display_formatter=None,
456 notebook_display_formatter=None,
455 terminal_display_formatter=None,
457 terminal_display_formatter=None,
456 recursive=True):
458 recursive=True):
457 """
459 """
458 See :class:`FileLink` for the ``path``, ``url_prefix``,
460 See :class:`FileLink` for the ``path``, ``url_prefix``,
459 ``result_html_prefix`` and ``result_html_suffix`` parameters.
461 ``result_html_prefix`` and ``result_html_suffix`` parameters.
460
462
461 included_suffixes : list
463 included_suffixes : list
462 Filename suffixes to include when formatting output [default: include
464 Filename suffixes to include when formatting output [default: include
463 all files]
465 all files]
464
466
465 notebook_display_formatter : function
467 notebook_display_formatter : function
466 Used to format links for display in the notebook. See discussion of
468 Used to format links for display in the notebook. See discussion of
467 formatter functions below.
469 formatter functions below.
468
470
469 terminal_display_formatter : function
471 terminal_display_formatter : function
470 Used to format links for display in the terminal. See discussion of
472 Used to format links for display in the terminal. See discussion of
471 formatter functions below.
473 formatter functions below.
472
474
473 Formatter functions must be of the form::
475 Formatter functions must be of the form::
474
476
475 f(dirname, fnames, included_suffixes)
477 f(dirname, fnames, included_suffixes)
476
478
477 dirname : str
479 dirname : str
478 The name of a directory
480 The name of a directory
479 fnames : list
481 fnames : list
480 The files in that directory
482 The files in that directory
481 included_suffixes : list
483 included_suffixes : list
482 The file suffixes that should be included in the output (passing None
484 The file suffixes that should be included in the output (passing None
483 meansto include all suffixes in the output in the built-in formatters)
485 meansto include all suffixes in the output in the built-in formatters)
484 recursive : boolean
486 recursive : boolean
485 Whether to recurse into subdirectories. Default is True.
487 Whether to recurse into subdirectories. Default is True.
486
488
487 The function should return a list of lines that will be printed in the
489 The function should return a list of lines that will be printed in the
488 notebook (if passing notebook_display_formatter) or the terminal (if
490 notebook (if passing notebook_display_formatter) or the terminal (if
489 passing terminal_display_formatter). This function is iterated over for
491 passing terminal_display_formatter). This function is iterated over for
490 each directory in self.path. Default formatters are in place, can be
492 each directory in self.path. Default formatters are in place, can be
491 passed here to support alternative formatting.
493 passed here to support alternative formatting.
492
494
493 """
495 """
494 if isfile(path):
496 if isfile(path):
495 raise ValueError("Cannot display a file using FileLinks. "
497 raise ValueError("Cannot display a file using FileLinks. "
496 "Use FileLink to display '%s'." % path)
498 "Use FileLink to display '%s'." % path)
497 self.included_suffixes = included_suffixes
499 self.included_suffixes = included_suffixes
498 # remove trailing slashes for more consistent output formatting
500 # remove trailing slashes for more consistent output formatting
499 path = path.rstrip('/')
501 path = path.rstrip('/')
500
502
501 self.path = path
503 self.path = path
502 self.url_prefix = url_prefix
504 self.url_prefix = url_prefix
503 self.result_html_prefix = result_html_prefix
505 self.result_html_prefix = result_html_prefix
504 self.result_html_suffix = result_html_suffix
506 self.result_html_suffix = result_html_suffix
505
507
506 self.notebook_display_formatter = \
508 self.notebook_display_formatter = \
507 notebook_display_formatter or self._get_notebook_display_formatter()
509 notebook_display_formatter or self._get_notebook_display_formatter()
508 self.terminal_display_formatter = \
510 self.terminal_display_formatter = \
509 terminal_display_formatter or self._get_terminal_display_formatter()
511 terminal_display_formatter or self._get_terminal_display_formatter()
510
512
511 self.recursive = recursive
513 self.recursive = recursive
512
514
513 def _get_display_formatter(
515 def _get_display_formatter(
514 self, dirname_output_format, fname_output_format, fp_format, fp_cleaner=None
516 self, dirname_output_format, fname_output_format, fp_format, fp_cleaner=None
515 ):
517 ):
516 """generate built-in formatter function
518 """generate built-in formatter function
517
519
518 this is used to define both the notebook and terminal built-in
520 this is used to define both the notebook and terminal built-in
519 formatters as they only differ by some wrapper text for each entry
521 formatters as they only differ by some wrapper text for each entry
520
522
521 dirname_output_format: string to use for formatting directory
523 dirname_output_format: string to use for formatting directory
522 names, dirname will be substituted for a single "%s" which
524 names, dirname will be substituted for a single "%s" which
523 must appear in this string
525 must appear in this string
524 fname_output_format: string to use for formatting file names,
526 fname_output_format: string to use for formatting file names,
525 if a single "%s" appears in the string, fname will be substituted
527 if a single "%s" appears in the string, fname will be substituted
526 if two "%s" appear in the string, the path to fname will be
528 if two "%s" appear in the string, the path to fname will be
527 substituted for the first and fname will be substituted for the
529 substituted for the first and fname will be substituted for the
528 second
530 second
529 fp_format: string to use for formatting filepaths, must contain
531 fp_format: string to use for formatting filepaths, must contain
530 exactly two "%s" and the dirname will be substituted for the first
532 exactly two "%s" and the dirname will be substituted for the first
531 and fname will be substituted for the second
533 and fname will be substituted for the second
532 """
534 """
533 def f(dirname, fnames, included_suffixes=None):
535 def f(dirname, fnames, included_suffixes=None):
534 result = []
536 result = []
535 # begin by figuring out which filenames, if any,
537 # begin by figuring out which filenames, if any,
536 # are going to be displayed
538 # are going to be displayed
537 display_fnames = []
539 display_fnames = []
538 for fname in fnames:
540 for fname in fnames:
539 if (isfile(join(dirname,fname)) and
541 if (isfile(join(dirname,fname)) and
540 (included_suffixes is None or
542 (included_suffixes is None or
541 splitext(fname)[1] in included_suffixes)):
543 splitext(fname)[1] in included_suffixes)):
542 display_fnames.append(fname)
544 display_fnames.append(fname)
543
545
544 if len(display_fnames) == 0:
546 if len(display_fnames) == 0:
545 # if there are no filenames to display, don't print anything
547 # if there are no filenames to display, don't print anything
546 # (not even the directory name)
548 # (not even the directory name)
547 pass
549 pass
548 else:
550 else:
549 # otherwise print the formatted directory name followed by
551 # otherwise print the formatted directory name followed by
550 # the formatted filenames
552 # the formatted filenames
551 dirname_output_line = dirname_output_format % dirname
553 dirname_output_line = dirname_output_format % dirname
552 result.append(dirname_output_line)
554 result.append(dirname_output_line)
553 for fname in display_fnames:
555 for fname in display_fnames:
554 fp = fp_format % (dirname,fname)
556 fp = fp_format % (dirname,fname)
555 if fp_cleaner is not None:
557 if fp_cleaner is not None:
556 fp = fp_cleaner(fp)
558 fp = fp_cleaner(fp)
557 try:
559 try:
558 # output can include both a filepath and a filename...
560 # output can include both a filepath and a filename...
559 fname_output_line = fname_output_format % (fp, fname)
561 fname_output_line = fname_output_format % (fp, fname)
560 except TypeError:
562 except TypeError:
561 # ... or just a single filepath
563 # ... or just a single filepath
562 fname_output_line = fname_output_format % fname
564 fname_output_line = fname_output_format % fname
563 result.append(fname_output_line)
565 result.append(fname_output_line)
564 return result
566 return result
565 return f
567 return f
566
568
567 def _get_notebook_display_formatter(self,
569 def _get_notebook_display_formatter(self,
568 spacer="&nbsp;&nbsp;"):
570 spacer="&nbsp;&nbsp;"):
569 """ generate function to use for notebook formatting
571 """ generate function to use for notebook formatting
570 """
572 """
571 dirname_output_format = \
573 dirname_output_format = \
572 self.result_html_prefix + "%s/" + self.result_html_suffix
574 self.result_html_prefix + "%s/" + self.result_html_suffix
573 fname_output_format = \
575 fname_output_format = \
574 self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix
576 self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix
575 fp_format = self.url_prefix + '%s/%s'
577 fp_format = self.url_prefix + '%s/%s'
576 if sep == "\\":
578 if sep == "\\":
577 # Working on a platform where the path separator is "\", so
579 # Working on a platform where the path separator is "\", so
578 # must convert these to "/" for generating a URI
580 # must convert these to "/" for generating a URI
579 def fp_cleaner(fp):
581 def fp_cleaner(fp):
580 # Replace all occurrences of backslash ("\") with a forward
582 # Replace all occurrences of backslash ("\") with a forward
581 # slash ("/") - this is necessary on windows when a path is
583 # slash ("/") - this is necessary on windows when a path is
582 # provided as input, but we must link to a URI
584 # provided as input, but we must link to a URI
583 return fp.replace('\\','/')
585 return fp.replace('\\','/')
584 else:
586 else:
585 fp_cleaner = None
587 fp_cleaner = None
586
588
587 return self._get_display_formatter(dirname_output_format,
589 return self._get_display_formatter(dirname_output_format,
588 fname_output_format,
590 fname_output_format,
589 fp_format,
591 fp_format,
590 fp_cleaner)
592 fp_cleaner)
591
593
592 def _get_terminal_display_formatter(self,
594 def _get_terminal_display_formatter(self,
593 spacer=" "):
595 spacer=" "):
594 """ generate function to use for terminal formatting
596 """ generate function to use for terminal formatting
595 """
597 """
596 dirname_output_format = "%s/"
598 dirname_output_format = "%s/"
597 fname_output_format = spacer + "%s"
599 fname_output_format = spacer + "%s"
598 fp_format = '%s/%s'
600 fp_format = '%s/%s'
599
601
600 return self._get_display_formatter(dirname_output_format,
602 return self._get_display_formatter(dirname_output_format,
601 fname_output_format,
603 fname_output_format,
602 fp_format)
604 fp_format)
603
605
604 def _format_path(self):
606 def _format_path(self):
605 result_lines = []
607 result_lines = []
606 if self.recursive:
608 if self.recursive:
607 walked_dir = list(walk(self.path))
609 walked_dir = list(walk(self.path))
608 else:
610 else:
609 walked_dir = [next(walk(self.path))]
611 walked_dir = [next(walk(self.path))]
610 walked_dir.sort()
612 walked_dir.sort()
611 for dirname, subdirs, fnames in walked_dir:
613 for dirname, subdirs, fnames in walked_dir:
612 result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes)
614 result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes)
613 return '\n'.join(result_lines)
615 return '\n'.join(result_lines)
614
616
615 def __repr__(self):
617 def __repr__(self):
616 """return newline-separated absolute paths
618 """return newline-separated absolute paths
617 """
619 """
618 result_lines = []
620 result_lines = []
619 if self.recursive:
621 if self.recursive:
620 walked_dir = list(walk(self.path))
622 walked_dir = list(walk(self.path))
621 else:
623 else:
622 walked_dir = [next(walk(self.path))]
624 walked_dir = [next(walk(self.path))]
623 walked_dir.sort()
625 walked_dir.sort()
624 for dirname, subdirs, fnames in walked_dir:
626 for dirname, subdirs, fnames in walked_dir:
625 result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes)
627 result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes)
626 return '\n'.join(result_lines)
628 return '\n'.join(result_lines)
627
629
628
630
629 class Code(TextDisplayObject):
631 class Code(TextDisplayObject):
630 """Display syntax-highlighted source code.
632 """Display syntax-highlighted source code.
631
633
632 This uses Pygments to highlight the code for HTML and Latex output.
634 This uses Pygments to highlight the code for HTML and Latex output.
633
635
634 Parameters
636 Parameters
635 ----------
637 ----------
636 data : str
638 data : str
637 The code as a string
639 The code as a string
638 url : str
640 url : str
639 A URL to fetch the code from
641 A URL to fetch the code from
640 filename : str
642 filename : str
641 A local filename to load the code from
643 A local filename to load the code from
642 language : str
644 language : str
643 The short name of a Pygments lexer to use for highlighting.
645 The short name of a Pygments lexer to use for highlighting.
644 If not specified, it will guess the lexer based on the filename
646 If not specified, it will guess the lexer based on the filename
645 or the code. Available lexers: http://pygments.org/docs/lexers/
647 or the code. Available lexers: http://pygments.org/docs/lexers/
646 """
648 """
647 def __init__(self, data=None, url=None, filename=None, language=None):
649 def __init__(self, data=None, url=None, filename=None, language=None):
648 self.language = language
650 self.language = language
649 super().__init__(data=data, url=url, filename=filename)
651 super().__init__(data=data, url=url, filename=filename)
650
652
651 def _get_lexer(self):
653 def _get_lexer(self):
652 if self.language:
654 if self.language:
653 from pygments.lexers import get_lexer_by_name
655 from pygments.lexers import get_lexer_by_name
654 return get_lexer_by_name(self.language)
656 return get_lexer_by_name(self.language)
655 elif self.filename:
657 elif self.filename:
656 from pygments.lexers import get_lexer_for_filename
658 from pygments.lexers import get_lexer_for_filename
657 return get_lexer_for_filename(self.filename)
659 return get_lexer_for_filename(self.filename)
658 else:
660 else:
659 from pygments.lexers import guess_lexer
661 from pygments.lexers import guess_lexer
660 return guess_lexer(self.data)
662 return guess_lexer(self.data)
661
663
662 def __repr__(self):
664 def __repr__(self):
663 return self.data
665 return self.data
664
666
665 def _repr_html_(self):
667 def _repr_html_(self):
666 from pygments import highlight
668 from pygments import highlight
667 from pygments.formatters import HtmlFormatter
669 from pygments.formatters import HtmlFormatter
668 fmt = HtmlFormatter()
670 fmt = HtmlFormatter()
669 style = '<style>{}</style>'.format(fmt.get_style_defs('.output_html'))
671 style = '<style>{}</style>'.format(fmt.get_style_defs('.output_html'))
670 return style + highlight(self.data, self._get_lexer(), fmt)
672 return style + highlight(self.data, self._get_lexer(), fmt)
671
673
672 def _repr_latex_(self):
674 def _repr_latex_(self):
673 from pygments import highlight
675 from pygments import highlight
674 from pygments.formatters import LatexFormatter
676 from pygments.formatters import LatexFormatter
675 return highlight(self.data, self._get_lexer(), LatexFormatter())
677 return highlight(self.data, self._get_lexer(), LatexFormatter())
@@ -1,46 +1,48 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Timezone utilities
3 Timezone utilities
4
4
5 Just UTC-awareness right now
5 Just UTC-awareness right now
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2013 The IPython Development Team
9 # Copyright (C) 2013 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 from datetime import tzinfo, timedelta, datetime
19 from datetime import tzinfo, timedelta, datetime
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Code
22 # Code
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # constant for zero offset
24 # constant for zero offset
25 ZERO = timedelta(0)
25 ZERO = timedelta(0)
26
26
27 class tzUTC(tzinfo):
27 class tzUTC(tzinfo):
28 """tzinfo object for UTC (zero offset)"""
28 """tzinfo object for UTC (zero offset)"""
29
29
30 def utcoffset(self, d):
30 def utcoffset(self, d):
31 return ZERO
31 return ZERO
32
32
33 def dst(self, d):
33 def dst(self, d):
34 return ZERO
34 return ZERO
35
35
36 UTC = tzUTC()
36
37 UTC = tzUTC() # type: ignore[abstract]
38
37
39
38 def utc_aware(unaware):
40 def utc_aware(unaware):
39 """decorator for adding UTC tzinfo to datetime's utcfoo methods"""
41 """decorator for adding UTC tzinfo to datetime's utcfoo methods"""
40 def utc_method(*args, **kwargs):
42 def utc_method(*args, **kwargs):
41 dt = unaware(*args, **kwargs)
43 dt = unaware(*args, **kwargs)
42 return dt.replace(tzinfo=UTC)
44 return dt.replace(tzinfo=UTC)
43 return utc_method
45 return utc_method
44
46
45 utcfromtimestamp = utc_aware(datetime.utcfromtimestamp)
47 utcfromtimestamp = utc_aware(datetime.utcfromtimestamp)
46 utcnow = utc_aware(datetime.utcnow)
48 utcnow = utc_aware(datetime.utcnow)
@@ -1,3 +1,32 b''
1 [build-system]
1 [build-system]
2 requires = ["setuptools >= 51.0.0"]
2 requires = ["setuptools >= 51.0.0"]
3 build-backend = "setuptools.build_meta"
3 build-backend = "setuptools.build_meta"
4 [tool.mypy]
5 python_version = 3.8
6 ignore_missing_imports = true
7 follow_imports = 'silent'
8 exclude = [
9 'test_\.+\.py',
10 'IPython.utils.tests.test_wildcard',
11 'testing',
12 'tests',
13 'PyColorize.py',
14 '_process_win32_controller.py',
15 'IPython/core/application.py',
16 'IPython/core/completerlib.py',
17 'IPython/core/displaypub.py',
18 'IPython/core/historyapp.py',
19 #'IPython/core/interactiveshell.py',
20 'IPython/core/magic.py',
21 'IPython/core/profileapp.py',
22 'IPython/core/ultratb.py',
23 'IPython/lib/deepreload.py',
24 'IPython/lib/pretty.py',
25 'IPython/sphinxext/ipython_directive.py',
26 'IPython/terminal/ipapp.py',
27 'IPython/utils/_process_win32.py',
28 'IPython/utils/path.py',
29 'IPython/utils/timing.py',
30 'IPython/utils/text.py'
31 ]
32
@@ -1,4 +0,0 b''
1 [mypy]
2 python_version = 3.8
3 ignore_missing_imports = True
4 follow_imports = silent
General Comments 0
You need to be logged in to leave comments. Login now