##// END OF EJS Templates
Merge branch 'master' into madbird1304/issue-13073-fix-paste-magic
Artur Svistunov -
r27661:91d34770 merge
parent child Browse files
Show More
@@ -0,0 +1,7 b''
1 Added shortcut for accepting auto suggestion
2 ============================================
3
4 Added End key shortcut for accepting auto-suggestion
5 This binding works in Vi mode too, provided
6 TerminalInteractiveShell.emacs_bindings_in_vi_insert_mode is set to be True.
7
@@ -39,7 +39,7 b' jobs:'
39 - name: Install and update Python dependencies
39 - name: Install and update Python dependencies
40 run: |
40 run: |
41 python -m pip install --upgrade -e file://$PWD#egg=ipython[test]
41 python -m pip install --upgrade -e file://$PWD#egg=ipython[test]
42 # we must instal IPython after ipykernel to get the right versions.
42 # we must install IPython after ipykernel to get the right versions.
43 python -m pip install --upgrade --upgrade-strategy eager flaky ipyparallel
43 python -m pip install --upgrade --upgrade-strategy eager flaky ipyparallel
44 python -m pip install --upgrade 'pytest<7'
44 python -m pip install --upgrade 'pytest<7'
45 - name: pytest
45 - name: pytest
@@ -17,6 +17,7 b' jobs:'
17 test:
17 test:
18 runs-on: ${{ matrix.os }}
18 runs-on: ${{ matrix.os }}
19 strategy:
19 strategy:
20 fail-fast: false
20 matrix:
21 matrix:
21 os: [ubuntu-latest, windows-latest]
22 os: [ubuntu-latest, windows-latest]
22 python-version: ["3.8", "3.9", "3.10"]
23 python-version: ["3.8", "3.9", "3.10"]
@@ -28,5 +28,13 b' __pycache__'
28 .pytest_cache
28 .pytest_cache
29 .python-version
29 .python-version
30 venv*/
30 venv*/
31 .idea/
32 .mypy_cache/
31 .mypy_cache/
32
33 # jetbrains ide stuff
34 *.iml
35 .idea/
36
37 # vscode ide stuff
38 *.code-workspace
39 .history
40 .vscode
@@ -28,7 +28,7 b' import sys'
28 # Don't forget to also update setup.py when this changes!
28 # Don't forget to also update setup.py when this changes!
29 if sys.version_info < (3, 8):
29 if sys.version_info < (3, 8):
30 raise ImportError(
30 raise ImportError(
31 """
31 """
32 IPython 8+ supports Python 3.8 and above, following NEP 29.
32 IPython 8+ supports Python 3.8 and above, following NEP 29.
33 When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
33 When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
34 Python 3.3 and 3.4 were supported up to IPython 6.x.
34 Python 3.3 and 3.4 were supported up to IPython 6.x.
@@ -40,7 +40,8 b' See IPython `README.rst` file for more information:'
40
40
41 https://github.com/ipython/ipython/blob/master/README.rst
41 https://github.com/ipython/ipython/blob/master/README.rst
42
42
43 """)
43 """
44 )
44
45
45 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
46 # Setup the top level names
47 # Setup the top level names
@@ -40,7 +40,7 b' class IPyAutocall(object):'
40 self._ip = ip
40 self._ip = ip
41
41
42 def set_ip(self, ip):
42 def set_ip(self, ip):
43 """ Will be used to set _ip point to current ipython instance b/f call
43 """Will be used to set _ip point to current ipython instance b/f call
44
44
45 Override this method if you don't want this to happen.
45 Override this method if you don't want this to happen.
46
46
@@ -41,7 +41,7 b' or using unicode completion:'
41
41
42 Only valid Python identifiers will complete. Combining characters (like arrow or
42 Only valid Python identifiers will complete. Combining characters (like arrow or
43 dots) are also available, unlike latex they need to be put after the their
43 dots) are also available, unlike latex they need to be put after the their
44 counterpart that is to say, `F\\\\vec<tab>` is correct, not `\\\\vec<tab>F`.
44 counterpart that is to say, ``F\\\\vec<tab>`` is correct, not ``\\\\vec<tab>F``.
45
45
46 Some browsers are known to display combining characters incorrectly.
46 Some browsers are known to display combining characters incorrectly.
47
47
@@ -50,7 +50,7 b' Backward latex completion'
50
50
51 It is sometime challenging to know how to type a character, if you are using
51 It is sometime challenging to know how to type a character, if you are using
52 IPython, or any compatible frontend you can prepend backslash to the character
52 IPython, or any compatible frontend you can prepend backslash to the character
53 and press `<tab>` to expand it to its latex form.
53 and press ``<tab>`` to expand it to its latex form.
54
54
55 .. code::
55 .. code::
56
56
@@ -589,7 +589,7 b' class Completer(Configurable):'
589
589
590 This will enable completion on elements of lists, results of function calls, etc.,
590 This will enable completion on elements of lists, results of function calls, etc.,
591 but can be unsafe because the code is actually evaluated on TAB.
591 but can be unsafe because the code is actually evaluated on TAB.
592 """
592 """,
593 ).tag(config=True)
593 ).tag(config=True)
594
594
595 use_jedi = Bool(default_value=JEDI_INSTALLED,
595 use_jedi = Bool(default_value=JEDI_INSTALLED,
@@ -1182,7 +1182,7 b' class IPCompleter(Completer):'
1182
1182
1183 # This is a list of names of unicode characters that can be completed
1183 # This is a list of names of unicode characters that can be completed
1184 # into their corresponding unicode value. The list is large, so we
1184 # into their corresponding unicode value. The list is large, so we
1185 # laziliy initialize it on first use. Consuming code should access this
1185 # lazily initialize it on first use. Consuming code should access this
1186 # attribute through the `@unicode_names` property.
1186 # attribute through the `@unicode_names` property.
1187 self._unicode_names = None
1187 self._unicode_names = None
1188
1188
@@ -2070,7 +2070,7 b' class IPCompleter(Completer):'
2070 indexed.
2070 indexed.
2071 line_buffer : optional, str
2071 line_buffer : optional, str
2072 The current line the cursor is in, this is mostly due to legacy
2072 The current line the cursor is in, this is mostly due to legacy
2073 reason that readline coudl only give a us the single current line.
2073 reason that readline could only give a us the single current line.
2074 Prefer `full_text`.
2074 Prefer `full_text`.
2075 text : str
2075 text : str
2076 The current "token" the cursor is in, mostly also for historical
2076 The current "token" the cursor is in, mostly also for historical
@@ -2139,8 +2139,9 b' class IPCompleter(Completer):'
2139 # different types of objects. The rlcomplete() method could then
2139 # different types of objects. The rlcomplete() method could then
2140 # simply collapse the dict into a list for readline, but we'd have
2140 # simply collapse the dict into a list for readline, but we'd have
2141 # richer completion semantics in other environments.
2141 # richer completion semantics in other environments.
2142 completions:Iterable[Any] = []
2142 is_magic_prefix = len(text) > 0 and text[0] == "%"
2143 if self.use_jedi:
2143 completions: Iterable[Any] = []
2144 if self.use_jedi and not is_magic_prefix:
2144 if not full_text:
2145 if not full_text:
2145 full_text = line_buffer
2146 full_text = line_buffer
2146 completions = self._jedi_matches(
2147 completions = self._jedi_matches(
@@ -101,7 +101,6 b' All the changes since then are under the same license as IPython.'
101 #
101 #
102 #*****************************************************************************
102 #*****************************************************************************
103
103
104 import bdb
105 import inspect
104 import inspect
106 import linecache
105 import linecache
107 import sys
106 import sys
@@ -884,7 +884,7 b' class Image(DisplayObject):'
884 a URL, or a filename from which to load image data.
884 a URL, or a filename from which to load image data.
885 The result is always embedding image data for inline images.
885 The result is always embedding image data for inline images.
886
886
887 >>> Image('http://www.google.fr/images/srpr/logo3w.png')
887 >>> Image('https://www.google.fr/images/srpr/logo3w.png') # doctest: +SKIP
888 <IPython.core.display.Image object>
888 <IPython.core.display.Image object>
889
889
890 >>> Image('/path/to/image.jpg')
890 >>> Image('/path/to/image.jpg')
@@ -897,7 +897,7 b' class Image(DisplayObject):'
897 it only generates ``<img>`` tag with a link to the source.
897 it only generates ``<img>`` tag with a link to the source.
898 This will not work in the qtconsole or offline.
898 This will not work in the qtconsole or offline.
899
899
900 >>> Image(url='http://www.google.fr/images/srpr/logo3w.png')
900 >>> Image(url='https://www.google.fr/images/srpr/logo3w.png')
901 <IPython.core.display.Image object>
901 <IPython.core.display.Image object>
902
902
903 """
903 """
@@ -166,7 +166,7 b' class HistoryAccessor(HistoryAccessorBase):'
166 in which case there will be no stored history, no SQLite connection,
166 in which case there will be no stored history, no SQLite connection,
167 and no background saving thread. This may be necessary in some
167 and no background saving thread. This may be necessary in some
168 threaded environments where IPython is embedded.
168 threaded environments where IPython is embedded.
169 """
169 """,
170 ).tag(config=True)
170 ).tag(config=True)
171
171
172 connection_options = Dict(
172 connection_options = Dict(
@@ -296,8 +296,8 b' class HistoryAccessor(HistoryAccessorBase):'
296 toget = "history.%s, output_history.output" % toget
296 toget = "history.%s, output_history.output" % toget
297 if latest:
297 if latest:
298 toget += ", MAX(session * 128 * 1024 + line)"
298 toget += ", MAX(session * 128 * 1024 + line)"
299 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
299 this_querry = "SELECT session, line, %s FROM %s " % (toget, sqlfrom) + sql
300 (toget, sqlfrom) + sql, params)
300 cur = self.db.execute(this_querry, params)
301 if latest:
301 if latest:
302 cur = (row[:-1] for row in cur)
302 cur = (row[:-1] for row in cur)
303 if output: # Regroup into 3-tuples, and parse JSON
303 if output: # Regroup into 3-tuples, and parse JSON
@@ -344,6 +344,11 b' class HistoryAccessor(HistoryAccessorBase):'
344 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
344 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
345 """Get the last n lines from the history database.
345 """Get the last n lines from the history database.
346
346
347 Most recent entry last.
348
349 Completion will be reordered so that that the last ones are when
350 possible from current session.
351
347 Parameters
352 Parameters
348 ----------
353 ----------
349 n : int
354 n : int
@@ -362,11 +367,31 b' class HistoryAccessor(HistoryAccessorBase):'
362 self.writeout_cache()
367 self.writeout_cache()
363 if not include_latest:
368 if not include_latest:
364 n += 1
369 n += 1
365 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
370 # cursor/line/entry
366 (n,), raw=raw, output=output)
371 this_cur = list(
372 self._run_sql(
373 "WHERE session == ? ORDER BY line DESC LIMIT ? ",
374 (self.session_number, n),
375 raw=raw,
376 output=output,
377 )
378 )
379 other_cur = list(
380 self._run_sql(
381 "WHERE session != ? ORDER BY session DESC, line DESC LIMIT ?",
382 (self.session_number, n),
383 raw=raw,
384 output=output,
385 )
386 )
387
388 everything = this_cur + other_cur
389
390 everything = everything[:n]
391
367 if not include_latest:
392 if not include_latest:
368 return reversed(list(cur)[1:])
393 return list(everything)[:0:-1]
369 return reversed(list(cur))
394 return list(everything)[::-1]
370
395
371 @catch_corrupt_db
396 @catch_corrupt_db
372 def search(self, pattern="*", raw=True, search_raw=True,
397 def search(self, pattern="*", raw=True, search_raw=True,
@@ -193,7 +193,7 b' def assemble_logical_lines():'
193 line = ''.join(parts)
193 line = ''.join(parts)
194
194
195 # Utilities
195 # Utilities
196 def _make_help_call(target, esc, lspace, next_input=None):
196 def _make_help_call(target, esc, lspace):
197 """Prepares a pinfo(2)/psearch call from a target name and the escape
197 """Prepares a pinfo(2)/psearch call from a target name and the escape
198 (i.e. ? or ??)"""
198 (i.e. ? or ??)"""
199 method = 'pinfo2' if esc == '??' \
199 method = 'pinfo2' if esc == '??' \
@@ -203,12 +203,13 b' def _make_help_call(target, esc, lspace, next_input=None):'
203 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
203 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
204 t_magic_name, _, t_magic_arg_s = arg.partition(' ')
204 t_magic_name, _, t_magic_arg_s = arg.partition(' ')
205 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
205 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
206 if next_input is None:
206 return "%sget_ipython().run_line_magic(%r, %r)" % (
207 return '%sget_ipython().run_line_magic(%r, %r)' % (lspace, t_magic_name, t_magic_arg_s)
207 lspace,
208 else:
208 t_magic_name,
209 return '%sget_ipython().set_next_input(%r);get_ipython().run_line_magic(%r, %r)' % \
209 t_magic_arg_s,
210 (lspace, next_input, t_magic_name, t_magic_arg_s)
210 )
211
211
212
212 # These define the transformations for the different escape characters.
213 # These define the transformations for the different escape characters.
213 def _tr_system(line_info):
214 def _tr_system(line_info):
214 "Translate lines escaped with: !"
215 "Translate lines escaped with: !"
@@ -349,10 +350,7 b' def help_end(line):'
349 esc = m.group(3)
350 esc = m.group(3)
350 lspace = _initial_space_re.match(line).group(0)
351 lspace = _initial_space_re.match(line).group(0)
351
352
352 # If we're mid-command, put it back on the next prompt for the user.
353 return _make_help_call(target, esc, lspace)
353 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
354
355 return _make_help_call(target, esc, lspace, next_input)
356
354
357
355
358 @CoroutineInputTransformer.wrap
356 @CoroutineInputTransformer.wrap
@@ -325,7 +325,7 b" ESC_PAREN = '/' # Call first argument with rest of line as arguments"
325 ESCAPE_SINGLES = {'!', '?', '%', ',', ';', '/'}
325 ESCAPE_SINGLES = {'!', '?', '%', ',', ';', '/'}
326 ESCAPE_DOUBLES = {'!!', '??'} # %% (cell magic) is handled separately
326 ESCAPE_DOUBLES = {'!!', '??'} # %% (cell magic) is handled separately
327
327
328 def _make_help_call(target, esc, next_input=None):
328 def _make_help_call(target, esc):
329 """Prepares a pinfo(2)/psearch call from a target name and the escape
329 """Prepares a pinfo(2)/psearch call from a target name and the escape
330 (i.e. ? or ??)"""
330 (i.e. ? or ??)"""
331 method = 'pinfo2' if esc == '??' \
331 method = 'pinfo2' if esc == '??' \
@@ -335,11 +335,8 b' def _make_help_call(target, esc, next_input=None):'
335 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
335 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
336 t_magic_name, _, t_magic_arg_s = arg.partition(' ')
336 t_magic_name, _, t_magic_arg_s = arg.partition(' ')
337 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
337 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
338 if next_input is None:
338 return "get_ipython().run_line_magic(%r, %r)" % (t_magic_name, t_magic_arg_s)
339 return 'get_ipython().run_line_magic(%r, %r)' % (t_magic_name, t_magic_arg_s)
339
340 else:
341 return 'get_ipython().set_next_input(%r);get_ipython().run_line_magic(%r, %r)' % \
342 (next_input, t_magic_name, t_magic_arg_s)
343
340
344 def _tr_help(content):
341 def _tr_help(content):
345 """Translate lines escaped with: ?
342 """Translate lines escaped with: ?
@@ -480,13 +477,8 b' class HelpEnd(TokenTransformBase):'
480 target = m.group(1)
477 target = m.group(1)
481 esc = m.group(3)
478 esc = m.group(3)
482
479
483 # If we're mid-command, put it back on the next prompt for the user.
484 next_input = None
485 if (not lines_before) and (not lines_after) \
486 and content.strip() != m.group(0):
487 next_input = content.rstrip('?\n')
488
480
489 call = _make_help_call(target, esc, next_input=next_input)
481 call = _make_help_call(target, esc)
490 new_line = indent + call + '\n'
482 new_line = indent + call + '\n'
491
483
492 return lines_before + [new_line] + lines_after
484 return lines_before + [new_line] + lines_after
@@ -14,40 +14,61 b''
14 import abc
14 import abc
15 import ast
15 import ast
16 import atexit
16 import atexit
17 import bdb
17 import builtins as builtin_mod
18 import builtins as builtin_mod
19 import dis
18 import functools
20 import functools
19 import inspect
21 import inspect
20 import os
22 import os
21 import re
23 import re
22 import runpy
24 import runpy
25 import subprocess
23 import sys
26 import sys
24 import tempfile
27 import tempfile
25 import traceback
28 import traceback
26 import types
29 import types
27 import subprocess
28 import warnings
30 import warnings
31 from ast import stmt
29 from io import open as io_open
32 from io import open as io_open
30
33 from logging import error
31 from pathlib import Path
34 from pathlib import Path
32 from pickleshare import PickleShareDB
35 from typing import Callable
36 from typing import List as ListType
37 from typing import Optional, Tuple
38 from warnings import warn
33
39
40 from pickleshare import PickleShareDB
41 from tempfile import TemporaryDirectory
42 from traitlets import (
43 Any,
44 Bool,
45 CaselessStrEnum,
46 Dict,
47 Enum,
48 Instance,
49 Integer,
50 List,
51 Type,
52 Unicode,
53 default,
54 observe,
55 validate,
56 )
34 from traitlets.config.configurable import SingletonConfigurable
57 from traitlets.config.configurable import SingletonConfigurable
35 from traitlets.utils.importstring import import_item
58 from traitlets.utils.importstring import import_item
36 from IPython.core import oinspect
59
37 from IPython.core import magic
60 import IPython.core.hooks
38 from IPython.core import page
61 from IPython.core import magic, oinspect, page, prefilter, ultratb
39 from IPython.core import prefilter
40 from IPython.core import ultratb
41 from IPython.core.alias import Alias, AliasManager
62 from IPython.core.alias import Alias, AliasManager
42 from IPython.core.autocall import ExitAutocall
63 from IPython.core.autocall import ExitAutocall
43 from IPython.core.builtin_trap import BuiltinTrap
64 from IPython.core.builtin_trap import BuiltinTrap
44 from IPython.core.events import EventManager, available_events
45 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
65 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
46 from IPython.core.debugger import InterruptiblePdb
66 from IPython.core.debugger import InterruptiblePdb
47 from IPython.core.display_trap import DisplayTrap
67 from IPython.core.display_trap import DisplayTrap
48 from IPython.core.displayhook import DisplayHook
68 from IPython.core.displayhook import DisplayHook
49 from IPython.core.displaypub import DisplayPublisher
69 from IPython.core.displaypub import DisplayPublisher
50 from IPython.core.error import InputRejected, UsageError
70 from IPython.core.error import InputRejected, UsageError
71 from IPython.core.events import EventManager, available_events
51 from IPython.core.extensions import ExtensionManager
72 from IPython.core.extensions import ExtensionManager
52 from IPython.core.formatters import DisplayFormatter
73 from IPython.core.formatters import DisplayFormatter
53 from IPython.core.history import HistoryManager
74 from IPython.core.history import HistoryManager
@@ -59,31 +80,17 b' from IPython.core.prefilter import PrefilterManager'
59 from IPython.core.profiledir import ProfileDir
80 from IPython.core.profiledir import ProfileDir
60 from IPython.core.usage import default_banner
81 from IPython.core.usage import default_banner
61 from IPython.display import display
82 from IPython.display import display
83 from IPython.paths import get_ipython_dir
62 from IPython.testing.skipdoctest import skip_doctest
84 from IPython.testing.skipdoctest import skip_doctest
63 from IPython.utils import PyColorize
85 from IPython.utils import PyColorize, io, openpy, py3compat
64 from IPython.utils import io
65 from IPython.utils import py3compat
66 from IPython.utils import openpy
67 from IPython.utils.decorators import undoc
86 from IPython.utils.decorators import undoc
68 from IPython.utils.io import ask_yes_no
87 from IPython.utils.io import ask_yes_no
69 from IPython.utils.ipstruct import Struct
88 from IPython.utils.ipstruct import Struct
70 from IPython.paths import get_ipython_dir
89 from IPython.utils.path import ensure_dir_exists, get_home_dir, get_py_filename
71 from IPython.utils.path import get_home_dir, get_py_filename, ensure_dir_exists
90 from IPython.utils.process import getoutput, system
72 from IPython.utils.process import system, getoutput
73 from IPython.utils.strdispatch import StrDispatch
91 from IPython.utils.strdispatch import StrDispatch
74 from IPython.utils.syspathcontext import prepended_to_syspath
92 from IPython.utils.syspathcontext import prepended_to_syspath
75 from IPython.utils.text import format_screen, LSString, SList, DollarFormatter
93 from IPython.utils.text import DollarFormatter, LSString, SList, format_screen
76 from IPython.utils.tempdir import TemporaryDirectory
77 from traitlets import (
78 Integer, Bool, CaselessStrEnum, Enum, List, Dict, Unicode, Instance, Type,
79 observe, default, validate, Any
80 )
81 from warnings import warn
82 from logging import error
83 import IPython.core.hooks
84
85 from typing import List as ListType, Tuple, Optional, Callable
86 from ast import stmt
87
94
88 sphinxify: Optional[Callable]
95 sphinxify: Optional[Callable]
89
96
@@ -122,8 +129,13 b' _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)'
122
129
123 # we still need to run things using the asyncio eventloop, but there is no
130 # we still need to run things using the asyncio eventloop, but there is no
124 # async integration
131 # async integration
125 from .async_helpers import _asyncio_runner, _pseudo_sync_runner
132 from .async_helpers import (
126 from .async_helpers import _curio_runner, _trio_runner, _should_be_async
133 _asyncio_runner,
134 _curio_runner,
135 _pseudo_sync_runner,
136 _should_be_async,
137 _trio_runner,
138 )
127
139
128 #-----------------------------------------------------------------------------
140 #-----------------------------------------------------------------------------
129 # Globals
141 # Globals
@@ -188,19 +200,29 b' class ExecutionInfo(object):'
188 store_history = False
200 store_history = False
189 silent = False
201 silent = False
190 shell_futures = True
202 shell_futures = True
203 cell_id = None
191
204
192 def __init__(self, raw_cell, store_history, silent, shell_futures):
205 def __init__(self, raw_cell, store_history, silent, shell_futures, cell_id):
193 self.raw_cell = raw_cell
206 self.raw_cell = raw_cell
194 self.store_history = store_history
207 self.store_history = store_history
195 self.silent = silent
208 self.silent = silent
196 self.shell_futures = shell_futures
209 self.shell_futures = shell_futures
210 self.cell_id = cell_id
197
211
198 def __repr__(self):
212 def __repr__(self):
199 name = self.__class__.__qualname__
213 name = self.__class__.__qualname__
200 raw_cell = ((self.raw_cell[:50] + '..')
214 raw_cell = (
201 if len(self.raw_cell) > 50 else self.raw_cell)
215 (self.raw_cell[:50] + "..") if len(self.raw_cell) > 50 else self.raw_cell
202 return '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s>' %\
216 )
203 (name, id(self), raw_cell, self.store_history, self.silent, self.shell_futures)
217 return '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s cell_id=%s>' % (
218 name,
219 id(self),
220 raw_cell,
221 self.store_history,
222 self.silent,
223 self.shell_futures,
224 self.cell_id,
225 )
204
226
205
227
206 class ExecutionResult(object):
228 class ExecutionResult(object):
@@ -747,6 +769,33 b' class InteractiveShell(SingletonConfigurable):'
747 # the appropriate time.
769 # the appropriate time.
748 self.display_trap = DisplayTrap(hook=self.displayhook)
770 self.display_trap = DisplayTrap(hook=self.displayhook)
749
771
772 @staticmethod
773 def get_path_links(p: Path):
774 """Gets path links including all symlinks
775
776 Examples
777 --------
778 In [1]: from IPython.core.interactiveshell import InteractiveShell
779
780 In [2]: import sys, pathlib
781
782 In [3]: paths = InteractiveShell.get_path_links(pathlib.Path(sys.executable))
783
784 In [4]: len(paths) == len(set(paths))
785 Out[4]: True
786
787 In [5]: bool(paths)
788 Out[5]: True
789 """
790 paths = [p]
791 while p.is_symlink():
792 new_path = Path(os.readlink(p))
793 if not new_path.is_absolute():
794 new_path = p.parent / new_path
795 p = new_path
796 paths.append(p)
797 return paths
798
750 def init_virtualenv(self):
799 def init_virtualenv(self):
751 """Add the current virtualenv to sys.path so the user can import modules from it.
800 """Add the current virtualenv to sys.path so the user can import modules from it.
752 This isn't perfect: it doesn't use the Python interpreter with which the
801 This isn't perfect: it doesn't use the Python interpreter with which the
@@ -772,10 +821,7 b' class InteractiveShell(SingletonConfigurable):'
772 # stdlib venv may symlink sys.executable, so we can't use realpath.
821 # stdlib venv may symlink sys.executable, so we can't use realpath.
773 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
822 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
774 # So we just check every item in the symlink tree (generally <= 3)
823 # So we just check every item in the symlink tree (generally <= 3)
775 paths = [p]
824 paths = self.get_path_links(p)
776 while p.is_symlink():
777 p = Path(os.readlink(p))
778 paths.append(p.resolve())
779
825
780 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
826 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
781 if p_venv.parts[1] == "cygdrive":
827 if p_venv.parts[1] == "cygdrive":
@@ -1941,10 +1987,19 b' class InteractiveShell(SingletonConfigurable):'
1941 # Exception classes can customise their traceback - we
1987 # Exception classes can customise their traceback - we
1942 # use this in IPython.parallel for exceptions occurring
1988 # use this in IPython.parallel for exceptions occurring
1943 # in the engines. This should return a list of strings.
1989 # in the engines. This should return a list of strings.
1944 stb = value._render_traceback_()
1990 if hasattr(value, "_render_traceback_"):
1991 stb = value._render_traceback_()
1992 else:
1993 stb = self.InteractiveTB.structured_traceback(
1994 etype, value, tb, tb_offset=tb_offset
1995 )
1996
1945 except Exception:
1997 except Exception:
1946 stb = self.InteractiveTB.structured_traceback(etype,
1998 print(
1947 value, tb, tb_offset=tb_offset)
1999 "Unexpected exception formatting exception. Falling back to standard exception"
2000 )
2001 traceback.print_exc()
2002 return None
1948
2003
1949 self._showtraceback(etype, value, stb)
2004 self._showtraceback(etype, value, stb)
1950 if self.call_pdb:
2005 if self.call_pdb:
@@ -2034,8 +2089,12 b' class InteractiveShell(SingletonConfigurable):'
2034 (typically over the network by remote frontends).
2089 (typically over the network by remote frontends).
2035 """
2090 """
2036 from IPython.core.completer import IPCompleter
2091 from IPython.core.completer import IPCompleter
2037 from IPython.core.completerlib import (module_completer,
2092 from IPython.core.completerlib import (
2038 magic_run_completer, cd_completer, reset_completer)
2093 cd_completer,
2094 magic_run_completer,
2095 module_completer,
2096 reset_completer,
2097 )
2039
2098
2040 self.Completer = IPCompleter(shell=self,
2099 self.Completer = IPCompleter(shell=self,
2041 namespace=self.user_ns,
2100 namespace=self.user_ns,
@@ -2414,14 +2473,9 b' class InteractiveShell(SingletonConfigurable):'
2414 cmd = self.var_expand(cmd, depth=1)
2473 cmd = self.var_expand(cmd, depth=1)
2415 # warn if there is an IPython magic alternative.
2474 # warn if there is an IPython magic alternative.
2416 main_cmd = cmd.split()[0]
2475 main_cmd = cmd.split()[0]
2417 has_magic_alternatives = ("pip", "conda", "cd", "ls")
2476 has_magic_alternatives = ("pip", "conda", "cd")
2418
2477
2419 # had to check if the command was an alias expanded because of `ls`
2478 if main_cmd in has_magic_alternatives:
2420 is_alias_expanded = self.alias_manager.is_alias(main_cmd) and (
2421 self.alias_manager.retrieve_alias(main_cmd).strip() == cmd.strip()
2422 )
2423
2424 if main_cmd in has_magic_alternatives and not is_alias_expanded:
2425 warnings.warn(
2479 warnings.warn(
2426 (
2480 (
2427 "You executed the system command !{0} which may not work "
2481 "You executed the system command !{0} which may not work "
@@ -2791,7 +2845,14 b' class InteractiveShell(SingletonConfigurable):'
2791 self.showtraceback()
2845 self.showtraceback()
2792 warn('Unknown failure executing module: <%s>' % mod_name)
2846 warn('Unknown failure executing module: <%s>' % mod_name)
2793
2847
2794 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2848 def run_cell(
2849 self,
2850 raw_cell,
2851 store_history=False,
2852 silent=False,
2853 shell_futures=True,
2854 cell_id=None,
2855 ):
2795 """Run a complete IPython cell.
2856 """Run a complete IPython cell.
2796
2857
2797 Parameters
2858 Parameters
@@ -2818,14 +2879,22 b' class InteractiveShell(SingletonConfigurable):'
2818 result = None
2879 result = None
2819 try:
2880 try:
2820 result = self._run_cell(
2881 result = self._run_cell(
2821 raw_cell, store_history, silent, shell_futures)
2882 raw_cell, store_history, silent, shell_futures, cell_id
2883 )
2822 finally:
2884 finally:
2823 self.events.trigger('post_execute')
2885 self.events.trigger('post_execute')
2824 if not silent:
2886 if not silent:
2825 self.events.trigger('post_run_cell', result)
2887 self.events.trigger('post_run_cell', result)
2826 return result
2888 return result
2827
2889
2828 def _run_cell(self, raw_cell:str, store_history:bool, silent:bool, shell_futures:bool) -> ExecutionResult:
2890 def _run_cell(
2891 self,
2892 raw_cell: str,
2893 store_history: bool,
2894 silent: bool,
2895 shell_futures: bool,
2896 cell_id: str,
2897 ) -> ExecutionResult:
2829 """Internal method to run a complete IPython cell."""
2898 """Internal method to run a complete IPython cell."""
2830
2899
2831 # we need to avoid calling self.transform_cell multiple time on the same thing
2900 # we need to avoid calling self.transform_cell multiple time on the same thing
@@ -2845,6 +2914,7 b' class InteractiveShell(SingletonConfigurable):'
2845 shell_futures=shell_futures,
2914 shell_futures=shell_futures,
2846 transformed_cell=transformed_cell,
2915 transformed_cell=transformed_cell,
2847 preprocessing_exc_tuple=preprocessing_exc_tuple,
2916 preprocessing_exc_tuple=preprocessing_exc_tuple,
2917 cell_id=cell_id,
2848 )
2918 )
2849
2919
2850 # run_cell_async is async, but may not actually need an eventloop.
2920 # run_cell_async is async, but may not actually need an eventloop.
@@ -2865,7 +2935,9 b' class InteractiveShell(SingletonConfigurable):'
2865 try:
2935 try:
2866 return runner(coro)
2936 return runner(coro)
2867 except BaseException as e:
2937 except BaseException as e:
2868 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures)
2938 info = ExecutionInfo(
2939 raw_cell, store_history, silent, shell_futures, cell_id
2940 )
2869 result = ExecutionResult(info)
2941 result = ExecutionResult(info)
2870 result.error_in_exec = e
2942 result.error_in_exec = e
2871 self.showtraceback(running_compiled_code=True)
2943 self.showtraceback(running_compiled_code=True)
@@ -2921,7 +2993,8 b' class InteractiveShell(SingletonConfigurable):'
2921 shell_futures=True,
2993 shell_futures=True,
2922 *,
2994 *,
2923 transformed_cell: Optional[str] = None,
2995 transformed_cell: Optional[str] = None,
2924 preprocessing_exc_tuple: Optional[Any] = None
2996 preprocessing_exc_tuple: Optional[Any] = None,
2997 cell_id=None,
2925 ) -> ExecutionResult:
2998 ) -> ExecutionResult:
2926 """Run a complete IPython cell asynchronously.
2999 """Run a complete IPython cell asynchronously.
2927
3000
@@ -2952,8 +3025,7 b' class InteractiveShell(SingletonConfigurable):'
2952
3025
2953 .. versionadded:: 7.0
3026 .. versionadded:: 7.0
2954 """
3027 """
2955 info = ExecutionInfo(
3028 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures, cell_id)
2956 raw_cell, store_history, silent, shell_futures)
2957 result = ExecutionResult(info)
3029 result = ExecutionResult(info)
2958
3030
2959 if (not raw_cell) or raw_cell.isspace():
3031 if (not raw_cell) or raw_cell.isspace():
@@ -3008,9 +3080,8 b' class InteractiveShell(SingletonConfigurable):'
3008 cell = raw_cell
3080 cell = raw_cell
3009
3081
3010 # Store raw and processed history
3082 # Store raw and processed history
3011 if store_history:
3083 if store_history and raw_cell.strip(" %") != "paste":
3012 self.history_manager.store_inputs(self.execution_count,
3084 self.history_manager.store_inputs(self.execution_count, cell, raw_cell)
3013 cell, raw_cell)
3014 if not silent:
3085 if not silent:
3015 self.logger.log(cell, raw_cell)
3086 self.logger.log(cell, raw_cell)
3016
3087
@@ -3141,6 +3212,29 b' class InteractiveShell(SingletonConfigurable):'
3141 ast.fix_missing_locations(node)
3212 ast.fix_missing_locations(node)
3142 return node
3213 return node
3143
3214
3215 def _update_code_co_name(self, code):
3216 """Python 3.10 changed the behaviour so that whenever a code object
3217 is assembled in the compile(ast) the co_firstlineno would be == 1.
3218
3219 This makes pydevd/debugpy think that all cells invoked are the same
3220 since it caches information based on (co_firstlineno, co_name, co_filename).
3221
3222 Given that, this function changes the code 'co_name' to be unique
3223 based on the first real lineno of the code (which also has a nice
3224 side effect of customizing the name so that it's not always <module>).
3225
3226 See: https://github.com/ipython/ipykernel/issues/841
3227 """
3228 if not hasattr(code, "replace"):
3229 # It may not be available on older versions of Python (only
3230 # available for 3.8 onwards).
3231 return code
3232 try:
3233 first_real_line = next(dis.findlinestarts(code))[1]
3234 except StopIteration:
3235 return code
3236 return code.replace(co_name="<cell line: %s>" % (first_real_line,))
3237
3144 async def run_ast_nodes(
3238 async def run_ast_nodes(
3145 self,
3239 self,
3146 nodelist: ListType[stmt],
3240 nodelist: ListType[stmt],
@@ -3239,6 +3333,7 b' class InteractiveShell(SingletonConfigurable):'
3239 else 0x0
3333 else 0x0
3240 ):
3334 ):
3241 code = compiler(mod, cell_name, mode)
3335 code = compiler(mod, cell_name, mode)
3336 code = self._update_code_co_name(code)
3242 asy = compare(code)
3337 asy = compare(code)
3243 if await self.run_code(code, result, async_=asy):
3338 if await self.run_code(code, result, async_=asy):
3244 return True
3339 return True
@@ -3309,6 +3404,11 b' class InteractiveShell(SingletonConfigurable):'
3309 result.error_in_exec = e
3404 result.error_in_exec = e
3310 self.showtraceback(exception_only=True)
3405 self.showtraceback(exception_only=True)
3311 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3406 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3407 except bdb.BdbQuit:
3408 etype, value, tb = sys.exc_info()
3409 if result is not None:
3410 result.error_in_exec = value
3411 # the BdbQuit stops here
3312 except self.custom_exceptions:
3412 except self.custom_exceptions:
3313 etype, value, tb = sys.exc_info()
3413 etype, value, tb = sys.exc_info()
3314 if result is not None:
3414 if result is not None:
@@ -3375,8 +3475,9 b' class InteractiveShell(SingletonConfigurable):'
3375 make sense in all contexts, for example a terminal ipython can't
3475 make sense in all contexts, for example a terminal ipython can't
3376 display figures inline.
3476 display figures inline.
3377 """
3477 """
3378 from IPython.core import pylabtools as pt
3379 from matplotlib_inline.backend_inline import configure_inline_support
3478 from matplotlib_inline.backend_inline import configure_inline_support
3479
3480 from IPython.core import pylabtools as pt
3380 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3481 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3381
3482
3382 if gui != 'inline':
3483 if gui != 'inline':
@@ -3679,6 +3780,10 b' class InteractiveShell(SingletonConfigurable):'
3679 pass
3780 pass
3680 del self.tempdirs
3781 del self.tempdirs
3681
3782
3783 # Restore user's cursor
3784 if hasattr(self, "editing_mode") and self.editing_mode == "vi":
3785 sys.stdout.write("\x1b[0 q")
3786 sys.stdout.flush()
3682
3787
3683 def cleanup(self):
3788 def cleanup(self):
3684 self.restore_sys_module_state()
3789 self.restore_sys_module_state()
@@ -311,7 +311,7 b' class MagicsManager(Configurable):'
311
311
312 For example::
312 For example::
313
313
314 c.MagicsManger.lazy_magics = {
314 c.MagicsManager.lazy_magics = {
315 "my_magic": "slow.to.import",
315 "my_magic": "slow.to.import",
316 "my_other_magic": "also.slow",
316 "my_other_magic": "also.slow",
317 }
317 }
@@ -511,7 +511,7 b' class ExecutionMagics(Magics):'
511 """Run the named file inside IPython as a program.
511 """Run the named file inside IPython as a program.
512
512
513 Usage::
513 Usage::
514
514
515 %run [-n -i -e -G]
515 %run [-n -i -e -G]
516 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
516 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
517 ( -m mod | filename ) [args]
517 ( -m mod | filename ) [args]
@@ -552,7 +552,7 b' class ExecutionMagics(Magics):'
552 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
552 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
553 To completely disable these expansions, you can use -G flag.
553 To completely disable these expansions, you can use -G flag.
554
554
555 On Windows systems, the use of single quotes `'` when specifying
555 On Windows systems, the use of single quotes `'` when specifying
556 a file is not supported. Use double quotes `"`.
556 a file is not supported. Use double quotes `"`.
557
557
558 Options:
558 Options:
@@ -127,7 +127,7 b' class OSMagics(Magics):'
127 Aliases expand Python variables just like system calls using ! or !!
127 Aliases expand Python variables just like system calls using ! or !!
128 do: all expressions prefixed with '$' get expanded. For details of
128 do: all expressions prefixed with '$' get expanded. For details of
129 the semantic rules, see PEP-215:
129 the semantic rules, see PEP-215:
130 http://www.python.org/peps/pep-0215.html. This is the library used by
130 https://peps.python.org/pep-0215/. This is the library used by
131 IPython for variable expansion. If you want to access a true shell
131 IPython for variable expansion. If you want to access a true shell
132 variable, an extra $ is necessary to prevent its expansion by
132 variable, an extra $ is necessary to prevent its expansion by
133 IPython::
133 IPython::
@@ -58,8 +58,8 b' def script_args(f):'
58 '--no-raise-error', action="store_false", dest='raise_error',
58 '--no-raise-error', action="store_false", dest='raise_error',
59 help="""Whether you should raise an error message in addition to
59 help="""Whether you should raise an error message in addition to
60 a stream on stderr if you get a nonzero exit code.
60 a stream on stderr if you get a nonzero exit code.
61 """
61 """,
62 )
62 ),
63 ]
63 ]
64 for arg in args:
64 for arg in args:
65 f = arg(f)
65 f = arg(f)
@@ -518,12 +518,12 b' class Inspector(Colorable):'
518 """Return a mime bundle representation of the input text.
518 """Return a mime bundle representation of the input text.
519
519
520 - if `formatter` is None, the returned mime bundle has
520 - if `formatter` is None, the returned mime bundle has
521 a `text/plain` field, with the input text.
521 a ``text/plain`` field, with the input text.
522 a `text/html` field with a `<pre>` tag containing the input text.
522 a ``text/html`` field with a ``<pre>`` tag containing the input text.
523
523
524 - if `formatter` is not None, it must be a callable transforming the
524 - if ``formatter`` is not None, it must be a callable transforming the
525 input text into a mime bundle. Default values for `text/plain` and
525 input text into a mime bundle. Default values for ``text/plain`` and
526 `text/html` representations are the ones described above.
526 ``text/html`` representations are the ones described above.
527
527
528 Note:
528 Note:
529
529
@@ -16,7 +16,7 b''
16 # release. 'dev' as a _version_extra string means this is a development
16 # release. 'dev' as a _version_extra string means this is a development
17 # version
17 # version
18 _version_major = 8
18 _version_major = 8
19 _version_minor = 1
19 _version_minor = 4
20 _version_patch = 0
20 _version_patch = 0
21 _version_extra = ".dev"
21 _version_extra = ".dev"
22 # _version_extra = "rc1"
22 # _version_extra = "rc1"
@@ -43,11 +43,11 b' def test_alias_args_error():'
43
43
44 def test_alias_args_commented():
44 def test_alias_args_commented():
45 """Check that alias correctly ignores 'commented out' args"""
45 """Check that alias correctly ignores 'commented out' args"""
46 _ip.magic('alias commetarg echo this is %%s a commented out arg')
46 _ip.run_line_magic("alias", "commentarg echo this is %%s a commented out arg")
47
47
48 with capture_output() as cap:
48 with capture_output() as cap:
49 _ip.run_cell('commetarg')
49 _ip.run_cell("commentarg")
50
50
51 # strip() is for pytest compat; testing via iptest patch IPython shell
51 # strip() is for pytest compat; testing via iptest patch IPython shell
52 # in testing.globalipapp and replace the system call which messed up the
52 # in testing.globalipapp and replace the system call which messed up the
53 # \r\n
53 # \r\n
@@ -4,11 +4,11 b''
4 import os
4 import os
5 import tempfile
5 import tempfile
6
6
7 from tempfile import TemporaryDirectory
7 from traitlets import Unicode
8 from traitlets import Unicode
8
9
9 from IPython.core.application import BaseIPythonApplication
10 from IPython.core.application import BaseIPythonApplication
10 from IPython.testing import decorators as dec
11 from IPython.testing import decorators as dec
11 from IPython.utils.tempdir import TemporaryDirectory
12
12
13
13
14 @dec.onlyif_unicode_paths
14 @dec.onlyif_unicode_paths
@@ -1262,3 +1262,14 b' class TestCompleter(unittest.TestCase):'
1262 _, matches = ip.complete(None, "test.meth(")
1262 _, matches = ip.complete(None, "test.meth(")
1263 self.assertIn("meth_arg1=", matches)
1263 self.assertIn("meth_arg1=", matches)
1264 self.assertNotIn("meth2_arg1=", matches)
1264 self.assertNotIn("meth2_arg1=", matches)
1265
1266 def test_percent_symbol_restrict_to_magic_completions(self):
1267 ip = get_ipython()
1268 completer = ip.Completer
1269 text = "%a"
1270
1271 with provisionalcompleter():
1272 completer.use_jedi = True
1273 completions = completer.completions(text, len(text))
1274 for c in completions:
1275 self.assertEqual(c.text[0], "%")
@@ -14,8 +14,9 b' import tempfile'
14 import unittest
14 import unittest
15 from os.path import join
15 from os.path import join
16
16
17 from tempfile import TemporaryDirectory
18
17 from IPython.core.completerlib import magic_run_completer, module_completion, try_import
19 from IPython.core.completerlib import magic_run_completer, module_completion, try_import
18 from IPython.utils.tempdir import TemporaryDirectory
19 from IPython.testing.decorators import onlyif_unicode_paths
20 from IPython.testing.decorators import onlyif_unicode_paths
20
21
21
22
@@ -1,8 +1,9 b''
1 import os.path
1 import os.path
2
2
3 from tempfile import TemporaryDirectory
4
3 import IPython.testing.tools as tt
5 import IPython.testing.tools as tt
4 from IPython.utils.syspathcontext import prepended_to_syspath
6 from IPython.utils.syspathcontext import prepended_to_syspath
5 from IPython.utils.tempdir import TemporaryDirectory
6
7
7 ext1_content = """
8 ext1_content = """
8 def load_ipython_extension(ip):
9 def load_ipython_extension(ip):
@@ -56,36 +56,42 b' def test_handlers():'
56 ip.user_ns['autocallable'] = autocallable
56 ip.user_ns['autocallable'] = autocallable
57
57
58 # auto
58 # auto
59 ip.magic('autocall 0')
59 ip.run_line_magic("autocall", "0")
60 # Only explicit escapes or instances of IPyAutocallable should get
60 # Only explicit escapes or instances of IPyAutocallable should get
61 # expanded
61 # expanded
62 run([
62 run(
63 ('len "abc"', 'len "abc"'),
63 [
64 ('autocallable', 'autocallable()'),
64 ('len "abc"', 'len "abc"'),
65 # Don't add extra brackets (gh-1117)
65 ("autocallable", "autocallable()"),
66 ('autocallable()', 'autocallable()'),
66 # Don't add extra brackets (gh-1117)
67 ])
67 ("autocallable()", "autocallable()"),
68 ip.magic('autocall 1')
68 ]
69 run([
69 )
70 ('len "abc"', 'len("abc")'),
70 ip.run_line_magic("autocall", "1")
71 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
71 run(
72 # Autocall is turned off if first arg is [] and the object
72 [
73 # is both callable and indexable. Like so:
73 ('len "abc"', 'len("abc")'),
74 ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__...
74 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
75 ('call_idx [1]', 'call_idx [1]'), # call_idx *does*..
75 # Autocall is turned off if first arg is [] and the object
76 ('call_idx 1', 'call_idx(1)'),
76 # is both callable and indexable. Like so:
77 ('len', 'len'), # only at 2 does it auto-call on single args
77 ("len [1,2]", "len([1,2])"), # len doesn't support __getitem__...
78 ])
78 ("call_idx [1]", "call_idx [1]"), # call_idx *does*..
79 ip.magic('autocall 2')
79 ("call_idx 1", "call_idx(1)"),
80 run([
80 ("len", "len"), # only at 2 does it auto-call on single args
81 ('len "abc"', 'len("abc")'),
81 ]
82 ('len "abc";', 'len("abc");'),
82 )
83 ('len [1,2]', 'len([1,2])'),
83 ip.run_line_magic("autocall", "2")
84 ('call_idx [1]', 'call_idx [1]'),
84 run(
85 ('call_idx 1', 'call_idx(1)'),
85 [
86 # This is what's different:
86 ('len "abc"', 'len("abc")'),
87 ('len', 'len()'), # only at 2 does it auto-call on single args
87 ('len "abc";', 'len("abc");'),
88 ])
88 ("len [1,2]", "len([1,2])"),
89 ip.magic('autocall 1')
89 ("call_idx [1]", "call_idx [1]"),
90 ("call_idx 1", "call_idx(1)"),
91 # This is what's different:
92 ("len", "len()"), # only at 2 does it auto-call on single args
93 ]
94 )
95 ip.run_line_magic("autocall", "1")
90
96
91 assert failures == []
97 assert failures == []
@@ -7,17 +7,19 b''
7
7
8 # stdlib
8 # stdlib
9 import io
9 import io
10 from pathlib import Path
10 import sqlite3
11 import sys
11 import sys
12 import tempfile
12 import tempfile
13 from datetime import datetime
13 from datetime import datetime
14 import sqlite3
14 from pathlib import Path
15
15
16 from tempfile import TemporaryDirectory
16 # our own packages
17 # our own packages
17 from traitlets.config.loader import Config
18 from traitlets.config.loader import Config
18 from IPython.utils.tempdir import TemporaryDirectory
19
19 from IPython.core.history import HistoryManager, extract_hist_ranges
20 from IPython.core.history import HistoryManager, extract_hist_ranges
20
21
22
21 def test_proper_default_encoding():
23 def test_proper_default_encoding():
22 assert sys.getdefaultencoding() == "utf-8"
24 assert sys.getdefaultencoding() == "utf-8"
23
25
@@ -50,13 +52,13 b' def test_history():'
50
52
51 # Check whether specifying a range beyond the end of the current
53 # Check whether specifying a range beyond the end of the current
52 # session results in an error (gh-804)
54 # session results in an error (gh-804)
53 ip.magic('%hist 2-500')
55 ip.run_line_magic("hist", "2-500")
54
56
55 # Check that we can write non-ascii characters to a file
57 # Check that we can write non-ascii characters to a file
56 ip.magic("%%hist -f %s" % (tmp_path / "test1"))
58 ip.run_line_magic("hist", "-f %s" % (tmp_path / "test1"))
57 ip.magic("%%hist -pf %s" % (tmp_path / "test2"))
59 ip.run_line_magic("hist", "-pf %s" % (tmp_path / "test2"))
58 ip.magic("%%hist -nf %s" % (tmp_path / "test3"))
60 ip.run_line_magic("hist", "-nf %s" % (tmp_path / "test3"))
59 ip.magic("%%save %s 1-10" % (tmp_path / "test4"))
61 ip.run_line_magic("save", "%s 1-10" % (tmp_path / "test4"))
60
62
61 # New session
63 # New session
62 ip.history_manager.reset()
64 ip.history_manager.reset()
@@ -122,7 +124,7 b' def test_history():'
122
124
123 # Cross testing: check that magic %save can get previous session.
125 # Cross testing: check that magic %save can get previous session.
124 testfilename = (tmp_path / "test.py").resolve()
126 testfilename = (tmp_path / "test.py").resolve()
125 ip.magic("save " + str(testfilename) + " ~1/1-3")
127 ip.run_line_magic("save", str(testfilename) + " ~1/1-3")
126 with io.open(testfilename, encoding="utf-8") as testfile:
128 with io.open(testfilename, encoding="utf-8") as testfile:
127 assert testfile.read() == "# coding: utf-8\n" + "\n".join(hist) + "\n"
129 assert testfile.read() == "# coding: utf-8\n" + "\n".join(hist) + "\n"
128
130
@@ -59,108 +59,93 b' syntax = \\'
59 ('x=1', 'x=1'), # normal input is unmodified
59 ('x=1', 'x=1'), # normal input is unmodified
60 (' ',' '), # blank lines are kept intact
60 (' ',' '), # blank lines are kept intact
61 ("a, b = %foo", "a, b = get_ipython().run_line_magic('foo', '')"),
61 ("a, b = %foo", "a, b = get_ipython().run_line_magic('foo', '')"),
62 ],
62 ],
63
63 classic_prompt=[
64 classic_prompt =
64 (">>> x=1", "x=1"),
65 [('>>> x=1', 'x=1'),
65 ("x=1", "x=1"), # normal input is unmodified
66 ('x=1', 'x=1'), # normal input is unmodified
66 (" ", " "), # blank lines are kept intact
67 (' ', ' '), # blank lines are kept intact
67 ],
68 ],
68 ipy_prompt=[
69
69 ("In [1]: x=1", "x=1"),
70 ipy_prompt =
70 ("x=1", "x=1"), # normal input is unmodified
71 [('In [1]: x=1', 'x=1'),
71 (" ", " "), # blank lines are kept intact
72 ('x=1', 'x=1'), # normal input is unmodified
72 ],
73 (' ',' '), # blank lines are kept intact
73 # Tests for the escape transformer to leave normal code alone
74 ],
74 escaped_noesc=[
75
75 (" ", " "),
76 # Tests for the escape transformer to leave normal code alone
76 ("x=1", "x=1"),
77 escaped_noesc =
77 ],
78 [ (' ', ' '),
78 # System calls
79 ('x=1', 'x=1'),
79 escaped_shell=[
80 ],
80 ("!ls", "get_ipython().system('ls')"),
81
81 # Double-escape shell, this means to capture the output of the
82 # System calls
82 # subprocess and return it
83 escaped_shell =
83 ("!!ls", "get_ipython().getoutput('ls')"),
84 [ ('!ls', "get_ipython().system('ls')"),
84 ],
85 # Double-escape shell, this means to capture the output of the
85 # Help/object info
86 # subprocess and return it
86 escaped_help=[
87 ('!!ls', "get_ipython().getoutput('ls')"),
87 ("?", "get_ipython().show_usage()"),
88 ],
88 ("?x1", "get_ipython().run_line_magic('pinfo', 'x1')"),
89
89 ("??x2", "get_ipython().run_line_magic('pinfo2', 'x2')"),
90 # Help/object info
90 ("?a.*s", "get_ipython().run_line_magic('psearch', 'a.*s')"),
91 escaped_help =
91 ("?%hist1", "get_ipython().run_line_magic('pinfo', '%hist1')"),
92 [ ('?', 'get_ipython().show_usage()'),
92 ("?%%hist2", "get_ipython().run_line_magic('pinfo', '%%hist2')"),
93 ('?x1', "get_ipython().run_line_magic('pinfo', 'x1')"),
93 ("?abc = qwe", "get_ipython().run_line_magic('pinfo', 'abc')"),
94 ('??x2', "get_ipython().run_line_magic('pinfo2', 'x2')"),
94 ],
95 ('?a.*s', "get_ipython().run_line_magic('psearch', 'a.*s')"),
95 end_help=[
96 ('?%hist1', "get_ipython().run_line_magic('pinfo', '%hist1')"),
96 ("x3?", "get_ipython().run_line_magic('pinfo', 'x3')"),
97 ('?%%hist2', "get_ipython().run_line_magic('pinfo', '%%hist2')"),
97 ("x4??", "get_ipython().run_line_magic('pinfo2', 'x4')"),
98 ('?abc = qwe', "get_ipython().run_line_magic('pinfo', 'abc')"),
98 ("%hist1?", "get_ipython().run_line_magic('pinfo', '%hist1')"),
99 ],
99 ("%hist2??", "get_ipython().run_line_magic('pinfo2', '%hist2')"),
100
100 ("%%hist3?", "get_ipython().run_line_magic('pinfo', '%%hist3')"),
101 end_help =
101 ("%%hist4??", "get_ipython().run_line_magic('pinfo2', '%%hist4')"),
102 [ ('x3?', "get_ipython().run_line_magic('pinfo', 'x3')"),
102 ("π.foo?", "get_ipython().run_line_magic('pinfo', 'π.foo')"),
103 ('x4??', "get_ipython().run_line_magic('pinfo2', 'x4')"),
103 ("f*?", "get_ipython().run_line_magic('psearch', 'f*')"),
104 ('%hist1?', "get_ipython().run_line_magic('pinfo', '%hist1')"),
104 ("ax.*aspe*?", "get_ipython().run_line_magic('psearch', 'ax.*aspe*')"),
105 ('%hist2??', "get_ipython().run_line_magic('pinfo2', '%hist2')"),
105 ("a = abc?", "get_ipython().run_line_magic('pinfo', 'abc')"),
106 ('%%hist3?', "get_ipython().run_line_magic('pinfo', '%%hist3')"),
106 ("a = abc.qe??", "get_ipython().run_line_magic('pinfo2', 'abc.qe')"),
107 ('%%hist4??', "get_ipython().run_line_magic('pinfo2', '%%hist4')"),
107 ("a = *.items?", "get_ipython().run_line_magic('psearch', '*.items')"),
108 ('π.foo?', "get_ipython().run_line_magic('pinfo', 'π.foo')"),
108 ("plot(a?", "get_ipython().run_line_magic('pinfo', 'a')"),
109 ('f*?', "get_ipython().run_line_magic('psearch', 'f*')"),
109 ("a*2 #comment?", "a*2 #comment?"),
110 ('ax.*aspe*?', "get_ipython().run_line_magic('psearch', 'ax.*aspe*')"),
110 ],
111 ('a = abc?', "get_ipython().set_next_input('a = abc');"
111 # Explicit magic calls
112 "get_ipython().run_line_magic('pinfo', 'abc')"),
112 escaped_magic=[
113 ('a = abc.qe??', "get_ipython().set_next_input('a = abc.qe');"
113 ("%cd", "get_ipython().run_line_magic('cd', '')"),
114 "get_ipython().run_line_magic('pinfo2', 'abc.qe')"),
114 ("%cd /home", "get_ipython().run_line_magic('cd', '/home')"),
115 ('a = *.items?', "get_ipython().set_next_input('a = *.items');"
115 # Backslashes need to be escaped.
116 "get_ipython().run_line_magic('psearch', '*.items')"),
116 ("%cd C:\\User", "get_ipython().run_line_magic('cd', 'C:\\\\User')"),
117 ('plot(a?', "get_ipython().set_next_input('plot(a');"
117 (" %magic", " get_ipython().run_line_magic('magic', '')"),
118 "get_ipython().run_line_magic('pinfo', 'a')"),
118 ],
119 ('a*2 #comment?', 'a*2 #comment?'),
119 # Quoting with separate arguments
120 ],
120 escaped_quote=[
121
121 (",f", 'f("")'),
122 # Explicit magic calls
122 (",f x", 'f("x")'),
123 escaped_magic =
123 (" ,f y", ' f("y")'),
124 [ ('%cd', "get_ipython().run_line_magic('cd', '')"),
124 (",f a b", 'f("a", "b")'),
125 ('%cd /home', "get_ipython().run_line_magic('cd', '/home')"),
125 ],
126 # Backslashes need to be escaped.
126 # Quoting with single argument
127 ('%cd C:\\User', "get_ipython().run_line_magic('cd', 'C:\\\\User')"),
127 escaped_quote2=[
128 (' %magic', " get_ipython().run_line_magic('magic', '')"),
128 (";f", 'f("")'),
129 ],
129 (";f x", 'f("x")'),
130
130 (" ;f y", ' f("y")'),
131 # Quoting with separate arguments
131 (";f a b", 'f("a b")'),
132 escaped_quote =
132 ],
133 [ (',f', 'f("")'),
133 # Simply apply parens
134 (',f x', 'f("x")'),
134 escaped_paren=[
135 (' ,f y', ' f("y")'),
135 ("/f", "f()"),
136 (',f a b', 'f("a", "b")'),
136 ("/f x", "f(x)"),
137 ],
137 (" /f y", " f(y)"),
138
138 ("/f a b", "f(a, b)"),
139 # Quoting with single argument
139 ],
140 escaped_quote2 =
140 # Check that we transform prompts before other transforms
141 [ (';f', 'f("")'),
141 mixed=[
142 (';f x', 'f("x")'),
142 ("In [1]: %lsmagic", "get_ipython().run_line_magic('lsmagic', '')"),
143 (' ;f y', ' f("y")'),
143 (">>> %lsmagic", "get_ipython().run_line_magic('lsmagic', '')"),
144 (';f a b', 'f("a b")'),
144 ("In [2]: !ls", "get_ipython().system('ls')"),
145 ],
145 ("In [3]: abs?", "get_ipython().run_line_magic('pinfo', 'abs')"),
146
146 ("In [4]: b = %who", "b = get_ipython().run_line_magic('who', '')"),
147 # Simply apply parens
147 ],
148 escaped_paren =
148 )
149 [ ('/f', 'f()'),
150 ('/f x', 'f(x)'),
151 (' /f y', ' f(y)'),
152 ('/f a b', 'f(a, b)'),
153 ],
154
155 # Check that we transform prompts before other transforms
156 mixed =
157 [ ('In [1]: %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
158 ('>>> %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
159 ('In [2]: !ls', "get_ipython().system('ls')"),
160 ('In [3]: abs?', "get_ipython().run_line_magic('pinfo', 'abs')"),
161 ('In [4]: b = %who', "b = get_ipython().run_line_magic('who', '')"),
162 ],
163 )
164
149
165 # multiline syntax examples. Each of these should be a list of lists, with
150 # multiline syntax examples. Each of these should be a list of lists, with
166 # each entry itself having pairs of raw/transformed input. The union (with
151 # each entry itself having pairs of raw/transformed input. The union (with
@@ -14,45 +14,65 b' import pytest'
14 from IPython.core import inputtransformer2 as ipt2
14 from IPython.core import inputtransformer2 as ipt2
15 from IPython.core.inputtransformer2 import _find_assign_op, make_tokens_by_line
15 from IPython.core.inputtransformer2 import _find_assign_op, make_tokens_by_line
16
16
17 MULTILINE_MAGIC = ("""\
17 MULTILINE_MAGIC = (
18 """\
18 a = f()
19 a = f()
19 %foo \\
20 %foo \\
20 bar
21 bar
21 g()
22 g()
22 """.splitlines(keepends=True), (2, 0), """\
23 """.splitlines(
24 keepends=True
25 ),
26 (2, 0),
27 """\
23 a = f()
28 a = f()
24 get_ipython().run_line_magic('foo', ' bar')
29 get_ipython().run_line_magic('foo', ' bar')
25 g()
30 g()
26 """.splitlines(keepends=True))
31 """.splitlines(
32 keepends=True
33 ),
34 )
27
35
28 INDENTED_MAGIC = ("""\
36 INDENTED_MAGIC = (
37 """\
29 for a in range(5):
38 for a in range(5):
30 %ls
39 %ls
31 """.splitlines(keepends=True), (2, 4), """\
40 """.splitlines(
41 keepends=True
42 ),
43 (2, 4),
44 """\
32 for a in range(5):
45 for a in range(5):
33 get_ipython().run_line_magic('ls', '')
46 get_ipython().run_line_magic('ls', '')
34 """.splitlines(keepends=True))
47 """.splitlines(
48 keepends=True
49 ),
50 )
35
51
36 CRLF_MAGIC = ([
52 CRLF_MAGIC = (
37 "a = f()\n",
53 ["a = f()\n", "%ls\r\n", "g()\n"],
38 "%ls\r\n",
54 (2, 0),
39 "g()\n"
55 ["a = f()\n", "get_ipython().run_line_magic('ls', '')\n", "g()\n"],
40 ], (2, 0), [
56 )
41 "a = f()\n",
57
42 "get_ipython().run_line_magic('ls', '')\n",
58 MULTILINE_MAGIC_ASSIGN = (
43 "g()\n"
59 """\
44 ])
45
46 MULTILINE_MAGIC_ASSIGN = ("""\
47 a = f()
60 a = f()
48 b = %foo \\
61 b = %foo \\
49 bar
62 bar
50 g()
63 g()
51 """.splitlines(keepends=True), (2, 4), """\
64 """.splitlines(
65 keepends=True
66 ),
67 (2, 4),
68 """\
52 a = f()
69 a = f()
53 b = get_ipython().run_line_magic('foo', ' bar')
70 b = get_ipython().run_line_magic('foo', ' bar')
54 g()
71 g()
55 """.splitlines(keepends=True))
72 """.splitlines(
73 keepends=True
74 ),
75 )
56
76
57 MULTILINE_SYSTEM_ASSIGN = ("""\
77 MULTILINE_SYSTEM_ASSIGN = ("""\
58 a = f()
78 a = f()
@@ -67,73 +87,76 b' g()'
67
87
68 #####
88 #####
69
89
70 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
90 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = (
91 """\
71 def test():
92 def test():
72 for i in range(1):
93 for i in range(1):
73 print(i)
94 print(i)
74 res =! ls
95 res =! ls
75 """.splitlines(keepends=True), (4, 7), '''\
96 """.splitlines(
97 keepends=True
98 ),
99 (4, 7),
100 """\
76 def test():
101 def test():
77 for i in range(1):
102 for i in range(1):
78 print(i)
103 print(i)
79 res =get_ipython().getoutput(\' ls\')
104 res =get_ipython().getoutput(\' ls\')
80 '''.splitlines(keepends=True))
105 """.splitlines(
106 keepends=True
107 ),
108 )
81
109
82 ######
110 ######
83
111
84 AUTOCALL_QUOTE = (
112 AUTOCALL_QUOTE = ([",f 1 2 3\n"], (1, 0), ['f("1", "2", "3")\n'])
85 [",f 1 2 3\n"], (1, 0),
86 ['f("1", "2", "3")\n']
87 )
88
113
89 AUTOCALL_QUOTE2 = (
114 AUTOCALL_QUOTE2 = ([";f 1 2 3\n"], (1, 0), ['f("1 2 3")\n'])
90 [";f 1 2 3\n"], (1, 0),
91 ['f("1 2 3")\n']
92 )
93
115
94 AUTOCALL_PAREN = (
116 AUTOCALL_PAREN = (["/f 1 2 3\n"], (1, 0), ["f(1, 2, 3)\n"])
95 ["/f 1 2 3\n"], (1, 0),
96 ['f(1, 2, 3)\n']
97 )
98
117
99 SIMPLE_HELP = (
118 SIMPLE_HELP = (["foo?\n"], (1, 0), ["get_ipython().run_line_magic('pinfo', 'foo')\n"])
100 ["foo?\n"], (1, 0),
101 ["get_ipython().run_line_magic('pinfo', 'foo')\n"]
102 )
103
119
104 DETAILED_HELP = (
120 DETAILED_HELP = (
105 ["foo??\n"], (1, 0),
121 ["foo??\n"],
106 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
122 (1, 0),
123 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"],
107 )
124 )
108
125
109 MAGIC_HELP = (
126 MAGIC_HELP = (["%foo?\n"], (1, 0), ["get_ipython().run_line_magic('pinfo', '%foo')\n"])
110 ["%foo?\n"], (1, 0),
111 ["get_ipython().run_line_magic('pinfo', '%foo')\n"]
112 )
113
127
114 HELP_IN_EXPR = (
128 HELP_IN_EXPR = (
115 ["a = b + c?\n"], (1, 0),
129 ["a = b + c?\n"],
116 ["get_ipython().set_next_input('a = b + c');"
130 (1, 0),
117 "get_ipython().run_line_magic('pinfo', 'c')\n"]
131 ["get_ipython().run_line_magic('pinfo', 'c')\n"],
118 )
132 )
119
133
120 HELP_CONTINUED_LINE = ("""\
134 HELP_CONTINUED_LINE = (
135 """\
121 a = \\
136 a = \\
122 zip?
137 zip?
123 """.splitlines(keepends=True), (1, 0),
138 """.splitlines(
124 [r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
139 keepends=True
140 ),
141 (1, 0),
142 [r"get_ipython().run_line_magic('pinfo', 'zip')" + "\n"],
125 )
143 )
126
144
127 HELP_MULTILINE = ("""\
145 HELP_MULTILINE = (
146 """\
128 (a,
147 (a,
129 b) = zip?
148 b) = zip?
130 """.splitlines(keepends=True), (1, 0),
149 """.splitlines(
131 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
150 keepends=True
151 ),
152 (1, 0),
153 [r"get_ipython().run_line_magic('pinfo', 'zip')" + "\n"],
132 )
154 )
133
155
134 HELP_UNICODE = (
156 HELP_UNICODE = (
135 ["π.foo?\n"], (1, 0),
157 ["π.foo?\n"],
136 ["get_ipython().run_line_magic('pinfo', 'π.foo')\n"]
158 (1, 0),
159 ["get_ipython().run_line_magic('pinfo', 'π.foo')\n"],
137 )
160 )
138
161
139
162
@@ -149,6 +172,7 b' def test_check_make_token_by_line_never_ends_empty():'
149 Check that not sequence of single or double characters ends up leading to en empty list of tokens
172 Check that not sequence of single or double characters ends up leading to en empty list of tokens
150 """
173 """
151 from string import printable
174 from string import printable
175
152 for c in printable:
176 for c in printable:
153 assert make_tokens_by_line(c)[-1] != []
177 assert make_tokens_by_line(c)[-1] != []
154 for k in printable:
178 for k in printable:
@@ -156,7 +180,7 b' def test_check_make_token_by_line_never_ends_empty():'
156
180
157
181
158 def check_find(transformer, case, match=True):
182 def check_find(transformer, case, match=True):
159 sample, expected_start, _ = case
183 sample, expected_start, _ = case
160 tbl = make_tokens_by_line(sample)
184 tbl = make_tokens_by_line(sample)
161 res = transformer.find(tbl)
185 res = transformer.find(tbl)
162 if match:
186 if match:
@@ -166,25 +190,30 b' def check_find(transformer, case, match=True):'
166 else:
190 else:
167 assert res is None
191 assert res is None
168
192
193
169 def check_transform(transformer_cls, case):
194 def check_transform(transformer_cls, case):
170 lines, start, expected = case
195 lines, start, expected = case
171 transformer = transformer_cls(start)
196 transformer = transformer_cls(start)
172 assert transformer.transform(lines) == expected
197 assert transformer.transform(lines) == expected
173
198
199
174 def test_continued_line():
200 def test_continued_line():
175 lines = MULTILINE_MAGIC_ASSIGN[0]
201 lines = MULTILINE_MAGIC_ASSIGN[0]
176 assert ipt2.find_end_of_continued_line(lines, 1) == 2
202 assert ipt2.find_end_of_continued_line(lines, 1) == 2
177
203
178 assert ipt2.assemble_continued_line(lines, (1, 5), 2) == "foo bar"
204 assert ipt2.assemble_continued_line(lines, (1, 5), 2) == "foo bar"
179
205
206
180 def test_find_assign_magic():
207 def test_find_assign_magic():
181 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
208 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
182 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
209 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
183 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
210 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
184
211
212
185 def test_transform_assign_magic():
213 def test_transform_assign_magic():
186 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
214 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
187
215
216
188 def test_find_assign_system():
217 def test_find_assign_system():
189 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
218 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
190 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
219 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
@@ -192,30 +221,36 b' def test_find_assign_system():'
192 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
221 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
193 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
222 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
194
223
224
195 def test_transform_assign_system():
225 def test_transform_assign_system():
196 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
226 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
197 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
227 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
198
228
229
199 def test_find_magic_escape():
230 def test_find_magic_escape():
200 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
231 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
201 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
232 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
202 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
233 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
203
234
235
204 def test_transform_magic_escape():
236 def test_transform_magic_escape():
205 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
237 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
206 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
238 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
207 check_transform(ipt2.EscapedCommand, CRLF_MAGIC)
239 check_transform(ipt2.EscapedCommand, CRLF_MAGIC)
208
240
241
209 def test_find_autocalls():
242 def test_find_autocalls():
210 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
243 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
211 print("Testing %r" % case[0])
244 print("Testing %r" % case[0])
212 check_find(ipt2.EscapedCommand, case)
245 check_find(ipt2.EscapedCommand, case)
213
246
247
214 def test_transform_autocall():
248 def test_transform_autocall():
215 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
249 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
216 print("Testing %r" % case[0])
250 print("Testing %r" % case[0])
217 check_transform(ipt2.EscapedCommand, case)
251 check_transform(ipt2.EscapedCommand, case)
218
252
253
219 def test_find_help():
254 def test_find_help():
220 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
255 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
221 check_find(ipt2.HelpEnd, case)
256 check_find(ipt2.HelpEnd, case)
@@ -233,6 +268,7 b' def test_find_help():'
233 # Nor in a string
268 # Nor in a string
234 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
269 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
235
270
271
236 def test_transform_help():
272 def test_transform_help():
237 tf = ipt2.HelpEnd((1, 0), (1, 9))
273 tf = ipt2.HelpEnd((1, 0), (1, 9))
238 assert tf.transform(HELP_IN_EXPR[0]) == HELP_IN_EXPR[2]
274 assert tf.transform(HELP_IN_EXPR[0]) == HELP_IN_EXPR[2]
@@ -246,10 +282,12 b' def test_transform_help():'
246 tf = ipt2.HelpEnd((1, 0), (1, 0))
282 tf = ipt2.HelpEnd((1, 0), (1, 0))
247 assert tf.transform(HELP_UNICODE[0]) == HELP_UNICODE[2]
283 assert tf.transform(HELP_UNICODE[0]) == HELP_UNICODE[2]
248
284
285
249 def test_find_assign_op_dedent():
286 def test_find_assign_op_dedent():
250 """
287 """
251 be careful that empty token like dedent are not counted as parens
288 be careful that empty token like dedent are not counted as parens
252 """
289 """
290
253 class Tk:
291 class Tk:
254 def __init__(self, s):
292 def __init__(self, s):
255 self.string = s
293 self.string = s
@@ -302,21 +340,23 b' def test_check_complete_param(code, expected, number):'
302 def test_check_complete():
340 def test_check_complete():
303 cc = ipt2.TransformerManager().check_complete
341 cc = ipt2.TransformerManager().check_complete
304
342
305 example = dedent("""
343 example = dedent(
344 """
306 if True:
345 if True:
307 a=1""" )
346 a=1"""
347 )
308
348
309 assert cc(example) == ("incomplete", 4)
349 assert cc(example) == ("incomplete", 4)
310 assert cc(example + "\n") == ("complete", None)
350 assert cc(example + "\n") == ("complete", None)
311 assert cc(example + "\n ") == ("complete", None)
351 assert cc(example + "\n ") == ("complete", None)
312
352
313 # no need to loop on all the letters/numbers.
353 # no need to loop on all the letters/numbers.
314 short = '12abAB'+string.printable[62:]
354 short = "12abAB" + string.printable[62:]
315 for c in short:
355 for c in short:
316 # test does not raise:
356 # test does not raise:
317 cc(c)
357 cc(c)
318 for k in short:
358 for k in short:
319 cc(c+k)
359 cc(c + k)
320
360
321 assert cc("def f():\n x=0\n \\\n ") == ("incomplete", 2)
361 assert cc("def f():\n x=0\n \\\n ") == ("incomplete", 2)
322
362
@@ -371,10 +411,9 b' def test_null_cleanup_transformer():'
371 assert manager.transform_cell("") == ""
411 assert manager.transform_cell("") == ""
372
412
373
413
374
375
376 def test_side_effects_I():
414 def test_side_effects_I():
377 count = 0
415 count = 0
416
378 def counter(lines):
417 def counter(lines):
379 nonlocal count
418 nonlocal count
380 count += 1
419 count += 1
@@ -384,14 +423,13 b' def test_side_effects_I():'
384
423
385 manager = ipt2.TransformerManager()
424 manager = ipt2.TransformerManager()
386 manager.cleanup_transforms.insert(0, counter)
425 manager.cleanup_transforms.insert(0, counter)
387 assert manager.check_complete("a=1\n") == ('complete', None)
426 assert manager.check_complete("a=1\n") == ("complete", None)
388 assert count == 0
427 assert count == 0
389
428
390
429
391
392
393 def test_side_effects_II():
430 def test_side_effects_II():
394 count = 0
431 count = 0
432
395 def counter(lines):
433 def counter(lines):
396 nonlocal count
434 nonlocal count
397 count += 1
435 count += 1
@@ -401,5 +439,5 b' def test_side_effects_II():'
401
439
402 manager = ipt2.TransformerManager()
440 manager = ipt2.TransformerManager()
403 manager.line_transforms.insert(0, counter)
441 manager.line_transforms.insert(0, counter)
404 assert manager.check_complete("b=1\n") == ('complete', None)
442 assert manager.check_complete("b=1\n") == ("complete", None)
405 assert count == 0
443 assert count == 0
@@ -380,7 +380,8 b' class InteractiveShellTestCase(unittest.TestCase):'
380 class A(object):
380 class A(object):
381 @property
381 @property
382 def foo(self):
382 def foo(self):
383 raise NotImplementedError()
383 raise NotImplementedError() # pragma: no cover
384
384 a = A()
385 a = A()
385
386
386 found = ip._ofind('a.foo', [('locals', locals())])
387 found = ip._ofind('a.foo', [('locals', locals())])
@@ -392,7 +393,7 b' class InteractiveShellTestCase(unittest.TestCase):'
392 class A(object):
393 class A(object):
393 @property
394 @property
394 def foo(self):
395 def foo(self):
395 raise NotImplementedError()
396 raise NotImplementedError() # pragma: no cover
396
397
397 a = A()
398 a = A()
398 a.a = A()
399 a.a = A()
@@ -546,7 +547,7 b' class TestSafeExecfileNonAsciiPath(unittest.TestCase):'
546 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
547 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
547 os.mkdir(self.TESTDIR)
548 os.mkdir(self.TESTDIR)
548 with open(
549 with open(
549 join(self.TESTDIR, u"åäötestscript.py"), "w", encoding="utf-8"
550 join(self.TESTDIR, "åäötestscript.py"), "w", encoding="utf-8"
550 ) as sfile:
551 ) as sfile:
551 sfile.write("pass\n")
552 sfile.write("pass\n")
552 self.oldpath = os.getcwd()
553 self.oldpath = os.getcwd()
@@ -585,9 +586,9 b' class ExitCodeChecks(tt.TempFileMixin):'
585 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
586 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
586
587
587 @onlyif_cmds_exist("csh")
588 @onlyif_cmds_exist("csh")
588 def test_exit_code_signal_csh(self):
589 def test_exit_code_signal_csh(self): # pragma: no cover
589 SHELL = os.environ.get('SHELL', None)
590 SHELL = os.environ.get("SHELL", None)
590 os.environ['SHELL'] = find_cmd("csh")
591 os.environ["SHELL"] = find_cmd("csh")
591 try:
592 try:
592 self.test_exit_code_signal()
593 self.test_exit_code_signal()
593 finally:
594 finally:
@@ -615,7 +616,7 b' class TestSystemRaw(ExitCodeChecks):'
615 def test_control_c(self, *mocks):
616 def test_control_c(self, *mocks):
616 try:
617 try:
617 self.system("sleep 1 # wont happen")
618 self.system("sleep 1 # wont happen")
618 except KeyboardInterrupt:
619 except KeyboardInterrupt: # pragma: no cove
619 self.fail(
620 self.fail(
620 "system call should intercept "
621 "system call should intercept "
621 "keyboard interrupt from subprocess.call"
622 "keyboard interrupt from subprocess.call"
@@ -623,7 +624,7 b' class TestSystemRaw(ExitCodeChecks):'
623 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
624 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
624
625
625 def test_magic_warnings(self):
626 def test_magic_warnings(self):
626 for magic_cmd in ("ls", "pip", "conda", "cd"):
627 for magic_cmd in ("pip", "conda", "cd"):
627 with self.assertWarnsRegex(Warning, "You executed the system command"):
628 with self.assertWarnsRegex(Warning, "You executed the system command"):
628 ip.system_raw(magic_cmd)
629 ip.system_raw(magic_cmd)
629
630
@@ -679,16 +680,20 b' class TestAstTransform(unittest.TestCase):'
679
680
680 def tearDown(self):
681 def tearDown(self):
681 ip.ast_transformers.remove(self.negator)
682 ip.ast_transformers.remove(self.negator)
682
683
684 def test_non_int_const(self):
685 with tt.AssertPrints("hello"):
686 ip.run_cell('print("hello")')
687
683 def test_run_cell(self):
688 def test_run_cell(self):
684 with tt.AssertPrints('-34'):
689 with tt.AssertPrints("-34"):
685 ip.run_cell('print (12 + 22)')
690 ip.run_cell("print(12 + 22)")
686
691
687 # A named reference to a number shouldn't be transformed.
692 # A named reference to a number shouldn't be transformed.
688 ip.user_ns['n'] = 55
693 ip.user_ns["n"] = 55
689 with tt.AssertNotPrints('-55'):
694 with tt.AssertNotPrints("-55"):
690 ip.run_cell('print (n)')
695 ip.run_cell("print(n)")
691
696
692 def test_timeit(self):
697 def test_timeit(self):
693 called = set()
698 called = set()
694 def f(x):
699 def f(x):
@@ -796,7 +801,11 b' class TestAstTransform2(unittest.TestCase):'
796 # This shouldn't throw an error
801 # This shouldn't throw an error
797 ip.run_cell("o = 2.0")
802 ip.run_cell("o = 2.0")
798 self.assertEqual(ip.user_ns['o'], 2.0)
803 self.assertEqual(ip.user_ns['o'], 2.0)
799
804
805 def test_run_cell_non_int(self):
806 ip.run_cell("n = 'a'")
807 assert self.calls == []
808
800 def test_timeit(self):
809 def test_timeit(self):
801 called = set()
810 called = set()
802 def f(x):
811 def f(x):
@@ -815,14 +824,9 b' class TestAstTransform2(unittest.TestCase):'
815 class ErrorTransformer(ast.NodeTransformer):
824 class ErrorTransformer(ast.NodeTransformer):
816 """Throws an error when it sees a number."""
825 """Throws an error when it sees a number."""
817
826
818 # for Python 3.7 and earlier
819 def visit_Num(self, node):
820 raise ValueError("test")
821
822 # for Python 3.8+
823 def visit_Constant(self, node):
827 def visit_Constant(self, node):
824 if isinstance(node.value, int):
828 if isinstance(node.value, int):
825 return self.visit_Num(node)
829 raise ValueError("test")
826 return node
830 return node
827
831
828
832
@@ -845,10 +849,6 b' class StringRejector(ast.NodeTransformer):'
845 not be executed by throwing an InputRejected.
849 not be executed by throwing an InputRejected.
846 """
850 """
847
851
848 #for python 3.7 and earlier
849 def visit_Str(self, node):
850 raise InputRejected("test")
851
852 # 3.8 only
852 # 3.8 only
853 def visit_Constant(self, node):
853 def visit_Constant(self, node):
854 if isinstance(node.value, str):
854 if isinstance(node.value, str):
@@ -236,7 +236,8 b' def test_run_cell():'
236 if 4:
236 if 4:
237 print "bar"
237 print "bar"
238
238
239 """)
239 """
240 )
240 # Simply verifies that this kind of input is run
241 # Simply verifies that this kind of input is run
241 ip.run_cell(complex)
242 ip.run_cell(complex)
242
243
@@ -2,9 +2,10 b''
2 """Test IPython.core.logger"""
2 """Test IPython.core.logger"""
3
3
4 import os.path
4 import os.path
5
5 import pytest
6 import pytest
7 from tempfile import TemporaryDirectory
6
8
7 from IPython.utils.tempdir import TemporaryDirectory
8
9
9 def test_logstart_inaccessible_file():
10 def test_logstart_inaccessible_file():
10 with pytest.raises(IOError):
11 with pytest.raises(IOError):
@@ -448,7 +448,9 b' def test_multiline_time():'
448 ip = get_ipython()
448 ip = get_ipython()
449 ip.user_ns.pop('run', None)
449 ip.user_ns.pop('run', None)
450
450
451 ip.run_cell(dedent("""\
451 ip.run_cell(
452 dedent(
453 """\
452 %%time
454 %%time
453 a = "ho"
455 a = "ho"
454 b = "hey"
456 b = "hey"
@@ -122,7 +122,8 b' class PasteTestCase(TestCase):'
122 ip.user_ns.pop("x")
122 ip.user_ns.pop("x")
123
123
124 def test_paste_py_multi(self):
124 def test_paste_py_multi(self):
125 self.paste("""
125 self.paste(
126 """
126 >>> x = [1,2,3]
127 >>> x = [1,2,3]
127 >>> y = []
128 >>> y = []
128 >>> for i in x:
129 >>> for i in x:
@@ -145,7 +146,8 b' class PasteTestCase(TestCase):'
145
146
146 def test_paste_email(self):
147 def test_paste_email(self):
147 "Test pasting of email-quoted contents"
148 "Test pasting of email-quoted contents"
148 self.paste("""\
149 self.paste(
150 """\
149 >> def foo(x):
151 >> def foo(x):
150 >> return x + 1
152 >> return x + 1
151 >> xx = foo(1.1)"""
153 >> xx = foo(1.1)"""
@@ -154,7 +156,8 b' class PasteTestCase(TestCase):'
154
156
155 def test_paste_email2(self):
157 def test_paste_email2(self):
156 "Email again; some programs add a space also at each quoting level"
158 "Email again; some programs add a space also at each quoting level"
157 self.paste("""\
159 self.paste(
160 """\
158 > > def foo(x):
161 > > def foo(x):
159 > > return x + 1
162 > > return x + 1
160 > > yy = foo(2.1) """
163 > > yy = foo(2.1) """
@@ -163,7 +166,8 b' class PasteTestCase(TestCase):'
163
166
164 def test_paste_email_py(self):
167 def test_paste_email_py(self):
165 "Email quoting of interactive input"
168 "Email quoting of interactive input"
166 self.paste("""\
169 self.paste(
170 """\
167 >> >>> def f(x):
171 >> >>> def f(x):
168 >> ... return x+1
172 >> ... return x+1
169 >> ...
173 >> ...
@@ -6,11 +6,11 b' import tempfile'
6 import warnings
6 import warnings
7 from unittest.mock import patch
7 from unittest.mock import patch
8
8
9 from testpath import modified_env, assert_isdir, assert_isfile
9 from tempfile import TemporaryDirectory
10 from testpath import assert_isdir, assert_isfile, modified_env
10
11
11 from IPython import paths
12 from IPython import paths
12 from IPython.testing.decorators import skip_win32
13 from IPython.testing.decorators import skip_win32
13 from IPython.utils.tempdir import TemporaryDirectory
14
14
15 TMP_TEST_DIR = os.path.realpath(tempfile.mkdtemp())
15 TMP_TEST_DIR = os.path.realpath(tempfile.mkdtemp())
16 HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
16 HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
@@ -23,17 +23,16 b' Authors'
23 import shutil
23 import shutil
24 import sys
24 import sys
25 import tempfile
25 import tempfile
26
27 from pathlib import Path
26 from pathlib import Path
28 from unittest import TestCase
27 from unittest import TestCase
29
28
30 from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
29 from tempfile import TemporaryDirectory
31 from IPython.core.profiledir import ProfileDir
32
30
31 from IPython.core.profileapp import list_bundled_profiles, list_profiles_in
32 from IPython.core.profiledir import ProfileDir
33 from IPython.testing import decorators as dec
33 from IPython.testing import decorators as dec
34 from IPython.testing import tools as tt
34 from IPython.testing import tools as tt
35 from IPython.utils.process import getoutput
35 from IPython.utils.process import getoutput
36 from IPython.utils.tempdir import TemporaryDirectory
37
36
38 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
39 # Globals
38 # Globals
@@ -109,7 +108,7 b' def test_list_profiles_in():'
109 for name in ("profile_foo", "profile_hello", "not_a_profile"):
108 for name in ("profile_foo", "profile_hello", "not_a_profile"):
110 Path(td / name).mkdir(parents=True)
109 Path(td / name).mkdir(parents=True)
111 if dec.unicode_paths:
110 if dec.unicode_paths:
112 Path(td / u"profile_ünicode").mkdir(parents=True)
111 Path(td / "profile_ünicode").mkdir(parents=True)
113
112
114 with open(td / "profile_file", "w", encoding="utf-8") as f:
113 with open(td / "profile_file", "w", encoding="utf-8") as f:
115 f.write("I am not a profile directory")
114 f.write("I am not a profile directory")
@@ -19,21 +19,22 b' as otherwise it may influence later tests.'
19 import functools
19 import functools
20 import os
20 import os
21 import platform
21 import platform
22 from os.path import join as pjoin
23 import random
22 import random
24 import string
23 import string
25 import sys
24 import sys
26 import textwrap
25 import textwrap
27 import unittest
26 import unittest
27 from os.path import join as pjoin
28 from unittest.mock import patch
28 from unittest.mock import patch
29
29
30 import pytest
30 import pytest
31 from tempfile import TemporaryDirectory
31
32
33 from IPython.core import debugger
32 from IPython.testing import decorators as dec
34 from IPython.testing import decorators as dec
33 from IPython.testing import tools as tt
35 from IPython.testing import tools as tt
34 from IPython.utils.io import capture_output
36 from IPython.utils.io import capture_output
35 from IPython.utils.tempdir import TemporaryDirectory
37
36 from IPython.core import debugger
37
38
38 def doctest_refbug():
39 def doctest_refbug():
39 """Very nasty problem with references held by multiple runs of a script.
40 """Very nasty problem with references held by multiple runs of a script.
@@ -411,6 +412,7 b' tclass.py: deleting object: C-third'
411 """Test %run notebook.ipynb error"""
412 """Test %run notebook.ipynb error"""
412 pytest.importorskip("nbformat")
413 pytest.importorskip("nbformat")
413 from nbformat import v4, writes
414 from nbformat import v4, writes
415
414 # %run when a file name isn't provided
416 # %run when a file name isn't provided
415 pytest.raises(Exception, _ip.magic, "run")
417 pytest.raises(Exception, _ip.magic, "run")
416
418
@@ -3,21 +3,20 b''
3 """
3 """
4 import io
4 import io
5 import logging
5 import logging
6 import os.path
6 import platform
7 import platform
7 import re
8 import re
8 import sys
9 import sys
9 import os.path
10 from textwrap import dedent
11 import traceback
10 import traceback
12 import unittest
11 import unittest
12 from textwrap import dedent
13
13
14 from IPython.core.ultratb import ColorTB, VerboseTB
14 from tempfile import TemporaryDirectory
15
16
15
16 from IPython.core.ultratb import ColorTB, VerboseTB
17 from IPython.testing import tools as tt
17 from IPython.testing import tools as tt
18 from IPython.testing.decorators import onlyif_unicode_paths
18 from IPython.testing.decorators import onlyif_unicode_paths
19 from IPython.utils.syspathcontext import prepended_to_syspath
19 from IPython.utils.syspathcontext import prepended_to_syspath
20 from IPython.utils.tempdir import TemporaryDirectory
21
20
22 file_1 = """1
21 file_1 = """1
23 2
22 2
@@ -207,7 +207,16 b' class TBTools(colorable.Colorable):'
207 # Number of frames to skip when reporting tracebacks
207 # Number of frames to skip when reporting tracebacks
208 tb_offset = 0
208 tb_offset = 0
209
209
210 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
210 def __init__(
211 self,
212 color_scheme="NoColor",
213 call_pdb=False,
214 ostream=None,
215 parent=None,
216 config=None,
217 *,
218 debugger_cls=None,
219 ):
211 # Whether to call the interactive pdb debugger after printing
220 # Whether to call the interactive pdb debugger after printing
212 # tracebacks or not
221 # tracebacks or not
213 super(TBTools, self).__init__(parent=parent, config=config)
222 super(TBTools, self).__init__(parent=parent, config=config)
@@ -227,9 +236,10 b' class TBTools(colorable.Colorable):'
227
236
228 self.set_colors(color_scheme)
237 self.set_colors(color_scheme)
229 self.old_scheme = color_scheme # save initial value for toggles
238 self.old_scheme = color_scheme # save initial value for toggles
239 self.debugger_cls = debugger_cls or debugger.Pdb
230
240
231 if call_pdb:
241 if call_pdb:
232 self.pdb = debugger.Pdb()
242 self.pdb = debugger_cls()
233 else:
243 else:
234 self.pdb = None
244 self.pdb = None
235
245
@@ -350,9 +360,6 b' class ListTB(TBTools):'
350 Because they are meant to be called without a full traceback (only a
360 Because they are meant to be called without a full traceback (only a
351 list), instances of this class can't call the interactive pdb debugger."""
361 list), instances of this class can't call the interactive pdb debugger."""
352
362
353 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
354 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
355 ostream=ostream, parent=parent,config=config)
356
363
357 def __call__(self, etype, value, elist):
364 def __call__(self, etype, value, elist):
358 self.ostream.flush()
365 self.ostream.flush()
@@ -628,8 +635,15 b' class VerboseTB(TBTools):'
628 tb_offset=1 allows use of this handler in interpreters which will have
635 tb_offset=1 allows use of this handler in interpreters which will have
629 their own code at the top of the traceback (VerboseTB will first
636 their own code at the top of the traceback (VerboseTB will first
630 remove that frame before printing the traceback info)."""
637 remove that frame before printing the traceback info)."""
631 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
638 TBTools.__init__(
632 ostream=ostream, parent=parent, config=config)
639 self,
640 color_scheme=color_scheme,
641 call_pdb=call_pdb,
642 ostream=ostream,
643 parent=parent,
644 config=config,
645 debugger_cls=debugger_cls,
646 )
633 self.tb_offset = tb_offset
647 self.tb_offset = tb_offset
634 self.long_header = long_header
648 self.long_header = long_header
635 self.include_vars = include_vars
649 self.include_vars = include_vars
@@ -642,7 +656,6 b' class VerboseTB(TBTools):'
642 check_cache = linecache.checkcache
656 check_cache = linecache.checkcache
643 self.check_cache = check_cache
657 self.check_cache = check_cache
644
658
645 self.debugger_cls = debugger_cls or debugger.Pdb
646 self.skip_hidden = True
659 self.skip_hidden = True
647
660
648 def format_record(self, frame_info):
661 def format_record(self, frame_info):
@@ -763,7 +776,7 b' class VerboseTB(TBTools):'
763 self,
776 self,
764 etype: type,
777 etype: type,
765 evalue: BaseException,
778 evalue: BaseException,
766 etb: TracebackType,
779 etb: Optional[TracebackType],
767 number_of_lines_of_context,
780 number_of_lines_of_context,
768 tb_offset: Optional[int],
781 tb_offset: Optional[int],
769 ):
782 ):
@@ -772,7 +785,6 b' class VerboseTB(TBTools):'
772 This may be called multiple times by Python 3 exception chaining
785 This may be called multiple times by Python 3 exception chaining
773 (PEP 3134).
786 (PEP 3134).
774 """
787 """
775 assert etb is not None
776 # some locals
788 # some locals
777 orig_etype = etype
789 orig_etype = etype
778 try:
790 try:
@@ -783,7 +795,9 b' class VerboseTB(TBTools):'
783 tb_offset = self.tb_offset if tb_offset is None else tb_offset
795 tb_offset = self.tb_offset if tb_offset is None else tb_offset
784 assert isinstance(tb_offset, int)
796 assert isinstance(tb_offset, int)
785 head = self.prepare_header(etype, self.long_header)
797 head = self.prepare_header(etype, self.long_header)
786 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
798 records = (
799 self.get_records(etb, number_of_lines_of_context, tb_offset) if etb else []
800 )
787
801
788 frames = []
802 frames = []
789 skipped = 0
803 skipped = 0
@@ -822,6 +836,7 b' class VerboseTB(TBTools):'
822 def get_records(
836 def get_records(
823 self, etb: TracebackType, number_of_lines_of_context: int, tb_offset: int
837 self, etb: TracebackType, number_of_lines_of_context: int, tb_offset: int
824 ):
838 ):
839 assert etb is not None
825 context = number_of_lines_of_context - 1
840 context = number_of_lines_of_context - 1
826 after = context // 2
841 after = context // 2
827 before = context - after
842 before = context - after
@@ -836,19 +851,17 b' class VerboseTB(TBTools):'
836 after=after,
851 after=after,
837 pygments_formatter=formatter,
852 pygments_formatter=formatter,
838 )
853 )
839 assert etb is not None
840 return list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
854 return list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
841
855
842 def structured_traceback(
856 def structured_traceback(
843 self,
857 self,
844 etype: type,
858 etype: type,
845 evalue: Optional[BaseException],
859 evalue: Optional[BaseException],
846 etb: TracebackType,
860 etb: Optional[TracebackType],
847 tb_offset: Optional[int] = None,
861 tb_offset: Optional[int] = None,
848 number_of_lines_of_context: int = 5,
862 number_of_lines_of_context: int = 5,
849 ):
863 ):
850 """Return a nice text document describing the traceback."""
864 """Return a nice text document describing the traceback."""
851 assert etb is not None
852 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
865 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
853 tb_offset)
866 tb_offset)
854
867
@@ -33,7 +33,7 b' from IPython.testing.decorators import skipif_not_numpy'
33
33
34 if platform.python_implementation() == "PyPy":
34 if platform.python_implementation() == "PyPy":
35 pytest.skip(
35 pytest.skip(
36 "Current autoreload implementation is extremly slow on PyPy",
36 "Current autoreload implementation is extremely slow on PyPy",
37 allow_module_level=True,
37 allow_module_level=True,
38 )
38 )
39
39
@@ -66,7 +66,9 b' class ImportDenier(importlib.abc.MetaPathFinder):'
66 """
66 """
67 Importing %s disabled by IPython, which has
67 Importing %s disabled by IPython, which has
68 already imported an Incompatible QT Binding: %s
68 already imported an Incompatible QT Binding: %s
69 """ % (fullname, loaded_api()))
69 """
70 % (fullname, loaded_api())
71 )
70
72
71
73
72 ID = ImportDenier()
74 ID = ImportDenier()
@@ -9,13 +9,3 b' Extra capabilities for IPython'
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
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 from IPython.lib.security import passwd
18
19 #-----------------------------------------------------------------------------
20 # Code
21 #-----------------------------------------------------------------------------
@@ -92,8 +92,8 b' class Audio(DisplayObject):'
92
92
93 From a File:
93 From a File:
94
94
95 >>> Audio('/path/to/sound.wav') # doctest: +SKIP
95 >>> Audio('IPython/lib/tests/test.wav') # doctest: +SKIP
96 >>> Audio(filename='/path/to/sound.ogg') # doctest: +SKIP
96 >>> Audio(filename='IPython/lib/tests/test.wav') # doctest: +SKIP
97
97
98 From Bytes:
98 From Bytes:
99
99
@@ -103,9 +103,9 b' class Audio(DisplayObject):'
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
@@ -510,12 +510,10 b' class FileLinks(FileLink):'
510
510
511 self.recursive = recursive
511 self.recursive = recursive
512
512
513 def _get_display_formatter(self,
513 def _get_display_formatter(
514 dirname_output_format,
514 self, dirname_output_format, fname_output_format, fp_format, fp_cleaner=None
515 fname_output_format,
515 ):
516 fp_format,
516 """generate built-in formatter function
517 fp_cleaner=None):
518 """ generate built-in formatter function
519
517
520 this is used to define both the notebook and terminal built-in
518 this is used to define both the notebook and terminal built-in
521 formatters as they only differ by some wrapper text for each entry
519 formatters as they only differ by some wrapper text for each entry
@@ -4,14 +4,15 b''
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import pytest
8 import types
7 import types
9
10 from pathlib import Path
8 from pathlib import Path
11
9
10 import pytest
11 from tempfile import TemporaryDirectory
12
13 from IPython.lib.deepreload import modules_reloading
14 from IPython.lib.deepreload import reload as dreload
12 from IPython.utils.syspathcontext import prepended_to_syspath
15 from IPython.utils.syspathcontext import prepended_to_syspath
13 from IPython.utils.tempdir import TemporaryDirectory
14 from IPython.lib.deepreload import reload as dreload, modules_reloading
15
16
16
17
17 def test_deepreload():
18 def test_deepreload():
@@ -31,7 +31,7 b' def no_op(*args, **kwargs):'
31
31
32
32
33 @onlyif_cmds_exist("latex", "dvipng")
33 @onlyif_cmds_exist("latex", "dvipng")
34 @pytest.mark.parametrize("s, wrap", [(u"$$x^2$$", False), (u"x^2", True)])
34 @pytest.mark.parametrize("s, wrap", [("$$x^2$$", False), ("x^2", True)])
35 def test_latex_to_png_dvipng_runs(s, wrap):
35 def test_latex_to_png_dvipng_runs(s, wrap):
36 """
36 """
37 Test that latex_to_png_dvipng just runs without error.
37 Test that latex_to_png_dvipng just runs without error.
@@ -273,7 +273,7 b' def test_unicode_repr():'
273 p = pretty.pretty(c)
273 p = pretty.pretty(c)
274 assert p == u
274 assert p == u
275 p = pretty.pretty([c])
275 p = pretty.pretty([c])
276 assert p == u"[%s]" % u
276 assert p == "[%s]" % u
277
277
278
278
279 def test_basic_class():
279 def test_basic_class():
@@ -220,6 +220,8 b' except Exception:'
220 # for tokenizing blocks
220 # for tokenizing blocks
221 COMMENT, INPUT, OUTPUT = range(3)
221 COMMENT, INPUT, OUTPUT = range(3)
222
222
223 PSEUDO_DECORATORS = ["suppress", "verbatim", "savefig", "doctest"]
224
223 #-----------------------------------------------------------------------------
225 #-----------------------------------------------------------------------------
224 # Functions and class declarations
226 # Functions and class declarations
225 #-----------------------------------------------------------------------------
227 #-----------------------------------------------------------------------------
@@ -263,11 +265,17 b' def block_parser(part, rgxin, rgxout, fmtin, fmtout):'
263 block.append((COMMENT, line))
265 block.append((COMMENT, line))
264 continue
266 continue
265
267
266 if line_stripped.startswith('@'):
268 if any(
267 # Here is where we assume there is, at most, one decorator.
269 line_stripped.startswith("@" + pseudo_decorator)
268 # Might need to rethink this.
270 for pseudo_decorator in PSEUDO_DECORATORS
269 decorator = line_stripped
271 ):
270 continue
272 if decorator:
273 raise RuntimeError(
274 "Applying multiple pseudo-decorators on one line is not supported"
275 )
276 else:
277 decorator = line_stripped
278 continue
271
279
272 # does this look like an input line?
280 # does this look like an input line?
273 matchin = rgxin.match(line)
281 matchin = rgxin.match(line)
@@ -68,6 +68,8 b' class TerminalPdb(Pdb):'
68 self.debugger_history = FileHistory(os.path.expanduser(str(p)))
68 self.debugger_history = FileHistory(os.path.expanduser(str(p)))
69 else:
69 else:
70 self.debugger_history = InMemoryHistory()
70 self.debugger_history = InMemoryHistory()
71 else:
72 self.debugger_history = self.shell.debugger_history
71
73
72 options = dict(
74 options = dict(
73 message=(lambda: PygmentsTokens(get_prompt_tokens())),
75 message=(lambda: PygmentsTokens(get_prompt_tokens())),
@@ -3,12 +3,10 b''
3 import asyncio
3 import asyncio
4 import os
4 import os
5 import sys
5 import sys
6 import warnings
7 from warnings import warn
6 from warnings import warn
8
7
9 from IPython.core.async_helpers import get_asyncio_loop
8 from IPython.core.async_helpers import get_asyncio_loop
10 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
9 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
11 from IPython.utils import io
12 from IPython.utils.py3compat import input
10 from IPython.utils.py3compat import input
13 from IPython.utils.terminal import toggle_set_term_title, set_term_title, restore_term_title
11 from IPython.utils.terminal import toggle_set_term_title, set_term_title, restore_term_title
14 from IPython.utils.process import abbrev_cwd
12 from IPython.utils.process import abbrev_cwd
@@ -32,7 +30,7 b' from prompt_toolkit.auto_suggest import AutoSuggestFromHistory'
32 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
30 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
33 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
31 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
34 from prompt_toolkit.formatted_text import PygmentsTokens
32 from prompt_toolkit.formatted_text import PygmentsTokens
35 from prompt_toolkit.history import InMemoryHistory
33 from prompt_toolkit.history import History
36 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
34 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
37 from prompt_toolkit.output import ColorDepth
35 from prompt_toolkit.output import ColorDepth
38 from prompt_toolkit.patch_stdout import patch_stdout
36 from prompt_toolkit.patch_stdout import patch_stdout
@@ -116,6 +114,59 b' def black_reformat_handler(text_before_cursor):'
116 return formatted_text
114 return formatted_text
117
115
118
116
117 def yapf_reformat_handler(text_before_cursor):
118 from yapf.yapflib import file_resources
119 from yapf.yapflib import yapf_api
120
121 style_config = file_resources.GetDefaultStyleForDir(os.getcwd())
122 formatted_text, was_formatted = yapf_api.FormatCode(
123 text_before_cursor, style_config=style_config
124 )
125 if was_formatted:
126 if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
127 formatted_text = formatted_text[:-1]
128 return formatted_text
129 else:
130 return text_before_cursor
131
132
133 class PtkHistoryAdapter(History):
134 """
135 Prompt toolkit has it's own way of handling history, Where it assumes it can
136 Push/pull from history.
137
138 """
139
140 def __init__(self, shell):
141 super().__init__()
142 self.shell = shell
143 self._refresh()
144
145 def append_string(self, string):
146 # we rely on sql for that.
147 self._loaded = False
148 self._refresh()
149
150 def _refresh(self):
151 if not self._loaded:
152 self._loaded_strings = list(self.load_history_strings())
153
154 def load_history_strings(self):
155 last_cell = ""
156 res = []
157 for __, ___, cell in self.shell.history_manager.get_tail(
158 self.shell.history_load_length, include_latest=True
159 ):
160 # Ignore blank lines and consecutive duplicates
161 cell = cell.rstrip()
162 if cell and (cell != last_cell):
163 res.append(cell)
164 last_cell = cell
165 yield from res[::-1]
166
167 def store_string(self, string: str) -> None:
168 pass
169
119 class TerminalInteractiveShell(InteractiveShell):
170 class TerminalInteractiveShell(InteractiveShell):
120 mime_renderers = Dict().tag(config=True)
171 mime_renderers = Dict().tag(config=True)
121
172
@@ -184,8 +235,8 b' class TerminalInteractiveShell(InteractiveShell):'
184 ).tag(config=True)
235 ).tag(config=True)
185
236
186 autoformatter = Unicode(
237 autoformatter = Unicode(
187 "black",
238 None,
188 help="Autoformatter to reformat Terminal code. Can be `'black'` or `None`",
239 help="Autoformatter to reformat Terminal code. Can be `'black'`, `'yapf'` or `None`",
189 allow_none=True
240 allow_none=True
190 ).tag(config=True)
241 ).tag(config=True)
191
242
@@ -232,6 +283,8 b' class TerminalInteractiveShell(InteractiveShell):'
232 self.reformat_handler = lambda x:x
283 self.reformat_handler = lambda x:x
233 elif formatter == 'black':
284 elif formatter == 'black':
234 self.reformat_handler = black_reformat_handler
285 self.reformat_handler = black_reformat_handler
286 elif formatter == "yapf":
287 self.reformat_handler = yapf_reformat_handler
235 else:
288 else:
236 raise ValueError
289 raise ValueError
237
290
@@ -379,16 +432,9 b' class TerminalInteractiveShell(InteractiveShell):'
379 # Set up keyboard shortcuts
432 # Set up keyboard shortcuts
380 key_bindings = create_ipython_shortcuts(self)
433 key_bindings = create_ipython_shortcuts(self)
381
434
435
382 # Pre-populate history from IPython's history database
436 # Pre-populate history from IPython's history database
383 history = InMemoryHistory()
437 history = PtkHistoryAdapter(self)
384 last_cell = u""
385 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
386 include_latest=True):
387 # Ignore blank lines and consecutive duplicates
388 cell = cell.rstrip()
389 if cell and (cell != last_cell):
390 history.append_string(cell)
391 last_cell = cell
392
438
393 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
439 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
394 self.style = DynamicStyle(lambda: self._style)
440 self.style = DynamicStyle(lambda: self._style)
@@ -568,7 +614,6 b' class TerminalInteractiveShell(InteractiveShell):'
568 def enable_win_unicode_console(self):
614 def enable_win_unicode_console(self):
569 # Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
615 # Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
570 # console by default, so WUC shouldn't be needed.
616 # console by default, so WUC shouldn't be needed.
571 from warnings import warn
572 warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
617 warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
573 DeprecationWarning,
618 DeprecationWarning,
574 stacklevel=2)
619 stacklevel=2)
@@ -1,7 +1,7 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The :class:`~IPython.core.application.Application` object for the command
4 The :class:`~traitlets.config.application.Application` object for the command
5 line :command:`ipython` program.
5 line :command:`ipython` program.
6 """
6 """
7
7
@@ -53,7 +53,7 b' class TerminalMagics(Magics):'
53 self.shell.user_ns['pasted_block'] = b
53 self.shell.user_ns['pasted_block'] = b
54 self.shell.using_paste_magics = True
54 self.shell.using_paste_magics = True
55 try:
55 try:
56 self.shell.run_cell(b)
56 self.shell.run_cell(b, store_history=True)
57 finally:
57 finally:
58 self.shell.using_paste_magics = False
58 self.shell.using_paste_magics = False
59
59
@@ -10,6 +10,7 b' import warnings'
10 import signal
10 import signal
11 import sys
11 import sys
12 import re
12 import re
13 import os
13 from typing import Callable
14 from typing import Callable
14
15
15
16
@@ -56,7 +57,7 b' def create_ipython_shortcuts(shell):'
56 & insert_mode
57 & insert_mode
57 ))(reformat_and_execute)
58 ))(reformat_and_execute)
58
59
59 kb.add('c-\\')(force_exit)
60 kb.add("c-\\")(quit)
60
61
61 kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
62 kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
62 )(previous_history_or_previous_completion)
63 )(previous_history_or_previous_completion)
@@ -139,12 +140,24 b' def create_ipython_shortcuts(shell):'
139 event.current_buffer.insert_text("{}")
140 event.current_buffer.insert_text("{}")
140 event.current_buffer.cursor_left()
141 event.current_buffer.cursor_left()
141
142
142 @kb.add('"', filter=focused_insert & auto_match & following_text(r"[,)}\]]|$"))
143 @kb.add(
144 '"',
145 filter=focused_insert
146 & auto_match
147 & preceding_text(r'^([^"]+|"[^"]*")*$')
148 & following_text(r"[,)}\]]|$"),
149 )
143 def _(event):
150 def _(event):
144 event.current_buffer.insert_text('""')
151 event.current_buffer.insert_text('""')
145 event.current_buffer.cursor_left()
152 event.current_buffer.cursor_left()
146
153
147 @kb.add("'", filter=focused_insert & auto_match & following_text(r"[,)}\]]|$"))
154 @kb.add(
155 "'",
156 filter=focused_insert
157 & auto_match
158 & preceding_text(r"^([^']+|'[^']*')*$")
159 & following_text(r"[,)}\]]|$"),
160 )
148 def _(event):
161 def _(event):
149 event.current_buffer.insert_text("''")
162 event.current_buffer.insert_text("''")
150 event.current_buffer.cursor_left()
163 event.current_buffer.cursor_left()
@@ -186,16 +199,6 b' def create_ipython_shortcuts(shell):'
186 event.current_buffer.insert_text("{}" + dashes)
199 event.current_buffer.insert_text("{}" + dashes)
187 event.current_buffer.cursor_left(len(dashes) + 1)
200 event.current_buffer.cursor_left(len(dashes) + 1)
188
201
189 @kb.add('"', filter=focused_insert & auto_match & preceding_text(r".*(r|R)$"))
190 def _(event):
191 event.current_buffer.insert_text('""')
192 event.current_buffer.cursor_left()
193
194 @kb.add("'", filter=focused_insert & auto_match & preceding_text(r".*(r|R)$"))
195 def _(event):
196 event.current_buffer.insert_text("''")
197 event.current_buffer.cursor_left()
198
199 # just move cursor
202 # just move cursor
200 @kb.add(")", filter=focused_insert & auto_match & following_text(r"^\)"))
203 @kb.add(")", filter=focused_insert & auto_match & following_text(r"^\)"))
201 @kb.add("]", filter=focused_insert & auto_match & following_text(r"^\]"))
204 @kb.add("]", filter=focused_insert & auto_match & following_text(r"^\]"))
@@ -265,15 +268,22 b' def create_ipython_shortcuts(shell):'
265 focused_insert_vi = has_focus(DEFAULT_BUFFER) & vi_insert_mode
268 focused_insert_vi = has_focus(DEFAULT_BUFFER) & vi_insert_mode
266
269
267 # Needed for to accept autosuggestions in vi insert mode
270 # Needed for to accept autosuggestions in vi insert mode
268 @kb.add("c-e", filter=focused_insert_vi & ebivim)
271 def _apply_autosuggest(event):
269 def _(event):
270 b = event.current_buffer
272 b = event.current_buffer
271 suggestion = b.suggestion
273 suggestion = b.suggestion
272 if suggestion:
274 if suggestion is not None and suggestion.text:
273 b.insert_text(suggestion.text)
275 b.insert_text(suggestion.text)
274 else:
276 else:
275 nc.end_of_line(event)
277 nc.end_of_line(event)
276
278
279 @kb.add("end", filter=has_focus(DEFAULT_BUFFER) & (ebivim | ~vi_insert_mode))
280 def _(event):
281 _apply_autosuggest(event)
282
283 @kb.add("c-e", filter=focused_insert_vi & ebivim)
284 def _(event):
285 _apply_autosuggest(event)
286
277 @kb.add("c-f", filter=focused_insert_vi)
287 @kb.add("c-f", filter=focused_insert_vi)
278 def _(event):
288 def _(event):
279 b = event.current_buffer
289 b = event.current_buffer
@@ -336,12 +346,7 b' def create_ipython_shortcuts(shell):'
336 shape = {InputMode.NAVIGATION: 2, InputMode.REPLACE: 4}.get(mode, 6)
346 shape = {InputMode.NAVIGATION: 2, InputMode.REPLACE: 4}.get(mode, 6)
337 cursor = "\x1b[{} q".format(shape)
347 cursor = "\x1b[{} q".format(shape)
338
348
339 if hasattr(sys.stdout, "_cli"):
349 sys.stdout.write(cursor)
340 write = sys.stdout._cli.output.write_raw
341 else:
342 write = sys.stdout.write
343
344 write(cursor)
345 sys.stdout.flush()
350 sys.stdout.flush()
346
351
347 self._input_mode = mode
352 self._input_mode = mode
@@ -454,11 +459,16 b' def reset_search_buffer(event):'
454 def suspend_to_bg(event):
459 def suspend_to_bg(event):
455 event.app.suspend_to_background()
460 event.app.suspend_to_background()
456
461
457 def force_exit(event):
462 def quit(event):
458 """
463 """
459 Force exit (with a non-zero return value)
464 On platforms that support SIGQUIT, send SIGQUIT to the current process.
465 On other platforms, just exit the process with a message.
460 """
466 """
461 sys.exit("Quit")
467 sigquit = getattr(signal, "SIGQUIT", None)
468 if sigquit is not None:
469 os.kill(0, signal.SIGQUIT)
470 else:
471 sys.exit("Quit")
462
472
463 def indent_buffer(event):
473 def indent_buffer(event):
464 event.current_buffer.insert_text(' ' * 4)
474 event.current_buffer.insert_text(' ' * 4)
@@ -38,7 +38,7 b' def ipfunc():'
38 ....: print(i, end=' ')
38 ....: print(i, end=' ')
39 ....: print(i+1, end=' ')
39 ....: print(i+1, end=' ')
40 ....:
40 ....:
41 0 1 1 2 2 3
41 0 1 1 2 2 3
42
42
43
43
44 It's OK to use '_' for the last result, but do NOT try to use IPython's
44 It's OK to use '_' for the last result, but do NOT try to use IPython's
@@ -50,7 +50,7 b' def ipfunc():'
50
50
51 In [8]: print(repr(_))
51 In [8]: print(repr(_))
52 'hi'
52 'hi'
53
53
54 In [7]: 3+4
54 In [7]: 3+4
55 Out[7]: 7
55 Out[7]: 7
56
56
@@ -60,7 +60,7 b' def ipfunc():'
60 In [9]: ipfunc()
60 In [9]: ipfunc()
61 Out[9]: 'ipfunc'
61 Out[9]: 'ipfunc'
62 """
62 """
63 return 'ipfunc'
63 return "ipfunc"
64
64
65
65
66 def ipos():
66 def ipos():
@@ -14,6 +14,7 b' import traceback'
14 import types
14 import types
15 import warnings
15 import warnings
16 from contextlib import contextmanager
16 from contextlib import contextmanager
17 from pathlib import Path
17 from typing import Any
18 from typing import Any
18 from typing import Callable
19 from typing import Callable
19 from typing import Dict
20 from typing import Dict
@@ -28,8 +29,6 b' from typing import Type'
28 from typing import TYPE_CHECKING
29 from typing import TYPE_CHECKING
29 from typing import Union
30 from typing import Union
30
31
31 import py.path
32
33 import pytest
32 import pytest
34 from _pytest import outcomes
33 from _pytest import outcomes
35 from _pytest._code.code import ExceptionInfo
34 from _pytest._code.code import ExceptionInfo
@@ -42,6 +41,7 b' from _pytest.config.argparsing import Parser'
42 from _pytest.fixtures import FixtureRequest
41 from _pytest.fixtures import FixtureRequest
43 from _pytest.nodes import Collector
42 from _pytest.nodes import Collector
44 from _pytest.outcomes import OutcomeException
43 from _pytest.outcomes import OutcomeException
44 from _pytest.pathlib import fnmatch_ex
45 from _pytest.pathlib import import_path
45 from _pytest.pathlib import import_path
46 from _pytest.python_api import approx
46 from _pytest.python_api import approx
47 from _pytest.warning_types import PytestWarning
47 from _pytest.warning_types import PytestWarning
@@ -126,35 +126,55 b' def pytest_unconfigure() -> None:'
126
126
127
127
128 def pytest_collect_file(
128 def pytest_collect_file(
129 path: py.path.local,
129 file_path: Path,
130 parent: Collector,
130 parent: Collector,
131 ) -> Optional[Union["IPDoctestModule", "IPDoctestTextfile"]]:
131 ) -> Optional[Union["IPDoctestModule", "IPDoctestTextfile"]]:
132 config = parent.config
132 config = parent.config
133 if path.ext == ".py":
133 if file_path.suffix == ".py":
134 if config.option.ipdoctestmodules and not _is_setup_py(path):
134 if config.option.ipdoctestmodules and not any(
135 mod: IPDoctestModule = IPDoctestModule.from_parent(parent, fspath=path)
135 (_is_setup_py(file_path), _is_main_py(file_path))
136 ):
137 mod: IPDoctestModule = IPDoctestModule.from_parent(parent, path=file_path)
136 return mod
138 return mod
137 elif _is_ipdoctest(config, path, parent):
139 elif _is_ipdoctest(config, file_path, parent):
138 txt: IPDoctestTextfile = IPDoctestTextfile.from_parent(parent, fspath=path)
140 txt: IPDoctestTextfile = IPDoctestTextfile.from_parent(parent, path=file_path)
139 return txt
141 return txt
140 return None
142 return None
141
143
142
144
143 def _is_setup_py(path: py.path.local) -> bool:
145 if int(pytest.__version__.split(".")[0]) < 7:
144 if path.basename != "setup.py":
146 _collect_file = pytest_collect_file
147
148 def pytest_collect_file(
149 path,
150 parent: Collector,
151 ) -> Optional[Union["IPDoctestModule", "IPDoctestTextfile"]]:
152 return _collect_file(Path(path), parent)
153
154 _import_path = import_path
155
156 def import_path(path, root):
157 import py.path
158
159 return _import_path(py.path.local(path))
160
161
162 def _is_setup_py(path: Path) -> bool:
163 if path.name != "setup.py":
145 return False
164 return False
146 contents = path.read_binary()
165 contents = path.read_bytes()
147 return b"setuptools" in contents or b"distutils" in contents
166 return b"setuptools" in contents or b"distutils" in contents
148
167
149
168
150 def _is_ipdoctest(config: Config, path: py.path.local, parent) -> bool:
169 def _is_ipdoctest(config: Config, path: Path, parent: Collector) -> bool:
151 if path.ext in (".txt", ".rst") and parent.session.isinitpath(path):
170 if path.suffix in (".txt", ".rst") and parent.session.isinitpath(path):
152 return True
171 return True
153 globs = config.getoption("ipdoctestglob") or ["test*.txt"]
172 globs = config.getoption("ipdoctestglob") or ["test*.txt"]
154 for glob in globs:
173 return any(fnmatch_ex(glob, path) for glob in globs)
155 if path.check(fnmatch=glob):
174
156 return True
175
157 return False
176 def _is_main_py(path: Path) -> bool:
177 return path.name == "__main__.py"
158
178
159
179
160 class ReprFailDoctest(TerminalRepr):
180 class ReprFailDoctest(TerminalRepr):
@@ -273,7 +293,7 b' class IPDoctestItem(pytest.Item):'
273 runner: "IPDocTestRunner",
293 runner: "IPDocTestRunner",
274 dtest: "doctest.DocTest",
294 dtest: "doctest.DocTest",
275 ):
295 ):
276 # incompatible signature due to to imposed limits on sublcass
296 # incompatible signature due to imposed limits on subclass
277 """The public named constructor."""
297 """The public named constructor."""
278 return super().from_parent(name=name, parent=parent, runner=runner, dtest=dtest)
298 return super().from_parent(name=name, parent=parent, runner=runner, dtest=dtest)
279
299
@@ -372,61 +392,63 b' class IPDoctestItem(pytest.Item):'
372 elif isinstance(excinfo.value, MultipleDoctestFailures):
392 elif isinstance(excinfo.value, MultipleDoctestFailures):
373 failures = excinfo.value.failures
393 failures = excinfo.value.failures
374
394
375 if failures is not None:
395 if failures is None:
376 reprlocation_lines = []
377 for failure in failures:
378 example = failure.example
379 test = failure.test
380 filename = test.filename
381 if test.lineno is None:
382 lineno = None
383 else:
384 lineno = test.lineno + example.lineno + 1
385 message = type(failure).__name__
386 # TODO: ReprFileLocation doesn't expect a None lineno.
387 reprlocation = ReprFileLocation(filename, lineno, message) # type: ignore[arg-type]
388 checker = _get_checker()
389 report_choice = _get_report_choice(
390 self.config.getoption("ipdoctestreport")
391 )
392 if lineno is not None:
393 assert failure.test.docstring is not None
394 lines = failure.test.docstring.splitlines(False)
395 # add line numbers to the left of the error message
396 assert test.lineno is not None
397 lines = [
398 "%03d %s" % (i + test.lineno + 1, x)
399 for (i, x) in enumerate(lines)
400 ]
401 # trim docstring error lines to 10
402 lines = lines[max(example.lineno - 9, 0) : example.lineno + 1]
403 else:
404 lines = [
405 "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example"
406 ]
407 indent = ">>>"
408 for line in example.source.splitlines():
409 lines.append(f"??? {indent} {line}")
410 indent = "..."
411 if isinstance(failure, doctest.DocTestFailure):
412 lines += checker.output_difference(
413 example, failure.got, report_choice
414 ).split("\n")
415 else:
416 inner_excinfo = ExceptionInfo(failure.exc_info)
417 lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)]
418 lines += [
419 x.strip("\n")
420 for x in traceback.format_exception(*failure.exc_info)
421 ]
422 reprlocation_lines.append((reprlocation, lines))
423 return ReprFailDoctest(reprlocation_lines)
424 else:
425 return super().repr_failure(excinfo)
396 return super().repr_failure(excinfo)
426
397
427 def reportinfo(self):
398 reprlocation_lines = []
399 for failure in failures:
400 example = failure.example
401 test = failure.test
402 filename = test.filename
403 if test.lineno is None:
404 lineno = None
405 else:
406 lineno = test.lineno + example.lineno + 1
407 message = type(failure).__name__
408 # TODO: ReprFileLocation doesn't expect a None lineno.
409 reprlocation = ReprFileLocation(filename, lineno, message) # type: ignore[arg-type]
410 checker = _get_checker()
411 report_choice = _get_report_choice(self.config.getoption("ipdoctestreport"))
412 if lineno is not None:
413 assert failure.test.docstring is not None
414 lines = failure.test.docstring.splitlines(False)
415 # add line numbers to the left of the error message
416 assert test.lineno is not None
417 lines = [
418 "%03d %s" % (i + test.lineno + 1, x) for (i, x) in enumerate(lines)
419 ]
420 # trim docstring error lines to 10
421 lines = lines[max(example.lineno - 9, 0) : example.lineno + 1]
422 else:
423 lines = [
424 "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example"
425 ]
426 indent = ">>>"
427 for line in example.source.splitlines():
428 lines.append(f"??? {indent} {line}")
429 indent = "..."
430 if isinstance(failure, doctest.DocTestFailure):
431 lines += checker.output_difference(
432 example, failure.got, report_choice
433 ).split("\n")
434 else:
435 inner_excinfo = ExceptionInfo.from_exc_info(failure.exc_info)
436 lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)]
437 lines += [
438 x.strip("\n") for x in traceback.format_exception(*failure.exc_info)
439 ]
440 reprlocation_lines.append((reprlocation, lines))
441 return ReprFailDoctest(reprlocation_lines)
442
443 def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]:
428 assert self.dtest is not None
444 assert self.dtest is not None
429 return self.fspath, self.dtest.lineno, "[ipdoctest] %s" % self.name
445 return self.path, self.dtest.lineno, "[ipdoctest] %s" % self.name
446
447 if int(pytest.__version__.split(".")[0]) < 7:
448
449 @property
450 def path(self) -> Path:
451 return Path(self.fspath)
430
452
431
453
432 def _get_flag_lookup() -> Dict[str, int]:
454 def _get_flag_lookup() -> Dict[str, int]:
@@ -474,9 +496,9 b' class IPDoctestTextfile(pytest.Module):'
474 # Inspired by doctest.testfile; ideally we would use it directly,
496 # Inspired by doctest.testfile; ideally we would use it directly,
475 # but it doesn't support passing a custom checker.
497 # but it doesn't support passing a custom checker.
476 encoding = self.config.getini("ipdoctest_encoding")
498 encoding = self.config.getini("ipdoctest_encoding")
477 text = self.fspath.read_text(encoding)
499 text = self.path.read_text(encoding)
478 filename = str(self.fspath)
500 filename = str(self.path)
479 name = self.fspath.basename
501 name = self.path.name
480 globs = {"__name__": "__main__"}
502 globs = {"__name__": "__main__"}
481
503
482 optionflags = get_optionflags(self)
504 optionflags = get_optionflags(self)
@@ -495,6 +517,27 b' class IPDoctestTextfile(pytest.Module):'
495 self, name=test.name, runner=runner, dtest=test
517 self, name=test.name, runner=runner, dtest=test
496 )
518 )
497
519
520 if int(pytest.__version__.split(".")[0]) < 7:
521
522 @property
523 def path(self) -> Path:
524 return Path(self.fspath)
525
526 @classmethod
527 def from_parent(
528 cls,
529 parent,
530 *,
531 fspath=None,
532 path: Optional[Path] = None,
533 **kw,
534 ):
535 if path is not None:
536 import py.path
537
538 fspath = py.path.local(path)
539 return super().from_parent(parent=parent, fspath=fspath, **kw)
540
498
541
499 def _check_all_skipped(test: "doctest.DocTest") -> None:
542 def _check_all_skipped(test: "doctest.DocTest") -> None:
500 """Raise pytest.skip() if all examples in the given DocTest have the SKIP
543 """Raise pytest.skip() if all examples in the given DocTest have the SKIP
@@ -559,15 +602,20 b' class IPDoctestModule(pytest.Module):'
559
602
560 def _find_lineno(self, obj, source_lines):
603 def _find_lineno(self, obj, source_lines):
561 """Doctest code does not take into account `@property`, this
604 """Doctest code does not take into account `@property`, this
562 is a hackish way to fix it.
605 is a hackish way to fix it. https://bugs.python.org/issue17446
563
606
564 https://bugs.python.org/issue17446
607 Wrapped Doctests will need to be unwrapped so the correct
608 line number is returned. This will be reported upstream. #8796
565 """
609 """
566 if isinstance(obj, property):
610 if isinstance(obj, property):
567 obj = getattr(obj, "fget", obj)
611 obj = getattr(obj, "fget", obj)
612
613 if hasattr(obj, "__wrapped__"):
614 # Get the main obj in case of it being wrapped
615 obj = inspect.unwrap(obj)
616
568 # Type ignored because this is a private function.
617 # Type ignored because this is a private function.
569 return DocTestFinder._find_lineno( # type: ignore
618 return super()._find_lineno( # type:ignore[misc]
570 self,
571 obj,
619 obj,
572 source_lines,
620 source_lines,
573 )
621 )
@@ -580,20 +628,28 b' class IPDoctestModule(pytest.Module):'
580 with _patch_unwrap_mock_aware():
628 with _patch_unwrap_mock_aware():
581
629
582 # Type ignored because this is a private function.
630 # Type ignored because this is a private function.
583 DocTestFinder._find( # type: ignore
631 super()._find( # type:ignore[misc]
584 self, tests, obj, name, module, source_lines, globs, seen
632 tests, obj, name, module, source_lines, globs, seen
585 )
633 )
586
634
587 if self.fspath.basename == "conftest.py":
635 if self.path.name == "conftest.py":
588 module = self.config.pluginmanager._importconftest(
636 if int(pytest.__version__.split(".")[0]) < 7:
589 self.fspath, self.config.getoption("importmode")
637 module = self.config.pluginmanager._importconftest(
590 )
638 self.path,
639 self.config.getoption("importmode"),
640 )
641 else:
642 module = self.config.pluginmanager._importconftest(
643 self.path,
644 self.config.getoption("importmode"),
645 rootpath=self.config.rootpath,
646 )
591 else:
647 else:
592 try:
648 try:
593 module = import_path(self.fspath)
649 module = import_path(self.path, root=self.config.rootpath)
594 except ImportError:
650 except ImportError:
595 if self.config.getvalue("ipdoctest_ignore_import_errors"):
651 if self.config.getvalue("ipdoctest_ignore_import_errors"):
596 pytest.skip("unable to import module %r" % self.fspath)
652 pytest.skip("unable to import module %r" % self.path)
597 else:
653 else:
598 raise
654 raise
599 # Uses internal doctest module parsing mechanism.
655 # Uses internal doctest module parsing mechanism.
@@ -612,6 +668,27 b' class IPDoctestModule(pytest.Module):'
612 self, name=test.name, runner=runner, dtest=test
668 self, name=test.name, runner=runner, dtest=test
613 )
669 )
614
670
671 if int(pytest.__version__.split(".")[0]) < 7:
672
673 @property
674 def path(self) -> Path:
675 return Path(self.fspath)
676
677 @classmethod
678 def from_parent(
679 cls,
680 parent,
681 *,
682 fspath=None,
683 path: Optional[Path] = None,
684 **kw,
685 ):
686 if path is not None:
687 import py.path
688
689 fspath = py.path.local(path)
690 return super().from_parent(parent=parent, fspath=fspath, **kw)
691
615
692
616 def _setup_fixtures(doctest_item: IPDoctestItem) -> FixtureRequest:
693 def _setup_fixtures(doctest_item: IPDoctestItem) -> FixtureRequest:
617 """Used by IPDoctestTextfile and IPDoctestItem to setup fixture information."""
694 """Used by IPDoctestTextfile and IPDoctestItem to setup fixture information."""
@@ -665,7 +742,7 b' def _init_checker_class() -> Type["IPDoctestOutputChecker"]:'
665 )
742 )
666
743
667 def check_output(self, want: str, got: str, optionflags: int) -> bool:
744 def check_output(self, want: str, got: str, optionflags: int) -> bool:
668 if IPDoctestOutputChecker.check_output(self, want, got, optionflags):
745 if super().check_output(want, got, optionflags):
669 return True
746 return True
670
747
671 allow_unicode = optionflags & _get_allow_unicode_flag()
748 allow_unicode = optionflags & _get_allow_unicode_flag()
@@ -689,7 +766,7 b' def _init_checker_class() -> Type["IPDoctestOutputChecker"]:'
689 if allow_number:
766 if allow_number:
690 got = self._remove_unwanted_precision(want, got)
767 got = self._remove_unwanted_precision(want, got)
691
768
692 return IPDoctestOutputChecker.check_output(self, want, got, optionflags)
769 return super().check_output(want, got, optionflags)
693
770
694 def _remove_unwanted_precision(self, want: str, got: str) -> str:
771 def _remove_unwanted_precision(self, want: str, got: str) -> str:
695 wants = list(self._number_re.finditer(want))
772 wants = list(self._number_re.finditer(want))
@@ -702,10 +779,7 b' def _init_checker_class() -> Type["IPDoctestOutputChecker"]:'
702 exponent: Optional[str] = w.group("exponent1")
779 exponent: Optional[str] = w.group("exponent1")
703 if exponent is None:
780 if exponent is None:
704 exponent = w.group("exponent2")
781 exponent = w.group("exponent2")
705 if fraction is None:
782 precision = 0 if fraction is None else len(fraction)
706 precision = 0
707 else:
708 precision = len(fraction)
709 if exponent is not None:
783 if exponent is not None:
710 precision -= int(exponent)
784 precision -= int(exponent)
711 if float(w.group()) == approx(float(g.group()), abs=10 ** -precision):
785 if float(w.group()) == approx(float(g.group()), abs=10 ** -precision):
@@ -10,8 +10,7 b' from tempfile import TemporaryDirectory'
10
10
11
11
12 class NamedFileInTemporaryDirectory(object):
12 class NamedFileInTemporaryDirectory(object):
13
13 def __init__(self, filename, mode="w+b", bufsize=-1, add_to_syspath=False, **kwds):
14 def __init__(self, filename, mode='w+b', bufsize=-1, **kwds):
15 """
14 """
16 Open a file named `filename` in a temporary directory.
15 Open a file named `filename` in a temporary directory.
17
16
@@ -10,24 +10,23 b' import sys'
10 import tempfile
10 import tempfile
11 import unittest
11 import unittest
12 from contextlib import contextmanager
12 from contextlib import contextmanager
13 from unittest.mock import patch
14 from os.path import join, abspath
15 from importlib import reload
13 from importlib import reload
14 from os.path import abspath, join
15 from unittest.mock import patch
16
16
17 import pytest
17 import pytest
18 from tempfile import TemporaryDirectory
18
19
19 import IPython
20 import IPython
20 from IPython import paths
21 from IPython import paths
21 from IPython.testing import decorators as dec
22 from IPython.testing import decorators as dec
22 from IPython.testing.decorators import (
23 from IPython.testing.decorators import (
24 onlyif_unicode_paths,
23 skip_if_not_win32,
25 skip_if_not_win32,
24 skip_win32,
26 skip_win32,
25 onlyif_unicode_paths,
26 )
27 )
27 from IPython.testing.tools import make_tempfile
28 from IPython.testing.tools import make_tempfile
28 from IPython.utils import path
29 from IPython.utils import path
29 from IPython.utils.tempdir import TemporaryDirectory
30
31
30
32 # Platform-dependent imports
31 # Platform-dependent imports
33 try:
32 try:
@@ -41,6 +40,7 b' except ImportError:'
41 import winreg as wreg
40 import winreg as wreg
42 except ImportError:
41 except ImportError:
43 import _winreg as wreg
42 import _winreg as wreg
43
44 #Add entries that needs to be stubbed by the testing code
44 #Add entries that needs to be stubbed by the testing code
45 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
45 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
46
46
@@ -470,11 +470,11 b' def strip_ansi(source):'
470
470
471 class EvalFormatter(Formatter):
471 class EvalFormatter(Formatter):
472 """A String Formatter that allows evaluation of simple expressions.
472 """A String Formatter that allows evaluation of simple expressions.
473
473
474 Note that this version interprets a : as specifying a format string (as per
474 Note that this version interprets a `:` as specifying a format string (as per
475 standard string formatting), so if slicing is required, you must explicitly
475 standard string formatting), so if slicing is required, you must explicitly
476 create a slice.
476 create a slice.
477
477
478 This is to be used in templating cases, such as the parallel batch
478 This is to be used in templating cases, such as the parallel batch
479 script templates, where simple arithmetic on arguments is useful.
479 script templates, where simple arithmetic on arguments is useful.
480
480
@@ -690,8 +690,8 b' def compute_item_matrix(items, row_first=False, empty=None, *args, **kwargs) :'
690 return ([[_get_or_default(items, c * nrow + r, default=empty) for c in range(ncol)] for r in range(nrow)], info)
690 return ([[_get_or_default(items, c * nrow + r, default=empty) for c in range(ncol)] for r in range(nrow)], info)
691
691
692
692
693 def columnize(items, row_first=False, separator=' ', displaywidth=80, spread=False):
693 def columnize(items, row_first=False, separator=" ", displaywidth=80, spread=False):
694 """ Transform a list of strings into a single string with columns.
694 """Transform a list of strings into a single string with columns.
695
695
696 Parameters
696 Parameters
697 ----------
697 ----------
@@ -3,4 +3,4 b''
3 ## Reporting a Vulnerability
3 ## Reporting a Vulnerability
4
4
5 All IPython and Jupyter security are handled via security@ipython.org.
5 All IPython and Jupyter security are handled via security@ipython.org.
6 You can find more informations on the Jupyter website. https://jupyter.org/security
6 You can find more information on the Jupyter website. https://jupyter.org/security
@@ -5,7 +5,7 b' matrix:'
5 environment:
5 environment:
6 global:
6 global:
7 APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022'
7 APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022'
8 COLUMNS: 120 # Appveyor web viwer window width is 130 chars
8 COLUMNS: 120 # Appveyor web viewer window width is 130 chars
9
9
10 matrix:
10 matrix:
11 - PYTHON: "C:\\Python38"
11 - PYTHON: "C:\\Python38"
@@ -17,22 +17,29 b' For example::'
17 def __init__(self, ip):
17 def __init__(self, ip):
18 self.shell = ip
18 self.shell = ip
19 self.last_x = None
19 self.last_x = None
20
20
21 def pre_execute(self):
21 def pre_execute(self):
22 self.last_x = self.shell.user_ns.get('x', None)
22 self.last_x = self.shell.user_ns.get('x', None)
23
23
24 def pre_run_cell(self, info):
24 def pre_run_cell(self, info):
25 print('Cell code: "%s"' % info.raw_cell)
25 print('info.raw_cell =', info.raw_cell)
26
26 print('info.store_history =', info.store_history)
27 print('info.silent =', info.silent)
28 print('info.shell_futures =', info.shell_futures)
29 print('info.cell_id =', info.cell_id)
30 print(dir(info))
31
27 def post_execute(self):
32 def post_execute(self):
28 if self.shell.user_ns.get('x', None) != self.last_x:
33 if self.shell.user_ns.get('x', None) != self.last_x:
29 print("x changed!")
34 print("x changed!")
30
35
31 def post_run_cell(self, result):
36 def post_run_cell(self, result):
32 print('Cell code: "%s"' % result.info.raw_cell)
37 print('result.execution_count = ', result.execution_count)
33 if result.error_before_exec:
38 print('result.error_before_exec = ', result.error_before_exec)
34 print('Error before execution: %s' % result.error_before_exec)
39 print('result.error_in_exec = ', result.error_in_exec)
35
40 print('result.info = ', result.info)
41 print('result.result = ', result.result)
42
36 def load_ipython_extension(ip):
43 def load_ipython_extension(ip):
37 vw = VarWatcher(ip)
44 vw = VarWatcher(ip)
38 ip.events.register('pre_execute', vw.pre_execute)
45 ip.events.register('pre_execute', vw.pre_execute)
@@ -40,6 +47,13 b' For example::'
40 ip.events.register('post_execute', vw.post_execute)
47 ip.events.register('post_execute', vw.post_execute)
41 ip.events.register('post_run_cell', vw.post_run_cell)
48 ip.events.register('post_run_cell', vw.post_run_cell)
42
49
50 .. versionadded:: 8.3
51
52 Since IPython 8.3 and ipykernel 6.12.1, the ``info`` objects in the callback
53 now have a the ``cell_id`` that will be set to the value sent by the
54 frontened, when those send it.
55
56
43
57
44 Events
58 Events
45 ======
59 ======
@@ -135,7 +135,7 b' Metadata'
135 ^^^^^^^^
135 ^^^^^^^^
136
136
137 We often want to provide frontends with guidance on how to display the data. To
137 We often want to provide frontends with guidance on how to display the data. To
138 support this, ``_repr_*_()`` methods (except `_repr_pretty_``?) can also return a ``(data, metadata)``
138 support this, ``_repr_*_()`` methods (except ``_repr_pretty_``?) can also return a ``(data, metadata)``
139 tuple where ``metadata`` is a dictionary containing arbitrary key-value pairs for
139 tuple where ``metadata`` is a dictionary containing arbitrary key-value pairs for
140 the frontend to interpret. An example use case is ``_repr_jpeg_()``, which can
140 the frontend to interpret. An example use case is ``_repr_jpeg_()``, which can
141 be set to return a jpeg image and a ``{'height': 400, 'width': 600}`` dictionary
141 be set to return a jpeg image and a ``{'height': 400, 'width': 600}`` dictionary
@@ -10,7 +10,7 b' thought to render a number of mimetypes in the shell. This can be used to either'
10 display inline images if your terminal emulator supports it; or open some
10 display inline images if your terminal emulator supports it; or open some
11 display results with external file viewers.
11 display results with external file viewers.
12
12
13 Registering new mimetype handlers can so far only be done my extensions and
13 Registering new mimetype handlers can so far only be done by extensions and
14 requires 4 steps:
14 requires 4 steps:
15
15
16 - Define a callable that takes 2 parameters:``data`` and ``metadata``; return
16 - Define a callable that takes 2 parameters:``data`` and ``metadata``; return
@@ -17,9 +17,9 b' interactively. Its main components are:'
17 * A powerful interactive Python shell.
17 * A powerful interactive Python shell.
18
18
19
19
20 .. image:: ./_images/ipython-6-screenshot.png
20 .. image:: ./_images/ipython-6-screenshot.png
21 :alt: Screenshot of IPython 6.0
21 :alt: Screenshot of IPython 6.0
22 :align: center
22 :align: center
23
23
24
24
25 * A `Jupyter <https://jupyter.org/>`_ kernel to work with Python code in Jupyter
25 * A `Jupyter <https://jupyter.org/>`_ kernel to work with Python code in Jupyter
@@ -59,7 +59,7 b" while some other do not. We'll come to this later."
59 Depending on the exact command you are typing you might realize that sometimes
59 Depending on the exact command you are typing you might realize that sometimes
60 :kbd:`Enter` will add a new line, and sometimes it will execute the current
60 :kbd:`Enter` will add a new line, and sometimes it will execute the current
61 statement. IPython tries to guess what you are doing, so most of the time you
61 statement. IPython tries to guess what you are doing, so most of the time you
62 should not have to care. Though if by any chance IPython does not the right
62 should not have to care. Though if by any chance IPython does not do the right
63 thing you can force execution of the current code block by pressing in sequence
63 thing you can force execution of the current code block by pressing in sequence
64 :kbd:`Esc` and :kbd:`Enter`. You can also force the insertion of a new line at
64 :kbd:`Esc` and :kbd:`Enter`. You can also force the insertion of a new line at
65 the position of the cursor by using :kbd:`Ctrl-o`.
65 the position of the cursor by using :kbd:`Ctrl-o`.
@@ -20,9 +20,6 b''
20 .. _ipython: https://ipython.org
20 .. _ipython: https://ipython.org
21 .. _`ipython manual`: https://ipython.org/documentation.html
21 .. _`ipython manual`: https://ipython.org/documentation.html
22 .. _ipython_github: http://github.com/ipython/ipython/
22 .. _ipython_github: http://github.com/ipython/ipython/
23 .. _ipython_github_repo: http://github.com/ipython/ipython/
24 .. _ipython_downloads: https://ipython.org/download.html
25 .. _ipython_pypi: http://pypi.python.org/pypi/ipython
26 .. _nbviewer: http://nbviewer.ipython.org
23 .. _nbviewer: http://nbviewer.ipython.org
27
24
28 .. _ZeroMQ: http://zeromq.org
25 .. _ZeroMQ: http://zeromq.org
@@ -35,8 +32,7 b''
35 .. _reST: http://docutils.sourceforge.net/rst.html
32 .. _reST: http://docutils.sourceforge.net/rst.html
36 .. _docutils: http://docutils.sourceforge.net
33 .. _docutils: http://docutils.sourceforge.net
37 .. _lyx: http://www.lyx.org
34 .. _lyx: http://www.lyx.org
38 .. _pep8: http://www.python.org/dev/peps/pep-0008
35 .. _pep8: https://peps.python.org/pep-0008/
39 .. _numpy_coding_guide: https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
40
36
41 .. Licenses
37 .. Licenses
42 .. _GPL: http://www.gnu.org/licenses/gpl.html
38 .. _GPL: http://www.gnu.org/licenses/gpl.html
@@ -204,7 +204,7 b" suppress the seed line so it doesn't show up in the rendered output"
204 [0.22591016, 0.77731835],
204 [0.22591016, 0.77731835],
205 [0.0072729 , 0.34273127]])
205 [0.0072729 , 0.34273127]])
206
206
207 For more information on @supress and @doctest decorators, please refer to the end of this file in
207 For more information on @suppress and @doctest decorators, please refer to the end of this file in
208 Pseudo-Decorators section.
208 Pseudo-Decorators section.
209
209
210 Another demonstration of multi-line input and output
210 Another demonstration of multi-line input and output
@@ -51,9 +51,9 b' Pull requests (226):'
51 * `542 <https://github.com/ipython/ipython/issues/542>`_: issue 440
51 * `542 <https://github.com/ipython/ipython/issues/542>`_: issue 440
52 * `533 <https://github.com/ipython/ipython/issues/533>`_: Remove unused configobj and validate libraries from externals.
52 * `533 <https://github.com/ipython/ipython/issues/533>`_: Remove unused configobj and validate libraries from externals.
53 * `538 <https://github.com/ipython/ipython/issues/538>`_: fix various tests on Windows
53 * `538 <https://github.com/ipython/ipython/issues/538>`_: fix various tests on Windows
54 * `540 <https://github.com/ipython/ipython/issues/540>`_: support `-pylab` flag with deprecation warning
54 * `540 <https://github.com/ipython/ipython/issues/540>`_: support ``-pylab`` flag with deprecation warning
55 * `537 <https://github.com/ipython/ipython/issues/537>`_: Docs update
55 * `537 <https://github.com/ipython/ipython/issues/537>`_: Docs update
56 * `536 <https://github.com/ipython/ipython/issues/536>`_: `setup.py install` depends on setuptools on Windows
56 * `536 <https://github.com/ipython/ipython/issues/536>`_: ``setup.py install`` depends on setuptools on Windows
57 * `480 <https://github.com/ipython/ipython/issues/480>`_: Get help mid-command
57 * `480 <https://github.com/ipython/ipython/issues/480>`_: Get help mid-command
58 * `462 <https://github.com/ipython/ipython/issues/462>`_: Str and Bytes traitlets
58 * `462 <https://github.com/ipython/ipython/issues/462>`_: Str and Bytes traitlets
59 * `534 <https://github.com/ipython/ipython/issues/534>`_: Handle unicode properly in IPython.zmq.iostream
59 * `534 <https://github.com/ipython/ipython/issues/534>`_: Handle unicode properly in IPython.zmq.iostream
@@ -916,7 +916,7 b' Pull Requests (687):'
916 * :ghpull:`4444`: Css cleaning
916 * :ghpull:`4444`: Css cleaning
917 * :ghpull:`4523`: Use username and password for MongoDB on ShiningPanda
917 * :ghpull:`4523`: Use username and password for MongoDB on ShiningPanda
918 * :ghpull:`4510`: Update whatsnew from PR files
918 * :ghpull:`4510`: Update whatsnew from PR files
919 * :ghpull:`4441`: add `setup.py jsversion`
919 * :ghpull:`4441`: add ``setup.py jsversion``
920 * :ghpull:`4518`: Fix for race condition in url file decoding.
920 * :ghpull:`4518`: Fix for race condition in url file decoding.
921 * :ghpull:`4497`: don't automatically unpack datetime objects in the message spec
921 * :ghpull:`4497`: don't automatically unpack datetime objects in the message spec
922 * :ghpull:`4506`: wait for empty queues as well as load-balanced tasks
922 * :ghpull:`4506`: wait for empty queues as well as load-balanced tasks
@@ -1050,7 +1050,7 b' Pull Requests (687):'
1050 * :ghpull:`4214`: engine ID metadata should be unicode, not bytes
1050 * :ghpull:`4214`: engine ID metadata should be unicode, not bytes
1051 * :ghpull:`4232`: no highlight if no language specified
1051 * :ghpull:`4232`: no highlight if no language specified
1052 * :ghpull:`4218`: Fix display of SyntaxError when .py file is modified
1052 * :ghpull:`4218`: Fix display of SyntaxError when .py file is modified
1053 * :ghpull:`4207`: add `setup.py css` command
1053 * :ghpull:`4207`: add ``setup.py css`` command
1054 * :ghpull:`4224`: clear previous callbacks on execute
1054 * :ghpull:`4224`: clear previous callbacks on execute
1055 * :ghpull:`4180`: Iptest refactoring
1055 * :ghpull:`4180`: Iptest refactoring
1056 * :ghpull:`4105`: JS output area misaligned
1056 * :ghpull:`4105`: JS output area misaligned
@@ -81,7 +81,7 b' New features'
81 :mod:`IPython.kernel`, :mod:`IPython.kernel.core`, :mod:`traitlets.config`,
81 :mod:`IPython.kernel`, :mod:`IPython.kernel.core`, :mod:`traitlets.config`,
82 :mod:`IPython.tools` and :mod:`IPython.testing`.
82 :mod:`IPython.tools` and :mod:`IPython.testing`.
83
83
84 * As part of merging in the `ipython1-dev` stuff, the `setup.py` script and
84 * As part of merging in the `ipython1-dev` stuff, the ``setup.py`` script and
85 friends have been completely refactored. Now we are checking for
85 friends have been completely refactored. Now we are checking for
86 dependencies using the approach that matplotlib uses.
86 dependencies using the approach that matplotlib uses.
87
87
@@ -161,7 +161,7 b' Backwards incompatible changes'
161 `'basic'` to `'b'`.
161 `'basic'` to `'b'`.
162
162
163 * IPython has a larger set of dependencies if you want all of its capabilities.
163 * IPython has a larger set of dependencies if you want all of its capabilities.
164 See the `setup.py` script for details.
164 See the ``setup.py`` script for details.
165
165
166 * The constructors for :class:`IPython.kernel.client.MultiEngineClient` and
166 * The constructors for :class:`IPython.kernel.client.MultiEngineClient` and
167 :class:`IPython.kernel.client.TaskClient` no longer take the (ip,port) tuple.
167 :class:`IPython.kernel.client.TaskClient` no longer take the (ip,port) tuple.
@@ -277,7 +277,7 b' automatically upgrade to the latest version compatible with your system.'
277
277
278 The ability to use only Python 3 on the code base of IPython brings a number
278 The ability to use only Python 3 on the code base of IPython brings a number
279 of advantages. Most of the newly written code make use of `optional function type
279 of advantages. Most of the newly written code make use of `optional function type
280 annotation <https://www.python.org/dev/peps/pep-0484/>`_ leading to clearer code
280 annotation <https://peps.python.org/pep-0484/>`_ leading to clearer code
281 and better documentation.
281 and better documentation.
282
282
283 The total size of the repository has also decreased by about 1500 lines (for the
283 The total size of the repository has also decreased by about 1500 lines (for the
@@ -2,6 +2,17 b''
2 7.x Series
2 7.x Series
3 ============
3 ============
4
4
5 .. _version 7.33:
6
7 IPython 7.33
8 ============
9
10 - Allow IPython hooks to receive current cell ids when frontend support it. See
11 :ghpull:`13600`
12
13 - ``?`` does not trigger the insertion of a new cell anymore as most frontend
14 allow proper multiline edition. :ghpull:`13625`
15
5
16
6 .. _version 7.32:
17 .. _version 7.32:
7
18
@@ -9,11 +20,15 b' IPython 7.32'
9 ============
20 ============
10
21
11
22
23
24 Autoload magic lazily
25 ---------------------
26
12 The ability to configure magics to be lazily loaded has been added to IPython.
27 The ability to configure magics to be lazily loaded has been added to IPython.
13 See the ``ipython --help-all`` section on ``MagicsManager.lazy_magic``.
28 See the ``ipython --help-all`` section on ``MagicsManager.lazy_magic``.
14 One can now use::
29 One can now use::
15
30
16 c.MagicsManger.lazy_magics = {
31 c.MagicsManager.lazy_magics = {
17 "my_magic": "slow.to.import",
32 "my_magic": "slow.to.import",
18 "my_other_magic": "also.slow",
33 "my_other_magic": "also.slow",
19 }
34 }
@@ -21,6 +36,21 b' One can now use::'
21 And on first use of ``%my_magic``, or corresponding cell magic, or other line magic,
36 And on first use of ``%my_magic``, or corresponding cell magic, or other line magic,
22 the corresponding ``load_ext`` will be called just before trying to invoke the magic.
37 the corresponding ``load_ext`` will be called just before trying to invoke the magic.
23
38
39 Misc
40 ----
41
42 - Update sphinxify for Docrepr 0.2.0 :ghpull:`13503`.
43 - Set co_name for cells run line by line (to fix debugging with Python 3.10)
44 :ghpull:`13535`
45
46
47 Many thanks to all the contributors to this release. You can find all individual
48 contributions to this milestone `on github
49 <https://github.com/ipython/ipython/milestone/99>`__.
50
51 Thanks as well to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
52 work on IPython and related libraries.
53
24 .. _version 7.31:
54 .. _version 7.31:
25
55
26 IPython 7.31
56 IPython 7.31
@@ -3,6 +3,134 b''
3 ============
3 ============
4
4
5
5
6 .. _version 8.3.0:
7
8 IPython 8.3.0
9 -------------
10
11 - :ghpull:`13625`, using ``?``, ``??``, ``*?`` will not call
12 ``set_next_input`` as most frontend allow proper multiline editing and it was
13 causing issues for many users of multi-cell frontends. This has been backported to 7.33
14
15
16 - :ghpull:`13600`, ``pre_run_*``-hooks will now have a ``cell_id`` attribute on
17 the info object when frontend provide it. This has been backported to 7.33
18
19 - :ghpull:`13624`, fixed :kbd:`End` key being broken after accepting an
20 auto-suggestion.
21
22 - :ghpull:`13657` fix issue where history from different sessions would be mixed.
23
24 .. _version 8.2.0:
25
26 IPython 8.2.0
27 -------------
28
29 IPython 8.2 mostly bring bugfixes to IPython.
30
31 - Auto-suggestion can now be elected with the ``end`` key. :ghpull:`13566`
32 - Some traceback issues with ``assert etb is not None`` have been fixed. :ghpull:`13588`
33 - History is now pulled from the sqitel database and not from in-memory.
34 In particular when using the ``%paste`` magic, the content of the pasted text will
35 be part of the history and not the verbatim text ``%paste`` anymore. :ghpull:`13592`
36 - Fix ``Ctrl-\\`` exit cleanup :ghpull:`13603`
37 - Fixes to ``ultratb`` ipdb support when used outside of IPython. :ghpull:`13498`
38
39
40 I am still trying to fix and investigate :ghissue:`13598`, which seem to be
41 random, and would appreciate help if you find reproducible minimal case. I've
42 tried to make various changes to the codebase to mitigate it, but a proper fix
43 will be difficult without understanding the cause.
44
45
46 All the issues on pull-requests for this release can be found in the `8.2
47 milestone. <https://github.com/ipython/ipython/milestone/100>`__ . And some
48 documentation only PR can be found as part of the `7.33 milestone
49 <https://github.com/ipython/ipython/milestone/101>`__ (currently not released).
50
51 Thanks to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
52 work on IPython and related libraries.
53
54 .. _version 8.1.1:
55
56 IPython 8.1.1
57 -------------
58
59 Fix an issue with virtualenv and Python 3.8 introduced in 8.1
60
61 Revert :ghpull:`13537` (fix an issue with symlinks in virtualenv) that raises an
62 error in Python 3.8, and fixed in a different way in :ghpull:`13559`.
63
64 .. _version 8.1:
65
66 IPython 8.1.0
67 -------------
68
69 IPython 8.1 is the first minor release after 8.0 and fixes a number of bugs and
70 Update a few behavior that were problematic with the 8.0 as with many new major
71 release.
72
73 Note that beyond the changes listed here, IPython 8.1.0 also contains all the
74 features listed in :ref:`version 7.32`.
75
76 - Misc and multiple fixes around quotation auto-closing. It is now disabled by
77 default. Run with ``TerminalInteractiveShell.auto_match=True`` to re-enabled
78 - Require pygments>=2.4.0 :ghpull:`13459`, this was implicit in the code, but
79 is now explicit in ``setup.cfg``/``setup.py``
80 - Docs improvement of ``core.magic_arguments`` examples. :ghpull:`13433`
81 - Multi-line edit executes too early with await. :ghpull:`13424`
82
83 - ``black`` is back as an optional dependency, and autoformatting disabled by
84 default until some fixes are implemented (black improperly reformat magics).
85 :ghpull:`13471` Additionally the ability to use ``yapf`` as a code
86 reformatter has been added :ghpull:`13528` . You can use
87 ``TerminalInteractiveShell.autoformatter="black"``,
88 ``TerminalInteractiveShell.autoformatter="yapf"`` to re-enable auto formating
89 with black, or switch to yapf.
90
91 - Fix and issue where ``display`` was not defined.
92
93 - Auto suggestions are now configurable. Currently only
94 ``AutoSuggestFromHistory`` (default) and ``None``. new provider contribution
95 welcomed. :ghpull:`13475`
96
97 - multiple packaging/testing improvement to simplify downstream packaging
98 (xfail with reasons, try to not access network...).
99
100 - Update deprecation. ``InteractiveShell.magic`` internal method has been
101 deprecated for many years but did not emit a warning until now.
102
103 - internal ``appended_to_syspath`` context manager has been deprecated.
104
105 - fix an issue with symlinks in virtualenv :ghpull:`13537` (Reverted in 8.1.1)
106
107 - Fix an issue with vim mode, where cursor would not be reset on exit :ghpull:`13472`
108
109 - ipython directive now remove only known pseudo-decorators :ghpull:`13532`
110
111 - ``IPython/lib/security`` which used to be used for jupyter notebook has been
112 removed.
113
114 - Fix an issue where ``async with`` would execute on new lines. :ghpull:`13436`
115
116
117 We want to remind users that IPython is part of the Jupyter organisations, and
118 thus governed by a Code of Conduct. Some of the behavior we have seen on GitHub is not acceptable.
119 Abuse and non-respectful comments on discussion will not be tolerated.
120
121 Many thanks to all the contributors to this release, many of the above fixed issue and
122 new features where done by first time contributors, showing there is still
123 plenty of easy contribution possible in IPython
124 . You can find all individual contributions
125 to this milestone `on github <https://github.com/ipython/ipython/milestone/91>`__.
126
127 Thanks as well to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
128 work on IPython and related libraries. In particular the Lazy autoloading of
129 magics that you will find described in the 7.32 release notes.
130
131
132 .. _version 8.0.1:
133
6 IPython 8.0.1 (CVE-2022-21699)
134 IPython 8.0.1 (CVE-2022-21699)
7 ------------------------------
135 ------------------------------
8
136
@@ -45,6 +173,7 b' Thus starting with this version:'
45 Further details can be read on the `GitHub Advisory <https://github.com/ipython/ipython/security/advisories/GHSA-pq7m-3gw7-gq5x>`__
173 Further details can be read on the `GitHub Advisory <https://github.com/ipython/ipython/security/advisories/GHSA-pq7m-3gw7-gq5x>`__
46
174
47
175
176 .. _version 8.0:
48
177
49 IPython 8.0
178 IPython 8.0
50 -----------
179 -----------
@@ -344,12 +473,11 b' For more information please see the following unit test : ``extensions/tests/tes'
344 Auto formatting with black in the CLI
473 Auto formatting with black in the CLI
345 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
474 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
346
475
347 If ``black`` is installed in the same environment as IPython, terminal IPython
348 will now *by default* reformat the code in the CLI when possible. You can
349 disable this with ``--TerminalInteractiveShell.autoformatter=None``.
350
351 This feature was present in 7.x, but disabled by default.
476 This feature was present in 7.x, but disabled by default.
352
477
478 In 8.0, input was automatically reformatted with Black when black was installed.
479 This feature has been reverted for the time being.
480 You can re-enable it by setting ``TerminalInteractiveShell.autoformatter`` to ``"black"``
353
481
354 History Range Glob feature
482 History Range Glob feature
355 ~~~~~~~~~~~~~~~~~~~~~~~~~~
483 ~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -393,8 +521,8 b' Automatic Vi prompt stripping'
393
521
394 When pasting code into IPython, it will strip the leading prompt characters if
522 When pasting code into IPython, it will strip the leading prompt characters if
395 there are any. For example, you can paste the following code into the console -
523 there are any. For example, you can paste the following code into the console -
396 it will still work, even though each line is prefixed with prompts (`In`,
524 it will still work, even though each line is prefixed with prompts (``In``,
397 `Out`)::
525 ``Out``)::
398
526
399 In [1]: 2 * 2 == 4
527 In [1]: 2 * 2 == 4
400 Out[1]: True
528 Out[1]: True
@@ -489,7 +617,7 b' who did a fantastic job at updating our code base, migrating to pytest, pushing'
489 our coverage, and fixing a large number of bugs. I highly recommend contacting
617 our coverage, and fixing a large number of bugs. I highly recommend contacting
490 them if you need help with C++ and Python projects.
618 them if you need help with C++ and Python projects.
491
619
492 You can find all relevant issues and PRs with the SDG 2021 tag `<https://github.com/ipython/ipython/issues?q=label%3A%22Numfocus+SDG+2021%22+>`__
620 You can find all relevant issues and PRs with `the SDG 2021 tag <https://github.com/ipython/ipython/issues?q=label%3A%22Numfocus+SDG+2021%22+>`__
493
621
494 Removing support for older Python versions
622 Removing support for older Python versions
495 ------------------------------------------
623 ------------------------------------------
@@ -15,7 +15,7 b''
15 "This is made difficult by the fact that Notebooks are not plain Python files,\n",
15 "This is made difficult by the fact that Notebooks are not plain Python files,\n",
16 "and thus cannot be imported by the regular Python machinery.\n",
16 "and thus cannot be imported by the regular Python machinery.\n",
17 "\n",
17 "\n",
18 "Fortunately, Python provides some fairly sophisticated [hooks](http://www.python.org/dev/peps/pep-0302/) into the import machinery,\n",
18 "Fortunately, Python provides some fairly sophisticated [hooks](https://peps.python.org/pep-0302/) into the import machinery,\n",
19 "so we can actually make IPython notebooks importable without much difficulty,\n",
19 "so we can actually make IPython notebooks importable without much difficulty,\n",
20 "and only using public APIs."
20 "and only using public APIs."
21 ]
21 ]
@@ -45,3 +45,4 b' addopts = --durations=10'
45 --ignore=IPython/utils/version.py
45 --ignore=IPython/utils/version.py
46 doctest_optionflags = NORMALIZE_WHITESPACE ELLIPSIS
46 doctest_optionflags = NORMALIZE_WHITESPACE ELLIPSIS
47 ipdoctest_optionflags = NORMALIZE_WHITESPACE ELLIPSIS
47 ipdoctest_optionflags = NORMALIZE_WHITESPACE ELLIPSIS
48 asyncio_mode = strict
@@ -63,17 +63,16 b' qtconsole ='
63 qtconsole
63 qtconsole
64 terminal =
64 terminal =
65 test =
65 test =
66 pytest<7
66 pytest<7.1
67 pytest-asyncio
67 pytest-asyncio
68 testpath
68 testpath
69 test_extra =
69 test_extra =
70 %(test)s
70 curio
71 curio
71 matplotlib!=3.2.0
72 matplotlib!=3.2.0
72 nbformat
73 nbformat
73 numpy>=1.19
74 numpy>=1.19
74 pandas
75 pandas
75 pytest<7
76 testpath
77 trio
76 trio
78 all =
77 all =
79 %(black)s
78 %(black)s
@@ -18,7 +18,6 b' requires utilities which are not available under Windows."""'
18
18
19 import os
19 import os
20 import sys
20 import sys
21 from itertools import chain
22
21
23 # **Python version check**
22 # **Python version check**
24 #
23 #
@@ -53,7 +52,9 b' See IPython `README.rst` file for more information:'
53
52
54 Python {py} detected.
53 Python {py} detected.
55 {pip}
54 {pip}
56 """.format(py=sys.version_info, pip=pip_message )
55 """.format(
56 py=sys.version_info, pip=pip_message
57 )
57
58
58 print(error, file=sys.stderr)
59 print(error, file=sys.stderr)
59 sys.exit(1)
60 sys.exit(1)
@@ -111,7 +111,7 b' then'
111 sleep 1
111 sleep 1
112 echo $BLUE"Saving API to file $PREV_RELEASE"$NOR
112 echo $BLUE"Saving API to file $PREV_RELEASE"$NOR
113 frappuccino IPython IPython.kernel IPython.lib IPython.qt IPython.lib.kernel IPython.html IPython.frontend IPython.external --save IPython-$PREV_RELEASE.json
113 frappuccino IPython IPython.kernel IPython.lib IPython.qt IPython.lib.kernel IPython.html IPython.frontend IPython.external --save IPython-$PREV_RELEASE.json
114 echo $BLUE"comming back to $BRANCH"$NOR
114 echo $BLUE"coming back to $BRANCH"$NOR
115 git checkout $BRANCH
115 git checkout $BRANCH
116 sleep 1
116 sleep 1
117 echo $BLUE"comparing ..."$NOR
117 echo $BLUE"comparing ..."$NOR
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now