##// END OF EJS Templates
Merge branch 'main' into shaperilio/autoreload-verbosity
Emilio Graff -
r27880:51eb040f merge
parent child Browse files
Show More
@@ -0,0 +1,3 b''
1 import os
2
3 GENERATING_DOCUMENTATION = os.environ.get("IN_SPHINX_RUN", None) == "True"
@@ -1,39 +1,39 b''
1 # This workflow will install Python dependencies, run tests and lint with a variety of Python versions
1 # This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2 # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
2 # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3
3
4 name: Python package
4 name: Python package
5
5
6 permissions:
6 permissions:
7 contents: read
7 contents: read
8
8
9 on:
9 on:
10 push:
10 push:
11 branches: [ main, 7.x ]
11 branches: [ main, 7.x ]
12 pull_request:
12 pull_request:
13 branches: [ main, 7.x ]
13 branches: [ main, 7.x ]
14
14
15 jobs:
15 jobs:
16 formatting:
16 formatting:
17
17
18 runs-on: ubuntu-latest
18 runs-on: ubuntu-latest
19 timeout-minutes: 5
19 timeout-minutes: 5
20 steps:
20 steps:
21 - uses: actions/checkout@v3
21 - uses: actions/checkout@v3
22 with:
22 with:
23 fetch-depth: 0
23 fetch-depth: 0
24 - name: Set up Python
24 - name: Set up Python
25 uses: actions/setup-python@v4
25 uses: actions/setup-python@v4
26 with:
26 with:
27 python-version: 3.x
27 python-version: 3.x
28 - name: Install dependencies
28 - name: Install dependencies
29 run: |
29 run: |
30 python -m pip install --upgrade pip
30 python -m pip install --upgrade pip
31 pip install darker black==21.12b0
31 pip install darker==1.5.1 black==22.10.0
32 - name: Lint with darker
32 - name: Lint with darker
33 run: |
33 run: |
34 darker -r 60625f241f298b5039cb2debc365db38aa7bb522 --check --diff . || (
34 darker -r 60625f241f298b5039cb2debc365db38aa7bb522 --check --diff . || (
35 echo "Changes need auto-formatting. Run:"
35 echo "Changes need auto-formatting. Run:"
36 echo " darker -r 60625f241f298b5039cb2debc365db38aa7bb522"
36 echo " darker -r 60625f241f298b5039cb2debc365db38aa7bb522"
37 echo "then commit and push changes to fix."
37 echo "then commit and push changes to fix."
38 exit 1
38 exit 1
39 )
39 )
@@ -1,40 +1,39 b''
1 MANIFEST
1 MANIFEST
2 build
2 build
3 dist
3 dist
4 _build
4 _build
5 docs/man/*.gz
5 docs/man/*.gz
6 docs/source/api/generated
6 docs/source/api/generated
7 docs/source/config/options
7 docs/source/config/options
8 docs/source/config/shortcuts/*.csv
8 docs/source/config/shortcuts/*.csv
9 docs/source/savefig
9 docs/source/savefig
10 docs/source/interactive/magics-generated.txt
10 docs/source/interactive/magics-generated.txt
11 docs/gh-pages
11 docs/gh-pages
12 jupyter_notebook/notebook/static/mathjax
12 jupyter_notebook/notebook/static/mathjax
13 jupyter_notebook/static/style/*.map
13 jupyter_notebook/static/style/*.map
14 *.py[co]
14 *.py[co]
15 __pycache__
15 __pycache__
16 *.egg-info
16 *.egg-info
17 *~
17 *~
18 *.bak
18 *.bak
19 .ipynb_checkpoints
19 .ipynb_checkpoints
20 .tox
20 .tox
21 .DS_Store
21 .DS_Store
22 \#*#
22 \#*#
23 .#*
23 .#*
24 .cache
24 .cache
25 .coverage
25 .coverage
26 *.swp
26 *.swp
27 .vscode
28 .pytest_cache
27 .pytest_cache
29 .python-version
28 .python-version
30 venv*/
29 venv*/
31 .mypy_cache/
30 .mypy_cache/
32
31
33 # jetbrains ide stuff
32 # jetbrains ide stuff
34 *.iml
33 *.iml
35 .idea/
34 .idea/
36
35
37 # vscode ide stuff
36 # vscode ide stuff
38 *.code-workspace
37 *.code-workspace
39 .history
38 .history
40 .vscode
39 .vscode
@@ -1,196 +1,199 b''
1 """Compiler tools with improved interactive support.
1 """Compiler tools with improved interactive support.
2
2
3 Provides compilation machinery similar to codeop, but with caching support so
3 Provides compilation machinery similar to codeop, but with caching support so
4 we can provide interactive tracebacks.
4 we can provide interactive tracebacks.
5
5
6 Authors
6 Authors
7 -------
7 -------
8 * Robert Kern
8 * Robert Kern
9 * Fernando Perez
9 * Fernando Perez
10 * Thomas Kluyver
10 * Thomas Kluyver
11 """
11 """
12
12
13 # Note: though it might be more natural to name this module 'compiler', that
13 # Note: though it might be more natural to name this module 'compiler', that
14 # name is in the stdlib and name collisions with the stdlib tend to produce
14 # name is in the stdlib and name collisions with the stdlib tend to produce
15 # weird problems (often with third-party tools).
15 # weird problems (often with third-party tools).
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2010-2011 The IPython Development Team.
18 # Copyright (C) 2010-2011 The IPython Development Team.
19 #
19 #
20 # Distributed under the terms of the BSD License.
20 # Distributed under the terms of the BSD License.
21 #
21 #
22 # The full license is in the file COPYING.txt, distributed with this software.
22 # The full license is in the file COPYING.txt, distributed with this software.
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Imports
26 # Imports
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 # Stdlib imports
29 # Stdlib imports
30 import __future__
30 import __future__
31 from ast import PyCF_ONLY_AST
31 from ast import PyCF_ONLY_AST
32 import codeop
32 import codeop
33 import functools
33 import functools
34 import hashlib
34 import hashlib
35 import linecache
35 import linecache
36 import operator
36 import operator
37 import time
37 import time
38 from contextlib import contextmanager
38 from contextlib import contextmanager
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Constants
41 # Constants
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 # Roughly equal to PyCF_MASK | PyCF_MASK_OBSOLETE as defined in pythonrun.h,
44 # Roughly equal to PyCF_MASK | PyCF_MASK_OBSOLETE as defined in pythonrun.h,
45 # this is used as a bitmask to extract future-related code flags.
45 # this is used as a bitmask to extract future-related code flags.
46 PyCF_MASK = functools.reduce(operator.or_,
46 PyCF_MASK = functools.reduce(operator.or_,
47 (getattr(__future__, fname).compiler_flag
47 (getattr(__future__, fname).compiler_flag
48 for fname in __future__.all_feature_names))
48 for fname in __future__.all_feature_names))
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Local utilities
51 # Local utilities
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53
53
54 def code_name(code, number=0):
54 def code_name(code, number=0):
55 """ Compute a (probably) unique name for code for caching.
55 """ Compute a (probably) unique name for code for caching.
56
56
57 This now expects code to be unicode.
57 This now expects code to be unicode.
58 """
58 """
59 hash_digest = hashlib.sha1(code.encode("utf-8")).hexdigest()
59 hash_digest = hashlib.sha1(code.encode("utf-8")).hexdigest()
60 # Include the number and 12 characters of the hash in the name. It's
60 # Include the number and 12 characters of the hash in the name. It's
61 # pretty much impossible that in a single session we'll have collisions
61 # pretty much impossible that in a single session we'll have collisions
62 # even with truncated hashes, and the full one makes tracebacks too long
62 # even with truncated hashes, and the full one makes tracebacks too long
63 return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
63 return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
64
64
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66 # Classes and functions
66 # Classes and functions
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68
68
69 class CachingCompiler(codeop.Compile):
69 class CachingCompiler(codeop.Compile):
70 """A compiler that caches code compiled from interactive statements.
70 """A compiler that caches code compiled from interactive statements.
71 """
71 """
72
72
73 def __init__(self):
73 def __init__(self):
74 codeop.Compile.__init__(self)
74 codeop.Compile.__init__(self)
75
75
76 # This is ugly, but it must be done this way to allow multiple
77 # simultaneous ipython instances to coexist. Since Python itself
78 # directly accesses the data structures in the linecache module, and
79 # the cache therein is global, we must work with that data structure.
80 # We must hold a reference to the original checkcache routine and call
81 # that in our own check_cache() below, but the special IPython cache
82 # must also be shared by all IPython instances. If we were to hold
83 # separate caches (one in each CachingCompiler instance), any call made
84 # by Python itself to linecache.checkcache() would obliterate the
85 # cached data from the other IPython instances.
86 if not hasattr(linecache, '_ipython_cache'):
87 linecache._ipython_cache = {}
88 if not hasattr(linecache, '_checkcache_ori'):
89 linecache._checkcache_ori = linecache.checkcache
90 # Now, we must monkeypatch the linecache directly so that parts of the
91 # stdlib that call it outside our control go through our codepath
92 # (otherwise we'd lose our tracebacks).
93 linecache.checkcache = check_linecache_ipython
94
95 # Caching a dictionary { filename: execution_count } for nicely
76 # Caching a dictionary { filename: execution_count } for nicely
96 # rendered tracebacks. The filename corresponds to the filename
77 # rendered tracebacks. The filename corresponds to the filename
97 # argument used for the builtins.compile function.
78 # argument used for the builtins.compile function.
98 self._filename_map = {}
79 self._filename_map = {}
99
80
100 def ast_parse(self, source, filename='<unknown>', symbol='exec'):
81 def ast_parse(self, source, filename='<unknown>', symbol='exec'):
101 """Parse code to an AST with the current compiler flags active.
82 """Parse code to an AST with the current compiler flags active.
102
83
103 Arguments are exactly the same as ast.parse (in the standard library),
84 Arguments are exactly the same as ast.parse (in the standard library),
104 and are passed to the built-in compile function."""
85 and are passed to the built-in compile function."""
105 return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
86 return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
106
87
107 def reset_compiler_flags(self):
88 def reset_compiler_flags(self):
108 """Reset compiler flags to default state."""
89 """Reset compiler flags to default state."""
109 # This value is copied from codeop.Compile.__init__, so if that ever
90 # This value is copied from codeop.Compile.__init__, so if that ever
110 # changes, it will need to be updated.
91 # changes, it will need to be updated.
111 self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
92 self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
112
93
113 @property
94 @property
114 def compiler_flags(self):
95 def compiler_flags(self):
115 """Flags currently active in the compilation process.
96 """Flags currently active in the compilation process.
116 """
97 """
117 return self.flags
98 return self.flags
118
99
119 def get_code_name(self, raw_code, transformed_code, number):
100 def get_code_name(self, raw_code, transformed_code, number):
120 """Compute filename given the code, and the cell number.
101 """Compute filename given the code, and the cell number.
121
102
122 Parameters
103 Parameters
123 ----------
104 ----------
124 raw_code : str
105 raw_code : str
125 The raw cell code.
106 The raw cell code.
126 transformed_code : str
107 transformed_code : str
127 The executable Python source code to cache and compile.
108 The executable Python source code to cache and compile.
128 number : int
109 number : int
129 A number which forms part of the code's name. Used for the execution
110 A number which forms part of the code's name. Used for the execution
130 counter.
111 counter.
131
112
132 Returns
113 Returns
133 -------
114 -------
134 The computed filename.
115 The computed filename.
135 """
116 """
136 return code_name(transformed_code, number)
117 return code_name(transformed_code, number)
137
118
138 def cache(self, transformed_code, number=0, raw_code=None):
119 def cache(self, transformed_code, number=0, raw_code=None):
139 """Make a name for a block of code, and cache the code.
120 """Make a name for a block of code, and cache the code.
140
121
141 Parameters
122 Parameters
142 ----------
123 ----------
143 transformed_code : str
124 transformed_code : str
144 The executable Python source code to cache and compile.
125 The executable Python source code to cache and compile.
145 number : int
126 number : int
146 A number which forms part of the code's name. Used for the execution
127 A number which forms part of the code's name. Used for the execution
147 counter.
128 counter.
148 raw_code : str
129 raw_code : str
149 The raw code before transformation, if None, set to `transformed_code`.
130 The raw code before transformation, if None, set to `transformed_code`.
150
131
151 Returns
132 Returns
152 -------
133 -------
153 The name of the cached code (as a string). Pass this as the filename
134 The name of the cached code (as a string). Pass this as the filename
154 argument to compilation, so that tracebacks are correctly hooked up.
135 argument to compilation, so that tracebacks are correctly hooked up.
155 """
136 """
156 if raw_code is None:
137 if raw_code is None:
157 raw_code = transformed_code
138 raw_code = transformed_code
158
139
159 name = self.get_code_name(raw_code, transformed_code, number)
140 name = self.get_code_name(raw_code, transformed_code, number)
160
141
161 # Save the execution count
142 # Save the execution count
162 self._filename_map[name] = number
143 self._filename_map[name] = number
163
144
145 # Since Python 2.5, setting mtime to `None` means the lines will
146 # never be removed by `linecache.checkcache`. This means all the
147 # monkeypatching has *never* been necessary, since this code was
148 # only added in 2010, at which point IPython had already stopped
149 # supporting Python 2.4.
150 #
151 # Note that `linecache.clearcache` and `linecache.updatecache` may
152 # still remove our code from the cache, but those show explicit
153 # intent, and we should not try to interfere. Normally the former
154 # is never called except when out of memory, and the latter is only
155 # called for lines *not* in the cache.
164 entry = (
156 entry = (
165 len(transformed_code),
157 len(transformed_code),
166 time.time(),
158 None,
167 [line + "\n" for line in transformed_code.splitlines()],
159 [line + "\n" for line in transformed_code.splitlines()],
168 name,
160 name,
169 )
161 )
170 linecache.cache[name] = entry
162 linecache.cache[name] = entry
171 linecache._ipython_cache[name] = entry
172 return name
163 return name
173
164
174 @contextmanager
165 @contextmanager
175 def extra_flags(self, flags):
166 def extra_flags(self, flags):
176 ## bits that we'll set to 1
167 ## bits that we'll set to 1
177 turn_on_bits = ~self.flags & flags
168 turn_on_bits = ~self.flags & flags
178
169
179
170
180 self.flags = self.flags | flags
171 self.flags = self.flags | flags
181 try:
172 try:
182 yield
173 yield
183 finally:
174 finally:
184 # turn off only the bits we turned on so that something like
175 # turn off only the bits we turned on so that something like
185 # __future__ that set flags stays.
176 # __future__ that set flags stays.
186 self.flags &= ~turn_on_bits
177 self.flags &= ~turn_on_bits
187
178
188
179
189 def check_linecache_ipython(*args):
180 def check_linecache_ipython(*args):
190 """Call linecache.checkcache() safely protecting our cached values.
181 """Deprecated since IPython 8.6. Call linecache.checkcache() directly.
182
183 It was already not necessary to call this function directly. If no
184 CachingCompiler had been created, this function would fail badly. If
185 an instance had been created, this function would've been monkeypatched
186 into place.
187
188 As of IPython 8.6, the monkeypatching has gone away entirely. But there
189 were still internal callers of this function, so maybe external callers
190 also existed?
191 """
191 """
192 # First call the original checkcache as intended
192 import warnings
193 linecache._checkcache_ori(*args)
193
194 # Then, update back the cache with our data, so that tracebacks related
194 warnings.warn(
195 # to our compiled codes can be produced.
195 "Deprecated Since IPython 8.6, Just call linecache.checkcache() directly.",
196 linecache.cache.update(linecache._ipython_cache)
196 DeprecationWarning,
197 stacklevel=2,
198 )
199 linecache.checkcache()
This diff has been collapsed as it changes many lines, (973 lines changed) Show them Hide them
@@ -1,2276 +1,2957 b''
1 """Completion for IPython.
1 """Completion for IPython.
2
2
3 This module started as fork of the rlcompleter module in the Python standard
3 This module started as fork of the rlcompleter module in the Python standard
4 library. The original enhancements made to rlcompleter have been sent
4 library. The original enhancements made to rlcompleter have been sent
5 upstream and were accepted as of Python 2.3,
5 upstream and were accepted as of Python 2.3,
6
6
7 This module now support a wide variety of completion mechanism both available
7 This module now support a wide variety of completion mechanism both available
8 for normal classic Python code, as well as completer for IPython specific
8 for normal classic Python code, as well as completer for IPython specific
9 Syntax like magics.
9 Syntax like magics.
10
10
11 Latex and Unicode completion
11 Latex and Unicode completion
12 ============================
12 ============================
13
13
14 IPython and compatible frontends not only can complete your code, but can help
14 IPython and compatible frontends not only can complete your code, but can help
15 you to input a wide range of characters. In particular we allow you to insert
15 you to input a wide range of characters. In particular we allow you to insert
16 a unicode character using the tab completion mechanism.
16 a unicode character using the tab completion mechanism.
17
17
18 Forward latex/unicode completion
18 Forward latex/unicode completion
19 --------------------------------
19 --------------------------------
20
20
21 Forward completion allows you to easily type a unicode character using its latex
21 Forward completion allows you to easily type a unicode character using its latex
22 name, or unicode long description. To do so type a backslash follow by the
22 name, or unicode long description. To do so type a backslash follow by the
23 relevant name and press tab:
23 relevant name and press tab:
24
24
25
25
26 Using latex completion:
26 Using latex completion:
27
27
28 .. code::
28 .. code::
29
29
30 \\alpha<tab>
30 \\alpha<tab>
31 α
31 α
32
32
33 or using unicode completion:
33 or using unicode completion:
34
34
35
35
36 .. code::
36 .. code::
37
37
38 \\GREEK SMALL LETTER ALPHA<tab>
38 \\GREEK SMALL LETTER ALPHA<tab>
39 α
39 α
40
40
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
48 Backward latex completion
48 Backward latex completion
49 -------------------------
49 -------------------------
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
57 \\α<tab>
57 \\α<tab>
58 \\alpha
58 \\alpha
59
59
60
60
61 Both forward and backward completions can be deactivated by setting the
61 Both forward and backward completions can be deactivated by setting the
62 ``Completer.backslash_combining_completions`` option to ``False``.
62 ``Completer.backslash_combining_completions`` option to ``False``.
63
63
64
64
65 Experimental
65 Experimental
66 ============
66 ============
67
67
68 Starting with IPython 6.0, this module can make use of the Jedi library to
68 Starting with IPython 6.0, this module can make use of the Jedi library to
69 generate completions both using static analysis of the code, and dynamically
69 generate completions both using static analysis of the code, and dynamically
70 inspecting multiple namespaces. Jedi is an autocompletion and static analysis
70 inspecting multiple namespaces. Jedi is an autocompletion and static analysis
71 for Python. The APIs attached to this new mechanism is unstable and will
71 for Python. The APIs attached to this new mechanism is unstable and will
72 raise unless use in an :any:`provisionalcompleter` context manager.
72 raise unless use in an :any:`provisionalcompleter` context manager.
73
73
74 You will find that the following are experimental:
74 You will find that the following are experimental:
75
75
76 - :any:`provisionalcompleter`
76 - :any:`provisionalcompleter`
77 - :any:`IPCompleter.completions`
77 - :any:`IPCompleter.completions`
78 - :any:`Completion`
78 - :any:`Completion`
79 - :any:`rectify_completions`
79 - :any:`rectify_completions`
80
80
81 .. note::
81 .. note::
82
82
83 better name for :any:`rectify_completions` ?
83 better name for :any:`rectify_completions` ?
84
84
85 We welcome any feedback on these new API, and we also encourage you to try this
85 We welcome any feedback on these new API, and we also encourage you to try this
86 module in debug mode (start IPython with ``--Completer.debug=True``) in order
86 module in debug mode (start IPython with ``--Completer.debug=True``) in order
87 to have extra logging information if :any:`jedi` is crashing, or if current
87 to have extra logging information if :any:`jedi` is crashing, or if current
88 IPython completer pending deprecations are returning results not yet handled
88 IPython completer pending deprecations are returning results not yet handled
89 by :any:`jedi`
89 by :any:`jedi`
90
90
91 Using Jedi for tab completion allow snippets like the following to work without
91 Using Jedi for tab completion allow snippets like the following to work without
92 having to execute any code:
92 having to execute any code:
93
93
94 >>> myvar = ['hello', 42]
94 >>> myvar = ['hello', 42]
95 ... myvar[1].bi<tab>
95 ... myvar[1].bi<tab>
96
96
97 Tab completion will be able to infer that ``myvar[1]`` is a real number without
97 Tab completion will be able to infer that ``myvar[1]`` is a real number without
98 executing any code unlike the previously available ``IPCompleter.greedy``
98 executing any code unlike the previously available ``IPCompleter.greedy``
99 option.
99 option.
100
100
101 Be sure to update :any:`jedi` to the latest stable version or to try the
101 Be sure to update :any:`jedi` to the latest stable version or to try the
102 current development version to get better completions.
102 current development version to get better completions.
103
104 Matchers
105 ========
106
107 All completions routines are implemented using unified *Matchers* API.
108 The matchers API is provisional and subject to change without notice.
109
110 The built-in matchers include:
111
112 - :any:`IPCompleter.dict_key_matcher`: dictionary key completions,
113 - :any:`IPCompleter.magic_matcher`: completions for magics,
114 - :any:`IPCompleter.unicode_name_matcher`,
115 :any:`IPCompleter.fwd_unicode_matcher`
116 and :any:`IPCompleter.latex_name_matcher`: see `Forward latex/unicode completion`_,
117 - :any:`back_unicode_name_matcher` and :any:`back_latex_name_matcher`: see `Backward latex completion`_,
118 - :any:`IPCompleter.file_matcher`: paths to files and directories,
119 - :any:`IPCompleter.python_func_kw_matcher` - function keywords,
120 - :any:`IPCompleter.python_matches` - globals and attributes (v1 API),
121 - ``IPCompleter.jedi_matcher`` - static analysis with Jedi,
122 - :any:`IPCompleter.custom_completer_matcher` - pluggable completer with a default
123 implementation in :any:`InteractiveShell` which uses IPython hooks system
124 (`complete_command`) with string dispatch (including regular expressions).
125 Differently to other matchers, ``custom_completer_matcher`` will not suppress
126 Jedi results to match behaviour in earlier IPython versions.
127
128 Custom matchers can be added by appending to ``IPCompleter.custom_matchers`` list.
129
130 Matcher API
131 -----------
132
133 Simplifying some details, the ``Matcher`` interface can described as
134
135 .. code-block::
136
137 MatcherAPIv1 = Callable[[str], list[str]]
138 MatcherAPIv2 = Callable[[CompletionContext], SimpleMatcherResult]
139
140 Matcher = MatcherAPIv1 | MatcherAPIv2
141
142 The ``MatcherAPIv1`` reflects the matcher API as available prior to IPython 8.6.0
143 and remains supported as a simplest way for generating completions. This is also
144 currently the only API supported by the IPython hooks system `complete_command`.
145
146 To distinguish between matcher versions ``matcher_api_version`` attribute is used.
147 More precisely, the API allows to omit ``matcher_api_version`` for v1 Matchers,
148 and requires a literal ``2`` for v2 Matchers.
149
150 Once the API stabilises future versions may relax the requirement for specifying
151 ``matcher_api_version`` by switching to :any:`functools.singledispatch`, therefore
152 please do not rely on the presence of ``matcher_api_version`` for any purposes.
153
154 Suppression of competing matchers
155 ---------------------------------
156
157 By default results from all matchers are combined, in the order determined by
158 their priority. Matchers can request to suppress results from subsequent
159 matchers by setting ``suppress`` to ``True`` in the ``MatcherResult``.
160
161 When multiple matchers simultaneously request surpression, the results from of
162 the matcher with higher priority will be returned.
163
164 Sometimes it is desirable to suppress most but not all other matchers;
165 this can be achieved by adding a list of identifiers of matchers which
166 should not be suppressed to ``MatcherResult`` under ``do_not_suppress`` key.
167
168 The suppression behaviour can is user-configurable via
169 :any:`IPCompleter.suppress_competing_matchers`.
103 """
170 """
104
171
105
172
106 # Copyright (c) IPython Development Team.
173 # Copyright (c) IPython Development Team.
107 # Distributed under the terms of the Modified BSD License.
174 # Distributed under the terms of the Modified BSD License.
108 #
175 #
109 # Some of this code originated from rlcompleter in the Python standard library
176 # Some of this code originated from rlcompleter in the Python standard library
110 # Copyright (C) 2001 Python Software Foundation, www.python.org
177 # Copyright (C) 2001 Python Software Foundation, www.python.org
111
178
112
179 from __future__ import annotations
113 import builtins as builtin_mod
180 import builtins as builtin_mod
114 import glob
181 import glob
115 import inspect
182 import inspect
116 import itertools
183 import itertools
117 import keyword
184 import keyword
118 import os
185 import os
119 import re
186 import re
120 import string
187 import string
121 import sys
188 import sys
122 import time
189 import time
123 import unicodedata
190 import unicodedata
124 import uuid
191 import uuid
125 import warnings
192 import warnings
126 from contextlib import contextmanager
193 from contextlib import contextmanager
194 from dataclasses import dataclass
195 from functools import cached_property, partial
127 from importlib import import_module
196 from importlib import import_module
128 from types import SimpleNamespace
197 from types import SimpleNamespace
129 from typing import Iterable, Iterator, List, Tuple, Union, Any, Sequence, Dict, NamedTuple, Pattern, Optional
198 from typing import (
199 Iterable,
200 Iterator,
201 List,
202 Tuple,
203 Union,
204 Any,
205 Sequence,
206 Dict,
207 NamedTuple,
208 Pattern,
209 Optional,
210 TYPE_CHECKING,
211 Set,
212 Literal,
213 )
130
214
131 from IPython.core.error import TryNext
215 from IPython.core.error import TryNext
132 from IPython.core.inputtransformer2 import ESC_MAGIC
216 from IPython.core.inputtransformer2 import ESC_MAGIC
133 from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol
217 from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol
134 from IPython.core.oinspect import InspectColors
218 from IPython.core.oinspect import InspectColors
135 from IPython.testing.skipdoctest import skip_doctest
219 from IPython.testing.skipdoctest import skip_doctest
136 from IPython.utils import generics
220 from IPython.utils import generics
221 from IPython.utils.decorators import sphinx_options
137 from IPython.utils.dir2 import dir2, get_real_method
222 from IPython.utils.dir2 import dir2, get_real_method
223 from IPython.utils.docs import GENERATING_DOCUMENTATION
138 from IPython.utils.path import ensure_dir_exists
224 from IPython.utils.path import ensure_dir_exists
139 from IPython.utils.process import arg_split
225 from IPython.utils.process import arg_split
140 from traitlets import Bool, Enum, Int, List as ListTrait, Unicode, default, observe
226 from traitlets import (
227 Bool,
228 Enum,
229 Int,
230 List as ListTrait,
231 Unicode,
232 Dict as DictTrait,
233 Union as UnionTrait,
234 default,
235 observe,
236 )
141 from traitlets.config.configurable import Configurable
237 from traitlets.config.configurable import Configurable
142
238
143 import __main__
239 import __main__
144
240
145 # skip module docstests
241 # skip module docstests
146 __skip_doctest__ = True
242 __skip_doctest__ = True
147
243
244
148 try:
245 try:
149 import jedi
246 import jedi
150 jedi.settings.case_insensitive_completion = False
247 jedi.settings.case_insensitive_completion = False
151 import jedi.api.helpers
248 import jedi.api.helpers
152 import jedi.api.classes
249 import jedi.api.classes
153 JEDI_INSTALLED = True
250 JEDI_INSTALLED = True
154 except ImportError:
251 except ImportError:
155 JEDI_INSTALLED = False
252 JEDI_INSTALLED = False
156 #-----------------------------------------------------------------------------
253
254
255 if TYPE_CHECKING or GENERATING_DOCUMENTATION:
256 from typing import cast
257 from typing_extensions import TypedDict, NotRequired, Protocol, TypeAlias
258 else:
259
260 def cast(obj, type_):
261 """Workaround for `TypeError: MatcherAPIv2() takes no arguments`"""
262 return obj
263
264 # do not require on runtime
265 NotRequired = Tuple # requires Python >=3.11
266 TypedDict = Dict # by extension of `NotRequired` requires 3.11 too
267 Protocol = object # requires Python >=3.8
268 TypeAlias = Any # requires Python >=3.10
269 if GENERATING_DOCUMENTATION:
270 from typing import TypedDict
271
272 # -----------------------------------------------------------------------------
157 # Globals
273 # Globals
158 #-----------------------------------------------------------------------------
274 #-----------------------------------------------------------------------------
159
275
160 # ranges where we have most of the valid unicode names. We could be more finer
276 # ranges where we have most of the valid unicode names. We could be more finer
161 # grained but is it worth it for performance While unicode have character in the
277 # grained but is it worth it for performance While unicode have character in the
162 # range 0, 0x110000, we seem to have name for about 10% of those. (131808 as I
278 # range 0, 0x110000, we seem to have name for about 10% of those. (131808 as I
163 # write this). With below range we cover them all, with a density of ~67%
279 # write this). With below range we cover them all, with a density of ~67%
164 # biggest next gap we consider only adds up about 1% density and there are 600
280 # biggest next gap we consider only adds up about 1% density and there are 600
165 # gaps that would need hard coding.
281 # gaps that would need hard coding.
166 _UNICODE_RANGES = [(32, 0x3134b), (0xe0001, 0xe01f0)]
282 _UNICODE_RANGES = [(32, 0x3134b), (0xe0001, 0xe01f0)]
167
283
168 # Public API
284 # Public API
169 __all__ = ['Completer','IPCompleter']
285 __all__ = ["Completer", "IPCompleter"]
170
286
171 if sys.platform == 'win32':
287 if sys.platform == 'win32':
172 PROTECTABLES = ' '
288 PROTECTABLES = ' '
173 else:
289 else:
174 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
290 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
175
291
176 # Protect against returning an enormous number of completions which the frontend
292 # Protect against returning an enormous number of completions which the frontend
177 # may have trouble processing.
293 # may have trouble processing.
178 MATCHES_LIMIT = 500
294 MATCHES_LIMIT = 500
179
295
296 # Completion type reported when no type can be inferred.
297 _UNKNOWN_TYPE = "<unknown>"
180
298
181 class ProvisionalCompleterWarning(FutureWarning):
299 class ProvisionalCompleterWarning(FutureWarning):
182 """
300 """
183 Exception raise by an experimental feature in this module.
301 Exception raise by an experimental feature in this module.
184
302
185 Wrap code in :any:`provisionalcompleter` context manager if you
303 Wrap code in :any:`provisionalcompleter` context manager if you
186 are certain you want to use an unstable feature.
304 are certain you want to use an unstable feature.
187 """
305 """
188 pass
306 pass
189
307
190 warnings.filterwarnings('error', category=ProvisionalCompleterWarning)
308 warnings.filterwarnings('error', category=ProvisionalCompleterWarning)
191
309
192
310
193 @skip_doctest
311 @skip_doctest
194 @contextmanager
312 @contextmanager
195 def provisionalcompleter(action='ignore'):
313 def provisionalcompleter(action='ignore'):
196 """
314 """
197 This context manager has to be used in any place where unstable completer
315 This context manager has to be used in any place where unstable completer
198 behavior and API may be called.
316 behavior and API may be called.
199
317
200 >>> with provisionalcompleter():
318 >>> with provisionalcompleter():
201 ... completer.do_experimental_things() # works
319 ... completer.do_experimental_things() # works
202
320
203 >>> completer.do_experimental_things() # raises.
321 >>> completer.do_experimental_things() # raises.
204
322
205 .. note::
323 .. note::
206
324
207 Unstable
325 Unstable
208
326
209 By using this context manager you agree that the API in use may change
327 By using this context manager you agree that the API in use may change
210 without warning, and that you won't complain if they do so.
328 without warning, and that you won't complain if they do so.
211
329
212 You also understand that, if the API is not to your liking, you should report
330 You also understand that, if the API is not to your liking, you should report
213 a bug to explain your use case upstream.
331 a bug to explain your use case upstream.
214
332
215 We'll be happy to get your feedback, feature requests, and improvements on
333 We'll be happy to get your feedback, feature requests, and improvements on
216 any of the unstable APIs!
334 any of the unstable APIs!
217 """
335 """
218 with warnings.catch_warnings():
336 with warnings.catch_warnings():
219 warnings.filterwarnings(action, category=ProvisionalCompleterWarning)
337 warnings.filterwarnings(action, category=ProvisionalCompleterWarning)
220 yield
338 yield
221
339
222
340
223 def has_open_quotes(s):
341 def has_open_quotes(s):
224 """Return whether a string has open quotes.
342 """Return whether a string has open quotes.
225
343
226 This simply counts whether the number of quote characters of either type in
344 This simply counts whether the number of quote characters of either type in
227 the string is odd.
345 the string is odd.
228
346
229 Returns
347 Returns
230 -------
348 -------
231 If there is an open quote, the quote character is returned. Else, return
349 If there is an open quote, the quote character is returned. Else, return
232 False.
350 False.
233 """
351 """
234 # We check " first, then ', so complex cases with nested quotes will get
352 # We check " first, then ', so complex cases with nested quotes will get
235 # the " to take precedence.
353 # the " to take precedence.
236 if s.count('"') % 2:
354 if s.count('"') % 2:
237 return '"'
355 return '"'
238 elif s.count("'") % 2:
356 elif s.count("'") % 2:
239 return "'"
357 return "'"
240 else:
358 else:
241 return False
359 return False
242
360
243
361
244 def protect_filename(s, protectables=PROTECTABLES):
362 def protect_filename(s, protectables=PROTECTABLES):
245 """Escape a string to protect certain characters."""
363 """Escape a string to protect certain characters."""
246 if set(s) & set(protectables):
364 if set(s) & set(protectables):
247 if sys.platform == "win32":
365 if sys.platform == "win32":
248 return '"' + s + '"'
366 return '"' + s + '"'
249 else:
367 else:
250 return "".join(("\\" + c if c in protectables else c) for c in s)
368 return "".join(("\\" + c if c in protectables else c) for c in s)
251 else:
369 else:
252 return s
370 return s
253
371
254
372
255 def expand_user(path:str) -> Tuple[str, bool, str]:
373 def expand_user(path:str) -> Tuple[str, bool, str]:
256 """Expand ``~``-style usernames in strings.
374 """Expand ``~``-style usernames in strings.
257
375
258 This is similar to :func:`os.path.expanduser`, but it computes and returns
376 This is similar to :func:`os.path.expanduser`, but it computes and returns
259 extra information that will be useful if the input was being used in
377 extra information that will be useful if the input was being used in
260 computing completions, and you wish to return the completions with the
378 computing completions, and you wish to return the completions with the
261 original '~' instead of its expanded value.
379 original '~' instead of its expanded value.
262
380
263 Parameters
381 Parameters
264 ----------
382 ----------
265 path : str
383 path : str
266 String to be expanded. If no ~ is present, the output is the same as the
384 String to be expanded. If no ~ is present, the output is the same as the
267 input.
385 input.
268
386
269 Returns
387 Returns
270 -------
388 -------
271 newpath : str
389 newpath : str
272 Result of ~ expansion in the input path.
390 Result of ~ expansion in the input path.
273 tilde_expand : bool
391 tilde_expand : bool
274 Whether any expansion was performed or not.
392 Whether any expansion was performed or not.
275 tilde_val : str
393 tilde_val : str
276 The value that ~ was replaced with.
394 The value that ~ was replaced with.
277 """
395 """
278 # Default values
396 # Default values
279 tilde_expand = False
397 tilde_expand = False
280 tilde_val = ''
398 tilde_val = ''
281 newpath = path
399 newpath = path
282
400
283 if path.startswith('~'):
401 if path.startswith('~'):
284 tilde_expand = True
402 tilde_expand = True
285 rest = len(path)-1
403 rest = len(path)-1
286 newpath = os.path.expanduser(path)
404 newpath = os.path.expanduser(path)
287 if rest:
405 if rest:
288 tilde_val = newpath[:-rest]
406 tilde_val = newpath[:-rest]
289 else:
407 else:
290 tilde_val = newpath
408 tilde_val = newpath
291
409
292 return newpath, tilde_expand, tilde_val
410 return newpath, tilde_expand, tilde_val
293
411
294
412
295 def compress_user(path:str, tilde_expand:bool, tilde_val:str) -> str:
413 def compress_user(path:str, tilde_expand:bool, tilde_val:str) -> str:
296 """Does the opposite of expand_user, with its outputs.
414 """Does the opposite of expand_user, with its outputs.
297 """
415 """
298 if tilde_expand:
416 if tilde_expand:
299 return path.replace(tilde_val, '~')
417 return path.replace(tilde_val, '~')
300 else:
418 else:
301 return path
419 return path
302
420
303
421
304 def completions_sorting_key(word):
422 def completions_sorting_key(word):
305 """key for sorting completions
423 """key for sorting completions
306
424
307 This does several things:
425 This does several things:
308
426
309 - Demote any completions starting with underscores to the end
427 - Demote any completions starting with underscores to the end
310 - Insert any %magic and %%cellmagic completions in the alphabetical order
428 - Insert any %magic and %%cellmagic completions in the alphabetical order
311 by their name
429 by their name
312 """
430 """
313 prio1, prio2 = 0, 0
431 prio1, prio2 = 0, 0
314
432
315 if word.startswith('__'):
433 if word.startswith('__'):
316 prio1 = 2
434 prio1 = 2
317 elif word.startswith('_'):
435 elif word.startswith('_'):
318 prio1 = 1
436 prio1 = 1
319
437
320 if word.endswith('='):
438 if word.endswith('='):
321 prio1 = -1
439 prio1 = -1
322
440
323 if word.startswith('%%'):
441 if word.startswith('%%'):
324 # If there's another % in there, this is something else, so leave it alone
442 # If there's another % in there, this is something else, so leave it alone
325 if not "%" in word[2:]:
443 if not "%" in word[2:]:
326 word = word[2:]
444 word = word[2:]
327 prio2 = 2
445 prio2 = 2
328 elif word.startswith('%'):
446 elif word.startswith('%'):
329 if not "%" in word[1:]:
447 if not "%" in word[1:]:
330 word = word[1:]
448 word = word[1:]
331 prio2 = 1
449 prio2 = 1
332
450
333 return prio1, word, prio2
451 return prio1, word, prio2
334
452
335
453
336 class _FakeJediCompletion:
454 class _FakeJediCompletion:
337 """
455 """
338 This is a workaround to communicate to the UI that Jedi has crashed and to
456 This is a workaround to communicate to the UI that Jedi has crashed and to
339 report a bug. Will be used only id :any:`IPCompleter.debug` is set to true.
457 report a bug. Will be used only id :any:`IPCompleter.debug` is set to true.
340
458
341 Added in IPython 6.0 so should likely be removed for 7.0
459 Added in IPython 6.0 so should likely be removed for 7.0
342
460
343 """
461 """
344
462
345 def __init__(self, name):
463 def __init__(self, name):
346
464
347 self.name = name
465 self.name = name
348 self.complete = name
466 self.complete = name
349 self.type = 'crashed'
467 self.type = 'crashed'
350 self.name_with_symbols = name
468 self.name_with_symbols = name
351 self.signature = ''
469 self.signature = ''
352 self._origin = 'fake'
470 self._origin = 'fake'
353
471
354 def __repr__(self):
472 def __repr__(self):
355 return '<Fake completion object jedi has crashed>'
473 return '<Fake completion object jedi has crashed>'
356
474
357
475
476 _JediCompletionLike = Union[jedi.api.Completion, _FakeJediCompletion]
477
478
358 class Completion:
479 class Completion:
359 """
480 """
360 Completion object used and return by IPython completers.
481 Completion object used and returned by IPython completers.
361
482
362 .. warning::
483 .. warning::
363
484
364 Unstable
485 Unstable
365
486
366 This function is unstable, API may change without warning.
487 This function is unstable, API may change without warning.
367 It will also raise unless use in proper context manager.
488 It will also raise unless use in proper context manager.
368
489
369 This act as a middle ground :any:`Completion` object between the
490 This act as a middle ground :any:`Completion` object between the
370 :any:`jedi.api.classes.Completion` object and the Prompt Toolkit completion
491 :any:`jedi.api.classes.Completion` object and the Prompt Toolkit completion
371 object. While Jedi need a lot of information about evaluator and how the
492 object. While Jedi need a lot of information about evaluator and how the
372 code should be ran/inspected, PromptToolkit (and other frontend) mostly
493 code should be ran/inspected, PromptToolkit (and other frontend) mostly
373 need user facing information.
494 need user facing information.
374
495
375 - Which range should be replaced replaced by what.
496 - Which range should be replaced replaced by what.
376 - Some metadata (like completion type), or meta information to displayed to
497 - Some metadata (like completion type), or meta information to displayed to
377 the use user.
498 the use user.
378
499
379 For debugging purpose we can also store the origin of the completion (``jedi``,
500 For debugging purpose we can also store the origin of the completion (``jedi``,
380 ``IPython.python_matches``, ``IPython.magics_matches``...).
501 ``IPython.python_matches``, ``IPython.magics_matches``...).
381 """
502 """
382
503
383 __slots__ = ['start', 'end', 'text', 'type', 'signature', '_origin']
504 __slots__ = ['start', 'end', 'text', 'type', 'signature', '_origin']
384
505
385 def __init__(self, start: int, end: int, text: str, *, type: str=None, _origin='', signature='') -> None:
506 def __init__(self, start: int, end: int, text: str, *, type: str=None, _origin='', signature='') -> None:
386 warnings.warn("``Completion`` is a provisional API (as of IPython 6.0). "
507 warnings.warn("``Completion`` is a provisional API (as of IPython 6.0). "
387 "It may change without warnings. "
508 "It may change without warnings. "
388 "Use in corresponding context manager.",
509 "Use in corresponding context manager.",
389 category=ProvisionalCompleterWarning, stacklevel=2)
510 category=ProvisionalCompleterWarning, stacklevel=2)
390
511
391 self.start = start
512 self.start = start
392 self.end = end
513 self.end = end
393 self.text = text
514 self.text = text
394 self.type = type
515 self.type = type
395 self.signature = signature
516 self.signature = signature
396 self._origin = _origin
517 self._origin = _origin
397
518
398 def __repr__(self):
519 def __repr__(self):
399 return '<Completion start=%s end=%s text=%r type=%r, signature=%r,>' % \
520 return '<Completion start=%s end=%s text=%r type=%r, signature=%r,>' % \
400 (self.start, self.end, self.text, self.type or '?', self.signature or '?')
521 (self.start, self.end, self.text, self.type or '?', self.signature or '?')
401
522
402 def __eq__(self, other)->Bool:
523 def __eq__(self, other)->Bool:
403 """
524 """
404 Equality and hash do not hash the type (as some completer may not be
525 Equality and hash do not hash the type (as some completer may not be
405 able to infer the type), but are use to (partially) de-duplicate
526 able to infer the type), but are use to (partially) de-duplicate
406 completion.
527 completion.
407
528
408 Completely de-duplicating completion is a bit tricker that just
529 Completely de-duplicating completion is a bit tricker that just
409 comparing as it depends on surrounding text, which Completions are not
530 comparing as it depends on surrounding text, which Completions are not
410 aware of.
531 aware of.
411 """
532 """
412 return self.start == other.start and \
533 return self.start == other.start and \
413 self.end == other.end and \
534 self.end == other.end and \
414 self.text == other.text
535 self.text == other.text
415
536
416 def __hash__(self):
537 def __hash__(self):
417 return hash((self.start, self.end, self.text))
538 return hash((self.start, self.end, self.text))
418
539
419
540
541 class SimpleCompletion:
542 """Completion item to be included in the dictionary returned by new-style Matcher (API v2).
543
544 .. warning::
545
546 Provisional
547
548 This class is used to describe the currently supported attributes of
549 simple completion items, and any additional implementation details
550 should not be relied on. Additional attributes may be included in
551 future versions, and meaning of text disambiguated from the current
552 dual meaning of "text to insert" and "text to used as a label".
553 """
554
555 __slots__ = ["text", "type"]
556
557 def __init__(self, text: str, *, type: str = None):
558 self.text = text
559 self.type = type
560
561 def __repr__(self):
562 return f"<SimpleCompletion text={self.text!r} type={self.type!r}>"
563
564
565 class _MatcherResultBase(TypedDict):
566 """Definition of dictionary to be returned by new-style Matcher (API v2)."""
567
568 #: Suffix of the provided ``CompletionContext.token``, if not given defaults to full token.
569 matched_fragment: NotRequired[str]
570
571 #: Whether to suppress results from all other matchers (True), some
572 #: matchers (set of identifiers) or none (False); default is False.
573 suppress: NotRequired[Union[bool, Set[str]]]
574
575 #: Identifiers of matchers which should NOT be suppressed when this matcher
576 #: requests to suppress all other matchers; defaults to an empty set.
577 do_not_suppress: NotRequired[Set[str]]
578
579 #: Are completions already ordered and should be left as-is? default is False.
580 ordered: NotRequired[bool]
581
582
583 @sphinx_options(show_inherited_members=True, exclude_inherited_from=["dict"])
584 class SimpleMatcherResult(_MatcherResultBase, TypedDict):
585 """Result of new-style completion matcher."""
586
587 # note: TypedDict is added again to the inheritance chain
588 # in order to get __orig_bases__ for documentation
589
590 #: List of candidate completions
591 completions: Sequence[SimpleCompletion]
592
593
594 class _JediMatcherResult(_MatcherResultBase):
595 """Matching result returned by Jedi (will be processed differently)"""
596
597 #: list of candidate completions
598 completions: Iterable[_JediCompletionLike]
599
600
601 @dataclass
602 class CompletionContext:
603 """Completion context provided as an argument to matchers in the Matcher API v2."""
604
605 # rationale: many legacy matchers relied on completer state (`self.text_until_cursor`)
606 # which was not explicitly visible as an argument of the matcher, making any refactor
607 # prone to errors; by explicitly passing `cursor_position` we can decouple the matchers
608 # from the completer, and make substituting them in sub-classes easier.
609
610 #: Relevant fragment of code directly preceding the cursor.
611 #: The extraction of token is implemented via splitter heuristic
612 #: (following readline behaviour for legacy reasons), which is user configurable
613 #: (by switching the greedy mode).
614 token: str
615
616 #: The full available content of the editor or buffer
617 full_text: str
618
619 #: Cursor position in the line (the same for ``full_text`` and ``text``).
620 cursor_position: int
621
622 #: Cursor line in ``full_text``.
623 cursor_line: int
624
625 #: The maximum number of completions that will be used downstream.
626 #: Matchers can use this information to abort early.
627 #: The built-in Jedi matcher is currently excepted from this limit.
628 # If not given, return all possible completions.
629 limit: Optional[int]
630
631 @cached_property
632 def text_until_cursor(self) -> str:
633 return self.line_with_cursor[: self.cursor_position]
634
635 @cached_property
636 def line_with_cursor(self) -> str:
637 return self.full_text.split("\n")[self.cursor_line]
638
639
640 #: Matcher results for API v2.
641 MatcherResult = Union[SimpleMatcherResult, _JediMatcherResult]
642
643
644 class _MatcherAPIv1Base(Protocol):
645 def __call__(self, text: str) -> list[str]:
646 """Call signature."""
647
648
649 class _MatcherAPIv1Total(_MatcherAPIv1Base, Protocol):
650 #: API version
651 matcher_api_version: Optional[Literal[1]]
652
653 def __call__(self, text: str) -> list[str]:
654 """Call signature."""
655
656
657 #: Protocol describing Matcher API v1.
658 MatcherAPIv1: TypeAlias = Union[_MatcherAPIv1Base, _MatcherAPIv1Total]
659
660
661 class MatcherAPIv2(Protocol):
662 """Protocol describing Matcher API v2."""
663
664 #: API version
665 matcher_api_version: Literal[2] = 2
666
667 def __call__(self, context: CompletionContext) -> MatcherResult:
668 """Call signature."""
669
670
671 Matcher: TypeAlias = Union[MatcherAPIv1, MatcherAPIv2]
672
673
674 def completion_matcher(
675 *, priority: float = None, identifier: str = None, api_version: int = 1
676 ):
677 """Adds attributes describing the matcher.
678
679 Parameters
680 ----------
681 priority : Optional[float]
682 The priority of the matcher, determines the order of execution of matchers.
683 Higher priority means that the matcher will be executed first. Defaults to 0.
684 identifier : Optional[str]
685 identifier of the matcher allowing users to modify the behaviour via traitlets,
686 and also used to for debugging (will be passed as ``origin`` with the completions).
687 Defaults to matcher function ``__qualname__``.
688 api_version: Optional[int]
689 version of the Matcher API used by this matcher.
690 Currently supported values are 1 and 2.
691 Defaults to 1.
692 """
693
694 def wrapper(func: Matcher):
695 func.matcher_priority = priority or 0
696 func.matcher_identifier = identifier or func.__qualname__
697 func.matcher_api_version = api_version
698 if TYPE_CHECKING:
699 if api_version == 1:
700 func = cast(func, MatcherAPIv1)
701 elif api_version == 2:
702 func = cast(func, MatcherAPIv2)
703 return func
704
705 return wrapper
706
707
708 def _get_matcher_priority(matcher: Matcher):
709 return getattr(matcher, "matcher_priority", 0)
710
711
712 def _get_matcher_id(matcher: Matcher):
713 return getattr(matcher, "matcher_identifier", matcher.__qualname__)
714
715
716 def _get_matcher_api_version(matcher):
717 return getattr(matcher, "matcher_api_version", 1)
718
719
720 context_matcher = partial(completion_matcher, api_version=2)
721
722
420 _IC = Iterable[Completion]
723 _IC = Iterable[Completion]
421
724
422
725
423 def _deduplicate_completions(text: str, completions: _IC)-> _IC:
726 def _deduplicate_completions(text: str, completions: _IC)-> _IC:
424 """
727 """
425 Deduplicate a set of completions.
728 Deduplicate a set of completions.
426
729
427 .. warning::
730 .. warning::
428
731
429 Unstable
732 Unstable
430
733
431 This function is unstable, API may change without warning.
734 This function is unstable, API may change without warning.
432
735
433 Parameters
736 Parameters
434 ----------
737 ----------
435 text : str
738 text : str
436 text that should be completed.
739 text that should be completed.
437 completions : Iterator[Completion]
740 completions : Iterator[Completion]
438 iterator over the completions to deduplicate
741 iterator over the completions to deduplicate
439
742
440 Yields
743 Yields
441 ------
744 ------
442 `Completions` objects
745 `Completions` objects
443 Completions coming from multiple sources, may be different but end up having
746 Completions coming from multiple sources, may be different but end up having
444 the same effect when applied to ``text``. If this is the case, this will
747 the same effect when applied to ``text``. If this is the case, this will
445 consider completions as equal and only emit the first encountered.
748 consider completions as equal and only emit the first encountered.
446 Not folded in `completions()` yet for debugging purpose, and to detect when
749 Not folded in `completions()` yet for debugging purpose, and to detect when
447 the IPython completer does return things that Jedi does not, but should be
750 the IPython completer does return things that Jedi does not, but should be
448 at some point.
751 at some point.
449 """
752 """
450 completions = list(completions)
753 completions = list(completions)
451 if not completions:
754 if not completions:
452 return
755 return
453
756
454 new_start = min(c.start for c in completions)
757 new_start = min(c.start for c in completions)
455 new_end = max(c.end for c in completions)
758 new_end = max(c.end for c in completions)
456
759
457 seen = set()
760 seen = set()
458 for c in completions:
761 for c in completions:
459 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
762 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
460 if new_text not in seen:
763 if new_text not in seen:
461 yield c
764 yield c
462 seen.add(new_text)
765 seen.add(new_text)
463
766
464
767
465 def rectify_completions(text: str, completions: _IC, *, _debug: bool = False) -> _IC:
768 def rectify_completions(text: str, completions: _IC, *, _debug: bool = False) -> _IC:
466 """
769 """
467 Rectify a set of completions to all have the same ``start`` and ``end``
770 Rectify a set of completions to all have the same ``start`` and ``end``
468
771
469 .. warning::
772 .. warning::
470
773
471 Unstable
774 Unstable
472
775
473 This function is unstable, API may change without warning.
776 This function is unstable, API may change without warning.
474 It will also raise unless use in proper context manager.
777 It will also raise unless use in proper context manager.
475
778
476 Parameters
779 Parameters
477 ----------
780 ----------
478 text : str
781 text : str
479 text that should be completed.
782 text that should be completed.
480 completions : Iterator[Completion]
783 completions : Iterator[Completion]
481 iterator over the completions to rectify
784 iterator over the completions to rectify
482 _debug : bool
785 _debug : bool
483 Log failed completion
786 Log failed completion
484
787
485 Notes
788 Notes
486 -----
789 -----
487 :any:`jedi.api.classes.Completion` s returned by Jedi may not have the same start and end, though
790 :any:`jedi.api.classes.Completion` s returned by Jedi may not have the same start and end, though
488 the Jupyter Protocol requires them to behave like so. This will readjust
791 the Jupyter Protocol requires them to behave like so. This will readjust
489 the completion to have the same ``start`` and ``end`` by padding both
792 the completion to have the same ``start`` and ``end`` by padding both
490 extremities with surrounding text.
793 extremities with surrounding text.
491
794
492 During stabilisation should support a ``_debug`` option to log which
795 During stabilisation should support a ``_debug`` option to log which
493 completion are return by the IPython completer and not found in Jedi in
796 completion are return by the IPython completer and not found in Jedi in
494 order to make upstream bug report.
797 order to make upstream bug report.
495 """
798 """
496 warnings.warn("`rectify_completions` is a provisional API (as of IPython 6.0). "
799 warnings.warn("`rectify_completions` is a provisional API (as of IPython 6.0). "
497 "It may change without warnings. "
800 "It may change without warnings. "
498 "Use in corresponding context manager.",
801 "Use in corresponding context manager.",
499 category=ProvisionalCompleterWarning, stacklevel=2)
802 category=ProvisionalCompleterWarning, stacklevel=2)
500
803
501 completions = list(completions)
804 completions = list(completions)
502 if not completions:
805 if not completions:
503 return
806 return
504 starts = (c.start for c in completions)
807 starts = (c.start for c in completions)
505 ends = (c.end for c in completions)
808 ends = (c.end for c in completions)
506
809
507 new_start = min(starts)
810 new_start = min(starts)
508 new_end = max(ends)
811 new_end = max(ends)
509
812
510 seen_jedi = set()
813 seen_jedi = set()
511 seen_python_matches = set()
814 seen_python_matches = set()
512 for c in completions:
815 for c in completions:
513 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
816 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
514 if c._origin == 'jedi':
817 if c._origin == 'jedi':
515 seen_jedi.add(new_text)
818 seen_jedi.add(new_text)
516 elif c._origin == 'IPCompleter.python_matches':
819 elif c._origin == 'IPCompleter.python_matches':
517 seen_python_matches.add(new_text)
820 seen_python_matches.add(new_text)
518 yield Completion(new_start, new_end, new_text, type=c.type, _origin=c._origin, signature=c.signature)
821 yield Completion(new_start, new_end, new_text, type=c.type, _origin=c._origin, signature=c.signature)
519 diff = seen_python_matches.difference(seen_jedi)
822 diff = seen_python_matches.difference(seen_jedi)
520 if diff and _debug:
823 if diff and _debug:
521 print('IPython.python matches have extras:', diff)
824 print('IPython.python matches have extras:', diff)
522
825
523
826
524 if sys.platform == 'win32':
827 if sys.platform == 'win32':
525 DELIMS = ' \t\n`!@#$^&*()=+[{]}|;\'",<>?'
828 DELIMS = ' \t\n`!@#$^&*()=+[{]}|;\'",<>?'
526 else:
829 else:
527 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
830 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
528
831
529 GREEDY_DELIMS = ' =\r\n'
832 GREEDY_DELIMS = ' =\r\n'
530
833
531
834
532 class CompletionSplitter(object):
835 class CompletionSplitter(object):
533 """An object to split an input line in a manner similar to readline.
836 """An object to split an input line in a manner similar to readline.
534
837
535 By having our own implementation, we can expose readline-like completion in
838 By having our own implementation, we can expose readline-like completion in
536 a uniform manner to all frontends. This object only needs to be given the
839 a uniform manner to all frontends. This object only needs to be given the
537 line of text to be split and the cursor position on said line, and it
840 line of text to be split and the cursor position on said line, and it
538 returns the 'word' to be completed on at the cursor after splitting the
841 returns the 'word' to be completed on at the cursor after splitting the
539 entire line.
842 entire line.
540
843
541 What characters are used as splitting delimiters can be controlled by
844 What characters are used as splitting delimiters can be controlled by
542 setting the ``delims`` attribute (this is a property that internally
845 setting the ``delims`` attribute (this is a property that internally
543 automatically builds the necessary regular expression)"""
846 automatically builds the necessary regular expression)"""
544
847
545 # Private interface
848 # Private interface
546
849
547 # A string of delimiter characters. The default value makes sense for
850 # A string of delimiter characters. The default value makes sense for
548 # IPython's most typical usage patterns.
851 # IPython's most typical usage patterns.
549 _delims = DELIMS
852 _delims = DELIMS
550
853
551 # The expression (a normal string) to be compiled into a regular expression
854 # The expression (a normal string) to be compiled into a regular expression
552 # for actual splitting. We store it as an attribute mostly for ease of
855 # for actual splitting. We store it as an attribute mostly for ease of
553 # debugging, since this type of code can be so tricky to debug.
856 # debugging, since this type of code can be so tricky to debug.
554 _delim_expr = None
857 _delim_expr = None
555
858
556 # The regular expression that does the actual splitting
859 # The regular expression that does the actual splitting
557 _delim_re = None
860 _delim_re = None
558
861
559 def __init__(self, delims=None):
862 def __init__(self, delims=None):
560 delims = CompletionSplitter._delims if delims is None else delims
863 delims = CompletionSplitter._delims if delims is None else delims
561 self.delims = delims
864 self.delims = delims
562
865
563 @property
866 @property
564 def delims(self):
867 def delims(self):
565 """Return the string of delimiter characters."""
868 """Return the string of delimiter characters."""
566 return self._delims
869 return self._delims
567
870
568 @delims.setter
871 @delims.setter
569 def delims(self, delims):
872 def delims(self, delims):
570 """Set the delimiters for line splitting."""
873 """Set the delimiters for line splitting."""
571 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
874 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
572 self._delim_re = re.compile(expr)
875 self._delim_re = re.compile(expr)
573 self._delims = delims
876 self._delims = delims
574 self._delim_expr = expr
877 self._delim_expr = expr
575
878
576 def split_line(self, line, cursor_pos=None):
879 def split_line(self, line, cursor_pos=None):
577 """Split a line of text with a cursor at the given position.
880 """Split a line of text with a cursor at the given position.
578 """
881 """
579 l = line if cursor_pos is None else line[:cursor_pos]
882 l = line if cursor_pos is None else line[:cursor_pos]
580 return self._delim_re.split(l)[-1]
883 return self._delim_re.split(l)[-1]
581
884
582
885
583
886
584 class Completer(Configurable):
887 class Completer(Configurable):
585
888
586 greedy = Bool(False,
889 greedy = Bool(False,
587 help="""Activate greedy completion
890 help="""Activate greedy completion
588 PENDING DEPRECATION. this is now mostly taken care of with Jedi.
891 PENDING DEPRECATION. this is now mostly taken care of with Jedi.
589
892
590 This will enable completion on elements of lists, results of function calls, etc.,
893 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.
894 but can be unsafe because the code is actually evaluated on TAB.
592 """,
895 """,
593 ).tag(config=True)
896 ).tag(config=True)
594
897
595 use_jedi = Bool(default_value=JEDI_INSTALLED,
898 use_jedi = Bool(default_value=JEDI_INSTALLED,
596 help="Experimental: Use Jedi to generate autocompletions. "
899 help="Experimental: Use Jedi to generate autocompletions. "
597 "Default to True if jedi is installed.").tag(config=True)
900 "Default to True if jedi is installed.").tag(config=True)
598
901
599 jedi_compute_type_timeout = Int(default_value=400,
902 jedi_compute_type_timeout = Int(default_value=400,
600 help="""Experimental: restrict time (in milliseconds) during which Jedi can compute types.
903 help="""Experimental: restrict time (in milliseconds) during which Jedi can compute types.
601 Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt
904 Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt
602 performance by preventing jedi to build its cache.
905 performance by preventing jedi to build its cache.
603 """).tag(config=True)
906 """).tag(config=True)
604
907
605 debug = Bool(default_value=False,
908 debug = Bool(default_value=False,
606 help='Enable debug for the Completer. Mostly print extra '
909 help='Enable debug for the Completer. Mostly print extra '
607 'information for experimental jedi integration.')\
910 'information for experimental jedi integration.')\
608 .tag(config=True)
911 .tag(config=True)
609
912
610 backslash_combining_completions = Bool(True,
913 backslash_combining_completions = Bool(True,
611 help="Enable unicode completions, e.g. \\alpha<tab> . "
914 help="Enable unicode completions, e.g. \\alpha<tab> . "
612 "Includes completion of latex commands, unicode names, and expanding "
915 "Includes completion of latex commands, unicode names, and expanding "
613 "unicode characters back to latex commands.").tag(config=True)
916 "unicode characters back to latex commands.").tag(config=True)
614
917
615 def __init__(self, namespace=None, global_namespace=None, **kwargs):
918 def __init__(self, namespace=None, global_namespace=None, **kwargs):
616 """Create a new completer for the command line.
919 """Create a new completer for the command line.
617
920
618 Completer(namespace=ns, global_namespace=ns2) -> completer instance.
921 Completer(namespace=ns, global_namespace=ns2) -> completer instance.
619
922
620 If unspecified, the default namespace where completions are performed
923 If unspecified, the default namespace where completions are performed
621 is __main__ (technically, __main__.__dict__). Namespaces should be
924 is __main__ (technically, __main__.__dict__). Namespaces should be
622 given as dictionaries.
925 given as dictionaries.
623
926
624 An optional second namespace can be given. This allows the completer
927 An optional second namespace can be given. This allows the completer
625 to handle cases where both the local and global scopes need to be
928 to handle cases where both the local and global scopes need to be
626 distinguished.
929 distinguished.
627 """
930 """
628
931
629 # Don't bind to namespace quite yet, but flag whether the user wants a
932 # Don't bind to namespace quite yet, but flag whether the user wants a
630 # specific namespace or to use __main__.__dict__. This will allow us
933 # specific namespace or to use __main__.__dict__. This will allow us
631 # to bind to __main__.__dict__ at completion time, not now.
934 # to bind to __main__.__dict__ at completion time, not now.
632 if namespace is None:
935 if namespace is None:
633 self.use_main_ns = True
936 self.use_main_ns = True
634 else:
937 else:
635 self.use_main_ns = False
938 self.use_main_ns = False
636 self.namespace = namespace
939 self.namespace = namespace
637
940
638 # The global namespace, if given, can be bound directly
941 # The global namespace, if given, can be bound directly
639 if global_namespace is None:
942 if global_namespace is None:
640 self.global_namespace = {}
943 self.global_namespace = {}
641 else:
944 else:
642 self.global_namespace = global_namespace
945 self.global_namespace = global_namespace
643
946
644 self.custom_matchers = []
947 self.custom_matchers = []
645
948
646 super(Completer, self).__init__(**kwargs)
949 super(Completer, self).__init__(**kwargs)
647
950
648 def complete(self, text, state):
951 def complete(self, text, state):
649 """Return the next possible completion for 'text'.
952 """Return the next possible completion for 'text'.
650
953
651 This is called successively with state == 0, 1, 2, ... until it
954 This is called successively with state == 0, 1, 2, ... until it
652 returns None. The completion should begin with 'text'.
955 returns None. The completion should begin with 'text'.
653
956
654 """
957 """
655 if self.use_main_ns:
958 if self.use_main_ns:
656 self.namespace = __main__.__dict__
959 self.namespace = __main__.__dict__
657
960
658 if state == 0:
961 if state == 0:
659 if "." in text:
962 if "." in text:
660 self.matches = self.attr_matches(text)
963 self.matches = self.attr_matches(text)
661 else:
964 else:
662 self.matches = self.global_matches(text)
965 self.matches = self.global_matches(text)
663 try:
966 try:
664 return self.matches[state]
967 return self.matches[state]
665 except IndexError:
968 except IndexError:
666 return None
969 return None
667
970
668 def global_matches(self, text):
971 def global_matches(self, text):
669 """Compute matches when text is a simple name.
972 """Compute matches when text is a simple name.
670
973
671 Return a list of all keywords, built-in functions and names currently
974 Return a list of all keywords, built-in functions and names currently
672 defined in self.namespace or self.global_namespace that match.
975 defined in self.namespace or self.global_namespace that match.
673
976
674 """
977 """
675 matches = []
978 matches = []
676 match_append = matches.append
979 match_append = matches.append
677 n = len(text)
980 n = len(text)
678 for lst in [
981 for lst in [
679 keyword.kwlist,
982 keyword.kwlist,
680 builtin_mod.__dict__.keys(),
983 builtin_mod.__dict__.keys(),
681 list(self.namespace.keys()),
984 list(self.namespace.keys()),
682 list(self.global_namespace.keys()),
985 list(self.global_namespace.keys()),
683 ]:
986 ]:
684 for word in lst:
987 for word in lst:
685 if word[:n] == text and word != "__builtins__":
988 if word[:n] == text and word != "__builtins__":
686 match_append(word)
989 match_append(word)
687
990
688 snake_case_re = re.compile(r"[^_]+(_[^_]+)+?\Z")
991 snake_case_re = re.compile(r"[^_]+(_[^_]+)+?\Z")
689 for lst in [list(self.namespace.keys()), list(self.global_namespace.keys())]:
992 for lst in [list(self.namespace.keys()), list(self.global_namespace.keys())]:
690 shortened = {
993 shortened = {
691 "_".join([sub[0] for sub in word.split("_")]): word
994 "_".join([sub[0] for sub in word.split("_")]): word
692 for word in lst
995 for word in lst
693 if snake_case_re.match(word)
996 if snake_case_re.match(word)
694 }
997 }
695 for word in shortened.keys():
998 for word in shortened.keys():
696 if word[:n] == text and word != "__builtins__":
999 if word[:n] == text and word != "__builtins__":
697 match_append(shortened[word])
1000 match_append(shortened[word])
698 return matches
1001 return matches
699
1002
700 def attr_matches(self, text):
1003 def attr_matches(self, text):
701 """Compute matches when text contains a dot.
1004 """Compute matches when text contains a dot.
702
1005
703 Assuming the text is of the form NAME.NAME....[NAME], and is
1006 Assuming the text is of the form NAME.NAME....[NAME], and is
704 evaluatable in self.namespace or self.global_namespace, it will be
1007 evaluatable in self.namespace or self.global_namespace, it will be
705 evaluated and its attributes (as revealed by dir()) are used as
1008 evaluated and its attributes (as revealed by dir()) are used as
706 possible completions. (For class instances, class members are
1009 possible completions. (For class instances, class members are
707 also considered.)
1010 also considered.)
708
1011
709 WARNING: this can still invoke arbitrary C code, if an object
1012 WARNING: this can still invoke arbitrary C code, if an object
710 with a __getattr__ hook is evaluated.
1013 with a __getattr__ hook is evaluated.
711
1014
712 """
1015 """
713
1016
714 # Another option, seems to work great. Catches things like ''.<tab>
1017 # Another option, seems to work great. Catches things like ''.<tab>
715 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
1018 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
716
1019
717 if m:
1020 if m:
718 expr, attr = m.group(1, 3)
1021 expr, attr = m.group(1, 3)
719 elif self.greedy:
1022 elif self.greedy:
720 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
1023 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
721 if not m2:
1024 if not m2:
722 return []
1025 return []
723 expr, attr = m2.group(1,2)
1026 expr, attr = m2.group(1,2)
724 else:
1027 else:
725 return []
1028 return []
726
1029
727 try:
1030 try:
728 obj = eval(expr, self.namespace)
1031 obj = eval(expr, self.namespace)
729 except:
1032 except:
730 try:
1033 try:
731 obj = eval(expr, self.global_namespace)
1034 obj = eval(expr, self.global_namespace)
732 except:
1035 except:
733 return []
1036 return []
734
1037
735 if self.limit_to__all__ and hasattr(obj, '__all__'):
1038 if self.limit_to__all__ and hasattr(obj, '__all__'):
736 words = get__all__entries(obj)
1039 words = get__all__entries(obj)
737 else:
1040 else:
738 words = dir2(obj)
1041 words = dir2(obj)
739
1042
740 try:
1043 try:
741 words = generics.complete_object(obj, words)
1044 words = generics.complete_object(obj, words)
742 except TryNext:
1045 except TryNext:
743 pass
1046 pass
744 except AssertionError:
1047 except AssertionError:
745 raise
1048 raise
746 except Exception:
1049 except Exception:
747 # Silence errors from completion function
1050 # Silence errors from completion function
748 #raise # dbg
1051 #raise # dbg
749 pass
1052 pass
750 # Build match list to return
1053 # Build match list to return
751 n = len(attr)
1054 n = len(attr)
752 return [u"%s.%s" % (expr, w) for w in words if w[:n] == attr ]
1055 return [u"%s.%s" % (expr, w) for w in words if w[:n] == attr ]
753
1056
754
1057
755 def get__all__entries(obj):
1058 def get__all__entries(obj):
756 """returns the strings in the __all__ attribute"""
1059 """returns the strings in the __all__ attribute"""
757 try:
1060 try:
758 words = getattr(obj, '__all__')
1061 words = getattr(obj, '__all__')
759 except:
1062 except:
760 return []
1063 return []
761
1064
762 return [w for w in words if isinstance(w, str)]
1065 return [w for w in words if isinstance(w, str)]
763
1066
764
1067
765 def match_dict_keys(keys: List[Union[str, bytes, Tuple[Union[str, bytes]]]], prefix: str, delims: str,
1068 def match_dict_keys(keys: List[Union[str, bytes, Tuple[Union[str, bytes]]]], prefix: str, delims: str,
766 extra_prefix: Optional[Tuple[str, bytes]]=None) -> Tuple[str, int, List[str]]:
1069 extra_prefix: Optional[Tuple[str, bytes]]=None) -> Tuple[str, int, List[str]]:
767 """Used by dict_key_matches, matching the prefix to a list of keys
1070 """Used by dict_key_matches, matching the prefix to a list of keys
768
1071
769 Parameters
1072 Parameters
770 ----------
1073 ----------
771 keys
1074 keys
772 list of keys in dictionary currently being completed.
1075 list of keys in dictionary currently being completed.
773 prefix
1076 prefix
774 Part of the text already typed by the user. E.g. `mydict[b'fo`
1077 Part of the text already typed by the user. E.g. `mydict[b'fo`
775 delims
1078 delims
776 String of delimiters to consider when finding the current key.
1079 String of delimiters to consider when finding the current key.
777 extra_prefix : optional
1080 extra_prefix : optional
778 Part of the text already typed in multi-key index cases. E.g. for
1081 Part of the text already typed in multi-key index cases. E.g. for
779 `mydict['foo', "bar", 'b`, this would be `('foo', 'bar')`.
1082 `mydict['foo', "bar", 'b`, this would be `('foo', 'bar')`.
780
1083
781 Returns
1084 Returns
782 -------
1085 -------
783 A tuple of three elements: ``quote``, ``token_start``, ``matched``, with
1086 A tuple of three elements: ``quote``, ``token_start``, ``matched``, with
784 ``quote`` being the quote that need to be used to close current string.
1087 ``quote`` being the quote that need to be used to close current string.
785 ``token_start`` the position where the replacement should start occurring,
1088 ``token_start`` the position where the replacement should start occurring,
786 ``matches`` a list of replacement/completion
1089 ``matches`` a list of replacement/completion
787
1090
788 """
1091 """
789 prefix_tuple = extra_prefix if extra_prefix else ()
1092 prefix_tuple = extra_prefix if extra_prefix else ()
790 Nprefix = len(prefix_tuple)
1093 Nprefix = len(prefix_tuple)
791 def filter_prefix_tuple(key):
1094 def filter_prefix_tuple(key):
792 # Reject too short keys
1095 # Reject too short keys
793 if len(key) <= Nprefix:
1096 if len(key) <= Nprefix:
794 return False
1097 return False
795 # Reject keys with non str/bytes in it
1098 # Reject keys with non str/bytes in it
796 for k in key:
1099 for k in key:
797 if not isinstance(k, (str, bytes)):
1100 if not isinstance(k, (str, bytes)):
798 return False
1101 return False
799 # Reject keys that do not match the prefix
1102 # Reject keys that do not match the prefix
800 for k, pt in zip(key, prefix_tuple):
1103 for k, pt in zip(key, prefix_tuple):
801 if k != pt:
1104 if k != pt:
802 return False
1105 return False
803 # All checks passed!
1106 # All checks passed!
804 return True
1107 return True
805
1108
806 filtered_keys:List[Union[str,bytes]] = []
1109 filtered_keys:List[Union[str,bytes]] = []
807 def _add_to_filtered_keys(key):
1110 def _add_to_filtered_keys(key):
808 if isinstance(key, (str, bytes)):
1111 if isinstance(key, (str, bytes)):
809 filtered_keys.append(key)
1112 filtered_keys.append(key)
810
1113
811 for k in keys:
1114 for k in keys:
812 if isinstance(k, tuple):
1115 if isinstance(k, tuple):
813 if filter_prefix_tuple(k):
1116 if filter_prefix_tuple(k):
814 _add_to_filtered_keys(k[Nprefix])
1117 _add_to_filtered_keys(k[Nprefix])
815 else:
1118 else:
816 _add_to_filtered_keys(k)
1119 _add_to_filtered_keys(k)
817
1120
818 if not prefix:
1121 if not prefix:
819 return '', 0, [repr(k) for k in filtered_keys]
1122 return '', 0, [repr(k) for k in filtered_keys]
820 quote_match = re.search('["\']', prefix)
1123 quote_match = re.search('["\']', prefix)
821 assert quote_match is not None # silence mypy
1124 assert quote_match is not None # silence mypy
822 quote = quote_match.group()
1125 quote = quote_match.group()
823 try:
1126 try:
824 prefix_str = eval(prefix + quote, {})
1127 prefix_str = eval(prefix + quote, {})
825 except Exception:
1128 except Exception:
826 return '', 0, []
1129 return '', 0, []
827
1130
828 pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$'
1131 pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$'
829 token_match = re.search(pattern, prefix, re.UNICODE)
1132 token_match = re.search(pattern, prefix, re.UNICODE)
830 assert token_match is not None # silence mypy
1133 assert token_match is not None # silence mypy
831 token_start = token_match.start()
1134 token_start = token_match.start()
832 token_prefix = token_match.group()
1135 token_prefix = token_match.group()
833
1136
834 matched:List[str] = []
1137 matched:List[str] = []
835 for key in filtered_keys:
1138 for key in filtered_keys:
836 try:
1139 try:
837 if not key.startswith(prefix_str):
1140 if not key.startswith(prefix_str):
838 continue
1141 continue
839 except (AttributeError, TypeError, UnicodeError):
1142 except (AttributeError, TypeError, UnicodeError):
840 # Python 3+ TypeError on b'a'.startswith('a') or vice-versa
1143 # Python 3+ TypeError on b'a'.startswith('a') or vice-versa
841 continue
1144 continue
842
1145
843 # reformat remainder of key to begin with prefix
1146 # reformat remainder of key to begin with prefix
844 rem = key[len(prefix_str):]
1147 rem = key[len(prefix_str):]
845 # force repr wrapped in '
1148 # force repr wrapped in '
846 rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"')
1149 rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"')
847 rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
1150 rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
848 if quote == '"':
1151 if quote == '"':
849 # The entered prefix is quoted with ",
1152 # The entered prefix is quoted with ",
850 # but the match is quoted with '.
1153 # but the match is quoted with '.
851 # A contained " hence needs escaping for comparison:
1154 # A contained " hence needs escaping for comparison:
852 rem_repr = rem_repr.replace('"', '\\"')
1155 rem_repr = rem_repr.replace('"', '\\"')
853
1156
854 # then reinsert prefix from start of token
1157 # then reinsert prefix from start of token
855 matched.append('%s%s' % (token_prefix, rem_repr))
1158 matched.append('%s%s' % (token_prefix, rem_repr))
856 return quote, token_start, matched
1159 return quote, token_start, matched
857
1160
858
1161
859 def cursor_to_position(text:str, line:int, column:int)->int:
1162 def cursor_to_position(text:str, line:int, column:int)->int:
860 """
1163 """
861 Convert the (line,column) position of the cursor in text to an offset in a
1164 Convert the (line,column) position of the cursor in text to an offset in a
862 string.
1165 string.
863
1166
864 Parameters
1167 Parameters
865 ----------
1168 ----------
866 text : str
1169 text : str
867 The text in which to calculate the cursor offset
1170 The text in which to calculate the cursor offset
868 line : int
1171 line : int
869 Line of the cursor; 0-indexed
1172 Line of the cursor; 0-indexed
870 column : int
1173 column : int
871 Column of the cursor 0-indexed
1174 Column of the cursor 0-indexed
872
1175
873 Returns
1176 Returns
874 -------
1177 -------
875 Position of the cursor in ``text``, 0-indexed.
1178 Position of the cursor in ``text``, 0-indexed.
876
1179
877 See Also
1180 See Also
878 --------
1181 --------
879 position_to_cursor : reciprocal of this function
1182 position_to_cursor : reciprocal of this function
880
1183
881 """
1184 """
882 lines = text.split('\n')
1185 lines = text.split('\n')
883 assert line <= len(lines), '{} <= {}'.format(str(line), str(len(lines)))
1186 assert line <= len(lines), '{} <= {}'.format(str(line), str(len(lines)))
884
1187
885 return sum(len(l) + 1 for l in lines[:line]) + column
1188 return sum(len(l) + 1 for l in lines[:line]) + column
886
1189
887 def position_to_cursor(text:str, offset:int)->Tuple[int, int]:
1190 def position_to_cursor(text:str, offset:int)->Tuple[int, int]:
888 """
1191 """
889 Convert the position of the cursor in text (0 indexed) to a line
1192 Convert the position of the cursor in text (0 indexed) to a line
890 number(0-indexed) and a column number (0-indexed) pair
1193 number(0-indexed) and a column number (0-indexed) pair
891
1194
892 Position should be a valid position in ``text``.
1195 Position should be a valid position in ``text``.
893
1196
894 Parameters
1197 Parameters
895 ----------
1198 ----------
896 text : str
1199 text : str
897 The text in which to calculate the cursor offset
1200 The text in which to calculate the cursor offset
898 offset : int
1201 offset : int
899 Position of the cursor in ``text``, 0-indexed.
1202 Position of the cursor in ``text``, 0-indexed.
900
1203
901 Returns
1204 Returns
902 -------
1205 -------
903 (line, column) : (int, int)
1206 (line, column) : (int, int)
904 Line of the cursor; 0-indexed, column of the cursor 0-indexed
1207 Line of the cursor; 0-indexed, column of the cursor 0-indexed
905
1208
906 See Also
1209 See Also
907 --------
1210 --------
908 cursor_to_position : reciprocal of this function
1211 cursor_to_position : reciprocal of this function
909
1212
910 """
1213 """
911
1214
912 assert 0 <= offset <= len(text) , "0 <= %s <= %s" % (offset , len(text))
1215 assert 0 <= offset <= len(text) , "0 <= %s <= %s" % (offset , len(text))
913
1216
914 before = text[:offset]
1217 before = text[:offset]
915 blines = before.split('\n') # ! splitnes trim trailing \n
1218 blines = before.split('\n') # ! splitnes trim trailing \n
916 line = before.count('\n')
1219 line = before.count('\n')
917 col = len(blines[-1])
1220 col = len(blines[-1])
918 return line, col
1221 return line, col
919
1222
920
1223
921 def _safe_isinstance(obj, module, class_name):
1224 def _safe_isinstance(obj, module, class_name):
922 """Checks if obj is an instance of module.class_name if loaded
1225 """Checks if obj is an instance of module.class_name if loaded
923 """
1226 """
924 return (module in sys.modules and
1227 return (module in sys.modules and
925 isinstance(obj, getattr(import_module(module), class_name)))
1228 isinstance(obj, getattr(import_module(module), class_name)))
926
1229
927 def back_unicode_name_matches(text:str) -> Tuple[str, Sequence[str]]:
1230
1231 @context_matcher()
1232 def back_unicode_name_matcher(context: CompletionContext):
1233 """Match Unicode characters back to Unicode name
1234
1235 Same as :any:`back_unicode_name_matches`, but adopted to new Matcher API.
1236 """
1237 fragment, matches = back_unicode_name_matches(context.text_until_cursor)
1238 return _convert_matcher_v1_result_to_v2(
1239 matches, type="unicode", fragment=fragment, suppress_if_matches=True
1240 )
1241
1242
1243 def back_unicode_name_matches(text: str) -> Tuple[str, Sequence[str]]:
928 """Match Unicode characters back to Unicode name
1244 """Match Unicode characters back to Unicode name
929
1245
930 This does ``☃`` -> ``\\snowman``
1246 This does ``☃`` -> ``\\snowman``
931
1247
932 Note that snowman is not a valid python3 combining character but will be expanded.
1248 Note that snowman is not a valid python3 combining character but will be expanded.
933 Though it will not recombine back to the snowman character by the completion machinery.
1249 Though it will not recombine back to the snowman character by the completion machinery.
934
1250
935 This will not either back-complete standard sequences like \\n, \\b ...
1251 This will not either back-complete standard sequences like \\n, \\b ...
936
1252
1253 .. deprecated:: 8.6
1254 You can use :meth:`back_unicode_name_matcher` instead.
1255
937 Returns
1256 Returns
938 =======
1257 =======
939
1258
940 Return a tuple with two elements:
1259 Return a tuple with two elements:
941
1260
942 - The Unicode character that was matched (preceded with a backslash), or
1261 - The Unicode character that was matched (preceded with a backslash), or
943 empty string,
1262 empty string,
944 - a sequence (of 1), name for the match Unicode character, preceded by
1263 - a sequence (of 1), name for the match Unicode character, preceded by
945 backslash, or empty if no match.
1264 backslash, or empty if no match.
946
947 """
1265 """
948 if len(text)<2:
1266 if len(text)<2:
949 return '', ()
1267 return '', ()
950 maybe_slash = text[-2]
1268 maybe_slash = text[-2]
951 if maybe_slash != '\\':
1269 if maybe_slash != '\\':
952 return '', ()
1270 return '', ()
953
1271
954 char = text[-1]
1272 char = text[-1]
955 # no expand on quote for completion in strings.
1273 # no expand on quote for completion in strings.
956 # nor backcomplete standard ascii keys
1274 # nor backcomplete standard ascii keys
957 if char in string.ascii_letters or char in ('"',"'"):
1275 if char in string.ascii_letters or char in ('"',"'"):
958 return '', ()
1276 return '', ()
959 try :
1277 try :
960 unic = unicodedata.name(char)
1278 unic = unicodedata.name(char)
961 return '\\'+char,('\\'+unic,)
1279 return '\\'+char,('\\'+unic,)
962 except KeyError:
1280 except KeyError:
963 pass
1281 pass
964 return '', ()
1282 return '', ()
965
1283
966 def back_latex_name_matches(text:str) -> Tuple[str, Sequence[str]] :
1284
1285 @context_matcher()
1286 def back_latex_name_matcher(context: CompletionContext):
1287 """Match latex characters back to unicode name
1288
1289 Same as :any:`back_latex_name_matches`, but adopted to new Matcher API.
1290 """
1291 fragment, matches = back_latex_name_matches(context.text_until_cursor)
1292 return _convert_matcher_v1_result_to_v2(
1293 matches, type="latex", fragment=fragment, suppress_if_matches=True
1294 )
1295
1296
1297 def back_latex_name_matches(text: str) -> Tuple[str, Sequence[str]]:
967 """Match latex characters back to unicode name
1298 """Match latex characters back to unicode name
968
1299
969 This does ``\\ℵ`` -> ``\\aleph``
1300 This does ``\\ℵ`` -> ``\\aleph``
970
1301
1302 .. deprecated:: 8.6
1303 You can use :meth:`back_latex_name_matcher` instead.
971 """
1304 """
972 if len(text)<2:
1305 if len(text)<2:
973 return '', ()
1306 return '', ()
974 maybe_slash = text[-2]
1307 maybe_slash = text[-2]
975 if maybe_slash != '\\':
1308 if maybe_slash != '\\':
976 return '', ()
1309 return '', ()
977
1310
978
1311
979 char = text[-1]
1312 char = text[-1]
980 # no expand on quote for completion in strings.
1313 # no expand on quote for completion in strings.
981 # nor backcomplete standard ascii keys
1314 # nor backcomplete standard ascii keys
982 if char in string.ascii_letters or char in ('"',"'"):
1315 if char in string.ascii_letters or char in ('"',"'"):
983 return '', ()
1316 return '', ()
984 try :
1317 try :
985 latex = reverse_latex_symbol[char]
1318 latex = reverse_latex_symbol[char]
986 # '\\' replace the \ as well
1319 # '\\' replace the \ as well
987 return '\\'+char,[latex]
1320 return '\\'+char,[latex]
988 except KeyError:
1321 except KeyError:
989 pass
1322 pass
990 return '', ()
1323 return '', ()
991
1324
992
1325
993 def _formatparamchildren(parameter) -> str:
1326 def _formatparamchildren(parameter) -> str:
994 """
1327 """
995 Get parameter name and value from Jedi Private API
1328 Get parameter name and value from Jedi Private API
996
1329
997 Jedi does not expose a simple way to get `param=value` from its API.
1330 Jedi does not expose a simple way to get `param=value` from its API.
998
1331
999 Parameters
1332 Parameters
1000 ----------
1333 ----------
1001 parameter
1334 parameter
1002 Jedi's function `Param`
1335 Jedi's function `Param`
1003
1336
1004 Returns
1337 Returns
1005 -------
1338 -------
1006 A string like 'a', 'b=1', '*args', '**kwargs'
1339 A string like 'a', 'b=1', '*args', '**kwargs'
1007
1340
1008 """
1341 """
1009 description = parameter.description
1342 description = parameter.description
1010 if not description.startswith('param '):
1343 if not description.startswith('param '):
1011 raise ValueError('Jedi function parameter description have change format.'
1344 raise ValueError('Jedi function parameter description have change format.'
1012 'Expected "param ...", found %r".' % description)
1345 'Expected "param ...", found %r".' % description)
1013 return description[6:]
1346 return description[6:]
1014
1347
1015 def _make_signature(completion)-> str:
1348 def _make_signature(completion)-> str:
1016 """
1349 """
1017 Make the signature from a jedi completion
1350 Make the signature from a jedi completion
1018
1351
1019 Parameters
1352 Parameters
1020 ----------
1353 ----------
1021 completion : jedi.Completion
1354 completion : jedi.Completion
1022 object does not complete a function type
1355 object does not complete a function type
1023
1356
1024 Returns
1357 Returns
1025 -------
1358 -------
1026 a string consisting of the function signature, with the parenthesis but
1359 a string consisting of the function signature, with the parenthesis but
1027 without the function name. example:
1360 without the function name. example:
1028 `(a, *args, b=1, **kwargs)`
1361 `(a, *args, b=1, **kwargs)`
1029
1362
1030 """
1363 """
1031
1364
1032 # it looks like this might work on jedi 0.17
1365 # it looks like this might work on jedi 0.17
1033 if hasattr(completion, 'get_signatures'):
1366 if hasattr(completion, 'get_signatures'):
1034 signatures = completion.get_signatures()
1367 signatures = completion.get_signatures()
1035 if not signatures:
1368 if not signatures:
1036 return '(?)'
1369 return '(?)'
1037
1370
1038 c0 = completion.get_signatures()[0]
1371 c0 = completion.get_signatures()[0]
1039 return '('+c0.to_string().split('(', maxsplit=1)[1]
1372 return '('+c0.to_string().split('(', maxsplit=1)[1]
1040
1373
1041 return '(%s)'% ', '.join([f for f in (_formatparamchildren(p) for signature in completion.get_signatures()
1374 return '(%s)'% ', '.join([f for f in (_formatparamchildren(p) for signature in completion.get_signatures()
1042 for p in signature.defined_names()) if f])
1375 for p in signature.defined_names()) if f])
1043
1376
1044
1377
1045 class _CompleteResult(NamedTuple):
1378 _CompleteResult = Dict[str, MatcherResult]
1046 matched_text : str
1379
1047 matches: Sequence[str]
1380
1048 matches_origin: Sequence[str]
1381 def _convert_matcher_v1_result_to_v2(
1049 jedi_matches: Any
1382 matches: Sequence[str],
1383 type: str,
1384 fragment: str = None,
1385 suppress_if_matches: bool = False,
1386 ) -> SimpleMatcherResult:
1387 """Utility to help with transition"""
1388 result = {
1389 "completions": [SimpleCompletion(text=match, type=type) for match in matches],
1390 "suppress": (True if matches else False) if suppress_if_matches else False,
1391 }
1392 if fragment is not None:
1393 result["matched_fragment"] = fragment
1394 return result
1050
1395
1051
1396
1052 class IPCompleter(Completer):
1397 class IPCompleter(Completer):
1053 """Extension of the completer class with IPython-specific features"""
1398 """Extension of the completer class with IPython-specific features"""
1054
1399
1055 __dict_key_regexps: Optional[Dict[bool,Pattern]] = None
1400 __dict_key_regexps: Optional[Dict[bool,Pattern]] = None
1056
1401
1057 @observe('greedy')
1402 @observe('greedy')
1058 def _greedy_changed(self, change):
1403 def _greedy_changed(self, change):
1059 """update the splitter and readline delims when greedy is changed"""
1404 """update the splitter and readline delims when greedy is changed"""
1060 if change['new']:
1405 if change['new']:
1061 self.splitter.delims = GREEDY_DELIMS
1406 self.splitter.delims = GREEDY_DELIMS
1062 else:
1407 else:
1063 self.splitter.delims = DELIMS
1408 self.splitter.delims = DELIMS
1064
1409
1065 dict_keys_only = Bool(False,
1410 dict_keys_only = Bool(
1066 help="""Whether to show dict key matches only""")
1411 False,
1412 help="""
1413 Whether to show dict key matches only.
1414
1415 (disables all matchers except for `IPCompleter.dict_key_matcher`).
1416 """,
1417 )
1418
1419 suppress_competing_matchers = UnionTrait(
1420 [Bool(allow_none=True), DictTrait(Bool(None, allow_none=True))],
1421 default_value=None,
1422 help="""
1423 Whether to suppress completions from other *Matchers*.
1424
1425 When set to ``None`` (default) the matchers will attempt to auto-detect
1426 whether suppression of other matchers is desirable. For example, at
1427 the beginning of a line followed by `%` we expect a magic completion
1428 to be the only applicable option, and after ``my_dict['`` we usually
1429 expect a completion with an existing dictionary key.
1430
1431 If you want to disable this heuristic and see completions from all matchers,
1432 set ``IPCompleter.suppress_competing_matchers = False``.
1433 To disable the heuristic for specific matchers provide a dictionary mapping:
1434 ``IPCompleter.suppress_competing_matchers = {'IPCompleter.dict_key_matcher': False}``.
1435
1436 Set ``IPCompleter.suppress_competing_matchers = True`` to limit
1437 completions to the set of matchers with the highest priority;
1438 this is equivalent to ``IPCompleter.merge_completions`` and
1439 can be beneficial for performance, but will sometimes omit relevant
1440 candidates from matchers further down the priority list.
1441 """,
1442 ).tag(config=True)
1067
1443
1068 merge_completions = Bool(True,
1444 merge_completions = Bool(
1445 True,
1069 help="""Whether to merge completion results into a single list
1446 help="""Whether to merge completion results into a single list
1070
1447
1071 If False, only the completion results from the first non-empty
1448 If False, only the completion results from the first non-empty
1072 completer will be returned.
1449 completer will be returned.
1073 """
1450
1451 As of version 8.6.0, setting the value to ``False`` is an alias for:
1452 ``IPCompleter.suppress_competing_matchers = True.``.
1453 """,
1454 ).tag(config=True)
1455
1456 disable_matchers = ListTrait(
1457 Unicode(), help="""List of matchers to disable."""
1074 ).tag(config=True)
1458 ).tag(config=True)
1075 omit__names = Enum((0,1,2), default_value=2,
1459
1460 omit__names = Enum(
1461 (0, 1, 2),
1462 default_value=2,
1076 help="""Instruct the completer to omit private method names
1463 help="""Instruct the completer to omit private method names
1077
1464
1078 Specifically, when completing on ``object.<tab>``.
1465 Specifically, when completing on ``object.<tab>``.
1079
1466
1080 When 2 [default]: all names that start with '_' will be excluded.
1467 When 2 [default]: all names that start with '_' will be excluded.
1081
1468
1082 When 1: all 'magic' names (``__foo__``) will be excluded.
1469 When 1: all 'magic' names (``__foo__``) will be excluded.
1083
1470
1084 When 0: nothing will be excluded.
1471 When 0: nothing will be excluded.
1085 """
1472 """
1086 ).tag(config=True)
1473 ).tag(config=True)
1087 limit_to__all__ = Bool(False,
1474 limit_to__all__ = Bool(False,
1088 help="""
1475 help="""
1089 DEPRECATED as of version 5.0.
1476 DEPRECATED as of version 5.0.
1090
1477
1091 Instruct the completer to use __all__ for the completion
1478 Instruct the completer to use __all__ for the completion
1092
1479
1093 Specifically, when completing on ``object.<tab>``.
1480 Specifically, when completing on ``object.<tab>``.
1094
1481
1095 When True: only those names in obj.__all__ will be included.
1482 When True: only those names in obj.__all__ will be included.
1096
1483
1097 When False [default]: the __all__ attribute is ignored
1484 When False [default]: the __all__ attribute is ignored
1098 """,
1485 """,
1099 ).tag(config=True)
1486 ).tag(config=True)
1100
1487
1101 profile_completions = Bool(
1488 profile_completions = Bool(
1102 default_value=False,
1489 default_value=False,
1103 help="If True, emit profiling data for completion subsystem using cProfile."
1490 help="If True, emit profiling data for completion subsystem using cProfile."
1104 ).tag(config=True)
1491 ).tag(config=True)
1105
1492
1106 profiler_output_dir = Unicode(
1493 profiler_output_dir = Unicode(
1107 default_value=".completion_profiles",
1494 default_value=".completion_profiles",
1108 help="Template for path at which to output profile data for completions."
1495 help="Template for path at which to output profile data for completions."
1109 ).tag(config=True)
1496 ).tag(config=True)
1110
1497
1111 @observe('limit_to__all__')
1498 @observe('limit_to__all__')
1112 def _limit_to_all_changed(self, change):
1499 def _limit_to_all_changed(self, change):
1113 warnings.warn('`IPython.core.IPCompleter.limit_to__all__` configuration '
1500 warnings.warn('`IPython.core.IPCompleter.limit_to__all__` configuration '
1114 'value has been deprecated since IPython 5.0, will be made to have '
1501 'value has been deprecated since IPython 5.0, will be made to have '
1115 'no effects and then removed in future version of IPython.',
1502 'no effects and then removed in future version of IPython.',
1116 UserWarning)
1503 UserWarning)
1117
1504
1118 def __init__(
1505 def __init__(
1119 self, shell=None, namespace=None, global_namespace=None, config=None, **kwargs
1506 self, shell=None, namespace=None, global_namespace=None, config=None, **kwargs
1120 ):
1507 ):
1121 """IPCompleter() -> completer
1508 """IPCompleter() -> completer
1122
1509
1123 Return a completer object.
1510 Return a completer object.
1124
1511
1125 Parameters
1512 Parameters
1126 ----------
1513 ----------
1127 shell
1514 shell
1128 a pointer to the ipython shell itself. This is needed
1515 a pointer to the ipython shell itself. This is needed
1129 because this completer knows about magic functions, and those can
1516 because this completer knows about magic functions, and those can
1130 only be accessed via the ipython instance.
1517 only be accessed via the ipython instance.
1131 namespace : dict, optional
1518 namespace : dict, optional
1132 an optional dict where completions are performed.
1519 an optional dict where completions are performed.
1133 global_namespace : dict, optional
1520 global_namespace : dict, optional
1134 secondary optional dict for completions, to
1521 secondary optional dict for completions, to
1135 handle cases (such as IPython embedded inside functions) where
1522 handle cases (such as IPython embedded inside functions) where
1136 both Python scopes are visible.
1523 both Python scopes are visible.
1137 config : Config
1524 config : Config
1138 traitlet's config object
1525 traitlet's config object
1139 **kwargs
1526 **kwargs
1140 passed to super class unmodified.
1527 passed to super class unmodified.
1141 """
1528 """
1142
1529
1143 self.magic_escape = ESC_MAGIC
1530 self.magic_escape = ESC_MAGIC
1144 self.splitter = CompletionSplitter()
1531 self.splitter = CompletionSplitter()
1145
1532
1146 # _greedy_changed() depends on splitter and readline being defined:
1533 # _greedy_changed() depends on splitter and readline being defined:
1147 super().__init__(
1534 super().__init__(
1148 namespace=namespace,
1535 namespace=namespace,
1149 global_namespace=global_namespace,
1536 global_namespace=global_namespace,
1150 config=config,
1537 config=config,
1151 **kwargs
1538 **kwargs,
1152 )
1539 )
1153
1540
1154 # List where completion matches will be stored
1541 # List where completion matches will be stored
1155 self.matches = []
1542 self.matches = []
1156 self.shell = shell
1543 self.shell = shell
1157 # Regexp to split filenames with spaces in them
1544 # Regexp to split filenames with spaces in them
1158 self.space_name_re = re.compile(r'([^\\] )')
1545 self.space_name_re = re.compile(r'([^\\] )')
1159 # Hold a local ref. to glob.glob for speed
1546 # Hold a local ref. to glob.glob for speed
1160 self.glob = glob.glob
1547 self.glob = glob.glob
1161
1548
1162 # Determine if we are running on 'dumb' terminals, like (X)Emacs
1549 # Determine if we are running on 'dumb' terminals, like (X)Emacs
1163 # buffers, to avoid completion problems.
1550 # buffers, to avoid completion problems.
1164 term = os.environ.get('TERM','xterm')
1551 term = os.environ.get('TERM','xterm')
1165 self.dumb_terminal = term in ['dumb','emacs']
1552 self.dumb_terminal = term in ['dumb','emacs']
1166
1553
1167 # Special handling of backslashes needed in win32 platforms
1554 # Special handling of backslashes needed in win32 platforms
1168 if sys.platform == "win32":
1555 if sys.platform == "win32":
1169 self.clean_glob = self._clean_glob_win32
1556 self.clean_glob = self._clean_glob_win32
1170 else:
1557 else:
1171 self.clean_glob = self._clean_glob
1558 self.clean_glob = self._clean_glob
1172
1559
1173 #regexp to parse docstring for function signature
1560 #regexp to parse docstring for function signature
1174 self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1561 self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1175 self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1562 self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1176 #use this if positional argument name is also needed
1563 #use this if positional argument name is also needed
1177 #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)')
1564 #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)')
1178
1565
1179 self.magic_arg_matchers = [
1566 self.magic_arg_matchers = [
1180 self.magic_config_matches,
1567 self.magic_config_matcher,
1181 self.magic_color_matches,
1568 self.magic_color_matcher,
1182 ]
1569 ]
1183
1570
1184 # This is set externally by InteractiveShell
1571 # This is set externally by InteractiveShell
1185 self.custom_completers = None
1572 self.custom_completers = None
1186
1573
1187 # This is a list of names of unicode characters that can be completed
1574 # This is a list of names of unicode characters that can be completed
1188 # into their corresponding unicode value. The list is large, so we
1575 # into their corresponding unicode value. The list is large, so we
1189 # lazily initialize it on first use. Consuming code should access this
1576 # lazily initialize it on first use. Consuming code should access this
1190 # attribute through the `@unicode_names` property.
1577 # attribute through the `@unicode_names` property.
1191 self._unicode_names = None
1578 self._unicode_names = None
1192
1579
1580 self._backslash_combining_matchers = [
1581 self.latex_name_matcher,
1582 self.unicode_name_matcher,
1583 back_latex_name_matcher,
1584 back_unicode_name_matcher,
1585 self.fwd_unicode_matcher,
1586 ]
1587
1588 if not self.backslash_combining_completions:
1589 for matcher in self._backslash_combining_matchers:
1590 self.disable_matchers.append(matcher.matcher_identifier)
1591
1592 if not self.merge_completions:
1593 self.suppress_competing_matchers = True
1594
1193 @property
1595 @property
1194 def matchers(self) -> List[Any]:
1596 def matchers(self) -> List[Matcher]:
1195 """All active matcher routines for completion"""
1597 """All active matcher routines for completion"""
1196 if self.dict_keys_only:
1598 if self.dict_keys_only:
1197 return [self.dict_key_matches]
1599 return [self.dict_key_matcher]
1198
1600
1199 if self.use_jedi:
1601 if self.use_jedi:
1200 return [
1602 return [
1201 *self.custom_matchers,
1603 *self.custom_matchers,
1202 self.dict_key_matches,
1604 *self._backslash_combining_matchers,
1203 self.file_matches,
1605 *self.magic_arg_matchers,
1204 self.magic_matches,
1606 self.custom_completer_matcher,
1607 self.magic_matcher,
1608 self._jedi_matcher,
1609 self.dict_key_matcher,
1610 self.file_matcher,
1205 ]
1611 ]
1206 else:
1612 else:
1207 return [
1613 return [
1208 *self.custom_matchers,
1614 *self.custom_matchers,
1209 self.dict_key_matches,
1615 *self._backslash_combining_matchers,
1616 *self.magic_arg_matchers,
1617 self.custom_completer_matcher,
1618 self.dict_key_matcher,
1619 # TODO: convert python_matches to v2 API
1620 self.magic_matcher,
1210 self.python_matches,
1621 self.python_matches,
1211 self.file_matches,
1622 self.file_matcher,
1212 self.magic_matches,
1623 self.python_func_kw_matcher,
1213 self.python_func_kw_matches,
1214 ]
1624 ]
1215
1625
1216 def all_completions(self, text:str) -> List[str]:
1626 def all_completions(self, text:str) -> List[str]:
1217 """
1627 """
1218 Wrapper around the completion methods for the benefit of emacs.
1628 Wrapper around the completion methods for the benefit of emacs.
1219 """
1629 """
1220 prefix = text.rpartition('.')[0]
1630 prefix = text.rpartition('.')[0]
1221 with provisionalcompleter():
1631 with provisionalcompleter():
1222 return ['.'.join([prefix, c.text]) if prefix and self.use_jedi else c.text
1632 return ['.'.join([prefix, c.text]) if prefix and self.use_jedi else c.text
1223 for c in self.completions(text, len(text))]
1633 for c in self.completions(text, len(text))]
1224
1634
1225 return self.complete(text)[1]
1635 return self.complete(text)[1]
1226
1636
1227 def _clean_glob(self, text:str):
1637 def _clean_glob(self, text:str):
1228 return self.glob("%s*" % text)
1638 return self.glob("%s*" % text)
1229
1639
1230 def _clean_glob_win32(self, text:str):
1640 def _clean_glob_win32(self, text:str):
1231 return [f.replace("\\","/")
1641 return [f.replace("\\","/")
1232 for f in self.glob("%s*" % text)]
1642 for f in self.glob("%s*" % text)]
1233
1643
1234 def file_matches(self, text:str)->List[str]:
1644 @context_matcher()
1645 def file_matcher(self, context: CompletionContext) -> SimpleMatcherResult:
1646 """Same as :any:`file_matches`, but adopted to new Matcher API."""
1647 matches = self.file_matches(context.token)
1648 # TODO: add a heuristic for suppressing (e.g. if it has OS-specific delimiter,
1649 # starts with `/home/`, `C:\`, etc)
1650 return _convert_matcher_v1_result_to_v2(matches, type="path")
1651
1652 def file_matches(self, text: str) -> List[str]:
1235 """Match filenames, expanding ~USER type strings.
1653 """Match filenames, expanding ~USER type strings.
1236
1654
1237 Most of the seemingly convoluted logic in this completer is an
1655 Most of the seemingly convoluted logic in this completer is an
1238 attempt to handle filenames with spaces in them. And yet it's not
1656 attempt to handle filenames with spaces in them. And yet it's not
1239 quite perfect, because Python's readline doesn't expose all of the
1657 quite perfect, because Python's readline doesn't expose all of the
1240 GNU readline details needed for this to be done correctly.
1658 GNU readline details needed for this to be done correctly.
1241
1659
1242 For a filename with a space in it, the printed completions will be
1660 For a filename with a space in it, the printed completions will be
1243 only the parts after what's already been typed (instead of the
1661 only the parts after what's already been typed (instead of the
1244 full completions, as is normally done). I don't think with the
1662 full completions, as is normally done). I don't think with the
1245 current (as of Python 2.3) Python readline it's possible to do
1663 current (as of Python 2.3) Python readline it's possible to do
1246 better."""
1664 better.
1665
1666 .. deprecated:: 8.6
1667 You can use :meth:`file_matcher` instead.
1668 """
1247
1669
1248 # chars that require escaping with backslash - i.e. chars
1670 # chars that require escaping with backslash - i.e. chars
1249 # that readline treats incorrectly as delimiters, but we
1671 # that readline treats incorrectly as delimiters, but we
1250 # don't want to treat as delimiters in filename matching
1672 # don't want to treat as delimiters in filename matching
1251 # when escaped with backslash
1673 # when escaped with backslash
1252 if text.startswith('!'):
1674 if text.startswith('!'):
1253 text = text[1:]
1675 text = text[1:]
1254 text_prefix = u'!'
1676 text_prefix = u'!'
1255 else:
1677 else:
1256 text_prefix = u''
1678 text_prefix = u''
1257
1679
1258 text_until_cursor = self.text_until_cursor
1680 text_until_cursor = self.text_until_cursor
1259 # track strings with open quotes
1681 # track strings with open quotes
1260 open_quotes = has_open_quotes(text_until_cursor)
1682 open_quotes = has_open_quotes(text_until_cursor)
1261
1683
1262 if '(' in text_until_cursor or '[' in text_until_cursor:
1684 if '(' in text_until_cursor or '[' in text_until_cursor:
1263 lsplit = text
1685 lsplit = text
1264 else:
1686 else:
1265 try:
1687 try:
1266 # arg_split ~ shlex.split, but with unicode bugs fixed by us
1688 # arg_split ~ shlex.split, but with unicode bugs fixed by us
1267 lsplit = arg_split(text_until_cursor)[-1]
1689 lsplit = arg_split(text_until_cursor)[-1]
1268 except ValueError:
1690 except ValueError:
1269 # typically an unmatched ", or backslash without escaped char.
1691 # typically an unmatched ", or backslash without escaped char.
1270 if open_quotes:
1692 if open_quotes:
1271 lsplit = text_until_cursor.split(open_quotes)[-1]
1693 lsplit = text_until_cursor.split(open_quotes)[-1]
1272 else:
1694 else:
1273 return []
1695 return []
1274 except IndexError:
1696 except IndexError:
1275 # tab pressed on empty line
1697 # tab pressed on empty line
1276 lsplit = ""
1698 lsplit = ""
1277
1699
1278 if not open_quotes and lsplit != protect_filename(lsplit):
1700 if not open_quotes and lsplit != protect_filename(lsplit):
1279 # if protectables are found, do matching on the whole escaped name
1701 # if protectables are found, do matching on the whole escaped name
1280 has_protectables = True
1702 has_protectables = True
1281 text0,text = text,lsplit
1703 text0,text = text,lsplit
1282 else:
1704 else:
1283 has_protectables = False
1705 has_protectables = False
1284 text = os.path.expanduser(text)
1706 text = os.path.expanduser(text)
1285
1707
1286 if text == "":
1708 if text == "":
1287 return [text_prefix + protect_filename(f) for f in self.glob("*")]
1709 return [text_prefix + protect_filename(f) for f in self.glob("*")]
1288
1710
1289 # Compute the matches from the filesystem
1711 # Compute the matches from the filesystem
1290 if sys.platform == 'win32':
1712 if sys.platform == 'win32':
1291 m0 = self.clean_glob(text)
1713 m0 = self.clean_glob(text)
1292 else:
1714 else:
1293 m0 = self.clean_glob(text.replace('\\', ''))
1715 m0 = self.clean_glob(text.replace('\\', ''))
1294
1716
1295 if has_protectables:
1717 if has_protectables:
1296 # If we had protectables, we need to revert our changes to the
1718 # If we had protectables, we need to revert our changes to the
1297 # beginning of filename so that we don't double-write the part
1719 # beginning of filename so that we don't double-write the part
1298 # of the filename we have so far
1720 # of the filename we have so far
1299 len_lsplit = len(lsplit)
1721 len_lsplit = len(lsplit)
1300 matches = [text_prefix + text0 +
1722 matches = [text_prefix + text0 +
1301 protect_filename(f[len_lsplit:]) for f in m0]
1723 protect_filename(f[len_lsplit:]) for f in m0]
1302 else:
1724 else:
1303 if open_quotes:
1725 if open_quotes:
1304 # if we have a string with an open quote, we don't need to
1726 # if we have a string with an open quote, we don't need to
1305 # protect the names beyond the quote (and we _shouldn't_, as
1727 # protect the names beyond the quote (and we _shouldn't_, as
1306 # it would cause bugs when the filesystem call is made).
1728 # it would cause bugs when the filesystem call is made).
1307 matches = m0 if sys.platform == "win32" else\
1729 matches = m0 if sys.platform == "win32" else\
1308 [protect_filename(f, open_quotes) for f in m0]
1730 [protect_filename(f, open_quotes) for f in m0]
1309 else:
1731 else:
1310 matches = [text_prefix +
1732 matches = [text_prefix +
1311 protect_filename(f) for f in m0]
1733 protect_filename(f) for f in m0]
1312
1734
1313 # Mark directories in input list by appending '/' to their names.
1735 # Mark directories in input list by appending '/' to their names.
1314 return [x+'/' if os.path.isdir(x) else x for x in matches]
1736 return [x+'/' if os.path.isdir(x) else x for x in matches]
1315
1737
1316 def magic_matches(self, text:str):
1738 @context_matcher()
1317 """Match magics"""
1739 def magic_matcher(self, context: CompletionContext) -> SimpleMatcherResult:
1740 """Match magics."""
1741 text = context.token
1742 matches = self.magic_matches(text)
1743 result = _convert_matcher_v1_result_to_v2(matches, type="magic")
1744 is_magic_prefix = len(text) > 0 and text[0] == "%"
1745 result["suppress"] = is_magic_prefix and bool(result["completions"])
1746 return result
1747
1748 def magic_matches(self, text: str):
1749 """Match magics.
1750
1751 .. deprecated:: 8.6
1752 You can use :meth:`magic_matcher` instead.
1753 """
1318 # Get all shell magics now rather than statically, so magics loaded at
1754 # Get all shell magics now rather than statically, so magics loaded at
1319 # runtime show up too.
1755 # runtime show up too.
1320 lsm = self.shell.magics_manager.lsmagic()
1756 lsm = self.shell.magics_manager.lsmagic()
1321 line_magics = lsm['line']
1757 line_magics = lsm['line']
1322 cell_magics = lsm['cell']
1758 cell_magics = lsm['cell']
1323 pre = self.magic_escape
1759 pre = self.magic_escape
1324 pre2 = pre+pre
1760 pre2 = pre+pre
1325
1761
1326 explicit_magic = text.startswith(pre)
1762 explicit_magic = text.startswith(pre)
1327
1763
1328 # Completion logic:
1764 # Completion logic:
1329 # - user gives %%: only do cell magics
1765 # - user gives %%: only do cell magics
1330 # - user gives %: do both line and cell magics
1766 # - user gives %: do both line and cell magics
1331 # - no prefix: do both
1767 # - no prefix: do both
1332 # In other words, line magics are skipped if the user gives %% explicitly
1768 # In other words, line magics are skipped if the user gives %% explicitly
1333 #
1769 #
1334 # We also exclude magics that match any currently visible names:
1770 # We also exclude magics that match any currently visible names:
1335 # https://github.com/ipython/ipython/issues/4877, unless the user has
1771 # https://github.com/ipython/ipython/issues/4877, unless the user has
1336 # typed a %:
1772 # typed a %:
1337 # https://github.com/ipython/ipython/issues/10754
1773 # https://github.com/ipython/ipython/issues/10754
1338 bare_text = text.lstrip(pre)
1774 bare_text = text.lstrip(pre)
1339 global_matches = self.global_matches(bare_text)
1775 global_matches = self.global_matches(bare_text)
1340 if not explicit_magic:
1776 if not explicit_magic:
1341 def matches(magic):
1777 def matches(magic):
1342 """
1778 """
1343 Filter magics, in particular remove magics that match
1779 Filter magics, in particular remove magics that match
1344 a name present in global namespace.
1780 a name present in global namespace.
1345 """
1781 """
1346 return ( magic.startswith(bare_text) and
1782 return ( magic.startswith(bare_text) and
1347 magic not in global_matches )
1783 magic not in global_matches )
1348 else:
1784 else:
1349 def matches(magic):
1785 def matches(magic):
1350 return magic.startswith(bare_text)
1786 return magic.startswith(bare_text)
1351
1787
1352 comp = [ pre2+m for m in cell_magics if matches(m)]
1788 comp = [ pre2+m for m in cell_magics if matches(m)]
1353 if not text.startswith(pre2):
1789 if not text.startswith(pre2):
1354 comp += [ pre+m for m in line_magics if matches(m)]
1790 comp += [ pre+m for m in line_magics if matches(m)]
1355
1791
1356 return comp
1792 return comp
1357
1793
1358 def magic_config_matches(self, text:str) -> List[str]:
1794 @context_matcher()
1359 """ Match class names and attributes for %config magic """
1795 def magic_config_matcher(self, context: CompletionContext) -> SimpleMatcherResult:
1796 """Match class names and attributes for %config magic."""
1797 # NOTE: uses `line_buffer` equivalent for compatibility
1798 matches = self.magic_config_matches(context.line_with_cursor)
1799 return _convert_matcher_v1_result_to_v2(matches, type="param")
1800
1801 def magic_config_matches(self, text: str) -> List[str]:
1802 """Match class names and attributes for %config magic.
1803
1804 .. deprecated:: 8.6
1805 You can use :meth:`magic_config_matcher` instead.
1806 """
1360 texts = text.strip().split()
1807 texts = text.strip().split()
1361
1808
1362 if len(texts) > 0 and (texts[0] == 'config' or texts[0] == '%config'):
1809 if len(texts) > 0 and (texts[0] == 'config' or texts[0] == '%config'):
1363 # get all configuration classes
1810 # get all configuration classes
1364 classes = sorted(set([ c for c in self.shell.configurables
1811 classes = sorted(set([ c for c in self.shell.configurables
1365 if c.__class__.class_traits(config=True)
1812 if c.__class__.class_traits(config=True)
1366 ]), key=lambda x: x.__class__.__name__)
1813 ]), key=lambda x: x.__class__.__name__)
1367 classnames = [ c.__class__.__name__ for c in classes ]
1814 classnames = [ c.__class__.__name__ for c in classes ]
1368
1815
1369 # return all classnames if config or %config is given
1816 # return all classnames if config or %config is given
1370 if len(texts) == 1:
1817 if len(texts) == 1:
1371 return classnames
1818 return classnames
1372
1819
1373 # match classname
1820 # match classname
1374 classname_texts = texts[1].split('.')
1821 classname_texts = texts[1].split('.')
1375 classname = classname_texts[0]
1822 classname = classname_texts[0]
1376 classname_matches = [ c for c in classnames
1823 classname_matches = [ c for c in classnames
1377 if c.startswith(classname) ]
1824 if c.startswith(classname) ]
1378
1825
1379 # return matched classes or the matched class with attributes
1826 # return matched classes or the matched class with attributes
1380 if texts[1].find('.') < 0:
1827 if texts[1].find('.') < 0:
1381 return classname_matches
1828 return classname_matches
1382 elif len(classname_matches) == 1 and \
1829 elif len(classname_matches) == 1 and \
1383 classname_matches[0] == classname:
1830 classname_matches[0] == classname:
1384 cls = classes[classnames.index(classname)].__class__
1831 cls = classes[classnames.index(classname)].__class__
1385 help = cls.class_get_help()
1832 help = cls.class_get_help()
1386 # strip leading '--' from cl-args:
1833 # strip leading '--' from cl-args:
1387 help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
1834 help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
1388 return [ attr.split('=')[0]
1835 return [ attr.split('=')[0]
1389 for attr in help.strip().splitlines()
1836 for attr in help.strip().splitlines()
1390 if attr.startswith(texts[1]) ]
1837 if attr.startswith(texts[1]) ]
1391 return []
1838 return []
1392
1839
1393 def magic_color_matches(self, text:str) -> List[str] :
1840 @context_matcher()
1394 """ Match color schemes for %colors magic"""
1841 def magic_color_matcher(self, context: CompletionContext) -> SimpleMatcherResult:
1842 """Match color schemes for %colors magic."""
1843 # NOTE: uses `line_buffer` equivalent for compatibility
1844 matches = self.magic_color_matches(context.line_with_cursor)
1845 return _convert_matcher_v1_result_to_v2(matches, type="param")
1846
1847 def magic_color_matches(self, text: str) -> List[str]:
1848 """Match color schemes for %colors magic.
1849
1850 .. deprecated:: 8.6
1851 You can use :meth:`magic_color_matcher` instead.
1852 """
1395 texts = text.split()
1853 texts = text.split()
1396 if text.endswith(' '):
1854 if text.endswith(' '):
1397 # .split() strips off the trailing whitespace. Add '' back
1855 # .split() strips off the trailing whitespace. Add '' back
1398 # so that: '%colors ' -> ['%colors', '']
1856 # so that: '%colors ' -> ['%colors', '']
1399 texts.append('')
1857 texts.append('')
1400
1858
1401 if len(texts) == 2 and (texts[0] == 'colors' or texts[0] == '%colors'):
1859 if len(texts) == 2 and (texts[0] == 'colors' or texts[0] == '%colors'):
1402 prefix = texts[1]
1860 prefix = texts[1]
1403 return [ color for color in InspectColors.keys()
1861 return [ color for color in InspectColors.keys()
1404 if color.startswith(prefix) ]
1862 if color.startswith(prefix) ]
1405 return []
1863 return []
1406
1864
1407 def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str) -> Iterable[Any]:
1865 @context_matcher(identifier="IPCompleter.jedi_matcher")
1866 def _jedi_matcher(self, context: CompletionContext) -> _JediMatcherResult:
1867 matches = self._jedi_matches(
1868 cursor_column=context.cursor_position,
1869 cursor_line=context.cursor_line,
1870 text=context.full_text,
1871 )
1872 return {
1873 "completions": matches,
1874 # static analysis should not suppress other matchers
1875 "suppress": False,
1876 }
1877
1878 def _jedi_matches(
1879 self, cursor_column: int, cursor_line: int, text: str
1880 ) -> Iterable[_JediCompletionLike]:
1408 """
1881 """
1409 Return a list of :any:`jedi.api.Completions` object from a ``text`` and
1882 Return a list of :any:`jedi.api.Completion`s object from a ``text`` and
1410 cursor position.
1883 cursor position.
1411
1884
1412 Parameters
1885 Parameters
1413 ----------
1886 ----------
1414 cursor_column : int
1887 cursor_column : int
1415 column position of the cursor in ``text``, 0-indexed.
1888 column position of the cursor in ``text``, 0-indexed.
1416 cursor_line : int
1889 cursor_line : int
1417 line position of the cursor in ``text``, 0-indexed
1890 line position of the cursor in ``text``, 0-indexed
1418 text : str
1891 text : str
1419 text to complete
1892 text to complete
1420
1893
1421 Notes
1894 Notes
1422 -----
1895 -----
1423 If ``IPCompleter.debug`` is ``True`` may return a :any:`_FakeJediCompletion`
1896 If ``IPCompleter.debug`` is ``True`` may return a :any:`_FakeJediCompletion`
1424 object containing a string with the Jedi debug information attached.
1897 object containing a string with the Jedi debug information attached.
1898
1899 .. deprecated:: 8.6
1900 You can use :meth:`_jedi_matcher` instead.
1425 """
1901 """
1426 namespaces = [self.namespace]
1902 namespaces = [self.namespace]
1427 if self.global_namespace is not None:
1903 if self.global_namespace is not None:
1428 namespaces.append(self.global_namespace)
1904 namespaces.append(self.global_namespace)
1429
1905
1430 completion_filter = lambda x:x
1906 completion_filter = lambda x:x
1431 offset = cursor_to_position(text, cursor_line, cursor_column)
1907 offset = cursor_to_position(text, cursor_line, cursor_column)
1432 # filter output if we are completing for object members
1908 # filter output if we are completing for object members
1433 if offset:
1909 if offset:
1434 pre = text[offset-1]
1910 pre = text[offset-1]
1435 if pre == '.':
1911 if pre == '.':
1436 if self.omit__names == 2:
1912 if self.omit__names == 2:
1437 completion_filter = lambda c:not c.name.startswith('_')
1913 completion_filter = lambda c:not c.name.startswith('_')
1438 elif self.omit__names == 1:
1914 elif self.omit__names == 1:
1439 completion_filter = lambda c:not (c.name.startswith('__') and c.name.endswith('__'))
1915 completion_filter = lambda c:not (c.name.startswith('__') and c.name.endswith('__'))
1440 elif self.omit__names == 0:
1916 elif self.omit__names == 0:
1441 completion_filter = lambda x:x
1917 completion_filter = lambda x:x
1442 else:
1918 else:
1443 raise ValueError("Don't understand self.omit__names == {}".format(self.omit__names))
1919 raise ValueError("Don't understand self.omit__names == {}".format(self.omit__names))
1444
1920
1445 interpreter = jedi.Interpreter(text[:offset], namespaces)
1921 interpreter = jedi.Interpreter(text[:offset], namespaces)
1446 try_jedi = True
1922 try_jedi = True
1447
1923
1448 try:
1924 try:
1449 # find the first token in the current tree -- if it is a ' or " then we are in a string
1925 # find the first token in the current tree -- if it is a ' or " then we are in a string
1450 completing_string = False
1926 completing_string = False
1451 try:
1927 try:
1452 first_child = next(c for c in interpreter._get_module().tree_node.children if hasattr(c, 'value'))
1928 first_child = next(c for c in interpreter._get_module().tree_node.children if hasattr(c, 'value'))
1453 except StopIteration:
1929 except StopIteration:
1454 pass
1930 pass
1455 else:
1931 else:
1456 # note the value may be ', ", or it may also be ''' or """, or
1932 # note the value may be ', ", or it may also be ''' or """, or
1457 # in some cases, """what/you/typed..., but all of these are
1933 # in some cases, """what/you/typed..., but all of these are
1458 # strings.
1934 # strings.
1459 completing_string = len(first_child.value) > 0 and first_child.value[0] in {"'", '"'}
1935 completing_string = len(first_child.value) > 0 and first_child.value[0] in {"'", '"'}
1460
1936
1461 # if we are in a string jedi is likely not the right candidate for
1937 # if we are in a string jedi is likely not the right candidate for
1462 # now. Skip it.
1938 # now. Skip it.
1463 try_jedi = not completing_string
1939 try_jedi = not completing_string
1464 except Exception as e:
1940 except Exception as e:
1465 # many of things can go wrong, we are using private API just don't crash.
1941 # many of things can go wrong, we are using private API just don't crash.
1466 if self.debug:
1942 if self.debug:
1467 print("Error detecting if completing a non-finished string :", e, '|')
1943 print("Error detecting if completing a non-finished string :", e, '|')
1468
1944
1469 if not try_jedi:
1945 if not try_jedi:
1470 return []
1946 return []
1471 try:
1947 try:
1472 return filter(completion_filter, interpreter.complete(column=cursor_column, line=cursor_line + 1))
1948 return filter(completion_filter, interpreter.complete(column=cursor_column, line=cursor_line + 1))
1473 except Exception as e:
1949 except Exception as e:
1474 if self.debug:
1950 if self.debug:
1475 return [_FakeJediCompletion('Oops Jedi has crashed, please report a bug with the following:\n"""\n%s\ns"""' % (e))]
1951 return [_FakeJediCompletion('Oops Jedi has crashed, please report a bug with the following:\n"""\n%s\ns"""' % (e))]
1476 else:
1952 else:
1477 return []
1953 return []
1478
1954
1479 def python_matches(self, text:str)->List[str]:
1955 def python_matches(self, text:str)->List[str]:
1480 """Match attributes or global python names"""
1956 """Match attributes or global python names"""
1481 if "." in text:
1957 if "." in text:
1482 try:
1958 try:
1483 matches = self.attr_matches(text)
1959 matches = self.attr_matches(text)
1484 if text.endswith('.') and self.omit__names:
1960 if text.endswith('.') and self.omit__names:
1485 if self.omit__names == 1:
1961 if self.omit__names == 1:
1486 # true if txt is _not_ a __ name, false otherwise:
1962 # true if txt is _not_ a __ name, false otherwise:
1487 no__name = (lambda txt:
1963 no__name = (lambda txt:
1488 re.match(r'.*\.__.*?__',txt) is None)
1964 re.match(r'.*\.__.*?__',txt) is None)
1489 else:
1965 else:
1490 # true if txt is _not_ a _ name, false otherwise:
1966 # true if txt is _not_ a _ name, false otherwise:
1491 no__name = (lambda txt:
1967 no__name = (lambda txt:
1492 re.match(r'\._.*?',txt[txt.rindex('.'):]) is None)
1968 re.match(r'\._.*?',txt[txt.rindex('.'):]) is None)
1493 matches = filter(no__name, matches)
1969 matches = filter(no__name, matches)
1494 except NameError:
1970 except NameError:
1495 # catches <undefined attributes>.<tab>
1971 # catches <undefined attributes>.<tab>
1496 matches = []
1972 matches = []
1497 else:
1973 else:
1498 matches = self.global_matches(text)
1974 matches = self.global_matches(text)
1499 return matches
1975 return matches
1500
1976
1501 def _default_arguments_from_docstring(self, doc):
1977 def _default_arguments_from_docstring(self, doc):
1502 """Parse the first line of docstring for call signature.
1978 """Parse the first line of docstring for call signature.
1503
1979
1504 Docstring should be of the form 'min(iterable[, key=func])\n'.
1980 Docstring should be of the form 'min(iterable[, key=func])\n'.
1505 It can also parse cython docstring of the form
1981 It can also parse cython docstring of the form
1506 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'.
1982 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'.
1507 """
1983 """
1508 if doc is None:
1984 if doc is None:
1509 return []
1985 return []
1510
1986
1511 #care only the firstline
1987 #care only the firstline
1512 line = doc.lstrip().splitlines()[0]
1988 line = doc.lstrip().splitlines()[0]
1513
1989
1514 #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1990 #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1515 #'min(iterable[, key=func])\n' -> 'iterable[, key=func]'
1991 #'min(iterable[, key=func])\n' -> 'iterable[, key=func]'
1516 sig = self.docstring_sig_re.search(line)
1992 sig = self.docstring_sig_re.search(line)
1517 if sig is None:
1993 if sig is None:
1518 return []
1994 return []
1519 # iterable[, key=func]' -> ['iterable[' ,' key=func]']
1995 # iterable[, key=func]' -> ['iterable[' ,' key=func]']
1520 sig = sig.groups()[0].split(',')
1996 sig = sig.groups()[0].split(',')
1521 ret = []
1997 ret = []
1522 for s in sig:
1998 for s in sig:
1523 #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1999 #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1524 ret += self.docstring_kwd_re.findall(s)
2000 ret += self.docstring_kwd_re.findall(s)
1525 return ret
2001 return ret
1526
2002
1527 def _default_arguments(self, obj):
2003 def _default_arguments(self, obj):
1528 """Return the list of default arguments of obj if it is callable,
2004 """Return the list of default arguments of obj if it is callable,
1529 or empty list otherwise."""
2005 or empty list otherwise."""
1530 call_obj = obj
2006 call_obj = obj
1531 ret = []
2007 ret = []
1532 if inspect.isbuiltin(obj):
2008 if inspect.isbuiltin(obj):
1533 pass
2009 pass
1534 elif not (inspect.isfunction(obj) or inspect.ismethod(obj)):
2010 elif not (inspect.isfunction(obj) or inspect.ismethod(obj)):
1535 if inspect.isclass(obj):
2011 if inspect.isclass(obj):
1536 #for cython embedsignature=True the constructor docstring
2012 #for cython embedsignature=True the constructor docstring
1537 #belongs to the object itself not __init__
2013 #belongs to the object itself not __init__
1538 ret += self._default_arguments_from_docstring(
2014 ret += self._default_arguments_from_docstring(
1539 getattr(obj, '__doc__', ''))
2015 getattr(obj, '__doc__', ''))
1540 # for classes, check for __init__,__new__
2016 # for classes, check for __init__,__new__
1541 call_obj = (getattr(obj, '__init__', None) or
2017 call_obj = (getattr(obj, '__init__', None) or
1542 getattr(obj, '__new__', None))
2018 getattr(obj, '__new__', None))
1543 # for all others, check if they are __call__able
2019 # for all others, check if they are __call__able
1544 elif hasattr(obj, '__call__'):
2020 elif hasattr(obj, '__call__'):
1545 call_obj = obj.__call__
2021 call_obj = obj.__call__
1546 ret += self._default_arguments_from_docstring(
2022 ret += self._default_arguments_from_docstring(
1547 getattr(call_obj, '__doc__', ''))
2023 getattr(call_obj, '__doc__', ''))
1548
2024
1549 _keeps = (inspect.Parameter.KEYWORD_ONLY,
2025 _keeps = (inspect.Parameter.KEYWORD_ONLY,
1550 inspect.Parameter.POSITIONAL_OR_KEYWORD)
2026 inspect.Parameter.POSITIONAL_OR_KEYWORD)
1551
2027
1552 try:
2028 try:
1553 sig = inspect.signature(obj)
2029 sig = inspect.signature(obj)
1554 ret.extend(k for k, v in sig.parameters.items() if
2030 ret.extend(k for k, v in sig.parameters.items() if
1555 v.kind in _keeps)
2031 v.kind in _keeps)
1556 except ValueError:
2032 except ValueError:
1557 pass
2033 pass
1558
2034
1559 return list(set(ret))
2035 return list(set(ret))
1560
2036
2037 @context_matcher()
2038 def python_func_kw_matcher(self, context: CompletionContext) -> SimpleMatcherResult:
2039 """Match named parameters (kwargs) of the last open function."""
2040 matches = self.python_func_kw_matches(context.token)
2041 return _convert_matcher_v1_result_to_v2(matches, type="param")
2042
1561 def python_func_kw_matches(self, text):
2043 def python_func_kw_matches(self, text):
1562 """Match named parameters (kwargs) of the last open function"""
2044 """Match named parameters (kwargs) of the last open function.
2045
2046 .. deprecated:: 8.6
2047 You can use :meth:`python_func_kw_matcher` instead.
2048 """
1563
2049
1564 if "." in text: # a parameter cannot be dotted
2050 if "." in text: # a parameter cannot be dotted
1565 return []
2051 return []
1566 try: regexp = self.__funcParamsRegex
2052 try: regexp = self.__funcParamsRegex
1567 except AttributeError:
2053 except AttributeError:
1568 regexp = self.__funcParamsRegex = re.compile(r'''
2054 regexp = self.__funcParamsRegex = re.compile(r'''
1569 '.*?(?<!\\)' | # single quoted strings or
2055 '.*?(?<!\\)' | # single quoted strings or
1570 ".*?(?<!\\)" | # double quoted strings or
2056 ".*?(?<!\\)" | # double quoted strings or
1571 \w+ | # identifier
2057 \w+ | # identifier
1572 \S # other characters
2058 \S # other characters
1573 ''', re.VERBOSE | re.DOTALL)
2059 ''', re.VERBOSE | re.DOTALL)
1574 # 1. find the nearest identifier that comes before an unclosed
2060 # 1. find the nearest identifier that comes before an unclosed
1575 # parenthesis before the cursor
2061 # parenthesis before the cursor
1576 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
2062 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
1577 tokens = regexp.findall(self.text_until_cursor)
2063 tokens = regexp.findall(self.text_until_cursor)
1578 iterTokens = reversed(tokens); openPar = 0
2064 iterTokens = reversed(tokens); openPar = 0
1579
2065
1580 for token in iterTokens:
2066 for token in iterTokens:
1581 if token == ')':
2067 if token == ')':
1582 openPar -= 1
2068 openPar -= 1
1583 elif token == '(':
2069 elif token == '(':
1584 openPar += 1
2070 openPar += 1
1585 if openPar > 0:
2071 if openPar > 0:
1586 # found the last unclosed parenthesis
2072 # found the last unclosed parenthesis
1587 break
2073 break
1588 else:
2074 else:
1589 return []
2075 return []
1590 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
2076 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
1591 ids = []
2077 ids = []
1592 isId = re.compile(r'\w+$').match
2078 isId = re.compile(r'\w+$').match
1593
2079
1594 while True:
2080 while True:
1595 try:
2081 try:
1596 ids.append(next(iterTokens))
2082 ids.append(next(iterTokens))
1597 if not isId(ids[-1]):
2083 if not isId(ids[-1]):
1598 ids.pop(); break
2084 ids.pop(); break
1599 if not next(iterTokens) == '.':
2085 if not next(iterTokens) == '.':
1600 break
2086 break
1601 except StopIteration:
2087 except StopIteration:
1602 break
2088 break
1603
2089
1604 # Find all named arguments already assigned to, as to avoid suggesting
2090 # Find all named arguments already assigned to, as to avoid suggesting
1605 # them again
2091 # them again
1606 usedNamedArgs = set()
2092 usedNamedArgs = set()
1607 par_level = -1
2093 par_level = -1
1608 for token, next_token in zip(tokens, tokens[1:]):
2094 for token, next_token in zip(tokens, tokens[1:]):
1609 if token == '(':
2095 if token == '(':
1610 par_level += 1
2096 par_level += 1
1611 elif token == ')':
2097 elif token == ')':
1612 par_level -= 1
2098 par_level -= 1
1613
2099
1614 if par_level != 0:
2100 if par_level != 0:
1615 continue
2101 continue
1616
2102
1617 if next_token != '=':
2103 if next_token != '=':
1618 continue
2104 continue
1619
2105
1620 usedNamedArgs.add(token)
2106 usedNamedArgs.add(token)
1621
2107
1622 argMatches = []
2108 argMatches = []
1623 try:
2109 try:
1624 callableObj = '.'.join(ids[::-1])
2110 callableObj = '.'.join(ids[::-1])
1625 namedArgs = self._default_arguments(eval(callableObj,
2111 namedArgs = self._default_arguments(eval(callableObj,
1626 self.namespace))
2112 self.namespace))
1627
2113
1628 # Remove used named arguments from the list, no need to show twice
2114 # Remove used named arguments from the list, no need to show twice
1629 for namedArg in set(namedArgs) - usedNamedArgs:
2115 for namedArg in set(namedArgs) - usedNamedArgs:
1630 if namedArg.startswith(text):
2116 if namedArg.startswith(text):
1631 argMatches.append("%s=" %namedArg)
2117 argMatches.append("%s=" %namedArg)
1632 except:
2118 except:
1633 pass
2119 pass
1634
2120
1635 return argMatches
2121 return argMatches
1636
2122
1637 @staticmethod
2123 @staticmethod
1638 def _get_keys(obj: Any) -> List[Any]:
2124 def _get_keys(obj: Any) -> List[Any]:
1639 # Objects can define their own completions by defining an
2125 # Objects can define their own completions by defining an
1640 # _ipy_key_completions_() method.
2126 # _ipy_key_completions_() method.
1641 method = get_real_method(obj, '_ipython_key_completions_')
2127 method = get_real_method(obj, '_ipython_key_completions_')
1642 if method is not None:
2128 if method is not None:
1643 return method()
2129 return method()
1644
2130
1645 # Special case some common in-memory dict-like types
2131 # Special case some common in-memory dict-like types
1646 if isinstance(obj, dict) or\
2132 if isinstance(obj, dict) or\
1647 _safe_isinstance(obj, 'pandas', 'DataFrame'):
2133 _safe_isinstance(obj, 'pandas', 'DataFrame'):
1648 try:
2134 try:
1649 return list(obj.keys())
2135 return list(obj.keys())
1650 except Exception:
2136 except Exception:
1651 return []
2137 return []
1652 elif _safe_isinstance(obj, 'numpy', 'ndarray') or\
2138 elif _safe_isinstance(obj, 'numpy', 'ndarray') or\
1653 _safe_isinstance(obj, 'numpy', 'void'):
2139 _safe_isinstance(obj, 'numpy', 'void'):
1654 return obj.dtype.names or []
2140 return obj.dtype.names or []
1655 return []
2141 return []
1656
2142
1657 def dict_key_matches(self, text:str) -> List[str]:
2143 @context_matcher()
1658 "Match string keys in a dictionary, after e.g. 'foo[' "
2144 def dict_key_matcher(self, context: CompletionContext) -> SimpleMatcherResult:
2145 """Match string keys in a dictionary, after e.g. ``foo[``."""
2146 matches = self.dict_key_matches(context.token)
2147 return _convert_matcher_v1_result_to_v2(
2148 matches, type="dict key", suppress_if_matches=True
2149 )
2150
2151 def dict_key_matches(self, text: str) -> List[str]:
2152 """Match string keys in a dictionary, after e.g. ``foo[``.
1659
2153
2154 .. deprecated:: 8.6
2155 You can use :meth:`dict_key_matcher` instead.
2156 """
1660
2157
1661 if self.__dict_key_regexps is not None:
2158 if self.__dict_key_regexps is not None:
1662 regexps = self.__dict_key_regexps
2159 regexps = self.__dict_key_regexps
1663 else:
2160 else:
1664 dict_key_re_fmt = r'''(?x)
2161 dict_key_re_fmt = r'''(?x)
1665 ( # match dict-referring expression wrt greedy setting
2162 ( # match dict-referring expression wrt greedy setting
1666 %s
2163 %s
1667 )
2164 )
1668 \[ # open bracket
2165 \[ # open bracket
1669 \s* # and optional whitespace
2166 \s* # and optional whitespace
1670 # Capture any number of str-like objects (e.g. "a", "b", 'c')
2167 # Capture any number of str-like objects (e.g. "a", "b", 'c')
1671 ((?:[uUbB]? # string prefix (r not handled)
2168 ((?:[uUbB]? # string prefix (r not handled)
1672 (?:
2169 (?:
1673 '(?:[^']|(?<!\\)\\')*'
2170 '(?:[^']|(?<!\\)\\')*'
1674 |
2171 |
1675 "(?:[^"]|(?<!\\)\\")*"
2172 "(?:[^"]|(?<!\\)\\")*"
1676 )
2173 )
1677 \s*,\s*
2174 \s*,\s*
1678 )*)
2175 )*)
1679 ([uUbB]? # string prefix (r not handled)
2176 ([uUbB]? # string prefix (r not handled)
1680 (?: # unclosed string
2177 (?: # unclosed string
1681 '(?:[^']|(?<!\\)\\')*
2178 '(?:[^']|(?<!\\)\\')*
1682 |
2179 |
1683 "(?:[^"]|(?<!\\)\\")*
2180 "(?:[^"]|(?<!\\)\\")*
1684 )
2181 )
1685 )?
2182 )?
1686 $
2183 $
1687 '''
2184 '''
1688 regexps = self.__dict_key_regexps = {
2185 regexps = self.__dict_key_regexps = {
1689 False: re.compile(dict_key_re_fmt % r'''
2186 False: re.compile(dict_key_re_fmt % r'''
1690 # identifiers separated by .
2187 # identifiers separated by .
1691 (?!\d)\w+
2188 (?!\d)\w+
1692 (?:\.(?!\d)\w+)*
2189 (?:\.(?!\d)\w+)*
1693 '''),
2190 '''),
1694 True: re.compile(dict_key_re_fmt % '''
2191 True: re.compile(dict_key_re_fmt % '''
1695 .+
2192 .+
1696 ''')
2193 ''')
1697 }
2194 }
1698
2195
1699 match = regexps[self.greedy].search(self.text_until_cursor)
2196 match = regexps[self.greedy].search(self.text_until_cursor)
1700
2197
1701 if match is None:
2198 if match is None:
1702 return []
2199 return []
1703
2200
1704 expr, prefix0, prefix = match.groups()
2201 expr, prefix0, prefix = match.groups()
1705 try:
2202 try:
1706 obj = eval(expr, self.namespace)
2203 obj = eval(expr, self.namespace)
1707 except Exception:
2204 except Exception:
1708 try:
2205 try:
1709 obj = eval(expr, self.global_namespace)
2206 obj = eval(expr, self.global_namespace)
1710 except Exception:
2207 except Exception:
1711 return []
2208 return []
1712
2209
1713 keys = self._get_keys(obj)
2210 keys = self._get_keys(obj)
1714 if not keys:
2211 if not keys:
1715 return keys
2212 return keys
1716
2213
1717 extra_prefix = eval(prefix0) if prefix0 != '' else None
2214 extra_prefix = eval(prefix0) if prefix0 != '' else None
1718
2215
1719 closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims, extra_prefix=extra_prefix)
2216 closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims, extra_prefix=extra_prefix)
1720 if not matches:
2217 if not matches:
1721 return matches
2218 return matches
1722
2219
1723 # get the cursor position of
2220 # get the cursor position of
1724 # - the text being completed
2221 # - the text being completed
1725 # - the start of the key text
2222 # - the start of the key text
1726 # - the start of the completion
2223 # - the start of the completion
1727 text_start = len(self.text_until_cursor) - len(text)
2224 text_start = len(self.text_until_cursor) - len(text)
1728 if prefix:
2225 if prefix:
1729 key_start = match.start(3)
2226 key_start = match.start(3)
1730 completion_start = key_start + token_offset
2227 completion_start = key_start + token_offset
1731 else:
2228 else:
1732 key_start = completion_start = match.end()
2229 key_start = completion_start = match.end()
1733
2230
1734 # grab the leading prefix, to make sure all completions start with `text`
2231 # grab the leading prefix, to make sure all completions start with `text`
1735 if text_start > key_start:
2232 if text_start > key_start:
1736 leading = ''
2233 leading = ''
1737 else:
2234 else:
1738 leading = text[text_start:completion_start]
2235 leading = text[text_start:completion_start]
1739
2236
1740 # the index of the `[` character
2237 # the index of the `[` character
1741 bracket_idx = match.end(1)
2238 bracket_idx = match.end(1)
1742
2239
1743 # append closing quote and bracket as appropriate
2240 # append closing quote and bracket as appropriate
1744 # this is *not* appropriate if the opening quote or bracket is outside
2241 # this is *not* appropriate if the opening quote or bracket is outside
1745 # the text given to this method
2242 # the text given to this method
1746 suf = ''
2243 suf = ''
1747 continuation = self.line_buffer[len(self.text_until_cursor):]
2244 continuation = self.line_buffer[len(self.text_until_cursor):]
1748 if key_start > text_start and closing_quote:
2245 if key_start > text_start and closing_quote:
1749 # quotes were opened inside text, maybe close them
2246 # quotes were opened inside text, maybe close them
1750 if continuation.startswith(closing_quote):
2247 if continuation.startswith(closing_quote):
1751 continuation = continuation[len(closing_quote):]
2248 continuation = continuation[len(closing_quote):]
1752 else:
2249 else:
1753 suf += closing_quote
2250 suf += closing_quote
1754 if bracket_idx > text_start:
2251 if bracket_idx > text_start:
1755 # brackets were opened inside text, maybe close them
2252 # brackets were opened inside text, maybe close them
1756 if not continuation.startswith(']'):
2253 if not continuation.startswith(']'):
1757 suf += ']'
2254 suf += ']'
1758
2255
1759 return [leading + k + suf for k in matches]
2256 return [leading + k + suf for k in matches]
1760
2257
2258 @context_matcher()
2259 def unicode_name_matcher(self, context: CompletionContext):
2260 """Same as :any:`unicode_name_matches`, but adopted to new Matcher API."""
2261 fragment, matches = self.unicode_name_matches(context.text_until_cursor)
2262 return _convert_matcher_v1_result_to_v2(
2263 matches, type="unicode", fragment=fragment, suppress_if_matches=True
2264 )
2265
1761 @staticmethod
2266 @staticmethod
1762 def unicode_name_matches(text:str) -> Tuple[str, List[str]] :
2267 def unicode_name_matches(text: str) -> Tuple[str, List[str]]:
1763 """Match Latex-like syntax for unicode characters base
2268 """Match Latex-like syntax for unicode characters base
1764 on the name of the character.
2269 on the name of the character.
1765
2270
1766 This does ``\\GREEK SMALL LETTER ETA`` -> ``η``
2271 This does ``\\GREEK SMALL LETTER ETA`` -> ``η``
1767
2272
1768 Works only on valid python 3 identifier, or on combining characters that
2273 Works only on valid python 3 identifier, or on combining characters that
1769 will combine to form a valid identifier.
2274 will combine to form a valid identifier.
1770 """
2275 """
1771 slashpos = text.rfind('\\')
2276 slashpos = text.rfind('\\')
1772 if slashpos > -1:
2277 if slashpos > -1:
1773 s = text[slashpos+1:]
2278 s = text[slashpos+1:]
1774 try :
2279 try :
1775 unic = unicodedata.lookup(s)
2280 unic = unicodedata.lookup(s)
1776 # allow combining chars
2281 # allow combining chars
1777 if ('a'+unic).isidentifier():
2282 if ('a'+unic).isidentifier():
1778 return '\\'+s,[unic]
2283 return '\\'+s,[unic]
1779 except KeyError:
2284 except KeyError:
1780 pass
2285 pass
1781 return '', []
2286 return '', []
1782
2287
2288 @context_matcher()
2289 def latex_name_matcher(self, context: CompletionContext):
2290 """Match Latex syntax for unicode characters.
1783
2291
1784 def latex_matches(self, text:str) -> Tuple[str, Sequence[str]]:
2292 This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``α``
2293 """
2294 fragment, matches = self.latex_matches(context.text_until_cursor)
2295 return _convert_matcher_v1_result_to_v2(
2296 matches, type="latex", fragment=fragment, suppress_if_matches=True
2297 )
2298
2299 def latex_matches(self, text: str) -> Tuple[str, Sequence[str]]:
1785 """Match Latex syntax for unicode characters.
2300 """Match Latex syntax for unicode characters.
1786
2301
1787 This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``α``
2302 This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``α``
2303
2304 .. deprecated:: 8.6
2305 You can use :meth:`latex_name_matcher` instead.
1788 """
2306 """
1789 slashpos = text.rfind('\\')
2307 slashpos = text.rfind('\\')
1790 if slashpos > -1:
2308 if slashpos > -1:
1791 s = text[slashpos:]
2309 s = text[slashpos:]
1792 if s in latex_symbols:
2310 if s in latex_symbols:
1793 # Try to complete a full latex symbol to unicode
2311 # Try to complete a full latex symbol to unicode
1794 # \\alpha -> α
2312 # \\alpha -> α
1795 return s, [latex_symbols[s]]
2313 return s, [latex_symbols[s]]
1796 else:
2314 else:
1797 # If a user has partially typed a latex symbol, give them
2315 # If a user has partially typed a latex symbol, give them
1798 # a full list of options \al -> [\aleph, \alpha]
2316 # a full list of options \al -> [\aleph, \alpha]
1799 matches = [k for k in latex_symbols if k.startswith(s)]
2317 matches = [k for k in latex_symbols if k.startswith(s)]
1800 if matches:
2318 if matches:
1801 return s, matches
2319 return s, matches
1802 return '', ()
2320 return '', ()
1803
2321
2322 @context_matcher()
2323 def custom_completer_matcher(self, context):
2324 """Dispatch custom completer.
2325
2326 If a match is found, suppresses all other matchers except for Jedi.
2327 """
2328 matches = self.dispatch_custom_completer(context.token) or []
2329 result = _convert_matcher_v1_result_to_v2(
2330 matches, type=_UNKNOWN_TYPE, suppress_if_matches=True
2331 )
2332 result["ordered"] = True
2333 result["do_not_suppress"] = {_get_matcher_id(self._jedi_matcher)}
2334 return result
2335
1804 def dispatch_custom_completer(self, text):
2336 def dispatch_custom_completer(self, text):
2337 """
2338 .. deprecated:: 8.6
2339 You can use :meth:`custom_completer_matcher` instead.
2340 """
1805 if not self.custom_completers:
2341 if not self.custom_completers:
1806 return
2342 return
1807
2343
1808 line = self.line_buffer
2344 line = self.line_buffer
1809 if not line.strip():
2345 if not line.strip():
1810 return None
2346 return None
1811
2347
1812 # Create a little structure to pass all the relevant information about
2348 # Create a little structure to pass all the relevant information about
1813 # the current completion to any custom completer.
2349 # the current completion to any custom completer.
1814 event = SimpleNamespace()
2350 event = SimpleNamespace()
1815 event.line = line
2351 event.line = line
1816 event.symbol = text
2352 event.symbol = text
1817 cmd = line.split(None,1)[0]
2353 cmd = line.split(None,1)[0]
1818 event.command = cmd
2354 event.command = cmd
1819 event.text_until_cursor = self.text_until_cursor
2355 event.text_until_cursor = self.text_until_cursor
1820
2356
1821 # for foo etc, try also to find completer for %foo
2357 # for foo etc, try also to find completer for %foo
1822 if not cmd.startswith(self.magic_escape):
2358 if not cmd.startswith(self.magic_escape):
1823 try_magic = self.custom_completers.s_matches(
2359 try_magic = self.custom_completers.s_matches(
1824 self.magic_escape + cmd)
2360 self.magic_escape + cmd)
1825 else:
2361 else:
1826 try_magic = []
2362 try_magic = []
1827
2363
1828 for c in itertools.chain(self.custom_completers.s_matches(cmd),
2364 for c in itertools.chain(self.custom_completers.s_matches(cmd),
1829 try_magic,
2365 try_magic,
1830 self.custom_completers.flat_matches(self.text_until_cursor)):
2366 self.custom_completers.flat_matches(self.text_until_cursor)):
1831 try:
2367 try:
1832 res = c(event)
2368 res = c(event)
1833 if res:
2369 if res:
1834 # first, try case sensitive match
2370 # first, try case sensitive match
1835 withcase = [r for r in res if r.startswith(text)]
2371 withcase = [r for r in res if r.startswith(text)]
1836 if withcase:
2372 if withcase:
1837 return withcase
2373 return withcase
1838 # if none, then case insensitive ones are ok too
2374 # if none, then case insensitive ones are ok too
1839 text_low = text.lower()
2375 text_low = text.lower()
1840 return [r for r in res if r.lower().startswith(text_low)]
2376 return [r for r in res if r.lower().startswith(text_low)]
1841 except TryNext:
2377 except TryNext:
1842 pass
2378 pass
1843 except KeyboardInterrupt:
2379 except KeyboardInterrupt:
1844 """
2380 """
1845 If custom completer take too long,
2381 If custom completer take too long,
1846 let keyboard interrupt abort and return nothing.
2382 let keyboard interrupt abort and return nothing.
1847 """
2383 """
1848 break
2384 break
1849
2385
1850 return None
2386 return None
1851
2387
1852 def completions(self, text: str, offset: int)->Iterator[Completion]:
2388 def completions(self, text: str, offset: int)->Iterator[Completion]:
1853 """
2389 """
1854 Returns an iterator over the possible completions
2390 Returns an iterator over the possible completions
1855
2391
1856 .. warning::
2392 .. warning::
1857
2393
1858 Unstable
2394 Unstable
1859
2395
1860 This function is unstable, API may change without warning.
2396 This function is unstable, API may change without warning.
1861 It will also raise unless use in proper context manager.
2397 It will also raise unless use in proper context manager.
1862
2398
1863 Parameters
2399 Parameters
1864 ----------
2400 ----------
1865 text : str
2401 text : str
1866 Full text of the current input, multi line string.
2402 Full text of the current input, multi line string.
1867 offset : int
2403 offset : int
1868 Integer representing the position of the cursor in ``text``. Offset
2404 Integer representing the position of the cursor in ``text``. Offset
1869 is 0-based indexed.
2405 is 0-based indexed.
1870
2406
1871 Yields
2407 Yields
1872 ------
2408 ------
1873 Completion
2409 Completion
1874
2410
1875 Notes
2411 Notes
1876 -----
2412 -----
1877 The cursor on a text can either be seen as being "in between"
2413 The cursor on a text can either be seen as being "in between"
1878 characters or "On" a character depending on the interface visible to
2414 characters or "On" a character depending on the interface visible to
1879 the user. For consistency the cursor being on "in between" characters X
2415 the user. For consistency the cursor being on "in between" characters X
1880 and Y is equivalent to the cursor being "on" character Y, that is to say
2416 and Y is equivalent to the cursor being "on" character Y, that is to say
1881 the character the cursor is on is considered as being after the cursor.
2417 the character the cursor is on is considered as being after the cursor.
1882
2418
1883 Combining characters may span more that one position in the
2419 Combining characters may span more that one position in the
1884 text.
2420 text.
1885
2421
1886 .. note::
2422 .. note::
1887
2423
1888 If ``IPCompleter.debug`` is :any:`True` will yield a ``--jedi/ipython--``
2424 If ``IPCompleter.debug`` is :any:`True` will yield a ``--jedi/ipython--``
1889 fake Completion token to distinguish completion returned by Jedi
2425 fake Completion token to distinguish completion returned by Jedi
1890 and usual IPython completion.
2426 and usual IPython completion.
1891
2427
1892 .. note::
2428 .. note::
1893
2429
1894 Completions are not completely deduplicated yet. If identical
2430 Completions are not completely deduplicated yet. If identical
1895 completions are coming from different sources this function does not
2431 completions are coming from different sources this function does not
1896 ensure that each completion object will only be present once.
2432 ensure that each completion object will only be present once.
1897 """
2433 """
1898 warnings.warn("_complete is a provisional API (as of IPython 6.0). "
2434 warnings.warn("_complete is a provisional API (as of IPython 6.0). "
1899 "It may change without warnings. "
2435 "It may change without warnings. "
1900 "Use in corresponding context manager.",
2436 "Use in corresponding context manager.",
1901 category=ProvisionalCompleterWarning, stacklevel=2)
2437 category=ProvisionalCompleterWarning, stacklevel=2)
1902
2438
1903 seen = set()
2439 seen = set()
1904 profiler:Optional[cProfile.Profile]
2440 profiler:Optional[cProfile.Profile]
1905 try:
2441 try:
1906 if self.profile_completions:
2442 if self.profile_completions:
1907 import cProfile
2443 import cProfile
1908 profiler = cProfile.Profile()
2444 profiler = cProfile.Profile()
1909 profiler.enable()
2445 profiler.enable()
1910 else:
2446 else:
1911 profiler = None
2447 profiler = None
1912
2448
1913 for c in self._completions(text, offset, _timeout=self.jedi_compute_type_timeout/1000):
2449 for c in self._completions(text, offset, _timeout=self.jedi_compute_type_timeout/1000):
1914 if c and (c in seen):
2450 if c and (c in seen):
1915 continue
2451 continue
1916 yield c
2452 yield c
1917 seen.add(c)
2453 seen.add(c)
1918 except KeyboardInterrupt:
2454 except KeyboardInterrupt:
1919 """if completions take too long and users send keyboard interrupt,
2455 """if completions take too long and users send keyboard interrupt,
1920 do not crash and return ASAP. """
2456 do not crash and return ASAP. """
1921 pass
2457 pass
1922 finally:
2458 finally:
1923 if profiler is not None:
2459 if profiler is not None:
1924 profiler.disable()
2460 profiler.disable()
1925 ensure_dir_exists(self.profiler_output_dir)
2461 ensure_dir_exists(self.profiler_output_dir)
1926 output_path = os.path.join(self.profiler_output_dir, str(uuid.uuid4()))
2462 output_path = os.path.join(self.profiler_output_dir, str(uuid.uuid4()))
1927 print("Writing profiler output to", output_path)
2463 print("Writing profiler output to", output_path)
1928 profiler.dump_stats(output_path)
2464 profiler.dump_stats(output_path)
1929
2465
1930 def _completions(self, full_text: str, offset: int, *, _timeout) -> Iterator[Completion]:
2466 def _completions(self, full_text: str, offset: int, *, _timeout) -> Iterator[Completion]:
1931 """
2467 """
1932 Core completion module.Same signature as :any:`completions`, with the
2468 Core completion module.Same signature as :any:`completions`, with the
1933 extra `timeout` parameter (in seconds).
2469 extra `timeout` parameter (in seconds).
1934
2470
1935 Computing jedi's completion ``.type`` can be quite expensive (it is a
2471 Computing jedi's completion ``.type`` can be quite expensive (it is a
1936 lazy property) and can require some warm-up, more warm up than just
2472 lazy property) and can require some warm-up, more warm up than just
1937 computing the ``name`` of a completion. The warm-up can be :
2473 computing the ``name`` of a completion. The warm-up can be :
1938
2474
1939 - Long warm-up the first time a module is encountered after
2475 - Long warm-up the first time a module is encountered after
1940 install/update: actually build parse/inference tree.
2476 install/update: actually build parse/inference tree.
1941
2477
1942 - first time the module is encountered in a session: load tree from
2478 - first time the module is encountered in a session: load tree from
1943 disk.
2479 disk.
1944
2480
1945 We don't want to block completions for tens of seconds so we give the
2481 We don't want to block completions for tens of seconds so we give the
1946 completer a "budget" of ``_timeout`` seconds per invocation to compute
2482 completer a "budget" of ``_timeout`` seconds per invocation to compute
1947 completions types, the completions that have not yet been computed will
2483 completions types, the completions that have not yet been computed will
1948 be marked as "unknown" an will have a chance to be computed next round
2484 be marked as "unknown" an will have a chance to be computed next round
1949 are things get cached.
2485 are things get cached.
1950
2486
1951 Keep in mind that Jedi is not the only thing treating the completion so
2487 Keep in mind that Jedi is not the only thing treating the completion so
1952 keep the timeout short-ish as if we take more than 0.3 second we still
2488 keep the timeout short-ish as if we take more than 0.3 second we still
1953 have lots of processing to do.
2489 have lots of processing to do.
1954
2490
1955 """
2491 """
1956 deadline = time.monotonic() + _timeout
2492 deadline = time.monotonic() + _timeout
1957
2493
1958
1959 before = full_text[:offset]
2494 before = full_text[:offset]
1960 cursor_line, cursor_column = position_to_cursor(full_text, offset)
2495 cursor_line, cursor_column = position_to_cursor(full_text, offset)
1961
2496
1962 matched_text, matches, matches_origin, jedi_matches = self._complete(
2497 jedi_matcher_id = _get_matcher_id(self._jedi_matcher)
1963 full_text=full_text, cursor_line=cursor_line, cursor_pos=cursor_column)
2498
2499 results = self._complete(
2500 full_text=full_text, cursor_line=cursor_line, cursor_pos=cursor_column
2501 )
2502 non_jedi_results: Dict[str, SimpleMatcherResult] = {
2503 identifier: result
2504 for identifier, result in results.items()
2505 if identifier != jedi_matcher_id
2506 }
2507
2508 jedi_matches = (
2509 cast(results[jedi_matcher_id], _JediMatcherResult)["completions"]
2510 if jedi_matcher_id in results
2511 else ()
2512 )
1964
2513
1965 iter_jm = iter(jedi_matches)
2514 iter_jm = iter(jedi_matches)
1966 if _timeout:
2515 if _timeout:
1967 for jm in iter_jm:
2516 for jm in iter_jm:
1968 try:
2517 try:
1969 type_ = jm.type
2518 type_ = jm.type
1970 except Exception:
2519 except Exception:
1971 if self.debug:
2520 if self.debug:
1972 print("Error in Jedi getting type of ", jm)
2521 print("Error in Jedi getting type of ", jm)
1973 type_ = None
2522 type_ = None
1974 delta = len(jm.name_with_symbols) - len(jm.complete)
2523 delta = len(jm.name_with_symbols) - len(jm.complete)
1975 if type_ == 'function':
2524 if type_ == 'function':
1976 signature = _make_signature(jm)
2525 signature = _make_signature(jm)
1977 else:
2526 else:
1978 signature = ''
2527 signature = ''
1979 yield Completion(start=offset - delta,
2528 yield Completion(start=offset - delta,
1980 end=offset,
2529 end=offset,
1981 text=jm.name_with_symbols,
2530 text=jm.name_with_symbols,
1982 type=type_,
2531 type=type_,
1983 signature=signature,
2532 signature=signature,
1984 _origin='jedi')
2533 _origin='jedi')
1985
2534
1986 if time.monotonic() > deadline:
2535 if time.monotonic() > deadline:
1987 break
2536 break
1988
2537
1989 for jm in iter_jm:
2538 for jm in iter_jm:
1990 delta = len(jm.name_with_symbols) - len(jm.complete)
2539 delta = len(jm.name_with_symbols) - len(jm.complete)
1991 yield Completion(start=offset - delta,
2540 yield Completion(
1992 end=offset,
2541 start=offset - delta,
1993 text=jm.name_with_symbols,
2542 end=offset,
1994 type='<unknown>', # don't compute type for speed
2543 text=jm.name_with_symbols,
1995 _origin='jedi',
2544 type=_UNKNOWN_TYPE, # don't compute type for speed
1996 signature='')
2545 _origin="jedi",
1997
2546 signature="",
1998
2547 )
1999 start_offset = before.rfind(matched_text)
2000
2548
2001 # TODO:
2549 # TODO:
2002 # Suppress this, right now just for debug.
2550 # Suppress this, right now just for debug.
2003 if jedi_matches and matches and self.debug:
2551 if jedi_matches and non_jedi_results and self.debug:
2004 yield Completion(start=start_offset, end=offset, text='--jedi/ipython--',
2552 some_start_offset = before.rfind(
2005 _origin='debug', type='none', signature='')
2553 next(iter(non_jedi_results.values()))["matched_fragment"]
2554 )
2555 yield Completion(
2556 start=some_start_offset,
2557 end=offset,
2558 text="--jedi/ipython--",
2559 _origin="debug",
2560 type="none",
2561 signature="",
2562 )
2006
2563
2007 # I'm unsure if this is always true, so let's assert and see if it
2564 ordered = []
2008 # crash
2565 sortable = []
2009 assert before.endswith(matched_text)
2566
2010 for m, t in zip(matches, matches_origin):
2567 for origin, result in non_jedi_results.items():
2011 yield Completion(start=start_offset, end=offset, text=m, _origin=t, signature='', type='<unknown>')
2568 matched_text = result["matched_fragment"]
2569 start_offset = before.rfind(matched_text)
2570 is_ordered = result.get("ordered", False)
2571 container = ordered if is_ordered else sortable
2572
2573 # I'm unsure if this is always true, so let's assert and see if it
2574 # crash
2575 assert before.endswith(matched_text)
2576
2577 for simple_completion in result["completions"]:
2578 completion = Completion(
2579 start=start_offset,
2580 end=offset,
2581 text=simple_completion.text,
2582 _origin=origin,
2583 signature="",
2584 type=simple_completion.type or _UNKNOWN_TYPE,
2585 )
2586 container.append(completion)
2012
2587
2588 yield from list(self._deduplicate(ordered + self._sort(sortable)))[
2589 :MATCHES_LIMIT
2590 ]
2013
2591
2014 def complete(self, text=None, line_buffer=None, cursor_pos=None) -> Tuple[str, Sequence[str]]:
2592 def complete(self, text=None, line_buffer=None, cursor_pos=None) -> Tuple[str, Sequence[str]]:
2015 """Find completions for the given text and line context.
2593 """Find completions for the given text and line context.
2016
2594
2017 Note that both the text and the line_buffer are optional, but at least
2595 Note that both the text and the line_buffer are optional, but at least
2018 one of them must be given.
2596 one of them must be given.
2019
2597
2020 Parameters
2598 Parameters
2021 ----------
2599 ----------
2022 text : string, optional
2600 text : string, optional
2023 Text to perform the completion on. If not given, the line buffer
2601 Text to perform the completion on. If not given, the line buffer
2024 is split using the instance's CompletionSplitter object.
2602 is split using the instance's CompletionSplitter object.
2025 line_buffer : string, optional
2603 line_buffer : string, optional
2026 If not given, the completer attempts to obtain the current line
2604 If not given, the completer attempts to obtain the current line
2027 buffer via readline. This keyword allows clients which are
2605 buffer via readline. This keyword allows clients which are
2028 requesting for text completions in non-readline contexts to inform
2606 requesting for text completions in non-readline contexts to inform
2029 the completer of the entire text.
2607 the completer of the entire text.
2030 cursor_pos : int, optional
2608 cursor_pos : int, optional
2031 Index of the cursor in the full line buffer. Should be provided by
2609 Index of the cursor in the full line buffer. Should be provided by
2032 remote frontends where kernel has no access to frontend state.
2610 remote frontends where kernel has no access to frontend state.
2033
2611
2034 Returns
2612 Returns
2035 -------
2613 -------
2036 Tuple of two items:
2614 Tuple of two items:
2037 text : str
2615 text : str
2038 Text that was actually used in the completion.
2616 Text that was actually used in the completion.
2039 matches : list
2617 matches : list
2040 A list of completion matches.
2618 A list of completion matches.
2041
2619
2042 Notes
2620 Notes
2043 -----
2621 -----
2044 This API is likely to be deprecated and replaced by
2622 This API is likely to be deprecated and replaced by
2045 :any:`IPCompleter.completions` in the future.
2623 :any:`IPCompleter.completions` in the future.
2046
2624
2047 """
2625 """
2048 warnings.warn('`Completer.complete` is pending deprecation since '
2626 warnings.warn('`Completer.complete` is pending deprecation since '
2049 'IPython 6.0 and will be replaced by `Completer.completions`.',
2627 'IPython 6.0 and will be replaced by `Completer.completions`.',
2050 PendingDeprecationWarning)
2628 PendingDeprecationWarning)
2051 # potential todo, FOLD the 3rd throw away argument of _complete
2629 # potential todo, FOLD the 3rd throw away argument of _complete
2052 # into the first 2 one.
2630 # into the first 2 one.
2053 return self._complete(line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0)[:2]
2631 # TODO: Q: does the above refer to jedi completions (i.e. 0-indexed?)
2632 # TODO: should we deprecate now, or does it stay?
2633
2634 results = self._complete(
2635 line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0
2636 )
2637
2638 jedi_matcher_id = _get_matcher_id(self._jedi_matcher)
2639
2640 return self._arrange_and_extract(
2641 results,
2642 # TODO: can we confirm that excluding Jedi here was a deliberate choice in previous version?
2643 skip_matchers={jedi_matcher_id},
2644 # this API does not support different start/end positions (fragments of token).
2645 abort_if_offset_changes=True,
2646 )
2647
2648 def _arrange_and_extract(
2649 self,
2650 results: Dict[str, MatcherResult],
2651 skip_matchers: Set[str],
2652 abort_if_offset_changes: bool,
2653 ):
2654
2655 sortable = []
2656 ordered = []
2657 most_recent_fragment = None
2658 for identifier, result in results.items():
2659 if identifier in skip_matchers:
2660 continue
2661 if not result["completions"]:
2662 continue
2663 if not most_recent_fragment:
2664 most_recent_fragment = result["matched_fragment"]
2665 if (
2666 abort_if_offset_changes
2667 and result["matched_fragment"] != most_recent_fragment
2668 ):
2669 break
2670 if result.get("ordered", False):
2671 ordered.extend(result["completions"])
2672 else:
2673 sortable.extend(result["completions"])
2674
2675 if not most_recent_fragment:
2676 most_recent_fragment = "" # to satisfy typechecker (and just in case)
2677
2678 return most_recent_fragment, [
2679 m.text for m in self._deduplicate(ordered + self._sort(sortable))
2680 ]
2054
2681
2055 def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None,
2682 def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None,
2056 full_text=None) -> _CompleteResult:
2683 full_text=None) -> _CompleteResult:
2057 """
2684 """
2058 Like complete but can also returns raw jedi completions as well as the
2685 Like complete but can also returns raw jedi completions as well as the
2059 origin of the completion text. This could (and should) be made much
2686 origin of the completion text. This could (and should) be made much
2060 cleaner but that will be simpler once we drop the old (and stateful)
2687 cleaner but that will be simpler once we drop the old (and stateful)
2061 :any:`complete` API.
2688 :any:`complete` API.
2062
2689
2063 With current provisional API, cursor_pos act both (depending on the
2690 With current provisional API, cursor_pos act both (depending on the
2064 caller) as the offset in the ``text`` or ``line_buffer``, or as the
2691 caller) as the offset in the ``text`` or ``line_buffer``, or as the
2065 ``column`` when passing multiline strings this could/should be renamed
2692 ``column`` when passing multiline strings this could/should be renamed
2066 but would add extra noise.
2693 but would add extra noise.
2067
2694
2068 Parameters
2695 Parameters
2069 ----------
2696 ----------
2070 cursor_line
2697 cursor_line
2071 Index of the line the cursor is on. 0 indexed.
2698 Index of the line the cursor is on. 0 indexed.
2072 cursor_pos
2699 cursor_pos
2073 Position of the cursor in the current line/line_buffer/text. 0
2700 Position of the cursor in the current line/line_buffer/text. 0
2074 indexed.
2701 indexed.
2075 line_buffer : optional, str
2702 line_buffer : optional, str
2076 The current line the cursor is in, this is mostly due to legacy
2703 The current line the cursor is in, this is mostly due to legacy
2077 reason that readline could only give a us the single current line.
2704 reason that readline could only give a us the single current line.
2078 Prefer `full_text`.
2705 Prefer `full_text`.
2079 text : str
2706 text : str
2080 The current "token" the cursor is in, mostly also for historical
2707 The current "token" the cursor is in, mostly also for historical
2081 reasons. as the completer would trigger only after the current line
2708 reasons. as the completer would trigger only after the current line
2082 was parsed.
2709 was parsed.
2083 full_text : str
2710 full_text : str
2084 Full text of the current cell.
2711 Full text of the current cell.
2085
2712
2086 Returns
2713 Returns
2087 -------
2714 -------
2088 A tuple of N elements which are (likely):
2715 An ordered dictionary where keys are identifiers of completion
2089 matched_text: ? the text that the complete matched
2716 matchers and values are ``MatcherResult``s.
2090 matches: list of completions ?
2091 matches_origin: ? list same length as matches, and where each completion came from
2092 jedi_matches: list of Jedi matches, have it's own structure.
2093 """
2717 """
2094
2718
2095
2096 # if the cursor position isn't given, the only sane assumption we can
2719 # if the cursor position isn't given, the only sane assumption we can
2097 # make is that it's at the end of the line (the common case)
2720 # make is that it's at the end of the line (the common case)
2098 if cursor_pos is None:
2721 if cursor_pos is None:
2099 cursor_pos = len(line_buffer) if text is None else len(text)
2722 cursor_pos = len(line_buffer) if text is None else len(text)
2100
2723
2101 if self.use_main_ns:
2724 if self.use_main_ns:
2102 self.namespace = __main__.__dict__
2725 self.namespace = __main__.__dict__
2103
2726
2104 # if text is either None or an empty string, rely on the line buffer
2727 # if text is either None or an empty string, rely on the line buffer
2105 if (not line_buffer) and full_text:
2728 if (not line_buffer) and full_text:
2106 line_buffer = full_text.split('\n')[cursor_line]
2729 line_buffer = full_text.split('\n')[cursor_line]
2107 if not text: # issue #11508: check line_buffer before calling split_line
2730 if not text: # issue #11508: check line_buffer before calling split_line
2108 text = self.splitter.split_line(line_buffer, cursor_pos) if line_buffer else ''
2731 text = (
2109
2732 self.splitter.split_line(line_buffer, cursor_pos) if line_buffer else ""
2110 if self.backslash_combining_completions:
2733 )
2111 # allow deactivation of these on windows.
2112 base_text = text if not line_buffer else line_buffer[:cursor_pos]
2113
2114 for meth in (self.latex_matches,
2115 self.unicode_name_matches,
2116 back_latex_name_matches,
2117 back_unicode_name_matches,
2118 self.fwd_unicode_match):
2119 name_text, name_matches = meth(base_text)
2120 if name_text:
2121 return _CompleteResult(name_text, name_matches[:MATCHES_LIMIT], \
2122 [meth.__qualname__]*min(len(name_matches), MATCHES_LIMIT), ())
2123
2124
2734
2125 # If no line buffer is given, assume the input text is all there was
2735 # If no line buffer is given, assume the input text is all there was
2126 if line_buffer is None:
2736 if line_buffer is None:
2127 line_buffer = text
2737 line_buffer = text
2128
2738
2739 # deprecated - do not use `line_buffer` in new code.
2129 self.line_buffer = line_buffer
2740 self.line_buffer = line_buffer
2130 self.text_until_cursor = self.line_buffer[:cursor_pos]
2741 self.text_until_cursor = self.line_buffer[:cursor_pos]
2131
2742
2132 # Do magic arg matches
2743 if not full_text:
2133 for matcher in self.magic_arg_matchers:
2744 full_text = line_buffer
2134 matches = list(matcher(line_buffer))[:MATCHES_LIMIT]
2745
2135 if matches:
2746 context = CompletionContext(
2136 origins = [matcher.__qualname__] * len(matches)
2747 full_text=full_text,
2137 return _CompleteResult(text, matches, origins, ())
2748 cursor_position=cursor_pos,
2749 cursor_line=cursor_line,
2750 token=text,
2751 limit=MATCHES_LIMIT,
2752 )
2138
2753
2139 # Start with a clean slate of completions
2754 # Start with a clean slate of completions
2140 matches = []
2755 results = {}
2141
2756
2142 # FIXME: we should extend our api to return a dict with completions for
2757 jedi_matcher_id = _get_matcher_id(self._jedi_matcher)
2143 # different types of objects. The rlcomplete() method could then
2144 # simply collapse the dict into a list for readline, but we'd have
2145 # richer completion semantics in other environments.
2146 is_magic_prefix = len(text) > 0 and text[0] == "%"
2147 completions: Iterable[Any] = []
2148 if self.use_jedi and not is_magic_prefix:
2149 if not full_text:
2150 full_text = line_buffer
2151 completions = self._jedi_matches(
2152 cursor_pos, cursor_line, full_text)
2153
2154 if self.merge_completions:
2155 matches = []
2156 for matcher in self.matchers:
2157 try:
2158 matches.extend([(m, matcher.__qualname__)
2159 for m in matcher(text)])
2160 except:
2161 # Show the ugly traceback if the matcher causes an
2162 # exception, but do NOT crash the kernel!
2163 sys.excepthook(*sys.exc_info())
2164 else:
2165 for matcher in self.matchers:
2166 matches = [(m, matcher.__qualname__)
2167 for m in matcher(text)]
2168 if matches:
2169 break
2170
2171 seen = set()
2172 filtered_matches = set()
2173 for m in matches:
2174 t, c = m
2175 if t not in seen:
2176 filtered_matches.add(m)
2177 seen.add(t)
2178
2758
2179 _filtered_matches = sorted(filtered_matches, key=lambda x: completions_sorting_key(x[0]))
2759 suppressed_matchers = set()
2180
2760
2181 custom_res = [(m, 'custom') for m in self.dispatch_custom_completer(text) or []]
2761 matchers = {
2182
2762 _get_matcher_id(matcher): matcher
2183 _filtered_matches = custom_res or _filtered_matches
2763 for matcher in sorted(
2184
2764 self.matchers, key=_get_matcher_priority, reverse=True
2185 _filtered_matches = _filtered_matches[:MATCHES_LIMIT]
2765 )
2186 _matches = [m[0] for m in _filtered_matches]
2766 }
2187 origins = [m[1] for m in _filtered_matches]
2188
2767
2189 self.matches = _matches
2768 for matcher_id, matcher in matchers.items():
2769 api_version = _get_matcher_api_version(matcher)
2770 matcher_id = _get_matcher_id(matcher)
2190
2771
2191 return _CompleteResult(text, _matches, origins, completions)
2772 if matcher_id in self.disable_matchers:
2192
2773 continue
2193 def fwd_unicode_match(self, text:str) -> Tuple[str, Sequence[str]]:
2774
2775 if matcher_id in results:
2776 warnings.warn(f"Duplicate matcher ID: {matcher_id}.")
2777
2778 if matcher_id in suppressed_matchers:
2779 continue
2780
2781 try:
2782 if api_version == 1:
2783 result = _convert_matcher_v1_result_to_v2(
2784 matcher(text), type=_UNKNOWN_TYPE
2785 )
2786 elif api_version == 2:
2787 result = cast(matcher, MatcherAPIv2)(context)
2788 else:
2789 raise ValueError(f"Unsupported API version {api_version}")
2790 except:
2791 # Show the ugly traceback if the matcher causes an
2792 # exception, but do NOT crash the kernel!
2793 sys.excepthook(*sys.exc_info())
2794 continue
2795
2796 # set default value for matched fragment if suffix was not selected.
2797 result["matched_fragment"] = result.get("matched_fragment", context.token)
2798
2799 if not suppressed_matchers:
2800 suppression_recommended = result.get("suppress", False)
2801
2802 suppression_config = (
2803 self.suppress_competing_matchers.get(matcher_id, None)
2804 if isinstance(self.suppress_competing_matchers, dict)
2805 else self.suppress_competing_matchers
2806 )
2807 should_suppress = (
2808 (suppression_config is True)
2809 or (suppression_recommended and (suppression_config is not False))
2810 ) and len(result["completions"])
2811
2812 if should_suppress:
2813 suppression_exceptions = result.get("do_not_suppress", set())
2814 try:
2815 to_suppress = set(suppression_recommended)
2816 except TypeError:
2817 to_suppress = set(matchers)
2818 suppressed_matchers = to_suppress - suppression_exceptions
2819
2820 new_results = {}
2821 for previous_matcher_id, previous_result in results.items():
2822 if previous_matcher_id not in suppressed_matchers:
2823 new_results[previous_matcher_id] = previous_result
2824 results = new_results
2825
2826 results[matcher_id] = result
2827
2828 _, matches = self._arrange_and_extract(
2829 results,
2830 # TODO Jedi completions non included in legacy stateful API; was this deliberate or omission?
2831 # if it was omission, we can remove the filtering step, otherwise remove this comment.
2832 skip_matchers={jedi_matcher_id},
2833 abort_if_offset_changes=False,
2834 )
2835
2836 # populate legacy stateful API
2837 self.matches = matches
2838
2839 return results
2840
2841 @staticmethod
2842 def _deduplicate(
2843 matches: Sequence[SimpleCompletion],
2844 ) -> Iterable[SimpleCompletion]:
2845 filtered_matches = {}
2846 for match in matches:
2847 text = match.text
2848 if (
2849 text not in filtered_matches
2850 or filtered_matches[text].type == _UNKNOWN_TYPE
2851 ):
2852 filtered_matches[text] = match
2853
2854 return filtered_matches.values()
2855
2856 @staticmethod
2857 def _sort(matches: Sequence[SimpleCompletion]):
2858 return sorted(matches, key=lambda x: completions_sorting_key(x.text))
2859
2860 @context_matcher()
2861 def fwd_unicode_matcher(self, context: CompletionContext):
2862 """Same as :any:`fwd_unicode_match`, but adopted to new Matcher API."""
2863 # TODO: use `context.limit` to terminate early once we matched the maximum
2864 # number that will be used downstream; can be added as an optional to
2865 # `fwd_unicode_match(text: str, limit: int = None)` or we could re-implement here.
2866 fragment, matches = self.fwd_unicode_match(context.text_until_cursor)
2867 return _convert_matcher_v1_result_to_v2(
2868 matches, type="unicode", fragment=fragment, suppress_if_matches=True
2869 )
2870
2871 def fwd_unicode_match(self, text: str) -> Tuple[str, Sequence[str]]:
2194 """
2872 """
2195 Forward match a string starting with a backslash with a list of
2873 Forward match a string starting with a backslash with a list of
2196 potential Unicode completions.
2874 potential Unicode completions.
2197
2875
2198 Will compute list list of Unicode character names on first call and cache it.
2876 Will compute list of Unicode character names on first call and cache it.
2877
2878 .. deprecated:: 8.6
2879 You can use :meth:`fwd_unicode_matcher` instead.
2199
2880
2200 Returns
2881 Returns
2201 -------
2882 -------
2202 At tuple with:
2883 At tuple with:
2203 - matched text (empty if no matches)
2884 - matched text (empty if no matches)
2204 - list of potential completions, empty tuple otherwise)
2885 - list of potential completions, empty tuple otherwise)
2205 """
2886 """
2206 # TODO: self.unicode_names is here a list we traverse each time with ~100k elements.
2887 # TODO: self.unicode_names is here a list we traverse each time with ~100k elements.
2207 # We could do a faster match using a Trie.
2888 # We could do a faster match using a Trie.
2208
2889
2209 # Using pygtrie the following seem to work:
2890 # Using pygtrie the following seem to work:
2210
2891
2211 # s = PrefixSet()
2892 # s = PrefixSet()
2212
2893
2213 # for c in range(0,0x10FFFF + 1):
2894 # for c in range(0,0x10FFFF + 1):
2214 # try:
2895 # try:
2215 # s.add(unicodedata.name(chr(c)))
2896 # s.add(unicodedata.name(chr(c)))
2216 # except ValueError:
2897 # except ValueError:
2217 # pass
2898 # pass
2218 # [''.join(k) for k in s.iter(prefix)]
2899 # [''.join(k) for k in s.iter(prefix)]
2219
2900
2220 # But need to be timed and adds an extra dependency.
2901 # But need to be timed and adds an extra dependency.
2221
2902
2222 slashpos = text.rfind('\\')
2903 slashpos = text.rfind('\\')
2223 # if text starts with slash
2904 # if text starts with slash
2224 if slashpos > -1:
2905 if slashpos > -1:
2225 # PERF: It's important that we don't access self._unicode_names
2906 # PERF: It's important that we don't access self._unicode_names
2226 # until we're inside this if-block. _unicode_names is lazily
2907 # until we're inside this if-block. _unicode_names is lazily
2227 # initialized, and it takes a user-noticeable amount of time to
2908 # initialized, and it takes a user-noticeable amount of time to
2228 # initialize it, so we don't want to initialize it unless we're
2909 # initialize it, so we don't want to initialize it unless we're
2229 # actually going to use it.
2910 # actually going to use it.
2230 s = text[slashpos + 1 :]
2911 s = text[slashpos + 1 :]
2231 sup = s.upper()
2912 sup = s.upper()
2232 candidates = [x for x in self.unicode_names if x.startswith(sup)]
2913 candidates = [x for x in self.unicode_names if x.startswith(sup)]
2233 if candidates:
2914 if candidates:
2234 return s, candidates
2915 return s, candidates
2235 candidates = [x for x in self.unicode_names if sup in x]
2916 candidates = [x for x in self.unicode_names if sup in x]
2236 if candidates:
2917 if candidates:
2237 return s, candidates
2918 return s, candidates
2238 splitsup = sup.split(" ")
2919 splitsup = sup.split(" ")
2239 candidates = [
2920 candidates = [
2240 x for x in self.unicode_names if all(u in x for u in splitsup)
2921 x for x in self.unicode_names if all(u in x for u in splitsup)
2241 ]
2922 ]
2242 if candidates:
2923 if candidates:
2243 return s, candidates
2924 return s, candidates
2244
2925
2245 return "", ()
2926 return "", ()
2246
2927
2247 # if text does not start with slash
2928 # if text does not start with slash
2248 else:
2929 else:
2249 return '', ()
2930 return '', ()
2250
2931
2251 @property
2932 @property
2252 def unicode_names(self) -> List[str]:
2933 def unicode_names(self) -> List[str]:
2253 """List of names of unicode code points that can be completed.
2934 """List of names of unicode code points that can be completed.
2254
2935
2255 The list is lazily initialized on first access.
2936 The list is lazily initialized on first access.
2256 """
2937 """
2257 if self._unicode_names is None:
2938 if self._unicode_names is None:
2258 names = []
2939 names = []
2259 for c in range(0,0x10FFFF + 1):
2940 for c in range(0,0x10FFFF + 1):
2260 try:
2941 try:
2261 names.append(unicodedata.name(chr(c)))
2942 names.append(unicodedata.name(chr(c)))
2262 except ValueError:
2943 except ValueError:
2263 pass
2944 pass
2264 self._unicode_names = _unicode_name_compute(_UNICODE_RANGES)
2945 self._unicode_names = _unicode_name_compute(_UNICODE_RANGES)
2265
2946
2266 return self._unicode_names
2947 return self._unicode_names
2267
2948
2268 def _unicode_name_compute(ranges:List[Tuple[int,int]]) -> List[str]:
2949 def _unicode_name_compute(ranges:List[Tuple[int,int]]) -> List[str]:
2269 names = []
2950 names = []
2270 for start,stop in ranges:
2951 for start,stop in ranges:
2271 for c in range(start, stop) :
2952 for c in range(start, stop) :
2272 try:
2953 try:
2273 names.append(unicodedata.name(chr(c)))
2954 names.append(unicodedata.name(chr(c)))
2274 except ValueError:
2955 except ValueError:
2275 pass
2956 pass
2276 return names
2957 return names
@@ -1,1277 +1,1290 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Top-level display functions for displaying object in different formats."""
2 """Top-level display functions for displaying object in different formats."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 from binascii import b2a_base64, hexlify
8 from binascii import b2a_base64, hexlify
9 import html
9 import html
10 import json
10 import json
11 import mimetypes
11 import mimetypes
12 import os
12 import os
13 import struct
13 import struct
14 import warnings
14 import warnings
15 from copy import deepcopy
15 from copy import deepcopy
16 from os.path import splitext
16 from os.path import splitext
17 from pathlib import Path, PurePath
17 from pathlib import Path, PurePath
18
18
19 from IPython.utils.py3compat import cast_unicode
19 from IPython.utils.py3compat import cast_unicode
20 from IPython.testing.skipdoctest import skip_doctest
20 from IPython.testing.skipdoctest import skip_doctest
21 from . import display_functions
21 from . import display_functions
22
22
23
23
24 __all__ = ['display_pretty', 'display_html', 'display_markdown',
24 __all__ = ['display_pretty', 'display_html', 'display_markdown',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
28 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats',
28 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats',
29 'set_matplotlib_close',
29 'set_matplotlib_close',
30 'Video']
30 'Video']
31
31
32 _deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
32 _deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
33
33
34 __all__ = __all__ + _deprecated_names
34 __all__ = __all__ + _deprecated_names
35
35
36
36
37 # ----- warn to import from IPython.display -----
37 # ----- warn to import from IPython.display -----
38
38
39 from warnings import warn
39 from warnings import warn
40
40
41
41
42 def __getattr__(name):
42 def __getattr__(name):
43 if name in _deprecated_names:
43 if name in _deprecated_names:
44 warn(f"Importing {name} from IPython.core.display is deprecated since IPython 7.14, please import from IPython display", DeprecationWarning, stacklevel=2)
44 warn(f"Importing {name} from IPython.core.display is deprecated since IPython 7.14, please import from IPython display", DeprecationWarning, stacklevel=2)
45 return getattr(display_functions, name)
45 return getattr(display_functions, name)
46
46
47 if name in globals().keys():
47 if name in globals().keys():
48 return globals()[name]
48 return globals()[name]
49 else:
49 else:
50 raise AttributeError(f"module {__name__} has no attribute {name}")
50 raise AttributeError(f"module {__name__} has no attribute {name}")
51
51
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # utility functions
54 # utility functions
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 def _safe_exists(path):
57 def _safe_exists(path):
58 """Check path, but don't let exceptions raise"""
58 """Check path, but don't let exceptions raise"""
59 try:
59 try:
60 return os.path.exists(path)
60 return os.path.exists(path)
61 except Exception:
61 except Exception:
62 return False
62 return False
63
63
64
64
65 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
65 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
66 """internal implementation of all display_foo methods
66 """internal implementation of all display_foo methods
67
67
68 Parameters
68 Parameters
69 ----------
69 ----------
70 mimetype : str
70 mimetype : str
71 The mimetype to be published (e.g. 'image/png')
71 The mimetype to be published (e.g. 'image/png')
72 *objs : object
72 *objs : object
73 The Python objects to display, or if raw=True raw text data to
73 The Python objects to display, or if raw=True raw text data to
74 display.
74 display.
75 raw : bool
75 raw : bool
76 Are the data objects raw data or Python objects that need to be
76 Are the data objects raw data or Python objects that need to be
77 formatted before display? [default: False]
77 formatted before display? [default: False]
78 metadata : dict (optional)
78 metadata : dict (optional)
79 Metadata to be associated with the specific mimetype output.
79 Metadata to be associated with the specific mimetype output.
80 """
80 """
81 if metadata:
81 if metadata:
82 metadata = {mimetype: metadata}
82 metadata = {mimetype: metadata}
83 if raw:
83 if raw:
84 # turn list of pngdata into list of { 'image/png': pngdata }
84 # turn list of pngdata into list of { 'image/png': pngdata }
85 objs = [ {mimetype: obj} for obj in objs ]
85 objs = [ {mimetype: obj} for obj in objs ]
86 display_functions.display(*objs, raw=raw, metadata=metadata, include=[mimetype])
86 display_functions.display(*objs, raw=raw, metadata=metadata, include=[mimetype])
87
87
88 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
89 # Main functions
89 # Main functions
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91
91
92
92
93 def display_pretty(*objs, **kwargs):
93 def display_pretty(*objs, **kwargs):
94 """Display the pretty (default) representation of an object.
94 """Display the pretty (default) representation of an object.
95
95
96 Parameters
96 Parameters
97 ----------
97 ----------
98 *objs : object
98 *objs : object
99 The Python objects to display, or if raw=True raw text data to
99 The Python objects to display, or if raw=True raw text data to
100 display.
100 display.
101 raw : bool
101 raw : bool
102 Are the data objects raw data or Python objects that need to be
102 Are the data objects raw data or Python objects that need to be
103 formatted before display? [default: False]
103 formatted before display? [default: False]
104 metadata : dict (optional)
104 metadata : dict (optional)
105 Metadata to be associated with the specific mimetype output.
105 Metadata to be associated with the specific mimetype output.
106 """
106 """
107 _display_mimetype('text/plain', objs, **kwargs)
107 _display_mimetype('text/plain', objs, **kwargs)
108
108
109
109
110 def display_html(*objs, **kwargs):
110 def display_html(*objs, **kwargs):
111 """Display the HTML representation of an object.
111 """Display the HTML representation of an object.
112
112
113 Note: If raw=False and the object does not have a HTML
113 Note: If raw=False and the object does not have a HTML
114 representation, no HTML will be shown.
114 representation, no HTML will be shown.
115
115
116 Parameters
116 Parameters
117 ----------
117 ----------
118 *objs : object
118 *objs : object
119 The Python objects to display, or if raw=True raw HTML data to
119 The Python objects to display, or if raw=True raw HTML data to
120 display.
120 display.
121 raw : bool
121 raw : bool
122 Are the data objects raw data or Python objects that need to be
122 Are the data objects raw data or Python objects that need to be
123 formatted before display? [default: False]
123 formatted before display? [default: False]
124 metadata : dict (optional)
124 metadata : dict (optional)
125 Metadata to be associated with the specific mimetype output.
125 Metadata to be associated with the specific mimetype output.
126 """
126 """
127 _display_mimetype('text/html', objs, **kwargs)
127 _display_mimetype('text/html', objs, **kwargs)
128
128
129
129
130 def display_markdown(*objs, **kwargs):
130 def display_markdown(*objs, **kwargs):
131 """Displays the Markdown representation of an object.
131 """Displays the Markdown representation of an object.
132
132
133 Parameters
133 Parameters
134 ----------
134 ----------
135 *objs : object
135 *objs : object
136 The Python objects to display, or if raw=True raw markdown data to
136 The Python objects to display, or if raw=True raw markdown data to
137 display.
137 display.
138 raw : bool
138 raw : bool
139 Are the data objects raw data or Python objects that need to be
139 Are the data objects raw data or Python objects that need to be
140 formatted before display? [default: False]
140 formatted before display? [default: False]
141 metadata : dict (optional)
141 metadata : dict (optional)
142 Metadata to be associated with the specific mimetype output.
142 Metadata to be associated with the specific mimetype output.
143 """
143 """
144
144
145 _display_mimetype('text/markdown', objs, **kwargs)
145 _display_mimetype('text/markdown', objs, **kwargs)
146
146
147
147
148 def display_svg(*objs, **kwargs):
148 def display_svg(*objs, **kwargs):
149 """Display the SVG representation of an object.
149 """Display the SVG representation of an object.
150
150
151 Parameters
151 Parameters
152 ----------
152 ----------
153 *objs : object
153 *objs : object
154 The Python objects to display, or if raw=True raw svg data to
154 The Python objects to display, or if raw=True raw svg data to
155 display.
155 display.
156 raw : bool
156 raw : bool
157 Are the data objects raw data or Python objects that need to be
157 Are the data objects raw data or Python objects that need to be
158 formatted before display? [default: False]
158 formatted before display? [default: False]
159 metadata : dict (optional)
159 metadata : dict (optional)
160 Metadata to be associated with the specific mimetype output.
160 Metadata to be associated with the specific mimetype output.
161 """
161 """
162 _display_mimetype('image/svg+xml', objs, **kwargs)
162 _display_mimetype('image/svg+xml', objs, **kwargs)
163
163
164
164
165 def display_png(*objs, **kwargs):
165 def display_png(*objs, **kwargs):
166 """Display the PNG representation of an object.
166 """Display the PNG representation of an object.
167
167
168 Parameters
168 Parameters
169 ----------
169 ----------
170 *objs : object
170 *objs : object
171 The Python objects to display, or if raw=True raw png data to
171 The Python objects to display, or if raw=True raw png data to
172 display.
172 display.
173 raw : bool
173 raw : bool
174 Are the data objects raw data or Python objects that need to be
174 Are the data objects raw data or Python objects that need to be
175 formatted before display? [default: False]
175 formatted before display? [default: False]
176 metadata : dict (optional)
176 metadata : dict (optional)
177 Metadata to be associated with the specific mimetype output.
177 Metadata to be associated with the specific mimetype output.
178 """
178 """
179 _display_mimetype('image/png', objs, **kwargs)
179 _display_mimetype('image/png', objs, **kwargs)
180
180
181
181
182 def display_jpeg(*objs, **kwargs):
182 def display_jpeg(*objs, **kwargs):
183 """Display the JPEG representation of an object.
183 """Display the JPEG representation of an object.
184
184
185 Parameters
185 Parameters
186 ----------
186 ----------
187 *objs : object
187 *objs : object
188 The Python objects to display, or if raw=True raw JPEG data to
188 The Python objects to display, or if raw=True raw JPEG data to
189 display.
189 display.
190 raw : bool
190 raw : bool
191 Are the data objects raw data or Python objects that need to be
191 Are the data objects raw data or Python objects that need to be
192 formatted before display? [default: False]
192 formatted before display? [default: False]
193 metadata : dict (optional)
193 metadata : dict (optional)
194 Metadata to be associated with the specific mimetype output.
194 Metadata to be associated with the specific mimetype output.
195 """
195 """
196 _display_mimetype('image/jpeg', objs, **kwargs)
196 _display_mimetype('image/jpeg', objs, **kwargs)
197
197
198
198
199 def display_latex(*objs, **kwargs):
199 def display_latex(*objs, **kwargs):
200 """Display the LaTeX representation of an object.
200 """Display the LaTeX representation of an object.
201
201
202 Parameters
202 Parameters
203 ----------
203 ----------
204 *objs : object
204 *objs : object
205 The Python objects to display, or if raw=True raw latex data to
205 The Python objects to display, or if raw=True raw latex data to
206 display.
206 display.
207 raw : bool
207 raw : bool
208 Are the data objects raw data or Python objects that need to be
208 Are the data objects raw data or Python objects that need to be
209 formatted before display? [default: False]
209 formatted before display? [default: False]
210 metadata : dict (optional)
210 metadata : dict (optional)
211 Metadata to be associated with the specific mimetype output.
211 Metadata to be associated with the specific mimetype output.
212 """
212 """
213 _display_mimetype('text/latex', objs, **kwargs)
213 _display_mimetype('text/latex', objs, **kwargs)
214
214
215
215
216 def display_json(*objs, **kwargs):
216 def display_json(*objs, **kwargs):
217 """Display the JSON representation of an object.
217 """Display the JSON representation of an object.
218
218
219 Note that not many frontends support displaying JSON.
219 Note that not many frontends support displaying JSON.
220
220
221 Parameters
221 Parameters
222 ----------
222 ----------
223 *objs : object
223 *objs : object
224 The Python objects to display, or if raw=True raw json data to
224 The Python objects to display, or if raw=True raw json data to
225 display.
225 display.
226 raw : bool
226 raw : bool
227 Are the data objects raw data or Python objects that need to be
227 Are the data objects raw data or Python objects that need to be
228 formatted before display? [default: False]
228 formatted before display? [default: False]
229 metadata : dict (optional)
229 metadata : dict (optional)
230 Metadata to be associated with the specific mimetype output.
230 Metadata to be associated with the specific mimetype output.
231 """
231 """
232 _display_mimetype('application/json', objs, **kwargs)
232 _display_mimetype('application/json', objs, **kwargs)
233
233
234
234
235 def display_javascript(*objs, **kwargs):
235 def display_javascript(*objs, **kwargs):
236 """Display the Javascript representation of an object.
236 """Display the Javascript representation of an object.
237
237
238 Parameters
238 Parameters
239 ----------
239 ----------
240 *objs : object
240 *objs : object
241 The Python objects to display, or if raw=True raw javascript data to
241 The Python objects to display, or if raw=True raw javascript data to
242 display.
242 display.
243 raw : bool
243 raw : bool
244 Are the data objects raw data or Python objects that need to be
244 Are the data objects raw data or Python objects that need to be
245 formatted before display? [default: False]
245 formatted before display? [default: False]
246 metadata : dict (optional)
246 metadata : dict (optional)
247 Metadata to be associated with the specific mimetype output.
247 Metadata to be associated with the specific mimetype output.
248 """
248 """
249 _display_mimetype('application/javascript', objs, **kwargs)
249 _display_mimetype('application/javascript', objs, **kwargs)
250
250
251
251
252 def display_pdf(*objs, **kwargs):
252 def display_pdf(*objs, **kwargs):
253 """Display the PDF representation of an object.
253 """Display the PDF representation of an object.
254
254
255 Parameters
255 Parameters
256 ----------
256 ----------
257 *objs : object
257 *objs : object
258 The Python objects to display, or if raw=True raw javascript data to
258 The Python objects to display, or if raw=True raw javascript data to
259 display.
259 display.
260 raw : bool
260 raw : bool
261 Are the data objects raw data or Python objects that need to be
261 Are the data objects raw data or Python objects that need to be
262 formatted before display? [default: False]
262 formatted before display? [default: False]
263 metadata : dict (optional)
263 metadata : dict (optional)
264 Metadata to be associated with the specific mimetype output.
264 Metadata to be associated with the specific mimetype output.
265 """
265 """
266 _display_mimetype('application/pdf', objs, **kwargs)
266 _display_mimetype('application/pdf', objs, **kwargs)
267
267
268
268
269 #-----------------------------------------------------------------------------
269 #-----------------------------------------------------------------------------
270 # Smart classes
270 # Smart classes
271 #-----------------------------------------------------------------------------
271 #-----------------------------------------------------------------------------
272
272
273
273
274 class DisplayObject(object):
274 class DisplayObject(object):
275 """An object that wraps data to be displayed."""
275 """An object that wraps data to be displayed."""
276
276
277 _read_flags = 'r'
277 _read_flags = 'r'
278 _show_mem_addr = False
278 _show_mem_addr = False
279 metadata = None
279 metadata = None
280
280
281 def __init__(self, data=None, url=None, filename=None, metadata=None):
281 def __init__(self, data=None, url=None, filename=None, metadata=None):
282 """Create a display object given raw data.
282 """Create a display object given raw data.
283
283
284 When this object is returned by an expression or passed to the
284 When this object is returned by an expression or passed to the
285 display function, it will result in the data being displayed
285 display function, it will result in the data being displayed
286 in the frontend. The MIME type of the data should match the
286 in the frontend. The MIME type of the data should match the
287 subclasses used, so the Png subclass should be used for 'image/png'
287 subclasses used, so the Png subclass should be used for 'image/png'
288 data. If the data is a URL, the data will first be downloaded
288 data. If the data is a URL, the data will first be downloaded
289 and then displayed. If
289 and then displayed. If
290
290
291 Parameters
291 Parameters
292 ----------
292 ----------
293 data : unicode, str or bytes
293 data : unicode, str or bytes
294 The raw data or a URL or file to load the data from
294 The raw data or a URL or file to load the data from
295 url : unicode
295 url : unicode
296 A URL to download the data from.
296 A URL to download the data from.
297 filename : unicode
297 filename : unicode
298 Path to a local file to load the data from.
298 Path to a local file to load the data from.
299 metadata : dict
299 metadata : dict
300 Dict of metadata associated to be the object when displayed
300 Dict of metadata associated to be the object when displayed
301 """
301 """
302 if isinstance(data, (Path, PurePath)):
302 if isinstance(data, (Path, PurePath)):
303 data = str(data)
303 data = str(data)
304
304
305 if data is not None and isinstance(data, str):
305 if data is not None and isinstance(data, str):
306 if data.startswith('http') and url is None:
306 if data.startswith('http') and url is None:
307 url = data
307 url = data
308 filename = None
308 filename = None
309 data = None
309 data = None
310 elif _safe_exists(data) and filename is None:
310 elif _safe_exists(data) and filename is None:
311 url = None
311 url = None
312 filename = data
312 filename = data
313 data = None
313 data = None
314
314
315 self.url = url
315 self.url = url
316 self.filename = filename
316 self.filename = filename
317 # because of @data.setter methods in
317 # because of @data.setter methods in
318 # subclasses ensure url and filename are set
318 # subclasses ensure url and filename are set
319 # before assigning to self.data
319 # before assigning to self.data
320 self.data = data
320 self.data = data
321
321
322 if metadata is not None:
322 if metadata is not None:
323 self.metadata = metadata
323 self.metadata = metadata
324 elif self.metadata is None:
324 elif self.metadata is None:
325 self.metadata = {}
325 self.metadata = {}
326
326
327 self.reload()
327 self.reload()
328 self._check_data()
328 self._check_data()
329
329
330 def __repr__(self):
330 def __repr__(self):
331 if not self._show_mem_addr:
331 if not self._show_mem_addr:
332 cls = self.__class__
332 cls = self.__class__
333 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
333 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
334 else:
334 else:
335 r = super(DisplayObject, self).__repr__()
335 r = super(DisplayObject, self).__repr__()
336 return r
336 return r
337
337
338 def _check_data(self):
338 def _check_data(self):
339 """Override in subclasses if there's something to check."""
339 """Override in subclasses if there's something to check."""
340 pass
340 pass
341
341
342 def _data_and_metadata(self):
342 def _data_and_metadata(self):
343 """shortcut for returning metadata with shape information, if defined"""
343 """shortcut for returning metadata with shape information, if defined"""
344 if self.metadata:
344 if self.metadata:
345 return self.data, deepcopy(self.metadata)
345 return self.data, deepcopy(self.metadata)
346 else:
346 else:
347 return self.data
347 return self.data
348
348
349 def reload(self):
349 def reload(self):
350 """Reload the raw data from file or URL."""
350 """Reload the raw data from file or URL."""
351 if self.filename is not None:
351 if self.filename is not None:
352 encoding = None if "b" in self._read_flags else "utf-8"
352 encoding = None if "b" in self._read_flags else "utf-8"
353 with open(self.filename, self._read_flags, encoding=encoding) as f:
353 with open(self.filename, self._read_flags, encoding=encoding) as f:
354 self.data = f.read()
354 self.data = f.read()
355 elif self.url is not None:
355 elif self.url is not None:
356 # Deferred import
356 # Deferred import
357 from urllib.request import urlopen
357 from urllib.request import urlopen
358 response = urlopen(self.url)
358 response = urlopen(self.url)
359 data = response.read()
359 data = response.read()
360 # extract encoding from header, if there is one:
360 # extract encoding from header, if there is one:
361 encoding = None
361 encoding = None
362 if 'content-type' in response.headers:
362 if 'content-type' in response.headers:
363 for sub in response.headers['content-type'].split(';'):
363 for sub in response.headers['content-type'].split(';'):
364 sub = sub.strip()
364 sub = sub.strip()
365 if sub.startswith('charset'):
365 if sub.startswith('charset'):
366 encoding = sub.split('=')[-1].strip()
366 encoding = sub.split('=')[-1].strip()
367 break
367 break
368 if 'content-encoding' in response.headers:
368 if 'content-encoding' in response.headers:
369 # TODO: do deflate?
369 # TODO: do deflate?
370 if 'gzip' in response.headers['content-encoding']:
370 if 'gzip' in response.headers['content-encoding']:
371 import gzip
371 import gzip
372 from io import BytesIO
372 from io import BytesIO
373
373
374 # assume utf-8 if encoding is not specified
374 # assume utf-8 if encoding is not specified
375 with gzip.open(
375 with gzip.open(
376 BytesIO(data), "rt", encoding=encoding or "utf-8"
376 BytesIO(data), "rt", encoding=encoding or "utf-8"
377 ) as fp:
377 ) as fp:
378 encoding = None
378 encoding = None
379 data = fp.read()
379 data = fp.read()
380
380
381 # decode data, if an encoding was specified
381 # decode data, if an encoding was specified
382 # We only touch self.data once since
382 # We only touch self.data once since
383 # subclasses such as SVG have @data.setter methods
383 # subclasses such as SVG have @data.setter methods
384 # that transform self.data into ... well svg.
384 # that transform self.data into ... well svg.
385 if encoding:
385 if encoding:
386 self.data = data.decode(encoding, 'replace')
386 self.data = data.decode(encoding, 'replace')
387 else:
387 else:
388 self.data = data
388 self.data = data
389
389
390
390
391 class TextDisplayObject(DisplayObject):
391 class TextDisplayObject(DisplayObject):
392 """Validate that display data is text"""
392 """Create a text display object given raw data.
393
394 Parameters
395 ----------
396 data : str or unicode
397 The raw data or a URL or file to load the data from.
398 url : unicode
399 A URL to download the data from.
400 filename : unicode
401 Path to a local file to load the data from.
402 metadata : dict
403 Dict of metadata associated to be the object when displayed
404 """
393 def _check_data(self):
405 def _check_data(self):
394 if self.data is not None and not isinstance(self.data, str):
406 if self.data is not None and not isinstance(self.data, str):
395 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
407 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
396
408
397 class Pretty(TextDisplayObject):
409 class Pretty(TextDisplayObject):
398
410
399 def _repr_pretty_(self, pp, cycle):
411 def _repr_pretty_(self, pp, cycle):
400 return pp.text(self.data)
412 return pp.text(self.data)
401
413
402
414
403 class HTML(TextDisplayObject):
415 class HTML(TextDisplayObject):
404
416
405 def __init__(self, data=None, url=None, filename=None, metadata=None):
417 def __init__(self, data=None, url=None, filename=None, metadata=None):
406 def warn():
418 def warn():
407 if not data:
419 if not data:
408 return False
420 return False
409
421
410 #
422 #
411 # Avoid calling lower() on the entire data, because it could be a
423 # Avoid calling lower() on the entire data, because it could be a
412 # long string and we're only interested in its beginning and end.
424 # long string and we're only interested in its beginning and end.
413 #
425 #
414 prefix = data[:10].lower()
426 prefix = data[:10].lower()
415 suffix = data[-10:].lower()
427 suffix = data[-10:].lower()
416 return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
428 return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
417
429
418 if warn():
430 if warn():
419 warnings.warn("Consider using IPython.display.IFrame instead")
431 warnings.warn("Consider using IPython.display.IFrame instead")
420 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
432 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
421
433
422 def _repr_html_(self):
434 def _repr_html_(self):
423 return self._data_and_metadata()
435 return self._data_and_metadata()
424
436
425 def __html__(self):
437 def __html__(self):
426 """
438 """
427 This method exists to inform other HTML-using modules (e.g. Markupsafe,
439 This method exists to inform other HTML-using modules (e.g. Markupsafe,
428 htmltag, etc) that this object is HTML and does not need things like
440 htmltag, etc) that this object is HTML and does not need things like
429 special characters (<>&) escaped.
441 special characters (<>&) escaped.
430 """
442 """
431 return self._repr_html_()
443 return self._repr_html_()
432
444
433
445
434 class Markdown(TextDisplayObject):
446 class Markdown(TextDisplayObject):
435
447
436 def _repr_markdown_(self):
448 def _repr_markdown_(self):
437 return self._data_and_metadata()
449 return self._data_and_metadata()
438
450
439
451
440 class Math(TextDisplayObject):
452 class Math(TextDisplayObject):
441
453
442 def _repr_latex_(self):
454 def _repr_latex_(self):
443 s = r"$\displaystyle %s$" % self.data.strip('$')
455 s = r"$\displaystyle %s$" % self.data.strip('$')
444 if self.metadata:
456 if self.metadata:
445 return s, deepcopy(self.metadata)
457 return s, deepcopy(self.metadata)
446 else:
458 else:
447 return s
459 return s
448
460
449
461
450 class Latex(TextDisplayObject):
462 class Latex(TextDisplayObject):
451
463
452 def _repr_latex_(self):
464 def _repr_latex_(self):
453 return self._data_and_metadata()
465 return self._data_and_metadata()
454
466
455
467
456 class SVG(DisplayObject):
468 class SVG(DisplayObject):
457 """Embed an SVG into the display.
469 """Embed an SVG into the display.
458
470
459 Note if you just want to view a svg image via a URL use `:class:Image` with
471 Note if you just want to view a svg image via a URL use `:class:Image` with
460 a url=URL keyword argument.
472 a url=URL keyword argument.
461 """
473 """
462
474
463 _read_flags = 'rb'
475 _read_flags = 'rb'
464 # wrap data in a property, which extracts the <svg> tag, discarding
476 # wrap data in a property, which extracts the <svg> tag, discarding
465 # document headers
477 # document headers
466 _data = None
478 _data = None
467
479
468 @property
480 @property
469 def data(self):
481 def data(self):
470 return self._data
482 return self._data
471
483
472 @data.setter
484 @data.setter
473 def data(self, svg):
485 def data(self, svg):
474 if svg is None:
486 if svg is None:
475 self._data = None
487 self._data = None
476 return
488 return
477 # parse into dom object
489 # parse into dom object
478 from xml.dom import minidom
490 from xml.dom import minidom
479 x = minidom.parseString(svg)
491 x = minidom.parseString(svg)
480 # get svg tag (should be 1)
492 # get svg tag (should be 1)
481 found_svg = x.getElementsByTagName('svg')
493 found_svg = x.getElementsByTagName('svg')
482 if found_svg:
494 if found_svg:
483 svg = found_svg[0].toxml()
495 svg = found_svg[0].toxml()
484 else:
496 else:
485 # fallback on the input, trust the user
497 # fallback on the input, trust the user
486 # but this is probably an error.
498 # but this is probably an error.
487 pass
499 pass
488 svg = cast_unicode(svg)
500 svg = cast_unicode(svg)
489 self._data = svg
501 self._data = svg
490
502
491 def _repr_svg_(self):
503 def _repr_svg_(self):
492 return self._data_and_metadata()
504 return self._data_and_metadata()
493
505
494 class ProgressBar(DisplayObject):
506 class ProgressBar(DisplayObject):
495 """Progressbar supports displaying a progressbar like element
507 """Progressbar supports displaying a progressbar like element
496 """
508 """
497 def __init__(self, total):
509 def __init__(self, total):
498 """Creates a new progressbar
510 """Creates a new progressbar
499
511
500 Parameters
512 Parameters
501 ----------
513 ----------
502 total : int
514 total : int
503 maximum size of the progressbar
515 maximum size of the progressbar
504 """
516 """
505 self.total = total
517 self.total = total
506 self._progress = 0
518 self._progress = 0
507 self.html_width = '60ex'
519 self.html_width = '60ex'
508 self.text_width = 60
520 self.text_width = 60
509 self._display_id = hexlify(os.urandom(8)).decode('ascii')
521 self._display_id = hexlify(os.urandom(8)).decode('ascii')
510
522
511 def __repr__(self):
523 def __repr__(self):
512 fraction = self.progress / self.total
524 fraction = self.progress / self.total
513 filled = '=' * int(fraction * self.text_width)
525 filled = '=' * int(fraction * self.text_width)
514 rest = ' ' * (self.text_width - len(filled))
526 rest = ' ' * (self.text_width - len(filled))
515 return '[{}{}] {}/{}'.format(
527 return '[{}{}] {}/{}'.format(
516 filled, rest,
528 filled, rest,
517 self.progress, self.total,
529 self.progress, self.total,
518 )
530 )
519
531
520 def _repr_html_(self):
532 def _repr_html_(self):
521 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
533 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
522 self.html_width, self.total, self.progress)
534 self.html_width, self.total, self.progress)
523
535
524 def display(self):
536 def display(self):
525 display_functions.display(self, display_id=self._display_id)
537 display_functions.display(self, display_id=self._display_id)
526
538
527 def update(self):
539 def update(self):
528 display_functions.display(self, display_id=self._display_id, update=True)
540 display_functions.display(self, display_id=self._display_id, update=True)
529
541
530 @property
542 @property
531 def progress(self):
543 def progress(self):
532 return self._progress
544 return self._progress
533
545
534 @progress.setter
546 @progress.setter
535 def progress(self, value):
547 def progress(self, value):
536 self._progress = value
548 self._progress = value
537 self.update()
549 self.update()
538
550
539 def __iter__(self):
551 def __iter__(self):
540 self.display()
552 self.display()
541 self._progress = -1 # First iteration is 0
553 self._progress = -1 # First iteration is 0
542 return self
554 return self
543
555
544 def __next__(self):
556 def __next__(self):
545 """Returns current value and increments display by one."""
557 """Returns current value and increments display by one."""
546 self.progress += 1
558 self.progress += 1
547 if self.progress < self.total:
559 if self.progress < self.total:
548 return self.progress
560 return self.progress
549 else:
561 else:
550 raise StopIteration()
562 raise StopIteration()
551
563
552 class JSON(DisplayObject):
564 class JSON(DisplayObject):
553 """JSON expects a JSON-able dict or list
565 """JSON expects a JSON-able dict or list
554
566
555 not an already-serialized JSON string.
567 not an already-serialized JSON string.
556
568
557 Scalar types (None, number, string) are not allowed, only dict or list containers.
569 Scalar types (None, number, string) are not allowed, only dict or list containers.
558 """
570 """
559 # wrap data in a property, which warns about passing already-serialized JSON
571 # wrap data in a property, which warns about passing already-serialized JSON
560 _data = None
572 _data = None
561 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
573 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
562 """Create a JSON display object given raw data.
574 """Create a JSON display object given raw data.
563
575
564 Parameters
576 Parameters
565 ----------
577 ----------
566 data : dict or list
578 data : dict or list
567 JSON data to display. Not an already-serialized JSON string.
579 JSON data to display. Not an already-serialized JSON string.
568 Scalar types (None, number, string) are not allowed, only dict
580 Scalar types (None, number, string) are not allowed, only dict
569 or list containers.
581 or list containers.
570 url : unicode
582 url : unicode
571 A URL to download the data from.
583 A URL to download the data from.
572 filename : unicode
584 filename : unicode
573 Path to a local file to load the data from.
585 Path to a local file to load the data from.
574 expanded : boolean
586 expanded : boolean
575 Metadata to control whether a JSON display component is expanded.
587 Metadata to control whether a JSON display component is expanded.
576 metadata : dict
588 metadata : dict
577 Specify extra metadata to attach to the json display object.
589 Specify extra metadata to attach to the json display object.
578 root : str
590 root : str
579 The name of the root element of the JSON tree
591 The name of the root element of the JSON tree
580 """
592 """
581 self.metadata = {
593 self.metadata = {
582 'expanded': expanded,
594 'expanded': expanded,
583 'root': root,
595 'root': root,
584 }
596 }
585 if metadata:
597 if metadata:
586 self.metadata.update(metadata)
598 self.metadata.update(metadata)
587 if kwargs:
599 if kwargs:
588 self.metadata.update(kwargs)
600 self.metadata.update(kwargs)
589 super(JSON, self).__init__(data=data, url=url, filename=filename)
601 super(JSON, self).__init__(data=data, url=url, filename=filename)
590
602
591 def _check_data(self):
603 def _check_data(self):
592 if self.data is not None and not isinstance(self.data, (dict, list)):
604 if self.data is not None and not isinstance(self.data, (dict, list)):
593 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
605 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
594
606
595 @property
607 @property
596 def data(self):
608 def data(self):
597 return self._data
609 return self._data
598
610
599 @data.setter
611 @data.setter
600 def data(self, data):
612 def data(self, data):
601 if isinstance(data, (Path, PurePath)):
613 if isinstance(data, (Path, PurePath)):
602 data = str(data)
614 data = str(data)
603
615
604 if isinstance(data, str):
616 if isinstance(data, str):
605 if self.filename is None and self.url is None:
617 if self.filename is None and self.url is None:
606 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
618 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
607 data = json.loads(data)
619 data = json.loads(data)
608 self._data = data
620 self._data = data
609
621
610 def _data_and_metadata(self):
622 def _data_and_metadata(self):
611 return self.data, self.metadata
623 return self.data, self.metadata
612
624
613 def _repr_json_(self):
625 def _repr_json_(self):
614 return self._data_and_metadata()
626 return self._data_and_metadata()
615
627
628
616 _css_t = """var link = document.createElement("link");
629 _css_t = """var link = document.createElement("link");
617 link.ref = "stylesheet";
630 link.rel = "stylesheet";
618 link.type = "text/css";
631 link.type = "text/css";
619 link.href = "%s";
632 link.href = "%s";
620 document.head.appendChild(link);
633 document.head.appendChild(link);
621 """
634 """
622
635
623 _lib_t1 = """new Promise(function(resolve, reject) {
636 _lib_t1 = """new Promise(function(resolve, reject) {
624 var script = document.createElement("script");
637 var script = document.createElement("script");
625 script.onload = resolve;
638 script.onload = resolve;
626 script.onerror = reject;
639 script.onerror = reject;
627 script.src = "%s";
640 script.src = "%s";
628 document.head.appendChild(script);
641 document.head.appendChild(script);
629 }).then(() => {
642 }).then(() => {
630 """
643 """
631
644
632 _lib_t2 = """
645 _lib_t2 = """
633 });"""
646 });"""
634
647
635 class GeoJSON(JSON):
648 class GeoJSON(JSON):
636 """GeoJSON expects JSON-able dict
649 """GeoJSON expects JSON-able dict
637
650
638 not an already-serialized JSON string.
651 not an already-serialized JSON string.
639
652
640 Scalar types (None, number, string) are not allowed, only dict containers.
653 Scalar types (None, number, string) are not allowed, only dict containers.
641 """
654 """
642
655
643 def __init__(self, *args, **kwargs):
656 def __init__(self, *args, **kwargs):
644 """Create a GeoJSON display object given raw data.
657 """Create a GeoJSON display object given raw data.
645
658
646 Parameters
659 Parameters
647 ----------
660 ----------
648 data : dict or list
661 data : dict or list
649 VegaLite data. Not an already-serialized JSON string.
662 VegaLite data. Not an already-serialized JSON string.
650 Scalar types (None, number, string) are not allowed, only dict
663 Scalar types (None, number, string) are not allowed, only dict
651 or list containers.
664 or list containers.
652 url_template : string
665 url_template : string
653 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
666 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
654 layer_options : dict
667 layer_options : dict
655 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
668 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
656 url : unicode
669 url : unicode
657 A URL to download the data from.
670 A URL to download the data from.
658 filename : unicode
671 filename : unicode
659 Path to a local file to load the data from.
672 Path to a local file to load the data from.
660 metadata : dict
673 metadata : dict
661 Specify extra metadata to attach to the json display object.
674 Specify extra metadata to attach to the json display object.
662
675
663 Examples
676 Examples
664 --------
677 --------
665 The following will display an interactive map of Mars with a point of
678 The following will display an interactive map of Mars with a point of
666 interest on frontend that do support GeoJSON display.
679 interest on frontend that do support GeoJSON display.
667
680
668 >>> from IPython.display import GeoJSON
681 >>> from IPython.display import GeoJSON
669
682
670 >>> GeoJSON(data={
683 >>> GeoJSON(data={
671 ... "type": "Feature",
684 ... "type": "Feature",
672 ... "geometry": {
685 ... "geometry": {
673 ... "type": "Point",
686 ... "type": "Point",
674 ... "coordinates": [-81.327, 296.038]
687 ... "coordinates": [-81.327, 296.038]
675 ... }
688 ... }
676 ... },
689 ... },
677 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
690 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
678 ... layer_options={
691 ... layer_options={
679 ... "basemap_id": "celestia_mars-shaded-16k_global",
692 ... "basemap_id": "celestia_mars-shaded-16k_global",
680 ... "attribution" : "Celestia/praesepe",
693 ... "attribution" : "Celestia/praesepe",
681 ... "minZoom" : 0,
694 ... "minZoom" : 0,
682 ... "maxZoom" : 18,
695 ... "maxZoom" : 18,
683 ... })
696 ... })
684 <IPython.core.display.GeoJSON object>
697 <IPython.core.display.GeoJSON object>
685
698
686 In the terminal IPython, you will only see the text representation of
699 In the terminal IPython, you will only see the text representation of
687 the GeoJSON object.
700 the GeoJSON object.
688
701
689 """
702 """
690
703
691 super(GeoJSON, self).__init__(*args, **kwargs)
704 super(GeoJSON, self).__init__(*args, **kwargs)
692
705
693
706
694 def _ipython_display_(self):
707 def _ipython_display_(self):
695 bundle = {
708 bundle = {
696 'application/geo+json': self.data,
709 'application/geo+json': self.data,
697 'text/plain': '<IPython.display.GeoJSON object>'
710 'text/plain': '<IPython.display.GeoJSON object>'
698 }
711 }
699 metadata = {
712 metadata = {
700 'application/geo+json': self.metadata
713 'application/geo+json': self.metadata
701 }
714 }
702 display_functions.display(bundle, metadata=metadata, raw=True)
715 display_functions.display(bundle, metadata=metadata, raw=True)
703
716
704 class Javascript(TextDisplayObject):
717 class Javascript(TextDisplayObject):
705
718
706 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
719 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
707 """Create a Javascript display object given raw data.
720 """Create a Javascript display object given raw data.
708
721
709 When this object is returned by an expression or passed to the
722 When this object is returned by an expression or passed to the
710 display function, it will result in the data being displayed
723 display function, it will result in the data being displayed
711 in the frontend. If the data is a URL, the data will first be
724 in the frontend. If the data is a URL, the data will first be
712 downloaded and then displayed.
725 downloaded and then displayed.
713
726
714 In the Notebook, the containing element will be available as `element`,
727 In the Notebook, the containing element will be available as `element`,
715 and jQuery will be available. Content appended to `element` will be
728 and jQuery will be available. Content appended to `element` will be
716 visible in the output area.
729 visible in the output area.
717
730
718 Parameters
731 Parameters
719 ----------
732 ----------
720 data : unicode, str or bytes
733 data : unicode, str or bytes
721 The Javascript source code or a URL to download it from.
734 The Javascript source code or a URL to download it from.
722 url : unicode
735 url : unicode
723 A URL to download the data from.
736 A URL to download the data from.
724 filename : unicode
737 filename : unicode
725 Path to a local file to load the data from.
738 Path to a local file to load the data from.
726 lib : list or str
739 lib : list or str
727 A sequence of Javascript library URLs to load asynchronously before
740 A sequence of Javascript library URLs to load asynchronously before
728 running the source code. The full URLs of the libraries should
741 running the source code. The full URLs of the libraries should
729 be given. A single Javascript library URL can also be given as a
742 be given. A single Javascript library URL can also be given as a
730 string.
743 string.
731 css : list or str
744 css : list or str
732 A sequence of css files to load before running the source code.
745 A sequence of css files to load before running the source code.
733 The full URLs of the css files should be given. A single css URL
746 The full URLs of the css files should be given. A single css URL
734 can also be given as a string.
747 can also be given as a string.
735 """
748 """
736 if isinstance(lib, str):
749 if isinstance(lib, str):
737 lib = [lib]
750 lib = [lib]
738 elif lib is None:
751 elif lib is None:
739 lib = []
752 lib = []
740 if isinstance(css, str):
753 if isinstance(css, str):
741 css = [css]
754 css = [css]
742 elif css is None:
755 elif css is None:
743 css = []
756 css = []
744 if not isinstance(lib, (list,tuple)):
757 if not isinstance(lib, (list,tuple)):
745 raise TypeError('expected sequence, got: %r' % lib)
758 raise TypeError('expected sequence, got: %r' % lib)
746 if not isinstance(css, (list,tuple)):
759 if not isinstance(css, (list,tuple)):
747 raise TypeError('expected sequence, got: %r' % css)
760 raise TypeError('expected sequence, got: %r' % css)
748 self.lib = lib
761 self.lib = lib
749 self.css = css
762 self.css = css
750 super(Javascript, self).__init__(data=data, url=url, filename=filename)
763 super(Javascript, self).__init__(data=data, url=url, filename=filename)
751
764
752 def _repr_javascript_(self):
765 def _repr_javascript_(self):
753 r = ''
766 r = ''
754 for c in self.css:
767 for c in self.css:
755 r += _css_t % c
768 r += _css_t % c
756 for l in self.lib:
769 for l in self.lib:
757 r += _lib_t1 % l
770 r += _lib_t1 % l
758 r += self.data
771 r += self.data
759 r += _lib_t2*len(self.lib)
772 r += _lib_t2*len(self.lib)
760 return r
773 return r
761
774
762 # constants for identifying png/jpeg data
775 # constants for identifying png/jpeg data
763 _PNG = b'\x89PNG\r\n\x1a\n'
776 _PNG = b'\x89PNG\r\n\x1a\n'
764 _JPEG = b'\xff\xd8'
777 _JPEG = b'\xff\xd8'
765
778
766 def _pngxy(data):
779 def _pngxy(data):
767 """read the (width, height) from a PNG header"""
780 """read the (width, height) from a PNG header"""
768 ihdr = data.index(b'IHDR')
781 ihdr = data.index(b'IHDR')
769 # next 8 bytes are width/height
782 # next 8 bytes are width/height
770 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
783 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
771
784
772 def _jpegxy(data):
785 def _jpegxy(data):
773 """read the (width, height) from a JPEG header"""
786 """read the (width, height) from a JPEG header"""
774 # adapted from http://www.64lines.com/jpeg-width-height
787 # adapted from http://www.64lines.com/jpeg-width-height
775
788
776 idx = 4
789 idx = 4
777 while True:
790 while True:
778 block_size = struct.unpack('>H', data[idx:idx+2])[0]
791 block_size = struct.unpack('>H', data[idx:idx+2])[0]
779 idx = idx + block_size
792 idx = idx + block_size
780 if data[idx:idx+2] == b'\xFF\xC0':
793 if data[idx:idx+2] == b'\xFF\xC0':
781 # found Start of Frame
794 # found Start of Frame
782 iSOF = idx
795 iSOF = idx
783 break
796 break
784 else:
797 else:
785 # read another block
798 # read another block
786 idx += 2
799 idx += 2
787
800
788 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
801 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
789 return w, h
802 return w, h
790
803
791 def _gifxy(data):
804 def _gifxy(data):
792 """read the (width, height) from a GIF header"""
805 """read the (width, height) from a GIF header"""
793 return struct.unpack('<HH', data[6:10])
806 return struct.unpack('<HH', data[6:10])
794
807
795
808
796 class Image(DisplayObject):
809 class Image(DisplayObject):
797
810
798 _read_flags = 'rb'
811 _read_flags = 'rb'
799 _FMT_JPEG = u'jpeg'
812 _FMT_JPEG = u'jpeg'
800 _FMT_PNG = u'png'
813 _FMT_PNG = u'png'
801 _FMT_GIF = u'gif'
814 _FMT_GIF = u'gif'
802 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
815 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
803 _MIMETYPES = {
816 _MIMETYPES = {
804 _FMT_PNG: 'image/png',
817 _FMT_PNG: 'image/png',
805 _FMT_JPEG: 'image/jpeg',
818 _FMT_JPEG: 'image/jpeg',
806 _FMT_GIF: 'image/gif',
819 _FMT_GIF: 'image/gif',
807 }
820 }
808
821
809 def __init__(
822 def __init__(
810 self,
823 self,
811 data=None,
824 data=None,
812 url=None,
825 url=None,
813 filename=None,
826 filename=None,
814 format=None,
827 format=None,
815 embed=None,
828 embed=None,
816 width=None,
829 width=None,
817 height=None,
830 height=None,
818 retina=False,
831 retina=False,
819 unconfined=False,
832 unconfined=False,
820 metadata=None,
833 metadata=None,
821 alt=None,
834 alt=None,
822 ):
835 ):
823 """Create a PNG/JPEG/GIF image object given raw data.
836 """Create a PNG/JPEG/GIF image object given raw data.
824
837
825 When this object is returned by an input cell or passed to the
838 When this object is returned by an input cell or passed to the
826 display function, it will result in the image being displayed
839 display function, it will result in the image being displayed
827 in the frontend.
840 in the frontend.
828
841
829 Parameters
842 Parameters
830 ----------
843 ----------
831 data : unicode, str or bytes
844 data : unicode, str or bytes
832 The raw image data or a URL or filename to load the data from.
845 The raw image data or a URL or filename to load the data from.
833 This always results in embedded image data.
846 This always results in embedded image data.
834
847
835 url : unicode
848 url : unicode
836 A URL to download the data from. If you specify `url=`,
849 A URL to download the data from. If you specify `url=`,
837 the image data will not be embedded unless you also specify `embed=True`.
850 the image data will not be embedded unless you also specify `embed=True`.
838
851
839 filename : unicode
852 filename : unicode
840 Path to a local file to load the data from.
853 Path to a local file to load the data from.
841 Images from a file are always embedded.
854 Images from a file are always embedded.
842
855
843 format : unicode
856 format : unicode
844 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
857 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
845 for format will be inferred from the filename extension.
858 for format will be inferred from the filename extension.
846
859
847 embed : bool
860 embed : bool
848 Should the image data be embedded using a data URI (True) or be
861 Should the image data be embedded using a data URI (True) or be
849 loaded using an <img> tag. Set this to True if you want the image
862 loaded using an <img> tag. Set this to True if you want the image
850 to be viewable later with no internet connection in the notebook.
863 to be viewable later with no internet connection in the notebook.
851
864
852 Default is `True`, unless the keyword argument `url` is set, then
865 Default is `True`, unless the keyword argument `url` is set, then
853 default value is `False`.
866 default value is `False`.
854
867
855 Note that QtConsole is not able to display images if `embed` is set to `False`
868 Note that QtConsole is not able to display images if `embed` is set to `False`
856
869
857 width : int
870 width : int
858 Width in pixels to which to constrain the image in html
871 Width in pixels to which to constrain the image in html
859
872
860 height : int
873 height : int
861 Height in pixels to which to constrain the image in html
874 Height in pixels to which to constrain the image in html
862
875
863 retina : bool
876 retina : bool
864 Automatically set the width and height to half of the measured
877 Automatically set the width and height to half of the measured
865 width and height.
878 width and height.
866 This only works for embedded images because it reads the width/height
879 This only works for embedded images because it reads the width/height
867 from image data.
880 from image data.
868 For non-embedded images, you can just set the desired display width
881 For non-embedded images, you can just set the desired display width
869 and height directly.
882 and height directly.
870
883
871 unconfined : bool
884 unconfined : bool
872 Set unconfined=True to disable max-width confinement of the image.
885 Set unconfined=True to disable max-width confinement of the image.
873
886
874 metadata : dict
887 metadata : dict
875 Specify extra metadata to attach to the image.
888 Specify extra metadata to attach to the image.
876
889
877 alt : unicode
890 alt : unicode
878 Alternative text for the image, for use by screen readers.
891 Alternative text for the image, for use by screen readers.
879
892
880 Examples
893 Examples
881 --------
894 --------
882 embedded image data, works in qtconsole and notebook
895 embedded image data, works in qtconsole and notebook
883 when passed positionally, the first arg can be any of raw image data,
896 when passed positionally, the first arg can be any of raw image data,
884 a URL, or a filename from which to load image data.
897 a URL, or a filename from which to load image data.
885 The result is always embedding image data for inline images.
898 The result is always embedding image data for inline images.
886
899
887 >>> Image('https://www.google.fr/images/srpr/logo3w.png') # doctest: +SKIP
900 >>> Image('https://www.google.fr/images/srpr/logo3w.png') # doctest: +SKIP
888 <IPython.core.display.Image object>
901 <IPython.core.display.Image object>
889
902
890 >>> Image('/path/to/image.jpg')
903 >>> Image('/path/to/image.jpg')
891 <IPython.core.display.Image object>
904 <IPython.core.display.Image object>
892
905
893 >>> Image(b'RAW_PNG_DATA...')
906 >>> Image(b'RAW_PNG_DATA...')
894 <IPython.core.display.Image object>
907 <IPython.core.display.Image object>
895
908
896 Specifying Image(url=...) does not embed the image data,
909 Specifying Image(url=...) does not embed the image data,
897 it only generates ``<img>`` tag with a link to the source.
910 it only generates ``<img>`` tag with a link to the source.
898 This will not work in the qtconsole or offline.
911 This will not work in the qtconsole or offline.
899
912
900 >>> Image(url='https://www.google.fr/images/srpr/logo3w.png')
913 >>> Image(url='https://www.google.fr/images/srpr/logo3w.png')
901 <IPython.core.display.Image object>
914 <IPython.core.display.Image object>
902
915
903 """
916 """
904 if isinstance(data, (Path, PurePath)):
917 if isinstance(data, (Path, PurePath)):
905 data = str(data)
918 data = str(data)
906
919
907 if filename is not None:
920 if filename is not None:
908 ext = self._find_ext(filename)
921 ext = self._find_ext(filename)
909 elif url is not None:
922 elif url is not None:
910 ext = self._find_ext(url)
923 ext = self._find_ext(url)
911 elif data is None:
924 elif data is None:
912 raise ValueError("No image data found. Expecting filename, url, or data.")
925 raise ValueError("No image data found. Expecting filename, url, or data.")
913 elif isinstance(data, str) and (
926 elif isinstance(data, str) and (
914 data.startswith('http') or _safe_exists(data)
927 data.startswith('http') or _safe_exists(data)
915 ):
928 ):
916 ext = self._find_ext(data)
929 ext = self._find_ext(data)
917 else:
930 else:
918 ext = None
931 ext = None
919
932
920 if format is None:
933 if format is None:
921 if ext is not None:
934 if ext is not None:
922 if ext == u'jpg' or ext == u'jpeg':
935 if ext == u'jpg' or ext == u'jpeg':
923 format = self._FMT_JPEG
936 format = self._FMT_JPEG
924 elif ext == u'png':
937 elif ext == u'png':
925 format = self._FMT_PNG
938 format = self._FMT_PNG
926 elif ext == u'gif':
939 elif ext == u'gif':
927 format = self._FMT_GIF
940 format = self._FMT_GIF
928 else:
941 else:
929 format = ext.lower()
942 format = ext.lower()
930 elif isinstance(data, bytes):
943 elif isinstance(data, bytes):
931 # infer image type from image data header,
944 # infer image type from image data header,
932 # only if format has not been specified.
945 # only if format has not been specified.
933 if data[:2] == _JPEG:
946 if data[:2] == _JPEG:
934 format = self._FMT_JPEG
947 format = self._FMT_JPEG
935
948
936 # failed to detect format, default png
949 # failed to detect format, default png
937 if format is None:
950 if format is None:
938 format = self._FMT_PNG
951 format = self._FMT_PNG
939
952
940 if format.lower() == 'jpg':
953 if format.lower() == 'jpg':
941 # jpg->jpeg
954 # jpg->jpeg
942 format = self._FMT_JPEG
955 format = self._FMT_JPEG
943
956
944 self.format = format.lower()
957 self.format = format.lower()
945 self.embed = embed if embed is not None else (url is None)
958 self.embed = embed if embed is not None else (url is None)
946
959
947 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
960 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
948 raise ValueError("Cannot embed the '%s' image format" % (self.format))
961 raise ValueError("Cannot embed the '%s' image format" % (self.format))
949 if self.embed:
962 if self.embed:
950 self._mimetype = self._MIMETYPES.get(self.format)
963 self._mimetype = self._MIMETYPES.get(self.format)
951
964
952 self.width = width
965 self.width = width
953 self.height = height
966 self.height = height
954 self.retina = retina
967 self.retina = retina
955 self.unconfined = unconfined
968 self.unconfined = unconfined
956 self.alt = alt
969 self.alt = alt
957 super(Image, self).__init__(data=data, url=url, filename=filename,
970 super(Image, self).__init__(data=data, url=url, filename=filename,
958 metadata=metadata)
971 metadata=metadata)
959
972
960 if self.width is None and self.metadata.get('width', {}):
973 if self.width is None and self.metadata.get('width', {}):
961 self.width = metadata['width']
974 self.width = metadata['width']
962
975
963 if self.height is None and self.metadata.get('height', {}):
976 if self.height is None and self.metadata.get('height', {}):
964 self.height = metadata['height']
977 self.height = metadata['height']
965
978
966 if self.alt is None and self.metadata.get("alt", {}):
979 if self.alt is None and self.metadata.get("alt", {}):
967 self.alt = metadata["alt"]
980 self.alt = metadata["alt"]
968
981
969 if retina:
982 if retina:
970 self._retina_shape()
983 self._retina_shape()
971
984
972
985
973 def _retina_shape(self):
986 def _retina_shape(self):
974 """load pixel-doubled width and height from image data"""
987 """load pixel-doubled width and height from image data"""
975 if not self.embed:
988 if not self.embed:
976 return
989 return
977 if self.format == self._FMT_PNG:
990 if self.format == self._FMT_PNG:
978 w, h = _pngxy(self.data)
991 w, h = _pngxy(self.data)
979 elif self.format == self._FMT_JPEG:
992 elif self.format == self._FMT_JPEG:
980 w, h = _jpegxy(self.data)
993 w, h = _jpegxy(self.data)
981 elif self.format == self._FMT_GIF:
994 elif self.format == self._FMT_GIF:
982 w, h = _gifxy(self.data)
995 w, h = _gifxy(self.data)
983 else:
996 else:
984 # retina only supports png
997 # retina only supports png
985 return
998 return
986 self.width = w // 2
999 self.width = w // 2
987 self.height = h // 2
1000 self.height = h // 2
988
1001
989 def reload(self):
1002 def reload(self):
990 """Reload the raw data from file or URL."""
1003 """Reload the raw data from file or URL."""
991 if self.embed:
1004 if self.embed:
992 super(Image,self).reload()
1005 super(Image,self).reload()
993 if self.retina:
1006 if self.retina:
994 self._retina_shape()
1007 self._retina_shape()
995
1008
996 def _repr_html_(self):
1009 def _repr_html_(self):
997 if not self.embed:
1010 if not self.embed:
998 width = height = klass = alt = ""
1011 width = height = klass = alt = ""
999 if self.width:
1012 if self.width:
1000 width = ' width="%d"' % self.width
1013 width = ' width="%d"' % self.width
1001 if self.height:
1014 if self.height:
1002 height = ' height="%d"' % self.height
1015 height = ' height="%d"' % self.height
1003 if self.unconfined:
1016 if self.unconfined:
1004 klass = ' class="unconfined"'
1017 klass = ' class="unconfined"'
1005 if self.alt:
1018 if self.alt:
1006 alt = ' alt="%s"' % html.escape(self.alt)
1019 alt = ' alt="%s"' % html.escape(self.alt)
1007 return '<img src="{url}"{width}{height}{klass}{alt}/>'.format(
1020 return '<img src="{url}"{width}{height}{klass}{alt}/>'.format(
1008 url=self.url,
1021 url=self.url,
1009 width=width,
1022 width=width,
1010 height=height,
1023 height=height,
1011 klass=klass,
1024 klass=klass,
1012 alt=alt,
1025 alt=alt,
1013 )
1026 )
1014
1027
1015 def _repr_mimebundle_(self, include=None, exclude=None):
1028 def _repr_mimebundle_(self, include=None, exclude=None):
1016 """Return the image as a mimebundle
1029 """Return the image as a mimebundle
1017
1030
1018 Any new mimetype support should be implemented here.
1031 Any new mimetype support should be implemented here.
1019 """
1032 """
1020 if self.embed:
1033 if self.embed:
1021 mimetype = self._mimetype
1034 mimetype = self._mimetype
1022 data, metadata = self._data_and_metadata(always_both=True)
1035 data, metadata = self._data_and_metadata(always_both=True)
1023 if metadata:
1036 if metadata:
1024 metadata = {mimetype: metadata}
1037 metadata = {mimetype: metadata}
1025 return {mimetype: data}, metadata
1038 return {mimetype: data}, metadata
1026 else:
1039 else:
1027 return {'text/html': self._repr_html_()}
1040 return {'text/html': self._repr_html_()}
1028
1041
1029 def _data_and_metadata(self, always_both=False):
1042 def _data_and_metadata(self, always_both=False):
1030 """shortcut for returning metadata with shape information, if defined"""
1043 """shortcut for returning metadata with shape information, if defined"""
1031 try:
1044 try:
1032 b64_data = b2a_base64(self.data).decode('ascii')
1045 b64_data = b2a_base64(self.data).decode('ascii')
1033 except TypeError as e:
1046 except TypeError as e:
1034 raise FileNotFoundError(
1047 raise FileNotFoundError(
1035 "No such file or directory: '%s'" % (self.data)) from e
1048 "No such file or directory: '%s'" % (self.data)) from e
1036 md = {}
1049 md = {}
1037 if self.metadata:
1050 if self.metadata:
1038 md.update(self.metadata)
1051 md.update(self.metadata)
1039 if self.width:
1052 if self.width:
1040 md['width'] = self.width
1053 md['width'] = self.width
1041 if self.height:
1054 if self.height:
1042 md['height'] = self.height
1055 md['height'] = self.height
1043 if self.unconfined:
1056 if self.unconfined:
1044 md['unconfined'] = self.unconfined
1057 md['unconfined'] = self.unconfined
1045 if self.alt:
1058 if self.alt:
1046 md["alt"] = self.alt
1059 md["alt"] = self.alt
1047 if md or always_both:
1060 if md or always_both:
1048 return b64_data, md
1061 return b64_data, md
1049 else:
1062 else:
1050 return b64_data
1063 return b64_data
1051
1064
1052 def _repr_png_(self):
1065 def _repr_png_(self):
1053 if self.embed and self.format == self._FMT_PNG:
1066 if self.embed and self.format == self._FMT_PNG:
1054 return self._data_and_metadata()
1067 return self._data_and_metadata()
1055
1068
1056 def _repr_jpeg_(self):
1069 def _repr_jpeg_(self):
1057 if self.embed and self.format == self._FMT_JPEG:
1070 if self.embed and self.format == self._FMT_JPEG:
1058 return self._data_and_metadata()
1071 return self._data_and_metadata()
1059
1072
1060 def _find_ext(self, s):
1073 def _find_ext(self, s):
1061 base, ext = splitext(s)
1074 base, ext = splitext(s)
1062
1075
1063 if not ext:
1076 if not ext:
1064 return base
1077 return base
1065
1078
1066 # `splitext` includes leading period, so we skip it
1079 # `splitext` includes leading period, so we skip it
1067 return ext[1:].lower()
1080 return ext[1:].lower()
1068
1081
1069
1082
1070 class Video(DisplayObject):
1083 class Video(DisplayObject):
1071
1084
1072 def __init__(self, data=None, url=None, filename=None, embed=False,
1085 def __init__(self, data=None, url=None, filename=None, embed=False,
1073 mimetype=None, width=None, height=None, html_attributes="controls"):
1086 mimetype=None, width=None, height=None, html_attributes="controls"):
1074 """Create a video object given raw data or an URL.
1087 """Create a video object given raw data or an URL.
1075
1088
1076 When this object is returned by an input cell or passed to the
1089 When this object is returned by an input cell or passed to the
1077 display function, it will result in the video being displayed
1090 display function, it will result in the video being displayed
1078 in the frontend.
1091 in the frontend.
1079
1092
1080 Parameters
1093 Parameters
1081 ----------
1094 ----------
1082 data : unicode, str or bytes
1095 data : unicode, str or bytes
1083 The raw video data or a URL or filename to load the data from.
1096 The raw video data or a URL or filename to load the data from.
1084 Raw data will require passing ``embed=True``.
1097 Raw data will require passing ``embed=True``.
1085
1098
1086 url : unicode
1099 url : unicode
1087 A URL for the video. If you specify ``url=``,
1100 A URL for the video. If you specify ``url=``,
1088 the image data will not be embedded.
1101 the image data will not be embedded.
1089
1102
1090 filename : unicode
1103 filename : unicode
1091 Path to a local file containing the video.
1104 Path to a local file containing the video.
1092 Will be interpreted as a local URL unless ``embed=True``.
1105 Will be interpreted as a local URL unless ``embed=True``.
1093
1106
1094 embed : bool
1107 embed : bool
1095 Should the video be embedded using a data URI (True) or be
1108 Should the video be embedded using a data URI (True) or be
1096 loaded using a <video> tag (False).
1109 loaded using a <video> tag (False).
1097
1110
1098 Since videos are large, embedding them should be avoided, if possible.
1111 Since videos are large, embedding them should be avoided, if possible.
1099 You must confirm embedding as your intention by passing ``embed=True``.
1112 You must confirm embedding as your intention by passing ``embed=True``.
1100
1113
1101 Local files can be displayed with URLs without embedding the content, via::
1114 Local files can be displayed with URLs without embedding the content, via::
1102
1115
1103 Video('./video.mp4')
1116 Video('./video.mp4')
1104
1117
1105 mimetype : unicode
1118 mimetype : unicode
1106 Specify the mimetype for embedded videos.
1119 Specify the mimetype for embedded videos.
1107 Default will be guessed from file extension, if available.
1120 Default will be guessed from file extension, if available.
1108
1121
1109 width : int
1122 width : int
1110 Width in pixels to which to constrain the video in HTML.
1123 Width in pixels to which to constrain the video in HTML.
1111 If not supplied, defaults to the width of the video.
1124 If not supplied, defaults to the width of the video.
1112
1125
1113 height : int
1126 height : int
1114 Height in pixels to which to constrain the video in html.
1127 Height in pixels to which to constrain the video in html.
1115 If not supplied, defaults to the height of the video.
1128 If not supplied, defaults to the height of the video.
1116
1129
1117 html_attributes : str
1130 html_attributes : str
1118 Attributes for the HTML ``<video>`` block.
1131 Attributes for the HTML ``<video>`` block.
1119 Default: ``"controls"`` to get video controls.
1132 Default: ``"controls"`` to get video controls.
1120 Other examples: ``"controls muted"`` for muted video with controls,
1133 Other examples: ``"controls muted"`` for muted video with controls,
1121 ``"loop autoplay"`` for looping autoplaying video without controls.
1134 ``"loop autoplay"`` for looping autoplaying video without controls.
1122
1135
1123 Examples
1136 Examples
1124 --------
1137 --------
1125 ::
1138 ::
1126
1139
1127 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1140 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1128 Video('path/to/video.mp4')
1141 Video('path/to/video.mp4')
1129 Video('path/to/video.mp4', embed=True)
1142 Video('path/to/video.mp4', embed=True)
1130 Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
1143 Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
1131 Video(b'raw-videodata', embed=True)
1144 Video(b'raw-videodata', embed=True)
1132 """
1145 """
1133 if isinstance(data, (Path, PurePath)):
1146 if isinstance(data, (Path, PurePath)):
1134 data = str(data)
1147 data = str(data)
1135
1148
1136 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1149 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1137 url = data
1150 url = data
1138 data = None
1151 data = None
1139 elif data is not None and os.path.exists(data):
1152 elif data is not None and os.path.exists(data):
1140 filename = data
1153 filename = data
1141 data = None
1154 data = None
1142
1155
1143 if data and not embed:
1156 if data and not embed:
1144 msg = ''.join([
1157 msg = ''.join([
1145 "To embed videos, you must pass embed=True ",
1158 "To embed videos, you must pass embed=True ",
1146 "(this may make your notebook files huge)\n",
1159 "(this may make your notebook files huge)\n",
1147 "Consider passing Video(url='...')",
1160 "Consider passing Video(url='...')",
1148 ])
1161 ])
1149 raise ValueError(msg)
1162 raise ValueError(msg)
1150
1163
1151 self.mimetype = mimetype
1164 self.mimetype = mimetype
1152 self.embed = embed
1165 self.embed = embed
1153 self.width = width
1166 self.width = width
1154 self.height = height
1167 self.height = height
1155 self.html_attributes = html_attributes
1168 self.html_attributes = html_attributes
1156 super(Video, self).__init__(data=data, url=url, filename=filename)
1169 super(Video, self).__init__(data=data, url=url, filename=filename)
1157
1170
1158 def _repr_html_(self):
1171 def _repr_html_(self):
1159 width = height = ''
1172 width = height = ''
1160 if self.width:
1173 if self.width:
1161 width = ' width="%d"' % self.width
1174 width = ' width="%d"' % self.width
1162 if self.height:
1175 if self.height:
1163 height = ' height="%d"' % self.height
1176 height = ' height="%d"' % self.height
1164
1177
1165 # External URLs and potentially local files are not embedded into the
1178 # External URLs and potentially local files are not embedded into the
1166 # notebook output.
1179 # notebook output.
1167 if not self.embed:
1180 if not self.embed:
1168 url = self.url if self.url is not None else self.filename
1181 url = self.url if self.url is not None else self.filename
1169 output = """<video src="{0}" {1} {2} {3}>
1182 output = """<video src="{0}" {1} {2} {3}>
1170 Your browser does not support the <code>video</code> element.
1183 Your browser does not support the <code>video</code> element.
1171 </video>""".format(url, self.html_attributes, width, height)
1184 </video>""".format(url, self.html_attributes, width, height)
1172 return output
1185 return output
1173
1186
1174 # Embedded videos are base64-encoded.
1187 # Embedded videos are base64-encoded.
1175 mimetype = self.mimetype
1188 mimetype = self.mimetype
1176 if self.filename is not None:
1189 if self.filename is not None:
1177 if not mimetype:
1190 if not mimetype:
1178 mimetype, _ = mimetypes.guess_type(self.filename)
1191 mimetype, _ = mimetypes.guess_type(self.filename)
1179
1192
1180 with open(self.filename, 'rb') as f:
1193 with open(self.filename, 'rb') as f:
1181 video = f.read()
1194 video = f.read()
1182 else:
1195 else:
1183 video = self.data
1196 video = self.data
1184 if isinstance(video, str):
1197 if isinstance(video, str):
1185 # unicode input is already b64-encoded
1198 # unicode input is already b64-encoded
1186 b64_video = video
1199 b64_video = video
1187 else:
1200 else:
1188 b64_video = b2a_base64(video).decode('ascii').rstrip()
1201 b64_video = b2a_base64(video).decode('ascii').rstrip()
1189
1202
1190 output = """<video {0} {1} {2}>
1203 output = """<video {0} {1} {2}>
1191 <source src="data:{3};base64,{4}" type="{3}">
1204 <source src="data:{3};base64,{4}" type="{3}">
1192 Your browser does not support the video tag.
1205 Your browser does not support the video tag.
1193 </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
1206 </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
1194 return output
1207 return output
1195
1208
1196 def reload(self):
1209 def reload(self):
1197 # TODO
1210 # TODO
1198 pass
1211 pass
1199
1212
1200
1213
1201 @skip_doctest
1214 @skip_doctest
1202 def set_matplotlib_formats(*formats, **kwargs):
1215 def set_matplotlib_formats(*formats, **kwargs):
1203 """
1216 """
1204 .. deprecated:: 7.23
1217 .. deprecated:: 7.23
1205
1218
1206 use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
1219 use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
1207
1220
1208 Select figure formats for the inline backend. Optionally pass quality for JPEG.
1221 Select figure formats for the inline backend. Optionally pass quality for JPEG.
1209
1222
1210 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1223 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1211
1224
1212 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1225 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1213
1226
1214 To set this in your config files use the following::
1227 To set this in your config files use the following::
1215
1228
1216 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1229 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1217 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1230 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1218
1231
1219 Parameters
1232 Parameters
1220 ----------
1233 ----------
1221 *formats : strs
1234 *formats : strs
1222 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1235 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1223 **kwargs
1236 **kwargs
1224 Keyword args will be relayed to ``figure.canvas.print_figure``.
1237 Keyword args will be relayed to ``figure.canvas.print_figure``.
1225 """
1238 """
1226 warnings.warn(
1239 warnings.warn(
1227 "`set_matplotlib_formats` is deprecated since IPython 7.23, directly "
1240 "`set_matplotlib_formats` is deprecated since IPython 7.23, directly "
1228 "use `matplotlib_inline.backend_inline.set_matplotlib_formats()`",
1241 "use `matplotlib_inline.backend_inline.set_matplotlib_formats()`",
1229 DeprecationWarning,
1242 DeprecationWarning,
1230 stacklevel=2,
1243 stacklevel=2,
1231 )
1244 )
1232
1245
1233 from matplotlib_inline.backend_inline import (
1246 from matplotlib_inline.backend_inline import (
1234 set_matplotlib_formats as set_matplotlib_formats_orig,
1247 set_matplotlib_formats as set_matplotlib_formats_orig,
1235 )
1248 )
1236
1249
1237 set_matplotlib_formats_orig(*formats, **kwargs)
1250 set_matplotlib_formats_orig(*formats, **kwargs)
1238
1251
1239 @skip_doctest
1252 @skip_doctest
1240 def set_matplotlib_close(close=True):
1253 def set_matplotlib_close(close=True):
1241 """
1254 """
1242 .. deprecated:: 7.23
1255 .. deprecated:: 7.23
1243
1256
1244 use `matplotlib_inline.backend_inline.set_matplotlib_close()`
1257 use `matplotlib_inline.backend_inline.set_matplotlib_close()`
1245
1258
1246 Set whether the inline backend closes all figures automatically or not.
1259 Set whether the inline backend closes all figures automatically or not.
1247
1260
1248 By default, the inline backend used in the IPython Notebook will close all
1261 By default, the inline backend used in the IPython Notebook will close all
1249 matplotlib figures automatically after each cell is run. This means that
1262 matplotlib figures automatically after each cell is run. This means that
1250 plots in different cells won't interfere. Sometimes, you may want to make
1263 plots in different cells won't interfere. Sometimes, you may want to make
1251 a plot in one cell and then refine it in later cells. This can be accomplished
1264 a plot in one cell and then refine it in later cells. This can be accomplished
1252 by::
1265 by::
1253
1266
1254 In [1]: set_matplotlib_close(False)
1267 In [1]: set_matplotlib_close(False)
1255
1268
1256 To set this in your config files use the following::
1269 To set this in your config files use the following::
1257
1270
1258 c.InlineBackend.close_figures = False
1271 c.InlineBackend.close_figures = False
1259
1272
1260 Parameters
1273 Parameters
1261 ----------
1274 ----------
1262 close : bool
1275 close : bool
1263 Should all matplotlib figures be automatically closed after each cell is
1276 Should all matplotlib figures be automatically closed after each cell is
1264 run?
1277 run?
1265 """
1278 """
1266 warnings.warn(
1279 warnings.warn(
1267 "`set_matplotlib_close` is deprecated since IPython 7.23, directly "
1280 "`set_matplotlib_close` is deprecated since IPython 7.23, directly "
1268 "use `matplotlib_inline.backend_inline.set_matplotlib_close()`",
1281 "use `matplotlib_inline.backend_inline.set_matplotlib_close()`",
1269 DeprecationWarning,
1282 DeprecationWarning,
1270 stacklevel=2,
1283 stacklevel=2,
1271 )
1284 )
1272
1285
1273 from matplotlib_inline.backend_inline import (
1286 from matplotlib_inline.backend_inline import (
1274 set_matplotlib_close as set_matplotlib_close_orig,
1287 set_matplotlib_close as set_matplotlib_close_orig,
1275 )
1288 )
1276
1289
1277 set_matplotlib_close_orig(close)
1290 set_matplotlib_close_orig(close)
@@ -1,167 +1,151 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A class for managing IPython extensions."""
2 """A class for managing IPython extensions."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 import os.path
8 import os.path
9 import sys
9 import sys
10 from importlib import import_module, reload
10 from importlib import import_module, reload
11
11
12 from traitlets.config.configurable import Configurable
12 from traitlets.config.configurable import Configurable
13 from IPython.utils.path import ensure_dir_exists, compress_user
13 from IPython.utils.path import ensure_dir_exists, compress_user
14 from IPython.utils.decorators import undoc
14 from IPython.utils.decorators import undoc
15 from traitlets import Instance
15 from traitlets import Instance
16
16
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Main class
19 # Main class
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 BUILTINS_EXTS = {"storemagic": False, "autoreload": False}
22 BUILTINS_EXTS = {"storemagic": False, "autoreload": False}
23
23
24
24
25 class ExtensionManager(Configurable):
25 class ExtensionManager(Configurable):
26 """A class to manage IPython extensions.
26 """A class to manage IPython extensions.
27
27
28 An IPython extension is an importable Python module that has
28 An IPython extension is an importable Python module that has
29 a function with the signature::
29 a function with the signature::
30
30
31 def load_ipython_extension(ipython):
31 def load_ipython_extension(ipython):
32 # Do things with ipython
32 # Do things with ipython
33
33
34 This function is called after your extension is imported and the
34 This function is called after your extension is imported and the
35 currently active :class:`InteractiveShell` instance is passed as
35 currently active :class:`InteractiveShell` instance is passed as
36 the only argument. You can do anything you want with IPython at
36 the only argument. You can do anything you want with IPython at
37 that point, including defining new magic and aliases, adding new
37 that point, including defining new magic and aliases, adding new
38 components, etc.
38 components, etc.
39
39
40 You can also optionally define an :func:`unload_ipython_extension(ipython)`
40 You can also optionally define an :func:`unload_ipython_extension(ipython)`
41 function, which will be called if the user unloads or reloads the extension.
41 function, which will be called if the user unloads or reloads the extension.
42 The extension manager will only call :func:`load_ipython_extension` again
42 The extension manager will only call :func:`load_ipython_extension` again
43 if the extension is reloaded.
43 if the extension is reloaded.
44
44
45 You can put your extension modules anywhere you want, as long as
45 You can put your extension modules anywhere you want, as long as
46 they can be imported by Python's standard import mechanism. However,
46 they can be imported by Python's standard import mechanism. However,
47 to make it easy to write extensions, you can also put your extensions
47 to make it easy to write extensions, you can also put your extensions
48 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
48 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
49 is added to ``sys.path`` automatically.
49 is added to ``sys.path`` automatically.
50 """
50 """
51
51
52 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
52 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
53
53
54 def __init__(self, shell=None, **kwargs):
54 def __init__(self, shell=None, **kwargs):
55 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
55 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
56 self.shell.observe(
56 self.shell.observe(
57 self._on_ipython_dir_changed, names=('ipython_dir',)
57 self._on_ipython_dir_changed, names=('ipython_dir',)
58 )
58 )
59 self.loaded = set()
59 self.loaded = set()
60
60
61 @property
61 @property
62 def ipython_extension_dir(self):
62 def ipython_extension_dir(self):
63 return os.path.join(self.shell.ipython_dir, u'extensions')
63 return os.path.join(self.shell.ipython_dir, u'extensions')
64
64
65 def _on_ipython_dir_changed(self, change):
65 def _on_ipython_dir_changed(self, change):
66 ensure_dir_exists(self.ipython_extension_dir)
66 ensure_dir_exists(self.ipython_extension_dir)
67
67
68 def load_extension(self, module_str: str):
68 def load_extension(self, module_str: str):
69 """Load an IPython extension by its module name.
69 """Load an IPython extension by its module name.
70
70
71 Returns the string "already loaded" if the extension is already loaded,
71 Returns the string "already loaded" if the extension is already loaded,
72 "no load function" if the module doesn't have a load_ipython_extension
72 "no load function" if the module doesn't have a load_ipython_extension
73 function, or None if it succeeded.
73 function, or None if it succeeded.
74 """
74 """
75 try:
75 try:
76 return self._load_extension(module_str)
76 return self._load_extension(module_str)
77 except ModuleNotFoundError:
77 except ModuleNotFoundError:
78 if module_str in BUILTINS_EXTS:
78 if module_str in BUILTINS_EXTS:
79 BUILTINS_EXTS[module_str] = True
79 BUILTINS_EXTS[module_str] = True
80 return self._load_extension("IPython.extensions." + module_str)
80 return self._load_extension("IPython.extensions." + module_str)
81 raise
81 raise
82
82
83 def _load_extension(self, module_str: str):
83 def _load_extension(self, module_str: str):
84 if module_str in self.loaded:
84 if module_str in self.loaded:
85 return "already loaded"
85 return "already loaded"
86
86
87 from IPython.utils.syspathcontext import prepended_to_syspath
87 from IPython.utils.syspathcontext import prepended_to_syspath
88
88
89 with self.shell.builtin_trap:
89 with self.shell.builtin_trap:
90 if module_str not in sys.modules:
90 if module_str not in sys.modules:
91 with prepended_to_syspath(self.ipython_extension_dir):
91 mod = import_module(module_str)
92 mod = import_module(module_str)
93 if mod.__file__.startswith(self.ipython_extension_dir):
94 print(("Loading extensions from {dir} is deprecated. "
95 "We recommend managing extensions like any "
96 "other Python packages, in site-packages.").format(
97 dir=compress_user(self.ipython_extension_dir)))
98 mod = sys.modules[module_str]
92 mod = sys.modules[module_str]
99 if self._call_load_ipython_extension(mod):
93 if self._call_load_ipython_extension(mod):
100 self.loaded.add(module_str)
94 self.loaded.add(module_str)
101 else:
95 else:
102 return "no load function"
96 return "no load function"
103
97
104 def unload_extension(self, module_str: str):
98 def unload_extension(self, module_str: str):
105 """Unload an IPython extension by its module name.
99 """Unload an IPython extension by its module name.
106
100
107 This function looks up the extension's name in ``sys.modules`` and
101 This function looks up the extension's name in ``sys.modules`` and
108 simply calls ``mod.unload_ipython_extension(self)``.
102 simply calls ``mod.unload_ipython_extension(self)``.
109
103
110 Returns the string "no unload function" if the extension doesn't define
104 Returns the string "no unload function" if the extension doesn't define
111 a function to unload itself, "not loaded" if the extension isn't loaded,
105 a function to unload itself, "not loaded" if the extension isn't loaded,
112 otherwise None.
106 otherwise None.
113 """
107 """
114 if BUILTINS_EXTS.get(module_str, False) is True:
108 if BUILTINS_EXTS.get(module_str, False) is True:
115 module_str = "IPython.extensions." + module_str
109 module_str = "IPython.extensions." + module_str
116 if module_str not in self.loaded:
110 if module_str not in self.loaded:
117 return "not loaded"
111 return "not loaded"
118
112
119 if module_str in sys.modules:
113 if module_str in sys.modules:
120 mod = sys.modules[module_str]
114 mod = sys.modules[module_str]
121 if self._call_unload_ipython_extension(mod):
115 if self._call_unload_ipython_extension(mod):
122 self.loaded.discard(module_str)
116 self.loaded.discard(module_str)
123 else:
117 else:
124 return "no unload function"
118 return "no unload function"
125
119
126 def reload_extension(self, module_str: str):
120 def reload_extension(self, module_str: str):
127 """Reload an IPython extension by calling reload.
121 """Reload an IPython extension by calling reload.
128
122
129 If the module has not been loaded before,
123 If the module has not been loaded before,
130 :meth:`InteractiveShell.load_extension` is called. Otherwise
124 :meth:`InteractiveShell.load_extension` is called. Otherwise
131 :func:`reload` is called and then the :func:`load_ipython_extension`
125 :func:`reload` is called and then the :func:`load_ipython_extension`
132 function of the module, if it exists is called.
126 function of the module, if it exists is called.
133 """
127 """
134 from IPython.utils.syspathcontext import prepended_to_syspath
128 from IPython.utils.syspathcontext import prepended_to_syspath
135
129
136 if BUILTINS_EXTS.get(module_str, False) is True:
130 if BUILTINS_EXTS.get(module_str, False) is True:
137 module_str = "IPython.extensions." + module_str
131 module_str = "IPython.extensions." + module_str
138
132
139 if (module_str in self.loaded) and (module_str in sys.modules):
133 if (module_str in self.loaded) and (module_str in sys.modules):
140 self.unload_extension(module_str)
134 self.unload_extension(module_str)
141 mod = sys.modules[module_str]
135 mod = sys.modules[module_str]
142 with prepended_to_syspath(self.ipython_extension_dir):
136 with prepended_to_syspath(self.ipython_extension_dir):
143 reload(mod)
137 reload(mod)
144 if self._call_load_ipython_extension(mod):
138 if self._call_load_ipython_extension(mod):
145 self.loaded.add(module_str)
139 self.loaded.add(module_str)
146 else:
140 else:
147 self.load_extension(module_str)
141 self.load_extension(module_str)
148
142
149 def _call_load_ipython_extension(self, mod):
143 def _call_load_ipython_extension(self, mod):
150 if hasattr(mod, 'load_ipython_extension'):
144 if hasattr(mod, 'load_ipython_extension'):
151 mod.load_ipython_extension(self.shell)
145 mod.load_ipython_extension(self.shell)
152 return True
146 return True
153
147
154 def _call_unload_ipython_extension(self, mod):
148 def _call_unload_ipython_extension(self, mod):
155 if hasattr(mod, 'unload_ipython_extension'):
149 if hasattr(mod, 'unload_ipython_extension'):
156 mod.unload_ipython_extension(self.shell)
150 mod.unload_ipython_extension(self.shell)
157 return True
151 return True
158
159 @undoc
160 def install_extension(self, url, filename=None):
161 """
162 Deprecated.
163 """
164 # Ensure the extension directory exists
165 raise DeprecationWarning(
166 '`install_extension` and the `install_ext` magic have been deprecated since IPython 4.0'
167 'Use pip or other package managers to manage ipython extensions.')
@@ -1,787 +1,797 b''
1 """Input transformer machinery to support IPython special syntax.
1 """Input transformer machinery to support IPython special syntax.
2
2
3 This includes the machinery to recognise and transform ``%magic`` commands,
3 This includes the machinery to recognise and transform ``%magic`` commands,
4 ``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
4 ``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
5
5
6 Added: IPython 7.0. Replaces inputsplitter and inputtransformer which were
6 Added: IPython 7.0. Replaces inputsplitter and inputtransformer which were
7 deprecated in 7.0.
7 deprecated in 7.0.
8 """
8 """
9
9
10 # Copyright (c) IPython Development Team.
10 # Copyright (c) IPython Development Team.
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12
12
13 import ast
13 import ast
14 from codeop import CommandCompiler, Compile
14 from codeop import CommandCompiler, Compile
15 import re
15 import re
16 import tokenize
16 import tokenize
17 from typing import List, Tuple, Optional, Any
17 from typing import List, Tuple, Optional, Any
18 import warnings
18 import warnings
19
19
20 _indent_re = re.compile(r'^[ \t]+')
20 _indent_re = re.compile(r'^[ \t]+')
21
21
22 def leading_empty_lines(lines):
22 def leading_empty_lines(lines):
23 """Remove leading empty lines
23 """Remove leading empty lines
24
24
25 If the leading lines are empty or contain only whitespace, they will be
25 If the leading lines are empty or contain only whitespace, they will be
26 removed.
26 removed.
27 """
27 """
28 if not lines:
28 if not lines:
29 return lines
29 return lines
30 for i, line in enumerate(lines):
30 for i, line in enumerate(lines):
31 if line and not line.isspace():
31 if line and not line.isspace():
32 return lines[i:]
32 return lines[i:]
33 return lines
33 return lines
34
34
35 def leading_indent(lines):
35 def leading_indent(lines):
36 """Remove leading indentation.
36 """Remove leading indentation.
37
37
38 If the first line starts with a spaces or tabs, the same whitespace will be
38 If the first line starts with a spaces or tabs, the same whitespace will be
39 removed from each following line in the cell.
39 removed from each following line in the cell.
40 """
40 """
41 if not lines:
41 if not lines:
42 return lines
42 return lines
43 m = _indent_re.match(lines[0])
43 m = _indent_re.match(lines[0])
44 if not m:
44 if not m:
45 return lines
45 return lines
46 space = m.group(0)
46 space = m.group(0)
47 n = len(space)
47 n = len(space)
48 return [l[n:] if l.startswith(space) else l
48 return [l[n:] if l.startswith(space) else l
49 for l in lines]
49 for l in lines]
50
50
51 class PromptStripper:
51 class PromptStripper:
52 """Remove matching input prompts from a block of input.
52 """Remove matching input prompts from a block of input.
53
53
54 Parameters
54 Parameters
55 ----------
55 ----------
56 prompt_re : regular expression
56 prompt_re : regular expression
57 A regular expression matching any input prompt (including continuation,
57 A regular expression matching any input prompt (including continuation,
58 e.g. ``...``)
58 e.g. ``...``)
59 initial_re : regular expression, optional
59 initial_re : regular expression, optional
60 A regular expression matching only the initial prompt, but not continuation.
60 A regular expression matching only the initial prompt, but not continuation.
61 If no initial expression is given, prompt_re will be used everywhere.
61 If no initial expression is given, prompt_re will be used everywhere.
62 Used mainly for plain Python prompts (``>>>``), where the continuation prompt
62 Used mainly for plain Python prompts (``>>>``), where the continuation prompt
63 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
63 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
64
64
65 Notes
65 Notes
66 -----
66 -----
67
67
68 If initial_re and prompt_re differ,
68 If initial_re and prompt_re differ,
69 only initial_re will be tested against the first line.
69 only initial_re will be tested against the first line.
70 If any prompt is found on the first two lines,
70 If any prompt is found on the first two lines,
71 prompts will be stripped from the rest of the block.
71 prompts will be stripped from the rest of the block.
72 """
72 """
73 def __init__(self, prompt_re, initial_re=None):
73 def __init__(self, prompt_re, initial_re=None):
74 self.prompt_re = prompt_re
74 self.prompt_re = prompt_re
75 self.initial_re = initial_re or prompt_re
75 self.initial_re = initial_re or prompt_re
76
76
77 def _strip(self, lines):
77 def _strip(self, lines):
78 return [self.prompt_re.sub('', l, count=1) for l in lines]
78 return [self.prompt_re.sub('', l, count=1) for l in lines]
79
79
80 def __call__(self, lines):
80 def __call__(self, lines):
81 if not lines:
81 if not lines:
82 return lines
82 return lines
83 if self.initial_re.match(lines[0]) or \
83 if self.initial_re.match(lines[0]) or \
84 (len(lines) > 1 and self.prompt_re.match(lines[1])):
84 (len(lines) > 1 and self.prompt_re.match(lines[1])):
85 return self._strip(lines)
85 return self._strip(lines)
86 return lines
86 return lines
87
87
88 classic_prompt = PromptStripper(
88 classic_prompt = PromptStripper(
89 prompt_re=re.compile(r'^(>>>|\.\.\.)( |$)'),
89 prompt_re=re.compile(r'^(>>>|\.\.\.)( |$)'),
90 initial_re=re.compile(r'^>>>( |$)')
90 initial_re=re.compile(r'^>>>( |$)')
91 )
91 )
92
92
93 ipython_prompt = PromptStripper(
93 ipython_prompt = PromptStripper(
94 re.compile(
94 re.compile(
95 r"""
95 r"""
96 ^( # Match from the beginning of a line, either:
96 ^( # Match from the beginning of a line, either:
97
97
98 # 1. First-line prompt:
98 # 1. First-line prompt:
99 ((\[nav\]|\[ins\])?\ )? # Vi editing mode prompt, if it's there
99 ((\[nav\]|\[ins\])?\ )? # Vi editing mode prompt, if it's there
100 In\ # The 'In' of the prompt, with a space
100 In\ # The 'In' of the prompt, with a space
101 \[\d+\]: # Command index, as displayed in the prompt
101 \[\d+\]: # Command index, as displayed in the prompt
102 \ # With a mandatory trailing space
102 \ # With a mandatory trailing space
103
103
104 | # ... or ...
104 | # ... or ...
105
105
106 # 2. The three dots of the multiline prompt
106 # 2. The three dots of the multiline prompt
107 \s* # All leading whitespace characters
107 \s* # All leading whitespace characters
108 \.{3,}: # The three (or more) dots
108 \.{3,}: # The three (or more) dots
109 \ ? # With an optional trailing space
109 \ ? # With an optional trailing space
110
110
111 )
111 )
112 """,
112 """,
113 re.VERBOSE,
113 re.VERBOSE,
114 )
114 )
115 )
115 )
116
116
117
117
118 def cell_magic(lines):
118 def cell_magic(lines):
119 if not lines or not lines[0].startswith('%%'):
119 if not lines or not lines[0].startswith('%%'):
120 return lines
120 return lines
121 if re.match(r'%%\w+\?', lines[0]):
121 if re.match(r'%%\w+\?', lines[0]):
122 # This case will be handled by help_end
122 # This case will be handled by help_end
123 return lines
123 return lines
124 magic_name, _, first_line = lines[0][2:].rstrip().partition(' ')
124 magic_name, _, first_line = lines[0][2:].rstrip().partition(' ')
125 body = ''.join(lines[1:])
125 body = ''.join(lines[1:])
126 return ['get_ipython().run_cell_magic(%r, %r, %r)\n'
126 return ['get_ipython().run_cell_magic(%r, %r, %r)\n'
127 % (magic_name, first_line, body)]
127 % (magic_name, first_line, body)]
128
128
129
129
130 def _find_assign_op(token_line) -> Optional[int]:
130 def _find_assign_op(token_line) -> Optional[int]:
131 """Get the index of the first assignment in the line ('=' not inside brackets)
131 """Get the index of the first assignment in the line ('=' not inside brackets)
132
132
133 Note: We don't try to support multiple special assignment (a = b = %foo)
133 Note: We don't try to support multiple special assignment (a = b = %foo)
134 """
134 """
135 paren_level = 0
135 paren_level = 0
136 for i, ti in enumerate(token_line):
136 for i, ti in enumerate(token_line):
137 s = ti.string
137 s = ti.string
138 if s == '=' and paren_level == 0:
138 if s == '=' and paren_level == 0:
139 return i
139 return i
140 if s in {'(','[','{'}:
140 if s in {'(','[','{'}:
141 paren_level += 1
141 paren_level += 1
142 elif s in {')', ']', '}'}:
142 elif s in {')', ']', '}'}:
143 if paren_level > 0:
143 if paren_level > 0:
144 paren_level -= 1
144 paren_level -= 1
145 return None
145 return None
146
146
147 def find_end_of_continued_line(lines, start_line: int):
147 def find_end_of_continued_line(lines, start_line: int):
148 """Find the last line of a line explicitly extended using backslashes.
148 """Find the last line of a line explicitly extended using backslashes.
149
149
150 Uses 0-indexed line numbers.
150 Uses 0-indexed line numbers.
151 """
151 """
152 end_line = start_line
152 end_line = start_line
153 while lines[end_line].endswith('\\\n'):
153 while lines[end_line].endswith('\\\n'):
154 end_line += 1
154 end_line += 1
155 if end_line >= len(lines):
155 if end_line >= len(lines):
156 break
156 break
157 return end_line
157 return end_line
158
158
159 def assemble_continued_line(lines, start: Tuple[int, int], end_line: int):
159 def assemble_continued_line(lines, start: Tuple[int, int], end_line: int):
160 r"""Assemble a single line from multiple continued line pieces
160 r"""Assemble a single line from multiple continued line pieces
161
161
162 Continued lines are lines ending in ``\``, and the line following the last
162 Continued lines are lines ending in ``\``, and the line following the last
163 ``\`` in the block.
163 ``\`` in the block.
164
164
165 For example, this code continues over multiple lines::
165 For example, this code continues over multiple lines::
166
166
167 if (assign_ix is not None) \
167 if (assign_ix is not None) \
168 and (len(line) >= assign_ix + 2) \
168 and (len(line) >= assign_ix + 2) \
169 and (line[assign_ix+1].string == '%') \
169 and (line[assign_ix+1].string == '%') \
170 and (line[assign_ix+2].type == tokenize.NAME):
170 and (line[assign_ix+2].type == tokenize.NAME):
171
171
172 This statement contains four continued line pieces.
172 This statement contains four continued line pieces.
173 Assembling these pieces into a single line would give::
173 Assembling these pieces into a single line would give::
174
174
175 if (assign_ix is not None) and (len(line) >= assign_ix + 2) and (line[...
175 if (assign_ix is not None) and (len(line) >= assign_ix + 2) and (line[...
176
176
177 This uses 0-indexed line numbers. *start* is (lineno, colno).
177 This uses 0-indexed line numbers. *start* is (lineno, colno).
178
178
179 Used to allow ``%magic`` and ``!system`` commands to be continued over
179 Used to allow ``%magic`` and ``!system`` commands to be continued over
180 multiple lines.
180 multiple lines.
181 """
181 """
182 parts = [lines[start[0]][start[1]:]] + lines[start[0]+1:end_line+1]
182 parts = [lines[start[0]][start[1]:]] + lines[start[0]+1:end_line+1]
183 return ' '.join([p.rstrip()[:-1] for p in parts[:-1]] # Strip backslash+newline
183 return ' '.join([p.rstrip()[:-1] for p in parts[:-1]] # Strip backslash+newline
184 + [parts[-1].rstrip()]) # Strip newline from last line
184 + [parts[-1].rstrip()]) # Strip newline from last line
185
185
186 class TokenTransformBase:
186 class TokenTransformBase:
187 """Base class for transformations which examine tokens.
187 """Base class for transformations which examine tokens.
188
188
189 Special syntax should not be transformed when it occurs inside strings or
189 Special syntax should not be transformed when it occurs inside strings or
190 comments. This is hard to reliably avoid with regexes. The solution is to
190 comments. This is hard to reliably avoid with regexes. The solution is to
191 tokenise the code as Python, and recognise the special syntax in the tokens.
191 tokenise the code as Python, and recognise the special syntax in the tokens.
192
192
193 IPython's special syntax is not valid Python syntax, so tokenising may go
193 IPython's special syntax is not valid Python syntax, so tokenising may go
194 wrong after the special syntax starts. These classes therefore find and
194 wrong after the special syntax starts. These classes therefore find and
195 transform *one* instance of special syntax at a time into regular Python
195 transform *one* instance of special syntax at a time into regular Python
196 syntax. After each transformation, tokens are regenerated to find the next
196 syntax. After each transformation, tokens are regenerated to find the next
197 piece of special syntax.
197 piece of special syntax.
198
198
199 Subclasses need to implement one class method (find)
199 Subclasses need to implement one class method (find)
200 and one regular method (transform).
200 and one regular method (transform).
201
201
202 The priority attribute can select which transformation to apply if multiple
202 The priority attribute can select which transformation to apply if multiple
203 transformers match in the same place. Lower numbers have higher priority.
203 transformers match in the same place. Lower numbers have higher priority.
204 This allows "%magic?" to be turned into a help call rather than a magic call.
204 This allows "%magic?" to be turned into a help call rather than a magic call.
205 """
205 """
206 # Lower numbers -> higher priority (for matches in the same location)
206 # Lower numbers -> higher priority (for matches in the same location)
207 priority = 10
207 priority = 10
208
208
209 def sortby(self):
209 def sortby(self):
210 return self.start_line, self.start_col, self.priority
210 return self.start_line, self.start_col, self.priority
211
211
212 def __init__(self, start):
212 def __init__(self, start):
213 self.start_line = start[0] - 1 # Shift from 1-index to 0-index
213 self.start_line = start[0] - 1 # Shift from 1-index to 0-index
214 self.start_col = start[1]
214 self.start_col = start[1]
215
215
216 @classmethod
216 @classmethod
217 def find(cls, tokens_by_line):
217 def find(cls, tokens_by_line):
218 """Find one instance of special syntax in the provided tokens.
218 """Find one instance of special syntax in the provided tokens.
219
219
220 Tokens are grouped into logical lines for convenience,
220 Tokens are grouped into logical lines for convenience,
221 so it is easy to e.g. look at the first token of each line.
221 so it is easy to e.g. look at the first token of each line.
222 *tokens_by_line* is a list of lists of tokenize.TokenInfo objects.
222 *tokens_by_line* is a list of lists of tokenize.TokenInfo objects.
223
223
224 This should return an instance of its class, pointing to the start
224 This should return an instance of its class, pointing to the start
225 position it has found, or None if it found no match.
225 position it has found, or None if it found no match.
226 """
226 """
227 raise NotImplementedError
227 raise NotImplementedError
228
228
229 def transform(self, lines: List[str]):
229 def transform(self, lines: List[str]):
230 """Transform one instance of special syntax found by ``find()``
230 """Transform one instance of special syntax found by ``find()``
231
231
232 Takes a list of strings representing physical lines,
232 Takes a list of strings representing physical lines,
233 returns a similar list of transformed lines.
233 returns a similar list of transformed lines.
234 """
234 """
235 raise NotImplementedError
235 raise NotImplementedError
236
236
237 class MagicAssign(TokenTransformBase):
237 class MagicAssign(TokenTransformBase):
238 """Transformer for assignments from magics (a = %foo)"""
238 """Transformer for assignments from magics (a = %foo)"""
239 @classmethod
239 @classmethod
240 def find(cls, tokens_by_line):
240 def find(cls, tokens_by_line):
241 """Find the first magic assignment (a = %foo) in the cell.
241 """Find the first magic assignment (a = %foo) in the cell.
242 """
242 """
243 for line in tokens_by_line:
243 for line in tokens_by_line:
244 assign_ix = _find_assign_op(line)
244 assign_ix = _find_assign_op(line)
245 if (assign_ix is not None) \
245 if (assign_ix is not None) \
246 and (len(line) >= assign_ix + 2) \
246 and (len(line) >= assign_ix + 2) \
247 and (line[assign_ix+1].string == '%') \
247 and (line[assign_ix+1].string == '%') \
248 and (line[assign_ix+2].type == tokenize.NAME):
248 and (line[assign_ix+2].type == tokenize.NAME):
249 return cls(line[assign_ix+1].start)
249 return cls(line[assign_ix+1].start)
250
250
251 def transform(self, lines: List[str]):
251 def transform(self, lines: List[str]):
252 """Transform a magic assignment found by the ``find()`` classmethod.
252 """Transform a magic assignment found by the ``find()`` classmethod.
253 """
253 """
254 start_line, start_col = self.start_line, self.start_col
254 start_line, start_col = self.start_line, self.start_col
255 lhs = lines[start_line][:start_col]
255 lhs = lines[start_line][:start_col]
256 end_line = find_end_of_continued_line(lines, start_line)
256 end_line = find_end_of_continued_line(lines, start_line)
257 rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
257 rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
258 assert rhs.startswith('%'), rhs
258 assert rhs.startswith('%'), rhs
259 magic_name, _, args = rhs[1:].partition(' ')
259 magic_name, _, args = rhs[1:].partition(' ')
260
260
261 lines_before = lines[:start_line]
261 lines_before = lines[:start_line]
262 call = "get_ipython().run_line_magic({!r}, {!r})".format(magic_name, args)
262 call = "get_ipython().run_line_magic({!r}, {!r})".format(magic_name, args)
263 new_line = lhs + call + '\n'
263 new_line = lhs + call + '\n'
264 lines_after = lines[end_line+1:]
264 lines_after = lines[end_line+1:]
265
265
266 return lines_before + [new_line] + lines_after
266 return lines_before + [new_line] + lines_after
267
267
268
268
269 class SystemAssign(TokenTransformBase):
269 class SystemAssign(TokenTransformBase):
270 """Transformer for assignments from system commands (a = !foo)"""
270 """Transformer for assignments from system commands (a = !foo)"""
271 @classmethod
271 @classmethod
272 def find(cls, tokens_by_line):
272 def find(cls, tokens_by_line):
273 """Find the first system assignment (a = !foo) in the cell.
273 """Find the first system assignment (a = !foo) in the cell.
274 """
274 """
275 for line in tokens_by_line:
275 for line in tokens_by_line:
276 assign_ix = _find_assign_op(line)
276 assign_ix = _find_assign_op(line)
277 if (assign_ix is not None) \
277 if (assign_ix is not None) \
278 and not line[assign_ix].line.strip().startswith('=') \
278 and not line[assign_ix].line.strip().startswith('=') \
279 and (len(line) >= assign_ix + 2) \
279 and (len(line) >= assign_ix + 2) \
280 and (line[assign_ix + 1].type == tokenize.ERRORTOKEN):
280 and (line[assign_ix + 1].type == tokenize.ERRORTOKEN):
281 ix = assign_ix + 1
281 ix = assign_ix + 1
282
282
283 while ix < len(line) and line[ix].type == tokenize.ERRORTOKEN:
283 while ix < len(line) and line[ix].type == tokenize.ERRORTOKEN:
284 if line[ix].string == '!':
284 if line[ix].string == '!':
285 return cls(line[ix].start)
285 return cls(line[ix].start)
286 elif not line[ix].string.isspace():
286 elif not line[ix].string.isspace():
287 break
287 break
288 ix += 1
288 ix += 1
289
289
290 def transform(self, lines: List[str]):
290 def transform(self, lines: List[str]):
291 """Transform a system assignment found by the ``find()`` classmethod.
291 """Transform a system assignment found by the ``find()`` classmethod.
292 """
292 """
293 start_line, start_col = self.start_line, self.start_col
293 start_line, start_col = self.start_line, self.start_col
294
294
295 lhs = lines[start_line][:start_col]
295 lhs = lines[start_line][:start_col]
296 end_line = find_end_of_continued_line(lines, start_line)
296 end_line = find_end_of_continued_line(lines, start_line)
297 rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
297 rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
298 assert rhs.startswith('!'), rhs
298 assert rhs.startswith('!'), rhs
299 cmd = rhs[1:]
299 cmd = rhs[1:]
300
300
301 lines_before = lines[:start_line]
301 lines_before = lines[:start_line]
302 call = "get_ipython().getoutput({!r})".format(cmd)
302 call = "get_ipython().getoutput({!r})".format(cmd)
303 new_line = lhs + call + '\n'
303 new_line = lhs + call + '\n'
304 lines_after = lines[end_line + 1:]
304 lines_after = lines[end_line + 1:]
305
305
306 return lines_before + [new_line] + lines_after
306 return lines_before + [new_line] + lines_after
307
307
308 # The escape sequences that define the syntax transformations IPython will
308 # The escape sequences that define the syntax transformations IPython will
309 # apply to user input. These can NOT be just changed here: many regular
309 # apply to user input. These can NOT be just changed here: many regular
310 # expressions and other parts of the code may use their hardcoded values, and
310 # expressions and other parts of the code may use their hardcoded values, and
311 # for all intents and purposes they constitute the 'IPython syntax', so they
311 # for all intents and purposes they constitute the 'IPython syntax', so they
312 # should be considered fixed.
312 # should be considered fixed.
313
313
314 ESC_SHELL = '!' # Send line to underlying system shell
314 ESC_SHELL = '!' # Send line to underlying system shell
315 ESC_SH_CAP = '!!' # Send line to system shell and capture output
315 ESC_SH_CAP = '!!' # Send line to system shell and capture output
316 ESC_HELP = '?' # Find information about object
316 ESC_HELP = '?' # Find information about object
317 ESC_HELP2 = '??' # Find extra-detailed information about object
317 ESC_HELP2 = '??' # Find extra-detailed information about object
318 ESC_MAGIC = '%' # Call magic function
318 ESC_MAGIC = '%' # Call magic function
319 ESC_MAGIC2 = '%%' # Call cell-magic function
319 ESC_MAGIC2 = '%%' # Call cell-magic function
320 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
320 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
321 ESC_QUOTE2 = ';' # Quote all args as a single string, call
321 ESC_QUOTE2 = ';' # Quote all args as a single string, call
322 ESC_PAREN = '/' # Call first argument with rest of line as arguments
322 ESC_PAREN = '/' # Call first argument with rest of line as arguments
323
323
324 ESCAPE_SINGLES = {'!', '?', '%', ',', ';', '/'}
324 ESCAPE_SINGLES = {'!', '?', '%', ',', ';', '/'}
325 ESCAPE_DOUBLES = {'!!', '??'} # %% (cell magic) is handled separately
325 ESCAPE_DOUBLES = {'!!', '??'} # %% (cell magic) is handled separately
326
326
327 def _make_help_call(target, esc):
327 def _make_help_call(target, esc):
328 """Prepares a pinfo(2)/psearch call from a target name and the escape
328 """Prepares a pinfo(2)/psearch call from a target name and the escape
329 (i.e. ? or ??)"""
329 (i.e. ? or ??)"""
330 method = 'pinfo2' if esc == '??' \
330 method = 'pinfo2' if esc == '??' \
331 else 'psearch' if '*' in target \
331 else 'psearch' if '*' in target \
332 else 'pinfo'
332 else 'pinfo'
333 arg = " ".join([method, target])
333 arg = " ".join([method, target])
334 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
334 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
335 t_magic_name, _, t_magic_arg_s = arg.partition(' ')
335 t_magic_name, _, t_magic_arg_s = arg.partition(' ')
336 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
336 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
337 return "get_ipython().run_line_magic(%r, %r)" % (t_magic_name, t_magic_arg_s)
337 return "get_ipython().run_line_magic(%r, %r)" % (t_magic_name, t_magic_arg_s)
338
338
339
339
340 def _tr_help(content):
340 def _tr_help(content):
341 """Translate lines escaped with: ?
341 """Translate lines escaped with: ?
342
342
343 A naked help line should fire the intro help screen (shell.show_usage())
343 A naked help line should fire the intro help screen (shell.show_usage())
344 """
344 """
345 if not content:
345 if not content:
346 return 'get_ipython().show_usage()'
346 return 'get_ipython().show_usage()'
347
347
348 return _make_help_call(content, '?')
348 return _make_help_call(content, '?')
349
349
350 def _tr_help2(content):
350 def _tr_help2(content):
351 """Translate lines escaped with: ??
351 """Translate lines escaped with: ??
352
352
353 A naked help line should fire the intro help screen (shell.show_usage())
353 A naked help line should fire the intro help screen (shell.show_usage())
354 """
354 """
355 if not content:
355 if not content:
356 return 'get_ipython().show_usage()'
356 return 'get_ipython().show_usage()'
357
357
358 return _make_help_call(content, '??')
358 return _make_help_call(content, '??')
359
359
360 def _tr_magic(content):
360 def _tr_magic(content):
361 "Translate lines escaped with a percent sign: %"
361 "Translate lines escaped with a percent sign: %"
362 name, _, args = content.partition(' ')
362 name, _, args = content.partition(' ')
363 return 'get_ipython().run_line_magic(%r, %r)' % (name, args)
363 return 'get_ipython().run_line_magic(%r, %r)' % (name, args)
364
364
365 def _tr_quote(content):
365 def _tr_quote(content):
366 "Translate lines escaped with a comma: ,"
366 "Translate lines escaped with a comma: ,"
367 name, _, args = content.partition(' ')
367 name, _, args = content.partition(' ')
368 return '%s("%s")' % (name, '", "'.join(args.split()) )
368 return '%s("%s")' % (name, '", "'.join(args.split()) )
369
369
370 def _tr_quote2(content):
370 def _tr_quote2(content):
371 "Translate lines escaped with a semicolon: ;"
371 "Translate lines escaped with a semicolon: ;"
372 name, _, args = content.partition(' ')
372 name, _, args = content.partition(' ')
373 return '%s("%s")' % (name, args)
373 return '%s("%s")' % (name, args)
374
374
375 def _tr_paren(content):
375 def _tr_paren(content):
376 "Translate lines escaped with a slash: /"
376 "Translate lines escaped with a slash: /"
377 name, _, args = content.partition(' ')
377 name, _, args = content.partition(' ')
378 return '%s(%s)' % (name, ", ".join(args.split()))
378 return '%s(%s)' % (name, ", ".join(args.split()))
379
379
380 tr = { ESC_SHELL : 'get_ipython().system({!r})'.format,
380 tr = { ESC_SHELL : 'get_ipython().system({!r})'.format,
381 ESC_SH_CAP : 'get_ipython().getoutput({!r})'.format,
381 ESC_SH_CAP : 'get_ipython().getoutput({!r})'.format,
382 ESC_HELP : _tr_help,
382 ESC_HELP : _tr_help,
383 ESC_HELP2 : _tr_help2,
383 ESC_HELP2 : _tr_help2,
384 ESC_MAGIC : _tr_magic,
384 ESC_MAGIC : _tr_magic,
385 ESC_QUOTE : _tr_quote,
385 ESC_QUOTE : _tr_quote,
386 ESC_QUOTE2 : _tr_quote2,
386 ESC_QUOTE2 : _tr_quote2,
387 ESC_PAREN : _tr_paren }
387 ESC_PAREN : _tr_paren }
388
388
389 class EscapedCommand(TokenTransformBase):
389 class EscapedCommand(TokenTransformBase):
390 """Transformer for escaped commands like %foo, !foo, or /foo"""
390 """Transformer for escaped commands like %foo, !foo, or /foo"""
391 @classmethod
391 @classmethod
392 def find(cls, tokens_by_line):
392 def find(cls, tokens_by_line):
393 """Find the first escaped command (%foo, !foo, etc.) in the cell.
393 """Find the first escaped command (%foo, !foo, etc.) in the cell.
394 """
394 """
395 for line in tokens_by_line:
395 for line in tokens_by_line:
396 if not line:
396 if not line:
397 continue
397 continue
398 ix = 0
398 ix = 0
399 ll = len(line)
399 ll = len(line)
400 while ll > ix and line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
400 while ll > ix and line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
401 ix += 1
401 ix += 1
402 if ix >= ll:
402 if ix >= ll:
403 continue
403 continue
404 if line[ix].string in ESCAPE_SINGLES:
404 if line[ix].string in ESCAPE_SINGLES:
405 return cls(line[ix].start)
405 return cls(line[ix].start)
406
406
407 def transform(self, lines):
407 def transform(self, lines):
408 """Transform an escaped line found by the ``find()`` classmethod.
408 """Transform an escaped line found by the ``find()`` classmethod.
409 """
409 """
410 start_line, start_col = self.start_line, self.start_col
410 start_line, start_col = self.start_line, self.start_col
411
411
412 indent = lines[start_line][:start_col]
412 indent = lines[start_line][:start_col]
413 end_line = find_end_of_continued_line(lines, start_line)
413 end_line = find_end_of_continued_line(lines, start_line)
414 line = assemble_continued_line(lines, (start_line, start_col), end_line)
414 line = assemble_continued_line(lines, (start_line, start_col), end_line)
415
415
416 if len(line) > 1 and line[:2] in ESCAPE_DOUBLES:
416 if len(line) > 1 and line[:2] in ESCAPE_DOUBLES:
417 escape, content = line[:2], line[2:]
417 escape, content = line[:2], line[2:]
418 else:
418 else:
419 escape, content = line[:1], line[1:]
419 escape, content = line[:1], line[1:]
420
420
421 if escape in tr:
421 if escape in tr:
422 call = tr[escape](content)
422 call = tr[escape](content)
423 else:
423 else:
424 call = ''
424 call = ''
425
425
426 lines_before = lines[:start_line]
426 lines_before = lines[:start_line]
427 new_line = indent + call + '\n'
427 new_line = indent + call + '\n'
428 lines_after = lines[end_line + 1:]
428 lines_after = lines[end_line + 1:]
429
429
430 return lines_before + [new_line] + lines_after
430 return lines_before + [new_line] + lines_after
431
431
432 _help_end_re = re.compile(r"""(%{0,2}
432
433 (?!\d)[\w*]+ # Variable name
433 _help_end_re = re.compile(
434 (\.(?!\d)[\w*]+)* # .etc.etc
434 r"""(%{0,2}
435 )
435 (?!\d)[\w*]+ # Variable name
436 (\?\??)$ # ? or ??
436 (\.(?!\d)[\w*]+|\[-?[0-9]+\])* # .etc.etc or [0], we only support literal integers.
437 """,
437 )
438 re.VERBOSE)
438 (\?\??)$ # ? or ??
439 """,
440 re.VERBOSE,
441 )
442
439
443
440 class HelpEnd(TokenTransformBase):
444 class HelpEnd(TokenTransformBase):
441 """Transformer for help syntax: obj? and obj??"""
445 """Transformer for help syntax: obj? and obj??"""
442 # This needs to be higher priority (lower number) than EscapedCommand so
446 # This needs to be higher priority (lower number) than EscapedCommand so
443 # that inspecting magics (%foo?) works.
447 # that inspecting magics (%foo?) works.
444 priority = 5
448 priority = 5
445
449
446 def __init__(self, start, q_locn):
450 def __init__(self, start, q_locn):
447 super().__init__(start)
451 super().__init__(start)
448 self.q_line = q_locn[0] - 1 # Shift from 1-indexed to 0-indexed
452 self.q_line = q_locn[0] - 1 # Shift from 1-indexed to 0-indexed
449 self.q_col = q_locn[1]
453 self.q_col = q_locn[1]
450
454
451 @classmethod
455 @classmethod
452 def find(cls, tokens_by_line):
456 def find(cls, tokens_by_line):
453 """Find the first help command (foo?) in the cell.
457 """Find the first help command (foo?) in the cell.
454 """
458 """
455 for line in tokens_by_line:
459 for line in tokens_by_line:
456 # Last token is NEWLINE; look at last but one
460 # Last token is NEWLINE; look at last but one
457 if len(line) > 2 and line[-2].string == '?':
461 if len(line) > 2 and line[-2].string == '?':
458 # Find the first token that's not INDENT/DEDENT
462 # Find the first token that's not INDENT/DEDENT
459 ix = 0
463 ix = 0
460 while line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
464 while line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
461 ix += 1
465 ix += 1
462 return cls(line[ix].start, line[-2].start)
466 return cls(line[ix].start, line[-2].start)
463
467
464 def transform(self, lines):
468 def transform(self, lines):
465 """Transform a help command found by the ``find()`` classmethod.
469 """Transform a help command found by the ``find()`` classmethod.
466 """
470 """
467 piece = ''.join(lines[self.start_line:self.q_line+1])
471
468 indent, content = piece[:self.start_col], piece[self.start_col:]
472 piece = "".join(lines[self.start_line : self.q_line + 1])
469 lines_before = lines[:self.start_line]
473 indent, content = piece[: self.start_col], piece[self.start_col :]
470 lines_after = lines[self.q_line + 1:]
474 lines_before = lines[: self.start_line]
475 lines_after = lines[self.q_line + 1 :]
471
476
472 m = _help_end_re.search(content)
477 m = _help_end_re.search(content)
473 if not m:
478 if not m:
474 raise SyntaxError(content)
479 raise SyntaxError(content)
475 assert m is not None, content
480 assert m is not None, content
476 target = m.group(1)
481 target = m.group(1)
477 esc = m.group(3)
482 esc = m.group(3)
478
483
479
484
480 call = _make_help_call(target, esc)
485 call = _make_help_call(target, esc)
481 new_line = indent + call + '\n'
486 new_line = indent + call + '\n'
482
487
483 return lines_before + [new_line] + lines_after
488 return lines_before + [new_line] + lines_after
484
489
485 def make_tokens_by_line(lines:List[str]):
490 def make_tokens_by_line(lines:List[str]):
486 """Tokenize a series of lines and group tokens by line.
491 """Tokenize a series of lines and group tokens by line.
487
492
488 The tokens for a multiline Python string or expression are grouped as one
493 The tokens for a multiline Python string or expression are grouped as one
489 line. All lines except the last lines should keep their line ending ('\\n',
494 line. All lines except the last lines should keep their line ending ('\\n',
490 '\\r\\n') for this to properly work. Use `.splitlines(keeplineending=True)`
495 '\\r\\n') for this to properly work. Use `.splitlines(keeplineending=True)`
491 for example when passing block of text to this function.
496 for example when passing block of text to this function.
492
497
493 """
498 """
494 # NL tokens are used inside multiline expressions, but also after blank
499 # NL tokens are used inside multiline expressions, but also after blank
495 # lines or comments. This is intentional - see https://bugs.python.org/issue17061
500 # lines or comments. This is intentional - see https://bugs.python.org/issue17061
496 # We want to group the former case together but split the latter, so we
501 # We want to group the former case together but split the latter, so we
497 # track parentheses level, similar to the internals of tokenize.
502 # track parentheses level, similar to the internals of tokenize.
498
503
499 # reexported from token on 3.7+
504 # reexported from token on 3.7+
500 NEWLINE, NL = tokenize.NEWLINE, tokenize.NL # type: ignore
505 NEWLINE, NL = tokenize.NEWLINE, tokenize.NL # type: ignore
501 tokens_by_line: List[List[Any]] = [[]]
506 tokens_by_line: List[List[Any]] = [[]]
502 if len(lines) > 1 and not lines[0].endswith(("\n", "\r", "\r\n", "\x0b", "\x0c")):
507 if len(lines) > 1 and not lines[0].endswith(("\n", "\r", "\r\n", "\x0b", "\x0c")):
503 warnings.warn(
508 warnings.warn(
504 "`make_tokens_by_line` received a list of lines which do not have lineending markers ('\\n', '\\r', '\\r\\n', '\\x0b', '\\x0c'), behavior will be unspecified",
509 "`make_tokens_by_line` received a list of lines which do not have lineending markers ('\\n', '\\r', '\\r\\n', '\\x0b', '\\x0c'), behavior will be unspecified",
505 stacklevel=2,
510 stacklevel=2,
506 )
511 )
507 parenlev = 0
512 parenlev = 0
508 try:
513 try:
509 for token in tokenize.generate_tokens(iter(lines).__next__):
514 for token in tokenize.generate_tokens(iter(lines).__next__):
510 tokens_by_line[-1].append(token)
515 tokens_by_line[-1].append(token)
511 if (token.type == NEWLINE) \
516 if (token.type == NEWLINE) \
512 or ((token.type == NL) and (parenlev <= 0)):
517 or ((token.type == NL) and (parenlev <= 0)):
513 tokens_by_line.append([])
518 tokens_by_line.append([])
514 elif token.string in {'(', '[', '{'}:
519 elif token.string in {'(', '[', '{'}:
515 parenlev += 1
520 parenlev += 1
516 elif token.string in {')', ']', '}'}:
521 elif token.string in {')', ']', '}'}:
517 if parenlev > 0:
522 if parenlev > 0:
518 parenlev -= 1
523 parenlev -= 1
519 except tokenize.TokenError:
524 except tokenize.TokenError:
520 # Input ended in a multiline string or expression. That's OK for us.
525 # Input ended in a multiline string or expression. That's OK for us.
521 pass
526 pass
522
527
523
528
524 if not tokens_by_line[-1]:
529 if not tokens_by_line[-1]:
525 tokens_by_line.pop()
530 tokens_by_line.pop()
526
531
527
532
528 return tokens_by_line
533 return tokens_by_line
529
534
530
535
531 def has_sunken_brackets(tokens: List[tokenize.TokenInfo]):
536 def has_sunken_brackets(tokens: List[tokenize.TokenInfo]):
532 """Check if the depth of brackets in the list of tokens drops below 0"""
537 """Check if the depth of brackets in the list of tokens drops below 0"""
533 parenlev = 0
538 parenlev = 0
534 for token in tokens:
539 for token in tokens:
535 if token.string in {"(", "[", "{"}:
540 if token.string in {"(", "[", "{"}:
536 parenlev += 1
541 parenlev += 1
537 elif token.string in {")", "]", "}"}:
542 elif token.string in {")", "]", "}"}:
538 parenlev -= 1
543 parenlev -= 1
539 if parenlev < 0:
544 if parenlev < 0:
540 return True
545 return True
541 return False
546 return False
542
547
543
548
544 def show_linewise_tokens(s: str):
549 def show_linewise_tokens(s: str):
545 """For investigation and debugging"""
550 """For investigation and debugging"""
546 if not s.endswith('\n'):
551 warnings.warn(
547 s += '\n'
552 "show_linewise_tokens is deprecated since IPython 8.6",
553 DeprecationWarning,
554 stacklevel=2,
555 )
556 if not s.endswith("\n"):
557 s += "\n"
548 lines = s.splitlines(keepends=True)
558 lines = s.splitlines(keepends=True)
549 for line in make_tokens_by_line(lines):
559 for line in make_tokens_by_line(lines):
550 print("Line -------")
560 print("Line -------")
551 for tokinfo in line:
561 for tokinfo in line:
552 print(" ", tokinfo)
562 print(" ", tokinfo)
553
563
554 # Arbitrary limit to prevent getting stuck in infinite loops
564 # Arbitrary limit to prevent getting stuck in infinite loops
555 TRANSFORM_LOOP_LIMIT = 500
565 TRANSFORM_LOOP_LIMIT = 500
556
566
557 class TransformerManager:
567 class TransformerManager:
558 """Applies various transformations to a cell or code block.
568 """Applies various transformations to a cell or code block.
559
569
560 The key methods for external use are ``transform_cell()``
570 The key methods for external use are ``transform_cell()``
561 and ``check_complete()``.
571 and ``check_complete()``.
562 """
572 """
563 def __init__(self):
573 def __init__(self):
564 self.cleanup_transforms = [
574 self.cleanup_transforms = [
565 leading_empty_lines,
575 leading_empty_lines,
566 leading_indent,
576 leading_indent,
567 classic_prompt,
577 classic_prompt,
568 ipython_prompt,
578 ipython_prompt,
569 ]
579 ]
570 self.line_transforms = [
580 self.line_transforms = [
571 cell_magic,
581 cell_magic,
572 ]
582 ]
573 self.token_transformers = [
583 self.token_transformers = [
574 MagicAssign,
584 MagicAssign,
575 SystemAssign,
585 SystemAssign,
576 EscapedCommand,
586 EscapedCommand,
577 HelpEnd,
587 HelpEnd,
578 ]
588 ]
579
589
580 def do_one_token_transform(self, lines):
590 def do_one_token_transform(self, lines):
581 """Find and run the transform earliest in the code.
591 """Find and run the transform earliest in the code.
582
592
583 Returns (changed, lines).
593 Returns (changed, lines).
584
594
585 This method is called repeatedly until changed is False, indicating
595 This method is called repeatedly until changed is False, indicating
586 that all available transformations are complete.
596 that all available transformations are complete.
587
597
588 The tokens following IPython special syntax might not be valid, so
598 The tokens following IPython special syntax might not be valid, so
589 the transformed code is retokenised every time to identify the next
599 the transformed code is retokenised every time to identify the next
590 piece of special syntax. Hopefully long code cells are mostly valid
600 piece of special syntax. Hopefully long code cells are mostly valid
591 Python, not using lots of IPython special syntax, so this shouldn't be
601 Python, not using lots of IPython special syntax, so this shouldn't be
592 a performance issue.
602 a performance issue.
593 """
603 """
594 tokens_by_line = make_tokens_by_line(lines)
604 tokens_by_line = make_tokens_by_line(lines)
595 candidates = []
605 candidates = []
596 for transformer_cls in self.token_transformers:
606 for transformer_cls in self.token_transformers:
597 transformer = transformer_cls.find(tokens_by_line)
607 transformer = transformer_cls.find(tokens_by_line)
598 if transformer:
608 if transformer:
599 candidates.append(transformer)
609 candidates.append(transformer)
600
610
601 if not candidates:
611 if not candidates:
602 # Nothing to transform
612 # Nothing to transform
603 return False, lines
613 return False, lines
604 ordered_transformers = sorted(candidates, key=TokenTransformBase.sortby)
614 ordered_transformers = sorted(candidates, key=TokenTransformBase.sortby)
605 for transformer in ordered_transformers:
615 for transformer in ordered_transformers:
606 try:
616 try:
607 return True, transformer.transform(lines)
617 return True, transformer.transform(lines)
608 except SyntaxError:
618 except SyntaxError:
609 pass
619 pass
610 return False, lines
620 return False, lines
611
621
612 def do_token_transforms(self, lines):
622 def do_token_transforms(self, lines):
613 for _ in range(TRANSFORM_LOOP_LIMIT):
623 for _ in range(TRANSFORM_LOOP_LIMIT):
614 changed, lines = self.do_one_token_transform(lines)
624 changed, lines = self.do_one_token_transform(lines)
615 if not changed:
625 if not changed:
616 return lines
626 return lines
617
627
618 raise RuntimeError("Input transformation still changing after "
628 raise RuntimeError("Input transformation still changing after "
619 "%d iterations. Aborting." % TRANSFORM_LOOP_LIMIT)
629 "%d iterations. Aborting." % TRANSFORM_LOOP_LIMIT)
620
630
621 def transform_cell(self, cell: str) -> str:
631 def transform_cell(self, cell: str) -> str:
622 """Transforms a cell of input code"""
632 """Transforms a cell of input code"""
623 if not cell.endswith('\n'):
633 if not cell.endswith('\n'):
624 cell += '\n' # Ensure the cell has a trailing newline
634 cell += '\n' # Ensure the cell has a trailing newline
625 lines = cell.splitlines(keepends=True)
635 lines = cell.splitlines(keepends=True)
626 for transform in self.cleanup_transforms + self.line_transforms:
636 for transform in self.cleanup_transforms + self.line_transforms:
627 lines = transform(lines)
637 lines = transform(lines)
628
638
629 lines = self.do_token_transforms(lines)
639 lines = self.do_token_transforms(lines)
630 return ''.join(lines)
640 return ''.join(lines)
631
641
632 def check_complete(self, cell: str):
642 def check_complete(self, cell: str):
633 """Return whether a block of code is ready to execute, or should be continued
643 """Return whether a block of code is ready to execute, or should be continued
634
644
635 Parameters
645 Parameters
636 ----------
646 ----------
637 cell : string
647 cell : string
638 Python input code, which can be multiline.
648 Python input code, which can be multiline.
639
649
640 Returns
650 Returns
641 -------
651 -------
642 status : str
652 status : str
643 One of 'complete', 'incomplete', or 'invalid' if source is not a
653 One of 'complete', 'incomplete', or 'invalid' if source is not a
644 prefix of valid code.
654 prefix of valid code.
645 indent_spaces : int or None
655 indent_spaces : int or None
646 The number of spaces by which to indent the next line of code. If
656 The number of spaces by which to indent the next line of code. If
647 status is not 'incomplete', this is None.
657 status is not 'incomplete', this is None.
648 """
658 """
649 # Remember if the lines ends in a new line.
659 # Remember if the lines ends in a new line.
650 ends_with_newline = False
660 ends_with_newline = False
651 for character in reversed(cell):
661 for character in reversed(cell):
652 if character == '\n':
662 if character == '\n':
653 ends_with_newline = True
663 ends_with_newline = True
654 break
664 break
655 elif character.strip():
665 elif character.strip():
656 break
666 break
657 else:
667 else:
658 continue
668 continue
659
669
660 if not ends_with_newline:
670 if not ends_with_newline:
661 # Append an newline for consistent tokenization
671 # Append an newline for consistent tokenization
662 # See https://bugs.python.org/issue33899
672 # See https://bugs.python.org/issue33899
663 cell += '\n'
673 cell += '\n'
664
674
665 lines = cell.splitlines(keepends=True)
675 lines = cell.splitlines(keepends=True)
666
676
667 if not lines:
677 if not lines:
668 return 'complete', None
678 return 'complete', None
669
679
670 if lines[-1].endswith('\\'):
680 if lines[-1].endswith('\\'):
671 # Explicit backslash continuation
681 # Explicit backslash continuation
672 return 'incomplete', find_last_indent(lines)
682 return 'incomplete', find_last_indent(lines)
673
683
674 try:
684 try:
675 for transform in self.cleanup_transforms:
685 for transform in self.cleanup_transforms:
676 if not getattr(transform, 'has_side_effects', False):
686 if not getattr(transform, 'has_side_effects', False):
677 lines = transform(lines)
687 lines = transform(lines)
678 except SyntaxError:
688 except SyntaxError:
679 return 'invalid', None
689 return 'invalid', None
680
690
681 if lines[0].startswith('%%'):
691 if lines[0].startswith('%%'):
682 # Special case for cell magics - completion marked by blank line
692 # Special case for cell magics - completion marked by blank line
683 if lines[-1].strip():
693 if lines[-1].strip():
684 return 'incomplete', find_last_indent(lines)
694 return 'incomplete', find_last_indent(lines)
685 else:
695 else:
686 return 'complete', None
696 return 'complete', None
687
697
688 try:
698 try:
689 for transform in self.line_transforms:
699 for transform in self.line_transforms:
690 if not getattr(transform, 'has_side_effects', False):
700 if not getattr(transform, 'has_side_effects', False):
691 lines = transform(lines)
701 lines = transform(lines)
692 lines = self.do_token_transforms(lines)
702 lines = self.do_token_transforms(lines)
693 except SyntaxError:
703 except SyntaxError:
694 return 'invalid', None
704 return 'invalid', None
695
705
696 tokens_by_line = make_tokens_by_line(lines)
706 tokens_by_line = make_tokens_by_line(lines)
697
707
698 # Bail if we got one line and there are more closing parentheses than
708 # Bail if we got one line and there are more closing parentheses than
699 # the opening ones
709 # the opening ones
700 if (
710 if (
701 len(lines) == 1
711 len(lines) == 1
702 and tokens_by_line
712 and tokens_by_line
703 and has_sunken_brackets(tokens_by_line[0])
713 and has_sunken_brackets(tokens_by_line[0])
704 ):
714 ):
705 return "invalid", None
715 return "invalid", None
706
716
707 if not tokens_by_line:
717 if not tokens_by_line:
708 return 'incomplete', find_last_indent(lines)
718 return 'incomplete', find_last_indent(lines)
709
719
710 if tokens_by_line[-1][-1].type != tokenize.ENDMARKER:
720 if tokens_by_line[-1][-1].type != tokenize.ENDMARKER:
711 # We're in a multiline string or expression
721 # We're in a multiline string or expression
712 return 'incomplete', find_last_indent(lines)
722 return 'incomplete', find_last_indent(lines)
713
723
714 newline_types = {tokenize.NEWLINE, tokenize.COMMENT, tokenize.ENDMARKER} # type: ignore
724 newline_types = {tokenize.NEWLINE, tokenize.COMMENT, tokenize.ENDMARKER} # type: ignore
715
725
716 # Pop the last line which only contains DEDENTs and ENDMARKER
726 # Pop the last line which only contains DEDENTs and ENDMARKER
717 last_token_line = None
727 last_token_line = None
718 if {t.type for t in tokens_by_line[-1]} in [
728 if {t.type for t in tokens_by_line[-1]} in [
719 {tokenize.DEDENT, tokenize.ENDMARKER},
729 {tokenize.DEDENT, tokenize.ENDMARKER},
720 {tokenize.ENDMARKER}
730 {tokenize.ENDMARKER}
721 ] and len(tokens_by_line) > 1:
731 ] and len(tokens_by_line) > 1:
722 last_token_line = tokens_by_line.pop()
732 last_token_line = tokens_by_line.pop()
723
733
724 while tokens_by_line[-1] and tokens_by_line[-1][-1].type in newline_types:
734 while tokens_by_line[-1] and tokens_by_line[-1][-1].type in newline_types:
725 tokens_by_line[-1].pop()
735 tokens_by_line[-1].pop()
726
736
727 if not tokens_by_line[-1]:
737 if not tokens_by_line[-1]:
728 return 'incomplete', find_last_indent(lines)
738 return 'incomplete', find_last_indent(lines)
729
739
730 if tokens_by_line[-1][-1].string == ':':
740 if tokens_by_line[-1][-1].string == ':':
731 # The last line starts a block (e.g. 'if foo:')
741 # The last line starts a block (e.g. 'if foo:')
732 ix = 0
742 ix = 0
733 while tokens_by_line[-1][ix].type in {tokenize.INDENT, tokenize.DEDENT}:
743 while tokens_by_line[-1][ix].type in {tokenize.INDENT, tokenize.DEDENT}:
734 ix += 1
744 ix += 1
735
745
736 indent = tokens_by_line[-1][ix].start[1]
746 indent = tokens_by_line[-1][ix].start[1]
737 return 'incomplete', indent + 4
747 return 'incomplete', indent + 4
738
748
739 if tokens_by_line[-1][0].line.endswith('\\'):
749 if tokens_by_line[-1][0].line.endswith('\\'):
740 return 'incomplete', None
750 return 'incomplete', None
741
751
742 # At this point, our checks think the code is complete (or invalid).
752 # At this point, our checks think the code is complete (or invalid).
743 # We'll use codeop.compile_command to check this with the real parser
753 # We'll use codeop.compile_command to check this with the real parser
744 try:
754 try:
745 with warnings.catch_warnings():
755 with warnings.catch_warnings():
746 warnings.simplefilter('error', SyntaxWarning)
756 warnings.simplefilter('error', SyntaxWarning)
747 res = compile_command(''.join(lines), symbol='exec')
757 res = compile_command(''.join(lines), symbol='exec')
748 except (SyntaxError, OverflowError, ValueError, TypeError,
758 except (SyntaxError, OverflowError, ValueError, TypeError,
749 MemoryError, SyntaxWarning):
759 MemoryError, SyntaxWarning):
750 return 'invalid', None
760 return 'invalid', None
751 else:
761 else:
752 if res is None:
762 if res is None:
753 return 'incomplete', find_last_indent(lines)
763 return 'incomplete', find_last_indent(lines)
754
764
755 if last_token_line and last_token_line[0].type == tokenize.DEDENT:
765 if last_token_line and last_token_line[0].type == tokenize.DEDENT:
756 if ends_with_newline:
766 if ends_with_newline:
757 return 'complete', None
767 return 'complete', None
758 return 'incomplete', find_last_indent(lines)
768 return 'incomplete', find_last_indent(lines)
759
769
760 # If there's a blank line at the end, assume we're ready to execute
770 # If there's a blank line at the end, assume we're ready to execute
761 if not lines[-1].strip():
771 if not lines[-1].strip():
762 return 'complete', None
772 return 'complete', None
763
773
764 return 'complete', None
774 return 'complete', None
765
775
766
776
767 def find_last_indent(lines):
777 def find_last_indent(lines):
768 m = _indent_re.match(lines[-1])
778 m = _indent_re.match(lines[-1])
769 if not m:
779 if not m:
770 return 0
780 return 0
771 return len(m.group(0).replace('\t', ' '*4))
781 return len(m.group(0).replace('\t', ' '*4))
772
782
773
783
774 class MaybeAsyncCompile(Compile):
784 class MaybeAsyncCompile(Compile):
775 def __init__(self, extra_flags=0):
785 def __init__(self, extra_flags=0):
776 super().__init__()
786 super().__init__()
777 self.flags |= extra_flags
787 self.flags |= extra_flags
778
788
779
789
780 class MaybeAsyncCommandCompiler(CommandCompiler):
790 class MaybeAsyncCommandCompiler(CommandCompiler):
781 def __init__(self, extra_flags=0):
791 def __init__(self, extra_flags=0):
782 self.compiler = MaybeAsyncCompile(extra_flags=extra_flags)
792 self.compiler = MaybeAsyncCompile(extra_flags=extra_flags)
783
793
784
794
785 _extra_flags = ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
795 _extra_flags = ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
786
796
787 compile_command = MaybeAsyncCommandCompiler(extra_flags=_extra_flags)
797 compile_command = MaybeAsyncCommandCompiler(extra_flags=_extra_flags)
@@ -1,3780 +1,3835 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Main IPython class."""
2 """Main IPython class."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13
13
14 import abc
14 import abc
15 import ast
15 import ast
16 import atexit
16 import atexit
17 import bdb
17 import bdb
18 import builtins as builtin_mod
18 import builtins as builtin_mod
19 import functools
19 import functools
20 import inspect
20 import inspect
21 import os
21 import os
22 import re
22 import re
23 import runpy
23 import runpy
24 import subprocess
24 import subprocess
25 import sys
25 import sys
26 import tempfile
26 import tempfile
27 import traceback
27 import traceback
28 import types
28 import types
29 import warnings
29 import warnings
30 from ast import stmt
30 from ast import stmt
31 from io import open as io_open
31 from io import open as io_open
32 from logging import error
32 from logging import error
33 from pathlib import Path
33 from pathlib import Path
34 from typing import Callable
34 from typing import Callable
35 from typing import List as ListType
35 from typing import List as ListType
36 from typing import Optional, Tuple
36 from typing import Optional, Tuple
37 from warnings import warn
37 from warnings import warn
38
38
39 from pickleshare import PickleShareDB
39 from pickleshare import PickleShareDB
40 from tempfile import TemporaryDirectory
40 from tempfile import TemporaryDirectory
41 from traitlets import (
41 from traitlets import (
42 Any,
42 Any,
43 Bool,
43 Bool,
44 CaselessStrEnum,
44 CaselessStrEnum,
45 Dict,
45 Dict,
46 Enum,
46 Enum,
47 Instance,
47 Instance,
48 Integer,
48 Integer,
49 List,
49 List,
50 Type,
50 Type,
51 Unicode,
51 Unicode,
52 default,
52 default,
53 observe,
53 observe,
54 validate,
54 validate,
55 )
55 )
56 from traitlets.config.configurable import SingletonConfigurable
56 from traitlets.config.configurable import SingletonConfigurable
57 from traitlets.utils.importstring import import_item
57 from traitlets.utils.importstring import import_item
58
58
59 import IPython.core.hooks
59 import IPython.core.hooks
60 from IPython.core import magic, oinspect, page, prefilter, ultratb
60 from IPython.core import magic, oinspect, page, prefilter, ultratb
61 from IPython.core.alias import Alias, AliasManager
61 from IPython.core.alias import Alias, AliasManager
62 from IPython.core.autocall import ExitAutocall
62 from IPython.core.autocall import ExitAutocall
63 from IPython.core.builtin_trap import BuiltinTrap
63 from IPython.core.builtin_trap import BuiltinTrap
64 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
64 from IPython.core.compilerop import CachingCompiler
65 from IPython.core.debugger import InterruptiblePdb
65 from IPython.core.debugger import InterruptiblePdb
66 from IPython.core.display_trap import DisplayTrap
66 from IPython.core.display_trap import DisplayTrap
67 from IPython.core.displayhook import DisplayHook
67 from IPython.core.displayhook import DisplayHook
68 from IPython.core.displaypub import DisplayPublisher
68 from IPython.core.displaypub import DisplayPublisher
69 from IPython.core.error import InputRejected, UsageError
69 from IPython.core.error import InputRejected, UsageError
70 from IPython.core.events import EventManager, available_events
70 from IPython.core.events import EventManager, available_events
71 from IPython.core.extensions import ExtensionManager
71 from IPython.core.extensions import ExtensionManager
72 from IPython.core.formatters import DisplayFormatter
72 from IPython.core.formatters import DisplayFormatter
73 from IPython.core.history import HistoryManager
73 from IPython.core.history import HistoryManager
74 from IPython.core.inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
74 from IPython.core.inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
75 from IPython.core.logger import Logger
75 from IPython.core.logger import Logger
76 from IPython.core.macro import Macro
76 from IPython.core.macro import Macro
77 from IPython.core.payload import PayloadManager
77 from IPython.core.payload import PayloadManager
78 from IPython.core.prefilter import PrefilterManager
78 from IPython.core.prefilter import PrefilterManager
79 from IPython.core.profiledir import ProfileDir
79 from IPython.core.profiledir import ProfileDir
80 from IPython.core.usage import default_banner
80 from IPython.core.usage import default_banner
81 from IPython.display import display
81 from IPython.display import display
82 from IPython.paths import get_ipython_dir
82 from IPython.paths import get_ipython_dir
83 from IPython.testing.skipdoctest import skip_doctest
83 from IPython.testing.skipdoctest import skip_doctest
84 from IPython.utils import PyColorize, io, openpy, py3compat
84 from IPython.utils import PyColorize, io, openpy, py3compat
85 from IPython.utils.decorators import undoc
85 from IPython.utils.decorators import undoc
86 from IPython.utils.io import ask_yes_no
86 from IPython.utils.io import ask_yes_no
87 from IPython.utils.ipstruct import Struct
87 from IPython.utils.ipstruct import Struct
88 from IPython.utils.path import ensure_dir_exists, get_home_dir, get_py_filename
88 from IPython.utils.path import ensure_dir_exists, get_home_dir, get_py_filename
89 from IPython.utils.process import getoutput, system
89 from IPython.utils.process import getoutput, system
90 from IPython.utils.strdispatch import StrDispatch
90 from IPython.utils.strdispatch import StrDispatch
91 from IPython.utils.syspathcontext import prepended_to_syspath
91 from IPython.utils.syspathcontext import prepended_to_syspath
92 from IPython.utils.text import DollarFormatter, LSString, SList, format_screen
92 from IPython.utils.text import DollarFormatter, LSString, SList, format_screen
93
93
94 sphinxify: Optional[Callable]
94 sphinxify: Optional[Callable]
95
95
96 try:
96 try:
97 import docrepr.sphinxify as sphx
97 import docrepr.sphinxify as sphx
98
98
99 def sphinxify(oinfo):
99 def sphinxify(oinfo):
100 wrapped_docstring = sphx.wrap_main_docstring(oinfo)
100 wrapped_docstring = sphx.wrap_main_docstring(oinfo)
101
101
102 def sphinxify_docstring(docstring):
102 def sphinxify_docstring(docstring):
103 with TemporaryDirectory() as dirname:
103 with TemporaryDirectory() as dirname:
104 return {
104 return {
105 "text/html": sphx.sphinxify(wrapped_docstring, dirname),
105 "text/html": sphx.sphinxify(wrapped_docstring, dirname),
106 "text/plain": docstring,
106 "text/plain": docstring,
107 }
107 }
108
108
109 return sphinxify_docstring
109 return sphinxify_docstring
110 except ImportError:
110 except ImportError:
111 sphinxify = None
111 sphinxify = None
112
112
113
113
114 class ProvisionalWarning(DeprecationWarning):
114 class ProvisionalWarning(DeprecationWarning):
115 """
115 """
116 Warning class for unstable features
116 Warning class for unstable features
117 """
117 """
118 pass
118 pass
119
119
120 from ast import Module
120 from ast import Module
121
121
122 _assign_nodes = (ast.AugAssign, ast.AnnAssign, ast.Assign)
122 _assign_nodes = (ast.AugAssign, ast.AnnAssign, ast.Assign)
123 _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)
123 _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)
124
124
125 #-----------------------------------------------------------------------------
125 #-----------------------------------------------------------------------------
126 # Await Helpers
126 # Await Helpers
127 #-----------------------------------------------------------------------------
127 #-----------------------------------------------------------------------------
128
128
129 # we still need to run things using the asyncio eventloop, but there is no
129 # we still need to run things using the asyncio eventloop, but there is no
130 # async integration
130 # async integration
131 from .async_helpers import (
131 from .async_helpers import (
132 _asyncio_runner,
132 _asyncio_runner,
133 _curio_runner,
133 _curio_runner,
134 _pseudo_sync_runner,
134 _pseudo_sync_runner,
135 _should_be_async,
135 _should_be_async,
136 _trio_runner,
136 _trio_runner,
137 )
137 )
138
138
139 #-----------------------------------------------------------------------------
139 #-----------------------------------------------------------------------------
140 # Globals
140 # Globals
141 #-----------------------------------------------------------------------------
141 #-----------------------------------------------------------------------------
142
142
143 # compiled regexps for autoindent management
143 # compiled regexps for autoindent management
144 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
144 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
145
145
146 #-----------------------------------------------------------------------------
146 #-----------------------------------------------------------------------------
147 # Utilities
147 # Utilities
148 #-----------------------------------------------------------------------------
148 #-----------------------------------------------------------------------------
149
149
150
151 def is_integer_string(s: str):
152 """
153 Variant of "str.isnumeric()" that allow negative values and other ints.
154 """
155 try:
156 int(s)
157 return True
158 except ValueError:
159 return False
160 raise ValueError("Unexpected error")
161
162
150 @undoc
163 @undoc
151 def softspace(file, newvalue):
164 def softspace(file, newvalue):
152 """Copied from code.py, to remove the dependency"""
165 """Copied from code.py, to remove the dependency"""
153
166
154 oldvalue = 0
167 oldvalue = 0
155 try:
168 try:
156 oldvalue = file.softspace
169 oldvalue = file.softspace
157 except AttributeError:
170 except AttributeError:
158 pass
171 pass
159 try:
172 try:
160 file.softspace = newvalue
173 file.softspace = newvalue
161 except (AttributeError, TypeError):
174 except (AttributeError, TypeError):
162 # "attribute-less object" or "read-only attributes"
175 # "attribute-less object" or "read-only attributes"
163 pass
176 pass
164 return oldvalue
177 return oldvalue
165
178
166 @undoc
179 @undoc
167 def no_op(*a, **kw):
180 def no_op(*a, **kw):
168 pass
181 pass
169
182
170
183
171 class SpaceInInput(Exception): pass
184 class SpaceInInput(Exception): pass
172
185
173
186
174 class SeparateUnicode(Unicode):
187 class SeparateUnicode(Unicode):
175 r"""A Unicode subclass to validate separate_in, separate_out, etc.
188 r"""A Unicode subclass to validate separate_in, separate_out, etc.
176
189
177 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
190 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
178 """
191 """
179
192
180 def validate(self, obj, value):
193 def validate(self, obj, value):
181 if value == '0': value = ''
194 if value == '0': value = ''
182 value = value.replace('\\n','\n')
195 value = value.replace('\\n','\n')
183 return super(SeparateUnicode, self).validate(obj, value)
196 return super(SeparateUnicode, self).validate(obj, value)
184
197
185
198
186 @undoc
199 @undoc
187 class DummyMod(object):
200 class DummyMod(object):
188 """A dummy module used for IPython's interactive module when
201 """A dummy module used for IPython's interactive module when
189 a namespace must be assigned to the module's __dict__."""
202 a namespace must be assigned to the module's __dict__."""
190 __spec__ = None
203 __spec__ = None
191
204
192
205
193 class ExecutionInfo(object):
206 class ExecutionInfo(object):
194 """The arguments used for a call to :meth:`InteractiveShell.run_cell`
207 """The arguments used for a call to :meth:`InteractiveShell.run_cell`
195
208
196 Stores information about what is going to happen.
209 Stores information about what is going to happen.
197 """
210 """
198 raw_cell = None
211 raw_cell = None
199 store_history = False
212 store_history = False
200 silent = False
213 silent = False
201 shell_futures = True
214 shell_futures = True
202 cell_id = None
215 cell_id = None
203
216
204 def __init__(self, raw_cell, store_history, silent, shell_futures, cell_id):
217 def __init__(self, raw_cell, store_history, silent, shell_futures, cell_id):
205 self.raw_cell = raw_cell
218 self.raw_cell = raw_cell
206 self.store_history = store_history
219 self.store_history = store_history
207 self.silent = silent
220 self.silent = silent
208 self.shell_futures = shell_futures
221 self.shell_futures = shell_futures
209 self.cell_id = cell_id
222 self.cell_id = cell_id
210
223
211 def __repr__(self):
224 def __repr__(self):
212 name = self.__class__.__qualname__
225 name = self.__class__.__qualname__
213 raw_cell = (
226 raw_cell = (
214 (self.raw_cell[:50] + "..") if len(self.raw_cell) > 50 else self.raw_cell
227 (self.raw_cell[:50] + "..") if len(self.raw_cell) > 50 else self.raw_cell
215 )
228 )
216 return '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s cell_id=%s>' % (
229 return (
217 name,
230 '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s cell_id=%s>'
218 id(self),
231 % (
219 raw_cell,
232 name,
220 self.store_history,
233 id(self),
221 self.silent,
234 raw_cell,
222 self.shell_futures,
235 self.store_history,
223 self.cell_id,
236 self.silent,
237 self.shell_futures,
238 self.cell_id,
239 )
224 )
240 )
225
241
226
242
227 class ExecutionResult(object):
243 class ExecutionResult(object):
228 """The result of a call to :meth:`InteractiveShell.run_cell`
244 """The result of a call to :meth:`InteractiveShell.run_cell`
229
245
230 Stores information about what took place.
246 Stores information about what took place.
231 """
247 """
232 execution_count = None
248 execution_count = None
233 error_before_exec = None
249 error_before_exec = None
234 error_in_exec: Optional[BaseException] = None
250 error_in_exec: Optional[BaseException] = None
235 info = None
251 info = None
236 result = None
252 result = None
237
253
238 def __init__(self, info):
254 def __init__(self, info):
239 self.info = info
255 self.info = info
240
256
241 @property
257 @property
242 def success(self):
258 def success(self):
243 return (self.error_before_exec is None) and (self.error_in_exec is None)
259 return (self.error_before_exec is None) and (self.error_in_exec is None)
244
260
245 def raise_error(self):
261 def raise_error(self):
246 """Reraises error if `success` is `False`, otherwise does nothing"""
262 """Reraises error if `success` is `False`, otherwise does nothing"""
247 if self.error_before_exec is not None:
263 if self.error_before_exec is not None:
248 raise self.error_before_exec
264 raise self.error_before_exec
249 if self.error_in_exec is not None:
265 if self.error_in_exec is not None:
250 raise self.error_in_exec
266 raise self.error_in_exec
251
267
252 def __repr__(self):
268 def __repr__(self):
253 name = self.__class__.__qualname__
269 name = self.__class__.__qualname__
254 return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s info=%s result=%s>' %\
270 return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s info=%s result=%s>' %\
255 (name, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.info), repr(self.result))
271 (name, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.info), repr(self.result))
256
272
273 @functools.wraps(io_open)
274 def _modified_open(file, *args, **kwargs):
275 if file in {0, 1, 2}:
276 raise ValueError(
277 f"IPython won't let you open fd={file} by default "
278 "as it is likely to crash IPython. If you know what you are doing, "
279 "you can use builtins' open."
280 )
281
282 return io_open(file, *args, **kwargs)
257
283
258 class InteractiveShell(SingletonConfigurable):
284 class InteractiveShell(SingletonConfigurable):
259 """An enhanced, interactive shell for Python."""
285 """An enhanced, interactive shell for Python."""
260
286
261 _instance = None
287 _instance = None
262
288
263 ast_transformers = List([], help=
289 ast_transformers = List([], help=
264 """
290 """
265 A list of ast.NodeTransformer subclass instances, which will be applied
291 A list of ast.NodeTransformer subclass instances, which will be applied
266 to user input before code is run.
292 to user input before code is run.
267 """
293 """
268 ).tag(config=True)
294 ).tag(config=True)
269
295
270 autocall = Enum((0,1,2), default_value=0, help=
296 autocall = Enum((0,1,2), default_value=0, help=
271 """
297 """
272 Make IPython automatically call any callable object even if you didn't
298 Make IPython automatically call any callable object even if you didn't
273 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
299 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
274 automatically. The value can be '0' to disable the feature, '1' for
300 automatically. The value can be '0' to disable the feature, '1' for
275 'smart' autocall, where it is not applied if there are no more
301 'smart' autocall, where it is not applied if there are no more
276 arguments on the line, and '2' for 'full' autocall, where all callable
302 arguments on the line, and '2' for 'full' autocall, where all callable
277 objects are automatically called (even if no arguments are present).
303 objects are automatically called (even if no arguments are present).
278 """
304 """
279 ).tag(config=True)
305 ).tag(config=True)
280
306
281 autoindent = Bool(True, help=
307 autoindent = Bool(True, help=
282 """
308 """
283 Autoindent IPython code entered interactively.
309 Autoindent IPython code entered interactively.
284 """
310 """
285 ).tag(config=True)
311 ).tag(config=True)
286
312
287 autoawait = Bool(True, help=
313 autoawait = Bool(True, help=
288 """
314 """
289 Automatically run await statement in the top level repl.
315 Automatically run await statement in the top level repl.
290 """
316 """
291 ).tag(config=True)
317 ).tag(config=True)
292
318
293 loop_runner_map ={
319 loop_runner_map ={
294 'asyncio':(_asyncio_runner, True),
320 'asyncio':(_asyncio_runner, True),
295 'curio':(_curio_runner, True),
321 'curio':(_curio_runner, True),
296 'trio':(_trio_runner, True),
322 'trio':(_trio_runner, True),
297 'sync': (_pseudo_sync_runner, False)
323 'sync': (_pseudo_sync_runner, False)
298 }
324 }
299
325
300 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
326 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
301 allow_none=True,
327 allow_none=True,
302 help="""Select the loop runner that will be used to execute top-level asynchronous code"""
328 help="""Select the loop runner that will be used to execute top-level asynchronous code"""
303 ).tag(config=True)
329 ).tag(config=True)
304
330
305 @default('loop_runner')
331 @default('loop_runner')
306 def _default_loop_runner(self):
332 def _default_loop_runner(self):
307 return import_item("IPython.core.interactiveshell._asyncio_runner")
333 return import_item("IPython.core.interactiveshell._asyncio_runner")
308
334
309 @validate('loop_runner')
335 @validate('loop_runner')
310 def _import_runner(self, proposal):
336 def _import_runner(self, proposal):
311 if isinstance(proposal.value, str):
337 if isinstance(proposal.value, str):
312 if proposal.value in self.loop_runner_map:
338 if proposal.value in self.loop_runner_map:
313 runner, autoawait = self.loop_runner_map[proposal.value]
339 runner, autoawait = self.loop_runner_map[proposal.value]
314 self.autoawait = autoawait
340 self.autoawait = autoawait
315 return runner
341 return runner
316 runner = import_item(proposal.value)
342 runner = import_item(proposal.value)
317 if not callable(runner):
343 if not callable(runner):
318 raise ValueError('loop_runner must be callable')
344 raise ValueError('loop_runner must be callable')
319 return runner
345 return runner
320 if not callable(proposal.value):
346 if not callable(proposal.value):
321 raise ValueError('loop_runner must be callable')
347 raise ValueError('loop_runner must be callable')
322 return proposal.value
348 return proposal.value
323
349
324 automagic = Bool(True, help=
350 automagic = Bool(True, help=
325 """
351 """
326 Enable magic commands to be called without the leading %.
352 Enable magic commands to be called without the leading %.
327 """
353 """
328 ).tag(config=True)
354 ).tag(config=True)
329
355
330 banner1 = Unicode(default_banner,
356 banner1 = Unicode(default_banner,
331 help="""The part of the banner to be printed before the profile"""
357 help="""The part of the banner to be printed before the profile"""
332 ).tag(config=True)
358 ).tag(config=True)
333 banner2 = Unicode('',
359 banner2 = Unicode('',
334 help="""The part of the banner to be printed after the profile"""
360 help="""The part of the banner to be printed after the profile"""
335 ).tag(config=True)
361 ).tag(config=True)
336
362
337 cache_size = Integer(1000, help=
363 cache_size = Integer(1000, help=
338 """
364 """
339 Set the size of the output cache. The default is 1000, you can
365 Set the size of the output cache. The default is 1000, you can
340 change it permanently in your config file. Setting it to 0 completely
366 change it permanently in your config file. Setting it to 0 completely
341 disables the caching system, and the minimum value accepted is 3 (if
367 disables the caching system, and the minimum value accepted is 3 (if
342 you provide a value less than 3, it is reset to 0 and a warning is
368 you provide a value less than 3, it is reset to 0 and a warning is
343 issued). This limit is defined because otherwise you'll spend more
369 issued). This limit is defined because otherwise you'll spend more
344 time re-flushing a too small cache than working
370 time re-flushing a too small cache than working
345 """
371 """
346 ).tag(config=True)
372 ).tag(config=True)
347 color_info = Bool(True, help=
373 color_info = Bool(True, help=
348 """
374 """
349 Use colors for displaying information about objects. Because this
375 Use colors for displaying information about objects. Because this
350 information is passed through a pager (like 'less'), and some pagers
376 information is passed through a pager (like 'less'), and some pagers
351 get confused with color codes, this capability can be turned off.
377 get confused with color codes, this capability can be turned off.
352 """
378 """
353 ).tag(config=True)
379 ).tag(config=True)
354 colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'),
380 colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'),
355 default_value='Neutral',
381 default_value='Neutral',
356 help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)."
382 help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)."
357 ).tag(config=True)
383 ).tag(config=True)
358 debug = Bool(False).tag(config=True)
384 debug = Bool(False).tag(config=True)
359 disable_failing_post_execute = Bool(False,
385 disable_failing_post_execute = Bool(False,
360 help="Don't call post-execute functions that have failed in the past."
386 help="Don't call post-execute functions that have failed in the past."
361 ).tag(config=True)
387 ).tag(config=True)
362 display_formatter = Instance(DisplayFormatter, allow_none=True)
388 display_formatter = Instance(DisplayFormatter, allow_none=True)
363 displayhook_class = Type(DisplayHook)
389 displayhook_class = Type(DisplayHook)
364 display_pub_class = Type(DisplayPublisher)
390 display_pub_class = Type(DisplayPublisher)
365 compiler_class = Type(CachingCompiler)
391 compiler_class = Type(CachingCompiler)
366
392
367 sphinxify_docstring = Bool(False, help=
393 sphinxify_docstring = Bool(False, help=
368 """
394 """
369 Enables rich html representation of docstrings. (This requires the
395 Enables rich html representation of docstrings. (This requires the
370 docrepr module).
396 docrepr module).
371 """).tag(config=True)
397 """).tag(config=True)
372
398
373 @observe("sphinxify_docstring")
399 @observe("sphinxify_docstring")
374 def _sphinxify_docstring_changed(self, change):
400 def _sphinxify_docstring_changed(self, change):
375 if change['new']:
401 if change['new']:
376 warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning)
402 warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning)
377
403
378 enable_html_pager = Bool(False, help=
404 enable_html_pager = Bool(False, help=
379 """
405 """
380 (Provisional API) enables html representation in mime bundles sent
406 (Provisional API) enables html representation in mime bundles sent
381 to pagers.
407 to pagers.
382 """).tag(config=True)
408 """).tag(config=True)
383
409
384 @observe("enable_html_pager")
410 @observe("enable_html_pager")
385 def _enable_html_pager_changed(self, change):
411 def _enable_html_pager_changed(self, change):
386 if change['new']:
412 if change['new']:
387 warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning)
413 warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning)
388
414
389 data_pub_class = None
415 data_pub_class = None
390
416
391 exit_now = Bool(False)
417 exit_now = Bool(False)
392 exiter = Instance(ExitAutocall)
418 exiter = Instance(ExitAutocall)
393 @default('exiter')
419 @default('exiter')
394 def _exiter_default(self):
420 def _exiter_default(self):
395 return ExitAutocall(self)
421 return ExitAutocall(self)
396 # Monotonically increasing execution counter
422 # Monotonically increasing execution counter
397 execution_count = Integer(1)
423 execution_count = Integer(1)
398 filename = Unicode("<ipython console>")
424 filename = Unicode("<ipython console>")
399 ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__
425 ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__
400
426
401 # Used to transform cells before running them, and check whether code is complete
427 # Used to transform cells before running them, and check whether code is complete
402 input_transformer_manager = Instance('IPython.core.inputtransformer2.TransformerManager',
428 input_transformer_manager = Instance('IPython.core.inputtransformer2.TransformerManager',
403 ())
429 ())
404
430
405 @property
431 @property
406 def input_transformers_cleanup(self):
432 def input_transformers_cleanup(self):
407 return self.input_transformer_manager.cleanup_transforms
433 return self.input_transformer_manager.cleanup_transforms
408
434
409 input_transformers_post = List([],
435 input_transformers_post = List([],
410 help="A list of string input transformers, to be applied after IPython's "
436 help="A list of string input transformers, to be applied after IPython's "
411 "own input transformations."
437 "own input transformations."
412 )
438 )
413
439
414 @property
440 @property
415 def input_splitter(self):
441 def input_splitter(self):
416 """Make this available for backward compatibility (pre-7.0 release) with existing code.
442 """Make this available for backward compatibility (pre-7.0 release) with existing code.
417
443
418 For example, ipykernel ipykernel currently uses
444 For example, ipykernel ipykernel currently uses
419 `shell.input_splitter.check_complete`
445 `shell.input_splitter.check_complete`
420 """
446 """
421 from warnings import warn
447 from warnings import warn
422 warn("`input_splitter` is deprecated since IPython 7.0, prefer `input_transformer_manager`.",
448 warn("`input_splitter` is deprecated since IPython 7.0, prefer `input_transformer_manager`.",
423 DeprecationWarning, stacklevel=2
449 DeprecationWarning, stacklevel=2
424 )
450 )
425 return self.input_transformer_manager
451 return self.input_transformer_manager
426
452
427 logstart = Bool(False, help=
453 logstart = Bool(False, help=
428 """
454 """
429 Start logging to the default log file in overwrite mode.
455 Start logging to the default log file in overwrite mode.
430 Use `logappend` to specify a log file to **append** logs to.
456 Use `logappend` to specify a log file to **append** logs to.
431 """
457 """
432 ).tag(config=True)
458 ).tag(config=True)
433 logfile = Unicode('', help=
459 logfile = Unicode('', help=
434 """
460 """
435 The name of the logfile to use.
461 The name of the logfile to use.
436 """
462 """
437 ).tag(config=True)
463 ).tag(config=True)
438 logappend = Unicode('', help=
464 logappend = Unicode('', help=
439 """
465 """
440 Start logging to the given file in append mode.
466 Start logging to the given file in append mode.
441 Use `logfile` to specify a log file to **overwrite** logs to.
467 Use `logfile` to specify a log file to **overwrite** logs to.
442 """
468 """
443 ).tag(config=True)
469 ).tag(config=True)
444 object_info_string_level = Enum((0,1,2), default_value=0,
470 object_info_string_level = Enum((0,1,2), default_value=0,
445 ).tag(config=True)
471 ).tag(config=True)
446 pdb = Bool(False, help=
472 pdb = Bool(False, help=
447 """
473 """
448 Automatically call the pdb debugger after every exception.
474 Automatically call the pdb debugger after every exception.
449 """
475 """
450 ).tag(config=True)
476 ).tag(config=True)
451 display_page = Bool(False,
477 display_page = Bool(False,
452 help="""If True, anything that would be passed to the pager
478 help="""If True, anything that would be passed to the pager
453 will be displayed as regular output instead."""
479 will be displayed as regular output instead."""
454 ).tag(config=True)
480 ).tag(config=True)
455
481
456
482
457 show_rewritten_input = Bool(True,
483 show_rewritten_input = Bool(True,
458 help="Show rewritten input, e.g. for autocall."
484 help="Show rewritten input, e.g. for autocall."
459 ).tag(config=True)
485 ).tag(config=True)
460
486
461 quiet = Bool(False).tag(config=True)
487 quiet = Bool(False).tag(config=True)
462
488
463 history_length = Integer(10000,
489 history_length = Integer(10000,
464 help='Total length of command history'
490 help='Total length of command history'
465 ).tag(config=True)
491 ).tag(config=True)
466
492
467 history_load_length = Integer(1000, help=
493 history_load_length = Integer(1000, help=
468 """
494 """
469 The number of saved history entries to be loaded
495 The number of saved history entries to be loaded
470 into the history buffer at startup.
496 into the history buffer at startup.
471 """
497 """
472 ).tag(config=True)
498 ).tag(config=True)
473
499
474 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'],
500 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'],
475 default_value='last_expr',
501 default_value='last_expr',
476 help="""
502 help="""
477 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying
503 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying
478 which nodes should be run interactively (displaying output from expressions).
504 which nodes should be run interactively (displaying output from expressions).
479 """
505 """
480 ).tag(config=True)
506 ).tag(config=True)
481
507
482 warn_venv = Bool(
508 warn_venv = Bool(
483 True,
509 True,
484 help="Warn if running in a virtual environment with no IPython installed (so IPython from the global environment is used).",
510 help="Warn if running in a virtual environment with no IPython installed (so IPython from the global environment is used).",
485 ).tag(config=True)
511 ).tag(config=True)
486
512
487 # TODO: this part of prompt management should be moved to the frontends.
513 # TODO: this part of prompt management should be moved to the frontends.
488 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
514 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
489 separate_in = SeparateUnicode('\n').tag(config=True)
515 separate_in = SeparateUnicode('\n').tag(config=True)
490 separate_out = SeparateUnicode('').tag(config=True)
516 separate_out = SeparateUnicode('').tag(config=True)
491 separate_out2 = SeparateUnicode('').tag(config=True)
517 separate_out2 = SeparateUnicode('').tag(config=True)
492 wildcards_case_sensitive = Bool(True).tag(config=True)
518 wildcards_case_sensitive = Bool(True).tag(config=True)
493 xmode = CaselessStrEnum(('Context', 'Plain', 'Verbose', 'Minimal'),
519 xmode = CaselessStrEnum(('Context', 'Plain', 'Verbose', 'Minimal'),
494 default_value='Context',
520 default_value='Context',
495 help="Switch modes for the IPython exception handlers."
521 help="Switch modes for the IPython exception handlers."
496 ).tag(config=True)
522 ).tag(config=True)
497
523
498 # Subcomponents of InteractiveShell
524 # Subcomponents of InteractiveShell
499 alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True)
525 alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True)
500 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
526 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
501 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap', allow_none=True)
527 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap', allow_none=True)
502 display_trap = Instance('IPython.core.display_trap.DisplayTrap', allow_none=True)
528 display_trap = Instance('IPython.core.display_trap.DisplayTrap', allow_none=True)
503 extension_manager = Instance('IPython.core.extensions.ExtensionManager', allow_none=True)
529 extension_manager = Instance('IPython.core.extensions.ExtensionManager', allow_none=True)
504 payload_manager = Instance('IPython.core.payload.PayloadManager', allow_none=True)
530 payload_manager = Instance('IPython.core.payload.PayloadManager', allow_none=True)
505 history_manager = Instance('IPython.core.history.HistoryAccessorBase', allow_none=True)
531 history_manager = Instance('IPython.core.history.HistoryAccessorBase', allow_none=True)
506 magics_manager = Instance('IPython.core.magic.MagicsManager', allow_none=True)
532 magics_manager = Instance('IPython.core.magic.MagicsManager', allow_none=True)
507
533
508 profile_dir = Instance('IPython.core.application.ProfileDir', allow_none=True)
534 profile_dir = Instance('IPython.core.application.ProfileDir', allow_none=True)
509 @property
535 @property
510 def profile(self):
536 def profile(self):
511 if self.profile_dir is not None:
537 if self.profile_dir is not None:
512 name = os.path.basename(self.profile_dir.location)
538 name = os.path.basename(self.profile_dir.location)
513 return name.replace('profile_','')
539 return name.replace('profile_','')
514
540
515
541
516 # Private interface
542 # Private interface
517 _post_execute = Dict()
543 _post_execute = Dict()
518
544
519 # Tracks any GUI loop loaded for pylab
545 # Tracks any GUI loop loaded for pylab
520 pylab_gui_select = None
546 pylab_gui_select = None
521
547
522 last_execution_succeeded = Bool(True, help='Did last executed command succeeded')
548 last_execution_succeeded = Bool(True, help='Did last executed command succeeded')
523
549
524 last_execution_result = Instance('IPython.core.interactiveshell.ExecutionResult', help='Result of executing the last command', allow_none=True)
550 last_execution_result = Instance('IPython.core.interactiveshell.ExecutionResult', help='Result of executing the last command', allow_none=True)
525
551
526 def __init__(self, ipython_dir=None, profile_dir=None,
552 def __init__(self, ipython_dir=None, profile_dir=None,
527 user_module=None, user_ns=None,
553 user_module=None, user_ns=None,
528 custom_exceptions=((), None), **kwargs):
554 custom_exceptions=((), None), **kwargs):
529 # This is where traits with a config_key argument are updated
555 # This is where traits with a config_key argument are updated
530 # from the values on config.
556 # from the values on config.
531 super(InteractiveShell, self).__init__(**kwargs)
557 super(InteractiveShell, self).__init__(**kwargs)
532 if 'PromptManager' in self.config:
558 if 'PromptManager' in self.config:
533 warn('As of IPython 5.0 `PromptManager` config will have no effect'
559 warn('As of IPython 5.0 `PromptManager` config will have no effect'
534 ' and has been replaced by TerminalInteractiveShell.prompts_class')
560 ' and has been replaced by TerminalInteractiveShell.prompts_class')
535 self.configurables = [self]
561 self.configurables = [self]
536
562
537 # These are relatively independent and stateless
563 # These are relatively independent and stateless
538 self.init_ipython_dir(ipython_dir)
564 self.init_ipython_dir(ipython_dir)
539 self.init_profile_dir(profile_dir)
565 self.init_profile_dir(profile_dir)
540 self.init_instance_attrs()
566 self.init_instance_attrs()
541 self.init_environment()
567 self.init_environment()
542
568
543 # Check if we're in a virtualenv, and set up sys.path.
569 # Check if we're in a virtualenv, and set up sys.path.
544 self.init_virtualenv()
570 self.init_virtualenv()
545
571
546 # Create namespaces (user_ns, user_global_ns, etc.)
572 # Create namespaces (user_ns, user_global_ns, etc.)
547 self.init_create_namespaces(user_module, user_ns)
573 self.init_create_namespaces(user_module, user_ns)
548 # This has to be done after init_create_namespaces because it uses
574 # This has to be done after init_create_namespaces because it uses
549 # something in self.user_ns, but before init_sys_modules, which
575 # something in self.user_ns, but before init_sys_modules, which
550 # is the first thing to modify sys.
576 # is the first thing to modify sys.
551 # TODO: When we override sys.stdout and sys.stderr before this class
577 # TODO: When we override sys.stdout and sys.stderr before this class
552 # is created, we are saving the overridden ones here. Not sure if this
578 # is created, we are saving the overridden ones here. Not sure if this
553 # is what we want to do.
579 # is what we want to do.
554 self.save_sys_module_state()
580 self.save_sys_module_state()
555 self.init_sys_modules()
581 self.init_sys_modules()
556
582
557 # While we're trying to have each part of the code directly access what
583 # While we're trying to have each part of the code directly access what
558 # it needs without keeping redundant references to objects, we have too
584 # it needs without keeping redundant references to objects, we have too
559 # much legacy code that expects ip.db to exist.
585 # much legacy code that expects ip.db to exist.
560 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
586 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
561
587
562 self.init_history()
588 self.init_history()
563 self.init_encoding()
589 self.init_encoding()
564 self.init_prefilter()
590 self.init_prefilter()
565
591
566 self.init_syntax_highlighting()
592 self.init_syntax_highlighting()
567 self.init_hooks()
593 self.init_hooks()
568 self.init_events()
594 self.init_events()
569 self.init_pushd_popd_magic()
595 self.init_pushd_popd_magic()
570 self.init_user_ns()
596 self.init_user_ns()
571 self.init_logger()
597 self.init_logger()
572 self.init_builtins()
598 self.init_builtins()
573
599
574 # The following was in post_config_initialization
600 # The following was in post_config_initialization
575 self.init_inspector()
601 self.init_inspector()
576 self.raw_input_original = input
602 self.raw_input_original = input
577 self.init_completer()
603 self.init_completer()
578 # TODO: init_io() needs to happen before init_traceback handlers
604 # TODO: init_io() needs to happen before init_traceback handlers
579 # because the traceback handlers hardcode the stdout/stderr streams.
605 # because the traceback handlers hardcode the stdout/stderr streams.
580 # This logic in in debugger.Pdb and should eventually be changed.
606 # This logic in in debugger.Pdb and should eventually be changed.
581 self.init_io()
607 self.init_io()
582 self.init_traceback_handlers(custom_exceptions)
608 self.init_traceback_handlers(custom_exceptions)
583 self.init_prompts()
609 self.init_prompts()
584 self.init_display_formatter()
610 self.init_display_formatter()
585 self.init_display_pub()
611 self.init_display_pub()
586 self.init_data_pub()
612 self.init_data_pub()
587 self.init_displayhook()
613 self.init_displayhook()
588 self.init_magics()
614 self.init_magics()
589 self.init_alias()
615 self.init_alias()
590 self.init_logstart()
616 self.init_logstart()
591 self.init_pdb()
617 self.init_pdb()
592 self.init_extension_manager()
618 self.init_extension_manager()
593 self.init_payload()
619 self.init_payload()
594 self.events.trigger('shell_initialized', self)
620 self.events.trigger('shell_initialized', self)
595 atexit.register(self.atexit_operations)
621 atexit.register(self.atexit_operations)
596
622
597 # The trio runner is used for running Trio in the foreground thread. It
623 # The trio runner is used for running Trio in the foreground thread. It
598 # is different from `_trio_runner(async_fn)` in `async_helpers.py`
624 # is different from `_trio_runner(async_fn)` in `async_helpers.py`
599 # which calls `trio.run()` for every cell. This runner runs all cells
625 # which calls `trio.run()` for every cell. This runner runs all cells
600 # inside a single Trio event loop. If used, it is set from
626 # inside a single Trio event loop. If used, it is set from
601 # `ipykernel.kernelapp`.
627 # `ipykernel.kernelapp`.
602 self.trio_runner = None
628 self.trio_runner = None
603
629
604 def get_ipython(self):
630 def get_ipython(self):
605 """Return the currently running IPython instance."""
631 """Return the currently running IPython instance."""
606 return self
632 return self
607
633
608 #-------------------------------------------------------------------------
634 #-------------------------------------------------------------------------
609 # Trait changed handlers
635 # Trait changed handlers
610 #-------------------------------------------------------------------------
636 #-------------------------------------------------------------------------
611 @observe('ipython_dir')
637 @observe('ipython_dir')
612 def _ipython_dir_changed(self, change):
638 def _ipython_dir_changed(self, change):
613 ensure_dir_exists(change['new'])
639 ensure_dir_exists(change['new'])
614
640
615 def set_autoindent(self,value=None):
641 def set_autoindent(self,value=None):
616 """Set the autoindent flag.
642 """Set the autoindent flag.
617
643
618 If called with no arguments, it acts as a toggle."""
644 If called with no arguments, it acts as a toggle."""
619 if value is None:
645 if value is None:
620 self.autoindent = not self.autoindent
646 self.autoindent = not self.autoindent
621 else:
647 else:
622 self.autoindent = value
648 self.autoindent = value
623
649
624 def set_trio_runner(self, tr):
650 def set_trio_runner(self, tr):
625 self.trio_runner = tr
651 self.trio_runner = tr
626
652
627 #-------------------------------------------------------------------------
653 #-------------------------------------------------------------------------
628 # init_* methods called by __init__
654 # init_* methods called by __init__
629 #-------------------------------------------------------------------------
655 #-------------------------------------------------------------------------
630
656
631 def init_ipython_dir(self, ipython_dir):
657 def init_ipython_dir(self, ipython_dir):
632 if ipython_dir is not None:
658 if ipython_dir is not None:
633 self.ipython_dir = ipython_dir
659 self.ipython_dir = ipython_dir
634 return
660 return
635
661
636 self.ipython_dir = get_ipython_dir()
662 self.ipython_dir = get_ipython_dir()
637
663
638 def init_profile_dir(self, profile_dir):
664 def init_profile_dir(self, profile_dir):
639 if profile_dir is not None:
665 if profile_dir is not None:
640 self.profile_dir = profile_dir
666 self.profile_dir = profile_dir
641 return
667 return
642 self.profile_dir = ProfileDir.create_profile_dir_by_name(
668 self.profile_dir = ProfileDir.create_profile_dir_by_name(
643 self.ipython_dir, "default"
669 self.ipython_dir, "default"
644 )
670 )
645
671
646 def init_instance_attrs(self):
672 def init_instance_attrs(self):
647 self.more = False
673 self.more = False
648
674
649 # command compiler
675 # command compiler
650 self.compile = self.compiler_class()
676 self.compile = self.compiler_class()
651
677
652 # Make an empty namespace, which extension writers can rely on both
678 # Make an empty namespace, which extension writers can rely on both
653 # existing and NEVER being used by ipython itself. This gives them a
679 # existing and NEVER being used by ipython itself. This gives them a
654 # convenient location for storing additional information and state
680 # convenient location for storing additional information and state
655 # their extensions may require, without fear of collisions with other
681 # their extensions may require, without fear of collisions with other
656 # ipython names that may develop later.
682 # ipython names that may develop later.
657 self.meta = Struct()
683 self.meta = Struct()
658
684
659 # Temporary files used for various purposes. Deleted at exit.
685 # Temporary files used for various purposes. Deleted at exit.
660 # The files here are stored with Path from Pathlib
686 # The files here are stored with Path from Pathlib
661 self.tempfiles = []
687 self.tempfiles = []
662 self.tempdirs = []
688 self.tempdirs = []
663
689
664 # keep track of where we started running (mainly for crash post-mortem)
690 # keep track of where we started running (mainly for crash post-mortem)
665 # This is not being used anywhere currently.
691 # This is not being used anywhere currently.
666 self.starting_dir = os.getcwd()
692 self.starting_dir = os.getcwd()
667
693
668 # Indentation management
694 # Indentation management
669 self.indent_current_nsp = 0
695 self.indent_current_nsp = 0
670
696
671 # Dict to track post-execution functions that have been registered
697 # Dict to track post-execution functions that have been registered
672 self._post_execute = {}
698 self._post_execute = {}
673
699
674 def init_environment(self):
700 def init_environment(self):
675 """Any changes we need to make to the user's environment."""
701 """Any changes we need to make to the user's environment."""
676 pass
702 pass
677
703
678 def init_encoding(self):
704 def init_encoding(self):
679 # Get system encoding at startup time. Certain terminals (like Emacs
705 # Get system encoding at startup time. Certain terminals (like Emacs
680 # under Win32 have it set to None, and we need to have a known valid
706 # under Win32 have it set to None, and we need to have a known valid
681 # encoding to use in the raw_input() method
707 # encoding to use in the raw_input() method
682 try:
708 try:
683 self.stdin_encoding = sys.stdin.encoding or 'ascii'
709 self.stdin_encoding = sys.stdin.encoding or 'ascii'
684 except AttributeError:
710 except AttributeError:
685 self.stdin_encoding = 'ascii'
711 self.stdin_encoding = 'ascii'
686
712
687
713
688 @observe('colors')
714 @observe('colors')
689 def init_syntax_highlighting(self, changes=None):
715 def init_syntax_highlighting(self, changes=None):
690 # Python source parser/formatter for syntax highlighting
716 # Python source parser/formatter for syntax highlighting
691 pyformat = PyColorize.Parser(style=self.colors, parent=self).format
717 pyformat = PyColorize.Parser(style=self.colors, parent=self).format
692 self.pycolorize = lambda src: pyformat(src,'str')
718 self.pycolorize = lambda src: pyformat(src,'str')
693
719
694 def refresh_style(self):
720 def refresh_style(self):
695 # No-op here, used in subclass
721 # No-op here, used in subclass
696 pass
722 pass
697
723
698 def init_pushd_popd_magic(self):
724 def init_pushd_popd_magic(self):
699 # for pushd/popd management
725 # for pushd/popd management
700 self.home_dir = get_home_dir()
726 self.home_dir = get_home_dir()
701
727
702 self.dir_stack = []
728 self.dir_stack = []
703
729
704 def init_logger(self):
730 def init_logger(self):
705 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
731 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
706 logmode='rotate')
732 logmode='rotate')
707
733
708 def init_logstart(self):
734 def init_logstart(self):
709 """Initialize logging in case it was requested at the command line.
735 """Initialize logging in case it was requested at the command line.
710 """
736 """
711 if self.logappend:
737 if self.logappend:
712 self.magic('logstart %s append' % self.logappend)
738 self.magic('logstart %s append' % self.logappend)
713 elif self.logfile:
739 elif self.logfile:
714 self.magic('logstart %s' % self.logfile)
740 self.magic('logstart %s' % self.logfile)
715 elif self.logstart:
741 elif self.logstart:
716 self.magic('logstart')
742 self.magic('logstart')
717
743
718
744
719 def init_builtins(self):
745 def init_builtins(self):
720 # A single, static flag that we set to True. Its presence indicates
746 # A single, static flag that we set to True. Its presence indicates
721 # that an IPython shell has been created, and we make no attempts at
747 # that an IPython shell has been created, and we make no attempts at
722 # removing on exit or representing the existence of more than one
748 # removing on exit or representing the existence of more than one
723 # IPython at a time.
749 # IPython at a time.
724 builtin_mod.__dict__['__IPYTHON__'] = True
750 builtin_mod.__dict__['__IPYTHON__'] = True
725 builtin_mod.__dict__['display'] = display
751 builtin_mod.__dict__['display'] = display
726
752
727 self.builtin_trap = BuiltinTrap(shell=self)
753 self.builtin_trap = BuiltinTrap(shell=self)
728
754
729 @observe('colors')
755 @observe('colors')
730 def init_inspector(self, changes=None):
756 def init_inspector(self, changes=None):
731 # Object inspector
757 # Object inspector
732 self.inspector = oinspect.Inspector(oinspect.InspectColors,
758 self.inspector = oinspect.Inspector(oinspect.InspectColors,
733 PyColorize.ANSICodeColors,
759 PyColorize.ANSICodeColors,
734 self.colors,
760 self.colors,
735 self.object_info_string_level)
761 self.object_info_string_level)
736
762
737 def init_io(self):
763 def init_io(self):
738 # implemented in subclasses, TerminalInteractiveShell does call
764 # implemented in subclasses, TerminalInteractiveShell does call
739 # colorama.init().
765 # colorama.init().
740 pass
766 pass
741
767
742 def init_prompts(self):
768 def init_prompts(self):
743 # Set system prompts, so that scripts can decide if they are running
769 # Set system prompts, so that scripts can decide if they are running
744 # interactively.
770 # interactively.
745 sys.ps1 = 'In : '
771 sys.ps1 = 'In : '
746 sys.ps2 = '...: '
772 sys.ps2 = '...: '
747 sys.ps3 = 'Out: '
773 sys.ps3 = 'Out: '
748
774
749 def init_display_formatter(self):
775 def init_display_formatter(self):
750 self.display_formatter = DisplayFormatter(parent=self)
776 self.display_formatter = DisplayFormatter(parent=self)
751 self.configurables.append(self.display_formatter)
777 self.configurables.append(self.display_formatter)
752
778
753 def init_display_pub(self):
779 def init_display_pub(self):
754 self.display_pub = self.display_pub_class(parent=self, shell=self)
780 self.display_pub = self.display_pub_class(parent=self, shell=self)
755 self.configurables.append(self.display_pub)
781 self.configurables.append(self.display_pub)
756
782
757 def init_data_pub(self):
783 def init_data_pub(self):
758 if not self.data_pub_class:
784 if not self.data_pub_class:
759 self.data_pub = None
785 self.data_pub = None
760 return
786 return
761 self.data_pub = self.data_pub_class(parent=self)
787 self.data_pub = self.data_pub_class(parent=self)
762 self.configurables.append(self.data_pub)
788 self.configurables.append(self.data_pub)
763
789
764 def init_displayhook(self):
790 def init_displayhook(self):
765 # Initialize displayhook, set in/out prompts and printing system
791 # Initialize displayhook, set in/out prompts and printing system
766 self.displayhook = self.displayhook_class(
792 self.displayhook = self.displayhook_class(
767 parent=self,
793 parent=self,
768 shell=self,
794 shell=self,
769 cache_size=self.cache_size,
795 cache_size=self.cache_size,
770 )
796 )
771 self.configurables.append(self.displayhook)
797 self.configurables.append(self.displayhook)
772 # This is a context manager that installs/revmoes the displayhook at
798 # This is a context manager that installs/revmoes the displayhook at
773 # the appropriate time.
799 # the appropriate time.
774 self.display_trap = DisplayTrap(hook=self.displayhook)
800 self.display_trap = DisplayTrap(hook=self.displayhook)
775
801
776 @staticmethod
802 @staticmethod
777 def get_path_links(p: Path):
803 def get_path_links(p: Path):
778 """Gets path links including all symlinks
804 """Gets path links including all symlinks
779
805
780 Examples
806 Examples
781 --------
807 --------
782 In [1]: from IPython.core.interactiveshell import InteractiveShell
808 In [1]: from IPython.core.interactiveshell import InteractiveShell
783
809
784 In [2]: import sys, pathlib
810 In [2]: import sys, pathlib
785
811
786 In [3]: paths = InteractiveShell.get_path_links(pathlib.Path(sys.executable))
812 In [3]: paths = InteractiveShell.get_path_links(pathlib.Path(sys.executable))
787
813
788 In [4]: len(paths) == len(set(paths))
814 In [4]: len(paths) == len(set(paths))
789 Out[4]: True
815 Out[4]: True
790
816
791 In [5]: bool(paths)
817 In [5]: bool(paths)
792 Out[5]: True
818 Out[5]: True
793 """
819 """
794 paths = [p]
820 paths = [p]
795 while p.is_symlink():
821 while p.is_symlink():
796 new_path = Path(os.readlink(p))
822 new_path = Path(os.readlink(p))
797 if not new_path.is_absolute():
823 if not new_path.is_absolute():
798 new_path = p.parent / new_path
824 new_path = p.parent / new_path
799 p = new_path
825 p = new_path
800 paths.append(p)
826 paths.append(p)
801 return paths
827 return paths
802
828
803 def init_virtualenv(self):
829 def init_virtualenv(self):
804 """Add the current virtualenv to sys.path so the user can import modules from it.
830 """Add the current virtualenv to sys.path so the user can import modules from it.
805 This isn't perfect: it doesn't use the Python interpreter with which the
831 This isn't perfect: it doesn't use the Python interpreter with which the
806 virtualenv was built, and it ignores the --no-site-packages option. A
832 virtualenv was built, and it ignores the --no-site-packages option. A
807 warning will appear suggesting the user installs IPython in the
833 warning will appear suggesting the user installs IPython in the
808 virtualenv, but for many cases, it probably works well enough.
834 virtualenv, but for many cases, it probably works well enough.
809
835
810 Adapted from code snippets online.
836 Adapted from code snippets online.
811
837
812 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
838 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
813 """
839 """
814 if 'VIRTUAL_ENV' not in os.environ:
840 if 'VIRTUAL_ENV' not in os.environ:
815 # Not in a virtualenv
841 # Not in a virtualenv
816 return
842 return
817 elif os.environ["VIRTUAL_ENV"] == "":
843 elif os.environ["VIRTUAL_ENV"] == "":
818 warn("Virtual env path set to '', please check if this is intended.")
844 warn("Virtual env path set to '', please check if this is intended.")
819 return
845 return
820
846
821 p = Path(sys.executable)
847 p = Path(sys.executable)
822 p_venv = Path(os.environ["VIRTUAL_ENV"])
848 p_venv = Path(os.environ["VIRTUAL_ENV"])
823
849
824 # fallback venv detection:
850 # fallback venv detection:
825 # stdlib venv may symlink sys.executable, so we can't use realpath.
851 # stdlib venv may symlink sys.executable, so we can't use realpath.
826 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
852 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
827 # So we just check every item in the symlink tree (generally <= 3)
853 # So we just check every item in the symlink tree (generally <= 3)
828 paths = self.get_path_links(p)
854 paths = self.get_path_links(p)
829
855
830 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
856 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
831 if p_venv.parts[1] == "cygdrive":
857 if p_venv.parts[1] == "cygdrive":
832 drive_name = p_venv.parts[2]
858 drive_name = p_venv.parts[2]
833 p_venv = (drive_name + ":/") / Path(*p_venv.parts[3:])
859 p_venv = (drive_name + ":/") / Path(*p_venv.parts[3:])
834
860
835 if any(p_venv == p.parents[1] for p in paths):
861 if any(p_venv == p.parents[1] for p in paths):
836 # Our exe is inside or has access to the virtualenv, don't need to do anything.
862 # Our exe is inside or has access to the virtualenv, don't need to do anything.
837 return
863 return
838
864
839 if sys.platform == "win32":
865 if sys.platform == "win32":
840 virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages"))
866 virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages"))
841 else:
867 else:
842 virtual_env_path = Path(
868 virtual_env_path = Path(
843 os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
869 os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
844 )
870 )
845 p_ver = sys.version_info[:2]
871 p_ver = sys.version_info[:2]
846
872
847 # Predict version from py[thon]-x.x in the $VIRTUAL_ENV
873 # Predict version from py[thon]-x.x in the $VIRTUAL_ENV
848 re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
874 re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
849 if re_m:
875 if re_m:
850 predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
876 predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
851 if predicted_path.exists():
877 if predicted_path.exists():
852 p_ver = re_m.groups()
878 p_ver = re_m.groups()
853
879
854 virtual_env = str(virtual_env_path).format(*p_ver)
880 virtual_env = str(virtual_env_path).format(*p_ver)
855 if self.warn_venv:
881 if self.warn_venv:
856 warn(
882 warn(
857 "Attempting to work in a virtualenv. If you encounter problems, "
883 "Attempting to work in a virtualenv. If you encounter problems, "
858 "please install IPython inside the virtualenv."
884 "please install IPython inside the virtualenv."
859 )
885 )
860 import site
886 import site
861 sys.path.insert(0, virtual_env)
887 sys.path.insert(0, virtual_env)
862 site.addsitedir(virtual_env)
888 site.addsitedir(virtual_env)
863
889
864 #-------------------------------------------------------------------------
890 #-------------------------------------------------------------------------
865 # Things related to injections into the sys module
891 # Things related to injections into the sys module
866 #-------------------------------------------------------------------------
892 #-------------------------------------------------------------------------
867
893
868 def save_sys_module_state(self):
894 def save_sys_module_state(self):
869 """Save the state of hooks in the sys module.
895 """Save the state of hooks in the sys module.
870
896
871 This has to be called after self.user_module is created.
897 This has to be called after self.user_module is created.
872 """
898 """
873 self._orig_sys_module_state = {'stdin': sys.stdin,
899 self._orig_sys_module_state = {'stdin': sys.stdin,
874 'stdout': sys.stdout,
900 'stdout': sys.stdout,
875 'stderr': sys.stderr,
901 'stderr': sys.stderr,
876 'excepthook': sys.excepthook}
902 'excepthook': sys.excepthook}
877 self._orig_sys_modules_main_name = self.user_module.__name__
903 self._orig_sys_modules_main_name = self.user_module.__name__
878 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
904 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
879
905
880 def restore_sys_module_state(self):
906 def restore_sys_module_state(self):
881 """Restore the state of the sys module."""
907 """Restore the state of the sys module."""
882 try:
908 try:
883 for k, v in self._orig_sys_module_state.items():
909 for k, v in self._orig_sys_module_state.items():
884 setattr(sys, k, v)
910 setattr(sys, k, v)
885 except AttributeError:
911 except AttributeError:
886 pass
912 pass
887 # Reset what what done in self.init_sys_modules
913 # Reset what what done in self.init_sys_modules
888 if self._orig_sys_modules_main_mod is not None:
914 if self._orig_sys_modules_main_mod is not None:
889 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
915 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
890
916
891 #-------------------------------------------------------------------------
917 #-------------------------------------------------------------------------
892 # Things related to the banner
918 # Things related to the banner
893 #-------------------------------------------------------------------------
919 #-------------------------------------------------------------------------
894
920
895 @property
921 @property
896 def banner(self):
922 def banner(self):
897 banner = self.banner1
923 banner = self.banner1
898 if self.profile and self.profile != 'default':
924 if self.profile and self.profile != 'default':
899 banner += '\nIPython profile: %s\n' % self.profile
925 banner += '\nIPython profile: %s\n' % self.profile
900 if self.banner2:
926 if self.banner2:
901 banner += '\n' + self.banner2
927 banner += '\n' + self.banner2
902 return banner
928 return banner
903
929
904 def show_banner(self, banner=None):
930 def show_banner(self, banner=None):
905 if banner is None:
931 if banner is None:
906 banner = self.banner
932 banner = self.banner
907 sys.stdout.write(banner)
933 sys.stdout.write(banner)
908
934
909 #-------------------------------------------------------------------------
935 #-------------------------------------------------------------------------
910 # Things related to hooks
936 # Things related to hooks
911 #-------------------------------------------------------------------------
937 #-------------------------------------------------------------------------
912
938
913 def init_hooks(self):
939 def init_hooks(self):
914 # hooks holds pointers used for user-side customizations
940 # hooks holds pointers used for user-side customizations
915 self.hooks = Struct()
941 self.hooks = Struct()
916
942
917 self.strdispatchers = {}
943 self.strdispatchers = {}
918
944
919 # Set all default hooks, defined in the IPython.hooks module.
945 # Set all default hooks, defined in the IPython.hooks module.
920 hooks = IPython.core.hooks
946 hooks = IPython.core.hooks
921 for hook_name in hooks.__all__:
947 for hook_name in hooks.__all__:
922 # default hooks have priority 100, i.e. low; user hooks should have
948 # default hooks have priority 100, i.e. low; user hooks should have
923 # 0-100 priority
949 # 0-100 priority
924 self.set_hook(hook_name, getattr(hooks, hook_name), 100)
950 self.set_hook(hook_name, getattr(hooks, hook_name), 100)
925
951
926 if self.display_page:
952 if self.display_page:
927 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
953 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
928
954
929 def set_hook(self, name, hook, priority=50, str_key=None, re_key=None):
955 def set_hook(self, name, hook, priority=50, str_key=None, re_key=None):
930 """set_hook(name,hook) -> sets an internal IPython hook.
956 """set_hook(name,hook) -> sets an internal IPython hook.
931
957
932 IPython exposes some of its internal API as user-modifiable hooks. By
958 IPython exposes some of its internal API as user-modifiable hooks. By
933 adding your function to one of these hooks, you can modify IPython's
959 adding your function to one of these hooks, you can modify IPython's
934 behavior to call at runtime your own routines."""
960 behavior to call at runtime your own routines."""
935
961
936 # At some point in the future, this should validate the hook before it
962 # At some point in the future, this should validate the hook before it
937 # accepts it. Probably at least check that the hook takes the number
963 # accepts it. Probably at least check that the hook takes the number
938 # of args it's supposed to.
964 # of args it's supposed to.
939
965
940 f = types.MethodType(hook,self)
966 f = types.MethodType(hook,self)
941
967
942 # check if the hook is for strdispatcher first
968 # check if the hook is for strdispatcher first
943 if str_key is not None:
969 if str_key is not None:
944 sdp = self.strdispatchers.get(name, StrDispatch())
970 sdp = self.strdispatchers.get(name, StrDispatch())
945 sdp.add_s(str_key, f, priority )
971 sdp.add_s(str_key, f, priority )
946 self.strdispatchers[name] = sdp
972 self.strdispatchers[name] = sdp
947 return
973 return
948 if re_key is not None:
974 if re_key is not None:
949 sdp = self.strdispatchers.get(name, StrDispatch())
975 sdp = self.strdispatchers.get(name, StrDispatch())
950 sdp.add_re(re.compile(re_key), f, priority )
976 sdp.add_re(re.compile(re_key), f, priority )
951 self.strdispatchers[name] = sdp
977 self.strdispatchers[name] = sdp
952 return
978 return
953
979
954 dp = getattr(self.hooks, name, None)
980 dp = getattr(self.hooks, name, None)
955 if name not in IPython.core.hooks.__all__:
981 if name not in IPython.core.hooks.__all__:
956 print("Warning! Hook '%s' is not one of %s" % \
982 print("Warning! Hook '%s' is not one of %s" % \
957 (name, IPython.core.hooks.__all__ ))
983 (name, IPython.core.hooks.__all__ ))
958
984
959 if name in IPython.core.hooks.deprecated:
985 if name in IPython.core.hooks.deprecated:
960 alternative = IPython.core.hooks.deprecated[name]
986 alternative = IPython.core.hooks.deprecated[name]
961 raise ValueError(
987 raise ValueError(
962 "Hook {} has been deprecated since IPython 5.0. Use {} instead.".format(
988 "Hook {} has been deprecated since IPython 5.0. Use {} instead.".format(
963 name, alternative
989 name, alternative
964 )
990 )
965 )
991 )
966
992
967 if not dp:
993 if not dp:
968 dp = IPython.core.hooks.CommandChainDispatcher()
994 dp = IPython.core.hooks.CommandChainDispatcher()
969
995
970 try:
996 try:
971 dp.add(f,priority)
997 dp.add(f,priority)
972 except AttributeError:
998 except AttributeError:
973 # it was not commandchain, plain old func - replace
999 # it was not commandchain, plain old func - replace
974 dp = f
1000 dp = f
975
1001
976 setattr(self.hooks,name, dp)
1002 setattr(self.hooks,name, dp)
977
1003
978 #-------------------------------------------------------------------------
1004 #-------------------------------------------------------------------------
979 # Things related to events
1005 # Things related to events
980 #-------------------------------------------------------------------------
1006 #-------------------------------------------------------------------------
981
1007
982 def init_events(self):
1008 def init_events(self):
983 self.events = EventManager(self, available_events)
1009 self.events = EventManager(self, available_events)
984
1010
985 self.events.register("pre_execute", self._clear_warning_registry)
1011 self.events.register("pre_execute", self._clear_warning_registry)
986
1012
987 def register_post_execute(self, func):
1013 def register_post_execute(self, func):
988 """DEPRECATED: Use ip.events.register('post_run_cell', func)
1014 """DEPRECATED: Use ip.events.register('post_run_cell', func)
989
1015
990 Register a function for calling after code execution.
1016 Register a function for calling after code execution.
991 """
1017 """
992 raise ValueError(
1018 raise ValueError(
993 "ip.register_post_execute is deprecated since IPython 1.0, use "
1019 "ip.register_post_execute is deprecated since IPython 1.0, use "
994 "ip.events.register('post_run_cell', func) instead."
1020 "ip.events.register('post_run_cell', func) instead."
995 )
1021 )
996
1022
997 def _clear_warning_registry(self):
1023 def _clear_warning_registry(self):
998 # clear the warning registry, so that different code blocks with
1024 # clear the warning registry, so that different code blocks with
999 # overlapping line number ranges don't cause spurious suppression of
1025 # overlapping line number ranges don't cause spurious suppression of
1000 # warnings (see gh-6611 for details)
1026 # warnings (see gh-6611 for details)
1001 if "__warningregistry__" in self.user_global_ns:
1027 if "__warningregistry__" in self.user_global_ns:
1002 del self.user_global_ns["__warningregistry__"]
1028 del self.user_global_ns["__warningregistry__"]
1003
1029
1004 #-------------------------------------------------------------------------
1030 #-------------------------------------------------------------------------
1005 # Things related to the "main" module
1031 # Things related to the "main" module
1006 #-------------------------------------------------------------------------
1032 #-------------------------------------------------------------------------
1007
1033
1008 def new_main_mod(self, filename, modname):
1034 def new_main_mod(self, filename, modname):
1009 """Return a new 'main' module object for user code execution.
1035 """Return a new 'main' module object for user code execution.
1010
1036
1011 ``filename`` should be the path of the script which will be run in the
1037 ``filename`` should be the path of the script which will be run in the
1012 module. Requests with the same filename will get the same module, with
1038 module. Requests with the same filename will get the same module, with
1013 its namespace cleared.
1039 its namespace cleared.
1014
1040
1015 ``modname`` should be the module name - normally either '__main__' or
1041 ``modname`` should be the module name - normally either '__main__' or
1016 the basename of the file without the extension.
1042 the basename of the file without the extension.
1017
1043
1018 When scripts are executed via %run, we must keep a reference to their
1044 When scripts are executed via %run, we must keep a reference to their
1019 __main__ module around so that Python doesn't
1045 __main__ module around so that Python doesn't
1020 clear it, rendering references to module globals useless.
1046 clear it, rendering references to module globals useless.
1021
1047
1022 This method keeps said reference in a private dict, keyed by the
1048 This method keeps said reference in a private dict, keyed by the
1023 absolute path of the script. This way, for multiple executions of the
1049 absolute path of the script. This way, for multiple executions of the
1024 same script we only keep one copy of the namespace (the last one),
1050 same script we only keep one copy of the namespace (the last one),
1025 thus preventing memory leaks from old references while allowing the
1051 thus preventing memory leaks from old references while allowing the
1026 objects from the last execution to be accessible.
1052 objects from the last execution to be accessible.
1027 """
1053 """
1028 filename = os.path.abspath(filename)
1054 filename = os.path.abspath(filename)
1029 try:
1055 try:
1030 main_mod = self._main_mod_cache[filename]
1056 main_mod = self._main_mod_cache[filename]
1031 except KeyError:
1057 except KeyError:
1032 main_mod = self._main_mod_cache[filename] = types.ModuleType(
1058 main_mod = self._main_mod_cache[filename] = types.ModuleType(
1033 modname,
1059 modname,
1034 doc="Module created for script run in IPython")
1060 doc="Module created for script run in IPython")
1035 else:
1061 else:
1036 main_mod.__dict__.clear()
1062 main_mod.__dict__.clear()
1037 main_mod.__name__ = modname
1063 main_mod.__name__ = modname
1038
1064
1039 main_mod.__file__ = filename
1065 main_mod.__file__ = filename
1040 # It seems pydoc (and perhaps others) needs any module instance to
1066 # It seems pydoc (and perhaps others) needs any module instance to
1041 # implement a __nonzero__ method
1067 # implement a __nonzero__ method
1042 main_mod.__nonzero__ = lambda : True
1068 main_mod.__nonzero__ = lambda : True
1043
1069
1044 return main_mod
1070 return main_mod
1045
1071
1046 def clear_main_mod_cache(self):
1072 def clear_main_mod_cache(self):
1047 """Clear the cache of main modules.
1073 """Clear the cache of main modules.
1048
1074
1049 Mainly for use by utilities like %reset.
1075 Mainly for use by utilities like %reset.
1050
1076
1051 Examples
1077 Examples
1052 --------
1078 --------
1053 In [15]: import IPython
1079 In [15]: import IPython
1054
1080
1055 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
1081 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
1056
1082
1057 In [17]: len(_ip._main_mod_cache) > 0
1083 In [17]: len(_ip._main_mod_cache) > 0
1058 Out[17]: True
1084 Out[17]: True
1059
1085
1060 In [18]: _ip.clear_main_mod_cache()
1086 In [18]: _ip.clear_main_mod_cache()
1061
1087
1062 In [19]: len(_ip._main_mod_cache) == 0
1088 In [19]: len(_ip._main_mod_cache) == 0
1063 Out[19]: True
1089 Out[19]: True
1064 """
1090 """
1065 self._main_mod_cache.clear()
1091 self._main_mod_cache.clear()
1066
1092
1067 #-------------------------------------------------------------------------
1093 #-------------------------------------------------------------------------
1068 # Things related to debugging
1094 # Things related to debugging
1069 #-------------------------------------------------------------------------
1095 #-------------------------------------------------------------------------
1070
1096
1071 def init_pdb(self):
1097 def init_pdb(self):
1072 # Set calling of pdb on exceptions
1098 # Set calling of pdb on exceptions
1073 # self.call_pdb is a property
1099 # self.call_pdb is a property
1074 self.call_pdb = self.pdb
1100 self.call_pdb = self.pdb
1075
1101
1076 def _get_call_pdb(self):
1102 def _get_call_pdb(self):
1077 return self._call_pdb
1103 return self._call_pdb
1078
1104
1079 def _set_call_pdb(self,val):
1105 def _set_call_pdb(self,val):
1080
1106
1081 if val not in (0,1,False,True):
1107 if val not in (0,1,False,True):
1082 raise ValueError('new call_pdb value must be boolean')
1108 raise ValueError('new call_pdb value must be boolean')
1083
1109
1084 # store value in instance
1110 # store value in instance
1085 self._call_pdb = val
1111 self._call_pdb = val
1086
1112
1087 # notify the actual exception handlers
1113 # notify the actual exception handlers
1088 self.InteractiveTB.call_pdb = val
1114 self.InteractiveTB.call_pdb = val
1089
1115
1090 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
1116 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
1091 'Control auto-activation of pdb at exceptions')
1117 'Control auto-activation of pdb at exceptions')
1092
1118
1093 def debugger(self,force=False):
1119 def debugger(self,force=False):
1094 """Call the pdb debugger.
1120 """Call the pdb debugger.
1095
1121
1096 Keywords:
1122 Keywords:
1097
1123
1098 - force(False): by default, this routine checks the instance call_pdb
1124 - force(False): by default, this routine checks the instance call_pdb
1099 flag and does not actually invoke the debugger if the flag is false.
1125 flag and does not actually invoke the debugger if the flag is false.
1100 The 'force' option forces the debugger to activate even if the flag
1126 The 'force' option forces the debugger to activate even if the flag
1101 is false.
1127 is false.
1102 """
1128 """
1103
1129
1104 if not (force or self.call_pdb):
1130 if not (force or self.call_pdb):
1105 return
1131 return
1106
1132
1107 if not hasattr(sys,'last_traceback'):
1133 if not hasattr(sys,'last_traceback'):
1108 error('No traceback has been produced, nothing to debug.')
1134 error('No traceback has been produced, nothing to debug.')
1109 return
1135 return
1110
1136
1111 self.InteractiveTB.debugger(force=True)
1137 self.InteractiveTB.debugger(force=True)
1112
1138
1113 #-------------------------------------------------------------------------
1139 #-------------------------------------------------------------------------
1114 # Things related to IPython's various namespaces
1140 # Things related to IPython's various namespaces
1115 #-------------------------------------------------------------------------
1141 #-------------------------------------------------------------------------
1116 default_user_namespaces = True
1142 default_user_namespaces = True
1117
1143
1118 def init_create_namespaces(self, user_module=None, user_ns=None):
1144 def init_create_namespaces(self, user_module=None, user_ns=None):
1119 # Create the namespace where the user will operate. user_ns is
1145 # Create the namespace where the user will operate. user_ns is
1120 # normally the only one used, and it is passed to the exec calls as
1146 # normally the only one used, and it is passed to the exec calls as
1121 # the locals argument. But we do carry a user_global_ns namespace
1147 # the locals argument. But we do carry a user_global_ns namespace
1122 # given as the exec 'globals' argument, This is useful in embedding
1148 # given as the exec 'globals' argument, This is useful in embedding
1123 # situations where the ipython shell opens in a context where the
1149 # situations where the ipython shell opens in a context where the
1124 # distinction between locals and globals is meaningful. For
1150 # distinction between locals and globals is meaningful. For
1125 # non-embedded contexts, it is just the same object as the user_ns dict.
1151 # non-embedded contexts, it is just the same object as the user_ns dict.
1126
1152
1127 # FIXME. For some strange reason, __builtins__ is showing up at user
1153 # FIXME. For some strange reason, __builtins__ is showing up at user
1128 # level as a dict instead of a module. This is a manual fix, but I
1154 # level as a dict instead of a module. This is a manual fix, but I
1129 # should really track down where the problem is coming from. Alex
1155 # should really track down where the problem is coming from. Alex
1130 # Schmolck reported this problem first.
1156 # Schmolck reported this problem first.
1131
1157
1132 # A useful post by Alex Martelli on this topic:
1158 # A useful post by Alex Martelli on this topic:
1133 # Re: inconsistent value from __builtins__
1159 # Re: inconsistent value from __builtins__
1134 # Von: Alex Martelli <aleaxit@yahoo.com>
1160 # Von: Alex Martelli <aleaxit@yahoo.com>
1135 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1161 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1136 # Gruppen: comp.lang.python
1162 # Gruppen: comp.lang.python
1137
1163
1138 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1164 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1139 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1165 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1140 # > <type 'dict'>
1166 # > <type 'dict'>
1141 # > >>> print type(__builtins__)
1167 # > >>> print type(__builtins__)
1142 # > <type 'module'>
1168 # > <type 'module'>
1143 # > Is this difference in return value intentional?
1169 # > Is this difference in return value intentional?
1144
1170
1145 # Well, it's documented that '__builtins__' can be either a dictionary
1171 # Well, it's documented that '__builtins__' can be either a dictionary
1146 # or a module, and it's been that way for a long time. Whether it's
1172 # or a module, and it's been that way for a long time. Whether it's
1147 # intentional (or sensible), I don't know. In any case, the idea is
1173 # intentional (or sensible), I don't know. In any case, the idea is
1148 # that if you need to access the built-in namespace directly, you
1174 # that if you need to access the built-in namespace directly, you
1149 # should start with "import __builtin__" (note, no 's') which will
1175 # should start with "import __builtin__" (note, no 's') which will
1150 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1176 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1151
1177
1152 # These routines return a properly built module and dict as needed by
1178 # These routines return a properly built module and dict as needed by
1153 # the rest of the code, and can also be used by extension writers to
1179 # the rest of the code, and can also be used by extension writers to
1154 # generate properly initialized namespaces.
1180 # generate properly initialized namespaces.
1155 if (user_ns is not None) or (user_module is not None):
1181 if (user_ns is not None) or (user_module is not None):
1156 self.default_user_namespaces = False
1182 self.default_user_namespaces = False
1157 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1183 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1158
1184
1159 # A record of hidden variables we have added to the user namespace, so
1185 # A record of hidden variables we have added to the user namespace, so
1160 # we can list later only variables defined in actual interactive use.
1186 # we can list later only variables defined in actual interactive use.
1161 self.user_ns_hidden = {}
1187 self.user_ns_hidden = {}
1162
1188
1163 # Now that FakeModule produces a real module, we've run into a nasty
1189 # Now that FakeModule produces a real module, we've run into a nasty
1164 # problem: after script execution (via %run), the module where the user
1190 # problem: after script execution (via %run), the module where the user
1165 # code ran is deleted. Now that this object is a true module (needed
1191 # code ran is deleted. Now that this object is a true module (needed
1166 # so doctest and other tools work correctly), the Python module
1192 # so doctest and other tools work correctly), the Python module
1167 # teardown mechanism runs over it, and sets to None every variable
1193 # teardown mechanism runs over it, and sets to None every variable
1168 # present in that module. Top-level references to objects from the
1194 # present in that module. Top-level references to objects from the
1169 # script survive, because the user_ns is updated with them. However,
1195 # script survive, because the user_ns is updated with them. However,
1170 # calling functions defined in the script that use other things from
1196 # calling functions defined in the script that use other things from
1171 # the script will fail, because the function's closure had references
1197 # the script will fail, because the function's closure had references
1172 # to the original objects, which are now all None. So we must protect
1198 # to the original objects, which are now all None. So we must protect
1173 # these modules from deletion by keeping a cache.
1199 # these modules from deletion by keeping a cache.
1174 #
1200 #
1175 # To avoid keeping stale modules around (we only need the one from the
1201 # To avoid keeping stale modules around (we only need the one from the
1176 # last run), we use a dict keyed with the full path to the script, so
1202 # last run), we use a dict keyed with the full path to the script, so
1177 # only the last version of the module is held in the cache. Note,
1203 # only the last version of the module is held in the cache. Note,
1178 # however, that we must cache the module *namespace contents* (their
1204 # however, that we must cache the module *namespace contents* (their
1179 # __dict__). Because if we try to cache the actual modules, old ones
1205 # __dict__). Because if we try to cache the actual modules, old ones
1180 # (uncached) could be destroyed while still holding references (such as
1206 # (uncached) could be destroyed while still holding references (such as
1181 # those held by GUI objects that tend to be long-lived)>
1207 # those held by GUI objects that tend to be long-lived)>
1182 #
1208 #
1183 # The %reset command will flush this cache. See the cache_main_mod()
1209 # The %reset command will flush this cache. See the cache_main_mod()
1184 # and clear_main_mod_cache() methods for details on use.
1210 # and clear_main_mod_cache() methods for details on use.
1185
1211
1186 # This is the cache used for 'main' namespaces
1212 # This is the cache used for 'main' namespaces
1187 self._main_mod_cache = {}
1213 self._main_mod_cache = {}
1188
1214
1189 # A table holding all the namespaces IPython deals with, so that
1215 # A table holding all the namespaces IPython deals with, so that
1190 # introspection facilities can search easily.
1216 # introspection facilities can search easily.
1191 self.ns_table = {'user_global':self.user_module.__dict__,
1217 self.ns_table = {'user_global':self.user_module.__dict__,
1192 'user_local':self.user_ns,
1218 'user_local':self.user_ns,
1193 'builtin':builtin_mod.__dict__
1219 'builtin':builtin_mod.__dict__
1194 }
1220 }
1195
1221
1196 @property
1222 @property
1197 def user_global_ns(self):
1223 def user_global_ns(self):
1198 return self.user_module.__dict__
1224 return self.user_module.__dict__
1199
1225
1200 def prepare_user_module(self, user_module=None, user_ns=None):
1226 def prepare_user_module(self, user_module=None, user_ns=None):
1201 """Prepare the module and namespace in which user code will be run.
1227 """Prepare the module and namespace in which user code will be run.
1202
1228
1203 When IPython is started normally, both parameters are None: a new module
1229 When IPython is started normally, both parameters are None: a new module
1204 is created automatically, and its __dict__ used as the namespace.
1230 is created automatically, and its __dict__ used as the namespace.
1205
1231
1206 If only user_module is provided, its __dict__ is used as the namespace.
1232 If only user_module is provided, its __dict__ is used as the namespace.
1207 If only user_ns is provided, a dummy module is created, and user_ns
1233 If only user_ns is provided, a dummy module is created, and user_ns
1208 becomes the global namespace. If both are provided (as they may be
1234 becomes the global namespace. If both are provided (as they may be
1209 when embedding), user_ns is the local namespace, and user_module
1235 when embedding), user_ns is the local namespace, and user_module
1210 provides the global namespace.
1236 provides the global namespace.
1211
1237
1212 Parameters
1238 Parameters
1213 ----------
1239 ----------
1214 user_module : module, optional
1240 user_module : module, optional
1215 The current user module in which IPython is being run. If None,
1241 The current user module in which IPython is being run. If None,
1216 a clean module will be created.
1242 a clean module will be created.
1217 user_ns : dict, optional
1243 user_ns : dict, optional
1218 A namespace in which to run interactive commands.
1244 A namespace in which to run interactive commands.
1219
1245
1220 Returns
1246 Returns
1221 -------
1247 -------
1222 A tuple of user_module and user_ns, each properly initialised.
1248 A tuple of user_module and user_ns, each properly initialised.
1223 """
1249 """
1224 if user_module is None and user_ns is not None:
1250 if user_module is None and user_ns is not None:
1225 user_ns.setdefault("__name__", "__main__")
1251 user_ns.setdefault("__name__", "__main__")
1226 user_module = DummyMod()
1252 user_module = DummyMod()
1227 user_module.__dict__ = user_ns
1253 user_module.__dict__ = user_ns
1228
1254
1229 if user_module is None:
1255 if user_module is None:
1230 user_module = types.ModuleType("__main__",
1256 user_module = types.ModuleType("__main__",
1231 doc="Automatically created module for IPython interactive environment")
1257 doc="Automatically created module for IPython interactive environment")
1232
1258
1233 # We must ensure that __builtin__ (without the final 's') is always
1259 # We must ensure that __builtin__ (without the final 's') is always
1234 # available and pointing to the __builtin__ *module*. For more details:
1260 # available and pointing to the __builtin__ *module*. For more details:
1235 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1261 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1236 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1262 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1237 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1263 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1238
1264
1239 if user_ns is None:
1265 if user_ns is None:
1240 user_ns = user_module.__dict__
1266 user_ns = user_module.__dict__
1241
1267
1242 return user_module, user_ns
1268 return user_module, user_ns
1243
1269
1244 def init_sys_modules(self):
1270 def init_sys_modules(self):
1245 # We need to insert into sys.modules something that looks like a
1271 # We need to insert into sys.modules something that looks like a
1246 # module but which accesses the IPython namespace, for shelve and
1272 # module but which accesses the IPython namespace, for shelve and
1247 # pickle to work interactively. Normally they rely on getting
1273 # pickle to work interactively. Normally they rely on getting
1248 # everything out of __main__, but for embedding purposes each IPython
1274 # everything out of __main__, but for embedding purposes each IPython
1249 # instance has its own private namespace, so we can't go shoving
1275 # instance has its own private namespace, so we can't go shoving
1250 # everything into __main__.
1276 # everything into __main__.
1251
1277
1252 # note, however, that we should only do this for non-embedded
1278 # note, however, that we should only do this for non-embedded
1253 # ipythons, which really mimic the __main__.__dict__ with their own
1279 # ipythons, which really mimic the __main__.__dict__ with their own
1254 # namespace. Embedded instances, on the other hand, should not do
1280 # namespace. Embedded instances, on the other hand, should not do
1255 # this because they need to manage the user local/global namespaces
1281 # this because they need to manage the user local/global namespaces
1256 # only, but they live within a 'normal' __main__ (meaning, they
1282 # only, but they live within a 'normal' __main__ (meaning, they
1257 # shouldn't overtake the execution environment of the script they're
1283 # shouldn't overtake the execution environment of the script they're
1258 # embedded in).
1284 # embedded in).
1259
1285
1260 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1286 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1261 main_name = self.user_module.__name__
1287 main_name = self.user_module.__name__
1262 sys.modules[main_name] = self.user_module
1288 sys.modules[main_name] = self.user_module
1263
1289
1264 def init_user_ns(self):
1290 def init_user_ns(self):
1265 """Initialize all user-visible namespaces to their minimum defaults.
1291 """Initialize all user-visible namespaces to their minimum defaults.
1266
1292
1267 Certain history lists are also initialized here, as they effectively
1293 Certain history lists are also initialized here, as they effectively
1268 act as user namespaces.
1294 act as user namespaces.
1269
1295
1270 Notes
1296 Notes
1271 -----
1297 -----
1272 All data structures here are only filled in, they are NOT reset by this
1298 All data structures here are only filled in, they are NOT reset by this
1273 method. If they were not empty before, data will simply be added to
1299 method. If they were not empty before, data will simply be added to
1274 them.
1300 them.
1275 """
1301 """
1276 # This function works in two parts: first we put a few things in
1302 # This function works in two parts: first we put a few things in
1277 # user_ns, and we sync that contents into user_ns_hidden so that these
1303 # user_ns, and we sync that contents into user_ns_hidden so that these
1278 # initial variables aren't shown by %who. After the sync, we add the
1304 # initial variables aren't shown by %who. After the sync, we add the
1279 # rest of what we *do* want the user to see with %who even on a new
1305 # rest of what we *do* want the user to see with %who even on a new
1280 # session (probably nothing, so they really only see their own stuff)
1306 # session (probably nothing, so they really only see their own stuff)
1281
1307
1282 # The user dict must *always* have a __builtin__ reference to the
1308 # The user dict must *always* have a __builtin__ reference to the
1283 # Python standard __builtin__ namespace, which must be imported.
1309 # Python standard __builtin__ namespace, which must be imported.
1284 # This is so that certain operations in prompt evaluation can be
1310 # This is so that certain operations in prompt evaluation can be
1285 # reliably executed with builtins. Note that we can NOT use
1311 # reliably executed with builtins. Note that we can NOT use
1286 # __builtins__ (note the 's'), because that can either be a dict or a
1312 # __builtins__ (note the 's'), because that can either be a dict or a
1287 # module, and can even mutate at runtime, depending on the context
1313 # module, and can even mutate at runtime, depending on the context
1288 # (Python makes no guarantees on it). In contrast, __builtin__ is
1314 # (Python makes no guarantees on it). In contrast, __builtin__ is
1289 # always a module object, though it must be explicitly imported.
1315 # always a module object, though it must be explicitly imported.
1290
1316
1291 # For more details:
1317 # For more details:
1292 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1318 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1293 ns = {}
1319 ns = {}
1294
1320
1295 # make global variables for user access to the histories
1321 # make global variables for user access to the histories
1296 ns['_ih'] = self.history_manager.input_hist_parsed
1322 ns['_ih'] = self.history_manager.input_hist_parsed
1297 ns['_oh'] = self.history_manager.output_hist
1323 ns['_oh'] = self.history_manager.output_hist
1298 ns['_dh'] = self.history_manager.dir_hist
1324 ns['_dh'] = self.history_manager.dir_hist
1299
1325
1300 # user aliases to input and output histories. These shouldn't show up
1326 # user aliases to input and output histories. These shouldn't show up
1301 # in %who, as they can have very large reprs.
1327 # in %who, as they can have very large reprs.
1302 ns['In'] = self.history_manager.input_hist_parsed
1328 ns['In'] = self.history_manager.input_hist_parsed
1303 ns['Out'] = self.history_manager.output_hist
1329 ns['Out'] = self.history_manager.output_hist
1304
1330
1305 # Store myself as the public api!!!
1331 # Store myself as the public api!!!
1306 ns['get_ipython'] = self.get_ipython
1332 ns['get_ipython'] = self.get_ipython
1307
1333
1308 ns['exit'] = self.exiter
1334 ns['exit'] = self.exiter
1309 ns['quit'] = self.exiter
1335 ns['quit'] = self.exiter
1336 ns["open"] = _modified_open
1310
1337
1311 # Sync what we've added so far to user_ns_hidden so these aren't seen
1338 # Sync what we've added so far to user_ns_hidden so these aren't seen
1312 # by %who
1339 # by %who
1313 self.user_ns_hidden.update(ns)
1340 self.user_ns_hidden.update(ns)
1314
1341
1315 # Anything put into ns now would show up in %who. Think twice before
1342 # Anything put into ns now would show up in %who. Think twice before
1316 # putting anything here, as we really want %who to show the user their
1343 # putting anything here, as we really want %who to show the user their
1317 # stuff, not our variables.
1344 # stuff, not our variables.
1318
1345
1319 # Finally, update the real user's namespace
1346 # Finally, update the real user's namespace
1320 self.user_ns.update(ns)
1347 self.user_ns.update(ns)
1321
1348
1322 @property
1349 @property
1323 def all_ns_refs(self):
1350 def all_ns_refs(self):
1324 """Get a list of references to all the namespace dictionaries in which
1351 """Get a list of references to all the namespace dictionaries in which
1325 IPython might store a user-created object.
1352 IPython might store a user-created object.
1326
1353
1327 Note that this does not include the displayhook, which also caches
1354 Note that this does not include the displayhook, which also caches
1328 objects from the output."""
1355 objects from the output."""
1329 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1356 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1330 [m.__dict__ for m in self._main_mod_cache.values()]
1357 [m.__dict__ for m in self._main_mod_cache.values()]
1331
1358
1332 def reset(self, new_session=True, aggressive=False):
1359 def reset(self, new_session=True, aggressive=False):
1333 """Clear all internal namespaces, and attempt to release references to
1360 """Clear all internal namespaces, and attempt to release references to
1334 user objects.
1361 user objects.
1335
1362
1336 If new_session is True, a new history session will be opened.
1363 If new_session is True, a new history session will be opened.
1337 """
1364 """
1338 # Clear histories
1365 # Clear histories
1339 self.history_manager.reset(new_session)
1366 self.history_manager.reset(new_session)
1340 # Reset counter used to index all histories
1367 # Reset counter used to index all histories
1341 if new_session:
1368 if new_session:
1342 self.execution_count = 1
1369 self.execution_count = 1
1343
1370
1344 # Reset last execution result
1371 # Reset last execution result
1345 self.last_execution_succeeded = True
1372 self.last_execution_succeeded = True
1346 self.last_execution_result = None
1373 self.last_execution_result = None
1347
1374
1348 # Flush cached output items
1375 # Flush cached output items
1349 if self.displayhook.do_full_cache:
1376 if self.displayhook.do_full_cache:
1350 self.displayhook.flush()
1377 self.displayhook.flush()
1351
1378
1352 # The main execution namespaces must be cleared very carefully,
1379 # The main execution namespaces must be cleared very carefully,
1353 # skipping the deletion of the builtin-related keys, because doing so
1380 # skipping the deletion of the builtin-related keys, because doing so
1354 # would cause errors in many object's __del__ methods.
1381 # would cause errors in many object's __del__ methods.
1355 if self.user_ns is not self.user_global_ns:
1382 if self.user_ns is not self.user_global_ns:
1356 self.user_ns.clear()
1383 self.user_ns.clear()
1357 ns = self.user_global_ns
1384 ns = self.user_global_ns
1358 drop_keys = set(ns.keys())
1385 drop_keys = set(ns.keys())
1359 drop_keys.discard('__builtin__')
1386 drop_keys.discard('__builtin__')
1360 drop_keys.discard('__builtins__')
1387 drop_keys.discard('__builtins__')
1361 drop_keys.discard('__name__')
1388 drop_keys.discard('__name__')
1362 for k in drop_keys:
1389 for k in drop_keys:
1363 del ns[k]
1390 del ns[k]
1364
1391
1365 self.user_ns_hidden.clear()
1392 self.user_ns_hidden.clear()
1366
1393
1367 # Restore the user namespaces to minimal usability
1394 # Restore the user namespaces to minimal usability
1368 self.init_user_ns()
1395 self.init_user_ns()
1369 if aggressive and not hasattr(self, "_sys_modules_keys"):
1396 if aggressive and not hasattr(self, "_sys_modules_keys"):
1370 print("Cannot restore sys.module, no snapshot")
1397 print("Cannot restore sys.module, no snapshot")
1371 elif aggressive:
1398 elif aggressive:
1372 print("culling sys module...")
1399 print("culling sys module...")
1373 current_keys = set(sys.modules.keys())
1400 current_keys = set(sys.modules.keys())
1374 for k in current_keys - self._sys_modules_keys:
1401 for k in current_keys - self._sys_modules_keys:
1375 if k.startswith("multiprocessing"):
1402 if k.startswith("multiprocessing"):
1376 continue
1403 continue
1377 del sys.modules[k]
1404 del sys.modules[k]
1378
1405
1379 # Restore the default and user aliases
1406 # Restore the default and user aliases
1380 self.alias_manager.clear_aliases()
1407 self.alias_manager.clear_aliases()
1381 self.alias_manager.init_aliases()
1408 self.alias_manager.init_aliases()
1382
1409
1383 # Now define aliases that only make sense on the terminal, because they
1410 # Now define aliases that only make sense on the terminal, because they
1384 # need direct access to the console in a way that we can't emulate in
1411 # need direct access to the console in a way that we can't emulate in
1385 # GUI or web frontend
1412 # GUI or web frontend
1386 if os.name == 'posix':
1413 if os.name == 'posix':
1387 for cmd in ('clear', 'more', 'less', 'man'):
1414 for cmd in ('clear', 'more', 'less', 'man'):
1388 if cmd not in self.magics_manager.magics['line']:
1415 if cmd not in self.magics_manager.magics['line']:
1389 self.alias_manager.soft_define_alias(cmd, cmd)
1416 self.alias_manager.soft_define_alias(cmd, cmd)
1390
1417
1391 # Flush the private list of module references kept for script
1418 # Flush the private list of module references kept for script
1392 # execution protection
1419 # execution protection
1393 self.clear_main_mod_cache()
1420 self.clear_main_mod_cache()
1394
1421
1395 def del_var(self, varname, by_name=False):
1422 def del_var(self, varname, by_name=False):
1396 """Delete a variable from the various namespaces, so that, as
1423 """Delete a variable from the various namespaces, so that, as
1397 far as possible, we're not keeping any hidden references to it.
1424 far as possible, we're not keeping any hidden references to it.
1398
1425
1399 Parameters
1426 Parameters
1400 ----------
1427 ----------
1401 varname : str
1428 varname : str
1402 The name of the variable to delete.
1429 The name of the variable to delete.
1403 by_name : bool
1430 by_name : bool
1404 If True, delete variables with the given name in each
1431 If True, delete variables with the given name in each
1405 namespace. If False (default), find the variable in the user
1432 namespace. If False (default), find the variable in the user
1406 namespace, and delete references to it.
1433 namespace, and delete references to it.
1407 """
1434 """
1408 if varname in ('__builtin__', '__builtins__'):
1435 if varname in ('__builtin__', '__builtins__'):
1409 raise ValueError("Refusing to delete %s" % varname)
1436 raise ValueError("Refusing to delete %s" % varname)
1410
1437
1411 ns_refs = self.all_ns_refs
1438 ns_refs = self.all_ns_refs
1412
1439
1413 if by_name: # Delete by name
1440 if by_name: # Delete by name
1414 for ns in ns_refs:
1441 for ns in ns_refs:
1415 try:
1442 try:
1416 del ns[varname]
1443 del ns[varname]
1417 except KeyError:
1444 except KeyError:
1418 pass
1445 pass
1419 else: # Delete by object
1446 else: # Delete by object
1420 try:
1447 try:
1421 obj = self.user_ns[varname]
1448 obj = self.user_ns[varname]
1422 except KeyError as e:
1449 except KeyError as e:
1423 raise NameError("name '%s' is not defined" % varname) from e
1450 raise NameError("name '%s' is not defined" % varname) from e
1424 # Also check in output history
1451 # Also check in output history
1425 ns_refs.append(self.history_manager.output_hist)
1452 ns_refs.append(self.history_manager.output_hist)
1426 for ns in ns_refs:
1453 for ns in ns_refs:
1427 to_delete = [n for n, o in ns.items() if o is obj]
1454 to_delete = [n for n, o in ns.items() if o is obj]
1428 for name in to_delete:
1455 for name in to_delete:
1429 del ns[name]
1456 del ns[name]
1430
1457
1431 # Ensure it is removed from the last execution result
1458 # Ensure it is removed from the last execution result
1432 if self.last_execution_result.result is obj:
1459 if self.last_execution_result.result is obj:
1433 self.last_execution_result = None
1460 self.last_execution_result = None
1434
1461
1435 # displayhook keeps extra references, but not in a dictionary
1462 # displayhook keeps extra references, but not in a dictionary
1436 for name in ('_', '__', '___'):
1463 for name in ('_', '__', '___'):
1437 if getattr(self.displayhook, name) is obj:
1464 if getattr(self.displayhook, name) is obj:
1438 setattr(self.displayhook, name, None)
1465 setattr(self.displayhook, name, None)
1439
1466
1440 def reset_selective(self, regex=None):
1467 def reset_selective(self, regex=None):
1441 """Clear selective variables from internal namespaces based on a
1468 """Clear selective variables from internal namespaces based on a
1442 specified regular expression.
1469 specified regular expression.
1443
1470
1444 Parameters
1471 Parameters
1445 ----------
1472 ----------
1446 regex : string or compiled pattern, optional
1473 regex : string or compiled pattern, optional
1447 A regular expression pattern that will be used in searching
1474 A regular expression pattern that will be used in searching
1448 variable names in the users namespaces.
1475 variable names in the users namespaces.
1449 """
1476 """
1450 if regex is not None:
1477 if regex is not None:
1451 try:
1478 try:
1452 m = re.compile(regex)
1479 m = re.compile(regex)
1453 except TypeError as e:
1480 except TypeError as e:
1454 raise TypeError('regex must be a string or compiled pattern') from e
1481 raise TypeError('regex must be a string or compiled pattern') from e
1455 # Search for keys in each namespace that match the given regex
1482 # Search for keys in each namespace that match the given regex
1456 # If a match is found, delete the key/value pair.
1483 # If a match is found, delete the key/value pair.
1457 for ns in self.all_ns_refs:
1484 for ns in self.all_ns_refs:
1458 for var in ns:
1485 for var in ns:
1459 if m.search(var):
1486 if m.search(var):
1460 del ns[var]
1487 del ns[var]
1461
1488
1462 def push(self, variables, interactive=True):
1489 def push(self, variables, interactive=True):
1463 """Inject a group of variables into the IPython user namespace.
1490 """Inject a group of variables into the IPython user namespace.
1464
1491
1465 Parameters
1492 Parameters
1466 ----------
1493 ----------
1467 variables : dict, str or list/tuple of str
1494 variables : dict, str or list/tuple of str
1468 The variables to inject into the user's namespace. If a dict, a
1495 The variables to inject into the user's namespace. If a dict, a
1469 simple update is done. If a str, the string is assumed to have
1496 simple update is done. If a str, the string is assumed to have
1470 variable names separated by spaces. A list/tuple of str can also
1497 variable names separated by spaces. A list/tuple of str can also
1471 be used to give the variable names. If just the variable names are
1498 be used to give the variable names. If just the variable names are
1472 give (list/tuple/str) then the variable values looked up in the
1499 give (list/tuple/str) then the variable values looked up in the
1473 callers frame.
1500 callers frame.
1474 interactive : bool
1501 interactive : bool
1475 If True (default), the variables will be listed with the ``who``
1502 If True (default), the variables will be listed with the ``who``
1476 magic.
1503 magic.
1477 """
1504 """
1478 vdict = None
1505 vdict = None
1479
1506
1480 # We need a dict of name/value pairs to do namespace updates.
1507 # We need a dict of name/value pairs to do namespace updates.
1481 if isinstance(variables, dict):
1508 if isinstance(variables, dict):
1482 vdict = variables
1509 vdict = variables
1483 elif isinstance(variables, (str, list, tuple)):
1510 elif isinstance(variables, (str, list, tuple)):
1484 if isinstance(variables, str):
1511 if isinstance(variables, str):
1485 vlist = variables.split()
1512 vlist = variables.split()
1486 else:
1513 else:
1487 vlist = variables
1514 vlist = variables
1488 vdict = {}
1515 vdict = {}
1489 cf = sys._getframe(1)
1516 cf = sys._getframe(1)
1490 for name in vlist:
1517 for name in vlist:
1491 try:
1518 try:
1492 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1519 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1493 except:
1520 except:
1494 print('Could not get variable %s from %s' %
1521 print('Could not get variable %s from %s' %
1495 (name,cf.f_code.co_name))
1522 (name,cf.f_code.co_name))
1496 else:
1523 else:
1497 raise ValueError('variables must be a dict/str/list/tuple')
1524 raise ValueError('variables must be a dict/str/list/tuple')
1498
1525
1499 # Propagate variables to user namespace
1526 # Propagate variables to user namespace
1500 self.user_ns.update(vdict)
1527 self.user_ns.update(vdict)
1501
1528
1502 # And configure interactive visibility
1529 # And configure interactive visibility
1503 user_ns_hidden = self.user_ns_hidden
1530 user_ns_hidden = self.user_ns_hidden
1504 if interactive:
1531 if interactive:
1505 for name in vdict:
1532 for name in vdict:
1506 user_ns_hidden.pop(name, None)
1533 user_ns_hidden.pop(name, None)
1507 else:
1534 else:
1508 user_ns_hidden.update(vdict)
1535 user_ns_hidden.update(vdict)
1509
1536
1510 def drop_by_id(self, variables):
1537 def drop_by_id(self, variables):
1511 """Remove a dict of variables from the user namespace, if they are the
1538 """Remove a dict of variables from the user namespace, if they are the
1512 same as the values in the dictionary.
1539 same as the values in the dictionary.
1513
1540
1514 This is intended for use by extensions: variables that they've added can
1541 This is intended for use by extensions: variables that they've added can
1515 be taken back out if they are unloaded, without removing any that the
1542 be taken back out if they are unloaded, without removing any that the
1516 user has overwritten.
1543 user has overwritten.
1517
1544
1518 Parameters
1545 Parameters
1519 ----------
1546 ----------
1520 variables : dict
1547 variables : dict
1521 A dictionary mapping object names (as strings) to the objects.
1548 A dictionary mapping object names (as strings) to the objects.
1522 """
1549 """
1523 for name, obj in variables.items():
1550 for name, obj in variables.items():
1524 if name in self.user_ns and self.user_ns[name] is obj:
1551 if name in self.user_ns and self.user_ns[name] is obj:
1525 del self.user_ns[name]
1552 del self.user_ns[name]
1526 self.user_ns_hidden.pop(name, None)
1553 self.user_ns_hidden.pop(name, None)
1527
1554
1528 #-------------------------------------------------------------------------
1555 #-------------------------------------------------------------------------
1529 # Things related to object introspection
1556 # Things related to object introspection
1530 #-------------------------------------------------------------------------
1557 #-------------------------------------------------------------------------
1531
1558
1532 def _ofind(self, oname, namespaces=None):
1559 def _ofind(self, oname, namespaces=None):
1533 """Find an object in the available namespaces.
1560 """Find an object in the available namespaces.
1534
1561
1535 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1562 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1536
1563
1537 Has special code to detect magic functions.
1564 Has special code to detect magic functions.
1538 """
1565 """
1539 oname = oname.strip()
1566 oname = oname.strip()
1540 if not oname.startswith(ESC_MAGIC) and \
1567 raw_parts = oname.split(".")
1541 not oname.startswith(ESC_MAGIC2) and \
1568 parts = []
1542 not all(a.isidentifier() for a in oname.split(".")):
1569 parts_ok = True
1543 return {'found': False}
1570 for p in raw_parts:
1571 if p.endswith("]"):
1572 var, *indices = p.split("[")
1573 if not var.isidentifier():
1574 parts_ok = False
1575 break
1576 parts.append(var)
1577 for ind in indices:
1578 if ind[-1] != "]" and not is_integer_string(ind[:-1]):
1579 parts_ok = False
1580 break
1581 parts.append(ind[:-1])
1582 continue
1583
1584 if not p.isidentifier():
1585 parts_ok = False
1586 parts.append(p)
1587
1588 if (
1589 not oname.startswith(ESC_MAGIC)
1590 and not oname.startswith(ESC_MAGIC2)
1591 and not parts_ok
1592 ):
1593 return {"found": False}
1544
1594
1545 if namespaces is None:
1595 if namespaces is None:
1546 # Namespaces to search in:
1596 # Namespaces to search in:
1547 # Put them in a list. The order is important so that we
1597 # Put them in a list. The order is important so that we
1548 # find things in the same order that Python finds them.
1598 # find things in the same order that Python finds them.
1549 namespaces = [ ('Interactive', self.user_ns),
1599 namespaces = [ ('Interactive', self.user_ns),
1550 ('Interactive (global)', self.user_global_ns),
1600 ('Interactive (global)', self.user_global_ns),
1551 ('Python builtin', builtin_mod.__dict__),
1601 ('Python builtin', builtin_mod.__dict__),
1552 ]
1602 ]
1553
1603
1554 ismagic = False
1604 ismagic = False
1555 isalias = False
1605 isalias = False
1556 found = False
1606 found = False
1557 ospace = None
1607 ospace = None
1558 parent = None
1608 parent = None
1559 obj = None
1609 obj = None
1560
1610
1561
1611
1562 # Look for the given name by splitting it in parts. If the head is
1612 # Look for the given name by splitting it in parts. If the head is
1563 # found, then we look for all the remaining parts as members, and only
1613 # found, then we look for all the remaining parts as members, and only
1564 # declare success if we can find them all.
1614 # declare success if we can find them all.
1565 oname_parts = oname.split('.')
1615 oname_parts = parts
1566 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1616 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1567 for nsname,ns in namespaces:
1617 for nsname,ns in namespaces:
1568 try:
1618 try:
1569 obj = ns[oname_head]
1619 obj = ns[oname_head]
1570 except KeyError:
1620 except KeyError:
1571 continue
1621 continue
1572 else:
1622 else:
1573 for idx, part in enumerate(oname_rest):
1623 for idx, part in enumerate(oname_rest):
1574 try:
1624 try:
1575 parent = obj
1625 parent = obj
1576 # The last part is looked up in a special way to avoid
1626 # The last part is looked up in a special way to avoid
1577 # descriptor invocation as it may raise or have side
1627 # descriptor invocation as it may raise or have side
1578 # effects.
1628 # effects.
1579 if idx == len(oname_rest) - 1:
1629 if idx == len(oname_rest) - 1:
1580 obj = self._getattr_property(obj, part)
1630 obj = self._getattr_property(obj, part)
1581 else:
1631 else:
1582 obj = getattr(obj, part)
1632 if is_integer_string(part):
1633 obj = obj[int(part)]
1634 else:
1635 obj = getattr(obj, part)
1583 except:
1636 except:
1584 # Blanket except b/c some badly implemented objects
1637 # Blanket except b/c some badly implemented objects
1585 # allow __getattr__ to raise exceptions other than
1638 # allow __getattr__ to raise exceptions other than
1586 # AttributeError, which then crashes IPython.
1639 # AttributeError, which then crashes IPython.
1587 break
1640 break
1588 else:
1641 else:
1589 # If we finish the for loop (no break), we got all members
1642 # If we finish the for loop (no break), we got all members
1590 found = True
1643 found = True
1591 ospace = nsname
1644 ospace = nsname
1592 break # namespace loop
1645 break # namespace loop
1593
1646
1594 # Try to see if it's magic
1647 # Try to see if it's magic
1595 if not found:
1648 if not found:
1596 obj = None
1649 obj = None
1597 if oname.startswith(ESC_MAGIC2):
1650 if oname.startswith(ESC_MAGIC2):
1598 oname = oname.lstrip(ESC_MAGIC2)
1651 oname = oname.lstrip(ESC_MAGIC2)
1599 obj = self.find_cell_magic(oname)
1652 obj = self.find_cell_magic(oname)
1600 elif oname.startswith(ESC_MAGIC):
1653 elif oname.startswith(ESC_MAGIC):
1601 oname = oname.lstrip(ESC_MAGIC)
1654 oname = oname.lstrip(ESC_MAGIC)
1602 obj = self.find_line_magic(oname)
1655 obj = self.find_line_magic(oname)
1603 else:
1656 else:
1604 # search without prefix, so run? will find %run?
1657 # search without prefix, so run? will find %run?
1605 obj = self.find_line_magic(oname)
1658 obj = self.find_line_magic(oname)
1606 if obj is None:
1659 if obj is None:
1607 obj = self.find_cell_magic(oname)
1660 obj = self.find_cell_magic(oname)
1608 if obj is not None:
1661 if obj is not None:
1609 found = True
1662 found = True
1610 ospace = 'IPython internal'
1663 ospace = 'IPython internal'
1611 ismagic = True
1664 ismagic = True
1612 isalias = isinstance(obj, Alias)
1665 isalias = isinstance(obj, Alias)
1613
1666
1614 # Last try: special-case some literals like '', [], {}, etc:
1667 # Last try: special-case some literals like '', [], {}, etc:
1615 if not found and oname_head in ["''",'""','[]','{}','()']:
1668 if not found and oname_head in ["''",'""','[]','{}','()']:
1616 obj = eval(oname_head)
1669 obj = eval(oname_head)
1617 found = True
1670 found = True
1618 ospace = 'Interactive'
1671 ospace = 'Interactive'
1619
1672
1620 return {
1673 return {
1621 'obj':obj,
1674 'obj':obj,
1622 'found':found,
1675 'found':found,
1623 'parent':parent,
1676 'parent':parent,
1624 'ismagic':ismagic,
1677 'ismagic':ismagic,
1625 'isalias':isalias,
1678 'isalias':isalias,
1626 'namespace':ospace
1679 'namespace':ospace
1627 }
1680 }
1628
1681
1629 @staticmethod
1682 @staticmethod
1630 def _getattr_property(obj, attrname):
1683 def _getattr_property(obj, attrname):
1631 """Property-aware getattr to use in object finding.
1684 """Property-aware getattr to use in object finding.
1632
1685
1633 If attrname represents a property, return it unevaluated (in case it has
1686 If attrname represents a property, return it unevaluated (in case it has
1634 side effects or raises an error.
1687 side effects or raises an error.
1635
1688
1636 """
1689 """
1637 if not isinstance(obj, type):
1690 if not isinstance(obj, type):
1638 try:
1691 try:
1639 # `getattr(type(obj), attrname)` is not guaranteed to return
1692 # `getattr(type(obj), attrname)` is not guaranteed to return
1640 # `obj`, but does so for property:
1693 # `obj`, but does so for property:
1641 #
1694 #
1642 # property.__get__(self, None, cls) -> self
1695 # property.__get__(self, None, cls) -> self
1643 #
1696 #
1644 # The universal alternative is to traverse the mro manually
1697 # The universal alternative is to traverse the mro manually
1645 # searching for attrname in class dicts.
1698 # searching for attrname in class dicts.
1646 attr = getattr(type(obj), attrname)
1699 if is_integer_string(attrname):
1700 return obj[int(attrname)]
1701 else:
1702 attr = getattr(type(obj), attrname)
1647 except AttributeError:
1703 except AttributeError:
1648 pass
1704 pass
1649 else:
1705 else:
1650 # This relies on the fact that data descriptors (with both
1706 # This relies on the fact that data descriptors (with both
1651 # __get__ & __set__ magic methods) take precedence over
1707 # __get__ & __set__ magic methods) take precedence over
1652 # instance-level attributes:
1708 # instance-level attributes:
1653 #
1709 #
1654 # class A(object):
1710 # class A(object):
1655 # @property
1711 # @property
1656 # def foobar(self): return 123
1712 # def foobar(self): return 123
1657 # a = A()
1713 # a = A()
1658 # a.__dict__['foobar'] = 345
1714 # a.__dict__['foobar'] = 345
1659 # a.foobar # == 123
1715 # a.foobar # == 123
1660 #
1716 #
1661 # So, a property may be returned right away.
1717 # So, a property may be returned right away.
1662 if isinstance(attr, property):
1718 if isinstance(attr, property):
1663 return attr
1719 return attr
1664
1720
1665 # Nothing helped, fall back.
1721 # Nothing helped, fall back.
1666 return getattr(obj, attrname)
1722 return getattr(obj, attrname)
1667
1723
1668 def _object_find(self, oname, namespaces=None):
1724 def _object_find(self, oname, namespaces=None):
1669 """Find an object and return a struct with info about it."""
1725 """Find an object and return a struct with info about it."""
1670 return Struct(self._ofind(oname, namespaces))
1726 return Struct(self._ofind(oname, namespaces))
1671
1727
1672 def _inspect(self, meth, oname, namespaces=None, **kw):
1728 def _inspect(self, meth, oname, namespaces=None, **kw):
1673 """Generic interface to the inspector system.
1729 """Generic interface to the inspector system.
1674
1730
1675 This function is meant to be called by pdef, pdoc & friends.
1731 This function is meant to be called by pdef, pdoc & friends.
1676 """
1732 """
1677 info = self._object_find(oname, namespaces)
1733 info = self._object_find(oname, namespaces)
1678 docformat = (
1734 docformat = (
1679 sphinxify(self.object_inspect(oname)) if self.sphinxify_docstring else None
1735 sphinxify(self.object_inspect(oname)) if self.sphinxify_docstring else None
1680 )
1736 )
1681 if info.found:
1737 if info.found:
1682 pmethod = getattr(self.inspector, meth)
1738 pmethod = getattr(self.inspector, meth)
1683 # TODO: only apply format_screen to the plain/text repr of the mime
1739 # TODO: only apply format_screen to the plain/text repr of the mime
1684 # bundle.
1740 # bundle.
1685 formatter = format_screen if info.ismagic else docformat
1741 formatter = format_screen if info.ismagic else docformat
1686 if meth == 'pdoc':
1742 if meth == 'pdoc':
1687 pmethod(info.obj, oname, formatter)
1743 pmethod(info.obj, oname, formatter)
1688 elif meth == 'pinfo':
1744 elif meth == 'pinfo':
1689 pmethod(
1745 pmethod(
1690 info.obj,
1746 info.obj,
1691 oname,
1747 oname,
1692 formatter,
1748 formatter,
1693 info,
1749 info,
1694 enable_html_pager=self.enable_html_pager,
1750 enable_html_pager=self.enable_html_pager,
1695 **kw,
1751 **kw,
1696 )
1752 )
1697 else:
1753 else:
1698 pmethod(info.obj, oname)
1754 pmethod(info.obj, oname)
1699 else:
1755 else:
1700 print('Object `%s` not found.' % oname)
1756 print('Object `%s` not found.' % oname)
1701 return 'not found' # so callers can take other action
1757 return 'not found' # so callers can take other action
1702
1758
1703 def object_inspect(self, oname, detail_level=0):
1759 def object_inspect(self, oname, detail_level=0):
1704 """Get object info about oname"""
1760 """Get object info about oname"""
1705 with self.builtin_trap:
1761 with self.builtin_trap:
1706 info = self._object_find(oname)
1762 info = self._object_find(oname)
1707 if info.found:
1763 if info.found:
1708 return self.inspector.info(info.obj, oname, info=info,
1764 return self.inspector.info(info.obj, oname, info=info,
1709 detail_level=detail_level
1765 detail_level=detail_level
1710 )
1766 )
1711 else:
1767 else:
1712 return oinspect.object_info(name=oname, found=False)
1768 return oinspect.object_info(name=oname, found=False)
1713
1769
1714 def object_inspect_text(self, oname, detail_level=0):
1770 def object_inspect_text(self, oname, detail_level=0):
1715 """Get object info as formatted text"""
1771 """Get object info as formatted text"""
1716 return self.object_inspect_mime(oname, detail_level)['text/plain']
1772 return self.object_inspect_mime(oname, detail_level)['text/plain']
1717
1773
1718 def object_inspect_mime(self, oname, detail_level=0, omit_sections=()):
1774 def object_inspect_mime(self, oname, detail_level=0, omit_sections=()):
1719 """Get object info as a mimebundle of formatted representations.
1775 """Get object info as a mimebundle of formatted representations.
1720
1776
1721 A mimebundle is a dictionary, keyed by mime-type.
1777 A mimebundle is a dictionary, keyed by mime-type.
1722 It must always have the key `'text/plain'`.
1778 It must always have the key `'text/plain'`.
1723 """
1779 """
1724 with self.builtin_trap:
1780 with self.builtin_trap:
1725 info = self._object_find(oname)
1781 info = self._object_find(oname)
1726 if info.found:
1782 if info.found:
1727 docformat = (
1783 docformat = (
1728 sphinxify(self.object_inspect(oname))
1784 sphinxify(self.object_inspect(oname))
1729 if self.sphinxify_docstring
1785 if self.sphinxify_docstring
1730 else None
1786 else None
1731 )
1787 )
1732 return self.inspector._get_info(
1788 return self.inspector._get_info(
1733 info.obj,
1789 info.obj,
1734 oname,
1790 oname,
1735 info=info,
1791 info=info,
1736 detail_level=detail_level,
1792 detail_level=detail_level,
1737 formatter=docformat,
1793 formatter=docformat,
1738 omit_sections=omit_sections,
1794 omit_sections=omit_sections,
1739 )
1795 )
1740 else:
1796 else:
1741 raise KeyError(oname)
1797 raise KeyError(oname)
1742
1798
1743 #-------------------------------------------------------------------------
1799 #-------------------------------------------------------------------------
1744 # Things related to history management
1800 # Things related to history management
1745 #-------------------------------------------------------------------------
1801 #-------------------------------------------------------------------------
1746
1802
1747 def init_history(self):
1803 def init_history(self):
1748 """Sets up the command history, and starts regular autosaves."""
1804 """Sets up the command history, and starts regular autosaves."""
1749 self.history_manager = HistoryManager(shell=self, parent=self)
1805 self.history_manager = HistoryManager(shell=self, parent=self)
1750 self.configurables.append(self.history_manager)
1806 self.configurables.append(self.history_manager)
1751
1807
1752 #-------------------------------------------------------------------------
1808 #-------------------------------------------------------------------------
1753 # Things related to exception handling and tracebacks (not debugging)
1809 # Things related to exception handling and tracebacks (not debugging)
1754 #-------------------------------------------------------------------------
1810 #-------------------------------------------------------------------------
1755
1811
1756 debugger_cls = InterruptiblePdb
1812 debugger_cls = InterruptiblePdb
1757
1813
1758 def init_traceback_handlers(self, custom_exceptions):
1814 def init_traceback_handlers(self, custom_exceptions):
1759 # Syntax error handler.
1815 # Syntax error handler.
1760 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor', parent=self)
1816 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor', parent=self)
1761
1817
1762 # The interactive one is initialized with an offset, meaning we always
1818 # The interactive one is initialized with an offset, meaning we always
1763 # want to remove the topmost item in the traceback, which is our own
1819 # want to remove the topmost item in the traceback, which is our own
1764 # internal code. Valid modes: ['Plain','Context','Verbose','Minimal']
1820 # internal code. Valid modes: ['Plain','Context','Verbose','Minimal']
1765 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1821 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1766 color_scheme='NoColor',
1822 color_scheme='NoColor',
1767 tb_offset = 1,
1823 tb_offset = 1,
1768 check_cache=check_linecache_ipython,
1769 debugger_cls=self.debugger_cls, parent=self)
1824 debugger_cls=self.debugger_cls, parent=self)
1770
1825
1771 # The instance will store a pointer to the system-wide exception hook,
1826 # The instance will store a pointer to the system-wide exception hook,
1772 # so that runtime code (such as magics) can access it. This is because
1827 # so that runtime code (such as magics) can access it. This is because
1773 # during the read-eval loop, it may get temporarily overwritten.
1828 # during the read-eval loop, it may get temporarily overwritten.
1774 self.sys_excepthook = sys.excepthook
1829 self.sys_excepthook = sys.excepthook
1775
1830
1776 # and add any custom exception handlers the user may have specified
1831 # and add any custom exception handlers the user may have specified
1777 self.set_custom_exc(*custom_exceptions)
1832 self.set_custom_exc(*custom_exceptions)
1778
1833
1779 # Set the exception mode
1834 # Set the exception mode
1780 self.InteractiveTB.set_mode(mode=self.xmode)
1835 self.InteractiveTB.set_mode(mode=self.xmode)
1781
1836
1782 def set_custom_exc(self, exc_tuple, handler):
1837 def set_custom_exc(self, exc_tuple, handler):
1783 """set_custom_exc(exc_tuple, handler)
1838 """set_custom_exc(exc_tuple, handler)
1784
1839
1785 Set a custom exception handler, which will be called if any of the
1840 Set a custom exception handler, which will be called if any of the
1786 exceptions in exc_tuple occur in the mainloop (specifically, in the
1841 exceptions in exc_tuple occur in the mainloop (specifically, in the
1787 run_code() method).
1842 run_code() method).
1788
1843
1789 Parameters
1844 Parameters
1790 ----------
1845 ----------
1791 exc_tuple : tuple of exception classes
1846 exc_tuple : tuple of exception classes
1792 A *tuple* of exception classes, for which to call the defined
1847 A *tuple* of exception classes, for which to call the defined
1793 handler. It is very important that you use a tuple, and NOT A
1848 handler. It is very important that you use a tuple, and NOT A
1794 LIST here, because of the way Python's except statement works. If
1849 LIST here, because of the way Python's except statement works. If
1795 you only want to trap a single exception, use a singleton tuple::
1850 you only want to trap a single exception, use a singleton tuple::
1796
1851
1797 exc_tuple == (MyCustomException,)
1852 exc_tuple == (MyCustomException,)
1798
1853
1799 handler : callable
1854 handler : callable
1800 handler must have the following signature::
1855 handler must have the following signature::
1801
1856
1802 def my_handler(self, etype, value, tb, tb_offset=None):
1857 def my_handler(self, etype, value, tb, tb_offset=None):
1803 ...
1858 ...
1804 return structured_traceback
1859 return structured_traceback
1805
1860
1806 Your handler must return a structured traceback (a list of strings),
1861 Your handler must return a structured traceback (a list of strings),
1807 or None.
1862 or None.
1808
1863
1809 This will be made into an instance method (via types.MethodType)
1864 This will be made into an instance method (via types.MethodType)
1810 of IPython itself, and it will be called if any of the exceptions
1865 of IPython itself, and it will be called if any of the exceptions
1811 listed in the exc_tuple are caught. If the handler is None, an
1866 listed in the exc_tuple are caught. If the handler is None, an
1812 internal basic one is used, which just prints basic info.
1867 internal basic one is used, which just prints basic info.
1813
1868
1814 To protect IPython from crashes, if your handler ever raises an
1869 To protect IPython from crashes, if your handler ever raises an
1815 exception or returns an invalid result, it will be immediately
1870 exception or returns an invalid result, it will be immediately
1816 disabled.
1871 disabled.
1817
1872
1818 Notes
1873 Notes
1819 -----
1874 -----
1820 WARNING: by putting in your own exception handler into IPython's main
1875 WARNING: by putting in your own exception handler into IPython's main
1821 execution loop, you run a very good chance of nasty crashes. This
1876 execution loop, you run a very good chance of nasty crashes. This
1822 facility should only be used if you really know what you are doing.
1877 facility should only be used if you really know what you are doing.
1823 """
1878 """
1824
1879
1825 if not isinstance(exc_tuple, tuple):
1880 if not isinstance(exc_tuple, tuple):
1826 raise TypeError("The custom exceptions must be given as a tuple.")
1881 raise TypeError("The custom exceptions must be given as a tuple.")
1827
1882
1828 def dummy_handler(self, etype, value, tb, tb_offset=None):
1883 def dummy_handler(self, etype, value, tb, tb_offset=None):
1829 print('*** Simple custom exception handler ***')
1884 print('*** Simple custom exception handler ***')
1830 print('Exception type :', etype)
1885 print('Exception type :', etype)
1831 print('Exception value:', value)
1886 print('Exception value:', value)
1832 print('Traceback :', tb)
1887 print('Traceback :', tb)
1833
1888
1834 def validate_stb(stb):
1889 def validate_stb(stb):
1835 """validate structured traceback return type
1890 """validate structured traceback return type
1836
1891
1837 return type of CustomTB *should* be a list of strings, but allow
1892 return type of CustomTB *should* be a list of strings, but allow
1838 single strings or None, which are harmless.
1893 single strings or None, which are harmless.
1839
1894
1840 This function will *always* return a list of strings,
1895 This function will *always* return a list of strings,
1841 and will raise a TypeError if stb is inappropriate.
1896 and will raise a TypeError if stb is inappropriate.
1842 """
1897 """
1843 msg = "CustomTB must return list of strings, not %r" % stb
1898 msg = "CustomTB must return list of strings, not %r" % stb
1844 if stb is None:
1899 if stb is None:
1845 return []
1900 return []
1846 elif isinstance(stb, str):
1901 elif isinstance(stb, str):
1847 return [stb]
1902 return [stb]
1848 elif not isinstance(stb, list):
1903 elif not isinstance(stb, list):
1849 raise TypeError(msg)
1904 raise TypeError(msg)
1850 # it's a list
1905 # it's a list
1851 for line in stb:
1906 for line in stb:
1852 # check every element
1907 # check every element
1853 if not isinstance(line, str):
1908 if not isinstance(line, str):
1854 raise TypeError(msg)
1909 raise TypeError(msg)
1855 return stb
1910 return stb
1856
1911
1857 if handler is None:
1912 if handler is None:
1858 wrapped = dummy_handler
1913 wrapped = dummy_handler
1859 else:
1914 else:
1860 def wrapped(self,etype,value,tb,tb_offset=None):
1915 def wrapped(self,etype,value,tb,tb_offset=None):
1861 """wrap CustomTB handler, to protect IPython from user code
1916 """wrap CustomTB handler, to protect IPython from user code
1862
1917
1863 This makes it harder (but not impossible) for custom exception
1918 This makes it harder (but not impossible) for custom exception
1864 handlers to crash IPython.
1919 handlers to crash IPython.
1865 """
1920 """
1866 try:
1921 try:
1867 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1922 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1868 return validate_stb(stb)
1923 return validate_stb(stb)
1869 except:
1924 except:
1870 # clear custom handler immediately
1925 # clear custom handler immediately
1871 self.set_custom_exc((), None)
1926 self.set_custom_exc((), None)
1872 print("Custom TB Handler failed, unregistering", file=sys.stderr)
1927 print("Custom TB Handler failed, unregistering", file=sys.stderr)
1873 # show the exception in handler first
1928 # show the exception in handler first
1874 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1929 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1875 print(self.InteractiveTB.stb2text(stb))
1930 print(self.InteractiveTB.stb2text(stb))
1876 print("The original exception:")
1931 print("The original exception:")
1877 stb = self.InteractiveTB.structured_traceback(
1932 stb = self.InteractiveTB.structured_traceback(
1878 (etype,value,tb), tb_offset=tb_offset
1933 (etype,value,tb), tb_offset=tb_offset
1879 )
1934 )
1880 return stb
1935 return stb
1881
1936
1882 self.CustomTB = types.MethodType(wrapped,self)
1937 self.CustomTB = types.MethodType(wrapped,self)
1883 self.custom_exceptions = exc_tuple
1938 self.custom_exceptions = exc_tuple
1884
1939
1885 def excepthook(self, etype, value, tb):
1940 def excepthook(self, etype, value, tb):
1886 """One more defense for GUI apps that call sys.excepthook.
1941 """One more defense for GUI apps that call sys.excepthook.
1887
1942
1888 GUI frameworks like wxPython trap exceptions and call
1943 GUI frameworks like wxPython trap exceptions and call
1889 sys.excepthook themselves. I guess this is a feature that
1944 sys.excepthook themselves. I guess this is a feature that
1890 enables them to keep running after exceptions that would
1945 enables them to keep running after exceptions that would
1891 otherwise kill their mainloop. This is a bother for IPython
1946 otherwise kill their mainloop. This is a bother for IPython
1892 which expects to catch all of the program exceptions with a try:
1947 which expects to catch all of the program exceptions with a try:
1893 except: statement.
1948 except: statement.
1894
1949
1895 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1950 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1896 any app directly invokes sys.excepthook, it will look to the user like
1951 any app directly invokes sys.excepthook, it will look to the user like
1897 IPython crashed. In order to work around this, we can disable the
1952 IPython crashed. In order to work around this, we can disable the
1898 CrashHandler and replace it with this excepthook instead, which prints a
1953 CrashHandler and replace it with this excepthook instead, which prints a
1899 regular traceback using our InteractiveTB. In this fashion, apps which
1954 regular traceback using our InteractiveTB. In this fashion, apps which
1900 call sys.excepthook will generate a regular-looking exception from
1955 call sys.excepthook will generate a regular-looking exception from
1901 IPython, and the CrashHandler will only be triggered by real IPython
1956 IPython, and the CrashHandler will only be triggered by real IPython
1902 crashes.
1957 crashes.
1903
1958
1904 This hook should be used sparingly, only in places which are not likely
1959 This hook should be used sparingly, only in places which are not likely
1905 to be true IPython errors.
1960 to be true IPython errors.
1906 """
1961 """
1907 self.showtraceback((etype, value, tb), tb_offset=0)
1962 self.showtraceback((etype, value, tb), tb_offset=0)
1908
1963
1909 def _get_exc_info(self, exc_tuple=None):
1964 def _get_exc_info(self, exc_tuple=None):
1910 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1965 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1911
1966
1912 Ensures sys.last_type,value,traceback hold the exc_info we found,
1967 Ensures sys.last_type,value,traceback hold the exc_info we found,
1913 from whichever source.
1968 from whichever source.
1914
1969
1915 raises ValueError if none of these contain any information
1970 raises ValueError if none of these contain any information
1916 """
1971 """
1917 if exc_tuple is None:
1972 if exc_tuple is None:
1918 etype, value, tb = sys.exc_info()
1973 etype, value, tb = sys.exc_info()
1919 else:
1974 else:
1920 etype, value, tb = exc_tuple
1975 etype, value, tb = exc_tuple
1921
1976
1922 if etype is None:
1977 if etype is None:
1923 if hasattr(sys, 'last_type'):
1978 if hasattr(sys, 'last_type'):
1924 etype, value, tb = sys.last_type, sys.last_value, \
1979 etype, value, tb = sys.last_type, sys.last_value, \
1925 sys.last_traceback
1980 sys.last_traceback
1926
1981
1927 if etype is None:
1982 if etype is None:
1928 raise ValueError("No exception to find")
1983 raise ValueError("No exception to find")
1929
1984
1930 # Now store the exception info in sys.last_type etc.
1985 # Now store the exception info in sys.last_type etc.
1931 # WARNING: these variables are somewhat deprecated and not
1986 # WARNING: these variables are somewhat deprecated and not
1932 # necessarily safe to use in a threaded environment, but tools
1987 # necessarily safe to use in a threaded environment, but tools
1933 # like pdb depend on their existence, so let's set them. If we
1988 # like pdb depend on their existence, so let's set them. If we
1934 # find problems in the field, we'll need to revisit their use.
1989 # find problems in the field, we'll need to revisit their use.
1935 sys.last_type = etype
1990 sys.last_type = etype
1936 sys.last_value = value
1991 sys.last_value = value
1937 sys.last_traceback = tb
1992 sys.last_traceback = tb
1938
1993
1939 return etype, value, tb
1994 return etype, value, tb
1940
1995
1941 def show_usage_error(self, exc):
1996 def show_usage_error(self, exc):
1942 """Show a short message for UsageErrors
1997 """Show a short message for UsageErrors
1943
1998
1944 These are special exceptions that shouldn't show a traceback.
1999 These are special exceptions that shouldn't show a traceback.
1945 """
2000 """
1946 print("UsageError: %s" % exc, file=sys.stderr)
2001 print("UsageError: %s" % exc, file=sys.stderr)
1947
2002
1948 def get_exception_only(self, exc_tuple=None):
2003 def get_exception_only(self, exc_tuple=None):
1949 """
2004 """
1950 Return as a string (ending with a newline) the exception that
2005 Return as a string (ending with a newline) the exception that
1951 just occurred, without any traceback.
2006 just occurred, without any traceback.
1952 """
2007 """
1953 etype, value, tb = self._get_exc_info(exc_tuple)
2008 etype, value, tb = self._get_exc_info(exc_tuple)
1954 msg = traceback.format_exception_only(etype, value)
2009 msg = traceback.format_exception_only(etype, value)
1955 return ''.join(msg)
2010 return ''.join(msg)
1956
2011
1957 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
2012 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
1958 exception_only=False, running_compiled_code=False):
2013 exception_only=False, running_compiled_code=False):
1959 """Display the exception that just occurred.
2014 """Display the exception that just occurred.
1960
2015
1961 If nothing is known about the exception, this is the method which
2016 If nothing is known about the exception, this is the method which
1962 should be used throughout the code for presenting user tracebacks,
2017 should be used throughout the code for presenting user tracebacks,
1963 rather than directly invoking the InteractiveTB object.
2018 rather than directly invoking the InteractiveTB object.
1964
2019
1965 A specific showsyntaxerror() also exists, but this method can take
2020 A specific showsyntaxerror() also exists, but this method can take
1966 care of calling it if needed, so unless you are explicitly catching a
2021 care of calling it if needed, so unless you are explicitly catching a
1967 SyntaxError exception, don't try to analyze the stack manually and
2022 SyntaxError exception, don't try to analyze the stack manually and
1968 simply call this method."""
2023 simply call this method."""
1969
2024
1970 try:
2025 try:
1971 try:
2026 try:
1972 etype, value, tb = self._get_exc_info(exc_tuple)
2027 etype, value, tb = self._get_exc_info(exc_tuple)
1973 except ValueError:
2028 except ValueError:
1974 print('No traceback available to show.', file=sys.stderr)
2029 print('No traceback available to show.', file=sys.stderr)
1975 return
2030 return
1976
2031
1977 if issubclass(etype, SyntaxError):
2032 if issubclass(etype, SyntaxError):
1978 # Though this won't be called by syntax errors in the input
2033 # Though this won't be called by syntax errors in the input
1979 # line, there may be SyntaxError cases with imported code.
2034 # line, there may be SyntaxError cases with imported code.
1980 self.showsyntaxerror(filename, running_compiled_code)
2035 self.showsyntaxerror(filename, running_compiled_code)
1981 elif etype is UsageError:
2036 elif etype is UsageError:
1982 self.show_usage_error(value)
2037 self.show_usage_error(value)
1983 else:
2038 else:
1984 if exception_only:
2039 if exception_only:
1985 stb = ['An exception has occurred, use %tb to see '
2040 stb = ['An exception has occurred, use %tb to see '
1986 'the full traceback.\n']
2041 'the full traceback.\n']
1987 stb.extend(self.InteractiveTB.get_exception_only(etype,
2042 stb.extend(self.InteractiveTB.get_exception_only(etype,
1988 value))
2043 value))
1989 else:
2044 else:
1990 try:
2045 try:
1991 # Exception classes can customise their traceback - we
2046 # Exception classes can customise their traceback - we
1992 # use this in IPython.parallel for exceptions occurring
2047 # use this in IPython.parallel for exceptions occurring
1993 # in the engines. This should return a list of strings.
2048 # in the engines. This should return a list of strings.
1994 if hasattr(value, "_render_traceback_"):
2049 if hasattr(value, "_render_traceback_"):
1995 stb = value._render_traceback_()
2050 stb = value._render_traceback_()
1996 else:
2051 else:
1997 stb = self.InteractiveTB.structured_traceback(
2052 stb = self.InteractiveTB.structured_traceback(
1998 etype, value, tb, tb_offset=tb_offset
2053 etype, value, tb, tb_offset=tb_offset
1999 )
2054 )
2000
2055
2001 except Exception:
2056 except Exception:
2002 print(
2057 print(
2003 "Unexpected exception formatting exception. Falling back to standard exception"
2058 "Unexpected exception formatting exception. Falling back to standard exception"
2004 )
2059 )
2005 traceback.print_exc()
2060 traceback.print_exc()
2006 return None
2061 return None
2007
2062
2008 self._showtraceback(etype, value, stb)
2063 self._showtraceback(etype, value, stb)
2009 if self.call_pdb:
2064 if self.call_pdb:
2010 # drop into debugger
2065 # drop into debugger
2011 self.debugger(force=True)
2066 self.debugger(force=True)
2012 return
2067 return
2013
2068
2014 # Actually show the traceback
2069 # Actually show the traceback
2015 self._showtraceback(etype, value, stb)
2070 self._showtraceback(etype, value, stb)
2016
2071
2017 except KeyboardInterrupt:
2072 except KeyboardInterrupt:
2018 print('\n' + self.get_exception_only(), file=sys.stderr)
2073 print('\n' + self.get_exception_only(), file=sys.stderr)
2019
2074
2020 def _showtraceback(self, etype, evalue, stb: str):
2075 def _showtraceback(self, etype, evalue, stb: str):
2021 """Actually show a traceback.
2076 """Actually show a traceback.
2022
2077
2023 Subclasses may override this method to put the traceback on a different
2078 Subclasses may override this method to put the traceback on a different
2024 place, like a side channel.
2079 place, like a side channel.
2025 """
2080 """
2026 val = self.InteractiveTB.stb2text(stb)
2081 val = self.InteractiveTB.stb2text(stb)
2027 try:
2082 try:
2028 print(val)
2083 print(val)
2029 except UnicodeEncodeError:
2084 except UnicodeEncodeError:
2030 print(val.encode("utf-8", "backslashreplace").decode())
2085 print(val.encode("utf-8", "backslashreplace").decode())
2031
2086
2032 def showsyntaxerror(self, filename=None, running_compiled_code=False):
2087 def showsyntaxerror(self, filename=None, running_compiled_code=False):
2033 """Display the syntax error that just occurred.
2088 """Display the syntax error that just occurred.
2034
2089
2035 This doesn't display a stack trace because there isn't one.
2090 This doesn't display a stack trace because there isn't one.
2036
2091
2037 If a filename is given, it is stuffed in the exception instead
2092 If a filename is given, it is stuffed in the exception instead
2038 of what was there before (because Python's parser always uses
2093 of what was there before (because Python's parser always uses
2039 "<string>" when reading from a string).
2094 "<string>" when reading from a string).
2040
2095
2041 If the syntax error occurred when running a compiled code (i.e. running_compile_code=True),
2096 If the syntax error occurred when running a compiled code (i.e. running_compile_code=True),
2042 longer stack trace will be displayed.
2097 longer stack trace will be displayed.
2043 """
2098 """
2044 etype, value, last_traceback = self._get_exc_info()
2099 etype, value, last_traceback = self._get_exc_info()
2045
2100
2046 if filename and issubclass(etype, SyntaxError):
2101 if filename and issubclass(etype, SyntaxError):
2047 try:
2102 try:
2048 value.filename = filename
2103 value.filename = filename
2049 except:
2104 except:
2050 # Not the format we expect; leave it alone
2105 # Not the format we expect; leave it alone
2051 pass
2106 pass
2052
2107
2053 # If the error occurred when executing compiled code, we should provide full stacktrace.
2108 # If the error occurred when executing compiled code, we should provide full stacktrace.
2054 elist = traceback.extract_tb(last_traceback) if running_compiled_code else []
2109 elist = traceback.extract_tb(last_traceback) if running_compiled_code else []
2055 stb = self.SyntaxTB.structured_traceback(etype, value, elist)
2110 stb = self.SyntaxTB.structured_traceback(etype, value, elist)
2056 self._showtraceback(etype, value, stb)
2111 self._showtraceback(etype, value, stb)
2057
2112
2058 # This is overridden in TerminalInteractiveShell to show a message about
2113 # This is overridden in TerminalInteractiveShell to show a message about
2059 # the %paste magic.
2114 # the %paste magic.
2060 def showindentationerror(self):
2115 def showindentationerror(self):
2061 """Called by _run_cell when there's an IndentationError in code entered
2116 """Called by _run_cell when there's an IndentationError in code entered
2062 at the prompt.
2117 at the prompt.
2063
2118
2064 This is overridden in TerminalInteractiveShell to show a message about
2119 This is overridden in TerminalInteractiveShell to show a message about
2065 the %paste magic."""
2120 the %paste magic."""
2066 self.showsyntaxerror()
2121 self.showsyntaxerror()
2067
2122
2068 @skip_doctest
2123 @skip_doctest
2069 def set_next_input(self, s, replace=False):
2124 def set_next_input(self, s, replace=False):
2070 """ Sets the 'default' input string for the next command line.
2125 """ Sets the 'default' input string for the next command line.
2071
2126
2072 Example::
2127 Example::
2073
2128
2074 In [1]: _ip.set_next_input("Hello Word")
2129 In [1]: _ip.set_next_input("Hello Word")
2075 In [2]: Hello Word_ # cursor is here
2130 In [2]: Hello Word_ # cursor is here
2076 """
2131 """
2077 self.rl_next_input = s
2132 self.rl_next_input = s
2078
2133
2079 def _indent_current_str(self):
2134 def _indent_current_str(self):
2080 """return the current level of indentation as a string"""
2135 """return the current level of indentation as a string"""
2081 return self.input_splitter.get_indent_spaces() * ' '
2136 return self.input_splitter.get_indent_spaces() * ' '
2082
2137
2083 #-------------------------------------------------------------------------
2138 #-------------------------------------------------------------------------
2084 # Things related to text completion
2139 # Things related to text completion
2085 #-------------------------------------------------------------------------
2140 #-------------------------------------------------------------------------
2086
2141
2087 def init_completer(self):
2142 def init_completer(self):
2088 """Initialize the completion machinery.
2143 """Initialize the completion machinery.
2089
2144
2090 This creates completion machinery that can be used by client code,
2145 This creates completion machinery that can be used by client code,
2091 either interactively in-process (typically triggered by the readline
2146 either interactively in-process (typically triggered by the readline
2092 library), programmatically (such as in test suites) or out-of-process
2147 library), programmatically (such as in test suites) or out-of-process
2093 (typically over the network by remote frontends).
2148 (typically over the network by remote frontends).
2094 """
2149 """
2095 from IPython.core.completer import IPCompleter
2150 from IPython.core.completer import IPCompleter
2096 from IPython.core.completerlib import (
2151 from IPython.core.completerlib import (
2097 cd_completer,
2152 cd_completer,
2098 magic_run_completer,
2153 magic_run_completer,
2099 module_completer,
2154 module_completer,
2100 reset_completer,
2155 reset_completer,
2101 )
2156 )
2102
2157
2103 self.Completer = IPCompleter(shell=self,
2158 self.Completer = IPCompleter(shell=self,
2104 namespace=self.user_ns,
2159 namespace=self.user_ns,
2105 global_namespace=self.user_global_ns,
2160 global_namespace=self.user_global_ns,
2106 parent=self,
2161 parent=self,
2107 )
2162 )
2108 self.configurables.append(self.Completer)
2163 self.configurables.append(self.Completer)
2109
2164
2110 # Add custom completers to the basic ones built into IPCompleter
2165 # Add custom completers to the basic ones built into IPCompleter
2111 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2166 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2112 self.strdispatchers['complete_command'] = sdisp
2167 self.strdispatchers['complete_command'] = sdisp
2113 self.Completer.custom_completers = sdisp
2168 self.Completer.custom_completers = sdisp
2114
2169
2115 self.set_hook('complete_command', module_completer, str_key = 'import')
2170 self.set_hook('complete_command', module_completer, str_key = 'import')
2116 self.set_hook('complete_command', module_completer, str_key = 'from')
2171 self.set_hook('complete_command', module_completer, str_key = 'from')
2117 self.set_hook('complete_command', module_completer, str_key = '%aimport')
2172 self.set_hook('complete_command', module_completer, str_key = '%aimport')
2118 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2173 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2119 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2174 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2120 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2175 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2121
2176
2122 @skip_doctest
2177 @skip_doctest
2123 def complete(self, text, line=None, cursor_pos=None):
2178 def complete(self, text, line=None, cursor_pos=None):
2124 """Return the completed text and a list of completions.
2179 """Return the completed text and a list of completions.
2125
2180
2126 Parameters
2181 Parameters
2127 ----------
2182 ----------
2128 text : string
2183 text : string
2129 A string of text to be completed on. It can be given as empty and
2184 A string of text to be completed on. It can be given as empty and
2130 instead a line/position pair are given. In this case, the
2185 instead a line/position pair are given. In this case, the
2131 completer itself will split the line like readline does.
2186 completer itself will split the line like readline does.
2132 line : string, optional
2187 line : string, optional
2133 The complete line that text is part of.
2188 The complete line that text is part of.
2134 cursor_pos : int, optional
2189 cursor_pos : int, optional
2135 The position of the cursor on the input line.
2190 The position of the cursor on the input line.
2136
2191
2137 Returns
2192 Returns
2138 -------
2193 -------
2139 text : string
2194 text : string
2140 The actual text that was completed.
2195 The actual text that was completed.
2141 matches : list
2196 matches : list
2142 A sorted list with all possible completions.
2197 A sorted list with all possible completions.
2143
2198
2144 Notes
2199 Notes
2145 -----
2200 -----
2146 The optional arguments allow the completion to take more context into
2201 The optional arguments allow the completion to take more context into
2147 account, and are part of the low-level completion API.
2202 account, and are part of the low-level completion API.
2148
2203
2149 This is a wrapper around the completion mechanism, similar to what
2204 This is a wrapper around the completion mechanism, similar to what
2150 readline does at the command line when the TAB key is hit. By
2205 readline does at the command line when the TAB key is hit. By
2151 exposing it as a method, it can be used by other non-readline
2206 exposing it as a method, it can be used by other non-readline
2152 environments (such as GUIs) for text completion.
2207 environments (such as GUIs) for text completion.
2153
2208
2154 Examples
2209 Examples
2155 --------
2210 --------
2156 In [1]: x = 'hello'
2211 In [1]: x = 'hello'
2157
2212
2158 In [2]: _ip.complete('x.l')
2213 In [2]: _ip.complete('x.l')
2159 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2214 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2160 """
2215 """
2161
2216
2162 # Inject names into __builtin__ so we can complete on the added names.
2217 # Inject names into __builtin__ so we can complete on the added names.
2163 with self.builtin_trap:
2218 with self.builtin_trap:
2164 return self.Completer.complete(text, line, cursor_pos)
2219 return self.Completer.complete(text, line, cursor_pos)
2165
2220
2166 def set_custom_completer(self, completer, pos=0) -> None:
2221 def set_custom_completer(self, completer, pos=0) -> None:
2167 """Adds a new custom completer function.
2222 """Adds a new custom completer function.
2168
2223
2169 The position argument (defaults to 0) is the index in the completers
2224 The position argument (defaults to 0) is the index in the completers
2170 list where you want the completer to be inserted.
2225 list where you want the completer to be inserted.
2171
2226
2172 `completer` should have the following signature::
2227 `completer` should have the following signature::
2173
2228
2174 def completion(self: Completer, text: string) -> List[str]:
2229 def completion(self: Completer, text: string) -> List[str]:
2175 raise NotImplementedError
2230 raise NotImplementedError
2176
2231
2177 It will be bound to the current Completer instance and pass some text
2232 It will be bound to the current Completer instance and pass some text
2178 and return a list with current completions to suggest to the user.
2233 and return a list with current completions to suggest to the user.
2179 """
2234 """
2180
2235
2181 newcomp = types.MethodType(completer, self.Completer)
2236 newcomp = types.MethodType(completer, self.Completer)
2182 self.Completer.custom_matchers.insert(pos,newcomp)
2237 self.Completer.custom_matchers.insert(pos,newcomp)
2183
2238
2184 def set_completer_frame(self, frame=None):
2239 def set_completer_frame(self, frame=None):
2185 """Set the frame of the completer."""
2240 """Set the frame of the completer."""
2186 if frame:
2241 if frame:
2187 self.Completer.namespace = frame.f_locals
2242 self.Completer.namespace = frame.f_locals
2188 self.Completer.global_namespace = frame.f_globals
2243 self.Completer.global_namespace = frame.f_globals
2189 else:
2244 else:
2190 self.Completer.namespace = self.user_ns
2245 self.Completer.namespace = self.user_ns
2191 self.Completer.global_namespace = self.user_global_ns
2246 self.Completer.global_namespace = self.user_global_ns
2192
2247
2193 #-------------------------------------------------------------------------
2248 #-------------------------------------------------------------------------
2194 # Things related to magics
2249 # Things related to magics
2195 #-------------------------------------------------------------------------
2250 #-------------------------------------------------------------------------
2196
2251
2197 def init_magics(self):
2252 def init_magics(self):
2198 from IPython.core import magics as m
2253 from IPython.core import magics as m
2199 self.magics_manager = magic.MagicsManager(shell=self,
2254 self.magics_manager = magic.MagicsManager(shell=self,
2200 parent=self,
2255 parent=self,
2201 user_magics=m.UserMagics(self))
2256 user_magics=m.UserMagics(self))
2202 self.configurables.append(self.magics_manager)
2257 self.configurables.append(self.magics_manager)
2203
2258
2204 # Expose as public API from the magics manager
2259 # Expose as public API from the magics manager
2205 self.register_magics = self.magics_manager.register
2260 self.register_magics = self.magics_manager.register
2206
2261
2207 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2262 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2208 m.ConfigMagics, m.DisplayMagics, m.ExecutionMagics,
2263 m.ConfigMagics, m.DisplayMagics, m.ExecutionMagics,
2209 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2264 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2210 m.NamespaceMagics, m.OSMagics, m.PackagingMagics,
2265 m.NamespaceMagics, m.OSMagics, m.PackagingMagics,
2211 m.PylabMagics, m.ScriptMagics,
2266 m.PylabMagics, m.ScriptMagics,
2212 )
2267 )
2213 self.register_magics(m.AsyncMagics)
2268 self.register_magics(m.AsyncMagics)
2214
2269
2215 # Register Magic Aliases
2270 # Register Magic Aliases
2216 mman = self.magics_manager
2271 mman = self.magics_manager
2217 # FIXME: magic aliases should be defined by the Magics classes
2272 # FIXME: magic aliases should be defined by the Magics classes
2218 # or in MagicsManager, not here
2273 # or in MagicsManager, not here
2219 mman.register_alias('ed', 'edit')
2274 mman.register_alias('ed', 'edit')
2220 mman.register_alias('hist', 'history')
2275 mman.register_alias('hist', 'history')
2221 mman.register_alias('rep', 'recall')
2276 mman.register_alias('rep', 'recall')
2222 mman.register_alias('SVG', 'svg', 'cell')
2277 mman.register_alias('SVG', 'svg', 'cell')
2223 mman.register_alias('HTML', 'html', 'cell')
2278 mman.register_alias('HTML', 'html', 'cell')
2224 mman.register_alias('file', 'writefile', 'cell')
2279 mman.register_alias('file', 'writefile', 'cell')
2225
2280
2226 # FIXME: Move the color initialization to the DisplayHook, which
2281 # FIXME: Move the color initialization to the DisplayHook, which
2227 # should be split into a prompt manager and displayhook. We probably
2282 # should be split into a prompt manager and displayhook. We probably
2228 # even need a centralize colors management object.
2283 # even need a centralize colors management object.
2229 self.run_line_magic('colors', self.colors)
2284 self.run_line_magic('colors', self.colors)
2230
2285
2231 # Defined here so that it's included in the documentation
2286 # Defined here so that it's included in the documentation
2232 @functools.wraps(magic.MagicsManager.register_function)
2287 @functools.wraps(magic.MagicsManager.register_function)
2233 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2288 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2234 self.magics_manager.register_function(
2289 self.magics_manager.register_function(
2235 func, magic_kind=magic_kind, magic_name=magic_name
2290 func, magic_kind=magic_kind, magic_name=magic_name
2236 )
2291 )
2237
2292
2238 def _find_with_lazy_load(self, /, type_, magic_name: str):
2293 def _find_with_lazy_load(self, /, type_, magic_name: str):
2239 """
2294 """
2240 Try to find a magic potentially lazy-loading it.
2295 Try to find a magic potentially lazy-loading it.
2241
2296
2242 Parameters
2297 Parameters
2243 ----------
2298 ----------
2244
2299
2245 type_: "line"|"cell"
2300 type_: "line"|"cell"
2246 the type of magics we are trying to find/lazy load.
2301 the type of magics we are trying to find/lazy load.
2247 magic_name: str
2302 magic_name: str
2248 The name of the magic we are trying to find/lazy load
2303 The name of the magic we are trying to find/lazy load
2249
2304
2250
2305
2251 Note that this may have any side effects
2306 Note that this may have any side effects
2252 """
2307 """
2253 finder = {"line": self.find_line_magic, "cell": self.find_cell_magic}[type_]
2308 finder = {"line": self.find_line_magic, "cell": self.find_cell_magic}[type_]
2254 fn = finder(magic_name)
2309 fn = finder(magic_name)
2255 if fn is not None:
2310 if fn is not None:
2256 return fn
2311 return fn
2257 lazy = self.magics_manager.lazy_magics.get(magic_name)
2312 lazy = self.magics_manager.lazy_magics.get(magic_name)
2258 if lazy is None:
2313 if lazy is None:
2259 return None
2314 return None
2260
2315
2261 self.run_line_magic("load_ext", lazy)
2316 self.run_line_magic("load_ext", lazy)
2262 res = finder(magic_name)
2317 res = finder(magic_name)
2263 return res
2318 return res
2264
2319
2265 def run_line_magic(self, magic_name: str, line, _stack_depth=1):
2320 def run_line_magic(self, magic_name: str, line, _stack_depth=1):
2266 """Execute the given line magic.
2321 """Execute the given line magic.
2267
2322
2268 Parameters
2323 Parameters
2269 ----------
2324 ----------
2270 magic_name : str
2325 magic_name : str
2271 Name of the desired magic function, without '%' prefix.
2326 Name of the desired magic function, without '%' prefix.
2272 line : str
2327 line : str
2273 The rest of the input line as a single string.
2328 The rest of the input line as a single string.
2274 _stack_depth : int
2329 _stack_depth : int
2275 If run_line_magic() is called from magic() then _stack_depth=2.
2330 If run_line_magic() is called from magic() then _stack_depth=2.
2276 This is added to ensure backward compatibility for use of 'get_ipython().magic()'
2331 This is added to ensure backward compatibility for use of 'get_ipython().magic()'
2277 """
2332 """
2278 fn = self._find_with_lazy_load("line", magic_name)
2333 fn = self._find_with_lazy_load("line", magic_name)
2279 if fn is None:
2334 if fn is None:
2280 lazy = self.magics_manager.lazy_magics.get(magic_name)
2335 lazy = self.magics_manager.lazy_magics.get(magic_name)
2281 if lazy:
2336 if lazy:
2282 self.run_line_magic("load_ext", lazy)
2337 self.run_line_magic("load_ext", lazy)
2283 fn = self.find_line_magic(magic_name)
2338 fn = self.find_line_magic(magic_name)
2284 if fn is None:
2339 if fn is None:
2285 cm = self.find_cell_magic(magic_name)
2340 cm = self.find_cell_magic(magic_name)
2286 etpl = "Line magic function `%%%s` not found%s."
2341 etpl = "Line magic function `%%%s` not found%s."
2287 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2342 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2288 'did you mean that instead?)' % magic_name )
2343 'did you mean that instead?)' % magic_name )
2289 raise UsageError(etpl % (magic_name, extra))
2344 raise UsageError(etpl % (magic_name, extra))
2290 else:
2345 else:
2291 # Note: this is the distance in the stack to the user's frame.
2346 # Note: this is the distance in the stack to the user's frame.
2292 # This will need to be updated if the internal calling logic gets
2347 # This will need to be updated if the internal calling logic gets
2293 # refactored, or else we'll be expanding the wrong variables.
2348 # refactored, or else we'll be expanding the wrong variables.
2294
2349
2295 # Determine stack_depth depending on where run_line_magic() has been called
2350 # Determine stack_depth depending on where run_line_magic() has been called
2296 stack_depth = _stack_depth
2351 stack_depth = _stack_depth
2297 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2352 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2298 # magic has opted out of var_expand
2353 # magic has opted out of var_expand
2299 magic_arg_s = line
2354 magic_arg_s = line
2300 else:
2355 else:
2301 magic_arg_s = self.var_expand(line, stack_depth)
2356 magic_arg_s = self.var_expand(line, stack_depth)
2302 # Put magic args in a list so we can call with f(*a) syntax
2357 # Put magic args in a list so we can call with f(*a) syntax
2303 args = [magic_arg_s]
2358 args = [magic_arg_s]
2304 kwargs = {}
2359 kwargs = {}
2305 # Grab local namespace if we need it:
2360 # Grab local namespace if we need it:
2306 if getattr(fn, "needs_local_scope", False):
2361 if getattr(fn, "needs_local_scope", False):
2307 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2362 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2308 with self.builtin_trap:
2363 with self.builtin_trap:
2309 result = fn(*args, **kwargs)
2364 result = fn(*args, **kwargs)
2310 return result
2365 return result
2311
2366
2312 def get_local_scope(self, stack_depth):
2367 def get_local_scope(self, stack_depth):
2313 """Get local scope at given stack depth.
2368 """Get local scope at given stack depth.
2314
2369
2315 Parameters
2370 Parameters
2316 ----------
2371 ----------
2317 stack_depth : int
2372 stack_depth : int
2318 Depth relative to calling frame
2373 Depth relative to calling frame
2319 """
2374 """
2320 return sys._getframe(stack_depth + 1).f_locals
2375 return sys._getframe(stack_depth + 1).f_locals
2321
2376
2322 def run_cell_magic(self, magic_name, line, cell):
2377 def run_cell_magic(self, magic_name, line, cell):
2323 """Execute the given cell magic.
2378 """Execute the given cell magic.
2324
2379
2325 Parameters
2380 Parameters
2326 ----------
2381 ----------
2327 magic_name : str
2382 magic_name : str
2328 Name of the desired magic function, without '%' prefix.
2383 Name of the desired magic function, without '%' prefix.
2329 line : str
2384 line : str
2330 The rest of the first input line as a single string.
2385 The rest of the first input line as a single string.
2331 cell : str
2386 cell : str
2332 The body of the cell as a (possibly multiline) string.
2387 The body of the cell as a (possibly multiline) string.
2333 """
2388 """
2334 fn = self._find_with_lazy_load("cell", magic_name)
2389 fn = self._find_with_lazy_load("cell", magic_name)
2335 if fn is None:
2390 if fn is None:
2336 lm = self.find_line_magic(magic_name)
2391 lm = self.find_line_magic(magic_name)
2337 etpl = "Cell magic `%%{0}` not found{1}."
2392 etpl = "Cell magic `%%{0}` not found{1}."
2338 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2393 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2339 'did you mean that instead?)'.format(magic_name))
2394 'did you mean that instead?)'.format(magic_name))
2340 raise UsageError(etpl.format(magic_name, extra))
2395 raise UsageError(etpl.format(magic_name, extra))
2341 elif cell == '':
2396 elif cell == '':
2342 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2397 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2343 if self.find_line_magic(magic_name) is not None:
2398 if self.find_line_magic(magic_name) is not None:
2344 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2399 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2345 raise UsageError(message)
2400 raise UsageError(message)
2346 else:
2401 else:
2347 # Note: this is the distance in the stack to the user's frame.
2402 # Note: this is the distance in the stack to the user's frame.
2348 # This will need to be updated if the internal calling logic gets
2403 # This will need to be updated if the internal calling logic gets
2349 # refactored, or else we'll be expanding the wrong variables.
2404 # refactored, or else we'll be expanding the wrong variables.
2350 stack_depth = 2
2405 stack_depth = 2
2351 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2406 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2352 # magic has opted out of var_expand
2407 # magic has opted out of var_expand
2353 magic_arg_s = line
2408 magic_arg_s = line
2354 else:
2409 else:
2355 magic_arg_s = self.var_expand(line, stack_depth)
2410 magic_arg_s = self.var_expand(line, stack_depth)
2356 kwargs = {}
2411 kwargs = {}
2357 if getattr(fn, "needs_local_scope", False):
2412 if getattr(fn, "needs_local_scope", False):
2358 kwargs['local_ns'] = self.user_ns
2413 kwargs['local_ns'] = self.user_ns
2359
2414
2360 with self.builtin_trap:
2415 with self.builtin_trap:
2361 args = (magic_arg_s, cell)
2416 args = (magic_arg_s, cell)
2362 result = fn(*args, **kwargs)
2417 result = fn(*args, **kwargs)
2363 return result
2418 return result
2364
2419
2365 def find_line_magic(self, magic_name):
2420 def find_line_magic(self, magic_name):
2366 """Find and return a line magic by name.
2421 """Find and return a line magic by name.
2367
2422
2368 Returns None if the magic isn't found."""
2423 Returns None if the magic isn't found."""
2369 return self.magics_manager.magics['line'].get(magic_name)
2424 return self.magics_manager.magics['line'].get(magic_name)
2370
2425
2371 def find_cell_magic(self, magic_name):
2426 def find_cell_magic(self, magic_name):
2372 """Find and return a cell magic by name.
2427 """Find and return a cell magic by name.
2373
2428
2374 Returns None if the magic isn't found."""
2429 Returns None if the magic isn't found."""
2375 return self.magics_manager.magics['cell'].get(magic_name)
2430 return self.magics_manager.magics['cell'].get(magic_name)
2376
2431
2377 def find_magic(self, magic_name, magic_kind='line'):
2432 def find_magic(self, magic_name, magic_kind='line'):
2378 """Find and return a magic of the given type by name.
2433 """Find and return a magic of the given type by name.
2379
2434
2380 Returns None if the magic isn't found."""
2435 Returns None if the magic isn't found."""
2381 return self.magics_manager.magics[magic_kind].get(magic_name)
2436 return self.magics_manager.magics[magic_kind].get(magic_name)
2382
2437
2383 def magic(self, arg_s):
2438 def magic(self, arg_s):
2384 """
2439 """
2385 DEPRECATED
2440 DEPRECATED
2386
2441
2387 Deprecated since IPython 0.13 (warning added in
2442 Deprecated since IPython 0.13 (warning added in
2388 8.1), use run_line_magic(magic_name, parameter_s).
2443 8.1), use run_line_magic(magic_name, parameter_s).
2389
2444
2390 Call a magic function by name.
2445 Call a magic function by name.
2391
2446
2392 Input: a string containing the name of the magic function to call and
2447 Input: a string containing the name of the magic function to call and
2393 any additional arguments to be passed to the magic.
2448 any additional arguments to be passed to the magic.
2394
2449
2395 magic('name -opt foo bar') is equivalent to typing at the ipython
2450 magic('name -opt foo bar') is equivalent to typing at the ipython
2396 prompt:
2451 prompt:
2397
2452
2398 In[1]: %name -opt foo bar
2453 In[1]: %name -opt foo bar
2399
2454
2400 To call a magic without arguments, simply use magic('name').
2455 To call a magic without arguments, simply use magic('name').
2401
2456
2402 This provides a proper Python function to call IPython's magics in any
2457 This provides a proper Python function to call IPython's magics in any
2403 valid Python code you can type at the interpreter, including loops and
2458 valid Python code you can type at the interpreter, including loops and
2404 compound statements.
2459 compound statements.
2405 """
2460 """
2406 warnings.warn(
2461 warnings.warn(
2407 "`magic(...)` is deprecated since IPython 0.13 (warning added in "
2462 "`magic(...)` is deprecated since IPython 0.13 (warning added in "
2408 "8.1), use run_line_magic(magic_name, parameter_s).",
2463 "8.1), use run_line_magic(magic_name, parameter_s).",
2409 DeprecationWarning,
2464 DeprecationWarning,
2410 stacklevel=2,
2465 stacklevel=2,
2411 )
2466 )
2412 # TODO: should we issue a loud deprecation warning here?
2467 # TODO: should we issue a loud deprecation warning here?
2413 magic_name, _, magic_arg_s = arg_s.partition(' ')
2468 magic_name, _, magic_arg_s = arg_s.partition(' ')
2414 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2469 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2415 return self.run_line_magic(magic_name, magic_arg_s, _stack_depth=2)
2470 return self.run_line_magic(magic_name, magic_arg_s, _stack_depth=2)
2416
2471
2417 #-------------------------------------------------------------------------
2472 #-------------------------------------------------------------------------
2418 # Things related to macros
2473 # Things related to macros
2419 #-------------------------------------------------------------------------
2474 #-------------------------------------------------------------------------
2420
2475
2421 def define_macro(self, name, themacro):
2476 def define_macro(self, name, themacro):
2422 """Define a new macro
2477 """Define a new macro
2423
2478
2424 Parameters
2479 Parameters
2425 ----------
2480 ----------
2426 name : str
2481 name : str
2427 The name of the macro.
2482 The name of the macro.
2428 themacro : str or Macro
2483 themacro : str or Macro
2429 The action to do upon invoking the macro. If a string, a new
2484 The action to do upon invoking the macro. If a string, a new
2430 Macro object is created by passing the string to it.
2485 Macro object is created by passing the string to it.
2431 """
2486 """
2432
2487
2433 from IPython.core import macro
2488 from IPython.core import macro
2434
2489
2435 if isinstance(themacro, str):
2490 if isinstance(themacro, str):
2436 themacro = macro.Macro(themacro)
2491 themacro = macro.Macro(themacro)
2437 if not isinstance(themacro, macro.Macro):
2492 if not isinstance(themacro, macro.Macro):
2438 raise ValueError('A macro must be a string or a Macro instance.')
2493 raise ValueError('A macro must be a string or a Macro instance.')
2439 self.user_ns[name] = themacro
2494 self.user_ns[name] = themacro
2440
2495
2441 #-------------------------------------------------------------------------
2496 #-------------------------------------------------------------------------
2442 # Things related to the running of system commands
2497 # Things related to the running of system commands
2443 #-------------------------------------------------------------------------
2498 #-------------------------------------------------------------------------
2444
2499
2445 def system_piped(self, cmd):
2500 def system_piped(self, cmd):
2446 """Call the given cmd in a subprocess, piping stdout/err
2501 """Call the given cmd in a subprocess, piping stdout/err
2447
2502
2448 Parameters
2503 Parameters
2449 ----------
2504 ----------
2450 cmd : str
2505 cmd : str
2451 Command to execute (can not end in '&', as background processes are
2506 Command to execute (can not end in '&', as background processes are
2452 not supported. Should not be a command that expects input
2507 not supported. Should not be a command that expects input
2453 other than simple text.
2508 other than simple text.
2454 """
2509 """
2455 if cmd.rstrip().endswith('&'):
2510 if cmd.rstrip().endswith('&'):
2456 # this is *far* from a rigorous test
2511 # this is *far* from a rigorous test
2457 # We do not support backgrounding processes because we either use
2512 # We do not support backgrounding processes because we either use
2458 # pexpect or pipes to read from. Users can always just call
2513 # pexpect or pipes to read from. Users can always just call
2459 # os.system() or use ip.system=ip.system_raw
2514 # os.system() or use ip.system=ip.system_raw
2460 # if they really want a background process.
2515 # if they really want a background process.
2461 raise OSError("Background processes not supported.")
2516 raise OSError("Background processes not supported.")
2462
2517
2463 # we explicitly do NOT return the subprocess status code, because
2518 # we explicitly do NOT return the subprocess status code, because
2464 # a non-None value would trigger :func:`sys.displayhook` calls.
2519 # a non-None value would trigger :func:`sys.displayhook` calls.
2465 # Instead, we store the exit_code in user_ns.
2520 # Instead, we store the exit_code in user_ns.
2466 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2521 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2467
2522
2468 def system_raw(self, cmd):
2523 def system_raw(self, cmd):
2469 """Call the given cmd in a subprocess using os.system on Windows or
2524 """Call the given cmd in a subprocess using os.system on Windows or
2470 subprocess.call using the system shell on other platforms.
2525 subprocess.call using the system shell on other platforms.
2471
2526
2472 Parameters
2527 Parameters
2473 ----------
2528 ----------
2474 cmd : str
2529 cmd : str
2475 Command to execute.
2530 Command to execute.
2476 """
2531 """
2477 cmd = self.var_expand(cmd, depth=1)
2532 cmd = self.var_expand(cmd, depth=1)
2478 # warn if there is an IPython magic alternative.
2533 # warn if there is an IPython magic alternative.
2479 main_cmd = cmd.split()[0]
2534 main_cmd = cmd.split()[0]
2480 has_magic_alternatives = ("pip", "conda", "cd")
2535 has_magic_alternatives = ("pip", "conda", "cd")
2481
2536
2482 if main_cmd in has_magic_alternatives:
2537 if main_cmd in has_magic_alternatives:
2483 warnings.warn(
2538 warnings.warn(
2484 (
2539 (
2485 "You executed the system command !{0} which may not work "
2540 "You executed the system command !{0} which may not work "
2486 "as expected. Try the IPython magic %{0} instead."
2541 "as expected. Try the IPython magic %{0} instead."
2487 ).format(main_cmd)
2542 ).format(main_cmd)
2488 )
2543 )
2489
2544
2490 # protect os.system from UNC paths on Windows, which it can't handle:
2545 # protect os.system from UNC paths on Windows, which it can't handle:
2491 if sys.platform == 'win32':
2546 if sys.platform == 'win32':
2492 from IPython.utils._process_win32 import AvoidUNCPath
2547 from IPython.utils._process_win32 import AvoidUNCPath
2493 with AvoidUNCPath() as path:
2548 with AvoidUNCPath() as path:
2494 if path is not None:
2549 if path is not None:
2495 cmd = '"pushd %s &&"%s' % (path, cmd)
2550 cmd = '"pushd %s &&"%s' % (path, cmd)
2496 try:
2551 try:
2497 ec = os.system(cmd)
2552 ec = os.system(cmd)
2498 except KeyboardInterrupt:
2553 except KeyboardInterrupt:
2499 print('\n' + self.get_exception_only(), file=sys.stderr)
2554 print('\n' + self.get_exception_only(), file=sys.stderr)
2500 ec = -2
2555 ec = -2
2501 else:
2556 else:
2502 # For posix the result of the subprocess.call() below is an exit
2557 # For posix the result of the subprocess.call() below is an exit
2503 # code, which by convention is zero for success, positive for
2558 # code, which by convention is zero for success, positive for
2504 # program failure. Exit codes above 128 are reserved for signals,
2559 # program failure. Exit codes above 128 are reserved for signals,
2505 # and the formula for converting a signal to an exit code is usually
2560 # and the formula for converting a signal to an exit code is usually
2506 # signal_number+128. To more easily differentiate between exit
2561 # signal_number+128. To more easily differentiate between exit
2507 # codes and signals, ipython uses negative numbers. For instance
2562 # codes and signals, ipython uses negative numbers. For instance
2508 # since control-c is signal 2 but exit code 130, ipython's
2563 # since control-c is signal 2 but exit code 130, ipython's
2509 # _exit_code variable will read -2. Note that some shells like
2564 # _exit_code variable will read -2. Note that some shells like
2510 # csh and fish don't follow sh/bash conventions for exit codes.
2565 # csh and fish don't follow sh/bash conventions for exit codes.
2511 executable = os.environ.get('SHELL', None)
2566 executable = os.environ.get('SHELL', None)
2512 try:
2567 try:
2513 # Use env shell instead of default /bin/sh
2568 # Use env shell instead of default /bin/sh
2514 ec = subprocess.call(cmd, shell=True, executable=executable)
2569 ec = subprocess.call(cmd, shell=True, executable=executable)
2515 except KeyboardInterrupt:
2570 except KeyboardInterrupt:
2516 # intercept control-C; a long traceback is not useful here
2571 # intercept control-C; a long traceback is not useful here
2517 print('\n' + self.get_exception_only(), file=sys.stderr)
2572 print('\n' + self.get_exception_only(), file=sys.stderr)
2518 ec = 130
2573 ec = 130
2519 if ec > 128:
2574 if ec > 128:
2520 ec = -(ec - 128)
2575 ec = -(ec - 128)
2521
2576
2522 # We explicitly do NOT return the subprocess status code, because
2577 # We explicitly do NOT return the subprocess status code, because
2523 # a non-None value would trigger :func:`sys.displayhook` calls.
2578 # a non-None value would trigger :func:`sys.displayhook` calls.
2524 # Instead, we store the exit_code in user_ns. Note the semantics
2579 # Instead, we store the exit_code in user_ns. Note the semantics
2525 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2580 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2526 # but raising SystemExit(_exit_code) will give status 254!
2581 # but raising SystemExit(_exit_code) will give status 254!
2527 self.user_ns['_exit_code'] = ec
2582 self.user_ns['_exit_code'] = ec
2528
2583
2529 # use piped system by default, because it is better behaved
2584 # use piped system by default, because it is better behaved
2530 system = system_piped
2585 system = system_piped
2531
2586
2532 def getoutput(self, cmd, split=True, depth=0):
2587 def getoutput(self, cmd, split=True, depth=0):
2533 """Get output (possibly including stderr) from a subprocess.
2588 """Get output (possibly including stderr) from a subprocess.
2534
2589
2535 Parameters
2590 Parameters
2536 ----------
2591 ----------
2537 cmd : str
2592 cmd : str
2538 Command to execute (can not end in '&', as background processes are
2593 Command to execute (can not end in '&', as background processes are
2539 not supported.
2594 not supported.
2540 split : bool, optional
2595 split : bool, optional
2541 If True, split the output into an IPython SList. Otherwise, an
2596 If True, split the output into an IPython SList. Otherwise, an
2542 IPython LSString is returned. These are objects similar to normal
2597 IPython LSString is returned. These are objects similar to normal
2543 lists and strings, with a few convenience attributes for easier
2598 lists and strings, with a few convenience attributes for easier
2544 manipulation of line-based output. You can use '?' on them for
2599 manipulation of line-based output. You can use '?' on them for
2545 details.
2600 details.
2546 depth : int, optional
2601 depth : int, optional
2547 How many frames above the caller are the local variables which should
2602 How many frames above the caller are the local variables which should
2548 be expanded in the command string? The default (0) assumes that the
2603 be expanded in the command string? The default (0) assumes that the
2549 expansion variables are in the stack frame calling this function.
2604 expansion variables are in the stack frame calling this function.
2550 """
2605 """
2551 if cmd.rstrip().endswith('&'):
2606 if cmd.rstrip().endswith('&'):
2552 # this is *far* from a rigorous test
2607 # this is *far* from a rigorous test
2553 raise OSError("Background processes not supported.")
2608 raise OSError("Background processes not supported.")
2554 out = getoutput(self.var_expand(cmd, depth=depth+1))
2609 out = getoutput(self.var_expand(cmd, depth=depth+1))
2555 if split:
2610 if split:
2556 out = SList(out.splitlines())
2611 out = SList(out.splitlines())
2557 else:
2612 else:
2558 out = LSString(out)
2613 out = LSString(out)
2559 return out
2614 return out
2560
2615
2561 #-------------------------------------------------------------------------
2616 #-------------------------------------------------------------------------
2562 # Things related to aliases
2617 # Things related to aliases
2563 #-------------------------------------------------------------------------
2618 #-------------------------------------------------------------------------
2564
2619
2565 def init_alias(self):
2620 def init_alias(self):
2566 self.alias_manager = AliasManager(shell=self, parent=self)
2621 self.alias_manager = AliasManager(shell=self, parent=self)
2567 self.configurables.append(self.alias_manager)
2622 self.configurables.append(self.alias_manager)
2568
2623
2569 #-------------------------------------------------------------------------
2624 #-------------------------------------------------------------------------
2570 # Things related to extensions
2625 # Things related to extensions
2571 #-------------------------------------------------------------------------
2626 #-------------------------------------------------------------------------
2572
2627
2573 def init_extension_manager(self):
2628 def init_extension_manager(self):
2574 self.extension_manager = ExtensionManager(shell=self, parent=self)
2629 self.extension_manager = ExtensionManager(shell=self, parent=self)
2575 self.configurables.append(self.extension_manager)
2630 self.configurables.append(self.extension_manager)
2576
2631
2577 #-------------------------------------------------------------------------
2632 #-------------------------------------------------------------------------
2578 # Things related to payloads
2633 # Things related to payloads
2579 #-------------------------------------------------------------------------
2634 #-------------------------------------------------------------------------
2580
2635
2581 def init_payload(self):
2636 def init_payload(self):
2582 self.payload_manager = PayloadManager(parent=self)
2637 self.payload_manager = PayloadManager(parent=self)
2583 self.configurables.append(self.payload_manager)
2638 self.configurables.append(self.payload_manager)
2584
2639
2585 #-------------------------------------------------------------------------
2640 #-------------------------------------------------------------------------
2586 # Things related to the prefilter
2641 # Things related to the prefilter
2587 #-------------------------------------------------------------------------
2642 #-------------------------------------------------------------------------
2588
2643
2589 def init_prefilter(self):
2644 def init_prefilter(self):
2590 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2645 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2591 self.configurables.append(self.prefilter_manager)
2646 self.configurables.append(self.prefilter_manager)
2592 # Ultimately this will be refactored in the new interpreter code, but
2647 # Ultimately this will be refactored in the new interpreter code, but
2593 # for now, we should expose the main prefilter method (there's legacy
2648 # for now, we should expose the main prefilter method (there's legacy
2594 # code out there that may rely on this).
2649 # code out there that may rely on this).
2595 self.prefilter = self.prefilter_manager.prefilter_lines
2650 self.prefilter = self.prefilter_manager.prefilter_lines
2596
2651
2597 def auto_rewrite_input(self, cmd):
2652 def auto_rewrite_input(self, cmd):
2598 """Print to the screen the rewritten form of the user's command.
2653 """Print to the screen the rewritten form of the user's command.
2599
2654
2600 This shows visual feedback by rewriting input lines that cause
2655 This shows visual feedback by rewriting input lines that cause
2601 automatic calling to kick in, like::
2656 automatic calling to kick in, like::
2602
2657
2603 /f x
2658 /f x
2604
2659
2605 into::
2660 into::
2606
2661
2607 ------> f(x)
2662 ------> f(x)
2608
2663
2609 after the user's input prompt. This helps the user understand that the
2664 after the user's input prompt. This helps the user understand that the
2610 input line was transformed automatically by IPython.
2665 input line was transformed automatically by IPython.
2611 """
2666 """
2612 if not self.show_rewritten_input:
2667 if not self.show_rewritten_input:
2613 return
2668 return
2614
2669
2615 # This is overridden in TerminalInteractiveShell to use fancy prompts
2670 # This is overridden in TerminalInteractiveShell to use fancy prompts
2616 print("------> " + cmd)
2671 print("------> " + cmd)
2617
2672
2618 #-------------------------------------------------------------------------
2673 #-------------------------------------------------------------------------
2619 # Things related to extracting values/expressions from kernel and user_ns
2674 # Things related to extracting values/expressions from kernel and user_ns
2620 #-------------------------------------------------------------------------
2675 #-------------------------------------------------------------------------
2621
2676
2622 def _user_obj_error(self):
2677 def _user_obj_error(self):
2623 """return simple exception dict
2678 """return simple exception dict
2624
2679
2625 for use in user_expressions
2680 for use in user_expressions
2626 """
2681 """
2627
2682
2628 etype, evalue, tb = self._get_exc_info()
2683 etype, evalue, tb = self._get_exc_info()
2629 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2684 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2630
2685
2631 exc_info = {
2686 exc_info = {
2632 "status": "error",
2687 "status": "error",
2633 "traceback": stb,
2688 "traceback": stb,
2634 "ename": etype.__name__,
2689 "ename": etype.__name__,
2635 "evalue": py3compat.safe_unicode(evalue),
2690 "evalue": py3compat.safe_unicode(evalue),
2636 }
2691 }
2637
2692
2638 return exc_info
2693 return exc_info
2639
2694
2640 def _format_user_obj(self, obj):
2695 def _format_user_obj(self, obj):
2641 """format a user object to display dict
2696 """format a user object to display dict
2642
2697
2643 for use in user_expressions
2698 for use in user_expressions
2644 """
2699 """
2645
2700
2646 data, md = self.display_formatter.format(obj)
2701 data, md = self.display_formatter.format(obj)
2647 value = {
2702 value = {
2648 'status' : 'ok',
2703 'status' : 'ok',
2649 'data' : data,
2704 'data' : data,
2650 'metadata' : md,
2705 'metadata' : md,
2651 }
2706 }
2652 return value
2707 return value
2653
2708
2654 def user_expressions(self, expressions):
2709 def user_expressions(self, expressions):
2655 """Evaluate a dict of expressions in the user's namespace.
2710 """Evaluate a dict of expressions in the user's namespace.
2656
2711
2657 Parameters
2712 Parameters
2658 ----------
2713 ----------
2659 expressions : dict
2714 expressions : dict
2660 A dict with string keys and string values. The expression values
2715 A dict with string keys and string values. The expression values
2661 should be valid Python expressions, each of which will be evaluated
2716 should be valid Python expressions, each of which will be evaluated
2662 in the user namespace.
2717 in the user namespace.
2663
2718
2664 Returns
2719 Returns
2665 -------
2720 -------
2666 A dict, keyed like the input expressions dict, with the rich mime-typed
2721 A dict, keyed like the input expressions dict, with the rich mime-typed
2667 display_data of each value.
2722 display_data of each value.
2668 """
2723 """
2669 out = {}
2724 out = {}
2670 user_ns = self.user_ns
2725 user_ns = self.user_ns
2671 global_ns = self.user_global_ns
2726 global_ns = self.user_global_ns
2672
2727
2673 for key, expr in expressions.items():
2728 for key, expr in expressions.items():
2674 try:
2729 try:
2675 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2730 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2676 except:
2731 except:
2677 value = self._user_obj_error()
2732 value = self._user_obj_error()
2678 out[key] = value
2733 out[key] = value
2679 return out
2734 return out
2680
2735
2681 #-------------------------------------------------------------------------
2736 #-------------------------------------------------------------------------
2682 # Things related to the running of code
2737 # Things related to the running of code
2683 #-------------------------------------------------------------------------
2738 #-------------------------------------------------------------------------
2684
2739
2685 def ex(self, cmd):
2740 def ex(self, cmd):
2686 """Execute a normal python statement in user namespace."""
2741 """Execute a normal python statement in user namespace."""
2687 with self.builtin_trap:
2742 with self.builtin_trap:
2688 exec(cmd, self.user_global_ns, self.user_ns)
2743 exec(cmd, self.user_global_ns, self.user_ns)
2689
2744
2690 def ev(self, expr):
2745 def ev(self, expr):
2691 """Evaluate python expression expr in user namespace.
2746 """Evaluate python expression expr in user namespace.
2692
2747
2693 Returns the result of evaluation
2748 Returns the result of evaluation
2694 """
2749 """
2695 with self.builtin_trap:
2750 with self.builtin_trap:
2696 return eval(expr, self.user_global_ns, self.user_ns)
2751 return eval(expr, self.user_global_ns, self.user_ns)
2697
2752
2698 def safe_execfile(self, fname, *where, exit_ignore=False, raise_exceptions=False, shell_futures=False):
2753 def safe_execfile(self, fname, *where, exit_ignore=False, raise_exceptions=False, shell_futures=False):
2699 """A safe version of the builtin execfile().
2754 """A safe version of the builtin execfile().
2700
2755
2701 This version will never throw an exception, but instead print
2756 This version will never throw an exception, but instead print
2702 helpful error messages to the screen. This only works on pure
2757 helpful error messages to the screen. This only works on pure
2703 Python files with the .py extension.
2758 Python files with the .py extension.
2704
2759
2705 Parameters
2760 Parameters
2706 ----------
2761 ----------
2707 fname : string
2762 fname : string
2708 The name of the file to be executed.
2763 The name of the file to be executed.
2709 *where : tuple
2764 *where : tuple
2710 One or two namespaces, passed to execfile() as (globals,locals).
2765 One or two namespaces, passed to execfile() as (globals,locals).
2711 If only one is given, it is passed as both.
2766 If only one is given, it is passed as both.
2712 exit_ignore : bool (False)
2767 exit_ignore : bool (False)
2713 If True, then silence SystemExit for non-zero status (it is always
2768 If True, then silence SystemExit for non-zero status (it is always
2714 silenced for zero status, as it is so common).
2769 silenced for zero status, as it is so common).
2715 raise_exceptions : bool (False)
2770 raise_exceptions : bool (False)
2716 If True raise exceptions everywhere. Meant for testing.
2771 If True raise exceptions everywhere. Meant for testing.
2717 shell_futures : bool (False)
2772 shell_futures : bool (False)
2718 If True, the code will share future statements with the interactive
2773 If True, the code will share future statements with the interactive
2719 shell. It will both be affected by previous __future__ imports, and
2774 shell. It will both be affected by previous __future__ imports, and
2720 any __future__ imports in the code will affect the shell. If False,
2775 any __future__ imports in the code will affect the shell. If False,
2721 __future__ imports are not shared in either direction.
2776 __future__ imports are not shared in either direction.
2722
2777
2723 """
2778 """
2724 fname = Path(fname).expanduser().resolve()
2779 fname = Path(fname).expanduser().resolve()
2725
2780
2726 # Make sure we can open the file
2781 # Make sure we can open the file
2727 try:
2782 try:
2728 with fname.open("rb"):
2783 with fname.open("rb"):
2729 pass
2784 pass
2730 except:
2785 except:
2731 warn('Could not open file <%s> for safe execution.' % fname)
2786 warn('Could not open file <%s> for safe execution.' % fname)
2732 return
2787 return
2733
2788
2734 # Find things also in current directory. This is needed to mimic the
2789 # Find things also in current directory. This is needed to mimic the
2735 # behavior of running a script from the system command line, where
2790 # behavior of running a script from the system command line, where
2736 # Python inserts the script's directory into sys.path
2791 # Python inserts the script's directory into sys.path
2737 dname = str(fname.parent)
2792 dname = str(fname.parent)
2738
2793
2739 with prepended_to_syspath(dname), self.builtin_trap:
2794 with prepended_to_syspath(dname), self.builtin_trap:
2740 try:
2795 try:
2741 glob, loc = (where + (None, ))[:2]
2796 glob, loc = (where + (None, ))[:2]
2742 py3compat.execfile(
2797 py3compat.execfile(
2743 fname, glob, loc,
2798 fname, glob, loc,
2744 self.compile if shell_futures else None)
2799 self.compile if shell_futures else None)
2745 except SystemExit as status:
2800 except SystemExit as status:
2746 # If the call was made with 0 or None exit status (sys.exit(0)
2801 # If the call was made with 0 or None exit status (sys.exit(0)
2747 # or sys.exit() ), don't bother showing a traceback, as both of
2802 # or sys.exit() ), don't bother showing a traceback, as both of
2748 # these are considered normal by the OS:
2803 # these are considered normal by the OS:
2749 # > python -c'import sys;sys.exit(0)'; echo $?
2804 # > python -c'import sys;sys.exit(0)'; echo $?
2750 # 0
2805 # 0
2751 # > python -c'import sys;sys.exit()'; echo $?
2806 # > python -c'import sys;sys.exit()'; echo $?
2752 # 0
2807 # 0
2753 # For other exit status, we show the exception unless
2808 # For other exit status, we show the exception unless
2754 # explicitly silenced, but only in short form.
2809 # explicitly silenced, but only in short form.
2755 if status.code:
2810 if status.code:
2756 if raise_exceptions:
2811 if raise_exceptions:
2757 raise
2812 raise
2758 if not exit_ignore:
2813 if not exit_ignore:
2759 self.showtraceback(exception_only=True)
2814 self.showtraceback(exception_only=True)
2760 except:
2815 except:
2761 if raise_exceptions:
2816 if raise_exceptions:
2762 raise
2817 raise
2763 # tb offset is 2 because we wrap execfile
2818 # tb offset is 2 because we wrap execfile
2764 self.showtraceback(tb_offset=2)
2819 self.showtraceback(tb_offset=2)
2765
2820
2766 def safe_execfile_ipy(self, fname, shell_futures=False, raise_exceptions=False):
2821 def safe_execfile_ipy(self, fname, shell_futures=False, raise_exceptions=False):
2767 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2822 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2768
2823
2769 Parameters
2824 Parameters
2770 ----------
2825 ----------
2771 fname : str
2826 fname : str
2772 The name of the file to execute. The filename must have a
2827 The name of the file to execute. The filename must have a
2773 .ipy or .ipynb extension.
2828 .ipy or .ipynb extension.
2774 shell_futures : bool (False)
2829 shell_futures : bool (False)
2775 If True, the code will share future statements with the interactive
2830 If True, the code will share future statements with the interactive
2776 shell. It will both be affected by previous __future__ imports, and
2831 shell. It will both be affected by previous __future__ imports, and
2777 any __future__ imports in the code will affect the shell. If False,
2832 any __future__ imports in the code will affect the shell. If False,
2778 __future__ imports are not shared in either direction.
2833 __future__ imports are not shared in either direction.
2779 raise_exceptions : bool (False)
2834 raise_exceptions : bool (False)
2780 If True raise exceptions everywhere. Meant for testing.
2835 If True raise exceptions everywhere. Meant for testing.
2781 """
2836 """
2782 fname = Path(fname).expanduser().resolve()
2837 fname = Path(fname).expanduser().resolve()
2783
2838
2784 # Make sure we can open the file
2839 # Make sure we can open the file
2785 try:
2840 try:
2786 with fname.open("rb"):
2841 with fname.open("rb"):
2787 pass
2842 pass
2788 except:
2843 except:
2789 warn('Could not open file <%s> for safe execution.' % fname)
2844 warn('Could not open file <%s> for safe execution.' % fname)
2790 return
2845 return
2791
2846
2792 # Find things also in current directory. This is needed to mimic the
2847 # Find things also in current directory. This is needed to mimic the
2793 # behavior of running a script from the system command line, where
2848 # behavior of running a script from the system command line, where
2794 # Python inserts the script's directory into sys.path
2849 # Python inserts the script's directory into sys.path
2795 dname = str(fname.parent)
2850 dname = str(fname.parent)
2796
2851
2797 def get_cells():
2852 def get_cells():
2798 """generator for sequence of code blocks to run"""
2853 """generator for sequence of code blocks to run"""
2799 if fname.suffix == ".ipynb":
2854 if fname.suffix == ".ipynb":
2800 from nbformat import read
2855 from nbformat import read
2801 nb = read(fname, as_version=4)
2856 nb = read(fname, as_version=4)
2802 if not nb.cells:
2857 if not nb.cells:
2803 return
2858 return
2804 for cell in nb.cells:
2859 for cell in nb.cells:
2805 if cell.cell_type == 'code':
2860 if cell.cell_type == 'code':
2806 yield cell.source
2861 yield cell.source
2807 else:
2862 else:
2808 yield fname.read_text(encoding="utf-8")
2863 yield fname.read_text(encoding="utf-8")
2809
2864
2810 with prepended_to_syspath(dname):
2865 with prepended_to_syspath(dname):
2811 try:
2866 try:
2812 for cell in get_cells():
2867 for cell in get_cells():
2813 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2868 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2814 if raise_exceptions:
2869 if raise_exceptions:
2815 result.raise_error()
2870 result.raise_error()
2816 elif not result.success:
2871 elif not result.success:
2817 break
2872 break
2818 except:
2873 except:
2819 if raise_exceptions:
2874 if raise_exceptions:
2820 raise
2875 raise
2821 self.showtraceback()
2876 self.showtraceback()
2822 warn('Unknown failure executing file: <%s>' % fname)
2877 warn('Unknown failure executing file: <%s>' % fname)
2823
2878
2824 def safe_run_module(self, mod_name, where):
2879 def safe_run_module(self, mod_name, where):
2825 """A safe version of runpy.run_module().
2880 """A safe version of runpy.run_module().
2826
2881
2827 This version will never throw an exception, but instead print
2882 This version will never throw an exception, but instead print
2828 helpful error messages to the screen.
2883 helpful error messages to the screen.
2829
2884
2830 `SystemExit` exceptions with status code 0 or None are ignored.
2885 `SystemExit` exceptions with status code 0 or None are ignored.
2831
2886
2832 Parameters
2887 Parameters
2833 ----------
2888 ----------
2834 mod_name : string
2889 mod_name : string
2835 The name of the module to be executed.
2890 The name of the module to be executed.
2836 where : dict
2891 where : dict
2837 The globals namespace.
2892 The globals namespace.
2838 """
2893 """
2839 try:
2894 try:
2840 try:
2895 try:
2841 where.update(
2896 where.update(
2842 runpy.run_module(str(mod_name), run_name="__main__",
2897 runpy.run_module(str(mod_name), run_name="__main__",
2843 alter_sys=True)
2898 alter_sys=True)
2844 )
2899 )
2845 except SystemExit as status:
2900 except SystemExit as status:
2846 if status.code:
2901 if status.code:
2847 raise
2902 raise
2848 except:
2903 except:
2849 self.showtraceback()
2904 self.showtraceback()
2850 warn('Unknown failure executing module: <%s>' % mod_name)
2905 warn('Unknown failure executing module: <%s>' % mod_name)
2851
2906
2852 def run_cell(
2907 def run_cell(
2853 self,
2908 self,
2854 raw_cell,
2909 raw_cell,
2855 store_history=False,
2910 store_history=False,
2856 silent=False,
2911 silent=False,
2857 shell_futures=True,
2912 shell_futures=True,
2858 cell_id=None,
2913 cell_id=None,
2859 ):
2914 ):
2860 """Run a complete IPython cell.
2915 """Run a complete IPython cell.
2861
2916
2862 Parameters
2917 Parameters
2863 ----------
2918 ----------
2864 raw_cell : str
2919 raw_cell : str
2865 The code (including IPython code such as %magic functions) to run.
2920 The code (including IPython code such as %magic functions) to run.
2866 store_history : bool
2921 store_history : bool
2867 If True, the raw and translated cell will be stored in IPython's
2922 If True, the raw and translated cell will be stored in IPython's
2868 history. For user code calling back into IPython's machinery, this
2923 history. For user code calling back into IPython's machinery, this
2869 should be set to False.
2924 should be set to False.
2870 silent : bool
2925 silent : bool
2871 If True, avoid side-effects, such as implicit displayhooks and
2926 If True, avoid side-effects, such as implicit displayhooks and
2872 and logging. silent=True forces store_history=False.
2927 and logging. silent=True forces store_history=False.
2873 shell_futures : bool
2928 shell_futures : bool
2874 If True, the code will share future statements with the interactive
2929 If True, the code will share future statements with the interactive
2875 shell. It will both be affected by previous __future__ imports, and
2930 shell. It will both be affected by previous __future__ imports, and
2876 any __future__ imports in the code will affect the shell. If False,
2931 any __future__ imports in the code will affect the shell. If False,
2877 __future__ imports are not shared in either direction.
2932 __future__ imports are not shared in either direction.
2878
2933
2879 Returns
2934 Returns
2880 -------
2935 -------
2881 result : :class:`ExecutionResult`
2936 result : :class:`ExecutionResult`
2882 """
2937 """
2883 result = None
2938 result = None
2884 try:
2939 try:
2885 result = self._run_cell(
2940 result = self._run_cell(
2886 raw_cell, store_history, silent, shell_futures, cell_id
2941 raw_cell, store_history, silent, shell_futures, cell_id
2887 )
2942 )
2888 finally:
2943 finally:
2889 self.events.trigger('post_execute')
2944 self.events.trigger('post_execute')
2890 if not silent:
2945 if not silent:
2891 self.events.trigger('post_run_cell', result)
2946 self.events.trigger('post_run_cell', result)
2892 return result
2947 return result
2893
2948
2894 def _run_cell(
2949 def _run_cell(
2895 self,
2950 self,
2896 raw_cell: str,
2951 raw_cell: str,
2897 store_history: bool,
2952 store_history: bool,
2898 silent: bool,
2953 silent: bool,
2899 shell_futures: bool,
2954 shell_futures: bool,
2900 cell_id: str,
2955 cell_id: str,
2901 ) -> ExecutionResult:
2956 ) -> ExecutionResult:
2902 """Internal method to run a complete IPython cell."""
2957 """Internal method to run a complete IPython cell."""
2903
2958
2904 # we need to avoid calling self.transform_cell multiple time on the same thing
2959 # we need to avoid calling self.transform_cell multiple time on the same thing
2905 # so we need to store some results:
2960 # so we need to store some results:
2906 preprocessing_exc_tuple = None
2961 preprocessing_exc_tuple = None
2907 try:
2962 try:
2908 transformed_cell = self.transform_cell(raw_cell)
2963 transformed_cell = self.transform_cell(raw_cell)
2909 except Exception:
2964 except Exception:
2910 transformed_cell = raw_cell
2965 transformed_cell = raw_cell
2911 preprocessing_exc_tuple = sys.exc_info()
2966 preprocessing_exc_tuple = sys.exc_info()
2912
2967
2913 assert transformed_cell is not None
2968 assert transformed_cell is not None
2914 coro = self.run_cell_async(
2969 coro = self.run_cell_async(
2915 raw_cell,
2970 raw_cell,
2916 store_history=store_history,
2971 store_history=store_history,
2917 silent=silent,
2972 silent=silent,
2918 shell_futures=shell_futures,
2973 shell_futures=shell_futures,
2919 transformed_cell=transformed_cell,
2974 transformed_cell=transformed_cell,
2920 preprocessing_exc_tuple=preprocessing_exc_tuple,
2975 preprocessing_exc_tuple=preprocessing_exc_tuple,
2921 cell_id=cell_id,
2976 cell_id=cell_id,
2922 )
2977 )
2923
2978
2924 # run_cell_async is async, but may not actually need an eventloop.
2979 # run_cell_async is async, but may not actually need an eventloop.
2925 # when this is the case, we want to run it using the pseudo_sync_runner
2980 # when this is the case, we want to run it using the pseudo_sync_runner
2926 # so that code can invoke eventloops (for example via the %run , and
2981 # so that code can invoke eventloops (for example via the %run , and
2927 # `%paste` magic.
2982 # `%paste` magic.
2928 if self.trio_runner:
2983 if self.trio_runner:
2929 runner = self.trio_runner
2984 runner = self.trio_runner
2930 elif self.should_run_async(
2985 elif self.should_run_async(
2931 raw_cell,
2986 raw_cell,
2932 transformed_cell=transformed_cell,
2987 transformed_cell=transformed_cell,
2933 preprocessing_exc_tuple=preprocessing_exc_tuple,
2988 preprocessing_exc_tuple=preprocessing_exc_tuple,
2934 ):
2989 ):
2935 runner = self.loop_runner
2990 runner = self.loop_runner
2936 else:
2991 else:
2937 runner = _pseudo_sync_runner
2992 runner = _pseudo_sync_runner
2938
2993
2939 try:
2994 try:
2940 return runner(coro)
2995 return runner(coro)
2941 except BaseException as e:
2996 except BaseException as e:
2942 info = ExecutionInfo(
2997 info = ExecutionInfo(
2943 raw_cell, store_history, silent, shell_futures, cell_id
2998 raw_cell, store_history, silent, shell_futures, cell_id
2944 )
2999 )
2945 result = ExecutionResult(info)
3000 result = ExecutionResult(info)
2946 result.error_in_exec = e
3001 result.error_in_exec = e
2947 self.showtraceback(running_compiled_code=True)
3002 self.showtraceback(running_compiled_code=True)
2948 return result
3003 return result
2949
3004
2950 def should_run_async(
3005 def should_run_async(
2951 self, raw_cell: str, *, transformed_cell=None, preprocessing_exc_tuple=None
3006 self, raw_cell: str, *, transformed_cell=None, preprocessing_exc_tuple=None
2952 ) -> bool:
3007 ) -> bool:
2953 """Return whether a cell should be run asynchronously via a coroutine runner
3008 """Return whether a cell should be run asynchronously via a coroutine runner
2954
3009
2955 Parameters
3010 Parameters
2956 ----------
3011 ----------
2957 raw_cell : str
3012 raw_cell : str
2958 The code to be executed
3013 The code to be executed
2959
3014
2960 Returns
3015 Returns
2961 -------
3016 -------
2962 result: bool
3017 result: bool
2963 Whether the code needs to be run with a coroutine runner or not
3018 Whether the code needs to be run with a coroutine runner or not
2964 .. versionadded:: 7.0
3019 .. versionadded:: 7.0
2965 """
3020 """
2966 if not self.autoawait:
3021 if not self.autoawait:
2967 return False
3022 return False
2968 if preprocessing_exc_tuple is not None:
3023 if preprocessing_exc_tuple is not None:
2969 return False
3024 return False
2970 assert preprocessing_exc_tuple is None
3025 assert preprocessing_exc_tuple is None
2971 if transformed_cell is None:
3026 if transformed_cell is None:
2972 warnings.warn(
3027 warnings.warn(
2973 "`should_run_async` will not call `transform_cell`"
3028 "`should_run_async` will not call `transform_cell`"
2974 " automatically in the future. Please pass the result to"
3029 " automatically in the future. Please pass the result to"
2975 " `transformed_cell` argument and any exception that happen"
3030 " `transformed_cell` argument and any exception that happen"
2976 " during the"
3031 " during the"
2977 "transform in `preprocessing_exc_tuple` in"
3032 "transform in `preprocessing_exc_tuple` in"
2978 " IPython 7.17 and above.",
3033 " IPython 7.17 and above.",
2979 DeprecationWarning,
3034 DeprecationWarning,
2980 stacklevel=2,
3035 stacklevel=2,
2981 )
3036 )
2982 try:
3037 try:
2983 cell = self.transform_cell(raw_cell)
3038 cell = self.transform_cell(raw_cell)
2984 except Exception:
3039 except Exception:
2985 # any exception during transform will be raised
3040 # any exception during transform will be raised
2986 # prior to execution
3041 # prior to execution
2987 return False
3042 return False
2988 else:
3043 else:
2989 cell = transformed_cell
3044 cell = transformed_cell
2990 return _should_be_async(cell)
3045 return _should_be_async(cell)
2991
3046
2992 async def run_cell_async(
3047 async def run_cell_async(
2993 self,
3048 self,
2994 raw_cell: str,
3049 raw_cell: str,
2995 store_history=False,
3050 store_history=False,
2996 silent=False,
3051 silent=False,
2997 shell_futures=True,
3052 shell_futures=True,
2998 *,
3053 *,
2999 transformed_cell: Optional[str] = None,
3054 transformed_cell: Optional[str] = None,
3000 preprocessing_exc_tuple: Optional[Any] = None,
3055 preprocessing_exc_tuple: Optional[Any] = None,
3001 cell_id=None,
3056 cell_id=None,
3002 ) -> ExecutionResult:
3057 ) -> ExecutionResult:
3003 """Run a complete IPython cell asynchronously.
3058 """Run a complete IPython cell asynchronously.
3004
3059
3005 Parameters
3060 Parameters
3006 ----------
3061 ----------
3007 raw_cell : str
3062 raw_cell : str
3008 The code (including IPython code such as %magic functions) to run.
3063 The code (including IPython code such as %magic functions) to run.
3009 store_history : bool
3064 store_history : bool
3010 If True, the raw and translated cell will be stored in IPython's
3065 If True, the raw and translated cell will be stored in IPython's
3011 history. For user code calling back into IPython's machinery, this
3066 history. For user code calling back into IPython's machinery, this
3012 should be set to False.
3067 should be set to False.
3013 silent : bool
3068 silent : bool
3014 If True, avoid side-effects, such as implicit displayhooks and
3069 If True, avoid side-effects, such as implicit displayhooks and
3015 and logging. silent=True forces store_history=False.
3070 and logging. silent=True forces store_history=False.
3016 shell_futures : bool
3071 shell_futures : bool
3017 If True, the code will share future statements with the interactive
3072 If True, the code will share future statements with the interactive
3018 shell. It will both be affected by previous __future__ imports, and
3073 shell. It will both be affected by previous __future__ imports, and
3019 any __future__ imports in the code will affect the shell. If False,
3074 any __future__ imports in the code will affect the shell. If False,
3020 __future__ imports are not shared in either direction.
3075 __future__ imports are not shared in either direction.
3021 transformed_cell: str
3076 transformed_cell: str
3022 cell that was passed through transformers
3077 cell that was passed through transformers
3023 preprocessing_exc_tuple:
3078 preprocessing_exc_tuple:
3024 trace if the transformation failed.
3079 trace if the transformation failed.
3025
3080
3026 Returns
3081 Returns
3027 -------
3082 -------
3028 result : :class:`ExecutionResult`
3083 result : :class:`ExecutionResult`
3029
3084
3030 .. versionadded:: 7.0
3085 .. versionadded:: 7.0
3031 """
3086 """
3032 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures, cell_id)
3087 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures, cell_id)
3033 result = ExecutionResult(info)
3088 result = ExecutionResult(info)
3034
3089
3035 if (not raw_cell) or raw_cell.isspace():
3090 if (not raw_cell) or raw_cell.isspace():
3036 self.last_execution_succeeded = True
3091 self.last_execution_succeeded = True
3037 self.last_execution_result = result
3092 self.last_execution_result = result
3038 return result
3093 return result
3039
3094
3040 if silent:
3095 if silent:
3041 store_history = False
3096 store_history = False
3042
3097
3043 if store_history:
3098 if store_history:
3044 result.execution_count = self.execution_count
3099 result.execution_count = self.execution_count
3045
3100
3046 def error_before_exec(value):
3101 def error_before_exec(value):
3047 if store_history:
3102 if store_history:
3048 self.execution_count += 1
3103 self.execution_count += 1
3049 result.error_before_exec = value
3104 result.error_before_exec = value
3050 self.last_execution_succeeded = False
3105 self.last_execution_succeeded = False
3051 self.last_execution_result = result
3106 self.last_execution_result = result
3052 return result
3107 return result
3053
3108
3054 self.events.trigger('pre_execute')
3109 self.events.trigger('pre_execute')
3055 if not silent:
3110 if not silent:
3056 self.events.trigger('pre_run_cell', info)
3111 self.events.trigger('pre_run_cell', info)
3057
3112
3058 if transformed_cell is None:
3113 if transformed_cell is None:
3059 warnings.warn(
3114 warnings.warn(
3060 "`run_cell_async` will not call `transform_cell`"
3115 "`run_cell_async` will not call `transform_cell`"
3061 " automatically in the future. Please pass the result to"
3116 " automatically in the future. Please pass the result to"
3062 " `transformed_cell` argument and any exception that happen"
3117 " `transformed_cell` argument and any exception that happen"
3063 " during the"
3118 " during the"
3064 "transform in `preprocessing_exc_tuple` in"
3119 "transform in `preprocessing_exc_tuple` in"
3065 " IPython 7.17 and above.",
3120 " IPython 7.17 and above.",
3066 DeprecationWarning,
3121 DeprecationWarning,
3067 stacklevel=2,
3122 stacklevel=2,
3068 )
3123 )
3069 # If any of our input transformation (input_transformer_manager or
3124 # If any of our input transformation (input_transformer_manager or
3070 # prefilter_manager) raises an exception, we store it in this variable
3125 # prefilter_manager) raises an exception, we store it in this variable
3071 # so that we can display the error after logging the input and storing
3126 # so that we can display the error after logging the input and storing
3072 # it in the history.
3127 # it in the history.
3073 try:
3128 try:
3074 cell = self.transform_cell(raw_cell)
3129 cell = self.transform_cell(raw_cell)
3075 except Exception:
3130 except Exception:
3076 preprocessing_exc_tuple = sys.exc_info()
3131 preprocessing_exc_tuple = sys.exc_info()
3077 cell = raw_cell # cell has to exist so it can be stored/logged
3132 cell = raw_cell # cell has to exist so it can be stored/logged
3078 else:
3133 else:
3079 preprocessing_exc_tuple = None
3134 preprocessing_exc_tuple = None
3080 else:
3135 else:
3081 if preprocessing_exc_tuple is None:
3136 if preprocessing_exc_tuple is None:
3082 cell = transformed_cell
3137 cell = transformed_cell
3083 else:
3138 else:
3084 cell = raw_cell
3139 cell = raw_cell
3085
3140
3086 # Store raw and processed history
3141 # Store raw and processed history
3087 if store_history and raw_cell.strip(" %") != "paste":
3142 if store_history and raw_cell.strip(" %") != "paste":
3088 self.history_manager.store_inputs(self.execution_count, cell, raw_cell)
3143 self.history_manager.store_inputs(self.execution_count, cell, raw_cell)
3089 if not silent:
3144 if not silent:
3090 self.logger.log(cell, raw_cell)
3145 self.logger.log(cell, raw_cell)
3091
3146
3092 # Display the exception if input processing failed.
3147 # Display the exception if input processing failed.
3093 if preprocessing_exc_tuple is not None:
3148 if preprocessing_exc_tuple is not None:
3094 self.showtraceback(preprocessing_exc_tuple)
3149 self.showtraceback(preprocessing_exc_tuple)
3095 if store_history:
3150 if store_history:
3096 self.execution_count += 1
3151 self.execution_count += 1
3097 return error_before_exec(preprocessing_exc_tuple[1])
3152 return error_before_exec(preprocessing_exc_tuple[1])
3098
3153
3099 # Our own compiler remembers the __future__ environment. If we want to
3154 # Our own compiler remembers the __future__ environment. If we want to
3100 # run code with a separate __future__ environment, use the default
3155 # run code with a separate __future__ environment, use the default
3101 # compiler
3156 # compiler
3102 compiler = self.compile if shell_futures else self.compiler_class()
3157 compiler = self.compile if shell_futures else self.compiler_class()
3103
3158
3104 _run_async = False
3159 _run_async = False
3105
3160
3106 with self.builtin_trap:
3161 with self.builtin_trap:
3107 cell_name = compiler.cache(cell, self.execution_count, raw_code=raw_cell)
3162 cell_name = compiler.cache(cell, self.execution_count, raw_code=raw_cell)
3108
3163
3109 with self.display_trap:
3164 with self.display_trap:
3110 # Compile to bytecode
3165 # Compile to bytecode
3111 try:
3166 try:
3112 code_ast = compiler.ast_parse(cell, filename=cell_name)
3167 code_ast = compiler.ast_parse(cell, filename=cell_name)
3113 except self.custom_exceptions as e:
3168 except self.custom_exceptions as e:
3114 etype, value, tb = sys.exc_info()
3169 etype, value, tb = sys.exc_info()
3115 self.CustomTB(etype, value, tb)
3170 self.CustomTB(etype, value, tb)
3116 return error_before_exec(e)
3171 return error_before_exec(e)
3117 except IndentationError as e:
3172 except IndentationError as e:
3118 self.showindentationerror()
3173 self.showindentationerror()
3119 return error_before_exec(e)
3174 return error_before_exec(e)
3120 except (OverflowError, SyntaxError, ValueError, TypeError,
3175 except (OverflowError, SyntaxError, ValueError, TypeError,
3121 MemoryError) as e:
3176 MemoryError) as e:
3122 self.showsyntaxerror()
3177 self.showsyntaxerror()
3123 return error_before_exec(e)
3178 return error_before_exec(e)
3124
3179
3125 # Apply AST transformations
3180 # Apply AST transformations
3126 try:
3181 try:
3127 code_ast = self.transform_ast(code_ast)
3182 code_ast = self.transform_ast(code_ast)
3128 except InputRejected as e:
3183 except InputRejected as e:
3129 self.showtraceback()
3184 self.showtraceback()
3130 return error_before_exec(e)
3185 return error_before_exec(e)
3131
3186
3132 # Give the displayhook a reference to our ExecutionResult so it
3187 # Give the displayhook a reference to our ExecutionResult so it
3133 # can fill in the output value.
3188 # can fill in the output value.
3134 self.displayhook.exec_result = result
3189 self.displayhook.exec_result = result
3135
3190
3136 # Execute the user code
3191 # Execute the user code
3137 interactivity = "none" if silent else self.ast_node_interactivity
3192 interactivity = "none" if silent else self.ast_node_interactivity
3138
3193
3139 has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
3194 has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
3140 interactivity=interactivity, compiler=compiler, result=result)
3195 interactivity=interactivity, compiler=compiler, result=result)
3141
3196
3142 self.last_execution_succeeded = not has_raised
3197 self.last_execution_succeeded = not has_raised
3143 self.last_execution_result = result
3198 self.last_execution_result = result
3144
3199
3145 # Reset this so later displayed values do not modify the
3200 # Reset this so later displayed values do not modify the
3146 # ExecutionResult
3201 # ExecutionResult
3147 self.displayhook.exec_result = None
3202 self.displayhook.exec_result = None
3148
3203
3149 if store_history:
3204 if store_history:
3150 # Write output to the database. Does nothing unless
3205 # Write output to the database. Does nothing unless
3151 # history output logging is enabled.
3206 # history output logging is enabled.
3152 self.history_manager.store_output(self.execution_count)
3207 self.history_manager.store_output(self.execution_count)
3153 # Each cell is a *single* input, regardless of how many lines it has
3208 # Each cell is a *single* input, regardless of how many lines it has
3154 self.execution_count += 1
3209 self.execution_count += 1
3155
3210
3156 return result
3211 return result
3157
3212
3158 def transform_cell(self, raw_cell):
3213 def transform_cell(self, raw_cell):
3159 """Transform an input cell before parsing it.
3214 """Transform an input cell before parsing it.
3160
3215
3161 Static transformations, implemented in IPython.core.inputtransformer2,
3216 Static transformations, implemented in IPython.core.inputtransformer2,
3162 deal with things like ``%magic`` and ``!system`` commands.
3217 deal with things like ``%magic`` and ``!system`` commands.
3163 These run on all input.
3218 These run on all input.
3164 Dynamic transformations, for things like unescaped magics and the exit
3219 Dynamic transformations, for things like unescaped magics and the exit
3165 autocall, depend on the state of the interpreter.
3220 autocall, depend on the state of the interpreter.
3166 These only apply to single line inputs.
3221 These only apply to single line inputs.
3167
3222
3168 These string-based transformations are followed by AST transformations;
3223 These string-based transformations are followed by AST transformations;
3169 see :meth:`transform_ast`.
3224 see :meth:`transform_ast`.
3170 """
3225 """
3171 # Static input transformations
3226 # Static input transformations
3172 cell = self.input_transformer_manager.transform_cell(raw_cell)
3227 cell = self.input_transformer_manager.transform_cell(raw_cell)
3173
3228
3174 if len(cell.splitlines()) == 1:
3229 if len(cell.splitlines()) == 1:
3175 # Dynamic transformations - only applied for single line commands
3230 # Dynamic transformations - only applied for single line commands
3176 with self.builtin_trap:
3231 with self.builtin_trap:
3177 # use prefilter_lines to handle trailing newlines
3232 # use prefilter_lines to handle trailing newlines
3178 # restore trailing newline for ast.parse
3233 # restore trailing newline for ast.parse
3179 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
3234 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
3180
3235
3181 lines = cell.splitlines(keepends=True)
3236 lines = cell.splitlines(keepends=True)
3182 for transform in self.input_transformers_post:
3237 for transform in self.input_transformers_post:
3183 lines = transform(lines)
3238 lines = transform(lines)
3184 cell = ''.join(lines)
3239 cell = ''.join(lines)
3185
3240
3186 return cell
3241 return cell
3187
3242
3188 def transform_ast(self, node):
3243 def transform_ast(self, node):
3189 """Apply the AST transformations from self.ast_transformers
3244 """Apply the AST transformations from self.ast_transformers
3190
3245
3191 Parameters
3246 Parameters
3192 ----------
3247 ----------
3193 node : ast.Node
3248 node : ast.Node
3194 The root node to be transformed. Typically called with the ast.Module
3249 The root node to be transformed. Typically called with the ast.Module
3195 produced by parsing user input.
3250 produced by parsing user input.
3196
3251
3197 Returns
3252 Returns
3198 -------
3253 -------
3199 An ast.Node corresponding to the node it was called with. Note that it
3254 An ast.Node corresponding to the node it was called with. Note that it
3200 may also modify the passed object, so don't rely on references to the
3255 may also modify the passed object, so don't rely on references to the
3201 original AST.
3256 original AST.
3202 """
3257 """
3203 for transformer in self.ast_transformers:
3258 for transformer in self.ast_transformers:
3204 try:
3259 try:
3205 node = transformer.visit(node)
3260 node = transformer.visit(node)
3206 except InputRejected:
3261 except InputRejected:
3207 # User-supplied AST transformers can reject an input by raising
3262 # User-supplied AST transformers can reject an input by raising
3208 # an InputRejected. Short-circuit in this case so that we
3263 # an InputRejected. Short-circuit in this case so that we
3209 # don't unregister the transform.
3264 # don't unregister the transform.
3210 raise
3265 raise
3211 except Exception:
3266 except Exception:
3212 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
3267 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
3213 self.ast_transformers.remove(transformer)
3268 self.ast_transformers.remove(transformer)
3214
3269
3215 if self.ast_transformers:
3270 if self.ast_transformers:
3216 ast.fix_missing_locations(node)
3271 ast.fix_missing_locations(node)
3217 return node
3272 return node
3218
3273
3219 async def run_ast_nodes(
3274 async def run_ast_nodes(
3220 self,
3275 self,
3221 nodelist: ListType[stmt],
3276 nodelist: ListType[stmt],
3222 cell_name: str,
3277 cell_name: str,
3223 interactivity="last_expr",
3278 interactivity="last_expr",
3224 compiler=compile,
3279 compiler=compile,
3225 result=None,
3280 result=None,
3226 ):
3281 ):
3227 """Run a sequence of AST nodes. The execution mode depends on the
3282 """Run a sequence of AST nodes. The execution mode depends on the
3228 interactivity parameter.
3283 interactivity parameter.
3229
3284
3230 Parameters
3285 Parameters
3231 ----------
3286 ----------
3232 nodelist : list
3287 nodelist : list
3233 A sequence of AST nodes to run.
3288 A sequence of AST nodes to run.
3234 cell_name : str
3289 cell_name : str
3235 Will be passed to the compiler as the filename of the cell. Typically
3290 Will be passed to the compiler as the filename of the cell. Typically
3236 the value returned by ip.compile.cache(cell).
3291 the value returned by ip.compile.cache(cell).
3237 interactivity : str
3292 interactivity : str
3238 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none',
3293 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none',
3239 specifying which nodes should be run interactively (displaying output
3294 specifying which nodes should be run interactively (displaying output
3240 from expressions). 'last_expr' will run the last node interactively
3295 from expressions). 'last_expr' will run the last node interactively
3241 only if it is an expression (i.e. expressions in loops or other blocks
3296 only if it is an expression (i.e. expressions in loops or other blocks
3242 are not displayed) 'last_expr_or_assign' will run the last expression
3297 are not displayed) 'last_expr_or_assign' will run the last expression
3243 or the last assignment. Other values for this parameter will raise a
3298 or the last assignment. Other values for this parameter will raise a
3244 ValueError.
3299 ValueError.
3245
3300
3246 compiler : callable
3301 compiler : callable
3247 A function with the same interface as the built-in compile(), to turn
3302 A function with the same interface as the built-in compile(), to turn
3248 the AST nodes into code objects. Default is the built-in compile().
3303 the AST nodes into code objects. Default is the built-in compile().
3249 result : ExecutionResult, optional
3304 result : ExecutionResult, optional
3250 An object to store exceptions that occur during execution.
3305 An object to store exceptions that occur during execution.
3251
3306
3252 Returns
3307 Returns
3253 -------
3308 -------
3254 True if an exception occurred while running code, False if it finished
3309 True if an exception occurred while running code, False if it finished
3255 running.
3310 running.
3256 """
3311 """
3257 if not nodelist:
3312 if not nodelist:
3258 return
3313 return
3259
3314
3260
3315
3261 if interactivity == 'last_expr_or_assign':
3316 if interactivity == 'last_expr_or_assign':
3262 if isinstance(nodelist[-1], _assign_nodes):
3317 if isinstance(nodelist[-1], _assign_nodes):
3263 asg = nodelist[-1]
3318 asg = nodelist[-1]
3264 if isinstance(asg, ast.Assign) and len(asg.targets) == 1:
3319 if isinstance(asg, ast.Assign) and len(asg.targets) == 1:
3265 target = asg.targets[0]
3320 target = asg.targets[0]
3266 elif isinstance(asg, _single_targets_nodes):
3321 elif isinstance(asg, _single_targets_nodes):
3267 target = asg.target
3322 target = asg.target
3268 else:
3323 else:
3269 target = None
3324 target = None
3270 if isinstance(target, ast.Name):
3325 if isinstance(target, ast.Name):
3271 nnode = ast.Expr(ast.Name(target.id, ast.Load()))
3326 nnode = ast.Expr(ast.Name(target.id, ast.Load()))
3272 ast.fix_missing_locations(nnode)
3327 ast.fix_missing_locations(nnode)
3273 nodelist.append(nnode)
3328 nodelist.append(nnode)
3274 interactivity = 'last_expr'
3329 interactivity = 'last_expr'
3275
3330
3276 _async = False
3331 _async = False
3277 if interactivity == 'last_expr':
3332 if interactivity == 'last_expr':
3278 if isinstance(nodelist[-1], ast.Expr):
3333 if isinstance(nodelist[-1], ast.Expr):
3279 interactivity = "last"
3334 interactivity = "last"
3280 else:
3335 else:
3281 interactivity = "none"
3336 interactivity = "none"
3282
3337
3283 if interactivity == 'none':
3338 if interactivity == 'none':
3284 to_run_exec, to_run_interactive = nodelist, []
3339 to_run_exec, to_run_interactive = nodelist, []
3285 elif interactivity == 'last':
3340 elif interactivity == 'last':
3286 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
3341 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
3287 elif interactivity == 'all':
3342 elif interactivity == 'all':
3288 to_run_exec, to_run_interactive = [], nodelist
3343 to_run_exec, to_run_interactive = [], nodelist
3289 else:
3344 else:
3290 raise ValueError("Interactivity was %r" % interactivity)
3345 raise ValueError("Interactivity was %r" % interactivity)
3291
3346
3292 try:
3347 try:
3293
3348
3294 def compare(code):
3349 def compare(code):
3295 is_async = inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE
3350 is_async = inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE
3296 return is_async
3351 return is_async
3297
3352
3298 # refactor that to just change the mod constructor.
3353 # refactor that to just change the mod constructor.
3299 to_run = []
3354 to_run = []
3300 for node in to_run_exec:
3355 for node in to_run_exec:
3301 to_run.append((node, "exec"))
3356 to_run.append((node, "exec"))
3302
3357
3303 for node in to_run_interactive:
3358 for node in to_run_interactive:
3304 to_run.append((node, "single"))
3359 to_run.append((node, "single"))
3305
3360
3306 for node, mode in to_run:
3361 for node, mode in to_run:
3307 if mode == "exec":
3362 if mode == "exec":
3308 mod = Module([node], [])
3363 mod = Module([node], [])
3309 elif mode == "single":
3364 elif mode == "single":
3310 mod = ast.Interactive([node])
3365 mod = ast.Interactive([node])
3311 with compiler.extra_flags(
3366 with compiler.extra_flags(
3312 getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
3367 getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
3313 if self.autoawait
3368 if self.autoawait
3314 else 0x0
3369 else 0x0
3315 ):
3370 ):
3316 code = compiler(mod, cell_name, mode)
3371 code = compiler(mod, cell_name, mode)
3317 asy = compare(code)
3372 asy = compare(code)
3318 if await self.run_code(code, result, async_=asy):
3373 if await self.run_code(code, result, async_=asy):
3319 return True
3374 return True
3320
3375
3321 # Flush softspace
3376 # Flush softspace
3322 if softspace(sys.stdout, 0):
3377 if softspace(sys.stdout, 0):
3323 print()
3378 print()
3324
3379
3325 except:
3380 except:
3326 # It's possible to have exceptions raised here, typically by
3381 # It's possible to have exceptions raised here, typically by
3327 # compilation of odd code (such as a naked 'return' outside a
3382 # compilation of odd code (such as a naked 'return' outside a
3328 # function) that did parse but isn't valid. Typically the exception
3383 # function) that did parse but isn't valid. Typically the exception
3329 # is a SyntaxError, but it's safest just to catch anything and show
3384 # is a SyntaxError, but it's safest just to catch anything and show
3330 # the user a traceback.
3385 # the user a traceback.
3331
3386
3332 # We do only one try/except outside the loop to minimize the impact
3387 # We do only one try/except outside the loop to minimize the impact
3333 # on runtime, and also because if any node in the node list is
3388 # on runtime, and also because if any node in the node list is
3334 # broken, we should stop execution completely.
3389 # broken, we should stop execution completely.
3335 if result:
3390 if result:
3336 result.error_before_exec = sys.exc_info()[1]
3391 result.error_before_exec = sys.exc_info()[1]
3337 self.showtraceback()
3392 self.showtraceback()
3338 return True
3393 return True
3339
3394
3340 return False
3395 return False
3341
3396
3342 async def run_code(self, code_obj, result=None, *, async_=False):
3397 async def run_code(self, code_obj, result=None, *, async_=False):
3343 """Execute a code object.
3398 """Execute a code object.
3344
3399
3345 When an exception occurs, self.showtraceback() is called to display a
3400 When an exception occurs, self.showtraceback() is called to display a
3346 traceback.
3401 traceback.
3347
3402
3348 Parameters
3403 Parameters
3349 ----------
3404 ----------
3350 code_obj : code object
3405 code_obj : code object
3351 A compiled code object, to be executed
3406 A compiled code object, to be executed
3352 result : ExecutionResult, optional
3407 result : ExecutionResult, optional
3353 An object to store exceptions that occur during execution.
3408 An object to store exceptions that occur during execution.
3354 async_ : Bool (Experimental)
3409 async_ : Bool (Experimental)
3355 Attempt to run top-level asynchronous code in a default loop.
3410 Attempt to run top-level asynchronous code in a default loop.
3356
3411
3357 Returns
3412 Returns
3358 -------
3413 -------
3359 False : successful execution.
3414 False : successful execution.
3360 True : an error occurred.
3415 True : an error occurred.
3361 """
3416 """
3362 # special value to say that anything above is IPython and should be
3417 # special value to say that anything above is IPython and should be
3363 # hidden.
3418 # hidden.
3364 __tracebackhide__ = "__ipython_bottom__"
3419 __tracebackhide__ = "__ipython_bottom__"
3365 # Set our own excepthook in case the user code tries to call it
3420 # Set our own excepthook in case the user code tries to call it
3366 # directly, so that the IPython crash handler doesn't get triggered
3421 # directly, so that the IPython crash handler doesn't get triggered
3367 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3422 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3368
3423
3369 # we save the original sys.excepthook in the instance, in case config
3424 # we save the original sys.excepthook in the instance, in case config
3370 # code (such as magics) needs access to it.
3425 # code (such as magics) needs access to it.
3371 self.sys_excepthook = old_excepthook
3426 self.sys_excepthook = old_excepthook
3372 outflag = True # happens in more places, so it's easier as default
3427 outflag = True # happens in more places, so it's easier as default
3373 try:
3428 try:
3374 try:
3429 try:
3375 if async_:
3430 if async_:
3376 await eval(code_obj, self.user_global_ns, self.user_ns)
3431 await eval(code_obj, self.user_global_ns, self.user_ns)
3377 else:
3432 else:
3378 exec(code_obj, self.user_global_ns, self.user_ns)
3433 exec(code_obj, self.user_global_ns, self.user_ns)
3379 finally:
3434 finally:
3380 # Reset our crash handler in place
3435 # Reset our crash handler in place
3381 sys.excepthook = old_excepthook
3436 sys.excepthook = old_excepthook
3382 except SystemExit as e:
3437 except SystemExit as e:
3383 if result is not None:
3438 if result is not None:
3384 result.error_in_exec = e
3439 result.error_in_exec = e
3385 self.showtraceback(exception_only=True)
3440 self.showtraceback(exception_only=True)
3386 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3441 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3387 except bdb.BdbQuit:
3442 except bdb.BdbQuit:
3388 etype, value, tb = sys.exc_info()
3443 etype, value, tb = sys.exc_info()
3389 if result is not None:
3444 if result is not None:
3390 result.error_in_exec = value
3445 result.error_in_exec = value
3391 # the BdbQuit stops here
3446 # the BdbQuit stops here
3392 except self.custom_exceptions:
3447 except self.custom_exceptions:
3393 etype, value, tb = sys.exc_info()
3448 etype, value, tb = sys.exc_info()
3394 if result is not None:
3449 if result is not None:
3395 result.error_in_exec = value
3450 result.error_in_exec = value
3396 self.CustomTB(etype, value, tb)
3451 self.CustomTB(etype, value, tb)
3397 except:
3452 except:
3398 if result is not None:
3453 if result is not None:
3399 result.error_in_exec = sys.exc_info()[1]
3454 result.error_in_exec = sys.exc_info()[1]
3400 self.showtraceback(running_compiled_code=True)
3455 self.showtraceback(running_compiled_code=True)
3401 else:
3456 else:
3402 outflag = False
3457 outflag = False
3403 return outflag
3458 return outflag
3404
3459
3405 # For backwards compatibility
3460 # For backwards compatibility
3406 runcode = run_code
3461 runcode = run_code
3407
3462
3408 def check_complete(self, code: str) -> Tuple[str, str]:
3463 def check_complete(self, code: str) -> Tuple[str, str]:
3409 """Return whether a block of code is ready to execute, or should be continued
3464 """Return whether a block of code is ready to execute, or should be continued
3410
3465
3411 Parameters
3466 Parameters
3412 ----------
3467 ----------
3413 code : string
3468 code : string
3414 Python input code, which can be multiline.
3469 Python input code, which can be multiline.
3415
3470
3416 Returns
3471 Returns
3417 -------
3472 -------
3418 status : str
3473 status : str
3419 One of 'complete', 'incomplete', or 'invalid' if source is not a
3474 One of 'complete', 'incomplete', or 'invalid' if source is not a
3420 prefix of valid code.
3475 prefix of valid code.
3421 indent : str
3476 indent : str
3422 When status is 'incomplete', this is some whitespace to insert on
3477 When status is 'incomplete', this is some whitespace to insert on
3423 the next line of the prompt.
3478 the next line of the prompt.
3424 """
3479 """
3425 status, nspaces = self.input_transformer_manager.check_complete(code)
3480 status, nspaces = self.input_transformer_manager.check_complete(code)
3426 return status, ' ' * (nspaces or 0)
3481 return status, ' ' * (nspaces or 0)
3427
3482
3428 #-------------------------------------------------------------------------
3483 #-------------------------------------------------------------------------
3429 # Things related to GUI support and pylab
3484 # Things related to GUI support and pylab
3430 #-------------------------------------------------------------------------
3485 #-------------------------------------------------------------------------
3431
3486
3432 active_eventloop = None
3487 active_eventloop = None
3433
3488
3434 def enable_gui(self, gui=None):
3489 def enable_gui(self, gui=None):
3435 raise NotImplementedError('Implement enable_gui in a subclass')
3490 raise NotImplementedError('Implement enable_gui in a subclass')
3436
3491
3437 def enable_matplotlib(self, gui=None):
3492 def enable_matplotlib(self, gui=None):
3438 """Enable interactive matplotlib and inline figure support.
3493 """Enable interactive matplotlib and inline figure support.
3439
3494
3440 This takes the following steps:
3495 This takes the following steps:
3441
3496
3442 1. select the appropriate eventloop and matplotlib backend
3497 1. select the appropriate eventloop and matplotlib backend
3443 2. set up matplotlib for interactive use with that backend
3498 2. set up matplotlib for interactive use with that backend
3444 3. configure formatters for inline figure display
3499 3. configure formatters for inline figure display
3445 4. enable the selected gui eventloop
3500 4. enable the selected gui eventloop
3446
3501
3447 Parameters
3502 Parameters
3448 ----------
3503 ----------
3449 gui : optional, string
3504 gui : optional, string
3450 If given, dictates the choice of matplotlib GUI backend to use
3505 If given, dictates the choice of matplotlib GUI backend to use
3451 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3506 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3452 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3507 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3453 matplotlib (as dictated by the matplotlib build-time options plus the
3508 matplotlib (as dictated by the matplotlib build-time options plus the
3454 user's matplotlibrc configuration file). Note that not all backends
3509 user's matplotlibrc configuration file). Note that not all backends
3455 make sense in all contexts, for example a terminal ipython can't
3510 make sense in all contexts, for example a terminal ipython can't
3456 display figures inline.
3511 display figures inline.
3457 """
3512 """
3458 from matplotlib_inline.backend_inline import configure_inline_support
3513 from matplotlib_inline.backend_inline import configure_inline_support
3459
3514
3460 from IPython.core import pylabtools as pt
3515 from IPython.core import pylabtools as pt
3461 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3516 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3462
3517
3463 if gui != 'inline':
3518 if gui != 'inline':
3464 # If we have our first gui selection, store it
3519 # If we have our first gui selection, store it
3465 if self.pylab_gui_select is None:
3520 if self.pylab_gui_select is None:
3466 self.pylab_gui_select = gui
3521 self.pylab_gui_select = gui
3467 # Otherwise if they are different
3522 # Otherwise if they are different
3468 elif gui != self.pylab_gui_select:
3523 elif gui != self.pylab_gui_select:
3469 print('Warning: Cannot change to a different GUI toolkit: %s.'
3524 print('Warning: Cannot change to a different GUI toolkit: %s.'
3470 ' Using %s instead.' % (gui, self.pylab_gui_select))
3525 ' Using %s instead.' % (gui, self.pylab_gui_select))
3471 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3526 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3472
3527
3473 pt.activate_matplotlib(backend)
3528 pt.activate_matplotlib(backend)
3474 configure_inline_support(self, backend)
3529 configure_inline_support(self, backend)
3475
3530
3476 # Now we must activate the gui pylab wants to use, and fix %run to take
3531 # Now we must activate the gui pylab wants to use, and fix %run to take
3477 # plot updates into account
3532 # plot updates into account
3478 self.enable_gui(gui)
3533 self.enable_gui(gui)
3479 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3534 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3480 pt.mpl_runner(self.safe_execfile)
3535 pt.mpl_runner(self.safe_execfile)
3481
3536
3482 return gui, backend
3537 return gui, backend
3483
3538
3484 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3539 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3485 """Activate pylab support at runtime.
3540 """Activate pylab support at runtime.
3486
3541
3487 This turns on support for matplotlib, preloads into the interactive
3542 This turns on support for matplotlib, preloads into the interactive
3488 namespace all of numpy and pylab, and configures IPython to correctly
3543 namespace all of numpy and pylab, and configures IPython to correctly
3489 interact with the GUI event loop. The GUI backend to be used can be
3544 interact with the GUI event loop. The GUI backend to be used can be
3490 optionally selected with the optional ``gui`` argument.
3545 optionally selected with the optional ``gui`` argument.
3491
3546
3492 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3547 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3493
3548
3494 Parameters
3549 Parameters
3495 ----------
3550 ----------
3496 gui : optional, string
3551 gui : optional, string
3497 If given, dictates the choice of matplotlib GUI backend to use
3552 If given, dictates the choice of matplotlib GUI backend to use
3498 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3553 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3499 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3554 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3500 matplotlib (as dictated by the matplotlib build-time options plus the
3555 matplotlib (as dictated by the matplotlib build-time options plus the
3501 user's matplotlibrc configuration file). Note that not all backends
3556 user's matplotlibrc configuration file). Note that not all backends
3502 make sense in all contexts, for example a terminal ipython can't
3557 make sense in all contexts, for example a terminal ipython can't
3503 display figures inline.
3558 display figures inline.
3504 import_all : optional, bool, default: True
3559 import_all : optional, bool, default: True
3505 Whether to do `from numpy import *` and `from pylab import *`
3560 Whether to do `from numpy import *` and `from pylab import *`
3506 in addition to module imports.
3561 in addition to module imports.
3507 welcome_message : deprecated
3562 welcome_message : deprecated
3508 This argument is ignored, no welcome message will be displayed.
3563 This argument is ignored, no welcome message will be displayed.
3509 """
3564 """
3510 from IPython.core.pylabtools import import_pylab
3565 from IPython.core.pylabtools import import_pylab
3511
3566
3512 gui, backend = self.enable_matplotlib(gui)
3567 gui, backend = self.enable_matplotlib(gui)
3513
3568
3514 # We want to prevent the loading of pylab to pollute the user's
3569 # We want to prevent the loading of pylab to pollute the user's
3515 # namespace as shown by the %who* magics, so we execute the activation
3570 # namespace as shown by the %who* magics, so we execute the activation
3516 # code in an empty namespace, and we update *both* user_ns and
3571 # code in an empty namespace, and we update *both* user_ns and
3517 # user_ns_hidden with this information.
3572 # user_ns_hidden with this information.
3518 ns = {}
3573 ns = {}
3519 import_pylab(ns, import_all)
3574 import_pylab(ns, import_all)
3520 # warn about clobbered names
3575 # warn about clobbered names
3521 ignored = {"__builtins__"}
3576 ignored = {"__builtins__"}
3522 both = set(ns).intersection(self.user_ns).difference(ignored)
3577 both = set(ns).intersection(self.user_ns).difference(ignored)
3523 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3578 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3524 self.user_ns.update(ns)
3579 self.user_ns.update(ns)
3525 self.user_ns_hidden.update(ns)
3580 self.user_ns_hidden.update(ns)
3526 return gui, backend, clobbered
3581 return gui, backend, clobbered
3527
3582
3528 #-------------------------------------------------------------------------
3583 #-------------------------------------------------------------------------
3529 # Utilities
3584 # Utilities
3530 #-------------------------------------------------------------------------
3585 #-------------------------------------------------------------------------
3531
3586
3532 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3587 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3533 """Expand python variables in a string.
3588 """Expand python variables in a string.
3534
3589
3535 The depth argument indicates how many frames above the caller should
3590 The depth argument indicates how many frames above the caller should
3536 be walked to look for the local namespace where to expand variables.
3591 be walked to look for the local namespace where to expand variables.
3537
3592
3538 The global namespace for expansion is always the user's interactive
3593 The global namespace for expansion is always the user's interactive
3539 namespace.
3594 namespace.
3540 """
3595 """
3541 ns = self.user_ns.copy()
3596 ns = self.user_ns.copy()
3542 try:
3597 try:
3543 frame = sys._getframe(depth+1)
3598 frame = sys._getframe(depth+1)
3544 except ValueError:
3599 except ValueError:
3545 # This is thrown if there aren't that many frames on the stack,
3600 # This is thrown if there aren't that many frames on the stack,
3546 # e.g. if a script called run_line_magic() directly.
3601 # e.g. if a script called run_line_magic() directly.
3547 pass
3602 pass
3548 else:
3603 else:
3549 ns.update(frame.f_locals)
3604 ns.update(frame.f_locals)
3550
3605
3551 try:
3606 try:
3552 # We have to use .vformat() here, because 'self' is a valid and common
3607 # We have to use .vformat() here, because 'self' is a valid and common
3553 # name, and expanding **ns for .format() would make it collide with
3608 # name, and expanding **ns for .format() would make it collide with
3554 # the 'self' argument of the method.
3609 # the 'self' argument of the method.
3555 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3610 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3556 except Exception:
3611 except Exception:
3557 # if formatter couldn't format, just let it go untransformed
3612 # if formatter couldn't format, just let it go untransformed
3558 pass
3613 pass
3559 return cmd
3614 return cmd
3560
3615
3561 def mktempfile(self, data=None, prefix='ipython_edit_'):
3616 def mktempfile(self, data=None, prefix='ipython_edit_'):
3562 """Make a new tempfile and return its filename.
3617 """Make a new tempfile and return its filename.
3563
3618
3564 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3619 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3565 but it registers the created filename internally so ipython cleans it up
3620 but it registers the created filename internally so ipython cleans it up
3566 at exit time.
3621 at exit time.
3567
3622
3568 Optional inputs:
3623 Optional inputs:
3569
3624
3570 - data(None): if data is given, it gets written out to the temp file
3625 - data(None): if data is given, it gets written out to the temp file
3571 immediately, and the file is closed again."""
3626 immediately, and the file is closed again."""
3572
3627
3573 dir_path = Path(tempfile.mkdtemp(prefix=prefix))
3628 dir_path = Path(tempfile.mkdtemp(prefix=prefix))
3574 self.tempdirs.append(dir_path)
3629 self.tempdirs.append(dir_path)
3575
3630
3576 handle, filename = tempfile.mkstemp(".py", prefix, dir=str(dir_path))
3631 handle, filename = tempfile.mkstemp(".py", prefix, dir=str(dir_path))
3577 os.close(handle) # On Windows, there can only be one open handle on a file
3632 os.close(handle) # On Windows, there can only be one open handle on a file
3578
3633
3579 file_path = Path(filename)
3634 file_path = Path(filename)
3580 self.tempfiles.append(file_path)
3635 self.tempfiles.append(file_path)
3581
3636
3582 if data:
3637 if data:
3583 file_path.write_text(data, encoding="utf-8")
3638 file_path.write_text(data, encoding="utf-8")
3584 return filename
3639 return filename
3585
3640
3586 def ask_yes_no(self, prompt, default=None, interrupt=None):
3641 def ask_yes_no(self, prompt, default=None, interrupt=None):
3587 if self.quiet:
3642 if self.quiet:
3588 return True
3643 return True
3589 return ask_yes_no(prompt,default,interrupt)
3644 return ask_yes_no(prompt,default,interrupt)
3590
3645
3591 def show_usage(self):
3646 def show_usage(self):
3592 """Show a usage message"""
3647 """Show a usage message"""
3593 page.page(IPython.core.usage.interactive_usage)
3648 page.page(IPython.core.usage.interactive_usage)
3594
3649
3595 def extract_input_lines(self, range_str, raw=False):
3650 def extract_input_lines(self, range_str, raw=False):
3596 """Return as a string a set of input history slices.
3651 """Return as a string a set of input history slices.
3597
3652
3598 Parameters
3653 Parameters
3599 ----------
3654 ----------
3600 range_str : str
3655 range_str : str
3601 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3656 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3602 since this function is for use by magic functions which get their
3657 since this function is for use by magic functions which get their
3603 arguments as strings. The number before the / is the session
3658 arguments as strings. The number before the / is the session
3604 number: ~n goes n back from the current session.
3659 number: ~n goes n back from the current session.
3605
3660
3606 If empty string is given, returns history of current session
3661 If empty string is given, returns history of current session
3607 without the last input.
3662 without the last input.
3608
3663
3609 raw : bool, optional
3664 raw : bool, optional
3610 By default, the processed input is used. If this is true, the raw
3665 By default, the processed input is used. If this is true, the raw
3611 input history is used instead.
3666 input history is used instead.
3612
3667
3613 Notes
3668 Notes
3614 -----
3669 -----
3615 Slices can be described with two notations:
3670 Slices can be described with two notations:
3616
3671
3617 * ``N:M`` -> standard python form, means including items N...(M-1).
3672 * ``N:M`` -> standard python form, means including items N...(M-1).
3618 * ``N-M`` -> include items N..M (closed endpoint).
3673 * ``N-M`` -> include items N..M (closed endpoint).
3619 """
3674 """
3620 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3675 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3621 text = "\n".join(x for _, _, x in lines)
3676 text = "\n".join(x for _, _, x in lines)
3622
3677
3623 # Skip the last line, as it's probably the magic that called this
3678 # Skip the last line, as it's probably the magic that called this
3624 if not range_str:
3679 if not range_str:
3625 if "\n" not in text:
3680 if "\n" not in text:
3626 text = ""
3681 text = ""
3627 else:
3682 else:
3628 text = text[: text.rfind("\n")]
3683 text = text[: text.rfind("\n")]
3629
3684
3630 return text
3685 return text
3631
3686
3632 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3687 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3633 """Get a code string from history, file, url, or a string or macro.
3688 """Get a code string from history, file, url, or a string or macro.
3634
3689
3635 This is mainly used by magic functions.
3690 This is mainly used by magic functions.
3636
3691
3637 Parameters
3692 Parameters
3638 ----------
3693 ----------
3639 target : str
3694 target : str
3640 A string specifying code to retrieve. This will be tried respectively
3695 A string specifying code to retrieve. This will be tried respectively
3641 as: ranges of input history (see %history for syntax), url,
3696 as: ranges of input history (see %history for syntax), url,
3642 corresponding .py file, filename, or an expression evaluating to a
3697 corresponding .py file, filename, or an expression evaluating to a
3643 string or Macro in the user namespace.
3698 string or Macro in the user namespace.
3644
3699
3645 If empty string is given, returns complete history of current
3700 If empty string is given, returns complete history of current
3646 session, without the last line.
3701 session, without the last line.
3647
3702
3648 raw : bool
3703 raw : bool
3649 If true (default), retrieve raw history. Has no effect on the other
3704 If true (default), retrieve raw history. Has no effect on the other
3650 retrieval mechanisms.
3705 retrieval mechanisms.
3651
3706
3652 py_only : bool (default False)
3707 py_only : bool (default False)
3653 Only try to fetch python code, do not try alternative methods to decode file
3708 Only try to fetch python code, do not try alternative methods to decode file
3654 if unicode fails.
3709 if unicode fails.
3655
3710
3656 Returns
3711 Returns
3657 -------
3712 -------
3658 A string of code.
3713 A string of code.
3659 ValueError is raised if nothing is found, and TypeError if it evaluates
3714 ValueError is raised if nothing is found, and TypeError if it evaluates
3660 to an object of another type. In each case, .args[0] is a printable
3715 to an object of another type. In each case, .args[0] is a printable
3661 message.
3716 message.
3662 """
3717 """
3663 code = self.extract_input_lines(target, raw=raw) # Grab history
3718 code = self.extract_input_lines(target, raw=raw) # Grab history
3664 if code:
3719 if code:
3665 return code
3720 return code
3666 try:
3721 try:
3667 if target.startswith(('http://', 'https://')):
3722 if target.startswith(('http://', 'https://')):
3668 return openpy.read_py_url(target, skip_encoding_cookie=skip_encoding_cookie)
3723 return openpy.read_py_url(target, skip_encoding_cookie=skip_encoding_cookie)
3669 except UnicodeDecodeError as e:
3724 except UnicodeDecodeError as e:
3670 if not py_only :
3725 if not py_only :
3671 # Deferred import
3726 # Deferred import
3672 from urllib.request import urlopen
3727 from urllib.request import urlopen
3673 response = urlopen(target)
3728 response = urlopen(target)
3674 return response.read().decode('latin1')
3729 return response.read().decode('latin1')
3675 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3730 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3676
3731
3677 potential_target = [target]
3732 potential_target = [target]
3678 try :
3733 try :
3679 potential_target.insert(0,get_py_filename(target))
3734 potential_target.insert(0,get_py_filename(target))
3680 except IOError:
3735 except IOError:
3681 pass
3736 pass
3682
3737
3683 for tgt in potential_target :
3738 for tgt in potential_target :
3684 if os.path.isfile(tgt): # Read file
3739 if os.path.isfile(tgt): # Read file
3685 try :
3740 try :
3686 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3741 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3687 except UnicodeDecodeError as e:
3742 except UnicodeDecodeError as e:
3688 if not py_only :
3743 if not py_only :
3689 with io_open(tgt,'r', encoding='latin1') as f :
3744 with io_open(tgt,'r', encoding='latin1') as f :
3690 return f.read()
3745 return f.read()
3691 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3746 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3692 elif os.path.isdir(os.path.expanduser(tgt)):
3747 elif os.path.isdir(os.path.expanduser(tgt)):
3693 raise ValueError("'%s' is a directory, not a regular file." % target)
3748 raise ValueError("'%s' is a directory, not a regular file." % target)
3694
3749
3695 if search_ns:
3750 if search_ns:
3696 # Inspect namespace to load object source
3751 # Inspect namespace to load object source
3697 object_info = self.object_inspect(target, detail_level=1)
3752 object_info = self.object_inspect(target, detail_level=1)
3698 if object_info['found'] and object_info['source']:
3753 if object_info['found'] and object_info['source']:
3699 return object_info['source']
3754 return object_info['source']
3700
3755
3701 try: # User namespace
3756 try: # User namespace
3702 codeobj = eval(target, self.user_ns)
3757 codeobj = eval(target, self.user_ns)
3703 except Exception as e:
3758 except Exception as e:
3704 raise ValueError(("'%s' was not found in history, as a file, url, "
3759 raise ValueError(("'%s' was not found in history, as a file, url, "
3705 "nor in the user namespace.") % target) from e
3760 "nor in the user namespace.") % target) from e
3706
3761
3707 if isinstance(codeobj, str):
3762 if isinstance(codeobj, str):
3708 return codeobj
3763 return codeobj
3709 elif isinstance(codeobj, Macro):
3764 elif isinstance(codeobj, Macro):
3710 return codeobj.value
3765 return codeobj.value
3711
3766
3712 raise TypeError("%s is neither a string nor a macro." % target,
3767 raise TypeError("%s is neither a string nor a macro." % target,
3713 codeobj)
3768 codeobj)
3714
3769
3715 def _atexit_once(self):
3770 def _atexit_once(self):
3716 """
3771 """
3717 At exist operation that need to be called at most once.
3772 At exist operation that need to be called at most once.
3718 Second call to this function per instance will do nothing.
3773 Second call to this function per instance will do nothing.
3719 """
3774 """
3720
3775
3721 if not getattr(self, "_atexit_once_called", False):
3776 if not getattr(self, "_atexit_once_called", False):
3722 self._atexit_once_called = True
3777 self._atexit_once_called = True
3723 # Clear all user namespaces to release all references cleanly.
3778 # Clear all user namespaces to release all references cleanly.
3724 self.reset(new_session=False)
3779 self.reset(new_session=False)
3725 # Close the history session (this stores the end time and line count)
3780 # Close the history session (this stores the end time and line count)
3726 # this must be *before* the tempfile cleanup, in case of temporary
3781 # this must be *before* the tempfile cleanup, in case of temporary
3727 # history db
3782 # history db
3728 self.history_manager.end_session()
3783 self.history_manager.end_session()
3729 self.history_manager = None
3784 self.history_manager = None
3730
3785
3731 #-------------------------------------------------------------------------
3786 #-------------------------------------------------------------------------
3732 # Things related to IPython exiting
3787 # Things related to IPython exiting
3733 #-------------------------------------------------------------------------
3788 #-------------------------------------------------------------------------
3734 def atexit_operations(self):
3789 def atexit_operations(self):
3735 """This will be executed at the time of exit.
3790 """This will be executed at the time of exit.
3736
3791
3737 Cleanup operations and saving of persistent data that is done
3792 Cleanup operations and saving of persistent data that is done
3738 unconditionally by IPython should be performed here.
3793 unconditionally by IPython should be performed here.
3739
3794
3740 For things that may depend on startup flags or platform specifics (such
3795 For things that may depend on startup flags or platform specifics (such
3741 as having readline or not), register a separate atexit function in the
3796 as having readline or not), register a separate atexit function in the
3742 code that has the appropriate information, rather than trying to
3797 code that has the appropriate information, rather than trying to
3743 clutter
3798 clutter
3744 """
3799 """
3745 self._atexit_once()
3800 self._atexit_once()
3746
3801
3747 # Cleanup all tempfiles and folders left around
3802 # Cleanup all tempfiles and folders left around
3748 for tfile in self.tempfiles:
3803 for tfile in self.tempfiles:
3749 try:
3804 try:
3750 tfile.unlink()
3805 tfile.unlink()
3751 self.tempfiles.remove(tfile)
3806 self.tempfiles.remove(tfile)
3752 except FileNotFoundError:
3807 except FileNotFoundError:
3753 pass
3808 pass
3754 del self.tempfiles
3809 del self.tempfiles
3755 for tdir in self.tempdirs:
3810 for tdir in self.tempdirs:
3756 try:
3811 try:
3757 tdir.rmdir()
3812 tdir.rmdir()
3758 self.tempdirs.remove(tdir)
3813 self.tempdirs.remove(tdir)
3759 except FileNotFoundError:
3814 except FileNotFoundError:
3760 pass
3815 pass
3761 del self.tempdirs
3816 del self.tempdirs
3762
3817
3763 # Restore user's cursor
3818 # Restore user's cursor
3764 if hasattr(self, "editing_mode") and self.editing_mode == "vi":
3819 if hasattr(self, "editing_mode") and self.editing_mode == "vi":
3765 sys.stdout.write("\x1b[0 q")
3820 sys.stdout.write("\x1b[0 q")
3766 sys.stdout.flush()
3821 sys.stdout.flush()
3767
3822
3768 def cleanup(self):
3823 def cleanup(self):
3769 self.restore_sys_module_state()
3824 self.restore_sys_module_state()
3770
3825
3771
3826
3772 # Overridden in terminal subclass to change prompts
3827 # Overridden in terminal subclass to change prompts
3773 def switch_doctest_mode(self, mode):
3828 def switch_doctest_mode(self, mode):
3774 pass
3829 pass
3775
3830
3776
3831
3777 class InteractiveShellABC(metaclass=abc.ABCMeta):
3832 class InteractiveShellABC(metaclass=abc.ABCMeta):
3778 """An abstract base class for InteractiveShell."""
3833 """An abstract base class for InteractiveShell."""
3779
3834
3780 InteractiveShellABC.register(InteractiveShell)
3835 InteractiveShellABC.register(InteractiveShell)
@@ -1,658 +1,661 b''
1 """Implementation of basic magic functions."""
1 """Implementation of basic magic functions."""
2
2
3
3
4 from logging import error
4 from logging import error
5 import io
5 import io
6 import os
6 import os
7 from pprint import pformat
7 from pprint import pformat
8 import sys
8 import sys
9 from warnings import warn
9 from warnings import warn
10
10
11 from traitlets.utils.importstring import import_item
11 from traitlets.utils.importstring import import_item
12 from IPython.core import magic_arguments, page
12 from IPython.core import magic_arguments, page
13 from IPython.core.error import UsageError
13 from IPython.core.error import UsageError
14 from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes
14 from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes
15 from IPython.utils.text import format_screen, dedent, indent
15 from IPython.utils.text import format_screen, dedent, indent
16 from IPython.testing.skipdoctest import skip_doctest
16 from IPython.testing.skipdoctest import skip_doctest
17 from IPython.utils.ipstruct import Struct
17 from IPython.utils.ipstruct import Struct
18
18
19
19
20 class MagicsDisplay(object):
20 class MagicsDisplay(object):
21 def __init__(self, magics_manager, ignore=None):
21 def __init__(self, magics_manager, ignore=None):
22 self.ignore = ignore if ignore else []
22 self.ignore = ignore if ignore else []
23 self.magics_manager = magics_manager
23 self.magics_manager = magics_manager
24
24
25 def _lsmagic(self):
25 def _lsmagic(self):
26 """The main implementation of the %lsmagic"""
26 """The main implementation of the %lsmagic"""
27 mesc = magic_escapes['line']
27 mesc = magic_escapes['line']
28 cesc = magic_escapes['cell']
28 cesc = magic_escapes['cell']
29 mman = self.magics_manager
29 mman = self.magics_manager
30 magics = mman.lsmagic()
30 magics = mman.lsmagic()
31 out = ['Available line magics:',
31 out = ['Available line magics:',
32 mesc + (' '+mesc).join(sorted([m for m,v in magics['line'].items() if (v not in self.ignore)])),
32 mesc + (' '+mesc).join(sorted([m for m,v in magics['line'].items() if (v not in self.ignore)])),
33 '',
33 '',
34 'Available cell magics:',
34 'Available cell magics:',
35 cesc + (' '+cesc).join(sorted([m for m,v in magics['cell'].items() if (v not in self.ignore)])),
35 cesc + (' '+cesc).join(sorted([m for m,v in magics['cell'].items() if (v not in self.ignore)])),
36 '',
36 '',
37 mman.auto_status()]
37 mman.auto_status()]
38 return '\n'.join(out)
38 return '\n'.join(out)
39
39
40 def _repr_pretty_(self, p, cycle):
40 def _repr_pretty_(self, p, cycle):
41 p.text(self._lsmagic())
41 p.text(self._lsmagic())
42
42
43 def __str__(self):
43 def __str__(self):
44 return self._lsmagic()
44 return self._lsmagic()
45
45
46 def _jsonable(self):
46 def _jsonable(self):
47 """turn magics dict into jsonable dict of the same structure
47 """turn magics dict into jsonable dict of the same structure
48
48
49 replaces object instances with their class names as strings
49 replaces object instances with their class names as strings
50 """
50 """
51 magic_dict = {}
51 magic_dict = {}
52 mman = self.magics_manager
52 mman = self.magics_manager
53 magics = mman.lsmagic()
53 magics = mman.lsmagic()
54 for key, subdict in magics.items():
54 for key, subdict in magics.items():
55 d = {}
55 d = {}
56 magic_dict[key] = d
56 magic_dict[key] = d
57 for name, obj in subdict.items():
57 for name, obj in subdict.items():
58 try:
58 try:
59 classname = obj.__self__.__class__.__name__
59 classname = obj.__self__.__class__.__name__
60 except AttributeError:
60 except AttributeError:
61 classname = 'Other'
61 classname = 'Other'
62
62
63 d[name] = classname
63 d[name] = classname
64 return magic_dict
64 return magic_dict
65
65
66 def _repr_json_(self):
66 def _repr_json_(self):
67 return self._jsonable()
67 return self._jsonable()
68
68
69
69
70 @magics_class
70 @magics_class
71 class BasicMagics(Magics):
71 class BasicMagics(Magics):
72 """Magics that provide central IPython functionality.
72 """Magics that provide central IPython functionality.
73
73
74 These are various magics that don't fit into specific categories but that
74 These are various magics that don't fit into specific categories but that
75 are all part of the base 'IPython experience'."""
75 are all part of the base 'IPython experience'."""
76
76
77 @skip_doctest
77 @skip_doctest
78 @magic_arguments.magic_arguments()
78 @magic_arguments.magic_arguments()
79 @magic_arguments.argument(
79 @magic_arguments.argument(
80 '-l', '--line', action='store_true',
80 '-l', '--line', action='store_true',
81 help="""Create a line magic alias."""
81 help="""Create a line magic alias."""
82 )
82 )
83 @magic_arguments.argument(
83 @magic_arguments.argument(
84 '-c', '--cell', action='store_true',
84 '-c', '--cell', action='store_true',
85 help="""Create a cell magic alias."""
85 help="""Create a cell magic alias."""
86 )
86 )
87 @magic_arguments.argument(
87 @magic_arguments.argument(
88 'name',
88 'name',
89 help="""Name of the magic to be created."""
89 help="""Name of the magic to be created."""
90 )
90 )
91 @magic_arguments.argument(
91 @magic_arguments.argument(
92 'target',
92 'target',
93 help="""Name of the existing line or cell magic."""
93 help="""Name of the existing line or cell magic."""
94 )
94 )
95 @magic_arguments.argument(
95 @magic_arguments.argument(
96 '-p', '--params', default=None,
96 '-p', '--params', default=None,
97 help="""Parameters passed to the magic function."""
97 help="""Parameters passed to the magic function."""
98 )
98 )
99 @line_magic
99 @line_magic
100 def alias_magic(self, line=''):
100 def alias_magic(self, line=''):
101 """Create an alias for an existing line or cell magic.
101 """Create an alias for an existing line or cell magic.
102
102
103 Examples
103 Examples
104 --------
104 --------
105 ::
105 ::
106
106
107 In [1]: %alias_magic t timeit
107 In [1]: %alias_magic t timeit
108 Created `%t` as an alias for `%timeit`.
108 Created `%t` as an alias for `%timeit`.
109 Created `%%t` as an alias for `%%timeit`.
109 Created `%%t` as an alias for `%%timeit`.
110
110
111 In [2]: %t -n1 pass
111 In [2]: %t -n1 pass
112 1 loops, best of 3: 954 ns per loop
112 1 loops, best of 3: 954 ns per loop
113
113
114 In [3]: %%t -n1
114 In [3]: %%t -n1
115 ...: pass
115 ...: pass
116 ...:
116 ...:
117 1 loops, best of 3: 954 ns per loop
117 1 loops, best of 3: 954 ns per loop
118
118
119 In [4]: %alias_magic --cell whereami pwd
119 In [4]: %alias_magic --cell whereami pwd
120 UsageError: Cell magic function `%%pwd` not found.
120 UsageError: Cell magic function `%%pwd` not found.
121 In [5]: %alias_magic --line whereami pwd
121 In [5]: %alias_magic --line whereami pwd
122 Created `%whereami` as an alias for `%pwd`.
122 Created `%whereami` as an alias for `%pwd`.
123
123
124 In [6]: %whereami
124 In [6]: %whereami
125 Out[6]: u'/home/testuser'
125 Out[6]: u'/home/testuser'
126
126
127 In [7]: %alias_magic h history "-p -l 30" --line
127 In [7]: %alias_magic h history "-p -l 30" --line
128 Created `%h` as an alias for `%history -l 30`.
128 Created `%h` as an alias for `%history -l 30`.
129 """
129 """
130
130
131 args = magic_arguments.parse_argstring(self.alias_magic, line)
131 args = magic_arguments.parse_argstring(self.alias_magic, line)
132 shell = self.shell
132 shell = self.shell
133 mman = self.shell.magics_manager
133 mman = self.shell.magics_manager
134 escs = ''.join(magic_escapes.values())
134 escs = ''.join(magic_escapes.values())
135
135
136 target = args.target.lstrip(escs)
136 target = args.target.lstrip(escs)
137 name = args.name.lstrip(escs)
137 name = args.name.lstrip(escs)
138
138
139 params = args.params
139 params = args.params
140 if (params and
140 if (params and
141 ((params.startswith('"') and params.endswith('"'))
141 ((params.startswith('"') and params.endswith('"'))
142 or (params.startswith("'") and params.endswith("'")))):
142 or (params.startswith("'") and params.endswith("'")))):
143 params = params[1:-1]
143 params = params[1:-1]
144
144
145 # Find the requested magics.
145 # Find the requested magics.
146 m_line = shell.find_magic(target, 'line')
146 m_line = shell.find_magic(target, 'line')
147 m_cell = shell.find_magic(target, 'cell')
147 m_cell = shell.find_magic(target, 'cell')
148 if args.line and m_line is None:
148 if args.line and m_line is None:
149 raise UsageError('Line magic function `%s%s` not found.' %
149 raise UsageError('Line magic function `%s%s` not found.' %
150 (magic_escapes['line'], target))
150 (magic_escapes['line'], target))
151 if args.cell and m_cell is None:
151 if args.cell and m_cell is None:
152 raise UsageError('Cell magic function `%s%s` not found.' %
152 raise UsageError('Cell magic function `%s%s` not found.' %
153 (magic_escapes['cell'], target))
153 (magic_escapes['cell'], target))
154
154
155 # If --line and --cell are not specified, default to the ones
155 # If --line and --cell are not specified, default to the ones
156 # that are available.
156 # that are available.
157 if not args.line and not args.cell:
157 if not args.line and not args.cell:
158 if not m_line and not m_cell:
158 if not m_line and not m_cell:
159 raise UsageError(
159 raise UsageError(
160 'No line or cell magic with name `%s` found.' % target
160 'No line or cell magic with name `%s` found.' % target
161 )
161 )
162 args.line = bool(m_line)
162 args.line = bool(m_line)
163 args.cell = bool(m_cell)
163 args.cell = bool(m_cell)
164
164
165 params_str = "" if params is None else " " + params
165 params_str = "" if params is None else " " + params
166
166
167 if args.line:
167 if args.line:
168 mman.register_alias(name, target, 'line', params)
168 mman.register_alias(name, target, 'line', params)
169 print('Created `%s%s` as an alias for `%s%s%s`.' % (
169 print('Created `%s%s` as an alias for `%s%s%s`.' % (
170 magic_escapes['line'], name,
170 magic_escapes['line'], name,
171 magic_escapes['line'], target, params_str))
171 magic_escapes['line'], target, params_str))
172
172
173 if args.cell:
173 if args.cell:
174 mman.register_alias(name, target, 'cell', params)
174 mman.register_alias(name, target, 'cell', params)
175 print('Created `%s%s` as an alias for `%s%s%s`.' % (
175 print('Created `%s%s` as an alias for `%s%s%s`.' % (
176 magic_escapes['cell'], name,
176 magic_escapes['cell'], name,
177 magic_escapes['cell'], target, params_str))
177 magic_escapes['cell'], target, params_str))
178
178
179 @line_magic
179 @line_magic
180 def lsmagic(self, parameter_s=''):
180 def lsmagic(self, parameter_s=''):
181 """List currently available magic functions."""
181 """List currently available magic functions."""
182 return MagicsDisplay(self.shell.magics_manager, ignore=[])
182 return MagicsDisplay(self.shell.magics_manager, ignore=[])
183
183
184 def _magic_docs(self, brief=False, rest=False):
184 def _magic_docs(self, brief=False, rest=False):
185 """Return docstrings from magic functions."""
185 """Return docstrings from magic functions."""
186 mman = self.shell.magics_manager
186 mman = self.shell.magics_manager
187 docs = mman.lsmagic_docs(brief, missing='No documentation')
187 docs = mman.lsmagic_docs(brief, missing='No documentation')
188
188
189 if rest:
189 if rest:
190 format_string = '**%s%s**::\n\n%s\n\n'
190 format_string = '**%s%s**::\n\n%s\n\n'
191 else:
191 else:
192 format_string = '%s%s:\n%s\n'
192 format_string = '%s%s:\n%s\n'
193
193
194 return ''.join(
194 return ''.join(
195 [format_string % (magic_escapes['line'], fname,
195 [format_string % (magic_escapes['line'], fname,
196 indent(dedent(fndoc)))
196 indent(dedent(fndoc)))
197 for fname, fndoc in sorted(docs['line'].items())]
197 for fname, fndoc in sorted(docs['line'].items())]
198 +
198 +
199 [format_string % (magic_escapes['cell'], fname,
199 [format_string % (magic_escapes['cell'], fname,
200 indent(dedent(fndoc)))
200 indent(dedent(fndoc)))
201 for fname, fndoc in sorted(docs['cell'].items())]
201 for fname, fndoc in sorted(docs['cell'].items())]
202 )
202 )
203
203
204 @line_magic
204 @line_magic
205 def magic(self, parameter_s=''):
205 def magic(self, parameter_s=''):
206 """Print information about the magic function system.
206 """Print information about the magic function system.
207
207
208 Supported formats: -latex, -brief, -rest
208 Supported formats: -latex, -brief, -rest
209 """
209 """
210
210
211 mode = ''
211 mode = ''
212 try:
212 try:
213 mode = parameter_s.split()[0][1:]
213 mode = parameter_s.split()[0][1:]
214 except IndexError:
214 except IndexError:
215 pass
215 pass
216
216
217 brief = (mode == 'brief')
217 brief = (mode == 'brief')
218 rest = (mode == 'rest')
218 rest = (mode == 'rest')
219 magic_docs = self._magic_docs(brief, rest)
219 magic_docs = self._magic_docs(brief, rest)
220
220
221 if mode == 'latex':
221 if mode == 'latex':
222 print(self.format_latex(magic_docs))
222 print(self.format_latex(magic_docs))
223 return
223 return
224 else:
224 else:
225 magic_docs = format_screen(magic_docs)
225 magic_docs = format_screen(magic_docs)
226
226
227 out = ["""
227 out = ["""
228 IPython's 'magic' functions
228 IPython's 'magic' functions
229 ===========================
229 ===========================
230
230
231 The magic function system provides a series of functions which allow you to
231 The magic function system provides a series of functions which allow you to
232 control the behavior of IPython itself, plus a lot of system-type
232 control the behavior of IPython itself, plus a lot of system-type
233 features. There are two kinds of magics, line-oriented and cell-oriented.
233 features. There are two kinds of magics, line-oriented and cell-oriented.
234
234
235 Line magics are prefixed with the % character and work much like OS
235 Line magics are prefixed with the % character and work much like OS
236 command-line calls: they get as an argument the rest of the line, where
236 command-line calls: they get as an argument the rest of the line, where
237 arguments are passed without parentheses or quotes. For example, this will
237 arguments are passed without parentheses or quotes. For example, this will
238 time the given statement::
238 time the given statement::
239
239
240 %timeit range(1000)
240 %timeit range(1000)
241
241
242 Cell magics are prefixed with a double %%, and they are functions that get as
242 Cell magics are prefixed with a double %%, and they are functions that get as
243 an argument not only the rest of the line, but also the lines below it in a
243 an argument not only the rest of the line, but also the lines below it in a
244 separate argument. These magics are called with two arguments: the rest of the
244 separate argument. These magics are called with two arguments: the rest of the
245 call line and the body of the cell, consisting of the lines below the first.
245 call line and the body of the cell, consisting of the lines below the first.
246 For example::
246 For example::
247
247
248 %%timeit x = numpy.random.randn((100, 100))
248 %%timeit x = numpy.random.randn((100, 100))
249 numpy.linalg.svd(x)
249 numpy.linalg.svd(x)
250
250
251 will time the execution of the numpy svd routine, running the assignment of x
251 will time the execution of the numpy svd routine, running the assignment of x
252 as part of the setup phase, which is not timed.
252 as part of the setup phase, which is not timed.
253
253
254 In a line-oriented client (the terminal or Qt console IPython), starting a new
254 In a line-oriented client (the terminal or Qt console IPython), starting a new
255 input with %% will automatically enter cell mode, and IPython will continue
255 input with %% will automatically enter cell mode, and IPython will continue
256 reading input until a blank line is given. In the notebook, simply type the
256 reading input until a blank line is given. In the notebook, simply type the
257 whole cell as one entity, but keep in mind that the %% escape can only be at
257 whole cell as one entity, but keep in mind that the %% escape can only be at
258 the very start of the cell.
258 the very start of the cell.
259
259
260 NOTE: If you have 'automagic' enabled (via the command line option or with the
260 NOTE: If you have 'automagic' enabled (via the command line option or with the
261 %automagic function), you don't need to type in the % explicitly for line
261 %automagic function), you don't need to type in the % explicitly for line
262 magics; cell magics always require an explicit '%%' escape. By default,
262 magics; cell magics always require an explicit '%%' escape. By default,
263 IPython ships with automagic on, so you should only rarely need the % escape.
263 IPython ships with automagic on, so you should only rarely need the % escape.
264
264
265 Example: typing '%cd mydir' (without the quotes) changes your working directory
265 Example: typing '%cd mydir' (without the quotes) changes your working directory
266 to 'mydir', if it exists.
266 to 'mydir', if it exists.
267
267
268 For a list of the available magic functions, use %lsmagic. For a description
268 For a list of the available magic functions, use %lsmagic. For a description
269 of any of them, type %magic_name?, e.g. '%cd?'.
269 of any of them, type %magic_name?, e.g. '%cd?'.
270
270
271 Currently the magic system has the following functions:""",
271 Currently the magic system has the following functions:""",
272 magic_docs,
272 magic_docs,
273 "Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
273 "Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
274 str(self.lsmagic()),
274 str(self.lsmagic()),
275 ]
275 ]
276 page.page('\n'.join(out))
276 page.page('\n'.join(out))
277
277
278
278
279 @line_magic
279 @line_magic
280 def page(self, parameter_s=''):
280 def page(self, parameter_s=''):
281 """Pretty print the object and display it through a pager.
281 """Pretty print the object and display it through a pager.
282
282
283 %page [options] OBJECT
283 %page [options] OBJECT
284
284
285 If no object is given, use _ (last output).
285 If no object is given, use _ (last output).
286
286
287 Options:
287 Options:
288
288
289 -r: page str(object), don't pretty-print it."""
289 -r: page str(object), don't pretty-print it."""
290
290
291 # After a function contributed by Olivier Aubert, slightly modified.
291 # After a function contributed by Olivier Aubert, slightly modified.
292
292
293 # Process options/args
293 # Process options/args
294 opts, args = self.parse_options(parameter_s, 'r')
294 opts, args = self.parse_options(parameter_s, 'r')
295 raw = 'r' in opts
295 raw = 'r' in opts
296
296
297 oname = args and args or '_'
297 oname = args and args or '_'
298 info = self.shell._ofind(oname)
298 info = self.shell._ofind(oname)
299 if info['found']:
299 if info['found']:
300 txt = (raw and str or pformat)( info['obj'] )
300 if raw:
301 txt = str(info["obj"])
302 else:
303 txt = pformat(info["obj"])
301 page.page(txt)
304 page.page(txt)
302 else:
305 else:
303 print('Object `%s` not found' % oname)
306 print('Object `%s` not found' % oname)
304
307
305 @line_magic
308 @line_magic
306 def pprint(self, parameter_s=''):
309 def pprint(self, parameter_s=''):
307 """Toggle pretty printing on/off."""
310 """Toggle pretty printing on/off."""
308 ptformatter = self.shell.display_formatter.formatters['text/plain']
311 ptformatter = self.shell.display_formatter.formatters['text/plain']
309 ptformatter.pprint = bool(1 - ptformatter.pprint)
312 ptformatter.pprint = bool(1 - ptformatter.pprint)
310 print('Pretty printing has been turned',
313 print('Pretty printing has been turned',
311 ['OFF','ON'][ptformatter.pprint])
314 ['OFF','ON'][ptformatter.pprint])
312
315
313 @line_magic
316 @line_magic
314 def colors(self, parameter_s=''):
317 def colors(self, parameter_s=''):
315 """Switch color scheme for prompts, info system and exception handlers.
318 """Switch color scheme for prompts, info system and exception handlers.
316
319
317 Currently implemented schemes: NoColor, Linux, LightBG.
320 Currently implemented schemes: NoColor, Linux, LightBG.
318
321
319 Color scheme names are not case-sensitive.
322 Color scheme names are not case-sensitive.
320
323
321 Examples
324 Examples
322 --------
325 --------
323 To get a plain black and white terminal::
326 To get a plain black and white terminal::
324
327
325 %colors nocolor
328 %colors nocolor
326 """
329 """
327 def color_switch_err(name):
330 def color_switch_err(name):
328 warn('Error changing %s color schemes.\n%s' %
331 warn('Error changing %s color schemes.\n%s' %
329 (name, sys.exc_info()[1]), stacklevel=2)
332 (name, sys.exc_info()[1]), stacklevel=2)
330
333
331
334
332 new_scheme = parameter_s.strip()
335 new_scheme = parameter_s.strip()
333 if not new_scheme:
336 if not new_scheme:
334 raise UsageError(
337 raise UsageError(
335 "%colors: you must specify a color scheme. See '%colors?'")
338 "%colors: you must specify a color scheme. See '%colors?'")
336 # local shortcut
339 # local shortcut
337 shell = self.shell
340 shell = self.shell
338
341
339 # Set shell colour scheme
342 # Set shell colour scheme
340 try:
343 try:
341 shell.colors = new_scheme
344 shell.colors = new_scheme
342 shell.refresh_style()
345 shell.refresh_style()
343 except:
346 except:
344 color_switch_err('shell')
347 color_switch_err('shell')
345
348
346 # Set exception colors
349 # Set exception colors
347 try:
350 try:
348 shell.InteractiveTB.set_colors(scheme = new_scheme)
351 shell.InteractiveTB.set_colors(scheme = new_scheme)
349 shell.SyntaxTB.set_colors(scheme = new_scheme)
352 shell.SyntaxTB.set_colors(scheme = new_scheme)
350 except:
353 except:
351 color_switch_err('exception')
354 color_switch_err('exception')
352
355
353 # Set info (for 'object?') colors
356 # Set info (for 'object?') colors
354 if shell.color_info:
357 if shell.color_info:
355 try:
358 try:
356 shell.inspector.set_active_scheme(new_scheme)
359 shell.inspector.set_active_scheme(new_scheme)
357 except:
360 except:
358 color_switch_err('object inspector')
361 color_switch_err('object inspector')
359 else:
362 else:
360 shell.inspector.set_active_scheme('NoColor')
363 shell.inspector.set_active_scheme('NoColor')
361
364
362 @line_magic
365 @line_magic
363 def xmode(self, parameter_s=''):
366 def xmode(self, parameter_s=''):
364 """Switch modes for the exception handlers.
367 """Switch modes for the exception handlers.
365
368
366 Valid modes: Plain, Context, Verbose, and Minimal.
369 Valid modes: Plain, Context, Verbose, and Minimal.
367
370
368 If called without arguments, acts as a toggle.
371 If called without arguments, acts as a toggle.
369
372
370 When in verbose mode the value `--show` (and `--hide`)
373 When in verbose mode the value `--show` (and `--hide`)
371 will respectively show (or hide) frames with ``__tracebackhide__ =
374 will respectively show (or hide) frames with ``__tracebackhide__ =
372 True`` value set.
375 True`` value set.
373 """
376 """
374
377
375 def xmode_switch_err(name):
378 def xmode_switch_err(name):
376 warn('Error changing %s exception modes.\n%s' %
379 warn('Error changing %s exception modes.\n%s' %
377 (name,sys.exc_info()[1]))
380 (name,sys.exc_info()[1]))
378
381
379 shell = self.shell
382 shell = self.shell
380 if parameter_s.strip() == "--show":
383 if parameter_s.strip() == "--show":
381 shell.InteractiveTB.skip_hidden = False
384 shell.InteractiveTB.skip_hidden = False
382 return
385 return
383 if parameter_s.strip() == "--hide":
386 if parameter_s.strip() == "--hide":
384 shell.InteractiveTB.skip_hidden = True
387 shell.InteractiveTB.skip_hidden = True
385 return
388 return
386
389
387 new_mode = parameter_s.strip().capitalize()
390 new_mode = parameter_s.strip().capitalize()
388 try:
391 try:
389 shell.InteractiveTB.set_mode(mode=new_mode)
392 shell.InteractiveTB.set_mode(mode=new_mode)
390 print('Exception reporting mode:',shell.InteractiveTB.mode)
393 print('Exception reporting mode:',shell.InteractiveTB.mode)
391 except:
394 except:
392 xmode_switch_err('user')
395 xmode_switch_err('user')
393
396
394 @line_magic
397 @line_magic
395 def quickref(self, arg):
398 def quickref(self, arg):
396 """ Show a quick reference sheet """
399 """ Show a quick reference sheet """
397 from IPython.core.usage import quick_reference
400 from IPython.core.usage import quick_reference
398 qr = quick_reference + self._magic_docs(brief=True)
401 qr = quick_reference + self._magic_docs(brief=True)
399 page.page(qr)
402 page.page(qr)
400
403
401 @line_magic
404 @line_magic
402 def doctest_mode(self, parameter_s=''):
405 def doctest_mode(self, parameter_s=''):
403 """Toggle doctest mode on and off.
406 """Toggle doctest mode on and off.
404
407
405 This mode is intended to make IPython behave as much as possible like a
408 This mode is intended to make IPython behave as much as possible like a
406 plain Python shell, from the perspective of how its prompts, exceptions
409 plain Python shell, from the perspective of how its prompts, exceptions
407 and output look. This makes it easy to copy and paste parts of a
410 and output look. This makes it easy to copy and paste parts of a
408 session into doctests. It does so by:
411 session into doctests. It does so by:
409
412
410 - Changing the prompts to the classic ``>>>`` ones.
413 - Changing the prompts to the classic ``>>>`` ones.
411 - Changing the exception reporting mode to 'Plain'.
414 - Changing the exception reporting mode to 'Plain'.
412 - Disabling pretty-printing of output.
415 - Disabling pretty-printing of output.
413
416
414 Note that IPython also supports the pasting of code snippets that have
417 Note that IPython also supports the pasting of code snippets that have
415 leading '>>>' and '...' prompts in them. This means that you can paste
418 leading '>>>' and '...' prompts in them. This means that you can paste
416 doctests from files or docstrings (even if they have leading
419 doctests from files or docstrings (even if they have leading
417 whitespace), and the code will execute correctly. You can then use
420 whitespace), and the code will execute correctly. You can then use
418 '%history -t' to see the translated history; this will give you the
421 '%history -t' to see the translated history; this will give you the
419 input after removal of all the leading prompts and whitespace, which
422 input after removal of all the leading prompts and whitespace, which
420 can be pasted back into an editor.
423 can be pasted back into an editor.
421
424
422 With these features, you can switch into this mode easily whenever you
425 With these features, you can switch into this mode easily whenever you
423 need to do testing and changes to doctests, without having to leave
426 need to do testing and changes to doctests, without having to leave
424 your existing IPython session.
427 your existing IPython session.
425 """
428 """
426
429
427 # Shorthands
430 # Shorthands
428 shell = self.shell
431 shell = self.shell
429 meta = shell.meta
432 meta = shell.meta
430 disp_formatter = self.shell.display_formatter
433 disp_formatter = self.shell.display_formatter
431 ptformatter = disp_formatter.formatters['text/plain']
434 ptformatter = disp_formatter.formatters['text/plain']
432 # dstore is a data store kept in the instance metadata bag to track any
435 # dstore is a data store kept in the instance metadata bag to track any
433 # changes we make, so we can undo them later.
436 # changes we make, so we can undo them later.
434 dstore = meta.setdefault('doctest_mode',Struct())
437 dstore = meta.setdefault('doctest_mode',Struct())
435 save_dstore = dstore.setdefault
438 save_dstore = dstore.setdefault
436
439
437 # save a few values we'll need to recover later
440 # save a few values we'll need to recover later
438 mode = save_dstore('mode',False)
441 mode = save_dstore('mode',False)
439 save_dstore('rc_pprint',ptformatter.pprint)
442 save_dstore('rc_pprint',ptformatter.pprint)
440 save_dstore('xmode',shell.InteractiveTB.mode)
443 save_dstore('xmode',shell.InteractiveTB.mode)
441 save_dstore('rc_separate_out',shell.separate_out)
444 save_dstore('rc_separate_out',shell.separate_out)
442 save_dstore('rc_separate_out2',shell.separate_out2)
445 save_dstore('rc_separate_out2',shell.separate_out2)
443 save_dstore('rc_separate_in',shell.separate_in)
446 save_dstore('rc_separate_in',shell.separate_in)
444 save_dstore('rc_active_types',disp_formatter.active_types)
447 save_dstore('rc_active_types',disp_formatter.active_types)
445
448
446 if not mode:
449 if not mode:
447 # turn on
450 # turn on
448
451
449 # Prompt separators like plain python
452 # Prompt separators like plain python
450 shell.separate_in = ''
453 shell.separate_in = ''
451 shell.separate_out = ''
454 shell.separate_out = ''
452 shell.separate_out2 = ''
455 shell.separate_out2 = ''
453
456
454
457
455 ptformatter.pprint = False
458 ptformatter.pprint = False
456 disp_formatter.active_types = ['text/plain']
459 disp_formatter.active_types = ['text/plain']
457
460
458 shell.magic('xmode Plain')
461 shell.magic('xmode Plain')
459 else:
462 else:
460 # turn off
463 # turn off
461 shell.separate_in = dstore.rc_separate_in
464 shell.separate_in = dstore.rc_separate_in
462
465
463 shell.separate_out = dstore.rc_separate_out
466 shell.separate_out = dstore.rc_separate_out
464 shell.separate_out2 = dstore.rc_separate_out2
467 shell.separate_out2 = dstore.rc_separate_out2
465
468
466 ptformatter.pprint = dstore.rc_pprint
469 ptformatter.pprint = dstore.rc_pprint
467 disp_formatter.active_types = dstore.rc_active_types
470 disp_formatter.active_types = dstore.rc_active_types
468
471
469 shell.magic('xmode ' + dstore.xmode)
472 shell.magic('xmode ' + dstore.xmode)
470
473
471 # mode here is the state before we switch; switch_doctest_mode takes
474 # mode here is the state before we switch; switch_doctest_mode takes
472 # the mode we're switching to.
475 # the mode we're switching to.
473 shell.switch_doctest_mode(not mode)
476 shell.switch_doctest_mode(not mode)
474
477
475 # Store new mode and inform
478 # Store new mode and inform
476 dstore.mode = bool(not mode)
479 dstore.mode = bool(not mode)
477 mode_label = ['OFF','ON'][dstore.mode]
480 mode_label = ['OFF','ON'][dstore.mode]
478 print('Doctest mode is:', mode_label)
481 print('Doctest mode is:', mode_label)
479
482
480 @line_magic
483 @line_magic
481 def gui(self, parameter_s=''):
484 def gui(self, parameter_s=''):
482 """Enable or disable IPython GUI event loop integration.
485 """Enable or disable IPython GUI event loop integration.
483
486
484 %gui [GUINAME]
487 %gui [GUINAME]
485
488
486 This magic replaces IPython's threaded shells that were activated
489 This magic replaces IPython's threaded shells that were activated
487 using the (pylab/wthread/etc.) command line flags. GUI toolkits
490 using the (pylab/wthread/etc.) command line flags. GUI toolkits
488 can now be enabled at runtime and keyboard
491 can now be enabled at runtime and keyboard
489 interrupts should work without any problems. The following toolkits
492 interrupts should work without any problems. The following toolkits
490 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
493 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
491
494
492 %gui wx # enable wxPython event loop integration
495 %gui wx # enable wxPython event loop integration
493 %gui qt4|qt # enable PyQt4 event loop integration
496 %gui qt4|qt # enable PyQt4 event loop integration
494 %gui qt5 # enable PyQt5 event loop integration
497 %gui qt5 # enable PyQt5 event loop integration
495 %gui gtk # enable PyGTK event loop integration
498 %gui gtk # enable PyGTK event loop integration
496 %gui gtk3 # enable Gtk3 event loop integration
499 %gui gtk3 # enable Gtk3 event loop integration
497 %gui gtk4 # enable Gtk4 event loop integration
500 %gui gtk4 # enable Gtk4 event loop integration
498 %gui tk # enable Tk event loop integration
501 %gui tk # enable Tk event loop integration
499 %gui osx # enable Cocoa event loop integration
502 %gui osx # enable Cocoa event loop integration
500 # (requires %matplotlib 1.1)
503 # (requires %matplotlib 1.1)
501 %gui # disable all event loop integration
504 %gui # disable all event loop integration
502
505
503 WARNING: after any of these has been called you can simply create
506 WARNING: after any of these has been called you can simply create
504 an application object, but DO NOT start the event loop yourself, as
507 an application object, but DO NOT start the event loop yourself, as
505 we have already handled that.
508 we have already handled that.
506 """
509 """
507 opts, arg = self.parse_options(parameter_s, '')
510 opts, arg = self.parse_options(parameter_s, '')
508 if arg=='': arg = None
511 if arg=='': arg = None
509 try:
512 try:
510 return self.shell.enable_gui(arg)
513 return self.shell.enable_gui(arg)
511 except Exception as e:
514 except Exception as e:
512 # print simple error message, rather than traceback if we can't
515 # print simple error message, rather than traceback if we can't
513 # hook up the GUI
516 # hook up the GUI
514 error(str(e))
517 error(str(e))
515
518
516 @skip_doctest
519 @skip_doctest
517 @line_magic
520 @line_magic
518 def precision(self, s=''):
521 def precision(self, s=''):
519 """Set floating point precision for pretty printing.
522 """Set floating point precision for pretty printing.
520
523
521 Can set either integer precision or a format string.
524 Can set either integer precision or a format string.
522
525
523 If numpy has been imported and precision is an int,
526 If numpy has been imported and precision is an int,
524 numpy display precision will also be set, via ``numpy.set_printoptions``.
527 numpy display precision will also be set, via ``numpy.set_printoptions``.
525
528
526 If no argument is given, defaults will be restored.
529 If no argument is given, defaults will be restored.
527
530
528 Examples
531 Examples
529 --------
532 --------
530 ::
533 ::
531
534
532 In [1]: from math import pi
535 In [1]: from math import pi
533
536
534 In [2]: %precision 3
537 In [2]: %precision 3
535 Out[2]: u'%.3f'
538 Out[2]: u'%.3f'
536
539
537 In [3]: pi
540 In [3]: pi
538 Out[3]: 3.142
541 Out[3]: 3.142
539
542
540 In [4]: %precision %i
543 In [4]: %precision %i
541 Out[4]: u'%i'
544 Out[4]: u'%i'
542
545
543 In [5]: pi
546 In [5]: pi
544 Out[5]: 3
547 Out[5]: 3
545
548
546 In [6]: %precision %e
549 In [6]: %precision %e
547 Out[6]: u'%e'
550 Out[6]: u'%e'
548
551
549 In [7]: pi**10
552 In [7]: pi**10
550 Out[7]: 9.364805e+04
553 Out[7]: 9.364805e+04
551
554
552 In [8]: %precision
555 In [8]: %precision
553 Out[8]: u'%r'
556 Out[8]: u'%r'
554
557
555 In [9]: pi**10
558 In [9]: pi**10
556 Out[9]: 93648.047476082982
559 Out[9]: 93648.047476082982
557 """
560 """
558 ptformatter = self.shell.display_formatter.formatters['text/plain']
561 ptformatter = self.shell.display_formatter.formatters['text/plain']
559 ptformatter.float_precision = s
562 ptformatter.float_precision = s
560 return ptformatter.float_format
563 return ptformatter.float_format
561
564
562 @magic_arguments.magic_arguments()
565 @magic_arguments.magic_arguments()
563 @magic_arguments.argument(
566 @magic_arguments.argument(
564 'filename', type=str,
567 'filename', type=str,
565 help='Notebook name or filename'
568 help='Notebook name or filename'
566 )
569 )
567 @line_magic
570 @line_magic
568 def notebook(self, s):
571 def notebook(self, s):
569 """Export and convert IPython notebooks.
572 """Export and convert IPython notebooks.
570
573
571 This function can export the current IPython history to a notebook file.
574 This function can export the current IPython history to a notebook file.
572 For example, to export the history to "foo.ipynb" do "%notebook foo.ipynb".
575 For example, to export the history to "foo.ipynb" do "%notebook foo.ipynb".
573 """
576 """
574 args = magic_arguments.parse_argstring(self.notebook, s)
577 args = magic_arguments.parse_argstring(self.notebook, s)
575 outfname = os.path.expanduser(args.filename)
578 outfname = os.path.expanduser(args.filename)
576
579
577 from nbformat import write, v4
580 from nbformat import write, v4
578
581
579 cells = []
582 cells = []
580 hist = list(self.shell.history_manager.get_range())
583 hist = list(self.shell.history_manager.get_range())
581 if(len(hist)<=1):
584 if(len(hist)<=1):
582 raise ValueError('History is empty, cannot export')
585 raise ValueError('History is empty, cannot export')
583 for session, execution_count, source in hist[:-1]:
586 for session, execution_count, source in hist[:-1]:
584 cells.append(v4.new_code_cell(
587 cells.append(v4.new_code_cell(
585 execution_count=execution_count,
588 execution_count=execution_count,
586 source=source
589 source=source
587 ))
590 ))
588 nb = v4.new_notebook(cells=cells)
591 nb = v4.new_notebook(cells=cells)
589 with io.open(outfname, "w", encoding="utf-8") as f:
592 with io.open(outfname, "w", encoding="utf-8") as f:
590 write(nb, f, version=4)
593 write(nb, f, version=4)
591
594
592 @magics_class
595 @magics_class
593 class AsyncMagics(BasicMagics):
596 class AsyncMagics(BasicMagics):
594
597
595 @line_magic
598 @line_magic
596 def autoawait(self, parameter_s):
599 def autoawait(self, parameter_s):
597 """
600 """
598 Allow to change the status of the autoawait option.
601 Allow to change the status of the autoawait option.
599
602
600 This allow you to set a specific asynchronous code runner.
603 This allow you to set a specific asynchronous code runner.
601
604
602 If no value is passed, print the currently used asynchronous integration
605 If no value is passed, print the currently used asynchronous integration
603 and whether it is activated.
606 and whether it is activated.
604
607
605 It can take a number of value evaluated in the following order:
608 It can take a number of value evaluated in the following order:
606
609
607 - False/false/off deactivate autoawait integration
610 - False/false/off deactivate autoawait integration
608 - True/true/on activate autoawait integration using configured default
611 - True/true/on activate autoawait integration using configured default
609 loop
612 loop
610 - asyncio/curio/trio activate autoawait integration and use integration
613 - asyncio/curio/trio activate autoawait integration and use integration
611 with said library.
614 with said library.
612
615
613 - `sync` turn on the pseudo-sync integration (mostly used for
616 - `sync` turn on the pseudo-sync integration (mostly used for
614 `IPython.embed()` which does not run IPython with a real eventloop and
617 `IPython.embed()` which does not run IPython with a real eventloop and
615 deactivate running asynchronous code. Turning on Asynchronous code with
618 deactivate running asynchronous code. Turning on Asynchronous code with
616 the pseudo sync loop is undefined behavior and may lead IPython to crash.
619 the pseudo sync loop is undefined behavior and may lead IPython to crash.
617
620
618 If the passed parameter does not match any of the above and is a python
621 If the passed parameter does not match any of the above and is a python
619 identifier, get said object from user namespace and set it as the
622 identifier, get said object from user namespace and set it as the
620 runner, and activate autoawait.
623 runner, and activate autoawait.
621
624
622 If the object is a fully qualified object name, attempt to import it and
625 If the object is a fully qualified object name, attempt to import it and
623 set it as the runner, and activate autoawait.
626 set it as the runner, and activate autoawait.
624
627
625 The exact behavior of autoawait is experimental and subject to change
628 The exact behavior of autoawait is experimental and subject to change
626 across version of IPython and Python.
629 across version of IPython and Python.
627 """
630 """
628
631
629 param = parameter_s.strip()
632 param = parameter_s.strip()
630 d = {True: "on", False: "off"}
633 d = {True: "on", False: "off"}
631
634
632 if not param:
635 if not param:
633 print("IPython autoawait is `{}`, and set to use `{}`".format(
636 print("IPython autoawait is `{}`, and set to use `{}`".format(
634 d[self.shell.autoawait],
637 d[self.shell.autoawait],
635 self.shell.loop_runner
638 self.shell.loop_runner
636 ))
639 ))
637 return None
640 return None
638
641
639 if param.lower() in ('false', 'off'):
642 if param.lower() in ('false', 'off'):
640 self.shell.autoawait = False
643 self.shell.autoawait = False
641 return None
644 return None
642 if param.lower() in ('true', 'on'):
645 if param.lower() in ('true', 'on'):
643 self.shell.autoawait = True
646 self.shell.autoawait = True
644 return None
647 return None
645
648
646 if param in self.shell.loop_runner_map:
649 if param in self.shell.loop_runner_map:
647 self.shell.loop_runner, self.shell.autoawait = self.shell.loop_runner_map[param]
650 self.shell.loop_runner, self.shell.autoawait = self.shell.loop_runner_map[param]
648 return None
651 return None
649
652
650 if param in self.shell.user_ns :
653 if param in self.shell.user_ns :
651 self.shell.loop_runner = self.shell.user_ns[param]
654 self.shell.loop_runner = self.shell.user_ns[param]
652 self.shell.autoawait = True
655 self.shell.autoawait = True
653 return None
656 return None
654
657
655 runner = import_item(param)
658 runner = import_item(param)
656
659
657 self.shell.loop_runner = runner
660 self.shell.loop_runner = runner
658 self.shell.autoawait = True
661 self.shell.autoawait = True
@@ -1,187 +1,210 b''
1 """Implementation of configuration-related magic functions.
1 """Implementation of configuration-related magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import re
16 import re
17
17
18 # Our own packages
18 # Our own packages
19 from IPython.core.error import UsageError
19 from IPython.core.error import UsageError
20 from IPython.core.magic import Magics, magics_class, line_magic
20 from IPython.core.magic import Magics, magics_class, line_magic
21 from logging import error
21 from logging import error
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Magic implementation classes
24 # Magic implementation classes
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 reg = re.compile(r'^\w+\.\w+$')
27 reg = re.compile(r'^\w+\.\w+$')
28 @magics_class
28 @magics_class
29 class ConfigMagics(Magics):
29 class ConfigMagics(Magics):
30
30
31 def __init__(self, shell):
31 def __init__(self, shell):
32 super(ConfigMagics, self).__init__(shell)
32 super(ConfigMagics, self).__init__(shell)
33 self.configurables = []
33 self.configurables = []
34
34
35 @line_magic
35 @line_magic
36 def config(self, s):
36 def config(self, s):
37 """configure IPython
37 """configure IPython
38
38
39 %config Class[.trait=value]
39 %config Class[.trait=value]
40
40
41 This magic exposes most of the IPython config system. Any
41 This magic exposes most of the IPython config system. Any
42 Configurable class should be able to be configured with the simple
42 Configurable class should be able to be configured with the simple
43 line::
43 line::
44
44
45 %config Class.trait=value
45 %config Class.trait=value
46
46
47 Where `value` will be resolved in the user's namespace, if it is an
47 Where `value` will be resolved in the user's namespace, if it is an
48 expression or variable name.
48 expression or variable name.
49
49
50 Examples
50 Examples
51 --------
51 --------
52
52
53 To see what classes are available for config, pass no arguments::
53 To see what classes are available for config, pass no arguments::
54
54
55 In [1]: %config
55 In [1]: %config
56 Available objects for config:
56 Available objects for config:
57 AliasManager
57 AliasManager
58 DisplayFormatter
58 DisplayFormatter
59 HistoryManager
59 HistoryManager
60 IPCompleter
60 IPCompleter
61 LoggingMagics
61 LoggingMagics
62 MagicsManager
62 MagicsManager
63 OSMagics
63 OSMagics
64 PrefilterManager
64 PrefilterManager
65 ScriptMagics
65 ScriptMagics
66 TerminalInteractiveShell
66 TerminalInteractiveShell
67
67
68 To view what is configurable on a given class, just pass the class
68 To view what is configurable on a given class, just pass the class
69 name::
69 name::
70
70
71 In [2]: %config IPCompleter
71 In [2]: %config IPCompleter
72 IPCompleter(Completer) options
72 IPCompleter(Completer) options
73 ----------------------------
73 ----------------------------
74 IPCompleter.backslash_combining_completions=<Bool>
74 IPCompleter.backslash_combining_completions=<Bool>
75 Enable unicode completions, e.g. \\alpha<tab> . Includes completion of latex
75 Enable unicode completions, e.g. \\alpha<tab> . Includes completion of latex
76 commands, unicode names, and expanding unicode characters back to latex
76 commands, unicode names, and expanding unicode characters back to latex
77 commands.
77 commands.
78 Current: True
78 Current: True
79 IPCompleter.debug=<Bool>
79 IPCompleter.debug=<Bool>
80 Enable debug for the Completer. Mostly print extra information for
80 Enable debug for the Completer. Mostly print extra information for
81 experimental jedi integration.
81 experimental jedi integration.
82 Current: False
82 Current: False
83 IPCompleter.disable_matchers=<list-item-1>...
84 List of matchers to disable.
85 Current: []
83 IPCompleter.greedy=<Bool>
86 IPCompleter.greedy=<Bool>
84 Activate greedy completion
87 Activate greedy completion
85 PENDING DEPRECATION. this is now mostly taken care of with Jedi.
88 PENDING DEPRECATION. this is now mostly taken care of with Jedi.
86 This will enable completion on elements of lists, results of function calls, etc.,
89 This will enable completion on elements of lists, results of function calls, etc.,
87 but can be unsafe because the code is actually evaluated on TAB.
90 but can be unsafe because the code is actually evaluated on TAB.
88 Current: False
91 Current: False
89 IPCompleter.jedi_compute_type_timeout=<Int>
92 IPCompleter.jedi_compute_type_timeout=<Int>
90 Experimental: restrict time (in milliseconds) during which Jedi can compute types.
93 Experimental: restrict time (in milliseconds) during which Jedi can compute types.
91 Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt
94 Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt
92 performance by preventing jedi to build its cache.
95 performance by preventing jedi to build its cache.
93 Current: 400
96 Current: 400
94 IPCompleter.limit_to__all__=<Bool>
97 IPCompleter.limit_to__all__=<Bool>
95 DEPRECATED as of version 5.0.
98 DEPRECATED as of version 5.0.
96 Instruct the completer to use __all__ for the completion
99 Instruct the completer to use __all__ for the completion
97 Specifically, when completing on ``object.<tab>``.
100 Specifically, when completing on ``object.<tab>``.
98 When True: only those names in obj.__all__ will be included.
101 When True: only those names in obj.__all__ will be included.
99 When False [default]: the __all__ attribute is ignored
102 When False [default]: the __all__ attribute is ignored
100 Current: False
103 Current: False
101 IPCompleter.merge_completions=<Bool>
104 IPCompleter.merge_completions=<Bool>
102 Whether to merge completion results into a single list
105 Whether to merge completion results into a single list
103 If False, only the completion results from the first non-empty
106 If False, only the completion results from the first non-empty
104 completer will be returned.
107 completer will be returned.
108 As of version 8.6.0, setting the value to ``False`` is an alias for:
109 ``IPCompleter.suppress_competing_matchers = True.``.
105 Current: True
110 Current: True
106 IPCompleter.omit__names=<Enum>
111 IPCompleter.omit__names=<Enum>
107 Instruct the completer to omit private method names
112 Instruct the completer to omit private method names
108 Specifically, when completing on ``object.<tab>``.
113 Specifically, when completing on ``object.<tab>``.
109 When 2 [default]: all names that start with '_' will be excluded.
114 When 2 [default]: all names that start with '_' will be excluded.
110 When 1: all 'magic' names (``__foo__``) will be excluded.
115 When 1: all 'magic' names (``__foo__``) will be excluded.
111 When 0: nothing will be excluded.
116 When 0: nothing will be excluded.
112 Choices: any of [0, 1, 2]
117 Choices: any of [0, 1, 2]
113 Current: 2
118 Current: 2
114 IPCompleter.profile_completions=<Bool>
119 IPCompleter.profile_completions=<Bool>
115 If True, emit profiling data for completion subsystem using cProfile.
120 If True, emit profiling data for completion subsystem using cProfile.
116 Current: False
121 Current: False
117 IPCompleter.profiler_output_dir=<Unicode>
122 IPCompleter.profiler_output_dir=<Unicode>
118 Template for path at which to output profile data for completions.
123 Template for path at which to output profile data for completions.
119 Current: '.completion_profiles'
124 Current: '.completion_profiles'
125 IPCompleter.suppress_competing_matchers=<Union>
126 Whether to suppress completions from other *Matchers*.
127 When set to ``None`` (default) the matchers will attempt to auto-detect
128 whether suppression of other matchers is desirable. For example, at the
129 beginning of a line followed by `%` we expect a magic completion to be the
130 only applicable option, and after ``my_dict['`` we usually expect a
131 completion with an existing dictionary key.
132 If you want to disable this heuristic and see completions from all matchers,
133 set ``IPCompleter.suppress_competing_matchers = False``. To disable the
134 heuristic for specific matchers provide a dictionary mapping:
135 ``IPCompleter.suppress_competing_matchers = {'IPCompleter.dict_key_matcher':
136 False}``.
137 Set ``IPCompleter.suppress_competing_matchers = True`` to limit completions
138 to the set of matchers with the highest priority; this is equivalent to
139 ``IPCompleter.merge_completions`` and can be beneficial for performance, but
140 will sometimes omit relevant candidates from matchers further down the
141 priority list.
142 Current: None
120 IPCompleter.use_jedi=<Bool>
143 IPCompleter.use_jedi=<Bool>
121 Experimental: Use Jedi to generate autocompletions. Default to True if jedi
144 Experimental: Use Jedi to generate autocompletions. Default to True if jedi
122 is installed.
145 is installed.
123 Current: True
146 Current: True
124
147
125 but the real use is in setting values::
148 but the real use is in setting values::
126
149
127 In [3]: %config IPCompleter.greedy = True
150 In [3]: %config IPCompleter.greedy = True
128
151
129 and these values are read from the user_ns if they are variables::
152 and these values are read from the user_ns if they are variables::
130
153
131 In [4]: feeling_greedy=False
154 In [4]: feeling_greedy=False
132
155
133 In [5]: %config IPCompleter.greedy = feeling_greedy
156 In [5]: %config IPCompleter.greedy = feeling_greedy
134
157
135 """
158 """
136 from traitlets.config.loader import Config
159 from traitlets.config.loader import Config
137 # some IPython objects are Configurable, but do not yet have
160 # some IPython objects are Configurable, but do not yet have
138 # any configurable traits. Exclude them from the effects of
161 # any configurable traits. Exclude them from the effects of
139 # this magic, as their presence is just noise:
162 # this magic, as their presence is just noise:
140 configurables = sorted(set([ c for c in self.shell.configurables
163 configurables = sorted(set([ c for c in self.shell.configurables
141 if c.__class__.class_traits(config=True)
164 if c.__class__.class_traits(config=True)
142 ]), key=lambda x: x.__class__.__name__)
165 ]), key=lambda x: x.__class__.__name__)
143 classnames = [ c.__class__.__name__ for c in configurables ]
166 classnames = [ c.__class__.__name__ for c in configurables ]
144
167
145 line = s.strip()
168 line = s.strip()
146 if not line:
169 if not line:
147 # print available configurable names
170 # print available configurable names
148 print("Available objects for config:")
171 print("Available objects for config:")
149 for name in classnames:
172 for name in classnames:
150 print(" ", name)
173 print(" ", name)
151 return
174 return
152 elif line in classnames:
175 elif line in classnames:
153 # `%config TerminalInteractiveShell` will print trait info for
176 # `%config TerminalInteractiveShell` will print trait info for
154 # TerminalInteractiveShell
177 # TerminalInteractiveShell
155 c = configurables[classnames.index(line)]
178 c = configurables[classnames.index(line)]
156 cls = c.__class__
179 cls = c.__class__
157 help = cls.class_get_help(c)
180 help = cls.class_get_help(c)
158 # strip leading '--' from cl-args:
181 # strip leading '--' from cl-args:
159 help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
182 help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
160 print(help)
183 print(help)
161 return
184 return
162 elif reg.match(line):
185 elif reg.match(line):
163 cls, attr = line.split('.')
186 cls, attr = line.split('.')
164 return getattr(configurables[classnames.index(cls)],attr)
187 return getattr(configurables[classnames.index(cls)],attr)
165 elif '=' not in line:
188 elif '=' not in line:
166 msg = "Invalid config statement: %r, "\
189 msg = "Invalid config statement: %r, "\
167 "should be `Class.trait = value`."
190 "should be `Class.trait = value`."
168
191
169 ll = line.lower()
192 ll = line.lower()
170 for classname in classnames:
193 for classname in classnames:
171 if ll == classname.lower():
194 if ll == classname.lower():
172 msg = msg + '\nDid you mean %s (note the case)?' % classname
195 msg = msg + '\nDid you mean %s (note the case)?' % classname
173 break
196 break
174
197
175 raise UsageError( msg % line)
198 raise UsageError( msg % line)
176
199
177 # otherwise, assume we are setting configurables.
200 # otherwise, assume we are setting configurables.
178 # leave quotes on args when splitting, because we want
201 # leave quotes on args when splitting, because we want
179 # unquoted args to eval in user_ns
202 # unquoted args to eval in user_ns
180 cfg = Config()
203 cfg = Config()
181 exec("cfg."+line, self.shell.user_ns, locals())
204 exec("cfg."+line, self.shell.user_ns, locals())
182
205
183 for configurable in configurables:
206 for configurable in configurables:
184 try:
207 try:
185 configurable.update_config(cfg)
208 configurable.update_config(cfg)
186 except Exception as e:
209 except Exception as e:
187 error(e)
210 error(e)
@@ -1,711 +1,711 b''
1 """Implementation of namespace-related magic functions.
1 """Implementation of namespace-related magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import gc
16 import gc
17 import re
17 import re
18 import sys
18 import sys
19
19
20 # Our own packages
20 # Our own packages
21 from IPython.core import page
21 from IPython.core import page
22 from IPython.core.error import StdinNotImplementedError, UsageError
22 from IPython.core.error import StdinNotImplementedError, UsageError
23 from IPython.core.magic import Magics, magics_class, line_magic
23 from IPython.core.magic import Magics, magics_class, line_magic
24 from IPython.testing.skipdoctest import skip_doctest
24 from IPython.testing.skipdoctest import skip_doctest
25 from IPython.utils.encoding import DEFAULT_ENCODING
25 from IPython.utils.encoding import DEFAULT_ENCODING
26 from IPython.utils.openpy import read_py_file
26 from IPython.utils.openpy import read_py_file
27 from IPython.utils.path import get_py_filename
27 from IPython.utils.path import get_py_filename
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Magic implementation classes
30 # Magic implementation classes
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 @magics_class
33 @magics_class
34 class NamespaceMagics(Magics):
34 class NamespaceMagics(Magics):
35 """Magics to manage various aspects of the user's namespace.
35 """Magics to manage various aspects of the user's namespace.
36
36
37 These include listing variables, introspecting into them, etc.
37 These include listing variables, introspecting into them, etc.
38 """
38 """
39
39
40 @line_magic
40 @line_magic
41 def pinfo(self, parameter_s='', namespaces=None):
41 def pinfo(self, parameter_s='', namespaces=None):
42 """Provide detailed information about an object.
42 """Provide detailed information about an object.
43
43
44 '%pinfo object' is just a synonym for object? or ?object."""
44 '%pinfo object' is just a synonym for object? or ?object."""
45
45
46 #print 'pinfo par: <%s>' % parameter_s # dbg
46 #print 'pinfo par: <%s>' % parameter_s # dbg
47 # detail_level: 0 -> obj? , 1 -> obj??
47 # detail_level: 0 -> obj? , 1 -> obj??
48 detail_level = 0
48 detail_level = 0
49 # We need to detect if we got called as 'pinfo pinfo foo', which can
49 # We need to detect if we got called as 'pinfo pinfo foo', which can
50 # happen if the user types 'pinfo foo?' at the cmd line.
50 # happen if the user types 'pinfo foo?' at the cmd line.
51 pinfo,qmark1,oname,qmark2 = \
51 pinfo,qmark1,oname,qmark2 = \
52 re.match(r'(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups()
52 re.match(r'(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups()
53 if pinfo or qmark1 or qmark2:
53 if pinfo or qmark1 or qmark2:
54 detail_level = 1
54 detail_level = 1
55 if "*" in oname:
55 if "*" in oname:
56 self.psearch(oname)
56 self.psearch(oname)
57 else:
57 else:
58 self.shell._inspect('pinfo', oname, detail_level=detail_level,
58 self.shell._inspect('pinfo', oname, detail_level=detail_level,
59 namespaces=namespaces)
59 namespaces=namespaces)
60
60
61 @line_magic
61 @line_magic
62 def pinfo2(self, parameter_s='', namespaces=None):
62 def pinfo2(self, parameter_s='', namespaces=None):
63 """Provide extra detailed information about an object.
63 """Provide extra detailed information about an object.
64
64
65 '%pinfo2 object' is just a synonym for object?? or ??object."""
65 '%pinfo2 object' is just a synonym for object?? or ??object."""
66 self.shell._inspect('pinfo', parameter_s, detail_level=1,
66 self.shell._inspect('pinfo', parameter_s, detail_level=1,
67 namespaces=namespaces)
67 namespaces=namespaces)
68
68
69 @skip_doctest
69 @skip_doctest
70 @line_magic
70 @line_magic
71 def pdef(self, parameter_s='', namespaces=None):
71 def pdef(self, parameter_s='', namespaces=None):
72 """Print the call signature for any callable object.
72 """Print the call signature for any callable object.
73
73
74 If the object is a class, print the constructor information.
74 If the object is a class, print the constructor information.
75
75
76 Examples
76 Examples
77 --------
77 --------
78 ::
78 ::
79
79
80 In [3]: %pdef urllib.urlopen
80 In [3]: %pdef urllib.urlopen
81 urllib.urlopen(url, data=None, proxies=None)
81 urllib.urlopen(url, data=None, proxies=None)
82 """
82 """
83 self.shell._inspect('pdef',parameter_s, namespaces)
83 self.shell._inspect('pdef',parameter_s, namespaces)
84
84
85 @line_magic
85 @line_magic
86 def pdoc(self, parameter_s='', namespaces=None):
86 def pdoc(self, parameter_s='', namespaces=None):
87 """Print the docstring for an object.
87 """Print the docstring for an object.
88
88
89 If the given object is a class, it will print both the class and the
89 If the given object is a class, it will print both the class and the
90 constructor docstrings."""
90 constructor docstrings."""
91 self.shell._inspect('pdoc',parameter_s, namespaces)
91 self.shell._inspect('pdoc',parameter_s, namespaces)
92
92
93 @line_magic
93 @line_magic
94 def psource(self, parameter_s='', namespaces=None):
94 def psource(self, parameter_s='', namespaces=None):
95 """Print (or run through pager) the source code for an object."""
95 """Print (or run through pager) the source code for an object."""
96 if not parameter_s:
96 if not parameter_s:
97 raise UsageError('Missing object name.')
97 raise UsageError('Missing object name.')
98 self.shell._inspect('psource',parameter_s, namespaces)
98 self.shell._inspect('psource',parameter_s, namespaces)
99
99
100 @line_magic
100 @line_magic
101 def pfile(self, parameter_s='', namespaces=None):
101 def pfile(self, parameter_s='', namespaces=None):
102 """Print (or run through pager) the file where an object is defined.
102 """Print (or run through pager) the file where an object is defined.
103
103
104 The file opens at the line where the object definition begins. IPython
104 The file opens at the line where the object definition begins. IPython
105 will honor the environment variable PAGER if set, and otherwise will
105 will honor the environment variable PAGER if set, and otherwise will
106 do its best to print the file in a convenient form.
106 do its best to print the file in a convenient form.
107
107
108 If the given argument is not an object currently defined, IPython will
108 If the given argument is not an object currently defined, IPython will
109 try to interpret it as a filename (automatically adding a .py extension
109 try to interpret it as a filename (automatically adding a .py extension
110 if needed). You can thus use %pfile as a syntax highlighting code
110 if needed). You can thus use %pfile as a syntax highlighting code
111 viewer."""
111 viewer."""
112
112
113 # first interpret argument as an object name
113 # first interpret argument as an object name
114 out = self.shell._inspect('pfile',parameter_s, namespaces)
114 out = self.shell._inspect('pfile',parameter_s, namespaces)
115 # if not, try the input as a filename
115 # if not, try the input as a filename
116 if out == 'not found':
116 if out == 'not found':
117 try:
117 try:
118 filename = get_py_filename(parameter_s)
118 filename = get_py_filename(parameter_s)
119 except IOError as msg:
119 except IOError as msg:
120 print(msg)
120 print(msg)
121 return
121 return
122 page.page(self.shell.pycolorize(read_py_file(filename, skip_encoding_cookie=False)))
122 page.page(self.shell.pycolorize(read_py_file(filename, skip_encoding_cookie=False)))
123
123
124 @line_magic
124 @line_magic
125 def psearch(self, parameter_s=''):
125 def psearch(self, parameter_s=''):
126 """Search for object in namespaces by wildcard.
126 """Search for object in namespaces by wildcard.
127
127
128 %psearch [options] PATTERN [OBJECT TYPE]
128 %psearch [options] PATTERN [OBJECT TYPE]
129
129
130 Note: ? can be used as a synonym for %psearch, at the beginning or at
130 Note: ? can be used as a synonym for %psearch, at the beginning or at
131 the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the
131 the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the
132 rest of the command line must be unchanged (options come first), so
132 rest of the command line must be unchanged (options come first), so
133 for example the following forms are equivalent
133 for example the following forms are equivalent
134
134
135 %psearch -i a* function
135 %psearch -i a* function
136 -i a* function?
136 -i a* function?
137 ?-i a* function
137 ?-i a* function
138
138
139 Arguments:
139 Arguments:
140
140
141 PATTERN
141 PATTERN
142
142
143 where PATTERN is a string containing * as a wildcard similar to its
143 where PATTERN is a string containing * as a wildcard similar to its
144 use in a shell. The pattern is matched in all namespaces on the
144 use in a shell. The pattern is matched in all namespaces on the
145 search path. By default objects starting with a single _ are not
145 search path. By default objects starting with a single _ are not
146 matched, many IPython generated objects have a single
146 matched, many IPython generated objects have a single
147 underscore. The default is case insensitive matching. Matching is
147 underscore. The default is case insensitive matching. Matching is
148 also done on the attributes of objects and not only on the objects
148 also done on the attributes of objects and not only on the objects
149 in a module.
149 in a module.
150
150
151 [OBJECT TYPE]
151 [OBJECT TYPE]
152
152
153 Is the name of a python type from the types module. The name is
153 Is the name of a python type from the types module. The name is
154 given in lowercase without the ending type, ex. StringType is
154 given in lowercase without the ending type, ex. StringType is
155 written string. By adding a type here only objects matching the
155 written string. By adding a type here only objects matching the
156 given type are matched. Using all here makes the pattern match all
156 given type are matched. Using all here makes the pattern match all
157 types (this is the default).
157 types (this is the default).
158
158
159 Options:
159 Options:
160
160
161 -a: makes the pattern match even objects whose names start with a
161 -a: makes the pattern match even objects whose names start with a
162 single underscore. These names are normally omitted from the
162 single underscore. These names are normally omitted from the
163 search.
163 search.
164
164
165 -i/-c: make the pattern case insensitive/sensitive. If neither of
165 -i/-c: make the pattern case insensitive/sensitive. If neither of
166 these options are given, the default is read from your configuration
166 these options are given, the default is read from your configuration
167 file, with the option ``InteractiveShell.wildcards_case_sensitive``.
167 file, with the option ``InteractiveShell.wildcards_case_sensitive``.
168 If this option is not specified in your configuration file, IPython's
168 If this option is not specified in your configuration file, IPython's
169 internal default is to do a case sensitive search.
169 internal default is to do a case sensitive search.
170
170
171 -e/-s NAMESPACE: exclude/search a given namespace. The pattern you
171 -e/-s NAMESPACE: exclude/search a given namespace. The pattern you
172 specify can be searched in any of the following namespaces:
172 specify can be searched in any of the following namespaces:
173 'builtin', 'user', 'user_global','internal', 'alias', where
173 'builtin', 'user', 'user_global','internal', 'alias', where
174 'builtin' and 'user' are the search defaults. Note that you should
174 'builtin' and 'user' are the search defaults. Note that you should
175 not use quotes when specifying namespaces.
175 not use quotes when specifying namespaces.
176
176
177 -l: List all available object types for object matching. This function
177 -l: List all available object types for object matching. This function
178 can be used without arguments.
178 can be used without arguments.
179
179
180 'Builtin' contains the python module builtin, 'user' contains all
180 'Builtin' contains the python module builtin, 'user' contains all
181 user data, 'alias' only contain the shell aliases and no python
181 user data, 'alias' only contain the shell aliases and no python
182 objects, 'internal' contains objects used by IPython. The
182 objects, 'internal' contains objects used by IPython. The
183 'user_global' namespace is only used by embedded IPython instances,
183 'user_global' namespace is only used by embedded IPython instances,
184 and it contains module-level globals. You can add namespaces to the
184 and it contains module-level globals. You can add namespaces to the
185 search with -s or exclude them with -e (these options can be given
185 search with -s or exclude them with -e (these options can be given
186 more than once).
186 more than once).
187
187
188 Examples
188 Examples
189 --------
189 --------
190 ::
190 ::
191
191
192 %psearch a* -> objects beginning with an a
192 %psearch a* -> objects beginning with an a
193 %psearch -e builtin a* -> objects NOT in the builtin space starting in a
193 %psearch -e builtin a* -> objects NOT in the builtin space starting in a
194 %psearch a* function -> all functions beginning with an a
194 %psearch a* function -> all functions beginning with an a
195 %psearch re.e* -> objects beginning with an e in module re
195 %psearch re.e* -> objects beginning with an e in module re
196 %psearch r*.e* -> objects that start with e in modules starting in r
196 %psearch r*.e* -> objects that start with e in modules starting in r
197 %psearch r*.* string -> all strings in modules beginning with r
197 %psearch r*.* string -> all strings in modules beginning with r
198
198
199 Case sensitive search::
199 Case sensitive search::
200
200
201 %psearch -c a* list all object beginning with lower case a
201 %psearch -c a* list all object beginning with lower case a
202
202
203 Show objects beginning with a single _::
203 Show objects beginning with a single _::
204
204
205 %psearch -a _* list objects beginning with a single underscore
205 %psearch -a _* list objects beginning with a single underscore
206
206
207 List available objects::
207 List available objects::
208
208
209 %psearch -l list all available object types
209 %psearch -l list all available object types
210 """
210 """
211 # default namespaces to be searched
211 # default namespaces to be searched
212 def_search = ['user_local', 'user_global', 'builtin']
212 def_search = ['user_local', 'user_global', 'builtin']
213
213
214 # Process options/args
214 # Process options/args
215 opts,args = self.parse_options(parameter_s,'cias:e:l',list_all=True)
215 opts,args = self.parse_options(parameter_s,'cias:e:l',list_all=True)
216 opt = opts.get
216 opt = opts.get
217 shell = self.shell
217 shell = self.shell
218 psearch = shell.inspector.psearch
218 psearch = shell.inspector.psearch
219
219
220 # select list object types
220 # select list object types
221 list_types = False
221 list_types = False
222 if 'l' in opts:
222 if 'l' in opts:
223 list_types = True
223 list_types = True
224
224
225 # select case options
225 # select case options
226 if 'i' in opts:
226 if 'i' in opts:
227 ignore_case = True
227 ignore_case = True
228 elif 'c' in opts:
228 elif 'c' in opts:
229 ignore_case = False
229 ignore_case = False
230 else:
230 else:
231 ignore_case = not shell.wildcards_case_sensitive
231 ignore_case = not shell.wildcards_case_sensitive
232
232
233 # Build list of namespaces to search from user options
233 # Build list of namespaces to search from user options
234 def_search.extend(opt('s',[]))
234 def_search.extend(opt('s',[]))
235 ns_exclude = ns_exclude=opt('e',[])
235 ns_exclude = ns_exclude=opt('e',[])
236 ns_search = [nm for nm in def_search if nm not in ns_exclude]
236 ns_search = [nm for nm in def_search if nm not in ns_exclude]
237
237
238 # Call the actual search
238 # Call the actual search
239 try:
239 try:
240 psearch(args,shell.ns_table,ns_search,
240 psearch(args,shell.ns_table,ns_search,
241 show_all=opt('a'),ignore_case=ignore_case, list_types=list_types)
241 show_all=opt('a'),ignore_case=ignore_case, list_types=list_types)
242 except:
242 except:
243 shell.showtraceback()
243 shell.showtraceback()
244
244
245 @skip_doctest
245 @skip_doctest
246 @line_magic
246 @line_magic
247 def who_ls(self, parameter_s=''):
247 def who_ls(self, parameter_s=''):
248 """Return a sorted list of all interactive variables.
248 """Return a sorted list of all interactive variables.
249
249
250 If arguments are given, only variables of types matching these
250 If arguments are given, only variables of types matching these
251 arguments are returned.
251 arguments are returned.
252
252
253 Examples
253 Examples
254 --------
254 --------
255 Define two variables and list them with who_ls::
255 Define two variables and list them with who_ls::
256
256
257 In [1]: alpha = 123
257 In [1]: alpha = 123
258
258
259 In [2]: beta = 'test'
259 In [2]: beta = 'test'
260
260
261 In [3]: %who_ls
261 In [3]: %who_ls
262 Out[3]: ['alpha', 'beta']
262 Out[3]: ['alpha', 'beta']
263
263
264 In [4]: %who_ls int
264 In [4]: %who_ls int
265 Out[4]: ['alpha']
265 Out[4]: ['alpha']
266
266
267 In [5]: %who_ls str
267 In [5]: %who_ls str
268 Out[5]: ['beta']
268 Out[5]: ['beta']
269 """
269 """
270
270
271 user_ns = self.shell.user_ns
271 user_ns = self.shell.user_ns
272 user_ns_hidden = self.shell.user_ns_hidden
272 user_ns_hidden = self.shell.user_ns_hidden
273 nonmatching = object() # This can never be in user_ns
273 nonmatching = object() # This can never be in user_ns
274 out = [ i for i in user_ns
274 out = [ i for i in user_ns
275 if not i.startswith('_') \
275 if not i.startswith('_') \
276 and (user_ns[i] is not user_ns_hidden.get(i, nonmatching)) ]
276 and (user_ns[i] is not user_ns_hidden.get(i, nonmatching)) ]
277
277
278 typelist = parameter_s.split()
278 typelist = parameter_s.split()
279 if typelist:
279 if typelist:
280 typeset = set(typelist)
280 typeset = set(typelist)
281 out = [i for i in out if type(user_ns[i]).__name__ in typeset]
281 out = [i for i in out if type(user_ns[i]).__name__ in typeset]
282
282
283 out.sort()
283 out.sort()
284 return out
284 return out
285
285
286 @skip_doctest
286 @skip_doctest
287 @line_magic
287 @line_magic
288 def who(self, parameter_s=''):
288 def who(self, parameter_s=''):
289 """Print all interactive variables, with some minimal formatting.
289 """Print all interactive variables, with some minimal formatting.
290
290
291 If any arguments are given, only variables whose type matches one of
291 If any arguments are given, only variables whose type matches one of
292 these are printed. For example::
292 these are printed. For example::
293
293
294 %who function str
294 %who function str
295
295
296 will only list functions and strings, excluding all other types of
296 will only list functions and strings, excluding all other types of
297 variables. To find the proper type names, simply use type(var) at a
297 variables. To find the proper type names, simply use type(var) at a
298 command line to see how python prints type names. For example:
298 command line to see how python prints type names. For example:
299
299
300 ::
300 ::
301
301
302 In [1]: type('hello')\\
302 In [1]: type('hello')\\
303 Out[1]: <type 'str'>
303 Out[1]: <type 'str'>
304
304
305 indicates that the type name for strings is 'str'.
305 indicates that the type name for strings is 'str'.
306
306
307 ``%who`` always excludes executed names loaded through your configuration
307 ``%who`` always excludes executed names loaded through your configuration
308 file and things which are internal to IPython.
308 file and things which are internal to IPython.
309
309
310 This is deliberate, as typically you may load many modules and the
310 This is deliberate, as typically you may load many modules and the
311 purpose of %who is to show you only what you've manually defined.
311 purpose of %who is to show you only what you've manually defined.
312
312
313 Examples
313 Examples
314 --------
314 --------
315
315
316 Define two variables and list them with who::
316 Define two variables and list them with who::
317
317
318 In [1]: alpha = 123
318 In [1]: alpha = 123
319
319
320 In [2]: beta = 'test'
320 In [2]: beta = 'test'
321
321
322 In [3]: %who
322 In [3]: %who
323 alpha beta
323 alpha beta
324
324
325 In [4]: %who int
325 In [4]: %who int
326 alpha
326 alpha
327
327
328 In [5]: %who str
328 In [5]: %who str
329 beta
329 beta
330 """
330 """
331
331
332 varlist = self.who_ls(parameter_s)
332 varlist = self.who_ls(parameter_s)
333 if not varlist:
333 if not varlist:
334 if parameter_s:
334 if parameter_s:
335 print('No variables match your requested type.')
335 print('No variables match your requested type.')
336 else:
336 else:
337 print('Interactive namespace is empty.')
337 print('Interactive namespace is empty.')
338 return
338 return
339
339
340 # if we have variables, move on...
340 # if we have variables, move on...
341 count = 0
341 count = 0
342 for i in varlist:
342 for i in varlist:
343 print(i+'\t', end=' ')
343 print(i+'\t', end=' ')
344 count += 1
344 count += 1
345 if count > 8:
345 if count > 8:
346 count = 0
346 count = 0
347 print()
347 print()
348 print()
348 print()
349
349
350 @skip_doctest
350 @skip_doctest
351 @line_magic
351 @line_magic
352 def whos(self, parameter_s=''):
352 def whos(self, parameter_s=''):
353 """Like %who, but gives some extra information about each variable.
353 """Like %who, but gives some extra information about each variable.
354
354
355 The same type filtering of %who can be applied here.
355 The same type filtering of %who can be applied here.
356
356
357 For all variables, the type is printed. Additionally it prints:
357 For all variables, the type is printed. Additionally it prints:
358
358
359 - For {},[],(): their length.
359 - For {},[],(): their length.
360
360
361 - For numpy arrays, a summary with shape, number of
361 - For numpy arrays, a summary with shape, number of
362 elements, typecode and size in memory.
362 elements, typecode and size in memory.
363
363
364 - Everything else: a string representation, snipping their middle if
364 - Everything else: a string representation, snipping their middle if
365 too long.
365 too long.
366
366
367 Examples
367 Examples
368 --------
368 --------
369 Define two variables and list them with whos::
369 Define two variables and list them with whos::
370
370
371 In [1]: alpha = 123
371 In [1]: alpha = 123
372
372
373 In [2]: beta = 'test'
373 In [2]: beta = 'test'
374
374
375 In [3]: %whos
375 In [3]: %whos
376 Variable Type Data/Info
376 Variable Type Data/Info
377 --------------------------------
377 --------------------------------
378 alpha int 123
378 alpha int 123
379 beta str test
379 beta str test
380 """
380 """
381
381
382 varnames = self.who_ls(parameter_s)
382 varnames = self.who_ls(parameter_s)
383 if not varnames:
383 if not varnames:
384 if parameter_s:
384 if parameter_s:
385 print('No variables match your requested type.')
385 print('No variables match your requested type.')
386 else:
386 else:
387 print('Interactive namespace is empty.')
387 print('Interactive namespace is empty.')
388 return
388 return
389
389
390 # if we have variables, move on...
390 # if we have variables, move on...
391
391
392 # for these types, show len() instead of data:
392 # for these types, show len() instead of data:
393 seq_types = ['dict', 'list', 'tuple']
393 seq_types = ['dict', 'list', 'tuple']
394
394
395 # for numpy arrays, display summary info
395 # for numpy arrays, display summary info
396 ndarray_type = None
396 ndarray_type = None
397 if 'numpy' in sys.modules:
397 if 'numpy' in sys.modules:
398 try:
398 try:
399 from numpy import ndarray
399 from numpy import ndarray
400 except ImportError:
400 except ImportError:
401 pass
401 pass
402 else:
402 else:
403 ndarray_type = ndarray.__name__
403 ndarray_type = ndarray.__name__
404
404
405 # Find all variable names and types so we can figure out column sizes
405 # Find all variable names and types so we can figure out column sizes
406
406
407 # some types are well known and can be shorter
407 # some types are well known and can be shorter
408 abbrevs = {'IPython.core.macro.Macro' : 'Macro'}
408 abbrevs = {'IPython.core.macro.Macro' : 'Macro'}
409 def type_name(v):
409 def type_name(v):
410 tn = type(v).__name__
410 tn = type(v).__name__
411 return abbrevs.get(tn,tn)
411 return abbrevs.get(tn,tn)
412
412
413 varlist = [self.shell.user_ns[n] for n in varnames]
413 varlist = [self.shell.user_ns[n] for n in varnames]
414
414
415 typelist = []
415 typelist = []
416 for vv in varlist:
416 for vv in varlist:
417 tt = type_name(vv)
417 tt = type_name(vv)
418
418
419 if tt=='instance':
419 if tt=='instance':
420 typelist.append( abbrevs.get(str(vv.__class__),
420 typelist.append( abbrevs.get(str(vv.__class__),
421 str(vv.__class__)))
421 str(vv.__class__)))
422 else:
422 else:
423 typelist.append(tt)
423 typelist.append(tt)
424
424
425 # column labels and # of spaces as separator
425 # column labels and # of spaces as separator
426 varlabel = 'Variable'
426 varlabel = 'Variable'
427 typelabel = 'Type'
427 typelabel = 'Type'
428 datalabel = 'Data/Info'
428 datalabel = 'Data/Info'
429 colsep = 3
429 colsep = 3
430 # variable format strings
430 # variable format strings
431 vformat = "{0:<{varwidth}}{1:<{typewidth}}"
431 vformat = "{0:<{varwidth}}{1:<{typewidth}}"
432 aformat = "%s: %s elems, type `%s`, %s bytes"
432 aformat = "%s: %s elems, type `%s`, %s bytes"
433 # find the size of the columns to format the output nicely
433 # find the size of the columns to format the output nicely
434 varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep
434 varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep
435 typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep
435 typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep
436 # table header
436 # table header
437 print(varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \
437 print(varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \
438 ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1))
438 ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1))
439 # and the table itself
439 # and the table itself
440 kb = 1024
440 kb = 1024
441 Mb = 1048576 # kb**2
441 Mb = 1048576 # kb**2
442 for vname,var,vtype in zip(varnames,varlist,typelist):
442 for vname,var,vtype in zip(varnames,varlist,typelist):
443 print(vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth), end=' ')
443 print(vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth), end=' ')
444 if vtype in seq_types:
444 if vtype in seq_types:
445 print("n="+str(len(var)))
445 print("n="+str(len(var)))
446 elif vtype == ndarray_type:
446 elif vtype == ndarray_type:
447 vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1]
447 vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1]
448 if vtype==ndarray_type:
448 if vtype==ndarray_type:
449 # numpy
449 # numpy
450 vsize = var.size
450 vsize = var.size
451 vbytes = vsize*var.itemsize
451 vbytes = vsize*var.itemsize
452 vdtype = var.dtype
452 vdtype = var.dtype
453
453
454 if vbytes < 100000:
454 if vbytes < 100000:
455 print(aformat % (vshape, vsize, vdtype, vbytes))
455 print(aformat % (vshape, vsize, vdtype, vbytes))
456 else:
456 else:
457 print(aformat % (vshape, vsize, vdtype, vbytes), end=' ')
457 print(aformat % (vshape, vsize, vdtype, vbytes), end=' ')
458 if vbytes < Mb:
458 if vbytes < Mb:
459 print('(%s kb)' % (vbytes/kb,))
459 print('(%s kb)' % (vbytes/kb,))
460 else:
460 else:
461 print('(%s Mb)' % (vbytes/Mb,))
461 print('(%s Mb)' % (vbytes/Mb,))
462 else:
462 else:
463 try:
463 try:
464 vstr = str(var)
464 vstr = str(var)
465 except UnicodeEncodeError:
465 except UnicodeEncodeError:
466 vstr = var.encode(DEFAULT_ENCODING,
466 vstr = var.encode(DEFAULT_ENCODING,
467 'backslashreplace')
467 'backslashreplace')
468 except:
468 except:
469 vstr = "<object with id %d (str() failed)>" % id(var)
469 vstr = "<object with id %d (str() failed)>" % id(var)
470 vstr = vstr.replace('\n', '\\n')
470 vstr = vstr.replace('\n', '\\n')
471 if len(vstr) < 50:
471 if len(vstr) < 50:
472 print(vstr)
472 print(vstr)
473 else:
473 else:
474 print(vstr[:25] + "<...>" + vstr[-25:])
474 print(vstr[:25] + "<...>" + vstr[-25:])
475
475
476 @line_magic
476 @line_magic
477 def reset(self, parameter_s=''):
477 def reset(self, parameter_s=''):
478 """Resets the namespace by removing all names defined by the user, if
478 """Resets the namespace by removing all names defined by the user, if
479 called without arguments, or by removing some types of objects, such
479 called without arguments, or by removing some types of objects, such
480 as everything currently in IPython's In[] and Out[] containers (see
480 as everything currently in IPython's In[] and Out[] containers (see
481 the parameters for details).
481 the parameters for details).
482
482
483 Parameters
483 Parameters
484 ----------
484 ----------
485 -f
485 -f
486 force reset without asking for confirmation.
486 force reset without asking for confirmation.
487 -s
487 -s
488 'Soft' reset: Only clears your namespace, leaving history intact.
488 'Soft' reset: Only clears your namespace, leaving history intact.
489 References to objects may be kept. By default (without this option),
489 References to objects may be kept. By default (without this option),
490 we do a 'hard' reset, giving you a new session and removing all
490 we do a 'hard' reset, giving you a new session and removing all
491 references to objects from the current session.
491 references to objects from the current session.
492 --aggressive
492 --aggressive
493 Try to aggressively remove modules from sys.modules ; this
493 Try to aggressively remove modules from sys.modules ; this
494 may allow you to reimport Python modules that have been updated and
494 may allow you to reimport Python modules that have been updated and
495 pick up changes, but can have unattended consequences.
495 pick up changes, but can have unintended consequences.
496
496
497 in
497 in
498 reset input history
498 reset input history
499 out
499 out
500 reset output history
500 reset output history
501 dhist
501 dhist
502 reset directory history
502 reset directory history
503 array
503 array
504 reset only variables that are NumPy arrays
504 reset only variables that are NumPy arrays
505
505
506 See Also
506 See Also
507 --------
507 --------
508 reset_selective : invoked as ``%reset_selective``
508 reset_selective : invoked as ``%reset_selective``
509
509
510 Examples
510 Examples
511 --------
511 --------
512 ::
512 ::
513
513
514 In [6]: a = 1
514 In [6]: a = 1
515
515
516 In [7]: a
516 In [7]: a
517 Out[7]: 1
517 Out[7]: 1
518
518
519 In [8]: 'a' in get_ipython().user_ns
519 In [8]: 'a' in get_ipython().user_ns
520 Out[8]: True
520 Out[8]: True
521
521
522 In [9]: %reset -f
522 In [9]: %reset -f
523
523
524 In [1]: 'a' in get_ipython().user_ns
524 In [1]: 'a' in get_ipython().user_ns
525 Out[1]: False
525 Out[1]: False
526
526
527 In [2]: %reset -f in
527 In [2]: %reset -f in
528 Flushing input history
528 Flushing input history
529
529
530 In [3]: %reset -f dhist in
530 In [3]: %reset -f dhist in
531 Flushing directory history
531 Flushing directory history
532 Flushing input history
532 Flushing input history
533
533
534 Notes
534 Notes
535 -----
535 -----
536 Calling this magic from clients that do not implement standard input,
536 Calling this magic from clients that do not implement standard input,
537 such as the ipython notebook interface, will reset the namespace
537 such as the ipython notebook interface, will reset the namespace
538 without confirmation.
538 without confirmation.
539 """
539 """
540 opts, args = self.parse_options(parameter_s, "sf", "aggressive", mode="list")
540 opts, args = self.parse_options(parameter_s, "sf", "aggressive", mode="list")
541 if "f" in opts:
541 if "f" in opts:
542 ans = True
542 ans = True
543 else:
543 else:
544 try:
544 try:
545 ans = self.shell.ask_yes_no(
545 ans = self.shell.ask_yes_no(
546 "Once deleted, variables cannot be recovered. Proceed (y/[n])?",
546 "Once deleted, variables cannot be recovered. Proceed (y/[n])?",
547 default='n')
547 default='n')
548 except StdinNotImplementedError:
548 except StdinNotImplementedError:
549 ans = True
549 ans = True
550 if not ans:
550 if not ans:
551 print('Nothing done.')
551 print('Nothing done.')
552 return
552 return
553
553
554 if 's' in opts: # Soft reset
554 if 's' in opts: # Soft reset
555 user_ns = self.shell.user_ns
555 user_ns = self.shell.user_ns
556 for i in self.who_ls():
556 for i in self.who_ls():
557 del(user_ns[i])
557 del(user_ns[i])
558 elif len(args) == 0: # Hard reset
558 elif len(args) == 0: # Hard reset
559 self.shell.reset(new_session=False, aggressive=("aggressive" in opts))
559 self.shell.reset(new_session=False, aggressive=("aggressive" in opts))
560
560
561 # reset in/out/dhist/array: previously extensinions/clearcmd.py
561 # reset in/out/dhist/array: previously extensinions/clearcmd.py
562 ip = self.shell
562 ip = self.shell
563 user_ns = self.shell.user_ns # local lookup, heavily used
563 user_ns = self.shell.user_ns # local lookup, heavily used
564
564
565 for target in args:
565 for target in args:
566 target = target.lower() # make matches case insensitive
566 target = target.lower() # make matches case insensitive
567 if target == 'out':
567 if target == 'out':
568 print("Flushing output cache (%d entries)" % len(user_ns['_oh']))
568 print("Flushing output cache (%d entries)" % len(user_ns['_oh']))
569 self.shell.displayhook.flush()
569 self.shell.displayhook.flush()
570
570
571 elif target == 'in':
571 elif target == 'in':
572 print("Flushing input history")
572 print("Flushing input history")
573 pc = self.shell.displayhook.prompt_count + 1
573 pc = self.shell.displayhook.prompt_count + 1
574 for n in range(1, pc):
574 for n in range(1, pc):
575 key = '_i'+repr(n)
575 key = '_i'+repr(n)
576 user_ns.pop(key,None)
576 user_ns.pop(key,None)
577 user_ns.update(dict(_i=u'',_ii=u'',_iii=u''))
577 user_ns.update(dict(_i=u'',_ii=u'',_iii=u''))
578 hm = ip.history_manager
578 hm = ip.history_manager
579 # don't delete these, as %save and %macro depending on the
579 # don't delete these, as %save and %macro depending on the
580 # length of these lists to be preserved
580 # length of these lists to be preserved
581 hm.input_hist_parsed[:] = [''] * pc
581 hm.input_hist_parsed[:] = [''] * pc
582 hm.input_hist_raw[:] = [''] * pc
582 hm.input_hist_raw[:] = [''] * pc
583 # hm has internal machinery for _i,_ii,_iii, clear it out
583 # hm has internal machinery for _i,_ii,_iii, clear it out
584 hm._i = hm._ii = hm._iii = hm._i00 = u''
584 hm._i = hm._ii = hm._iii = hm._i00 = u''
585
585
586 elif target == 'array':
586 elif target == 'array':
587 # Support cleaning up numpy arrays
587 # Support cleaning up numpy arrays
588 try:
588 try:
589 from numpy import ndarray
589 from numpy import ndarray
590 # This must be done with items and not iteritems because
590 # This must be done with items and not iteritems because
591 # we're going to modify the dict in-place.
591 # we're going to modify the dict in-place.
592 for x,val in list(user_ns.items()):
592 for x,val in list(user_ns.items()):
593 if isinstance(val,ndarray):
593 if isinstance(val,ndarray):
594 del user_ns[x]
594 del user_ns[x]
595 except ImportError:
595 except ImportError:
596 print("reset array only works if Numpy is available.")
596 print("reset array only works if Numpy is available.")
597
597
598 elif target == 'dhist':
598 elif target == 'dhist':
599 print("Flushing directory history")
599 print("Flushing directory history")
600 del user_ns['_dh'][:]
600 del user_ns['_dh'][:]
601
601
602 else:
602 else:
603 print("Don't know how to reset ", end=' ')
603 print("Don't know how to reset ", end=' ')
604 print(target + ", please run `%reset?` for details")
604 print(target + ", please run `%reset?` for details")
605
605
606 gc.collect()
606 gc.collect()
607
607
608 @line_magic
608 @line_magic
609 def reset_selective(self, parameter_s=''):
609 def reset_selective(self, parameter_s=''):
610 """Resets the namespace by removing names defined by the user.
610 """Resets the namespace by removing names defined by the user.
611
611
612 Input/Output history are left around in case you need them.
612 Input/Output history are left around in case you need them.
613
613
614 %reset_selective [-f] regex
614 %reset_selective [-f] regex
615
615
616 No action is taken if regex is not included
616 No action is taken if regex is not included
617
617
618 Options
618 Options
619 -f : force reset without asking for confirmation.
619 -f : force reset without asking for confirmation.
620
620
621 See Also
621 See Also
622 --------
622 --------
623 reset : invoked as ``%reset``
623 reset : invoked as ``%reset``
624
624
625 Examples
625 Examples
626 --------
626 --------
627 We first fully reset the namespace so your output looks identical to
627 We first fully reset the namespace so your output looks identical to
628 this example for pedagogical reasons; in practice you do not need a
628 this example for pedagogical reasons; in practice you do not need a
629 full reset::
629 full reset::
630
630
631 In [1]: %reset -f
631 In [1]: %reset -f
632
632
633 Now, with a clean namespace we can make a few variables and use
633 Now, with a clean namespace we can make a few variables and use
634 ``%reset_selective`` to only delete names that match our regexp::
634 ``%reset_selective`` to only delete names that match our regexp::
635
635
636 In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8
636 In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8
637
637
638 In [3]: who_ls
638 In [3]: who_ls
639 Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c']
639 Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c']
640
640
641 In [4]: %reset_selective -f b[2-3]m
641 In [4]: %reset_selective -f b[2-3]m
642
642
643 In [5]: who_ls
643 In [5]: who_ls
644 Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
644 Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
645
645
646 In [6]: %reset_selective -f d
646 In [6]: %reset_selective -f d
647
647
648 In [7]: who_ls
648 In [7]: who_ls
649 Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
649 Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
650
650
651 In [8]: %reset_selective -f c
651 In [8]: %reset_selective -f c
652
652
653 In [9]: who_ls
653 In [9]: who_ls
654 Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m']
654 Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m']
655
655
656 In [10]: %reset_selective -f b
656 In [10]: %reset_selective -f b
657
657
658 In [11]: who_ls
658 In [11]: who_ls
659 Out[11]: ['a']
659 Out[11]: ['a']
660
660
661 Notes
661 Notes
662 -----
662 -----
663 Calling this magic from clients that do not implement standard input,
663 Calling this magic from clients that do not implement standard input,
664 such as the ipython notebook interface, will reset the namespace
664 such as the ipython notebook interface, will reset the namespace
665 without confirmation.
665 without confirmation.
666 """
666 """
667
667
668 opts, regex = self.parse_options(parameter_s,'f')
668 opts, regex = self.parse_options(parameter_s,'f')
669
669
670 if 'f' in opts:
670 if 'f' in opts:
671 ans = True
671 ans = True
672 else:
672 else:
673 try:
673 try:
674 ans = self.shell.ask_yes_no(
674 ans = self.shell.ask_yes_no(
675 "Once deleted, variables cannot be recovered. Proceed (y/[n])? ",
675 "Once deleted, variables cannot be recovered. Proceed (y/[n])? ",
676 default='n')
676 default='n')
677 except StdinNotImplementedError:
677 except StdinNotImplementedError:
678 ans = True
678 ans = True
679 if not ans:
679 if not ans:
680 print('Nothing done.')
680 print('Nothing done.')
681 return
681 return
682 user_ns = self.shell.user_ns
682 user_ns = self.shell.user_ns
683 if not regex:
683 if not regex:
684 print('No regex pattern specified. Nothing done.')
684 print('No regex pattern specified. Nothing done.')
685 return
685 return
686 else:
686 else:
687 try:
687 try:
688 m = re.compile(regex)
688 m = re.compile(regex)
689 except TypeError as e:
689 except TypeError as e:
690 raise TypeError('regex must be a string or compiled pattern') from e
690 raise TypeError('regex must be a string or compiled pattern') from e
691 for i in self.who_ls():
691 for i in self.who_ls():
692 if m.search(i):
692 if m.search(i):
693 del(user_ns[i])
693 del(user_ns[i])
694
694
695 @line_magic
695 @line_magic
696 def xdel(self, parameter_s=''):
696 def xdel(self, parameter_s=''):
697 """Delete a variable, trying to clear it from anywhere that
697 """Delete a variable, trying to clear it from anywhere that
698 IPython's machinery has references to it. By default, this uses
698 IPython's machinery has references to it. By default, this uses
699 the identity of the named object in the user namespace to remove
699 the identity of the named object in the user namespace to remove
700 references held under other names. The object is also removed
700 references held under other names. The object is also removed
701 from the output history.
701 from the output history.
702
702
703 Options
703 Options
704 -n : Delete the specified name from all namespaces, without
704 -n : Delete the specified name from all namespaces, without
705 checking their identity.
705 checking their identity.
706 """
706 """
707 opts, varname = self.parse_options(parameter_s,'n')
707 opts, varname = self.parse_options(parameter_s,'n')
708 try:
708 try:
709 self.shell.del_var(varname, ('n' in opts))
709 self.shell.del_var(varname, ('n' in opts))
710 except (NameError, ValueError) as e:
710 except (NameError, ValueError) as e:
711 print(type(e).__name__ +": "+ str(e))
711 print(type(e).__name__ +": "+ str(e))
@@ -1,424 +1,425 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities."""
2 """Pylab (matplotlib) support utilities."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from io import BytesIO
7 from io import BytesIO
8 from binascii import b2a_base64
8 from binascii import b2a_base64
9 from functools import partial
9 from functools import partial
10 import warnings
10 import warnings
11
11
12 from IPython.core.display import _pngxy
12 from IPython.core.display import _pngxy
13 from IPython.utils.decorators import flag_calls
13 from IPython.utils.decorators import flag_calls
14
14
15 # If user specifies a GUI, that dictates the backend, otherwise we read the
15 # If user specifies a GUI, that dictates the backend, otherwise we read the
16 # user's mpl default from the mpl rc structure
16 # user's mpl default from the mpl rc structure
17 backends = {
17 backends = {
18 "tk": "TkAgg",
18 "tk": "TkAgg",
19 "gtk": "GTKAgg",
19 "gtk": "GTKAgg",
20 "gtk3": "GTK3Agg",
20 "gtk3": "GTK3Agg",
21 "gtk4": "GTK4Agg",
21 "gtk4": "GTK4Agg",
22 "wx": "WXAgg",
22 "wx": "WXAgg",
23 "qt4": "Qt4Agg",
23 "qt4": "Qt4Agg",
24 "qt5": "Qt5Agg",
24 "qt5": "Qt5Agg",
25 "qt6": "QtAgg",
25 "qt6": "QtAgg",
26 "qt": "Qt5Agg",
26 "qt": "Qt5Agg",
27 "osx": "MacOSX",
27 "osx": "MacOSX",
28 "nbagg": "nbAgg",
28 "nbagg": "nbAgg",
29 "webagg": "WebAgg",
29 "notebook": "nbAgg",
30 "notebook": "nbAgg",
30 "agg": "agg",
31 "agg": "agg",
31 "svg": "svg",
32 "svg": "svg",
32 "pdf": "pdf",
33 "pdf": "pdf",
33 "ps": "ps",
34 "ps": "ps",
34 "inline": "module://matplotlib_inline.backend_inline",
35 "inline": "module://matplotlib_inline.backend_inline",
35 "ipympl": "module://ipympl.backend_nbagg",
36 "ipympl": "module://ipympl.backend_nbagg",
36 "widget": "module://ipympl.backend_nbagg",
37 "widget": "module://ipympl.backend_nbagg",
37 }
38 }
38
39
39 # We also need a reverse backends2guis mapping that will properly choose which
40 # We also need a reverse backends2guis mapping that will properly choose which
40 # GUI support to activate based on the desired matplotlib backend. For the
41 # GUI support to activate based on the desired matplotlib backend. For the
41 # most part it's just a reverse of the above dict, but we also need to add a
42 # most part it's just a reverse of the above dict, but we also need to add a
42 # few others that map to the same GUI manually:
43 # few others that map to the same GUI manually:
43 backend2gui = dict(zip(backends.values(), backends.keys()))
44 backend2gui = dict(zip(backends.values(), backends.keys()))
44 # In the reverse mapping, there are a few extra valid matplotlib backends that
45 # In the reverse mapping, there are a few extra valid matplotlib backends that
45 # map to the same GUI support
46 # map to the same GUI support
46 backend2gui["GTK"] = backend2gui["GTKCairo"] = "gtk"
47 backend2gui["GTK"] = backend2gui["GTKCairo"] = "gtk"
47 backend2gui["GTK3Cairo"] = "gtk3"
48 backend2gui["GTK3Cairo"] = "gtk3"
48 backend2gui["GTK4Cairo"] = "gtk4"
49 backend2gui["GTK4Cairo"] = "gtk4"
49 backend2gui["WX"] = "wx"
50 backend2gui["WX"] = "wx"
50 backend2gui["CocoaAgg"] = "osx"
51 backend2gui["CocoaAgg"] = "osx"
51 # There needs to be a hysteresis here as the new QtAgg Matplotlib backend
52 # There needs to be a hysteresis here as the new QtAgg Matplotlib backend
52 # supports either Qt5 or Qt6 and the IPython qt event loop support Qt4, Qt5,
53 # supports either Qt5 or Qt6 and the IPython qt event loop support Qt4, Qt5,
53 # and Qt6.
54 # and Qt6.
54 backend2gui["QtAgg"] = "qt"
55 backend2gui["QtAgg"] = "qt"
55 backend2gui["Qt4Agg"] = "qt"
56 backend2gui["Qt4Agg"] = "qt"
56 backend2gui["Qt5Agg"] = "qt"
57 backend2gui["Qt5Agg"] = "qt"
57
58
58 # And some backends that don't need GUI integration
59 # And some backends that don't need GUI integration
59 del backend2gui["nbAgg"]
60 del backend2gui["nbAgg"]
60 del backend2gui["agg"]
61 del backend2gui["agg"]
61 del backend2gui["svg"]
62 del backend2gui["svg"]
62 del backend2gui["pdf"]
63 del backend2gui["pdf"]
63 del backend2gui["ps"]
64 del backend2gui["ps"]
64 del backend2gui["module://matplotlib_inline.backend_inline"]
65 del backend2gui["module://matplotlib_inline.backend_inline"]
65 del backend2gui["module://ipympl.backend_nbagg"]
66 del backend2gui["module://ipympl.backend_nbagg"]
66
67
67 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
68 # Matplotlib utilities
69 # Matplotlib utilities
69 #-----------------------------------------------------------------------------
70 #-----------------------------------------------------------------------------
70
71
71
72
72 def getfigs(*fig_nums):
73 def getfigs(*fig_nums):
73 """Get a list of matplotlib figures by figure numbers.
74 """Get a list of matplotlib figures by figure numbers.
74
75
75 If no arguments are given, all available figures are returned. If the
76 If no arguments are given, all available figures are returned. If the
76 argument list contains references to invalid figures, a warning is printed
77 argument list contains references to invalid figures, a warning is printed
77 but the function continues pasting further figures.
78 but the function continues pasting further figures.
78
79
79 Parameters
80 Parameters
80 ----------
81 ----------
81 figs : tuple
82 figs : tuple
82 A tuple of ints giving the figure numbers of the figures to return.
83 A tuple of ints giving the figure numbers of the figures to return.
83 """
84 """
84 from matplotlib._pylab_helpers import Gcf
85 from matplotlib._pylab_helpers import Gcf
85 if not fig_nums:
86 if not fig_nums:
86 fig_managers = Gcf.get_all_fig_managers()
87 fig_managers = Gcf.get_all_fig_managers()
87 return [fm.canvas.figure for fm in fig_managers]
88 return [fm.canvas.figure for fm in fig_managers]
88 else:
89 else:
89 figs = []
90 figs = []
90 for num in fig_nums:
91 for num in fig_nums:
91 f = Gcf.figs.get(num)
92 f = Gcf.figs.get(num)
92 if f is None:
93 if f is None:
93 print('Warning: figure %s not available.' % num)
94 print('Warning: figure %s not available.' % num)
94 else:
95 else:
95 figs.append(f.canvas.figure)
96 figs.append(f.canvas.figure)
96 return figs
97 return figs
97
98
98
99
99 def figsize(sizex, sizey):
100 def figsize(sizex, sizey):
100 """Set the default figure size to be [sizex, sizey].
101 """Set the default figure size to be [sizex, sizey].
101
102
102 This is just an easy to remember, convenience wrapper that sets::
103 This is just an easy to remember, convenience wrapper that sets::
103
104
104 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
105 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
105 """
106 """
106 import matplotlib
107 import matplotlib
107 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
108 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
108
109
109
110
110 def print_figure(fig, fmt="png", bbox_inches="tight", base64=False, **kwargs):
111 def print_figure(fig, fmt="png", bbox_inches="tight", base64=False, **kwargs):
111 """Print a figure to an image, and return the resulting file data
112 """Print a figure to an image, and return the resulting file data
112
113
113 Returned data will be bytes unless ``fmt='svg'``,
114 Returned data will be bytes unless ``fmt='svg'``,
114 in which case it will be unicode.
115 in which case it will be unicode.
115
116
116 Any keyword args are passed to fig.canvas.print_figure,
117 Any keyword args are passed to fig.canvas.print_figure,
117 such as ``quality`` or ``bbox_inches``.
118 such as ``quality`` or ``bbox_inches``.
118
119
119 If `base64` is True, return base64-encoded str instead of raw bytes
120 If `base64` is True, return base64-encoded str instead of raw bytes
120 for binary-encoded image formats
121 for binary-encoded image formats
121
122
122 .. versionadded:: 7.29
123 .. versionadded:: 7.29
123 base64 argument
124 base64 argument
124 """
125 """
125 # When there's an empty figure, we shouldn't return anything, otherwise we
126 # When there's an empty figure, we shouldn't return anything, otherwise we
126 # get big blank areas in the qt console.
127 # get big blank areas in the qt console.
127 if not fig.axes and not fig.lines:
128 if not fig.axes and not fig.lines:
128 return
129 return
129
130
130 dpi = fig.dpi
131 dpi = fig.dpi
131 if fmt == 'retina':
132 if fmt == 'retina':
132 dpi = dpi * 2
133 dpi = dpi * 2
133 fmt = 'png'
134 fmt = 'png'
134
135
135 # build keyword args
136 # build keyword args
136 kw = {
137 kw = {
137 "format":fmt,
138 "format":fmt,
138 "facecolor":fig.get_facecolor(),
139 "facecolor":fig.get_facecolor(),
139 "edgecolor":fig.get_edgecolor(),
140 "edgecolor":fig.get_edgecolor(),
140 "dpi":dpi,
141 "dpi":dpi,
141 "bbox_inches":bbox_inches,
142 "bbox_inches":bbox_inches,
142 }
143 }
143 # **kwargs get higher priority
144 # **kwargs get higher priority
144 kw.update(kwargs)
145 kw.update(kwargs)
145
146
146 bytes_io = BytesIO()
147 bytes_io = BytesIO()
147 if fig.canvas is None:
148 if fig.canvas is None:
148 from matplotlib.backend_bases import FigureCanvasBase
149 from matplotlib.backend_bases import FigureCanvasBase
149 FigureCanvasBase(fig)
150 FigureCanvasBase(fig)
150
151
151 fig.canvas.print_figure(bytes_io, **kw)
152 fig.canvas.print_figure(bytes_io, **kw)
152 data = bytes_io.getvalue()
153 data = bytes_io.getvalue()
153 if fmt == 'svg':
154 if fmt == 'svg':
154 data = data.decode('utf-8')
155 data = data.decode('utf-8')
155 elif base64:
156 elif base64:
156 data = b2a_base64(data).decode("ascii")
157 data = b2a_base64(data).decode("ascii")
157 return data
158 return data
158
159
159 def retina_figure(fig, base64=False, **kwargs):
160 def retina_figure(fig, base64=False, **kwargs):
160 """format a figure as a pixel-doubled (retina) PNG
161 """format a figure as a pixel-doubled (retina) PNG
161
162
162 If `base64` is True, return base64-encoded str instead of raw bytes
163 If `base64` is True, return base64-encoded str instead of raw bytes
163 for binary-encoded image formats
164 for binary-encoded image formats
164
165
165 .. versionadded:: 7.29
166 .. versionadded:: 7.29
166 base64 argument
167 base64 argument
167 """
168 """
168 pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs)
169 pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs)
169 # Make sure that retina_figure acts just like print_figure and returns
170 # Make sure that retina_figure acts just like print_figure and returns
170 # None when the figure is empty.
171 # None when the figure is empty.
171 if pngdata is None:
172 if pngdata is None:
172 return
173 return
173 w, h = _pngxy(pngdata)
174 w, h = _pngxy(pngdata)
174 metadata = {"width": w//2, "height":h//2}
175 metadata = {"width": w//2, "height":h//2}
175 if base64:
176 if base64:
176 pngdata = b2a_base64(pngdata).decode("ascii")
177 pngdata = b2a_base64(pngdata).decode("ascii")
177 return pngdata, metadata
178 return pngdata, metadata
178
179
179
180
180 # We need a little factory function here to create the closure where
181 # We need a little factory function here to create the closure where
181 # safe_execfile can live.
182 # safe_execfile can live.
182 def mpl_runner(safe_execfile):
183 def mpl_runner(safe_execfile):
183 """Factory to return a matplotlib-enabled runner for %run.
184 """Factory to return a matplotlib-enabled runner for %run.
184
185
185 Parameters
186 Parameters
186 ----------
187 ----------
187 safe_execfile : function
188 safe_execfile : function
188 This must be a function with the same interface as the
189 This must be a function with the same interface as the
189 :meth:`safe_execfile` method of IPython.
190 :meth:`safe_execfile` method of IPython.
190
191
191 Returns
192 Returns
192 -------
193 -------
193 A function suitable for use as the ``runner`` argument of the %run magic
194 A function suitable for use as the ``runner`` argument of the %run magic
194 function.
195 function.
195 """
196 """
196
197
197 def mpl_execfile(fname,*where,**kw):
198 def mpl_execfile(fname,*where,**kw):
198 """matplotlib-aware wrapper around safe_execfile.
199 """matplotlib-aware wrapper around safe_execfile.
199
200
200 Its interface is identical to that of the :func:`execfile` builtin.
201 Its interface is identical to that of the :func:`execfile` builtin.
201
202
202 This is ultimately a call to execfile(), but wrapped in safeties to
203 This is ultimately a call to execfile(), but wrapped in safeties to
203 properly handle interactive rendering."""
204 properly handle interactive rendering."""
204
205
205 import matplotlib
206 import matplotlib
206 import matplotlib.pyplot as plt
207 import matplotlib.pyplot as plt
207
208
208 #print '*** Matplotlib runner ***' # dbg
209 #print '*** Matplotlib runner ***' # dbg
209 # turn off rendering until end of script
210 # turn off rendering until end of script
210 is_interactive = matplotlib.rcParams['interactive']
211 is_interactive = matplotlib.rcParams['interactive']
211 matplotlib.interactive(False)
212 matplotlib.interactive(False)
212 safe_execfile(fname,*where,**kw)
213 safe_execfile(fname,*where,**kw)
213 matplotlib.interactive(is_interactive)
214 matplotlib.interactive(is_interactive)
214 # make rendering call now, if the user tried to do it
215 # make rendering call now, if the user tried to do it
215 if plt.draw_if_interactive.called:
216 if plt.draw_if_interactive.called:
216 plt.draw()
217 plt.draw()
217 plt.draw_if_interactive.called = False
218 plt.draw_if_interactive.called = False
218
219
219 # re-draw everything that is stale
220 # re-draw everything that is stale
220 try:
221 try:
221 da = plt.draw_all
222 da = plt.draw_all
222 except AttributeError:
223 except AttributeError:
223 pass
224 pass
224 else:
225 else:
225 da()
226 da()
226
227
227 return mpl_execfile
228 return mpl_execfile
228
229
229
230
230 def _reshow_nbagg_figure(fig):
231 def _reshow_nbagg_figure(fig):
231 """reshow an nbagg figure"""
232 """reshow an nbagg figure"""
232 try:
233 try:
233 reshow = fig.canvas.manager.reshow
234 reshow = fig.canvas.manager.reshow
234 except AttributeError as e:
235 except AttributeError as e:
235 raise NotImplementedError() from e
236 raise NotImplementedError() from e
236 else:
237 else:
237 reshow()
238 reshow()
238
239
239
240
240 def select_figure_formats(shell, formats, **kwargs):
241 def select_figure_formats(shell, formats, **kwargs):
241 """Select figure formats for the inline backend.
242 """Select figure formats for the inline backend.
242
243
243 Parameters
244 Parameters
244 ----------
245 ----------
245 shell : InteractiveShell
246 shell : InteractiveShell
246 The main IPython instance.
247 The main IPython instance.
247 formats : str or set
248 formats : str or set
248 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
249 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
249 **kwargs : any
250 **kwargs : any
250 Extra keyword arguments to be passed to fig.canvas.print_figure.
251 Extra keyword arguments to be passed to fig.canvas.print_figure.
251 """
252 """
252 import matplotlib
253 import matplotlib
253 from matplotlib.figure import Figure
254 from matplotlib.figure import Figure
254
255
255 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
256 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
256 png_formatter = shell.display_formatter.formatters['image/png']
257 png_formatter = shell.display_formatter.formatters['image/png']
257 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
258 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
258 pdf_formatter = shell.display_formatter.formatters['application/pdf']
259 pdf_formatter = shell.display_formatter.formatters['application/pdf']
259
260
260 if isinstance(formats, str):
261 if isinstance(formats, str):
261 formats = {formats}
262 formats = {formats}
262 # cast in case of list / tuple
263 # cast in case of list / tuple
263 formats = set(formats)
264 formats = set(formats)
264
265
265 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
266 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
266 mplbackend = matplotlib.get_backend().lower()
267 mplbackend = matplotlib.get_backend().lower()
267 if mplbackend == 'nbagg' or mplbackend == 'module://ipympl.backend_nbagg':
268 if mplbackend == 'nbagg' or mplbackend == 'module://ipympl.backend_nbagg':
268 formatter = shell.display_formatter.ipython_display_formatter
269 formatter = shell.display_formatter.ipython_display_formatter
269 formatter.for_type(Figure, _reshow_nbagg_figure)
270 formatter.for_type(Figure, _reshow_nbagg_figure)
270
271
271 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
272 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
272 bad = formats.difference(supported)
273 bad = formats.difference(supported)
273 if bad:
274 if bad:
274 bs = "%s" % ','.join([repr(f) for f in bad])
275 bs = "%s" % ','.join([repr(f) for f in bad])
275 gs = "%s" % ','.join([repr(f) for f in supported])
276 gs = "%s" % ','.join([repr(f) for f in supported])
276 raise ValueError("supported formats are: %s not %s" % (gs, bs))
277 raise ValueError("supported formats are: %s not %s" % (gs, bs))
277
278
278 if "png" in formats:
279 if "png" in formats:
279 png_formatter.for_type(
280 png_formatter.for_type(
280 Figure, partial(print_figure, fmt="png", base64=True, **kwargs)
281 Figure, partial(print_figure, fmt="png", base64=True, **kwargs)
281 )
282 )
282 if "retina" in formats or "png2x" in formats:
283 if "retina" in formats or "png2x" in formats:
283 png_formatter.for_type(Figure, partial(retina_figure, base64=True, **kwargs))
284 png_formatter.for_type(Figure, partial(retina_figure, base64=True, **kwargs))
284 if "jpg" in formats or "jpeg" in formats:
285 if "jpg" in formats or "jpeg" in formats:
285 jpg_formatter.for_type(
286 jpg_formatter.for_type(
286 Figure, partial(print_figure, fmt="jpg", base64=True, **kwargs)
287 Figure, partial(print_figure, fmt="jpg", base64=True, **kwargs)
287 )
288 )
288 if "svg" in formats:
289 if "svg" in formats:
289 svg_formatter.for_type(Figure, partial(print_figure, fmt="svg", **kwargs))
290 svg_formatter.for_type(Figure, partial(print_figure, fmt="svg", **kwargs))
290 if "pdf" in formats:
291 if "pdf" in formats:
291 pdf_formatter.for_type(
292 pdf_formatter.for_type(
292 Figure, partial(print_figure, fmt="pdf", base64=True, **kwargs)
293 Figure, partial(print_figure, fmt="pdf", base64=True, **kwargs)
293 )
294 )
294
295
295 #-----------------------------------------------------------------------------
296 #-----------------------------------------------------------------------------
296 # Code for initializing matplotlib and importing pylab
297 # Code for initializing matplotlib and importing pylab
297 #-----------------------------------------------------------------------------
298 #-----------------------------------------------------------------------------
298
299
299
300
300 def find_gui_and_backend(gui=None, gui_select=None):
301 def find_gui_and_backend(gui=None, gui_select=None):
301 """Given a gui string return the gui and mpl backend.
302 """Given a gui string return the gui and mpl backend.
302
303
303 Parameters
304 Parameters
304 ----------
305 ----------
305 gui : str
306 gui : str
306 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
307 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
307 gui_select : str
308 gui_select : str
308 Can be one of ('tk','gtk','wx','qt','qt4','inline').
309 Can be one of ('tk','gtk','wx','qt','qt4','inline').
309 This is any gui already selected by the shell.
310 This is any gui already selected by the shell.
310
311
311 Returns
312 Returns
312 -------
313 -------
313 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
314 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
314 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
315 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
315 """
316 """
316
317
317 import matplotlib
318 import matplotlib
318
319
319 if gui and gui != 'auto':
320 if gui and gui != 'auto':
320 # select backend based on requested gui
321 # select backend based on requested gui
321 backend = backends[gui]
322 backend = backends[gui]
322 if gui == 'agg':
323 if gui == 'agg':
323 gui = None
324 gui = None
324 else:
325 else:
325 # We need to read the backend from the original data structure, *not*
326 # We need to read the backend from the original data structure, *not*
326 # from mpl.rcParams, since a prior invocation of %matplotlib may have
327 # from mpl.rcParams, since a prior invocation of %matplotlib may have
327 # overwritten that.
328 # overwritten that.
328 # WARNING: this assumes matplotlib 1.1 or newer!!
329 # WARNING: this assumes matplotlib 1.1 or newer!!
329 backend = matplotlib.rcParamsOrig['backend']
330 backend = matplotlib.rcParamsOrig['backend']
330 # In this case, we need to find what the appropriate gui selection call
331 # In this case, we need to find what the appropriate gui selection call
331 # should be for IPython, so we can activate inputhook accordingly
332 # should be for IPython, so we can activate inputhook accordingly
332 gui = backend2gui.get(backend, None)
333 gui = backend2gui.get(backend, None)
333
334
334 # If we have already had a gui active, we need it and inline are the
335 # If we have already had a gui active, we need it and inline are the
335 # ones allowed.
336 # ones allowed.
336 if gui_select and gui != gui_select:
337 if gui_select and gui != gui_select:
337 gui = gui_select
338 gui = gui_select
338 backend = backends[gui]
339 backend = backends[gui]
339
340
340 return gui, backend
341 return gui, backend
341
342
342
343
343 def activate_matplotlib(backend):
344 def activate_matplotlib(backend):
344 """Activate the given backend and set interactive to True."""
345 """Activate the given backend and set interactive to True."""
345
346
346 import matplotlib
347 import matplotlib
347 matplotlib.interactive(True)
348 matplotlib.interactive(True)
348
349
349 # Matplotlib had a bug where even switch_backend could not force
350 # Matplotlib had a bug where even switch_backend could not force
350 # the rcParam to update. This needs to be set *before* the module
351 # the rcParam to update. This needs to be set *before* the module
351 # magic of switch_backend().
352 # magic of switch_backend().
352 matplotlib.rcParams['backend'] = backend
353 matplotlib.rcParams['backend'] = backend
353
354
354 # Due to circular imports, pyplot may be only partially initialised
355 # Due to circular imports, pyplot may be only partially initialised
355 # when this function runs.
356 # when this function runs.
356 # So avoid needing matplotlib attribute-lookup to access pyplot.
357 # So avoid needing matplotlib attribute-lookup to access pyplot.
357 from matplotlib import pyplot as plt
358 from matplotlib import pyplot as plt
358
359
359 plt.switch_backend(backend)
360 plt.switch_backend(backend)
360
361
361 plt.show._needmain = False
362 plt.show._needmain = False
362 # We need to detect at runtime whether show() is called by the user.
363 # We need to detect at runtime whether show() is called by the user.
363 # For this, we wrap it into a decorator which adds a 'called' flag.
364 # For this, we wrap it into a decorator which adds a 'called' flag.
364 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
365 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
365
366
366
367
367 def import_pylab(user_ns, import_all=True):
368 def import_pylab(user_ns, import_all=True):
368 """Populate the namespace with pylab-related values.
369 """Populate the namespace with pylab-related values.
369
370
370 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
371 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
371
372
372 Also imports a few names from IPython (figsize, display, getfigs)
373 Also imports a few names from IPython (figsize, display, getfigs)
373
374
374 """
375 """
375
376
376 # Import numpy as np/pyplot as plt are conventions we're trying to
377 # Import numpy as np/pyplot as plt are conventions we're trying to
377 # somewhat standardize on. Making them available to users by default
378 # somewhat standardize on. Making them available to users by default
378 # will greatly help this.
379 # will greatly help this.
379 s = ("import numpy\n"
380 s = ("import numpy\n"
380 "import matplotlib\n"
381 "import matplotlib\n"
381 "from matplotlib import pylab, mlab, pyplot\n"
382 "from matplotlib import pylab, mlab, pyplot\n"
382 "np = numpy\n"
383 "np = numpy\n"
383 "plt = pyplot\n"
384 "plt = pyplot\n"
384 )
385 )
385 exec(s, user_ns)
386 exec(s, user_ns)
386
387
387 if import_all:
388 if import_all:
388 s = ("from matplotlib.pylab import *\n"
389 s = ("from matplotlib.pylab import *\n"
389 "from numpy import *\n")
390 "from numpy import *\n")
390 exec(s, user_ns)
391 exec(s, user_ns)
391
392
392 # IPython symbols to add
393 # IPython symbols to add
393 user_ns['figsize'] = figsize
394 user_ns['figsize'] = figsize
394 from IPython.display import display
395 from IPython.display import display
395 # Add display and getfigs to the user's namespace
396 # Add display and getfigs to the user's namespace
396 user_ns['display'] = display
397 user_ns['display'] = display
397 user_ns['getfigs'] = getfigs
398 user_ns['getfigs'] = getfigs
398
399
399
400
400 def configure_inline_support(shell, backend):
401 def configure_inline_support(shell, backend):
401 """
402 """
402 .. deprecated:: 7.23
403 .. deprecated:: 7.23
403
404
404 use `matplotlib_inline.backend_inline.configure_inline_support()`
405 use `matplotlib_inline.backend_inline.configure_inline_support()`
405
406
406 Configure an IPython shell object for matplotlib use.
407 Configure an IPython shell object for matplotlib use.
407
408
408 Parameters
409 Parameters
409 ----------
410 ----------
410 shell : InteractiveShell instance
411 shell : InteractiveShell instance
411 backend : matplotlib backend
412 backend : matplotlib backend
412 """
413 """
413 warnings.warn(
414 warnings.warn(
414 "`configure_inline_support` is deprecated since IPython 7.23, directly "
415 "`configure_inline_support` is deprecated since IPython 7.23, directly "
415 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
416 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
416 DeprecationWarning,
417 DeprecationWarning,
417 stacklevel=2,
418 stacklevel=2,
418 )
419 )
419
420
420 from matplotlib_inline.backend_inline import (
421 from matplotlib_inline.backend_inline import (
421 configure_inline_support as configure_inline_support_orig,
422 configure_inline_support as configure_inline_support_orig,
422 )
423 )
423
424
424 configure_inline_support_orig(shell, backend)
425 configure_inline_support_orig(shell, backend)
@@ -1,54 +1,54 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Release data for the IPython project."""
2 """Release data for the IPython project."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2008, IPython Development Team.
5 # Copyright (c) 2008, IPython Development Team.
6 # Copyright (c) 2001, Fernando Perez <fernando.perez@colorado.edu>
6 # Copyright (c) 2001, Fernando Perez <fernando.perez@colorado.edu>
7 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
7 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
8 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
8 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
9 #
9 #
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11 #
11 #
12 # The full license is in the file COPYING.txt, distributed with this software.
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # IPython version information. An empty _version_extra corresponds to a full
15 # IPython version information. An empty _version_extra corresponds to a full
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 = 6
19 _version_minor = 7
20 _version_patch = 0
20 _version_patch = 0
21 _version_extra = ".dev"
21 _version_extra = ".dev"
22 # _version_extra = "rc1"
22 # _version_extra = "rc1"
23 # _version_extra = "" # Uncomment this for full releases
23 # _version_extra = "" # Uncomment this for full releases
24
24
25 # Construct full version string from these.
25 # Construct full version string from these.
26 _ver = [_version_major, _version_minor, _version_patch]
26 _ver = [_version_major, _version_minor, _version_patch]
27
27
28 __version__ = '.'.join(map(str, _ver))
28 __version__ = '.'.join(map(str, _ver))
29 if _version_extra:
29 if _version_extra:
30 __version__ = __version__ + _version_extra
30 __version__ = __version__ + _version_extra
31
31
32 version = __version__ # backwards compatibility name
32 version = __version__ # backwards compatibility name
33 version_info = (_version_major, _version_minor, _version_patch, _version_extra)
33 version_info = (_version_major, _version_minor, _version_patch, _version_extra)
34
34
35 # Change this when incrementing the kernel protocol version
35 # Change this when incrementing the kernel protocol version
36 kernel_protocol_version_info = (5, 0)
36 kernel_protocol_version_info = (5, 0)
37 kernel_protocol_version = "%i.%i" % kernel_protocol_version_info
37 kernel_protocol_version = "%i.%i" % kernel_protocol_version_info
38
38
39 license = 'BSD'
39 license = "BSD-3-Clause"
40
40
41 authors = {'Fernando' : ('Fernando Perez','fperez.net@gmail.com'),
41 authors = {'Fernando' : ('Fernando Perez','fperez.net@gmail.com'),
42 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
42 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
43 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu'),
43 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu'),
44 'Ville' : ('Ville Vainio','vivainio@gmail.com'),
44 'Ville' : ('Ville Vainio','vivainio@gmail.com'),
45 'Brian' : ('Brian E Granger', 'ellisonbg@gmail.com'),
45 'Brian' : ('Brian E Granger', 'ellisonbg@gmail.com'),
46 'Min' : ('Min Ragan-Kelley', 'benjaminrk@gmail.com'),
46 'Min' : ('Min Ragan-Kelley', 'benjaminrk@gmail.com'),
47 'Thomas' : ('Thomas A. Kluyver', 'takowl@gmail.com'),
47 'Thomas' : ('Thomas A. Kluyver', 'takowl@gmail.com'),
48 'Jorgen' : ('Jorgen Stenarson', 'jorgen.stenarson@bostream.nu'),
48 'Jorgen' : ('Jorgen Stenarson', 'jorgen.stenarson@bostream.nu'),
49 'Matthias' : ('Matthias Bussonnier', 'bussonniermatthias@gmail.com'),
49 'Matthias' : ('Matthias Bussonnier', 'bussonniermatthias@gmail.com'),
50 }
50 }
51
51
52 author = 'The IPython Development Team'
52 author = 'The IPython Development Team'
53
53
54 author_email = 'ipython-dev@python.org'
54 author_email = 'ipython-dev@python.org'
@@ -1,4 +1,4 b''
1 # coding: iso-8859-5
1 # coding: iso-8859-5
2 # (Unlikely to be the default encoding for most testers.)
2 # (Unlikely to be the default encoding for most testers.)
3 # ������������������� <- Cyrillic characters
3 # ������������������� <- Cyrillic characters
4 u = '����'
4 u = "����"
@@ -1,1275 +1,1446 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for the IPython tab-completion machinery."""
2 """Tests for the IPython tab-completion machinery."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 import pytest
8 import pytest
9 import sys
9 import sys
10 import textwrap
10 import textwrap
11 import unittest
11 import unittest
12
12
13 from contextlib import contextmanager
13 from contextlib import contextmanager
14
14
15 from traitlets.config.loader import Config
15 from traitlets.config.loader import Config
16 from IPython import get_ipython
16 from IPython import get_ipython
17 from IPython.core import completer
17 from IPython.core import completer
18 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
18 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
19 from IPython.utils.generics import complete_object
19 from IPython.utils.generics import complete_object
20 from IPython.testing import decorators as dec
20 from IPython.testing import decorators as dec
21
21
22 from IPython.core.completer import (
22 from IPython.core.completer import (
23 Completion,
23 Completion,
24 provisionalcompleter,
24 provisionalcompleter,
25 match_dict_keys,
25 match_dict_keys,
26 _deduplicate_completions,
26 _deduplicate_completions,
27 completion_matcher,
28 SimpleCompletion,
29 CompletionContext,
27 )
30 )
28
31
29 # -----------------------------------------------------------------------------
32 # -----------------------------------------------------------------------------
30 # Test functions
33 # Test functions
31 # -----------------------------------------------------------------------------
34 # -----------------------------------------------------------------------------
32
35
33 def recompute_unicode_ranges():
36 def recompute_unicode_ranges():
34 """
37 """
35 utility to recompute the largest unicode range without any characters
38 utility to recompute the largest unicode range without any characters
36
39
37 use to recompute the gap in the global _UNICODE_RANGES of completer.py
40 use to recompute the gap in the global _UNICODE_RANGES of completer.py
38 """
41 """
39 import itertools
42 import itertools
40 import unicodedata
43 import unicodedata
41 valid = []
44 valid = []
42 for c in range(0,0x10FFFF + 1):
45 for c in range(0,0x10FFFF + 1):
43 try:
46 try:
44 unicodedata.name(chr(c))
47 unicodedata.name(chr(c))
45 except ValueError:
48 except ValueError:
46 continue
49 continue
47 valid.append(c)
50 valid.append(c)
48
51
49 def ranges(i):
52 def ranges(i):
50 for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
53 for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
51 b = list(b)
54 b = list(b)
52 yield b[0][1], b[-1][1]
55 yield b[0][1], b[-1][1]
53
56
54 rg = list(ranges(valid))
57 rg = list(ranges(valid))
55 lens = []
58 lens = []
56 gap_lens = []
59 gap_lens = []
57 pstart, pstop = 0,0
60 pstart, pstop = 0,0
58 for start, stop in rg:
61 for start, stop in rg:
59 lens.append(stop-start)
62 lens.append(stop-start)
60 gap_lens.append((start - pstop, hex(pstop), hex(start), f'{round((start - pstop)/0xe01f0*100)}%'))
63 gap_lens.append((start - pstop, hex(pstop), hex(start), f'{round((start - pstop)/0xe01f0*100)}%'))
61 pstart, pstop = start, stop
64 pstart, pstop = start, stop
62
65
63 return sorted(gap_lens)[-1]
66 return sorted(gap_lens)[-1]
64
67
65
68
66
69
67 def test_unicode_range():
70 def test_unicode_range():
68 """
71 """
69 Test that the ranges we test for unicode names give the same number of
72 Test that the ranges we test for unicode names give the same number of
70 results than testing the full length.
73 results than testing the full length.
71 """
74 """
72 from IPython.core.completer import _unicode_name_compute, _UNICODE_RANGES
75 from IPython.core.completer import _unicode_name_compute, _UNICODE_RANGES
73
76
74 expected_list = _unicode_name_compute([(0, 0x110000)])
77 expected_list = _unicode_name_compute([(0, 0x110000)])
75 test = _unicode_name_compute(_UNICODE_RANGES)
78 test = _unicode_name_compute(_UNICODE_RANGES)
76 len_exp = len(expected_list)
79 len_exp = len(expected_list)
77 len_test = len(test)
80 len_test = len(test)
78
81
79 # do not inline the len() or on error pytest will try to print the 130 000 +
82 # do not inline the len() or on error pytest will try to print the 130 000 +
80 # elements.
83 # elements.
81 message = None
84 message = None
82 if len_exp != len_test or len_exp > 131808:
85 if len_exp != len_test or len_exp > 131808:
83 size, start, stop, prct = recompute_unicode_ranges()
86 size, start, stop, prct = recompute_unicode_ranges()
84 message = f"""_UNICODE_RANGES likely wrong and need updating. This is
87 message = f"""_UNICODE_RANGES likely wrong and need updating. This is
85 likely due to a new release of Python. We've find that the biggest gap
88 likely due to a new release of Python. We've find that the biggest gap
86 in unicode characters has reduces in size to be {size} characters
89 in unicode characters has reduces in size to be {size} characters
87 ({prct}), from {start}, to {stop}. In completer.py likely update to
90 ({prct}), from {start}, to {stop}. In completer.py likely update to
88
91
89 _UNICODE_RANGES = [(32, {start}), ({stop}, 0xe01f0)]
92 _UNICODE_RANGES = [(32, {start}), ({stop}, 0xe01f0)]
90
93
91 And update the assertion below to use
94 And update the assertion below to use
92
95
93 len_exp <= {len_exp}
96 len_exp <= {len_exp}
94 """
97 """
95 assert len_exp == len_test, message
98 assert len_exp == len_test, message
96
99
97 # fail if new unicode symbols have been added.
100 # fail if new unicode symbols have been added.
98 assert len_exp <= 138552, message
101 assert len_exp <= 138552, message
99
102
100
103
101 @contextmanager
104 @contextmanager
102 def greedy_completion():
105 def greedy_completion():
103 ip = get_ipython()
106 ip = get_ipython()
104 greedy_original = ip.Completer.greedy
107 greedy_original = ip.Completer.greedy
105 try:
108 try:
106 ip.Completer.greedy = True
109 ip.Completer.greedy = True
107 yield
110 yield
108 finally:
111 finally:
109 ip.Completer.greedy = greedy_original
112 ip.Completer.greedy = greedy_original
110
113
111
114
115 @contextmanager
116 def custom_matchers(matchers):
117 ip = get_ipython()
118 try:
119 ip.Completer.custom_matchers.extend(matchers)
120 yield
121 finally:
122 ip.Completer.custom_matchers.clear()
123
124
112 def test_protect_filename():
125 def test_protect_filename():
113 if sys.platform == "win32":
126 if sys.platform == "win32":
114 pairs = [
127 pairs = [
115 ("abc", "abc"),
128 ("abc", "abc"),
116 (" abc", '" abc"'),
129 (" abc", '" abc"'),
117 ("a bc", '"a bc"'),
130 ("a bc", '"a bc"'),
118 ("a bc", '"a bc"'),
131 ("a bc", '"a bc"'),
119 (" bc", '" bc"'),
132 (" bc", '" bc"'),
120 ]
133 ]
121 else:
134 else:
122 pairs = [
135 pairs = [
123 ("abc", "abc"),
136 ("abc", "abc"),
124 (" abc", r"\ abc"),
137 (" abc", r"\ abc"),
125 ("a bc", r"a\ bc"),
138 ("a bc", r"a\ bc"),
126 ("a bc", r"a\ \ bc"),
139 ("a bc", r"a\ \ bc"),
127 (" bc", r"\ \ bc"),
140 (" bc", r"\ \ bc"),
128 # On posix, we also protect parens and other special characters.
141 # On posix, we also protect parens and other special characters.
129 ("a(bc", r"a\(bc"),
142 ("a(bc", r"a\(bc"),
130 ("a)bc", r"a\)bc"),
143 ("a)bc", r"a\)bc"),
131 ("a( )bc", r"a\(\ \)bc"),
144 ("a( )bc", r"a\(\ \)bc"),
132 ("a[1]bc", r"a\[1\]bc"),
145 ("a[1]bc", r"a\[1\]bc"),
133 ("a{1}bc", r"a\{1\}bc"),
146 ("a{1}bc", r"a\{1\}bc"),
134 ("a#bc", r"a\#bc"),
147 ("a#bc", r"a\#bc"),
135 ("a?bc", r"a\?bc"),
148 ("a?bc", r"a\?bc"),
136 ("a=bc", r"a\=bc"),
149 ("a=bc", r"a\=bc"),
137 ("a\\bc", r"a\\bc"),
150 ("a\\bc", r"a\\bc"),
138 ("a|bc", r"a\|bc"),
151 ("a|bc", r"a\|bc"),
139 ("a;bc", r"a\;bc"),
152 ("a;bc", r"a\;bc"),
140 ("a:bc", r"a\:bc"),
153 ("a:bc", r"a\:bc"),
141 ("a'bc", r"a\'bc"),
154 ("a'bc", r"a\'bc"),
142 ("a*bc", r"a\*bc"),
155 ("a*bc", r"a\*bc"),
143 ('a"bc', r"a\"bc"),
156 ('a"bc', r"a\"bc"),
144 ("a^bc", r"a\^bc"),
157 ("a^bc", r"a\^bc"),
145 ("a&bc", r"a\&bc"),
158 ("a&bc", r"a\&bc"),
146 ]
159 ]
147 # run the actual tests
160 # run the actual tests
148 for s1, s2 in pairs:
161 for s1, s2 in pairs:
149 s1p = completer.protect_filename(s1)
162 s1p = completer.protect_filename(s1)
150 assert s1p == s2
163 assert s1p == s2
151
164
152
165
153 def check_line_split(splitter, test_specs):
166 def check_line_split(splitter, test_specs):
154 for part1, part2, split in test_specs:
167 for part1, part2, split in test_specs:
155 cursor_pos = len(part1)
168 cursor_pos = len(part1)
156 line = part1 + part2
169 line = part1 + part2
157 out = splitter.split_line(line, cursor_pos)
170 out = splitter.split_line(line, cursor_pos)
158 assert out == split
171 assert out == split
159
172
160
173
161 def test_line_split():
174 def test_line_split():
162 """Basic line splitter test with default specs."""
175 """Basic line splitter test with default specs."""
163 sp = completer.CompletionSplitter()
176 sp = completer.CompletionSplitter()
164 # The format of the test specs is: part1, part2, expected answer. Parts 1
177 # The format of the test specs is: part1, part2, expected answer. Parts 1
165 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
178 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
166 # was at the end of part1. So an empty part2 represents someone hitting
179 # was at the end of part1. So an empty part2 represents someone hitting
167 # tab at the end of the line, the most common case.
180 # tab at the end of the line, the most common case.
168 t = [
181 t = [
169 ("run some/scrip", "", "some/scrip"),
182 ("run some/scrip", "", "some/scrip"),
170 ("run scripts/er", "ror.py foo", "scripts/er"),
183 ("run scripts/er", "ror.py foo", "scripts/er"),
171 ("echo $HOM", "", "HOM"),
184 ("echo $HOM", "", "HOM"),
172 ("print sys.pa", "", "sys.pa"),
185 ("print sys.pa", "", "sys.pa"),
173 ("print(sys.pa", "", "sys.pa"),
186 ("print(sys.pa", "", "sys.pa"),
174 ("execfile('scripts/er", "", "scripts/er"),
187 ("execfile('scripts/er", "", "scripts/er"),
175 ("a[x.", "", "x."),
188 ("a[x.", "", "x."),
176 ("a[x.", "y", "x."),
189 ("a[x.", "y", "x."),
177 ('cd "some_file/', "", "some_file/"),
190 ('cd "some_file/', "", "some_file/"),
178 ]
191 ]
179 check_line_split(sp, t)
192 check_line_split(sp, t)
180 # Ensure splitting works OK with unicode by re-running the tests with
193 # Ensure splitting works OK with unicode by re-running the tests with
181 # all inputs turned into unicode
194 # all inputs turned into unicode
182 check_line_split(sp, [map(str, p) for p in t])
195 check_line_split(sp, [map(str, p) for p in t])
183
196
184
197
185 class NamedInstanceClass:
198 class NamedInstanceClass:
186 instances = {}
199 instances = {}
187
200
188 def __init__(self, name):
201 def __init__(self, name):
189 self.instances[name] = self
202 self.instances[name] = self
190
203
191 @classmethod
204 @classmethod
192 def _ipython_key_completions_(cls):
205 def _ipython_key_completions_(cls):
193 return cls.instances.keys()
206 return cls.instances.keys()
194
207
195
208
196 class KeyCompletable:
209 class KeyCompletable:
197 def __init__(self, things=()):
210 def __init__(self, things=()):
198 self.things = things
211 self.things = things
199
212
200 def _ipython_key_completions_(self):
213 def _ipython_key_completions_(self):
201 return list(self.things)
214 return list(self.things)
202
215
203
216
204 class TestCompleter(unittest.TestCase):
217 class TestCompleter(unittest.TestCase):
205 def setUp(self):
218 def setUp(self):
206 """
219 """
207 We want to silence all PendingDeprecationWarning when testing the completer
220 We want to silence all PendingDeprecationWarning when testing the completer
208 """
221 """
209 self._assertwarns = self.assertWarns(PendingDeprecationWarning)
222 self._assertwarns = self.assertWarns(PendingDeprecationWarning)
210 self._assertwarns.__enter__()
223 self._assertwarns.__enter__()
211
224
212 def tearDown(self):
225 def tearDown(self):
213 try:
226 try:
214 self._assertwarns.__exit__(None, None, None)
227 self._assertwarns.__exit__(None, None, None)
215 except AssertionError:
228 except AssertionError:
216 pass
229 pass
217
230
218 def test_custom_completion_error(self):
231 def test_custom_completion_error(self):
219 """Test that errors from custom attribute completers are silenced."""
232 """Test that errors from custom attribute completers are silenced."""
220 ip = get_ipython()
233 ip = get_ipython()
221
234
222 class A:
235 class A:
223 pass
236 pass
224
237
225 ip.user_ns["x"] = A()
238 ip.user_ns["x"] = A()
226
239
227 @complete_object.register(A)
240 @complete_object.register(A)
228 def complete_A(a, existing_completions):
241 def complete_A(a, existing_completions):
229 raise TypeError("this should be silenced")
242 raise TypeError("this should be silenced")
230
243
231 ip.complete("x.")
244 ip.complete("x.")
232
245
233 def test_custom_completion_ordering(self):
246 def test_custom_completion_ordering(self):
234 """Test that errors from custom attribute completers are silenced."""
247 """Test that errors from custom attribute completers are silenced."""
235 ip = get_ipython()
248 ip = get_ipython()
236
249
237 _, matches = ip.complete('in')
250 _, matches = ip.complete('in')
238 assert matches.index('input') < matches.index('int')
251 assert matches.index('input') < matches.index('int')
239
252
240 def complete_example(a):
253 def complete_example(a):
241 return ['example2', 'example1']
254 return ['example2', 'example1']
242
255
243 ip.Completer.custom_completers.add_re('ex*', complete_example)
256 ip.Completer.custom_completers.add_re('ex*', complete_example)
244 _, matches = ip.complete('ex')
257 _, matches = ip.complete('ex')
245 assert matches.index('example2') < matches.index('example1')
258 assert matches.index('example2') < matches.index('example1')
246
259
247 def test_unicode_completions(self):
260 def test_unicode_completions(self):
248 ip = get_ipython()
261 ip = get_ipython()
249 # Some strings that trigger different types of completion. Check them both
262 # Some strings that trigger different types of completion. Check them both
250 # in str and unicode forms
263 # in str and unicode forms
251 s = ["ru", "%ru", "cd /", "floa", "float(x)/"]
264 s = ["ru", "%ru", "cd /", "floa", "float(x)/"]
252 for t in s + list(map(str, s)):
265 for t in s + list(map(str, s)):
253 # We don't need to check exact completion values (they may change
266 # We don't need to check exact completion values (they may change
254 # depending on the state of the namespace, but at least no exceptions
267 # depending on the state of the namespace, but at least no exceptions
255 # should be thrown and the return value should be a pair of text, list
268 # should be thrown and the return value should be a pair of text, list
256 # values.
269 # values.
257 text, matches = ip.complete(t)
270 text, matches = ip.complete(t)
258 self.assertIsInstance(text, str)
271 self.assertIsInstance(text, str)
259 self.assertIsInstance(matches, list)
272 self.assertIsInstance(matches, list)
260
273
261 def test_latex_completions(self):
274 def test_latex_completions(self):
262 from IPython.core.latex_symbols import latex_symbols
275 from IPython.core.latex_symbols import latex_symbols
263 import random
276 import random
264
277
265 ip = get_ipython()
278 ip = get_ipython()
266 # Test some random unicode symbols
279 # Test some random unicode symbols
267 keys = random.sample(sorted(latex_symbols), 10)
280 keys = random.sample(sorted(latex_symbols), 10)
268 for k in keys:
281 for k in keys:
269 text, matches = ip.complete(k)
282 text, matches = ip.complete(k)
270 self.assertEqual(text, k)
283 self.assertEqual(text, k)
271 self.assertEqual(matches, [latex_symbols[k]])
284 self.assertEqual(matches, [latex_symbols[k]])
272 # Test a more complex line
285 # Test a more complex line
273 text, matches = ip.complete("print(\\alpha")
286 text, matches = ip.complete("print(\\alpha")
274 self.assertEqual(text, "\\alpha")
287 self.assertEqual(text, "\\alpha")
275 self.assertEqual(matches[0], latex_symbols["\\alpha"])
288 self.assertEqual(matches[0], latex_symbols["\\alpha"])
276 # Test multiple matching latex symbols
289 # Test multiple matching latex symbols
277 text, matches = ip.complete("\\al")
290 text, matches = ip.complete("\\al")
278 self.assertIn("\\alpha", matches)
291 self.assertIn("\\alpha", matches)
279 self.assertIn("\\aleph", matches)
292 self.assertIn("\\aleph", matches)
280
293
281 def test_latex_no_results(self):
294 def test_latex_no_results(self):
282 """
295 """
283 forward latex should really return nothing in either field if nothing is found.
296 forward latex should really return nothing in either field if nothing is found.
284 """
297 """
285 ip = get_ipython()
298 ip = get_ipython()
286 text, matches = ip.Completer.latex_matches("\\really_i_should_match_nothing")
299 text, matches = ip.Completer.latex_matches("\\really_i_should_match_nothing")
287 self.assertEqual(text, "")
300 self.assertEqual(text, "")
288 self.assertEqual(matches, ())
301 self.assertEqual(matches, ())
289
302
290 def test_back_latex_completion(self):
303 def test_back_latex_completion(self):
291 ip = get_ipython()
304 ip = get_ipython()
292
305
293 # do not return more than 1 matches for \beta, only the latex one.
306 # do not return more than 1 matches for \beta, only the latex one.
294 name, matches = ip.complete("\\β")
307 name, matches = ip.complete("\\β")
295 self.assertEqual(matches, ["\\beta"])
308 self.assertEqual(matches, ["\\beta"])
296
309
297 def test_back_unicode_completion(self):
310 def test_back_unicode_completion(self):
298 ip = get_ipython()
311 ip = get_ipython()
299
312
300 name, matches = ip.complete("\\Ⅴ")
313 name, matches = ip.complete("\\Ⅴ")
301 self.assertEqual(matches, ("\\ROMAN NUMERAL FIVE",))
314 self.assertEqual(matches, ["\\ROMAN NUMERAL FIVE"])
302
315
303 def test_forward_unicode_completion(self):
316 def test_forward_unicode_completion(self):
304 ip = get_ipython()
317 ip = get_ipython()
305
318
306 name, matches = ip.complete("\\ROMAN NUMERAL FIVE")
319 name, matches = ip.complete("\\ROMAN NUMERAL FIVE")
307 self.assertEqual(matches, ["Ⅴ"]) # This is not a V
320 self.assertEqual(matches, ["Ⅴ"]) # This is not a V
308 self.assertEqual(matches, ["\u2164"]) # same as above but explicit.
321 self.assertEqual(matches, ["\u2164"]) # same as above but explicit.
309
322
310 def test_delim_setting(self):
323 def test_delim_setting(self):
311 sp = completer.CompletionSplitter()
324 sp = completer.CompletionSplitter()
312 sp.delims = " "
325 sp.delims = " "
313 self.assertEqual(sp.delims, " ")
326 self.assertEqual(sp.delims, " ")
314 self.assertEqual(sp._delim_expr, r"[\ ]")
327 self.assertEqual(sp._delim_expr, r"[\ ]")
315
328
316 def test_spaces(self):
329 def test_spaces(self):
317 """Test with only spaces as split chars."""
330 """Test with only spaces as split chars."""
318 sp = completer.CompletionSplitter()
331 sp = completer.CompletionSplitter()
319 sp.delims = " "
332 sp.delims = " "
320 t = [("foo", "", "foo"), ("run foo", "", "foo"), ("run foo", "bar", "foo")]
333 t = [("foo", "", "foo"), ("run foo", "", "foo"), ("run foo", "bar", "foo")]
321 check_line_split(sp, t)
334 check_line_split(sp, t)
322
335
323 def test_has_open_quotes1(self):
336 def test_has_open_quotes1(self):
324 for s in ["'", "'''", "'hi' '"]:
337 for s in ["'", "'''", "'hi' '"]:
325 self.assertEqual(completer.has_open_quotes(s), "'")
338 self.assertEqual(completer.has_open_quotes(s), "'")
326
339
327 def test_has_open_quotes2(self):
340 def test_has_open_quotes2(self):
328 for s in ['"', '"""', '"hi" "']:
341 for s in ['"', '"""', '"hi" "']:
329 self.assertEqual(completer.has_open_quotes(s), '"')
342 self.assertEqual(completer.has_open_quotes(s), '"')
330
343
331 def test_has_open_quotes3(self):
344 def test_has_open_quotes3(self):
332 for s in ["''", "''' '''", "'hi' 'ipython'"]:
345 for s in ["''", "''' '''", "'hi' 'ipython'"]:
333 self.assertFalse(completer.has_open_quotes(s))
346 self.assertFalse(completer.has_open_quotes(s))
334
347
335 def test_has_open_quotes4(self):
348 def test_has_open_quotes4(self):
336 for s in ['""', '""" """', '"hi" "ipython"']:
349 for s in ['""', '""" """', '"hi" "ipython"']:
337 self.assertFalse(completer.has_open_quotes(s))
350 self.assertFalse(completer.has_open_quotes(s))
338
351
339 @pytest.mark.xfail(
352 @pytest.mark.xfail(
340 sys.platform == "win32", reason="abspath completions fail on Windows"
353 sys.platform == "win32", reason="abspath completions fail on Windows"
341 )
354 )
342 def test_abspath_file_completions(self):
355 def test_abspath_file_completions(self):
343 ip = get_ipython()
356 ip = get_ipython()
344 with TemporaryDirectory() as tmpdir:
357 with TemporaryDirectory() as tmpdir:
345 prefix = os.path.join(tmpdir, "foo")
358 prefix = os.path.join(tmpdir, "foo")
346 suffixes = ["1", "2"]
359 suffixes = ["1", "2"]
347 names = [prefix + s for s in suffixes]
360 names = [prefix + s for s in suffixes]
348 for n in names:
361 for n in names:
349 open(n, "w", encoding="utf-8").close()
362 open(n, "w", encoding="utf-8").close()
350
363
351 # Check simple completion
364 # Check simple completion
352 c = ip.complete(prefix)[1]
365 c = ip.complete(prefix)[1]
353 self.assertEqual(c, names)
366 self.assertEqual(c, names)
354
367
355 # Now check with a function call
368 # Now check with a function call
356 cmd = 'a = f("%s' % prefix
369 cmd = 'a = f("%s' % prefix
357 c = ip.complete(prefix, cmd)[1]
370 c = ip.complete(prefix, cmd)[1]
358 comp = [prefix + s for s in suffixes]
371 comp = [prefix + s for s in suffixes]
359 self.assertEqual(c, comp)
372 self.assertEqual(c, comp)
360
373
361 def test_local_file_completions(self):
374 def test_local_file_completions(self):
362 ip = get_ipython()
375 ip = get_ipython()
363 with TemporaryWorkingDirectory():
376 with TemporaryWorkingDirectory():
364 prefix = "./foo"
377 prefix = "./foo"
365 suffixes = ["1", "2"]
378 suffixes = ["1", "2"]
366 names = [prefix + s for s in suffixes]
379 names = [prefix + s for s in suffixes]
367 for n in names:
380 for n in names:
368 open(n, "w", encoding="utf-8").close()
381 open(n, "w", encoding="utf-8").close()
369
382
370 # Check simple completion
383 # Check simple completion
371 c = ip.complete(prefix)[1]
384 c = ip.complete(prefix)[1]
372 self.assertEqual(c, names)
385 self.assertEqual(c, names)
373
386
374 # Now check with a function call
387 # Now check with a function call
375 cmd = 'a = f("%s' % prefix
388 cmd = 'a = f("%s' % prefix
376 c = ip.complete(prefix, cmd)[1]
389 c = ip.complete(prefix, cmd)[1]
377 comp = {prefix + s for s in suffixes}
390 comp = {prefix + s for s in suffixes}
378 self.assertTrue(comp.issubset(set(c)))
391 self.assertTrue(comp.issubset(set(c)))
379
392
380 def test_quoted_file_completions(self):
393 def test_quoted_file_completions(self):
381 ip = get_ipython()
394 ip = get_ipython()
395
396 def _(text):
397 return ip.Completer._complete(
398 cursor_line=0, cursor_pos=len(text), full_text=text
399 )["IPCompleter.file_matcher"]["completions"]
400
382 with TemporaryWorkingDirectory():
401 with TemporaryWorkingDirectory():
383 name = "foo'bar"
402 name = "foo'bar"
384 open(name, "w", encoding="utf-8").close()
403 open(name, "w", encoding="utf-8").close()
385
404
386 # Don't escape Windows
405 # Don't escape Windows
387 escaped = name if sys.platform == "win32" else "foo\\'bar"
406 escaped = name if sys.platform == "win32" else "foo\\'bar"
388
407
389 # Single quote matches embedded single quote
408 # Single quote matches embedded single quote
390 text = "open('foo"
409 c = _("open('foo")[0]
391 c = ip.Completer._complete(
410 self.assertEqual(c.text, escaped)
392 cursor_line=0, cursor_pos=len(text), full_text=text
393 )[1]
394 self.assertEqual(c, [escaped])
395
411
396 # Double quote requires no escape
412 # Double quote requires no escape
397 text = 'open("foo'
413 c = _('open("foo')[0]
398 c = ip.Completer._complete(
414 self.assertEqual(c.text, name)
399 cursor_line=0, cursor_pos=len(text), full_text=text
400 )[1]
401 self.assertEqual(c, [name])
402
415
403 # No quote requires an escape
416 # No quote requires an escape
404 text = "%ls foo"
417 c = _("%ls foo")[0]
405 c = ip.Completer._complete(
418 self.assertEqual(c.text, escaped)
406 cursor_line=0, cursor_pos=len(text), full_text=text
407 )[1]
408 self.assertEqual(c, [escaped])
409
419
410 def test_all_completions_dups(self):
420 def test_all_completions_dups(self):
411 """
421 """
412 Make sure the output of `IPCompleter.all_completions` does not have
422 Make sure the output of `IPCompleter.all_completions` does not have
413 duplicated prefixes.
423 duplicated prefixes.
414 """
424 """
415 ip = get_ipython()
425 ip = get_ipython()
416 c = ip.Completer
426 c = ip.Completer
417 ip.ex("class TestClass():\n\ta=1\n\ta1=2")
427 ip.ex("class TestClass():\n\ta=1\n\ta1=2")
418 for jedi_status in [True, False]:
428 for jedi_status in [True, False]:
419 with provisionalcompleter():
429 with provisionalcompleter():
420 ip.Completer.use_jedi = jedi_status
430 ip.Completer.use_jedi = jedi_status
421 matches = c.all_completions("TestCl")
431 matches = c.all_completions("TestCl")
422 assert matches == ["TestClass"], (jedi_status, matches)
432 assert matches == ["TestClass"], (jedi_status, matches)
423 matches = c.all_completions("TestClass.")
433 matches = c.all_completions("TestClass.")
424 assert len(matches) > 2, (jedi_status, matches)
434 assert len(matches) > 2, (jedi_status, matches)
425 matches = c.all_completions("TestClass.a")
435 matches = c.all_completions("TestClass.a")
426 assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status
436 assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status
427
437
428 def test_jedi(self):
438 def test_jedi(self):
429 """
439 """
430 A couple of issue we had with Jedi
440 A couple of issue we had with Jedi
431 """
441 """
432 ip = get_ipython()
442 ip = get_ipython()
433
443
434 def _test_complete(reason, s, comp, start=None, end=None):
444 def _test_complete(reason, s, comp, start=None, end=None):
435 l = len(s)
445 l = len(s)
436 start = start if start is not None else l
446 start = start if start is not None else l
437 end = end if end is not None else l
447 end = end if end is not None else l
438 with provisionalcompleter():
448 with provisionalcompleter():
439 ip.Completer.use_jedi = True
449 ip.Completer.use_jedi = True
440 completions = set(ip.Completer.completions(s, l))
450 completions = set(ip.Completer.completions(s, l))
441 ip.Completer.use_jedi = False
451 ip.Completer.use_jedi = False
442 assert Completion(start, end, comp) in completions, reason
452 assert Completion(start, end, comp) in completions, reason
443
453
444 def _test_not_complete(reason, s, comp):
454 def _test_not_complete(reason, s, comp):
445 l = len(s)
455 l = len(s)
446 with provisionalcompleter():
456 with provisionalcompleter():
447 ip.Completer.use_jedi = True
457 ip.Completer.use_jedi = True
448 completions = set(ip.Completer.completions(s, l))
458 completions = set(ip.Completer.completions(s, l))
449 ip.Completer.use_jedi = False
459 ip.Completer.use_jedi = False
450 assert Completion(l, l, comp) not in completions, reason
460 assert Completion(l, l, comp) not in completions, reason
451
461
452 import jedi
462 import jedi
453
463
454 jedi_version = tuple(int(i) for i in jedi.__version__.split(".")[:3])
464 jedi_version = tuple(int(i) for i in jedi.__version__.split(".")[:3])
455 if jedi_version > (0, 10):
465 if jedi_version > (0, 10):
456 _test_complete("jedi >0.9 should complete and not crash", "a=1;a.", "real")
466 _test_complete("jedi >0.9 should complete and not crash", "a=1;a.", "real")
457 _test_complete("can infer first argument", 'a=(1,"foo");a[0].', "real")
467 _test_complete("can infer first argument", 'a=(1,"foo");a[0].', "real")
458 _test_complete("can infer second argument", 'a=(1,"foo");a[1].', "capitalize")
468 _test_complete("can infer second argument", 'a=(1,"foo");a[1].', "capitalize")
459 _test_complete("cover duplicate completions", "im", "import", 0, 2)
469 _test_complete("cover duplicate completions", "im", "import", 0, 2)
460
470
461 _test_not_complete("does not mix types", 'a=(1,"foo");a[0].', "capitalize")
471 _test_not_complete("does not mix types", 'a=(1,"foo");a[0].', "capitalize")
462
472
463 def test_completion_have_signature(self):
473 def test_completion_have_signature(self):
464 """
474 """
465 Lets make sure jedi is capable of pulling out the signature of the function we are completing.
475 Lets make sure jedi is capable of pulling out the signature of the function we are completing.
466 """
476 """
467 ip = get_ipython()
477 ip = get_ipython()
468 with provisionalcompleter():
478 with provisionalcompleter():
469 ip.Completer.use_jedi = True
479 ip.Completer.use_jedi = True
470 completions = ip.Completer.completions("ope", 3)
480 completions = ip.Completer.completions("ope", 3)
471 c = next(completions) # should be `open`
481 c = next(completions) # should be `open`
472 ip.Completer.use_jedi = False
482 ip.Completer.use_jedi = False
473 assert "file" in c.signature, "Signature of function was not found by completer"
483 assert "file" in c.signature, "Signature of function was not found by completer"
474 assert (
484 assert (
475 "encoding" in c.signature
485 "encoding" in c.signature
476 ), "Signature of function was not found by completer"
486 ), "Signature of function was not found by completer"
477
487
488 def test_completions_have_type(self):
489 """
490 Lets make sure matchers provide completion type.
491 """
492 ip = get_ipython()
493 with provisionalcompleter():
494 ip.Completer.use_jedi = False
495 completions = ip.Completer.completions("%tim", 3)
496 c = next(completions) # should be `%time` or similar
497 assert c.type == "magic", "Type of magic was not assigned by completer"
498
478 @pytest.mark.xfail(reason="Known failure on jedi<=0.18.0")
499 @pytest.mark.xfail(reason="Known failure on jedi<=0.18.0")
479 def test_deduplicate_completions(self):
500 def test_deduplicate_completions(self):
480 """
501 """
481 Test that completions are correctly deduplicated (even if ranges are not the same)
502 Test that completions are correctly deduplicated (even if ranges are not the same)
482 """
503 """
483 ip = get_ipython()
504 ip = get_ipython()
484 ip.ex(
505 ip.ex(
485 textwrap.dedent(
506 textwrap.dedent(
486 """
507 """
487 class Z:
508 class Z:
488 zoo = 1
509 zoo = 1
489 """
510 """
490 )
511 )
491 )
512 )
492 with provisionalcompleter():
513 with provisionalcompleter():
493 ip.Completer.use_jedi = True
514 ip.Completer.use_jedi = True
494 l = list(
515 l = list(
495 _deduplicate_completions("Z.z", ip.Completer.completions("Z.z", 3))
516 _deduplicate_completions("Z.z", ip.Completer.completions("Z.z", 3))
496 )
517 )
497 ip.Completer.use_jedi = False
518 ip.Completer.use_jedi = False
498
519
499 assert len(l) == 1, "Completions (Z.z<tab>) correctly deduplicate: %s " % l
520 assert len(l) == 1, "Completions (Z.z<tab>) correctly deduplicate: %s " % l
500 assert l[0].text == "zoo" # and not `it.accumulate`
521 assert l[0].text == "zoo" # and not `it.accumulate`
501
522
502 def test_greedy_completions(self):
523 def test_greedy_completions(self):
503 """
524 """
504 Test the capability of the Greedy completer.
525 Test the capability of the Greedy completer.
505
526
506 Most of the test here does not really show off the greedy completer, for proof
527 Most of the test here does not really show off the greedy completer, for proof
507 each of the text below now pass with Jedi. The greedy completer is capable of more.
528 each of the text below now pass with Jedi. The greedy completer is capable of more.
508
529
509 See the :any:`test_dict_key_completion_contexts`
530 See the :any:`test_dict_key_completion_contexts`
510
531
511 """
532 """
512 ip = get_ipython()
533 ip = get_ipython()
513 ip.ex("a=list(range(5))")
534 ip.ex("a=list(range(5))")
514 _, c = ip.complete(".", line="a[0].")
535 _, c = ip.complete(".", line="a[0].")
515 self.assertFalse(".real" in c, "Shouldn't have completed on a[0]: %s" % c)
536 self.assertFalse(".real" in c, "Shouldn't have completed on a[0]: %s" % c)
516
537
517 def _(line, cursor_pos, expect, message, completion):
538 def _(line, cursor_pos, expect, message, completion):
518 with greedy_completion(), provisionalcompleter():
539 with greedy_completion(), provisionalcompleter():
519 ip.Completer.use_jedi = False
540 ip.Completer.use_jedi = False
520 _, c = ip.complete(".", line=line, cursor_pos=cursor_pos)
541 _, c = ip.complete(".", line=line, cursor_pos=cursor_pos)
521 self.assertIn(expect, c, message % c)
542 self.assertIn(expect, c, message % c)
522
543
523 ip.Completer.use_jedi = True
544 ip.Completer.use_jedi = True
524 with provisionalcompleter():
545 with provisionalcompleter():
525 completions = ip.Completer.completions(line, cursor_pos)
546 completions = ip.Completer.completions(line, cursor_pos)
526 self.assertIn(completion, completions)
547 self.assertIn(completion, completions)
527
548
528 with provisionalcompleter():
549 with provisionalcompleter():
529 _(
550 _(
530 "a[0].",
551 "a[0].",
531 5,
552 5,
532 "a[0].real",
553 "a[0].real",
533 "Should have completed on a[0].: %s",
554 "Should have completed on a[0].: %s",
534 Completion(5, 5, "real"),
555 Completion(5, 5, "real"),
535 )
556 )
536 _(
557 _(
537 "a[0].r",
558 "a[0].r",
538 6,
559 6,
539 "a[0].real",
560 "a[0].real",
540 "Should have completed on a[0].r: %s",
561 "Should have completed on a[0].r: %s",
541 Completion(5, 6, "real"),
562 Completion(5, 6, "real"),
542 )
563 )
543
564
544 _(
565 _(
545 "a[0].from_",
566 "a[0].from_",
546 10,
567 10,
547 "a[0].from_bytes",
568 "a[0].from_bytes",
548 "Should have completed on a[0].from_: %s",
569 "Should have completed on a[0].from_: %s",
549 Completion(5, 10, "from_bytes"),
570 Completion(5, 10, "from_bytes"),
550 )
571 )
551
572
552 def test_omit__names(self):
573 def test_omit__names(self):
553 # also happens to test IPCompleter as a configurable
574 # also happens to test IPCompleter as a configurable
554 ip = get_ipython()
575 ip = get_ipython()
555 ip._hidden_attr = 1
576 ip._hidden_attr = 1
556 ip._x = {}
577 ip._x = {}
557 c = ip.Completer
578 c = ip.Completer
558 ip.ex("ip=get_ipython()")
579 ip.ex("ip=get_ipython()")
559 cfg = Config()
580 cfg = Config()
560 cfg.IPCompleter.omit__names = 0
581 cfg.IPCompleter.omit__names = 0
561 c.update_config(cfg)
582 c.update_config(cfg)
562 with provisionalcompleter():
583 with provisionalcompleter():
563 c.use_jedi = False
584 c.use_jedi = False
564 s, matches = c.complete("ip.")
585 s, matches = c.complete("ip.")
565 self.assertIn("ip.__str__", matches)
586 self.assertIn("ip.__str__", matches)
566 self.assertIn("ip._hidden_attr", matches)
587 self.assertIn("ip._hidden_attr", matches)
567
588
568 # c.use_jedi = True
589 # c.use_jedi = True
569 # completions = set(c.completions('ip.', 3))
590 # completions = set(c.completions('ip.', 3))
570 # self.assertIn(Completion(3, 3, '__str__'), completions)
591 # self.assertIn(Completion(3, 3, '__str__'), completions)
571 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
592 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
572
593
573 cfg = Config()
594 cfg = Config()
574 cfg.IPCompleter.omit__names = 1
595 cfg.IPCompleter.omit__names = 1
575 c.update_config(cfg)
596 c.update_config(cfg)
576 with provisionalcompleter():
597 with provisionalcompleter():
577 c.use_jedi = False
598 c.use_jedi = False
578 s, matches = c.complete("ip.")
599 s, matches = c.complete("ip.")
579 self.assertNotIn("ip.__str__", matches)
600 self.assertNotIn("ip.__str__", matches)
580 # self.assertIn('ip._hidden_attr', matches)
601 # self.assertIn('ip._hidden_attr', matches)
581
602
582 # c.use_jedi = True
603 # c.use_jedi = True
583 # completions = set(c.completions('ip.', 3))
604 # completions = set(c.completions('ip.', 3))
584 # self.assertNotIn(Completion(3,3,'__str__'), completions)
605 # self.assertNotIn(Completion(3,3,'__str__'), completions)
585 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
606 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
586
607
587 cfg = Config()
608 cfg = Config()
588 cfg.IPCompleter.omit__names = 2
609 cfg.IPCompleter.omit__names = 2
589 c.update_config(cfg)
610 c.update_config(cfg)
590 with provisionalcompleter():
611 with provisionalcompleter():
591 c.use_jedi = False
612 c.use_jedi = False
592 s, matches = c.complete("ip.")
613 s, matches = c.complete("ip.")
593 self.assertNotIn("ip.__str__", matches)
614 self.assertNotIn("ip.__str__", matches)
594 self.assertNotIn("ip._hidden_attr", matches)
615 self.assertNotIn("ip._hidden_attr", matches)
595
616
596 # c.use_jedi = True
617 # c.use_jedi = True
597 # completions = set(c.completions('ip.', 3))
618 # completions = set(c.completions('ip.', 3))
598 # self.assertNotIn(Completion(3,3,'__str__'), completions)
619 # self.assertNotIn(Completion(3,3,'__str__'), completions)
599 # self.assertNotIn(Completion(3,3, "_hidden_attr"), completions)
620 # self.assertNotIn(Completion(3,3, "_hidden_attr"), completions)
600
621
601 with provisionalcompleter():
622 with provisionalcompleter():
602 c.use_jedi = False
623 c.use_jedi = False
603 s, matches = c.complete("ip._x.")
624 s, matches = c.complete("ip._x.")
604 self.assertIn("ip._x.keys", matches)
625 self.assertIn("ip._x.keys", matches)
605
626
606 # c.use_jedi = True
627 # c.use_jedi = True
607 # completions = set(c.completions('ip._x.', 6))
628 # completions = set(c.completions('ip._x.', 6))
608 # self.assertIn(Completion(6,6, "keys"), completions)
629 # self.assertIn(Completion(6,6, "keys"), completions)
609
630
610 del ip._hidden_attr
631 del ip._hidden_attr
611 del ip._x
632 del ip._x
612
633
613 def test_limit_to__all__False_ok(self):
634 def test_limit_to__all__False_ok(self):
614 """
635 """
615 Limit to all is deprecated, once we remove it this test can go away.
636 Limit to all is deprecated, once we remove it this test can go away.
616 """
637 """
617 ip = get_ipython()
638 ip = get_ipython()
618 c = ip.Completer
639 c = ip.Completer
619 c.use_jedi = False
640 c.use_jedi = False
620 ip.ex("class D: x=24")
641 ip.ex("class D: x=24")
621 ip.ex("d=D()")
642 ip.ex("d=D()")
622 cfg = Config()
643 cfg = Config()
623 cfg.IPCompleter.limit_to__all__ = False
644 cfg.IPCompleter.limit_to__all__ = False
624 c.update_config(cfg)
645 c.update_config(cfg)
625 s, matches = c.complete("d.")
646 s, matches = c.complete("d.")
626 self.assertIn("d.x", matches)
647 self.assertIn("d.x", matches)
627
648
628 def test_get__all__entries_ok(self):
649 def test_get__all__entries_ok(self):
629 class A:
650 class A:
630 __all__ = ["x", 1]
651 __all__ = ["x", 1]
631
652
632 words = completer.get__all__entries(A())
653 words = completer.get__all__entries(A())
633 self.assertEqual(words, ["x"])
654 self.assertEqual(words, ["x"])
634
655
635 def test_get__all__entries_no__all__ok(self):
656 def test_get__all__entries_no__all__ok(self):
636 class A:
657 class A:
637 pass
658 pass
638
659
639 words = completer.get__all__entries(A())
660 words = completer.get__all__entries(A())
640 self.assertEqual(words, [])
661 self.assertEqual(words, [])
641
662
642 def test_func_kw_completions(self):
663 def test_func_kw_completions(self):
643 ip = get_ipython()
664 ip = get_ipython()
644 c = ip.Completer
665 c = ip.Completer
645 c.use_jedi = False
666 c.use_jedi = False
646 ip.ex("def myfunc(a=1,b=2): return a+b")
667 ip.ex("def myfunc(a=1,b=2): return a+b")
647 s, matches = c.complete(None, "myfunc(1,b")
668 s, matches = c.complete(None, "myfunc(1,b")
648 self.assertIn("b=", matches)
669 self.assertIn("b=", matches)
649 # Simulate completing with cursor right after b (pos==10):
670 # Simulate completing with cursor right after b (pos==10):
650 s, matches = c.complete(None, "myfunc(1,b)", 10)
671 s, matches = c.complete(None, "myfunc(1,b)", 10)
651 self.assertIn("b=", matches)
672 self.assertIn("b=", matches)
652 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
673 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
653 self.assertIn("b=", matches)
674 self.assertIn("b=", matches)
654 # builtin function
675 # builtin function
655 s, matches = c.complete(None, "min(k, k")
676 s, matches = c.complete(None, "min(k, k")
656 self.assertIn("key=", matches)
677 self.assertIn("key=", matches)
657
678
658 def test_default_arguments_from_docstring(self):
679 def test_default_arguments_from_docstring(self):
659 ip = get_ipython()
680 ip = get_ipython()
660 c = ip.Completer
681 c = ip.Completer
661 kwd = c._default_arguments_from_docstring("min(iterable[, key=func]) -> value")
682 kwd = c._default_arguments_from_docstring("min(iterable[, key=func]) -> value")
662 self.assertEqual(kwd, ["key"])
683 self.assertEqual(kwd, ["key"])
663 # with cython type etc
684 # with cython type etc
664 kwd = c._default_arguments_from_docstring(
685 kwd = c._default_arguments_from_docstring(
665 "Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
686 "Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
666 )
687 )
667 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
688 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
668 # white spaces
689 # white spaces
669 kwd = c._default_arguments_from_docstring(
690 kwd = c._default_arguments_from_docstring(
670 "\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
691 "\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
671 )
692 )
672 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
693 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
673
694
674 def test_line_magics(self):
695 def test_line_magics(self):
675 ip = get_ipython()
696 ip = get_ipython()
676 c = ip.Completer
697 c = ip.Completer
677 s, matches = c.complete(None, "lsmag")
698 s, matches = c.complete(None, "lsmag")
678 self.assertIn("%lsmagic", matches)
699 self.assertIn("%lsmagic", matches)
679 s, matches = c.complete(None, "%lsmag")
700 s, matches = c.complete(None, "%lsmag")
680 self.assertIn("%lsmagic", matches)
701 self.assertIn("%lsmagic", matches)
681
702
682 def test_cell_magics(self):
703 def test_cell_magics(self):
683 from IPython.core.magic import register_cell_magic
704 from IPython.core.magic import register_cell_magic
684
705
685 @register_cell_magic
706 @register_cell_magic
686 def _foo_cellm(line, cell):
707 def _foo_cellm(line, cell):
687 pass
708 pass
688
709
689 ip = get_ipython()
710 ip = get_ipython()
690 c = ip.Completer
711 c = ip.Completer
691
712
692 s, matches = c.complete(None, "_foo_ce")
713 s, matches = c.complete(None, "_foo_ce")
693 self.assertIn("%%_foo_cellm", matches)
714 self.assertIn("%%_foo_cellm", matches)
694 s, matches = c.complete(None, "%%_foo_ce")
715 s, matches = c.complete(None, "%%_foo_ce")
695 self.assertIn("%%_foo_cellm", matches)
716 self.assertIn("%%_foo_cellm", matches)
696
717
697 def test_line_cell_magics(self):
718 def test_line_cell_magics(self):
698 from IPython.core.magic import register_line_cell_magic
719 from IPython.core.magic import register_line_cell_magic
699
720
700 @register_line_cell_magic
721 @register_line_cell_magic
701 def _bar_cellm(line, cell):
722 def _bar_cellm(line, cell):
702 pass
723 pass
703
724
704 ip = get_ipython()
725 ip = get_ipython()
705 c = ip.Completer
726 c = ip.Completer
706
727
707 # The policy here is trickier, see comments in completion code. The
728 # The policy here is trickier, see comments in completion code. The
708 # returned values depend on whether the user passes %% or not explicitly,
729 # returned values depend on whether the user passes %% or not explicitly,
709 # and this will show a difference if the same name is both a line and cell
730 # and this will show a difference if the same name is both a line and cell
710 # magic.
731 # magic.
711 s, matches = c.complete(None, "_bar_ce")
732 s, matches = c.complete(None, "_bar_ce")
712 self.assertIn("%_bar_cellm", matches)
733 self.assertIn("%_bar_cellm", matches)
713 self.assertIn("%%_bar_cellm", matches)
734 self.assertIn("%%_bar_cellm", matches)
714 s, matches = c.complete(None, "%_bar_ce")
735 s, matches = c.complete(None, "%_bar_ce")
715 self.assertIn("%_bar_cellm", matches)
736 self.assertIn("%_bar_cellm", matches)
716 self.assertIn("%%_bar_cellm", matches)
737 self.assertIn("%%_bar_cellm", matches)
717 s, matches = c.complete(None, "%%_bar_ce")
738 s, matches = c.complete(None, "%%_bar_ce")
718 self.assertNotIn("%_bar_cellm", matches)
739 self.assertNotIn("%_bar_cellm", matches)
719 self.assertIn("%%_bar_cellm", matches)
740 self.assertIn("%%_bar_cellm", matches)
720
741
721 def test_magic_completion_order(self):
742 def test_magic_completion_order(self):
722 ip = get_ipython()
743 ip = get_ipython()
723 c = ip.Completer
744 c = ip.Completer
724
745
725 # Test ordering of line and cell magics.
746 # Test ordering of line and cell magics.
726 text, matches = c.complete("timeit")
747 text, matches = c.complete("timeit")
727 self.assertEqual(matches, ["%timeit", "%%timeit"])
748 self.assertEqual(matches, ["%timeit", "%%timeit"])
728
749
729 def test_magic_completion_shadowing(self):
750 def test_magic_completion_shadowing(self):
730 ip = get_ipython()
751 ip = get_ipython()
731 c = ip.Completer
752 c = ip.Completer
732 c.use_jedi = False
753 c.use_jedi = False
733
754
734 # Before importing matplotlib, %matplotlib magic should be the only option.
755 # Before importing matplotlib, %matplotlib magic should be the only option.
735 text, matches = c.complete("mat")
756 text, matches = c.complete("mat")
736 self.assertEqual(matches, ["%matplotlib"])
757 self.assertEqual(matches, ["%matplotlib"])
737
758
738 # The newly introduced name should shadow the magic.
759 # The newly introduced name should shadow the magic.
739 ip.run_cell("matplotlib = 1")
760 ip.run_cell("matplotlib = 1")
740 text, matches = c.complete("mat")
761 text, matches = c.complete("mat")
741 self.assertEqual(matches, ["matplotlib"])
762 self.assertEqual(matches, ["matplotlib"])
742
763
743 # After removing matplotlib from namespace, the magic should again be
764 # After removing matplotlib from namespace, the magic should again be
744 # the only option.
765 # the only option.
745 del ip.user_ns["matplotlib"]
766 del ip.user_ns["matplotlib"]
746 text, matches = c.complete("mat")
767 text, matches = c.complete("mat")
747 self.assertEqual(matches, ["%matplotlib"])
768 self.assertEqual(matches, ["%matplotlib"])
748
769
749 def test_magic_completion_shadowing_explicit(self):
770 def test_magic_completion_shadowing_explicit(self):
750 """
771 """
751 If the user try to complete a shadowed magic, and explicit % start should
772 If the user try to complete a shadowed magic, and explicit % start should
752 still return the completions.
773 still return the completions.
753 """
774 """
754 ip = get_ipython()
775 ip = get_ipython()
755 c = ip.Completer
776 c = ip.Completer
756
777
757 # Before importing matplotlib, %matplotlib magic should be the only option.
778 # Before importing matplotlib, %matplotlib magic should be the only option.
758 text, matches = c.complete("%mat")
779 text, matches = c.complete("%mat")
759 self.assertEqual(matches, ["%matplotlib"])
780 self.assertEqual(matches, ["%matplotlib"])
760
781
761 ip.run_cell("matplotlib = 1")
782 ip.run_cell("matplotlib = 1")
762
783
763 # After removing matplotlib from namespace, the magic should still be
784 # After removing matplotlib from namespace, the magic should still be
764 # the only option.
785 # the only option.
765 text, matches = c.complete("%mat")
786 text, matches = c.complete("%mat")
766 self.assertEqual(matches, ["%matplotlib"])
787 self.assertEqual(matches, ["%matplotlib"])
767
788
768 def test_magic_config(self):
789 def test_magic_config(self):
769 ip = get_ipython()
790 ip = get_ipython()
770 c = ip.Completer
791 c = ip.Completer
771
792
772 s, matches = c.complete(None, "conf")
793 s, matches = c.complete(None, "conf")
773 self.assertIn("%config", matches)
794 self.assertIn("%config", matches)
774 s, matches = c.complete(None, "conf")
795 s, matches = c.complete(None, "conf")
775 self.assertNotIn("AliasManager", matches)
796 self.assertNotIn("AliasManager", matches)
776 s, matches = c.complete(None, "config ")
797 s, matches = c.complete(None, "config ")
777 self.assertIn("AliasManager", matches)
798 self.assertIn("AliasManager", matches)
778 s, matches = c.complete(None, "%config ")
799 s, matches = c.complete(None, "%config ")
779 self.assertIn("AliasManager", matches)
800 self.assertIn("AliasManager", matches)
780 s, matches = c.complete(None, "config Ali")
801 s, matches = c.complete(None, "config Ali")
781 self.assertListEqual(["AliasManager"], matches)
802 self.assertListEqual(["AliasManager"], matches)
782 s, matches = c.complete(None, "%config Ali")
803 s, matches = c.complete(None, "%config Ali")
783 self.assertListEqual(["AliasManager"], matches)
804 self.assertListEqual(["AliasManager"], matches)
784 s, matches = c.complete(None, "config AliasManager")
805 s, matches = c.complete(None, "config AliasManager")
785 self.assertListEqual(["AliasManager"], matches)
806 self.assertListEqual(["AliasManager"], matches)
786 s, matches = c.complete(None, "%config AliasManager")
807 s, matches = c.complete(None, "%config AliasManager")
787 self.assertListEqual(["AliasManager"], matches)
808 self.assertListEqual(["AliasManager"], matches)
788 s, matches = c.complete(None, "config AliasManager.")
809 s, matches = c.complete(None, "config AliasManager.")
789 self.assertIn("AliasManager.default_aliases", matches)
810 self.assertIn("AliasManager.default_aliases", matches)
790 s, matches = c.complete(None, "%config AliasManager.")
811 s, matches = c.complete(None, "%config AliasManager.")
791 self.assertIn("AliasManager.default_aliases", matches)
812 self.assertIn("AliasManager.default_aliases", matches)
792 s, matches = c.complete(None, "config AliasManager.de")
813 s, matches = c.complete(None, "config AliasManager.de")
793 self.assertListEqual(["AliasManager.default_aliases"], matches)
814 self.assertListEqual(["AliasManager.default_aliases"], matches)
794 s, matches = c.complete(None, "config AliasManager.de")
815 s, matches = c.complete(None, "config AliasManager.de")
795 self.assertListEqual(["AliasManager.default_aliases"], matches)
816 self.assertListEqual(["AliasManager.default_aliases"], matches)
796
817
797 def test_magic_color(self):
818 def test_magic_color(self):
798 ip = get_ipython()
819 ip = get_ipython()
799 c = ip.Completer
820 c = ip.Completer
800
821
801 s, matches = c.complete(None, "colo")
822 s, matches = c.complete(None, "colo")
802 self.assertIn("%colors", matches)
823 self.assertIn("%colors", matches)
803 s, matches = c.complete(None, "colo")
824 s, matches = c.complete(None, "colo")
804 self.assertNotIn("NoColor", matches)
825 self.assertNotIn("NoColor", matches)
805 s, matches = c.complete(None, "%colors") # No trailing space
826 s, matches = c.complete(None, "%colors") # No trailing space
806 self.assertNotIn("NoColor", matches)
827 self.assertNotIn("NoColor", matches)
807 s, matches = c.complete(None, "colors ")
828 s, matches = c.complete(None, "colors ")
808 self.assertIn("NoColor", matches)
829 self.assertIn("NoColor", matches)
809 s, matches = c.complete(None, "%colors ")
830 s, matches = c.complete(None, "%colors ")
810 self.assertIn("NoColor", matches)
831 self.assertIn("NoColor", matches)
811 s, matches = c.complete(None, "colors NoCo")
832 s, matches = c.complete(None, "colors NoCo")
812 self.assertListEqual(["NoColor"], matches)
833 self.assertListEqual(["NoColor"], matches)
813 s, matches = c.complete(None, "%colors NoCo")
834 s, matches = c.complete(None, "%colors NoCo")
814 self.assertListEqual(["NoColor"], matches)
835 self.assertListEqual(["NoColor"], matches)
815
836
816 def test_match_dict_keys(self):
837 def test_match_dict_keys(self):
817 """
838 """
818 Test that match_dict_keys works on a couple of use case does return what
839 Test that match_dict_keys works on a couple of use case does return what
819 expected, and does not crash
840 expected, and does not crash
820 """
841 """
821 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
842 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
822
843
823 keys = ["foo", b"far"]
844 keys = ["foo", b"far"]
824 assert match_dict_keys(keys, "b'", delims=delims) == ("'", 2, ["far"])
845 assert match_dict_keys(keys, "b'", delims=delims) == ("'", 2, ["far"])
825 assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2, ["far"])
846 assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2, ["far"])
826 assert match_dict_keys(keys, 'b"', delims=delims) == ('"', 2, ["far"])
847 assert match_dict_keys(keys, 'b"', delims=delims) == ('"', 2, ["far"])
827 assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2, ["far"])
848 assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2, ["far"])
828
849
829 assert match_dict_keys(keys, "'", delims=delims) == ("'", 1, ["foo"])
850 assert match_dict_keys(keys, "'", delims=delims) == ("'", 1, ["foo"])
830 assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1, ["foo"])
851 assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1, ["foo"])
831 assert match_dict_keys(keys, '"', delims=delims) == ('"', 1, ["foo"])
852 assert match_dict_keys(keys, '"', delims=delims) == ('"', 1, ["foo"])
832 assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1, ["foo"])
853 assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1, ["foo"])
833
854
834 match_dict_keys
855 match_dict_keys
835
856
836 def test_match_dict_keys_tuple(self):
857 def test_match_dict_keys_tuple(self):
837 """
858 """
838 Test that match_dict_keys called with extra prefix works on a couple of use case,
859 Test that match_dict_keys called with extra prefix works on a couple of use case,
839 does return what expected, and does not crash.
860 does return what expected, and does not crash.
840 """
861 """
841 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
862 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
842
863
843 keys = [("foo", "bar"), ("foo", "oof"), ("foo", b"bar"), ('other', 'test')]
864 keys = [("foo", "bar"), ("foo", "oof"), ("foo", b"bar"), ('other', 'test')]
844
865
845 # Completion on first key == "foo"
866 # Completion on first key == "foo"
846 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["bar", "oof"])
867 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["bar", "oof"])
847 assert match_dict_keys(keys, "\"", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["bar", "oof"])
868 assert match_dict_keys(keys, "\"", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["bar", "oof"])
848 assert match_dict_keys(keys, "'o", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["oof"])
869 assert match_dict_keys(keys, "'o", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["oof"])
849 assert match_dict_keys(keys, "\"o", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["oof"])
870 assert match_dict_keys(keys, "\"o", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["oof"])
850 assert match_dict_keys(keys, "b'", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
871 assert match_dict_keys(keys, "b'", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
851 assert match_dict_keys(keys, "b\"", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
872 assert match_dict_keys(keys, "b\"", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
852 assert match_dict_keys(keys, "b'b", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
873 assert match_dict_keys(keys, "b'b", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
853 assert match_dict_keys(keys, "b\"b", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
874 assert match_dict_keys(keys, "b\"b", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
854
875
855 # No Completion
876 # No Completion
856 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("no_foo",)) == ("'", 1, [])
877 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("no_foo",)) == ("'", 1, [])
857 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("fo",)) == ("'", 1, [])
878 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("fo",)) == ("'", 1, [])
858
879
859 keys = [('foo1', 'foo2', 'foo3', 'foo4'), ('foo1', 'foo2', 'bar', 'foo4')]
880 keys = [('foo1', 'foo2', 'foo3', 'foo4'), ('foo1', 'foo2', 'bar', 'foo4')]
860 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1',)) == ("'", 1, ["foo2", "foo2"])
881 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1',)) == ("'", 1, ["foo2", "foo2"])
861 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2')) == ("'", 1, ["foo3"])
882 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2')) == ("'", 1, ["foo3"])
862 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3')) == ("'", 1, ["foo4"])
883 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3')) == ("'", 1, ["foo4"])
863 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3', 'foo4')) == ("'", 1, [])
884 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3', 'foo4')) == ("'", 1, [])
864
885
865 def test_dict_key_completion_string(self):
886 def test_dict_key_completion_string(self):
866 """Test dictionary key completion for string keys"""
887 """Test dictionary key completion for string keys"""
867 ip = get_ipython()
888 ip = get_ipython()
868 complete = ip.Completer.complete
889 complete = ip.Completer.complete
869
890
870 ip.user_ns["d"] = {"abc": None}
891 ip.user_ns["d"] = {"abc": None}
871
892
872 # check completion at different stages
893 # check completion at different stages
873 _, matches = complete(line_buffer="d[")
894 _, matches = complete(line_buffer="d[")
874 self.assertIn("'abc'", matches)
895 self.assertIn("'abc'", matches)
875 self.assertNotIn("'abc']", matches)
896 self.assertNotIn("'abc']", matches)
876
897
877 _, matches = complete(line_buffer="d['")
898 _, matches = complete(line_buffer="d['")
878 self.assertIn("abc", matches)
899 self.assertIn("abc", matches)
879 self.assertNotIn("abc']", matches)
900 self.assertNotIn("abc']", matches)
880
901
881 _, matches = complete(line_buffer="d['a")
902 _, matches = complete(line_buffer="d['a")
882 self.assertIn("abc", matches)
903 self.assertIn("abc", matches)
883 self.assertNotIn("abc']", matches)
904 self.assertNotIn("abc']", matches)
884
905
885 # check use of different quoting
906 # check use of different quoting
886 _, matches = complete(line_buffer='d["')
907 _, matches = complete(line_buffer='d["')
887 self.assertIn("abc", matches)
908 self.assertIn("abc", matches)
888 self.assertNotIn('abc"]', matches)
909 self.assertNotIn('abc"]', matches)
889
910
890 _, matches = complete(line_buffer='d["a')
911 _, matches = complete(line_buffer='d["a')
891 self.assertIn("abc", matches)
912 self.assertIn("abc", matches)
892 self.assertNotIn('abc"]', matches)
913 self.assertNotIn('abc"]', matches)
893
914
894 # check sensitivity to following context
915 # check sensitivity to following context
895 _, matches = complete(line_buffer="d[]", cursor_pos=2)
916 _, matches = complete(line_buffer="d[]", cursor_pos=2)
896 self.assertIn("'abc'", matches)
917 self.assertIn("'abc'", matches)
897
918
898 _, matches = complete(line_buffer="d['']", cursor_pos=3)
919 _, matches = complete(line_buffer="d['']", cursor_pos=3)
899 self.assertIn("abc", matches)
920 self.assertIn("abc", matches)
900 self.assertNotIn("abc'", matches)
921 self.assertNotIn("abc'", matches)
901 self.assertNotIn("abc']", matches)
922 self.assertNotIn("abc']", matches)
902
923
903 # check multiple solutions are correctly returned and that noise is not
924 # check multiple solutions are correctly returned and that noise is not
904 ip.user_ns["d"] = {
925 ip.user_ns["d"] = {
905 "abc": None,
926 "abc": None,
906 "abd": None,
927 "abd": None,
907 "bad": None,
928 "bad": None,
908 object(): None,
929 object(): None,
909 5: None,
930 5: None,
910 ("abe", None): None,
931 ("abe", None): None,
911 (None, "abf"): None
932 (None, "abf"): None
912 }
933 }
913
934
914 _, matches = complete(line_buffer="d['a")
935 _, matches = complete(line_buffer="d['a")
915 self.assertIn("abc", matches)
936 self.assertIn("abc", matches)
916 self.assertIn("abd", matches)
937 self.assertIn("abd", matches)
917 self.assertNotIn("bad", matches)
938 self.assertNotIn("bad", matches)
918 self.assertNotIn("abe", matches)
939 self.assertNotIn("abe", matches)
919 self.assertNotIn("abf", matches)
940 self.assertNotIn("abf", matches)
920 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
941 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
921
942
922 # check escaping and whitespace
943 # check escaping and whitespace
923 ip.user_ns["d"] = {"a\nb": None, "a'b": None, 'a"b': None, "a word": None}
944 ip.user_ns["d"] = {"a\nb": None, "a'b": None, 'a"b': None, "a word": None}
924 _, matches = complete(line_buffer="d['a")
945 _, matches = complete(line_buffer="d['a")
925 self.assertIn("a\\nb", matches)
946 self.assertIn("a\\nb", matches)
926 self.assertIn("a\\'b", matches)
947 self.assertIn("a\\'b", matches)
927 self.assertIn('a"b', matches)
948 self.assertIn('a"b', matches)
928 self.assertIn("a word", matches)
949 self.assertIn("a word", matches)
929 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
950 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
930
951
931 # - can complete on non-initial word of the string
952 # - can complete on non-initial word of the string
932 _, matches = complete(line_buffer="d['a w")
953 _, matches = complete(line_buffer="d['a w")
933 self.assertIn("word", matches)
954 self.assertIn("word", matches)
934
955
935 # - understands quote escaping
956 # - understands quote escaping
936 _, matches = complete(line_buffer="d['a\\'")
957 _, matches = complete(line_buffer="d['a\\'")
937 self.assertIn("b", matches)
958 self.assertIn("b", matches)
938
959
939 # - default quoting should work like repr
960 # - default quoting should work like repr
940 _, matches = complete(line_buffer="d[")
961 _, matches = complete(line_buffer="d[")
941 self.assertIn('"a\'b"', matches)
962 self.assertIn('"a\'b"', matches)
942
963
943 # - when opening quote with ", possible to match with unescaped apostrophe
964 # - when opening quote with ", possible to match with unescaped apostrophe
944 _, matches = complete(line_buffer="d[\"a'")
965 _, matches = complete(line_buffer="d[\"a'")
945 self.assertIn("b", matches)
966 self.assertIn("b", matches)
946
967
947 # need to not split at delims that readline won't split at
968 # need to not split at delims that readline won't split at
948 if "-" not in ip.Completer.splitter.delims:
969 if "-" not in ip.Completer.splitter.delims:
949 ip.user_ns["d"] = {"before-after": None}
970 ip.user_ns["d"] = {"before-after": None}
950 _, matches = complete(line_buffer="d['before-af")
971 _, matches = complete(line_buffer="d['before-af")
951 self.assertIn("before-after", matches)
972 self.assertIn("before-after", matches)
952
973
953 # check completion on tuple-of-string keys at different stage - on first key
974 # check completion on tuple-of-string keys at different stage - on first key
954 ip.user_ns["d"] = {('foo', 'bar'): None}
975 ip.user_ns["d"] = {('foo', 'bar'): None}
955 _, matches = complete(line_buffer="d[")
976 _, matches = complete(line_buffer="d[")
956 self.assertIn("'foo'", matches)
977 self.assertIn("'foo'", matches)
957 self.assertNotIn("'foo']", matches)
978 self.assertNotIn("'foo']", matches)
958 self.assertNotIn("'bar'", matches)
979 self.assertNotIn("'bar'", matches)
959 self.assertNotIn("foo", matches)
980 self.assertNotIn("foo", matches)
960 self.assertNotIn("bar", matches)
981 self.assertNotIn("bar", matches)
961
982
962 # - match the prefix
983 # - match the prefix
963 _, matches = complete(line_buffer="d['f")
984 _, matches = complete(line_buffer="d['f")
964 self.assertIn("foo", matches)
985 self.assertIn("foo", matches)
965 self.assertNotIn("foo']", matches)
986 self.assertNotIn("foo']", matches)
966 self.assertNotIn('foo"]', matches)
987 self.assertNotIn('foo"]', matches)
967 _, matches = complete(line_buffer="d['foo")
988 _, matches = complete(line_buffer="d['foo")
968 self.assertIn("foo", matches)
989 self.assertIn("foo", matches)
969
990
970 # - can complete on second key
991 # - can complete on second key
971 _, matches = complete(line_buffer="d['foo', ")
992 _, matches = complete(line_buffer="d['foo', ")
972 self.assertIn("'bar'", matches)
993 self.assertIn("'bar'", matches)
973 _, matches = complete(line_buffer="d['foo', 'b")
994 _, matches = complete(line_buffer="d['foo', 'b")
974 self.assertIn("bar", matches)
995 self.assertIn("bar", matches)
975 self.assertNotIn("foo", matches)
996 self.assertNotIn("foo", matches)
976
997
977 # - does not propose missing keys
998 # - does not propose missing keys
978 _, matches = complete(line_buffer="d['foo', 'f")
999 _, matches = complete(line_buffer="d['foo', 'f")
979 self.assertNotIn("bar", matches)
1000 self.assertNotIn("bar", matches)
980 self.assertNotIn("foo", matches)
1001 self.assertNotIn("foo", matches)
981
1002
982 # check sensitivity to following context
1003 # check sensitivity to following context
983 _, matches = complete(line_buffer="d['foo',]", cursor_pos=8)
1004 _, matches = complete(line_buffer="d['foo',]", cursor_pos=8)
984 self.assertIn("'bar'", matches)
1005 self.assertIn("'bar'", matches)
985 self.assertNotIn("bar", matches)
1006 self.assertNotIn("bar", matches)
986 self.assertNotIn("'foo'", matches)
1007 self.assertNotIn("'foo'", matches)
987 self.assertNotIn("foo", matches)
1008 self.assertNotIn("foo", matches)
988
1009
989 _, matches = complete(line_buffer="d['']", cursor_pos=3)
1010 _, matches = complete(line_buffer="d['']", cursor_pos=3)
990 self.assertIn("foo", matches)
1011 self.assertIn("foo", matches)
991 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1012 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
992
1013
993 _, matches = complete(line_buffer='d[""]', cursor_pos=3)
1014 _, matches = complete(line_buffer='d[""]', cursor_pos=3)
994 self.assertIn("foo", matches)
1015 self.assertIn("foo", matches)
995 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1016 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
996
1017
997 _, matches = complete(line_buffer='d["foo","]', cursor_pos=9)
1018 _, matches = complete(line_buffer='d["foo","]', cursor_pos=9)
998 self.assertIn("bar", matches)
1019 self.assertIn("bar", matches)
999 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1020 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1000
1021
1001 _, matches = complete(line_buffer='d["foo",]', cursor_pos=8)
1022 _, matches = complete(line_buffer='d["foo",]', cursor_pos=8)
1002 self.assertIn("'bar'", matches)
1023 self.assertIn("'bar'", matches)
1003 self.assertNotIn("bar", matches)
1024 self.assertNotIn("bar", matches)
1004
1025
1005 # Can complete with longer tuple keys
1026 # Can complete with longer tuple keys
1006 ip.user_ns["d"] = {('foo', 'bar', 'foobar'): None}
1027 ip.user_ns["d"] = {('foo', 'bar', 'foobar'): None}
1007
1028
1008 # - can complete second key
1029 # - can complete second key
1009 _, matches = complete(line_buffer="d['foo', 'b")
1030 _, matches = complete(line_buffer="d['foo', 'b")
1010 self.assertIn("bar", matches)
1031 self.assertIn("bar", matches)
1011 self.assertNotIn("foo", matches)
1032 self.assertNotIn("foo", matches)
1012 self.assertNotIn("foobar", matches)
1033 self.assertNotIn("foobar", matches)
1013
1034
1014 # - can complete third key
1035 # - can complete third key
1015 _, matches = complete(line_buffer="d['foo', 'bar', 'fo")
1036 _, matches = complete(line_buffer="d['foo', 'bar', 'fo")
1016 self.assertIn("foobar", matches)
1037 self.assertIn("foobar", matches)
1017 self.assertNotIn("foo", matches)
1038 self.assertNotIn("foo", matches)
1018 self.assertNotIn("bar", matches)
1039 self.assertNotIn("bar", matches)
1019
1040
1020 def test_dict_key_completion_contexts(self):
1041 def test_dict_key_completion_contexts(self):
1021 """Test expression contexts in which dict key completion occurs"""
1042 """Test expression contexts in which dict key completion occurs"""
1022 ip = get_ipython()
1043 ip = get_ipython()
1023 complete = ip.Completer.complete
1044 complete = ip.Completer.complete
1024 d = {"abc": None}
1045 d = {"abc": None}
1025 ip.user_ns["d"] = d
1046 ip.user_ns["d"] = d
1026
1047
1027 class C:
1048 class C:
1028 data = d
1049 data = d
1029
1050
1030 ip.user_ns["C"] = C
1051 ip.user_ns["C"] = C
1031 ip.user_ns["get"] = lambda: d
1052 ip.user_ns["get"] = lambda: d
1032
1053
1033 def assert_no_completion(**kwargs):
1054 def assert_no_completion(**kwargs):
1034 _, matches = complete(**kwargs)
1055 _, matches = complete(**kwargs)
1035 self.assertNotIn("abc", matches)
1056 self.assertNotIn("abc", matches)
1036 self.assertNotIn("abc'", matches)
1057 self.assertNotIn("abc'", matches)
1037 self.assertNotIn("abc']", matches)
1058 self.assertNotIn("abc']", matches)
1038 self.assertNotIn("'abc'", matches)
1059 self.assertNotIn("'abc'", matches)
1039 self.assertNotIn("'abc']", matches)
1060 self.assertNotIn("'abc']", matches)
1040
1061
1041 def assert_completion(**kwargs):
1062 def assert_completion(**kwargs):
1042 _, matches = complete(**kwargs)
1063 _, matches = complete(**kwargs)
1043 self.assertIn("'abc'", matches)
1064 self.assertIn("'abc'", matches)
1044 self.assertNotIn("'abc']", matches)
1065 self.assertNotIn("'abc']", matches)
1045
1066
1046 # no completion after string closed, even if reopened
1067 # no completion after string closed, even if reopened
1047 assert_no_completion(line_buffer="d['a'")
1068 assert_no_completion(line_buffer="d['a'")
1048 assert_no_completion(line_buffer='d["a"')
1069 assert_no_completion(line_buffer='d["a"')
1049 assert_no_completion(line_buffer="d['a' + ")
1070 assert_no_completion(line_buffer="d['a' + ")
1050 assert_no_completion(line_buffer="d['a' + '")
1071 assert_no_completion(line_buffer="d['a' + '")
1051
1072
1052 # completion in non-trivial expressions
1073 # completion in non-trivial expressions
1053 assert_completion(line_buffer="+ d[")
1074 assert_completion(line_buffer="+ d[")
1054 assert_completion(line_buffer="(d[")
1075 assert_completion(line_buffer="(d[")
1055 assert_completion(line_buffer="C.data[")
1076 assert_completion(line_buffer="C.data[")
1056
1077
1057 # greedy flag
1078 # greedy flag
1058 def assert_completion(**kwargs):
1079 def assert_completion(**kwargs):
1059 _, matches = complete(**kwargs)
1080 _, matches = complete(**kwargs)
1060 self.assertIn("get()['abc']", matches)
1081 self.assertIn("get()['abc']", matches)
1061
1082
1062 assert_no_completion(line_buffer="get()[")
1083 assert_no_completion(line_buffer="get()[")
1063 with greedy_completion():
1084 with greedy_completion():
1064 assert_completion(line_buffer="get()[")
1085 assert_completion(line_buffer="get()[")
1065 assert_completion(line_buffer="get()['")
1086 assert_completion(line_buffer="get()['")
1066 assert_completion(line_buffer="get()['a")
1087 assert_completion(line_buffer="get()['a")
1067 assert_completion(line_buffer="get()['ab")
1088 assert_completion(line_buffer="get()['ab")
1068 assert_completion(line_buffer="get()['abc")
1089 assert_completion(line_buffer="get()['abc")
1069
1090
1070 def test_dict_key_completion_bytes(self):
1091 def test_dict_key_completion_bytes(self):
1071 """Test handling of bytes in dict key completion"""
1092 """Test handling of bytes in dict key completion"""
1072 ip = get_ipython()
1093 ip = get_ipython()
1073 complete = ip.Completer.complete
1094 complete = ip.Completer.complete
1074
1095
1075 ip.user_ns["d"] = {"abc": None, b"abd": None}
1096 ip.user_ns["d"] = {"abc": None, b"abd": None}
1076
1097
1077 _, matches = complete(line_buffer="d[")
1098 _, matches = complete(line_buffer="d[")
1078 self.assertIn("'abc'", matches)
1099 self.assertIn("'abc'", matches)
1079 self.assertIn("b'abd'", matches)
1100 self.assertIn("b'abd'", matches)
1080
1101
1081 if False: # not currently implemented
1102 if False: # not currently implemented
1082 _, matches = complete(line_buffer="d[b")
1103 _, matches = complete(line_buffer="d[b")
1083 self.assertIn("b'abd'", matches)
1104 self.assertIn("b'abd'", matches)
1084 self.assertNotIn("b'abc'", matches)
1105 self.assertNotIn("b'abc'", matches)
1085
1106
1086 _, matches = complete(line_buffer="d[b'")
1107 _, matches = complete(line_buffer="d[b'")
1087 self.assertIn("abd", matches)
1108 self.assertIn("abd", matches)
1088 self.assertNotIn("abc", matches)
1109 self.assertNotIn("abc", matches)
1089
1110
1090 _, matches = complete(line_buffer="d[B'")
1111 _, matches = complete(line_buffer="d[B'")
1091 self.assertIn("abd", matches)
1112 self.assertIn("abd", matches)
1092 self.assertNotIn("abc", matches)
1113 self.assertNotIn("abc", matches)
1093
1114
1094 _, matches = complete(line_buffer="d['")
1115 _, matches = complete(line_buffer="d['")
1095 self.assertIn("abc", matches)
1116 self.assertIn("abc", matches)
1096 self.assertNotIn("abd", matches)
1117 self.assertNotIn("abd", matches)
1097
1118
1098 def test_dict_key_completion_unicode_py3(self):
1119 def test_dict_key_completion_unicode_py3(self):
1099 """Test handling of unicode in dict key completion"""
1120 """Test handling of unicode in dict key completion"""
1100 ip = get_ipython()
1121 ip = get_ipython()
1101 complete = ip.Completer.complete
1122 complete = ip.Completer.complete
1102
1123
1103 ip.user_ns["d"] = {"a\u05d0": None}
1124 ip.user_ns["d"] = {"a\u05d0": None}
1104
1125
1105 # query using escape
1126 # query using escape
1106 if sys.platform != "win32":
1127 if sys.platform != "win32":
1107 # Known failure on Windows
1128 # Known failure on Windows
1108 _, matches = complete(line_buffer="d['a\\u05d0")
1129 _, matches = complete(line_buffer="d['a\\u05d0")
1109 self.assertIn("u05d0", matches) # tokenized after \\
1130 self.assertIn("u05d0", matches) # tokenized after \\
1110
1131
1111 # query using character
1132 # query using character
1112 _, matches = complete(line_buffer="d['a\u05d0")
1133 _, matches = complete(line_buffer="d['a\u05d0")
1113 self.assertIn("a\u05d0", matches)
1134 self.assertIn("a\u05d0", matches)
1114
1135
1115 with greedy_completion():
1136 with greedy_completion():
1116 # query using escape
1137 # query using escape
1117 _, matches = complete(line_buffer="d['a\\u05d0")
1138 _, matches = complete(line_buffer="d['a\\u05d0")
1118 self.assertIn("d['a\\u05d0']", matches) # tokenized after \\
1139 self.assertIn("d['a\\u05d0']", matches) # tokenized after \\
1119
1140
1120 # query using character
1141 # query using character
1121 _, matches = complete(line_buffer="d['a\u05d0")
1142 _, matches = complete(line_buffer="d['a\u05d0")
1122 self.assertIn("d['a\u05d0']", matches)
1143 self.assertIn("d['a\u05d0']", matches)
1123
1144
1124 @dec.skip_without("numpy")
1145 @dec.skip_without("numpy")
1125 def test_struct_array_key_completion(self):
1146 def test_struct_array_key_completion(self):
1126 """Test dict key completion applies to numpy struct arrays"""
1147 """Test dict key completion applies to numpy struct arrays"""
1127 import numpy
1148 import numpy
1128
1149
1129 ip = get_ipython()
1150 ip = get_ipython()
1130 complete = ip.Completer.complete
1151 complete = ip.Completer.complete
1131 ip.user_ns["d"] = numpy.array([], dtype=[("hello", "f"), ("world", "f")])
1152 ip.user_ns["d"] = numpy.array([], dtype=[("hello", "f"), ("world", "f")])
1132 _, matches = complete(line_buffer="d['")
1153 _, matches = complete(line_buffer="d['")
1133 self.assertIn("hello", matches)
1154 self.assertIn("hello", matches)
1134 self.assertIn("world", matches)
1155 self.assertIn("world", matches)
1135 # complete on the numpy struct itself
1156 # complete on the numpy struct itself
1136 dt = numpy.dtype(
1157 dt = numpy.dtype(
1137 [("my_head", [("my_dt", ">u4"), ("my_df", ">u4")]), ("my_data", ">f4", 5)]
1158 [("my_head", [("my_dt", ">u4"), ("my_df", ">u4")]), ("my_data", ">f4", 5)]
1138 )
1159 )
1139 x = numpy.zeros(2, dtype=dt)
1160 x = numpy.zeros(2, dtype=dt)
1140 ip.user_ns["d"] = x[1]
1161 ip.user_ns["d"] = x[1]
1141 _, matches = complete(line_buffer="d['")
1162 _, matches = complete(line_buffer="d['")
1142 self.assertIn("my_head", matches)
1163 self.assertIn("my_head", matches)
1143 self.assertIn("my_data", matches)
1164 self.assertIn("my_data", matches)
1144 # complete on a nested level
1165 # complete on a nested level
1145 with greedy_completion():
1166 with greedy_completion():
1146 ip.user_ns["d"] = numpy.zeros(2, dtype=dt)
1167 ip.user_ns["d"] = numpy.zeros(2, dtype=dt)
1147 _, matches = complete(line_buffer="d[1]['my_head']['")
1168 _, matches = complete(line_buffer="d[1]['my_head']['")
1148 self.assertTrue(any(["my_dt" in m for m in matches]))
1169 self.assertTrue(any(["my_dt" in m for m in matches]))
1149 self.assertTrue(any(["my_df" in m for m in matches]))
1170 self.assertTrue(any(["my_df" in m for m in matches]))
1150
1171
1151 @dec.skip_without("pandas")
1172 @dec.skip_without("pandas")
1152 def test_dataframe_key_completion(self):
1173 def test_dataframe_key_completion(self):
1153 """Test dict key completion applies to pandas DataFrames"""
1174 """Test dict key completion applies to pandas DataFrames"""
1154 import pandas
1175 import pandas
1155
1176
1156 ip = get_ipython()
1177 ip = get_ipython()
1157 complete = ip.Completer.complete
1178 complete = ip.Completer.complete
1158 ip.user_ns["d"] = pandas.DataFrame({"hello": [1], "world": [2]})
1179 ip.user_ns["d"] = pandas.DataFrame({"hello": [1], "world": [2]})
1159 _, matches = complete(line_buffer="d['")
1180 _, matches = complete(line_buffer="d['")
1160 self.assertIn("hello", matches)
1181 self.assertIn("hello", matches)
1161 self.assertIn("world", matches)
1182 self.assertIn("world", matches)
1162
1183
1163 def test_dict_key_completion_invalids(self):
1184 def test_dict_key_completion_invalids(self):
1164 """Smoke test cases dict key completion can't handle"""
1185 """Smoke test cases dict key completion can't handle"""
1165 ip = get_ipython()
1186 ip = get_ipython()
1166 complete = ip.Completer.complete
1187 complete = ip.Completer.complete
1167
1188
1168 ip.user_ns["no_getitem"] = None
1189 ip.user_ns["no_getitem"] = None
1169 ip.user_ns["no_keys"] = []
1190 ip.user_ns["no_keys"] = []
1170 ip.user_ns["cant_call_keys"] = dict
1191 ip.user_ns["cant_call_keys"] = dict
1171 ip.user_ns["empty"] = {}
1192 ip.user_ns["empty"] = {}
1172 ip.user_ns["d"] = {"abc": 5}
1193 ip.user_ns["d"] = {"abc": 5}
1173
1194
1174 _, matches = complete(line_buffer="no_getitem['")
1195 _, matches = complete(line_buffer="no_getitem['")
1175 _, matches = complete(line_buffer="no_keys['")
1196 _, matches = complete(line_buffer="no_keys['")
1176 _, matches = complete(line_buffer="cant_call_keys['")
1197 _, matches = complete(line_buffer="cant_call_keys['")
1177 _, matches = complete(line_buffer="empty['")
1198 _, matches = complete(line_buffer="empty['")
1178 _, matches = complete(line_buffer="name_error['")
1199 _, matches = complete(line_buffer="name_error['")
1179 _, matches = complete(line_buffer="d['\\") # incomplete escape
1200 _, matches = complete(line_buffer="d['\\") # incomplete escape
1180
1201
1181 def test_object_key_completion(self):
1202 def test_object_key_completion(self):
1182 ip = get_ipython()
1203 ip = get_ipython()
1183 ip.user_ns["key_completable"] = KeyCompletable(["qwerty", "qwick"])
1204 ip.user_ns["key_completable"] = KeyCompletable(["qwerty", "qwick"])
1184
1205
1185 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
1206 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
1186 self.assertIn("qwerty", matches)
1207 self.assertIn("qwerty", matches)
1187 self.assertIn("qwick", matches)
1208 self.assertIn("qwick", matches)
1188
1209
1189 def test_class_key_completion(self):
1210 def test_class_key_completion(self):
1190 ip = get_ipython()
1211 ip = get_ipython()
1191 NamedInstanceClass("qwerty")
1212 NamedInstanceClass("qwerty")
1192 NamedInstanceClass("qwick")
1213 NamedInstanceClass("qwick")
1193 ip.user_ns["named_instance_class"] = NamedInstanceClass
1214 ip.user_ns["named_instance_class"] = NamedInstanceClass
1194
1215
1195 _, matches = ip.Completer.complete(line_buffer="named_instance_class['qw")
1216 _, matches = ip.Completer.complete(line_buffer="named_instance_class['qw")
1196 self.assertIn("qwerty", matches)
1217 self.assertIn("qwerty", matches)
1197 self.assertIn("qwick", matches)
1218 self.assertIn("qwick", matches)
1198
1219
1199 def test_tryimport(self):
1220 def test_tryimport(self):
1200 """
1221 """
1201 Test that try-import don't crash on trailing dot, and import modules before
1222 Test that try-import don't crash on trailing dot, and import modules before
1202 """
1223 """
1203 from IPython.core.completerlib import try_import
1224 from IPython.core.completerlib import try_import
1204
1225
1205 assert try_import("IPython.")
1226 assert try_import("IPython.")
1206
1227
1207 def test_aimport_module_completer(self):
1228 def test_aimport_module_completer(self):
1208 ip = get_ipython()
1229 ip = get_ipython()
1209 _, matches = ip.complete("i", "%aimport i")
1230 _, matches = ip.complete("i", "%aimport i")
1210 self.assertIn("io", matches)
1231 self.assertIn("io", matches)
1211 self.assertNotIn("int", matches)
1232 self.assertNotIn("int", matches)
1212
1233
1213 def test_nested_import_module_completer(self):
1234 def test_nested_import_module_completer(self):
1214 ip = get_ipython()
1235 ip = get_ipython()
1215 _, matches = ip.complete(None, "import IPython.co", 17)
1236 _, matches = ip.complete(None, "import IPython.co", 17)
1216 self.assertIn("IPython.core", matches)
1237 self.assertIn("IPython.core", matches)
1217 self.assertNotIn("import IPython.core", matches)
1238 self.assertNotIn("import IPython.core", matches)
1218 self.assertNotIn("IPython.display", matches)
1239 self.assertNotIn("IPython.display", matches)
1219
1240
1220 def test_import_module_completer(self):
1241 def test_import_module_completer(self):
1221 ip = get_ipython()
1242 ip = get_ipython()
1222 _, matches = ip.complete("i", "import i")
1243 _, matches = ip.complete("i", "import i")
1223 self.assertIn("io", matches)
1244 self.assertIn("io", matches)
1224 self.assertNotIn("int", matches)
1245 self.assertNotIn("int", matches)
1225
1246
1226 def test_from_module_completer(self):
1247 def test_from_module_completer(self):
1227 ip = get_ipython()
1248 ip = get_ipython()
1228 _, matches = ip.complete("B", "from io import B", 16)
1249 _, matches = ip.complete("B", "from io import B", 16)
1229 self.assertIn("BytesIO", matches)
1250 self.assertIn("BytesIO", matches)
1230 self.assertNotIn("BaseException", matches)
1251 self.assertNotIn("BaseException", matches)
1231
1252
1232 def test_snake_case_completion(self):
1253 def test_snake_case_completion(self):
1233 ip = get_ipython()
1254 ip = get_ipython()
1234 ip.Completer.use_jedi = False
1255 ip.Completer.use_jedi = False
1235 ip.user_ns["some_three"] = 3
1256 ip.user_ns["some_three"] = 3
1236 ip.user_ns["some_four"] = 4
1257 ip.user_ns["some_four"] = 4
1237 _, matches = ip.complete("s_", "print(s_f")
1258 _, matches = ip.complete("s_", "print(s_f")
1238 self.assertIn("some_three", matches)
1259 self.assertIn("some_three", matches)
1239 self.assertIn("some_four", matches)
1260 self.assertIn("some_four", matches)
1240
1261
1241 def test_mix_terms(self):
1262 def test_mix_terms(self):
1242 ip = get_ipython()
1263 ip = get_ipython()
1243 from textwrap import dedent
1264 from textwrap import dedent
1244
1265
1245 ip.Completer.use_jedi = False
1266 ip.Completer.use_jedi = False
1246 ip.ex(
1267 ip.ex(
1247 dedent(
1268 dedent(
1248 """
1269 """
1249 class Test:
1270 class Test:
1250 def meth(self, meth_arg1):
1271 def meth(self, meth_arg1):
1251 print("meth")
1272 print("meth")
1252
1273
1253 def meth_1(self, meth1_arg1, meth1_arg2):
1274 def meth_1(self, meth1_arg1, meth1_arg2):
1254 print("meth1")
1275 print("meth1")
1255
1276
1256 def meth_2(self, meth2_arg1, meth2_arg2):
1277 def meth_2(self, meth2_arg1, meth2_arg2):
1257 print("meth2")
1278 print("meth2")
1258 test = Test()
1279 test = Test()
1259 """
1280 """
1260 )
1281 )
1261 )
1282 )
1262 _, matches = ip.complete(None, "test.meth(")
1283 _, matches = ip.complete(None, "test.meth(")
1263 self.assertIn("meth_arg1=", matches)
1284 self.assertIn("meth_arg1=", matches)
1264 self.assertNotIn("meth2_arg1=", matches)
1285 self.assertNotIn("meth2_arg1=", matches)
1265
1286
1266 def test_percent_symbol_restrict_to_magic_completions(self):
1287 def test_percent_symbol_restrict_to_magic_completions(self):
1267 ip = get_ipython()
1288 ip = get_ipython()
1268 completer = ip.Completer
1289 completer = ip.Completer
1269 text = "%a"
1290 text = "%a"
1270
1291
1271 with provisionalcompleter():
1292 with provisionalcompleter():
1272 completer.use_jedi = True
1293 completer.use_jedi = True
1273 completions = completer.completions(text, len(text))
1294 completions = completer.completions(text, len(text))
1274 for c in completions:
1295 for c in completions:
1275 self.assertEqual(c.text[0], "%")
1296 self.assertEqual(c.text[0], "%")
1297
1298 def test_fwd_unicode_restricts(self):
1299 ip = get_ipython()
1300 completer = ip.Completer
1301 text = "\\ROMAN NUMERAL FIVE"
1302
1303 with provisionalcompleter():
1304 completer.use_jedi = True
1305 completions = [
1306 completion.text for completion in completer.completions(text, len(text))
1307 ]
1308 self.assertEqual(completions, ["\u2164"])
1309
1310 def test_dict_key_restrict_to_dicts(self):
1311 """Test that dict key suppresses non-dict completion items"""
1312 ip = get_ipython()
1313 c = ip.Completer
1314 d = {"abc": None}
1315 ip.user_ns["d"] = d
1316
1317 text = 'd["a'
1318
1319 def _():
1320 with provisionalcompleter():
1321 c.use_jedi = True
1322 return [
1323 completion.text for completion in c.completions(text, len(text))
1324 ]
1325
1326 completions = _()
1327 self.assertEqual(completions, ["abc"])
1328
1329 # check that it can be disabled in granular manner:
1330 cfg = Config()
1331 cfg.IPCompleter.suppress_competing_matchers = {
1332 "IPCompleter.dict_key_matcher": False
1333 }
1334 c.update_config(cfg)
1335
1336 completions = _()
1337 self.assertIn("abc", completions)
1338 self.assertGreater(len(completions), 1)
1339
1340 def test_matcher_suppression(self):
1341 @completion_matcher(identifier="a_matcher")
1342 def a_matcher(text):
1343 return ["completion_a"]
1344
1345 @completion_matcher(identifier="b_matcher", api_version=2)
1346 def b_matcher(context: CompletionContext):
1347 text = context.token
1348 result = {"completions": [SimpleCompletion("completion_b")]}
1349
1350 if text == "suppress c":
1351 result["suppress"] = {"c_matcher"}
1352
1353 if text.startswith("suppress all"):
1354 result["suppress"] = True
1355 if text == "suppress all but c":
1356 result["do_not_suppress"] = {"c_matcher"}
1357 if text == "suppress all but a":
1358 result["do_not_suppress"] = {"a_matcher"}
1359
1360 return result
1361
1362 @completion_matcher(identifier="c_matcher")
1363 def c_matcher(text):
1364 return ["completion_c"]
1365
1366 with custom_matchers([a_matcher, b_matcher, c_matcher]):
1367 ip = get_ipython()
1368 c = ip.Completer
1369
1370 def _(text, expected):
1371 c.use_jedi = False
1372 s, matches = c.complete(text)
1373 self.assertEqual(expected, matches)
1374
1375 _("do not suppress", ["completion_a", "completion_b", "completion_c"])
1376 _("suppress all", ["completion_b"])
1377 _("suppress all but a", ["completion_a", "completion_b"])
1378 _("suppress all but c", ["completion_b", "completion_c"])
1379
1380 def configure(suppression_config):
1381 cfg = Config()
1382 cfg.IPCompleter.suppress_competing_matchers = suppression_config
1383 c.update_config(cfg)
1384
1385 # test that configuration takes priority over the run-time decisions
1386
1387 configure(False)
1388 _("suppress all", ["completion_a", "completion_b", "completion_c"])
1389
1390 configure({"b_matcher": False})
1391 _("suppress all", ["completion_a", "completion_b", "completion_c"])
1392
1393 configure({"a_matcher": False})
1394 _("suppress all", ["completion_b"])
1395
1396 configure({"b_matcher": True})
1397 _("do not suppress", ["completion_b"])
1398
1399 def test_matcher_disabling(self):
1400 @completion_matcher(identifier="a_matcher")
1401 def a_matcher(text):
1402 return ["completion_a"]
1403
1404 @completion_matcher(identifier="b_matcher")
1405 def b_matcher(text):
1406 return ["completion_b"]
1407
1408 def _(expected):
1409 s, matches = c.complete("completion_")
1410 self.assertEqual(expected, matches)
1411
1412 with custom_matchers([a_matcher, b_matcher]):
1413 ip = get_ipython()
1414 c = ip.Completer
1415
1416 _(["completion_a", "completion_b"])
1417
1418 cfg = Config()
1419 cfg.IPCompleter.disable_matchers = ["b_matcher"]
1420 c.update_config(cfg)
1421
1422 _(["completion_a"])
1423
1424 cfg.IPCompleter.disable_matchers = []
1425 c.update_config(cfg)
1426
1427 def test_matcher_priority(self):
1428 @completion_matcher(identifier="a_matcher", priority=0, api_version=2)
1429 def a_matcher(text):
1430 return {"completions": [SimpleCompletion("completion_a")], "suppress": True}
1431
1432 @completion_matcher(identifier="b_matcher", priority=2, api_version=2)
1433 def b_matcher(text):
1434 return {"completions": [SimpleCompletion("completion_b")], "suppress": True}
1435
1436 def _(expected):
1437 s, matches = c.complete("completion_")
1438 self.assertEqual(expected, matches)
1439
1440 with custom_matchers([a_matcher, b_matcher]):
1441 ip = get_ipython()
1442 c = ip.Completer
1443
1444 _(["completion_b"])
1445 a_matcher.matcher_priority = 3
1446 _(["completion_a"])
@@ -1,1100 +1,1112 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the key interactiveshell module.
2 """Tests for the key interactiveshell module.
3
3
4 Historically the main classes in interactiveshell have been under-tested. This
4 Historically the main classes in interactiveshell have been under-tested. This
5 module should grow as many single-method tests as possible to trap many of the
5 module should grow as many single-method tests as possible to trap many of the
6 recurring bugs we seem to encounter with high-level interaction.
6 recurring bugs we seem to encounter with high-level interaction.
7 """
7 """
8
8
9 # Copyright (c) IPython Development Team.
9 # Copyright (c) IPython Development Team.
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11
11
12 import asyncio
12 import asyncio
13 import ast
13 import ast
14 import os
14 import os
15 import signal
15 import signal
16 import shutil
16 import shutil
17 import sys
17 import sys
18 import tempfile
18 import tempfile
19 import unittest
19 import unittest
20 from unittest import mock
20 from unittest import mock
21
21
22 from os.path import join
22 from os.path import join
23
23
24 from IPython.core.error import InputRejected
24 from IPython.core.error import InputRejected
25 from IPython.core.inputtransformer import InputTransformer
25 from IPython.core.inputtransformer import InputTransformer
26 from IPython.core import interactiveshell
26 from IPython.core import interactiveshell
27 from IPython.testing.decorators import (
27 from IPython.testing.decorators import (
28 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
28 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
29 )
29 )
30 from IPython.testing import tools as tt
30 from IPython.testing import tools as tt
31 from IPython.utils.process import find_cmd
31 from IPython.utils.process import find_cmd
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Globals
34 # Globals
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # This is used by every single test, no point repeating it ad nauseam
36 # This is used by every single test, no point repeating it ad nauseam
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Tests
39 # Tests
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42 class DerivedInterrupt(KeyboardInterrupt):
42 class DerivedInterrupt(KeyboardInterrupt):
43 pass
43 pass
44
44
45 class InteractiveShellTestCase(unittest.TestCase):
45 class InteractiveShellTestCase(unittest.TestCase):
46 def test_naked_string_cells(self):
46 def test_naked_string_cells(self):
47 """Test that cells with only naked strings are fully executed"""
47 """Test that cells with only naked strings are fully executed"""
48 # First, single-line inputs
48 # First, single-line inputs
49 ip.run_cell('"a"\n')
49 ip.run_cell('"a"\n')
50 self.assertEqual(ip.user_ns['_'], 'a')
50 self.assertEqual(ip.user_ns['_'], 'a')
51 # And also multi-line cells
51 # And also multi-line cells
52 ip.run_cell('"""a\nb"""\n')
52 ip.run_cell('"""a\nb"""\n')
53 self.assertEqual(ip.user_ns['_'], 'a\nb')
53 self.assertEqual(ip.user_ns['_'], 'a\nb')
54
54
55 def test_run_empty_cell(self):
55 def test_run_empty_cell(self):
56 """Just make sure we don't get a horrible error with a blank
56 """Just make sure we don't get a horrible error with a blank
57 cell of input. Yes, I did overlook that."""
57 cell of input. Yes, I did overlook that."""
58 old_xc = ip.execution_count
58 old_xc = ip.execution_count
59 res = ip.run_cell('')
59 res = ip.run_cell('')
60 self.assertEqual(ip.execution_count, old_xc)
60 self.assertEqual(ip.execution_count, old_xc)
61 self.assertEqual(res.execution_count, None)
61 self.assertEqual(res.execution_count, None)
62
62
63 def test_run_cell_multiline(self):
63 def test_run_cell_multiline(self):
64 """Multi-block, multi-line cells must execute correctly.
64 """Multi-block, multi-line cells must execute correctly.
65 """
65 """
66 src = '\n'.join(["x=1",
66 src = '\n'.join(["x=1",
67 "y=2",
67 "y=2",
68 "if 1:",
68 "if 1:",
69 " x += 1",
69 " x += 1",
70 " y += 1",])
70 " y += 1",])
71 res = ip.run_cell(src)
71 res = ip.run_cell(src)
72 self.assertEqual(ip.user_ns['x'], 2)
72 self.assertEqual(ip.user_ns['x'], 2)
73 self.assertEqual(ip.user_ns['y'], 3)
73 self.assertEqual(ip.user_ns['y'], 3)
74 self.assertEqual(res.success, True)
74 self.assertEqual(res.success, True)
75 self.assertEqual(res.result, None)
75 self.assertEqual(res.result, None)
76
76
77 def test_multiline_string_cells(self):
77 def test_multiline_string_cells(self):
78 "Code sprinkled with multiline strings should execute (GH-306)"
78 "Code sprinkled with multiline strings should execute (GH-306)"
79 ip.run_cell('tmp=0')
79 ip.run_cell('tmp=0')
80 self.assertEqual(ip.user_ns['tmp'], 0)
80 self.assertEqual(ip.user_ns['tmp'], 0)
81 res = ip.run_cell('tmp=1;"""a\nb"""\n')
81 res = ip.run_cell('tmp=1;"""a\nb"""\n')
82 self.assertEqual(ip.user_ns['tmp'], 1)
82 self.assertEqual(ip.user_ns['tmp'], 1)
83 self.assertEqual(res.success, True)
83 self.assertEqual(res.success, True)
84 self.assertEqual(res.result, "a\nb")
84 self.assertEqual(res.result, "a\nb")
85
85
86 def test_dont_cache_with_semicolon(self):
86 def test_dont_cache_with_semicolon(self):
87 "Ending a line with semicolon should not cache the returned object (GH-307)"
87 "Ending a line with semicolon should not cache the returned object (GH-307)"
88 oldlen = len(ip.user_ns['Out'])
88 oldlen = len(ip.user_ns['Out'])
89 for cell in ['1;', '1;1;']:
89 for cell in ['1;', '1;1;']:
90 res = ip.run_cell(cell, store_history=True)
90 res = ip.run_cell(cell, store_history=True)
91 newlen = len(ip.user_ns['Out'])
91 newlen = len(ip.user_ns['Out'])
92 self.assertEqual(oldlen, newlen)
92 self.assertEqual(oldlen, newlen)
93 self.assertIsNone(res.result)
93 self.assertIsNone(res.result)
94 i = 0
94 i = 0
95 #also test the default caching behavior
95 #also test the default caching behavior
96 for cell in ['1', '1;1']:
96 for cell in ['1', '1;1']:
97 ip.run_cell(cell, store_history=True)
97 ip.run_cell(cell, store_history=True)
98 newlen = len(ip.user_ns['Out'])
98 newlen = len(ip.user_ns['Out'])
99 i += 1
99 i += 1
100 self.assertEqual(oldlen+i, newlen)
100 self.assertEqual(oldlen+i, newlen)
101
101
102 def test_syntax_error(self):
102 def test_syntax_error(self):
103 res = ip.run_cell("raise = 3")
103 res = ip.run_cell("raise = 3")
104 self.assertIsInstance(res.error_before_exec, SyntaxError)
104 self.assertIsInstance(res.error_before_exec, SyntaxError)
105
105
106 def test_open_standard_input_stream(self):
107 res = ip.run_cell("open(0)")
108 self.assertIsInstance(res.error_in_exec, ValueError)
109
110 def test_open_standard_output_stream(self):
111 res = ip.run_cell("open(1)")
112 self.assertIsInstance(res.error_in_exec, ValueError)
113
114 def test_open_standard_error_stream(self):
115 res = ip.run_cell("open(2)")
116 self.assertIsInstance(res.error_in_exec, ValueError)
117
106 def test_In_variable(self):
118 def test_In_variable(self):
107 "Verify that In variable grows with user input (GH-284)"
119 "Verify that In variable grows with user input (GH-284)"
108 oldlen = len(ip.user_ns['In'])
120 oldlen = len(ip.user_ns['In'])
109 ip.run_cell('1;', store_history=True)
121 ip.run_cell('1;', store_history=True)
110 newlen = len(ip.user_ns['In'])
122 newlen = len(ip.user_ns['In'])
111 self.assertEqual(oldlen+1, newlen)
123 self.assertEqual(oldlen+1, newlen)
112 self.assertEqual(ip.user_ns['In'][-1],'1;')
124 self.assertEqual(ip.user_ns['In'][-1],'1;')
113
125
114 def test_magic_names_in_string(self):
126 def test_magic_names_in_string(self):
115 ip.run_cell('a = """\n%exit\n"""')
127 ip.run_cell('a = """\n%exit\n"""')
116 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
128 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
117
129
118 def test_trailing_newline(self):
130 def test_trailing_newline(self):
119 """test that running !(command) does not raise a SyntaxError"""
131 """test that running !(command) does not raise a SyntaxError"""
120 ip.run_cell('!(true)\n', False)
132 ip.run_cell('!(true)\n', False)
121 ip.run_cell('!(true)\n\n\n', False)
133 ip.run_cell('!(true)\n\n\n', False)
122
134
123 def test_gh_597(self):
135 def test_gh_597(self):
124 """Pretty-printing lists of objects with non-ascii reprs may cause
136 """Pretty-printing lists of objects with non-ascii reprs may cause
125 problems."""
137 problems."""
126 class Spam(object):
138 class Spam(object):
127 def __repr__(self):
139 def __repr__(self):
128 return "\xe9"*50
140 return "\xe9"*50
129 import IPython.core.formatters
141 import IPython.core.formatters
130 f = IPython.core.formatters.PlainTextFormatter()
142 f = IPython.core.formatters.PlainTextFormatter()
131 f([Spam(),Spam()])
143 f([Spam(),Spam()])
132
144
133
145
134 def test_future_flags(self):
146 def test_future_flags(self):
135 """Check that future flags are used for parsing code (gh-777)"""
147 """Check that future flags are used for parsing code (gh-777)"""
136 ip.run_cell('from __future__ import barry_as_FLUFL')
148 ip.run_cell('from __future__ import barry_as_FLUFL')
137 try:
149 try:
138 ip.run_cell('prfunc_return_val = 1 <> 2')
150 ip.run_cell('prfunc_return_val = 1 <> 2')
139 assert 'prfunc_return_val' in ip.user_ns
151 assert 'prfunc_return_val' in ip.user_ns
140 finally:
152 finally:
141 # Reset compiler flags so we don't mess up other tests.
153 # Reset compiler flags so we don't mess up other tests.
142 ip.compile.reset_compiler_flags()
154 ip.compile.reset_compiler_flags()
143
155
144 def test_can_pickle(self):
156 def test_can_pickle(self):
145 "Can we pickle objects defined interactively (GH-29)"
157 "Can we pickle objects defined interactively (GH-29)"
146 ip = get_ipython()
158 ip = get_ipython()
147 ip.reset()
159 ip.reset()
148 ip.run_cell(("class Mylist(list):\n"
160 ip.run_cell(("class Mylist(list):\n"
149 " def __init__(self,x=[]):\n"
161 " def __init__(self,x=[]):\n"
150 " list.__init__(self,x)"))
162 " list.__init__(self,x)"))
151 ip.run_cell("w=Mylist([1,2,3])")
163 ip.run_cell("w=Mylist([1,2,3])")
152
164
153 from pickle import dumps
165 from pickle import dumps
154
166
155 # We need to swap in our main module - this is only necessary
167 # We need to swap in our main module - this is only necessary
156 # inside the test framework, because IPython puts the interactive module
168 # inside the test framework, because IPython puts the interactive module
157 # in place (but the test framework undoes this).
169 # in place (but the test framework undoes this).
158 _main = sys.modules['__main__']
170 _main = sys.modules['__main__']
159 sys.modules['__main__'] = ip.user_module
171 sys.modules['__main__'] = ip.user_module
160 try:
172 try:
161 res = dumps(ip.user_ns["w"])
173 res = dumps(ip.user_ns["w"])
162 finally:
174 finally:
163 sys.modules['__main__'] = _main
175 sys.modules['__main__'] = _main
164 self.assertTrue(isinstance(res, bytes))
176 self.assertTrue(isinstance(res, bytes))
165
177
166 def test_global_ns(self):
178 def test_global_ns(self):
167 "Code in functions must be able to access variables outside them."
179 "Code in functions must be able to access variables outside them."
168 ip = get_ipython()
180 ip = get_ipython()
169 ip.run_cell("a = 10")
181 ip.run_cell("a = 10")
170 ip.run_cell(("def f(x):\n"
182 ip.run_cell(("def f(x):\n"
171 " return x + a"))
183 " return x + a"))
172 ip.run_cell("b = f(12)")
184 ip.run_cell("b = f(12)")
173 self.assertEqual(ip.user_ns["b"], 22)
185 self.assertEqual(ip.user_ns["b"], 22)
174
186
175 def test_bad_custom_tb(self):
187 def test_bad_custom_tb(self):
176 """Check that InteractiveShell is protected from bad custom exception handlers"""
188 """Check that InteractiveShell is protected from bad custom exception handlers"""
177 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
189 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
178 self.assertEqual(ip.custom_exceptions, (IOError,))
190 self.assertEqual(ip.custom_exceptions, (IOError,))
179 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
191 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
180 ip.run_cell(u'raise IOError("foo")')
192 ip.run_cell(u'raise IOError("foo")')
181 self.assertEqual(ip.custom_exceptions, ())
193 self.assertEqual(ip.custom_exceptions, ())
182
194
183 def test_bad_custom_tb_return(self):
195 def test_bad_custom_tb_return(self):
184 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
196 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
185 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
197 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
186 self.assertEqual(ip.custom_exceptions, (NameError,))
198 self.assertEqual(ip.custom_exceptions, (NameError,))
187 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
199 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
188 ip.run_cell(u'a=abracadabra')
200 ip.run_cell(u'a=abracadabra')
189 self.assertEqual(ip.custom_exceptions, ())
201 self.assertEqual(ip.custom_exceptions, ())
190
202
191 def test_drop_by_id(self):
203 def test_drop_by_id(self):
192 myvars = {"a":object(), "b":object(), "c": object()}
204 myvars = {"a":object(), "b":object(), "c": object()}
193 ip.push(myvars, interactive=False)
205 ip.push(myvars, interactive=False)
194 for name in myvars:
206 for name in myvars:
195 assert name in ip.user_ns, name
207 assert name in ip.user_ns, name
196 assert name in ip.user_ns_hidden, name
208 assert name in ip.user_ns_hidden, name
197 ip.user_ns['b'] = 12
209 ip.user_ns['b'] = 12
198 ip.drop_by_id(myvars)
210 ip.drop_by_id(myvars)
199 for name in ["a", "c"]:
211 for name in ["a", "c"]:
200 assert name not in ip.user_ns, name
212 assert name not in ip.user_ns, name
201 assert name not in ip.user_ns_hidden, name
213 assert name not in ip.user_ns_hidden, name
202 assert ip.user_ns['b'] == 12
214 assert ip.user_ns['b'] == 12
203 ip.reset()
215 ip.reset()
204
216
205 def test_var_expand(self):
217 def test_var_expand(self):
206 ip.user_ns['f'] = u'Ca\xf1o'
218 ip.user_ns['f'] = u'Ca\xf1o'
207 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
219 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
208 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
220 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
209 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
221 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
210 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
222 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
211
223
212 self.assertEqual(ip.var_expand(u"grep x | awk '{print $1}'"), u"grep x | awk '{print $1}'")
224 self.assertEqual(ip.var_expand(u"grep x | awk '{print $1}'"), u"grep x | awk '{print $1}'")
213
225
214 ip.user_ns['f'] = b'Ca\xc3\xb1o'
226 ip.user_ns['f'] = b'Ca\xc3\xb1o'
215 # This should not raise any exception:
227 # This should not raise any exception:
216 ip.var_expand(u'echo $f')
228 ip.var_expand(u'echo $f')
217
229
218 def test_var_expand_local(self):
230 def test_var_expand_local(self):
219 """Test local variable expansion in !system and %magic calls"""
231 """Test local variable expansion in !system and %magic calls"""
220 # !system
232 # !system
221 ip.run_cell(
233 ip.run_cell(
222 "def test():\n"
234 "def test():\n"
223 ' lvar = "ttt"\n'
235 ' lvar = "ttt"\n'
224 " ret = !echo {lvar}\n"
236 " ret = !echo {lvar}\n"
225 " return ret[0]\n"
237 " return ret[0]\n"
226 )
238 )
227 res = ip.user_ns["test"]()
239 res = ip.user_ns["test"]()
228 self.assertIn("ttt", res)
240 self.assertIn("ttt", res)
229
241
230 # %magic
242 # %magic
231 ip.run_cell(
243 ip.run_cell(
232 "def makemacro():\n"
244 "def makemacro():\n"
233 ' macroname = "macro_var_expand_locals"\n'
245 ' macroname = "macro_var_expand_locals"\n'
234 " %macro {macroname} codestr\n"
246 " %macro {macroname} codestr\n"
235 )
247 )
236 ip.user_ns["codestr"] = "str(12)"
248 ip.user_ns["codestr"] = "str(12)"
237 ip.run_cell("makemacro()")
249 ip.run_cell("makemacro()")
238 self.assertIn("macro_var_expand_locals", ip.user_ns)
250 self.assertIn("macro_var_expand_locals", ip.user_ns)
239
251
240 def test_var_expand_self(self):
252 def test_var_expand_self(self):
241 """Test variable expansion with the name 'self', which was failing.
253 """Test variable expansion with the name 'self', which was failing.
242
254
243 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
255 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
244 """
256 """
245 ip.run_cell(
257 ip.run_cell(
246 "class cTest:\n"
258 "class cTest:\n"
247 ' classvar="see me"\n'
259 ' classvar="see me"\n'
248 " def test(self):\n"
260 " def test(self):\n"
249 " res = !echo Variable: {self.classvar}\n"
261 " res = !echo Variable: {self.classvar}\n"
250 " return res[0]\n"
262 " return res[0]\n"
251 )
263 )
252 self.assertIn("see me", ip.user_ns["cTest"]().test())
264 self.assertIn("see me", ip.user_ns["cTest"]().test())
253
265
254 def test_bad_var_expand(self):
266 def test_bad_var_expand(self):
255 """var_expand on invalid formats shouldn't raise"""
267 """var_expand on invalid formats shouldn't raise"""
256 # SyntaxError
268 # SyntaxError
257 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
269 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
258 # NameError
270 # NameError
259 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
271 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
260 # ZeroDivisionError
272 # ZeroDivisionError
261 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
273 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
262
274
263 def test_silent_postexec(self):
275 def test_silent_postexec(self):
264 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
276 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
265 pre_explicit = mock.Mock()
277 pre_explicit = mock.Mock()
266 pre_always = mock.Mock()
278 pre_always = mock.Mock()
267 post_explicit = mock.Mock()
279 post_explicit = mock.Mock()
268 post_always = mock.Mock()
280 post_always = mock.Mock()
269 all_mocks = [pre_explicit, pre_always, post_explicit, post_always]
281 all_mocks = [pre_explicit, pre_always, post_explicit, post_always]
270
282
271 ip.events.register('pre_run_cell', pre_explicit)
283 ip.events.register('pre_run_cell', pre_explicit)
272 ip.events.register('pre_execute', pre_always)
284 ip.events.register('pre_execute', pre_always)
273 ip.events.register('post_run_cell', post_explicit)
285 ip.events.register('post_run_cell', post_explicit)
274 ip.events.register('post_execute', post_always)
286 ip.events.register('post_execute', post_always)
275
287
276 try:
288 try:
277 ip.run_cell("1", silent=True)
289 ip.run_cell("1", silent=True)
278 assert pre_always.called
290 assert pre_always.called
279 assert not pre_explicit.called
291 assert not pre_explicit.called
280 assert post_always.called
292 assert post_always.called
281 assert not post_explicit.called
293 assert not post_explicit.called
282 # double-check that non-silent exec did what we expected
294 # double-check that non-silent exec did what we expected
283 # silent to avoid
295 # silent to avoid
284 ip.run_cell("1")
296 ip.run_cell("1")
285 assert pre_explicit.called
297 assert pre_explicit.called
286 assert post_explicit.called
298 assert post_explicit.called
287 info, = pre_explicit.call_args[0]
299 info, = pre_explicit.call_args[0]
288 result, = post_explicit.call_args[0]
300 result, = post_explicit.call_args[0]
289 self.assertEqual(info, result.info)
301 self.assertEqual(info, result.info)
290 # check that post hooks are always called
302 # check that post hooks are always called
291 [m.reset_mock() for m in all_mocks]
303 [m.reset_mock() for m in all_mocks]
292 ip.run_cell("syntax error")
304 ip.run_cell("syntax error")
293 assert pre_always.called
305 assert pre_always.called
294 assert pre_explicit.called
306 assert pre_explicit.called
295 assert post_always.called
307 assert post_always.called
296 assert post_explicit.called
308 assert post_explicit.called
297 info, = pre_explicit.call_args[0]
309 info, = pre_explicit.call_args[0]
298 result, = post_explicit.call_args[0]
310 result, = post_explicit.call_args[0]
299 self.assertEqual(info, result.info)
311 self.assertEqual(info, result.info)
300 finally:
312 finally:
301 # remove post-exec
313 # remove post-exec
302 ip.events.unregister('pre_run_cell', pre_explicit)
314 ip.events.unregister('pre_run_cell', pre_explicit)
303 ip.events.unregister('pre_execute', pre_always)
315 ip.events.unregister('pre_execute', pre_always)
304 ip.events.unregister('post_run_cell', post_explicit)
316 ip.events.unregister('post_run_cell', post_explicit)
305 ip.events.unregister('post_execute', post_always)
317 ip.events.unregister('post_execute', post_always)
306
318
307 def test_silent_noadvance(self):
319 def test_silent_noadvance(self):
308 """run_cell(silent=True) doesn't advance execution_count"""
320 """run_cell(silent=True) doesn't advance execution_count"""
309 ec = ip.execution_count
321 ec = ip.execution_count
310 # silent should force store_history=False
322 # silent should force store_history=False
311 ip.run_cell("1", store_history=True, silent=True)
323 ip.run_cell("1", store_history=True, silent=True)
312
324
313 self.assertEqual(ec, ip.execution_count)
325 self.assertEqual(ec, ip.execution_count)
314 # double-check that non-silent exec did what we expected
326 # double-check that non-silent exec did what we expected
315 # silent to avoid
327 # silent to avoid
316 ip.run_cell("1", store_history=True)
328 ip.run_cell("1", store_history=True)
317 self.assertEqual(ec+1, ip.execution_count)
329 self.assertEqual(ec+1, ip.execution_count)
318
330
319 def test_silent_nodisplayhook(self):
331 def test_silent_nodisplayhook(self):
320 """run_cell(silent=True) doesn't trigger displayhook"""
332 """run_cell(silent=True) doesn't trigger displayhook"""
321 d = dict(called=False)
333 d = dict(called=False)
322
334
323 trap = ip.display_trap
335 trap = ip.display_trap
324 save_hook = trap.hook
336 save_hook = trap.hook
325
337
326 def failing_hook(*args, **kwargs):
338 def failing_hook(*args, **kwargs):
327 d['called'] = True
339 d['called'] = True
328
340
329 try:
341 try:
330 trap.hook = failing_hook
342 trap.hook = failing_hook
331 res = ip.run_cell("1", silent=True)
343 res = ip.run_cell("1", silent=True)
332 self.assertFalse(d['called'])
344 self.assertFalse(d['called'])
333 self.assertIsNone(res.result)
345 self.assertIsNone(res.result)
334 # double-check that non-silent exec did what we expected
346 # double-check that non-silent exec did what we expected
335 # silent to avoid
347 # silent to avoid
336 ip.run_cell("1")
348 ip.run_cell("1")
337 self.assertTrue(d['called'])
349 self.assertTrue(d['called'])
338 finally:
350 finally:
339 trap.hook = save_hook
351 trap.hook = save_hook
340
352
341 def test_ofind_line_magic(self):
353 def test_ofind_line_magic(self):
342 from IPython.core.magic import register_line_magic
354 from IPython.core.magic import register_line_magic
343
355
344 @register_line_magic
356 @register_line_magic
345 def lmagic(line):
357 def lmagic(line):
346 "A line magic"
358 "A line magic"
347
359
348 # Get info on line magic
360 # Get info on line magic
349 lfind = ip._ofind("lmagic")
361 lfind = ip._ofind("lmagic")
350 info = dict(
362 info = dict(
351 found=True,
363 found=True,
352 isalias=False,
364 isalias=False,
353 ismagic=True,
365 ismagic=True,
354 namespace="IPython internal",
366 namespace="IPython internal",
355 obj=lmagic,
367 obj=lmagic,
356 parent=None,
368 parent=None,
357 )
369 )
358 self.assertEqual(lfind, info)
370 self.assertEqual(lfind, info)
359
371
360 def test_ofind_cell_magic(self):
372 def test_ofind_cell_magic(self):
361 from IPython.core.magic import register_cell_magic
373 from IPython.core.magic import register_cell_magic
362
374
363 @register_cell_magic
375 @register_cell_magic
364 def cmagic(line, cell):
376 def cmagic(line, cell):
365 "A cell magic"
377 "A cell magic"
366
378
367 # Get info on cell magic
379 # Get info on cell magic
368 find = ip._ofind("cmagic")
380 find = ip._ofind("cmagic")
369 info = dict(
381 info = dict(
370 found=True,
382 found=True,
371 isalias=False,
383 isalias=False,
372 ismagic=True,
384 ismagic=True,
373 namespace="IPython internal",
385 namespace="IPython internal",
374 obj=cmagic,
386 obj=cmagic,
375 parent=None,
387 parent=None,
376 )
388 )
377 self.assertEqual(find, info)
389 self.assertEqual(find, info)
378
390
379 def test_ofind_property_with_error(self):
391 def test_ofind_property_with_error(self):
380 class A(object):
392 class A(object):
381 @property
393 @property
382 def foo(self):
394 def foo(self):
383 raise NotImplementedError() # pragma: no cover
395 raise NotImplementedError() # pragma: no cover
384
396
385 a = A()
397 a = A()
386
398
387 found = ip._ofind('a.foo', [('locals', locals())])
399 found = ip._ofind('a.foo', [('locals', locals())])
388 info = dict(found=True, isalias=False, ismagic=False,
400 info = dict(found=True, isalias=False, ismagic=False,
389 namespace='locals', obj=A.foo, parent=a)
401 namespace='locals', obj=A.foo, parent=a)
390 self.assertEqual(found, info)
402 self.assertEqual(found, info)
391
403
392 def test_ofind_multiple_attribute_lookups(self):
404 def test_ofind_multiple_attribute_lookups(self):
393 class A(object):
405 class A(object):
394 @property
406 @property
395 def foo(self):
407 def foo(self):
396 raise NotImplementedError() # pragma: no cover
408 raise NotImplementedError() # pragma: no cover
397
409
398 a = A()
410 a = A()
399 a.a = A()
411 a.a = A()
400 a.a.a = A()
412 a.a.a = A()
401
413
402 found = ip._ofind('a.a.a.foo', [('locals', locals())])
414 found = ip._ofind('a.a.a.foo', [('locals', locals())])
403 info = dict(found=True, isalias=False, ismagic=False,
415 info = dict(found=True, isalias=False, ismagic=False,
404 namespace='locals', obj=A.foo, parent=a.a.a)
416 namespace='locals', obj=A.foo, parent=a.a.a)
405 self.assertEqual(found, info)
417 self.assertEqual(found, info)
406
418
407 def test_ofind_slotted_attributes(self):
419 def test_ofind_slotted_attributes(self):
408 class A(object):
420 class A(object):
409 __slots__ = ['foo']
421 __slots__ = ['foo']
410 def __init__(self):
422 def __init__(self):
411 self.foo = 'bar'
423 self.foo = 'bar'
412
424
413 a = A()
425 a = A()
414 found = ip._ofind('a.foo', [('locals', locals())])
426 found = ip._ofind('a.foo', [('locals', locals())])
415 info = dict(found=True, isalias=False, ismagic=False,
427 info = dict(found=True, isalias=False, ismagic=False,
416 namespace='locals', obj=a.foo, parent=a)
428 namespace='locals', obj=a.foo, parent=a)
417 self.assertEqual(found, info)
429 self.assertEqual(found, info)
418
430
419 found = ip._ofind('a.bar', [('locals', locals())])
431 found = ip._ofind('a.bar', [('locals', locals())])
420 info = dict(found=False, isalias=False, ismagic=False,
432 info = dict(found=False, isalias=False, ismagic=False,
421 namespace=None, obj=None, parent=a)
433 namespace=None, obj=None, parent=a)
422 self.assertEqual(found, info)
434 self.assertEqual(found, info)
423
435
424 def test_ofind_prefers_property_to_instance_level_attribute(self):
436 def test_ofind_prefers_property_to_instance_level_attribute(self):
425 class A(object):
437 class A(object):
426 @property
438 @property
427 def foo(self):
439 def foo(self):
428 return 'bar'
440 return 'bar'
429 a = A()
441 a = A()
430 a.__dict__["foo"] = "baz"
442 a.__dict__["foo"] = "baz"
431 self.assertEqual(a.foo, "bar")
443 self.assertEqual(a.foo, "bar")
432 found = ip._ofind("a.foo", [("locals", locals())])
444 found = ip._ofind("a.foo", [("locals", locals())])
433 self.assertIs(found["obj"], A.foo)
445 self.assertIs(found["obj"], A.foo)
434
446
435 def test_custom_syntaxerror_exception(self):
447 def test_custom_syntaxerror_exception(self):
436 called = []
448 called = []
437 def my_handler(shell, etype, value, tb, tb_offset=None):
449 def my_handler(shell, etype, value, tb, tb_offset=None):
438 called.append(etype)
450 called.append(etype)
439 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
451 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
440
452
441 ip.set_custom_exc((SyntaxError,), my_handler)
453 ip.set_custom_exc((SyntaxError,), my_handler)
442 try:
454 try:
443 ip.run_cell("1f")
455 ip.run_cell("1f")
444 # Check that this was called, and only once.
456 # Check that this was called, and only once.
445 self.assertEqual(called, [SyntaxError])
457 self.assertEqual(called, [SyntaxError])
446 finally:
458 finally:
447 # Reset the custom exception hook
459 # Reset the custom exception hook
448 ip.set_custom_exc((), None)
460 ip.set_custom_exc((), None)
449
461
450 def test_custom_exception(self):
462 def test_custom_exception(self):
451 called = []
463 called = []
452 def my_handler(shell, etype, value, tb, tb_offset=None):
464 def my_handler(shell, etype, value, tb, tb_offset=None):
453 called.append(etype)
465 called.append(etype)
454 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
466 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
455
467
456 ip.set_custom_exc((ValueError,), my_handler)
468 ip.set_custom_exc((ValueError,), my_handler)
457 try:
469 try:
458 res = ip.run_cell("raise ValueError('test')")
470 res = ip.run_cell("raise ValueError('test')")
459 # Check that this was called, and only once.
471 # Check that this was called, and only once.
460 self.assertEqual(called, [ValueError])
472 self.assertEqual(called, [ValueError])
461 # Check that the error is on the result object
473 # Check that the error is on the result object
462 self.assertIsInstance(res.error_in_exec, ValueError)
474 self.assertIsInstance(res.error_in_exec, ValueError)
463 finally:
475 finally:
464 # Reset the custom exception hook
476 # Reset the custom exception hook
465 ip.set_custom_exc((), None)
477 ip.set_custom_exc((), None)
466
478
467 @mock.patch("builtins.print")
479 @mock.patch("builtins.print")
468 def test_showtraceback_with_surrogates(self, mocked_print):
480 def test_showtraceback_with_surrogates(self, mocked_print):
469 values = []
481 values = []
470
482
471 def mock_print_func(value, sep=" ", end="\n", file=sys.stdout, flush=False):
483 def mock_print_func(value, sep=" ", end="\n", file=sys.stdout, flush=False):
472 values.append(value)
484 values.append(value)
473 if value == chr(0xD8FF):
485 if value == chr(0xD8FF):
474 raise UnicodeEncodeError("utf-8", chr(0xD8FF), 0, 1, "")
486 raise UnicodeEncodeError("utf-8", chr(0xD8FF), 0, 1, "")
475
487
476 # mock builtins.print
488 # mock builtins.print
477 mocked_print.side_effect = mock_print_func
489 mocked_print.side_effect = mock_print_func
478
490
479 # ip._showtraceback() is replaced in globalipapp.py.
491 # ip._showtraceback() is replaced in globalipapp.py.
480 # Call original method to test.
492 # Call original method to test.
481 interactiveshell.InteractiveShell._showtraceback(ip, None, None, chr(0xD8FF))
493 interactiveshell.InteractiveShell._showtraceback(ip, None, None, chr(0xD8FF))
482
494
483 self.assertEqual(mocked_print.call_count, 2)
495 self.assertEqual(mocked_print.call_count, 2)
484 self.assertEqual(values, [chr(0xD8FF), "\\ud8ff"])
496 self.assertEqual(values, [chr(0xD8FF), "\\ud8ff"])
485
497
486 def test_mktempfile(self):
498 def test_mktempfile(self):
487 filename = ip.mktempfile()
499 filename = ip.mktempfile()
488 # Check that we can open the file again on Windows
500 # Check that we can open the file again on Windows
489 with open(filename, "w", encoding="utf-8") as f:
501 with open(filename, "w", encoding="utf-8") as f:
490 f.write("abc")
502 f.write("abc")
491
503
492 filename = ip.mktempfile(data="blah")
504 filename = ip.mktempfile(data="blah")
493 with open(filename, "r", encoding="utf-8") as f:
505 with open(filename, "r", encoding="utf-8") as f:
494 self.assertEqual(f.read(), "blah")
506 self.assertEqual(f.read(), "blah")
495
507
496 def test_new_main_mod(self):
508 def test_new_main_mod(self):
497 # Smoketest to check that this accepts a unicode module name
509 # Smoketest to check that this accepts a unicode module name
498 name = u'jiefmw'
510 name = u'jiefmw'
499 mod = ip.new_main_mod(u'%s.py' % name, name)
511 mod = ip.new_main_mod(u'%s.py' % name, name)
500 self.assertEqual(mod.__name__, name)
512 self.assertEqual(mod.__name__, name)
501
513
502 def test_get_exception_only(self):
514 def test_get_exception_only(self):
503 try:
515 try:
504 raise KeyboardInterrupt
516 raise KeyboardInterrupt
505 except KeyboardInterrupt:
517 except KeyboardInterrupt:
506 msg = ip.get_exception_only()
518 msg = ip.get_exception_only()
507 self.assertEqual(msg, 'KeyboardInterrupt\n')
519 self.assertEqual(msg, 'KeyboardInterrupt\n')
508
520
509 try:
521 try:
510 raise DerivedInterrupt("foo")
522 raise DerivedInterrupt("foo")
511 except KeyboardInterrupt:
523 except KeyboardInterrupt:
512 msg = ip.get_exception_only()
524 msg = ip.get_exception_only()
513 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
525 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
514
526
515 def test_inspect_text(self):
527 def test_inspect_text(self):
516 ip.run_cell('a = 5')
528 ip.run_cell('a = 5')
517 text = ip.object_inspect_text('a')
529 text = ip.object_inspect_text('a')
518 self.assertIsInstance(text, str)
530 self.assertIsInstance(text, str)
519
531
520 def test_last_execution_result(self):
532 def test_last_execution_result(self):
521 """ Check that last execution result gets set correctly (GH-10702) """
533 """ Check that last execution result gets set correctly (GH-10702) """
522 result = ip.run_cell('a = 5; a')
534 result = ip.run_cell('a = 5; a')
523 self.assertTrue(ip.last_execution_succeeded)
535 self.assertTrue(ip.last_execution_succeeded)
524 self.assertEqual(ip.last_execution_result.result, 5)
536 self.assertEqual(ip.last_execution_result.result, 5)
525
537
526 result = ip.run_cell('a = x_invalid_id_x')
538 result = ip.run_cell('a = x_invalid_id_x')
527 self.assertFalse(ip.last_execution_succeeded)
539 self.assertFalse(ip.last_execution_succeeded)
528 self.assertFalse(ip.last_execution_result.success)
540 self.assertFalse(ip.last_execution_result.success)
529 self.assertIsInstance(ip.last_execution_result.error_in_exec, NameError)
541 self.assertIsInstance(ip.last_execution_result.error_in_exec, NameError)
530
542
531 def test_reset_aliasing(self):
543 def test_reset_aliasing(self):
532 """ Check that standard posix aliases work after %reset. """
544 """ Check that standard posix aliases work after %reset. """
533 if os.name != 'posix':
545 if os.name != 'posix':
534 return
546 return
535
547
536 ip.reset()
548 ip.reset()
537 for cmd in ('clear', 'more', 'less', 'man'):
549 for cmd in ('clear', 'more', 'less', 'man'):
538 res = ip.run_cell('%' + cmd)
550 res = ip.run_cell('%' + cmd)
539 self.assertEqual(res.success, True)
551 self.assertEqual(res.success, True)
540
552
541
553
542 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
554 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
543
555
544 @onlyif_unicode_paths
556 @onlyif_unicode_paths
545 def setUp(self):
557 def setUp(self):
546 self.BASETESTDIR = tempfile.mkdtemp()
558 self.BASETESTDIR = tempfile.mkdtemp()
547 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
559 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
548 os.mkdir(self.TESTDIR)
560 os.mkdir(self.TESTDIR)
549 with open(
561 with open(
550 join(self.TESTDIR, "åäötestscript.py"), "w", encoding="utf-8"
562 join(self.TESTDIR, "åäötestscript.py"), "w", encoding="utf-8"
551 ) as sfile:
563 ) as sfile:
552 sfile.write("pass\n")
564 sfile.write("pass\n")
553 self.oldpath = os.getcwd()
565 self.oldpath = os.getcwd()
554 os.chdir(self.TESTDIR)
566 os.chdir(self.TESTDIR)
555 self.fname = u"åäötestscript.py"
567 self.fname = u"åäötestscript.py"
556
568
557 def tearDown(self):
569 def tearDown(self):
558 os.chdir(self.oldpath)
570 os.chdir(self.oldpath)
559 shutil.rmtree(self.BASETESTDIR)
571 shutil.rmtree(self.BASETESTDIR)
560
572
561 @onlyif_unicode_paths
573 @onlyif_unicode_paths
562 def test_1(self):
574 def test_1(self):
563 """Test safe_execfile with non-ascii path
575 """Test safe_execfile with non-ascii path
564 """
576 """
565 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
577 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
566
578
567 class ExitCodeChecks(tt.TempFileMixin):
579 class ExitCodeChecks(tt.TempFileMixin):
568
580
569 def setUp(self):
581 def setUp(self):
570 self.system = ip.system_raw
582 self.system = ip.system_raw
571
583
572 def test_exit_code_ok(self):
584 def test_exit_code_ok(self):
573 self.system('exit 0')
585 self.system('exit 0')
574 self.assertEqual(ip.user_ns['_exit_code'], 0)
586 self.assertEqual(ip.user_ns['_exit_code'], 0)
575
587
576 def test_exit_code_error(self):
588 def test_exit_code_error(self):
577 self.system('exit 1')
589 self.system('exit 1')
578 self.assertEqual(ip.user_ns['_exit_code'], 1)
590 self.assertEqual(ip.user_ns['_exit_code'], 1)
579
591
580 @skipif(not hasattr(signal, 'SIGALRM'))
592 @skipif(not hasattr(signal, 'SIGALRM'))
581 def test_exit_code_signal(self):
593 def test_exit_code_signal(self):
582 self.mktmp("import signal, time\n"
594 self.mktmp("import signal, time\n"
583 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
595 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
584 "time.sleep(1)\n")
596 "time.sleep(1)\n")
585 self.system("%s %s" % (sys.executable, self.fname))
597 self.system("%s %s" % (sys.executable, self.fname))
586 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
598 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
587
599
588 @onlyif_cmds_exist("csh")
600 @onlyif_cmds_exist("csh")
589 def test_exit_code_signal_csh(self): # pragma: no cover
601 def test_exit_code_signal_csh(self): # pragma: no cover
590 SHELL = os.environ.get("SHELL", None)
602 SHELL = os.environ.get("SHELL", None)
591 os.environ["SHELL"] = find_cmd("csh")
603 os.environ["SHELL"] = find_cmd("csh")
592 try:
604 try:
593 self.test_exit_code_signal()
605 self.test_exit_code_signal()
594 finally:
606 finally:
595 if SHELL is not None:
607 if SHELL is not None:
596 os.environ['SHELL'] = SHELL
608 os.environ['SHELL'] = SHELL
597 else:
609 else:
598 del os.environ['SHELL']
610 del os.environ['SHELL']
599
611
600
612
601 class TestSystemRaw(ExitCodeChecks):
613 class TestSystemRaw(ExitCodeChecks):
602
614
603 def setUp(self):
615 def setUp(self):
604 super().setUp()
616 super().setUp()
605 self.system = ip.system_raw
617 self.system = ip.system_raw
606
618
607 @onlyif_unicode_paths
619 @onlyif_unicode_paths
608 def test_1(self):
620 def test_1(self):
609 """Test system_raw with non-ascii cmd
621 """Test system_raw with non-ascii cmd
610 """
622 """
611 cmd = u'''python -c "'åäö'" '''
623 cmd = u'''python -c "'åäö'" '''
612 ip.system_raw(cmd)
624 ip.system_raw(cmd)
613
625
614 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
626 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
615 @mock.patch('os.system', side_effect=KeyboardInterrupt)
627 @mock.patch('os.system', side_effect=KeyboardInterrupt)
616 def test_control_c(self, *mocks):
628 def test_control_c(self, *mocks):
617 try:
629 try:
618 self.system("sleep 1 # wont happen")
630 self.system("sleep 1 # wont happen")
619 except KeyboardInterrupt: # pragma: no cove
631 except KeyboardInterrupt: # pragma: no cove
620 self.fail(
632 self.fail(
621 "system call should intercept "
633 "system call should intercept "
622 "keyboard interrupt from subprocess.call"
634 "keyboard interrupt from subprocess.call"
623 )
635 )
624 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
636 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
625
637
626 def test_magic_warnings(self):
638 def test_magic_warnings(self):
627 for magic_cmd in ("pip", "conda", "cd"):
639 for magic_cmd in ("pip", "conda", "cd"):
628 with self.assertWarnsRegex(Warning, "You executed the system command"):
640 with self.assertWarnsRegex(Warning, "You executed the system command"):
629 ip.system_raw(magic_cmd)
641 ip.system_raw(magic_cmd)
630
642
631 # TODO: Exit codes are currently ignored on Windows.
643 # TODO: Exit codes are currently ignored on Windows.
632 class TestSystemPipedExitCode(ExitCodeChecks):
644 class TestSystemPipedExitCode(ExitCodeChecks):
633
645
634 def setUp(self):
646 def setUp(self):
635 super().setUp()
647 super().setUp()
636 self.system = ip.system_piped
648 self.system = ip.system_piped
637
649
638 @skip_win32
650 @skip_win32
639 def test_exit_code_ok(self):
651 def test_exit_code_ok(self):
640 ExitCodeChecks.test_exit_code_ok(self)
652 ExitCodeChecks.test_exit_code_ok(self)
641
653
642 @skip_win32
654 @skip_win32
643 def test_exit_code_error(self):
655 def test_exit_code_error(self):
644 ExitCodeChecks.test_exit_code_error(self)
656 ExitCodeChecks.test_exit_code_error(self)
645
657
646 @skip_win32
658 @skip_win32
647 def test_exit_code_signal(self):
659 def test_exit_code_signal(self):
648 ExitCodeChecks.test_exit_code_signal(self)
660 ExitCodeChecks.test_exit_code_signal(self)
649
661
650 class TestModules(tt.TempFileMixin):
662 class TestModules(tt.TempFileMixin):
651 def test_extraneous_loads(self):
663 def test_extraneous_loads(self):
652 """Test we're not loading modules on startup that we shouldn't.
664 """Test we're not loading modules on startup that we shouldn't.
653 """
665 """
654 self.mktmp("import sys\n"
666 self.mktmp("import sys\n"
655 "print('numpy' in sys.modules)\n"
667 "print('numpy' in sys.modules)\n"
656 "print('ipyparallel' in sys.modules)\n"
668 "print('ipyparallel' in sys.modules)\n"
657 "print('ipykernel' in sys.modules)\n"
669 "print('ipykernel' in sys.modules)\n"
658 )
670 )
659 out = "False\nFalse\nFalse\n"
671 out = "False\nFalse\nFalse\n"
660 tt.ipexec_validate(self.fname, out)
672 tt.ipexec_validate(self.fname, out)
661
673
662 class Negator(ast.NodeTransformer):
674 class Negator(ast.NodeTransformer):
663 """Negates all number literals in an AST."""
675 """Negates all number literals in an AST."""
664
676
665 # for python 3.7 and earlier
677 # for python 3.7 and earlier
666 def visit_Num(self, node):
678 def visit_Num(self, node):
667 node.n = -node.n
679 node.n = -node.n
668 return node
680 return node
669
681
670 # for python 3.8+
682 # for python 3.8+
671 def visit_Constant(self, node):
683 def visit_Constant(self, node):
672 if isinstance(node.value, int):
684 if isinstance(node.value, int):
673 return self.visit_Num(node)
685 return self.visit_Num(node)
674 return node
686 return node
675
687
676 class TestAstTransform(unittest.TestCase):
688 class TestAstTransform(unittest.TestCase):
677 def setUp(self):
689 def setUp(self):
678 self.negator = Negator()
690 self.negator = Negator()
679 ip.ast_transformers.append(self.negator)
691 ip.ast_transformers.append(self.negator)
680
692
681 def tearDown(self):
693 def tearDown(self):
682 ip.ast_transformers.remove(self.negator)
694 ip.ast_transformers.remove(self.negator)
683
695
684 def test_non_int_const(self):
696 def test_non_int_const(self):
685 with tt.AssertPrints("hello"):
697 with tt.AssertPrints("hello"):
686 ip.run_cell('print("hello")')
698 ip.run_cell('print("hello")')
687
699
688 def test_run_cell(self):
700 def test_run_cell(self):
689 with tt.AssertPrints("-34"):
701 with tt.AssertPrints("-34"):
690 ip.run_cell("print(12 + 22)")
702 ip.run_cell("print(12 + 22)")
691
703
692 # A named reference to a number shouldn't be transformed.
704 # A named reference to a number shouldn't be transformed.
693 ip.user_ns["n"] = 55
705 ip.user_ns["n"] = 55
694 with tt.AssertNotPrints("-55"):
706 with tt.AssertNotPrints("-55"):
695 ip.run_cell("print(n)")
707 ip.run_cell("print(n)")
696
708
697 def test_timeit(self):
709 def test_timeit(self):
698 called = set()
710 called = set()
699 def f(x):
711 def f(x):
700 called.add(x)
712 called.add(x)
701 ip.push({'f':f})
713 ip.push({'f':f})
702
714
703 with tt.AssertPrints("std. dev. of"):
715 with tt.AssertPrints("std. dev. of"):
704 ip.run_line_magic("timeit", "-n1 f(1)")
716 ip.run_line_magic("timeit", "-n1 f(1)")
705 self.assertEqual(called, {-1})
717 self.assertEqual(called, {-1})
706 called.clear()
718 called.clear()
707
719
708 with tt.AssertPrints("std. dev. of"):
720 with tt.AssertPrints("std. dev. of"):
709 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
721 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
710 self.assertEqual(called, {-2, -3})
722 self.assertEqual(called, {-2, -3})
711
723
712 def test_time(self):
724 def test_time(self):
713 called = []
725 called = []
714 def f(x):
726 def f(x):
715 called.append(x)
727 called.append(x)
716 ip.push({'f':f})
728 ip.push({'f':f})
717
729
718 # Test with an expression
730 # Test with an expression
719 with tt.AssertPrints("Wall time: "):
731 with tt.AssertPrints("Wall time: "):
720 ip.run_line_magic("time", "f(5+9)")
732 ip.run_line_magic("time", "f(5+9)")
721 self.assertEqual(called, [-14])
733 self.assertEqual(called, [-14])
722 called[:] = []
734 called[:] = []
723
735
724 # Test with a statement (different code path)
736 # Test with a statement (different code path)
725 with tt.AssertPrints("Wall time: "):
737 with tt.AssertPrints("Wall time: "):
726 ip.run_line_magic("time", "a = f(-3 + -2)")
738 ip.run_line_magic("time", "a = f(-3 + -2)")
727 self.assertEqual(called, [5])
739 self.assertEqual(called, [5])
728
740
729 def test_macro(self):
741 def test_macro(self):
730 ip.push({'a':10})
742 ip.push({'a':10})
731 # The AST transformation makes this do a+=-1
743 # The AST transformation makes this do a+=-1
732 ip.define_macro("amacro", "a+=1\nprint(a)")
744 ip.define_macro("amacro", "a+=1\nprint(a)")
733
745
734 with tt.AssertPrints("9"):
746 with tt.AssertPrints("9"):
735 ip.run_cell("amacro")
747 ip.run_cell("amacro")
736 with tt.AssertPrints("8"):
748 with tt.AssertPrints("8"):
737 ip.run_cell("amacro")
749 ip.run_cell("amacro")
738
750
739 class TestMiscTransform(unittest.TestCase):
751 class TestMiscTransform(unittest.TestCase):
740
752
741
753
742 def test_transform_only_once(self):
754 def test_transform_only_once(self):
743 cleanup = 0
755 cleanup = 0
744 line_t = 0
756 line_t = 0
745 def count_cleanup(lines):
757 def count_cleanup(lines):
746 nonlocal cleanup
758 nonlocal cleanup
747 cleanup += 1
759 cleanup += 1
748 return lines
760 return lines
749
761
750 def count_line_t(lines):
762 def count_line_t(lines):
751 nonlocal line_t
763 nonlocal line_t
752 line_t += 1
764 line_t += 1
753 return lines
765 return lines
754
766
755 ip.input_transformer_manager.cleanup_transforms.append(count_cleanup)
767 ip.input_transformer_manager.cleanup_transforms.append(count_cleanup)
756 ip.input_transformer_manager.line_transforms.append(count_line_t)
768 ip.input_transformer_manager.line_transforms.append(count_line_t)
757
769
758 ip.run_cell('1')
770 ip.run_cell('1')
759
771
760 assert cleanup == 1
772 assert cleanup == 1
761 assert line_t == 1
773 assert line_t == 1
762
774
763 class IntegerWrapper(ast.NodeTransformer):
775 class IntegerWrapper(ast.NodeTransformer):
764 """Wraps all integers in a call to Integer()"""
776 """Wraps all integers in a call to Integer()"""
765
777
766 # for Python 3.7 and earlier
778 # for Python 3.7 and earlier
767
779
768 # for Python 3.7 and earlier
780 # for Python 3.7 and earlier
769 def visit_Num(self, node):
781 def visit_Num(self, node):
770 if isinstance(node.n, int):
782 if isinstance(node.n, int):
771 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
783 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
772 args=[node], keywords=[])
784 args=[node], keywords=[])
773 return node
785 return node
774
786
775 # For Python 3.8+
787 # For Python 3.8+
776 def visit_Constant(self, node):
788 def visit_Constant(self, node):
777 if isinstance(node.value, int):
789 if isinstance(node.value, int):
778 return self.visit_Num(node)
790 return self.visit_Num(node)
779 return node
791 return node
780
792
781
793
782 class TestAstTransform2(unittest.TestCase):
794 class TestAstTransform2(unittest.TestCase):
783 def setUp(self):
795 def setUp(self):
784 self.intwrapper = IntegerWrapper()
796 self.intwrapper = IntegerWrapper()
785 ip.ast_transformers.append(self.intwrapper)
797 ip.ast_transformers.append(self.intwrapper)
786
798
787 self.calls = []
799 self.calls = []
788 def Integer(*args):
800 def Integer(*args):
789 self.calls.append(args)
801 self.calls.append(args)
790 return args
802 return args
791 ip.push({"Integer": Integer})
803 ip.push({"Integer": Integer})
792
804
793 def tearDown(self):
805 def tearDown(self):
794 ip.ast_transformers.remove(self.intwrapper)
806 ip.ast_transformers.remove(self.intwrapper)
795 del ip.user_ns['Integer']
807 del ip.user_ns['Integer']
796
808
797 def test_run_cell(self):
809 def test_run_cell(self):
798 ip.run_cell("n = 2")
810 ip.run_cell("n = 2")
799 self.assertEqual(self.calls, [(2,)])
811 self.assertEqual(self.calls, [(2,)])
800
812
801 # This shouldn't throw an error
813 # This shouldn't throw an error
802 ip.run_cell("o = 2.0")
814 ip.run_cell("o = 2.0")
803 self.assertEqual(ip.user_ns['o'], 2.0)
815 self.assertEqual(ip.user_ns['o'], 2.0)
804
816
805 def test_run_cell_non_int(self):
817 def test_run_cell_non_int(self):
806 ip.run_cell("n = 'a'")
818 ip.run_cell("n = 'a'")
807 assert self.calls == []
819 assert self.calls == []
808
820
809 def test_timeit(self):
821 def test_timeit(self):
810 called = set()
822 called = set()
811 def f(x):
823 def f(x):
812 called.add(x)
824 called.add(x)
813 ip.push({'f':f})
825 ip.push({'f':f})
814
826
815 with tt.AssertPrints("std. dev. of"):
827 with tt.AssertPrints("std. dev. of"):
816 ip.run_line_magic("timeit", "-n1 f(1)")
828 ip.run_line_magic("timeit", "-n1 f(1)")
817 self.assertEqual(called, {(1,)})
829 self.assertEqual(called, {(1,)})
818 called.clear()
830 called.clear()
819
831
820 with tt.AssertPrints("std. dev. of"):
832 with tt.AssertPrints("std. dev. of"):
821 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
833 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
822 self.assertEqual(called, {(2,), (3,)})
834 self.assertEqual(called, {(2,), (3,)})
823
835
824 class ErrorTransformer(ast.NodeTransformer):
836 class ErrorTransformer(ast.NodeTransformer):
825 """Throws an error when it sees a number."""
837 """Throws an error when it sees a number."""
826
838
827 def visit_Constant(self, node):
839 def visit_Constant(self, node):
828 if isinstance(node.value, int):
840 if isinstance(node.value, int):
829 raise ValueError("test")
841 raise ValueError("test")
830 return node
842 return node
831
843
832
844
833 class TestAstTransformError(unittest.TestCase):
845 class TestAstTransformError(unittest.TestCase):
834 def test_unregistering(self):
846 def test_unregistering(self):
835 err_transformer = ErrorTransformer()
847 err_transformer = ErrorTransformer()
836 ip.ast_transformers.append(err_transformer)
848 ip.ast_transformers.append(err_transformer)
837
849
838 with self.assertWarnsRegex(UserWarning, "It will be unregistered"):
850 with self.assertWarnsRegex(UserWarning, "It will be unregistered"):
839 ip.run_cell("1 + 2")
851 ip.run_cell("1 + 2")
840
852
841 # This should have been removed.
853 # This should have been removed.
842 self.assertNotIn(err_transformer, ip.ast_transformers)
854 self.assertNotIn(err_transformer, ip.ast_transformers)
843
855
844
856
845 class StringRejector(ast.NodeTransformer):
857 class StringRejector(ast.NodeTransformer):
846 """Throws an InputRejected when it sees a string literal.
858 """Throws an InputRejected when it sees a string literal.
847
859
848 Used to verify that NodeTransformers can signal that a piece of code should
860 Used to verify that NodeTransformers can signal that a piece of code should
849 not be executed by throwing an InputRejected.
861 not be executed by throwing an InputRejected.
850 """
862 """
851
863
852 # 3.8 only
864 # 3.8 only
853 def visit_Constant(self, node):
865 def visit_Constant(self, node):
854 if isinstance(node.value, str):
866 if isinstance(node.value, str):
855 raise InputRejected("test")
867 raise InputRejected("test")
856 return node
868 return node
857
869
858
870
859 class TestAstTransformInputRejection(unittest.TestCase):
871 class TestAstTransformInputRejection(unittest.TestCase):
860
872
861 def setUp(self):
873 def setUp(self):
862 self.transformer = StringRejector()
874 self.transformer = StringRejector()
863 ip.ast_transformers.append(self.transformer)
875 ip.ast_transformers.append(self.transformer)
864
876
865 def tearDown(self):
877 def tearDown(self):
866 ip.ast_transformers.remove(self.transformer)
878 ip.ast_transformers.remove(self.transformer)
867
879
868 def test_input_rejection(self):
880 def test_input_rejection(self):
869 """Check that NodeTransformers can reject input."""
881 """Check that NodeTransformers can reject input."""
870
882
871 expect_exception_tb = tt.AssertPrints("InputRejected: test")
883 expect_exception_tb = tt.AssertPrints("InputRejected: test")
872 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
884 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
873
885
874 # Run the same check twice to verify that the transformer is not
886 # Run the same check twice to verify that the transformer is not
875 # disabled after raising.
887 # disabled after raising.
876 with expect_exception_tb, expect_no_cell_output:
888 with expect_exception_tb, expect_no_cell_output:
877 ip.run_cell("'unsafe'")
889 ip.run_cell("'unsafe'")
878
890
879 with expect_exception_tb, expect_no_cell_output:
891 with expect_exception_tb, expect_no_cell_output:
880 res = ip.run_cell("'unsafe'")
892 res = ip.run_cell("'unsafe'")
881
893
882 self.assertIsInstance(res.error_before_exec, InputRejected)
894 self.assertIsInstance(res.error_before_exec, InputRejected)
883
895
884 def test__IPYTHON__():
896 def test__IPYTHON__():
885 # This shouldn't raise a NameError, that's all
897 # This shouldn't raise a NameError, that's all
886 __IPYTHON__
898 __IPYTHON__
887
899
888
900
889 class DummyRepr(object):
901 class DummyRepr(object):
890 def __repr__(self):
902 def __repr__(self):
891 return "DummyRepr"
903 return "DummyRepr"
892
904
893 def _repr_html_(self):
905 def _repr_html_(self):
894 return "<b>dummy</b>"
906 return "<b>dummy</b>"
895
907
896 def _repr_javascript_(self):
908 def _repr_javascript_(self):
897 return "console.log('hi');", {'key': 'value'}
909 return "console.log('hi');", {'key': 'value'}
898
910
899
911
900 def test_user_variables():
912 def test_user_variables():
901 # enable all formatters
913 # enable all formatters
902 ip.display_formatter.active_types = ip.display_formatter.format_types
914 ip.display_formatter.active_types = ip.display_formatter.format_types
903
915
904 ip.user_ns['dummy'] = d = DummyRepr()
916 ip.user_ns['dummy'] = d = DummyRepr()
905 keys = {'dummy', 'doesnotexist'}
917 keys = {'dummy', 'doesnotexist'}
906 r = ip.user_expressions({ key:key for key in keys})
918 r = ip.user_expressions({ key:key for key in keys})
907
919
908 assert keys == set(r.keys())
920 assert keys == set(r.keys())
909 dummy = r["dummy"]
921 dummy = r["dummy"]
910 assert {"status", "data", "metadata"} == set(dummy.keys())
922 assert {"status", "data", "metadata"} == set(dummy.keys())
911 assert dummy["status"] == "ok"
923 assert dummy["status"] == "ok"
912 data = dummy["data"]
924 data = dummy["data"]
913 metadata = dummy["metadata"]
925 metadata = dummy["metadata"]
914 assert data.get("text/html") == d._repr_html_()
926 assert data.get("text/html") == d._repr_html_()
915 js, jsmd = d._repr_javascript_()
927 js, jsmd = d._repr_javascript_()
916 assert data.get("application/javascript") == js
928 assert data.get("application/javascript") == js
917 assert metadata.get("application/javascript") == jsmd
929 assert metadata.get("application/javascript") == jsmd
918
930
919 dne = r["doesnotexist"]
931 dne = r["doesnotexist"]
920 assert dne["status"] == "error"
932 assert dne["status"] == "error"
921 assert dne["ename"] == "NameError"
933 assert dne["ename"] == "NameError"
922
934
923 # back to text only
935 # back to text only
924 ip.display_formatter.active_types = ['text/plain']
936 ip.display_formatter.active_types = ['text/plain']
925
937
926 def test_user_expression():
938 def test_user_expression():
927 # enable all formatters
939 # enable all formatters
928 ip.display_formatter.active_types = ip.display_formatter.format_types
940 ip.display_formatter.active_types = ip.display_formatter.format_types
929 query = {
941 query = {
930 'a' : '1 + 2',
942 'a' : '1 + 2',
931 'b' : '1/0',
943 'b' : '1/0',
932 }
944 }
933 r = ip.user_expressions(query)
945 r = ip.user_expressions(query)
934 import pprint
946 import pprint
935 pprint.pprint(r)
947 pprint.pprint(r)
936 assert set(r.keys()) == set(query.keys())
948 assert set(r.keys()) == set(query.keys())
937 a = r["a"]
949 a = r["a"]
938 assert {"status", "data", "metadata"} == set(a.keys())
950 assert {"status", "data", "metadata"} == set(a.keys())
939 assert a["status"] == "ok"
951 assert a["status"] == "ok"
940 data = a["data"]
952 data = a["data"]
941 metadata = a["metadata"]
953 metadata = a["metadata"]
942 assert data.get("text/plain") == "3"
954 assert data.get("text/plain") == "3"
943
955
944 b = r["b"]
956 b = r["b"]
945 assert b["status"] == "error"
957 assert b["status"] == "error"
946 assert b["ename"] == "ZeroDivisionError"
958 assert b["ename"] == "ZeroDivisionError"
947
959
948 # back to text only
960 # back to text only
949 ip.display_formatter.active_types = ['text/plain']
961 ip.display_formatter.active_types = ['text/plain']
950
962
951
963
952 class TestSyntaxErrorTransformer(unittest.TestCase):
964 class TestSyntaxErrorTransformer(unittest.TestCase):
953 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
965 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
954
966
955 @staticmethod
967 @staticmethod
956 def transformer(lines):
968 def transformer(lines):
957 for line in lines:
969 for line in lines:
958 pos = line.find('syntaxerror')
970 pos = line.find('syntaxerror')
959 if pos >= 0:
971 if pos >= 0:
960 e = SyntaxError('input contains "syntaxerror"')
972 e = SyntaxError('input contains "syntaxerror"')
961 e.text = line
973 e.text = line
962 e.offset = pos + 1
974 e.offset = pos + 1
963 raise e
975 raise e
964 return lines
976 return lines
965
977
966 def setUp(self):
978 def setUp(self):
967 ip.input_transformers_post.append(self.transformer)
979 ip.input_transformers_post.append(self.transformer)
968
980
969 def tearDown(self):
981 def tearDown(self):
970 ip.input_transformers_post.remove(self.transformer)
982 ip.input_transformers_post.remove(self.transformer)
971
983
972 def test_syntaxerror_input_transformer(self):
984 def test_syntaxerror_input_transformer(self):
973 with tt.AssertPrints('1234'):
985 with tt.AssertPrints('1234'):
974 ip.run_cell('1234')
986 ip.run_cell('1234')
975 with tt.AssertPrints('SyntaxError: invalid syntax'):
987 with tt.AssertPrints('SyntaxError: invalid syntax'):
976 ip.run_cell('1 2 3') # plain python syntax error
988 ip.run_cell('1 2 3') # plain python syntax error
977 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
989 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
978 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
990 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
979 with tt.AssertPrints('3456'):
991 with tt.AssertPrints('3456'):
980 ip.run_cell('3456')
992 ip.run_cell('3456')
981
993
982
994
983 class TestWarningSuppression(unittest.TestCase):
995 class TestWarningSuppression(unittest.TestCase):
984 def test_warning_suppression(self):
996 def test_warning_suppression(self):
985 ip.run_cell("import warnings")
997 ip.run_cell("import warnings")
986 try:
998 try:
987 with self.assertWarnsRegex(UserWarning, "asdf"):
999 with self.assertWarnsRegex(UserWarning, "asdf"):
988 ip.run_cell("warnings.warn('asdf')")
1000 ip.run_cell("warnings.warn('asdf')")
989 # Here's the real test -- if we run that again, we should get the
1001 # Here's the real test -- if we run that again, we should get the
990 # warning again. Traditionally, each warning was only issued once per
1002 # warning again. Traditionally, each warning was only issued once per
991 # IPython session (approximately), even if the user typed in new and
1003 # IPython session (approximately), even if the user typed in new and
992 # different code that should have also triggered the warning, leading
1004 # different code that should have also triggered the warning, leading
993 # to much confusion.
1005 # to much confusion.
994 with self.assertWarnsRegex(UserWarning, "asdf"):
1006 with self.assertWarnsRegex(UserWarning, "asdf"):
995 ip.run_cell("warnings.warn('asdf')")
1007 ip.run_cell("warnings.warn('asdf')")
996 finally:
1008 finally:
997 ip.run_cell("del warnings")
1009 ip.run_cell("del warnings")
998
1010
999
1011
1000 def test_deprecation_warning(self):
1012 def test_deprecation_warning(self):
1001 ip.run_cell("""
1013 ip.run_cell("""
1002 import warnings
1014 import warnings
1003 def wrn():
1015 def wrn():
1004 warnings.warn(
1016 warnings.warn(
1005 "I AM A WARNING",
1017 "I AM A WARNING",
1006 DeprecationWarning
1018 DeprecationWarning
1007 )
1019 )
1008 """)
1020 """)
1009 try:
1021 try:
1010 with self.assertWarnsRegex(DeprecationWarning, "I AM A WARNING"):
1022 with self.assertWarnsRegex(DeprecationWarning, "I AM A WARNING"):
1011 ip.run_cell("wrn()")
1023 ip.run_cell("wrn()")
1012 finally:
1024 finally:
1013 ip.run_cell("del warnings")
1025 ip.run_cell("del warnings")
1014 ip.run_cell("del wrn")
1026 ip.run_cell("del wrn")
1015
1027
1016
1028
1017 class TestImportNoDeprecate(tt.TempFileMixin):
1029 class TestImportNoDeprecate(tt.TempFileMixin):
1018
1030
1019 def setUp(self):
1031 def setUp(self):
1020 """Make a valid python temp file."""
1032 """Make a valid python temp file."""
1021 self.mktmp("""
1033 self.mktmp("""
1022 import warnings
1034 import warnings
1023 def wrn():
1035 def wrn():
1024 warnings.warn(
1036 warnings.warn(
1025 "I AM A WARNING",
1037 "I AM A WARNING",
1026 DeprecationWarning
1038 DeprecationWarning
1027 )
1039 )
1028 """)
1040 """)
1029 super().setUp()
1041 super().setUp()
1030
1042
1031 def test_no_dep(self):
1043 def test_no_dep(self):
1032 """
1044 """
1033 No deprecation warning should be raised from imported functions
1045 No deprecation warning should be raised from imported functions
1034 """
1046 """
1035 ip.run_cell("from {} import wrn".format(self.fname))
1047 ip.run_cell("from {} import wrn".format(self.fname))
1036
1048
1037 with tt.AssertNotPrints("I AM A WARNING"):
1049 with tt.AssertNotPrints("I AM A WARNING"):
1038 ip.run_cell("wrn()")
1050 ip.run_cell("wrn()")
1039 ip.run_cell("del wrn")
1051 ip.run_cell("del wrn")
1040
1052
1041
1053
1042 def test_custom_exc_count():
1054 def test_custom_exc_count():
1043 hook = mock.Mock(return_value=None)
1055 hook = mock.Mock(return_value=None)
1044 ip.set_custom_exc((SyntaxError,), hook)
1056 ip.set_custom_exc((SyntaxError,), hook)
1045 before = ip.execution_count
1057 before = ip.execution_count
1046 ip.run_cell("def foo()", store_history=True)
1058 ip.run_cell("def foo()", store_history=True)
1047 # restore default excepthook
1059 # restore default excepthook
1048 ip.set_custom_exc((), None)
1060 ip.set_custom_exc((), None)
1049 assert hook.call_count == 1
1061 assert hook.call_count == 1
1050 assert ip.execution_count == before + 1
1062 assert ip.execution_count == before + 1
1051
1063
1052
1064
1053 def test_run_cell_async():
1065 def test_run_cell_async():
1054 ip.run_cell("import asyncio")
1066 ip.run_cell("import asyncio")
1055 coro = ip.run_cell_async("await asyncio.sleep(0.01)\n5")
1067 coro = ip.run_cell_async("await asyncio.sleep(0.01)\n5")
1056 assert asyncio.iscoroutine(coro)
1068 assert asyncio.iscoroutine(coro)
1057 loop = asyncio.new_event_loop()
1069 loop = asyncio.new_event_loop()
1058 result = loop.run_until_complete(coro)
1070 result = loop.run_until_complete(coro)
1059 assert isinstance(result, interactiveshell.ExecutionResult)
1071 assert isinstance(result, interactiveshell.ExecutionResult)
1060 assert result.result == 5
1072 assert result.result == 5
1061
1073
1062
1074
1063 def test_run_cell_await():
1075 def test_run_cell_await():
1064 ip.run_cell("import asyncio")
1076 ip.run_cell("import asyncio")
1065 result = ip.run_cell("await asyncio.sleep(0.01); 10")
1077 result = ip.run_cell("await asyncio.sleep(0.01); 10")
1066 assert ip.user_ns["_"] == 10
1078 assert ip.user_ns["_"] == 10
1067
1079
1068
1080
1069 def test_run_cell_asyncio_run():
1081 def test_run_cell_asyncio_run():
1070 ip.run_cell("import asyncio")
1082 ip.run_cell("import asyncio")
1071 result = ip.run_cell("await asyncio.sleep(0.01); 1")
1083 result = ip.run_cell("await asyncio.sleep(0.01); 1")
1072 assert ip.user_ns["_"] == 1
1084 assert ip.user_ns["_"] == 1
1073 result = ip.run_cell("asyncio.run(asyncio.sleep(0.01)); 2")
1085 result = ip.run_cell("asyncio.run(asyncio.sleep(0.01)); 2")
1074 assert ip.user_ns["_"] == 2
1086 assert ip.user_ns["_"] == 2
1075 result = ip.run_cell("await asyncio.sleep(0.01); 3")
1087 result = ip.run_cell("await asyncio.sleep(0.01); 3")
1076 assert ip.user_ns["_"] == 3
1088 assert ip.user_ns["_"] == 3
1077
1089
1078
1090
1079 def test_should_run_async():
1091 def test_should_run_async():
1080 assert not ip.should_run_async("a = 5")
1092 assert not ip.should_run_async("a = 5")
1081 assert ip.should_run_async("await x")
1093 assert ip.should_run_async("await x")
1082 assert ip.should_run_async("import asyncio; await asyncio.sleep(1)")
1094 assert ip.should_run_async("import asyncio; await asyncio.sleep(1)")
1083
1095
1084
1096
1085 def test_set_custom_completer():
1097 def test_set_custom_completer():
1086 num_completers = len(ip.Completer.matchers)
1098 num_completers = len(ip.Completer.matchers)
1087
1099
1088 def foo(*args, **kwargs):
1100 def foo(*args, **kwargs):
1089 return "I'm a completer!"
1101 return "I'm a completer!"
1090
1102
1091 ip.set_custom_completer(foo, 0)
1103 ip.set_custom_completer(foo, 0)
1092
1104
1093 # check that we've really added a new completer
1105 # check that we've really added a new completer
1094 assert len(ip.Completer.matchers) == num_completers + 1
1106 assert len(ip.Completer.matchers) == num_completers + 1
1095
1107
1096 # check that the first completer is the function we defined
1108 # check that the first completer is the function we defined
1097 assert ip.Completer.matchers[0]() == "I'm a completer!"
1109 assert ip.Completer.matchers[0]() == "I'm a completer!"
1098
1110
1099 # clean up
1111 # clean up
1100 ip.Completer.custom_matchers.pop()
1112 ip.Completer.custom_matchers.pop()
@@ -1,248 +1,291 b''
1 """Tests for the key interactiveshell module, where the main ipython class is defined.
1 """Tests for the key interactiveshell module, where the main ipython class is defined.
2 """
2 """
3 #-----------------------------------------------------------------------------
4 # Module imports
5 #-----------------------------------------------------------------------------
6
3
4 import stack_data
5 import sys
7
6
8 # our own packages
7 SV_VERSION = tuple([int(x) for x in stack_data.__version__.split(".")[0:2]])
9
8
10 #-----------------------------------------------------------------------------
11 # Test functions
12 #-----------------------------------------------------------------------------
13
9
14 def test_reset():
10 def test_reset():
15 """reset must clear most namespaces."""
11 """reset must clear most namespaces."""
16
12
17 # Check that reset runs without error
13 # Check that reset runs without error
18 ip.reset()
14 ip.reset()
19
15
20 # Once we've reset it (to clear of any junk that might have been there from
16 # Once we've reset it (to clear of any junk that might have been there from
21 # other tests, we can count how many variables are in the user's namespace
17 # other tests, we can count how many variables are in the user's namespace
22 nvars_user_ns = len(ip.user_ns)
18 nvars_user_ns = len(ip.user_ns)
23 nvars_hidden = len(ip.user_ns_hidden)
19 nvars_hidden = len(ip.user_ns_hidden)
24
20
25 # Now add a few variables to user_ns, and check that reset clears them
21 # Now add a few variables to user_ns, and check that reset clears them
26 ip.user_ns['x'] = 1
22 ip.user_ns['x'] = 1
27 ip.user_ns['y'] = 1
23 ip.user_ns['y'] = 1
28 ip.reset()
24 ip.reset()
29
25
30 # Finally, check that all namespaces have only as many variables as we
26 # Finally, check that all namespaces have only as many variables as we
31 # expect to find in them:
27 # expect to find in them:
32 assert len(ip.user_ns) == nvars_user_ns
28 assert len(ip.user_ns) == nvars_user_ns
33 assert len(ip.user_ns_hidden) == nvars_hidden
29 assert len(ip.user_ns_hidden) == nvars_hidden
34
30
35
31
36 # Tests for reporting of exceptions in various modes, handling of SystemExit,
32 # Tests for reporting of exceptions in various modes, handling of SystemExit,
37 # and %tb functionality. This is really a mix of testing ultraTB and interactiveshell.
33 # and %tb functionality. This is really a mix of testing ultraTB and interactiveshell.
38
34
39 def doctest_tb_plain():
35 def doctest_tb_plain():
40 """
36 """
41 In [18]: xmode plain
37 In [18]: xmode plain
42 Exception reporting mode: Plain
38 Exception reporting mode: Plain
43
39
44 In [19]: run simpleerr.py
40 In [19]: run simpleerr.py
45 Traceback (most recent call last):
41 Traceback (most recent call last):
46 File ...:...
42 File ...:...
47 bar(mode)
43 bar(mode)
48 File ...:... in bar
44 File ...:... in bar
49 div0()
45 div0()
50 File ...:... in div0
46 File ...:... in div0
51 x/y
47 x/y
52 ZeroDivisionError: ...
48 ZeroDivisionError: ...
53 """
49 """
54
50
55
51
56 def doctest_tb_context():
52 def doctest_tb_context():
57 """
53 """
58 In [3]: xmode context
54 In [3]: xmode context
59 Exception reporting mode: Context
55 Exception reporting mode: Context
60
56
61 In [4]: run simpleerr.py
57 In [4]: run simpleerr.py
62 ---------------------------------------------------------------------------
58 ---------------------------------------------------------------------------
63 ZeroDivisionError Traceback (most recent call last)
59 ZeroDivisionError Traceback (most recent call last)
64 <BLANKLINE>
60 <BLANKLINE>
65 ...
61 ...
66 30 except IndexError:
62 30 except IndexError:
67 31 mode = 'div'
63 31 mode = 'div'
68 ---> 33 bar(mode)
64 ---> 33 bar(mode)
69 <BLANKLINE>
65 <BLANKLINE>
70 ... in bar(mode)
66 ... in bar(mode)
71 15 "bar"
67 15 "bar"
72 16 if mode=='div':
68 16 if mode=='div':
73 ---> 17 div0()
69 ---> 17 div0()
74 18 elif mode=='exit':
70 18 elif mode=='exit':
75 19 try:
71 19 try:
76 <BLANKLINE>
72 <BLANKLINE>
77 ... in div0()
73 ... in div0()
78 6 x = 1
74 6 x = 1
79 7 y = 0
75 7 y = 0
80 ----> 8 x/y
76 ----> 8 x/y
81 <BLANKLINE>
77 <BLANKLINE>
82 ZeroDivisionError: ..."""
78 ZeroDivisionError: ..."""
83
79
84
80
85 def doctest_tb_verbose():
81 def doctest_tb_verbose():
86 """
82 """
87 In [5]: xmode verbose
83 In [5]: xmode verbose
88 Exception reporting mode: Verbose
84 Exception reporting mode: Verbose
89
85
90 In [6]: run simpleerr.py
86 In [6]: run simpleerr.py
91 ---------------------------------------------------------------------------
87 ---------------------------------------------------------------------------
92 ZeroDivisionError Traceback (most recent call last)
88 ZeroDivisionError Traceback (most recent call last)
93 <BLANKLINE>
89 <BLANKLINE>
94 ...
90 ...
95 30 except IndexError:
91 30 except IndexError:
96 31 mode = 'div'
92 31 mode = 'div'
97 ---> 33 bar(mode)
93 ---> 33 bar(mode)
98 mode = 'div'
94 mode = 'div'
99 <BLANKLINE>
95 <BLANKLINE>
100 ... in bar(mode='div')
96 ... in bar(mode='div')
101 15 "bar"
97 15 "bar"
102 16 if mode=='div':
98 16 if mode=='div':
103 ---> 17 div0()
99 ---> 17 div0()
104 18 elif mode=='exit':
100 18 elif mode=='exit':
105 19 try:
101 19 try:
106 <BLANKLINE>
102 <BLANKLINE>
107 ... in div0()
103 ... in div0()
108 6 x = 1
104 6 x = 1
109 7 y = 0
105 7 y = 0
110 ----> 8 x/y
106 ----> 8 x/y
111 x = 1
107 x = 1
112 y = 0
108 y = 0
113 <BLANKLINE>
109 <BLANKLINE>
114 ZeroDivisionError: ...
110 ZeroDivisionError: ...
115 """
111 """
116
112
117
113
118 def doctest_tb_sysexit():
114 def doctest_tb_sysexit():
119 """
115 """
120 In [17]: %xmode plain
116 In [17]: %xmode plain
121 Exception reporting mode: Plain
117 Exception reporting mode: Plain
122
118
123 In [18]: %run simpleerr.py exit
119 In [18]: %run simpleerr.py exit
124 An exception has occurred, use %tb to see the full traceback.
120 An exception has occurred, use %tb to see the full traceback.
125 SystemExit: (1, 'Mode = exit')
121 SystemExit: (1, 'Mode = exit')
126
122
127 In [19]: %run simpleerr.py exit 2
123 In [19]: %run simpleerr.py exit 2
128 An exception has occurred, use %tb to see the full traceback.
124 An exception has occurred, use %tb to see the full traceback.
129 SystemExit: (2, 'Mode = exit')
125 SystemExit: (2, 'Mode = exit')
130
126
131 In [20]: %tb
127 In [20]: %tb
132 Traceback (most recent call last):
128 Traceback (most recent call last):
133 File ...:... in execfile
129 File ...:... in execfile
134 exec(compiler(f.read(), fname, "exec"), glob, loc)
130 exec(compiler(f.read(), fname, "exec"), glob, loc)
135 File ...:...
131 File ...:...
136 bar(mode)
132 bar(mode)
137 File ...:... in bar
133 File ...:... in bar
138 sysexit(stat, mode)
134 sysexit(stat, mode)
139 File ...:... in sysexit
135 File ...:... in sysexit
140 raise SystemExit(stat, f"Mode = {mode}")
136 raise SystemExit(stat, f"Mode = {mode}")
141 SystemExit: (2, 'Mode = exit')
137 SystemExit: (2, 'Mode = exit')
142
138
143 In [21]: %xmode context
139 In [21]: %xmode context
144 Exception reporting mode: Context
140 Exception reporting mode: Context
145
141
146 In [22]: %tb
142 In [22]: %tb
147 ---------------------------------------------------------------------------
143 ---------------------------------------------------------------------------
148 SystemExit Traceback (most recent call last)
144 SystemExit Traceback (most recent call last)
149 File ..., in execfile(fname, glob, loc, compiler)
145 File ..., in execfile(fname, glob, loc, compiler)
150 ... with open(fname, "rb") as f:
146 ... with open(fname, "rb") as f:
151 ... compiler = compiler or compile
147 ... compiler = compiler or compile
152 ---> ... exec(compiler(f.read(), fname, "exec"), glob, loc)
148 ---> ... exec(compiler(f.read(), fname, "exec"), glob, loc)
153 ...
149 ...
154 30 except IndexError:
150 30 except IndexError:
155 31 mode = 'div'
151 31 mode = 'div'
156 ---> 33 bar(mode)
152 ---> 33 bar(mode)
157 <BLANKLINE>
153 <BLANKLINE>
158 ...bar(mode)
154 ...bar(mode)
159 21 except:
155 21 except:
160 22 stat = 1
156 22 stat = 1
161 ---> 23 sysexit(stat, mode)
157 ---> 23 sysexit(stat, mode)
162 24 else:
158 24 else:
163 25 raise ValueError('Unknown mode')
159 25 raise ValueError('Unknown mode')
164 <BLANKLINE>
160 <BLANKLINE>
165 ...sysexit(stat, mode)
161 ...sysexit(stat, mode)
166 10 def sysexit(stat, mode):
162 10 def sysexit(stat, mode):
167 ---> 11 raise SystemExit(stat, f"Mode = {mode}")
163 ---> 11 raise SystemExit(stat, f"Mode = {mode}")
168 <BLANKLINE>
164 <BLANKLINE>
169 SystemExit: (2, 'Mode = exit')
165 SystemExit: (2, 'Mode = exit')
170 """
166 """
171
167
172
168
173 def doctest_tb_sysexit_verbose():
169 if sys.version_info >= (3, 9):
174 """
170 if SV_VERSION < (0, 6):
175 In [18]: %run simpleerr.py exit
171
176 An exception has occurred, use %tb to see the full traceback.
172 def doctest_tb_sysexit_verbose_stack_data_05():
177 SystemExit: (1, 'Mode = exit')
173 """
178
174 In [18]: %run simpleerr.py exit
179 In [19]: %run simpleerr.py exit 2
175 An exception has occurred, use %tb to see the full traceback.
180 An exception has occurred, use %tb to see the full traceback.
176 SystemExit: (1, 'Mode = exit')
181 SystemExit: (2, 'Mode = exit')
177
182
178 In [19]: %run simpleerr.py exit 2
183 In [23]: %xmode verbose
179 An exception has occurred, use %tb to see the full traceback.
184 Exception reporting mode: Verbose
180 SystemExit: (2, 'Mode = exit')
185
181
186 In [24]: %tb
182 In [23]: %xmode verbose
187 ---------------------------------------------------------------------------
183 Exception reporting mode: Verbose
188 SystemExit Traceback (most recent call last)
184
189 <BLANKLINE>
185 In [24]: %tb
190 ...
186 ---------------------------------------------------------------------------
191 30 except IndexError:
187 SystemExit Traceback (most recent call last)
192 31 mode = 'div'
188 <BLANKLINE>
193 ---> 33 bar(mode)
189 ...
194 mode = 'exit'
190 30 except IndexError:
195 <BLANKLINE>
191 31 mode = 'div'
196 ... in bar(mode='exit')
192 ---> 33 bar(mode)
197 ... except:
193 mode = 'exit'
198 ... stat = 1
194 <BLANKLINE>
199 ---> ... sysexit(stat, mode)
195 ... in bar(mode='exit')
200 mode = 'exit'
196 ... except:
201 stat = 2
197 ... stat = 1
202 ... else:
198 ---> ... sysexit(stat, mode)
203 ... raise ValueError('Unknown mode')
199 mode = 'exit'
204 <BLANKLINE>
200 stat = 2
205 ... in sysexit(stat=2, mode='exit')
201 ... else:
206 10 def sysexit(stat, mode):
202 ... raise ValueError('Unknown mode')
207 ---> 11 raise SystemExit(stat, f"Mode = {mode}")
203 <BLANKLINE>
208 stat = 2
204 ... in sysexit(stat=2, mode='exit')
209 <BLANKLINE>
205 10 def sysexit(stat, mode):
210 SystemExit: (2, 'Mode = exit')
206 ---> 11 raise SystemExit(stat, f"Mode = {mode}")
211 """
207 stat = 2
212
208 <BLANKLINE>
209 SystemExit: (2, 'Mode = exit')
210 """
211
212 else:
213 # currently the only difference is
214 # + mode = 'exit'
215
216 def doctest_tb_sysexit_verbose_stack_data_06():
217 """
218 In [18]: %run simpleerr.py exit
219 An exception has occurred, use %tb to see the full traceback.
220 SystemExit: (1, 'Mode = exit')
221
222 In [19]: %run simpleerr.py exit 2
223 An exception has occurred, use %tb to see the full traceback.
224 SystemExit: (2, 'Mode = exit')
225
226 In [23]: %xmode verbose
227 Exception reporting mode: Verbose
228
229 In [24]: %tb
230 ---------------------------------------------------------------------------
231 SystemExit Traceback (most recent call last)
232 <BLANKLINE>
233 ...
234 30 except IndexError:
235 31 mode = 'div'
236 ---> 33 bar(mode)
237 mode = 'exit'
238 <BLANKLINE>
239 ... in bar(mode='exit')
240 ... except:
241 ... stat = 1
242 ---> ... sysexit(stat, mode)
243 mode = 'exit'
244 stat = 2
245 ... else:
246 ... raise ValueError('Unknown mode')
247 <BLANKLINE>
248 ... in sysexit(stat=2, mode='exit')
249 10 def sysexit(stat, mode):
250 ---> 11 raise SystemExit(stat, f"Mode = {mode}")
251 stat = 2
252 mode = 'exit'
253 <BLANKLINE>
254 SystemExit: (2, 'Mode = exit')
255 """
213
256
214 def test_run_cell():
257 def test_run_cell():
215 import textwrap
258 import textwrap
216
259
217 ip.run_cell("a = 10\na+=1")
260 ip.run_cell("a = 10\na+=1")
218 ip.run_cell("assert a == 11\nassert 1")
261 ip.run_cell("assert a == 11\nassert 1")
219
262
220 assert ip.user_ns["a"] == 11
263 assert ip.user_ns["a"] == 11
221 complex = textwrap.dedent(
264 complex = textwrap.dedent(
222 """
265 """
223 if 1:
266 if 1:
224 print "hello"
267 print "hello"
225 if 1:
268 if 1:
226 print "world"
269 print "world"
227
270
228 if 2:
271 if 2:
229 print "foo"
272 print "foo"
230
273
231 if 3:
274 if 3:
232 print "bar"
275 print "bar"
233
276
234 if 4:
277 if 4:
235 print "bar"
278 print "bar"
236
279
237 """
280 """
238 )
281 )
239 # Simply verifies that this kind of input is run
282 # Simply verifies that this kind of input is run
240 ip.run_cell(complex)
283 ip.run_cell(complex)
241
284
242
285
243 def test_db():
286 def test_db():
244 """Test the internal database used for variable persistence."""
287 """Test the internal database used for variable persistence."""
245 ip.db["__unittest_"] = 12
288 ip.db["__unittest_"] = 12
246 assert ip.db["__unittest_"] == 12
289 assert ip.db["__unittest_"] == 12
247 del ip.db["__unittest_"]
290 del ip.db["__unittest_"]
248 assert "__unittest_" not in ip.db
291 assert "__unittest_" not in ip.db
@@ -1,1451 +1,1454 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions."""
2 """Tests for various magic functions."""
3
3
4 import gc
4 import gc
5 import io
5 import io
6 import os
6 import os
7 import re
7 import re
8 import shlex
8 import shlex
9 import sys
9 import sys
10 import warnings
10 import warnings
11 from importlib import invalidate_caches
11 from importlib import invalidate_caches
12 from io import StringIO
12 from io import StringIO
13 from pathlib import Path
13 from pathlib import Path
14 from textwrap import dedent
14 from textwrap import dedent
15 from unittest import TestCase, mock
15 from unittest import TestCase, mock
16
16
17 import pytest
17 import pytest
18
18
19 from IPython import get_ipython
19 from IPython import get_ipython
20 from IPython.core import magic
20 from IPython.core import magic
21 from IPython.core.error import UsageError
21 from IPython.core.error import UsageError
22 from IPython.core.magic import (
22 from IPython.core.magic import (
23 Magics,
23 Magics,
24 cell_magic,
24 cell_magic,
25 line_magic,
25 line_magic,
26 magics_class,
26 magics_class,
27 register_cell_magic,
27 register_cell_magic,
28 register_line_magic,
28 register_line_magic,
29 )
29 )
30 from IPython.core.magics import code, execution, logging, osm, script
30 from IPython.core.magics import code, execution, logging, osm, script
31 from IPython.testing import decorators as dec
31 from IPython.testing import decorators as dec
32 from IPython.testing import tools as tt
32 from IPython.testing import tools as tt
33 from IPython.utils.io import capture_output
33 from IPython.utils.io import capture_output
34 from IPython.utils.process import find_cmd
34 from IPython.utils.process import find_cmd
35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
36 from IPython.utils.syspathcontext import prepended_to_syspath
36 from IPython.utils.syspathcontext import prepended_to_syspath
37
37
38 from .test_debugger import PdbTestInput
38 from .test_debugger import PdbTestInput
39
39
40 from tempfile import NamedTemporaryFile
40 from tempfile import NamedTemporaryFile
41
41
42 @magic.magics_class
42 @magic.magics_class
43 class DummyMagics(magic.Magics): pass
43 class DummyMagics(magic.Magics): pass
44
44
45 def test_extract_code_ranges():
45 def test_extract_code_ranges():
46 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
46 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
47 expected = [
47 expected = [
48 (0, 1),
48 (0, 1),
49 (2, 3),
49 (2, 3),
50 (4, 6),
50 (4, 6),
51 (6, 9),
51 (6, 9),
52 (9, 14),
52 (9, 14),
53 (16, None),
53 (16, None),
54 (None, 9),
54 (None, 9),
55 (9, None),
55 (9, None),
56 (None, 13),
56 (None, 13),
57 (None, None),
57 (None, None),
58 ]
58 ]
59 actual = list(code.extract_code_ranges(instr))
59 actual = list(code.extract_code_ranges(instr))
60 assert actual == expected
60 assert actual == expected
61
61
62 def test_extract_symbols():
62 def test_extract_symbols():
63 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
63 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
64 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
64 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
65 expected = [([], ['a']),
65 expected = [([], ['a']),
66 (["def b():\n return 42\n"], []),
66 (["def b():\n return 42\n"], []),
67 (["class A: pass\n"], []),
67 (["class A: pass\n"], []),
68 (["class A: pass\n", "def b():\n return 42\n"], []),
68 (["class A: pass\n", "def b():\n return 42\n"], []),
69 (["class A: pass\n"], ['a']),
69 (["class A: pass\n"], ['a']),
70 ([], ['z'])]
70 ([], ['z'])]
71 for symbols, exp in zip(symbols_args, expected):
71 for symbols, exp in zip(symbols_args, expected):
72 assert code.extract_symbols(source, symbols) == exp
72 assert code.extract_symbols(source, symbols) == exp
73
73
74
74
75 def test_extract_symbols_raises_exception_with_non_python_code():
75 def test_extract_symbols_raises_exception_with_non_python_code():
76 source = ("=begin A Ruby program :)=end\n"
76 source = ("=begin A Ruby program :)=end\n"
77 "def hello\n"
77 "def hello\n"
78 "puts 'Hello world'\n"
78 "puts 'Hello world'\n"
79 "end")
79 "end")
80 with pytest.raises(SyntaxError):
80 with pytest.raises(SyntaxError):
81 code.extract_symbols(source, "hello")
81 code.extract_symbols(source, "hello")
82
82
83
83
84 def test_magic_not_found():
84 def test_magic_not_found():
85 # magic not found raises UsageError
85 # magic not found raises UsageError
86 with pytest.raises(UsageError):
86 with pytest.raises(UsageError):
87 _ip.magic('doesntexist')
87 _ip.run_line_magic("doesntexist", "")
88
88
89 # ensure result isn't success when a magic isn't found
89 # ensure result isn't success when a magic isn't found
90 result = _ip.run_cell('%doesntexist')
90 result = _ip.run_cell('%doesntexist')
91 assert isinstance(result.error_in_exec, UsageError)
91 assert isinstance(result.error_in_exec, UsageError)
92
92
93
93
94 def test_cell_magic_not_found():
94 def test_cell_magic_not_found():
95 # magic not found raises UsageError
95 # magic not found raises UsageError
96 with pytest.raises(UsageError):
96 with pytest.raises(UsageError):
97 _ip.run_cell_magic('doesntexist', 'line', 'cell')
97 _ip.run_cell_magic('doesntexist', 'line', 'cell')
98
98
99 # ensure result isn't success when a magic isn't found
99 # ensure result isn't success when a magic isn't found
100 result = _ip.run_cell('%%doesntexist')
100 result = _ip.run_cell('%%doesntexist')
101 assert isinstance(result.error_in_exec, UsageError)
101 assert isinstance(result.error_in_exec, UsageError)
102
102
103
103
104 def test_magic_error_status():
104 def test_magic_error_status():
105 def fail(shell):
105 def fail(shell):
106 1/0
106 1/0
107 _ip.register_magic_function(fail)
107 _ip.register_magic_function(fail)
108 result = _ip.run_cell('%fail')
108 result = _ip.run_cell('%fail')
109 assert isinstance(result.error_in_exec, ZeroDivisionError)
109 assert isinstance(result.error_in_exec, ZeroDivisionError)
110
110
111
111
112 def test_config():
112 def test_config():
113 """ test that config magic does not raise
113 """ test that config magic does not raise
114 can happen if Configurable init is moved too early into
114 can happen if Configurable init is moved too early into
115 Magics.__init__ as then a Config object will be registered as a
115 Magics.__init__ as then a Config object will be registered as a
116 magic.
116 magic.
117 """
117 """
118 ## should not raise.
118 ## should not raise.
119 _ip.magic('config')
119 _ip.run_line_magic("config", "")
120
120
121
121 def test_config_available_configs():
122 def test_config_available_configs():
122 """ test that config magic prints available configs in unique and
123 """ test that config magic prints available configs in unique and
123 sorted order. """
124 sorted order. """
124 with capture_output() as captured:
125 with capture_output() as captured:
125 _ip.magic('config')
126 _ip.run_line_magic("config", "")
126
127
127 stdout = captured.stdout
128 stdout = captured.stdout
128 config_classes = stdout.strip().split('\n')[1:]
129 config_classes = stdout.strip().split('\n')[1:]
129 assert config_classes == sorted(set(config_classes))
130 assert config_classes == sorted(set(config_classes))
130
131
131 def test_config_print_class():
132 def test_config_print_class():
132 """ test that config with a classname prints the class's options. """
133 """ test that config with a classname prints the class's options. """
133 with capture_output() as captured:
134 with capture_output() as captured:
134 _ip.magic('config TerminalInteractiveShell')
135 _ip.run_line_magic("config", "TerminalInteractiveShell")
135
136
136 stdout = captured.stdout
137 stdout = captured.stdout
137 assert re.match(
138 assert re.match(
138 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
139 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
139 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
140 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
140
141
141
142
142 def test_rehashx():
143 def test_rehashx():
143 # clear up everything
144 # clear up everything
144 _ip.alias_manager.clear_aliases()
145 _ip.alias_manager.clear_aliases()
145 del _ip.db['syscmdlist']
146 del _ip.db['syscmdlist']
146
147
147 _ip.magic('rehashx')
148 _ip.run_line_magic("rehashx", "")
148 # Practically ALL ipython development systems will have more than 10 aliases
149 # Practically ALL ipython development systems will have more than 10 aliases
149
150
150 assert len(_ip.alias_manager.aliases) > 10
151 assert len(_ip.alias_manager.aliases) > 10
151 for name, cmd in _ip.alias_manager.aliases:
152 for name, cmd in _ip.alias_manager.aliases:
152 # we must strip dots from alias names
153 # we must strip dots from alias names
153 assert "." not in name
154 assert "." not in name
154
155
155 # rehashx must fill up syscmdlist
156 # rehashx must fill up syscmdlist
156 scoms = _ip.db['syscmdlist']
157 scoms = _ip.db['syscmdlist']
157 assert len(scoms) > 10
158 assert len(scoms) > 10
158
159
159
160
160 def test_magic_parse_options():
161 def test_magic_parse_options():
161 """Test that we don't mangle paths when parsing magic options."""
162 """Test that we don't mangle paths when parsing magic options."""
162 ip = get_ipython()
163 ip = get_ipython()
163 path = 'c:\\x'
164 path = 'c:\\x'
164 m = DummyMagics(ip)
165 m = DummyMagics(ip)
165 opts = m.parse_options('-f %s' % path,'f:')[0]
166 opts = m.parse_options('-f %s' % path,'f:')[0]
166 # argv splitting is os-dependent
167 # argv splitting is os-dependent
167 if os.name == 'posix':
168 if os.name == 'posix':
168 expected = 'c:x'
169 expected = 'c:x'
169 else:
170 else:
170 expected = path
171 expected = path
171 assert opts["f"] == expected
172 assert opts["f"] == expected
172
173
173
174
174 def test_magic_parse_long_options():
175 def test_magic_parse_long_options():
175 """Magic.parse_options can handle --foo=bar long options"""
176 """Magic.parse_options can handle --foo=bar long options"""
176 ip = get_ipython()
177 ip = get_ipython()
177 m = DummyMagics(ip)
178 m = DummyMagics(ip)
178 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
179 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
179 assert "foo" in opts
180 assert "foo" in opts
180 assert "bar" in opts
181 assert "bar" in opts
181 assert opts["bar"] == "bubble"
182 assert opts["bar"] == "bubble"
182
183
183
184
184 def doctest_hist_f():
185 def doctest_hist_f():
185 """Test %hist -f with temporary filename.
186 """Test %hist -f with temporary filename.
186
187
187 In [9]: import tempfile
188 In [9]: import tempfile
188
189
189 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
190 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
190
191
191 In [11]: %hist -nl -f $tfile 3
192 In [11]: %hist -nl -f $tfile 3
192
193
193 In [13]: import os; os.unlink(tfile)
194 In [13]: import os; os.unlink(tfile)
194 """
195 """
195
196
196
197
197 def doctest_hist_op():
198 def doctest_hist_op():
198 """Test %hist -op
199 """Test %hist -op
199
200
200 In [1]: class b(float):
201 In [1]: class b(float):
201 ...: pass
202 ...: pass
202 ...:
203 ...:
203
204
204 In [2]: class s(object):
205 In [2]: class s(object):
205 ...: def __str__(self):
206 ...: def __str__(self):
206 ...: return 's'
207 ...: return 's'
207 ...:
208 ...:
208
209
209 In [3]:
210 In [3]:
210
211
211 In [4]: class r(b):
212 In [4]: class r(b):
212 ...: def __repr__(self):
213 ...: def __repr__(self):
213 ...: return 'r'
214 ...: return 'r'
214 ...:
215 ...:
215
216
216 In [5]: class sr(s,r): pass
217 In [5]: class sr(s,r): pass
217 ...:
218 ...:
218
219
219 In [6]:
220 In [6]:
220
221
221 In [7]: bb=b()
222 In [7]: bb=b()
222
223
223 In [8]: ss=s()
224 In [8]: ss=s()
224
225
225 In [9]: rr=r()
226 In [9]: rr=r()
226
227
227 In [10]: ssrr=sr()
228 In [10]: ssrr=sr()
228
229
229 In [11]: 4.5
230 In [11]: 4.5
230 Out[11]: 4.5
231 Out[11]: 4.5
231
232
232 In [12]: str(ss)
233 In [12]: str(ss)
233 Out[12]: 's'
234 Out[12]: 's'
234
235
235 In [13]:
236 In [13]:
236
237
237 In [14]: %hist -op
238 In [14]: %hist -op
238 >>> class b:
239 >>> class b:
239 ... pass
240 ... pass
240 ...
241 ...
241 >>> class s(b):
242 >>> class s(b):
242 ... def __str__(self):
243 ... def __str__(self):
243 ... return 's'
244 ... return 's'
244 ...
245 ...
245 >>>
246 >>>
246 >>> class r(b):
247 >>> class r(b):
247 ... def __repr__(self):
248 ... def __repr__(self):
248 ... return 'r'
249 ... return 'r'
249 ...
250 ...
250 >>> class sr(s,r): pass
251 >>> class sr(s,r): pass
251 >>>
252 >>>
252 >>> bb=b()
253 >>> bb=b()
253 >>> ss=s()
254 >>> ss=s()
254 >>> rr=r()
255 >>> rr=r()
255 >>> ssrr=sr()
256 >>> ssrr=sr()
256 >>> 4.5
257 >>> 4.5
257 4.5
258 4.5
258 >>> str(ss)
259 >>> str(ss)
259 's'
260 's'
260 >>>
261 >>>
261 """
262 """
262
263
263 def test_hist_pof():
264 def test_hist_pof():
264 ip = get_ipython()
265 ip = get_ipython()
265 ip.run_cell("1+2", store_history=True)
266 ip.run_cell("1+2", store_history=True)
266 #raise Exception(ip.history_manager.session_number)
267 #raise Exception(ip.history_manager.session_number)
267 #raise Exception(list(ip.history_manager._get_range_session()))
268 #raise Exception(list(ip.history_manager._get_range_session()))
268 with TemporaryDirectory() as td:
269 with TemporaryDirectory() as td:
269 tf = os.path.join(td, 'hist.py')
270 tf = os.path.join(td, 'hist.py')
270 ip.run_line_magic('history', '-pof %s' % tf)
271 ip.run_line_magic('history', '-pof %s' % tf)
271 assert os.path.isfile(tf)
272 assert os.path.isfile(tf)
272
273
273
274
274 def test_macro():
275 def test_macro():
275 ip = get_ipython()
276 ip = get_ipython()
276 ip.history_manager.reset() # Clear any existing history.
277 ip.history_manager.reset() # Clear any existing history.
277 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
278 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
278 for i, cmd in enumerate(cmds, start=1):
279 for i, cmd in enumerate(cmds, start=1):
279 ip.history_manager.store_inputs(i, cmd)
280 ip.history_manager.store_inputs(i, cmd)
280 ip.magic("macro test 1-3")
281 ip.run_line_magic("macro", "test 1-3")
281 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
282 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
282
283
283 # List macros
284 # List macros
284 assert "test" in ip.magic("macro")
285 assert "test" in ip.run_line_magic("macro", "")
285
286
286
287
287 def test_macro_run():
288 def test_macro_run():
288 """Test that we can run a multi-line macro successfully."""
289 """Test that we can run a multi-line macro successfully."""
289 ip = get_ipython()
290 ip = get_ipython()
290 ip.history_manager.reset()
291 ip.history_manager.reset()
291 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
292 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
292 for cmd in cmds:
293 for cmd in cmds:
293 ip.run_cell(cmd, store_history=True)
294 ip.run_cell(cmd, store_history=True)
294 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
295 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
295 with tt.AssertPrints("12"):
296 with tt.AssertPrints("12"):
296 ip.run_cell("test")
297 ip.run_cell("test")
297 with tt.AssertPrints("13"):
298 with tt.AssertPrints("13"):
298 ip.run_cell("test")
299 ip.run_cell("test")
299
300
300
301
301 def test_magic_magic():
302 def test_magic_magic():
302 """Test %magic"""
303 """Test %magic"""
303 ip = get_ipython()
304 ip = get_ipython()
304 with capture_output() as captured:
305 with capture_output() as captured:
305 ip.magic("magic")
306 ip.run_line_magic("magic", "")
306
307
307 stdout = captured.stdout
308 stdout = captured.stdout
308 assert "%magic" in stdout
309 assert "%magic" in stdout
309 assert "IPython" in stdout
310 assert "IPython" in stdout
310 assert "Available" in stdout
311 assert "Available" in stdout
311
312
312
313
313 @dec.skipif_not_numpy
314 @dec.skipif_not_numpy
314 def test_numpy_reset_array_undec():
315 def test_numpy_reset_array_undec():
315 "Test '%reset array' functionality"
316 "Test '%reset array' functionality"
316 _ip.ex("import numpy as np")
317 _ip.ex("import numpy as np")
317 _ip.ex("a = np.empty(2)")
318 _ip.ex("a = np.empty(2)")
318 assert "a" in _ip.user_ns
319 assert "a" in _ip.user_ns
319 _ip.magic("reset -f array")
320 _ip.run_line_magic("reset", "-f array")
320 assert "a" not in _ip.user_ns
321 assert "a" not in _ip.user_ns
321
322
322
323
323 def test_reset_out():
324 def test_reset_out():
324 "Test '%reset out' magic"
325 "Test '%reset out' magic"
325 _ip.run_cell("parrot = 'dead'", store_history=True)
326 _ip.run_cell("parrot = 'dead'", store_history=True)
326 # test '%reset -f out', make an Out prompt
327 # test '%reset -f out', make an Out prompt
327 _ip.run_cell("parrot", store_history=True)
328 _ip.run_cell("parrot", store_history=True)
328 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
329 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
329 _ip.magic("reset -f out")
330 _ip.run_line_magic("reset", "-f out")
330 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
331 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
331 assert len(_ip.user_ns["Out"]) == 0
332 assert len(_ip.user_ns["Out"]) == 0
332
333
333
334
334 def test_reset_in():
335 def test_reset_in():
335 "Test '%reset in' magic"
336 "Test '%reset in' magic"
336 # test '%reset -f in'
337 # test '%reset -f in'
337 _ip.run_cell("parrot", store_history=True)
338 _ip.run_cell("parrot", store_history=True)
338 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
339 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
339 _ip.magic("%reset -f in")
340 _ip.run_line_magic("reset", "-f in")
340 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
341 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
341 assert len(set(_ip.user_ns["In"])) == 1
342 assert len(set(_ip.user_ns["In"])) == 1
342
343
343
344
344 def test_reset_dhist():
345 def test_reset_dhist():
345 "Test '%reset dhist' magic"
346 "Test '%reset dhist' magic"
346 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
347 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
347 _ip.magic("cd " + os.path.dirname(pytest.__file__))
348 _ip.run_line_magic("cd", os.path.dirname(pytest.__file__))
348 _ip.magic("cd -")
349 _ip.run_line_magic("cd", "-")
349 assert len(_ip.user_ns["_dh"]) > 0
350 assert len(_ip.user_ns["_dh"]) > 0
350 _ip.magic("reset -f dhist")
351 _ip.run_line_magic("reset", "-f dhist")
351 assert len(_ip.user_ns["_dh"]) == 0
352 assert len(_ip.user_ns["_dh"]) == 0
352 _ip.run_cell("_dh = [d for d in tmp]") # restore
353 _ip.run_cell("_dh = [d for d in tmp]") # restore
353
354
354
355
355 def test_reset_in_length():
356 def test_reset_in_length():
356 "Test that '%reset in' preserves In[] length"
357 "Test that '%reset in' preserves In[] length"
357 _ip.run_cell("print 'foo'")
358 _ip.run_cell("print 'foo'")
358 _ip.run_cell("reset -f in")
359 _ip.run_cell("reset -f in")
359 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
360 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
360
361
361
362
362 class TestResetErrors(TestCase):
363 class TestResetErrors(TestCase):
363
364
364 def test_reset_redefine(self):
365 def test_reset_redefine(self):
365
366
366 @magics_class
367 @magics_class
367 class KernelMagics(Magics):
368 class KernelMagics(Magics):
368 @line_magic
369 @line_magic
369 def less(self, shell): pass
370 def less(self, shell): pass
370
371
371 _ip.register_magics(KernelMagics)
372 _ip.register_magics(KernelMagics)
372
373
373 with self.assertLogs() as cm:
374 with self.assertLogs() as cm:
374 # hack, we want to just capture logs, but assertLogs fails if not
375 # hack, we want to just capture logs, but assertLogs fails if not
375 # logs get produce.
376 # logs get produce.
376 # so log one things we ignore.
377 # so log one things we ignore.
377 import logging as log_mod
378 import logging as log_mod
378 log = log_mod.getLogger()
379 log = log_mod.getLogger()
379 log.info('Nothing')
380 log.info('Nothing')
380 # end hack.
381 # end hack.
381 _ip.run_cell("reset -f")
382 _ip.run_cell("reset -f")
382
383
383 assert len(cm.output) == 1
384 assert len(cm.output) == 1
384 for out in cm.output:
385 for out in cm.output:
385 assert "Invalid alias" not in out
386 assert "Invalid alias" not in out
386
387
387 def test_tb_syntaxerror():
388 def test_tb_syntaxerror():
388 """test %tb after a SyntaxError"""
389 """test %tb after a SyntaxError"""
389 ip = get_ipython()
390 ip = get_ipython()
390 ip.run_cell("for")
391 ip.run_cell("for")
391
392
392 # trap and validate stdout
393 # trap and validate stdout
393 save_stdout = sys.stdout
394 save_stdout = sys.stdout
394 try:
395 try:
395 sys.stdout = StringIO()
396 sys.stdout = StringIO()
396 ip.run_cell("%tb")
397 ip.run_cell("%tb")
397 out = sys.stdout.getvalue()
398 out = sys.stdout.getvalue()
398 finally:
399 finally:
399 sys.stdout = save_stdout
400 sys.stdout = save_stdout
400 # trim output, and only check the last line
401 # trim output, and only check the last line
401 last_line = out.rstrip().splitlines()[-1].strip()
402 last_line = out.rstrip().splitlines()[-1].strip()
402 assert last_line == "SyntaxError: invalid syntax"
403 assert last_line == "SyntaxError: invalid syntax"
403
404
404
405
405 def test_time():
406 def test_time():
406 ip = get_ipython()
407 ip = get_ipython()
407
408
408 with tt.AssertPrints("Wall time: "):
409 with tt.AssertPrints("Wall time: "):
409 ip.run_cell("%time None")
410 ip.run_cell("%time None")
410
411
411 ip.run_cell("def f(kmjy):\n"
412 ip.run_cell("def f(kmjy):\n"
412 " %time print (2*kmjy)")
413 " %time print (2*kmjy)")
413
414
414 with tt.AssertPrints("Wall time: "):
415 with tt.AssertPrints("Wall time: "):
415 with tt.AssertPrints("hihi", suppress=False):
416 with tt.AssertPrints("hihi", suppress=False):
416 ip.run_cell("f('hi')")
417 ip.run_cell("f('hi')")
417
418
418 def test_time_last_not_expression():
419 def test_time_last_not_expression():
419 ip.run_cell("%%time\n"
420 ip.run_cell("%%time\n"
420 "var_1 = 1\n"
421 "var_1 = 1\n"
421 "var_2 = 2\n")
422 "var_2 = 2\n")
422 assert ip.user_ns['var_1'] == 1
423 assert ip.user_ns['var_1'] == 1
423 del ip.user_ns['var_1']
424 del ip.user_ns['var_1']
424 assert ip.user_ns['var_2'] == 2
425 assert ip.user_ns['var_2'] == 2
425 del ip.user_ns['var_2']
426 del ip.user_ns['var_2']
426
427
427
428
428 @dec.skip_win32
429 @dec.skip_win32
429 def test_time2():
430 def test_time2():
430 ip = get_ipython()
431 ip = get_ipython()
431
432
432 with tt.AssertPrints("CPU times: user "):
433 with tt.AssertPrints("CPU times: user "):
433 ip.run_cell("%time None")
434 ip.run_cell("%time None")
434
435
435 def test_time3():
436 def test_time3():
436 """Erroneous magic function calls, issue gh-3334"""
437 """Erroneous magic function calls, issue gh-3334"""
437 ip = get_ipython()
438 ip = get_ipython()
438 ip.user_ns.pop('run', None)
439 ip.user_ns.pop('run', None)
439
440
440 with tt.AssertNotPrints("not found", channel='stderr'):
441 with tt.AssertNotPrints("not found", channel='stderr'):
441 ip.run_cell("%%time\n"
442 ip.run_cell("%%time\n"
442 "run = 0\n"
443 "run = 0\n"
443 "run += 1")
444 "run += 1")
444
445
445 def test_multiline_time():
446 def test_multiline_time():
446 """Make sure last statement from time return a value."""
447 """Make sure last statement from time return a value."""
447 ip = get_ipython()
448 ip = get_ipython()
448 ip.user_ns.pop('run', None)
449 ip.user_ns.pop('run', None)
449
450
450 ip.run_cell(
451 ip.run_cell(
451 dedent(
452 dedent(
452 """\
453 """\
453 %%time
454 %%time
454 a = "ho"
455 a = "ho"
455 b = "hey"
456 b = "hey"
456 a+b
457 a+b
457 """
458 """
458 )
459 )
459 )
460 )
460 assert ip.user_ns_hidden["_"] == "hohey"
461 assert ip.user_ns_hidden["_"] == "hohey"
461
462
462
463
463 def test_time_local_ns():
464 def test_time_local_ns():
464 """
465 """
465 Test that local_ns is actually global_ns when running a cell magic
466 Test that local_ns is actually global_ns when running a cell magic
466 """
467 """
467 ip = get_ipython()
468 ip = get_ipython()
468 ip.run_cell("%%time\n" "myvar = 1")
469 ip.run_cell("%%time\n" "myvar = 1")
469 assert ip.user_ns["myvar"] == 1
470 assert ip.user_ns["myvar"] == 1
470 del ip.user_ns["myvar"]
471 del ip.user_ns["myvar"]
471
472
472
473
473 def test_doctest_mode():
474 def test_doctest_mode():
474 "Toggle doctest_mode twice, it should be a no-op and run without error"
475 "Toggle doctest_mode twice, it should be a no-op and run without error"
475 _ip.magic('doctest_mode')
476 _ip.run_line_magic("doctest_mode", "")
476 _ip.magic('doctest_mode')
477 _ip.run_line_magic("doctest_mode", "")
477
478
478
479
479 def test_parse_options():
480 def test_parse_options():
480 """Tests for basic options parsing in magics."""
481 """Tests for basic options parsing in magics."""
481 # These are only the most minimal of tests, more should be added later. At
482 # These are only the most minimal of tests, more should be added later. At
482 # the very least we check that basic text/unicode calls work OK.
483 # the very least we check that basic text/unicode calls work OK.
483 m = DummyMagics(_ip)
484 m = DummyMagics(_ip)
484 assert m.parse_options("foo", "")[1] == "foo"
485 assert m.parse_options("foo", "")[1] == "foo"
485 assert m.parse_options("foo", "")[1] == "foo"
486 assert m.parse_options("foo", "")[1] == "foo"
486
487
487
488
488 def test_parse_options_preserve_non_option_string():
489 def test_parse_options_preserve_non_option_string():
489 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
490 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
490 m = DummyMagics(_ip)
491 m = DummyMagics(_ip)
491 opts, stmt = m.parse_options(
492 opts, stmt = m.parse_options(
492 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
493 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
493 )
494 )
494 assert opts == {"n": "1", "r": "13"}
495 assert opts == {"n": "1", "r": "13"}
495 assert stmt == "_ = 314 + foo"
496 assert stmt == "_ = 314 + foo"
496
497
497
498
498 def test_run_magic_preserve_code_block():
499 def test_run_magic_preserve_code_block():
499 """Test to assert preservation of non-option part of magic-block, while running magic."""
500 """Test to assert preservation of non-option part of magic-block, while running magic."""
500 _ip.user_ns["spaces"] = []
501 _ip.user_ns["spaces"] = []
501 _ip.magic("timeit -n1 -r1 spaces.append([s.count(' ') for s in ['document']])")
502 _ip.run_line_magic(
503 "timeit", "-n1 -r1 spaces.append([s.count(' ') for s in ['document']])"
504 )
502 assert _ip.user_ns["spaces"] == [[0]]
505 assert _ip.user_ns["spaces"] == [[0]]
503
506
504
507
505 def test_dirops():
508 def test_dirops():
506 """Test various directory handling operations."""
509 """Test various directory handling operations."""
507 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
510 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
508 curpath = os.getcwd
511 curpath = os.getcwd
509 startdir = os.getcwd()
512 startdir = os.getcwd()
510 ipdir = os.path.realpath(_ip.ipython_dir)
513 ipdir = os.path.realpath(_ip.ipython_dir)
511 try:
514 try:
512 _ip.magic('cd "%s"' % ipdir)
515 _ip.run_line_magic("cd", '"%s"' % ipdir)
513 assert curpath() == ipdir
516 assert curpath() == ipdir
514 _ip.magic('cd -')
517 _ip.run_line_magic("cd", "-")
515 assert curpath() == startdir
518 assert curpath() == startdir
516 _ip.magic('pushd "%s"' % ipdir)
519 _ip.run_line_magic("pushd", '"%s"' % ipdir)
517 assert curpath() == ipdir
520 assert curpath() == ipdir
518 _ip.magic('popd')
521 _ip.run_line_magic("popd", "")
519 assert curpath() == startdir
522 assert curpath() == startdir
520 finally:
523 finally:
521 os.chdir(startdir)
524 os.chdir(startdir)
522
525
523
526
524 def test_cd_force_quiet():
527 def test_cd_force_quiet():
525 """Test OSMagics.cd_force_quiet option"""
528 """Test OSMagics.cd_force_quiet option"""
526 _ip.config.OSMagics.cd_force_quiet = True
529 _ip.config.OSMagics.cd_force_quiet = True
527 osmagics = osm.OSMagics(shell=_ip)
530 osmagics = osm.OSMagics(shell=_ip)
528
531
529 startdir = os.getcwd()
532 startdir = os.getcwd()
530 ipdir = os.path.realpath(_ip.ipython_dir)
533 ipdir = os.path.realpath(_ip.ipython_dir)
531
534
532 try:
535 try:
533 with tt.AssertNotPrints(ipdir):
536 with tt.AssertNotPrints(ipdir):
534 osmagics.cd('"%s"' % ipdir)
537 osmagics.cd('"%s"' % ipdir)
535 with tt.AssertNotPrints(startdir):
538 with tt.AssertNotPrints(startdir):
536 osmagics.cd('-')
539 osmagics.cd('-')
537 finally:
540 finally:
538 os.chdir(startdir)
541 os.chdir(startdir)
539
542
540
543
541 def test_xmode():
544 def test_xmode():
542 # Calling xmode three times should be a no-op
545 # Calling xmode three times should be a no-op
543 xmode = _ip.InteractiveTB.mode
546 xmode = _ip.InteractiveTB.mode
544 for i in range(4):
547 for i in range(4):
545 _ip.magic("xmode")
548 _ip.run_line_magic("xmode", "")
546 assert _ip.InteractiveTB.mode == xmode
549 assert _ip.InteractiveTB.mode == xmode
547
550
548 def test_reset_hard():
551 def test_reset_hard():
549 monitor = []
552 monitor = []
550 class A(object):
553 class A(object):
551 def __del__(self):
554 def __del__(self):
552 monitor.append(1)
555 monitor.append(1)
553 def __repr__(self):
556 def __repr__(self):
554 return "<A instance>"
557 return "<A instance>"
555
558
556 _ip.user_ns["a"] = A()
559 _ip.user_ns["a"] = A()
557 _ip.run_cell("a")
560 _ip.run_cell("a")
558
561
559 assert monitor == []
562 assert monitor == []
560 _ip.magic("reset -f")
563 _ip.run_line_magic("reset", "-f")
561 assert monitor == [1]
564 assert monitor == [1]
562
565
563 class TestXdel(tt.TempFileMixin):
566 class TestXdel(tt.TempFileMixin):
564 def test_xdel(self):
567 def test_xdel(self):
565 """Test that references from %run are cleared by xdel."""
568 """Test that references from %run are cleared by xdel."""
566 src = ("class A(object):\n"
569 src = ("class A(object):\n"
567 " monitor = []\n"
570 " monitor = []\n"
568 " def __del__(self):\n"
571 " def __del__(self):\n"
569 " self.monitor.append(1)\n"
572 " self.monitor.append(1)\n"
570 "a = A()\n")
573 "a = A()\n")
571 self.mktmp(src)
574 self.mktmp(src)
572 # %run creates some hidden references...
575 # %run creates some hidden references...
573 _ip.magic("run %s" % self.fname)
576 _ip.run_line_magic("run", "%s" % self.fname)
574 # ... as does the displayhook.
577 # ... as does the displayhook.
575 _ip.run_cell("a")
578 _ip.run_cell("a")
576
579
577 monitor = _ip.user_ns["A"].monitor
580 monitor = _ip.user_ns["A"].monitor
578 assert monitor == []
581 assert monitor == []
579
582
580 _ip.magic("xdel a")
583 _ip.run_line_magic("xdel", "a")
581
584
582 # Check that a's __del__ method has been called.
585 # Check that a's __del__ method has been called.
583 gc.collect(0)
586 gc.collect(0)
584 assert monitor == [1]
587 assert monitor == [1]
585
588
586 def doctest_who():
589 def doctest_who():
587 """doctest for %who
590 """doctest for %who
588
591
589 In [1]: %reset -sf
592 In [1]: %reset -sf
590
593
591 In [2]: alpha = 123
594 In [2]: alpha = 123
592
595
593 In [3]: beta = 'beta'
596 In [3]: beta = 'beta'
594
597
595 In [4]: %who int
598 In [4]: %who int
596 alpha
599 alpha
597
600
598 In [5]: %who str
601 In [5]: %who str
599 beta
602 beta
600
603
601 In [6]: %whos
604 In [6]: %whos
602 Variable Type Data/Info
605 Variable Type Data/Info
603 ----------------------------
606 ----------------------------
604 alpha int 123
607 alpha int 123
605 beta str beta
608 beta str beta
606
609
607 In [7]: %who_ls
610 In [7]: %who_ls
608 Out[7]: ['alpha', 'beta']
611 Out[7]: ['alpha', 'beta']
609 """
612 """
610
613
611 def test_whos():
614 def test_whos():
612 """Check that whos is protected against objects where repr() fails."""
615 """Check that whos is protected against objects where repr() fails."""
613 class A(object):
616 class A(object):
614 def __repr__(self):
617 def __repr__(self):
615 raise Exception()
618 raise Exception()
616 _ip.user_ns['a'] = A()
619 _ip.user_ns['a'] = A()
617 _ip.magic("whos")
620 _ip.run_line_magic("whos", "")
618
621
619 def doctest_precision():
622 def doctest_precision():
620 """doctest for %precision
623 """doctest for %precision
621
624
622 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
625 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
623
626
624 In [2]: %precision 5
627 In [2]: %precision 5
625 Out[2]: '%.5f'
628 Out[2]: '%.5f'
626
629
627 In [3]: f.float_format
630 In [3]: f.float_format
628 Out[3]: '%.5f'
631 Out[3]: '%.5f'
629
632
630 In [4]: %precision %e
633 In [4]: %precision %e
631 Out[4]: '%e'
634 Out[4]: '%e'
632
635
633 In [5]: f(3.1415927)
636 In [5]: f(3.1415927)
634 Out[5]: '3.141593e+00'
637 Out[5]: '3.141593e+00'
635 """
638 """
636
639
637 def test_debug_magic():
640 def test_debug_magic():
638 """Test debugging a small code with %debug
641 """Test debugging a small code with %debug
639
642
640 In [1]: with PdbTestInput(['c']):
643 In [1]: with PdbTestInput(['c']):
641 ...: %debug print("a b") #doctest: +ELLIPSIS
644 ...: %debug print("a b") #doctest: +ELLIPSIS
642 ...:
645 ...:
643 ...
646 ...
644 ipdb> c
647 ipdb> c
645 a b
648 a b
646 In [2]:
649 In [2]:
647 """
650 """
648
651
649 def test_psearch():
652 def test_psearch():
650 with tt.AssertPrints("dict.fromkeys"):
653 with tt.AssertPrints("dict.fromkeys"):
651 _ip.run_cell("dict.fr*?")
654 _ip.run_cell("dict.fr*?")
652 with tt.AssertPrints("π.is_integer"):
655 with tt.AssertPrints("π.is_integer"):
653 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
656 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
654
657
655 def test_timeit_shlex():
658 def test_timeit_shlex():
656 """test shlex issues with timeit (#1109)"""
659 """test shlex issues with timeit (#1109)"""
657 _ip.ex("def f(*a,**kw): pass")
660 _ip.ex("def f(*a,**kw): pass")
658 _ip.magic('timeit -n1 "this is a bug".count(" ")')
661 _ip.run_line_magic("timeit", '-n1 "this is a bug".count(" ")')
659 _ip.magic('timeit -r1 -n1 f(" ", 1)')
662 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1)')
660 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
663 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1, " ", 2, " ")')
661 _ip.magic('timeit -r1 -n1 ("a " + "b")')
664 _ip.run_line_magic("timeit", '-r1 -n1 ("a " + "b")')
662 _ip.magic('timeit -r1 -n1 f("a " + "b")')
665 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b")')
663 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
666 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b ")')
664
667
665
668
666 def test_timeit_special_syntax():
669 def test_timeit_special_syntax():
667 "Test %%timeit with IPython special syntax"
670 "Test %%timeit with IPython special syntax"
668 @register_line_magic
671 @register_line_magic
669 def lmagic(line):
672 def lmagic(line):
670 ip = get_ipython()
673 ip = get_ipython()
671 ip.user_ns['lmagic_out'] = line
674 ip.user_ns['lmagic_out'] = line
672
675
673 # line mode test
676 # line mode test
674 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
677 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
675 assert _ip.user_ns["lmagic_out"] == "my line"
678 assert _ip.user_ns["lmagic_out"] == "my line"
676 # cell mode test
679 # cell mode test
677 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
680 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
678 assert _ip.user_ns["lmagic_out"] == "my line2"
681 assert _ip.user_ns["lmagic_out"] == "my line2"
679
682
680
683
681 def test_timeit_return():
684 def test_timeit_return():
682 """
685 """
683 test whether timeit -o return object
686 test whether timeit -o return object
684 """
687 """
685
688
686 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
689 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
687 assert(res is not None)
690 assert(res is not None)
688
691
689 def test_timeit_quiet():
692 def test_timeit_quiet():
690 """
693 """
691 test quiet option of timeit magic
694 test quiet option of timeit magic
692 """
695 """
693 with tt.AssertNotPrints("loops"):
696 with tt.AssertNotPrints("loops"):
694 _ip.run_cell("%timeit -n1 -r1 -q 1")
697 _ip.run_cell("%timeit -n1 -r1 -q 1")
695
698
696 def test_timeit_return_quiet():
699 def test_timeit_return_quiet():
697 with tt.AssertNotPrints("loops"):
700 with tt.AssertNotPrints("loops"):
698 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
701 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
699 assert (res is not None)
702 assert (res is not None)
700
703
701 def test_timeit_invalid_return():
704 def test_timeit_invalid_return():
702 with pytest.raises(SyntaxError):
705 with pytest.raises(SyntaxError):
703 _ip.run_line_magic('timeit', 'return')
706 _ip.run_line_magic('timeit', 'return')
704
707
705 @dec.skipif(execution.profile is None)
708 @dec.skipif(execution.profile is None)
706 def test_prun_special_syntax():
709 def test_prun_special_syntax():
707 "Test %%prun with IPython special syntax"
710 "Test %%prun with IPython special syntax"
708 @register_line_magic
711 @register_line_magic
709 def lmagic(line):
712 def lmagic(line):
710 ip = get_ipython()
713 ip = get_ipython()
711 ip.user_ns['lmagic_out'] = line
714 ip.user_ns['lmagic_out'] = line
712
715
713 # line mode test
716 # line mode test
714 _ip.run_line_magic("prun", "-q %lmagic my line")
717 _ip.run_line_magic("prun", "-q %lmagic my line")
715 assert _ip.user_ns["lmagic_out"] == "my line"
718 assert _ip.user_ns["lmagic_out"] == "my line"
716 # cell mode test
719 # cell mode test
717 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
720 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
718 assert _ip.user_ns["lmagic_out"] == "my line2"
721 assert _ip.user_ns["lmagic_out"] == "my line2"
719
722
720
723
721 @dec.skipif(execution.profile is None)
724 @dec.skipif(execution.profile is None)
722 def test_prun_quotes():
725 def test_prun_quotes():
723 "Test that prun does not clobber string escapes (GH #1302)"
726 "Test that prun does not clobber string escapes (GH #1302)"
724 _ip.magic(r"prun -q x = '\t'")
727 _ip.magic(r"prun -q x = '\t'")
725 assert _ip.user_ns["x"] == "\t"
728 assert _ip.user_ns["x"] == "\t"
726
729
727
730
728 def test_extension():
731 def test_extension():
729 # Debugging information for failures of this test
732 # Debugging information for failures of this test
730 print('sys.path:')
733 print('sys.path:')
731 for p in sys.path:
734 for p in sys.path:
732 print(' ', p)
735 print(' ', p)
733 print('CWD', os.getcwd())
736 print('CWD', os.getcwd())
734
737
735 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
738 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
736 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
739 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
737 sys.path.insert(0, daft_path)
740 sys.path.insert(0, daft_path)
738 try:
741 try:
739 _ip.user_ns.pop('arq', None)
742 _ip.user_ns.pop('arq', None)
740 invalidate_caches() # Clear import caches
743 invalidate_caches() # Clear import caches
741 _ip.magic("load_ext daft_extension")
744 _ip.run_line_magic("load_ext", "daft_extension")
742 assert _ip.user_ns["arq"] == 185
745 assert _ip.user_ns["arq"] == 185
743 _ip.magic("unload_ext daft_extension")
746 _ip.run_line_magic("unload_ext", "daft_extension")
744 assert 'arq' not in _ip.user_ns
747 assert 'arq' not in _ip.user_ns
745 finally:
748 finally:
746 sys.path.remove(daft_path)
749 sys.path.remove(daft_path)
747
750
748
751
749 def test_notebook_export_json():
752 def test_notebook_export_json():
750 pytest.importorskip("nbformat")
753 pytest.importorskip("nbformat")
751 _ip = get_ipython()
754 _ip = get_ipython()
752 _ip.history_manager.reset() # Clear any existing history.
755 _ip.history_manager.reset() # Clear any existing history.
753 cmds = ["a=1", "def b():\n return a**2", "print('noël, été', b())"]
756 cmds = ["a=1", "def b():\n return a**2", "print('noël, été', b())"]
754 for i, cmd in enumerate(cmds, start=1):
757 for i, cmd in enumerate(cmds, start=1):
755 _ip.history_manager.store_inputs(i, cmd)
758 _ip.history_manager.store_inputs(i, cmd)
756 with TemporaryDirectory() as td:
759 with TemporaryDirectory() as td:
757 outfile = os.path.join(td, "nb.ipynb")
760 outfile = os.path.join(td, "nb.ipynb")
758 _ip.magic("notebook %s" % outfile)
761 _ip.run_line_magic("notebook", "%s" % outfile)
759
762
760
763
761 class TestEnv(TestCase):
764 class TestEnv(TestCase):
762
765
763 def test_env(self):
766 def test_env(self):
764 env = _ip.magic("env")
767 env = _ip.run_line_magic("env", "")
765 self.assertTrue(isinstance(env, dict))
768 self.assertTrue(isinstance(env, dict))
766
769
767 def test_env_secret(self):
770 def test_env_secret(self):
768 env = _ip.magic("env")
771 env = _ip.run_line_magic("env", "")
769 hidden = "<hidden>"
772 hidden = "<hidden>"
770 with mock.patch.dict(
773 with mock.patch.dict(
771 os.environ,
774 os.environ,
772 {
775 {
773 "API_KEY": "abc123",
776 "API_KEY": "abc123",
774 "SECRET_THING": "ssshhh",
777 "SECRET_THING": "ssshhh",
775 "JUPYTER_TOKEN": "",
778 "JUPYTER_TOKEN": "",
776 "VAR": "abc"
779 "VAR": "abc"
777 }
780 }
778 ):
781 ):
779 env = _ip.magic("env")
782 env = _ip.run_line_magic("env", "")
780 assert env["API_KEY"] == hidden
783 assert env["API_KEY"] == hidden
781 assert env["SECRET_THING"] == hidden
784 assert env["SECRET_THING"] == hidden
782 assert env["JUPYTER_TOKEN"] == hidden
785 assert env["JUPYTER_TOKEN"] == hidden
783 assert env["VAR"] == "abc"
786 assert env["VAR"] == "abc"
784
787
785 def test_env_get_set_simple(self):
788 def test_env_get_set_simple(self):
786 env = _ip.magic("env var val1")
789 env = _ip.run_line_magic("env", "var val1")
787 self.assertEqual(env, None)
790 self.assertEqual(env, None)
788 self.assertEqual(os.environ['var'], 'val1')
791 self.assertEqual(os.environ["var"], "val1")
789 self.assertEqual(_ip.magic("env var"), 'val1')
792 self.assertEqual(_ip.run_line_magic("env", "var"), "val1")
790 env = _ip.magic("env var=val2")
793 env = _ip.run_line_magic("env", "var=val2")
791 self.assertEqual(env, None)
794 self.assertEqual(env, None)
792 self.assertEqual(os.environ['var'], 'val2')
795 self.assertEqual(os.environ['var'], 'val2')
793
796
794 def test_env_get_set_complex(self):
797 def test_env_get_set_complex(self):
795 env = _ip.magic("env var 'val1 '' 'val2")
798 env = _ip.run_line_magic("env", "var 'val1 '' 'val2")
796 self.assertEqual(env, None)
799 self.assertEqual(env, None)
797 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
800 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
798 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
801 self.assertEqual(_ip.run_line_magic("env", "var"), "'val1 '' 'val2")
799 env = _ip.magic('env var=val2 val3="val4')
802 env = _ip.run_line_magic("env", 'var=val2 val3="val4')
800 self.assertEqual(env, None)
803 self.assertEqual(env, None)
801 self.assertEqual(os.environ['var'], 'val2 val3="val4')
804 self.assertEqual(os.environ['var'], 'val2 val3="val4')
802
805
803 def test_env_set_bad_input(self):
806 def test_env_set_bad_input(self):
804 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
807 self.assertRaises(UsageError, lambda: _ip.run_line_magic("set_env", "var"))
805
808
806 def test_env_set_whitespace(self):
809 def test_env_set_whitespace(self):
807 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
810 self.assertRaises(UsageError, lambda: _ip.run_line_magic("env", "var A=B"))
808
811
809
812
810 class CellMagicTestCase(TestCase):
813 class CellMagicTestCase(TestCase):
811
814
812 def check_ident(self, magic):
815 def check_ident(self, magic):
813 # Manually called, we get the result
816 # Manually called, we get the result
814 out = _ip.run_cell_magic(magic, "a", "b")
817 out = _ip.run_cell_magic(magic, "a", "b")
815 assert out == ("a", "b")
818 assert out == ("a", "b")
816 # Via run_cell, it goes into the user's namespace via displayhook
819 # Via run_cell, it goes into the user's namespace via displayhook
817 _ip.run_cell("%%" + magic + " c\nd\n")
820 _ip.run_cell("%%" + magic + " c\nd\n")
818 assert _ip.user_ns["_"] == ("c", "d\n")
821 assert _ip.user_ns["_"] == ("c", "d\n")
819
822
820 def test_cell_magic_func_deco(self):
823 def test_cell_magic_func_deco(self):
821 "Cell magic using simple decorator"
824 "Cell magic using simple decorator"
822 @register_cell_magic
825 @register_cell_magic
823 def cellm(line, cell):
826 def cellm(line, cell):
824 return line, cell
827 return line, cell
825
828
826 self.check_ident('cellm')
829 self.check_ident('cellm')
827
830
828 def test_cell_magic_reg(self):
831 def test_cell_magic_reg(self):
829 "Cell magic manually registered"
832 "Cell magic manually registered"
830 def cellm(line, cell):
833 def cellm(line, cell):
831 return line, cell
834 return line, cell
832
835
833 _ip.register_magic_function(cellm, 'cell', 'cellm2')
836 _ip.register_magic_function(cellm, 'cell', 'cellm2')
834 self.check_ident('cellm2')
837 self.check_ident('cellm2')
835
838
836 def test_cell_magic_class(self):
839 def test_cell_magic_class(self):
837 "Cell magics declared via a class"
840 "Cell magics declared via a class"
838 @magics_class
841 @magics_class
839 class MyMagics(Magics):
842 class MyMagics(Magics):
840
843
841 @cell_magic
844 @cell_magic
842 def cellm3(self, line, cell):
845 def cellm3(self, line, cell):
843 return line, cell
846 return line, cell
844
847
845 _ip.register_magics(MyMagics)
848 _ip.register_magics(MyMagics)
846 self.check_ident('cellm3')
849 self.check_ident('cellm3')
847
850
848 def test_cell_magic_class2(self):
851 def test_cell_magic_class2(self):
849 "Cell magics declared via a class, #2"
852 "Cell magics declared via a class, #2"
850 @magics_class
853 @magics_class
851 class MyMagics2(Magics):
854 class MyMagics2(Magics):
852
855
853 @cell_magic('cellm4')
856 @cell_magic('cellm4')
854 def cellm33(self, line, cell):
857 def cellm33(self, line, cell):
855 return line, cell
858 return line, cell
856
859
857 _ip.register_magics(MyMagics2)
860 _ip.register_magics(MyMagics2)
858 self.check_ident('cellm4')
861 self.check_ident('cellm4')
859 # Check that nothing is registered as 'cellm33'
862 # Check that nothing is registered as 'cellm33'
860 c33 = _ip.find_cell_magic('cellm33')
863 c33 = _ip.find_cell_magic('cellm33')
861 assert c33 == None
864 assert c33 == None
862
865
863 def test_file():
866 def test_file():
864 """Basic %%writefile"""
867 """Basic %%writefile"""
865 ip = get_ipython()
868 ip = get_ipython()
866 with TemporaryDirectory() as td:
869 with TemporaryDirectory() as td:
867 fname = os.path.join(td, "file1")
870 fname = os.path.join(td, "file1")
868 ip.run_cell_magic(
871 ip.run_cell_magic(
869 "writefile",
872 "writefile",
870 fname,
873 fname,
871 "\n".join(
874 "\n".join(
872 [
875 [
873 "line1",
876 "line1",
874 "line2",
877 "line2",
875 ]
878 ]
876 ),
879 ),
877 )
880 )
878 s = Path(fname).read_text(encoding="utf-8")
881 s = Path(fname).read_text(encoding="utf-8")
879 assert "line1\n" in s
882 assert "line1\n" in s
880 assert "line2" in s
883 assert "line2" in s
881
884
882
885
883 @dec.skip_win32
886 @dec.skip_win32
884 def test_file_single_quote():
887 def test_file_single_quote():
885 """Basic %%writefile with embedded single quotes"""
888 """Basic %%writefile with embedded single quotes"""
886 ip = get_ipython()
889 ip = get_ipython()
887 with TemporaryDirectory() as td:
890 with TemporaryDirectory() as td:
888 fname = os.path.join(td, "'file1'")
891 fname = os.path.join(td, "'file1'")
889 ip.run_cell_magic(
892 ip.run_cell_magic(
890 "writefile",
893 "writefile",
891 fname,
894 fname,
892 "\n".join(
895 "\n".join(
893 [
896 [
894 "line1",
897 "line1",
895 "line2",
898 "line2",
896 ]
899 ]
897 ),
900 ),
898 )
901 )
899 s = Path(fname).read_text(encoding="utf-8")
902 s = Path(fname).read_text(encoding="utf-8")
900 assert "line1\n" in s
903 assert "line1\n" in s
901 assert "line2" in s
904 assert "line2" in s
902
905
903
906
904 @dec.skip_win32
907 @dec.skip_win32
905 def test_file_double_quote():
908 def test_file_double_quote():
906 """Basic %%writefile with embedded double quotes"""
909 """Basic %%writefile with embedded double quotes"""
907 ip = get_ipython()
910 ip = get_ipython()
908 with TemporaryDirectory() as td:
911 with TemporaryDirectory() as td:
909 fname = os.path.join(td, '"file1"')
912 fname = os.path.join(td, '"file1"')
910 ip.run_cell_magic(
913 ip.run_cell_magic(
911 "writefile",
914 "writefile",
912 fname,
915 fname,
913 "\n".join(
916 "\n".join(
914 [
917 [
915 "line1",
918 "line1",
916 "line2",
919 "line2",
917 ]
920 ]
918 ),
921 ),
919 )
922 )
920 s = Path(fname).read_text(encoding="utf-8")
923 s = Path(fname).read_text(encoding="utf-8")
921 assert "line1\n" in s
924 assert "line1\n" in s
922 assert "line2" in s
925 assert "line2" in s
923
926
924
927
925 def test_file_var_expand():
928 def test_file_var_expand():
926 """%%writefile $filename"""
929 """%%writefile $filename"""
927 ip = get_ipython()
930 ip = get_ipython()
928 with TemporaryDirectory() as td:
931 with TemporaryDirectory() as td:
929 fname = os.path.join(td, "file1")
932 fname = os.path.join(td, "file1")
930 ip.user_ns["filename"] = fname
933 ip.user_ns["filename"] = fname
931 ip.run_cell_magic(
934 ip.run_cell_magic(
932 "writefile",
935 "writefile",
933 "$filename",
936 "$filename",
934 "\n".join(
937 "\n".join(
935 [
938 [
936 "line1",
939 "line1",
937 "line2",
940 "line2",
938 ]
941 ]
939 ),
942 ),
940 )
943 )
941 s = Path(fname).read_text(encoding="utf-8")
944 s = Path(fname).read_text(encoding="utf-8")
942 assert "line1\n" in s
945 assert "line1\n" in s
943 assert "line2" in s
946 assert "line2" in s
944
947
945
948
946 def test_file_unicode():
949 def test_file_unicode():
947 """%%writefile with unicode cell"""
950 """%%writefile with unicode cell"""
948 ip = get_ipython()
951 ip = get_ipython()
949 with TemporaryDirectory() as td:
952 with TemporaryDirectory() as td:
950 fname = os.path.join(td, 'file1')
953 fname = os.path.join(td, 'file1')
951 ip.run_cell_magic("writefile", fname, u'\n'.join([
954 ip.run_cell_magic("writefile", fname, u'\n'.join([
952 u'liné1',
955 u'liné1',
953 u'liné2',
956 u'liné2',
954 ]))
957 ]))
955 with io.open(fname, encoding='utf-8') as f:
958 with io.open(fname, encoding='utf-8') as f:
956 s = f.read()
959 s = f.read()
957 assert "liné1\n" in s
960 assert "liné1\n" in s
958 assert "liné2" in s
961 assert "liné2" in s
959
962
960
963
961 def test_file_amend():
964 def test_file_amend():
962 """%%writefile -a amends files"""
965 """%%writefile -a amends files"""
963 ip = get_ipython()
966 ip = get_ipython()
964 with TemporaryDirectory() as td:
967 with TemporaryDirectory() as td:
965 fname = os.path.join(td, "file2")
968 fname = os.path.join(td, "file2")
966 ip.run_cell_magic(
969 ip.run_cell_magic(
967 "writefile",
970 "writefile",
968 fname,
971 fname,
969 "\n".join(
972 "\n".join(
970 [
973 [
971 "line1",
974 "line1",
972 "line2",
975 "line2",
973 ]
976 ]
974 ),
977 ),
975 )
978 )
976 ip.run_cell_magic(
979 ip.run_cell_magic(
977 "writefile",
980 "writefile",
978 "-a %s" % fname,
981 "-a %s" % fname,
979 "\n".join(
982 "\n".join(
980 [
983 [
981 "line3",
984 "line3",
982 "line4",
985 "line4",
983 ]
986 ]
984 ),
987 ),
985 )
988 )
986 s = Path(fname).read_text(encoding="utf-8")
989 s = Path(fname).read_text(encoding="utf-8")
987 assert "line1\n" in s
990 assert "line1\n" in s
988 assert "line3\n" in s
991 assert "line3\n" in s
989
992
990
993
991 def test_file_spaces():
994 def test_file_spaces():
992 """%%file with spaces in filename"""
995 """%%file with spaces in filename"""
993 ip = get_ipython()
996 ip = get_ipython()
994 with TemporaryWorkingDirectory() as td:
997 with TemporaryWorkingDirectory() as td:
995 fname = "file name"
998 fname = "file name"
996 ip.run_cell_magic(
999 ip.run_cell_magic(
997 "file",
1000 "file",
998 '"%s"' % fname,
1001 '"%s"' % fname,
999 "\n".join(
1002 "\n".join(
1000 [
1003 [
1001 "line1",
1004 "line1",
1002 "line2",
1005 "line2",
1003 ]
1006 ]
1004 ),
1007 ),
1005 )
1008 )
1006 s = Path(fname).read_text(encoding="utf-8")
1009 s = Path(fname).read_text(encoding="utf-8")
1007 assert "line1\n" in s
1010 assert "line1\n" in s
1008 assert "line2" in s
1011 assert "line2" in s
1009
1012
1010
1013
1011 def test_script_config():
1014 def test_script_config():
1012 ip = get_ipython()
1015 ip = get_ipython()
1013 ip.config.ScriptMagics.script_magics = ['whoda']
1016 ip.config.ScriptMagics.script_magics = ['whoda']
1014 sm = script.ScriptMagics(shell=ip)
1017 sm = script.ScriptMagics(shell=ip)
1015 assert "whoda" in sm.magics["cell"]
1018 assert "whoda" in sm.magics["cell"]
1016
1019
1017
1020
1018 def test_script_out():
1021 def test_script_out():
1019 ip = get_ipython()
1022 ip = get_ipython()
1020 ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
1023 ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
1021 assert ip.user_ns["output"].strip() == "hi"
1024 assert ip.user_ns["output"].strip() == "hi"
1022
1025
1023
1026
1024 def test_script_err():
1027 def test_script_err():
1025 ip = get_ipython()
1028 ip = get_ipython()
1026 ip.run_cell_magic(
1029 ip.run_cell_magic(
1027 "script",
1030 "script",
1028 f"--err error {sys.executable}",
1031 f"--err error {sys.executable}",
1029 "import sys; print('hello', file=sys.stderr)",
1032 "import sys; print('hello', file=sys.stderr)",
1030 )
1033 )
1031 assert ip.user_ns["error"].strip() == "hello"
1034 assert ip.user_ns["error"].strip() == "hello"
1032
1035
1033
1036
1034 def test_script_out_err():
1037 def test_script_out_err():
1035
1038
1036 ip = get_ipython()
1039 ip = get_ipython()
1037 ip.run_cell_magic(
1040 ip.run_cell_magic(
1038 "script",
1041 "script",
1039 f"--out output --err error {sys.executable}",
1042 f"--out output --err error {sys.executable}",
1040 "\n".join(
1043 "\n".join(
1041 [
1044 [
1042 "import sys",
1045 "import sys",
1043 "print('hi')",
1046 "print('hi')",
1044 "print('hello', file=sys.stderr)",
1047 "print('hello', file=sys.stderr)",
1045 ]
1048 ]
1046 ),
1049 ),
1047 )
1050 )
1048 assert ip.user_ns["output"].strip() == "hi"
1051 assert ip.user_ns["output"].strip() == "hi"
1049 assert ip.user_ns["error"].strip() == "hello"
1052 assert ip.user_ns["error"].strip() == "hello"
1050
1053
1051
1054
1052 async def test_script_bg_out():
1055 async def test_script_bg_out():
1053 ip = get_ipython()
1056 ip = get_ipython()
1054 ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1057 ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1055 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1058 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1056 assert ip.user_ns["output"].at_eof()
1059 assert ip.user_ns["output"].at_eof()
1057
1060
1058
1061
1059 async def test_script_bg_err():
1062 async def test_script_bg_err():
1060 ip = get_ipython()
1063 ip = get_ipython()
1061 ip.run_cell_magic(
1064 ip.run_cell_magic(
1062 "script",
1065 "script",
1063 f"--bg --err error {sys.executable}",
1066 f"--bg --err error {sys.executable}",
1064 "import sys; print('hello', file=sys.stderr)",
1067 "import sys; print('hello', file=sys.stderr)",
1065 )
1068 )
1066 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1069 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1067 assert ip.user_ns["error"].at_eof()
1070 assert ip.user_ns["error"].at_eof()
1068
1071
1069
1072
1070 async def test_script_bg_out_err():
1073 async def test_script_bg_out_err():
1071 ip = get_ipython()
1074 ip = get_ipython()
1072 ip.run_cell_magic(
1075 ip.run_cell_magic(
1073 "script",
1076 "script",
1074 f"--bg --out output --err error {sys.executable}",
1077 f"--bg --out output --err error {sys.executable}",
1075 "\n".join(
1078 "\n".join(
1076 [
1079 [
1077 "import sys",
1080 "import sys",
1078 "print('hi')",
1081 "print('hi')",
1079 "print('hello', file=sys.stderr)",
1082 "print('hello', file=sys.stderr)",
1080 ]
1083 ]
1081 ),
1084 ),
1082 )
1085 )
1083 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1086 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1084 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1087 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1085 assert ip.user_ns["output"].at_eof()
1088 assert ip.user_ns["output"].at_eof()
1086 assert ip.user_ns["error"].at_eof()
1089 assert ip.user_ns["error"].at_eof()
1087
1090
1088
1091
1089 async def test_script_bg_proc():
1092 async def test_script_bg_proc():
1090 ip = get_ipython()
1093 ip = get_ipython()
1091 ip.run_cell_magic(
1094 ip.run_cell_magic(
1092 "script",
1095 "script",
1093 f"--bg --out output --proc p {sys.executable}",
1096 f"--bg --out output --proc p {sys.executable}",
1094 "\n".join(
1097 "\n".join(
1095 [
1098 [
1096 "import sys",
1099 "import sys",
1097 "print('hi')",
1100 "print('hi')",
1098 "print('hello', file=sys.stderr)",
1101 "print('hello', file=sys.stderr)",
1099 ]
1102 ]
1100 ),
1103 ),
1101 )
1104 )
1102 p = ip.user_ns["p"]
1105 p = ip.user_ns["p"]
1103 await p.wait()
1106 await p.wait()
1104 assert p.returncode == 0
1107 assert p.returncode == 0
1105 assert (await p.stdout.read()).strip() == b"hi"
1108 assert (await p.stdout.read()).strip() == b"hi"
1106 # not captured, so empty
1109 # not captured, so empty
1107 assert (await p.stderr.read()) == b""
1110 assert (await p.stderr.read()) == b""
1108 assert p.stdout.at_eof()
1111 assert p.stdout.at_eof()
1109 assert p.stderr.at_eof()
1112 assert p.stderr.at_eof()
1110
1113
1111
1114
1112 def test_script_defaults():
1115 def test_script_defaults():
1113 ip = get_ipython()
1116 ip = get_ipython()
1114 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1117 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1115 try:
1118 try:
1116 find_cmd(cmd)
1119 find_cmd(cmd)
1117 except Exception:
1120 except Exception:
1118 pass
1121 pass
1119 else:
1122 else:
1120 assert cmd in ip.magics_manager.magics["cell"]
1123 assert cmd in ip.magics_manager.magics["cell"]
1121
1124
1122
1125
1123 @magics_class
1126 @magics_class
1124 class FooFoo(Magics):
1127 class FooFoo(Magics):
1125 """class with both %foo and %%foo magics"""
1128 """class with both %foo and %%foo magics"""
1126 @line_magic('foo')
1129 @line_magic('foo')
1127 def line_foo(self, line):
1130 def line_foo(self, line):
1128 "I am line foo"
1131 "I am line foo"
1129 pass
1132 pass
1130
1133
1131 @cell_magic("foo")
1134 @cell_magic("foo")
1132 def cell_foo(self, line, cell):
1135 def cell_foo(self, line, cell):
1133 "I am cell foo, not line foo"
1136 "I am cell foo, not line foo"
1134 pass
1137 pass
1135
1138
1136 def test_line_cell_info():
1139 def test_line_cell_info():
1137 """%%foo and %foo magics are distinguishable to inspect"""
1140 """%%foo and %foo magics are distinguishable to inspect"""
1138 ip = get_ipython()
1141 ip = get_ipython()
1139 ip.magics_manager.register(FooFoo)
1142 ip.magics_manager.register(FooFoo)
1140 oinfo = ip.object_inspect("foo")
1143 oinfo = ip.object_inspect("foo")
1141 assert oinfo["found"] is True
1144 assert oinfo["found"] is True
1142 assert oinfo["ismagic"] is True
1145 assert oinfo["ismagic"] is True
1143
1146
1144 oinfo = ip.object_inspect("%%foo")
1147 oinfo = ip.object_inspect("%%foo")
1145 assert oinfo["found"] is True
1148 assert oinfo["found"] is True
1146 assert oinfo["ismagic"] is True
1149 assert oinfo["ismagic"] is True
1147 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1150 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1148
1151
1149 oinfo = ip.object_inspect("%foo")
1152 oinfo = ip.object_inspect("%foo")
1150 assert oinfo["found"] is True
1153 assert oinfo["found"] is True
1151 assert oinfo["ismagic"] is True
1154 assert oinfo["ismagic"] is True
1152 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1155 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1153
1156
1154
1157
1155 def test_multiple_magics():
1158 def test_multiple_magics():
1156 ip = get_ipython()
1159 ip = get_ipython()
1157 foo1 = FooFoo(ip)
1160 foo1 = FooFoo(ip)
1158 foo2 = FooFoo(ip)
1161 foo2 = FooFoo(ip)
1159 mm = ip.magics_manager
1162 mm = ip.magics_manager
1160 mm.register(foo1)
1163 mm.register(foo1)
1161 assert mm.magics["line"]["foo"].__self__ is foo1
1164 assert mm.magics["line"]["foo"].__self__ is foo1
1162 mm.register(foo2)
1165 mm.register(foo2)
1163 assert mm.magics["line"]["foo"].__self__ is foo2
1166 assert mm.magics["line"]["foo"].__self__ is foo2
1164
1167
1165
1168
1166 def test_alias_magic():
1169 def test_alias_magic():
1167 """Test %alias_magic."""
1170 """Test %alias_magic."""
1168 ip = get_ipython()
1171 ip = get_ipython()
1169 mm = ip.magics_manager
1172 mm = ip.magics_manager
1170
1173
1171 # Basic operation: both cell and line magics are created, if possible.
1174 # Basic operation: both cell and line magics are created, if possible.
1172 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1175 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1173 assert "timeit_alias" in mm.magics["line"]
1176 assert "timeit_alias" in mm.magics["line"]
1174 assert "timeit_alias" in mm.magics["cell"]
1177 assert "timeit_alias" in mm.magics["cell"]
1175
1178
1176 # --cell is specified, line magic not created.
1179 # --cell is specified, line magic not created.
1177 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1180 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1178 assert "timeit_cell_alias" not in mm.magics["line"]
1181 assert "timeit_cell_alias" not in mm.magics["line"]
1179 assert "timeit_cell_alias" in mm.magics["cell"]
1182 assert "timeit_cell_alias" in mm.magics["cell"]
1180
1183
1181 # Test that line alias is created successfully.
1184 # Test that line alias is created successfully.
1182 ip.run_line_magic("alias_magic", "--line env_alias env")
1185 ip.run_line_magic("alias_magic", "--line env_alias env")
1183 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1186 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1184
1187
1185 # Test that line alias with parameters passed in is created successfully.
1188 # Test that line alias with parameters passed in is created successfully.
1186 ip.run_line_magic(
1189 ip.run_line_magic(
1187 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1190 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1188 )
1191 )
1189 assert "history_alias" in mm.magics["line"]
1192 assert "history_alias" in mm.magics["line"]
1190
1193
1191
1194
1192 def test_save():
1195 def test_save():
1193 """Test %save."""
1196 """Test %save."""
1194 ip = get_ipython()
1197 ip = get_ipython()
1195 ip.history_manager.reset() # Clear any existing history.
1198 ip.history_manager.reset() # Clear any existing history.
1196 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1199 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1197 for i, cmd in enumerate(cmds, start=1):
1200 for i, cmd in enumerate(cmds, start=1):
1198 ip.history_manager.store_inputs(i, cmd)
1201 ip.history_manager.store_inputs(i, cmd)
1199 with TemporaryDirectory() as tmpdir:
1202 with TemporaryDirectory() as tmpdir:
1200 file = os.path.join(tmpdir, "testsave.py")
1203 file = os.path.join(tmpdir, "testsave.py")
1201 ip.run_line_magic("save", "%s 1-10" % file)
1204 ip.run_line_magic("save", "%s 1-10" % file)
1202 content = Path(file).read_text(encoding="utf-8")
1205 content = Path(file).read_text(encoding="utf-8")
1203 assert content.count(cmds[0]) == 1
1206 assert content.count(cmds[0]) == 1
1204 assert "coding: utf-8" in content
1207 assert "coding: utf-8" in content
1205 ip.run_line_magic("save", "-a %s 1-10" % file)
1208 ip.run_line_magic("save", "-a %s 1-10" % file)
1206 content = Path(file).read_text(encoding="utf-8")
1209 content = Path(file).read_text(encoding="utf-8")
1207 assert content.count(cmds[0]) == 2
1210 assert content.count(cmds[0]) == 2
1208 assert "coding: utf-8" in content
1211 assert "coding: utf-8" in content
1209
1212
1210
1213
1211 def test_save_with_no_args():
1214 def test_save_with_no_args():
1212 ip = get_ipython()
1215 ip = get_ipython()
1213 ip.history_manager.reset() # Clear any existing history.
1216 ip.history_manager.reset() # Clear any existing history.
1214 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1217 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1215 for i, cmd in enumerate(cmds, start=1):
1218 for i, cmd in enumerate(cmds, start=1):
1216 ip.history_manager.store_inputs(i, cmd)
1219 ip.history_manager.store_inputs(i, cmd)
1217
1220
1218 with TemporaryDirectory() as tmpdir:
1221 with TemporaryDirectory() as tmpdir:
1219 path = os.path.join(tmpdir, "testsave.py")
1222 path = os.path.join(tmpdir, "testsave.py")
1220 ip.run_line_magic("save", path)
1223 ip.run_line_magic("save", path)
1221 content = Path(path).read_text(encoding="utf-8")
1224 content = Path(path).read_text(encoding="utf-8")
1222 expected_content = dedent(
1225 expected_content = dedent(
1223 """\
1226 """\
1224 # coding: utf-8
1227 # coding: utf-8
1225 a=1
1228 a=1
1226 def b():
1229 def b():
1227 return a**2
1230 return a**2
1228 print(a, b())
1231 print(a, b())
1229 """
1232 """
1230 )
1233 )
1231 assert content == expected_content
1234 assert content == expected_content
1232
1235
1233
1236
1234 def test_store():
1237 def test_store():
1235 """Test %store."""
1238 """Test %store."""
1236 ip = get_ipython()
1239 ip = get_ipython()
1237 ip.run_line_magic('load_ext', 'storemagic')
1240 ip.run_line_magic('load_ext', 'storemagic')
1238
1241
1239 # make sure the storage is empty
1242 # make sure the storage is empty
1240 ip.run_line_magic("store", "-z")
1243 ip.run_line_magic("store", "-z")
1241 ip.user_ns["var"] = 42
1244 ip.user_ns["var"] = 42
1242 ip.run_line_magic("store", "var")
1245 ip.run_line_magic("store", "var")
1243 ip.user_ns["var"] = 39
1246 ip.user_ns["var"] = 39
1244 ip.run_line_magic("store", "-r")
1247 ip.run_line_magic("store", "-r")
1245 assert ip.user_ns["var"] == 42
1248 assert ip.user_ns["var"] == 42
1246
1249
1247 ip.run_line_magic("store", "-d var")
1250 ip.run_line_magic("store", "-d var")
1248 ip.user_ns["var"] = 39
1251 ip.user_ns["var"] = 39
1249 ip.run_line_magic("store", "-r")
1252 ip.run_line_magic("store", "-r")
1250 assert ip.user_ns["var"] == 39
1253 assert ip.user_ns["var"] == 39
1251
1254
1252
1255
1253 def _run_edit_test(arg_s, exp_filename=None,
1256 def _run_edit_test(arg_s, exp_filename=None,
1254 exp_lineno=-1,
1257 exp_lineno=-1,
1255 exp_contents=None,
1258 exp_contents=None,
1256 exp_is_temp=None):
1259 exp_is_temp=None):
1257 ip = get_ipython()
1260 ip = get_ipython()
1258 M = code.CodeMagics(ip)
1261 M = code.CodeMagics(ip)
1259 last_call = ['','']
1262 last_call = ['','']
1260 opts,args = M.parse_options(arg_s,'prxn:')
1263 opts,args = M.parse_options(arg_s,'prxn:')
1261 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1264 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1262
1265
1263 if exp_filename is not None:
1266 if exp_filename is not None:
1264 assert exp_filename == filename
1267 assert exp_filename == filename
1265 if exp_contents is not None:
1268 if exp_contents is not None:
1266 with io.open(filename, 'r', encoding='utf-8') as f:
1269 with io.open(filename, 'r', encoding='utf-8') as f:
1267 contents = f.read()
1270 contents = f.read()
1268 assert exp_contents == contents
1271 assert exp_contents == contents
1269 if exp_lineno != -1:
1272 if exp_lineno != -1:
1270 assert exp_lineno == lineno
1273 assert exp_lineno == lineno
1271 if exp_is_temp is not None:
1274 if exp_is_temp is not None:
1272 assert exp_is_temp == is_temp
1275 assert exp_is_temp == is_temp
1273
1276
1274
1277
1275 def test_edit_interactive():
1278 def test_edit_interactive():
1276 """%edit on interactively defined objects"""
1279 """%edit on interactively defined objects"""
1277 ip = get_ipython()
1280 ip = get_ipython()
1278 n = ip.execution_count
1281 n = ip.execution_count
1279 ip.run_cell("def foo(): return 1", store_history=True)
1282 ip.run_cell("def foo(): return 1", store_history=True)
1280
1283
1281 with pytest.raises(code.InteractivelyDefined) as e:
1284 with pytest.raises(code.InteractivelyDefined) as e:
1282 _run_edit_test("foo")
1285 _run_edit_test("foo")
1283 assert e.value.index == n
1286 assert e.value.index == n
1284
1287
1285
1288
1286 def test_edit_cell():
1289 def test_edit_cell():
1287 """%edit [cell id]"""
1290 """%edit [cell id]"""
1288 ip = get_ipython()
1291 ip = get_ipython()
1289
1292
1290 ip.run_cell("def foo(): return 1", store_history=True)
1293 ip.run_cell("def foo(): return 1", store_history=True)
1291
1294
1292 # test
1295 # test
1293 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1296 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1294
1297
1295 def test_edit_fname():
1298 def test_edit_fname():
1296 """%edit file"""
1299 """%edit file"""
1297 # test
1300 # test
1298 _run_edit_test("test file.py", exp_filename="test file.py")
1301 _run_edit_test("test file.py", exp_filename="test file.py")
1299
1302
1300 def test_bookmark():
1303 def test_bookmark():
1301 ip = get_ipython()
1304 ip = get_ipython()
1302 ip.run_line_magic('bookmark', 'bmname')
1305 ip.run_line_magic('bookmark', 'bmname')
1303 with tt.AssertPrints('bmname'):
1306 with tt.AssertPrints('bmname'):
1304 ip.run_line_magic('bookmark', '-l')
1307 ip.run_line_magic('bookmark', '-l')
1305 ip.run_line_magic('bookmark', '-d bmname')
1308 ip.run_line_magic('bookmark', '-d bmname')
1306
1309
1307 def test_ls_magic():
1310 def test_ls_magic():
1308 ip = get_ipython()
1311 ip = get_ipython()
1309 json_formatter = ip.display_formatter.formatters['application/json']
1312 json_formatter = ip.display_formatter.formatters['application/json']
1310 json_formatter.enabled = True
1313 json_formatter.enabled = True
1311 lsmagic = ip.magic('lsmagic')
1314 lsmagic = ip.run_line_magic("lsmagic", "")
1312 with warnings.catch_warnings(record=True) as w:
1315 with warnings.catch_warnings(record=True) as w:
1313 j = json_formatter(lsmagic)
1316 j = json_formatter(lsmagic)
1314 assert sorted(j) == ["cell", "line"]
1317 assert sorted(j) == ["cell", "line"]
1315 assert w == [] # no warnings
1318 assert w == [] # no warnings
1316
1319
1317
1320
1318 def test_strip_initial_indent():
1321 def test_strip_initial_indent():
1319 def sii(s):
1322 def sii(s):
1320 lines = s.splitlines()
1323 lines = s.splitlines()
1321 return '\n'.join(code.strip_initial_indent(lines))
1324 return '\n'.join(code.strip_initial_indent(lines))
1322
1325
1323 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1326 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1324 assert sii(" a\n b\nc") == "a\n b\nc"
1327 assert sii(" a\n b\nc") == "a\n b\nc"
1325 assert sii("a\n b") == "a\n b"
1328 assert sii("a\n b") == "a\n b"
1326
1329
1327 def test_logging_magic_quiet_from_arg():
1330 def test_logging_magic_quiet_from_arg():
1328 _ip.config.LoggingMagics.quiet = False
1331 _ip.config.LoggingMagics.quiet = False
1329 lm = logging.LoggingMagics(shell=_ip)
1332 lm = logging.LoggingMagics(shell=_ip)
1330 with TemporaryDirectory() as td:
1333 with TemporaryDirectory() as td:
1331 try:
1334 try:
1332 with tt.AssertNotPrints(re.compile("Activating.*")):
1335 with tt.AssertNotPrints(re.compile("Activating.*")):
1333 lm.logstart('-q {}'.format(
1336 lm.logstart('-q {}'.format(
1334 os.path.join(td, "quiet_from_arg.log")))
1337 os.path.join(td, "quiet_from_arg.log")))
1335 finally:
1338 finally:
1336 _ip.logger.logstop()
1339 _ip.logger.logstop()
1337
1340
1338 def test_logging_magic_quiet_from_config():
1341 def test_logging_magic_quiet_from_config():
1339 _ip.config.LoggingMagics.quiet = True
1342 _ip.config.LoggingMagics.quiet = True
1340 lm = logging.LoggingMagics(shell=_ip)
1343 lm = logging.LoggingMagics(shell=_ip)
1341 with TemporaryDirectory() as td:
1344 with TemporaryDirectory() as td:
1342 try:
1345 try:
1343 with tt.AssertNotPrints(re.compile("Activating.*")):
1346 with tt.AssertNotPrints(re.compile("Activating.*")):
1344 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1347 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1345 finally:
1348 finally:
1346 _ip.logger.logstop()
1349 _ip.logger.logstop()
1347
1350
1348
1351
1349 def test_logging_magic_not_quiet():
1352 def test_logging_magic_not_quiet():
1350 _ip.config.LoggingMagics.quiet = False
1353 _ip.config.LoggingMagics.quiet = False
1351 lm = logging.LoggingMagics(shell=_ip)
1354 lm = logging.LoggingMagics(shell=_ip)
1352 with TemporaryDirectory() as td:
1355 with TemporaryDirectory() as td:
1353 try:
1356 try:
1354 with tt.AssertPrints(re.compile("Activating.*")):
1357 with tt.AssertPrints(re.compile("Activating.*")):
1355 lm.logstart(os.path.join(td, "not_quiet.log"))
1358 lm.logstart(os.path.join(td, "not_quiet.log"))
1356 finally:
1359 finally:
1357 _ip.logger.logstop()
1360 _ip.logger.logstop()
1358
1361
1359
1362
1360 def test_time_no_var_expand():
1363 def test_time_no_var_expand():
1361 _ip.user_ns['a'] = 5
1364 _ip.user_ns["a"] = 5
1362 _ip.user_ns['b'] = []
1365 _ip.user_ns["b"] = []
1363 _ip.magic('time b.append("{a}")')
1366 _ip.run_line_magic("time", 'b.append("{a}")')
1364 assert _ip.user_ns['b'] == ['{a}']
1367 assert _ip.user_ns["b"] == ["{a}"]
1365
1368
1366
1369
1367 # this is slow, put at the end for local testing.
1370 # this is slow, put at the end for local testing.
1368 def test_timeit_arguments():
1371 def test_timeit_arguments():
1369 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1372 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1370 _ip.magic("timeit -n1 -r1 a=('#')")
1373 _ip.run_line_magic("timeit", "-n1 -r1 a=('#')")
1371
1374
1372
1375
1373 MINIMAL_LAZY_MAGIC = """
1376 MINIMAL_LAZY_MAGIC = """
1374 from IPython.core.magic import (
1377 from IPython.core.magic import (
1375 Magics,
1378 Magics,
1376 magics_class,
1379 magics_class,
1377 line_magic,
1380 line_magic,
1378 cell_magic,
1381 cell_magic,
1379 )
1382 )
1380
1383
1381
1384
1382 @magics_class
1385 @magics_class
1383 class LazyMagics(Magics):
1386 class LazyMagics(Magics):
1384 @line_magic
1387 @line_magic
1385 def lazy_line(self, line):
1388 def lazy_line(self, line):
1386 print("Lazy Line")
1389 print("Lazy Line")
1387
1390
1388 @cell_magic
1391 @cell_magic
1389 def lazy_cell(self, line, cell):
1392 def lazy_cell(self, line, cell):
1390 print("Lazy Cell")
1393 print("Lazy Cell")
1391
1394
1392
1395
1393 def load_ipython_extension(ipython):
1396 def load_ipython_extension(ipython):
1394 ipython.register_magics(LazyMagics)
1397 ipython.register_magics(LazyMagics)
1395 """
1398 """
1396
1399
1397
1400
1398 def test_lazy_magics():
1401 def test_lazy_magics():
1399 with pytest.raises(UsageError):
1402 with pytest.raises(UsageError):
1400 ip.run_line_magic("lazy_line", "")
1403 ip.run_line_magic("lazy_line", "")
1401
1404
1402 startdir = os.getcwd()
1405 startdir = os.getcwd()
1403
1406
1404 with TemporaryDirectory() as tmpdir:
1407 with TemporaryDirectory() as tmpdir:
1405 with prepended_to_syspath(tmpdir):
1408 with prepended_to_syspath(tmpdir):
1406 ptempdir = Path(tmpdir)
1409 ptempdir = Path(tmpdir)
1407 tf = ptempdir / "lazy_magic_module.py"
1410 tf = ptempdir / "lazy_magic_module.py"
1408 tf.write_text(MINIMAL_LAZY_MAGIC)
1411 tf.write_text(MINIMAL_LAZY_MAGIC)
1409 ip.magics_manager.register_lazy("lazy_line", Path(tf.name).name[:-3])
1412 ip.magics_manager.register_lazy("lazy_line", Path(tf.name).name[:-3])
1410 with tt.AssertPrints("Lazy Line"):
1413 with tt.AssertPrints("Lazy Line"):
1411 ip.run_line_magic("lazy_line", "")
1414 ip.run_line_magic("lazy_line", "")
1412
1415
1413
1416
1414 TEST_MODULE = """
1417 TEST_MODULE = """
1415 print('Loaded my_tmp')
1418 print('Loaded my_tmp')
1416 if __name__ == "__main__":
1419 if __name__ == "__main__":
1417 print('I just ran a script')
1420 print('I just ran a script')
1418 """
1421 """
1419
1422
1420 def test_run_module_from_import_hook():
1423 def test_run_module_from_import_hook():
1421 "Test that a module can be loaded via an import hook"
1424 "Test that a module can be loaded via an import hook"
1422 with TemporaryDirectory() as tmpdir:
1425 with TemporaryDirectory() as tmpdir:
1423 fullpath = os.path.join(tmpdir, "my_tmp.py")
1426 fullpath = os.path.join(tmpdir, "my_tmp.py")
1424 Path(fullpath).write_text(TEST_MODULE, encoding="utf-8")
1427 Path(fullpath).write_text(TEST_MODULE, encoding="utf-8")
1425
1428
1426 import importlib.abc
1429 import importlib.abc
1427 import importlib.util
1430 import importlib.util
1428
1431
1429 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1432 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1430 def find_spec(self, fullname, path, target=None):
1433 def find_spec(self, fullname, path, target=None):
1431 if fullname == "my_tmp":
1434 if fullname == "my_tmp":
1432 return importlib.util.spec_from_loader(fullname, self)
1435 return importlib.util.spec_from_loader(fullname, self)
1433
1436
1434 def get_filename(self, fullname):
1437 def get_filename(self, fullname):
1435 assert fullname == "my_tmp"
1438 assert fullname == "my_tmp"
1436 return fullpath
1439 return fullpath
1437
1440
1438 def get_data(self, path):
1441 def get_data(self, path):
1439 assert Path(path).samefile(fullpath)
1442 assert Path(path).samefile(fullpath)
1440 return Path(fullpath).read_text(encoding="utf-8")
1443 return Path(fullpath).read_text(encoding="utf-8")
1441
1444
1442 sys.meta_path.insert(0, MyTempImporter())
1445 sys.meta_path.insert(0, MyTempImporter())
1443
1446
1444 with capture_output() as captured:
1447 with capture_output() as captured:
1445 _ip.magic("run -m my_tmp")
1448 _ip.run_line_magic("run", "-m my_tmp")
1446 _ip.run_cell("import my_tmp")
1449 _ip.run_cell("import my_tmp")
1447
1450
1448 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1451 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1449 assert output == captured.stdout
1452 assert output == captured.stdout
1450
1453
1451 sys.meta_path.pop(0)
1454 sys.meta_path.pop(0)
@@ -1,476 +1,541 b''
1 """Tests for the object inspection functionality.
1 """Tests for the object inspection functionality.
2 """
2 """
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 from contextlib import contextmanager
8 from inspect import signature, Signature, Parameter
9 from inspect import signature, Signature, Parameter
9 import inspect
10 import inspect
10 import os
11 import os
11 import pytest
12 import pytest
12 import re
13 import re
13 import sys
14 import sys
14
15
15 from .. import oinspect
16 from .. import oinspect
16
17
17 from decorator import decorator
18 from decorator import decorator
18
19
19 from IPython.testing.tools import AssertPrints, AssertNotPrints
20 from IPython.testing.tools import AssertPrints, AssertNotPrints
20 from IPython.utils.path import compress_user
21 from IPython.utils.path import compress_user
21
22
22
23
23 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
24 # Globals and constants
25 # Globals and constants
25 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
26
27
27 inspector = None
28 inspector = None
28
29
29 def setup_module():
30 def setup_module():
30 global inspector
31 global inspector
31 inspector = oinspect.Inspector()
32 inspector = oinspect.Inspector()
32
33
33
34
34 class SourceModuleMainTest:
35 class SourceModuleMainTest:
35 __module__ = "__main__"
36 __module__ = "__main__"
36
37
37
38
38 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
39 # Local utilities
40 # Local utilities
40 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
41
42
42 # WARNING: since this test checks the line number where a function is
43 # WARNING: since this test checks the line number where a function is
43 # defined, if any code is inserted above, the following line will need to be
44 # defined, if any code is inserted above, the following line will need to be
44 # updated. Do NOT insert any whitespace between the next line and the function
45 # updated. Do NOT insert any whitespace between the next line and the function
45 # definition below.
46 # definition below.
46 THIS_LINE_NUMBER = 46 # Put here the actual number of this line
47 THIS_LINE_NUMBER = 47 # Put here the actual number of this line
47
48
48
49
49 def test_find_source_lines():
50 def test_find_source_lines():
50 assert oinspect.find_source_lines(test_find_source_lines) == THIS_LINE_NUMBER + 3
51 assert oinspect.find_source_lines(test_find_source_lines) == THIS_LINE_NUMBER + 3
51 assert oinspect.find_source_lines(type) is None
52 assert oinspect.find_source_lines(type) is None
52 assert oinspect.find_source_lines(SourceModuleMainTest) is None
53 assert oinspect.find_source_lines(SourceModuleMainTest) is None
53 assert oinspect.find_source_lines(SourceModuleMainTest()) is None
54 assert oinspect.find_source_lines(SourceModuleMainTest()) is None
54
55
55
56
56 def test_getsource():
57 def test_getsource():
57 assert oinspect.getsource(type) is None
58 assert oinspect.getsource(type) is None
58 assert oinspect.getsource(SourceModuleMainTest) is None
59 assert oinspect.getsource(SourceModuleMainTest) is None
59 assert oinspect.getsource(SourceModuleMainTest()) is None
60 assert oinspect.getsource(SourceModuleMainTest()) is None
60
61
61
62
62 def test_inspect_getfile_raises_exception():
63 def test_inspect_getfile_raises_exception():
63 """Check oinspect.find_file/getsource/find_source_lines expectations"""
64 """Check oinspect.find_file/getsource/find_source_lines expectations"""
64 with pytest.raises(TypeError):
65 with pytest.raises(TypeError):
65 inspect.getfile(type)
66 inspect.getfile(type)
66 with pytest.raises(OSError if sys.version_info >= (3, 10) else TypeError):
67 with pytest.raises(OSError if sys.version_info >= (3, 10) else TypeError):
67 inspect.getfile(SourceModuleMainTest)
68 inspect.getfile(SourceModuleMainTest)
68
69
69
70
70 # A couple of utilities to ensure these tests work the same from a source or a
71 # A couple of utilities to ensure these tests work the same from a source or a
71 # binary install
72 # binary install
72 def pyfile(fname):
73 def pyfile(fname):
73 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
74 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
74
75
75
76
76 def match_pyfiles(f1, f2):
77 def match_pyfiles(f1, f2):
77 assert pyfile(f1) == pyfile(f2)
78 assert pyfile(f1) == pyfile(f2)
78
79
79
80
80 def test_find_file():
81 def test_find_file():
81 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
82 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
82 assert oinspect.find_file(type) is None
83 assert oinspect.find_file(type) is None
83 assert oinspect.find_file(SourceModuleMainTest) is None
84 assert oinspect.find_file(SourceModuleMainTest) is None
84 assert oinspect.find_file(SourceModuleMainTest()) is None
85 assert oinspect.find_file(SourceModuleMainTest()) is None
85
86
86
87
87 def test_find_file_decorated1():
88 def test_find_file_decorated1():
88
89
89 @decorator
90 @decorator
90 def noop1(f):
91 def noop1(f):
91 def wrapper(*a, **kw):
92 def wrapper(*a, **kw):
92 return f(*a, **kw)
93 return f(*a, **kw)
93 return wrapper
94 return wrapper
94
95
95 @noop1
96 @noop1
96 def f(x):
97 def f(x):
97 "My docstring"
98 "My docstring"
98
99
99 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
100 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
100 assert f.__doc__ == "My docstring"
101 assert f.__doc__ == "My docstring"
101
102
102
103
103 def test_find_file_decorated2():
104 def test_find_file_decorated2():
104
105
105 @decorator
106 @decorator
106 def noop2(f, *a, **kw):
107 def noop2(f, *a, **kw):
107 return f(*a, **kw)
108 return f(*a, **kw)
108
109
109 @noop2
110 @noop2
110 @noop2
111 @noop2
111 @noop2
112 @noop2
112 def f(x):
113 def f(x):
113 "My docstring 2"
114 "My docstring 2"
114
115
115 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
116 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
116 assert f.__doc__ == "My docstring 2"
117 assert f.__doc__ == "My docstring 2"
117
118
118
119
119 def test_find_file_magic():
120 def test_find_file_magic():
120 run = ip.find_line_magic('run')
121 run = ip.find_line_magic('run')
121 assert oinspect.find_file(run) is not None
122 assert oinspect.find_file(run) is not None
122
123
123
124
124 # A few generic objects we can then inspect in the tests below
125 # A few generic objects we can then inspect in the tests below
125
126
126 class Call(object):
127 class Call(object):
127 """This is the class docstring."""
128 """This is the class docstring."""
128
129
129 def __init__(self, x, y=1):
130 def __init__(self, x, y=1):
130 """This is the constructor docstring."""
131 """This is the constructor docstring."""
131
132
132 def __call__(self, *a, **kw):
133 def __call__(self, *a, **kw):
133 """This is the call docstring."""
134 """This is the call docstring."""
134
135
135 def method(self, x, z=2):
136 def method(self, x, z=2):
136 """Some method's docstring"""
137 """Some method's docstring"""
137
138
138 class HasSignature(object):
139 class HasSignature(object):
139 """This is the class docstring."""
140 """This is the class docstring."""
140 __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
141 __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
141
142
142 def __init__(self, *args):
143 def __init__(self, *args):
143 """This is the init docstring"""
144 """This is the init docstring"""
144
145
145
146
146 class SimpleClass(object):
147 class SimpleClass(object):
147 def method(self, x, z=2):
148 def method(self, x, z=2):
148 """Some method's docstring"""
149 """Some method's docstring"""
149
150
150
151
151 class Awkward(object):
152 class Awkward(object):
152 def __getattr__(self, name):
153 def __getattr__(self, name):
153 raise Exception(name)
154 raise Exception(name)
154
155
155 class NoBoolCall:
156 class NoBoolCall:
156 """
157 """
157 callable with `__bool__` raising should still be inspect-able.
158 callable with `__bool__` raising should still be inspect-able.
158 """
159 """
159
160
160 def __call__(self):
161 def __call__(self):
161 """does nothing"""
162 """does nothing"""
162 pass
163 pass
163
164
164 def __bool__(self):
165 def __bool__(self):
165 """just raise NotImplemented"""
166 """just raise NotImplemented"""
166 raise NotImplementedError('Must be implemented')
167 raise NotImplementedError('Must be implemented')
167
168
168
169
169 class SerialLiar(object):
170 class SerialLiar(object):
170 """Attribute accesses always get another copy of the same class.
171 """Attribute accesses always get another copy of the same class.
171
172
172 unittest.mock.call does something similar, but it's not ideal for testing
173 unittest.mock.call does something similar, but it's not ideal for testing
173 as the failure mode is to eat all your RAM. This gives up after 10k levels.
174 as the failure mode is to eat all your RAM. This gives up after 10k levels.
174 """
175 """
175 def __init__(self, max_fibbing_twig, lies_told=0):
176 def __init__(self, max_fibbing_twig, lies_told=0):
176 if lies_told > 10000:
177 if lies_told > 10000:
177 raise RuntimeError('Nose too long, honesty is the best policy')
178 raise RuntimeError('Nose too long, honesty is the best policy')
178 self.max_fibbing_twig = max_fibbing_twig
179 self.max_fibbing_twig = max_fibbing_twig
179 self.lies_told = lies_told
180 self.lies_told = lies_told
180 max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told)
181 max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told)
181
182
182 def __getattr__(self, item):
183 def __getattr__(self, item):
183 return SerialLiar(self.max_fibbing_twig, self.lies_told + 1)
184 return SerialLiar(self.max_fibbing_twig, self.lies_told + 1)
184
185
185 #-----------------------------------------------------------------------------
186 #-----------------------------------------------------------------------------
186 # Tests
187 # Tests
187 #-----------------------------------------------------------------------------
188 #-----------------------------------------------------------------------------
188
189
189 def test_info():
190 def test_info():
190 "Check that Inspector.info fills out various fields as expected."
191 "Check that Inspector.info fills out various fields as expected."
191 i = inspector.info(Call, oname="Call")
192 i = inspector.info(Call, oname="Call")
192 assert i["type_name"] == "type"
193 assert i["type_name"] == "type"
193 expected_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
194 expected_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
194 assert i["base_class"] == expected_class
195 assert i["base_class"] == expected_class
195 assert re.search(
196 assert re.search(
196 "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>",
197 "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>",
197 i["string_form"],
198 i["string_form"],
198 )
199 )
199 fname = __file__
200 fname = __file__
200 if fname.endswith(".pyc"):
201 if fname.endswith(".pyc"):
201 fname = fname[:-1]
202 fname = fname[:-1]
202 # case-insensitive comparison needed on some filesystems
203 # case-insensitive comparison needed on some filesystems
203 # e.g. Windows:
204 # e.g. Windows:
204 assert i["file"].lower() == compress_user(fname).lower()
205 assert i["file"].lower() == compress_user(fname).lower()
205 assert i["definition"] == None
206 assert i["definition"] == None
206 assert i["docstring"] == Call.__doc__
207 assert i["docstring"] == Call.__doc__
207 assert i["source"] == None
208 assert i["source"] == None
208 assert i["isclass"] is True
209 assert i["isclass"] is True
209 assert i["init_definition"] == "Call(x, y=1)"
210 assert i["init_definition"] == "Call(x, y=1)"
210 assert i["init_docstring"] == Call.__init__.__doc__
211 assert i["init_docstring"] == Call.__init__.__doc__
211
212
212 i = inspector.info(Call, detail_level=1)
213 i = inspector.info(Call, detail_level=1)
213 assert i["source"] is not None
214 assert i["source"] is not None
214 assert i["docstring"] == None
215 assert i["docstring"] == None
215
216
216 c = Call(1)
217 c = Call(1)
217 c.__doc__ = "Modified instance docstring"
218 c.__doc__ = "Modified instance docstring"
218 i = inspector.info(c)
219 i = inspector.info(c)
219 assert i["type_name"] == "Call"
220 assert i["type_name"] == "Call"
220 assert i["docstring"] == "Modified instance docstring"
221 assert i["docstring"] == "Modified instance docstring"
221 assert i["class_docstring"] == Call.__doc__
222 assert i["class_docstring"] == Call.__doc__
222 assert i["init_docstring"] == Call.__init__.__doc__
223 assert i["init_docstring"] == Call.__init__.__doc__
223 assert i["call_docstring"] == Call.__call__.__doc__
224 assert i["call_docstring"] == Call.__call__.__doc__
224
225
225
226
226 def test_class_signature():
227 def test_class_signature():
227 info = inspector.info(HasSignature, "HasSignature")
228 info = inspector.info(HasSignature, "HasSignature")
228 assert info["init_definition"] == "HasSignature(test)"
229 assert info["init_definition"] == "HasSignature(test)"
229 assert info["init_docstring"] == HasSignature.__init__.__doc__
230 assert info["init_docstring"] == HasSignature.__init__.__doc__
230
231
231
232
232 def test_info_awkward():
233 def test_info_awkward():
233 # Just test that this doesn't throw an error.
234 # Just test that this doesn't throw an error.
234 inspector.info(Awkward())
235 inspector.info(Awkward())
235
236
236 def test_bool_raise():
237 def test_bool_raise():
237 inspector.info(NoBoolCall())
238 inspector.info(NoBoolCall())
238
239
239 def test_info_serialliar():
240 def test_info_serialliar():
240 fib_tracker = [0]
241 fib_tracker = [0]
241 inspector.info(SerialLiar(fib_tracker))
242 inspector.info(SerialLiar(fib_tracker))
242
243
243 # Nested attribute access should be cut off at 100 levels deep to avoid
244 # Nested attribute access should be cut off at 100 levels deep to avoid
244 # infinite loops: https://github.com/ipython/ipython/issues/9122
245 # infinite loops: https://github.com/ipython/ipython/issues/9122
245 assert fib_tracker[0] < 9000
246 assert fib_tracker[0] < 9000
246
247
247 def support_function_one(x, y=2, *a, **kw):
248 def support_function_one(x, y=2, *a, **kw):
248 """A simple function."""
249 """A simple function."""
249
250
250 def test_calldef_none():
251 def test_calldef_none():
251 # We should ignore __call__ for all of these.
252 # We should ignore __call__ for all of these.
252 for obj in [support_function_one, SimpleClass().method, any, str.upper]:
253 for obj in [support_function_one, SimpleClass().method, any, str.upper]:
253 i = inspector.info(obj)
254 i = inspector.info(obj)
254 assert i["call_def"] is None
255 assert i["call_def"] is None
255
256
256
257
257 def f_kwarg(pos, *, kwonly):
258 def f_kwarg(pos, *, kwonly):
258 pass
259 pass
259
260
260 def test_definition_kwonlyargs():
261 def test_definition_kwonlyargs():
261 i = inspector.info(f_kwarg, oname="f_kwarg") # analysis:ignore
262 i = inspector.info(f_kwarg, oname="f_kwarg") # analysis:ignore
262 assert i["definition"] == "f_kwarg(pos, *, kwonly)"
263 assert i["definition"] == "f_kwarg(pos, *, kwonly)"
263
264
264
265
265 def test_getdoc():
266 def test_getdoc():
266 class A(object):
267 class A(object):
267 """standard docstring"""
268 """standard docstring"""
268 pass
269 pass
269
270
270 class B(object):
271 class B(object):
271 """standard docstring"""
272 """standard docstring"""
272 def getdoc(self):
273 def getdoc(self):
273 return "custom docstring"
274 return "custom docstring"
274
275
275 class C(object):
276 class C(object):
276 """standard docstring"""
277 """standard docstring"""
277 def getdoc(self):
278 def getdoc(self):
278 return None
279 return None
279
280
280 a = A()
281 a = A()
281 b = B()
282 b = B()
282 c = C()
283 c = C()
283
284
284 assert oinspect.getdoc(a) == "standard docstring"
285 assert oinspect.getdoc(a) == "standard docstring"
285 assert oinspect.getdoc(b) == "custom docstring"
286 assert oinspect.getdoc(b) == "custom docstring"
286 assert oinspect.getdoc(c) == "standard docstring"
287 assert oinspect.getdoc(c) == "standard docstring"
287
288
288
289
289 def test_empty_property_has_no_source():
290 def test_empty_property_has_no_source():
290 i = inspector.info(property(), detail_level=1)
291 i = inspector.info(property(), detail_level=1)
291 assert i["source"] is None
292 assert i["source"] is None
292
293
293
294
294 def test_property_sources():
295 def test_property_sources():
295 # A simple adder whose source and signature stays
296 # A simple adder whose source and signature stays
296 # the same across Python distributions
297 # the same across Python distributions
297 def simple_add(a, b):
298 def simple_add(a, b):
298 "Adds two numbers"
299 "Adds two numbers"
299 return a + b
300 return a + b
300
301
301 class A(object):
302 class A(object):
302 @property
303 @property
303 def foo(self):
304 def foo(self):
304 return 'bar'
305 return 'bar'
305
306
306 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
307 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
307
308
308 dname = property(oinspect.getdoc)
309 dname = property(oinspect.getdoc)
309 adder = property(simple_add)
310 adder = property(simple_add)
310
311
311 i = inspector.info(A.foo, detail_level=1)
312 i = inspector.info(A.foo, detail_level=1)
312 assert "def foo(self):" in i["source"]
313 assert "def foo(self):" in i["source"]
313 assert "lambda self, v:" in i["source"]
314 assert "lambda self, v:" in i["source"]
314
315
315 i = inspector.info(A.dname, detail_level=1)
316 i = inspector.info(A.dname, detail_level=1)
316 assert "def getdoc(obj)" in i["source"]
317 assert "def getdoc(obj)" in i["source"]
317
318
318 i = inspector.info(A.adder, detail_level=1)
319 i = inspector.info(A.adder, detail_level=1)
319 assert "def simple_add(a, b)" in i["source"]
320 assert "def simple_add(a, b)" in i["source"]
320
321
321
322
322 def test_property_docstring_is_in_info_for_detail_level_0():
323 def test_property_docstring_is_in_info_for_detail_level_0():
323 class A(object):
324 class A(object):
324 @property
325 @property
325 def foobar(self):
326 def foobar(self):
326 """This is `foobar` property."""
327 """This is `foobar` property."""
327 pass
328 pass
328
329
329 ip.user_ns["a_obj"] = A()
330 ip.user_ns["a_obj"] = A()
330 assert (
331 assert (
331 "This is `foobar` property."
332 "This is `foobar` property."
332 == ip.object_inspect("a_obj.foobar", detail_level=0)["docstring"]
333 == ip.object_inspect("a_obj.foobar", detail_level=0)["docstring"]
333 )
334 )
334
335
335 ip.user_ns["a_cls"] = A
336 ip.user_ns["a_cls"] = A
336 assert (
337 assert (
337 "This is `foobar` property."
338 "This is `foobar` property."
338 == ip.object_inspect("a_cls.foobar", detail_level=0)["docstring"]
339 == ip.object_inspect("a_cls.foobar", detail_level=0)["docstring"]
339 )
340 )
340
341
341
342
342 def test_pdef():
343 def test_pdef():
343 # See gh-1914
344 # See gh-1914
344 def foo(): pass
345 def foo(): pass
345 inspector.pdef(foo, 'foo')
346 inspector.pdef(foo, 'foo')
346
347
347
348
349 @contextmanager
350 def cleanup_user_ns(**kwargs):
351 """
352 On exit delete all the keys that were not in user_ns before entering.
353
354 It does not restore old values !
355
356 Parameters
357 ----------
358
359 **kwargs
360 used to update ip.user_ns
361
362 """
363 try:
364 known = set(ip.user_ns.keys())
365 ip.user_ns.update(kwargs)
366 yield
367 finally:
368 added = set(ip.user_ns.keys()) - known
369 for k in added:
370 del ip.user_ns[k]
371
372
373 def test_pinfo_getindex():
374 def dummy():
375 """
376 MARKER
377 """
378
379 container = [dummy]
380 with cleanup_user_ns(container=container):
381 with AssertPrints("MARKER"):
382 ip._inspect("pinfo", "container[0]", detail_level=0)
383 assert "container" not in ip.user_ns.keys()
384
385
386 def test_qmark_getindex():
387 def dummy():
388 """
389 MARKER 2
390 """
391
392 container = [dummy]
393 with cleanup_user_ns(container=container):
394 with AssertPrints("MARKER 2"):
395 ip.run_cell("container[0]?")
396 assert "container" not in ip.user_ns.keys()
397
398
399 def test_qmark_getindex_negatif():
400 def dummy():
401 """
402 MARKER 3
403 """
404
405 container = [dummy]
406 with cleanup_user_ns(container=container):
407 with AssertPrints("MARKER 3"):
408 ip.run_cell("container[-1]?")
409 assert "container" not in ip.user_ns.keys()
410
411
412
348 def test_pinfo_nonascii():
413 def test_pinfo_nonascii():
349 # See gh-1177
414 # See gh-1177
350 from . import nonascii2
415 from . import nonascii2
351 ip.user_ns['nonascii2'] = nonascii2
416 ip.user_ns['nonascii2'] = nonascii2
352 ip._inspect('pinfo', 'nonascii2', detail_level=1)
417 ip._inspect('pinfo', 'nonascii2', detail_level=1)
353
418
354 def test_pinfo_type():
419 def test_pinfo_type():
355 """
420 """
356 type can fail in various edge case, for example `type.__subclass__()`
421 type can fail in various edge case, for example `type.__subclass__()`
357 """
422 """
358 ip._inspect('pinfo', 'type')
423 ip._inspect('pinfo', 'type')
359
424
360
425
361 def test_pinfo_docstring_no_source():
426 def test_pinfo_docstring_no_source():
362 """Docstring should be included with detail_level=1 if there is no source"""
427 """Docstring should be included with detail_level=1 if there is no source"""
363 with AssertPrints('Docstring:'):
428 with AssertPrints('Docstring:'):
364 ip._inspect('pinfo', 'str.format', detail_level=0)
429 ip._inspect('pinfo', 'str.format', detail_level=0)
365 with AssertPrints('Docstring:'):
430 with AssertPrints('Docstring:'):
366 ip._inspect('pinfo', 'str.format', detail_level=1)
431 ip._inspect('pinfo', 'str.format', detail_level=1)
367
432
368
433
369 def test_pinfo_no_docstring_if_source():
434 def test_pinfo_no_docstring_if_source():
370 """Docstring should not be included with detail_level=1 if source is found"""
435 """Docstring should not be included with detail_level=1 if source is found"""
371 def foo():
436 def foo():
372 """foo has a docstring"""
437 """foo has a docstring"""
373
438
374 ip.user_ns['foo'] = foo
439 ip.user_ns['foo'] = foo
375
440
376 with AssertPrints('Docstring:'):
441 with AssertPrints('Docstring:'):
377 ip._inspect('pinfo', 'foo', detail_level=0)
442 ip._inspect('pinfo', 'foo', detail_level=0)
378 with AssertPrints('Source:'):
443 with AssertPrints('Source:'):
379 ip._inspect('pinfo', 'foo', detail_level=1)
444 ip._inspect('pinfo', 'foo', detail_level=1)
380 with AssertNotPrints('Docstring:'):
445 with AssertNotPrints('Docstring:'):
381 ip._inspect('pinfo', 'foo', detail_level=1)
446 ip._inspect('pinfo', 'foo', detail_level=1)
382
447
383
448
384 def test_pinfo_docstring_if_detail_and_no_source():
449 def test_pinfo_docstring_if_detail_and_no_source():
385 """ Docstring should be displayed if source info not available """
450 """ Docstring should be displayed if source info not available """
386 obj_def = '''class Foo(object):
451 obj_def = '''class Foo(object):
387 """ This is a docstring for Foo """
452 """ This is a docstring for Foo """
388 def bar(self):
453 def bar(self):
389 """ This is a docstring for Foo.bar """
454 """ This is a docstring for Foo.bar """
390 pass
455 pass
391 '''
456 '''
392
457
393 ip.run_cell(obj_def)
458 ip.run_cell(obj_def)
394 ip.run_cell('foo = Foo()')
459 ip.run_cell('foo = Foo()')
395
460
396 with AssertNotPrints("Source:"):
461 with AssertNotPrints("Source:"):
397 with AssertPrints('Docstring:'):
462 with AssertPrints('Docstring:'):
398 ip._inspect('pinfo', 'foo', detail_level=0)
463 ip._inspect('pinfo', 'foo', detail_level=0)
399 with AssertPrints('Docstring:'):
464 with AssertPrints('Docstring:'):
400 ip._inspect('pinfo', 'foo', detail_level=1)
465 ip._inspect('pinfo', 'foo', detail_level=1)
401 with AssertPrints('Docstring:'):
466 with AssertPrints('Docstring:'):
402 ip._inspect('pinfo', 'foo.bar', detail_level=0)
467 ip._inspect('pinfo', 'foo.bar', detail_level=0)
403
468
404 with AssertNotPrints('Docstring:'):
469 with AssertNotPrints('Docstring:'):
405 with AssertPrints('Source:'):
470 with AssertPrints('Source:'):
406 ip._inspect('pinfo', 'foo.bar', detail_level=1)
471 ip._inspect('pinfo', 'foo.bar', detail_level=1)
407
472
408
473
409 def test_pinfo_magic():
474 def test_pinfo_magic():
410 with AssertPrints('Docstring:'):
475 with AssertPrints('Docstring:'):
411 ip._inspect('pinfo', 'lsmagic', detail_level=0)
476 ip._inspect('pinfo', 'lsmagic', detail_level=0)
412
477
413 with AssertPrints('Source:'):
478 with AssertPrints('Source:'):
414 ip._inspect('pinfo', 'lsmagic', detail_level=1)
479 ip._inspect('pinfo', 'lsmagic', detail_level=1)
415
480
416
481
417 def test_init_colors():
482 def test_init_colors():
418 # ensure colors are not present in signature info
483 # ensure colors are not present in signature info
419 info = inspector.info(HasSignature)
484 info = inspector.info(HasSignature)
420 init_def = info["init_definition"]
485 init_def = info["init_definition"]
421 assert "[0m" not in init_def
486 assert "[0m" not in init_def
422
487
423
488
424 def test_builtin_init():
489 def test_builtin_init():
425 info = inspector.info(list)
490 info = inspector.info(list)
426 init_def = info['init_definition']
491 init_def = info['init_definition']
427 assert init_def is not None
492 assert init_def is not None
428
493
429
494
430 def test_render_signature_short():
495 def test_render_signature_short():
431 def short_fun(a=1): pass
496 def short_fun(a=1): pass
432 sig = oinspect._render_signature(
497 sig = oinspect._render_signature(
433 signature(short_fun),
498 signature(short_fun),
434 short_fun.__name__,
499 short_fun.__name__,
435 )
500 )
436 assert sig == "short_fun(a=1)"
501 assert sig == "short_fun(a=1)"
437
502
438
503
439 def test_render_signature_long():
504 def test_render_signature_long():
440 from typing import Optional
505 from typing import Optional
441
506
442 def long_function(
507 def long_function(
443 a_really_long_parameter: int,
508 a_really_long_parameter: int,
444 and_another_long_one: bool = False,
509 and_another_long_one: bool = False,
445 let_us_make_sure_this_is_looong: Optional[str] = None,
510 let_us_make_sure_this_is_looong: Optional[str] = None,
446 ) -> bool: pass
511 ) -> bool: pass
447
512
448 sig = oinspect._render_signature(
513 sig = oinspect._render_signature(
449 signature(long_function),
514 signature(long_function),
450 long_function.__name__,
515 long_function.__name__,
451 )
516 )
452 assert sig in [
517 assert sig in [
453 # Python >=3.9
518 # Python >=3.9
454 '''\
519 '''\
455 long_function(
520 long_function(
456 a_really_long_parameter: int,
521 a_really_long_parameter: int,
457 and_another_long_one: bool = False,
522 and_another_long_one: bool = False,
458 let_us_make_sure_this_is_looong: Optional[str] = None,
523 let_us_make_sure_this_is_looong: Optional[str] = None,
459 ) -> bool\
524 ) -> bool\
460 ''',
525 ''',
461 # Python >=3.7
526 # Python >=3.7
462 '''\
527 '''\
463 long_function(
528 long_function(
464 a_really_long_parameter: int,
529 a_really_long_parameter: int,
465 and_another_long_one: bool = False,
530 and_another_long_one: bool = False,
466 let_us_make_sure_this_is_looong: Union[str, NoneType] = None,
531 let_us_make_sure_this_is_looong: Union[str, NoneType] = None,
467 ) -> bool\
532 ) -> bool\
468 ''', # Python <=3.6
533 ''', # Python <=3.6
469 '''\
534 '''\
470 long_function(
535 long_function(
471 a_really_long_parameter:int,
536 a_really_long_parameter:int,
472 and_another_long_one:bool=False,
537 and_another_long_one:bool=False,
473 let_us_make_sure_this_is_looong:Union[str, NoneType]=None,
538 let_us_make_sure_this_is_looong:Union[str, NoneType]=None,
474 ) -> bool\
539 ) -> bool\
475 ''',
540 ''',
476 ]
541 ]
@@ -1,622 +1,626 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for code execution (%run and related), which is particularly tricky.
2 """Tests for code execution (%run and related), which is particularly tricky.
3
3
4 Because of how %run manages namespaces, and the fact that we are trying here to
4 Because of how %run manages namespaces, and the fact that we are trying here to
5 verify subtle object deletion and reference counting issues, the %run tests
5 verify subtle object deletion and reference counting issues, the %run tests
6 will be kept in this separate file. This makes it easier to aggregate in one
6 will be kept in this separate file. This makes it easier to aggregate in one
7 place the tricks needed to handle it; most other magics are much easier to test
7 place the tricks needed to handle it; most other magics are much easier to test
8 and we do so in a common test_magic file.
8 and we do so in a common test_magic file.
9
9
10 Note that any test using `run -i` should make sure to do a `reset` afterwards,
10 Note that any test using `run -i` should make sure to do a `reset` afterwards,
11 as otherwise it may influence later tests.
11 as otherwise it may influence later tests.
12 """
12 """
13
13
14 # Copyright (c) IPython Development Team.
14 # Copyright (c) IPython Development Team.
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16
16
17
17
18
18
19 import functools
19 import functools
20 import os
20 import os
21 import platform
21 import platform
22 import random
22 import random
23 import string
23 import string
24 import sys
24 import sys
25 import textwrap
25 import textwrap
26 import unittest
26 import unittest
27 from os.path import join as pjoin
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 from tempfile import TemporaryDirectory
32
32
33 from IPython.core import debugger
33 from IPython.core import debugger
34 from IPython.testing import decorators as dec
34 from IPython.testing import decorators as dec
35 from IPython.testing import tools as tt
35 from IPython.testing import tools as tt
36 from IPython.utils.io import capture_output
36 from IPython.utils.io import capture_output
37
37
38
38
39 def doctest_refbug():
39 def doctest_refbug():
40 """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.
41 See: https://github.com/ipython/ipython/issues/141
41 See: https://github.com/ipython/ipython/issues/141
42
42
43 In [1]: _ip.clear_main_mod_cache()
43 In [1]: _ip.clear_main_mod_cache()
44 # random
44 # random
45
45
46 In [2]: %run refbug
46 In [2]: %run refbug
47
47
48 In [3]: call_f()
48 In [3]: call_f()
49 lowercased: hello
49 lowercased: hello
50
50
51 In [4]: %run refbug
51 In [4]: %run refbug
52
52
53 In [5]: call_f()
53 In [5]: call_f()
54 lowercased: hello
54 lowercased: hello
55 lowercased: hello
55 lowercased: hello
56 """
56 """
57
57
58
58
59 def doctest_run_builtins():
59 def doctest_run_builtins():
60 r"""Check that %run doesn't damage __builtins__.
60 r"""Check that %run doesn't damage __builtins__.
61
61
62 In [1]: import tempfile
62 In [1]: import tempfile
63
63
64 In [2]: bid1 = id(__builtins__)
64 In [2]: bid1 = id(__builtins__)
65
65
66 In [3]: fname = tempfile.mkstemp('.py')[1]
66 In [3]: fname = tempfile.mkstemp('.py')[1]
67
67
68 In [3]: f = open(fname, 'w', encoding='utf-8')
68 In [3]: f = open(fname, 'w', encoding='utf-8')
69
69
70 In [4]: dummy= f.write('pass\n')
70 In [4]: dummy= f.write('pass\n')
71
71
72 In [5]: f.flush()
72 In [5]: f.flush()
73
73
74 In [6]: t1 = type(__builtins__)
74 In [6]: t1 = type(__builtins__)
75
75
76 In [7]: %run $fname
76 In [7]: %run $fname
77
77
78 In [7]: f.close()
78 In [7]: f.close()
79
79
80 In [8]: bid2 = id(__builtins__)
80 In [8]: bid2 = id(__builtins__)
81
81
82 In [9]: t2 = type(__builtins__)
82 In [9]: t2 = type(__builtins__)
83
83
84 In [10]: t1 == t2
84 In [10]: t1 == t2
85 Out[10]: True
85 Out[10]: True
86
86
87 In [10]: bid1 == bid2
87 In [10]: bid1 == bid2
88 Out[10]: True
88 Out[10]: True
89
89
90 In [12]: try:
90 In [12]: try:
91 ....: os.unlink(fname)
91 ....: os.unlink(fname)
92 ....: except:
92 ....: except:
93 ....: pass
93 ....: pass
94 ....:
94 ....:
95 """
95 """
96
96
97
97
98 def doctest_run_option_parser():
98 def doctest_run_option_parser():
99 r"""Test option parser in %run.
99 r"""Test option parser in %run.
100
100
101 In [1]: %run print_argv.py
101 In [1]: %run print_argv.py
102 []
102 []
103
103
104 In [2]: %run print_argv.py print*.py
104 In [2]: %run print_argv.py print*.py
105 ['print_argv.py']
105 ['print_argv.py']
106
106
107 In [3]: %run -G print_argv.py print*.py
107 In [3]: %run -G print_argv.py print*.py
108 ['print*.py']
108 ['print*.py']
109
109
110 """
110 """
111
111
112
112
113 @dec.skip_win32
113 @dec.skip_win32
114 def doctest_run_option_parser_for_posix():
114 def doctest_run_option_parser_for_posix():
115 r"""Test option parser in %run (Linux/OSX specific).
115 r"""Test option parser in %run (Linux/OSX specific).
116
116
117 You need double quote to escape glob in POSIX systems:
117 You need double quote to escape glob in POSIX systems:
118
118
119 In [1]: %run print_argv.py print\\*.py
119 In [1]: %run print_argv.py print\\*.py
120 ['print*.py']
120 ['print*.py']
121
121
122 You can't use quote to escape glob in POSIX systems:
122 You can't use quote to escape glob in POSIX systems:
123
123
124 In [2]: %run print_argv.py 'print*.py'
124 In [2]: %run print_argv.py 'print*.py'
125 ['print_argv.py']
125 ['print_argv.py']
126
126
127 """
127 """
128
128
129
129
130 doctest_run_option_parser_for_posix.__skip_doctest__ = sys.platform == "win32"
130 doctest_run_option_parser_for_posix.__skip_doctest__ = sys.platform == "win32"
131
131
132
132
133 @dec.skip_if_not_win32
133 @dec.skip_if_not_win32
134 def doctest_run_option_parser_for_windows():
134 def doctest_run_option_parser_for_windows():
135 r"""Test option parser in %run (Windows specific).
135 r"""Test option parser in %run (Windows specific).
136
136
137 In Windows, you can't escape ``*` `by backslash:
137 In Windows, you can't escape ``*` `by backslash:
138
138
139 In [1]: %run print_argv.py print\\*.py
139 In [1]: %run print_argv.py print\\*.py
140 ['print\\\\*.py']
140 ['print\\\\*.py']
141
141
142 You can use quote to escape glob:
142 You can use quote to escape glob:
143
143
144 In [2]: %run print_argv.py 'print*.py'
144 In [2]: %run print_argv.py 'print*.py'
145 ["'print*.py'"]
145 ["'print*.py'"]
146
146
147 """
147 """
148
148
149
149
150 doctest_run_option_parser_for_windows.__skip_doctest__ = sys.platform != "win32"
150 doctest_run_option_parser_for_windows.__skip_doctest__ = sys.platform != "win32"
151
151
152
152
153 def doctest_reset_del():
153 def doctest_reset_del():
154 """Test that resetting doesn't cause errors in __del__ methods.
154 """Test that resetting doesn't cause errors in __del__ methods.
155
155
156 In [2]: class A(object):
156 In [2]: class A(object):
157 ...: def __del__(self):
157 ...: def __del__(self):
158 ...: print(str("Hi"))
158 ...: print(str("Hi"))
159 ...:
159 ...:
160
160
161 In [3]: a = A()
161 In [3]: a = A()
162
162
163 In [4]: get_ipython().reset(); import gc; x = gc.collect(0)
163 In [4]: get_ipython().reset(); import gc; x = gc.collect(0)
164 Hi
164 Hi
165
165
166 In [5]: 1+1
166 In [5]: 1+1
167 Out[5]: 2
167 Out[5]: 2
168 """
168 """
169
169
170 # For some tests, it will be handy to organize them in a class with a common
170 # For some tests, it will be handy to organize them in a class with a common
171 # setup that makes a temp file
171 # setup that makes a temp file
172
172
173 class TestMagicRunPass(tt.TempFileMixin):
173 class TestMagicRunPass(tt.TempFileMixin):
174
174
175 def setUp(self):
175 def setUp(self):
176 content = "a = [1,2,3]\nb = 1"
176 content = "a = [1,2,3]\nb = 1"
177 self.mktmp(content)
177 self.mktmp(content)
178
178
179 def run_tmpfile(self):
179 def run_tmpfile(self):
180 _ip = get_ipython()
180 _ip = get_ipython()
181 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
181 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
182 # See below and ticket https://bugs.launchpad.net/bugs/366353
182 # See below and ticket https://bugs.launchpad.net/bugs/366353
183 _ip.magic('run %s' % self.fname)
183 _ip.run_line_magic("run", self.fname)
184
184
185 def run_tmpfile_p(self):
185 def run_tmpfile_p(self):
186 _ip = get_ipython()
186 _ip = get_ipython()
187 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
187 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
188 # See below and ticket https://bugs.launchpad.net/bugs/366353
188 # See below and ticket https://bugs.launchpad.net/bugs/366353
189 _ip.magic('run -p %s' % self.fname)
189 _ip.run_line_magic("run", "-p %s" % self.fname)
190
190
191 def test_builtins_id(self):
191 def test_builtins_id(self):
192 """Check that %run doesn't damage __builtins__ """
192 """Check that %run doesn't damage __builtins__ """
193 _ip = get_ipython()
193 _ip = get_ipython()
194 # Test that the id of __builtins__ is not modified by %run
194 # Test that the id of __builtins__ is not modified by %run
195 bid1 = id(_ip.user_ns['__builtins__'])
195 bid1 = id(_ip.user_ns['__builtins__'])
196 self.run_tmpfile()
196 self.run_tmpfile()
197 bid2 = id(_ip.user_ns['__builtins__'])
197 bid2 = id(_ip.user_ns['__builtins__'])
198 assert bid1 == bid2
198 assert bid1 == bid2
199
199
200 def test_builtins_type(self):
200 def test_builtins_type(self):
201 """Check that the type of __builtins__ doesn't change with %run.
201 """Check that the type of __builtins__ doesn't change with %run.
202
202
203 However, the above could pass if __builtins__ was already modified to
203 However, the above could pass if __builtins__ was already modified to
204 be a dict (it should be a module) by a previous use of %run. So we
204 be a dict (it should be a module) by a previous use of %run. So we
205 also check explicitly that it really is a module:
205 also check explicitly that it really is a module:
206 """
206 """
207 _ip = get_ipython()
207 _ip = get_ipython()
208 self.run_tmpfile()
208 self.run_tmpfile()
209 assert type(_ip.user_ns["__builtins__"]) == type(sys)
209 assert type(_ip.user_ns["__builtins__"]) == type(sys)
210
210
211 def test_run_profile(self):
211 def test_run_profile(self):
212 """Test that the option -p, which invokes the profiler, do not
212 """Test that the option -p, which invokes the profiler, do not
213 crash by invoking execfile"""
213 crash by invoking execfile"""
214 self.run_tmpfile_p()
214 self.run_tmpfile_p()
215
215
216 def test_run_debug_twice(self):
216 def test_run_debug_twice(self):
217 # https://github.com/ipython/ipython/issues/10028
217 # https://github.com/ipython/ipython/issues/10028
218 _ip = get_ipython()
218 _ip = get_ipython()
219 with tt.fake_input(['c']):
219 with tt.fake_input(["c"]):
220 _ip.magic('run -d %s' % self.fname)
220 _ip.run_line_magic("run", "-d %s" % self.fname)
221 with tt.fake_input(['c']):
221 with tt.fake_input(["c"]):
222 _ip.magic('run -d %s' % self.fname)
222 _ip.run_line_magic("run", "-d %s" % self.fname)
223
223
224 def test_run_debug_twice_with_breakpoint(self):
224 def test_run_debug_twice_with_breakpoint(self):
225 """Make a valid python temp file."""
225 """Make a valid python temp file."""
226 _ip = get_ipython()
226 _ip = get_ipython()
227 with tt.fake_input(['b 2', 'c', 'c']):
227 with tt.fake_input(["b 2", "c", "c"]):
228 _ip.magic('run -d %s' % self.fname)
228 _ip.run_line_magic("run", "-d %s" % self.fname)
229
229
230 with tt.fake_input(['c']):
230 with tt.fake_input(["c"]):
231 with tt.AssertNotPrints('KeyError'):
231 with tt.AssertNotPrints("KeyError"):
232 _ip.magic('run -d %s' % self.fname)
232 _ip.run_line_magic("run", "-d %s" % self.fname)
233
233
234
234
235 class TestMagicRunSimple(tt.TempFileMixin):
235 class TestMagicRunSimple(tt.TempFileMixin):
236
236
237 def test_simpledef(self):
237 def test_simpledef(self):
238 """Test that simple class definitions work."""
238 """Test that simple class definitions work."""
239 src = ("class foo: pass\n"
239 src = ("class foo: pass\n"
240 "def f(): return foo()")
240 "def f(): return foo()")
241 self.mktmp(src)
241 self.mktmp(src)
242 _ip.magic("run %s" % self.fname)
242 _ip.run_line_magic("run", str(self.fname))
243 _ip.run_cell("t = isinstance(f(), foo)")
243 _ip.run_cell("t = isinstance(f(), foo)")
244 assert _ip.user_ns["t"] is True
244 assert _ip.user_ns["t"] is True
245
245
246 @pytest.mark.xfail(
246 @pytest.mark.xfail(
247 platform.python_implementation() == "PyPy",
247 platform.python_implementation() == "PyPy",
248 reason="expecting __del__ call on exit is unreliable and doesn't happen on PyPy",
248 reason="expecting __del__ call on exit is unreliable and doesn't happen on PyPy",
249 )
249 )
250 def test_obj_del(self):
250 def test_obj_del(self):
251 """Test that object's __del__ methods are called on exit."""
251 """Test that object's __del__ methods are called on exit."""
252 src = ("class A(object):\n"
252 src = ("class A(object):\n"
253 " def __del__(self):\n"
253 " def __del__(self):\n"
254 " print('object A deleted')\n"
254 " print('object A deleted')\n"
255 "a = A()\n")
255 "a = A()\n")
256 self.mktmp(src)
256 self.mktmp(src)
257 err = None
257 err = None
258 tt.ipexec_validate(self.fname, 'object A deleted', err)
258 tt.ipexec_validate(self.fname, 'object A deleted', err)
259
259
260 def test_aggressive_namespace_cleanup(self):
260 def test_aggressive_namespace_cleanup(self):
261 """Test that namespace cleanup is not too aggressive GH-238
261 """Test that namespace cleanup is not too aggressive GH-238
262
262
263 Returning from another run magic deletes the namespace"""
263 Returning from another run magic deletes the namespace"""
264 # see ticket https://github.com/ipython/ipython/issues/238
264 # see ticket https://github.com/ipython/ipython/issues/238
265
265
266 with tt.TempFileMixin() as empty:
266 with tt.TempFileMixin() as empty:
267 empty.mktmp("")
267 empty.mktmp("")
268 # On Windows, the filename will have \users in it, so we need to use the
268 # On Windows, the filename will have \users in it, so we need to use the
269 # repr so that the \u becomes \\u.
269 # repr so that the \u becomes \\u.
270 src = (
270 src = (
271 "ip = get_ipython()\n"
271 "ip = get_ipython()\n"
272 "for i in range(5):\n"
272 "for i in range(5):\n"
273 " try:\n"
273 " try:\n"
274 " ip.magic(%r)\n"
274 " ip.magic(%r)\n"
275 " except NameError as e:\n"
275 " except NameError as e:\n"
276 " print(i)\n"
276 " print(i)\n"
277 " break\n" % ("run " + empty.fname)
277 " break\n" % ("run " + empty.fname)
278 )
278 )
279 self.mktmp(src)
279 self.mktmp(src)
280 _ip.magic("run %s" % self.fname)
280 _ip.run_line_magic("run", str(self.fname))
281 _ip.run_cell("ip == get_ipython()")
281 _ip.run_cell("ip == get_ipython()")
282 assert _ip.user_ns["i"] == 4
282 assert _ip.user_ns["i"] == 4
283
283
284 def test_run_second(self):
284 def test_run_second(self):
285 """Test that running a second file doesn't clobber the first, gh-3547"""
285 """Test that running a second file doesn't clobber the first, gh-3547"""
286 self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n")
286 self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n")
287
287
288 with tt.TempFileMixin() as empty:
288 with tt.TempFileMixin() as empty:
289 empty.mktmp("")
289 empty.mktmp("")
290
290
291 _ip.magic("run %s" % self.fname)
291 _ip.run_line_magic("run", self.fname)
292 _ip.magic("run %s" % empty.fname)
292 _ip.run_line_magic("run", empty.fname)
293 assert _ip.user_ns["afunc"]() == 1
293 assert _ip.user_ns["afunc"]() == 1
294
294
295 def test_tclass(self):
295 def test_tclass(self):
296 mydir = os.path.dirname(__file__)
296 mydir = os.path.dirname(__file__)
297 tc = os.path.join(mydir, "tclass")
297 tc = os.path.join(mydir, "tclass")
298 src = f"""\
298 src = f"""\
299 import gc
299 import gc
300 %run "{tc}" C-first
300 %run "{tc}" C-first
301 gc.collect(0)
301 gc.collect(0)
302 %run "{tc}" C-second
302 %run "{tc}" C-second
303 gc.collect(0)
303 gc.collect(0)
304 %run "{tc}" C-third
304 %run "{tc}" C-third
305 gc.collect(0)
305 gc.collect(0)
306 %reset -f
306 %reset -f
307 """
307 """
308 self.mktmp(src, ".ipy")
308 self.mktmp(src, ".ipy")
309 out = """\
309 out = """\
310 ARGV 1-: ['C-first']
310 ARGV 1-: ['C-first']
311 ARGV 1-: ['C-second']
311 ARGV 1-: ['C-second']
312 tclass.py: deleting object: C-first
312 tclass.py: deleting object: C-first
313 ARGV 1-: ['C-third']
313 ARGV 1-: ['C-third']
314 tclass.py: deleting object: C-second
314 tclass.py: deleting object: C-second
315 tclass.py: deleting object: C-third
315 tclass.py: deleting object: C-third
316 """
316 """
317 err = None
317 err = None
318 tt.ipexec_validate(self.fname, out, err)
318 tt.ipexec_validate(self.fname, out, err)
319
319
320 def test_run_i_after_reset(self):
320 def test_run_i_after_reset(self):
321 """Check that %run -i still works after %reset (gh-693)"""
321 """Check that %run -i still works after %reset (gh-693)"""
322 src = "yy = zz\n"
322 src = "yy = zz\n"
323 self.mktmp(src)
323 self.mktmp(src)
324 _ip.run_cell("zz = 23")
324 _ip.run_cell("zz = 23")
325 try:
325 try:
326 _ip.magic("run -i %s" % self.fname)
326 _ip.run_line_magic("run", "-i %s" % self.fname)
327 assert _ip.user_ns["yy"] == 23
327 assert _ip.user_ns["yy"] == 23
328 finally:
328 finally:
329 _ip.magic('reset -f')
329 _ip.run_line_magic("reset", "-f")
330
330
331 _ip.run_cell("zz = 23")
331 _ip.run_cell("zz = 23")
332 try:
332 try:
333 _ip.magic("run -i %s" % self.fname)
333 _ip.run_line_magic("run", "-i %s" % self.fname)
334 assert _ip.user_ns["yy"] == 23
334 assert _ip.user_ns["yy"] == 23
335 finally:
335 finally:
336 _ip.magic('reset -f')
336 _ip.run_line_magic("reset", "-f")
337
337
338 def test_unicode(self):
338 def test_unicode(self):
339 """Check that files in odd encodings are accepted."""
339 """Check that files in odd encodings are accepted."""
340 mydir = os.path.dirname(__file__)
340 mydir = os.path.dirname(__file__)
341 na = os.path.join(mydir, 'nonascii.py')
341 na = os.path.join(mydir, "nonascii.py")
342 _ip.magic('run "%s"' % na)
342 _ip.magic('run "%s"' % na)
343 assert _ip.user_ns["u"] == "Ўт№Ф"
343 assert _ip.user_ns["u"] == "Ўт№Ф"
344
344
345 def test_run_py_file_attribute(self):
345 def test_run_py_file_attribute(self):
346 """Test handling of `__file__` attribute in `%run <file>.py`."""
346 """Test handling of `__file__` attribute in `%run <file>.py`."""
347 src = "t = __file__\n"
347 src = "t = __file__\n"
348 self.mktmp(src)
348 self.mktmp(src)
349 _missing = object()
349 _missing = object()
350 file1 = _ip.user_ns.get('__file__', _missing)
350 file1 = _ip.user_ns.get("__file__", _missing)
351 _ip.magic('run %s' % self.fname)
351 _ip.run_line_magic("run", self.fname)
352 file2 = _ip.user_ns.get('__file__', _missing)
352 file2 = _ip.user_ns.get("__file__", _missing)
353
353
354 # Check that __file__ was equal to the filename in the script's
354 # Check that __file__ was equal to the filename in the script's
355 # namespace.
355 # namespace.
356 assert _ip.user_ns["t"] == self.fname
356 assert _ip.user_ns["t"] == self.fname
357
357
358 # Check that __file__ was not leaked back into user_ns.
358 # Check that __file__ was not leaked back into user_ns.
359 assert file1 == file2
359 assert file1 == file2
360
360
361 def test_run_ipy_file_attribute(self):
361 def test_run_ipy_file_attribute(self):
362 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
362 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
363 src = "t = __file__\n"
363 src = "t = __file__\n"
364 self.mktmp(src, ext='.ipy')
364 self.mktmp(src, ext='.ipy')
365 _missing = object()
365 _missing = object()
366 file1 = _ip.user_ns.get('__file__', _missing)
366 file1 = _ip.user_ns.get("__file__", _missing)
367 _ip.magic('run %s' % self.fname)
367 _ip.run_line_magic("run", self.fname)
368 file2 = _ip.user_ns.get('__file__', _missing)
368 file2 = _ip.user_ns.get("__file__", _missing)
369
369
370 # Check that __file__ was equal to the filename in the script's
370 # Check that __file__ was equal to the filename in the script's
371 # namespace.
371 # namespace.
372 assert _ip.user_ns["t"] == self.fname
372 assert _ip.user_ns["t"] == self.fname
373
373
374 # Check that __file__ was not leaked back into user_ns.
374 # Check that __file__ was not leaked back into user_ns.
375 assert file1 == file2
375 assert file1 == file2
376
376
377 def test_run_formatting(self):
377 def test_run_formatting(self):
378 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
378 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
379 src = "pass"
379 src = "pass"
380 self.mktmp(src)
380 self.mktmp(src)
381 _ip.magic('run -t -N 1 %s' % self.fname)
381 _ip.run_line_magic("run", "-t -N 1 %s" % self.fname)
382 _ip.magic('run -t -N 10 %s' % self.fname)
382 _ip.run_line_magic("run", "-t -N 10 %s" % self.fname)
383
383
384 def test_ignore_sys_exit(self):
384 def test_ignore_sys_exit(self):
385 """Test the -e option to ignore sys.exit()"""
385 """Test the -e option to ignore sys.exit()"""
386 src = "import sys; sys.exit(1)"
386 src = "import sys; sys.exit(1)"
387 self.mktmp(src)
387 self.mktmp(src)
388 with tt.AssertPrints('SystemExit'):
388 with tt.AssertPrints("SystemExit"):
389 _ip.magic('run %s' % self.fname)
389 _ip.run_line_magic("run", self.fname)
390
390
391 with tt.AssertNotPrints('SystemExit'):
391 with tt.AssertNotPrints("SystemExit"):
392 _ip.magic('run -e %s' % self.fname)
392 _ip.run_line_magic("run", "-e %s" % self.fname)
393
393
394 def test_run_nb(self):
394 def test_run_nb(self):
395 """Test %run notebook.ipynb"""
395 """Test %run notebook.ipynb"""
396 pytest.importorskip("nbformat")
396 pytest.importorskip("nbformat")
397 from nbformat import v4, writes
397 from nbformat import v4, writes
398 nb = v4.new_notebook(
398 nb = v4.new_notebook(
399 cells=[
399 cells=[
400 v4.new_markdown_cell("The Ultimate Question of Everything"),
400 v4.new_markdown_cell("The Ultimate Question of Everything"),
401 v4.new_code_cell("answer=42")
401 v4.new_code_cell("answer=42")
402 ]
402 ]
403 )
403 )
404 src = writes(nb, version=4)
404 src = writes(nb, version=4)
405 self.mktmp(src, ext='.ipynb')
405 self.mktmp(src, ext='.ipynb')
406
406
407 _ip.magic("run %s" % self.fname)
407 _ip.run_line_magic("run", self.fname)
408
408
409 assert _ip.user_ns["answer"] == 42
409 assert _ip.user_ns["answer"] == 42
410
410
411 def test_run_nb_error(self):
411 def test_run_nb_error(self):
412 """Test %run notebook.ipynb error"""
412 """Test %run notebook.ipynb error"""
413 pytest.importorskip("nbformat")
413 pytest.importorskip("nbformat")
414 from nbformat import v4, writes
414 from nbformat import v4, writes
415
415
416 # %run when a file name isn't provided
416 # %run when a file name isn't provided
417 pytest.raises(Exception, _ip.magic, "run")
417 pytest.raises(Exception, _ip.magic, "run")
418
418
419 # %run when a file doesn't exist
419 # %run when a file doesn't exist
420 pytest.raises(Exception, _ip.magic, "run foobar.ipynb")
420 pytest.raises(Exception, _ip.magic, "run foobar.ipynb")
421
421
422 # %run on a notebook with an error
422 # %run on a notebook with an error
423 nb = v4.new_notebook(
423 nb = v4.new_notebook(
424 cells=[
424 cells=[
425 v4.new_code_cell("0/0")
425 v4.new_code_cell("0/0")
426 ]
426 ]
427 )
427 )
428 src = writes(nb, version=4)
428 src = writes(nb, version=4)
429 self.mktmp(src, ext='.ipynb')
429 self.mktmp(src, ext='.ipynb')
430 pytest.raises(Exception, _ip.magic, "run %s" % self.fname)
430 pytest.raises(Exception, _ip.magic, "run %s" % self.fname)
431
431
432 def test_file_options(self):
432 def test_file_options(self):
433 src = ('import sys\n'
433 src = ('import sys\n'
434 'a = " ".join(sys.argv[1:])\n')
434 'a = " ".join(sys.argv[1:])\n')
435 self.mktmp(src)
435 self.mktmp(src)
436 test_opts = "-x 3 --verbose"
436 test_opts = "-x 3 --verbose"
437 _ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts))
437 _ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts))
438 assert _ip.user_ns["a"] == test_opts
438 assert _ip.user_ns["a"] == test_opts
439
439
440
440
441 class TestMagicRunWithPackage(unittest.TestCase):
441 class TestMagicRunWithPackage(unittest.TestCase):
442
442
443 def writefile(self, name, content):
443 def writefile(self, name, content):
444 path = os.path.join(self.tempdir.name, name)
444 path = os.path.join(self.tempdir.name, name)
445 d = os.path.dirname(path)
445 d = os.path.dirname(path)
446 if not os.path.isdir(d):
446 if not os.path.isdir(d):
447 os.makedirs(d)
447 os.makedirs(d)
448 with open(path, "w", encoding="utf-8") as f:
448 with open(path, "w", encoding="utf-8") as f:
449 f.write(textwrap.dedent(content))
449 f.write(textwrap.dedent(content))
450
450
451 def setUp(self):
451 def setUp(self):
452 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
452 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
453 """Temporary (probably) valid python package name."""
453 """Temporary (probably) valid python package name."""
454
454
455 self.value = int(random.random() * 10000)
455 self.value = int(random.random() * 10000)
456
456
457 self.tempdir = TemporaryDirectory()
457 self.tempdir = TemporaryDirectory()
458 self.__orig_cwd = os.getcwd()
458 self.__orig_cwd = os.getcwd()
459 sys.path.insert(0, self.tempdir.name)
459 sys.path.insert(0, self.tempdir.name)
460
460
461 self.writefile(os.path.join(package, '__init__.py'), '')
461 self.writefile(os.path.join(package, '__init__.py'), '')
462 self.writefile(os.path.join(package, 'sub.py'), """
462 self.writefile(os.path.join(package, 'sub.py'), """
463 x = {0!r}
463 x = {0!r}
464 """.format(self.value))
464 """.format(self.value))
465 self.writefile(os.path.join(package, 'relative.py'), """
465 self.writefile(os.path.join(package, 'relative.py'), """
466 from .sub import x
466 from .sub import x
467 """)
467 """)
468 self.writefile(os.path.join(package, 'absolute.py'), """
468 self.writefile(os.path.join(package, 'absolute.py'), """
469 from {0}.sub import x
469 from {0}.sub import x
470 """.format(package))
470 """.format(package))
471 self.writefile(os.path.join(package, 'args.py'), """
471 self.writefile(os.path.join(package, 'args.py'), """
472 import sys
472 import sys
473 a = " ".join(sys.argv[1:])
473 a = " ".join(sys.argv[1:])
474 """.format(package))
474 """.format(package))
475
475
476 def tearDown(self):
476 def tearDown(self):
477 os.chdir(self.__orig_cwd)
477 os.chdir(self.__orig_cwd)
478 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
478 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
479 self.tempdir.cleanup()
479 self.tempdir.cleanup()
480
480
481 def check_run_submodule(self, submodule, opts=''):
481 def check_run_submodule(self, submodule, opts=""):
482 _ip.user_ns.pop('x', None)
482 _ip.user_ns.pop("x", None)
483 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
483 _ip.run_line_magic(
484 self.assertEqual(_ip.user_ns['x'], self.value,
484 "run", "{2} -m {0}.{1}".format(self.package, submodule, opts)
485 'Variable `x` is not loaded from module `{0}`.'
485 )
486 .format(submodule))
486 self.assertEqual(
487 _ip.user_ns["x"],
488 self.value,
489 "Variable `x` is not loaded from module `{0}`.".format(submodule),
490 )
487
491
488 def test_run_submodule_with_absolute_import(self):
492 def test_run_submodule_with_absolute_import(self):
489 self.check_run_submodule('absolute')
493 self.check_run_submodule('absolute')
490
494
491 def test_run_submodule_with_relative_import(self):
495 def test_run_submodule_with_relative_import(self):
492 """Run submodule that has a relative import statement (#2727)."""
496 """Run submodule that has a relative import statement (#2727)."""
493 self.check_run_submodule('relative')
497 self.check_run_submodule('relative')
494
498
495 def test_prun_submodule_with_absolute_import(self):
499 def test_prun_submodule_with_absolute_import(self):
496 self.check_run_submodule('absolute', '-p')
500 self.check_run_submodule('absolute', '-p')
497
501
498 def test_prun_submodule_with_relative_import(self):
502 def test_prun_submodule_with_relative_import(self):
499 self.check_run_submodule('relative', '-p')
503 self.check_run_submodule('relative', '-p')
500
504
501 def with_fake_debugger(func):
505 def with_fake_debugger(func):
502 @functools.wraps(func)
506 @functools.wraps(func)
503 def wrapper(*args, **kwds):
507 def wrapper(*args, **kwds):
504 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
508 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
505 return func(*args, **kwds)
509 return func(*args, **kwds)
506 return wrapper
510 return wrapper
507
511
508 @with_fake_debugger
512 @with_fake_debugger
509 def test_debug_run_submodule_with_absolute_import(self):
513 def test_debug_run_submodule_with_absolute_import(self):
510 self.check_run_submodule('absolute', '-d')
514 self.check_run_submodule('absolute', '-d')
511
515
512 @with_fake_debugger
516 @with_fake_debugger
513 def test_debug_run_submodule_with_relative_import(self):
517 def test_debug_run_submodule_with_relative_import(self):
514 self.check_run_submodule('relative', '-d')
518 self.check_run_submodule('relative', '-d')
515
519
516 def test_module_options(self):
520 def test_module_options(self):
517 _ip.user_ns.pop("a", None)
521 _ip.user_ns.pop("a", None)
518 test_opts = "-x abc -m test"
522 test_opts = "-x abc -m test"
519 _ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts))
523 _ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts))
520 assert _ip.user_ns["a"] == test_opts
524 assert _ip.user_ns["a"] == test_opts
521
525
522 def test_module_options_with_separator(self):
526 def test_module_options_with_separator(self):
523 _ip.user_ns.pop("a", None)
527 _ip.user_ns.pop("a", None)
524 test_opts = "-x abc -m test"
528 test_opts = "-x abc -m test"
525 _ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts))
529 _ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts))
526 assert _ip.user_ns["a"] == test_opts
530 assert _ip.user_ns["a"] == test_opts
527
531
528
532
529 def test_run__name__():
533 def test_run__name__():
530 with TemporaryDirectory() as td:
534 with TemporaryDirectory() as td:
531 path = pjoin(td, "foo.py")
535 path = pjoin(td, "foo.py")
532 with open(path, "w", encoding="utf-8") as f:
536 with open(path, "w", encoding="utf-8") as f:
533 f.write("q = __name__")
537 f.write("q = __name__")
534
538
535 _ip.user_ns.pop("q", None)
539 _ip.user_ns.pop("q", None)
536 _ip.magic("run {}".format(path))
540 _ip.run_line_magic("run", "{}".format(path))
537 assert _ip.user_ns.pop("q") == "__main__"
541 assert _ip.user_ns.pop("q") == "__main__"
538
542
539 _ip.magic("run -n {}".format(path))
543 _ip.run_line_magic("run", "-n {}".format(path))
540 assert _ip.user_ns.pop("q") == "foo"
544 assert _ip.user_ns.pop("q") == "foo"
541
545
542 try:
546 try:
543 _ip.magic("run -i -n {}".format(path))
547 _ip.run_line_magic("run", "-i -n {}".format(path))
544 assert _ip.user_ns.pop("q") == "foo"
548 assert _ip.user_ns.pop("q") == "foo"
545 finally:
549 finally:
546 _ip.magic('reset -f')
550 _ip.run_line_magic("reset", "-f")
547
551
548
552
549 def test_run_tb():
553 def test_run_tb():
550 """Test traceback offset in %run"""
554 """Test traceback offset in %run"""
551 with TemporaryDirectory() as td:
555 with TemporaryDirectory() as td:
552 path = pjoin(td, "foo.py")
556 path = pjoin(td, "foo.py")
553 with open(path, "w", encoding="utf-8") as f:
557 with open(path, "w", encoding="utf-8") as f:
554 f.write(
558 f.write(
555 "\n".join(
559 "\n".join(
556 [
560 [
557 "def foo():",
561 "def foo():",
558 " return bar()",
562 " return bar()",
559 "def bar():",
563 "def bar():",
560 " raise RuntimeError('hello!')",
564 " raise RuntimeError('hello!')",
561 "foo()",
565 "foo()",
562 ]
566 ]
563 )
567 )
564 )
568 )
565 with capture_output() as io:
569 with capture_output() as io:
566 _ip.magic('run {}'.format(path))
570 _ip.run_line_magic("run", "{}".format(path))
567 out = io.stdout
571 out = io.stdout
568 assert "execfile" not in out
572 assert "execfile" not in out
569 assert "RuntimeError" in out
573 assert "RuntimeError" in out
570 assert out.count("---->") == 3
574 assert out.count("---->") == 3
571 del ip.user_ns['bar']
575 del ip.user_ns['bar']
572 del ip.user_ns['foo']
576 del ip.user_ns['foo']
573
577
574
578
575 def test_multiprocessing_run():
579 def test_multiprocessing_run():
576 """Set we can run mutiprocesgin without messing up up main namespace
580 """Set we can run mutiprocesgin without messing up up main namespace
577
581
578 Note that import `nose.tools as nt` mdify the value s
582 Note that import `nose.tools as nt` mdify the value s
579 sys.module['__mp_main__'] so we need to temporarily set it to None to test
583 sys.module['__mp_main__'] so we need to temporarily set it to None to test
580 the issue.
584 the issue.
581 """
585 """
582 with TemporaryDirectory() as td:
586 with TemporaryDirectory() as td:
583 mpm = sys.modules.get('__mp_main__')
587 mpm = sys.modules.get('__mp_main__')
584 sys.modules['__mp_main__'] = None
588 sys.modules['__mp_main__'] = None
585 try:
589 try:
586 path = pjoin(td, "test.py")
590 path = pjoin(td, "test.py")
587 with open(path, "w", encoding="utf-8") as f:
591 with open(path, "w", encoding="utf-8") as f:
588 f.write("import multiprocessing\nprint('hoy')")
592 f.write("import multiprocessing\nprint('hoy')")
589 with capture_output() as io:
593 with capture_output() as io:
590 _ip.run_line_magic('run', path)
594 _ip.run_line_magic('run', path)
591 _ip.run_cell("i_m_undefined")
595 _ip.run_cell("i_m_undefined")
592 out = io.stdout
596 out = io.stdout
593 assert "hoy" in out
597 assert "hoy" in out
594 assert "AttributeError" not in out
598 assert "AttributeError" not in out
595 assert "NameError" in out
599 assert "NameError" in out
596 assert out.count("---->") == 1
600 assert out.count("---->") == 1
597 except:
601 except:
598 raise
602 raise
599 finally:
603 finally:
600 sys.modules['__mp_main__'] = mpm
604 sys.modules['__mp_main__'] = mpm
601
605
602
606
603 def test_script_tb():
607 def test_script_tb():
604 """Test traceback offset in `ipython script.py`"""
608 """Test traceback offset in `ipython script.py`"""
605 with TemporaryDirectory() as td:
609 with TemporaryDirectory() as td:
606 path = pjoin(td, "foo.py")
610 path = pjoin(td, "foo.py")
607 with open(path, "w", encoding="utf-8") as f:
611 with open(path, "w", encoding="utf-8") as f:
608 f.write(
612 f.write(
609 "\n".join(
613 "\n".join(
610 [
614 [
611 "def foo():",
615 "def foo():",
612 " return bar()",
616 " return bar()",
613 "def bar():",
617 "def bar():",
614 " raise RuntimeError('hello!')",
618 " raise RuntimeError('hello!')",
615 "foo()",
619 "foo()",
616 ]
620 ]
617 )
621 )
618 )
622 )
619 out, err = tt.ipexec(path)
623 out, err = tt.ipexec(path)
620 assert "execfile" not in out
624 assert "execfile" not in out
621 assert "RuntimeError" in out
625 assert "RuntimeError" in out
622 assert out.count("---->") == 3
626 assert out.count("---->") == 3
@@ -1,1201 +1,1201 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Verbose and colourful traceback formatting.
3 Verbose and colourful traceback formatting.
4
4
5 **ColorTB**
5 **ColorTB**
6
6
7 I've always found it a bit hard to visually parse tracebacks in Python. The
7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 ColorTB class is a solution to that problem. It colors the different parts of a
8 ColorTB class is a solution to that problem. It colors the different parts of a
9 traceback in a manner similar to what you would expect from a syntax-highlighting
9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 text editor.
10 text editor.
11
11
12 Installation instructions for ColorTB::
12 Installation instructions for ColorTB::
13
13
14 import sys,ultratb
14 import sys,ultratb
15 sys.excepthook = ultratb.ColorTB()
15 sys.excepthook = ultratb.ColorTB()
16
16
17 **VerboseTB**
17 **VerboseTB**
18
18
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 and intended it for CGI programmers, but why should they have all the fun? I
21 and intended it for CGI programmers, but why should they have all the fun? I
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 but kind of neat, and maybe useful for long-running programs that you believe
23 but kind of neat, and maybe useful for long-running programs that you believe
24 are bug-free. If a crash *does* occur in that type of program you want details.
24 are bug-free. If a crash *does* occur in that type of program you want details.
25 Give it a shot--you'll love it or you'll hate it.
25 Give it a shot--you'll love it or you'll hate it.
26
26
27 .. note::
27 .. note::
28
28
29 The Verbose mode prints the variables currently visible where the exception
29 The Verbose mode prints the variables currently visible where the exception
30 happened (shortening their strings if too long). This can potentially be
30 happened (shortening their strings if too long). This can potentially be
31 very slow, if you happen to have a huge data structure whose string
31 very slow, if you happen to have a huge data structure whose string
32 representation is complex to compute. Your computer may appear to freeze for
32 representation is complex to compute. Your computer may appear to freeze for
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 with Ctrl-C (maybe hitting it more than once).
34 with Ctrl-C (maybe hitting it more than once).
35
35
36 If you encounter this kind of situation often, you may want to use the
36 If you encounter this kind of situation often, you may want to use the
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 variables (but otherwise includes the information and context given by
38 variables (but otherwise includes the information and context given by
39 Verbose).
39 Verbose).
40
40
41 .. note::
41 .. note::
42
42
43 The verbose mode print all variables in the stack, which means it can
43 The verbose mode print all variables in the stack, which means it can
44 potentially leak sensitive information like access keys, or unencrypted
44 potentially leak sensitive information like access keys, or unencrypted
45 password.
45 password.
46
46
47 Installation instructions for VerboseTB::
47 Installation instructions for VerboseTB::
48
48
49 import sys,ultratb
49 import sys,ultratb
50 sys.excepthook = ultratb.VerboseTB()
50 sys.excepthook = ultratb.VerboseTB()
51
51
52 Note: Much of the code in this module was lifted verbatim from the standard
52 Note: Much of the code in this module was lifted verbatim from the standard
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54
54
55 Color schemes
55 Color schemes
56 -------------
56 -------------
57
57
58 The colors are defined in the class TBTools through the use of the
58 The colors are defined in the class TBTools through the use of the
59 ColorSchemeTable class. Currently the following exist:
59 ColorSchemeTable class. Currently the following exist:
60
60
61 - NoColor: allows all of this module to be used in any terminal (the color
61 - NoColor: allows all of this module to be used in any terminal (the color
62 escapes are just dummy blank strings).
62 escapes are just dummy blank strings).
63
63
64 - Linux: is meant to look good in a terminal like the Linux console (black
64 - Linux: is meant to look good in a terminal like the Linux console (black
65 or very dark background).
65 or very dark background).
66
66
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 in light background terminals.
68 in light background terminals.
69
69
70 - Neutral: a neutral color scheme that should be readable on both light and
70 - Neutral: a neutral color scheme that should be readable on both light and
71 dark background
71 dark background
72
72
73 You can implement other color schemes easily, the syntax is fairly
73 You can implement other color schemes easily, the syntax is fairly
74 self-explanatory. Please send back new schemes you develop to the author for
74 self-explanatory. Please send back new schemes you develop to the author for
75 possible inclusion in future releases.
75 possible inclusion in future releases.
76
76
77 Inheritance diagram:
77 Inheritance diagram:
78
78
79 .. inheritance-diagram:: IPython.core.ultratb
79 .. inheritance-diagram:: IPython.core.ultratb
80 :parts: 3
80 :parts: 3
81 """
81 """
82
82
83 #*****************************************************************************
83 #*****************************************************************************
84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
86 #
86 #
87 # Distributed under the terms of the BSD License. The full license is in
87 # Distributed under the terms of the BSD License. The full license is in
88 # the file COPYING, distributed as part of this software.
88 # the file COPYING, distributed as part of this software.
89 #*****************************************************************************
89 #*****************************************************************************
90
90
91
91
92 import inspect
92 import inspect
93 import linecache
93 import linecache
94 import pydoc
94 import pydoc
95 import sys
95 import sys
96 import time
96 import time
97 import traceback
97 import traceback
98 from types import TracebackType
98 from types import TracebackType
99 from typing import Tuple, List, Any, Optional
99 from typing import Tuple, List, Any, Optional
100
100
101 import stack_data
101 import stack_data
102 from pygments.formatters.terminal256 import Terminal256Formatter
102 from pygments.formatters.terminal256 import Terminal256Formatter
103 from pygments.styles import get_style_by_name
103 from pygments.styles import get_style_by_name
104
104
105 # IPython's own modules
105 # IPython's own modules
106 from IPython import get_ipython
106 from IPython import get_ipython
107 from IPython.core import debugger
107 from IPython.core import debugger
108 from IPython.core.display_trap import DisplayTrap
108 from IPython.core.display_trap import DisplayTrap
109 from IPython.core.excolors import exception_colors
109 from IPython.core.excolors import exception_colors
110 from IPython.utils import path as util_path
110 from IPython.utils import path as util_path
111 from IPython.utils import py3compat
111 from IPython.utils import py3compat
112 from IPython.utils.terminal import get_terminal_size
112 from IPython.utils.terminal import get_terminal_size
113
113
114 import IPython.utils.colorable as colorable
114 import IPython.utils.colorable as colorable
115
115
116 # Globals
116 # Globals
117 # amount of space to put line numbers before verbose tracebacks
117 # amount of space to put line numbers before verbose tracebacks
118 INDENT_SIZE = 8
118 INDENT_SIZE = 8
119
119
120 # Default color scheme. This is used, for example, by the traceback
120 # Default color scheme. This is used, for example, by the traceback
121 # formatter. When running in an actual IPython instance, the user's rc.colors
121 # formatter. When running in an actual IPython instance, the user's rc.colors
122 # value is used, but having a module global makes this functionality available
122 # value is used, but having a module global makes this functionality available
123 # to users of ultratb who are NOT running inside ipython.
123 # to users of ultratb who are NOT running inside ipython.
124 DEFAULT_SCHEME = 'NoColor'
124 DEFAULT_SCHEME = 'NoColor'
125
125
126 # ---------------------------------------------------------------------------
126 # ---------------------------------------------------------------------------
127 # Code begins
127 # Code begins
128
128
129 # Helper function -- largely belongs to VerboseTB, but we need the same
129 # Helper function -- largely belongs to VerboseTB, but we need the same
130 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
130 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
131 # can be recognized properly by ipython.el's py-traceback-line-re
131 # can be recognized properly by ipython.el's py-traceback-line-re
132 # (SyntaxErrors have to be treated specially because they have no traceback)
132 # (SyntaxErrors have to be treated specially because they have no traceback)
133
133
134
134
135 def _format_traceback_lines(lines, Colors, has_colors: bool, lvals):
135 def _format_traceback_lines(lines, Colors, has_colors: bool, lvals):
136 """
136 """
137 Format tracebacks lines with pointing arrow, leading numbers...
137 Format tracebacks lines with pointing arrow, leading numbers...
138
138
139 Parameters
139 Parameters
140 ----------
140 ----------
141 lines : list[Line]
141 lines : list[Line]
142 Colors
142 Colors
143 ColorScheme used.
143 ColorScheme used.
144 lvals : str
144 lvals : str
145 Values of local variables, already colored, to inject just after the error line.
145 Values of local variables, already colored, to inject just after the error line.
146 """
146 """
147 numbers_width = INDENT_SIZE - 1
147 numbers_width = INDENT_SIZE - 1
148 res = []
148 res = []
149
149
150 for stack_line in lines:
150 for stack_line in lines:
151 if stack_line is stack_data.LINE_GAP:
151 if stack_line is stack_data.LINE_GAP:
152 res.append('%s (...)%s\n' % (Colors.linenoEm, Colors.Normal))
152 res.append('%s (...)%s\n' % (Colors.linenoEm, Colors.Normal))
153 continue
153 continue
154
154
155 line = stack_line.render(pygmented=has_colors).rstrip('\n') + '\n'
155 line = stack_line.render(pygmented=has_colors).rstrip('\n') + '\n'
156 lineno = stack_line.lineno
156 lineno = stack_line.lineno
157 if stack_line.is_current:
157 if stack_line.is_current:
158 # This is the line with the error
158 # This is the line with the error
159 pad = numbers_width - len(str(lineno))
159 pad = numbers_width - len(str(lineno))
160 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
160 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
161 start_color = Colors.linenoEm
161 start_color = Colors.linenoEm
162 else:
162 else:
163 num = '%*s' % (numbers_width, lineno)
163 num = '%*s' % (numbers_width, lineno)
164 start_color = Colors.lineno
164 start_color = Colors.lineno
165
165
166 line = '%s%s%s %s' % (start_color, num, Colors.Normal, line)
166 line = '%s%s%s %s' % (start_color, num, Colors.Normal, line)
167
167
168 res.append(line)
168 res.append(line)
169 if lvals and stack_line.is_current:
169 if lvals and stack_line.is_current:
170 res.append(lvals + '\n')
170 res.append(lvals + '\n')
171 return res
171 return res
172
172
173
173
174 def _format_filename(file, ColorFilename, ColorNormal, *, lineno=None):
174 def _format_filename(file, ColorFilename, ColorNormal, *, lineno=None):
175 """
175 """
176 Format filename lines with `In [n]` if it's the nth code cell or `File *.py` if it's a module.
176 Format filename lines with `In [n]` if it's the nth code cell or `File *.py` if it's a module.
177
177
178 Parameters
178 Parameters
179 ----------
179 ----------
180 file : str
180 file : str
181 ColorFilename
181 ColorFilename
182 ColorScheme's filename coloring to be used.
182 ColorScheme's filename coloring to be used.
183 ColorNormal
183 ColorNormal
184 ColorScheme's normal coloring to be used.
184 ColorScheme's normal coloring to be used.
185 """
185 """
186 ipinst = get_ipython()
186 ipinst = get_ipython()
187
187
188 if ipinst is not None and file in ipinst.compile._filename_map:
188 if ipinst is not None and file in ipinst.compile._filename_map:
189 file = "[%s]" % ipinst.compile._filename_map[file]
189 file = "[%s]" % ipinst.compile._filename_map[file]
190 if lineno is None:
190 if lineno is None:
191 tpl_link = f"Cell {ColorFilename}In {{file}}{ColorNormal}"
191 tpl_link = f"Cell {ColorFilename}In {{file}}{ColorNormal}"
192 else:
192 else:
193 tpl_link = f"Cell {ColorFilename}In {{file}}, line {{lineno}}{ColorNormal}"
193 tpl_link = f"Cell {ColorFilename}In {{file}}, line {{lineno}}{ColorNormal}"
194 else:
194 else:
195 file = util_path.compress_user(
195 file = util_path.compress_user(
196 py3compat.cast_unicode(file, util_path.fs_encoding)
196 py3compat.cast_unicode(file, util_path.fs_encoding)
197 )
197 )
198 if lineno is None:
198 if lineno is None:
199 tpl_link = f"File {ColorFilename}{{file}}{ColorNormal}"
199 tpl_link = f"File {ColorFilename}{{file}}{ColorNormal}"
200 else:
200 else:
201 tpl_link = f"File {ColorFilename}{{file}}:{{lineno}}{ColorNormal}"
201 tpl_link = f"File {ColorFilename}{{file}}:{{lineno}}{ColorNormal}"
202
202
203 return tpl_link.format(file=file, lineno=lineno)
203 return tpl_link.format(file=file, lineno=lineno)
204
204
205 #---------------------------------------------------------------------------
205 #---------------------------------------------------------------------------
206 # Module classes
206 # Module classes
207 class TBTools(colorable.Colorable):
207 class TBTools(colorable.Colorable):
208 """Basic tools used by all traceback printer classes."""
208 """Basic tools used by all traceback printer classes."""
209
209
210 # Number of frames to skip when reporting tracebacks
210 # Number of frames to skip when reporting tracebacks
211 tb_offset = 0
211 tb_offset = 0
212
212
213 def __init__(
213 def __init__(
214 self,
214 self,
215 color_scheme="NoColor",
215 color_scheme="NoColor",
216 call_pdb=False,
216 call_pdb=False,
217 ostream=None,
217 ostream=None,
218 parent=None,
218 parent=None,
219 config=None,
219 config=None,
220 *,
220 *,
221 debugger_cls=None,
221 debugger_cls=None,
222 ):
222 ):
223 # Whether to call the interactive pdb debugger after printing
223 # Whether to call the interactive pdb debugger after printing
224 # tracebacks or not
224 # tracebacks or not
225 super(TBTools, self).__init__(parent=parent, config=config)
225 super(TBTools, self).__init__(parent=parent, config=config)
226 self.call_pdb = call_pdb
226 self.call_pdb = call_pdb
227
227
228 # Output stream to write to. Note that we store the original value in
228 # Output stream to write to. Note that we store the original value in
229 # a private attribute and then make the public ostream a property, so
229 # a private attribute and then make the public ostream a property, so
230 # that we can delay accessing sys.stdout until runtime. The way
230 # that we can delay accessing sys.stdout until runtime. The way
231 # things are written now, the sys.stdout object is dynamically managed
231 # things are written now, the sys.stdout object is dynamically managed
232 # so a reference to it should NEVER be stored statically. This
232 # so a reference to it should NEVER be stored statically. This
233 # property approach confines this detail to a single location, and all
233 # property approach confines this detail to a single location, and all
234 # subclasses can simply access self.ostream for writing.
234 # subclasses can simply access self.ostream for writing.
235 self._ostream = ostream
235 self._ostream = ostream
236
236
237 # Create color table
237 # Create color table
238 self.color_scheme_table = exception_colors()
238 self.color_scheme_table = exception_colors()
239
239
240 self.set_colors(color_scheme)
240 self.set_colors(color_scheme)
241 self.old_scheme = color_scheme # save initial value for toggles
241 self.old_scheme = color_scheme # save initial value for toggles
242 self.debugger_cls = debugger_cls or debugger.Pdb
242 self.debugger_cls = debugger_cls or debugger.Pdb
243
243
244 if call_pdb:
244 if call_pdb:
245 self.pdb = self.debugger_cls()
245 self.pdb = self.debugger_cls()
246 else:
246 else:
247 self.pdb = None
247 self.pdb = None
248
248
249 def _get_ostream(self):
249 def _get_ostream(self):
250 """Output stream that exceptions are written to.
250 """Output stream that exceptions are written to.
251
251
252 Valid values are:
252 Valid values are:
253
253
254 - None: the default, which means that IPython will dynamically resolve
254 - None: the default, which means that IPython will dynamically resolve
255 to sys.stdout. This ensures compatibility with most tools, including
255 to sys.stdout. This ensures compatibility with most tools, including
256 Windows (where plain stdout doesn't recognize ANSI escapes).
256 Windows (where plain stdout doesn't recognize ANSI escapes).
257
257
258 - Any object with 'write' and 'flush' attributes.
258 - Any object with 'write' and 'flush' attributes.
259 """
259 """
260 return sys.stdout if self._ostream is None else self._ostream
260 return sys.stdout if self._ostream is None else self._ostream
261
261
262 def _set_ostream(self, val):
262 def _set_ostream(self, val):
263 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
263 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
264 self._ostream = val
264 self._ostream = val
265
265
266 ostream = property(_get_ostream, _set_ostream)
266 ostream = property(_get_ostream, _set_ostream)
267
267
268 @staticmethod
268 @staticmethod
269 def _get_chained_exception(exception_value):
269 def _get_chained_exception(exception_value):
270 cause = getattr(exception_value, "__cause__", None)
270 cause = getattr(exception_value, "__cause__", None)
271 if cause:
271 if cause:
272 return cause
272 return cause
273 if getattr(exception_value, "__suppress_context__", False):
273 if getattr(exception_value, "__suppress_context__", False):
274 return None
274 return None
275 return getattr(exception_value, "__context__", None)
275 return getattr(exception_value, "__context__", None)
276
276
277 def get_parts_of_chained_exception(
277 def get_parts_of_chained_exception(
278 self, evalue
278 self, evalue
279 ) -> Optional[Tuple[type, BaseException, TracebackType]]:
279 ) -> Optional[Tuple[type, BaseException, TracebackType]]:
280
280
281 chained_evalue = self._get_chained_exception(evalue)
281 chained_evalue = self._get_chained_exception(evalue)
282
282
283 if chained_evalue:
283 if chained_evalue:
284 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
284 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
285 return None
285 return None
286
286
287 def prepare_chained_exception_message(self, cause) -> List[Any]:
287 def prepare_chained_exception_message(self, cause) -> List[Any]:
288 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
288 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
289 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
289 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
290
290
291 if cause:
291 if cause:
292 message = [[direct_cause]]
292 message = [[direct_cause]]
293 else:
293 else:
294 message = [[exception_during_handling]]
294 message = [[exception_during_handling]]
295 return message
295 return message
296
296
297 @property
297 @property
298 def has_colors(self) -> bool:
298 def has_colors(self) -> bool:
299 return self.color_scheme_table.active_scheme_name.lower() != "nocolor"
299 return self.color_scheme_table.active_scheme_name.lower() != "nocolor"
300
300
301 def set_colors(self, *args, **kw):
301 def set_colors(self, *args, **kw):
302 """Shorthand access to the color table scheme selector method."""
302 """Shorthand access to the color table scheme selector method."""
303
303
304 # Set own color table
304 # Set own color table
305 self.color_scheme_table.set_active_scheme(*args, **kw)
305 self.color_scheme_table.set_active_scheme(*args, **kw)
306 # for convenience, set Colors to the active scheme
306 # for convenience, set Colors to the active scheme
307 self.Colors = self.color_scheme_table.active_colors
307 self.Colors = self.color_scheme_table.active_colors
308 # Also set colors of debugger
308 # Also set colors of debugger
309 if hasattr(self, 'pdb') and self.pdb is not None:
309 if hasattr(self, 'pdb') and self.pdb is not None:
310 self.pdb.set_colors(*args, **kw)
310 self.pdb.set_colors(*args, **kw)
311
311
312 def color_toggle(self):
312 def color_toggle(self):
313 """Toggle between the currently active color scheme and NoColor."""
313 """Toggle between the currently active color scheme and NoColor."""
314
314
315 if self.color_scheme_table.active_scheme_name == 'NoColor':
315 if self.color_scheme_table.active_scheme_name == 'NoColor':
316 self.color_scheme_table.set_active_scheme(self.old_scheme)
316 self.color_scheme_table.set_active_scheme(self.old_scheme)
317 self.Colors = self.color_scheme_table.active_colors
317 self.Colors = self.color_scheme_table.active_colors
318 else:
318 else:
319 self.old_scheme = self.color_scheme_table.active_scheme_name
319 self.old_scheme = self.color_scheme_table.active_scheme_name
320 self.color_scheme_table.set_active_scheme('NoColor')
320 self.color_scheme_table.set_active_scheme('NoColor')
321 self.Colors = self.color_scheme_table.active_colors
321 self.Colors = self.color_scheme_table.active_colors
322
322
323 def stb2text(self, stb):
323 def stb2text(self, stb):
324 """Convert a structured traceback (a list) to a string."""
324 """Convert a structured traceback (a list) to a string."""
325 return '\n'.join(stb)
325 return '\n'.join(stb)
326
326
327 def text(self, etype, value, tb, tb_offset: Optional[int] = None, context=5):
327 def text(self, etype, value, tb, tb_offset: Optional[int] = None, context=5):
328 """Return formatted traceback.
328 """Return formatted traceback.
329
329
330 Subclasses may override this if they add extra arguments.
330 Subclasses may override this if they add extra arguments.
331 """
331 """
332 tb_list = self.structured_traceback(etype, value, tb,
332 tb_list = self.structured_traceback(etype, value, tb,
333 tb_offset, context)
333 tb_offset, context)
334 return self.stb2text(tb_list)
334 return self.stb2text(tb_list)
335
335
336 def structured_traceback(
336 def structured_traceback(
337 self, etype, evalue, tb, tb_offset: Optional[int] = None, context=5, mode=None
337 self, etype, evalue, tb, tb_offset: Optional[int] = None, context=5, mode=None
338 ):
338 ):
339 """Return a list of traceback frames.
339 """Return a list of traceback frames.
340
340
341 Must be implemented by each class.
341 Must be implemented by each class.
342 """
342 """
343 raise NotImplementedError()
343 raise NotImplementedError()
344
344
345
345
346 #---------------------------------------------------------------------------
346 #---------------------------------------------------------------------------
347 class ListTB(TBTools):
347 class ListTB(TBTools):
348 """Print traceback information from a traceback list, with optional color.
348 """Print traceback information from a traceback list, with optional color.
349
349
350 Calling requires 3 arguments: (etype, evalue, elist)
350 Calling requires 3 arguments: (etype, evalue, elist)
351 as would be obtained by::
351 as would be obtained by::
352
352
353 etype, evalue, tb = sys.exc_info()
353 etype, evalue, tb = sys.exc_info()
354 if tb:
354 if tb:
355 elist = traceback.extract_tb(tb)
355 elist = traceback.extract_tb(tb)
356 else:
356 else:
357 elist = None
357 elist = None
358
358
359 It can thus be used by programs which need to process the traceback before
359 It can thus be used by programs which need to process the traceback before
360 printing (such as console replacements based on the code module from the
360 printing (such as console replacements based on the code module from the
361 standard library).
361 standard library).
362
362
363 Because they are meant to be called without a full traceback (only a
363 Because they are meant to be called without a full traceback (only a
364 list), instances of this class can't call the interactive pdb debugger."""
364 list), instances of this class can't call the interactive pdb debugger."""
365
365
366
366
367 def __call__(self, etype, value, elist):
367 def __call__(self, etype, value, elist):
368 self.ostream.flush()
368 self.ostream.flush()
369 self.ostream.write(self.text(etype, value, elist))
369 self.ostream.write(self.text(etype, value, elist))
370 self.ostream.write('\n')
370 self.ostream.write('\n')
371
371
372 def _extract_tb(self, tb):
372 def _extract_tb(self, tb):
373 if tb:
373 if tb:
374 return traceback.extract_tb(tb)
374 return traceback.extract_tb(tb)
375 else:
375 else:
376 return None
376 return None
377
377
378 def structured_traceback(
378 def structured_traceback(
379 self,
379 self,
380 etype: type,
380 etype: type,
381 evalue: BaseException,
381 evalue: BaseException,
382 etb: Optional[TracebackType] = None,
382 etb: Optional[TracebackType] = None,
383 tb_offset: Optional[int] = None,
383 tb_offset: Optional[int] = None,
384 context=5,
384 context=5,
385 ):
385 ):
386 """Return a color formatted string with the traceback info.
386 """Return a color formatted string with the traceback info.
387
387
388 Parameters
388 Parameters
389 ----------
389 ----------
390 etype : exception type
390 etype : exception type
391 Type of the exception raised.
391 Type of the exception raised.
392 evalue : object
392 evalue : object
393 Data stored in the exception
393 Data stored in the exception
394 etb : list | TracebackType | None
394 etb : list | TracebackType | None
395 If list: List of frames, see class docstring for details.
395 If list: List of frames, see class docstring for details.
396 If Traceback: Traceback of the exception.
396 If Traceback: Traceback of the exception.
397 tb_offset : int, optional
397 tb_offset : int, optional
398 Number of frames in the traceback to skip. If not given, the
398 Number of frames in the traceback to skip. If not given, the
399 instance evalue is used (set in constructor).
399 instance evalue is used (set in constructor).
400 context : int, optional
400 context : int, optional
401 Number of lines of context information to print.
401 Number of lines of context information to print.
402
402
403 Returns
403 Returns
404 -------
404 -------
405 String with formatted exception.
405 String with formatted exception.
406 """
406 """
407 # This is a workaround to get chained_exc_ids in recursive calls
407 # This is a workaround to get chained_exc_ids in recursive calls
408 # etb should not be a tuple if structured_traceback is not recursive
408 # etb should not be a tuple if structured_traceback is not recursive
409 if isinstance(etb, tuple):
409 if isinstance(etb, tuple):
410 etb, chained_exc_ids = etb
410 etb, chained_exc_ids = etb
411 else:
411 else:
412 chained_exc_ids = set()
412 chained_exc_ids = set()
413
413
414 if isinstance(etb, list):
414 if isinstance(etb, list):
415 elist = etb
415 elist = etb
416 elif etb is not None:
416 elif etb is not None:
417 elist = self._extract_tb(etb)
417 elist = self._extract_tb(etb)
418 else:
418 else:
419 elist = []
419 elist = []
420 tb_offset = self.tb_offset if tb_offset is None else tb_offset
420 tb_offset = self.tb_offset if tb_offset is None else tb_offset
421 assert isinstance(tb_offset, int)
421 assert isinstance(tb_offset, int)
422 Colors = self.Colors
422 Colors = self.Colors
423 out_list = []
423 out_list = []
424 if elist:
424 if elist:
425
425
426 if tb_offset and len(elist) > tb_offset:
426 if tb_offset and len(elist) > tb_offset:
427 elist = elist[tb_offset:]
427 elist = elist[tb_offset:]
428
428
429 out_list.append('Traceback %s(most recent call last)%s:' %
429 out_list.append('Traceback %s(most recent call last)%s:' %
430 (Colors.normalEm, Colors.Normal) + '\n')
430 (Colors.normalEm, Colors.Normal) + '\n')
431 out_list.extend(self._format_list(elist))
431 out_list.extend(self._format_list(elist))
432 # The exception info should be a single entry in the list.
432 # The exception info should be a single entry in the list.
433 lines = ''.join(self._format_exception_only(etype, evalue))
433 lines = ''.join(self._format_exception_only(etype, evalue))
434 out_list.append(lines)
434 out_list.append(lines)
435
435
436 exception = self.get_parts_of_chained_exception(evalue)
436 exception = self.get_parts_of_chained_exception(evalue)
437
437
438 if exception and not id(exception[1]) in chained_exc_ids:
438 if exception and not id(exception[1]) in chained_exc_ids:
439 chained_exception_message = self.prepare_chained_exception_message(
439 chained_exception_message = self.prepare_chained_exception_message(
440 evalue.__cause__)[0]
440 evalue.__cause__)[0]
441 etype, evalue, etb = exception
441 etype, evalue, etb = exception
442 # Trace exception to avoid infinite 'cause' loop
442 # Trace exception to avoid infinite 'cause' loop
443 chained_exc_ids.add(id(exception[1]))
443 chained_exc_ids.add(id(exception[1]))
444 chained_exceptions_tb_offset = 0
444 chained_exceptions_tb_offset = 0
445 out_list = (
445 out_list = (
446 self.structured_traceback(
446 self.structured_traceback(
447 etype, evalue, (etb, chained_exc_ids),
447 etype, evalue, (etb, chained_exc_ids),
448 chained_exceptions_tb_offset, context)
448 chained_exceptions_tb_offset, context)
449 + chained_exception_message
449 + chained_exception_message
450 + out_list)
450 + out_list)
451
451
452 return out_list
452 return out_list
453
453
454 def _format_list(self, extracted_list):
454 def _format_list(self, extracted_list):
455 """Format a list of traceback entry tuples for printing.
455 """Format a list of traceback entry tuples for printing.
456
456
457 Given a list of tuples as returned by extract_tb() or
457 Given a list of tuples as returned by extract_tb() or
458 extract_stack(), return a list of strings ready for printing.
458 extract_stack(), return a list of strings ready for printing.
459 Each string in the resulting list corresponds to the item with the
459 Each string in the resulting list corresponds to the item with the
460 same index in the argument list. Each string ends in a newline;
460 same index in the argument list. Each string ends in a newline;
461 the strings may contain internal newlines as well, for those items
461 the strings may contain internal newlines as well, for those items
462 whose source text line is not None.
462 whose source text line is not None.
463
463
464 Lifted almost verbatim from traceback.py
464 Lifted almost verbatim from traceback.py
465 """
465 """
466
466
467 Colors = self.Colors
467 Colors = self.Colors
468 list = []
468 list = []
469 for ind, (filename, lineno, name, line) in enumerate(extracted_list):
469 for ind, (filename, lineno, name, line) in enumerate(extracted_list):
470 normalCol, nameCol, fileCol, lineCol = (
470 normalCol, nameCol, fileCol, lineCol = (
471 # Emphasize the last entry
471 # Emphasize the last entry
472 (Colors.normalEm, Colors.nameEm, Colors.filenameEm, Colors.line)
472 (Colors.normalEm, Colors.nameEm, Colors.filenameEm, Colors.line)
473 if ind == len(extracted_list) - 1
473 if ind == len(extracted_list) - 1
474 else (Colors.Normal, Colors.name, Colors.filename, "")
474 else (Colors.Normal, Colors.name, Colors.filename, "")
475 )
475 )
476
476
477 fns = _format_filename(filename, fileCol, normalCol, lineno=lineno)
477 fns = _format_filename(filename, fileCol, normalCol, lineno=lineno)
478 item = f"{normalCol} {fns}"
478 item = f"{normalCol} {fns}"
479
479
480 if name != "<module>":
480 if name != "<module>":
481 item += f" in {nameCol}{name}{normalCol}\n"
481 item += f" in {nameCol}{name}{normalCol}\n"
482 else:
482 else:
483 item += "\n"
483 item += "\n"
484 if line:
484 if line:
485 item += f"{lineCol} {line.strip()}{normalCol}\n"
485 item += f"{lineCol} {line.strip()}{normalCol}\n"
486 list.append(item)
486 list.append(item)
487
487
488 return list
488 return list
489
489
490 def _format_exception_only(self, etype, value):
490 def _format_exception_only(self, etype, value):
491 """Format the exception part of a traceback.
491 """Format the exception part of a traceback.
492
492
493 The arguments are the exception type and value such as given by
493 The arguments are the exception type and value such as given by
494 sys.exc_info()[:2]. The return value is a list of strings, each ending
494 sys.exc_info()[:2]. The return value is a list of strings, each ending
495 in a newline. Normally, the list contains a single string; however,
495 in a newline. Normally, the list contains a single string; however,
496 for SyntaxError exceptions, it contains several lines that (when
496 for SyntaxError exceptions, it contains several lines that (when
497 printed) display detailed information about where the syntax error
497 printed) display detailed information about where the syntax error
498 occurred. The message indicating which exception occurred is the
498 occurred. The message indicating which exception occurred is the
499 always last string in the list.
499 always last string in the list.
500
500
501 Also lifted nearly verbatim from traceback.py
501 Also lifted nearly verbatim from traceback.py
502 """
502 """
503 have_filedata = False
503 have_filedata = False
504 Colors = self.Colors
504 Colors = self.Colors
505 list = []
505 list = []
506 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
506 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
507 if value is None:
507 if value is None:
508 # Not sure if this can still happen in Python 2.6 and above
508 # Not sure if this can still happen in Python 2.6 and above
509 list.append(stype + '\n')
509 list.append(stype + '\n')
510 else:
510 else:
511 if issubclass(etype, SyntaxError):
511 if issubclass(etype, SyntaxError):
512 have_filedata = True
512 have_filedata = True
513 if not value.filename: value.filename = "<string>"
513 if not value.filename: value.filename = "<string>"
514 if value.lineno:
514 if value.lineno:
515 lineno = value.lineno
515 lineno = value.lineno
516 textline = linecache.getline(value.filename, value.lineno)
516 textline = linecache.getline(value.filename, value.lineno)
517 else:
517 else:
518 lineno = "unknown"
518 lineno = "unknown"
519 textline = ""
519 textline = ""
520 list.append(
520 list.append(
521 "%s %s%s\n"
521 "%s %s%s\n"
522 % (
522 % (
523 Colors.normalEm,
523 Colors.normalEm,
524 _format_filename(
524 _format_filename(
525 value.filename,
525 value.filename,
526 Colors.filenameEm,
526 Colors.filenameEm,
527 Colors.normalEm,
527 Colors.normalEm,
528 lineno=(None if lineno == "unknown" else lineno),
528 lineno=(None if lineno == "unknown" else lineno),
529 ),
529 ),
530 Colors.Normal,
530 Colors.Normal,
531 )
531 )
532 )
532 )
533 if textline == "":
533 if textline == "":
534 textline = py3compat.cast_unicode(value.text, "utf-8")
534 textline = py3compat.cast_unicode(value.text, "utf-8")
535
535
536 if textline is not None:
536 if textline is not None:
537 i = 0
537 i = 0
538 while i < len(textline) and textline[i].isspace():
538 while i < len(textline) and textline[i].isspace():
539 i += 1
539 i += 1
540 list.append('%s %s%s\n' % (Colors.line,
540 list.append('%s %s%s\n' % (Colors.line,
541 textline.strip(),
541 textline.strip(),
542 Colors.Normal))
542 Colors.Normal))
543 if value.offset is not None:
543 if value.offset is not None:
544 s = ' '
544 s = ' '
545 for c in textline[i:value.offset - 1]:
545 for c in textline[i:value.offset - 1]:
546 if c.isspace():
546 if c.isspace():
547 s += c
547 s += c
548 else:
548 else:
549 s += ' '
549 s += ' '
550 list.append('%s%s^%s\n' % (Colors.caret, s,
550 list.append('%s%s^%s\n' % (Colors.caret, s,
551 Colors.Normal))
551 Colors.Normal))
552
552
553 try:
553 try:
554 s = value.msg
554 s = value.msg
555 except Exception:
555 except Exception:
556 s = self._some_str(value)
556 s = self._some_str(value)
557 if s:
557 if s:
558 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
558 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
559 Colors.Normal, s))
559 Colors.Normal, s))
560 else:
560 else:
561 list.append('%s\n' % stype)
561 list.append('%s\n' % stype)
562
562
563 # sync with user hooks
563 # sync with user hooks
564 if have_filedata:
564 if have_filedata:
565 ipinst = get_ipython()
565 ipinst = get_ipython()
566 if ipinst is not None:
566 if ipinst is not None:
567 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
567 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
568
568
569 return list
569 return list
570
570
571 def get_exception_only(self, etype, value):
571 def get_exception_only(self, etype, value):
572 """Only print the exception type and message, without a traceback.
572 """Only print the exception type and message, without a traceback.
573
573
574 Parameters
574 Parameters
575 ----------
575 ----------
576 etype : exception type
576 etype : exception type
577 value : exception value
577 value : exception value
578 """
578 """
579 return ListTB.structured_traceback(self, etype, value)
579 return ListTB.structured_traceback(self, etype, value)
580
580
581 def show_exception_only(self, etype, evalue):
581 def show_exception_only(self, etype, evalue):
582 """Only print the exception type and message, without a traceback.
582 """Only print the exception type and message, without a traceback.
583
583
584 Parameters
584 Parameters
585 ----------
585 ----------
586 etype : exception type
586 etype : exception type
587 evalue : exception value
587 evalue : exception value
588 """
588 """
589 # This method needs to use __call__ from *this* class, not the one from
589 # This method needs to use __call__ from *this* class, not the one from
590 # a subclass whose signature or behavior may be different
590 # a subclass whose signature or behavior may be different
591 ostream = self.ostream
591 ostream = self.ostream
592 ostream.flush()
592 ostream.flush()
593 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
593 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
594 ostream.flush()
594 ostream.flush()
595
595
596 def _some_str(self, value):
596 def _some_str(self, value):
597 # Lifted from traceback.py
597 # Lifted from traceback.py
598 try:
598 try:
599 return py3compat.cast_unicode(str(value))
599 return py3compat.cast_unicode(str(value))
600 except:
600 except:
601 return u'<unprintable %s object>' % type(value).__name__
601 return u'<unprintable %s object>' % type(value).__name__
602
602
603
603
604 #----------------------------------------------------------------------------
604 #----------------------------------------------------------------------------
605 class VerboseTB(TBTools):
605 class VerboseTB(TBTools):
606 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
606 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
607 of HTML. Requires inspect and pydoc. Crazy, man.
607 of HTML. Requires inspect and pydoc. Crazy, man.
608
608
609 Modified version which optionally strips the topmost entries from the
609 Modified version which optionally strips the topmost entries from the
610 traceback, to be used with alternate interpreters (because their own code
610 traceback, to be used with alternate interpreters (because their own code
611 would appear in the traceback)."""
611 would appear in the traceback)."""
612
612
613 _tb_highlight = "bg:ansiyellow"
614
613 def __init__(
615 def __init__(
614 self,
616 self,
615 color_scheme: str = "Linux",
617 color_scheme: str = "Linux",
616 call_pdb: bool = False,
618 call_pdb: bool = False,
617 ostream=None,
619 ostream=None,
618 tb_offset: int = 0,
620 tb_offset: int = 0,
619 long_header: bool = False,
621 long_header: bool = False,
620 include_vars: bool = True,
622 include_vars: bool = True,
621 check_cache=None,
623 check_cache=None,
622 debugger_cls=None,
624 debugger_cls=None,
623 parent=None,
625 parent=None,
624 config=None,
626 config=None,
625 ):
627 ):
626 """Specify traceback offset, headers and color scheme.
628 """Specify traceback offset, headers and color scheme.
627
629
628 Define how many frames to drop from the tracebacks. Calling it with
630 Define how many frames to drop from the tracebacks. Calling it with
629 tb_offset=1 allows use of this handler in interpreters which will have
631 tb_offset=1 allows use of this handler in interpreters which will have
630 their own code at the top of the traceback (VerboseTB will first
632 their own code at the top of the traceback (VerboseTB will first
631 remove that frame before printing the traceback info)."""
633 remove that frame before printing the traceback info)."""
632 TBTools.__init__(
634 TBTools.__init__(
633 self,
635 self,
634 color_scheme=color_scheme,
636 color_scheme=color_scheme,
635 call_pdb=call_pdb,
637 call_pdb=call_pdb,
636 ostream=ostream,
638 ostream=ostream,
637 parent=parent,
639 parent=parent,
638 config=config,
640 config=config,
639 debugger_cls=debugger_cls,
641 debugger_cls=debugger_cls,
640 )
642 )
641 self.tb_offset = tb_offset
643 self.tb_offset = tb_offset
642 self.long_header = long_header
644 self.long_header = long_header
643 self.include_vars = include_vars
645 self.include_vars = include_vars
644 # By default we use linecache.checkcache, but the user can provide a
646 # By default we use linecache.checkcache, but the user can provide a
645 # different check_cache implementation. This is used by the IPython
647 # different check_cache implementation. This was formerly used by the
646 # kernel to provide tracebacks for interactive code that is cached,
648 # IPython kernel for interactive code, but is no longer necessary.
647 # by a compiler instance that flushes the linecache but preserves its
648 # own code cache.
649 if check_cache is None:
649 if check_cache is None:
650 check_cache = linecache.checkcache
650 check_cache = linecache.checkcache
651 self.check_cache = check_cache
651 self.check_cache = check_cache
652
652
653 self.skip_hidden = True
653 self.skip_hidden = True
654
654
655 def format_record(self, frame_info):
655 def format_record(self, frame_info):
656 """Format a single stack frame"""
656 """Format a single stack frame"""
657 Colors = self.Colors # just a shorthand + quicker name lookup
657 Colors = self.Colors # just a shorthand + quicker name lookup
658 ColorsNormal = Colors.Normal # used a lot
658 ColorsNormal = Colors.Normal # used a lot
659
659
660 if isinstance(frame_info, stack_data.RepeatedFrames):
660 if isinstance(frame_info, stack_data.RepeatedFrames):
661 return ' %s[... skipping similar frames: %s]%s\n' % (
661 return ' %s[... skipping similar frames: %s]%s\n' % (
662 Colors.excName, frame_info.description, ColorsNormal)
662 Colors.excName, frame_info.description, ColorsNormal)
663
663
664 indent = " " * INDENT_SIZE
664 indent = " " * INDENT_SIZE
665 em_normal = "%s\n%s%s" % (Colors.valEm, indent, ColorsNormal)
665 em_normal = "%s\n%s%s" % (Colors.valEm, indent, ColorsNormal)
666 tpl_call = f"in {Colors.vName}{{file}}{Colors.valEm}{{scope}}{ColorsNormal}"
666 tpl_call = f"in {Colors.vName}{{file}}{Colors.valEm}{{scope}}{ColorsNormal}"
667 tpl_call_fail = "in %s%%s%s(***failed resolving arguments***)%s" % (
667 tpl_call_fail = "in %s%%s%s(***failed resolving arguments***)%s" % (
668 Colors.vName,
668 Colors.vName,
669 Colors.valEm,
669 Colors.valEm,
670 ColorsNormal,
670 ColorsNormal,
671 )
671 )
672 tpl_name_val = "%%s %s= %%s%s" % (Colors.valEm, ColorsNormal)
672 tpl_name_val = "%%s %s= %%s%s" % (Colors.valEm, ColorsNormal)
673
673
674 link = _format_filename(
674 link = _format_filename(
675 frame_info.filename,
675 frame_info.filename,
676 Colors.filenameEm,
676 Colors.filenameEm,
677 ColorsNormal,
677 ColorsNormal,
678 lineno=frame_info.lineno,
678 lineno=frame_info.lineno,
679 )
679 )
680 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
680 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
681
681
682 func = frame_info.executing.code_qualname()
682 func = frame_info.executing.code_qualname()
683 if func == "<module>":
683 if func == "<module>":
684 call = ""
684 call = ""
685 else:
685 else:
686 # Decide whether to include variable details or not
686 # Decide whether to include variable details or not
687 var_repr = eqrepr if self.include_vars else nullrepr
687 var_repr = eqrepr if self.include_vars else nullrepr
688 try:
688 try:
689 scope = inspect.formatargvalues(
689 scope = inspect.formatargvalues(
690 args, varargs, varkw, locals_, formatvalue=var_repr
690 args, varargs, varkw, locals_, formatvalue=var_repr
691 )
691 )
692 call = tpl_call.format(file=func, scope=scope)
692 call = tpl_call.format(file=func, scope=scope)
693 except KeyError:
693 except KeyError:
694 # This happens in situations like errors inside generator
694 # This happens in situations like errors inside generator
695 # expressions, where local variables are listed in the
695 # expressions, where local variables are listed in the
696 # line, but can't be extracted from the frame. I'm not
696 # line, but can't be extracted from the frame. I'm not
697 # 100% sure this isn't actually a bug in inspect itself,
697 # 100% sure this isn't actually a bug in inspect itself,
698 # but since there's no info for us to compute with, the
698 # but since there's no info for us to compute with, the
699 # best we can do is report the failure and move on. Here
699 # best we can do is report the failure and move on. Here
700 # we must *not* call any traceback construction again,
700 # we must *not* call any traceback construction again,
701 # because that would mess up use of %debug later on. So we
701 # because that would mess up use of %debug later on. So we
702 # simply report the failure and move on. The only
702 # simply report the failure and move on. The only
703 # limitation will be that this frame won't have locals
703 # limitation will be that this frame won't have locals
704 # listed in the call signature. Quite subtle problem...
704 # listed in the call signature. Quite subtle problem...
705 # I can't think of a good way to validate this in a unit
705 # I can't think of a good way to validate this in a unit
706 # test, but running a script consisting of:
706 # test, but running a script consisting of:
707 # dict( (k,v.strip()) for (k,v) in range(10) )
707 # dict( (k,v.strip()) for (k,v) in range(10) )
708 # will illustrate the error, if this exception catch is
708 # will illustrate the error, if this exception catch is
709 # disabled.
709 # disabled.
710 call = tpl_call_fail % func
710 call = tpl_call_fail % func
711
711
712 lvals = ''
712 lvals = ''
713 lvals_list = []
713 lvals_list = []
714 if self.include_vars:
714 if self.include_vars:
715 try:
715 try:
716 # we likely want to fix stackdata at some point, but
716 # we likely want to fix stackdata at some point, but
717 # still need a workaround.
717 # still need a workaround.
718 fibp = frame_info.variables_in_executing_piece
718 fibp = frame_info.variables_in_executing_piece
719 for var in fibp:
719 for var in fibp:
720 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
720 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
721 except Exception:
721 except Exception:
722 lvals_list.append(
722 lvals_list.append(
723 "Exception trying to inspect frame. No more locals available."
723 "Exception trying to inspect frame. No more locals available."
724 )
724 )
725 if lvals_list:
725 if lvals_list:
726 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
726 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
727
727
728 result = f'{link}{", " if call else ""}{call}\n'
728 result = f'{link}{", " if call else ""}{call}\n'
729
729
730 result += ''.join(_format_traceback_lines(frame_info.lines, Colors, self.has_colors, lvals))
730 result += ''.join(_format_traceback_lines(frame_info.lines, Colors, self.has_colors, lvals))
731 return result
731 return result
732
732
733 def prepare_header(self, etype, long_version=False):
733 def prepare_header(self, etype, long_version=False):
734 colors = self.Colors # just a shorthand + quicker name lookup
734 colors = self.Colors # just a shorthand + quicker name lookup
735 colorsnormal = colors.Normal # used a lot
735 colorsnormal = colors.Normal # used a lot
736 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
736 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
737 width = min(75, get_terminal_size()[0])
737 width = min(75, get_terminal_size()[0])
738 if long_version:
738 if long_version:
739 # Header with the exception type, python version, and date
739 # Header with the exception type, python version, and date
740 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
740 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
741 date = time.ctime(time.time())
741 date = time.ctime(time.time())
742
742
743 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
743 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
744 exc, ' ' * (width - len(str(etype)) - len(pyver)),
744 exc, ' ' * (width - len(str(etype)) - len(pyver)),
745 pyver, date.rjust(width) )
745 pyver, date.rjust(width) )
746 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
746 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
747 "\ncalls leading up to the error, with the most recent (innermost) call last."
747 "\ncalls leading up to the error, with the most recent (innermost) call last."
748 else:
748 else:
749 # Simplified header
749 # Simplified header
750 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
750 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
751 rjust(width - len(str(etype))) )
751 rjust(width - len(str(etype))) )
752
752
753 return head
753 return head
754
754
755 def format_exception(self, etype, evalue):
755 def format_exception(self, etype, evalue):
756 colors = self.Colors # just a shorthand + quicker name lookup
756 colors = self.Colors # just a shorthand + quicker name lookup
757 colorsnormal = colors.Normal # used a lot
757 colorsnormal = colors.Normal # used a lot
758 # Get (safely) a string form of the exception info
758 # Get (safely) a string form of the exception info
759 try:
759 try:
760 etype_str, evalue_str = map(str, (etype, evalue))
760 etype_str, evalue_str = map(str, (etype, evalue))
761 except:
761 except:
762 # User exception is improperly defined.
762 # User exception is improperly defined.
763 etype, evalue = str, sys.exc_info()[:2]
763 etype, evalue = str, sys.exc_info()[:2]
764 etype_str, evalue_str = map(str, (etype, evalue))
764 etype_str, evalue_str = map(str, (etype, evalue))
765 # ... and format it
765 # ... and format it
766 return ['%s%s%s: %s' % (colors.excName, etype_str,
766 return ['%s%s%s: %s' % (colors.excName, etype_str,
767 colorsnormal, py3compat.cast_unicode(evalue_str))]
767 colorsnormal, py3compat.cast_unicode(evalue_str))]
768
768
769 def format_exception_as_a_whole(
769 def format_exception_as_a_whole(
770 self,
770 self,
771 etype: type,
771 etype: type,
772 evalue: BaseException,
772 evalue: BaseException,
773 etb: Optional[TracebackType],
773 etb: Optional[TracebackType],
774 number_of_lines_of_context,
774 number_of_lines_of_context,
775 tb_offset: Optional[int],
775 tb_offset: Optional[int],
776 ):
776 ):
777 """Formats the header, traceback and exception message for a single exception.
777 """Formats the header, traceback and exception message for a single exception.
778
778
779 This may be called multiple times by Python 3 exception chaining
779 This may be called multiple times by Python 3 exception chaining
780 (PEP 3134).
780 (PEP 3134).
781 """
781 """
782 # some locals
782 # some locals
783 orig_etype = etype
783 orig_etype = etype
784 try:
784 try:
785 etype = etype.__name__
785 etype = etype.__name__
786 except AttributeError:
786 except AttributeError:
787 pass
787 pass
788
788
789 tb_offset = self.tb_offset if tb_offset is None else tb_offset
789 tb_offset = self.tb_offset if tb_offset is None else tb_offset
790 assert isinstance(tb_offset, int)
790 assert isinstance(tb_offset, int)
791 head = self.prepare_header(etype, self.long_header)
791 head = self.prepare_header(etype, self.long_header)
792 records = (
792 records = (
793 self.get_records(etb, number_of_lines_of_context, tb_offset) if etb else []
793 self.get_records(etb, number_of_lines_of_context, tb_offset) if etb else []
794 )
794 )
795
795
796 frames = []
796 frames = []
797 skipped = 0
797 skipped = 0
798 lastrecord = len(records) - 1
798 lastrecord = len(records) - 1
799 for i, r in enumerate(records):
799 for i, r in enumerate(records):
800 if not isinstance(r, stack_data.RepeatedFrames) and self.skip_hidden:
800 if not isinstance(r, stack_data.RepeatedFrames) and self.skip_hidden:
801 if r.frame.f_locals.get("__tracebackhide__", 0) and i != lastrecord:
801 if r.frame.f_locals.get("__tracebackhide__", 0) and i != lastrecord:
802 skipped += 1
802 skipped += 1
803 continue
803 continue
804 if skipped:
804 if skipped:
805 Colors = self.Colors # just a shorthand + quicker name lookup
805 Colors = self.Colors # just a shorthand + quicker name lookup
806 ColorsNormal = Colors.Normal # used a lot
806 ColorsNormal = Colors.Normal # used a lot
807 frames.append(
807 frames.append(
808 " %s[... skipping hidden %s frame]%s\n"
808 " %s[... skipping hidden %s frame]%s\n"
809 % (Colors.excName, skipped, ColorsNormal)
809 % (Colors.excName, skipped, ColorsNormal)
810 )
810 )
811 skipped = 0
811 skipped = 0
812 frames.append(self.format_record(r))
812 frames.append(self.format_record(r))
813 if skipped:
813 if skipped:
814 Colors = self.Colors # just a shorthand + quicker name lookup
814 Colors = self.Colors # just a shorthand + quicker name lookup
815 ColorsNormal = Colors.Normal # used a lot
815 ColorsNormal = Colors.Normal # used a lot
816 frames.append(
816 frames.append(
817 " %s[... skipping hidden %s frame]%s\n"
817 " %s[... skipping hidden %s frame]%s\n"
818 % (Colors.excName, skipped, ColorsNormal)
818 % (Colors.excName, skipped, ColorsNormal)
819 )
819 )
820
820
821 formatted_exception = self.format_exception(etype, evalue)
821 formatted_exception = self.format_exception(etype, evalue)
822 if records:
822 if records:
823 frame_info = records[-1]
823 frame_info = records[-1]
824 ipinst = get_ipython()
824 ipinst = get_ipython()
825 if ipinst is not None:
825 if ipinst is not None:
826 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
826 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
827
827
828 return [[head] + frames + [''.join(formatted_exception[0])]]
828 return [[head] + frames + [''.join(formatted_exception[0])]]
829
829
830 def get_records(
830 def get_records(
831 self, etb: TracebackType, number_of_lines_of_context: int, tb_offset: int
831 self, etb: TracebackType, number_of_lines_of_context: int, tb_offset: int
832 ):
832 ):
833 assert etb is not None
833 assert etb is not None
834 context = number_of_lines_of_context - 1
834 context = number_of_lines_of_context - 1
835 after = context // 2
835 after = context // 2
836 before = context - after
836 before = context - after
837 if self.has_colors:
837 if self.has_colors:
838 style = get_style_by_name("default")
838 style = get_style_by_name("default")
839 style = stack_data.style_with_executing_node(style, "bg:ansiyellow")
839 style = stack_data.style_with_executing_node(style, self._tb_highlight)
840 formatter = Terminal256Formatter(style=style)
840 formatter = Terminal256Formatter(style=style)
841 else:
841 else:
842 formatter = None
842 formatter = None
843 options = stack_data.Options(
843 options = stack_data.Options(
844 before=before,
844 before=before,
845 after=after,
845 after=after,
846 pygments_formatter=formatter,
846 pygments_formatter=formatter,
847 )
847 )
848 return list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
848 return list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
849
849
850 def structured_traceback(
850 def structured_traceback(
851 self,
851 self,
852 etype: type,
852 etype: type,
853 evalue: Optional[BaseException],
853 evalue: Optional[BaseException],
854 etb: Optional[TracebackType],
854 etb: Optional[TracebackType],
855 tb_offset: Optional[int] = None,
855 tb_offset: Optional[int] = None,
856 number_of_lines_of_context: int = 5,
856 number_of_lines_of_context: int = 5,
857 ):
857 ):
858 """Return a nice text document describing the traceback."""
858 """Return a nice text document describing the traceback."""
859 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
859 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
860 tb_offset)
860 tb_offset)
861
861
862 colors = self.Colors # just a shorthand + quicker name lookup
862 colors = self.Colors # just a shorthand + quicker name lookup
863 colorsnormal = colors.Normal # used a lot
863 colorsnormal = colors.Normal # used a lot
864 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
864 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
865 structured_traceback_parts = [head]
865 structured_traceback_parts = [head]
866 chained_exceptions_tb_offset = 0
866 chained_exceptions_tb_offset = 0
867 lines_of_context = 3
867 lines_of_context = 3
868 formatted_exceptions = formatted_exception
868 formatted_exceptions = formatted_exception
869 exception = self.get_parts_of_chained_exception(evalue)
869 exception = self.get_parts_of_chained_exception(evalue)
870 if exception:
870 if exception:
871 assert evalue is not None
871 assert evalue is not None
872 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
872 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
873 etype, evalue, etb = exception
873 etype, evalue, etb = exception
874 else:
874 else:
875 evalue = None
875 evalue = None
876 chained_exc_ids = set()
876 chained_exc_ids = set()
877 while evalue:
877 while evalue:
878 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
878 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
879 chained_exceptions_tb_offset)
879 chained_exceptions_tb_offset)
880 exception = self.get_parts_of_chained_exception(evalue)
880 exception = self.get_parts_of_chained_exception(evalue)
881
881
882 if exception and not id(exception[1]) in chained_exc_ids:
882 if exception and not id(exception[1]) in chained_exc_ids:
883 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
883 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
884 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
884 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
885 etype, evalue, etb = exception
885 etype, evalue, etb = exception
886 else:
886 else:
887 evalue = None
887 evalue = None
888
888
889 # we want to see exceptions in a reversed order:
889 # we want to see exceptions in a reversed order:
890 # the first exception should be on top
890 # the first exception should be on top
891 for formatted_exception in reversed(formatted_exceptions):
891 for formatted_exception in reversed(formatted_exceptions):
892 structured_traceback_parts += formatted_exception
892 structured_traceback_parts += formatted_exception
893
893
894 return structured_traceback_parts
894 return structured_traceback_parts
895
895
896 def debugger(self, force: bool = False):
896 def debugger(self, force: bool = False):
897 """Call up the pdb debugger if desired, always clean up the tb
897 """Call up the pdb debugger if desired, always clean up the tb
898 reference.
898 reference.
899
899
900 Keywords:
900 Keywords:
901
901
902 - force(False): by default, this routine checks the instance call_pdb
902 - force(False): by default, this routine checks the instance call_pdb
903 flag and does not actually invoke the debugger if the flag is false.
903 flag and does not actually invoke the debugger if the flag is false.
904 The 'force' option forces the debugger to activate even if the flag
904 The 'force' option forces the debugger to activate even if the flag
905 is false.
905 is false.
906
906
907 If the call_pdb flag is set, the pdb interactive debugger is
907 If the call_pdb flag is set, the pdb interactive debugger is
908 invoked. In all cases, the self.tb reference to the current traceback
908 invoked. In all cases, the self.tb reference to the current traceback
909 is deleted to prevent lingering references which hamper memory
909 is deleted to prevent lingering references which hamper memory
910 management.
910 management.
911
911
912 Note that each call to pdb() does an 'import readline', so if your app
912 Note that each call to pdb() does an 'import readline', so if your app
913 requires a special setup for the readline completers, you'll have to
913 requires a special setup for the readline completers, you'll have to
914 fix that by hand after invoking the exception handler."""
914 fix that by hand after invoking the exception handler."""
915
915
916 if force or self.call_pdb:
916 if force or self.call_pdb:
917 if self.pdb is None:
917 if self.pdb is None:
918 self.pdb = self.debugger_cls()
918 self.pdb = self.debugger_cls()
919 # the system displayhook may have changed, restore the original
919 # the system displayhook may have changed, restore the original
920 # for pdb
920 # for pdb
921 display_trap = DisplayTrap(hook=sys.__displayhook__)
921 display_trap = DisplayTrap(hook=sys.__displayhook__)
922 with display_trap:
922 with display_trap:
923 self.pdb.reset()
923 self.pdb.reset()
924 # Find the right frame so we don't pop up inside ipython itself
924 # Find the right frame so we don't pop up inside ipython itself
925 if hasattr(self, 'tb') and self.tb is not None:
925 if hasattr(self, 'tb') and self.tb is not None:
926 etb = self.tb
926 etb = self.tb
927 else:
927 else:
928 etb = self.tb = sys.last_traceback
928 etb = self.tb = sys.last_traceback
929 while self.tb is not None and self.tb.tb_next is not None:
929 while self.tb is not None and self.tb.tb_next is not None:
930 assert self.tb.tb_next is not None
930 assert self.tb.tb_next is not None
931 self.tb = self.tb.tb_next
931 self.tb = self.tb.tb_next
932 if etb and etb.tb_next:
932 if etb and etb.tb_next:
933 etb = etb.tb_next
933 etb = etb.tb_next
934 self.pdb.botframe = etb.tb_frame
934 self.pdb.botframe = etb.tb_frame
935 self.pdb.interaction(None, etb)
935 self.pdb.interaction(None, etb)
936
936
937 if hasattr(self, 'tb'):
937 if hasattr(self, 'tb'):
938 del self.tb
938 del self.tb
939
939
940 def handler(self, info=None):
940 def handler(self, info=None):
941 (etype, evalue, etb) = info or sys.exc_info()
941 (etype, evalue, etb) = info or sys.exc_info()
942 self.tb = etb
942 self.tb = etb
943 ostream = self.ostream
943 ostream = self.ostream
944 ostream.flush()
944 ostream.flush()
945 ostream.write(self.text(etype, evalue, etb))
945 ostream.write(self.text(etype, evalue, etb))
946 ostream.write('\n')
946 ostream.write('\n')
947 ostream.flush()
947 ostream.flush()
948
948
949 # Changed so an instance can just be called as VerboseTB_inst() and print
949 # Changed so an instance can just be called as VerboseTB_inst() and print
950 # out the right info on its own.
950 # out the right info on its own.
951 def __call__(self, etype=None, evalue=None, etb=None):
951 def __call__(self, etype=None, evalue=None, etb=None):
952 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
952 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
953 if etb is None:
953 if etb is None:
954 self.handler()
954 self.handler()
955 else:
955 else:
956 self.handler((etype, evalue, etb))
956 self.handler((etype, evalue, etb))
957 try:
957 try:
958 self.debugger()
958 self.debugger()
959 except KeyboardInterrupt:
959 except KeyboardInterrupt:
960 print("\nKeyboardInterrupt")
960 print("\nKeyboardInterrupt")
961
961
962
962
963 #----------------------------------------------------------------------------
963 #----------------------------------------------------------------------------
964 class FormattedTB(VerboseTB, ListTB):
964 class FormattedTB(VerboseTB, ListTB):
965 """Subclass ListTB but allow calling with a traceback.
965 """Subclass ListTB but allow calling with a traceback.
966
966
967 It can thus be used as a sys.excepthook for Python > 2.1.
967 It can thus be used as a sys.excepthook for Python > 2.1.
968
968
969 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
969 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
970
970
971 Allows a tb_offset to be specified. This is useful for situations where
971 Allows a tb_offset to be specified. This is useful for situations where
972 one needs to remove a number of topmost frames from the traceback (such as
972 one needs to remove a number of topmost frames from the traceback (such as
973 occurs with python programs that themselves execute other python code,
973 occurs with python programs that themselves execute other python code,
974 like Python shells). """
974 like Python shells). """
975
975
976 mode: str
976 mode: str
977
977
978 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
978 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
979 ostream=None,
979 ostream=None,
980 tb_offset=0, long_header=False, include_vars=False,
980 tb_offset=0, long_header=False, include_vars=False,
981 check_cache=None, debugger_cls=None,
981 check_cache=None, debugger_cls=None,
982 parent=None, config=None):
982 parent=None, config=None):
983
983
984 # NEVER change the order of this list. Put new modes at the end:
984 # NEVER change the order of this list. Put new modes at the end:
985 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
985 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
986 self.verbose_modes = self.valid_modes[1:3]
986 self.verbose_modes = self.valid_modes[1:3]
987
987
988 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
988 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
989 ostream=ostream, tb_offset=tb_offset,
989 ostream=ostream, tb_offset=tb_offset,
990 long_header=long_header, include_vars=include_vars,
990 long_header=long_header, include_vars=include_vars,
991 check_cache=check_cache, debugger_cls=debugger_cls,
991 check_cache=check_cache, debugger_cls=debugger_cls,
992 parent=parent, config=config)
992 parent=parent, config=config)
993
993
994 # Different types of tracebacks are joined with different separators to
994 # Different types of tracebacks are joined with different separators to
995 # form a single string. They are taken from this dict
995 # form a single string. They are taken from this dict
996 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
996 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
997 Minimal='')
997 Minimal='')
998 # set_mode also sets the tb_join_char attribute
998 # set_mode also sets the tb_join_char attribute
999 self.set_mode(mode)
999 self.set_mode(mode)
1000
1000
1001 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1001 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1002 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1002 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1003 mode = self.mode
1003 mode = self.mode
1004 if mode in self.verbose_modes:
1004 if mode in self.verbose_modes:
1005 # Verbose modes need a full traceback
1005 # Verbose modes need a full traceback
1006 return VerboseTB.structured_traceback(
1006 return VerboseTB.structured_traceback(
1007 self, etype, value, tb, tb_offset, number_of_lines_of_context
1007 self, etype, value, tb, tb_offset, number_of_lines_of_context
1008 )
1008 )
1009 elif mode == 'Minimal':
1009 elif mode == 'Minimal':
1010 return ListTB.get_exception_only(self, etype, value)
1010 return ListTB.get_exception_only(self, etype, value)
1011 else:
1011 else:
1012 # We must check the source cache because otherwise we can print
1012 # We must check the source cache because otherwise we can print
1013 # out-of-date source code.
1013 # out-of-date source code.
1014 self.check_cache()
1014 self.check_cache()
1015 # Now we can extract and format the exception
1015 # Now we can extract and format the exception
1016 return ListTB.structured_traceback(
1016 return ListTB.structured_traceback(
1017 self, etype, value, tb, tb_offset, number_of_lines_of_context
1017 self, etype, value, tb, tb_offset, number_of_lines_of_context
1018 )
1018 )
1019
1019
1020 def stb2text(self, stb):
1020 def stb2text(self, stb):
1021 """Convert a structured traceback (a list) to a string."""
1021 """Convert a structured traceback (a list) to a string."""
1022 return self.tb_join_char.join(stb)
1022 return self.tb_join_char.join(stb)
1023
1023
1024 def set_mode(self, mode: Optional[str] = None):
1024 def set_mode(self, mode: Optional[str] = None):
1025 """Switch to the desired mode.
1025 """Switch to the desired mode.
1026
1026
1027 If mode is not specified, cycles through the available modes."""
1027 If mode is not specified, cycles through the available modes."""
1028
1028
1029 if not mode:
1029 if not mode:
1030 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1030 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1031 len(self.valid_modes)
1031 len(self.valid_modes)
1032 self.mode = self.valid_modes[new_idx]
1032 self.mode = self.valid_modes[new_idx]
1033 elif mode not in self.valid_modes:
1033 elif mode not in self.valid_modes:
1034 raise ValueError(
1034 raise ValueError(
1035 "Unrecognized mode in FormattedTB: <" + mode + ">\n"
1035 "Unrecognized mode in FormattedTB: <" + mode + ">\n"
1036 "Valid modes: " + str(self.valid_modes)
1036 "Valid modes: " + str(self.valid_modes)
1037 )
1037 )
1038 else:
1038 else:
1039 assert isinstance(mode, str)
1039 assert isinstance(mode, str)
1040 self.mode = mode
1040 self.mode = mode
1041 # include variable details only in 'Verbose' mode
1041 # include variable details only in 'Verbose' mode
1042 self.include_vars = (self.mode == self.valid_modes[2])
1042 self.include_vars = (self.mode == self.valid_modes[2])
1043 # Set the join character for generating text tracebacks
1043 # Set the join character for generating text tracebacks
1044 self.tb_join_char = self._join_chars[self.mode]
1044 self.tb_join_char = self._join_chars[self.mode]
1045
1045
1046 # some convenient shortcuts
1046 # some convenient shortcuts
1047 def plain(self):
1047 def plain(self):
1048 self.set_mode(self.valid_modes[0])
1048 self.set_mode(self.valid_modes[0])
1049
1049
1050 def context(self):
1050 def context(self):
1051 self.set_mode(self.valid_modes[1])
1051 self.set_mode(self.valid_modes[1])
1052
1052
1053 def verbose(self):
1053 def verbose(self):
1054 self.set_mode(self.valid_modes[2])
1054 self.set_mode(self.valid_modes[2])
1055
1055
1056 def minimal(self):
1056 def minimal(self):
1057 self.set_mode(self.valid_modes[3])
1057 self.set_mode(self.valid_modes[3])
1058
1058
1059
1059
1060 #----------------------------------------------------------------------------
1060 #----------------------------------------------------------------------------
1061 class AutoFormattedTB(FormattedTB):
1061 class AutoFormattedTB(FormattedTB):
1062 """A traceback printer which can be called on the fly.
1062 """A traceback printer which can be called on the fly.
1063
1063
1064 It will find out about exceptions by itself.
1064 It will find out about exceptions by itself.
1065
1065
1066 A brief example::
1066 A brief example::
1067
1067
1068 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1068 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1069 try:
1069 try:
1070 ...
1070 ...
1071 except:
1071 except:
1072 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1072 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1073 """
1073 """
1074
1074
1075 def __call__(self, etype=None, evalue=None, etb=None,
1075 def __call__(self, etype=None, evalue=None, etb=None,
1076 out=None, tb_offset=None):
1076 out=None, tb_offset=None):
1077 """Print out a formatted exception traceback.
1077 """Print out a formatted exception traceback.
1078
1078
1079 Optional arguments:
1079 Optional arguments:
1080 - out: an open file-like object to direct output to.
1080 - out: an open file-like object to direct output to.
1081
1081
1082 - tb_offset: the number of frames to skip over in the stack, on a
1082 - tb_offset: the number of frames to skip over in the stack, on a
1083 per-call basis (this overrides temporarily the instance's tb_offset
1083 per-call basis (this overrides temporarily the instance's tb_offset
1084 given at initialization time."""
1084 given at initialization time."""
1085
1085
1086 if out is None:
1086 if out is None:
1087 out = self.ostream
1087 out = self.ostream
1088 out.flush()
1088 out.flush()
1089 out.write(self.text(etype, evalue, etb, tb_offset))
1089 out.write(self.text(etype, evalue, etb, tb_offset))
1090 out.write('\n')
1090 out.write('\n')
1091 out.flush()
1091 out.flush()
1092 # FIXME: we should remove the auto pdb behavior from here and leave
1092 # FIXME: we should remove the auto pdb behavior from here and leave
1093 # that to the clients.
1093 # that to the clients.
1094 try:
1094 try:
1095 self.debugger()
1095 self.debugger()
1096 except KeyboardInterrupt:
1096 except KeyboardInterrupt:
1097 print("\nKeyboardInterrupt")
1097 print("\nKeyboardInterrupt")
1098
1098
1099 def structured_traceback(self, etype=None, value=None, tb=None,
1099 def structured_traceback(self, etype=None, value=None, tb=None,
1100 tb_offset=None, number_of_lines_of_context=5):
1100 tb_offset=None, number_of_lines_of_context=5):
1101
1101
1102 etype: type
1102 etype: type
1103 value: BaseException
1103 value: BaseException
1104 # tb: TracebackType or tupleof tb types ?
1104 # tb: TracebackType or tupleof tb types ?
1105 if etype is None:
1105 if etype is None:
1106 etype, value, tb = sys.exc_info()
1106 etype, value, tb = sys.exc_info()
1107 if isinstance(tb, tuple):
1107 if isinstance(tb, tuple):
1108 # tb is a tuple if this is a chained exception.
1108 # tb is a tuple if this is a chained exception.
1109 self.tb = tb[0]
1109 self.tb = tb[0]
1110 else:
1110 else:
1111 self.tb = tb
1111 self.tb = tb
1112 return FormattedTB.structured_traceback(
1112 return FormattedTB.structured_traceback(
1113 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1113 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1114
1114
1115
1115
1116 #---------------------------------------------------------------------------
1116 #---------------------------------------------------------------------------
1117
1117
1118 # A simple class to preserve Nathan's original functionality.
1118 # A simple class to preserve Nathan's original functionality.
1119 class ColorTB(FormattedTB):
1119 class ColorTB(FormattedTB):
1120 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1120 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1121
1121
1122 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1122 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1123 FormattedTB.__init__(self, color_scheme=color_scheme,
1123 FormattedTB.__init__(self, color_scheme=color_scheme,
1124 call_pdb=call_pdb, **kwargs)
1124 call_pdb=call_pdb, **kwargs)
1125
1125
1126
1126
1127 class SyntaxTB(ListTB):
1127 class SyntaxTB(ListTB):
1128 """Extension which holds some state: the last exception value"""
1128 """Extension which holds some state: the last exception value"""
1129
1129
1130 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1130 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1131 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1131 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1132 self.last_syntax_error = None
1132 self.last_syntax_error = None
1133
1133
1134 def __call__(self, etype, value, elist):
1134 def __call__(self, etype, value, elist):
1135 self.last_syntax_error = value
1135 self.last_syntax_error = value
1136
1136
1137 ListTB.__call__(self, etype, value, elist)
1137 ListTB.__call__(self, etype, value, elist)
1138
1138
1139 def structured_traceback(self, etype, value, elist, tb_offset=None,
1139 def structured_traceback(self, etype, value, elist, tb_offset=None,
1140 context=5):
1140 context=5):
1141 # If the source file has been edited, the line in the syntax error can
1141 # If the source file has been edited, the line in the syntax error can
1142 # be wrong (retrieved from an outdated cache). This replaces it with
1142 # be wrong (retrieved from an outdated cache). This replaces it with
1143 # the current value.
1143 # the current value.
1144 if isinstance(value, SyntaxError) \
1144 if isinstance(value, SyntaxError) \
1145 and isinstance(value.filename, str) \
1145 and isinstance(value.filename, str) \
1146 and isinstance(value.lineno, int):
1146 and isinstance(value.lineno, int):
1147 linecache.checkcache(value.filename)
1147 linecache.checkcache(value.filename)
1148 newtext = linecache.getline(value.filename, value.lineno)
1148 newtext = linecache.getline(value.filename, value.lineno)
1149 if newtext:
1149 if newtext:
1150 value.text = newtext
1150 value.text = newtext
1151 self.last_syntax_error = value
1151 self.last_syntax_error = value
1152 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1152 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1153 tb_offset=tb_offset, context=context)
1153 tb_offset=tb_offset, context=context)
1154
1154
1155 def clear_err_state(self):
1155 def clear_err_state(self):
1156 """Return the current error state and clear it"""
1156 """Return the current error state and clear it"""
1157 e = self.last_syntax_error
1157 e = self.last_syntax_error
1158 self.last_syntax_error = None
1158 self.last_syntax_error = None
1159 return e
1159 return e
1160
1160
1161 def stb2text(self, stb):
1161 def stb2text(self, stb):
1162 """Convert a structured traceback (a list) to a string."""
1162 """Convert a structured traceback (a list) to a string."""
1163 return ''.join(stb)
1163 return ''.join(stb)
1164
1164
1165
1165
1166 # some internal-use functions
1166 # some internal-use functions
1167 def text_repr(value):
1167 def text_repr(value):
1168 """Hopefully pretty robust repr equivalent."""
1168 """Hopefully pretty robust repr equivalent."""
1169 # this is pretty horrible but should always return *something*
1169 # this is pretty horrible but should always return *something*
1170 try:
1170 try:
1171 return pydoc.text.repr(value)
1171 return pydoc.text.repr(value)
1172 except KeyboardInterrupt:
1172 except KeyboardInterrupt:
1173 raise
1173 raise
1174 except:
1174 except:
1175 try:
1175 try:
1176 return repr(value)
1176 return repr(value)
1177 except KeyboardInterrupt:
1177 except KeyboardInterrupt:
1178 raise
1178 raise
1179 except:
1179 except:
1180 try:
1180 try:
1181 # all still in an except block so we catch
1181 # all still in an except block so we catch
1182 # getattr raising
1182 # getattr raising
1183 name = getattr(value, '__name__', None)
1183 name = getattr(value, '__name__', None)
1184 if name:
1184 if name:
1185 # ick, recursion
1185 # ick, recursion
1186 return text_repr(name)
1186 return text_repr(name)
1187 klass = getattr(value, '__class__', None)
1187 klass = getattr(value, '__class__', None)
1188 if klass:
1188 if klass:
1189 return '%s instance' % text_repr(klass)
1189 return '%s instance' % text_repr(klass)
1190 except KeyboardInterrupt:
1190 except KeyboardInterrupt:
1191 raise
1191 raise
1192 except:
1192 except:
1193 return 'UNRECOVERABLE REPR FAILURE'
1193 return 'UNRECOVERABLE REPR FAILURE'
1194
1194
1195
1195
1196 def eqrepr(value, repr=text_repr):
1196 def eqrepr(value, repr=text_repr):
1197 return '=%s' % repr(value)
1197 return '=%s' % repr(value)
1198
1198
1199
1199
1200 def nullrepr(value, repr=text_repr):
1200 def nullrepr(value, repr=text_repr):
1201 return ''
1201 return ''
@@ -1,676 +1,680 b''
1 """IPython extension to reload modules before executing user code.
1 """IPython extension to reload modules before executing user code.
2
2
3 ``autoreload`` reloads modules automatically before entering the execution of
3 ``autoreload`` reloads modules automatically before entering the execution of
4 code typed at the IPython prompt.
4 code typed at the IPython prompt.
5
5
6 This makes for example the following workflow possible:
6 This makes for example the following workflow possible:
7
7
8 .. sourcecode:: ipython
8 .. sourcecode:: ipython
9
9
10 In [1]: %load_ext autoreload
10 In [1]: %load_ext autoreload
11
11
12 In [2]: %autoreload 2
12 In [2]: %autoreload 2
13
13
14 In [3]: from foo import some_function
14 In [3]: from foo import some_function
15
15
16 In [4]: some_function()
16 In [4]: some_function()
17 Out[4]: 42
17 Out[4]: 42
18
18
19 In [5]: # open foo.py in an editor and change some_function to return 43
19 In [5]: # open foo.py in an editor and change some_function to return 43
20
20
21 In [6]: some_function()
21 In [6]: some_function()
22 Out[6]: 43
22 Out[6]: 43
23
23
24 The module was reloaded without reloading it explicitly, and the object
24 The module was reloaded without reloading it explicitly, and the object
25 imported with ``from foo import ...`` was also updated.
25 imported with ``from foo import ...`` was also updated.
26
26
27 Usage
27 Usage
28 =====
28 =====
29
29
30 The following magic commands are provided:
30 The following magic commands are provided:
31
31
32 ``%autoreload``, ``%autoreload now``
32 ``%autoreload``, ``%autoreload now``
33
33
34 Reload all modules (except those excluded by ``%aimport``)
34 Reload all modules (except those excluded by ``%aimport``)
35 automatically now.
35 automatically now.
36
36
37 ``%autoreload 0``, ``%autoreload off``
37 ``%autoreload 0``, ``%autoreload off``
38
38
39 Disable automatic reloading.
39 Disable automatic reloading.
40
40
41 ``%autoreload 1``, ``%autoreload explicit``
41 ``%autoreload 1``, ``%autoreload explicit``
42
42
43 Reload all modules imported with ``%aimport`` every time before
43 Reload all modules imported with ``%aimport`` every time before
44 executing the Python code typed.
44 executing the Python code typed.
45
45
46 ``%autoreload 2``, ``%autoreload all``
46 ``%autoreload 2``, ``%autoreload all``
47
47
48 Reload all modules (except those excluded by ``%aimport``) every
48 Reload all modules (except those excluded by ``%aimport``) every
49 time before executing the Python code typed.
49 time before executing the Python code typed.
50
50
51 ``%autoreload 3``, ``%autoreload complete``
51 ``%autoreload 3``, ``%autoreload complete``
52
52
53 Same as 2/all, but also adds any new objects in the module. See
53 Same as 2/all, but also adds any new objects in the module. See
54 unit test at IPython/extensions/tests/test_autoreload.py::test_autoload_newly_added_objects
54 unit test at IPython/extensions/tests/test_autoreload.py::test_autoload_newly_added_objects
55
55
56 ``%aimport``
56 ``%aimport``
57
57
58 List modules which are to be automatically imported or not to be imported.
58 List modules which are to be automatically imported or not to be imported.
59
59
60 ``%aimport foo``
60 ``%aimport foo``
61
61
62 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
62 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
63
63
64 ``%aimport foo, bar``
64 ``%aimport foo, bar``
65
65
66 Import modules 'foo', 'bar' and mark them to be autoreloaded for ``%autoreload 1``
66 Import modules 'foo', 'bar' and mark them to be autoreloaded for ``%autoreload 1``
67
67
68 ``%aimport -foo``
68 ``%aimport -foo``
69
69
70 Mark module 'foo' to not be autoreloaded.
70 Mark module 'foo' to not be autoreloaded.
71
71
72 ``%averbose off``
72 ``%averbose off``
73
73
74 Perform autoreload tasks quietly
74 Perform autoreload tasks quietly
75
75
76 ``%averbose on``
76 ``%averbose on``
77
77
78 Report activity with `print` statements.
78 Report activity with `print` statements.
79
79
80 ``%averbose log``
80 ``%averbose log``
81
81
82 Report activity with the logger.
82 Report activity with the logger.
83
83
84 Caveats
84 Caveats
85 =======
85 =======
86
86
87 Reloading Python modules in a reliable way is in general difficult,
87 Reloading Python modules in a reliable way is in general difficult,
88 and unexpected things may occur. ``%autoreload`` tries to work around
88 and unexpected things may occur. ``%autoreload`` tries to work around
89 common pitfalls by replacing function code objects and parts of
89 common pitfalls by replacing function code objects and parts of
90 classes previously in the module with new versions. This makes the
90 classes previously in the module with new versions. This makes the
91 following things to work:
91 following things to work:
92
92
93 - Functions and classes imported via 'from xxx import foo' are upgraded
93 - Functions and classes imported via 'from xxx import foo' are upgraded
94 to new versions when 'xxx' is reloaded.
94 to new versions when 'xxx' is reloaded.
95
95
96 - Methods and properties of classes are upgraded on reload, so that
96 - Methods and properties of classes are upgraded on reload, so that
97 calling 'c.foo()' on an object 'c' created before the reload causes
97 calling 'c.foo()' on an object 'c' created before the reload causes
98 the new code for 'foo' to be executed.
98 the new code for 'foo' to be executed.
99
99
100 Some of the known remaining caveats are:
100 Some of the known remaining caveats are:
101
101
102 - Replacing code objects does not always succeed: changing a @property
102 - Replacing code objects does not always succeed: changing a @property
103 in a class to an ordinary method or a method to a member variable
103 in a class to an ordinary method or a method to a member variable
104 can cause problems (but in old objects only).
104 can cause problems (but in old objects only).
105
105
106 - Functions that are removed (eg. via monkey-patching) from a module
106 - Functions that are removed (eg. via monkey-patching) from a module
107 before it is reloaded are not upgraded.
107 before it is reloaded are not upgraded.
108
108
109 - C extension modules cannot be reloaded, and so cannot be autoreloaded.
109 - C extension modules cannot be reloaded, and so cannot be autoreloaded.
110
111 - While comparing Enum and Flag, the 'is' Identity Operator is used (even in the case '==' has been used (Similar to the 'None' keyword)).
112
113 - Reloading a module, or importing the same module by a different name, creates new Enums. These may look the same, but are not.
110 """
114 """
111
115
112 from IPython.core.magic import Magics, magics_class, line_magic
116 from IPython.core.magic import Magics, magics_class, line_magic
113
117
114 __skip_doctest__ = True
118 __skip_doctest__ = True
115
119
116 # -----------------------------------------------------------------------------
120 # -----------------------------------------------------------------------------
117 # Copyright (C) 2000 Thomas Heller
121 # Copyright (C) 2000 Thomas Heller
118 # Copyright (C) 2008 Pauli Virtanen <pav@iki.fi>
122 # Copyright (C) 2008 Pauli Virtanen <pav@iki.fi>
119 # Copyright (C) 2012 The IPython Development Team
123 # Copyright (C) 2012 The IPython Development Team
120 #
124 #
121 # Distributed under the terms of the BSD License. The full license is in
125 # Distributed under the terms of the BSD License. The full license is in
122 # the file COPYING, distributed as part of this software.
126 # the file COPYING, distributed as part of this software.
123 # -----------------------------------------------------------------------------
127 # -----------------------------------------------------------------------------
124 #
128 #
125 # This IPython module is written by Pauli Virtanen, based on the autoreload
129 # This IPython module is written by Pauli Virtanen, based on the autoreload
126 # code by Thomas Heller.
130 # code by Thomas Heller.
127
131
128 # -----------------------------------------------------------------------------
132 # -----------------------------------------------------------------------------
129 # Imports
133 # Imports
130 # -----------------------------------------------------------------------------
134 # -----------------------------------------------------------------------------
131
135
132 import os
136 import os
133 import sys
137 import sys
134 import traceback
138 import traceback
135 import types
139 import types
136 import weakref
140 import weakref
137 import gc
141 import gc
138 import logging
142 import logging
139 from importlib import import_module, reload
143 from importlib import import_module, reload
140 from importlib.util import source_from_cache
144 from importlib.util import source_from_cache
141
145
142 # ------------------------------------------------------------------------------
146 # ------------------------------------------------------------------------------
143 # Autoreload functionality
147 # Autoreload functionality
144 # ------------------------------------------------------------------------------
148 # ------------------------------------------------------------------------------
145
149
146
150
147 class ModuleReloader:
151 class ModuleReloader:
148 enabled = False
152 enabled = False
149 """Whether this reloader is enabled"""
153 """Whether this reloader is enabled"""
150
154
151 check_all = True
155 check_all = True
152 """Autoreload all modules, not just those listed in 'modules'"""
156 """Autoreload all modules, not just those listed in 'modules'"""
153
157
154 autoload_obj = False
158 autoload_obj = False
155 """Autoreload all modules AND autoload all new objects"""
159 """Autoreload all modules AND autoload all new objects"""
156
160
157 def __init__(self, shell=None):
161 def __init__(self, shell=None):
158 # Modules that failed to reload: {module: mtime-on-failed-reload, ...}
162 # Modules that failed to reload: {module: mtime-on-failed-reload, ...}
159 self.failed = {}
163 self.failed = {}
160 # Modules specially marked as autoreloadable.
164 # Modules specially marked as autoreloadable.
161 self.modules = {}
165 self.modules = {}
162 # Modules specially marked as not autoreloadable.
166 # Modules specially marked as not autoreloadable.
163 self.skip_modules = {}
167 self.skip_modules = {}
164 # (module-name, name) -> weakref, for replacing old code objects
168 # (module-name, name) -> weakref, for replacing old code objects
165 self.old_objects = {}
169 self.old_objects = {}
166 # Module modification timestamps
170 # Module modification timestamps
167 self.modules_mtimes = {}
171 self.modules_mtimes = {}
168 self.shell = shell
172 self.shell = shell
169
173
170 # Reporting callable for verbosity
174 # Reporting callable for verbosity
171 self._report = lambda msg: None # by default, be quiet.
175 self._report = lambda msg: None # by default, be quiet.
172
176
173 # Cache module modification times
177 # Cache module modification times
174 self.check(check_all=True, do_reload=False)
178 self.check(check_all=True, do_reload=False)
175
179
176 def mark_module_skipped(self, module_name):
180 def mark_module_skipped(self, module_name):
177 """Skip reloading the named module in the future"""
181 """Skip reloading the named module in the future"""
178 try:
182 try:
179 del self.modules[module_name]
183 del self.modules[module_name]
180 except KeyError:
184 except KeyError:
181 pass
185 pass
182 self.skip_modules[module_name] = True
186 self.skip_modules[module_name] = True
183
187
184 def mark_module_reloadable(self, module_name):
188 def mark_module_reloadable(self, module_name):
185 """Reload the named module in the future (if it is imported)"""
189 """Reload the named module in the future (if it is imported)"""
186 try:
190 try:
187 del self.skip_modules[module_name]
191 del self.skip_modules[module_name]
188 except KeyError:
192 except KeyError:
189 pass
193 pass
190 self.modules[module_name] = True
194 self.modules[module_name] = True
191
195
192 def aimport_module(self, module_name):
196 def aimport_module(self, module_name):
193 """Import a module, and mark it reloadable
197 """Import a module, and mark it reloadable
194
198
195 Returns
199 Returns
196 -------
200 -------
197 top_module : module
201 top_module : module
198 The imported module if it is top-level, or the top-level
202 The imported module if it is top-level, or the top-level
199 top_name : module
203 top_name : module
200 Name of top_module
204 Name of top_module
201
205
202 """
206 """
203 self.mark_module_reloadable(module_name)
207 self.mark_module_reloadable(module_name)
204
208
205 import_module(module_name)
209 import_module(module_name)
206 top_name = module_name.split(".")[0]
210 top_name = module_name.split(".")[0]
207 top_module = sys.modules[top_name]
211 top_module = sys.modules[top_name]
208 return top_module, top_name
212 return top_module, top_name
209
213
210 def filename_and_mtime(self, module):
214 def filename_and_mtime(self, module):
211 if not hasattr(module, "__file__") or module.__file__ is None:
215 if not hasattr(module, "__file__") or module.__file__ is None:
212 return None, None
216 return None, None
213
217
214 if getattr(module, "__name__", None) in [None, "__mp_main__", "__main__"]:
218 if getattr(module, "__name__", None) in [None, "__mp_main__", "__main__"]:
215 # we cannot reload(__main__) or reload(__mp_main__)
219 # we cannot reload(__main__) or reload(__mp_main__)
216 return None, None
220 return None, None
217
221
218 filename = module.__file__
222 filename = module.__file__
219 path, ext = os.path.splitext(filename)
223 path, ext = os.path.splitext(filename)
220
224
221 if ext.lower() == ".py":
225 if ext.lower() == ".py":
222 py_filename = filename
226 py_filename = filename
223 else:
227 else:
224 try:
228 try:
225 py_filename = source_from_cache(filename)
229 py_filename = source_from_cache(filename)
226 except ValueError:
230 except ValueError:
227 return None, None
231 return None, None
228
232
229 try:
233 try:
230 pymtime = os.stat(py_filename).st_mtime
234 pymtime = os.stat(py_filename).st_mtime
231 except OSError:
235 except OSError:
232 return None, None
236 return None, None
233
237
234 return py_filename, pymtime
238 return py_filename, pymtime
235
239
236 def check(self, check_all=False, do_reload=True):
240 def check(self, check_all=False, do_reload=True):
237 """Check whether some modules need to be reloaded."""
241 """Check whether some modules need to be reloaded."""
238
242
239 if not self.enabled and not check_all:
243 if not self.enabled and not check_all:
240 return
244 return
241
245
242 if check_all or self.check_all:
246 if check_all or self.check_all:
243 modules = list(sys.modules.keys())
247 modules = list(sys.modules.keys())
244 else:
248 else:
245 modules = list(self.modules.keys())
249 modules = list(self.modules.keys())
246
250
247 for modname in modules:
251 for modname in modules:
248 m = sys.modules.get(modname, None)
252 m = sys.modules.get(modname, None)
249
253
250 if modname in self.skip_modules:
254 if modname in self.skip_modules:
251 continue
255 continue
252
256
253 py_filename, pymtime = self.filename_and_mtime(m)
257 py_filename, pymtime = self.filename_and_mtime(m)
254 if py_filename is None:
258 if py_filename is None:
255 continue
259 continue
256
260
257 try:
261 try:
258 if pymtime <= self.modules_mtimes[modname]:
262 if pymtime <= self.modules_mtimes[modname]:
259 continue
263 continue
260 except KeyError:
264 except KeyError:
261 self.modules_mtimes[modname] = pymtime
265 self.modules_mtimes[modname] = pymtime
262 continue
266 continue
263 else:
267 else:
264 if self.failed.get(py_filename, None) == pymtime:
268 if self.failed.get(py_filename, None) == pymtime:
265 continue
269 continue
266
270
267 self.modules_mtimes[modname] = pymtime
271 self.modules_mtimes[modname] = pymtime
268
272
269 # If we've reached this point, we should try to reload the module
273 # If we've reached this point, we should try to reload the module
270 if do_reload:
274 if do_reload:
271 self._report(f"Reloading '{modname}'.")
275 self._report(f"Reloading '{modname}'.")
272 try:
276 try:
273 if self.autoload_obj:
277 if self.autoload_obj:
274 superreload(m, reload, self.old_objects, self.shell)
278 superreload(m, reload, self.old_objects, self.shell)
275 else:
279 else:
276 superreload(m, reload, self.old_objects)
280 superreload(m, reload, self.old_objects)
277 if py_filename in self.failed:
281 if py_filename in self.failed:
278 del self.failed[py_filename]
282 del self.failed[py_filename]
279 except:
283 except:
280 print(
284 print(
281 "[autoreload of {} failed: {}]".format(
285 "[autoreload of {} failed: {}]".format(
282 modname, traceback.format_exc(10)
286 modname, traceback.format_exc(10)
283 ),
287 ),
284 file=sys.stderr,
288 file=sys.stderr,
285 )
289 )
286 self.failed[py_filename] = pymtime
290 self.failed[py_filename] = pymtime
287
291
288
292
289 # ------------------------------------------------------------------------------
293 # ------------------------------------------------------------------------------
290 # superreload
294 # superreload
291 # ------------------------------------------------------------------------------
295 # ------------------------------------------------------------------------------
292
296
293
297
294 func_attrs = [
298 func_attrs = [
295 "__code__",
299 "__code__",
296 "__defaults__",
300 "__defaults__",
297 "__doc__",
301 "__doc__",
298 "__closure__",
302 "__closure__",
299 "__globals__",
303 "__globals__",
300 "__dict__",
304 "__dict__",
301 ]
305 ]
302
306
303
307
304 def update_function(old, new):
308 def update_function(old, new):
305 """Upgrade the code object of a function"""
309 """Upgrade the code object of a function"""
306 for name in func_attrs:
310 for name in func_attrs:
307 try:
311 try:
308 setattr(old, name, getattr(new, name))
312 setattr(old, name, getattr(new, name))
309 except (AttributeError, TypeError):
313 except (AttributeError, TypeError):
310 pass
314 pass
311
315
312
316
313 def update_instances(old, new):
317 def update_instances(old, new):
314 """Use garbage collector to find all instances that refer to the old
318 """Use garbage collector to find all instances that refer to the old
315 class definition and update their __class__ to point to the new class
319 class definition and update their __class__ to point to the new class
316 definition"""
320 definition"""
317
321
318 refs = gc.get_referrers(old)
322 refs = gc.get_referrers(old)
319
323
320 for ref in refs:
324 for ref in refs:
321 if type(ref) is old:
325 if type(ref) is old:
322 object.__setattr__(ref, "__class__", new)
326 object.__setattr__(ref, "__class__", new)
323
327
324
328
325 def update_class(old, new):
329 def update_class(old, new):
326 """Replace stuff in the __dict__ of a class, and upgrade
330 """Replace stuff in the __dict__ of a class, and upgrade
327 method code objects, and add new methods, if any"""
331 method code objects, and add new methods, if any"""
328 for key in list(old.__dict__.keys()):
332 for key in list(old.__dict__.keys()):
329 old_obj = getattr(old, key)
333 old_obj = getattr(old, key)
330 try:
334 try:
331 new_obj = getattr(new, key)
335 new_obj = getattr(new, key)
332 # explicitly checking that comparison returns True to handle
336 # explicitly checking that comparison returns True to handle
333 # cases where `==` doesn't return a boolean.
337 # cases where `==` doesn't return a boolean.
334 if (old_obj == new_obj) is True:
338 if (old_obj == new_obj) is True:
335 continue
339 continue
336 except AttributeError:
340 except AttributeError:
337 # obsolete attribute: remove it
341 # obsolete attribute: remove it
338 try:
342 try:
339 delattr(old, key)
343 delattr(old, key)
340 except (AttributeError, TypeError):
344 except (AttributeError, TypeError):
341 pass
345 pass
342 continue
346 continue
343 except ValueError:
347 except ValueError:
344 # can't compare nested structures containing
348 # can't compare nested structures containing
345 # numpy arrays using `==`
349 # numpy arrays using `==`
346 pass
350 pass
347
351
348 if update_generic(old_obj, new_obj):
352 if update_generic(old_obj, new_obj):
349 continue
353 continue
350
354
351 try:
355 try:
352 setattr(old, key, getattr(new, key))
356 setattr(old, key, getattr(new, key))
353 except (AttributeError, TypeError):
357 except (AttributeError, TypeError):
354 pass # skip non-writable attributes
358 pass # skip non-writable attributes
355
359
356 for key in list(new.__dict__.keys()):
360 for key in list(new.__dict__.keys()):
357 if key not in list(old.__dict__.keys()):
361 if key not in list(old.__dict__.keys()):
358 try:
362 try:
359 setattr(old, key, getattr(new, key))
363 setattr(old, key, getattr(new, key))
360 except (AttributeError, TypeError):
364 except (AttributeError, TypeError):
361 pass # skip non-writable attributes
365 pass # skip non-writable attributes
362
366
363 # update all instances of class
367 # update all instances of class
364 update_instances(old, new)
368 update_instances(old, new)
365
369
366
370
367 def update_property(old, new):
371 def update_property(old, new):
368 """Replace get/set/del functions of a property"""
372 """Replace get/set/del functions of a property"""
369 update_generic(old.fdel, new.fdel)
373 update_generic(old.fdel, new.fdel)
370 update_generic(old.fget, new.fget)
374 update_generic(old.fget, new.fget)
371 update_generic(old.fset, new.fset)
375 update_generic(old.fset, new.fset)
372
376
373
377
374 def isinstance2(a, b, typ):
378 def isinstance2(a, b, typ):
375 return isinstance(a, typ) and isinstance(b, typ)
379 return isinstance(a, typ) and isinstance(b, typ)
376
380
377
381
378 UPDATE_RULES = [
382 UPDATE_RULES = [
379 (lambda a, b: isinstance2(a, b, type), update_class),
383 (lambda a, b: isinstance2(a, b, type), update_class),
380 (lambda a, b: isinstance2(a, b, types.FunctionType), update_function),
384 (lambda a, b: isinstance2(a, b, types.FunctionType), update_function),
381 (lambda a, b: isinstance2(a, b, property), update_property),
385 (lambda a, b: isinstance2(a, b, property), update_property),
382 ]
386 ]
383 UPDATE_RULES.extend(
387 UPDATE_RULES.extend(
384 [
388 [
385 (
389 (
386 lambda a, b: isinstance2(a, b, types.MethodType),
390 lambda a, b: isinstance2(a, b, types.MethodType),
387 lambda a, b: update_function(a.__func__, b.__func__),
391 lambda a, b: update_function(a.__func__, b.__func__),
388 ),
392 ),
389 ]
393 ]
390 )
394 )
391
395
392
396
393 def update_generic(a, b):
397 def update_generic(a, b):
394 for type_check, update in UPDATE_RULES:
398 for type_check, update in UPDATE_RULES:
395 if type_check(a, b):
399 if type_check(a, b):
396 update(a, b)
400 update(a, b)
397 return True
401 return True
398 return False
402 return False
399
403
400
404
401 class StrongRef:
405 class StrongRef:
402 def __init__(self, obj):
406 def __init__(self, obj):
403 self.obj = obj
407 self.obj = obj
404
408
405 def __call__(self):
409 def __call__(self):
406 return self.obj
410 return self.obj
407
411
408
412
409 mod_attrs = [
413 mod_attrs = [
410 "__name__",
414 "__name__",
411 "__doc__",
415 "__doc__",
412 "__package__",
416 "__package__",
413 "__loader__",
417 "__loader__",
414 "__spec__",
418 "__spec__",
415 "__file__",
419 "__file__",
416 "__cached__",
420 "__cached__",
417 "__builtins__",
421 "__builtins__",
418 ]
422 ]
419
423
420
424
421 def append_obj(module, d, name, obj, autoload=False):
425 def append_obj(module, d, name, obj, autoload=False):
422 in_module = hasattr(obj, "__module__") and obj.__module__ == module.__name__
426 in_module = hasattr(obj, "__module__") and obj.__module__ == module.__name__
423 if autoload:
427 if autoload:
424 # check needed for module global built-ins
428 # check needed for module global built-ins
425 if not in_module and name in mod_attrs:
429 if not in_module and name in mod_attrs:
426 return False
430 return False
427 else:
431 else:
428 if not in_module:
432 if not in_module:
429 return False
433 return False
430
434
431 key = (module.__name__, name)
435 key = (module.__name__, name)
432 try:
436 try:
433 d.setdefault(key, []).append(weakref.ref(obj))
437 d.setdefault(key, []).append(weakref.ref(obj))
434 except TypeError:
438 except TypeError:
435 pass
439 pass
436 return True
440 return True
437
441
438
442
439 def superreload(module, reload=reload, old_objects=None, shell=None):
443 def superreload(module, reload=reload, old_objects=None, shell=None):
440 """Enhanced version of the builtin reload function.
444 """Enhanced version of the builtin reload function.
441
445
442 superreload remembers objects previously in the module, and
446 superreload remembers objects previously in the module, and
443
447
444 - upgrades the class dictionary of every old class in the module
448 - upgrades the class dictionary of every old class in the module
445 - upgrades the code object of every old function and method
449 - upgrades the code object of every old function and method
446 - clears the module's namespace before reloading
450 - clears the module's namespace before reloading
447
451
448 """
452 """
449 if old_objects is None:
453 if old_objects is None:
450 old_objects = {}
454 old_objects = {}
451
455
452 # collect old objects in the module
456 # collect old objects in the module
453 for name, obj in list(module.__dict__.items()):
457 for name, obj in list(module.__dict__.items()):
454 if not append_obj(module, old_objects, name, obj):
458 if not append_obj(module, old_objects, name, obj):
455 continue
459 continue
456 key = (module.__name__, name)
460 key = (module.__name__, name)
457 try:
461 try:
458 old_objects.setdefault(key, []).append(weakref.ref(obj))
462 old_objects.setdefault(key, []).append(weakref.ref(obj))
459 except TypeError:
463 except TypeError:
460 pass
464 pass
461
465
462 # reload module
466 # reload module
463 try:
467 try:
464 # clear namespace first from old cruft
468 # clear namespace first from old cruft
465 old_dict = module.__dict__.copy()
469 old_dict = module.__dict__.copy()
466 old_name = module.__name__
470 old_name = module.__name__
467 module.__dict__.clear()
471 module.__dict__.clear()
468 module.__dict__["__name__"] = old_name
472 module.__dict__["__name__"] = old_name
469 module.__dict__["__loader__"] = old_dict["__loader__"]
473 module.__dict__["__loader__"] = old_dict["__loader__"]
470 except (TypeError, AttributeError, KeyError):
474 except (TypeError, AttributeError, KeyError):
471 pass
475 pass
472
476
473 try:
477 try:
474 module = reload(module)
478 module = reload(module)
475 except:
479 except:
476 # restore module dictionary on failed reload
480 # restore module dictionary on failed reload
477 module.__dict__.update(old_dict)
481 module.__dict__.update(old_dict)
478 raise
482 raise
479
483
480 # iterate over all objects and update functions & classes
484 # iterate over all objects and update functions & classes
481 for name, new_obj in list(module.__dict__.items()):
485 for name, new_obj in list(module.__dict__.items()):
482 key = (module.__name__, name)
486 key = (module.__name__, name)
483 if key not in old_objects:
487 if key not in old_objects:
484 # here 'shell' acts both as a flag and as an output var
488 # here 'shell' acts both as a flag and as an output var
485 if (
489 if (
486 shell is None
490 shell is None
487 or name == "Enum"
491 or name == "Enum"
488 or not append_obj(module, old_objects, name, new_obj, True)
492 or not append_obj(module, old_objects, name, new_obj, True)
489 ):
493 ):
490 continue
494 continue
491 shell.user_ns[name] = new_obj
495 shell.user_ns[name] = new_obj
492
496
493 new_refs = []
497 new_refs = []
494 for old_ref in old_objects[key]:
498 for old_ref in old_objects[key]:
495 old_obj = old_ref()
499 old_obj = old_ref()
496 if old_obj is None:
500 if old_obj is None:
497 continue
501 continue
498 new_refs.append(old_ref)
502 new_refs.append(old_ref)
499 update_generic(old_obj, new_obj)
503 update_generic(old_obj, new_obj)
500
504
501 if new_refs:
505 if new_refs:
502 old_objects[key] = new_refs
506 old_objects[key] = new_refs
503 else:
507 else:
504 del old_objects[key]
508 del old_objects[key]
505
509
506 return module
510 return module
507
511
508
512
509 # ------------------------------------------------------------------------------
513 # ------------------------------------------------------------------------------
510 # IPython connectivity
514 # IPython connectivity
511 # ------------------------------------------------------------------------------
515 # ------------------------------------------------------------------------------
512
516
513
517
514 @magics_class
518 @magics_class
515 class AutoreloadMagics(Magics):
519 class AutoreloadMagics(Magics):
516 def __init__(self, *a, **kw):
520 def __init__(self, *a, **kw):
517 super().__init__(*a, **kw)
521 super().__init__(*a, **kw)
518 self._reloader = ModuleReloader(self.shell)
522 self._reloader = ModuleReloader(self.shell)
519 self._reloader.check_all = False
523 self._reloader.check_all = False
520 self._reloader.autoload_obj = False
524 self._reloader.autoload_obj = False
521 self.loaded_modules = set(sys.modules)
525 self.loaded_modules = set(sys.modules)
522
526
523 @line_magic
527 @line_magic
524 def autoreload(self, parameter_s=""):
528 def autoreload(self, parameter_s=""):
525 r"""%autoreload => Reload modules automatically
529 r"""%autoreload => Reload modules automatically
526
530
527 %autoreload or %autoreload now
531 %autoreload or %autoreload now
528 Reload all modules (except those excluded by %aimport) automatically
532 Reload all modules (except those excluded by %aimport) automatically
529 now.
533 now.
530
534
531 %autoreload 0 or %autoreload off
535 %autoreload 0 or %autoreload off
532 Disable automatic reloading.
536 Disable automatic reloading.
533
537
534 %autoreload 1 or %autoreload explicit
538 %autoreload 1 or %autoreload explicit
535 Reload only modules imported with %aimport every time before executing
539 Reload only modules imported with %aimport every time before executing
536 the Python code typed.
540 the Python code typed.
537
541
538 %autoreload 2 or %autoreload all
542 %autoreload 2 or %autoreload all
539 Reload all modules (except those excluded by %aimport) every time
543 Reload all modules (except those excluded by %aimport) every time
540 before executing the Python code typed.
544 before executing the Python code typed.
541
545
542 %autoreload 3 or %autoreload complete
546 %autoreload 3 or %autoreload complete
543 Same as 2/all, but also but also adds any new objects in the module. See
547 Same as 2/all, but also but also adds any new objects in the module. See
544 unit test at IPython/extensions/tests/test_autoreload.py::test_autoload_newly_added_objects
548 unit test at IPython/extensions/tests/test_autoreload.py::test_autoload_newly_added_objects
545
549
546 Reloading Python modules in a reliable way is in general
550 Reloading Python modules in a reliable way is in general
547 difficult, and unexpected things may occur. %autoreload tries to
551 difficult, and unexpected things may occur. %autoreload tries to
548 work around common pitfalls by replacing function code objects and
552 work around common pitfalls by replacing function code objects and
549 parts of classes previously in the module with new versions. This
553 parts of classes previously in the module with new versions. This
550 makes the following things to work:
554 makes the following things to work:
551
555
552 - Functions and classes imported via 'from xxx import foo' are upgraded
556 - Functions and classes imported via 'from xxx import foo' are upgraded
553 to new versions when 'xxx' is reloaded.
557 to new versions when 'xxx' is reloaded.
554
558
555 - Methods and properties of classes are upgraded on reload, so that
559 - Methods and properties of classes are upgraded on reload, so that
556 calling 'c.foo()' on an object 'c' created before the reload causes
560 calling 'c.foo()' on an object 'c' created before the reload causes
557 the new code for 'foo' to be executed.
561 the new code for 'foo' to be executed.
558
562
559 Some of the known remaining caveats are:
563 Some of the known remaining caveats are:
560
564
561 - Replacing code objects does not always succeed: changing a @property
565 - Replacing code objects does not always succeed: changing a @property
562 in a class to an ordinary method or a method to a member variable
566 in a class to an ordinary method or a method to a member variable
563 can cause problems (but in old objects only).
567 can cause problems (but in old objects only).
564
568
565 - Functions that are removed (eg. via monkey-patching) from a module
569 - Functions that are removed (eg. via monkey-patching) from a module
566 before it is reloaded are not upgraded.
570 before it is reloaded are not upgraded.
567
571
568 - C extension modules cannot be reloaded, and so cannot be
572 - C extension modules cannot be reloaded, and so cannot be
569 autoreloaded.
573 autoreloaded.
570
574
571 """
575 """
572 if parameter_s == "" or parameter_s.lower() == "now":
576 if parameter_s == "" or parameter_s.lower() == "now":
573 self._reloader.check(True)
577 self._reloader.check(True)
574 elif parameter_s == "0" or parameter_s.lower() == "off":
578 elif parameter_s == "0" or parameter_s.lower() == "off":
575 self._reloader.enabled = False
579 self._reloader.enabled = False
576 elif parameter_s == "1" or parameter_s.lower() == "explicit":
580 elif parameter_s == "1" or parameter_s.lower() == "explicit":
577 self._reloader.check_all = False
581 self._reloader.check_all = False
578 self._reloader.enabled = True
582 self._reloader.enabled = True
579 elif parameter_s == "2" or parameter_s.lower() == "all":
583 elif parameter_s == "2" or parameter_s.lower() == "all":
580 self._reloader.check_all = True
584 self._reloader.check_all = True
581 self._reloader.enabled = True
585 self._reloader.enabled = True
582 elif parameter_s == "3" or parameter_s.lower() == "complete":
586 elif parameter_s == "3" or parameter_s.lower() == "complete":
583 self._reloader.check_all = True
587 self._reloader.check_all = True
584 self._reloader.enabled = True
588 self._reloader.enabled = True
585 self._reloader.autoload_obj = True
589 self._reloader.autoload_obj = True
586 else:
590 else:
587 raise ValueError(f'Unrecognized parameter "{parameter_s}".')
591 raise ValueError(f'Unrecognized parameter "{parameter_s}".')
588
592
589 @line_magic
593 @line_magic
590 def aimport(self, parameter_s="", stream=None):
594 def aimport(self, parameter_s="", stream=None):
591 """%aimport => Import modules for automatic reloading.
595 """%aimport => Import modules for automatic reloading.
592
596
593 %aimport
597 %aimport
594 List modules to automatically import and not to import.
598 List modules to automatically import and not to import.
595
599
596 %aimport foo
600 %aimport foo
597 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
601 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
598
602
599 %aimport foo, bar
603 %aimport foo, bar
600 Import modules 'foo', 'bar' and mark them to be autoreloaded for %autoreload 1
604 Import modules 'foo', 'bar' and mark them to be autoreloaded for %autoreload 1
601
605
602 %aimport -foo, bar
606 %aimport -foo, bar
603 Mark module 'foo' to not be autoreloaded for %autoreload 1, 2, or 3, and 'bar'
607 Mark module 'foo' to not be autoreloaded for %autoreload 1, 2, or 3, and 'bar'
604 to be autoreloaded for 1.
608 to be autoreloaded for 1.
605 """
609 """
606 modname = parameter_s
610 modname = parameter_s
607 if not modname:
611 if not modname:
608 to_reload = sorted(self._reloader.modules.keys())
612 to_reload = sorted(self._reloader.modules.keys())
609 to_skip = sorted(self._reloader.skip_modules.keys())
613 to_skip = sorted(self._reloader.skip_modules.keys())
610 if stream is None:
614 if stream is None:
611 stream = sys.stdout
615 stream = sys.stdout
612 if self._reloader.check_all:
616 if self._reloader.check_all:
613 stream.write("Modules to reload:\nall-except-skipped\n")
617 stream.write("Modules to reload:\nall-except-skipped\n")
614 else:
618 else:
615 stream.write("Modules to reload:\n%s\n" % " ".join(to_reload))
619 stream.write("Modules to reload:\n%s\n" % " ".join(to_reload))
616 stream.write("\nModules to skip:\n%s\n" % " ".join(to_skip))
620 stream.write("\nModules to skip:\n%s\n" % " ".join(to_skip))
617 else:
621 else:
618 for _module in [_.strip() for _ in modname.split(",")]:
622 for _module in [_.strip() for _ in modname.split(",")]:
619 if _module.startswith("-"):
623 if _module.startswith("-"):
620 _module = _module[1:].strip()
624 _module = _module[1:].strip()
621 self._reloader.mark_module_skipped(_module)
625 self._reloader.mark_module_skipped(_module)
622 else:
626 else:
623 top_module, top_name = self._reloader.aimport_module(_module)
627 top_module, top_name = self._reloader.aimport_module(_module)
624
628
625 # Inject module to user namespace
629 # Inject module to user namespace
626 self.shell.push({top_name: top_module})
630 self.shell.push({top_name: top_module})
627
631
628 @line_magic
632 @line_magic
629 def averbose(self, parameter_s=""):
633 def averbose(self, parameter_s=""):
630 r"""%averbose => Turn verbosity on/off for autoreloading.
634 r"""%averbose => Turn verbosity on/off for autoreloading.
631
635
632 %averbose 0 or %averbose off
636 %averbose 0 or %averbose off
633 Turn off any reporting during autoreload.
637 Turn off any reporting during autoreload.
634
638
635 %averbose 1 or %averbose on
639 %averbose 1 or %averbose on
636 Report autoreload activity via print statements.
640 Report autoreload activity via print statements.
637
641
638 %averbose 2 or %averbose log
642 %averbose 2 or %averbose log
639 Report autoreload activity via logging.
643 Report autoreload activity via logging.
640 """
644 """
641
645
642 if parameter_s == "0" or parameter_s.lower() == "off":
646 if parameter_s == "0" or parameter_s.lower() == "off":
643 self._reloader._report = lambda msg: None
647 self._reloader._report = lambda msg: None
644 elif parameter_s == "1" or parameter_s.lower() == "on":
648 elif parameter_s == "1" or parameter_s.lower() == "on":
645 self._reloader._report = lambda msg: print(msg)
649 self._reloader._report = lambda msg: print(msg)
646 elif parameter_s == "2" or parameter_s.lower() == "log":
650 elif parameter_s == "2" or parameter_s.lower() == "log":
647 self._reloader._report = lambda msg: logging.getLogger("autoreload").info(
651 self._reloader._report = lambda msg: logging.getLogger("autoreload").info(
648 msg
652 msg
649 )
653 )
650 else:
654 else:
651 raise ValueError(f'Unrecognized parameter "{parameter_s}".')
655 raise ValueError(f'Unrecognized parameter "{parameter_s}".')
652
656
653 def pre_run_cell(self):
657 def pre_run_cell(self):
654 if self._reloader.enabled:
658 if self._reloader.enabled:
655 try:
659 try:
656 self._reloader.check()
660 self._reloader.check()
657 except:
661 except:
658 pass
662 pass
659
663
660 def post_execute_hook(self):
664 def post_execute_hook(self):
661 """Cache the modification times of any modules imported in this execution"""
665 """Cache the modification times of any modules imported in this execution"""
662 newly_loaded_modules = set(sys.modules) - self.loaded_modules
666 newly_loaded_modules = set(sys.modules) - self.loaded_modules
663 for modname in newly_loaded_modules:
667 for modname in newly_loaded_modules:
664 _, pymtime = self._reloader.filename_and_mtime(sys.modules[modname])
668 _, pymtime = self._reloader.filename_and_mtime(sys.modules[modname])
665 if pymtime is not None:
669 if pymtime is not None:
666 self._reloader.modules_mtimes[modname] = pymtime
670 self._reloader.modules_mtimes[modname] = pymtime
667
671
668 self.loaded_modules.update(newly_loaded_modules)
672 self.loaded_modules.update(newly_loaded_modules)
669
673
670
674
671 def load_ipython_extension(ip):
675 def load_ipython_extension(ip):
672 """Load the extension in IPython."""
676 """Load the extension in IPython."""
673 auto_reload = AutoreloadMagics(ip)
677 auto_reload = AutoreloadMagics(ip)
674 ip.register_magics(auto_reload)
678 ip.register_magics(auto_reload)
675 ip.events.register("pre_run_cell", auto_reload.pre_run_cell)
679 ip.events.register("pre_run_cell", auto_reload.pre_run_cell)
676 ip.events.register("post_execute", auto_reload.post_execute_hook)
680 ip.events.register("post_execute", auto_reload.post_execute_hook)
@@ -1,11 +1,14 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 from IPython.testing import decorators as dec
2 from IPython.testing import decorators as dec
3
3
4
4 def test_import_backgroundjobs():
5 def test_import_backgroundjobs():
5 from IPython.lib import backgroundjobs
6 from IPython.lib import backgroundjobs
6
7
8
7 def test_import_deepreload():
9 def test_import_deepreload():
8 from IPython.lib import deepreload
10 from IPython.lib import deepreload
9
11
12
10 def test_import_demo():
13 def test_import_demo():
11 from IPython.lib import demo
14 from IPython.lib import demo
@@ -1,1271 +1,1272 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Sphinx directive to support embedded IPython code.
3 Sphinx directive to support embedded IPython code.
4
4
5 IPython provides an extension for `Sphinx <http://www.sphinx-doc.org/>`_ to
5 IPython provides an extension for `Sphinx <http://www.sphinx-doc.org/>`_ to
6 highlight and run code.
6 highlight and run code.
7
7
8 This directive allows pasting of entire interactive IPython sessions, prompts
8 This directive allows pasting of entire interactive IPython sessions, prompts
9 and all, and their code will actually get re-executed at doc build time, with
9 and all, and their code will actually get re-executed at doc build time, with
10 all prompts renumbered sequentially. It also allows you to input code as a pure
10 all prompts renumbered sequentially. It also allows you to input code as a pure
11 python input by giving the argument python to the directive. The output looks
11 python input by giving the argument python to the directive. The output looks
12 like an interactive ipython section.
12 like an interactive ipython section.
13
13
14 Here is an example of how the IPython directive can
14 Here is an example of how the IPython directive can
15 **run** python code, at build time.
15 **run** python code, at build time.
16
16
17 .. ipython::
17 .. ipython::
18
18
19 In [1]: 1+1
19 In [1]: 1+1
20
20
21 In [1]: import datetime
21 In [1]: import datetime
22 ...: datetime.date.fromisoformat('2022-02-22')
22 ...: datetime.date.fromisoformat('2022-02-22')
23
23
24 It supports IPython construct that plain
24 It supports IPython construct that plain
25 Python does not understand (like magics):
25 Python does not understand (like magics):
26
26
27 .. ipython::
27 .. ipython::
28
28
29 In [0]: import time
29 In [0]: import time
30
30
31 In [0]: %pdoc time.sleep
31 In [0]: %pdoc time.sleep
32
32
33 This will also support top-level async when using IPython 7.0+
33 This will also support top-level async when using IPython 7.0+
34
34
35 .. ipython::
35 .. ipython::
36
36
37 In [2]: import asyncio
37 In [2]: import asyncio
38 ...: print('before')
38 ...: print('before')
39 ...: await asyncio.sleep(1)
39 ...: await asyncio.sleep(1)
40 ...: print('after')
40 ...: print('after')
41
41
42
42
43 The namespace will persist across multiple code chucks, Let's define a variable:
43 The namespace will persist across multiple code chucks, Let's define a variable:
44
44
45 .. ipython::
45 .. ipython::
46
46
47 In [0]: who = "World"
47 In [0]: who = "World"
48
48
49 And now say hello:
49 And now say hello:
50
50
51 .. ipython::
51 .. ipython::
52
52
53 In [0]: print('Hello,', who)
53 In [0]: print('Hello,', who)
54
54
55 If the current section raises an exception, you can add the ``:okexcept:`` flag
55 If the current section raises an exception, you can add the ``:okexcept:`` flag
56 to the current block, otherwise the build will fail.
56 to the current block, otherwise the build will fail.
57
57
58 .. ipython::
58 .. ipython::
59 :okexcept:
59 :okexcept:
60
60
61 In [1]: 1/0
61 In [1]: 1/0
62
62
63 IPython Sphinx directive module
63 IPython Sphinx directive module
64 ===============================
64 ===============================
65
65
66 To enable this directive, simply list it in your Sphinx ``conf.py`` file
66 To enable this directive, simply list it in your Sphinx ``conf.py`` file
67 (making sure the directory where you placed it is visible to sphinx, as is
67 (making sure the directory where you placed it is visible to sphinx, as is
68 needed for all Sphinx directives). For example, to enable syntax highlighting
68 needed for all Sphinx directives). For example, to enable syntax highlighting
69 and the IPython directive::
69 and the IPython directive::
70
70
71 extensions = ['IPython.sphinxext.ipython_console_highlighting',
71 extensions = ['IPython.sphinxext.ipython_console_highlighting',
72 'IPython.sphinxext.ipython_directive']
72 'IPython.sphinxext.ipython_directive']
73
73
74 The IPython directive outputs code-blocks with the language 'ipython'. So
74 The IPython directive outputs code-blocks with the language 'ipython'. So
75 if you do not have the syntax highlighting extension enabled as well, then
75 if you do not have the syntax highlighting extension enabled as well, then
76 all rendered code-blocks will be uncolored. By default this directive assumes
76 all rendered code-blocks will be uncolored. By default this directive assumes
77 that your prompts are unchanged IPython ones, but this can be customized.
77 that your prompts are unchanged IPython ones, but this can be customized.
78 The configurable options that can be placed in conf.py are:
78 The configurable options that can be placed in conf.py are:
79
79
80 ipython_savefig_dir:
80 ipython_savefig_dir:
81 The directory in which to save the figures. This is relative to the
81 The directory in which to save the figures. This is relative to the
82 Sphinx source directory. The default is `html_static_path`.
82 Sphinx source directory. The default is `html_static_path`.
83 ipython_rgxin:
83 ipython_rgxin:
84 The compiled regular expression to denote the start of IPython input
84 The compiled regular expression to denote the start of IPython input
85 lines. The default is ``re.compile('In \\[(\\d+)\\]:\\s?(.*)\\s*')``. You
85 lines. The default is ``re.compile('In \\[(\\d+)\\]:\\s?(.*)\\s*')``. You
86 shouldn't need to change this.
86 shouldn't need to change this.
87 ipython_warning_is_error: [default to True]
87 ipython_warning_is_error: [default to True]
88 Fail the build if something unexpected happen, for example if a block raise
88 Fail the build if something unexpected happen, for example if a block raise
89 an exception but does not have the `:okexcept:` flag. The exact behavior of
89 an exception but does not have the `:okexcept:` flag. The exact behavior of
90 what is considered strict, may change between the sphinx directive version.
90 what is considered strict, may change between the sphinx directive version.
91 ipython_rgxout:
91 ipython_rgxout:
92 The compiled regular expression to denote the start of IPython output
92 The compiled regular expression to denote the start of IPython output
93 lines. The default is ``re.compile('Out\\[(\\d+)\\]:\\s?(.*)\\s*')``. You
93 lines. The default is ``re.compile('Out\\[(\\d+)\\]:\\s?(.*)\\s*')``. You
94 shouldn't need to change this.
94 shouldn't need to change this.
95 ipython_promptin:
95 ipython_promptin:
96 The string to represent the IPython input prompt in the generated ReST.
96 The string to represent the IPython input prompt in the generated ReST.
97 The default is ``'In [%d]:'``. This expects that the line numbers are used
97 The default is ``'In [%d]:'``. This expects that the line numbers are used
98 in the prompt.
98 in the prompt.
99 ipython_promptout:
99 ipython_promptout:
100 The string to represent the IPython prompt in the generated ReST. The
100 The string to represent the IPython prompt in the generated ReST. The
101 default is ``'Out [%d]:'``. This expects that the line numbers are used
101 default is ``'Out [%d]:'``. This expects that the line numbers are used
102 in the prompt.
102 in the prompt.
103 ipython_mplbackend:
103 ipython_mplbackend:
104 The string which specifies if the embedded Sphinx shell should import
104 The string which specifies if the embedded Sphinx shell should import
105 Matplotlib and set the backend. The value specifies a backend that is
105 Matplotlib and set the backend. The value specifies a backend that is
106 passed to `matplotlib.use()` before any lines in `ipython_execlines` are
106 passed to `matplotlib.use()` before any lines in `ipython_execlines` are
107 executed. If not specified in conf.py, then the default value of 'agg' is
107 executed. If not specified in conf.py, then the default value of 'agg' is
108 used. To use the IPython directive without matplotlib as a dependency, set
108 used. To use the IPython directive without matplotlib as a dependency, set
109 the value to `None`. It may end up that matplotlib is still imported
109 the value to `None`. It may end up that matplotlib is still imported
110 if the user specifies so in `ipython_execlines` or makes use of the
110 if the user specifies so in `ipython_execlines` or makes use of the
111 @savefig pseudo decorator.
111 @savefig pseudo decorator.
112 ipython_execlines:
112 ipython_execlines:
113 A list of strings to be exec'd in the embedded Sphinx shell. Typical
113 A list of strings to be exec'd in the embedded Sphinx shell. Typical
114 usage is to make certain packages always available. Set this to an empty
114 usage is to make certain packages always available. Set this to an empty
115 list if you wish to have no imports always available. If specified in
115 list if you wish to have no imports always available. If specified in
116 ``conf.py`` as `None`, then it has the effect of making no imports available.
116 ``conf.py`` as `None`, then it has the effect of making no imports available.
117 If omitted from conf.py altogether, then the default value of
117 If omitted from conf.py altogether, then the default value of
118 ['import numpy as np', 'import matplotlib.pyplot as plt'] is used.
118 ['import numpy as np', 'import matplotlib.pyplot as plt'] is used.
119 ipython_holdcount
119 ipython_holdcount
120 When the @suppress pseudo-decorator is used, the execution count can be
120 When the @suppress pseudo-decorator is used, the execution count can be
121 incremented or not. The default behavior is to hold the execution count,
121 incremented or not. The default behavior is to hold the execution count,
122 corresponding to a value of `True`. Set this to `False` to increment
122 corresponding to a value of `True`. Set this to `False` to increment
123 the execution count after each suppressed command.
123 the execution count after each suppressed command.
124
124
125 As an example, to use the IPython directive when `matplotlib` is not available,
125 As an example, to use the IPython directive when `matplotlib` is not available,
126 one sets the backend to `None`::
126 one sets the backend to `None`::
127
127
128 ipython_mplbackend = None
128 ipython_mplbackend = None
129
129
130 An example usage of the directive is:
130 An example usage of the directive is:
131
131
132 .. code-block:: rst
132 .. code-block:: rst
133
133
134 .. ipython::
134 .. ipython::
135
135
136 In [1]: x = 1
136 In [1]: x = 1
137
137
138 In [2]: y = x**2
138 In [2]: y = x**2
139
139
140 In [3]: print(y)
140 In [3]: print(y)
141
141
142 See http://matplotlib.org/sampledoc/ipython_directive.html for additional
142 See http://matplotlib.org/sampledoc/ipython_directive.html for additional
143 documentation.
143 documentation.
144
144
145 Pseudo-Decorators
145 Pseudo-Decorators
146 =================
146 =================
147
147
148 Note: Only one decorator is supported per input. If more than one decorator
148 Note: Only one decorator is supported per input. If more than one decorator
149 is specified, then only the last one is used.
149 is specified, then only the last one is used.
150
150
151 In addition to the Pseudo-Decorators/options described at the above link,
151 In addition to the Pseudo-Decorators/options described at the above link,
152 several enhancements have been made. The directive will emit a message to the
152 several enhancements have been made. The directive will emit a message to the
153 console at build-time if code-execution resulted in an exception or warning.
153 console at build-time if code-execution resulted in an exception or warning.
154 You can suppress these on a per-block basis by specifying the :okexcept:
154 You can suppress these on a per-block basis by specifying the :okexcept:
155 or :okwarning: options:
155 or :okwarning: options:
156
156
157 .. code-block:: rst
157 .. code-block:: rst
158
158
159 .. ipython::
159 .. ipython::
160 :okexcept:
160 :okexcept:
161 :okwarning:
161 :okwarning:
162
162
163 In [1]: 1/0
163 In [1]: 1/0
164 In [2]: # raise warning.
164 In [2]: # raise warning.
165
165
166 To Do
166 To Do
167 =====
167 =====
168
168
169 - Turn the ad-hoc test() function into a real test suite.
169 - Turn the ad-hoc test() function into a real test suite.
170 - Break up ipython-specific functionality from matplotlib stuff into better
170 - Break up ipython-specific functionality from matplotlib stuff into better
171 separated code.
171 separated code.
172
172
173 """
173 """
174
174
175 # Authors
175 # Authors
176 # =======
176 # =======
177 #
177 #
178 # - John D Hunter: original author.
178 # - John D Hunter: original author.
179 # - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
179 # - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
180 # - VáclavŠmilauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
180 # - VáclavŠmilauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
181 # - Skipper Seabold, refactoring, cleanups, pure python addition
181 # - Skipper Seabold, refactoring, cleanups, pure python addition
182
182
183 #-----------------------------------------------------------------------------
183 #-----------------------------------------------------------------------------
184 # Imports
184 # Imports
185 #-----------------------------------------------------------------------------
185 #-----------------------------------------------------------------------------
186
186
187 # Stdlib
187 # Stdlib
188 import atexit
188 import atexit
189 import errno
189 import errno
190 import os
190 import os
191 import pathlib
191 import pathlib
192 import re
192 import re
193 import sys
193 import sys
194 import tempfile
194 import tempfile
195 import ast
195 import ast
196 import warnings
196 import warnings
197 import shutil
197 import shutil
198 from io import StringIO
198 from io import StringIO
199
199
200 # Third-party
200 # Third-party
201 from docutils.parsers.rst import directives
201 from docutils.parsers.rst import directives
202 from docutils.parsers.rst import Directive
202 from docutils.parsers.rst import Directive
203 from sphinx.util import logging
203 from sphinx.util import logging
204
204
205 # Our own
205 # Our own
206 from traitlets.config import Config
206 from traitlets.config import Config
207 from IPython import InteractiveShell
207 from IPython import InteractiveShell
208 from IPython.core.profiledir import ProfileDir
208 from IPython.core.profiledir import ProfileDir
209
209
210 use_matplotlib = False
210 use_matplotlib = False
211 try:
211 try:
212 import matplotlib
212 import matplotlib
213 use_matplotlib = True
213 use_matplotlib = True
214 except Exception:
214 except Exception:
215 pass
215 pass
216
216
217 #-----------------------------------------------------------------------------
217 #-----------------------------------------------------------------------------
218 # Globals
218 # Globals
219 #-----------------------------------------------------------------------------
219 #-----------------------------------------------------------------------------
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"]
223 PSEUDO_DECORATORS = ["suppress", "verbatim", "savefig", "doctest"]
224
224
225 #-----------------------------------------------------------------------------
225 #-----------------------------------------------------------------------------
226 # Functions and class declarations
226 # Functions and class declarations
227 #-----------------------------------------------------------------------------
227 #-----------------------------------------------------------------------------
228
228
229 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
229 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
230 """
230 """
231 part is a string of ipython text, comprised of at most one
231 part is a string of ipython text, comprised of at most one
232 input, one output, comments, and blank lines. The block parser
232 input, one output, comments, and blank lines. The block parser
233 parses the text into a list of::
233 parses the text into a list of::
234
234
235 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
235 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
236
236
237 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
237 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
238 data is, depending on the type of token::
238 data is, depending on the type of token::
239
239
240 COMMENT : the comment string
240 COMMENT : the comment string
241
241
242 INPUT: the (DECORATOR, INPUT_LINE, REST) where
242 INPUT: the (DECORATOR, INPUT_LINE, REST) where
243 DECORATOR: the input decorator (or None)
243 DECORATOR: the input decorator (or None)
244 INPUT_LINE: the input as string (possibly multi-line)
244 INPUT_LINE: the input as string (possibly multi-line)
245 REST : any stdout generated by the input line (not OUTPUT)
245 REST : any stdout generated by the input line (not OUTPUT)
246
246
247 OUTPUT: the output string, possibly multi-line
247 OUTPUT: the output string, possibly multi-line
248
248
249 """
249 """
250 block = []
250 block = []
251 lines = part.split('\n')
251 lines = part.split('\n')
252 N = len(lines)
252 N = len(lines)
253 i = 0
253 i = 0
254 decorator = None
254 decorator = None
255 while 1:
255 while 1:
256
256
257 if i==N:
257 if i==N:
258 # nothing left to parse -- the last line
258 # nothing left to parse -- the last line
259 break
259 break
260
260
261 line = lines[i]
261 line = lines[i]
262 i += 1
262 i += 1
263 line_stripped = line.strip()
263 line_stripped = line.strip()
264 if line_stripped.startswith('#'):
264 if line_stripped.startswith('#'):
265 block.append((COMMENT, line))
265 block.append((COMMENT, line))
266 continue
266 continue
267
267
268 if any(
268 if any(
269 line_stripped.startswith("@" + pseudo_decorator)
269 line_stripped.startswith("@" + pseudo_decorator)
270 for pseudo_decorator in PSEUDO_DECORATORS
270 for pseudo_decorator in PSEUDO_DECORATORS
271 ):
271 ):
272 if decorator:
272 if decorator:
273 raise RuntimeError(
273 raise RuntimeError(
274 "Applying multiple pseudo-decorators on one line is not supported"
274 "Applying multiple pseudo-decorators on one line is not supported"
275 )
275 )
276 else:
276 else:
277 decorator = line_stripped
277 decorator = line_stripped
278 continue
278 continue
279
279
280 # does this look like an input line?
280 # does this look like an input line?
281 matchin = rgxin.match(line)
281 matchin = rgxin.match(line)
282 if matchin:
282 if matchin:
283 lineno, inputline = int(matchin.group(1)), matchin.group(2)
283 lineno, inputline = int(matchin.group(1)), matchin.group(2)
284
284
285 # the ....: continuation string
285 # the ....: continuation string
286 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
286 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
287 Nc = len(continuation)
287 Nc = len(continuation)
288 # input lines can continue on for more than one line, if
288 # input lines can continue on for more than one line, if
289 # we have a '\' line continuation char or a function call
289 # we have a '\' line continuation char or a function call
290 # echo line 'print'. The input line can only be
290 # echo line 'print'. The input line can only be
291 # terminated by the end of the block or an output line, so
291 # terminated by the end of the block or an output line, so
292 # we parse out the rest of the input line if it is
292 # we parse out the rest of the input line if it is
293 # multiline as well as any echo text
293 # multiline as well as any echo text
294
294
295 rest = []
295 rest = []
296 while i<N:
296 while i<N:
297
297
298 # look ahead; if the next line is blank, or a comment, or
298 # look ahead; if the next line is blank, or a comment, or
299 # an output line, we're done
299 # an output line, we're done
300
300
301 nextline = lines[i]
301 nextline = lines[i]
302 matchout = rgxout.match(nextline)
302 matchout = rgxout.match(nextline)
303 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
303 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
304 if matchout or nextline.startswith('#'):
304 if matchout or nextline.startswith('#'):
305 break
305 break
306 elif nextline.startswith(continuation):
306 elif nextline.startswith(continuation):
307 # The default ipython_rgx* treat the space following the colon as optional.
307 # The default ipython_rgx* treat the space following the colon as optional.
308 # However, If the space is there we must consume it or code
308 # However, If the space is there we must consume it or code
309 # employing the cython_magic extension will fail to execute.
309 # employing the cython_magic extension will fail to execute.
310 #
310 #
311 # This works with the default ipython_rgx* patterns,
311 # This works with the default ipython_rgx* patterns,
312 # If you modify them, YMMV.
312 # If you modify them, YMMV.
313 nextline = nextline[Nc:]
313 nextline = nextline[Nc:]
314 if nextline and nextline[0] == ' ':
314 if nextline and nextline[0] == ' ':
315 nextline = nextline[1:]
315 nextline = nextline[1:]
316
316
317 inputline += '\n' + nextline
317 inputline += '\n' + nextline
318 else:
318 else:
319 rest.append(nextline)
319 rest.append(nextline)
320 i+= 1
320 i+= 1
321
321
322 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
322 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
323 continue
323 continue
324
324
325 # if it looks like an output line grab all the text to the end
325 # if it looks like an output line grab all the text to the end
326 # of the block
326 # of the block
327 matchout = rgxout.match(line)
327 matchout = rgxout.match(line)
328 if matchout:
328 if matchout:
329 lineno, output = int(matchout.group(1)), matchout.group(2)
329 lineno, output = int(matchout.group(1)), matchout.group(2)
330 if i<N-1:
330 if i<N-1:
331 output = '\n'.join([output] + lines[i:])
331 output = '\n'.join([output] + lines[i:])
332
332
333 block.append((OUTPUT, output))
333 block.append((OUTPUT, output))
334 break
334 break
335
335
336 return block
336 return block
337
337
338
338
339 class EmbeddedSphinxShell(object):
339 class EmbeddedSphinxShell(object):
340 """An embedded IPython instance to run inside Sphinx"""
340 """An embedded IPython instance to run inside Sphinx"""
341
341
342 def __init__(self, exec_lines=None):
342 def __init__(self, exec_lines=None):
343
343
344 self.cout = StringIO()
344 self.cout = StringIO()
345
345
346 if exec_lines is None:
346 if exec_lines is None:
347 exec_lines = []
347 exec_lines = []
348
348
349 # Create config object for IPython
349 # Create config object for IPython
350 config = Config()
350 config = Config()
351 config.HistoryManager.hist_file = ':memory:'
351 config.HistoryManager.hist_file = ':memory:'
352 config.InteractiveShell.autocall = False
352 config.InteractiveShell.autocall = False
353 config.InteractiveShell.autoindent = False
353 config.InteractiveShell.autoindent = False
354 config.InteractiveShell.colors = 'NoColor'
354 config.InteractiveShell.colors = 'NoColor'
355
355
356 # create a profile so instance history isn't saved
356 # create a profile so instance history isn't saved
357 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
357 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
358 profname = 'auto_profile_sphinx_build'
358 profname = 'auto_profile_sphinx_build'
359 pdir = os.path.join(tmp_profile_dir,profname)
359 pdir = os.path.join(tmp_profile_dir,profname)
360 profile = ProfileDir.create_profile_dir(pdir)
360 profile = ProfileDir.create_profile_dir(pdir)
361
361
362 # Create and initialize global ipython, but don't start its mainloop.
362 # Create and initialize global ipython, but don't start its mainloop.
363 # This will persist across different EmbeddedSphinxShell instances.
363 # This will persist across different EmbeddedSphinxShell instances.
364 IP = InteractiveShell.instance(config=config, profile_dir=profile)
364 IP = InteractiveShell.instance(config=config, profile_dir=profile)
365 atexit.register(self.cleanup)
365 atexit.register(self.cleanup)
366
366
367 # Store a few parts of IPython we'll need.
367 # Store a few parts of IPython we'll need.
368 self.IP = IP
368 self.IP = IP
369 self.user_ns = self.IP.user_ns
369 self.user_ns = self.IP.user_ns
370 self.user_global_ns = self.IP.user_global_ns
370 self.user_global_ns = self.IP.user_global_ns
371
371
372 self.input = ''
372 self.input = ''
373 self.output = ''
373 self.output = ''
374 self.tmp_profile_dir = tmp_profile_dir
374 self.tmp_profile_dir = tmp_profile_dir
375
375
376 self.is_verbatim = False
376 self.is_verbatim = False
377 self.is_doctest = False
377 self.is_doctest = False
378 self.is_suppress = False
378 self.is_suppress = False
379
379
380 # Optionally, provide more detailed information to shell.
380 # Optionally, provide more detailed information to shell.
381 # this is assigned by the SetUp method of IPythonDirective
381 # this is assigned by the SetUp method of IPythonDirective
382 # to point at itself.
382 # to point at itself.
383 #
383 #
384 # So, you can access handy things at self.directive.state
384 # So, you can access handy things at self.directive.state
385 self.directive = None
385 self.directive = None
386
386
387 # on the first call to the savefig decorator, we'll import
387 # on the first call to the savefig decorator, we'll import
388 # pyplot as plt so we can make a call to the plt.gcf().savefig
388 # pyplot as plt so we can make a call to the plt.gcf().savefig
389 self._pyplot_imported = False
389 self._pyplot_imported = False
390
390
391 # Prepopulate the namespace.
391 # Prepopulate the namespace.
392 for line in exec_lines:
392 for line in exec_lines:
393 self.process_input_line(line, store_history=False)
393 self.process_input_line(line, store_history=False)
394
394
395 def cleanup(self):
395 def cleanup(self):
396 shutil.rmtree(self.tmp_profile_dir, ignore_errors=True)
396 shutil.rmtree(self.tmp_profile_dir, ignore_errors=True)
397
397
398 def clear_cout(self):
398 def clear_cout(self):
399 self.cout.seek(0)
399 self.cout.seek(0)
400 self.cout.truncate(0)
400 self.cout.truncate(0)
401
401
402 def process_input_line(self, line, store_history):
402 def process_input_line(self, line, store_history):
403 return self.process_input_lines([line], store_history=store_history)
403 return self.process_input_lines([line], store_history=store_history)
404
404
405 def process_input_lines(self, lines, store_history=True):
405 def process_input_lines(self, lines, store_history=True):
406 """process the input, capturing stdout"""
406 """process the input, capturing stdout"""
407 stdout = sys.stdout
407 stdout = sys.stdout
408 source_raw = '\n'.join(lines)
408 source_raw = '\n'.join(lines)
409 try:
409 try:
410 sys.stdout = self.cout
410 sys.stdout = self.cout
411 self.IP.run_cell(source_raw, store_history=store_history)
411 self.IP.run_cell(source_raw, store_history=store_history)
412 finally:
412 finally:
413 sys.stdout = stdout
413 sys.stdout = stdout
414
414
415 def process_image(self, decorator):
415 def process_image(self, decorator):
416 """
416 """
417 # build out an image directive like
417 # build out an image directive like
418 # .. image:: somefile.png
418 # .. image:: somefile.png
419 # :width 4in
419 # :width 4in
420 #
420 #
421 # from an input like
421 # from an input like
422 # savefig somefile.png width=4in
422 # savefig somefile.png width=4in
423 """
423 """
424 savefig_dir = self.savefig_dir
424 savefig_dir = self.savefig_dir
425 source_dir = self.source_dir
425 source_dir = self.source_dir
426 saveargs = decorator.split(' ')
426 saveargs = decorator.split(' ')
427 filename = saveargs[1]
427 filename = saveargs[1]
428 # insert relative path to image file in source
428 # insert relative path to image file in source
429 # as absolute path for Sphinx
429 # as absolute path for Sphinx
430 # sphinx expects a posix path, even on Windows
430 # sphinx expects a posix path, even on Windows
431 path = pathlib.Path(savefig_dir, filename)
431 path = pathlib.Path(savefig_dir, filename)
432 outfile = '/' + path.relative_to(source_dir).as_posix()
432 outfile = '/' + path.relative_to(source_dir).as_posix()
433
433
434 imagerows = ['.. image:: %s' % outfile]
434 imagerows = ['.. image:: %s' % outfile]
435
435
436 for kwarg in saveargs[2:]:
436 for kwarg in saveargs[2:]:
437 arg, val = kwarg.split('=')
437 arg, val = kwarg.split('=')
438 arg = arg.strip()
438 arg = arg.strip()
439 val = val.strip()
439 val = val.strip()
440 imagerows.append(' :%s: %s'%(arg, val))
440 imagerows.append(' :%s: %s'%(arg, val))
441
441
442 image_file = os.path.basename(outfile) # only return file name
442 image_file = os.path.basename(outfile) # only return file name
443 image_directive = '\n'.join(imagerows)
443 image_directive = '\n'.join(imagerows)
444 return image_file, image_directive
444 return image_file, image_directive
445
445
446 # Callbacks for each type of token
446 # Callbacks for each type of token
447 def process_input(self, data, input_prompt, lineno):
447 def process_input(self, data, input_prompt, lineno):
448 """
448 """
449 Process data block for INPUT token.
449 Process data block for INPUT token.
450
450
451 """
451 """
452 decorator, input, rest = data
452 decorator, input, rest = data
453 image_file = None
453 image_file = None
454 image_directive = None
454 image_directive = None
455
455
456 is_verbatim = decorator=='@verbatim' or self.is_verbatim
456 is_verbatim = decorator=='@verbatim' or self.is_verbatim
457 is_doctest = (decorator is not None and \
457 is_doctest = (decorator is not None and \
458 decorator.startswith('@doctest')) or self.is_doctest
458 decorator.startswith('@doctest')) or self.is_doctest
459 is_suppress = decorator=='@suppress' or self.is_suppress
459 is_suppress = decorator=='@suppress' or self.is_suppress
460 is_okexcept = decorator=='@okexcept' or self.is_okexcept
460 is_okexcept = decorator=='@okexcept' or self.is_okexcept
461 is_okwarning = decorator=='@okwarning' or self.is_okwarning
461 is_okwarning = decorator=='@okwarning' or self.is_okwarning
462 is_savefig = decorator is not None and \
462 is_savefig = decorator is not None and \
463 decorator.startswith('@savefig')
463 decorator.startswith('@savefig')
464
464
465 input_lines = input.split('\n')
465 input_lines = input.split('\n')
466 if len(input_lines) > 1:
466 if len(input_lines) > 1:
467 if input_lines[-1] != "":
467 if input_lines[-1] != "":
468 input_lines.append('') # make sure there's a blank line
468 input_lines.append('') # make sure there's a blank line
469 # so splitter buffer gets reset
469 # so splitter buffer gets reset
470
470
471 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
471 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
472
472
473 if is_savefig:
473 if is_savefig:
474 image_file, image_directive = self.process_image(decorator)
474 image_file, image_directive = self.process_image(decorator)
475
475
476 ret = []
476 ret = []
477 is_semicolon = False
477 is_semicolon = False
478
478
479 # Hold the execution count, if requested to do so.
479 # Hold the execution count, if requested to do so.
480 if is_suppress and self.hold_count:
480 if is_suppress and self.hold_count:
481 store_history = False
481 store_history = False
482 else:
482 else:
483 store_history = True
483 store_history = True
484
484
485 # Note: catch_warnings is not thread safe
485 # Note: catch_warnings is not thread safe
486 with warnings.catch_warnings(record=True) as ws:
486 with warnings.catch_warnings(record=True) as ws:
487 if input_lines[0].endswith(';'):
487 if input_lines[0].endswith(';'):
488 is_semicolon = True
488 is_semicolon = True
489 #for i, line in enumerate(input_lines):
489 #for i, line in enumerate(input_lines):
490
490
491 # process the first input line
491 # process the first input line
492 if is_verbatim:
492 if is_verbatim:
493 self.process_input_lines([''])
493 self.process_input_lines([''])
494 self.IP.execution_count += 1 # increment it anyway
494 self.IP.execution_count += 1 # increment it anyway
495 else:
495 else:
496 # only submit the line in non-verbatim mode
496 # only submit the line in non-verbatim mode
497 self.process_input_lines(input_lines, store_history=store_history)
497 self.process_input_lines(input_lines, store_history=store_history)
498
498
499 if not is_suppress:
499 if not is_suppress:
500 for i, line in enumerate(input_lines):
500 for i, line in enumerate(input_lines):
501 if i == 0:
501 if i == 0:
502 formatted_line = '%s %s'%(input_prompt, line)
502 formatted_line = '%s %s'%(input_prompt, line)
503 else:
503 else:
504 formatted_line = '%s %s'%(continuation, line)
504 formatted_line = '%s %s'%(continuation, line)
505 ret.append(formatted_line)
505 ret.append(formatted_line)
506
506
507 if not is_suppress and len(rest.strip()) and is_verbatim:
507 if not is_suppress and len(rest.strip()) and is_verbatim:
508 # The "rest" is the standard output of the input. This needs to be
508 # The "rest" is the standard output of the input. This needs to be
509 # added when in verbatim mode. If there is no "rest", then we don't
509 # added when in verbatim mode. If there is no "rest", then we don't
510 # add it, as the new line will be added by the processed output.
510 # add it, as the new line will be added by the processed output.
511 ret.append(rest)
511 ret.append(rest)
512
512
513 # Fetch the processed output. (This is not the submitted output.)
513 # Fetch the processed output. (This is not the submitted output.)
514 self.cout.seek(0)
514 self.cout.seek(0)
515 processed_output = self.cout.read()
515 processed_output = self.cout.read()
516 if not is_suppress and not is_semicolon:
516 if not is_suppress and not is_semicolon:
517 #
517 #
518 # In IPythonDirective.run, the elements of `ret` are eventually
518 # In IPythonDirective.run, the elements of `ret` are eventually
519 # combined such that '' entries correspond to newlines. So if
519 # combined such that '' entries correspond to newlines. So if
520 # `processed_output` is equal to '', then the adding it to `ret`
520 # `processed_output` is equal to '', then the adding it to `ret`
521 # ensures that there is a blank line between consecutive inputs
521 # ensures that there is a blank line between consecutive inputs
522 # that have no outputs, as in:
522 # that have no outputs, as in:
523 #
523 #
524 # In [1]: x = 4
524 # In [1]: x = 4
525 #
525 #
526 # In [2]: x = 5
526 # In [2]: x = 5
527 #
527 #
528 # When there is processed output, it has a '\n' at the tail end. So
528 # When there is processed output, it has a '\n' at the tail end. So
529 # adding the output to `ret` will provide the necessary spacing
529 # adding the output to `ret` will provide the necessary spacing
530 # between consecutive input/output blocks, as in:
530 # between consecutive input/output blocks, as in:
531 #
531 #
532 # In [1]: x
532 # In [1]: x
533 # Out[1]: 5
533 # Out[1]: 5
534 #
534 #
535 # In [2]: x
535 # In [2]: x
536 # Out[2]: 5
536 # Out[2]: 5
537 #
537 #
538 # When there is stdout from the input, it also has a '\n' at the
538 # When there is stdout from the input, it also has a '\n' at the
539 # tail end, and so this ensures proper spacing as well. E.g.:
539 # tail end, and so this ensures proper spacing as well. E.g.:
540 #
540 #
541 # In [1]: print x
541 # In [1]: print x
542 # 5
542 # 5
543 #
543 #
544 # In [2]: x = 5
544 # In [2]: x = 5
545 #
545 #
546 # When in verbatim mode, `processed_output` is empty (because
546 # When in verbatim mode, `processed_output` is empty (because
547 # nothing was passed to IP. Sometimes the submitted code block has
547 # nothing was passed to IP. Sometimes the submitted code block has
548 # an Out[] portion and sometimes it does not. When it does not, we
548 # an Out[] portion and sometimes it does not. When it does not, we
549 # need to ensure proper spacing, so we have to add '' to `ret`.
549 # need to ensure proper spacing, so we have to add '' to `ret`.
550 # However, if there is an Out[] in the submitted code, then we do
550 # However, if there is an Out[] in the submitted code, then we do
551 # not want to add a newline as `process_output` has stuff to add.
551 # not want to add a newline as `process_output` has stuff to add.
552 # The difficulty is that `process_input` doesn't know if
552 # The difficulty is that `process_input` doesn't know if
553 # `process_output` will be called---so it doesn't know if there is
553 # `process_output` will be called---so it doesn't know if there is
554 # Out[] in the code block. The requires that we include a hack in
554 # Out[] in the code block. The requires that we include a hack in
555 # `process_block`. See the comments there.
555 # `process_block`. See the comments there.
556 #
556 #
557 ret.append(processed_output)
557 ret.append(processed_output)
558 elif is_semicolon:
558 elif is_semicolon:
559 # Make sure there is a newline after the semicolon.
559 # Make sure there is a newline after the semicolon.
560 ret.append('')
560 ret.append('')
561
561
562 # context information
562 # context information
563 filename = "Unknown"
563 filename = "Unknown"
564 lineno = 0
564 lineno = 0
565 if self.directive.state:
565 if self.directive.state:
566 filename = self.directive.state.document.current_source
566 filename = self.directive.state.document.current_source
567 lineno = self.directive.state.document.current_line
567 lineno = self.directive.state.document.current_line
568
568
569 # Use sphinx logger for warnings
569 # Use sphinx logger for warnings
570 logger = logging.getLogger(__name__)
570 logger = logging.getLogger(__name__)
571
571
572 # output any exceptions raised during execution to stdout
572 # output any exceptions raised during execution to stdout
573 # unless :okexcept: has been specified.
573 # unless :okexcept: has been specified.
574 if not is_okexcept and (
574 if not is_okexcept and (
575 ("Traceback" in processed_output) or ("SyntaxError" in processed_output)
575 ("Traceback" in processed_output) or ("SyntaxError" in processed_output)
576 ):
576 ):
577 s = "\n>>>" + ("-" * 73) + "\n"
577 s = "\n>>>" + ("-" * 73) + "\n"
578 s += "Exception in %s at block ending on line %s\n" % (filename, lineno)
578 s += "Exception in %s at block ending on line %s\n" % (filename, lineno)
579 s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n"
579 s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n"
580 s += processed_output + "\n"
580 s += processed_output + "\n"
581 s += "<<<" + ("-" * 73)
581 s += "<<<" + ("-" * 73)
582 logger.warning(s)
582 logger.warning(s)
583 if self.warning_is_error:
583 if self.warning_is_error:
584 raise RuntimeError('Non Expected exception in `{}` line {}'.format(filename, lineno))
584 raise RuntimeError('Non Expected exception in `{}` line {}'.format(filename, lineno))
585
585
586 # output any warning raised during execution to stdout
586 # output any warning raised during execution to stdout
587 # unless :okwarning: has been specified.
587 # unless :okwarning: has been specified.
588 if not is_okwarning:
588 if not is_okwarning:
589 for w in ws:
589 for w in ws:
590 s = "\n>>>" + ("-" * 73) + "\n"
590 s = "\n>>>" + ("-" * 73) + "\n"
591 s += "Warning in %s at block ending on line %s\n" % (filename, lineno)
591 s += "Warning in %s at block ending on line %s\n" % (filename, lineno)
592 s += "Specify :okwarning: as an option in the ipython:: block to suppress this message\n"
592 s += "Specify :okwarning: as an option in the ipython:: block to suppress this message\n"
593 s += ("-" * 76) + "\n"
593 s += ("-" * 76) + "\n"
594 s += warnings.formatwarning(
594 s += warnings.formatwarning(
595 w.message, w.category, w.filename, w.lineno, w.line
595 w.message, w.category, w.filename, w.lineno, w.line
596 )
596 )
597 s += "<<<" + ("-" * 73)
597 s += "<<<" + ("-" * 73)
598 logger.warning(s)
598 logger.warning(s)
599 if self.warning_is_error:
599 if self.warning_is_error:
600 raise RuntimeError('Non Expected warning in `{}` line {}'.format(filename, lineno))
600 raise RuntimeError('Non Expected warning in `{}` line {}'.format(filename, lineno))
601
601
602 self.clear_cout()
602 self.clear_cout()
603 return (ret, input_lines, processed_output,
603 return (ret, input_lines, processed_output,
604 is_doctest, decorator, image_file, image_directive)
604 is_doctest, decorator, image_file, image_directive)
605
605
606
606
607 def process_output(self, data, output_prompt, input_lines, output,
607 def process_output(self, data, output_prompt, input_lines, output,
608 is_doctest, decorator, image_file):
608 is_doctest, decorator, image_file):
609 """
609 """
610 Process data block for OUTPUT token.
610 Process data block for OUTPUT token.
611
611
612 """
612 """
613 # Recall: `data` is the submitted output, and `output` is the processed
613 # Recall: `data` is the submitted output, and `output` is the processed
614 # output from `input_lines`.
614 # output from `input_lines`.
615
615
616 TAB = ' ' * 4
616 TAB = ' ' * 4
617
617
618 if is_doctest and output is not None:
618 if is_doctest and output is not None:
619
619
620 found = output # This is the processed output
620 found = output # This is the processed output
621 found = found.strip()
621 found = found.strip()
622 submitted = data.strip()
622 submitted = data.strip()
623
623
624 if self.directive is None:
624 if self.directive is None:
625 source = 'Unavailable'
625 source = 'Unavailable'
626 content = 'Unavailable'
626 content = 'Unavailable'
627 else:
627 else:
628 source = self.directive.state.document.current_source
628 source = self.directive.state.document.current_source
629 content = self.directive.content
629 content = self.directive.content
630 # Add tabs and join into a single string.
630 # Add tabs and join into a single string.
631 content = '\n'.join([TAB + line for line in content])
631 content = '\n'.join([TAB + line for line in content])
632
632
633 # Make sure the output contains the output prompt.
633 # Make sure the output contains the output prompt.
634 ind = found.find(output_prompt)
634 ind = found.find(output_prompt)
635 if ind < 0:
635 if ind < 0:
636 e = ('output does not contain output prompt\n\n'
636 e = ('output does not contain output prompt\n\n'
637 'Document source: {0}\n\n'
637 'Document source: {0}\n\n'
638 'Raw content: \n{1}\n\n'
638 'Raw content: \n{1}\n\n'
639 'Input line(s):\n{TAB}{2}\n\n'
639 'Input line(s):\n{TAB}{2}\n\n'
640 'Output line(s):\n{TAB}{3}\n\n')
640 'Output line(s):\n{TAB}{3}\n\n')
641 e = e.format(source, content, '\n'.join(input_lines),
641 e = e.format(source, content, '\n'.join(input_lines),
642 repr(found), TAB=TAB)
642 repr(found), TAB=TAB)
643 raise RuntimeError(e)
643 raise RuntimeError(e)
644 found = found[len(output_prompt):].strip()
644 found = found[len(output_prompt):].strip()
645
645
646 # Handle the actual doctest comparison.
646 # Handle the actual doctest comparison.
647 if decorator.strip() == '@doctest':
647 if decorator.strip() == '@doctest':
648 # Standard doctest
648 # Standard doctest
649 if found != submitted:
649 if found != submitted:
650 e = ('doctest failure\n\n'
650 e = ('doctest failure\n\n'
651 'Document source: {0}\n\n'
651 'Document source: {0}\n\n'
652 'Raw content: \n{1}\n\n'
652 'Raw content: \n{1}\n\n'
653 'On input line(s):\n{TAB}{2}\n\n'
653 'On input line(s):\n{TAB}{2}\n\n'
654 'we found output:\n{TAB}{3}\n\n'
654 'we found output:\n{TAB}{3}\n\n'
655 'instead of the expected:\n{TAB}{4}\n\n')
655 'instead of the expected:\n{TAB}{4}\n\n')
656 e = e.format(source, content, '\n'.join(input_lines),
656 e = e.format(source, content, '\n'.join(input_lines),
657 repr(found), repr(submitted), TAB=TAB)
657 repr(found), repr(submitted), TAB=TAB)
658 raise RuntimeError(e)
658 raise RuntimeError(e)
659 else:
659 else:
660 self.custom_doctest(decorator, input_lines, found, submitted)
660 self.custom_doctest(decorator, input_lines, found, submitted)
661
661
662 # When in verbatim mode, this holds additional submitted output
662 # When in verbatim mode, this holds additional submitted output
663 # to be written in the final Sphinx output.
663 # to be written in the final Sphinx output.
664 # https://github.com/ipython/ipython/issues/5776
664 # https://github.com/ipython/ipython/issues/5776
665 out_data = []
665 out_data = []
666
666
667 is_verbatim = decorator=='@verbatim' or self.is_verbatim
667 is_verbatim = decorator=='@verbatim' or self.is_verbatim
668 if is_verbatim and data.strip():
668 if is_verbatim and data.strip():
669 # Note that `ret` in `process_block` has '' as its last element if
669 # Note that `ret` in `process_block` has '' as its last element if
670 # the code block was in verbatim mode. So if there is no submitted
670 # the code block was in verbatim mode. So if there is no submitted
671 # output, then we will have proper spacing only if we do not add
671 # output, then we will have proper spacing only if we do not add
672 # an additional '' to `out_data`. This is why we condition on
672 # an additional '' to `out_data`. This is why we condition on
673 # `and data.strip()`.
673 # `and data.strip()`.
674
674
675 # The submitted output has no output prompt. If we want the
675 # The submitted output has no output prompt. If we want the
676 # prompt and the code to appear, we need to join them now
676 # prompt and the code to appear, we need to join them now
677 # instead of adding them separately---as this would create an
677 # instead of adding them separately---as this would create an
678 # undesired newline. How we do this ultimately depends on the
678 # undesired newline. How we do this ultimately depends on the
679 # format of the output regex. I'll do what works for the default
679 # format of the output regex. I'll do what works for the default
680 # prompt for now, and we might have to adjust if it doesn't work
680 # prompt for now, and we might have to adjust if it doesn't work
681 # in other cases. Finally, the submitted output does not have
681 # in other cases. Finally, the submitted output does not have
682 # a trailing newline, so we must add it manually.
682 # a trailing newline, so we must add it manually.
683 out_data.append("{0} {1}\n".format(output_prompt, data))
683 out_data.append("{0} {1}\n".format(output_prompt, data))
684
684
685 return out_data
685 return out_data
686
686
687 def process_comment(self, data):
687 def process_comment(self, data):
688 """Process data fPblock for COMMENT token."""
688 """Process data fPblock for COMMENT token."""
689 if not self.is_suppress:
689 if not self.is_suppress:
690 return [data]
690 return [data]
691
691
692 def save_image(self, image_file):
692 def save_image(self, image_file):
693 """
693 """
694 Saves the image file to disk.
694 Saves the image file to disk.
695 """
695 """
696 self.ensure_pyplot()
696 self.ensure_pyplot()
697 command = 'plt.gcf().savefig("%s")'%image_file
697 command = 'plt.gcf().savefig("%s")'%image_file
698 #print 'SAVEFIG', command # dbg
698 #print 'SAVEFIG', command # dbg
699 self.process_input_line('bookmark ipy_thisdir', store_history=False)
699 self.process_input_line('bookmark ipy_thisdir', store_history=False)
700 self.process_input_line('cd -b ipy_savedir', store_history=False)
700 self.process_input_line('cd -b ipy_savedir', store_history=False)
701 self.process_input_line(command, store_history=False)
701 self.process_input_line(command, store_history=False)
702 self.process_input_line('cd -b ipy_thisdir', store_history=False)
702 self.process_input_line('cd -b ipy_thisdir', store_history=False)
703 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
703 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
704 self.clear_cout()
704 self.clear_cout()
705
705
706 def process_block(self, block):
706 def process_block(self, block):
707 """
707 """
708 process block from the block_parser and return a list of processed lines
708 process block from the block_parser and return a list of processed lines
709 """
709 """
710 ret = []
710 ret = []
711 output = None
711 output = None
712 input_lines = None
712 input_lines = None
713 lineno = self.IP.execution_count
713 lineno = self.IP.execution_count
714
714
715 input_prompt = self.promptin % lineno
715 input_prompt = self.promptin % lineno
716 output_prompt = self.promptout % lineno
716 output_prompt = self.promptout % lineno
717 image_file = None
717 image_file = None
718 image_directive = None
718 image_directive = None
719
719
720 found_input = False
720 found_input = False
721 for token, data in block:
721 for token, data in block:
722 if token == COMMENT:
722 if token == COMMENT:
723 out_data = self.process_comment(data)
723 out_data = self.process_comment(data)
724 elif token == INPUT:
724 elif token == INPUT:
725 found_input = True
725 found_input = True
726 (out_data, input_lines, output, is_doctest,
726 (out_data, input_lines, output, is_doctest,
727 decorator, image_file, image_directive) = \
727 decorator, image_file, image_directive) = \
728 self.process_input(data, input_prompt, lineno)
728 self.process_input(data, input_prompt, lineno)
729 elif token == OUTPUT:
729 elif token == OUTPUT:
730 if not found_input:
730 if not found_input:
731
731
732 TAB = ' ' * 4
732 TAB = ' ' * 4
733 linenumber = 0
733 linenumber = 0
734 source = 'Unavailable'
734 source = 'Unavailable'
735 content = 'Unavailable'
735 content = 'Unavailable'
736 if self.directive:
736 if self.directive:
737 linenumber = self.directive.state.document.current_line
737 linenumber = self.directive.state.document.current_line
738 source = self.directive.state.document.current_source
738 source = self.directive.state.document.current_source
739 content = self.directive.content
739 content = self.directive.content
740 # Add tabs and join into a single string.
740 # Add tabs and join into a single string.
741 content = '\n'.join([TAB + line for line in content])
741 content = '\n'.join([TAB + line for line in content])
742
742
743 e = ('\n\nInvalid block: Block contains an output prompt '
743 e = ('\n\nInvalid block: Block contains an output prompt '
744 'without an input prompt.\n\n'
744 'without an input prompt.\n\n'
745 'Document source: {0}\n\n'
745 'Document source: {0}\n\n'
746 'Content begins at line {1}: \n\n{2}\n\n'
746 'Content begins at line {1}: \n\n{2}\n\n'
747 'Problematic block within content: \n\n{TAB}{3}\n\n')
747 'Problematic block within content: \n\n{TAB}{3}\n\n')
748 e = e.format(source, linenumber, content, block, TAB=TAB)
748 e = e.format(source, linenumber, content, block, TAB=TAB)
749
749
750 # Write, rather than include in exception, since Sphinx
750 # Write, rather than include in exception, since Sphinx
751 # will truncate tracebacks.
751 # will truncate tracebacks.
752 sys.stdout.write(e)
752 sys.stdout.write(e)
753 raise RuntimeError('An invalid block was detected.')
753 raise RuntimeError('An invalid block was detected.')
754 out_data = \
754 out_data = \
755 self.process_output(data, output_prompt, input_lines,
755 self.process_output(data, output_prompt, input_lines,
756 output, is_doctest, decorator,
756 output, is_doctest, decorator,
757 image_file)
757 image_file)
758 if out_data:
758 if out_data:
759 # Then there was user submitted output in verbatim mode.
759 # Then there was user submitted output in verbatim mode.
760 # We need to remove the last element of `ret` that was
760 # We need to remove the last element of `ret` that was
761 # added in `process_input`, as it is '' and would introduce
761 # added in `process_input`, as it is '' and would introduce
762 # an undesirable newline.
762 # an undesirable newline.
763 assert(ret[-1] == '')
763 assert(ret[-1] == '')
764 del ret[-1]
764 del ret[-1]
765
765
766 if out_data:
766 if out_data:
767 ret.extend(out_data)
767 ret.extend(out_data)
768
768
769 # save the image files
769 # save the image files
770 if image_file is not None:
770 if image_file is not None:
771 self.save_image(image_file)
771 self.save_image(image_file)
772
772
773 return ret, image_directive
773 return ret, image_directive
774
774
775 def ensure_pyplot(self):
775 def ensure_pyplot(self):
776 """
776 """
777 Ensures that pyplot has been imported into the embedded IPython shell.
777 Ensures that pyplot has been imported into the embedded IPython shell.
778
778
779 Also, makes sure to set the backend appropriately if not set already.
779 Also, makes sure to set the backend appropriately if not set already.
780
780
781 """
781 """
782 # We are here if the @figure pseudo decorator was used. Thus, it's
782 # We are here if the @figure pseudo decorator was used. Thus, it's
783 # possible that we could be here even if python_mplbackend were set to
783 # possible that we could be here even if python_mplbackend were set to
784 # `None`. That's also strange and perhaps worthy of raising an
784 # `None`. That's also strange and perhaps worthy of raising an
785 # exception, but for now, we just set the backend to 'agg'.
785 # exception, but for now, we just set the backend to 'agg'.
786
786
787 if not self._pyplot_imported:
787 if not self._pyplot_imported:
788 if 'matplotlib.backends' not in sys.modules:
788 if 'matplotlib.backends' not in sys.modules:
789 # Then ipython_matplotlib was set to None but there was a
789 # Then ipython_matplotlib was set to None but there was a
790 # call to the @figure decorator (and ipython_execlines did
790 # call to the @figure decorator (and ipython_execlines did
791 # not set a backend).
791 # not set a backend).
792 #raise Exception("No backend was set, but @figure was used!")
792 #raise Exception("No backend was set, but @figure was used!")
793 import matplotlib
793 import matplotlib
794 matplotlib.use('agg')
794 matplotlib.use('agg')
795
795
796 # Always import pyplot into embedded shell.
796 # Always import pyplot into embedded shell.
797 self.process_input_line('import matplotlib.pyplot as plt',
797 self.process_input_line('import matplotlib.pyplot as plt',
798 store_history=False)
798 store_history=False)
799 self._pyplot_imported = True
799 self._pyplot_imported = True
800
800
801 def process_pure_python(self, content):
801 def process_pure_python(self, content):
802 """
802 """
803 content is a list of strings. it is unedited directive content
803 content is a list of strings. it is unedited directive content
804
804
805 This runs it line by line in the InteractiveShell, prepends
805 This runs it line by line in the InteractiveShell, prepends
806 prompts as needed capturing stderr and stdout, then returns
806 prompts as needed capturing stderr and stdout, then returns
807 the content as a list as if it were ipython code
807 the content as a list as if it were ipython code
808 """
808 """
809 output = []
809 output = []
810 savefig = False # keep up with this to clear figure
810 savefig = False # keep up with this to clear figure
811 multiline = False # to handle line continuation
811 multiline = False # to handle line continuation
812 multiline_start = None
812 multiline_start = None
813 fmtin = self.promptin
813 fmtin = self.promptin
814
814
815 ct = 0
815 ct = 0
816
816
817 for lineno, line in enumerate(content):
817 for lineno, line in enumerate(content):
818
818
819 line_stripped = line.strip()
819 line_stripped = line.strip()
820 if not len(line):
820 if not len(line):
821 output.append(line)
821 output.append(line)
822 continue
822 continue
823
823
824 # handle pseudo-decorators, whilst ensuring real python decorators are treated as input
824 # handle pseudo-decorators, whilst ensuring real python decorators are treated as input
825 if any(
825 if any(
826 line_stripped.startswith("@" + pseudo_decorator)
826 line_stripped.startswith("@" + pseudo_decorator)
827 for pseudo_decorator in PSEUDO_DECORATORS
827 for pseudo_decorator in PSEUDO_DECORATORS
828 ):
828 ):
829 output.extend([line])
829 output.extend([line])
830 if 'savefig' in line:
830 if 'savefig' in line:
831 savefig = True # and need to clear figure
831 savefig = True # and need to clear figure
832 continue
832 continue
833
833
834 # handle comments
834 # handle comments
835 if line_stripped.startswith('#'):
835 if line_stripped.startswith('#'):
836 output.extend([line])
836 output.extend([line])
837 continue
837 continue
838
838
839 # deal with lines checking for multiline
839 # deal with lines checking for multiline
840 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
840 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
841 if not multiline:
841 if not multiline:
842 modified = u"%s %s" % (fmtin % ct, line_stripped)
842 modified = u"%s %s" % (fmtin % ct, line_stripped)
843 output.append(modified)
843 output.append(modified)
844 ct += 1
844 ct += 1
845 try:
845 try:
846 ast.parse(line_stripped)
846 ast.parse(line_stripped)
847 output.append(u'')
847 output.append(u'')
848 except Exception: # on a multiline
848 except Exception: # on a multiline
849 multiline = True
849 multiline = True
850 multiline_start = lineno
850 multiline_start = lineno
851 else: # still on a multiline
851 else: # still on a multiline
852 modified = u'%s %s' % (continuation, line)
852 modified = u'%s %s' % (continuation, line)
853 output.append(modified)
853 output.append(modified)
854
854
855 # if the next line is indented, it should be part of multiline
855 # if the next line is indented, it should be part of multiline
856 if len(content) > lineno + 1:
856 if len(content) > lineno + 1:
857 nextline = content[lineno + 1]
857 nextline = content[lineno + 1]
858 if len(nextline) - len(nextline.lstrip()) > 3:
858 if len(nextline) - len(nextline.lstrip()) > 3:
859 continue
859 continue
860 try:
860 try:
861 mod = ast.parse(
861 mod = ast.parse(
862 '\n'.join(content[multiline_start:lineno+1]))
862 '\n'.join(content[multiline_start:lineno+1]))
863 if isinstance(mod.body[0], ast.FunctionDef):
863 if isinstance(mod.body[0], ast.FunctionDef):
864 # check to see if we have the whole function
864 # check to see if we have the whole function
865 for element in mod.body[0].body:
865 for element in mod.body[0].body:
866 if isinstance(element, ast.Return):
866 if isinstance(element, ast.Return):
867 multiline = False
867 multiline = False
868 else:
868 else:
869 output.append(u'')
869 output.append(u'')
870 multiline = False
870 multiline = False
871 except Exception:
871 except Exception:
872 pass
872 pass
873
873
874 if savefig: # clear figure if plotted
874 if savefig: # clear figure if plotted
875 self.ensure_pyplot()
875 self.ensure_pyplot()
876 self.process_input_line('plt.clf()', store_history=False)
876 self.process_input_line('plt.clf()', store_history=False)
877 self.clear_cout()
877 self.clear_cout()
878 savefig = False
878 savefig = False
879
879
880 return output
880 return output
881
881
882 def custom_doctest(self, decorator, input_lines, found, submitted):
882 def custom_doctest(self, decorator, input_lines, found, submitted):
883 """
883 """
884 Perform a specialized doctest.
884 Perform a specialized doctest.
885
885
886 """
886 """
887 from .custom_doctests import doctests
887 from .custom_doctests import doctests
888
888
889 args = decorator.split()
889 args = decorator.split()
890 doctest_type = args[1]
890 doctest_type = args[1]
891 if doctest_type in doctests:
891 if doctest_type in doctests:
892 doctests[doctest_type](self, args, input_lines, found, submitted)
892 doctests[doctest_type](self, args, input_lines, found, submitted)
893 else:
893 else:
894 e = "Invalid option to @doctest: {0}".format(doctest_type)
894 e = "Invalid option to @doctest: {0}".format(doctest_type)
895 raise Exception(e)
895 raise Exception(e)
896
896
897
897
898 class IPythonDirective(Directive):
898 class IPythonDirective(Directive):
899
899
900 has_content = True
900 has_content = True
901 required_arguments = 0
901 required_arguments = 0
902 optional_arguments = 4 # python, suppress, verbatim, doctest
902 optional_arguments = 4 # python, suppress, verbatim, doctest
903 final_argumuent_whitespace = True
903 final_argumuent_whitespace = True
904 option_spec = { 'python': directives.unchanged,
904 option_spec = { 'python': directives.unchanged,
905 'suppress' : directives.flag,
905 'suppress' : directives.flag,
906 'verbatim' : directives.flag,
906 'verbatim' : directives.flag,
907 'doctest' : directives.flag,
907 'doctest' : directives.flag,
908 'okexcept': directives.flag,
908 'okexcept': directives.flag,
909 'okwarning': directives.flag
909 'okwarning': directives.flag
910 }
910 }
911
911
912 shell = None
912 shell = None
913
913
914 seen_docs = set()
914 seen_docs = set()
915
915
916 def get_config_options(self):
916 def get_config_options(self):
917 # contains sphinx configuration variables
917 # contains sphinx configuration variables
918 config = self.state.document.settings.env.config
918 config = self.state.document.settings.env.config
919
919
920 # get config variables to set figure output directory
920 # get config variables to set figure output directory
921 savefig_dir = config.ipython_savefig_dir
921 savefig_dir = config.ipython_savefig_dir
922 source_dir = self.state.document.settings.env.srcdir
922 source_dir = self.state.document.settings.env.srcdir
923 savefig_dir = os.path.join(source_dir, savefig_dir)
923 savefig_dir = os.path.join(source_dir, savefig_dir)
924
924
925 # get regex and prompt stuff
925 # get regex and prompt stuff
926 rgxin = config.ipython_rgxin
926 rgxin = config.ipython_rgxin
927 rgxout = config.ipython_rgxout
927 rgxout = config.ipython_rgxout
928 warning_is_error= config.ipython_warning_is_error
928 warning_is_error= config.ipython_warning_is_error
929 promptin = config.ipython_promptin
929 promptin = config.ipython_promptin
930 promptout = config.ipython_promptout
930 promptout = config.ipython_promptout
931 mplbackend = config.ipython_mplbackend
931 mplbackend = config.ipython_mplbackend
932 exec_lines = config.ipython_execlines
932 exec_lines = config.ipython_execlines
933 hold_count = config.ipython_holdcount
933 hold_count = config.ipython_holdcount
934
934
935 return (savefig_dir, source_dir, rgxin, rgxout,
935 return (savefig_dir, source_dir, rgxin, rgxout,
936 promptin, promptout, mplbackend, exec_lines, hold_count, warning_is_error)
936 promptin, promptout, mplbackend, exec_lines, hold_count, warning_is_error)
937
937
938 def setup(self):
938 def setup(self):
939 # Get configuration values.
939 # Get configuration values.
940 (savefig_dir, source_dir, rgxin, rgxout, promptin, promptout,
940 (savefig_dir, source_dir, rgxin, rgxout, promptin, promptout,
941 mplbackend, exec_lines, hold_count, warning_is_error) = self.get_config_options()
941 mplbackend, exec_lines, hold_count, warning_is_error) = self.get_config_options()
942
942
943 try:
943 try:
944 os.makedirs(savefig_dir)
944 os.makedirs(savefig_dir)
945 except OSError as e:
945 except OSError as e:
946 if e.errno != errno.EEXIST:
946 if e.errno != errno.EEXIST:
947 raise
947 raise
948
948
949 if self.shell is None:
949 if self.shell is None:
950 # We will be here many times. However, when the
950 # We will be here many times. However, when the
951 # EmbeddedSphinxShell is created, its interactive shell member
951 # EmbeddedSphinxShell is created, its interactive shell member
952 # is the same for each instance.
952 # is the same for each instance.
953
953
954 if mplbackend and 'matplotlib.backends' not in sys.modules and use_matplotlib:
954 if mplbackend and 'matplotlib.backends' not in sys.modules and use_matplotlib:
955 import matplotlib
955 import matplotlib
956 matplotlib.use(mplbackend)
956 matplotlib.use(mplbackend)
957
957
958 # Must be called after (potentially) importing matplotlib and
958 # Must be called after (potentially) importing matplotlib and
959 # setting its backend since exec_lines might import pylab.
959 # setting its backend since exec_lines might import pylab.
960 self.shell = EmbeddedSphinxShell(exec_lines)
960 self.shell = EmbeddedSphinxShell(exec_lines)
961
961
962 # Store IPython directive to enable better error messages
962 # Store IPython directive to enable better error messages
963 self.shell.directive = self
963 self.shell.directive = self
964
964
965 # reset the execution count if we haven't processed this doc
965 # reset the execution count if we haven't processed this doc
966 #NOTE: this may be borked if there are multiple seen_doc tmp files
966 #NOTE: this may be borked if there are multiple seen_doc tmp files
967 #check time stamp?
967 #check time stamp?
968 if not self.state.document.current_source in self.seen_docs:
968 if not self.state.document.current_source in self.seen_docs:
969 self.shell.IP.history_manager.reset()
969 self.shell.IP.history_manager.reset()
970 self.shell.IP.execution_count = 1
970 self.shell.IP.execution_count = 1
971 self.seen_docs.add(self.state.document.current_source)
971 self.seen_docs.add(self.state.document.current_source)
972
972
973 # and attach to shell so we don't have to pass them around
973 # and attach to shell so we don't have to pass them around
974 self.shell.rgxin = rgxin
974 self.shell.rgxin = rgxin
975 self.shell.rgxout = rgxout
975 self.shell.rgxout = rgxout
976 self.shell.promptin = promptin
976 self.shell.promptin = promptin
977 self.shell.promptout = promptout
977 self.shell.promptout = promptout
978 self.shell.savefig_dir = savefig_dir
978 self.shell.savefig_dir = savefig_dir
979 self.shell.source_dir = source_dir
979 self.shell.source_dir = source_dir
980 self.shell.hold_count = hold_count
980 self.shell.hold_count = hold_count
981 self.shell.warning_is_error = warning_is_error
981 self.shell.warning_is_error = warning_is_error
982
982
983 # setup bookmark for saving figures directory
983 # setup bookmark for saving figures directory
984 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
984 self.shell.process_input_line(
985 store_history=False)
985 'bookmark ipy_savedir "%s"' % savefig_dir, store_history=False
986 )
986 self.shell.clear_cout()
987 self.shell.clear_cout()
987
988
988 return rgxin, rgxout, promptin, promptout
989 return rgxin, rgxout, promptin, promptout
989
990
990 def teardown(self):
991 def teardown(self):
991 # delete last bookmark
992 # delete last bookmark
992 self.shell.process_input_line('bookmark -d ipy_savedir',
993 self.shell.process_input_line('bookmark -d ipy_savedir',
993 store_history=False)
994 store_history=False)
994 self.shell.clear_cout()
995 self.shell.clear_cout()
995
996
996 def run(self):
997 def run(self):
997 debug = False
998 debug = False
998
999
999 #TODO, any reason block_parser can't be a method of embeddable shell
1000 #TODO, any reason block_parser can't be a method of embeddable shell
1000 # then we wouldn't have to carry these around
1001 # then we wouldn't have to carry these around
1001 rgxin, rgxout, promptin, promptout = self.setup()
1002 rgxin, rgxout, promptin, promptout = self.setup()
1002
1003
1003 options = self.options
1004 options = self.options
1004 self.shell.is_suppress = 'suppress' in options
1005 self.shell.is_suppress = 'suppress' in options
1005 self.shell.is_doctest = 'doctest' in options
1006 self.shell.is_doctest = 'doctest' in options
1006 self.shell.is_verbatim = 'verbatim' in options
1007 self.shell.is_verbatim = 'verbatim' in options
1007 self.shell.is_okexcept = 'okexcept' in options
1008 self.shell.is_okexcept = 'okexcept' in options
1008 self.shell.is_okwarning = 'okwarning' in options
1009 self.shell.is_okwarning = 'okwarning' in options
1009
1010
1010 # handle pure python code
1011 # handle pure python code
1011 if 'python' in self.arguments:
1012 if 'python' in self.arguments:
1012 content = self.content
1013 content = self.content
1013 self.content = self.shell.process_pure_python(content)
1014 self.content = self.shell.process_pure_python(content)
1014
1015
1015 # parts consists of all text within the ipython-block.
1016 # parts consists of all text within the ipython-block.
1016 # Each part is an input/output block.
1017 # Each part is an input/output block.
1017 parts = '\n'.join(self.content).split('\n\n')
1018 parts = '\n'.join(self.content).split('\n\n')
1018
1019
1019 lines = ['.. code-block:: ipython', '']
1020 lines = ['.. code-block:: ipython', '']
1020 figures = []
1021 figures = []
1021
1022
1022 # Use sphinx logger for warnings
1023 # Use sphinx logger for warnings
1023 logger = logging.getLogger(__name__)
1024 logger = logging.getLogger(__name__)
1024
1025
1025 for part in parts:
1026 for part in parts:
1026 block = block_parser(part, rgxin, rgxout, promptin, promptout)
1027 block = block_parser(part, rgxin, rgxout, promptin, promptout)
1027 if len(block):
1028 if len(block):
1028 rows, figure = self.shell.process_block(block)
1029 rows, figure = self.shell.process_block(block)
1029 for row in rows:
1030 for row in rows:
1030 lines.extend([' {0}'.format(line)
1031 lines.extend([' {0}'.format(line)
1031 for line in row.split('\n')])
1032 for line in row.split('\n')])
1032
1033
1033 if figure is not None:
1034 if figure is not None:
1034 figures.append(figure)
1035 figures.append(figure)
1035 else:
1036 else:
1036 message = 'Code input with no code at {}, line {}'\
1037 message = 'Code input with no code at {}, line {}'\
1037 .format(
1038 .format(
1038 self.state.document.current_source,
1039 self.state.document.current_source,
1039 self.state.document.current_line)
1040 self.state.document.current_line)
1040 if self.shell.warning_is_error:
1041 if self.shell.warning_is_error:
1041 raise RuntimeError(message)
1042 raise RuntimeError(message)
1042 else:
1043 else:
1043 logger.warning(message)
1044 logger.warning(message)
1044
1045
1045 for figure in figures:
1046 for figure in figures:
1046 lines.append('')
1047 lines.append('')
1047 lines.extend(figure.split('\n'))
1048 lines.extend(figure.split('\n'))
1048 lines.append('')
1049 lines.append('')
1049
1050
1050 if len(lines) > 2:
1051 if len(lines) > 2:
1051 if debug:
1052 if debug:
1052 print('\n'.join(lines))
1053 print('\n'.join(lines))
1053 else:
1054 else:
1054 # This has to do with input, not output. But if we comment
1055 # This has to do with input, not output. But if we comment
1055 # these lines out, then no IPython code will appear in the
1056 # these lines out, then no IPython code will appear in the
1056 # final output.
1057 # final output.
1057 self.state_machine.insert_input(
1058 self.state_machine.insert_input(
1058 lines, self.state_machine.input_lines.source(0))
1059 lines, self.state_machine.input_lines.source(0))
1059
1060
1060 # cleanup
1061 # cleanup
1061 self.teardown()
1062 self.teardown()
1062
1063
1063 return []
1064 return []
1064
1065
1065 # Enable as a proper Sphinx directive
1066 # Enable as a proper Sphinx directive
1066 def setup(app):
1067 def setup(app):
1067 setup.app = app
1068 setup.app = app
1068
1069
1069 app.add_directive('ipython', IPythonDirective)
1070 app.add_directive('ipython', IPythonDirective)
1070 app.add_config_value('ipython_savefig_dir', 'savefig', 'env')
1071 app.add_config_value('ipython_savefig_dir', 'savefig', 'env')
1071 app.add_config_value('ipython_warning_is_error', True, 'env')
1072 app.add_config_value('ipython_warning_is_error', True, 'env')
1072 app.add_config_value('ipython_rgxin',
1073 app.add_config_value('ipython_rgxin',
1073 re.compile(r'In \[(\d+)\]:\s?(.*)\s*'), 'env')
1074 re.compile(r'In \[(\d+)\]:\s?(.*)\s*'), 'env')
1074 app.add_config_value('ipython_rgxout',
1075 app.add_config_value('ipython_rgxout',
1075 re.compile(r'Out\[(\d+)\]:\s?(.*)\s*'), 'env')
1076 re.compile(r'Out\[(\d+)\]:\s?(.*)\s*'), 'env')
1076 app.add_config_value('ipython_promptin', 'In [%d]:', 'env')
1077 app.add_config_value('ipython_promptin', 'In [%d]:', 'env')
1077 app.add_config_value('ipython_promptout', 'Out[%d]:', 'env')
1078 app.add_config_value('ipython_promptout', 'Out[%d]:', 'env')
1078
1079
1079 # We could just let matplotlib pick whatever is specified as the default
1080 # We could just let matplotlib pick whatever is specified as the default
1080 # backend in the matplotlibrc file, but this would cause issues if the
1081 # backend in the matplotlibrc file, but this would cause issues if the
1081 # backend didn't work in headless environments. For this reason, 'agg'
1082 # backend didn't work in headless environments. For this reason, 'agg'
1082 # is a good default backend choice.
1083 # is a good default backend choice.
1083 app.add_config_value('ipython_mplbackend', 'agg', 'env')
1084 app.add_config_value('ipython_mplbackend', 'agg', 'env')
1084
1085
1085 # If the user sets this config value to `None`, then EmbeddedSphinxShell's
1086 # If the user sets this config value to `None`, then EmbeddedSphinxShell's
1086 # __init__ method will treat it as [].
1087 # __init__ method will treat it as [].
1087 execlines = ['import numpy as np']
1088 execlines = ['import numpy as np']
1088 if use_matplotlib:
1089 if use_matplotlib:
1089 execlines.append('import matplotlib.pyplot as plt')
1090 execlines.append('import matplotlib.pyplot as plt')
1090 app.add_config_value('ipython_execlines', execlines, 'env')
1091 app.add_config_value('ipython_execlines', execlines, 'env')
1091
1092
1092 app.add_config_value('ipython_holdcount', True, 'env')
1093 app.add_config_value('ipython_holdcount', True, 'env')
1093
1094
1094 metadata = {'parallel_read_safe': True, 'parallel_write_safe': True}
1095 metadata = {'parallel_read_safe': True, 'parallel_write_safe': True}
1095 return metadata
1096 return metadata
1096
1097
1097 # Simple smoke test, needs to be converted to a proper automatic test.
1098 # Simple smoke test, needs to be converted to a proper automatic test.
1098 def test():
1099 def test():
1099
1100
1100 examples = [
1101 examples = [
1101 r"""
1102 r"""
1102 In [9]: pwd
1103 In [9]: pwd
1103 Out[9]: '/home/jdhunter/py4science/book'
1104 Out[9]: '/home/jdhunter/py4science/book'
1104
1105
1105 In [10]: cd bookdata/
1106 In [10]: cd bookdata/
1106 /home/jdhunter/py4science/book/bookdata
1107 /home/jdhunter/py4science/book/bookdata
1107
1108
1108 In [2]: from pylab import *
1109 In [2]: from pylab import *
1109
1110
1110 In [2]: ion()
1111 In [2]: ion()
1111
1112
1112 In [3]: im = imread('stinkbug.png')
1113 In [3]: im = imread('stinkbug.png')
1113
1114
1114 @savefig mystinkbug.png width=4in
1115 @savefig mystinkbug.png width=4in
1115 In [4]: imshow(im)
1116 In [4]: imshow(im)
1116 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
1117 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
1117
1118
1118 """,
1119 """,
1119 r"""
1120 r"""
1120
1121
1121 In [1]: x = 'hello world'
1122 In [1]: x = 'hello world'
1122
1123
1123 # string methods can be
1124 # string methods can be
1124 # used to alter the string
1125 # used to alter the string
1125 @doctest
1126 @doctest
1126 In [2]: x.upper()
1127 In [2]: x.upper()
1127 Out[2]: 'HELLO WORLD'
1128 Out[2]: 'HELLO WORLD'
1128
1129
1129 @verbatim
1130 @verbatim
1130 In [3]: x.st<TAB>
1131 In [3]: x.st<TAB>
1131 x.startswith x.strip
1132 x.startswith x.strip
1132 """,
1133 """,
1133 r"""
1134 r"""
1134
1135
1135 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
1136 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
1136 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
1137 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
1137
1138
1138 In [131]: print url.split('&')
1139 In [131]: print url.split('&')
1139 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
1140 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
1140
1141
1141 In [60]: import urllib
1142 In [60]: import urllib
1142
1143
1143 """,
1144 """,
1144 r"""\
1145 r"""\
1145
1146
1146 In [133]: import numpy.random
1147 In [133]: import numpy.random
1147
1148
1148 @suppress
1149 @suppress
1149 In [134]: numpy.random.seed(2358)
1150 In [134]: numpy.random.seed(2358)
1150
1151
1151 @doctest
1152 @doctest
1152 In [135]: numpy.random.rand(10,2)
1153 In [135]: numpy.random.rand(10,2)
1153 Out[135]:
1154 Out[135]:
1154 array([[ 0.64524308, 0.59943846],
1155 array([[ 0.64524308, 0.59943846],
1155 [ 0.47102322, 0.8715456 ],
1156 [ 0.47102322, 0.8715456 ],
1156 [ 0.29370834, 0.74776844],
1157 [ 0.29370834, 0.74776844],
1157 [ 0.99539577, 0.1313423 ],
1158 [ 0.99539577, 0.1313423 ],
1158 [ 0.16250302, 0.21103583],
1159 [ 0.16250302, 0.21103583],
1159 [ 0.81626524, 0.1312433 ],
1160 [ 0.81626524, 0.1312433 ],
1160 [ 0.67338089, 0.72302393],
1161 [ 0.67338089, 0.72302393],
1161 [ 0.7566368 , 0.07033696],
1162 [ 0.7566368 , 0.07033696],
1162 [ 0.22591016, 0.77731835],
1163 [ 0.22591016, 0.77731835],
1163 [ 0.0072729 , 0.34273127]])
1164 [ 0.0072729 , 0.34273127]])
1164
1165
1165 """,
1166 """,
1166
1167
1167 r"""
1168 r"""
1168 In [106]: print x
1169 In [106]: print x
1169 jdh
1170 jdh
1170
1171
1171 In [109]: for i in range(10):
1172 In [109]: for i in range(10):
1172 .....: print i
1173 .....: print i
1173 .....:
1174 .....:
1174 .....:
1175 .....:
1175 0
1176 0
1176 1
1177 1
1177 2
1178 2
1178 3
1179 3
1179 4
1180 4
1180 5
1181 5
1181 6
1182 6
1182 7
1183 7
1183 8
1184 8
1184 9
1185 9
1185 """,
1186 """,
1186
1187
1187 r"""
1188 r"""
1188
1189
1189 In [144]: from pylab import *
1190 In [144]: from pylab import *
1190
1191
1191 In [145]: ion()
1192 In [145]: ion()
1192
1193
1193 # use a semicolon to suppress the output
1194 # use a semicolon to suppress the output
1194 @savefig test_hist.png width=4in
1195 @savefig test_hist.png width=4in
1195 In [151]: hist(np.random.randn(10000), 100);
1196 In [151]: hist(np.random.randn(10000), 100);
1196
1197
1197
1198
1198 @savefig test_plot.png width=4in
1199 @savefig test_plot.png width=4in
1199 In [151]: plot(np.random.randn(10000), 'o');
1200 In [151]: plot(np.random.randn(10000), 'o');
1200 """,
1201 """,
1201
1202
1202 r"""
1203 r"""
1203 # use a semicolon to suppress the output
1204 # use a semicolon to suppress the output
1204 In [151]: plt.clf()
1205 In [151]: plt.clf()
1205
1206
1206 @savefig plot_simple.png width=4in
1207 @savefig plot_simple.png width=4in
1207 In [151]: plot([1,2,3])
1208 In [151]: plot([1,2,3])
1208
1209
1209 @savefig hist_simple.png width=4in
1210 @savefig hist_simple.png width=4in
1210 In [151]: hist(np.random.randn(10000), 100);
1211 In [151]: hist(np.random.randn(10000), 100);
1211
1212
1212 """,
1213 """,
1213 r"""
1214 r"""
1214 # update the current fig
1215 # update the current fig
1215 In [151]: ylabel('number')
1216 In [151]: ylabel('number')
1216
1217
1217 In [152]: title('normal distribution')
1218 In [152]: title('normal distribution')
1218
1219
1219
1220
1220 @savefig hist_with_text.png
1221 @savefig hist_with_text.png
1221 In [153]: grid(True)
1222 In [153]: grid(True)
1222
1223
1223 @doctest float
1224 @doctest float
1224 In [154]: 0.1 + 0.2
1225 In [154]: 0.1 + 0.2
1225 Out[154]: 0.3
1226 Out[154]: 0.3
1226
1227
1227 @doctest float
1228 @doctest float
1228 In [155]: np.arange(16).reshape(4,4)
1229 In [155]: np.arange(16).reshape(4,4)
1229 Out[155]:
1230 Out[155]:
1230 array([[ 0, 1, 2, 3],
1231 array([[ 0, 1, 2, 3],
1231 [ 4, 5, 6, 7],
1232 [ 4, 5, 6, 7],
1232 [ 8, 9, 10, 11],
1233 [ 8, 9, 10, 11],
1233 [12, 13, 14, 15]])
1234 [12, 13, 14, 15]])
1234
1235
1235 In [1]: x = np.arange(16, dtype=float).reshape(4,4)
1236 In [1]: x = np.arange(16, dtype=float).reshape(4,4)
1236
1237
1237 In [2]: x[0,0] = np.inf
1238 In [2]: x[0,0] = np.inf
1238
1239
1239 In [3]: x[0,1] = np.nan
1240 In [3]: x[0,1] = np.nan
1240
1241
1241 @doctest float
1242 @doctest float
1242 In [4]: x
1243 In [4]: x
1243 Out[4]:
1244 Out[4]:
1244 array([[ inf, nan, 2., 3.],
1245 array([[ inf, nan, 2., 3.],
1245 [ 4., 5., 6., 7.],
1246 [ 4., 5., 6., 7.],
1246 [ 8., 9., 10., 11.],
1247 [ 8., 9., 10., 11.],
1247 [ 12., 13., 14., 15.]])
1248 [ 12., 13., 14., 15.]])
1248
1249
1249
1250
1250 """,
1251 """,
1251 ]
1252 ]
1252 # skip local-file depending first example:
1253 # skip local-file depending first example:
1253 examples = examples[1:]
1254 examples = examples[1:]
1254
1255
1255 #ipython_directive.DEBUG = True # dbg
1256 #ipython_directive.DEBUG = True # dbg
1256 #options = dict(suppress=True) # dbg
1257 #options = dict(suppress=True) # dbg
1257 options = {}
1258 options = {}
1258 for example in examples:
1259 for example in examples:
1259 content = example.split('\n')
1260 content = example.split('\n')
1260 IPythonDirective('debug', arguments=None, options=options,
1261 IPythonDirective('debug', arguments=None, options=options,
1261 content=content, lineno=0,
1262 content=content, lineno=0,
1262 content_offset=None, block_text=None,
1263 content_offset=None, block_text=None,
1263 state=None, state_machine=None,
1264 state=None, state_machine=None,
1264 )
1265 )
1265
1266
1266 # Run test suite as a script
1267 # Run test suite as a script
1267 if __name__=='__main__':
1268 if __name__=='__main__':
1268 if not os.path.isdir('_static'):
1269 if not os.path.isdir('_static'):
1269 os.mkdir('_static')
1270 os.mkdir('_static')
1270 test()
1271 test()
1271 print('All OK? Check figures in _static/')
1272 print('All OK? Check figures in _static/')
@@ -1,774 +1,773 b''
1 """IPython terminal interface using prompt_toolkit"""
1 """IPython terminal interface using prompt_toolkit"""
2
2
3 import asyncio
3 import asyncio
4 import os
4 import os
5 import sys
5 import sys
6 from warnings import warn
6 from warnings import warn
7
7
8 from IPython.core.async_helpers import get_asyncio_loop
8 from IPython.core.async_helpers import get_asyncio_loop
9 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
9 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
10 from IPython.utils.py3compat import input
10 from IPython.utils.py3compat import input
11 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
12 from IPython.utils.process import abbrev_cwd
12 from IPython.utils.process import abbrev_cwd
13 from traitlets import (
13 from traitlets import (
14 Bool,
14 Bool,
15 Unicode,
15 Unicode,
16 Dict,
16 Dict,
17 Integer,
17 Integer,
18 observe,
18 observe,
19 Instance,
19 Instance,
20 Type,
20 Type,
21 default,
21 default,
22 Enum,
22 Enum,
23 Union,
23 Union,
24 Any,
24 Any,
25 validate,
25 validate,
26 Float,
26 Float,
27 )
27 )
28
28
29 from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
29 from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
30 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
30 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
31 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
31 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
32 from prompt_toolkit.formatted_text import PygmentsTokens
32 from prompt_toolkit.formatted_text import PygmentsTokens
33 from prompt_toolkit.history import History
33 from prompt_toolkit.history import History
34 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
34 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
35 from prompt_toolkit.output import ColorDepth
35 from prompt_toolkit.output import ColorDepth
36 from prompt_toolkit.patch_stdout import patch_stdout
36 from prompt_toolkit.patch_stdout import patch_stdout
37 from prompt_toolkit.shortcuts import PromptSession, CompleteStyle, print_formatted_text
37 from prompt_toolkit.shortcuts import PromptSession, CompleteStyle, print_formatted_text
38 from prompt_toolkit.styles import DynamicStyle, merge_styles
38 from prompt_toolkit.styles import DynamicStyle, merge_styles
39 from prompt_toolkit.styles.pygments import style_from_pygments_cls, style_from_pygments_dict
39 from prompt_toolkit.styles.pygments import style_from_pygments_cls, style_from_pygments_dict
40 from prompt_toolkit import __version__ as ptk_version
40 from prompt_toolkit import __version__ as ptk_version
41
41
42 from pygments.styles import get_style_by_name
42 from pygments.styles import get_style_by_name
43 from pygments.style import Style
43 from pygments.style import Style
44 from pygments.token import Token
44 from pygments.token import Token
45
45
46 from .debugger import TerminalPdb, Pdb
46 from .debugger import TerminalPdb, Pdb
47 from .magics import TerminalMagics
47 from .magics import TerminalMagics
48 from .pt_inputhooks import get_inputhook_name_and_func
48 from .pt_inputhooks import get_inputhook_name_and_func
49 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
49 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
50 from .ptutils import IPythonPTCompleter, IPythonPTLexer
50 from .ptutils import IPythonPTCompleter, IPythonPTLexer
51 from .shortcuts import create_ipython_shortcuts
51 from .shortcuts import create_ipython_shortcuts
52
52
53 PTK3 = ptk_version.startswith('3.')
53 PTK3 = ptk_version.startswith('3.')
54
54
55
55
56 class _NoStyle(Style): pass
56 class _NoStyle(Style): pass
57
57
58
58
59
59
60 _style_overrides_light_bg = {
60 _style_overrides_light_bg = {
61 Token.Prompt: '#ansibrightblue',
61 Token.Prompt: '#ansibrightblue',
62 Token.PromptNum: '#ansiblue bold',
62 Token.PromptNum: '#ansiblue bold',
63 Token.OutPrompt: '#ansibrightred',
63 Token.OutPrompt: '#ansibrightred',
64 Token.OutPromptNum: '#ansired bold',
64 Token.OutPromptNum: '#ansired bold',
65 }
65 }
66
66
67 _style_overrides_linux = {
67 _style_overrides_linux = {
68 Token.Prompt: '#ansibrightgreen',
68 Token.Prompt: '#ansibrightgreen',
69 Token.PromptNum: '#ansigreen bold',
69 Token.PromptNum: '#ansigreen bold',
70 Token.OutPrompt: '#ansibrightred',
70 Token.OutPrompt: '#ansibrightred',
71 Token.OutPromptNum: '#ansired bold',
71 Token.OutPromptNum: '#ansired bold',
72 }
72 }
73
73
74 def get_default_editor():
74 def get_default_editor():
75 try:
75 try:
76 return os.environ['EDITOR']
76 return os.environ['EDITOR']
77 except KeyError:
77 except KeyError:
78 pass
78 pass
79 except UnicodeError:
79 except UnicodeError:
80 warn("$EDITOR environment variable is not pure ASCII. Using platform "
80 warn("$EDITOR environment variable is not pure ASCII. Using platform "
81 "default editor.")
81 "default editor.")
82
82
83 if os.name == 'posix':
83 if os.name == 'posix':
84 return 'vi' # the only one guaranteed to be there!
84 return 'vi' # the only one guaranteed to be there!
85 else:
85 else:
86 return 'notepad' # same in Windows!
86 return 'notepad' # same in Windows!
87
87
88 # conservatively check for tty
88 # conservatively check for tty
89 # overridden streams can result in things like:
89 # overridden streams can result in things like:
90 # - sys.stdin = None
90 # - sys.stdin = None
91 # - no isatty method
91 # - no isatty method
92 for _name in ('stdin', 'stdout', 'stderr'):
92 for _name in ('stdin', 'stdout', 'stderr'):
93 _stream = getattr(sys, _name)
93 _stream = getattr(sys, _name)
94 try:
94 try:
95 if not _stream or not hasattr(_stream, "isatty") or not _stream.isatty():
95 if not _stream or not hasattr(_stream, "isatty") or not _stream.isatty():
96 _is_tty = False
96 _is_tty = False
97 break
97 break
98 except ValueError:
98 except ValueError:
99 # stream is closed
99 # stream is closed
100 _is_tty = False
100 _is_tty = False
101 break
101 break
102 else:
102 else:
103 _is_tty = True
103 _is_tty = True
104
104
105
105
106 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
106 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
107
107
108 def black_reformat_handler(text_before_cursor):
108 def black_reformat_handler(text_before_cursor):
109 """
109 """
110 We do not need to protect against error,
110 We do not need to protect against error,
111 this is taken care at a higher level where any reformat error is ignored.
111 this is taken care at a higher level where any reformat error is ignored.
112 Indeed we may call reformatting on incomplete code.
112 Indeed we may call reformatting on incomplete code.
113 """
113 """
114 import black
114 import black
115
115
116 formatted_text = black.format_str(text_before_cursor, mode=black.FileMode())
116 formatted_text = black.format_str(text_before_cursor, mode=black.FileMode())
117 if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
117 if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
118 formatted_text = formatted_text[:-1]
118 formatted_text = formatted_text[:-1]
119 return formatted_text
119 return formatted_text
120
120
121
121
122 def yapf_reformat_handler(text_before_cursor):
122 def yapf_reformat_handler(text_before_cursor):
123 from yapf.yapflib import file_resources
123 from yapf.yapflib import file_resources
124 from yapf.yapflib import yapf_api
124 from yapf.yapflib import yapf_api
125
125
126 style_config = file_resources.GetDefaultStyleForDir(os.getcwd())
126 style_config = file_resources.GetDefaultStyleForDir(os.getcwd())
127 formatted_text, was_formatted = yapf_api.FormatCode(
127 formatted_text, was_formatted = yapf_api.FormatCode(
128 text_before_cursor, style_config=style_config
128 text_before_cursor, style_config=style_config
129 )
129 )
130 if was_formatted:
130 if was_formatted:
131 if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
131 if not text_before_cursor.endswith("\n") and formatted_text.endswith("\n"):
132 formatted_text = formatted_text[:-1]
132 formatted_text = formatted_text[:-1]
133 return formatted_text
133 return formatted_text
134 else:
134 else:
135 return text_before_cursor
135 return text_before_cursor
136
136
137
137
138 class PtkHistoryAdapter(History):
138 class PtkHistoryAdapter(History):
139 """
139 """
140 Prompt toolkit has it's own way of handling history, Where it assumes it can
140 Prompt toolkit has it's own way of handling history, Where it assumes it can
141 Push/pull from history.
141 Push/pull from history.
142
142
143 """
143 """
144
144
145 def __init__(self, shell):
145 def __init__(self, shell):
146 super().__init__()
146 super().__init__()
147 self.shell = shell
147 self.shell = shell
148 self._refresh()
148 self._refresh()
149
149
150 def append_string(self, string):
150 def append_string(self, string):
151 # we rely on sql for that.
151 # we rely on sql for that.
152 self._loaded = False
152 self._loaded = False
153 self._refresh()
153 self._refresh()
154
154
155 def _refresh(self):
155 def _refresh(self):
156 if not self._loaded:
156 if not self._loaded:
157 self._loaded_strings = list(self.load_history_strings())
157 self._loaded_strings = list(self.load_history_strings())
158
158
159 def load_history_strings(self):
159 def load_history_strings(self):
160 last_cell = ""
160 last_cell = ""
161 res = []
161 res = []
162 for __, ___, cell in self.shell.history_manager.get_tail(
162 for __, ___, cell in self.shell.history_manager.get_tail(
163 self.shell.history_load_length, include_latest=True
163 self.shell.history_load_length, include_latest=True
164 ):
164 ):
165 # Ignore blank lines and consecutive duplicates
165 # Ignore blank lines and consecutive duplicates
166 cell = cell.rstrip()
166 cell = cell.rstrip()
167 if cell and (cell != last_cell):
167 if cell and (cell != last_cell):
168 res.append(cell)
168 res.append(cell)
169 last_cell = cell
169 last_cell = cell
170 yield from res[::-1]
170 yield from res[::-1]
171
171
172 def store_string(self, string: str) -> None:
172 def store_string(self, string: str) -> None:
173 pass
173 pass
174
174
175 class TerminalInteractiveShell(InteractiveShell):
175 class TerminalInteractiveShell(InteractiveShell):
176 mime_renderers = Dict().tag(config=True)
176 mime_renderers = Dict().tag(config=True)
177
177
178 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
178 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
179 'to reserve for the tab completion menu, '
179 'to reserve for the tab completion menu, '
180 'search history, ...etc, the height of '
180 'search history, ...etc, the height of '
181 'these menus will at most this value. '
181 'these menus will at most this value. '
182 'Increase it is you prefer long and skinny '
182 'Increase it is you prefer long and skinny '
183 'menus, decrease for short and wide.'
183 'menus, decrease for short and wide.'
184 ).tag(config=True)
184 ).tag(config=True)
185
185
186 pt_app = None
186 pt_app = None
187 debugger_history = None
187 debugger_history = None
188
188
189 debugger_history_file = Unicode(
189 debugger_history_file = Unicode(
190 "~/.pdbhistory", help="File in which to store and read history"
190 "~/.pdbhistory", help="File in which to store and read history"
191 ).tag(config=True)
191 ).tag(config=True)
192
192
193 simple_prompt = Bool(_use_simple_prompt,
193 simple_prompt = Bool(_use_simple_prompt,
194 help="""Use `raw_input` for the REPL, without completion and prompt colors.
194 help="""Use `raw_input` for the REPL, without completion and prompt colors.
195
195
196 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
196 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
197 IPython own testing machinery, and emacs inferior-shell integration through elpy.
197 IPython own testing machinery, and emacs inferior-shell integration through elpy.
198
198
199 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
199 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
200 environment variable is set, or the current terminal is not a tty."""
200 environment variable is set, or the current terminal is not a tty."""
201 ).tag(config=True)
201 ).tag(config=True)
202
202
203 @property
203 @property
204 def debugger_cls(self):
204 def debugger_cls(self):
205 return Pdb if self.simple_prompt else TerminalPdb
205 return Pdb if self.simple_prompt else TerminalPdb
206
206
207 confirm_exit = Bool(True,
207 confirm_exit = Bool(True,
208 help="""
208 help="""
209 Set to confirm when you try to exit IPython with an EOF (Control-D
209 Set to confirm when you try to exit IPython with an EOF (Control-D
210 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
210 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
211 you can force a direct exit without any confirmation.""",
211 you can force a direct exit without any confirmation.""",
212 ).tag(config=True)
212 ).tag(config=True)
213
213
214 editing_mode = Unicode('emacs',
214 editing_mode = Unicode('emacs',
215 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
215 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
216 ).tag(config=True)
216 ).tag(config=True)
217
217
218 emacs_bindings_in_vi_insert_mode = Bool(
218 emacs_bindings_in_vi_insert_mode = Bool(
219 True,
219 True,
220 help="Add shortcuts from 'emacs' insert mode to 'vi' insert mode.",
220 help="Add shortcuts from 'emacs' insert mode to 'vi' insert mode.",
221 ).tag(config=True)
221 ).tag(config=True)
222
222
223 modal_cursor = Bool(
223 modal_cursor = Bool(
224 True,
224 True,
225 help="""
225 help="""
226 Cursor shape changes depending on vi mode: beam in vi insert mode,
226 Cursor shape changes depending on vi mode: beam in vi insert mode,
227 block in nav mode, underscore in replace mode.""",
227 block in nav mode, underscore in replace mode.""",
228 ).tag(config=True)
228 ).tag(config=True)
229
229
230 ttimeoutlen = Float(
230 ttimeoutlen = Float(
231 0.01,
231 0.01,
232 help="""The time in milliseconds that is waited for a key code
232 help="""The time in milliseconds that is waited for a key code
233 to complete.""",
233 to complete.""",
234 ).tag(config=True)
234 ).tag(config=True)
235
235
236 timeoutlen = Float(
236 timeoutlen = Float(
237 0.5,
237 0.5,
238 help="""The time in milliseconds that is waited for a mapped key
238 help="""The time in milliseconds that is waited for a mapped key
239 sequence to complete.""",
239 sequence to complete.""",
240 ).tag(config=True)
240 ).tag(config=True)
241
241
242 autoformatter = Unicode(
242 autoformatter = Unicode(
243 None,
243 None,
244 help="Autoformatter to reformat Terminal code. Can be `'black'`, `'yapf'` or `None`",
244 help="Autoformatter to reformat Terminal code. Can be `'black'`, `'yapf'` or `None`",
245 allow_none=True
245 allow_none=True
246 ).tag(config=True)
246 ).tag(config=True)
247
247
248 auto_match = Bool(
248 auto_match = Bool(
249 False,
249 False,
250 help="""
250 help="""
251 Automatically add/delete closing bracket or quote when opening bracket or quote is entered/deleted.
251 Automatically add/delete closing bracket or quote when opening bracket or quote is entered/deleted.
252 Brackets: (), [], {}
252 Brackets: (), [], {}
253 Quotes: '', \"\"
253 Quotes: '', \"\"
254 """,
254 """,
255 ).tag(config=True)
255 ).tag(config=True)
256
256
257 mouse_support = Bool(False,
257 mouse_support = Bool(False,
258 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
258 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
259 ).tag(config=True)
259 ).tag(config=True)
260
260
261 # We don't load the list of styles for the help string, because loading
261 # We don't load the list of styles for the help string, because loading
262 # Pygments plugins takes time and can cause unexpected errors.
262 # Pygments plugins takes time and can cause unexpected errors.
263 highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
263 highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
264 help="""The name or class of a Pygments style to use for syntax
264 help="""The name or class of a Pygments style to use for syntax
265 highlighting. To see available styles, run `pygmentize -L styles`."""
265 highlighting. To see available styles, run `pygmentize -L styles`."""
266 ).tag(config=True)
266 ).tag(config=True)
267
267
268 @validate('editing_mode')
268 @validate('editing_mode')
269 def _validate_editing_mode(self, proposal):
269 def _validate_editing_mode(self, proposal):
270 if proposal['value'].lower() == 'vim':
270 if proposal['value'].lower() == 'vim':
271 proposal['value']= 'vi'
271 proposal['value']= 'vi'
272 elif proposal['value'].lower() == 'default':
272 elif proposal['value'].lower() == 'default':
273 proposal['value']= 'emacs'
273 proposal['value']= 'emacs'
274
274
275 if hasattr(EditingMode, proposal['value'].upper()):
275 if hasattr(EditingMode, proposal['value'].upper()):
276 return proposal['value'].lower()
276 return proposal['value'].lower()
277
277
278 return self.editing_mode
278 return self.editing_mode
279
279
280
280
281 @observe('editing_mode')
281 @observe('editing_mode')
282 def _editing_mode(self, change):
282 def _editing_mode(self, change):
283 if self.pt_app:
283 if self.pt_app:
284 self.pt_app.editing_mode = getattr(EditingMode, change.new.upper())
284 self.pt_app.editing_mode = getattr(EditingMode, change.new.upper())
285
285
286 def _set_formatter(self, formatter):
286 def _set_formatter(self, formatter):
287 if formatter is None:
287 if formatter is None:
288 self.reformat_handler = lambda x:x
288 self.reformat_handler = lambda x:x
289 elif formatter == 'black':
289 elif formatter == 'black':
290 self.reformat_handler = black_reformat_handler
290 self.reformat_handler = black_reformat_handler
291 elif formatter == "yapf":
291 elif formatter == "yapf":
292 self.reformat_handler = yapf_reformat_handler
292 self.reformat_handler = yapf_reformat_handler
293 else:
293 else:
294 raise ValueError
294 raise ValueError
295
295
296 @observe("autoformatter")
296 @observe("autoformatter")
297 def _autoformatter_changed(self, change):
297 def _autoformatter_changed(self, change):
298 formatter = change.new
298 formatter = change.new
299 self._set_formatter(formatter)
299 self._set_formatter(formatter)
300
300
301 @observe('highlighting_style')
301 @observe('highlighting_style')
302 @observe('colors')
302 @observe('colors')
303 def _highlighting_style_changed(self, change):
303 def _highlighting_style_changed(self, change):
304 self.refresh_style()
304 self.refresh_style()
305
305
306 def refresh_style(self):
306 def refresh_style(self):
307 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
307 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
308
308
309
309
310 highlighting_style_overrides = Dict(
310 highlighting_style_overrides = Dict(
311 help="Override highlighting format for specific tokens"
311 help="Override highlighting format for specific tokens"
312 ).tag(config=True)
312 ).tag(config=True)
313
313
314 true_color = Bool(False,
314 true_color = Bool(False,
315 help="""Use 24bit colors instead of 256 colors in prompt highlighting.
315 help="""Use 24bit colors instead of 256 colors in prompt highlighting.
316 If your terminal supports true color, the following command should
316 If your terminal supports true color, the following command should
317 print ``TRUECOLOR`` in orange::
317 print ``TRUECOLOR`` in orange::
318
318
319 printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"
319 printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"
320 """,
320 """,
321 ).tag(config=True)
321 ).tag(config=True)
322
322
323 editor = Unicode(get_default_editor(),
323 editor = Unicode(get_default_editor(),
324 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
324 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
325 ).tag(config=True)
325 ).tag(config=True)
326
326
327 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
327 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
328
328
329 prompts = Instance(Prompts)
329 prompts = Instance(Prompts)
330
330
331 @default('prompts')
331 @default('prompts')
332 def _prompts_default(self):
332 def _prompts_default(self):
333 return self.prompts_class(self)
333 return self.prompts_class(self)
334
334
335 # @observe('prompts')
335 # @observe('prompts')
336 # def _(self, change):
336 # def _(self, change):
337 # self._update_layout()
337 # self._update_layout()
338
338
339 @default('displayhook_class')
339 @default('displayhook_class')
340 def _displayhook_class_default(self):
340 def _displayhook_class_default(self):
341 return RichPromptDisplayHook
341 return RichPromptDisplayHook
342
342
343 term_title = Bool(True,
343 term_title = Bool(True,
344 help="Automatically set the terminal title"
344 help="Automatically set the terminal title"
345 ).tag(config=True)
345 ).tag(config=True)
346
346
347 term_title_format = Unicode("IPython: {cwd}",
347 term_title_format = Unicode("IPython: {cwd}",
348 help="Customize the terminal title format. This is a python format string. " +
348 help="Customize the terminal title format. This is a python format string. " +
349 "Available substitutions are: {cwd}."
349 "Available substitutions are: {cwd}."
350 ).tag(config=True)
350 ).tag(config=True)
351
351
352 display_completions = Enum(('column', 'multicolumn','readlinelike'),
352 display_completions = Enum(('column', 'multicolumn','readlinelike'),
353 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
353 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
354 "'readlinelike'. These options are for `prompt_toolkit`, see "
354 "'readlinelike'. These options are for `prompt_toolkit`, see "
355 "`prompt_toolkit` documentation for more information."
355 "`prompt_toolkit` documentation for more information."
356 ),
356 ),
357 default_value='multicolumn').tag(config=True)
357 default_value='multicolumn').tag(config=True)
358
358
359 highlight_matching_brackets = Bool(True,
359 highlight_matching_brackets = Bool(True,
360 help="Highlight matching brackets.",
360 help="Highlight matching brackets.",
361 ).tag(config=True)
361 ).tag(config=True)
362
362
363 extra_open_editor_shortcuts = Bool(False,
363 extra_open_editor_shortcuts = Bool(False,
364 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
364 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
365 "This is in addition to the F2 binding, which is always enabled."
365 "This is in addition to the F2 binding, which is always enabled."
366 ).tag(config=True)
366 ).tag(config=True)
367
367
368 handle_return = Any(None,
368 handle_return = Any(None,
369 help="Provide an alternative handler to be called when the user presses "
369 help="Provide an alternative handler to be called when the user presses "
370 "Return. This is an advanced option intended for debugging, which "
370 "Return. This is an advanced option intended for debugging, which "
371 "may be changed or removed in later releases."
371 "may be changed or removed in later releases."
372 ).tag(config=True)
372 ).tag(config=True)
373
373
374 enable_history_search = Bool(True,
374 enable_history_search = Bool(True,
375 help="Allows to enable/disable the prompt toolkit history search"
375 help="Allows to enable/disable the prompt toolkit history search"
376 ).tag(config=True)
376 ).tag(config=True)
377
377
378 autosuggestions_provider = Unicode(
378 autosuggestions_provider = Unicode(
379 "AutoSuggestFromHistory",
379 "AutoSuggestFromHistory",
380 help="Specifies from which source automatic suggestions are provided. "
380 help="Specifies from which source automatic suggestions are provided. "
381 "Can be set to `'AutoSuggestFromHistory`' or `None` to disable"
381 "Can be set to `'AutoSuggestFromHistory`' or `None` to disable"
382 "automatic suggestions. Default is `'AutoSuggestFromHistory`'.",
382 "automatic suggestions. Default is `'AutoSuggestFromHistory`'.",
383 allow_none=True,
383 allow_none=True,
384 ).tag(config=True)
384 ).tag(config=True)
385
385
386 def _set_autosuggestions(self, provider):
386 def _set_autosuggestions(self, provider):
387 if provider is None:
387 if provider is None:
388 self.auto_suggest = None
388 self.auto_suggest = None
389 elif provider == "AutoSuggestFromHistory":
389 elif provider == "AutoSuggestFromHistory":
390 self.auto_suggest = AutoSuggestFromHistory()
390 self.auto_suggest = AutoSuggestFromHistory()
391 else:
391 else:
392 raise ValueError("No valid provider.")
392 raise ValueError("No valid provider.")
393 if self.pt_app:
393 if self.pt_app:
394 self.pt_app.auto_suggest = self.auto_suggest
394 self.pt_app.auto_suggest = self.auto_suggest
395
395
396 @observe("autosuggestions_provider")
396 @observe("autosuggestions_provider")
397 def _autosuggestions_provider_changed(self, change):
397 def _autosuggestions_provider_changed(self, change):
398 provider = change.new
398 provider = change.new
399 self._set_autosuggestions(provider)
399 self._set_autosuggestions(provider)
400
400
401 prompt_includes_vi_mode = Bool(True,
401 prompt_includes_vi_mode = Bool(True,
402 help="Display the current vi mode (when using vi editing mode)."
402 help="Display the current vi mode (when using vi editing mode)."
403 ).tag(config=True)
403 ).tag(config=True)
404
404
405 @observe('term_title')
405 @observe('term_title')
406 def init_term_title(self, change=None):
406 def init_term_title(self, change=None):
407 # Enable or disable the terminal title.
407 # Enable or disable the terminal title.
408 if self.term_title:
408 if self.term_title and _is_tty:
409 toggle_set_term_title(True)
409 toggle_set_term_title(True)
410 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
410 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
411 else:
411 else:
412 toggle_set_term_title(False)
412 toggle_set_term_title(False)
413
413
414 def restore_term_title(self):
414 def restore_term_title(self):
415 if self.term_title:
415 if self.term_title and _is_tty:
416 restore_term_title()
416 restore_term_title()
417
417
418 def init_display_formatter(self):
418 def init_display_formatter(self):
419 super(TerminalInteractiveShell, self).init_display_formatter()
419 super(TerminalInteractiveShell, self).init_display_formatter()
420 # terminal only supports plain text
420 # terminal only supports plain text
421 self.display_formatter.active_types = ["text/plain"]
421 self.display_formatter.active_types = ["text/plain"]
422
422
423 def init_prompt_toolkit_cli(self):
423 def init_prompt_toolkit_cli(self):
424 if self.simple_prompt:
424 if self.simple_prompt:
425 # Fall back to plain non-interactive output for tests.
425 # Fall back to plain non-interactive output for tests.
426 # This is very limited.
426 # This is very limited.
427 def prompt():
427 def prompt():
428 prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
428 prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
429 lines = [input(prompt_text)]
429 lines = [input(prompt_text)]
430 prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
430 prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
431 while self.check_complete('\n'.join(lines))[0] == 'incomplete':
431 while self.check_complete('\n'.join(lines))[0] == 'incomplete':
432 lines.append( input(prompt_continuation) )
432 lines.append( input(prompt_continuation) )
433 return '\n'.join(lines)
433 return '\n'.join(lines)
434 self.prompt_for_code = prompt
434 self.prompt_for_code = prompt
435 return
435 return
436
436
437 # Set up keyboard shortcuts
437 # Set up keyboard shortcuts
438 key_bindings = create_ipython_shortcuts(self)
438 key_bindings = create_ipython_shortcuts(self)
439
439
440
440
441 # Pre-populate history from IPython's history database
441 # Pre-populate history from IPython's history database
442 history = PtkHistoryAdapter(self)
442 history = PtkHistoryAdapter(self)
443
443
444 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
444 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
445 self.style = DynamicStyle(lambda: self._style)
445 self.style = DynamicStyle(lambda: self._style)
446
446
447 editing_mode = getattr(EditingMode, self.editing_mode.upper())
447 editing_mode = getattr(EditingMode, self.editing_mode.upper())
448
448
449 self.pt_loop = asyncio.new_event_loop()
449 self.pt_loop = asyncio.new_event_loop()
450 self.pt_app = PromptSession(
450 self.pt_app = PromptSession(
451 auto_suggest=self.auto_suggest,
451 auto_suggest=self.auto_suggest,
452 editing_mode=editing_mode,
452 editing_mode=editing_mode,
453 key_bindings=key_bindings,
453 key_bindings=key_bindings,
454 history=history,
454 history=history,
455 completer=IPythonPTCompleter(shell=self),
455 completer=IPythonPTCompleter(shell=self),
456 enable_history_search=self.enable_history_search,
456 enable_history_search=self.enable_history_search,
457 style=self.style,
457 style=self.style,
458 include_default_pygments_style=False,
458 include_default_pygments_style=False,
459 mouse_support=self.mouse_support,
459 mouse_support=self.mouse_support,
460 enable_open_in_editor=self.extra_open_editor_shortcuts,
460 enable_open_in_editor=self.extra_open_editor_shortcuts,
461 color_depth=self.color_depth,
461 color_depth=self.color_depth,
462 tempfile_suffix=".py",
462 tempfile_suffix=".py",
463 **self._extra_prompt_options()
463 **self._extra_prompt_options()
464 )
464 )
465
465
466 def _make_style_from_name_or_cls(self, name_or_cls):
466 def _make_style_from_name_or_cls(self, name_or_cls):
467 """
467 """
468 Small wrapper that make an IPython compatible style from a style name
468 Small wrapper that make an IPython compatible style from a style name
469
469
470 We need that to add style for prompt ... etc.
470 We need that to add style for prompt ... etc.
471 """
471 """
472 style_overrides = {}
472 style_overrides = {}
473 if name_or_cls == 'legacy':
473 if name_or_cls == 'legacy':
474 legacy = self.colors.lower()
474 legacy = self.colors.lower()
475 if legacy == 'linux':
475 if legacy == 'linux':
476 style_cls = get_style_by_name('monokai')
476 style_cls = get_style_by_name('monokai')
477 style_overrides = _style_overrides_linux
477 style_overrides = _style_overrides_linux
478 elif legacy == 'lightbg':
478 elif legacy == 'lightbg':
479 style_overrides = _style_overrides_light_bg
479 style_overrides = _style_overrides_light_bg
480 style_cls = get_style_by_name('pastie')
480 style_cls = get_style_by_name('pastie')
481 elif legacy == 'neutral':
481 elif legacy == 'neutral':
482 # The default theme needs to be visible on both a dark background
482 # The default theme needs to be visible on both a dark background
483 # and a light background, because we can't tell what the terminal
483 # and a light background, because we can't tell what the terminal
484 # looks like. These tweaks to the default theme help with that.
484 # looks like. These tweaks to the default theme help with that.
485 style_cls = get_style_by_name('default')
485 style_cls = get_style_by_name('default')
486 style_overrides.update({
486 style_overrides.update({
487 Token.Number: '#ansigreen',
487 Token.Number: '#ansigreen',
488 Token.Operator: 'noinherit',
488 Token.Operator: 'noinherit',
489 Token.String: '#ansiyellow',
489 Token.String: '#ansiyellow',
490 Token.Name.Function: '#ansiblue',
490 Token.Name.Function: '#ansiblue',
491 Token.Name.Class: 'bold #ansiblue',
491 Token.Name.Class: 'bold #ansiblue',
492 Token.Name.Namespace: 'bold #ansiblue',
492 Token.Name.Namespace: 'bold #ansiblue',
493 Token.Name.Variable.Magic: '#ansiblue',
493 Token.Name.Variable.Magic: '#ansiblue',
494 Token.Prompt: '#ansigreen',
494 Token.Prompt: '#ansigreen',
495 Token.PromptNum: '#ansibrightgreen bold',
495 Token.PromptNum: '#ansibrightgreen bold',
496 Token.OutPrompt: '#ansired',
496 Token.OutPrompt: '#ansired',
497 Token.OutPromptNum: '#ansibrightred bold',
497 Token.OutPromptNum: '#ansibrightred bold',
498 })
498 })
499
499
500 # Hack: Due to limited color support on the Windows console
500 # Hack: Due to limited color support on the Windows console
501 # the prompt colors will be wrong without this
501 # the prompt colors will be wrong without this
502 if os.name == 'nt':
502 if os.name == 'nt':
503 style_overrides.update({
503 style_overrides.update({
504 Token.Prompt: '#ansidarkgreen',
504 Token.Prompt: '#ansidarkgreen',
505 Token.PromptNum: '#ansigreen bold',
505 Token.PromptNum: '#ansigreen bold',
506 Token.OutPrompt: '#ansidarkred',
506 Token.OutPrompt: '#ansidarkred',
507 Token.OutPromptNum: '#ansired bold',
507 Token.OutPromptNum: '#ansired bold',
508 })
508 })
509 elif legacy =='nocolor':
509 elif legacy =='nocolor':
510 style_cls=_NoStyle
510 style_cls=_NoStyle
511 style_overrides = {}
511 style_overrides = {}
512 else :
512 else :
513 raise ValueError('Got unknown colors: ', legacy)
513 raise ValueError('Got unknown colors: ', legacy)
514 else :
514 else :
515 if isinstance(name_or_cls, str):
515 if isinstance(name_or_cls, str):
516 style_cls = get_style_by_name(name_or_cls)
516 style_cls = get_style_by_name(name_or_cls)
517 else:
517 else:
518 style_cls = name_or_cls
518 style_cls = name_or_cls
519 style_overrides = {
519 style_overrides = {
520 Token.Prompt: '#ansigreen',
520 Token.Prompt: '#ansigreen',
521 Token.PromptNum: '#ansibrightgreen bold',
521 Token.PromptNum: '#ansibrightgreen bold',
522 Token.OutPrompt: '#ansired',
522 Token.OutPrompt: '#ansired',
523 Token.OutPromptNum: '#ansibrightred bold',
523 Token.OutPromptNum: '#ansibrightred bold',
524 }
524 }
525 style_overrides.update(self.highlighting_style_overrides)
525 style_overrides.update(self.highlighting_style_overrides)
526 style = merge_styles([
526 style = merge_styles([
527 style_from_pygments_cls(style_cls),
527 style_from_pygments_cls(style_cls),
528 style_from_pygments_dict(style_overrides),
528 style_from_pygments_dict(style_overrides),
529 ])
529 ])
530
530
531 return style
531 return style
532
532
533 @property
533 @property
534 def pt_complete_style(self):
534 def pt_complete_style(self):
535 return {
535 return {
536 'multicolumn': CompleteStyle.MULTI_COLUMN,
536 'multicolumn': CompleteStyle.MULTI_COLUMN,
537 'column': CompleteStyle.COLUMN,
537 'column': CompleteStyle.COLUMN,
538 'readlinelike': CompleteStyle.READLINE_LIKE,
538 'readlinelike': CompleteStyle.READLINE_LIKE,
539 }[self.display_completions]
539 }[self.display_completions]
540
540
541 @property
541 @property
542 def color_depth(self):
542 def color_depth(self):
543 return (ColorDepth.TRUE_COLOR if self.true_color else None)
543 return (ColorDepth.TRUE_COLOR if self.true_color else None)
544
544
545 def _extra_prompt_options(self):
545 def _extra_prompt_options(self):
546 """
546 """
547 Return the current layout option for the current Terminal InteractiveShell
547 Return the current layout option for the current Terminal InteractiveShell
548 """
548 """
549 def get_message():
549 def get_message():
550 return PygmentsTokens(self.prompts.in_prompt_tokens())
550 return PygmentsTokens(self.prompts.in_prompt_tokens())
551
551
552 if self.editing_mode == 'emacs':
552 if self.editing_mode == 'emacs':
553 # with emacs mode the prompt is (usually) static, so we call only
553 # with emacs mode the prompt is (usually) static, so we call only
554 # the function once. With VI mode it can toggle between [ins] and
554 # the function once. With VI mode it can toggle between [ins] and
555 # [nor] so we can't precompute.
555 # [nor] so we can't precompute.
556 # here I'm going to favor the default keybinding which almost
556 # here I'm going to favor the default keybinding which almost
557 # everybody uses to decrease CPU usage.
557 # everybody uses to decrease CPU usage.
558 # if we have issues with users with custom Prompts we can see how to
558 # if we have issues with users with custom Prompts we can see how to
559 # work around this.
559 # work around this.
560 get_message = get_message()
560 get_message = get_message()
561
561
562 options = {
562 options = {
563 'complete_in_thread': False,
563 'complete_in_thread': False,
564 'lexer':IPythonPTLexer(),
564 'lexer':IPythonPTLexer(),
565 'reserve_space_for_menu':self.space_for_menu,
565 'reserve_space_for_menu':self.space_for_menu,
566 'message': get_message,
566 'message': get_message,
567 'prompt_continuation': (
567 'prompt_continuation': (
568 lambda width, lineno, is_soft_wrap:
568 lambda width, lineno, is_soft_wrap:
569 PygmentsTokens(self.prompts.continuation_prompt_tokens(width))),
569 PygmentsTokens(self.prompts.continuation_prompt_tokens(width))),
570 'multiline': True,
570 'multiline': True,
571 'complete_style': self.pt_complete_style,
571 'complete_style': self.pt_complete_style,
572
572
573 # Highlight matching brackets, but only when this setting is
573 # Highlight matching brackets, but only when this setting is
574 # enabled, and only when the DEFAULT_BUFFER has the focus.
574 # enabled, and only when the DEFAULT_BUFFER has the focus.
575 'input_processors': [ConditionalProcessor(
575 'input_processors': [ConditionalProcessor(
576 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
576 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
577 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
577 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
578 Condition(lambda: self.highlight_matching_brackets))],
578 Condition(lambda: self.highlight_matching_brackets))],
579 }
579 }
580 if not PTK3:
580 if not PTK3:
581 options['inputhook'] = self.inputhook
581 options['inputhook'] = self.inputhook
582
582
583 return options
583 return options
584
584
585 def prompt_for_code(self):
585 def prompt_for_code(self):
586 if self.rl_next_input:
586 if self.rl_next_input:
587 default = self.rl_next_input
587 default = self.rl_next_input
588 self.rl_next_input = None
588 self.rl_next_input = None
589 else:
589 else:
590 default = ''
590 default = ''
591
591
592 # In order to make sure that asyncio code written in the
592 # In order to make sure that asyncio code written in the
593 # interactive shell doesn't interfere with the prompt, we run the
593 # interactive shell doesn't interfere with the prompt, we run the
594 # prompt in a different event loop.
594 # prompt in a different event loop.
595 # If we don't do this, people could spawn coroutine with a
595 # If we don't do this, people could spawn coroutine with a
596 # while/true inside which will freeze the prompt.
596 # while/true inside which will freeze the prompt.
597
597
598 policy = asyncio.get_event_loop_policy()
598 policy = asyncio.get_event_loop_policy()
599 old_loop = get_asyncio_loop()
599 old_loop = get_asyncio_loop()
600
600
601 # FIXME: prompt_toolkit is using the deprecated `asyncio.get_event_loop`
601 # FIXME: prompt_toolkit is using the deprecated `asyncio.get_event_loop`
602 # to get the current event loop.
602 # to get the current event loop.
603 # This will probably be replaced by an attribute or input argument,
603 # This will probably be replaced by an attribute or input argument,
604 # at which point we can stop calling the soon-to-be-deprecated `set_event_loop` here.
604 # at which point we can stop calling the soon-to-be-deprecated `set_event_loop` here.
605 if old_loop is not self.pt_loop:
605 if old_loop is not self.pt_loop:
606 policy.set_event_loop(self.pt_loop)
606 policy.set_event_loop(self.pt_loop)
607 try:
607 try:
608 with patch_stdout(raw=True):
608 with patch_stdout(raw=True):
609 text = self.pt_app.prompt(
609 text = self.pt_app.prompt(
610 default=default,
610 default=default,
611 **self._extra_prompt_options())
611 **self._extra_prompt_options())
612 finally:
612 finally:
613 # Restore the original event loop.
613 # Restore the original event loop.
614 if old_loop is not None and old_loop is not self.pt_loop:
614 if old_loop is not None and old_loop is not self.pt_loop:
615 policy.set_event_loop(old_loop)
615 policy.set_event_loop(old_loop)
616
616
617 return text
617 return text
618
618
619 def enable_win_unicode_console(self):
619 def enable_win_unicode_console(self):
620 # Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
620 # Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
621 # console by default, so WUC shouldn't be needed.
621 # console by default, so WUC shouldn't be needed.
622 warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
622 warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
623 DeprecationWarning,
623 DeprecationWarning,
624 stacklevel=2)
624 stacklevel=2)
625
625
626 def init_io(self):
626 def init_io(self):
627 if sys.platform not in {'win32', 'cli'}:
627 if sys.platform not in {'win32', 'cli'}:
628 return
628 return
629
629
630 import colorama
630 import colorama
631 colorama.init()
631 colorama.init()
632
632
633 def init_magics(self):
633 def init_magics(self):
634 super(TerminalInteractiveShell, self).init_magics()
634 super(TerminalInteractiveShell, self).init_magics()
635 self.register_magics(TerminalMagics)
635 self.register_magics(TerminalMagics)
636
636
637 def init_alias(self):
637 def init_alias(self):
638 # The parent class defines aliases that can be safely used with any
638 # The parent class defines aliases that can be safely used with any
639 # frontend.
639 # frontend.
640 super(TerminalInteractiveShell, self).init_alias()
640 super(TerminalInteractiveShell, self).init_alias()
641
641
642 # Now define aliases that only make sense on the terminal, because they
642 # Now define aliases that only make sense on the terminal, because they
643 # need direct access to the console in a way that we can't emulate in
643 # need direct access to the console in a way that we can't emulate in
644 # GUI or web frontend
644 # GUI or web frontend
645 if os.name == 'posix':
645 if os.name == 'posix':
646 for cmd in ('clear', 'more', 'less', 'man'):
646 for cmd in ('clear', 'more', 'less', 'man'):
647 self.alias_manager.soft_define_alias(cmd, cmd)
647 self.alias_manager.soft_define_alias(cmd, cmd)
648
648
649
649
650 def __init__(self, *args, **kwargs):
650 def __init__(self, *args, **kwargs):
651 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
651 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
652 self._set_autosuggestions(self.autosuggestions_provider)
652 self._set_autosuggestions(self.autosuggestions_provider)
653 self.init_prompt_toolkit_cli()
653 self.init_prompt_toolkit_cli()
654 self.init_term_title()
654 self.init_term_title()
655 self.keep_running = True
655 self.keep_running = True
656 self._set_formatter(self.autoformatter)
656 self._set_formatter(self.autoformatter)
657
657
658
658
659 def ask_exit(self):
659 def ask_exit(self):
660 self.keep_running = False
660 self.keep_running = False
661
661
662 rl_next_input = None
662 rl_next_input = None
663
663
664 def interact(self):
664 def interact(self):
665 self.keep_running = True
665 self.keep_running = True
666 while self.keep_running:
666 while self.keep_running:
667 print(self.separate_in, end='')
667 print(self.separate_in, end='')
668
668
669 try:
669 try:
670 code = self.prompt_for_code()
670 code = self.prompt_for_code()
671 except EOFError:
671 except EOFError:
672 if (not self.confirm_exit) \
672 if (not self.confirm_exit) \
673 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
673 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
674 self.ask_exit()
674 self.ask_exit()
675
675
676 else:
676 else:
677 if code:
677 if code:
678 self.run_cell(code, store_history=True)
678 self.run_cell(code, store_history=True)
679
679
680 def mainloop(self):
680 def mainloop(self):
681 # An extra layer of protection in case someone mashing Ctrl-C breaks
681 # An extra layer of protection in case someone mashing Ctrl-C breaks
682 # out of our internal code.
682 # out of our internal code.
683 while True:
683 while True:
684 try:
684 try:
685 self.interact()
685 self.interact()
686 break
686 break
687 except KeyboardInterrupt as e:
687 except KeyboardInterrupt as e:
688 print("\n%s escaped interact()\n" % type(e).__name__)
688 print("\n%s escaped interact()\n" % type(e).__name__)
689 finally:
689 finally:
690 # An interrupt during the eventloop will mess up the
690 # An interrupt during the eventloop will mess up the
691 # internal state of the prompt_toolkit library.
691 # internal state of the prompt_toolkit library.
692 # Stopping the eventloop fixes this, see
692 # Stopping the eventloop fixes this, see
693 # https://github.com/ipython/ipython/pull/9867
693 # https://github.com/ipython/ipython/pull/9867
694 if hasattr(self, '_eventloop'):
694 if hasattr(self, '_eventloop'):
695 self._eventloop.stop()
695 self._eventloop.stop()
696
696
697 self.restore_term_title()
697 self.restore_term_title()
698
698
699 # try to call some at-exit operation optimistically as some things can't
699 # try to call some at-exit operation optimistically as some things can't
700 # be done during interpreter shutdown. this is technically inaccurate as
700 # be done during interpreter shutdown. this is technically inaccurate as
701 # this make mainlool not re-callable, but that should be a rare if not
701 # this make mainlool not re-callable, but that should be a rare if not
702 # in existent use case.
702 # in existent use case.
703
703
704 self._atexit_once()
704 self._atexit_once()
705
705
706
706
707 _inputhook = None
707 _inputhook = None
708 def inputhook(self, context):
708 def inputhook(self, context):
709 if self._inputhook is not None:
709 if self._inputhook is not None:
710 self._inputhook(context)
710 self._inputhook(context)
711
711
712 active_eventloop = None
712 active_eventloop = None
713 def enable_gui(self, gui=None):
713 def enable_gui(self, gui=None):
714 if gui and (gui != 'inline') :
714 if gui and (gui not in {"inline", "webagg"}):
715 self.active_eventloop, self._inputhook =\
715 self.active_eventloop, self._inputhook = get_inputhook_name_and_func(gui)
716 get_inputhook_name_and_func(gui)
717 else:
716 else:
718 self.active_eventloop = self._inputhook = None
717 self.active_eventloop = self._inputhook = None
719
718
720 # For prompt_toolkit 3.0. We have to create an asyncio event loop with
719 # For prompt_toolkit 3.0. We have to create an asyncio event loop with
721 # this inputhook.
720 # this inputhook.
722 if PTK3:
721 if PTK3:
723 import asyncio
722 import asyncio
724 from prompt_toolkit.eventloop import new_eventloop_with_inputhook
723 from prompt_toolkit.eventloop import new_eventloop_with_inputhook
725
724
726 if gui == 'asyncio':
725 if gui == 'asyncio':
727 # When we integrate the asyncio event loop, run the UI in the
726 # When we integrate the asyncio event loop, run the UI in the
728 # same event loop as the rest of the code. don't use an actual
727 # same event loop as the rest of the code. don't use an actual
729 # input hook. (Asyncio is not made for nesting event loops.)
728 # input hook. (Asyncio is not made for nesting event loops.)
730 self.pt_loop = get_asyncio_loop()
729 self.pt_loop = get_asyncio_loop()
731
730
732 elif self._inputhook:
731 elif self._inputhook:
733 # If an inputhook was set, create a new asyncio event loop with
732 # If an inputhook was set, create a new asyncio event loop with
734 # this inputhook for the prompt.
733 # this inputhook for the prompt.
735 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
734 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
736 else:
735 else:
737 # When there's no inputhook, run the prompt in a separate
736 # When there's no inputhook, run the prompt in a separate
738 # asyncio event loop.
737 # asyncio event loop.
739 self.pt_loop = asyncio.new_event_loop()
738 self.pt_loop = asyncio.new_event_loop()
740
739
741 # Run !system commands directly, not through pipes, so terminal programs
740 # Run !system commands directly, not through pipes, so terminal programs
742 # work correctly.
741 # work correctly.
743 system = InteractiveShell.system_raw
742 system = InteractiveShell.system_raw
744
743
745 def auto_rewrite_input(self, cmd):
744 def auto_rewrite_input(self, cmd):
746 """Overridden from the parent class to use fancy rewriting prompt"""
745 """Overridden from the parent class to use fancy rewriting prompt"""
747 if not self.show_rewritten_input:
746 if not self.show_rewritten_input:
748 return
747 return
749
748
750 tokens = self.prompts.rewrite_prompt_tokens()
749 tokens = self.prompts.rewrite_prompt_tokens()
751 if self.pt_app:
750 if self.pt_app:
752 print_formatted_text(PygmentsTokens(tokens), end='',
751 print_formatted_text(PygmentsTokens(tokens), end='',
753 style=self.pt_app.app.style)
752 style=self.pt_app.app.style)
754 print(cmd)
753 print(cmd)
755 else:
754 else:
756 prompt = ''.join(s for t, s in tokens)
755 prompt = ''.join(s for t, s in tokens)
757 print(prompt, cmd, sep='')
756 print(prompt, cmd, sep='')
758
757
759 _prompts_before = None
758 _prompts_before = None
760 def switch_doctest_mode(self, mode):
759 def switch_doctest_mode(self, mode):
761 """Switch prompts to classic for %doctest_mode"""
760 """Switch prompts to classic for %doctest_mode"""
762 if mode:
761 if mode:
763 self._prompts_before = self.prompts
762 self._prompts_before = self.prompts
764 self.prompts = ClassicPrompts(self)
763 self.prompts = ClassicPrompts(self)
765 elif self._prompts_before:
764 elif self._prompts_before:
766 self.prompts = self._prompts_before
765 self.prompts = self._prompts_before
767 self._prompts_before = None
766 self._prompts_before = None
768 # self._update_layout()
767 # self._update_layout()
769
768
770
769
771 InteractiveShellABC.register(TerminalInteractiveShell)
770 InteractiveShellABC.register(TerminalInteractiveShell)
772
771
773 if __name__ == '__main__':
772 if __name__ == '__main__':
774 TerminalInteractiveShell.instance().interact()
773 TerminalInteractiveShell.instance().interact()
@@ -1,342 +1,343 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The :class:`~traitlets.config.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
8 # Copyright (c) IPython Development Team.
8 # Copyright (c) IPython Development Team.
9 # Distributed under the terms of the Modified BSD License.
9 # Distributed under the terms of the Modified BSD License.
10
10
11
11
12 import logging
12 import logging
13 import os
13 import os
14 import sys
14 import sys
15 import warnings
15 import warnings
16
16
17 from traitlets.config.loader import Config
17 from traitlets.config.loader import Config
18 from traitlets.config.application import boolean_flag, catch_config_error
18 from traitlets.config.application import boolean_flag, catch_config_error
19 from IPython.core import release
19 from IPython.core import release
20 from IPython.core import usage
20 from IPython.core import usage
21 from IPython.core.completer import IPCompleter
21 from IPython.core.completer import IPCompleter
22 from IPython.core.crashhandler import CrashHandler
22 from IPython.core.crashhandler import CrashHandler
23 from IPython.core.formatters import PlainTextFormatter
23 from IPython.core.formatters import PlainTextFormatter
24 from IPython.core.history import HistoryManager
24 from IPython.core.history import HistoryManager
25 from IPython.core.application import (
25 from IPython.core.application import (
26 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
26 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
27 )
27 )
28 from IPython.core.magic import MagicsManager
28 from IPython.core.magic import MagicsManager
29 from IPython.core.magics import (
29 from IPython.core.magics import (
30 ScriptMagics, LoggingMagics
30 ScriptMagics, LoggingMagics
31 )
31 )
32 from IPython.core.shellapp import (
32 from IPython.core.shellapp import (
33 InteractiveShellApp, shell_flags, shell_aliases
33 InteractiveShellApp, shell_flags, shell_aliases
34 )
34 )
35 from IPython.extensions.storemagic import StoreMagics
35 from IPython.extensions.storemagic import StoreMagics
36 from .interactiveshell import TerminalInteractiveShell
36 from .interactiveshell import TerminalInteractiveShell
37 from IPython.paths import get_ipython_dir
37 from IPython.paths import get_ipython_dir
38 from traitlets import (
38 from traitlets import (
39 Bool, List, default, observe, Type
39 Bool, List, default, observe, Type
40 )
40 )
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Globals, utilities and helpers
43 # Globals, utilities and helpers
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 _examples = """
46 _examples = """
47 ipython --matplotlib # enable matplotlib integration
47 ipython --matplotlib # enable matplotlib integration
48 ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
48 ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
49
49
50 ipython --log-level=DEBUG # set logging to DEBUG
50 ipython --log-level=DEBUG # set logging to DEBUG
51 ipython --profile=foo # start with profile foo
51 ipython --profile=foo # start with profile foo
52
52
53 ipython profile create foo # create profile foo w/ default config files
53 ipython profile create foo # create profile foo w/ default config files
54 ipython help profile # show the help for the profile subcmd
54 ipython help profile # show the help for the profile subcmd
55
55
56 ipython locate # print the path to the IPython directory
56 ipython locate # print the path to the IPython directory
57 ipython locate profile foo # print the path to the directory for profile `foo`
57 ipython locate profile foo # print the path to the directory for profile `foo`
58 """
58 """
59
59
60 #-----------------------------------------------------------------------------
60 #-----------------------------------------------------------------------------
61 # Crash handler for this application
61 # Crash handler for this application
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63
63
64 class IPAppCrashHandler(CrashHandler):
64 class IPAppCrashHandler(CrashHandler):
65 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
65 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
66
66
67 def __init__(self, app):
67 def __init__(self, app):
68 contact_name = release.author
68 contact_name = release.author
69 contact_email = release.author_email
69 contact_email = release.author_email
70 bug_tracker = 'https://github.com/ipython/ipython/issues'
70 bug_tracker = 'https://github.com/ipython/ipython/issues'
71 super(IPAppCrashHandler,self).__init__(
71 super(IPAppCrashHandler,self).__init__(
72 app, contact_name, contact_email, bug_tracker
72 app, contact_name, contact_email, bug_tracker
73 )
73 )
74
74
75 def make_report(self,traceback):
75 def make_report(self,traceback):
76 """Return a string containing a crash report."""
76 """Return a string containing a crash report."""
77
77
78 sec_sep = self.section_sep
78 sec_sep = self.section_sep
79 # Start with parent report
79 # Start with parent report
80 report = [super(IPAppCrashHandler, self).make_report(traceback)]
80 report = [super(IPAppCrashHandler, self).make_report(traceback)]
81 # Add interactive-specific info we may have
81 # Add interactive-specific info we may have
82 rpt_add = report.append
82 rpt_add = report.append
83 try:
83 try:
84 rpt_add(sec_sep+"History of session input:")
84 rpt_add(sec_sep+"History of session input:")
85 for line in self.app.shell.user_ns['_ih']:
85 for line in self.app.shell.user_ns['_ih']:
86 rpt_add(line)
86 rpt_add(line)
87 rpt_add('\n*** Last line of input (may not be in above history):\n')
87 rpt_add('\n*** Last line of input (may not be in above history):\n')
88 rpt_add(self.app.shell._last_input_line+'\n')
88 rpt_add(self.app.shell._last_input_line+'\n')
89 except:
89 except:
90 pass
90 pass
91
91
92 return ''.join(report)
92 return ''.join(report)
93
93
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95 # Aliases and Flags
95 # Aliases and Flags
96 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
97 flags = dict(base_flags)
97 flags = dict(base_flags)
98 flags.update(shell_flags)
98 flags.update(shell_flags)
99 frontend_flags = {}
99 frontend_flags = {}
100 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
100 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
101 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
101 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
102 'Turn on auto editing of files with syntax errors.',
102 'Turn on auto editing of files with syntax errors.',
103 'Turn off auto editing of files with syntax errors.'
103 'Turn off auto editing of files with syntax errors.'
104 )
104 )
105 addflag('simple-prompt', 'TerminalInteractiveShell.simple_prompt',
105 addflag('simple-prompt', 'TerminalInteractiveShell.simple_prompt',
106 "Force simple minimal prompt using `raw_input`",
106 "Force simple minimal prompt using `raw_input`",
107 "Use a rich interactive prompt with prompt_toolkit",
107 "Use a rich interactive prompt with prompt_toolkit",
108 )
108 )
109
109
110 addflag('banner', 'TerminalIPythonApp.display_banner',
110 addflag('banner', 'TerminalIPythonApp.display_banner',
111 "Display a banner upon starting IPython.",
111 "Display a banner upon starting IPython.",
112 "Don't display a banner upon starting IPython."
112 "Don't display a banner upon starting IPython."
113 )
113 )
114 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
114 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
115 """Set to confirm when you try to exit IPython with an EOF (Control-D
115 """Set to confirm when you try to exit IPython with an EOF (Control-D
116 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
116 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
117 you can force a direct exit without any confirmation.""",
117 you can force a direct exit without any confirmation.""",
118 "Don't prompt the user when exiting."
118 "Don't prompt the user when exiting."
119 )
119 )
120 addflag('term-title', 'TerminalInteractiveShell.term_title',
120 addflag('term-title', 'TerminalInteractiveShell.term_title',
121 "Enable auto setting the terminal title.",
121 "Enable auto setting the terminal title.",
122 "Disable auto setting the terminal title."
122 "Disable auto setting the terminal title."
123 )
123 )
124 classic_config = Config()
124 classic_config = Config()
125 classic_config.InteractiveShell.cache_size = 0
125 classic_config.InteractiveShell.cache_size = 0
126 classic_config.PlainTextFormatter.pprint = False
126 classic_config.PlainTextFormatter.pprint = False
127 classic_config.TerminalInteractiveShell.prompts_class='IPython.terminal.prompts.ClassicPrompts'
127 classic_config.TerminalInteractiveShell.prompts_class='IPython.terminal.prompts.ClassicPrompts'
128 classic_config.InteractiveShell.separate_in = ''
128 classic_config.InteractiveShell.separate_in = ''
129 classic_config.InteractiveShell.separate_out = ''
129 classic_config.InteractiveShell.separate_out = ''
130 classic_config.InteractiveShell.separate_out2 = ''
130 classic_config.InteractiveShell.separate_out2 = ''
131 classic_config.InteractiveShell.colors = 'NoColor'
131 classic_config.InteractiveShell.colors = 'NoColor'
132 classic_config.InteractiveShell.xmode = 'Plain'
132 classic_config.InteractiveShell.xmode = 'Plain'
133
133
134 frontend_flags['classic']=(
134 frontend_flags['classic']=(
135 classic_config,
135 classic_config,
136 "Gives IPython a similar feel to the classic Python prompt."
136 "Gives IPython a similar feel to the classic Python prompt."
137 )
137 )
138 # # log doesn't make so much sense this way anymore
138 # # log doesn't make so much sense this way anymore
139 # paa('--log','-l',
139 # paa('--log','-l',
140 # action='store_true', dest='InteractiveShell.logstart',
140 # action='store_true', dest='InteractiveShell.logstart',
141 # help="Start logging to the default log file (./ipython_log.py).")
141 # help="Start logging to the default log file (./ipython_log.py).")
142 #
142 #
143 # # quick is harder to implement
143 # # quick is harder to implement
144 frontend_flags['quick']=(
144 frontend_flags['quick']=(
145 {'TerminalIPythonApp' : {'quick' : True}},
145 {'TerminalIPythonApp' : {'quick' : True}},
146 "Enable quick startup with no config files."
146 "Enable quick startup with no config files."
147 )
147 )
148
148
149 frontend_flags['i'] = (
149 frontend_flags['i'] = (
150 {'TerminalIPythonApp' : {'force_interact' : True}},
150 {'TerminalIPythonApp' : {'force_interact' : True}},
151 """If running code from the command line, become interactive afterwards.
151 """If running code from the command line, become interactive afterwards.
152 It is often useful to follow this with `--` to treat remaining flags as
152 It is often useful to follow this with `--` to treat remaining flags as
153 script arguments.
153 script arguments.
154 """
154 """
155 )
155 )
156 flags.update(frontend_flags)
156 flags.update(frontend_flags)
157
157
158 aliases = dict(base_aliases)
158 aliases = dict(base_aliases)
159 aliases.update(shell_aliases)
159 aliases.update(shell_aliases)
160
160
161 #-----------------------------------------------------------------------------
161 #-----------------------------------------------------------------------------
162 # Main classes and functions
162 # Main classes and functions
163 #-----------------------------------------------------------------------------
163 #-----------------------------------------------------------------------------
164
164
165
165
166 class LocateIPythonApp(BaseIPythonApplication):
166 class LocateIPythonApp(BaseIPythonApplication):
167 description = """print the path to the IPython dir"""
167 description = """print the path to the IPython dir"""
168 subcommands = dict(
168 subcommands = dict(
169 profile=('IPython.core.profileapp.ProfileLocate',
169 profile=('IPython.core.profileapp.ProfileLocate',
170 "print the path to an IPython profile directory",
170 "print the path to an IPython profile directory",
171 ),
171 ),
172 )
172 )
173 def start(self):
173 def start(self):
174 if self.subapp is not None:
174 if self.subapp is not None:
175 return self.subapp.start()
175 return self.subapp.start()
176 else:
176 else:
177 print(self.ipython_dir)
177 print(self.ipython_dir)
178
178
179
179
180 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
180 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
181 name = u'ipython'
181 name = u'ipython'
182 description = usage.cl_usage
182 description = usage.cl_usage
183 crash_handler_class = IPAppCrashHandler
183 crash_handler_class = IPAppCrashHandler
184 examples = _examples
184 examples = _examples
185
185
186 flags = flags
186 flags = flags
187 aliases = aliases
187 aliases = aliases
188 classes = List()
188 classes = List()
189
189
190 interactive_shell_class = Type(
190 interactive_shell_class = Type(
191 klass=object, # use default_value otherwise which only allow subclasses.
191 klass=object, # use default_value otherwise which only allow subclasses.
192 default_value=TerminalInteractiveShell,
192 default_value=TerminalInteractiveShell,
193 help="Class to use to instantiate the TerminalInteractiveShell object. Useful for custom Frontends"
193 help="Class to use to instantiate the TerminalInteractiveShell object. Useful for custom Frontends"
194 ).tag(config=True)
194 ).tag(config=True)
195
195
196 @default('classes')
196 @default('classes')
197 def _classes_default(self):
197 def _classes_default(self):
198 """This has to be in a method, for TerminalIPythonApp to be available."""
198 """This has to be in a method, for TerminalIPythonApp to be available."""
199 return [
199 return [
200 InteractiveShellApp, # ShellApp comes before TerminalApp, because
200 InteractiveShellApp, # ShellApp comes before TerminalApp, because
201 self.__class__, # it will also affect subclasses (e.g. QtConsole)
201 self.__class__, # it will also affect subclasses (e.g. QtConsole)
202 TerminalInteractiveShell,
202 TerminalInteractiveShell,
203 HistoryManager,
203 HistoryManager,
204 MagicsManager,
204 MagicsManager,
205 ProfileDir,
205 ProfileDir,
206 PlainTextFormatter,
206 PlainTextFormatter,
207 IPCompleter,
207 IPCompleter,
208 ScriptMagics,
208 ScriptMagics,
209 LoggingMagics,
209 LoggingMagics,
210 StoreMagics,
210 StoreMagics,
211 ]
211 ]
212
212
213 subcommands = dict(
213 subcommands = dict(
214 profile = ("IPython.core.profileapp.ProfileApp",
214 profile = ("IPython.core.profileapp.ProfileApp",
215 "Create and manage IPython profiles."
215 "Create and manage IPython profiles."
216 ),
216 ),
217 kernel = ("ipykernel.kernelapp.IPKernelApp",
217 kernel = ("ipykernel.kernelapp.IPKernelApp",
218 "Start a kernel without an attached frontend."
218 "Start a kernel without an attached frontend."
219 ),
219 ),
220 locate=('IPython.terminal.ipapp.LocateIPythonApp',
220 locate=('IPython.terminal.ipapp.LocateIPythonApp',
221 LocateIPythonApp.description
221 LocateIPythonApp.description
222 ),
222 ),
223 history=('IPython.core.historyapp.HistoryApp',
223 history=('IPython.core.historyapp.HistoryApp',
224 "Manage the IPython history database."
224 "Manage the IPython history database."
225 ),
225 ),
226 )
226 )
227
227
228
228
229 # *do* autocreate requested profile, but don't create the config file.
229 # *do* autocreate requested profile, but don't create the config file.
230 auto_create=Bool(True)
230 auto_create=Bool(True)
231 # configurables
231 # configurables
232 quick = Bool(False,
232 quick = Bool(False,
233 help="""Start IPython quickly by skipping the loading of config files."""
233 help="""Start IPython quickly by skipping the loading of config files."""
234 ).tag(config=True)
234 ).tag(config=True)
235 @observe('quick')
235 @observe('quick')
236 def _quick_changed(self, change):
236 def _quick_changed(self, change):
237 if change['new']:
237 if change['new']:
238 self.load_config_file = lambda *a, **kw: None
238 self.load_config_file = lambda *a, **kw: None
239
239
240 display_banner = Bool(True,
240 display_banner = Bool(True,
241 help="Whether to display a banner upon starting IPython."
241 help="Whether to display a banner upon starting IPython."
242 ).tag(config=True)
242 ).tag(config=True)
243
243
244 # if there is code of files to run from the cmd line, don't interact
244 # if there is code of files to run from the cmd line, don't interact
245 # unless the --i flag (App.force_interact) is true.
245 # unless the --i flag (App.force_interact) is true.
246 force_interact = Bool(False,
246 force_interact = Bool(False,
247 help="""If a command or file is given via the command-line,
247 help="""If a command or file is given via the command-line,
248 e.g. 'ipython foo.py', start an interactive shell after executing the
248 e.g. 'ipython foo.py', start an interactive shell after executing the
249 file or command."""
249 file or command."""
250 ).tag(config=True)
250 ).tag(config=True)
251 @observe('force_interact')
251 @observe('force_interact')
252 def _force_interact_changed(self, change):
252 def _force_interact_changed(self, change):
253 if change['new']:
253 if change['new']:
254 self.interact = True
254 self.interact = True
255
255
256 @observe('file_to_run', 'code_to_run', 'module_to_run')
256 @observe('file_to_run', 'code_to_run', 'module_to_run')
257 def _file_to_run_changed(self, change):
257 def _file_to_run_changed(self, change):
258 new = change['new']
258 new = change['new']
259 if new:
259 if new:
260 self.something_to_run = True
260 self.something_to_run = True
261 if new and not self.force_interact:
261 if new and not self.force_interact:
262 self.interact = False
262 self.interact = False
263
263
264 # internal, not-configurable
264 # internal, not-configurable
265 something_to_run=Bool(False)
265 something_to_run=Bool(False)
266
266
267 @catch_config_error
267 @catch_config_error
268 def initialize(self, argv=None):
268 def initialize(self, argv=None):
269 """Do actions after construct, but before starting the app."""
269 """Do actions after construct, but before starting the app."""
270 super(TerminalIPythonApp, self).initialize(argv)
270 super(TerminalIPythonApp, self).initialize(argv)
271 if self.subapp is not None:
271 if self.subapp is not None:
272 # don't bother initializing further, starting subapp
272 # don't bother initializing further, starting subapp
273 return
273 return
274 # print self.extra_args
274 # print self.extra_args
275 if self.extra_args and not self.something_to_run:
275 if self.extra_args and not self.something_to_run:
276 self.file_to_run = self.extra_args[0]
276 self.file_to_run = self.extra_args[0]
277 self.init_path()
277 self.init_path()
278 # create the shell
278 # create the shell
279 self.init_shell()
279 self.init_shell()
280 # and draw the banner
280 # and draw the banner
281 self.init_banner()
281 self.init_banner()
282 # Now a variety of things that happen after the banner is printed.
282 # Now a variety of things that happen after the banner is printed.
283 self.init_gui_pylab()
283 self.init_gui_pylab()
284 self.init_extensions()
284 self.init_extensions()
285 self.init_code()
285 self.init_code()
286
286
287 def init_shell(self):
287 def init_shell(self):
288 """initialize the InteractiveShell instance"""
288 """initialize the InteractiveShell instance"""
289 # Create an InteractiveShell instance.
289 # Create an InteractiveShell instance.
290 # shell.display_banner should always be False for the terminal
290 # shell.display_banner should always be False for the terminal
291 # based app, because we call shell.show_banner() by hand below
291 # based app, because we call shell.show_banner() by hand below
292 # so the banner shows *before* all extension loading stuff.
292 # so the banner shows *before* all extension loading stuff.
293 self.shell = self.interactive_shell_class.instance(parent=self,
293 self.shell = self.interactive_shell_class.instance(parent=self,
294 profile_dir=self.profile_dir,
294 profile_dir=self.profile_dir,
295 ipython_dir=self.ipython_dir, user_ns=self.user_ns)
295 ipython_dir=self.ipython_dir, user_ns=self.user_ns)
296 self.shell.configurables.append(self)
296 self.shell.configurables.append(self)
297
297
298 def init_banner(self):
298 def init_banner(self):
299 """optionally display the banner"""
299 """optionally display the banner"""
300 if self.display_banner and self.interact:
300 if self.display_banner and self.interact:
301 self.shell.show_banner()
301 self.shell.show_banner()
302 # Make sure there is a space below the banner.
302 # Make sure there is a space below the banner.
303 if self.log_level <= logging.INFO: print()
303 if self.log_level <= logging.INFO: print()
304
304
305 def _pylab_changed(self, name, old, new):
305 def _pylab_changed(self, name, old, new):
306 """Replace --pylab='inline' with --pylab='auto'"""
306 """Replace --pylab='inline' with --pylab='auto'"""
307 if new == 'inline':
307 if new == 'inline':
308 warnings.warn("'inline' not available as pylab backend, "
308 warnings.warn("'inline' not available as pylab backend, "
309 "using 'auto' instead.")
309 "using 'auto' instead.")
310 self.pylab = 'auto'
310 self.pylab = 'auto'
311
311
312 def start(self):
312 def start(self):
313 if self.subapp is not None:
313 if self.subapp is not None:
314 return self.subapp.start()
314 return self.subapp.start()
315 # perform any prexec steps:
315 # perform any prexec steps:
316 if self.interact:
316 if self.interact:
317 self.log.debug("Starting IPython's mainloop...")
317 self.log.debug("Starting IPython's mainloop...")
318 self.shell.mainloop()
318 self.shell.mainloop()
319 else:
319 else:
320 self.log.debug("IPython not interactive...")
320 self.log.debug("IPython not interactive...")
321 self.shell.restore_term_title()
321 if not self.shell.last_execution_succeeded:
322 if not self.shell.last_execution_succeeded:
322 sys.exit(1)
323 sys.exit(1)
323
324
324 def load_default_config(ipython_dir=None):
325 def load_default_config(ipython_dir=None):
325 """Load the default config file from the default ipython_dir.
326 """Load the default config file from the default ipython_dir.
326
327
327 This is useful for embedded shells.
328 This is useful for embedded shells.
328 """
329 """
329 if ipython_dir is None:
330 if ipython_dir is None:
330 ipython_dir = get_ipython_dir()
331 ipython_dir = get_ipython_dir()
331
332
332 profile_dir = os.path.join(ipython_dir, 'profile_default')
333 profile_dir = os.path.join(ipython_dir, 'profile_default')
333 app = TerminalIPythonApp()
334 app = TerminalIPythonApp()
334 app.config_file_paths.append(profile_dir)
335 app.config_file_paths.append(profile_dir)
335 app.load_config_file()
336 app.load_config_file()
336 return app.config
337 return app.config
337
338
338 launch_new_instance = TerminalIPythonApp.launch_instance
339 launch_new_instance = TerminalIPythonApp.launch_instance
339
340
340
341
341 if __name__ == '__main__':
342 if __name__ == '__main__':
342 launch_new_instance()
343 launch_new_instance()
@@ -1,214 +1,214 b''
1 """Extra magics for terminal use."""
1 """Extra magics for terminal use."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6
6
7 from logging import error
7 from logging import error
8 import os
8 import os
9 import sys
9 import sys
10
10
11 from IPython.core.error import TryNext, UsageError
11 from IPython.core.error import TryNext, UsageError
12 from IPython.core.magic import Magics, magics_class, line_magic
12 from IPython.core.magic import Magics, magics_class, line_magic
13 from IPython.lib.clipboard import ClipboardEmpty
13 from IPython.lib.clipboard import ClipboardEmpty
14 from IPython.testing.skipdoctest import skip_doctest
14 from IPython.testing.skipdoctest import skip_doctest
15 from IPython.utils.text import SList, strip_email_quotes
15 from IPython.utils.text import SList, strip_email_quotes
16 from IPython.utils import py3compat
16 from IPython.utils import py3compat
17
17
18 def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False):
18 def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False):
19 """ Yield pasted lines until the user enters the given sentinel value.
19 """ Yield pasted lines until the user enters the given sentinel value.
20 """
20 """
21 if not quiet:
21 if not quiet:
22 print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
22 print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
23 % sentinel)
23 % sentinel)
24 prompt = ":"
24 prompt = ":"
25 else:
25 else:
26 prompt = ""
26 prompt = ""
27 while True:
27 while True:
28 try:
28 try:
29 l = l_input(prompt)
29 l = l_input(prompt)
30 if l == sentinel:
30 if l == sentinel:
31 return
31 return
32 else:
32 else:
33 yield l
33 yield l
34 except EOFError:
34 except EOFError:
35 print('<EOF>')
35 print('<EOF>')
36 return
36 return
37
37
38
38
39 @magics_class
39 @magics_class
40 class TerminalMagics(Magics):
40 class TerminalMagics(Magics):
41 def __init__(self, shell):
41 def __init__(self, shell):
42 super(TerminalMagics, self).__init__(shell)
42 super(TerminalMagics, self).__init__(shell)
43
43
44 def store_or_execute(self, block, name):
44 def store_or_execute(self, block, name, store_history=False):
45 """ Execute a block, or store it in a variable, per the user's request.
45 """ Execute a block, or store it in a variable, per the user's request.
46 """
46 """
47 if name:
47 if name:
48 # If storing it for further editing
48 # If storing it for further editing
49 self.shell.user_ns[name] = SList(block.splitlines())
49 self.shell.user_ns[name] = SList(block.splitlines())
50 print("Block assigned to '%s'" % name)
50 print("Block assigned to '%s'" % name)
51 else:
51 else:
52 b = self.preclean_input(block)
52 b = self.preclean_input(block)
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, store_history=True)
56 self.shell.run_cell(b, store_history)
57 finally:
57 finally:
58 self.shell.using_paste_magics = False
58 self.shell.using_paste_magics = False
59
59
60 def preclean_input(self, block):
60 def preclean_input(self, block):
61 lines = block.splitlines()
61 lines = block.splitlines()
62 while lines and not lines[0].strip():
62 while lines and not lines[0].strip():
63 lines = lines[1:]
63 lines = lines[1:]
64 return strip_email_quotes('\n'.join(lines))
64 return strip_email_quotes('\n'.join(lines))
65
65
66 def rerun_pasted(self, name='pasted_block'):
66 def rerun_pasted(self, name='pasted_block'):
67 """ Rerun a previously pasted command.
67 """ Rerun a previously pasted command.
68 """
68 """
69 b = self.shell.user_ns.get(name)
69 b = self.shell.user_ns.get(name)
70
70
71 # Sanity checks
71 # Sanity checks
72 if b is None:
72 if b is None:
73 raise UsageError('No previous pasted block available')
73 raise UsageError('No previous pasted block available')
74 if not isinstance(b, str):
74 if not isinstance(b, str):
75 raise UsageError(
75 raise UsageError(
76 "Variable 'pasted_block' is not a string, can't execute")
76 "Variable 'pasted_block' is not a string, can't execute")
77
77
78 print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
78 print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
79 self.shell.run_cell(b)
79 self.shell.run_cell(b)
80
80
81 @line_magic
81 @line_magic
82 def autoindent(self, parameter_s = ''):
82 def autoindent(self, parameter_s = ''):
83 """Toggle autoindent on/off (deprecated)"""
83 """Toggle autoindent on/off (deprecated)"""
84 self.shell.set_autoindent()
84 self.shell.set_autoindent()
85 print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
85 print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
86
86
87 @skip_doctest
87 @skip_doctest
88 @line_magic
88 @line_magic
89 def cpaste(self, parameter_s=''):
89 def cpaste(self, parameter_s=''):
90 """Paste & execute a pre-formatted code block from clipboard.
90 """Paste & execute a pre-formatted code block from clipboard.
91
91
92 You must terminate the block with '--' (two minus-signs) or Ctrl-D
92 You must terminate the block with '--' (two minus-signs) or Ctrl-D
93 alone on the line. You can also provide your own sentinel with '%paste
93 alone on the line. You can also provide your own sentinel with '%paste
94 -s %%' ('%%' is the new sentinel for this operation).
94 -s %%' ('%%' is the new sentinel for this operation).
95
95
96 The block is dedented prior to execution to enable execution of method
96 The block is dedented prior to execution to enable execution of method
97 definitions. '>' and '+' characters at the beginning of a line are
97 definitions. '>' and '+' characters at the beginning of a line are
98 ignored, to allow pasting directly from e-mails, diff files and
98 ignored, to allow pasting directly from e-mails, diff files and
99 doctests (the '...' continuation prompt is also stripped). The
99 doctests (the '...' continuation prompt is also stripped). The
100 executed block is also assigned to variable named 'pasted_block' for
100 executed block is also assigned to variable named 'pasted_block' for
101 later editing with '%edit pasted_block'.
101 later editing with '%edit pasted_block'.
102
102
103 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
103 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
104 This assigns the pasted block to variable 'foo' as string, without
104 This assigns the pasted block to variable 'foo' as string, without
105 dedenting or executing it (preceding >>> and + is still stripped)
105 dedenting or executing it (preceding >>> and + is still stripped)
106
106
107 '%cpaste -r' re-executes the block previously entered by cpaste.
107 '%cpaste -r' re-executes the block previously entered by cpaste.
108 '%cpaste -q' suppresses any additional output messages.
108 '%cpaste -q' suppresses any additional output messages.
109
109
110 Do not be alarmed by garbled output on Windows (it's a readline bug).
110 Do not be alarmed by garbled output on Windows (it's a readline bug).
111 Just press enter and type -- (and press enter again) and the block
111 Just press enter and type -- (and press enter again) and the block
112 will be what was just pasted.
112 will be what was just pasted.
113
113
114 Shell escapes are not supported (yet).
114 Shell escapes are not supported (yet).
115
115
116 See Also
116 See Also
117 --------
117 --------
118 paste : automatically pull code from clipboard.
118 paste : automatically pull code from clipboard.
119
119
120 Examples
120 Examples
121 --------
121 --------
122 ::
122 ::
123
123
124 In [8]: %cpaste
124 In [8]: %cpaste
125 Pasting code; enter '--' alone on the line to stop.
125 Pasting code; enter '--' alone on the line to stop.
126 :>>> a = ["world!", "Hello"]
126 :>>> a = ["world!", "Hello"]
127 :>>> print(" ".join(sorted(a)))
127 :>>> print(" ".join(sorted(a)))
128 :--
128 :--
129 Hello world!
129 Hello world!
130
130
131 ::
131 ::
132 In [8]: %cpaste
132 In [8]: %cpaste
133 Pasting code; enter '--' alone on the line to stop.
133 Pasting code; enter '--' alone on the line to stop.
134 :>>> %alias_magic t timeit
134 :>>> %alias_magic t timeit
135 :>>> %t -n1 pass
135 :>>> %t -n1 pass
136 :--
136 :--
137 Created `%t` as an alias for `%timeit`.
137 Created `%t` as an alias for `%timeit`.
138 Created `%%t` as an alias for `%%timeit`.
138 Created `%%t` as an alias for `%%timeit`.
139 354 ns ± 224 ns per loop (mean ± std. dev. of 7 runs, 1 loop each)
139 354 ns ± 224 ns per loop (mean ± std. dev. of 7 runs, 1 loop each)
140 """
140 """
141 opts, name = self.parse_options(parameter_s, 'rqs:', mode='string')
141 opts, name = self.parse_options(parameter_s, 'rqs:', mode='string')
142 if 'r' in opts:
142 if 'r' in opts:
143 self.rerun_pasted()
143 self.rerun_pasted()
144 return
144 return
145
145
146 quiet = ('q' in opts)
146 quiet = ('q' in opts)
147
147
148 sentinel = opts.get('s', u'--')
148 sentinel = opts.get('s', u'--')
149 block = '\n'.join(get_pasted_lines(sentinel, quiet=quiet))
149 block = '\n'.join(get_pasted_lines(sentinel, quiet=quiet))
150 self.store_or_execute(block, name)
150 self.store_or_execute(block, name, store_history=False)
151
151
152 @line_magic
152 @line_magic
153 def paste(self, parameter_s=''):
153 def paste(self, parameter_s=''):
154 """Paste & execute a pre-formatted code block from clipboard.
154 """Paste & execute a pre-formatted code block from clipboard.
155
155
156 The text is pulled directly from the clipboard without user
156 The text is pulled directly from the clipboard without user
157 intervention and printed back on the screen before execution (unless
157 intervention and printed back on the screen before execution (unless
158 the -q flag is given to force quiet mode).
158 the -q flag is given to force quiet mode).
159
159
160 The block is dedented prior to execution to enable execution of method
160 The block is dedented prior to execution to enable execution of method
161 definitions. '>' and '+' characters at the beginning of a line are
161 definitions. '>' and '+' characters at the beginning of a line are
162 ignored, to allow pasting directly from e-mails, diff files and
162 ignored, to allow pasting directly from e-mails, diff files and
163 doctests (the '...' continuation prompt is also stripped). The
163 doctests (the '...' continuation prompt is also stripped). The
164 executed block is also assigned to variable named 'pasted_block' for
164 executed block is also assigned to variable named 'pasted_block' for
165 later editing with '%edit pasted_block'.
165 later editing with '%edit pasted_block'.
166
166
167 You can also pass a variable name as an argument, e.g. '%paste foo'.
167 You can also pass a variable name as an argument, e.g. '%paste foo'.
168 This assigns the pasted block to variable 'foo' as string, without
168 This assigns the pasted block to variable 'foo' as string, without
169 executing it (preceding >>> and + is still stripped).
169 executing it (preceding >>> and + is still stripped).
170
170
171 Options:
171 Options:
172
172
173 -r: re-executes the block previously entered by cpaste.
173 -r: re-executes the block previously entered by cpaste.
174
174
175 -q: quiet mode: do not echo the pasted text back to the terminal.
175 -q: quiet mode: do not echo the pasted text back to the terminal.
176
176
177 IPython statements (magics, shell escapes) are not supported (yet).
177 IPython statements (magics, shell escapes) are not supported (yet).
178
178
179 See Also
179 See Also
180 --------
180 --------
181 cpaste : manually paste code into terminal until you mark its end.
181 cpaste : manually paste code into terminal until you mark its end.
182 """
182 """
183 opts, name = self.parse_options(parameter_s, 'rq', mode='string')
183 opts, name = self.parse_options(parameter_s, 'rq', mode='string')
184 if 'r' in opts:
184 if 'r' in opts:
185 self.rerun_pasted()
185 self.rerun_pasted()
186 return
186 return
187 try:
187 try:
188 block = self.shell.hooks.clipboard_get()
188 block = self.shell.hooks.clipboard_get()
189 except TryNext as clipboard_exc:
189 except TryNext as clipboard_exc:
190 message = getattr(clipboard_exc, 'args')
190 message = getattr(clipboard_exc, 'args')
191 if message:
191 if message:
192 error(message[0])
192 error(message[0])
193 else:
193 else:
194 error('Could not get text from the clipboard.')
194 error('Could not get text from the clipboard.')
195 return
195 return
196 except ClipboardEmpty as e:
196 except ClipboardEmpty as e:
197 raise UsageError("The clipboard appears to be empty") from e
197 raise UsageError("The clipboard appears to be empty") from e
198
198
199 # By default, echo back to terminal unless quiet mode is requested
199 # By default, echo back to terminal unless quiet mode is requested
200 if 'q' not in opts:
200 if 'q' not in opts:
201 sys.stdout.write(self.shell.pycolorize(block))
201 sys.stdout.write(self.shell.pycolorize(block))
202 if not block.endswith("\n"):
202 if not block.endswith("\n"):
203 sys.stdout.write("\n")
203 sys.stdout.write("\n")
204 sys.stdout.write("## -- End pasted text --\n")
204 sys.stdout.write("## -- End pasted text --\n")
205
205
206 self.store_or_execute(block, name)
206 self.store_or_execute(block, name, store_history=True)
207
207
208 # Class-level: add a '%cls' magic only on Windows
208 # Class-level: add a '%cls' magic only on Windows
209 if sys.platform == 'win32':
209 if sys.platform == 'win32':
210 @line_magic
210 @line_magic
211 def cls(self, s):
211 def cls(self, s):
212 """Clear screen.
212 """Clear screen.
213 """
213 """
214 os.system("cls")
214 os.system("cls")
@@ -1,63 +1,62 b''
1 """
1 """
2 Inputhook for running the original asyncio event loop while we're waiting for
2 Inputhook for running the original asyncio event loop while we're waiting for
3 input.
3 input.
4
4
5 By default, in IPython, we run the prompt with a different asyncio event loop,
5 By default, in IPython, we run the prompt with a different asyncio event loop,
6 because otherwise we risk that people are freezing the prompt by scheduling bad
6 because otherwise we risk that people are freezing the prompt by scheduling bad
7 coroutines. E.g., a coroutine that does a while/true and never yield back
7 coroutines. E.g., a coroutine that does a while/true and never yield back
8 control to the loop. We can't cancel that.
8 control to the loop. We can't cancel that.
9
9
10 However, sometimes we want the asyncio loop to keep running while waiting for
10 However, sometimes we want the asyncio loop to keep running while waiting for
11 a prompt.
11 a prompt.
12
12
13 The following example will print the numbers from 1 to 10 above the prompt,
13 The following example will print the numbers from 1 to 10 above the prompt,
14 while we are waiting for input. (This works also because we use
14 while we are waiting for input. (This works also because we use
15 prompt_toolkit`s `patch_stdout`)::
15 prompt_toolkit`s `patch_stdout`)::
16
16
17 In [1]: import asyncio
17 In [1]: import asyncio
18
18
19 In [2]: %gui asyncio
19 In [2]: %gui asyncio
20
20
21 In [3]: async def f():
21 In [3]: async def f():
22 ...: for i in range(10):
22 ...: for i in range(10):
23 ...: await asyncio.sleep(1)
23 ...: await asyncio.sleep(1)
24 ...: print(i)
24 ...: print(i)
25
25
26
26
27 In [4]: asyncio.ensure_future(f())
27 In [4]: asyncio.ensure_future(f())
28
28
29 """
29 """
30 from prompt_toolkit import __version__ as ptk_version
30 from prompt_toolkit import __version__ as ptk_version
31
31
32 from IPython.core.async_helpers import get_asyncio_loop
32 from IPython.core.async_helpers import get_asyncio_loop
33
33
34 PTK3 = ptk_version.startswith('3.')
34 PTK3 = ptk_version.startswith("3.")
35
36
35
37
36
38 def inputhook(context):
37 def inputhook(context):
39 """
38 """
40 Inputhook for asyncio event loop integration.
39 Inputhook for asyncio event loop integration.
41 """
40 """
42 # For prompt_toolkit 3.0, this input hook literally doesn't do anything.
41 # For prompt_toolkit 3.0, this input hook literally doesn't do anything.
43 # The event loop integration here is implemented in `interactiveshell.py`
42 # The event loop integration here is implemented in `interactiveshell.py`
44 # by running the prompt itself in the current asyncio loop. The main reason
43 # by running the prompt itself in the current asyncio loop. The main reason
45 # for this is that nesting asyncio event loops is unreliable.
44 # for this is that nesting asyncio event loops is unreliable.
46 if PTK3:
45 if PTK3:
47 return
46 return
48
47
49 # For prompt_toolkit 2.0, we can run the current asyncio event loop,
48 # For prompt_toolkit 2.0, we can run the current asyncio event loop,
50 # because prompt_toolkit 2.0 uses a different event loop internally.
49 # because prompt_toolkit 2.0 uses a different event loop internally.
51
50
52 # get the persistent asyncio event loop
51 # get the persistent asyncio event loop
53 loop = get_asyncio_loop()
52 loop = get_asyncio_loop()
54
53
55 def stop():
54 def stop():
56 loop.stop()
55 loop.stop()
57
56
58 fileno = context.fileno()
57 fileno = context.fileno()
59 loop.add_reader(fileno, stop)
58 loop.add_reader(fileno, stop)
60 try:
59 try:
61 loop.run_forever()
60 loop.run_forever()
62 finally:
61 finally:
63 loop.remove_reader(fileno)
62 loop.remove_reader(fileno)
@@ -1,58 +1,60 b''
1 # Code borrowed from python-prompt-toolkit examples
1 # Code borrowed from python-prompt-toolkit examples
2 # https://github.com/jonathanslenders/python-prompt-toolkit/blob/77cdcfbc7f4b4c34a9d2f9a34d422d7152f16209/examples/inputhook.py
2 # https://github.com/jonathanslenders/python-prompt-toolkit/blob/77cdcfbc7f4b4c34a9d2f9a34d422d7152f16209/examples/inputhook.py
3
3
4 # Copyright (c) 2014, Jonathan Slenders
4 # Copyright (c) 2014, Jonathan Slenders
5 # All rights reserved.
5 # All rights reserved.
6 #
6 #
7 # Redistribution and use in source and binary forms, with or without modification,
7 # Redistribution and use in source and binary forms, with or without modification,
8 # are permitted provided that the following conditions are met:
8 # are permitted provided that the following conditions are met:
9 #
9 #
10 # * Redistributions of source code must retain the above copyright notice, this
10 # * Redistributions of source code must retain the above copyright notice, this
11 # list of conditions and the following disclaimer.
11 # list of conditions and the following disclaimer.
12 #
12 #
13 # * Redistributions in binary form must reproduce the above copyright notice, this
13 # * Redistributions in binary form must reproduce the above copyright notice, this
14 # list of conditions and the following disclaimer in the documentation and/or
14 # list of conditions and the following disclaimer in the documentation and/or
15 # other materials provided with the distribution.
15 # other materials provided with the distribution.
16 #
16 #
17 # * Neither the name of the {organization} nor the names of its
17 # * Neither the name of the {organization} nor the names of its
18 # contributors may be used to endorse or promote products derived from
18 # contributors may be used to endorse or promote products derived from
19 # this software without specific prior written permission.
19 # this software without specific prior written permission.
20 #
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
24 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
25 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
31
32 """
32 """
33 PyGTK input hook for prompt_toolkit.
33 PyGTK input hook for prompt_toolkit.
34
34
35 Listens on the pipe prompt_toolkit sets up for a notification that it should
35 Listens on the pipe prompt_toolkit sets up for a notification that it should
36 return control to the terminal event loop.
36 return control to the terminal event loop.
37 """
37 """
38
38
39 import gtk, gobject
39 import gtk, gobject
40
40
41 # Enable threading in GTK. (Otherwise, GTK will keep the GIL.)
41 # Enable threading in GTK. (Otherwise, GTK will keep the GIL.)
42 gtk.gdk.threads_init()
42 gtk.gdk.threads_init()
43
43
44
44 def inputhook(context):
45 def inputhook(context):
45 """
46 """
46 When the eventloop of prompt-toolkit is idle, call this inputhook.
47 When the eventloop of prompt-toolkit is idle, call this inputhook.
47
48
48 This will run the GTK main loop until the file descriptor
49 This will run the GTK main loop until the file descriptor
49 `context.fileno()` becomes ready.
50 `context.fileno()` becomes ready.
50
51
51 :param context: An `InputHookContext` instance.
52 :param context: An `InputHookContext` instance.
52 """
53 """
54
53 def _main_quit(*a, **kw):
55 def _main_quit(*a, **kw):
54 gtk.main_quit()
56 gtk.main_quit()
55 return False
57 return False
56
58
57 gobject.io_add_watch(context.fileno(), gobject.IO_IN, _main_quit)
59 gobject.io_add_watch(context.fileno(), gobject.IO_IN, _main_quit)
58 gtk.main()
60 gtk.main()
@@ -1,12 +1,14 b''
1 """prompt_toolkit input hook for GTK 3
1 """prompt_toolkit input hook for GTK 3
2 """
2 """
3
3
4 from gi.repository import Gtk, GLib
4 from gi.repository import Gtk, GLib
5
5
6
6 def _main_quit(*args, **kwargs):
7 def _main_quit(*args, **kwargs):
7 Gtk.main_quit()
8 Gtk.main_quit()
8 return False
9 return False
9
10
11
10 def inputhook(context):
12 def inputhook(context):
11 GLib.io_add_watch(context.fileno(), GLib.PRIORITY_DEFAULT, GLib.IO_IN, _main_quit)
13 GLib.io_add_watch(context.fileno(), GLib.PRIORITY_DEFAULT, GLib.IO_IN, _main_quit)
12 Gtk.main()
14 Gtk.main()
@@ -1,860 +1,860 b''
1 # Based on Pytest doctest.py
1 # Based on Pytest doctest.py
2 # Original license:
2 # Original license:
3 # The MIT License (MIT)
3 # The MIT License (MIT)
4 #
4 #
5 # Copyright (c) 2004-2021 Holger Krekel and others
5 # Copyright (c) 2004-2021 Holger Krekel and others
6 """Discover and run ipdoctests in modules and test files."""
6 """Discover and run ipdoctests in modules and test files."""
7 import builtins
7 import builtins
8 import bdb
8 import bdb
9 import inspect
9 import inspect
10 import os
10 import os
11 import platform
11 import platform
12 import sys
12 import sys
13 import traceback
13 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 pathlib import Path
18 from typing import Any
18 from typing import Any
19 from typing import Callable
19 from typing import Callable
20 from typing import Dict
20 from typing import Dict
21 from typing import Generator
21 from typing import Generator
22 from typing import Iterable
22 from typing import Iterable
23 from typing import List
23 from typing import List
24 from typing import Optional
24 from typing import Optional
25 from typing import Pattern
25 from typing import Pattern
26 from typing import Sequence
26 from typing import Sequence
27 from typing import Tuple
27 from typing import Tuple
28 from typing import Type
28 from typing import Type
29 from typing import TYPE_CHECKING
29 from typing import TYPE_CHECKING
30 from typing import Union
30 from typing import Union
31
31
32 import pytest
32 import pytest
33 from _pytest import outcomes
33 from _pytest import outcomes
34 from _pytest._code.code import ExceptionInfo
34 from _pytest._code.code import ExceptionInfo
35 from _pytest._code.code import ReprFileLocation
35 from _pytest._code.code import ReprFileLocation
36 from _pytest._code.code import TerminalRepr
36 from _pytest._code.code import TerminalRepr
37 from _pytest._io import TerminalWriter
37 from _pytest._io import TerminalWriter
38 from _pytest.compat import safe_getattr
38 from _pytest.compat import safe_getattr
39 from _pytest.config import Config
39 from _pytest.config import Config
40 from _pytest.config.argparsing import Parser
40 from _pytest.config.argparsing import Parser
41 from _pytest.fixtures import FixtureRequest
41 from _pytest.fixtures import FixtureRequest
42 from _pytest.nodes import Collector
42 from _pytest.nodes import Collector
43 from _pytest.outcomes import OutcomeException
43 from _pytest.outcomes import OutcomeException
44 from _pytest.pathlib import fnmatch_ex
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
48
48
49 if TYPE_CHECKING:
49 if TYPE_CHECKING:
50 import doctest
50 import doctest
51
51
52 DOCTEST_REPORT_CHOICE_NONE = "none"
52 DOCTEST_REPORT_CHOICE_NONE = "none"
53 DOCTEST_REPORT_CHOICE_CDIFF = "cdiff"
53 DOCTEST_REPORT_CHOICE_CDIFF = "cdiff"
54 DOCTEST_REPORT_CHOICE_NDIFF = "ndiff"
54 DOCTEST_REPORT_CHOICE_NDIFF = "ndiff"
55 DOCTEST_REPORT_CHOICE_UDIFF = "udiff"
55 DOCTEST_REPORT_CHOICE_UDIFF = "udiff"
56 DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE = "only_first_failure"
56 DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE = "only_first_failure"
57
57
58 DOCTEST_REPORT_CHOICES = (
58 DOCTEST_REPORT_CHOICES = (
59 DOCTEST_REPORT_CHOICE_NONE,
59 DOCTEST_REPORT_CHOICE_NONE,
60 DOCTEST_REPORT_CHOICE_CDIFF,
60 DOCTEST_REPORT_CHOICE_CDIFF,
61 DOCTEST_REPORT_CHOICE_NDIFF,
61 DOCTEST_REPORT_CHOICE_NDIFF,
62 DOCTEST_REPORT_CHOICE_UDIFF,
62 DOCTEST_REPORT_CHOICE_UDIFF,
63 DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE,
63 DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE,
64 )
64 )
65
65
66 # Lazy definition of runner class
66 # Lazy definition of runner class
67 RUNNER_CLASS = None
67 RUNNER_CLASS = None
68 # Lazy definition of output checker class
68 # Lazy definition of output checker class
69 CHECKER_CLASS: Optional[Type["IPDoctestOutputChecker"]] = None
69 CHECKER_CLASS: Optional[Type["IPDoctestOutputChecker"]] = None
70
70
71
71
72 def pytest_addoption(parser: Parser) -> None:
72 def pytest_addoption(parser: Parser) -> None:
73 parser.addini(
73 parser.addini(
74 "ipdoctest_optionflags",
74 "ipdoctest_optionflags",
75 "option flags for ipdoctests",
75 "option flags for ipdoctests",
76 type="args",
76 type="args",
77 default=["ELLIPSIS"],
77 default=["ELLIPSIS"],
78 )
78 )
79 parser.addini(
79 parser.addini(
80 "ipdoctest_encoding", "encoding used for ipdoctest files", default="utf-8"
80 "ipdoctest_encoding", "encoding used for ipdoctest files", default="utf-8"
81 )
81 )
82 group = parser.getgroup("collect")
82 group = parser.getgroup("collect")
83 group.addoption(
83 group.addoption(
84 "--ipdoctest-modules",
84 "--ipdoctest-modules",
85 action="store_true",
85 action="store_true",
86 default=False,
86 default=False,
87 help="run ipdoctests in all .py modules",
87 help="run ipdoctests in all .py modules",
88 dest="ipdoctestmodules",
88 dest="ipdoctestmodules",
89 )
89 )
90 group.addoption(
90 group.addoption(
91 "--ipdoctest-report",
91 "--ipdoctest-report",
92 type=str.lower,
92 type=str.lower,
93 default="udiff",
93 default="udiff",
94 help="choose another output format for diffs on ipdoctest failure",
94 help="choose another output format for diffs on ipdoctest failure",
95 choices=DOCTEST_REPORT_CHOICES,
95 choices=DOCTEST_REPORT_CHOICES,
96 dest="ipdoctestreport",
96 dest="ipdoctestreport",
97 )
97 )
98 group.addoption(
98 group.addoption(
99 "--ipdoctest-glob",
99 "--ipdoctest-glob",
100 action="append",
100 action="append",
101 default=[],
101 default=[],
102 metavar="pat",
102 metavar="pat",
103 help="ipdoctests file matching pattern, default: test*.txt",
103 help="ipdoctests file matching pattern, default: test*.txt",
104 dest="ipdoctestglob",
104 dest="ipdoctestglob",
105 )
105 )
106 group.addoption(
106 group.addoption(
107 "--ipdoctest-ignore-import-errors",
107 "--ipdoctest-ignore-import-errors",
108 action="store_true",
108 action="store_true",
109 default=False,
109 default=False,
110 help="ignore ipdoctest ImportErrors",
110 help="ignore ipdoctest ImportErrors",
111 dest="ipdoctest_ignore_import_errors",
111 dest="ipdoctest_ignore_import_errors",
112 )
112 )
113 group.addoption(
113 group.addoption(
114 "--ipdoctest-continue-on-failure",
114 "--ipdoctest-continue-on-failure",
115 action="store_true",
115 action="store_true",
116 default=False,
116 default=False,
117 help="for a given ipdoctest, continue to run after the first failure",
117 help="for a given ipdoctest, continue to run after the first failure",
118 dest="ipdoctest_continue_on_failure",
118 dest="ipdoctest_continue_on_failure",
119 )
119 )
120
120
121
121
122 def pytest_unconfigure() -> None:
122 def pytest_unconfigure() -> None:
123 global RUNNER_CLASS
123 global RUNNER_CLASS
124
124
125 RUNNER_CLASS = None
125 RUNNER_CLASS = None
126
126
127
127
128 def pytest_collect_file(
128 def pytest_collect_file(
129 file_path: Path,
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 file_path.suffix == ".py":
133 if file_path.suffix == ".py":
134 if config.option.ipdoctestmodules and not any(
134 if config.option.ipdoctestmodules and not any(
135 (_is_setup_py(file_path), _is_main_py(file_path))
135 (_is_setup_py(file_path), _is_main_py(file_path))
136 ):
136 ):
137 mod: IPDoctestModule = IPDoctestModule.from_parent(parent, path=file_path)
137 mod: IPDoctestModule = IPDoctestModule.from_parent(parent, path=file_path)
138 return mod
138 return mod
139 elif _is_ipdoctest(config, file_path, parent):
139 elif _is_ipdoctest(config, file_path, parent):
140 txt: IPDoctestTextfile = IPDoctestTextfile.from_parent(parent, path=file_path)
140 txt: IPDoctestTextfile = IPDoctestTextfile.from_parent(parent, path=file_path)
141 return txt
141 return txt
142 return None
142 return None
143
143
144
144
145 if int(pytest.__version__.split(".")[0]) < 7:
145 if int(pytest.__version__.split(".")[0]) < 7:
146 _collect_file = pytest_collect_file
146 _collect_file = pytest_collect_file
147
147
148 def pytest_collect_file(
148 def pytest_collect_file(
149 path,
149 path,
150 parent: Collector,
150 parent: Collector,
151 ) -> Optional[Union["IPDoctestModule", "IPDoctestTextfile"]]:
151 ) -> Optional[Union["IPDoctestModule", "IPDoctestTextfile"]]:
152 return _collect_file(Path(path), parent)
152 return _collect_file(Path(path), parent)
153
153
154 _import_path = import_path
154 _import_path = import_path
155
155
156 def import_path(path, root):
156 def import_path(path, root):
157 import py.path
157 import py.path
158
158
159 return _import_path(py.path.local(path))
159 return _import_path(py.path.local(path))
160
160
161
161
162 def _is_setup_py(path: Path) -> bool:
162 def _is_setup_py(path: Path) -> bool:
163 if path.name != "setup.py":
163 if path.name != "setup.py":
164 return False
164 return False
165 contents = path.read_bytes()
165 contents = path.read_bytes()
166 return b"setuptools" in contents or b"distutils" in contents
166 return b"setuptools" in contents or b"distutils" in contents
167
167
168
168
169 def _is_ipdoctest(config: Config, path: Path, parent: Collector) -> bool:
169 def _is_ipdoctest(config: Config, path: Path, parent: Collector) -> bool:
170 if path.suffix in (".txt", ".rst") and parent.session.isinitpath(path):
170 if path.suffix in (".txt", ".rst") and parent.session.isinitpath(path):
171 return True
171 return True
172 globs = config.getoption("ipdoctestglob") or ["test*.txt"]
172 globs = config.getoption("ipdoctestglob") or ["test*.txt"]
173 return any(fnmatch_ex(glob, path) for glob in globs)
173 return any(fnmatch_ex(glob, path) for glob in globs)
174
174
175
175
176 def _is_main_py(path: Path) -> bool:
176 def _is_main_py(path: Path) -> bool:
177 return path.name == "__main__.py"
177 return path.name == "__main__.py"
178
178
179
179
180 class ReprFailDoctest(TerminalRepr):
180 class ReprFailDoctest(TerminalRepr):
181 def __init__(
181 def __init__(
182 self, reprlocation_lines: Sequence[Tuple[ReprFileLocation, Sequence[str]]]
182 self, reprlocation_lines: Sequence[Tuple[ReprFileLocation, Sequence[str]]]
183 ) -> None:
183 ) -> None:
184 self.reprlocation_lines = reprlocation_lines
184 self.reprlocation_lines = reprlocation_lines
185
185
186 def toterminal(self, tw: TerminalWriter) -> None:
186 def toterminal(self, tw: TerminalWriter) -> None:
187 for reprlocation, lines in self.reprlocation_lines:
187 for reprlocation, lines in self.reprlocation_lines:
188 for line in lines:
188 for line in lines:
189 tw.line(line)
189 tw.line(line)
190 reprlocation.toterminal(tw)
190 reprlocation.toterminal(tw)
191
191
192
192
193 class MultipleDoctestFailures(Exception):
193 class MultipleDoctestFailures(Exception):
194 def __init__(self, failures: Sequence["doctest.DocTestFailure"]) -> None:
194 def __init__(self, failures: Sequence["doctest.DocTestFailure"]) -> None:
195 super().__init__()
195 super().__init__()
196 self.failures = failures
196 self.failures = failures
197
197
198
198
199 def _init_runner_class() -> Type["IPDocTestRunner"]:
199 def _init_runner_class() -> Type["IPDocTestRunner"]:
200 import doctest
200 import doctest
201 from .ipdoctest import IPDocTestRunner
201 from .ipdoctest import IPDocTestRunner
202
202
203 class PytestDoctestRunner(IPDocTestRunner):
203 class PytestDoctestRunner(IPDocTestRunner):
204 """Runner to collect failures.
204 """Runner to collect failures.
205
205
206 Note that the out variable in this case is a list instead of a
206 Note that the out variable in this case is a list instead of a
207 stdout-like object.
207 stdout-like object.
208 """
208 """
209
209
210 def __init__(
210 def __init__(
211 self,
211 self,
212 checker: Optional["IPDoctestOutputChecker"] = None,
212 checker: Optional["IPDoctestOutputChecker"] = None,
213 verbose: Optional[bool] = None,
213 verbose: Optional[bool] = None,
214 optionflags: int = 0,
214 optionflags: int = 0,
215 continue_on_failure: bool = True,
215 continue_on_failure: bool = True,
216 ) -> None:
216 ) -> None:
217 super().__init__(checker=checker, verbose=verbose, optionflags=optionflags)
217 super().__init__(checker=checker, verbose=verbose, optionflags=optionflags)
218 self.continue_on_failure = continue_on_failure
218 self.continue_on_failure = continue_on_failure
219
219
220 def report_failure(
220 def report_failure(
221 self,
221 self,
222 out,
222 out,
223 test: "doctest.DocTest",
223 test: "doctest.DocTest",
224 example: "doctest.Example",
224 example: "doctest.Example",
225 got: str,
225 got: str,
226 ) -> None:
226 ) -> None:
227 failure = doctest.DocTestFailure(test, example, got)
227 failure = doctest.DocTestFailure(test, example, got)
228 if self.continue_on_failure:
228 if self.continue_on_failure:
229 out.append(failure)
229 out.append(failure)
230 else:
230 else:
231 raise failure
231 raise failure
232
232
233 def report_unexpected_exception(
233 def report_unexpected_exception(
234 self,
234 self,
235 out,
235 out,
236 test: "doctest.DocTest",
236 test: "doctest.DocTest",
237 example: "doctest.Example",
237 example: "doctest.Example",
238 exc_info: Tuple[Type[BaseException], BaseException, types.TracebackType],
238 exc_info: Tuple[Type[BaseException], BaseException, types.TracebackType],
239 ) -> None:
239 ) -> None:
240 if isinstance(exc_info[1], OutcomeException):
240 if isinstance(exc_info[1], OutcomeException):
241 raise exc_info[1]
241 raise exc_info[1]
242 if isinstance(exc_info[1], bdb.BdbQuit):
242 if isinstance(exc_info[1], bdb.BdbQuit):
243 outcomes.exit("Quitting debugger")
243 outcomes.exit("Quitting debugger")
244 failure = doctest.UnexpectedException(test, example, exc_info)
244 failure = doctest.UnexpectedException(test, example, exc_info)
245 if self.continue_on_failure:
245 if self.continue_on_failure:
246 out.append(failure)
246 out.append(failure)
247 else:
247 else:
248 raise failure
248 raise failure
249
249
250 return PytestDoctestRunner
250 return PytestDoctestRunner
251
251
252
252
253 def _get_runner(
253 def _get_runner(
254 checker: Optional["IPDoctestOutputChecker"] = None,
254 checker: Optional["IPDoctestOutputChecker"] = None,
255 verbose: Optional[bool] = None,
255 verbose: Optional[bool] = None,
256 optionflags: int = 0,
256 optionflags: int = 0,
257 continue_on_failure: bool = True,
257 continue_on_failure: bool = True,
258 ) -> "IPDocTestRunner":
258 ) -> "IPDocTestRunner":
259 # We need this in order to do a lazy import on doctest
259 # We need this in order to do a lazy import on doctest
260 global RUNNER_CLASS
260 global RUNNER_CLASS
261 if RUNNER_CLASS is None:
261 if RUNNER_CLASS is None:
262 RUNNER_CLASS = _init_runner_class()
262 RUNNER_CLASS = _init_runner_class()
263 # Type ignored because the continue_on_failure argument is only defined on
263 # Type ignored because the continue_on_failure argument is only defined on
264 # PytestDoctestRunner, which is lazily defined so can't be used as a type.
264 # PytestDoctestRunner, which is lazily defined so can't be used as a type.
265 return RUNNER_CLASS( # type: ignore
265 return RUNNER_CLASS( # type: ignore
266 checker=checker,
266 checker=checker,
267 verbose=verbose,
267 verbose=verbose,
268 optionflags=optionflags,
268 optionflags=optionflags,
269 continue_on_failure=continue_on_failure,
269 continue_on_failure=continue_on_failure,
270 )
270 )
271
271
272
272
273 class IPDoctestItem(pytest.Item):
273 class IPDoctestItem(pytest.Item):
274 def __init__(
274 def __init__(
275 self,
275 self,
276 name: str,
276 name: str,
277 parent: "Union[IPDoctestTextfile, IPDoctestModule]",
277 parent: "Union[IPDoctestTextfile, IPDoctestModule]",
278 runner: Optional["IPDocTestRunner"] = None,
278 runner: Optional["IPDocTestRunner"] = None,
279 dtest: Optional["doctest.DocTest"] = None,
279 dtest: Optional["doctest.DocTest"] = None,
280 ) -> None:
280 ) -> None:
281 super().__init__(name, parent)
281 super().__init__(name, parent)
282 self.runner = runner
282 self.runner = runner
283 self.dtest = dtest
283 self.dtest = dtest
284 self.obj = None
284 self.obj = None
285 self.fixture_request: Optional[FixtureRequest] = None
285 self.fixture_request: Optional[FixtureRequest] = None
286
286
287 @classmethod
287 @classmethod
288 def from_parent( # type: ignore
288 def from_parent( # type: ignore
289 cls,
289 cls,
290 parent: "Union[IPDoctestTextfile, IPDoctestModule]",
290 parent: "Union[IPDoctestTextfile, IPDoctestModule]",
291 *,
291 *,
292 name: str,
292 name: str,
293 runner: "IPDocTestRunner",
293 runner: "IPDocTestRunner",
294 dtest: "doctest.DocTest",
294 dtest: "doctest.DocTest",
295 ):
295 ):
296 # incompatible signature due to imposed limits on subclass
296 # incompatible signature due to imposed limits on subclass
297 """The public named constructor."""
297 """The public named constructor."""
298 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)
299
299
300 def setup(self) -> None:
300 def setup(self) -> None:
301 if self.dtest is not None:
301 if self.dtest is not None:
302 self.fixture_request = _setup_fixtures(self)
302 self.fixture_request = _setup_fixtures(self)
303 globs = dict(getfixture=self.fixture_request.getfixturevalue)
303 globs = dict(getfixture=self.fixture_request.getfixturevalue)
304 for name, value in self.fixture_request.getfixturevalue(
304 for name, value in self.fixture_request.getfixturevalue(
305 "ipdoctest_namespace"
305 "ipdoctest_namespace"
306 ).items():
306 ).items():
307 globs[name] = value
307 globs[name] = value
308 self.dtest.globs.update(globs)
308 self.dtest.globs.update(globs)
309
309
310 from .ipdoctest import IPExample
310 from .ipdoctest import IPExample
311
311
312 if isinstance(self.dtest.examples[0], IPExample):
312 if isinstance(self.dtest.examples[0], IPExample):
313 # for IPython examples *only*, we swap the globals with the ipython
313 # for IPython examples *only*, we swap the globals with the ipython
314 # namespace, after updating it with the globals (which doctest
314 # namespace, after updating it with the globals (which doctest
315 # fills with the necessary info from the module being tested).
315 # fills with the necessary info from the module being tested).
316 self._user_ns_orig = {}
316 self._user_ns_orig = {}
317 self._user_ns_orig.update(_ip.user_ns)
317 self._user_ns_orig.update(_ip.user_ns)
318 _ip.user_ns.update(self.dtest.globs)
318 _ip.user_ns.update(self.dtest.globs)
319 # We must remove the _ key in the namespace, so that Python's
319 # We must remove the _ key in the namespace, so that Python's
320 # doctest code sets it naturally
320 # doctest code sets it naturally
321 _ip.user_ns.pop("_", None)
321 _ip.user_ns.pop("_", None)
322 _ip.user_ns["__builtins__"] = builtins
322 _ip.user_ns["__builtins__"] = builtins
323 self.dtest.globs = _ip.user_ns
323 self.dtest.globs = _ip.user_ns
324
324
325 def teardown(self) -> None:
325 def teardown(self) -> None:
326 from .ipdoctest import IPExample
326 from .ipdoctest import IPExample
327
327
328 # Undo the test.globs reassignment we made
328 # Undo the test.globs reassignment we made
329 if isinstance(self.dtest.examples[0], IPExample):
329 if isinstance(self.dtest.examples[0], IPExample):
330 self.dtest.globs = {}
330 self.dtest.globs = {}
331 _ip.user_ns.clear()
331 _ip.user_ns.clear()
332 _ip.user_ns.update(self._user_ns_orig)
332 _ip.user_ns.update(self._user_ns_orig)
333 del self._user_ns_orig
333 del self._user_ns_orig
334
334
335 self.dtest.globs.clear()
335 self.dtest.globs.clear()
336
336
337 def runtest(self) -> None:
337 def runtest(self) -> None:
338 assert self.dtest is not None
338 assert self.dtest is not None
339 assert self.runner is not None
339 assert self.runner is not None
340 _check_all_skipped(self.dtest)
340 _check_all_skipped(self.dtest)
341 self._disable_output_capturing_for_darwin()
341 self._disable_output_capturing_for_darwin()
342 failures: List["doctest.DocTestFailure"] = []
342 failures: List["doctest.DocTestFailure"] = []
343
343
344 # exec(compile(..., "single", ...), ...) puts result in builtins._
344 # exec(compile(..., "single", ...), ...) puts result in builtins._
345 had_underscore_value = hasattr(builtins, "_")
345 had_underscore_value = hasattr(builtins, "_")
346 underscore_original_value = getattr(builtins, "_", None)
346 underscore_original_value = getattr(builtins, "_", None)
347
347
348 # Save our current directory and switch out to the one where the
348 # Save our current directory and switch out to the one where the
349 # test was originally created, in case another doctest did a
349 # test was originally created, in case another doctest did a
350 # directory change. We'll restore this in the finally clause.
350 # directory change. We'll restore this in the finally clause.
351 curdir = os.getcwd()
351 curdir = os.getcwd()
352 os.chdir(self.fspath.dirname)
352 os.chdir(self.fspath.dirname)
353 try:
353 try:
354 # Type ignored because we change the type of `out` from what
354 # Type ignored because we change the type of `out` from what
355 # ipdoctest expects.
355 # ipdoctest expects.
356 self.runner.run(self.dtest, out=failures, clear_globs=False) # type: ignore[arg-type]
356 self.runner.run(self.dtest, out=failures, clear_globs=False) # type: ignore[arg-type]
357 finally:
357 finally:
358 os.chdir(curdir)
358 os.chdir(curdir)
359 if had_underscore_value:
359 if had_underscore_value:
360 setattr(builtins, "_", underscore_original_value)
360 setattr(builtins, "_", underscore_original_value)
361 elif hasattr(builtins, "_"):
361 elif hasattr(builtins, "_"):
362 delattr(builtins, "_")
362 delattr(builtins, "_")
363
363
364 if failures:
364 if failures:
365 raise MultipleDoctestFailures(failures)
365 raise MultipleDoctestFailures(failures)
366
366
367 def _disable_output_capturing_for_darwin(self) -> None:
367 def _disable_output_capturing_for_darwin(self) -> None:
368 """Disable output capturing. Otherwise, stdout is lost to ipdoctest (pytest#985)."""
368 """Disable output capturing. Otherwise, stdout is lost to ipdoctest (pytest#985)."""
369 if platform.system() != "Darwin":
369 if platform.system() != "Darwin":
370 return
370 return
371 capman = self.config.pluginmanager.getplugin("capturemanager")
371 capman = self.config.pluginmanager.getplugin("capturemanager")
372 if capman:
372 if capman:
373 capman.suspend_global_capture(in_=True)
373 capman.suspend_global_capture(in_=True)
374 out, err = capman.read_global_capture()
374 out, err = capman.read_global_capture()
375 sys.stdout.write(out)
375 sys.stdout.write(out)
376 sys.stderr.write(err)
376 sys.stderr.write(err)
377
377
378 # TODO: Type ignored -- breaks Liskov Substitution.
378 # TODO: Type ignored -- breaks Liskov Substitution.
379 def repr_failure( # type: ignore[override]
379 def repr_failure( # type: ignore[override]
380 self,
380 self,
381 excinfo: ExceptionInfo[BaseException],
381 excinfo: ExceptionInfo[BaseException],
382 ) -> Union[str, TerminalRepr]:
382 ) -> Union[str, TerminalRepr]:
383 import doctest
383 import doctest
384
384
385 failures: Optional[
385 failures: Optional[
386 Sequence[Union[doctest.DocTestFailure, doctest.UnexpectedException]]
386 Sequence[Union[doctest.DocTestFailure, doctest.UnexpectedException]]
387 ] = None
387 ] = None
388 if isinstance(
388 if isinstance(
389 excinfo.value, (doctest.DocTestFailure, doctest.UnexpectedException)
389 excinfo.value, (doctest.DocTestFailure, doctest.UnexpectedException)
390 ):
390 ):
391 failures = [excinfo.value]
391 failures = [excinfo.value]
392 elif isinstance(excinfo.value, MultipleDoctestFailures):
392 elif isinstance(excinfo.value, MultipleDoctestFailures):
393 failures = excinfo.value.failures
393 failures = excinfo.value.failures
394
394
395 if failures is None:
395 if failures is None:
396 return super().repr_failure(excinfo)
396 return super().repr_failure(excinfo)
397
397
398 reprlocation_lines = []
398 reprlocation_lines = []
399 for failure in failures:
399 for failure in failures:
400 example = failure.example
400 example = failure.example
401 test = failure.test
401 test = failure.test
402 filename = test.filename
402 filename = test.filename
403 if test.lineno is None:
403 if test.lineno is None:
404 lineno = None
404 lineno = None
405 else:
405 else:
406 lineno = test.lineno + example.lineno + 1
406 lineno = test.lineno + example.lineno + 1
407 message = type(failure).__name__
407 message = type(failure).__name__
408 # TODO: ReprFileLocation doesn't expect a None lineno.
408 # TODO: ReprFileLocation doesn't expect a None lineno.
409 reprlocation = ReprFileLocation(filename, lineno, message) # type: ignore[arg-type]
409 reprlocation = ReprFileLocation(filename, lineno, message) # type: ignore[arg-type]
410 checker = _get_checker()
410 checker = _get_checker()
411 report_choice = _get_report_choice(self.config.getoption("ipdoctestreport"))
411 report_choice = _get_report_choice(self.config.getoption("ipdoctestreport"))
412 if lineno is not None:
412 if lineno is not None:
413 assert failure.test.docstring is not None
413 assert failure.test.docstring is not None
414 lines = failure.test.docstring.splitlines(False)
414 lines = failure.test.docstring.splitlines(False)
415 # add line numbers to the left of the error message
415 # add line numbers to the left of the error message
416 assert test.lineno is not None
416 assert test.lineno is not None
417 lines = [
417 lines = [
418 "%03d %s" % (i + test.lineno + 1, x) for (i, x) in enumerate(lines)
418 "%03d %s" % (i + test.lineno + 1, x) for (i, x) in enumerate(lines)
419 ]
419 ]
420 # trim docstring error lines to 10
420 # trim docstring error lines to 10
421 lines = lines[max(example.lineno - 9, 0) : example.lineno + 1]
421 lines = lines[max(example.lineno - 9, 0) : example.lineno + 1]
422 else:
422 else:
423 lines = [
423 lines = [
424 "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example"
424 "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example"
425 ]
425 ]
426 indent = ">>>"
426 indent = ">>>"
427 for line in example.source.splitlines():
427 for line in example.source.splitlines():
428 lines.append(f"??? {indent} {line}")
428 lines.append(f"??? {indent} {line}")
429 indent = "..."
429 indent = "..."
430 if isinstance(failure, doctest.DocTestFailure):
430 if isinstance(failure, doctest.DocTestFailure):
431 lines += checker.output_difference(
431 lines += checker.output_difference(
432 example, failure.got, report_choice
432 example, failure.got, report_choice
433 ).split("\n")
433 ).split("\n")
434 else:
434 else:
435 inner_excinfo = ExceptionInfo.from_exc_info(failure.exc_info)
435 inner_excinfo = ExceptionInfo.from_exc_info(failure.exc_info)
436 lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)]
436 lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)]
437 lines += [
437 lines += [
438 x.strip("\n") for x in traceback.format_exception(*failure.exc_info)
438 x.strip("\n") for x in traceback.format_exception(*failure.exc_info)
439 ]
439 ]
440 reprlocation_lines.append((reprlocation, lines))
440 reprlocation_lines.append((reprlocation, lines))
441 return ReprFailDoctest(reprlocation_lines)
441 return ReprFailDoctest(reprlocation_lines)
442
442
443 def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]:
443 def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]:
444 assert self.dtest is not None
444 assert self.dtest is not None
445 return self.path, self.dtest.lineno, "[ipdoctest] %s" % self.name
445 return self.path, self.dtest.lineno, "[ipdoctest] %s" % self.name
446
446
447 if int(pytest.__version__.split(".")[0]) < 7:
447 if int(pytest.__version__.split(".")[0]) < 7:
448
448
449 @property
449 @property
450 def path(self) -> Path:
450 def path(self) -> Path:
451 return Path(self.fspath)
451 return Path(self.fspath)
452
452
453
453
454 def _get_flag_lookup() -> Dict[str, int]:
454 def _get_flag_lookup() -> Dict[str, int]:
455 import doctest
455 import doctest
456
456
457 return dict(
457 return dict(
458 DONT_ACCEPT_TRUE_FOR_1=doctest.DONT_ACCEPT_TRUE_FOR_1,
458 DONT_ACCEPT_TRUE_FOR_1=doctest.DONT_ACCEPT_TRUE_FOR_1,
459 DONT_ACCEPT_BLANKLINE=doctest.DONT_ACCEPT_BLANKLINE,
459 DONT_ACCEPT_BLANKLINE=doctest.DONT_ACCEPT_BLANKLINE,
460 NORMALIZE_WHITESPACE=doctest.NORMALIZE_WHITESPACE,
460 NORMALIZE_WHITESPACE=doctest.NORMALIZE_WHITESPACE,
461 ELLIPSIS=doctest.ELLIPSIS,
461 ELLIPSIS=doctest.ELLIPSIS,
462 IGNORE_EXCEPTION_DETAIL=doctest.IGNORE_EXCEPTION_DETAIL,
462 IGNORE_EXCEPTION_DETAIL=doctest.IGNORE_EXCEPTION_DETAIL,
463 COMPARISON_FLAGS=doctest.COMPARISON_FLAGS,
463 COMPARISON_FLAGS=doctest.COMPARISON_FLAGS,
464 ALLOW_UNICODE=_get_allow_unicode_flag(),
464 ALLOW_UNICODE=_get_allow_unicode_flag(),
465 ALLOW_BYTES=_get_allow_bytes_flag(),
465 ALLOW_BYTES=_get_allow_bytes_flag(),
466 NUMBER=_get_number_flag(),
466 NUMBER=_get_number_flag(),
467 )
467 )
468
468
469
469
470 def get_optionflags(parent):
470 def get_optionflags(parent):
471 optionflags_str = parent.config.getini("ipdoctest_optionflags")
471 optionflags_str = parent.config.getini("ipdoctest_optionflags")
472 flag_lookup_table = _get_flag_lookup()
472 flag_lookup_table = _get_flag_lookup()
473 flag_acc = 0
473 flag_acc = 0
474 for flag in optionflags_str:
474 for flag in optionflags_str:
475 flag_acc |= flag_lookup_table[flag]
475 flag_acc |= flag_lookup_table[flag]
476 return flag_acc
476 return flag_acc
477
477
478
478
479 def _get_continue_on_failure(config):
479 def _get_continue_on_failure(config):
480 continue_on_failure = config.getvalue("ipdoctest_continue_on_failure")
480 continue_on_failure = config.getvalue("ipdoctest_continue_on_failure")
481 if continue_on_failure:
481 if continue_on_failure:
482 # We need to turn off this if we use pdb since we should stop at
482 # We need to turn off this if we use pdb since we should stop at
483 # the first failure.
483 # the first failure.
484 if config.getvalue("usepdb"):
484 if config.getvalue("usepdb"):
485 continue_on_failure = False
485 continue_on_failure = False
486 return continue_on_failure
486 return continue_on_failure
487
487
488
488
489 class IPDoctestTextfile(pytest.Module):
489 class IPDoctestTextfile(pytest.Module):
490 obj = None
490 obj = None
491
491
492 def collect(self) -> Iterable[IPDoctestItem]:
492 def collect(self) -> Iterable[IPDoctestItem]:
493 import doctest
493 import doctest
494 from .ipdoctest import IPDocTestParser
494 from .ipdoctest import IPDocTestParser
495
495
496 # Inspired by doctest.testfile; ideally we would use it directly,
496 # Inspired by doctest.testfile; ideally we would use it directly,
497 # but it doesn't support passing a custom checker.
497 # but it doesn't support passing a custom checker.
498 encoding = self.config.getini("ipdoctest_encoding")
498 encoding = self.config.getini("ipdoctest_encoding")
499 text = self.path.read_text(encoding)
499 text = self.path.read_text(encoding)
500 filename = str(self.path)
500 filename = str(self.path)
501 name = self.path.name
501 name = self.path.name
502 globs = {"__name__": "__main__"}
502 globs = {"__name__": "__main__"}
503
503
504 optionflags = get_optionflags(self)
504 optionflags = get_optionflags(self)
505
505
506 runner = _get_runner(
506 runner = _get_runner(
507 verbose=False,
507 verbose=False,
508 optionflags=optionflags,
508 optionflags=optionflags,
509 checker=_get_checker(),
509 checker=_get_checker(),
510 continue_on_failure=_get_continue_on_failure(self.config),
510 continue_on_failure=_get_continue_on_failure(self.config),
511 )
511 )
512
512
513 parser = IPDocTestParser()
513 parser = IPDocTestParser()
514 test = parser.get_doctest(text, globs, name, filename, 0)
514 test = parser.get_doctest(text, globs, name, filename, 0)
515 if test.examples:
515 if test.examples:
516 yield IPDoctestItem.from_parent(
516 yield IPDoctestItem.from_parent(
517 self, name=test.name, runner=runner, dtest=test
517 self, name=test.name, runner=runner, dtest=test
518 )
518 )
519
519
520 if int(pytest.__version__.split(".")[0]) < 7:
520 if int(pytest.__version__.split(".")[0]) < 7:
521
521
522 @property
522 @property
523 def path(self) -> Path:
523 def path(self) -> Path:
524 return Path(self.fspath)
524 return Path(self.fspath)
525
525
526 @classmethod
526 @classmethod
527 def from_parent(
527 def from_parent(
528 cls,
528 cls,
529 parent,
529 parent,
530 *,
530 *,
531 fspath=None,
531 fspath=None,
532 path: Optional[Path] = None,
532 path: Optional[Path] = None,
533 **kw,
533 **kw,
534 ):
534 ):
535 if path is not None:
535 if path is not None:
536 import py.path
536 import py.path
537
537
538 fspath = py.path.local(path)
538 fspath = py.path.local(path)
539 return super().from_parent(parent=parent, fspath=fspath, **kw)
539 return super().from_parent(parent=parent, fspath=fspath, **kw)
540
540
541
541
542 def _check_all_skipped(test: "doctest.DocTest") -> None:
542 def _check_all_skipped(test: "doctest.DocTest") -> None:
543 """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
544 option set."""
544 option set."""
545 import doctest
545 import doctest
546
546
547 all_skipped = all(x.options.get(doctest.SKIP, False) for x in test.examples)
547 all_skipped = all(x.options.get(doctest.SKIP, False) for x in test.examples)
548 if all_skipped:
548 if all_skipped:
549 pytest.skip("all docstests skipped by +SKIP option")
549 pytest.skip("all docstests skipped by +SKIP option")
550
550
551
551
552 def _is_mocked(obj: object) -> bool:
552 def _is_mocked(obj: object) -> bool:
553 """Return if an object is possibly a mock object by checking the
553 """Return if an object is possibly a mock object by checking the
554 existence of a highly improbable attribute."""
554 existence of a highly improbable attribute."""
555 return (
555 return (
556 safe_getattr(obj, "pytest_mock_example_attribute_that_shouldnt_exist", None)
556 safe_getattr(obj, "pytest_mock_example_attribute_that_shouldnt_exist", None)
557 is not None
557 is not None
558 )
558 )
559
559
560
560
561 @contextmanager
561 @contextmanager
562 def _patch_unwrap_mock_aware() -> Generator[None, None, None]:
562 def _patch_unwrap_mock_aware() -> Generator[None, None, None]:
563 """Context manager which replaces ``inspect.unwrap`` with a version
563 """Context manager which replaces ``inspect.unwrap`` with a version
564 that's aware of mock objects and doesn't recurse into them."""
564 that's aware of mock objects and doesn't recurse into them."""
565 real_unwrap = inspect.unwrap
565 real_unwrap = inspect.unwrap
566
566
567 def _mock_aware_unwrap(
567 def _mock_aware_unwrap(
568 func: Callable[..., Any], *, stop: Optional[Callable[[Any], Any]] = None
568 func: Callable[..., Any], *, stop: Optional[Callable[[Any], Any]] = None
569 ) -> Any:
569 ) -> Any:
570 try:
570 try:
571 if stop is None or stop is _is_mocked:
571 if stop is None or stop is _is_mocked:
572 return real_unwrap(func, stop=_is_mocked)
572 return real_unwrap(func, stop=_is_mocked)
573 _stop = stop
573 _stop = stop
574 return real_unwrap(func, stop=lambda obj: _is_mocked(obj) or _stop(func))
574 return real_unwrap(func, stop=lambda obj: _is_mocked(obj) or _stop(func))
575 except Exception as e:
575 except Exception as e:
576 warnings.warn(
576 warnings.warn(
577 "Got %r when unwrapping %r. This is usually caused "
577 "Got %r when unwrapping %r. This is usually caused "
578 "by a violation of Python's object protocol; see e.g. "
578 "by a violation of Python's object protocol; see e.g. "
579 "https://github.com/pytest-dev/pytest/issues/5080" % (e, func),
579 "https://github.com/pytest-dev/pytest/issues/5080" % (e, func),
580 PytestWarning,
580 PytestWarning,
581 )
581 )
582 raise
582 raise
583
583
584 inspect.unwrap = _mock_aware_unwrap
584 inspect.unwrap = _mock_aware_unwrap
585 try:
585 try:
586 yield
586 yield
587 finally:
587 finally:
588 inspect.unwrap = real_unwrap
588 inspect.unwrap = real_unwrap
589
589
590
590
591 class IPDoctestModule(pytest.Module):
591 class IPDoctestModule(pytest.Module):
592 def collect(self) -> Iterable[IPDoctestItem]:
592 def collect(self) -> Iterable[IPDoctestItem]:
593 import doctest
593 import doctest
594 from .ipdoctest import DocTestFinder, IPDocTestParser
594 from .ipdoctest import DocTestFinder, IPDocTestParser
595
595
596 class MockAwareDocTestFinder(DocTestFinder):
596 class MockAwareDocTestFinder(DocTestFinder):
597 """A hackish ipdoctest finder that overrides stdlib internals to fix a stdlib bug.
597 """A hackish ipdoctest finder that overrides stdlib internals to fix a stdlib bug.
598
598
599 https://github.com/pytest-dev/pytest/issues/3456
599 https://github.com/pytest-dev/pytest/issues/3456
600 https://bugs.python.org/issue25532
600 https://bugs.python.org/issue25532
601 """
601 """
602
602
603 def _find_lineno(self, obj, source_lines):
603 def _find_lineno(self, obj, source_lines):
604 """Doctest code does not take into account `@property`, this
604 """Doctest code does not take into account `@property`, this
605 is a hackish way to fix it. https://bugs.python.org/issue17446
605 is a hackish way to fix it. https://bugs.python.org/issue17446
606
606
607 Wrapped Doctests will need to be unwrapped so the correct
607 Wrapped Doctests will need to be unwrapped so the correct
608 line number is returned. This will be reported upstream. #8796
608 line number is returned. This will be reported upstream. #8796
609 """
609 """
610 if isinstance(obj, property):
610 if isinstance(obj, property):
611 obj = getattr(obj, "fget", obj)
611 obj = getattr(obj, "fget", obj)
612
612
613 if hasattr(obj, "__wrapped__"):
613 if hasattr(obj, "__wrapped__"):
614 # Get the main obj in case of it being wrapped
614 # Get the main obj in case of it being wrapped
615 obj = inspect.unwrap(obj)
615 obj = inspect.unwrap(obj)
616
616
617 # Type ignored because this is a private function.
617 # Type ignored because this is a private function.
618 return super()._find_lineno( # type:ignore[misc]
618 return super()._find_lineno( # type:ignore[misc]
619 obj,
619 obj,
620 source_lines,
620 source_lines,
621 )
621 )
622
622
623 def _find(
623 def _find(
624 self, tests, obj, name, module, source_lines, globs, seen
624 self, tests, obj, name, module, source_lines, globs, seen
625 ) -> None:
625 ) -> None:
626 if _is_mocked(obj):
626 if _is_mocked(obj):
627 return
627 return
628 with _patch_unwrap_mock_aware():
628 with _patch_unwrap_mock_aware():
629
629
630 # Type ignored because this is a private function.
630 # Type ignored because this is a private function.
631 super()._find( # type:ignore[misc]
631 super()._find( # type:ignore[misc]
632 tests, obj, name, module, source_lines, globs, seen
632 tests, obj, name, module, source_lines, globs, seen
633 )
633 )
634
634
635 if self.path.name == "conftest.py":
635 if self.path.name == "conftest.py":
636 if int(pytest.__version__.split(".")[0]) < 7:
636 if int(pytest.__version__.split(".")[0]) < 7:
637 module = self.config.pluginmanager._importconftest(
637 module = self.config.pluginmanager._importconftest(
638 self.path,
638 self.path,
639 self.config.getoption("importmode"),
639 self.config.getoption("importmode"),
640 )
640 )
641 else:
641 else:
642 module = self.config.pluginmanager._importconftest(
642 module = self.config.pluginmanager._importconftest(
643 self.path,
643 self.path,
644 self.config.getoption("importmode"),
644 self.config.getoption("importmode"),
645 rootpath=self.config.rootpath,
645 rootpath=self.config.rootpath,
646 )
646 )
647 else:
647 else:
648 try:
648 try:
649 module = import_path(self.path, root=self.config.rootpath)
649 module = import_path(self.path, root=self.config.rootpath)
650 except ImportError:
650 except ImportError:
651 if self.config.getvalue("ipdoctest_ignore_import_errors"):
651 if self.config.getvalue("ipdoctest_ignore_import_errors"):
652 pytest.skip("unable to import module %r" % self.path)
652 pytest.skip("unable to import module %r" % self.path)
653 else:
653 else:
654 raise
654 raise
655 # Uses internal doctest module parsing mechanism.
655 # Uses internal doctest module parsing mechanism.
656 finder = MockAwareDocTestFinder(parser=IPDocTestParser())
656 finder = MockAwareDocTestFinder(parser=IPDocTestParser())
657 optionflags = get_optionflags(self)
657 optionflags = get_optionflags(self)
658 runner = _get_runner(
658 runner = _get_runner(
659 verbose=False,
659 verbose=False,
660 optionflags=optionflags,
660 optionflags=optionflags,
661 checker=_get_checker(),
661 checker=_get_checker(),
662 continue_on_failure=_get_continue_on_failure(self.config),
662 continue_on_failure=_get_continue_on_failure(self.config),
663 )
663 )
664
664
665 for test in finder.find(module, module.__name__):
665 for test in finder.find(module, module.__name__):
666 if test.examples: # skip empty ipdoctests
666 if test.examples: # skip empty ipdoctests
667 yield IPDoctestItem.from_parent(
667 yield IPDoctestItem.from_parent(
668 self, name=test.name, runner=runner, dtest=test
668 self, name=test.name, runner=runner, dtest=test
669 )
669 )
670
670
671 if int(pytest.__version__.split(".")[0]) < 7:
671 if int(pytest.__version__.split(".")[0]) < 7:
672
672
673 @property
673 @property
674 def path(self) -> Path:
674 def path(self) -> Path:
675 return Path(self.fspath)
675 return Path(self.fspath)
676
676
677 @classmethod
677 @classmethod
678 def from_parent(
678 def from_parent(
679 cls,
679 cls,
680 parent,
680 parent,
681 *,
681 *,
682 fspath=None,
682 fspath=None,
683 path: Optional[Path] = None,
683 path: Optional[Path] = None,
684 **kw,
684 **kw,
685 ):
685 ):
686 if path is not None:
686 if path is not None:
687 import py.path
687 import py.path
688
688
689 fspath = py.path.local(path)
689 fspath = py.path.local(path)
690 return super().from_parent(parent=parent, fspath=fspath, **kw)
690 return super().from_parent(parent=parent, fspath=fspath, **kw)
691
691
692
692
693 def _setup_fixtures(doctest_item: IPDoctestItem) -> FixtureRequest:
693 def _setup_fixtures(doctest_item: IPDoctestItem) -> FixtureRequest:
694 """Used by IPDoctestTextfile and IPDoctestItem to setup fixture information."""
694 """Used by IPDoctestTextfile and IPDoctestItem to setup fixture information."""
695
695
696 def func() -> None:
696 def func() -> None:
697 pass
697 pass
698
698
699 doctest_item.funcargs = {} # type: ignore[attr-defined]
699 doctest_item.funcargs = {} # type: ignore[attr-defined]
700 fm = doctest_item.session._fixturemanager
700 fm = doctest_item.session._fixturemanager
701 doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined]
701 doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined]
702 node=doctest_item, func=func, cls=None, funcargs=False
702 node=doctest_item, func=func, cls=None, funcargs=False
703 )
703 )
704 fixture_request = FixtureRequest(doctest_item, _ispytest=True)
704 fixture_request = FixtureRequest(doctest_item, _ispytest=True)
705 fixture_request._fillfixtures()
705 fixture_request._fillfixtures()
706 return fixture_request
706 return fixture_request
707
707
708
708
709 def _init_checker_class() -> Type["IPDoctestOutputChecker"]:
709 def _init_checker_class() -> Type["IPDoctestOutputChecker"]:
710 import doctest
710 import doctest
711 import re
711 import re
712 from .ipdoctest import IPDoctestOutputChecker
712 from .ipdoctest import IPDoctestOutputChecker
713
713
714 class LiteralsOutputChecker(IPDoctestOutputChecker):
714 class LiteralsOutputChecker(IPDoctestOutputChecker):
715 # Based on doctest_nose_plugin.py from the nltk project
715 # Based on doctest_nose_plugin.py from the nltk project
716 # (https://github.com/nltk/nltk) and on the "numtest" doctest extension
716 # (https://github.com/nltk/nltk) and on the "numtest" doctest extension
717 # by Sebastien Boisgerault (https://github.com/boisgera/numtest).
717 # by Sebastien Boisgerault (https://github.com/boisgera/numtest).
718
718
719 _unicode_literal_re = re.compile(r"(\W|^)[uU]([rR]?[\'\"])", re.UNICODE)
719 _unicode_literal_re = re.compile(r"(\W|^)[uU]([rR]?[\'\"])", re.UNICODE)
720 _bytes_literal_re = re.compile(r"(\W|^)[bB]([rR]?[\'\"])", re.UNICODE)
720 _bytes_literal_re = re.compile(r"(\W|^)[bB]([rR]?[\'\"])", re.UNICODE)
721 _number_re = re.compile(
721 _number_re = re.compile(
722 r"""
722 r"""
723 (?P<number>
723 (?P<number>
724 (?P<mantissa>
724 (?P<mantissa>
725 (?P<integer1> [+-]?\d*)\.(?P<fraction>\d+)
725 (?P<integer1> [+-]?\d*)\.(?P<fraction>\d+)
726 |
726 |
727 (?P<integer2> [+-]?\d+)\.
727 (?P<integer2> [+-]?\d+)\.
728 )
728 )
729 (?:
729 (?:
730 [Ee]
730 [Ee]
731 (?P<exponent1> [+-]?\d+)
731 (?P<exponent1> [+-]?\d+)
732 )?
732 )?
733 |
733 |
734 (?P<integer3> [+-]?\d+)
734 (?P<integer3> [+-]?\d+)
735 (?:
735 (?:
736 [Ee]
736 [Ee]
737 (?P<exponent2> [+-]?\d+)
737 (?P<exponent2> [+-]?\d+)
738 )
738 )
739 )
739 )
740 """,
740 """,
741 re.VERBOSE,
741 re.VERBOSE,
742 )
742 )
743
743
744 def check_output(self, want: str, got: str, optionflags: int) -> bool:
744 def check_output(self, want: str, got: str, optionflags: int) -> bool:
745 if super().check_output(want, got, optionflags):
745 if super().check_output(want, got, optionflags):
746 return True
746 return True
747
747
748 allow_unicode = optionflags & _get_allow_unicode_flag()
748 allow_unicode = optionflags & _get_allow_unicode_flag()
749 allow_bytes = optionflags & _get_allow_bytes_flag()
749 allow_bytes = optionflags & _get_allow_bytes_flag()
750 allow_number = optionflags & _get_number_flag()
750 allow_number = optionflags & _get_number_flag()
751
751
752 if not allow_unicode and not allow_bytes and not allow_number:
752 if not allow_unicode and not allow_bytes and not allow_number:
753 return False
753 return False
754
754
755 def remove_prefixes(regex: Pattern[str], txt: str) -> str:
755 def remove_prefixes(regex: Pattern[str], txt: str) -> str:
756 return re.sub(regex, r"\1\2", txt)
756 return re.sub(regex, r"\1\2", txt)
757
757
758 if allow_unicode:
758 if allow_unicode:
759 want = remove_prefixes(self._unicode_literal_re, want)
759 want = remove_prefixes(self._unicode_literal_re, want)
760 got = remove_prefixes(self._unicode_literal_re, got)
760 got = remove_prefixes(self._unicode_literal_re, got)
761
761
762 if allow_bytes:
762 if allow_bytes:
763 want = remove_prefixes(self._bytes_literal_re, want)
763 want = remove_prefixes(self._bytes_literal_re, want)
764 got = remove_prefixes(self._bytes_literal_re, got)
764 got = remove_prefixes(self._bytes_literal_re, got)
765
765
766 if allow_number:
766 if allow_number:
767 got = self._remove_unwanted_precision(want, got)
767 got = self._remove_unwanted_precision(want, got)
768
768
769 return super().check_output(want, got, optionflags)
769 return super().check_output(want, got, optionflags)
770
770
771 def _remove_unwanted_precision(self, want: str, got: str) -> str:
771 def _remove_unwanted_precision(self, want: str, got: str) -> str:
772 wants = list(self._number_re.finditer(want))
772 wants = list(self._number_re.finditer(want))
773 gots = list(self._number_re.finditer(got))
773 gots = list(self._number_re.finditer(got))
774 if len(wants) != len(gots):
774 if len(wants) != len(gots):
775 return got
775 return got
776 offset = 0
776 offset = 0
777 for w, g in zip(wants, gots):
777 for w, g in zip(wants, gots):
778 fraction: Optional[str] = w.group("fraction")
778 fraction: Optional[str] = w.group("fraction")
779 exponent: Optional[str] = w.group("exponent1")
779 exponent: Optional[str] = w.group("exponent1")
780 if exponent is None:
780 if exponent is None:
781 exponent = w.group("exponent2")
781 exponent = w.group("exponent2")
782 precision = 0 if fraction is None else len(fraction)
782 precision = 0 if fraction is None else len(fraction)
783 if exponent is not None:
783 if exponent is not None:
784 precision -= int(exponent)
784 precision -= int(exponent)
785 if float(w.group()) == approx(float(g.group()), abs=10 ** -precision):
785 if float(w.group()) == approx(float(g.group()), abs=10**-precision):
786 # They're close enough. Replace the text we actually
786 # They're close enough. Replace the text we actually
787 # got with the text we want, so that it will match when we
787 # got with the text we want, so that it will match when we
788 # check the string literally.
788 # check the string literally.
789 got = (
789 got = (
790 got[: g.start() + offset] + w.group() + got[g.end() + offset :]
790 got[: g.start() + offset] + w.group() + got[g.end() + offset :]
791 )
791 )
792 offset += w.end() - w.start() - (g.end() - g.start())
792 offset += w.end() - w.start() - (g.end() - g.start())
793 return got
793 return got
794
794
795 return LiteralsOutputChecker
795 return LiteralsOutputChecker
796
796
797
797
798 def _get_checker() -> "IPDoctestOutputChecker":
798 def _get_checker() -> "IPDoctestOutputChecker":
799 """Return a IPDoctestOutputChecker subclass that supports some
799 """Return a IPDoctestOutputChecker subclass that supports some
800 additional options:
800 additional options:
801
801
802 * ALLOW_UNICODE and ALLOW_BYTES options to ignore u'' and b''
802 * ALLOW_UNICODE and ALLOW_BYTES options to ignore u'' and b''
803 prefixes (respectively) in string literals. Useful when the same
803 prefixes (respectively) in string literals. Useful when the same
804 ipdoctest should run in Python 2 and Python 3.
804 ipdoctest should run in Python 2 and Python 3.
805
805
806 * NUMBER to ignore floating-point differences smaller than the
806 * NUMBER to ignore floating-point differences smaller than the
807 precision of the literal number in the ipdoctest.
807 precision of the literal number in the ipdoctest.
808
808
809 An inner class is used to avoid importing "ipdoctest" at the module
809 An inner class is used to avoid importing "ipdoctest" at the module
810 level.
810 level.
811 """
811 """
812 global CHECKER_CLASS
812 global CHECKER_CLASS
813 if CHECKER_CLASS is None:
813 if CHECKER_CLASS is None:
814 CHECKER_CLASS = _init_checker_class()
814 CHECKER_CLASS = _init_checker_class()
815 return CHECKER_CLASS()
815 return CHECKER_CLASS()
816
816
817
817
818 def _get_allow_unicode_flag() -> int:
818 def _get_allow_unicode_flag() -> int:
819 """Register and return the ALLOW_UNICODE flag."""
819 """Register and return the ALLOW_UNICODE flag."""
820 import doctest
820 import doctest
821
821
822 return doctest.register_optionflag("ALLOW_UNICODE")
822 return doctest.register_optionflag("ALLOW_UNICODE")
823
823
824
824
825 def _get_allow_bytes_flag() -> int:
825 def _get_allow_bytes_flag() -> int:
826 """Register and return the ALLOW_BYTES flag."""
826 """Register and return the ALLOW_BYTES flag."""
827 import doctest
827 import doctest
828
828
829 return doctest.register_optionflag("ALLOW_BYTES")
829 return doctest.register_optionflag("ALLOW_BYTES")
830
830
831
831
832 def _get_number_flag() -> int:
832 def _get_number_flag() -> int:
833 """Register and return the NUMBER flag."""
833 """Register and return the NUMBER flag."""
834 import doctest
834 import doctest
835
835
836 return doctest.register_optionflag("NUMBER")
836 return doctest.register_optionflag("NUMBER")
837
837
838
838
839 def _get_report_choice(key: str) -> int:
839 def _get_report_choice(key: str) -> int:
840 """Return the actual `ipdoctest` module flag value.
840 """Return the actual `ipdoctest` module flag value.
841
841
842 We want to do it as late as possible to avoid importing `ipdoctest` and all
842 We want to do it as late as possible to avoid importing `ipdoctest` and all
843 its dependencies when parsing options, as it adds overhead and breaks tests.
843 its dependencies when parsing options, as it adds overhead and breaks tests.
844 """
844 """
845 import doctest
845 import doctest
846
846
847 return {
847 return {
848 DOCTEST_REPORT_CHOICE_UDIFF: doctest.REPORT_UDIFF,
848 DOCTEST_REPORT_CHOICE_UDIFF: doctest.REPORT_UDIFF,
849 DOCTEST_REPORT_CHOICE_CDIFF: doctest.REPORT_CDIFF,
849 DOCTEST_REPORT_CHOICE_CDIFF: doctest.REPORT_CDIFF,
850 DOCTEST_REPORT_CHOICE_NDIFF: doctest.REPORT_NDIFF,
850 DOCTEST_REPORT_CHOICE_NDIFF: doctest.REPORT_NDIFF,
851 DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE: doctest.REPORT_ONLY_FIRST_FAILURE,
851 DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE: doctest.REPORT_ONLY_FIRST_FAILURE,
852 DOCTEST_REPORT_CHOICE_NONE: 0,
852 DOCTEST_REPORT_CHOICE_NONE: 0,
853 }[key]
853 }[key]
854
854
855
855
856 @pytest.fixture(scope="session")
856 @pytest.fixture(scope="session")
857 def ipdoctest_namespace() -> Dict[str, Any]:
857 def ipdoctest_namespace() -> Dict[str, Any]:
858 """Fixture that returns a :py:class:`dict` that will be injected into the
858 """Fixture that returns a :py:class:`dict` that will be injected into the
859 namespace of ipdoctests."""
859 namespace of ipdoctests."""
860 return dict()
860 return dict()
@@ -1,2 +1,2 b''
1 x = 1
1 x = 1
2 print('x is:',x)
2 print("x is:", x)
@@ -1,2 +1,2 b''
1 # GENERATED BY setup.py
1 # GENERATED BY setup.py
2 commit = u""
2 commit = ""
@@ -1,58 +1,83 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Decorators that don't go anywhere else.
2 """Decorators that don't go anywhere else.
3
3
4 This module contains misc. decorators that don't really go with another module
4 This module contains misc. decorators that don't really go with another module
5 in :mod:`IPython.utils`. Beore putting something here please see if it should
5 in :mod:`IPython.utils`. Before putting something here please see if it should
6 go into another topical module in :mod:`IPython.utils`.
6 go into another topical module in :mod:`IPython.utils`.
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2008-2011 The IPython Development Team
10 # Copyright (C) 2008-2011 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 from typing import Sequence
20
21 from IPython.utils.docs import GENERATING_DOCUMENTATION
22
19
23
20 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
21 # Code
25 # Code
22 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
23
27
24 def flag_calls(func):
28 def flag_calls(func):
25 """Wrap a function to detect and flag when it gets called.
29 """Wrap a function to detect and flag when it gets called.
26
30
27 This is a decorator which takes a function and wraps it in a function with
31 This is a decorator which takes a function and wraps it in a function with
28 a 'called' attribute. wrapper.called is initialized to False.
32 a 'called' attribute. wrapper.called is initialized to False.
29
33
30 The wrapper.called attribute is set to False right before each call to the
34 The wrapper.called attribute is set to False right before each call to the
31 wrapped function, so if the call fails it remains False. After the call
35 wrapped function, so if the call fails it remains False. After the call
32 completes, wrapper.called is set to True and the output is returned.
36 completes, wrapper.called is set to True and the output is returned.
33
37
34 Testing for truth in wrapper.called allows you to determine if a call to
38 Testing for truth in wrapper.called allows you to determine if a call to
35 func() was attempted and succeeded."""
39 func() was attempted and succeeded."""
36
40
37 # don't wrap twice
41 # don't wrap twice
38 if hasattr(func, 'called'):
42 if hasattr(func, 'called'):
39 return func
43 return func
40
44
41 def wrapper(*args,**kw):
45 def wrapper(*args,**kw):
42 wrapper.called = False
46 wrapper.called = False
43 out = func(*args,**kw)
47 out = func(*args,**kw)
44 wrapper.called = True
48 wrapper.called = True
45 return out
49 return out
46
50
47 wrapper.called = False
51 wrapper.called = False
48 wrapper.__doc__ = func.__doc__
52 wrapper.__doc__ = func.__doc__
49 return wrapper
53 return wrapper
50
54
55
51 def undoc(func):
56 def undoc(func):
52 """Mark a function or class as undocumented.
57 """Mark a function or class as undocumented.
53
58
54 This is found by inspecting the AST, so for now it must be used directly
59 This is found by inspecting the AST, so for now it must be used directly
55 as @undoc, not as e.g. @decorators.undoc
60 as @undoc, not as e.g. @decorators.undoc
56 """
61 """
57 return func
62 return func
58
63
64
65 def sphinx_options(
66 show_inheritance: bool = True,
67 show_inherited_members: bool = False,
68 exclude_inherited_from: Sequence[str] = tuple(),
69 ):
70 """Set sphinx options"""
71
72 def wrapper(func):
73 if not GENERATING_DOCUMENTATION:
74 return func
75
76 func._sphinx_options = dict(
77 show_inheritance=show_inheritance,
78 show_inherited_members=show_inherited_members,
79 exclude_inherited_from=exclude_inherited_from,
80 )
81 return func
82
83 return wrapper
@@ -1,129 +1,141 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for working with terminals.
3 Utilities for working with terminals.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian E. Granger
7 * Brian E. Granger
8 * Fernando Perez
8 * Fernando Perez
9 * Alexander Belchenko (e-mail: bialix AT ukr.net)
9 * Alexander Belchenko (e-mail: bialix AT ukr.net)
10 """
10 """
11
11
12 # Copyright (c) IPython Development Team.
12 # Copyright (c) IPython Development Team.
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14
14
15 import os
15 import os
16 import sys
16 import sys
17 import warnings
17 import warnings
18 from shutil import get_terminal_size as _get_terminal_size
18 from shutil import get_terminal_size as _get_terminal_size
19
19
20 # This variable is part of the expected API of the module:
20 # This variable is part of the expected API of the module:
21 ignore_termtitle = True
21 ignore_termtitle = True
22
22
23
23
24
24
25 if os.name == 'posix':
25 if os.name == 'posix':
26 def _term_clear():
26 def _term_clear():
27 os.system('clear')
27 os.system('clear')
28 elif sys.platform == 'win32':
28 elif sys.platform == 'win32':
29 def _term_clear():
29 def _term_clear():
30 os.system('cls')
30 os.system('cls')
31 else:
31 else:
32 def _term_clear():
32 def _term_clear():
33 pass
33 pass
34
34
35
35
36
36
37 def toggle_set_term_title(val):
37 def toggle_set_term_title(val):
38 """Control whether set_term_title is active or not.
38 """Control whether set_term_title is active or not.
39
39
40 set_term_title() allows writing to the console titlebar. In embedded
40 set_term_title() allows writing to the console titlebar. In embedded
41 widgets this can cause problems, so this call can be used to toggle it on
41 widgets this can cause problems, so this call can be used to toggle it on
42 or off as needed.
42 or off as needed.
43
43
44 The default state of the module is for the function to be disabled.
44 The default state of the module is for the function to be disabled.
45
45
46 Parameters
46 Parameters
47 ----------
47 ----------
48 val : bool
48 val : bool
49 If True, set_term_title() actually writes to the terminal (using the
49 If True, set_term_title() actually writes to the terminal (using the
50 appropriate platform-specific module). If False, it is a no-op.
50 appropriate platform-specific module). If False, it is a no-op.
51 """
51 """
52 global ignore_termtitle
52 global ignore_termtitle
53 ignore_termtitle = not(val)
53 ignore_termtitle = not(val)
54
54
55
55
56 def _set_term_title(*args,**kw):
56 def _set_term_title(*args,**kw):
57 """Dummy no-op."""
57 """Dummy no-op."""
58 pass
58 pass
59
59
60
60
61 def _restore_term_title():
61 def _restore_term_title():
62 pass
62 pass
63
63
64
64
65 _xterm_term_title_saved = False
66
67
65 def _set_term_title_xterm(title):
68 def _set_term_title_xterm(title):
66 """ Change virtual terminal title in xterm-workalikes """
69 """ Change virtual terminal title in xterm-workalikes """
67 # save the current title to the xterm "stack"
70 global _xterm_term_title_saved
68 sys.stdout.write('\033[22;0t')
71 # Only save the title the first time we set, otherwise restore will only
72 # go back one title (probably undoing a %cd title change).
73 if not _xterm_term_title_saved:
74 # save the current title to the xterm "stack"
75 sys.stdout.write("\033[22;0t")
76 _xterm_term_title_saved = True
69 sys.stdout.write('\033]0;%s\007' % title)
77 sys.stdout.write('\033]0;%s\007' % title)
70
78
71
79
72 def _restore_term_title_xterm():
80 def _restore_term_title_xterm():
81 # Make sure the restore has at least one accompanying set.
82 global _xterm_term_title_saved
83 assert _xterm_term_title_saved
73 sys.stdout.write('\033[23;0t')
84 sys.stdout.write('\033[23;0t')
85 _xterm_term_title_saved = False
74
86
75
87
76 if os.name == 'posix':
88 if os.name == 'posix':
77 TERM = os.environ.get('TERM','')
89 TERM = os.environ.get('TERM','')
78 if TERM.startswith('xterm'):
90 if TERM.startswith('xterm'):
79 _set_term_title = _set_term_title_xterm
91 _set_term_title = _set_term_title_xterm
80 _restore_term_title = _restore_term_title_xterm
92 _restore_term_title = _restore_term_title_xterm
81 elif sys.platform == 'win32':
93 elif sys.platform == 'win32':
82 try:
94 try:
83 import ctypes
95 import ctypes
84
96
85 SetConsoleTitleW = ctypes.windll.kernel32.SetConsoleTitleW
97 SetConsoleTitleW = ctypes.windll.kernel32.SetConsoleTitleW
86 SetConsoleTitleW.argtypes = [ctypes.c_wchar_p]
98 SetConsoleTitleW.argtypes = [ctypes.c_wchar_p]
87
99
88 def _set_term_title(title):
100 def _set_term_title(title):
89 """Set terminal title using ctypes to access the Win32 APIs."""
101 """Set terminal title using ctypes to access the Win32 APIs."""
90 SetConsoleTitleW(title)
102 SetConsoleTitleW(title)
91 except ImportError:
103 except ImportError:
92 def _set_term_title(title):
104 def _set_term_title(title):
93 """Set terminal title using the 'title' command."""
105 """Set terminal title using the 'title' command."""
94 global ignore_termtitle
106 global ignore_termtitle
95
107
96 try:
108 try:
97 # Cannot be on network share when issuing system commands
109 # Cannot be on network share when issuing system commands
98 curr = os.getcwd()
110 curr = os.getcwd()
99 os.chdir("C:")
111 os.chdir("C:")
100 ret = os.system("title " + title)
112 ret = os.system("title " + title)
101 finally:
113 finally:
102 os.chdir(curr)
114 os.chdir(curr)
103 if ret:
115 if ret:
104 # non-zero return code signals error, don't try again
116 # non-zero return code signals error, don't try again
105 ignore_termtitle = True
117 ignore_termtitle = True
106
118
107
119
108 def set_term_title(title):
120 def set_term_title(title):
109 """Set terminal title using the necessary platform-dependent calls."""
121 """Set terminal title using the necessary platform-dependent calls."""
110 if ignore_termtitle:
122 if ignore_termtitle:
111 return
123 return
112 _set_term_title(title)
124 _set_term_title(title)
113
125
114
126
115 def restore_term_title():
127 def restore_term_title():
116 """Restore, if possible, terminal title to the original state"""
128 """Restore, if possible, terminal title to the original state"""
117 if ignore_termtitle:
129 if ignore_termtitle:
118 return
130 return
119 _restore_term_title()
131 _restore_term_title()
120
132
121
133
122 def freeze_term_title():
134 def freeze_term_title():
123 warnings.warn("This function is deprecated, use toggle_set_term_title()")
135 warnings.warn("This function is deprecated, use toggle_set_term_title()")
124 global ignore_termtitle
136 global ignore_termtitle
125 ignore_termtitle = True
137 ignore_termtitle = True
126
138
127
139
128 def get_terminal_size(defaultx=80, defaulty=25):
140 def get_terminal_size(defaultx=80, defaulty=25):
129 return _get_terminal_size((defaultx, defaulty))
141 return _get_terminal_size((defaultx, defaulty))
@@ -1,67 +1,66 b''
1 from IPython.utils.dir2 import dir2
1 from IPython.utils.dir2 import dir2
2
2
3 import pytest
3 import pytest
4
4
5
5
6 class Base(object):
6 class Base(object):
7 x = 1
7 x = 1
8 z = 23
8 z = 23
9
9
10
10
11 def test_base():
11 def test_base():
12 res = dir2(Base())
12 res = dir2(Base())
13 assert "x" in res
13 assert "x" in res
14 assert "z" in res
14 assert "z" in res
15 assert "y" not in res
15 assert "y" not in res
16 assert "__class__" in res
16 assert "__class__" in res
17 assert res.count("x") == 1
17 assert res.count("x") == 1
18 assert res.count("__class__") == 1
18 assert res.count("__class__") == 1
19
19
20
20
21 def test_SubClass():
21 def test_SubClass():
22
23 class SubClass(Base):
22 class SubClass(Base):
24 y = 2
23 y = 2
25
24
26 res = dir2(SubClass())
25 res = dir2(SubClass())
27 assert "y" in res
26 assert "y" in res
28 assert res.count("y") == 1
27 assert res.count("y") == 1
29 assert res.count("x") == 1
28 assert res.count("x") == 1
30
29
31
30
32 def test_SubClass_with_trait_names_attr():
31 def test_SubClass_with_trait_names_attr():
33 # usecase: trait_names is used in a class describing psychological classification
32 # usecase: trait_names is used in a class describing psychological classification
34
33
35 class SubClass(Base):
34 class SubClass(Base):
36 y = 2
35 y = 2
37 trait_names = 44
36 trait_names = 44
38
37
39 res = dir2(SubClass())
38 res = dir2(SubClass())
40 assert "trait_names" in res
39 assert "trait_names" in res
41
40
42
41
43 def test_misbehaving_object_without_trait_names():
42 def test_misbehaving_object_without_trait_names():
44 # dir2 shouldn't raise even when objects are dumb and raise
43 # dir2 shouldn't raise even when objects are dumb and raise
45 # something other than AttribteErrors on bad getattr.
44 # something other than AttribteErrors on bad getattr.
46
45
47 class MisbehavingGetattr:
46 class MisbehavingGetattr:
48 def __getattr__(self, attr):
47 def __getattr__(self, attr):
49 raise KeyError("I should be caught")
48 raise KeyError("I should be caught")
50
49
51 def some_method(self):
50 def some_method(self):
52 return True
51 return True
53
52
54 class SillierWithDir(MisbehavingGetattr):
53 class SillierWithDir(MisbehavingGetattr):
55 def __dir__(self):
54 def __dir__(self):
56 return ['some_method']
55 return ["some_method"]
57
56
58 for bad_klass in (MisbehavingGetattr, SillierWithDir):
57 for bad_klass in (MisbehavingGetattr, SillierWithDir):
59 obj = bad_klass()
58 obj = bad_klass()
60
59
61 assert obj.some_method()
60 assert obj.some_method()
62
61
63 with pytest.raises(KeyError):
62 with pytest.raises(KeyError):
64 obj.other_method()
63 obj.other_method()
65
64
66 res = dir2(obj)
65 res = dir2(obj)
67 assert "some_method" in res
66 assert "some_method" in res
@@ -1,174 +1,174 b''
1 .. image:: https://codecov.io/github/ipython/ipython/coverage.svg?branch=main
1 .. image:: https://codecov.io/github/ipython/ipython/coverage.svg?branch=main
2 :target: https://codecov.io/github/ipython/ipython?branch=main
2 :target: https://codecov.io/github/ipython/ipython?branch=main
3
3
4 .. image:: https://img.shields.io/pypi/v/IPython.svg
4 .. image:: https://img.shields.io/pypi/v/IPython.svg
5 :target: https://pypi.python.org/pypi/ipython
5 :target: https://pypi.python.org/pypi/ipython
6
6
7 .. image:: https://github.com/ipython/ipython/actions/workflows/test.yml/badge.svg
7 .. image:: https://github.com/ipython/ipython/actions/workflows/test.yml/badge.svg
8 :target: https://github.com/ipython/ipython/actions/workflows/test.yml)
8 :target: https://github.com/ipython/ipython/actions/workflows/test.yml)
9
9
10 .. image:: https://www.codetriage.com/ipython/ipython/badges/users.svg
10 .. image:: https://www.codetriage.com/ipython/ipython/badges/users.svg
11 :target: https://www.codetriage.com/ipython/ipython/
11 :target: https://www.codetriage.com/ipython/ipython/
12
12
13 .. image:: https://raster.shields.io/badge/Follows-NEP29-brightgreen.png
13 .. image:: https://raster.shields.io/badge/Follows-NEP29-brightgreen.png
14 :target: https://numpy.org/neps/nep-0029-deprecation_policy.html
14 :target: https://numpy.org/neps/nep-0029-deprecation_policy.html
15
15
16 .. image:: https://tidelift.com/subscription/pkg/pypi-ipython
16 .. image:: https://tidelift.com/badges/package/pypi/ipython?style=flat
17 :target: https://tidelift.com/badges/package/pypi/ipython?style=flat
17 :target: https://tidelift.com/subscription/pkg/pypi-ipython
18
18
19
19
20 ===========================================
20 ===========================================
21 IPython: Productive Interactive Computing
21 IPython: Productive Interactive Computing
22 ===========================================
22 ===========================================
23
23
24 Overview
24 Overview
25 ========
25 ========
26
26
27 Welcome to IPython. Our full documentation is available on `ipython.readthedocs.io
27 Welcome to IPython. Our full documentation is available on `ipython.readthedocs.io
28 <https://ipython.readthedocs.io/en/stable/>`_ and contains information on how to install, use, and
28 <https://ipython.readthedocs.io/en/stable/>`_ and contains information on how to install, use, and
29 contribute to the project.
29 contribute to the project.
30 IPython (Interactive Python) is a command shell for interactive computing in multiple programming languages, originally developed for the Python programming language, that offers introspection, rich media, shell syntax, tab completion, and history.
30 IPython (Interactive Python) is a command shell for interactive computing in multiple programming languages, originally developed for the Python programming language, that offers introspection, rich media, shell syntax, tab completion, and history.
31
31
32 **IPython versions and Python Support**
32 **IPython versions and Python Support**
33
33
34 Starting with IPython 7.10, IPython follows `NEP 29 <https://numpy.org/neps/nep-0029-deprecation_policy.html>`_
34 Starting with IPython 7.10, IPython follows `NEP 29 <https://numpy.org/neps/nep-0029-deprecation_policy.html>`_
35
35
36 **IPython 7.17+** requires Python version 3.7 and above.
36 **IPython 7.17+** requires Python version 3.7 and above.
37
37
38 **IPython 7.10+** requires Python version 3.6 and above.
38 **IPython 7.10+** requires Python version 3.6 and above.
39
39
40 **IPython 7.0** requires Python version 3.5 and above.
40 **IPython 7.0** requires Python version 3.5 and above.
41
41
42 **IPython 6.x** requires Python version 3.3 and above.
42 **IPython 6.x** requires Python version 3.3 and above.
43
43
44 **IPython 5.x LTS** is the compatible release for Python 2.7.
44 **IPython 5.x LTS** is the compatible release for Python 2.7.
45 If you require Python 2 support, you **must** use IPython 5.x LTS. Please
45 If you require Python 2 support, you **must** use IPython 5.x LTS. Please
46 update your project configurations and requirements as necessary.
46 update your project configurations and requirements as necessary.
47
47
48
48
49 The Notebook, Qt console and a number of other pieces are now parts of *Jupyter*.
49 The Notebook, Qt console and a number of other pieces are now parts of *Jupyter*.
50 See the `Jupyter installation docs <https://jupyter.readthedocs.io/en/latest/install.html>`__
50 See the `Jupyter installation docs <https://jupyter.readthedocs.io/en/latest/install.html>`__
51 if you want to use these.
51 if you want to use these.
52
52
53 Main features of IPython
53 Main features of IPython
54 ========================
54 ========================
55 Comprehensive object introspection.
55 Comprehensive object introspection.
56
56
57 Input history, persistent across sessions.
57 Input history, persistent across sessions.
58
58
59 Caching of output results during a session with automatically generated references.
59 Caching of output results during a session with automatically generated references.
60
60
61 Extensible tab completion, with support by default for completion of python variables and keywords, filenames and function keywords.
61 Extensible tab completion, with support by default for completion of python variables and keywords, filenames and function keywords.
62
62
63 Extensible system of ‘magic’ commands for controlling the environment and performing many tasks related to IPython or the operating system.
63 Extensible system of ‘magic’ commands for controlling the environment and performing many tasks related to IPython or the operating system.
64
64
65 A rich configuration system with easy switching between different setups (simpler than changing $PYTHONSTARTUP environment variables every time).
65 A rich configuration system with easy switching between different setups (simpler than changing $PYTHONSTARTUP environment variables every time).
66
66
67 Session logging and reloading.
67 Session logging and reloading.
68
68
69 Extensible syntax processing for special purpose situations.
69 Extensible syntax processing for special purpose situations.
70
70
71 Access to the system shell with user-extensible alias system.
71 Access to the system shell with user-extensible alias system.
72
72
73 Easily embeddable in other Python programs and GUIs.
73 Easily embeddable in other Python programs and GUIs.
74
74
75 Integrated access to the pdb debugger and the Python profiler.
75 Integrated access to the pdb debugger and the Python profiler.
76
76
77
77
78 Development and Instant running
78 Development and Instant running
79 ===============================
79 ===============================
80
80
81 You can find the latest version of the development documentation on `readthedocs
81 You can find the latest version of the development documentation on `readthedocs
82 <https://ipython.readthedocs.io/en/latest/>`_.
82 <https://ipython.readthedocs.io/en/latest/>`_.
83
83
84 You can run IPython from this directory without even installing it system-wide
84 You can run IPython from this directory without even installing it system-wide
85 by typing at the terminal::
85 by typing at the terminal::
86
86
87 $ python -m IPython
87 $ python -m IPython
88
88
89 Or see the `development installation docs
89 Or see the `development installation docs
90 <https://ipython.readthedocs.io/en/latest/install/install.html#installing-the-development-version>`_
90 <https://ipython.readthedocs.io/en/latest/install/install.html#installing-the-development-version>`_
91 for the latest revision on read the docs.
91 for the latest revision on read the docs.
92
92
93 Documentation and installation instructions for older version of IPython can be
93 Documentation and installation instructions for older version of IPython can be
94 found on the `IPython website <https://ipython.org/documentation.html>`_
94 found on the `IPython website <https://ipython.org/documentation.html>`_
95
95
96
96
97
97
98 IPython requires Python version 3 or above
98 IPython requires Python version 3 or above
99 ==========================================
99 ==========================================
100
100
101 Starting with version 6.0, IPython does not support Python 2.7, 3.0, 3.1, or
101 Starting with version 6.0, IPython does not support Python 2.7, 3.0, 3.1, or
102 3.2.
102 3.2.
103
103
104 For a version compatible with Python 2.7, please install the 5.x LTS Long Term
104 For a version compatible with Python 2.7, please install the 5.x LTS Long Term
105 Support version.
105 Support version.
106
106
107 If you are encountering this error message you are likely trying to install or
107 If you are encountering this error message you are likely trying to install or
108 use IPython from source. You need to checkout the remote 5.x branch. If you are
108 use IPython from source. You need to checkout the remote 5.x branch. If you are
109 using git the following should work::
109 using git the following should work::
110
110
111 $ git fetch origin
111 $ git fetch origin
112 $ git checkout 5.x
112 $ git checkout 5.x
113
113
114 If you encounter this error message with a regular install of IPython, then you
114 If you encounter this error message with a regular install of IPython, then you
115 likely need to update your package manager, for example if you are using `pip`
115 likely need to update your package manager, for example if you are using `pip`
116 check the version of pip with::
116 check the version of pip with::
117
117
118 $ pip --version
118 $ pip --version
119
119
120 You will need to update pip to the version 9.0.1 or greater. If you are not using
120 You will need to update pip to the version 9.0.1 or greater. If you are not using
121 pip, please inquiry with the maintainers of the package for your package
121 pip, please inquiry with the maintainers of the package for your package
122 manager.
122 manager.
123
123
124 For more information see one of our blog posts:
124 For more information see one of our blog posts:
125
125
126 https://blog.jupyter.org/release-of-ipython-5-0-8ce60b8d2e8e
126 https://blog.jupyter.org/release-of-ipython-5-0-8ce60b8d2e8e
127
127
128 As well as the following Pull-Request for discussion:
128 As well as the following Pull-Request for discussion:
129
129
130 https://github.com/ipython/ipython/pull/9900
130 https://github.com/ipython/ipython/pull/9900
131
131
132 This error does also occur if you are invoking ``setup.py`` directly – which you
132 This error does also occur if you are invoking ``setup.py`` directly – which you
133 should not – or are using ``easy_install`` If this is the case, use ``pip
133 should not – or are using ``easy_install`` If this is the case, use ``pip
134 install .`` instead of ``setup.py install`` , and ``pip install -e .`` instead
134 install .`` instead of ``setup.py install`` , and ``pip install -e .`` instead
135 of ``setup.py develop`` If you are depending on IPython as a dependency you may
135 of ``setup.py develop`` If you are depending on IPython as a dependency you may
136 also want to have a conditional dependency on IPython depending on the Python
136 also want to have a conditional dependency on IPython depending on the Python
137 version::
137 version::
138
138
139 install_req = ['ipython']
139 install_req = ['ipython']
140 if sys.version_info[0] < 3 and 'bdist_wheel' not in sys.argv:
140 if sys.version_info[0] < 3 and 'bdist_wheel' not in sys.argv:
141 install_req.remove('ipython')
141 install_req.remove('ipython')
142 install_req.append('ipython<6')
142 install_req.append('ipython<6')
143
143
144 setup(
144 setup(
145 ...
145 ...
146 install_requires=install_req
146 install_requires=install_req
147 )
147 )
148
148
149 Alternatives to IPython
149 Alternatives to IPython
150 =======================
150 =======================
151
151
152 IPython may not be to your taste; if that's the case there might be similar
152 IPython may not be to your taste; if that's the case there might be similar
153 project that you might want to use:
153 project that you might want to use:
154
154
155 - The classic Python REPL.
155 - The classic Python REPL.
156 - `bpython <https://bpython-interpreter.org/>`_
156 - `bpython <https://bpython-interpreter.org/>`_
157 - `mypython <https://www.asmeurer.com/mypython/>`_
157 - `mypython <https://www.asmeurer.com/mypython/>`_
158 - `ptpython and ptipython <https://pypi.org/project/ptpython/>`_
158 - `ptpython and ptipython <https://pypi.org/project/ptpython/>`_
159 - `Xonsh <https://xon.sh/>`_
159 - `Xonsh <https://xon.sh/>`_
160
160
161 Ignoring commits with git blame.ignoreRevsFile
161 Ignoring commits with git blame.ignoreRevsFile
162 ==============================================
162 ==============================================
163
163
164 As of git 2.23, it is possible to make formatting changes without breaking
164 As of git 2.23, it is possible to make formatting changes without breaking
165 ``git blame``. See the `git documentation
165 ``git blame``. See the `git documentation
166 <https://git-scm.com/docs/git-config#Documentation/git-config.txt-blameignoreRevsFile>`_
166 <https://git-scm.com/docs/git-config#Documentation/git-config.txt-blameignoreRevsFile>`_
167 for more details.
167 for more details.
168
168
169 To use this feature you must:
169 To use this feature you must:
170
170
171 - Install git >= 2.23
171 - Install git >= 2.23
172 - Configure your local git repo by running:
172 - Configure your local git repo by running:
173 - POSIX: ``tools\configure-git-blame-ignore-revs.sh``
173 - POSIX: ``tools\configure-git-blame-ignore-revs.sh``
174 - Windows: ``tools\configure-git-blame-ignore-revs.bat``
174 - Windows: ``tools\configure-git-blame-ignore-revs.bat``
@@ -1,326 +1,334 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 #
2 #
3 # IPython documentation build configuration file.
3 # IPython documentation build configuration file.
4
4
5 # NOTE: This file has been edited manually from the auto-generated one from
5 # NOTE: This file has been edited manually from the auto-generated one from
6 # sphinx. Do NOT delete and re-generate. If any changes from sphinx are
6 # sphinx. Do NOT delete and re-generate. If any changes from sphinx are
7 # needed, generate a scratch one and merge by hand any new fields needed.
7 # needed, generate a scratch one and merge by hand any new fields needed.
8
8
9 #
9 #
10 # This file is execfile()d with the current directory set to its containing dir.
10 # This file is execfile()d with the current directory set to its containing dir.
11 #
11 #
12 # The contents of this file are pickled, so don't put values in the namespace
12 # The contents of this file are pickled, so don't put values in the namespace
13 # that aren't pickleable (module imports are okay, they're removed automatically).
13 # that aren't pickleable (module imports are okay, they're removed automatically).
14 #
14 #
15 # All configuration values have a default value; values that are commented out
15 # All configuration values have a default value; values that are commented out
16 # serve to show the default value.
16 # serve to show the default value.
17
17
18 import sys, os
18 import sys, os
19 from pathlib import Path
19 from pathlib import Path
20
20
21 # https://read-the-docs.readthedocs.io/en/latest/faq.html
21 # https://read-the-docs.readthedocs.io/en/latest/faq.html
22 ON_RTD = os.environ.get('READTHEDOCS', None) == 'True'
22 ON_RTD = os.environ.get('READTHEDOCS', None) == 'True'
23
23
24 if ON_RTD:
24 if ON_RTD:
25 tags.add('rtd')
25 tags.add('rtd')
26
26
27 # RTD doesn't use the Makefile, so re-run autogen_{things}.py here.
27 # RTD doesn't use the Makefile, so re-run autogen_{things}.py here.
28 for name in ("config", "api", "magics", "shortcuts"):
28 for name in ("config", "api", "magics", "shortcuts"):
29 fname = Path("autogen_{}.py".format(name))
29 fname = Path("autogen_{}.py".format(name))
30 fpath = (Path(__file__).parent).joinpath("..", fname)
30 fpath = (Path(__file__).parent).joinpath("..", fname)
31 with open(fpath, encoding="utf-8") as f:
31 with open(fpath, encoding="utf-8") as f:
32 exec(
32 exec(
33 compile(f.read(), fname, "exec"),
33 compile(f.read(), fname, "exec"),
34 {
34 {
35 "__file__": fpath,
35 "__file__": fpath,
36 "__name__": "__main__",
36 "__name__": "__main__",
37 },
37 },
38 )
38 )
39 else:
39 else:
40 import sphinx_rtd_theme
40 import sphinx_rtd_theme
41 html_theme = "sphinx_rtd_theme"
41 html_theme = "sphinx_rtd_theme"
42 html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
42 html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
43
43
44 # Allow Python scripts to change behaviour during sphinx run
45 os.environ["IN_SPHINX_RUN"] = "True"
46
47 autodoc_type_aliases = {
48 "Matcher": " IPython.core.completer.Matcher",
49 "MatcherAPIv1": " IPython.core.completer.MatcherAPIv1",
50 }
51
44 # If your extensions are in another directory, add it here. If the directory
52 # If your extensions are in another directory, add it here. If the directory
45 # is relative to the documentation root, use os.path.abspath to make it
53 # is relative to the documentation root, use os.path.abspath to make it
46 # absolute, like shown here.
54 # absolute, like shown here.
47 sys.path.insert(0, os.path.abspath('../sphinxext'))
55 sys.path.insert(0, os.path.abspath('../sphinxext'))
48
56
49 # We load the ipython release info into a dict by explicit execution
57 # We load the ipython release info into a dict by explicit execution
50 iprelease = {}
58 iprelease = {}
51 exec(
59 exec(
52 compile(
60 compile(
53 open("../../IPython/core/release.py", encoding="utf-8").read(),
61 open("../../IPython/core/release.py", encoding="utf-8").read(),
54 "../../IPython/core/release.py",
62 "../../IPython/core/release.py",
55 "exec",
63 "exec",
56 ),
64 ),
57 iprelease,
65 iprelease,
58 )
66 )
59
67
60 # General configuration
68 # General configuration
61 # ---------------------
69 # ---------------------
62
70
63 # Add any Sphinx extension module names here, as strings. They can be extensions
71 # Add any Sphinx extension module names here, as strings. They can be extensions
64 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
72 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
65 extensions = [
73 extensions = [
66 'sphinx.ext.autodoc',
74 'sphinx.ext.autodoc',
67 'sphinx.ext.autosummary',
75 'sphinx.ext.autosummary',
68 'sphinx.ext.doctest',
76 'sphinx.ext.doctest',
69 'sphinx.ext.inheritance_diagram',
77 'sphinx.ext.inheritance_diagram',
70 'sphinx.ext.intersphinx',
78 'sphinx.ext.intersphinx',
71 'sphinx.ext.graphviz',
79 'sphinx.ext.graphviz',
72 'IPython.sphinxext.ipython_console_highlighting',
80 'IPython.sphinxext.ipython_console_highlighting',
73 'IPython.sphinxext.ipython_directive',
81 'IPython.sphinxext.ipython_directive',
74 'sphinx.ext.napoleon', # to preprocess docstrings
82 'sphinx.ext.napoleon', # to preprocess docstrings
75 'github', # for easy GitHub links
83 'github', # for easy GitHub links
76 'magics',
84 'magics',
77 'configtraits',
85 'configtraits',
78 ]
86 ]
79
87
80 # Add any paths that contain templates here, relative to this directory.
88 # Add any paths that contain templates here, relative to this directory.
81 templates_path = ['_templates']
89 templates_path = ['_templates']
82
90
83 # The suffix of source filenames.
91 # The suffix of source filenames.
84 source_suffix = '.rst'
92 source_suffix = '.rst'
85
93
86 rst_prolog = ''
94 rst_prolog = ''
87
95
88 def is_stable(extra):
96 def is_stable(extra):
89 for ext in {'dev', 'b', 'rc'}:
97 for ext in {'dev', 'b', 'rc'}:
90 if ext in extra:
98 if ext in extra:
91 return False
99 return False
92 return True
100 return True
93
101
94 if is_stable(iprelease['_version_extra']):
102 if is_stable(iprelease['_version_extra']):
95 tags.add('ipystable')
103 tags.add('ipystable')
96 print('Adding Tag: ipystable')
104 print('Adding Tag: ipystable')
97 else:
105 else:
98 tags.add('ipydev')
106 tags.add('ipydev')
99 print('Adding Tag: ipydev')
107 print('Adding Tag: ipydev')
100 rst_prolog += """
108 rst_prolog += """
101 .. warning::
109 .. warning::
102
110
103 This documentation covers a development version of IPython. The development
111 This documentation covers a development version of IPython. The development
104 version may differ significantly from the latest stable release.
112 version may differ significantly from the latest stable release.
105 """
113 """
106
114
107 rst_prolog += """
115 rst_prolog += """
108 .. important::
116 .. important::
109
117
110 This documentation covers IPython versions 6.0 and higher. Beginning with
118 This documentation covers IPython versions 6.0 and higher. Beginning with
111 version 6.0, IPython stopped supporting compatibility with Python versions
119 version 6.0, IPython stopped supporting compatibility with Python versions
112 lower than 3.3 including all versions of Python 2.7.
120 lower than 3.3 including all versions of Python 2.7.
113
121
114 If you are looking for an IPython version compatible with Python 2.7,
122 If you are looking for an IPython version compatible with Python 2.7,
115 please use the IPython 5.x LTS release and refer to its documentation (LTS
123 please use the IPython 5.x LTS release and refer to its documentation (LTS
116 is the long term support release).
124 is the long term support release).
117
125
118 """
126 """
119
127
120 # The master toctree document.
128 # The master toctree document.
121 master_doc = 'index'
129 master_doc = 'index'
122
130
123 # General substitutions.
131 # General substitutions.
124 project = 'IPython'
132 project = 'IPython'
125 copyright = 'The IPython Development Team'
133 copyright = 'The IPython Development Team'
126
134
127 # ghissue config
135 # ghissue config
128 github_project_url = "https://github.com/ipython/ipython"
136 github_project_url = "https://github.com/ipython/ipython"
129
137
130 # numpydoc config
138 # numpydoc config
131 numpydoc_show_class_members = False # Otherwise Sphinx emits thousands of warnings
139 numpydoc_show_class_members = False # Otherwise Sphinx emits thousands of warnings
132 numpydoc_class_members_toctree = False
140 numpydoc_class_members_toctree = False
133 warning_is_error = True
141 warning_is_error = True
134
142
135 import logging
143 import logging
136
144
137 class ConfigtraitFilter(logging.Filter):
145 class ConfigtraitFilter(logging.Filter):
138 """
146 """
139 This is a filter to remove in sphinx 3+ the error about config traits being duplicated.
147 This is a filter to remove in sphinx 3+ the error about config traits being duplicated.
140
148
141 As we autogenerate configuration traits from, subclasses have lots of
149 As we autogenerate configuration traits from, subclasses have lots of
142 duplication and we want to silence them. Indeed we build on travis with
150 duplication and we want to silence them. Indeed we build on travis with
143 warnings-as-error set to True, so those duplicate items make the build fail.
151 warnings-as-error set to True, so those duplicate items make the build fail.
144 """
152 """
145
153
146 def filter(self, record):
154 def filter(self, record):
147 if record.args and record.args[0] == 'configtrait' and 'duplicate' in record.msg:
155 if record.args and record.args[0] == 'configtrait' and 'duplicate' in record.msg:
148 return False
156 return False
149 return True
157 return True
150
158
151 ct_filter = ConfigtraitFilter()
159 ct_filter = ConfigtraitFilter()
152
160
153 import sphinx.util
161 import sphinx.util
154 logger = sphinx.util.logging.getLogger('sphinx.domains.std').logger
162 logger = sphinx.util.logging.getLogger('sphinx.domains.std').logger
155
163
156 logger.addFilter(ct_filter)
164 logger.addFilter(ct_filter)
157
165
158 # The default replacements for |version| and |release|, also used in various
166 # The default replacements for |version| and |release|, also used in various
159 # other places throughout the built documents.
167 # other places throughout the built documents.
160 #
168 #
161 # The full version, including alpha/beta/rc tags.
169 # The full version, including alpha/beta/rc tags.
162 release = "%s" % iprelease['version']
170 release = "%s" % iprelease['version']
163 # Just the X.Y.Z part, no '-dev'
171 # Just the X.Y.Z part, no '-dev'
164 version = iprelease['version'].split('-', 1)[0]
172 version = iprelease['version'].split('-', 1)[0]
165
173
166
174
167 # There are two options for replacing |today|: either, you set today to some
175 # There are two options for replacing |today|: either, you set today to some
168 # non-false value, then it is used:
176 # non-false value, then it is used:
169 #today = ''
177 #today = ''
170 # Else, today_fmt is used as the format for a strftime call.
178 # Else, today_fmt is used as the format for a strftime call.
171 today_fmt = '%B %d, %Y'
179 today_fmt = '%B %d, %Y'
172
180
173 # List of documents that shouldn't be included in the build.
181 # List of documents that shouldn't be included in the build.
174 #unused_docs = []
182 #unused_docs = []
175
183
176 # Exclude these glob-style patterns when looking for source files. They are
184 # Exclude these glob-style patterns when looking for source files. They are
177 # relative to the source/ directory.
185 # relative to the source/ directory.
178 exclude_patterns = []
186 exclude_patterns = []
179
187
180
188
181 # If true, '()' will be appended to :func: etc. cross-reference text.
189 # If true, '()' will be appended to :func: etc. cross-reference text.
182 #add_function_parentheses = True
190 #add_function_parentheses = True
183
191
184 # If true, the current module name will be prepended to all description
192 # If true, the current module name will be prepended to all description
185 # unit titles (such as .. function::).
193 # unit titles (such as .. function::).
186 #add_module_names = True
194 #add_module_names = True
187
195
188 # If true, sectionauthor and moduleauthor directives will be shown in the
196 # If true, sectionauthor and moduleauthor directives will be shown in the
189 # output. They are ignored by default.
197 # output. They are ignored by default.
190 #show_authors = False
198 #show_authors = False
191
199
192 # The name of the Pygments (syntax highlighting) style to use.
200 # The name of the Pygments (syntax highlighting) style to use.
193 pygments_style = 'sphinx'
201 pygments_style = 'sphinx'
194
202
195 # Set the default role so we can use `foo` instead of ``foo``
203 # Set the default role so we can use `foo` instead of ``foo``
196 default_role = 'literal'
204 default_role = 'literal'
197
205
198 # Options for HTML output
206 # Options for HTML output
199 # -----------------------
207 # -----------------------
200
208
201 # The style sheet to use for HTML and HTML Help pages. A file of that name
209 # The style sheet to use for HTML and HTML Help pages. A file of that name
202 # must exist either in Sphinx' static/ path, or in one of the custom paths
210 # must exist either in Sphinx' static/ path, or in one of the custom paths
203 # given in html_static_path.
211 # given in html_static_path.
204 # html_style = 'default.css'
212 # html_style = 'default.css'
205
213
206
214
207 # The name for this set of Sphinx documents. If None, it defaults to
215 # The name for this set of Sphinx documents. If None, it defaults to
208 # "<project> v<release> documentation".
216 # "<project> v<release> documentation".
209 #html_title = None
217 #html_title = None
210
218
211 # The name of an image file (within the static path) to place at the top of
219 # The name of an image file (within the static path) to place at the top of
212 # the sidebar.
220 # the sidebar.
213 #html_logo = None
221 #html_logo = None
214
222
215 # Add any paths that contain custom static files (such as style sheets) here,
223 # Add any paths that contain custom static files (such as style sheets) here,
216 # relative to this directory. They are copied after the builtin static files,
224 # relative to this directory. They are copied after the builtin static files,
217 # so a file named "default.css" will overwrite the builtin "default.css".
225 # so a file named "default.css" will overwrite the builtin "default.css".
218 html_static_path = ['_static']
226 html_static_path = ['_static']
219
227
220 # Favicon needs the directory name
228 # Favicon needs the directory name
221 html_favicon = '_static/favicon.ico'
229 html_favicon = '_static/favicon.ico'
222 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
230 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
223 # using the given strftime format.
231 # using the given strftime format.
224 html_last_updated_fmt = '%b %d, %Y'
232 html_last_updated_fmt = '%b %d, %Y'
225
233
226 # If true, SmartyPants will be used to convert quotes and dashes to
234 # If true, SmartyPants will be used to convert quotes and dashes to
227 # typographically correct entities.
235 # typographically correct entities.
228 #html_use_smartypants = True
236 #html_use_smartypants = True
229
237
230 # Custom sidebar templates, maps document names to template names.
238 # Custom sidebar templates, maps document names to template names.
231 #html_sidebars = {}
239 #html_sidebars = {}
232
240
233 # Additional templates that should be rendered to pages, maps page names to
241 # Additional templates that should be rendered to pages, maps page names to
234 # template names.
242 # template names.
235 html_additional_pages = {
243 html_additional_pages = {
236 'interactive/htmlnotebook': 'notebook_redirect.html',
244 'interactive/htmlnotebook': 'notebook_redirect.html',
237 'interactive/notebook': 'notebook_redirect.html',
245 'interactive/notebook': 'notebook_redirect.html',
238 'interactive/nbconvert': 'notebook_redirect.html',
246 'interactive/nbconvert': 'notebook_redirect.html',
239 'interactive/public_server': 'notebook_redirect.html',
247 'interactive/public_server': 'notebook_redirect.html',
240 }
248 }
241
249
242 # If false, no module index is generated.
250 # If false, no module index is generated.
243 #html_use_modindex = True
251 #html_use_modindex = True
244
252
245 # If true, the reST sources are included in the HTML build as _sources/<name>.
253 # If true, the reST sources are included in the HTML build as _sources/<name>.
246 #html_copy_source = True
254 #html_copy_source = True
247
255
248 # If true, an OpenSearch description file will be output, and all pages will
256 # If true, an OpenSearch description file will be output, and all pages will
249 # contain a <link> tag referring to it. The value of this option must be the
257 # contain a <link> tag referring to it. The value of this option must be the
250 # base URL from which the finished HTML is served.
258 # base URL from which the finished HTML is served.
251 #html_use_opensearch = ''
259 #html_use_opensearch = ''
252
260
253 # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
261 # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
254 #html_file_suffix = ''
262 #html_file_suffix = ''
255
263
256 # Output file base name for HTML help builder.
264 # Output file base name for HTML help builder.
257 htmlhelp_basename = 'ipythondoc'
265 htmlhelp_basename = 'ipythondoc'
258
266
259 intersphinx_mapping = {'python': ('https://docs.python.org/3/', None),
267 intersphinx_mapping = {'python': ('https://docs.python.org/3/', None),
260 'rpy2': ('https://rpy2.github.io/doc/latest/html/', None),
268 'rpy2': ('https://rpy2.github.io/doc/latest/html/', None),
261 'jupyterclient': ('https://jupyter-client.readthedocs.io/en/latest/', None),
269 'jupyterclient': ('https://jupyter-client.readthedocs.io/en/latest/', None),
262 'jupyter': ('https://jupyter.readthedocs.io/en/latest/', None),
270 'jupyter': ('https://jupyter.readthedocs.io/en/latest/', None),
263 'jedi': ('https://jedi.readthedocs.io/en/latest/', None),
271 'jedi': ('https://jedi.readthedocs.io/en/latest/', None),
264 'traitlets': ('https://traitlets.readthedocs.io/en/latest/', None),
272 'traitlets': ('https://traitlets.readthedocs.io/en/latest/', None),
265 'ipykernel': ('https://ipykernel.readthedocs.io/en/latest/', None),
273 'ipykernel': ('https://ipykernel.readthedocs.io/en/latest/', None),
266 'prompt_toolkit' : ('https://python-prompt-toolkit.readthedocs.io/en/stable/', None),
274 'prompt_toolkit' : ('https://python-prompt-toolkit.readthedocs.io/en/stable/', None),
267 'ipywidgets': ('https://ipywidgets.readthedocs.io/en/stable/', None),
275 'ipywidgets': ('https://ipywidgets.readthedocs.io/en/stable/', None),
268 'ipyparallel': ('https://ipyparallel.readthedocs.io/en/stable/', None),
276 'ipyparallel': ('https://ipyparallel.readthedocs.io/en/stable/', None),
269 'pip': ('https://pip.pypa.io/en/stable/', None)
277 'pip': ('https://pip.pypa.io/en/stable/', None)
270 }
278 }
271
279
272 # Options for LaTeX output
280 # Options for LaTeX output
273 # ------------------------
281 # ------------------------
274
282
275 # The font size ('10pt', '11pt' or '12pt').
283 # The font size ('10pt', '11pt' or '12pt').
276 latex_font_size = '11pt'
284 latex_font_size = '11pt'
277
285
278 # Grouping the document tree into LaTeX files. List of tuples
286 # Grouping the document tree into LaTeX files. List of tuples
279 # (source start file, target name, title, author, document class [howto/manual]).
287 # (source start file, target name, title, author, document class [howto/manual]).
280
288
281 latex_documents = [
289 latex_documents = [
282 ('index', 'ipython.tex', 'IPython Documentation',
290 ('index', 'ipython.tex', 'IPython Documentation',
283 u"""The IPython Development Team""", 'manual', True),
291 u"""The IPython Development Team""", 'manual', True),
284 ('parallel/winhpc_index', 'winhpc_whitepaper.tex',
292 ('parallel/winhpc_index', 'winhpc_whitepaper.tex',
285 'Using IPython on Windows HPC Server 2008',
293 'Using IPython on Windows HPC Server 2008',
286 u"Brian E. Granger", 'manual', True)
294 u"Brian E. Granger", 'manual', True)
287 ]
295 ]
288
296
289 # The name of an image file (relative to this directory) to place at the top of
297 # The name of an image file (relative to this directory) to place at the top of
290 # the title page.
298 # the title page.
291 #latex_logo = None
299 #latex_logo = None
292
300
293 # For "manual" documents, if this is true, then toplevel headings are parts,
301 # For "manual" documents, if this is true, then toplevel headings are parts,
294 # not chapters.
302 # not chapters.
295 #latex_use_parts = False
303 #latex_use_parts = False
296
304
297 # Additional stuff for the LaTeX preamble.
305 # Additional stuff for the LaTeX preamble.
298 #latex_preamble = ''
306 #latex_preamble = ''
299
307
300 # Documents to append as an appendix to all manuals.
308 # Documents to append as an appendix to all manuals.
301 #latex_appendices = []
309 #latex_appendices = []
302
310
303 # If false, no module index is generated.
311 # If false, no module index is generated.
304 latex_use_modindex = True
312 latex_use_modindex = True
305
313
306
314
307 # Options for texinfo output
315 # Options for texinfo output
308 # --------------------------
316 # --------------------------
309
317
310 texinfo_documents = [
318 texinfo_documents = [
311 (master_doc, 'ipython', 'IPython Documentation',
319 (master_doc, 'ipython', 'IPython Documentation',
312 'The IPython Development Team',
320 'The IPython Development Team',
313 'IPython',
321 'IPython',
314 'IPython Documentation',
322 'IPython Documentation',
315 'Programming',
323 'Programming',
316 1),
324 1),
317 ]
325 ]
318
326
319 modindex_common_prefix = ['IPython.']
327 modindex_common_prefix = ['IPython.']
320
328
321
329
322 # Cleanup
330 # Cleanup
323 # -------
331 # -------
324 # delete release info to avoid pickling errors from sphinx
332 # delete release info to avoid pickling errors from sphinx
325
333
326 del iprelease
334 del iprelease
@@ -1,313 +1,313 b''
1 =======================
1 =======================
2 Specific config details
2 Specific config details
3 =======================
3 =======================
4
4
5 .. _custom_prompts:
5 .. _custom_prompts:
6
6
7 Custom Prompts
7 Custom Prompts
8 ==============
8 ==============
9
9
10 .. versionchanged:: 5.0
10 .. versionchanged:: 5.0
11
11
12 From IPython 5, prompts are produced as a list of Pygments tokens, which are
12 From IPython 5, prompts are produced as a list of Pygments tokens, which are
13 tuples of (token_type, text). You can customise prompts by writing a method
13 tuples of (token_type, text). You can customise prompts by writing a method
14 which generates a list of tokens.
14 which generates a list of tokens.
15
15
16 There are four kinds of prompt:
16 There are four kinds of prompt:
17
17
18 * The **in** prompt is shown before the first line of input
18 * The **in** prompt is shown before the first line of input
19 (default like ``In [1]:``).
19 (default like ``In [1]:``).
20 * The **continuation** prompt is shown before further lines of input
20 * The **continuation** prompt is shown before further lines of input
21 (default like ``...:``).
21 (default like ``...:``).
22 * The **rewrite** prompt is shown to highlight how special syntax has been
22 * The **rewrite** prompt is shown to highlight how special syntax has been
23 interpreted (default like ``----->``).
23 interpreted (default like ``----->``).
24 * The **out** prompt is shown before the result from evaluating the input
24 * The **out** prompt is shown before the result from evaluating the input
25 (default like ``Out[1]:``).
25 (default like ``Out[1]:``).
26
26
27 Custom prompts are supplied together as a class. If you want to customise only
27 Custom prompts are supplied together as a class. If you want to customise only
28 some of the prompts, inherit from :class:`IPython.terminal.prompts.Prompts`,
28 some of the prompts, inherit from :class:`IPython.terminal.prompts.Prompts`,
29 which defines the defaults. The required interface is like this:
29 which defines the defaults. The required interface is like this:
30
30
31 .. class:: MyPrompts(shell)
31 .. class:: MyPrompts(shell)
32
32
33 Prompt style definition. *shell* is a reference to the
33 Prompt style definition. *shell* is a reference to the
34 :class:`~.TerminalInteractiveShell` instance.
34 :class:`~.TerminalInteractiveShell` instance.
35
35
36 .. method:: in_prompt_tokens(cli=None)
36 .. method:: in_prompt_tokens(cli=None)
37 continuation_prompt_tokens(self, cli=None, width=None)
37 continuation_prompt_tokens(self, cli=None, width=None)
38 rewrite_prompt_tokens()
38 rewrite_prompt_tokens()
39 out_prompt_tokens()
39 out_prompt_tokens()
40
40
41 Return the respective prompts as lists of ``(token_type, text)`` tuples.
41 Return the respective prompts as lists of ``(token_type, text)`` tuples.
42
42
43 For continuation prompts, *width* is an integer representing the width of
43 For continuation prompts, *width* is an integer representing the width of
44 the prompt area in terminal columns.
44 the prompt area in terminal columns.
45
45
46 *cli*, where used, is the prompt_toolkit ``CommandLineInterface`` instance.
46 *cli*, where used, is the prompt_toolkit ``CommandLineInterface`` instance.
47 This is mainly for compatibility with the API prompt_toolkit expects.
47 This is mainly for compatibility with the API prompt_toolkit expects.
48
48
49 Here is an example Prompt class that will show the current working directory
49 Here is an example Prompt class that will show the current working directory
50 in the input prompt:
50 in the input prompt:
51
51
52 .. code-block:: python
52 .. code-block:: python
53
53
54 from IPython.terminal.prompts import Prompts, Token
54 from IPython.terminal.prompts import Prompts, Token
55 import os
55 import os
56
56
57 class MyPrompt(Prompts):
57 class MyPrompt(Prompts):
58 def in_prompt_tokens(self, cli=None):
58 def in_prompt_tokens(self, cli=None):
59 return [(Token, os.getcwd()),
59 return [(Token, os.getcwd()),
60 (Token.Prompt, ' >>>')]
60 (Token.Prompt, ' >>>')]
61
61
62 To set the new prompt, assign it to the ``prompts`` attribute of the IPython
62 To set the new prompt, assign it to the ``prompts`` attribute of the IPython
63 shell:
63 shell:
64
64
65 .. code-block:: python
65 .. code-block:: python
66
66
67 In [2]: ip = get_ipython()
67 In [2]: ip = get_ipython()
68 ...: ip.prompts = MyPrompt(ip)
68 ...: ip.prompts = MyPrompt(ip)
69
69
70 /home/bob >>> # it works
70 /home/bob >>> # it works
71
71
72 See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write an
72 See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write
73 extensions to customise prompts.
73 extensions to customise prompts.
74
74
75 Inside IPython or in a startup script, you can use a custom prompts class
75 Inside IPython or in a startup script, you can use a custom prompts class
76 by setting ``get_ipython().prompts`` to an *instance* of the class.
76 by setting ``get_ipython().prompts`` to an *instance* of the class.
77 In configuration, ``TerminalInteractiveShell.prompts_class`` may be set to
77 In configuration, ``TerminalInteractiveShell.prompts_class`` may be set to
78 either the class object, or a string of its full importable name.
78 either the class object, or a string of its full importable name.
79
79
80 To include invisible terminal control sequences in a prompt, use
80 To include invisible terminal control sequences in a prompt, use
81 ``Token.ZeroWidthEscape`` as the token type. Tokens with this type are ignored
81 ``Token.ZeroWidthEscape`` as the token type. Tokens with this type are ignored
82 when calculating the width.
82 when calculating the width.
83
83
84 Colours in the prompt are determined by the token types and the highlighting
84 Colours in the prompt are determined by the token types and the highlighting
85 style; see below for more details. The tokens used in the default prompts are
85 style; see below for more details. The tokens used in the default prompts are
86 ``Prompt``, ``PromptNum``, ``OutPrompt`` and ``OutPromptNum``.
86 ``Prompt``, ``PromptNum``, ``OutPrompt`` and ``OutPromptNum``.
87
87
88 .. _termcolour:
88 .. _termcolour:
89
89
90 Terminal Colors
90 Terminal Colors
91 ===============
91 ===============
92
92
93 .. versionchanged:: 5.0
93 .. versionchanged:: 5.0
94
94
95 There are two main configuration options controlling colours.
95 There are two main configuration options controlling colours.
96
96
97 ``InteractiveShell.colors`` sets the colour of tracebacks and object info (the
97 ``InteractiveShell.colors`` sets the colour of tracebacks and object info (the
98 output from e.g. ``zip?``). It may also affect other things if the option below
98 output from e.g. ``zip?``). It may also affect other things if the option below
99 is set to ``'legacy'``. It has four case-insensitive values:
99 is set to ``'legacy'``. It has four case-insensitive values:
100 ``'nocolor', 'neutral', 'linux', 'lightbg'``. The default is *neutral*, which
100 ``'nocolor', 'neutral', 'linux', 'lightbg'``. The default is *neutral*, which
101 should be legible on either dark or light terminal backgrounds. *linux* is
101 should be legible on either dark or light terminal backgrounds. *linux* is
102 optimised for dark backgrounds and *lightbg* for light ones.
102 optimised for dark backgrounds and *lightbg* for light ones.
103
103
104 ``TerminalInteractiveShell.highlighting_style`` determines prompt colours and
104 ``TerminalInteractiveShell.highlighting_style`` determines prompt colours and
105 syntax highlighting. It takes the name (as a string) or class (as a subclass of
105 syntax highlighting. It takes the name (as a string) or class (as a subclass of
106 ``pygments.style.Style``) of a Pygments style, or the special value ``'legacy'``
106 ``pygments.style.Style``) of a Pygments style, or the special value ``'legacy'``
107 to pick a style in accordance with ``InteractiveShell.colors``.
107 to pick a style in accordance with ``InteractiveShell.colors``.
108
108
109 You can see the Pygments styles available on your system by running::
109 You can see the Pygments styles available on your system by running::
110
110
111 import pygments
111 import pygments
112 list(pygments.styles.get_all_styles())
112 list(pygments.styles.get_all_styles())
113
113
114 Additionally, ``TerminalInteractiveShell.highlighting_style_overrides`` can override
114 Additionally, ``TerminalInteractiveShell.highlighting_style_overrides`` can override
115 specific styles in the highlighting. It should be a dictionary mapping Pygments
115 specific styles in the highlighting. It should be a dictionary mapping Pygments
116 token types to strings defining the style. See `Pygments' documentation
116 token types to strings defining the style. See `Pygments' documentation
117 <http://pygments.org/docs/styles/#creating-own-styles>`__ for the language used
117 <http://pygments.org/docs/styles/#creating-own-styles>`__ for the language used
118 to define styles.
118 to define styles.
119
119
120 Colors in the pager
120 Colors in the pager
121 -------------------
121 -------------------
122
122
123 On some systems, the default pager has problems with ANSI colour codes.
123 On some systems, the default pager has problems with ANSI colour codes.
124 To configure your default pager to allow these:
124 To configure your default pager to allow these:
125
125
126 1. Set the environment PAGER variable to ``less``.
126 1. Set the environment PAGER variable to ``less``.
127 2. Set the environment LESS variable to ``-r`` (plus any other options
127 2. Set the environment LESS variable to ``-r`` (plus any other options
128 you always want to pass to less by default). This tells less to
128 you always want to pass to less by default). This tells less to
129 properly interpret control sequences, which is how color
129 properly interpret control sequences, which is how color
130 information is given to your terminal.
130 information is given to your terminal.
131
131
132 .. _editors:
132 .. _editors:
133
133
134 Editor configuration
134 Editor configuration
135 ====================
135 ====================
136
136
137 IPython can integrate with text editors in a number of different ways:
137 IPython can integrate with text editors in a number of different ways:
138
138
139 * Editors (such as `(X)Emacs`_, vim_ and TextMate_) can
139 * Editors (such as `(X)Emacs`_, vim_ and TextMate_) can
140 send code to IPython for execution.
140 send code to IPython for execution.
141
141
142 * IPython's ``%edit`` magic command can open an editor of choice to edit
142 * IPython's ``%edit`` magic command can open an editor of choice to edit
143 a code block.
143 a code block.
144
144
145 The %edit command (and its alias %ed) will invoke the editor set in your
145 The %edit command (and its alias %ed) will invoke the editor set in your
146 environment as :envvar:`EDITOR`. If this variable is not set, it will default
146 environment as :envvar:`EDITOR`. If this variable is not set, it will default
147 to vi under Linux/Unix and to notepad under Windows. You may want to set this
147 to vi under Linux/Unix and to notepad under Windows. You may want to set this
148 variable properly and to a lightweight editor which doesn't take too long to
148 variable properly and to a lightweight editor which doesn't take too long to
149 start (that is, something other than a new instance of Emacs). This way you
149 start (that is, something other than a new instance of Emacs). This way you
150 can edit multi-line code quickly and with the power of a real editor right
150 can edit multi-line code quickly and with the power of a real editor right
151 inside IPython.
151 inside IPython.
152
152
153 You can also control the editor by setting :attr:`TerminalInteractiveShell.editor`
153 You can also control the editor by setting :attr:`TerminalInteractiveShell.editor`
154 in :file:`ipython_config.py`.
154 in :file:`ipython_config.py`.
155
155
156 Vim
156 Vim
157 ---
157 ---
158
158
159 Paul Ivanov's `vim-ipython <https://github.com/ivanov/vim-ipython>`_ provides
159 Paul Ivanov's `vim-ipython <https://github.com/ivanov/vim-ipython>`_ provides
160 powerful IPython integration for vim.
160 powerful IPython integration for vim.
161
161
162 .. _emacs:
162 .. _emacs:
163
163
164 (X)Emacs
164 (X)Emacs
165 --------
165 --------
166
166
167 If you are a dedicated Emacs user, and want to use Emacs when IPython's
167 If you are a dedicated Emacs user, and want to use Emacs when IPython's
168 ``%edit`` magic command is called you should set up the Emacs server so that
168 ``%edit`` magic command is called you should set up the Emacs server so that
169 new requests are handled by the original process. This means that almost no
169 new requests are handled by the original process. This means that almost no
170 time is spent in handling the request (assuming an Emacs process is already
170 time is spent in handling the request (assuming an Emacs process is already
171 running). For this to work, you need to set your EDITOR environment variable
171 running). For this to work, you need to set your EDITOR environment variable
172 to 'emacsclient'. The code below, supplied by Francois Pinard, can then be
172 to 'emacsclient'. The code below, supplied by Francois Pinard, can then be
173 used in your :file:`.emacs` file to enable the server:
173 used in your :file:`.emacs` file to enable the server:
174
174
175 .. code-block:: common-lisp
175 .. code-block:: common-lisp
176
176
177 (defvar server-buffer-clients)
177 (defvar server-buffer-clients)
178 (when (and (fboundp 'server-start) (string-equal (getenv "TERM") 'xterm))
178 (when (and (fboundp 'server-start) (string-equal (getenv "TERM") 'xterm))
179 (server-start)
179 (server-start)
180 (defun fp-kill-server-with-buffer-routine ()
180 (defun fp-kill-server-with-buffer-routine ()
181 (and server-buffer-clients (server-done)))
181 (and server-buffer-clients (server-done)))
182 (add-hook 'kill-buffer-hook 'fp-kill-server-with-buffer-routine))
182 (add-hook 'kill-buffer-hook 'fp-kill-server-with-buffer-routine))
183
183
184 Thanks to the work of Alexander Schmolck and Prabhu Ramachandran,
184 Thanks to the work of Alexander Schmolck and Prabhu Ramachandran,
185 currently (X)Emacs and IPython get along very well in other ways.
185 currently (X)Emacs and IPython get along very well in other ways.
186
186
187 With (X)EMacs >= 24, You can enable IPython in python-mode with:
187 With (X)EMacs >= 24, You can enable IPython in python-mode with:
188
188
189 .. code-block:: common-lisp
189 .. code-block:: common-lisp
190
190
191 (require 'python)
191 (require 'python)
192 (setq python-shell-interpreter "ipython")
192 (setq python-shell-interpreter "ipython")
193
193
194 .. _`(X)Emacs`: http://www.gnu.org/software/emacs/
194 .. _`(X)Emacs`: http://www.gnu.org/software/emacs/
195 .. _TextMate: http://macromates.com/
195 .. _TextMate: http://macromates.com/
196 .. _vim: http://www.vim.org/
196 .. _vim: http://www.vim.org/
197
197
198 .. _custom_keyboard_shortcuts:
198 .. _custom_keyboard_shortcuts:
199
199
200 Keyboard Shortcuts
200 Keyboard Shortcuts
201 ==================
201 ==================
202
202
203 .. versionchanged:: 5.0
203 .. versionchanged:: 5.0
204
204
205 You can customise keyboard shortcuts for terminal IPython. Put code like this in
205 You can customise keyboard shortcuts for terminal IPython. Put code like this in
206 a :ref:`startup file <startup_files>`::
206 a :ref:`startup file <startup_files>`::
207
207
208 from IPython import get_ipython
208 from IPython import get_ipython
209 from prompt_toolkit.enums import DEFAULT_BUFFER
209 from prompt_toolkit.enums import DEFAULT_BUFFER
210 from prompt_toolkit.keys import Keys
210 from prompt_toolkit.keys import Keys
211 from prompt_toolkit.filters import HasFocus, HasSelection, ViInsertMode, EmacsInsertMode
211 from prompt_toolkit.filters import HasFocus, HasSelection, ViInsertMode, EmacsInsertMode
212
212
213 ip = get_ipython()
213 ip = get_ipython()
214 insert_mode = ViInsertMode() | EmacsInsertMode()
214 insert_mode = ViInsertMode() | EmacsInsertMode()
215
215
216 def insert_unexpected(event):
216 def insert_unexpected(event):
217 buf = event.current_buffer
217 buf = event.current_buffer
218 buf.insert_text('The Spanish Inquisition')
218 buf.insert_text('The Spanish Inquisition')
219 # Register the shortcut if IPython is using prompt_toolkit
219 # Register the shortcut if IPython is using prompt_toolkit
220 if getattr(ip, 'pt_app', None):
220 if getattr(ip, 'pt_app', None):
221 registry = ip.pt_app.key_bindings
221 registry = ip.pt_app.key_bindings
222 registry.add_binding(Keys.ControlN,
222 registry.add_binding(Keys.ControlN,
223 filter=(HasFocus(DEFAULT_BUFFER)
223 filter=(HasFocus(DEFAULT_BUFFER)
224 & ~HasSelection()
224 & ~HasSelection()
225 & insert_mode))(insert_unexpected)
225 & insert_mode))(insert_unexpected)
226
226
227
227
228 Here is a second example that bind the key sequence ``j``, ``k`` to switch to
228 Here is a second example that bind the key sequence ``j``, ``k`` to switch to
229 VI input mode to ``Normal`` when in insert mode::
229 VI input mode to ``Normal`` when in insert mode::
230
230
231 from IPython import get_ipython
231 from IPython import get_ipython
232 from prompt_toolkit.enums import DEFAULT_BUFFER
232 from prompt_toolkit.enums import DEFAULT_BUFFER
233 from prompt_toolkit.filters import HasFocus, ViInsertMode
233 from prompt_toolkit.filters import HasFocus, ViInsertMode
234 from prompt_toolkit.key_binding.vi_state import InputMode
234 from prompt_toolkit.key_binding.vi_state import InputMode
235
235
236 ip = get_ipython()
236 ip = get_ipython()
237
237
238 def switch_to_navigation_mode(event):
238 def switch_to_navigation_mode(event):
239 vi_state = event.cli.vi_state
239 vi_state = event.cli.vi_state
240 vi_state.input_mode = InputMode.NAVIGATION
240 vi_state.input_mode = InputMode.NAVIGATION
241
241
242 if getattr(ip, 'pt_app', None):
242 if getattr(ip, 'pt_app', None):
243 registry = ip.pt_app.key_bindings
243 registry = ip.pt_app.key_bindings
244 registry.add_binding(u'j',u'k',
244 registry.add_binding(u'j',u'k',
245 filter=(HasFocus(DEFAULT_BUFFER)
245 filter=(HasFocus(DEFAULT_BUFFER)
246 & ViInsertMode()))(switch_to_navigation_mode)
246 & ViInsertMode()))(switch_to_navigation_mode)
247
247
248 For more information on filters and what you can do with the ``event`` object,
248 For more information on filters and what you can do with the ``event`` object,
249 `see the prompt_toolkit docs
249 `see the prompt_toolkit docs
250 <https://python-prompt-toolkit.readthedocs.io/en/latest/pages/asking_for_input.html#adding-custom-key-bindings>`__.
250 <https://python-prompt-toolkit.readthedocs.io/en/latest/pages/asking_for_input.html#adding-custom-key-bindings>`__.
251
251
252
252
253 Enter to execute
253 Enter to execute
254 ----------------
254 ----------------
255
255
256 In the Terminal IPython shell – which by default uses the ``prompt_toolkit``
256 In the Terminal IPython shell – which by default uses the ``prompt_toolkit``
257 interface, the semantic meaning of pressing the :kbd:`Enter` key can be
257 interface, the semantic meaning of pressing the :kbd:`Enter` key can be
258 ambiguous. In some case :kbd:`Enter` should execute code, and in others it
258 ambiguous. In some case :kbd:`Enter` should execute code, and in others it
259 should add a new line. IPython uses heuristics to decide whether to execute or
259 should add a new line. IPython uses heuristics to decide whether to execute or
260 insert a new line at cursor position. For example, if we detect that the current
260 insert a new line at cursor position. For example, if we detect that the current
261 code is not valid Python, then the user is likely editing code and the right
261 code is not valid Python, then the user is likely editing code and the right
262 behavior is to likely to insert a new line. If the current code is a simple
262 behavior is to likely to insert a new line. If the current code is a simple
263 statement like `ord('*')`, then the right behavior is likely to execute. Though
263 statement like `ord('*')`, then the right behavior is likely to execute. Though
264 the exact desired semantics often varies from users to users.
264 the exact desired semantics often varies from users to users.
265
265
266 As the exact behavior of :kbd:`Enter` is ambiguous, it has been special cased
266 As the exact behavior of :kbd:`Enter` is ambiguous, it has been special cased
267 to allow users to completely configure the behavior they like. Hence you can
267 to allow users to completely configure the behavior they like. Hence you can
268 have enter always execute code. If you prefer fancier behavior, you need to get
268 have enter always execute code. If you prefer fancier behavior, you need to get
269 your hands dirty and read the ``prompt_toolkit`` and IPython documentation
269 your hands dirty and read the ``prompt_toolkit`` and IPython documentation
270 though. See :ghpull:`10500`, set the
270 though. See :ghpull:`10500`, set the
271 ``c.TerminalInteractiveShell.handle_return`` option and get inspiration from the
271 ``c.TerminalInteractiveShell.handle_return`` option and get inspiration from the
272 following example that only auto-executes the input if it begins with a bang or
272 following example that only auto-executes the input if it begins with a bang or
273 a modulo character (``!`` or ``%``). To use the following code, add it to your
273 a modulo character (``!`` or ``%``). To use the following code, add it to your
274 IPython configuration::
274 IPython configuration::
275
275
276 def custom_return(shell):
276 def custom_return(shell):
277
277
278 """This function is required by the API. It takes a reference to
278 """This function is required by the API. It takes a reference to
279 the shell, which is the same thing `get_ipython()` evaluates to.
279 the shell, which is the same thing `get_ipython()` evaluates to.
280 This function must return a function that handles each keypress
280 This function must return a function that handles each keypress
281 event. That function, named `handle` here, references `shell`
281 event. That function, named `handle` here, references `shell`
282 by closure."""
282 by closure."""
283
283
284 def handle(event):
284 def handle(event):
285
285
286 """This function is called each time `Enter` is pressed,
286 """This function is called each time `Enter` is pressed,
287 and takes a reference to a Prompt Toolkit event object.
287 and takes a reference to a Prompt Toolkit event object.
288 If the current input starts with a bang or modulo, then
288 If the current input starts with a bang or modulo, then
289 the input is executed, otherwise a newline is entered,
289 the input is executed, otherwise a newline is entered,
290 followed by any spaces needed to auto-indent."""
290 followed by any spaces needed to auto-indent."""
291
291
292 # set up a few handy references to nested items...
292 # set up a few handy references to nested items...
293
293
294 buffer = event.current_buffer
294 buffer = event.current_buffer
295 document = buffer.document
295 document = buffer.document
296 text = document.text
296 text = document.text
297
297
298 if text.startswith('!') or text.startswith('%'): # execute the input...
298 if text.startswith('!') or text.startswith('%'): # execute the input...
299
299
300 buffer.accept_action.validate_and_handle(event.cli, buffer)
300 buffer.accept_action.validate_and_handle(event.cli, buffer)
301
301
302 else: # insert a newline with auto-indentation...
302 else: # insert a newline with auto-indentation...
303
303
304 if document.line_count > 1: text = text[:document.cursor_position]
304 if document.line_count > 1: text = text[:document.cursor_position]
305 indent = shell.check_complete(text)[1]
305 indent = shell.check_complete(text)[1]
306 buffer.insert_text('\n' + indent)
306 buffer.insert_text('\n' + indent)
307
307
308 # if you just wanted a plain newline without any indentation, you
308 # if you just wanted a plain newline without any indentation, you
309 # could use `buffer.insert_text('\n')` instead of the lines above
309 # could use `buffer.insert_text('\n')` instead of the lines above
310
310
311 return handle
311 return handle
312
312
313 c.TerminalInteractiveShell.handle_return = custom_return
313 c.TerminalInteractiveShell.handle_return = custom_return
@@ -1,103 +1,99 b''
1 .. _extensions_overview:
1 .. _extensions_overview:
2
2
3 ==================
3 ==================
4 IPython extensions
4 IPython extensions
5 ==================
5 ==================
6
6
7 A level above configuration are IPython extensions, Python modules which modify
7 A level above configuration are IPython extensions, Python modules which modify
8 the behaviour of the shell. They are referred to by an importable module name,
8 the behaviour of the shell. They are referred to by an importable module name,
9 and can be placed anywhere you'd normally import from, or in
9 and can be placed anywhere you'd normally import from.
10 ``.ipython/extensions/``.
11
10
12 Getting extensions
11 Getting extensions
13 ==================
12 ==================
14
13
15 A few important extensions are :ref:`bundled with IPython <bundled_extensions>`.
14 A few important extensions are :ref:`bundled with IPython <bundled_extensions>`.
16 Others can be found on the `extensions index
15 Others can be found on the `extensions index
17 <https://github.com/ipython/ipython/wiki/Extensions-Index>`_ on the wiki, and
16 <https://github.com/ipython/ipython/wiki/Extensions-Index>`_ on the wiki, and
18 the `Framework :: IPython tag <https://pypi.python.org/pypi?:action=browse&c=586>`_
17 the `Framework :: IPython tag <https://pypi.python.org/pypi?:action=browse&c=586>`_
19 on PyPI.
18 on PyPI.
20
19
21 Extensions on PyPI can be installed using ``pip``, like any other Python package.
20 Extensions on PyPI can be installed using ``pip``, like any other Python package.
22
21
23 Using extensions
22 Using extensions
24 ================
23 ================
25
24
26 To load an extension while IPython is running, use the ``%load_ext`` magic:
25 To load an extension while IPython is running, use the ``%load_ext`` magic:
27
26
28 .. sourcecode:: ipython
27 .. sourcecode:: ipython
29
28
30 In [1]: %load_ext myextension
29 In [1]: %load_ext myextension
31
30
32 To load it each time IPython starts, list it in your configuration file::
31 To load it each time IPython starts, list it in your configuration file::
33
32
34 c.InteractiveShellApp.extensions = [
33 c.InteractiveShellApp.extensions = [
35 'myextension'
34 'myextension'
36 ]
35 ]
37
36
38 Writing extensions
37 Writing extensions
39 ==================
38 ==================
40
39
41 An IPython extension is an importable Python module that has a couple of special
40 An IPython extension is an importable Python module that has a couple of special
42 functions to load and unload it. Here is a template::
41 functions to load and unload it. Here is a template::
43
42
44 # myextension.py
43 # myextension.py
45
44
46 def load_ipython_extension(ipython):
45 def load_ipython_extension(ipython):
47 # The `ipython` argument is the currently active `InteractiveShell`
46 # The `ipython` argument is the currently active `InteractiveShell`
48 # instance, which can be used in any way. This allows you to register
47 # instance, which can be used in any way. This allows you to register
49 # new magics or aliases, for example.
48 # new magics or aliases, for example.
50
49
51 def unload_ipython_extension(ipython):
50 def unload_ipython_extension(ipython):
52 # If you want your extension to be unloadable, put that logic here.
51 # If you want your extension to be unloadable, put that logic here.
53
52
54 This :func:`load_ipython_extension` function is called after your extension is
53 This :func:`load_ipython_extension` function is called after your extension is
55 imported, and the currently active :class:`~IPython.core.interactiveshell.InteractiveShell`
54 imported, and the currently active :class:`~IPython.core.interactiveshell.InteractiveShell`
56 instance is passed as the only argument. You can do anything you want with
55 instance is passed as the only argument. You can do anything you want with
57 IPython at that point.
56 IPython at that point.
58
57
59 :func:`load_ipython_extension` will not be called again if the user use
58 :func:`load_ipython_extension` will not be called again if the user use
60 `%load_extension`. The user have to explicitly ask the extension to be
59 `%load_extension`. The user have to explicitly ask the extension to be
61 reloaded (with `%reload_extension`). In case where the use ask the extension to
60 reloaded (with `%reload_extension`). In case where the use ask the extension to
62 be reloaded, , the extension will be unloaded (with
61 be reloaded, , the extension will be unloaded (with
63 `unload_ipython_extension`), and loaded again.
62 `unload_ipython_extension`), and loaded again.
64
63
65 Useful :class:`InteractiveShell` methods include :meth:`~IPython.core.interactiveshell.InteractiveShell.register_magic_function`,
64 Useful :class:`InteractiveShell` methods include :meth:`~IPython.core.interactiveshell.InteractiveShell.register_magic_function`,
66 :meth:`~IPython.core.interactiveshell.InteractiveShell.push` (to add variables to the user namespace) and
65 :meth:`~IPython.core.interactiveshell.InteractiveShell.push` (to add variables to the user namespace) and
67 :meth:`~IPython.core.interactiveshell.InteractiveShell.drop_by_id` (to remove variables on unloading).
66 :meth:`~IPython.core.interactiveshell.InteractiveShell.drop_by_id` (to remove variables on unloading).
68
67
69 .. seealso::
68 .. seealso::
70
69
71 :ref:`defining_magics`
70 :ref:`defining_magics`
72
71
73 You can put your extension modules anywhere you want, as long as they can be
72 You can put your extension modules anywhere you want, as long as they can be
74 imported by Python's standard import mechanism. However, to make it easy to
73 imported by Python's standard import mechanism.
75 write extensions, you can also put your extensions in :file:`extensions/`
76 within the :ref:`IPython directory <ipythondir>`. This directory is
77 added to :data:`sys.path` automatically.
78
74
79 When your extension is ready for general use, please add it to the `extensions
75 When your extension is ready for general use, please add it to the `extensions
80 index <https://github.com/ipython/ipython/wiki/Extensions-Index>`_. We also
76 index <https://github.com/ipython/ipython/wiki/Extensions-Index>`_. We also
81 encourage you to upload it to PyPI and use the ``Framework :: IPython``
77 encourage you to upload it to PyPI and use the ``Framework :: IPython``
82 classifier, so that users can install it with standard packaging tools.
78 classifier, so that users can install it with standard packaging tools.
83
79
84 .. _bundled_extensions:
80 .. _bundled_extensions:
85
81
86 Extensions bundled with IPython
82 Extensions bundled with IPython
87 ===============================
83 ===============================
88
84
89 .. toctree::
85 .. toctree::
90 :maxdepth: 1
86 :maxdepth: 1
91
87
92 autoreload
88 autoreload
93 storemagic
89 storemagic
94
90
95 * ``octavemagic`` used to be bundled, but is now part of `oct2py <https://blink1073.github.io/oct2py/>`_.
91 * ``octavemagic`` used to be bundled, but is now part of `oct2py <https://blink1073.github.io/oct2py/>`_.
96 Use ``%load_ext oct2py.ipython`` to load it.
92 Use ``%load_ext oct2py.ipython`` to load it.
97 * ``rmagic`` is now part of `rpy2 <http://rpy.sourceforge.net/>`_. Use
93 * ``rmagic`` is now part of `rpy2 <http://rpy.sourceforge.net/>`_. Use
98 ``%load_ext rpy2.ipython`` to load it, and see :mod:`rpy2.ipython.rmagic` for
94 ``%load_ext rpy2.ipython`` to load it, and see :mod:`rpy2.ipython.rmagic` for
99 details of how to use it.
95 details of how to use it.
100 * ``cythonmagic`` used to be bundled, but is now part of `cython <https://github.com/cython/cython/>`_
96 * ``cythonmagic`` used to be bundled, but is now part of `cython <https://github.com/cython/cython/>`_
101 Use ``%load_ext Cython`` to load it.
97 Use ``%load_ext Cython`` to load it.
102 * ``sympyprinting`` used to be a bundled extension, but you should now use
98 * ``sympyprinting`` used to be a bundled extension, but you should now use
103 :func:`sympy.init_printing` instead.
99 :func:`sympy.init_printing` instead.
@@ -1,1196 +1,1260 b''
1 ============
1 ============
2 8.x Series
2 8.x Series
3 ============
3 ============
4
4
5 .. _version 8.6.0:
6
7 IPython 8.6.0
8 -------------
9
10 Back to a more regular release schedule (at least I try), as Friday is
11 already over by more than 24h hours. This is a slightly bigger release with a
12 few new features that contain no less then 25 PRs.
13
14 We'll notably found a couple of non negligible changes:
15
16 The ``install_ext`` and related functions have been removed after being
17 deprecated for years. You can use pip to install extensions. ``pip`` did not
18 exists when ``install_ext`` was introduced. You can still load local extensions
19 without installing them. Just set your ``sys.path`` for example. :ghpull:`13744`
20
21 IPython now have extra entry points that that the major *and minor* version of
22 python. For some of you this mean that you can do a quick ``ipython3.10`` to
23 launch IPython from the Python 3.10 interpreter, while still using Python 3.11
24 as your main Python. :ghpull:`13743`
25
26 The completer matcher API have been improved. See :ghpull:`13745`. This should
27 improve the type inference and improve dict keys completions in many use case.
28 Tanks ``@krassowski`` for all the works, and the D.E. Shaw group for sponsoring
29 it.
30
31 The color of error nodes in tracebacks can now be customized. See
32 :ghpull:`13756`. This is a private attribute until someone find the time to
33 properly add a configuration option. Note that with Python 3.11 that also show
34 the relevant nodes in traceback, it would be good to leverage this informations
35 (plus the "did you mean" info added on attribute errors). But that's likely work
36 I won't have time to do before long, so contributions welcome.
37
38 As we follow NEP 29, we removed support for numpy 1.19 :ghpull:`13760`.
39
40
41 The ``open()`` function present in the user namespace by default will now refuse
42 to open the file descriptors 0,1,2 (stdin, out, err), to avoid crashing IPython.
43 This mostly occurs in teaching context when incorrect values get passed around.
44
45
46 The ``?``, ``??``, and corresponding ``pinfo``, ``pinfo2`` magics can now find
47 objects insides arrays. That is to say, the following now works::
48
49
50 >>> def my_func(*arg, **kwargs):pass
51 >>> container = [my_func]
52 >>> container[0]?
53
54
55 If ``container`` define a custom ``getitem``, this __will__ trigger the custom
56 method. So don't put side effects in your ``getitems``. Thanks the D.E. Shaw
57 group for the request and sponsoring the work.
58
59
60 As usual you can find the full list of PRs on GitHub under `the 8.6 milestone
61 <https://github.com/ipython/ipython/pulls?q=milestone%3A8.6>`__.
62
63 Thanks to all hacktoberfest contributors, please contribute to
64 `closember.org <https://closember.org/>`__.
65
66 Thanks to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
67 work on IPython and related libraries.
68
5 .. _version 8.5.0:
69 .. _version 8.5.0:
6
70
7 IPython 8.5.0
71 IPython 8.5.0
8 -------------
72 -------------
9
73
10 First release since a couple of month due to various reasons and timing preventing
74 First release since a couple of month due to various reasons and timing preventing
11 me for sticking to the usual monthly release the last Friday of each month. This
75 me for sticking to the usual monthly release the last Friday of each month. This
12 is of non negligible size as it has more than two dozen PRs with various fixes
76 is of non negligible size as it has more than two dozen PRs with various fixes
13 an bug fixes.
77 an bug fixes.
14
78
15 Many thanks to everybody who contributed PRs for your patience in review and
79 Many thanks to everybody who contributed PRs for your patience in review and
16 merges.
80 merges.
17
81
18 Here is a non exhaustive list of changes that have been implemented for IPython
82 Here is a non exhaustive list of changes that have been implemented for IPython
19 8.5.0. As usual you can find the full list of issues and PRs tagged with `the
83 8.5.0. As usual you can find the full list of issues and PRs tagged with `the
20 8.5 milestone
84 8.5 milestone
21 <https://github.com/ipython/ipython/pulls?q=is%3Aclosed+milestone%3A8.5+>`__.
85 <https://github.com/ipython/ipython/pulls?q=is%3Aclosed+milestone%3A8.5+>`__.
22
86
23 - Added shortcut for accepting auto suggestion. The End key shortcut for
87 - Added shortcut for accepting auto suggestion. The End key shortcut for
24 accepting auto-suggestion This binding works in Vi mode too, provided
88 accepting auto-suggestion This binding works in Vi mode too, provided
25 ``TerminalInteractiveShell.emacs_bindings_in_vi_insert_mode`` is set to be
89 ``TerminalInteractiveShell.emacs_bindings_in_vi_insert_mode`` is set to be
26 ``True`` :ghpull:`13566`.
90 ``True`` :ghpull:`13566`.
27
91
28 - No popup in window for latex generation w hen generating latex (e.g. via
92 - No popup in window for latex generation w hen generating latex (e.g. via
29 `_latex_repr_`) no popup window is shows under Windows. :ghpull:`13679`
93 `_latex_repr_`) no popup window is shows under Windows. :ghpull:`13679`
30
94
31 - Fixed error raised when attempting to tab-complete an input string with
95 - Fixed error raised when attempting to tab-complete an input string with
32 consecutive periods or forward slashes (such as "file:///var/log/...").
96 consecutive periods or forward slashes (such as "file:///var/log/...").
33 :ghpull:`13675`
97 :ghpull:`13675`
34
98
35 - Relative filenames in Latex rendering :
99 - Relative filenames in Latex rendering :
36 The `latex_to_png_dvipng` command internally generates input and output file
100 The `latex_to_png_dvipng` command internally generates input and output file
37 arguments to `latex` and `dvipis`. These arguments are now generated as
101 arguments to `latex` and `dvipis`. These arguments are now generated as
38 relative files to the current working directory instead of absolute file
102 relative files to the current working directory instead of absolute file
39 paths. This solves a problem where the current working directory contains
103 paths. This solves a problem where the current working directory contains
40 characters that are not handled properly by `latex` and `dvips`. There are
104 characters that are not handled properly by `latex` and `dvips`. There are
41 no changes to the user API. :ghpull:`13680`
105 no changes to the user API. :ghpull:`13680`
42
106
43 - Stripping decorators bug: Fixed bug which meant that ipython code blocks in
107 - Stripping decorators bug: Fixed bug which meant that ipython code blocks in
44 restructured text documents executed with the ipython-sphinx extension
108 restructured text documents executed with the ipython-sphinx extension
45 skipped any lines of code containing python decorators. :ghpull:`13612`
109 skipped any lines of code containing python decorators. :ghpull:`13612`
46
110
47 - Allow some modules with frozen dataclasses to be reloaded. :ghpull:`13732`
111 - Allow some modules with frozen dataclasses to be reloaded. :ghpull:`13732`
48 - Fix paste magic on wayland. :ghpull:`13671`
112 - Fix paste magic on wayland. :ghpull:`13671`
49 - show maxlen in deque's repr. :ghpull:`13648`
113 - show maxlen in deque's repr. :ghpull:`13648`
50
114
51 Restore line numbers for Input
115 Restore line numbers for Input
52 ------------------------------
116 ------------------------------
53
117
54 Line number information in tracebacks from input are restored.
118 Line number information in tracebacks from input are restored.
55 Line numbers from input were removed during the transition to v8 enhanced traceback reporting.
119 Line numbers from input were removed during the transition to v8 enhanced traceback reporting.
56
120
57 So, instead of::
121 So, instead of::
58
122
59 ---------------------------------------------------------------------------
123 ---------------------------------------------------------------------------
60 ZeroDivisionError Traceback (most recent call last)
124 ZeroDivisionError Traceback (most recent call last)
61 Input In [3], in <cell line: 1>()
125 Input In [3], in <cell line: 1>()
62 ----> 1 myfunc(2)
126 ----> 1 myfunc(2)
63
127
64 Input In [2], in myfunc(z)
128 Input In [2], in myfunc(z)
65 1 def myfunc(z):
129 1 def myfunc(z):
66 ----> 2 foo.boo(z-1)
130 ----> 2 foo.boo(z-1)
67
131
68 File ~/code/python/ipython/foo.py:3, in boo(x)
132 File ~/code/python/ipython/foo.py:3, in boo(x)
69 2 def boo(x):
133 2 def boo(x):
70 ----> 3 return 1/(1-x)
134 ----> 3 return 1/(1-x)
71
135
72 ZeroDivisionError: division by zero
136 ZeroDivisionError: division by zero
73
137
74 The error traceback now looks like::
138 The error traceback now looks like::
75
139
76 ---------------------------------------------------------------------------
140 ---------------------------------------------------------------------------
77 ZeroDivisionError Traceback (most recent call last)
141 ZeroDivisionError Traceback (most recent call last)
78 Cell In [3], line 1
142 Cell In [3], line 1
79 ----> 1 myfunc(2)
143 ----> 1 myfunc(2)
80
144
81 Cell In [2], line 2, in myfunc(z)
145 Cell In [2], line 2, in myfunc(z)
82 1 def myfunc(z):
146 1 def myfunc(z):
83 ----> 2 foo.boo(z-1)
147 ----> 2 foo.boo(z-1)
84
148
85 File ~/code/python/ipython/foo.py:3, in boo(x)
149 File ~/code/python/ipython/foo.py:3, in boo(x)
86 2 def boo(x):
150 2 def boo(x):
87 ----> 3 return 1/(1-x)
151 ----> 3 return 1/(1-x)
88
152
89 ZeroDivisionError: division by zero
153 ZeroDivisionError: division by zero
90
154
91 or, with xmode=Plain::
155 or, with xmode=Plain::
92
156
93 Traceback (most recent call last):
157 Traceback (most recent call last):
94 Cell In [12], line 1
158 Cell In [12], line 1
95 myfunc(2)
159 myfunc(2)
96 Cell In [6], line 2 in myfunc
160 Cell In [6], line 2 in myfunc
97 foo.boo(z-1)
161 foo.boo(z-1)
98 File ~/code/python/ipython/foo.py:3 in boo
162 File ~/code/python/ipython/foo.py:3 in boo
99 return 1/(1-x)
163 return 1/(1-x)
100 ZeroDivisionError: division by zero
164 ZeroDivisionError: division by zero
101
165
102 :ghpull:`13560`
166 :ghpull:`13560`
103
167
104 New setting to silence warning if working inside a virtual environment
168 New setting to silence warning if working inside a virtual environment
105 ----------------------------------------------------------------------
169 ----------------------------------------------------------------------
106
170
107 Previously, when starting IPython in a virtual environment without IPython installed (so IPython from the global environment is used), the following warning was printed:
171 Previously, when starting IPython in a virtual environment without IPython installed (so IPython from the global environment is used), the following warning was printed:
108
172
109 Attempting to work in a virtualenv. If you encounter problems, please install IPython inside the virtualenv.
173 Attempting to work in a virtualenv. If you encounter problems, please install IPython inside the virtualenv.
110
174
111 This warning can be permanently silenced by setting ``c.InteractiveShell.warn_venv`` to ``False`` (the default is ``True``).
175 This warning can be permanently silenced by setting ``c.InteractiveShell.warn_venv`` to ``False`` (the default is ``True``).
112
176
113 :ghpull:`13706`
177 :ghpull:`13706`
114
178
115 -------
179 -------
116
180
117 Thanks to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
181 Thanks to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
118 work on IPython and related libraries.
182 work on IPython and related libraries.
119
183
120
184
121 .. _version 8.4.0:
185 .. _version 8.4.0:
122
186
123 IPython 8.4.0
187 IPython 8.4.0
124 -------------
188 -------------
125
189
126 As for 7.34, this version contains a single fix: fix uncaught BdbQuit exceptions on ipdb
190 As for 7.34, this version contains a single fix: fix uncaught BdbQuit exceptions on ipdb
127 exit :ghpull:`13668`, and a single typo fix in documentation: :ghpull:`13682`
191 exit :ghpull:`13668`, and a single typo fix in documentation: :ghpull:`13682`
128
192
129 Thanks to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
193 Thanks to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
130 work on IPython and related libraries.
194 work on IPython and related libraries.
131
195
132
196
133 .. _version 8.3.0:
197 .. _version 8.3.0:
134
198
135 IPython 8.3.0
199 IPython 8.3.0
136 -------------
200 -------------
137
201
138 - :ghpull:`13625`, using ``?``, ``??``, ``*?`` will not call
202 - :ghpull:`13625`, using ``?``, ``??``, ``*?`` will not call
139 ``set_next_input`` as most frontend allow proper multiline editing and it was
203 ``set_next_input`` as most frontend allow proper multiline editing and it was
140 causing issues for many users of multi-cell frontends. This has been backported to 7.33
204 causing issues for many users of multi-cell frontends. This has been backported to 7.33
141
205
142
206
143 - :ghpull:`13600`, ``pre_run_*``-hooks will now have a ``cell_id`` attribute on
207 - :ghpull:`13600`, ``pre_run_*``-hooks will now have a ``cell_id`` attribute on
144 the info object when frontend provide it. This has been backported to 7.33
208 the info object when frontend provide it. This has been backported to 7.33
145
209
146 - :ghpull:`13624`, fixed :kbd:`End` key being broken after accepting an
210 - :ghpull:`13624`, fixed :kbd:`End` key being broken after accepting an
147 auto-suggestion.
211 auto-suggestion.
148
212
149 - :ghpull:`13657` fix issue where history from different sessions would be mixed.
213 - :ghpull:`13657` fix issue where history from different sessions would be mixed.
150
214
151 .. _version 8.2.0:
215 .. _version 8.2.0:
152
216
153 IPython 8.2.0
217 IPython 8.2.0
154 -------------
218 -------------
155
219
156 IPython 8.2 mostly bring bugfixes to IPython.
220 IPython 8.2 mostly bring bugfixes to IPython.
157
221
158 - Auto-suggestion can now be elected with the ``end`` key. :ghpull:`13566`
222 - Auto-suggestion can now be elected with the ``end`` key. :ghpull:`13566`
159 - Some traceback issues with ``assert etb is not None`` have been fixed. :ghpull:`13588`
223 - Some traceback issues with ``assert etb is not None`` have been fixed. :ghpull:`13588`
160 - History is now pulled from the sqitel database and not from in-memory.
224 - History is now pulled from the sqitel database and not from in-memory.
161 In particular when using the ``%paste`` magic, the content of the pasted text will
225 In particular when using the ``%paste`` magic, the content of the pasted text will
162 be part of the history and not the verbatim text ``%paste`` anymore. :ghpull:`13592`
226 be part of the history and not the verbatim text ``%paste`` anymore. :ghpull:`13592`
163 - Fix ``Ctrl-\\`` exit cleanup :ghpull:`13603`
227 - Fix ``Ctrl-\\`` exit cleanup :ghpull:`13603`
164 - Fixes to ``ultratb`` ipdb support when used outside of IPython. :ghpull:`13498`
228 - Fixes to ``ultratb`` ipdb support when used outside of IPython. :ghpull:`13498`
165
229
166
230
167 I am still trying to fix and investigate :ghissue:`13598`, which seem to be
231 I am still trying to fix and investigate :ghissue:`13598`, which seem to be
168 random, and would appreciate help if you find reproducible minimal case. I've
232 random, and would appreciate help if you find reproducible minimal case. I've
169 tried to make various changes to the codebase to mitigate it, but a proper fix
233 tried to make various changes to the codebase to mitigate it, but a proper fix
170 will be difficult without understanding the cause.
234 will be difficult without understanding the cause.
171
235
172
236
173 All the issues on pull-requests for this release can be found in the `8.2
237 All the issues on pull-requests for this release can be found in the `8.2
174 milestone. <https://github.com/ipython/ipython/milestone/100>`__ . And some
238 milestone. <https://github.com/ipython/ipython/milestone/100>`__ . And some
175 documentation only PR can be found as part of the `7.33 milestone
239 documentation only PR can be found as part of the `7.33 milestone
176 <https://github.com/ipython/ipython/milestone/101>`__ (currently not released).
240 <https://github.com/ipython/ipython/milestone/101>`__ (currently not released).
177
241
178 Thanks to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
242 Thanks to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
179 work on IPython and related libraries.
243 work on IPython and related libraries.
180
244
181 .. _version 8.1.1:
245 .. _version 8.1.1:
182
246
183 IPython 8.1.1
247 IPython 8.1.1
184 -------------
248 -------------
185
249
186 Fix an issue with virtualenv and Python 3.8 introduced in 8.1
250 Fix an issue with virtualenv and Python 3.8 introduced in 8.1
187
251
188 Revert :ghpull:`13537` (fix an issue with symlinks in virtualenv) that raises an
252 Revert :ghpull:`13537` (fix an issue with symlinks in virtualenv) that raises an
189 error in Python 3.8, and fixed in a different way in :ghpull:`13559`.
253 error in Python 3.8, and fixed in a different way in :ghpull:`13559`.
190
254
191 .. _version 8.1:
255 .. _version 8.1:
192
256
193 IPython 8.1.0
257 IPython 8.1.0
194 -------------
258 -------------
195
259
196 IPython 8.1 is the first minor release after 8.0 and fixes a number of bugs and
260 IPython 8.1 is the first minor release after 8.0 and fixes a number of bugs and
197 Update a few behavior that were problematic with the 8.0 as with many new major
261 Update a few behavior that were problematic with the 8.0 as with many new major
198 release.
262 release.
199
263
200 Note that beyond the changes listed here, IPython 8.1.0 also contains all the
264 Note that beyond the changes listed here, IPython 8.1.0 also contains all the
201 features listed in :ref:`version 7.32`.
265 features listed in :ref:`version 7.32`.
202
266
203 - Misc and multiple fixes around quotation auto-closing. It is now disabled by
267 - Misc and multiple fixes around quotation auto-closing. It is now disabled by
204 default. Run with ``TerminalInteractiveShell.auto_match=True`` to re-enabled
268 default. Run with ``TerminalInteractiveShell.auto_match=True`` to re-enabled
205 - Require pygments>=2.4.0 :ghpull:`13459`, this was implicit in the code, but
269 - Require pygments>=2.4.0 :ghpull:`13459`, this was implicit in the code, but
206 is now explicit in ``setup.cfg``/``setup.py``
270 is now explicit in ``setup.cfg``/``setup.py``
207 - Docs improvement of ``core.magic_arguments`` examples. :ghpull:`13433`
271 - Docs improvement of ``core.magic_arguments`` examples. :ghpull:`13433`
208 - Multi-line edit executes too early with await. :ghpull:`13424`
272 - Multi-line edit executes too early with await. :ghpull:`13424`
209
273
210 - ``black`` is back as an optional dependency, and autoformatting disabled by
274 - ``black`` is back as an optional dependency, and autoformatting disabled by
211 default until some fixes are implemented (black improperly reformat magics).
275 default until some fixes are implemented (black improperly reformat magics).
212 :ghpull:`13471` Additionally the ability to use ``yapf`` as a code
276 :ghpull:`13471` Additionally the ability to use ``yapf`` as a code
213 reformatter has been added :ghpull:`13528` . You can use
277 reformatter has been added :ghpull:`13528` . You can use
214 ``TerminalInteractiveShell.autoformatter="black"``,
278 ``TerminalInteractiveShell.autoformatter="black"``,
215 ``TerminalInteractiveShell.autoformatter="yapf"`` to re-enable auto formating
279 ``TerminalInteractiveShell.autoformatter="yapf"`` to re-enable auto formating
216 with black, or switch to yapf.
280 with black, or switch to yapf.
217
281
218 - Fix and issue where ``display`` was not defined.
282 - Fix and issue where ``display`` was not defined.
219
283
220 - Auto suggestions are now configurable. Currently only
284 - Auto suggestions are now configurable. Currently only
221 ``AutoSuggestFromHistory`` (default) and ``None``. new provider contribution
285 ``AutoSuggestFromHistory`` (default) and ``None``. new provider contribution
222 welcomed. :ghpull:`13475`
286 welcomed. :ghpull:`13475`
223
287
224 - multiple packaging/testing improvement to simplify downstream packaging
288 - multiple packaging/testing improvement to simplify downstream packaging
225 (xfail with reasons, try to not access network...).
289 (xfail with reasons, try to not access network...).
226
290
227 - Update deprecation. ``InteractiveShell.magic`` internal method has been
291 - Update deprecation. ``InteractiveShell.magic`` internal method has been
228 deprecated for many years but did not emit a warning until now.
292 deprecated for many years but did not emit a warning until now.
229
293
230 - internal ``appended_to_syspath`` context manager has been deprecated.
294 - internal ``appended_to_syspath`` context manager has been deprecated.
231
295
232 - fix an issue with symlinks in virtualenv :ghpull:`13537` (Reverted in 8.1.1)
296 - fix an issue with symlinks in virtualenv :ghpull:`13537` (Reverted in 8.1.1)
233
297
234 - Fix an issue with vim mode, where cursor would not be reset on exit :ghpull:`13472`
298 - Fix an issue with vim mode, where cursor would not be reset on exit :ghpull:`13472`
235
299
236 - ipython directive now remove only known pseudo-decorators :ghpull:`13532`
300 - ipython directive now remove only known pseudo-decorators :ghpull:`13532`
237
301
238 - ``IPython/lib/security`` which used to be used for jupyter notebook has been
302 - ``IPython/lib/security`` which used to be used for jupyter notebook has been
239 removed.
303 removed.
240
304
241 - Fix an issue where ``async with`` would execute on new lines. :ghpull:`13436`
305 - Fix an issue where ``async with`` would execute on new lines. :ghpull:`13436`
242
306
243
307
244 We want to remind users that IPython is part of the Jupyter organisations, and
308 We want to remind users that IPython is part of the Jupyter organisations, and
245 thus governed by a Code of Conduct. Some of the behavior we have seen on GitHub is not acceptable.
309 thus governed by a Code of Conduct. Some of the behavior we have seen on GitHub is not acceptable.
246 Abuse and non-respectful comments on discussion will not be tolerated.
310 Abuse and non-respectful comments on discussion will not be tolerated.
247
311
248 Many thanks to all the contributors to this release, many of the above fixed issue and
312 Many thanks to all the contributors to this release, many of the above fixed issue and
249 new features where done by first time contributors, showing there is still
313 new features where done by first time contributors, showing there is still
250 plenty of easy contribution possible in IPython
314 plenty of easy contribution possible in IPython
251 . You can find all individual contributions
315 . You can find all individual contributions
252 to this milestone `on github <https://github.com/ipython/ipython/milestone/91>`__.
316 to this milestone `on github <https://github.com/ipython/ipython/milestone/91>`__.
253
317
254 Thanks as well to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
318 Thanks as well to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
255 work on IPython and related libraries. In particular the Lazy autoloading of
319 work on IPython and related libraries. In particular the Lazy autoloading of
256 magics that you will find described in the 7.32 release notes.
320 magics that you will find described in the 7.32 release notes.
257
321
258
322
259 .. _version 8.0.1:
323 .. _version 8.0.1:
260
324
261 IPython 8.0.1 (CVE-2022-21699)
325 IPython 8.0.1 (CVE-2022-21699)
262 ------------------------------
326 ------------------------------
263
327
264 IPython 8.0.1, 7.31.1 and 5.11 are security releases that change some default
328 IPython 8.0.1, 7.31.1 and 5.11 are security releases that change some default
265 values in order to prevent potential Execution with Unnecessary Privileges.
329 values in order to prevent potential Execution with Unnecessary Privileges.
266
330
267 Almost all version of IPython looks for configuration and profiles in current
331 Almost all version of IPython looks for configuration and profiles in current
268 working directory. Since IPython was developed before pip and environments
332 working directory. Since IPython was developed before pip and environments
269 existed it was used a convenient way to load code/packages in a project
333 existed it was used a convenient way to load code/packages in a project
270 dependant way.
334 dependant way.
271
335
272 In 2022, it is not necessary anymore, and can lead to confusing behavior where
336 In 2022, it is not necessary anymore, and can lead to confusing behavior where
273 for example cloning a repository and starting IPython or loading a notebook from
337 for example cloning a repository and starting IPython or loading a notebook from
274 any Jupyter-Compatible interface that has ipython set as a kernel can lead to
338 any Jupyter-Compatible interface that has ipython set as a kernel can lead to
275 code execution.
339 code execution.
276
340
277
341
278 I did not find any standard way for packaged to advertise CVEs they fix, I'm
342 I did not find any standard way for packaged to advertise CVEs they fix, I'm
279 thus trying to add a ``__patched_cves__`` attribute to the IPython module that
343 thus trying to add a ``__patched_cves__`` attribute to the IPython module that
280 list the CVEs that should have been fixed. This attribute is informational only
344 list the CVEs that should have been fixed. This attribute is informational only
281 as if a executable has a flaw, this value can always be changed by an attacker.
345 as if a executable has a flaw, this value can always be changed by an attacker.
282
346
283 .. code::
347 .. code::
284
348
285 In [1]: import IPython
349 In [1]: import IPython
286
350
287 In [2]: IPython.__patched_cves__
351 In [2]: IPython.__patched_cves__
288 Out[2]: {'CVE-2022-21699'}
352 Out[2]: {'CVE-2022-21699'}
289
353
290 In [3]: 'CVE-2022-21699' in IPython.__patched_cves__
354 In [3]: 'CVE-2022-21699' in IPython.__patched_cves__
291 Out[3]: True
355 Out[3]: True
292
356
293 Thus starting with this version:
357 Thus starting with this version:
294
358
295 - The current working directory is not searched anymore for profiles or
359 - The current working directory is not searched anymore for profiles or
296 configurations files.
360 configurations files.
297 - Added a ``__patched_cves__`` attribute (set of strings) to IPython module that contain
361 - Added a ``__patched_cves__`` attribute (set of strings) to IPython module that contain
298 the list of fixed CVE. This is informational only.
362 the list of fixed CVE. This is informational only.
299
363
300 Further details can be read on the `GitHub Advisory <https://github.com/ipython/ipython/security/advisories/GHSA-pq7m-3gw7-gq5x>`__
364 Further details can be read on the `GitHub Advisory <https://github.com/ipython/ipython/security/advisories/GHSA-pq7m-3gw7-gq5x>`__
301
365
302
366
303 .. _version 8.0:
367 .. _version 8.0:
304
368
305 IPython 8.0
369 IPython 8.0
306 -----------
370 -----------
307
371
308 IPython 8.0 is bringing a large number of new features and improvements to both the
372 IPython 8.0 is bringing a large number of new features and improvements to both the
309 user of the terminal and of the kernel via Jupyter. The removal of compatibility
373 user of the terminal and of the kernel via Jupyter. The removal of compatibility
310 with older version of Python is also the opportunity to do a couple of
374 with older version of Python is also the opportunity to do a couple of
311 performance improvements in particular with respect to startup time.
375 performance improvements in particular with respect to startup time.
312 The 8.x branch started diverging from its predecessor around IPython 7.12
376 The 8.x branch started diverging from its predecessor around IPython 7.12
313 (January 2020).
377 (January 2020).
314
378
315 This release contains 250+ pull requests, in addition to many of the features
379 This release contains 250+ pull requests, in addition to many of the features
316 and backports that have made it to the 7.x branch. Please see the
380 and backports that have made it to the 7.x branch. Please see the
317 `8.0 milestone <https://github.com/ipython/ipython/milestone/73?closed=1>`__ for the full list of pull requests.
381 `8.0 milestone <https://github.com/ipython/ipython/milestone/73?closed=1>`__ for the full list of pull requests.
318
382
319 Please feel free to send pull requests to updates those notes after release,
383 Please feel free to send pull requests to updates those notes after release,
320 I have likely forgotten a few things reviewing 250+ PRs.
384 I have likely forgotten a few things reviewing 250+ PRs.
321
385
322 Dependencies changes/downstream packaging
386 Dependencies changes/downstream packaging
323 -----------------------------------------
387 -----------------------------------------
324
388
325 Most of our building steps have been changed to be (mostly) declarative
389 Most of our building steps have been changed to be (mostly) declarative
326 and follow PEP 517. We are trying to completely remove ``setup.py`` (:ghpull:`13238`) and are
390 and follow PEP 517. We are trying to completely remove ``setup.py`` (:ghpull:`13238`) and are
327 looking for help to do so.
391 looking for help to do so.
328
392
329 - minimum supported ``traitlets`` version is now 5+
393 - minimum supported ``traitlets`` version is now 5+
330 - we now require ``stack_data``
394 - we now require ``stack_data``
331 - minimal Python is now 3.8
395 - minimal Python is now 3.8
332 - ``nose`` is not a testing requirement anymore
396 - ``nose`` is not a testing requirement anymore
333 - ``pytest`` replaces nose.
397 - ``pytest`` replaces nose.
334 - ``iptest``/``iptest3`` cli entrypoints do not exists anymore.
398 - ``iptest``/``iptest3`` cli entrypoints do not exists anymore.
335 - minimum officially support ``numpy`` version has been bumped, but this should
399 - minimum officially support ``numpy`` version has been bumped, but this should
336 not have much effect on packaging.
400 not have much effect on packaging.
337
401
338
402
339 Deprecation and removal
403 Deprecation and removal
340 -----------------------
404 -----------------------
341
405
342 We removed almost all features, arguments, functions, and modules that were
406 We removed almost all features, arguments, functions, and modules that were
343 marked as deprecated between IPython 1.0 and 5.0. As a reminder, 5.0 was released
407 marked as deprecated between IPython 1.0 and 5.0. As a reminder, 5.0 was released
344 in 2016, and 1.0 in 2013. Last release of the 5 branch was 5.10.0, in May 2020.
408 in 2016, and 1.0 in 2013. Last release of the 5 branch was 5.10.0, in May 2020.
345 The few remaining deprecated features we left have better deprecation warnings
409 The few remaining deprecated features we left have better deprecation warnings
346 or have been turned into explicit errors for better error messages.
410 or have been turned into explicit errors for better error messages.
347
411
348 I will use this occasion to add the following requests to anyone emitting a
412 I will use this occasion to add the following requests to anyone emitting a
349 deprecation warning:
413 deprecation warning:
350
414
351 - Please add at least ``stacklevel=2`` so that the warning is emitted into the
415 - Please add at least ``stacklevel=2`` so that the warning is emitted into the
352 caller context, and not the callee one.
416 caller context, and not the callee one.
353 - Please add **since which version** something is deprecated.
417 - Please add **since which version** something is deprecated.
354
418
355 As a side note, it is much easier to conditionally compare version
419 As a side note, it is much easier to conditionally compare version
356 numbers rather than using ``try/except`` when functionality changes with a version.
420 numbers rather than using ``try/except`` when functionality changes with a version.
357
421
358 I won't list all the removed features here, but modules like ``IPython.kernel``,
422 I won't list all the removed features here, but modules like ``IPython.kernel``,
359 which was just a shim module around ``ipykernel`` for the past 8 years, have been
423 which was just a shim module around ``ipykernel`` for the past 8 years, have been
360 removed, and so many other similar things that pre-date the name **Jupyter**
424 removed, and so many other similar things that pre-date the name **Jupyter**
361 itself.
425 itself.
362
426
363 We no longer need to add ``IPython.extensions`` to the PYTHONPATH because that is being
427 We no longer need to add ``IPython.extensions`` to the PYTHONPATH because that is being
364 handled by ``load_extension``.
428 handled by ``load_extension``.
365
429
366 We are also removing ``Cythonmagic``, ``sympyprinting`` and ``rmagic`` as they are now in
430 We are also removing ``Cythonmagic``, ``sympyprinting`` and ``rmagic`` as they are now in
367 other packages and no longer need to be inside IPython.
431 other packages and no longer need to be inside IPython.
368
432
369
433
370 Documentation
434 Documentation
371 -------------
435 -------------
372
436
373 The majority of our docstrings have now been reformatted and automatically fixed by
437 The majority of our docstrings have now been reformatted and automatically fixed by
374 the experimental `Vélin <https://pypi.org/project/velin/>`_ project to conform
438 the experimental `Vélin <https://pypi.org/project/velin/>`_ project to conform
375 to numpydoc.
439 to numpydoc.
376
440
377 Type annotations
441 Type annotations
378 ----------------
442 ----------------
379
443
380 While IPython itself is highly dynamic and can't be completely typed, many of
444 While IPython itself is highly dynamic and can't be completely typed, many of
381 the functions now have type annotations, and part of the codebase is now checked
445 the functions now have type annotations, and part of the codebase is now checked
382 by mypy.
446 by mypy.
383
447
384
448
385 Featured changes
449 Featured changes
386 ----------------
450 ----------------
387
451
388 Here is a features list of changes in IPython 8.0. This is of course non-exhaustive.
452 Here is a features list of changes in IPython 8.0. This is of course non-exhaustive.
389 Please note as well that many features have been added in the 7.x branch as well
453 Please note as well that many features have been added in the 7.x branch as well
390 (and hence why you want to read the 7.x what's new notes), in particular
454 (and hence why you want to read the 7.x what's new notes), in particular
391 features contributed by QuantStack (with respect to debugger protocol and Xeus
455 features contributed by QuantStack (with respect to debugger protocol and Xeus
392 Python), as well as many debugger features that I was pleased to implement as
456 Python), as well as many debugger features that I was pleased to implement as
393 part of my work at QuanSight and sponsored by DE Shaw.
457 part of my work at QuanSight and sponsored by DE Shaw.
394
458
395 Traceback improvements
459 Traceback improvements
396 ~~~~~~~~~~~~~~~~~~~~~~
460 ~~~~~~~~~~~~~~~~~~~~~~
397
461
398 Previously, error tracebacks for errors happening in code cells were showing a
462 Previously, error tracebacks for errors happening in code cells were showing a
399 hash, the one used for compiling the Python AST::
463 hash, the one used for compiling the Python AST::
400
464
401 In [1]: def foo():
465 In [1]: def foo():
402 ...: return 3 / 0
466 ...: return 3 / 0
403 ...:
467 ...:
404
468
405 In [2]: foo()
469 In [2]: foo()
406 ---------------------------------------------------------------------------
470 ---------------------------------------------------------------------------
407 ZeroDivisionError Traceback (most recent call last)
471 ZeroDivisionError Traceback (most recent call last)
408 <ipython-input-2-c19b6d9633cf> in <module>
472 <ipython-input-2-c19b6d9633cf> in <module>
409 ----> 1 foo()
473 ----> 1 foo()
410
474
411 <ipython-input-1-1595a74c32d5> in foo()
475 <ipython-input-1-1595a74c32d5> in foo()
412 1 def foo():
476 1 def foo():
413 ----> 2 return 3 / 0
477 ----> 2 return 3 / 0
414 3
478 3
415
479
416 ZeroDivisionError: division by zero
480 ZeroDivisionError: division by zero
417
481
418 The error traceback is now correctly formatted, showing the cell number in which the error happened::
482 The error traceback is now correctly formatted, showing the cell number in which the error happened::
419
483
420 In [1]: def foo():
484 In [1]: def foo():
421 ...: return 3 / 0
485 ...: return 3 / 0
422 ...:
486 ...:
423
487
424 Input In [2]: foo()
488 Input In [2]: foo()
425 ---------------------------------------------------------------------------
489 ---------------------------------------------------------------------------
426 ZeroDivisionError Traceback (most recent call last)
490 ZeroDivisionError Traceback (most recent call last)
427 input In [2], in <module>
491 input In [2], in <module>
428 ----> 1 foo()
492 ----> 1 foo()
429
493
430 Input In [1], in foo()
494 Input In [1], in foo()
431 1 def foo():
495 1 def foo():
432 ----> 2 return 3 / 0
496 ----> 2 return 3 / 0
433
497
434 ZeroDivisionError: division by zero
498 ZeroDivisionError: division by zero
435
499
436 The ``stack_data`` package has been integrated, which provides smarter information in the traceback;
500 The ``stack_data`` package has been integrated, which provides smarter information in the traceback;
437 in particular it will highlight the AST node where an error occurs which can help to quickly narrow down errors.
501 in particular it will highlight the AST node where an error occurs which can help to quickly narrow down errors.
438
502
439 For example in the following snippet::
503 For example in the following snippet::
440
504
441 def foo(i):
505 def foo(i):
442 x = [[[0]]]
506 x = [[[0]]]
443 return x[0][i][0]
507 return x[0][i][0]
444
508
445
509
446 def bar():
510 def bar():
447 return foo(0) + foo(
511 return foo(0) + foo(
448 1
512 1
449 ) + foo(2)
513 ) + foo(2)
450
514
451
515
452 calling ``bar()`` would raise an ``IndexError`` on the return line of ``foo``,
516 calling ``bar()`` would raise an ``IndexError`` on the return line of ``foo``,
453 and IPython 8.0 is capable of telling you where the index error occurs::
517 and IPython 8.0 is capable of telling you where the index error occurs::
454
518
455
519
456 IndexError
520 IndexError
457 Input In [2], in <module>
521 Input In [2], in <module>
458 ----> 1 bar()
522 ----> 1 bar()
459 ^^^^^
523 ^^^^^
460
524
461 Input In [1], in bar()
525 Input In [1], in bar()
462 6 def bar():
526 6 def bar():
463 ----> 7 return foo(0) + foo(
527 ----> 7 return foo(0) + foo(
464 ^^^^
528 ^^^^
465 8 1
529 8 1
466 ^^^^^^^^
530 ^^^^^^^^
467 9 ) + foo(2)
531 9 ) + foo(2)
468 ^^^^
532 ^^^^
469
533
470 Input In [1], in foo(i)
534 Input In [1], in foo(i)
471 1 def foo(i):
535 1 def foo(i):
472 2 x = [[[0]]]
536 2 x = [[[0]]]
473 ----> 3 return x[0][i][0]
537 ----> 3 return x[0][i][0]
474 ^^^^^^^
538 ^^^^^^^
475
539
476 The corresponding locations marked here with ``^`` will show up highlighted in
540 The corresponding locations marked here with ``^`` will show up highlighted in
477 the terminal and notebooks.
541 the terminal and notebooks.
478
542
479 Finally, a colon ``::`` and line number is appended after a filename in
543 Finally, a colon ``::`` and line number is appended after a filename in
480 traceback::
544 traceback::
481
545
482
546
483 ZeroDivisionError Traceback (most recent call last)
547 ZeroDivisionError Traceback (most recent call last)
484 File ~/error.py:4, in <module>
548 File ~/error.py:4, in <module>
485 1 def f():
549 1 def f():
486 2 1/0
550 2 1/0
487 ----> 4 f()
551 ----> 4 f()
488
552
489 File ~/error.py:2, in f()
553 File ~/error.py:2, in f()
490 1 def f():
554 1 def f():
491 ----> 2 1/0
555 ----> 2 1/0
492
556
493 Many terminals and editors have integrations enabling you to directly jump to the
557 Many terminals and editors have integrations enabling you to directly jump to the
494 relevant file/line when this syntax is used, so this small addition may have a high
558 relevant file/line when this syntax is used, so this small addition may have a high
495 impact on productivity.
559 impact on productivity.
496
560
497
561
498 Autosuggestions
562 Autosuggestions
499 ~~~~~~~~~~~~~~~
563 ~~~~~~~~~~~~~~~
500
564
501 Autosuggestion is a very useful feature available in `fish <https://fishshell.com/>`__, `zsh <https://en.wikipedia.org/wiki/Z_shell>`__, and `prompt-toolkit <https://python-prompt-toolkit.readthedocs.io/en/master/pages/asking_for_input.html#auto-suggestion>`__.
565 Autosuggestion is a very useful feature available in `fish <https://fishshell.com/>`__, `zsh <https://en.wikipedia.org/wiki/Z_shell>`__, and `prompt-toolkit <https://python-prompt-toolkit.readthedocs.io/en/master/pages/asking_for_input.html#auto-suggestion>`__.
502
566
503 `Ptpython <https://github.com/prompt-toolkit/ptpython#ptpython>`__ allows users to enable this feature in
567 `Ptpython <https://github.com/prompt-toolkit/ptpython#ptpython>`__ allows users to enable this feature in
504 `ptpython/config.py <https://github.com/prompt-toolkit/ptpython/blob/master/examples/ptpython_config/config.py#L90>`__.
568 `ptpython/config.py <https://github.com/prompt-toolkit/ptpython/blob/master/examples/ptpython_config/config.py#L90>`__.
505
569
506 This feature allows users to accept autosuggestions with ctrl e, ctrl f,
570 This feature allows users to accept autosuggestions with ctrl e, ctrl f,
507 or right arrow as described below.
571 or right arrow as described below.
508
572
509 1. Start ipython
573 1. Start ipython
510
574
511 .. image:: ../_images/8.0/auto_suggest_1_prompt_no_text.png
575 .. image:: ../_images/8.0/auto_suggest_1_prompt_no_text.png
512
576
513 2. Run ``print("hello")``
577 2. Run ``print("hello")``
514
578
515 .. image:: ../_images/8.0/auto_suggest_2_print_hello_suggest.png
579 .. image:: ../_images/8.0/auto_suggest_2_print_hello_suggest.png
516
580
517 3. start typing ``print`` again to see the autosuggestion
581 3. start typing ``print`` again to see the autosuggestion
518
582
519 .. image:: ../_images/8.0/auto_suggest_3_print_hello_suggest.png
583 .. image:: ../_images/8.0/auto_suggest_3_print_hello_suggest.png
520
584
521 4. Press ``ctrl-f``, or ``ctrl-e``, or ``right-arrow`` to accept the suggestion
585 4. Press ``ctrl-f``, or ``ctrl-e``, or ``right-arrow`` to accept the suggestion
522
586
523 .. image:: ../_images/8.0/auto_suggest_4_print_hello.png
587 .. image:: ../_images/8.0/auto_suggest_4_print_hello.png
524
588
525 You can also complete word by word:
589 You can also complete word by word:
526
590
527 1. Run ``def say_hello(): print("hello")``
591 1. Run ``def say_hello(): print("hello")``
528
592
529 .. image:: ../_images/8.0/auto_suggest_second_prompt.png
593 .. image:: ../_images/8.0/auto_suggest_second_prompt.png
530
594
531 2. Start typing the first letter if ``def`` to see the autosuggestion
595 2. Start typing the first letter if ``def`` to see the autosuggestion
532
596
533 .. image:: ../_images/8.0/auto_suggest_d_phantom.png
597 .. image:: ../_images/8.0/auto_suggest_d_phantom.png
534
598
535 3. Press ``alt-f`` (or ``escape`` followed by ``f``), to accept the first word of the suggestion
599 3. Press ``alt-f`` (or ``escape`` followed by ``f``), to accept the first word of the suggestion
536
600
537 .. image:: ../_images/8.0/auto_suggest_def_phantom.png
601 .. image:: ../_images/8.0/auto_suggest_def_phantom.png
538
602
539 Importantly, this feature does not interfere with tab completion:
603 Importantly, this feature does not interfere with tab completion:
540
604
541 1. After running ``def say_hello(): print("hello")``, press d
605 1. After running ``def say_hello(): print("hello")``, press d
542
606
543 .. image:: ../_images/8.0/auto_suggest_d_phantom.png
607 .. image:: ../_images/8.0/auto_suggest_d_phantom.png
544
608
545 2. Press Tab to start tab completion
609 2. Press Tab to start tab completion
546
610
547 .. image:: ../_images/8.0/auto_suggest_d_completions.png
611 .. image:: ../_images/8.0/auto_suggest_d_completions.png
548
612
549 3A. Press Tab again to select the first option
613 3A. Press Tab again to select the first option
550
614
551 .. image:: ../_images/8.0/auto_suggest_def_completions.png
615 .. image:: ../_images/8.0/auto_suggest_def_completions.png
552
616
553 3B. Press ``alt f`` (``escape``, ``f``) to accept to accept the first word of the suggestion
617 3B. Press ``alt f`` (``escape``, ``f``) to accept to accept the first word of the suggestion
554
618
555 .. image:: ../_images/8.0/auto_suggest_def_phantom.png
619 .. image:: ../_images/8.0/auto_suggest_def_phantom.png
556
620
557 3C. Press ``ctrl-f`` or ``ctrl-e`` to accept the entire suggestion
621 3C. Press ``ctrl-f`` or ``ctrl-e`` to accept the entire suggestion
558
622
559 .. image:: ../_images/8.0/auto_suggest_match_parens.png
623 .. image:: ../_images/8.0/auto_suggest_match_parens.png
560
624
561
625
562 Currently, autosuggestions are only shown in the emacs or vi insert editing modes:
626 Currently, autosuggestions are only shown in the emacs or vi insert editing modes:
563
627
564 - The ctrl e, ctrl f, and alt f shortcuts work by default in emacs mode.
628 - The ctrl e, ctrl f, and alt f shortcuts work by default in emacs mode.
565 - To use these shortcuts in vi insert mode, you will have to create `custom keybindings in your config.py <https://github.com/mskar/setup/commit/2892fcee46f9f80ef7788f0749edc99daccc52f4/>`__.
629 - To use these shortcuts in vi insert mode, you will have to create `custom keybindings in your config.py <https://github.com/mskar/setup/commit/2892fcee46f9f80ef7788f0749edc99daccc52f4/>`__.
566
630
567
631
568 Show pinfo information in ipdb using "?" and "??"
632 Show pinfo information in ipdb using "?" and "??"
569 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
633 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
570
634
571 In IPDB, it is now possible to show the information about an object using "?"
635 In IPDB, it is now possible to show the information about an object using "?"
572 and "??", in much the same way that it can be done when using the IPython prompt::
636 and "??", in much the same way that it can be done when using the IPython prompt::
573
637
574 ipdb> partial?
638 ipdb> partial?
575 Init signature: partial(self, /, *args, **kwargs)
639 Init signature: partial(self, /, *args, **kwargs)
576 Docstring:
640 Docstring:
577 partial(func, *args, **keywords) - new function with partial application
641 partial(func, *args, **keywords) - new function with partial application
578 of the given arguments and keywords.
642 of the given arguments and keywords.
579 File: ~/.pyenv/versions/3.8.6/lib/python3.8/functools.py
643 File: ~/.pyenv/versions/3.8.6/lib/python3.8/functools.py
580 Type: type
644 Type: type
581 Subclasses:
645 Subclasses:
582
646
583 Previously, ``pinfo`` or ``pinfo2`` command had to be used for this purpose.
647 Previously, ``pinfo`` or ``pinfo2`` command had to be used for this purpose.
584
648
585
649
586 Autoreload 3 feature
650 Autoreload 3 feature
587 ~~~~~~~~~~~~~~~~~~~~
651 ~~~~~~~~~~~~~~~~~~~~
588
652
589 Example: When an IPython session is run with the 'autoreload' extension loaded,
653 Example: When an IPython session is run with the 'autoreload' extension loaded,
590 you will now have the option '3' to select, which means the following:
654 you will now have the option '3' to select, which means the following:
591
655
592 1. replicate all functionality from option 2
656 1. replicate all functionality from option 2
593 2. autoload all new funcs/classes/enums/globals from the module when they are added
657 2. autoload all new funcs/classes/enums/globals from the module when they are added
594 3. autoload all newly imported funcs/classes/enums/globals from external modules
658 3. autoload all newly imported funcs/classes/enums/globals from external modules
595
659
596 Try ``%autoreload 3`` in an IPython session after running ``%load_ext autoreload``.
660 Try ``%autoreload 3`` in an IPython session after running ``%load_ext autoreload``.
597
661
598 For more information please see the following unit test : ``extensions/tests/test_autoreload.py:test_autoload_newly_added_objects``
662 For more information please see the following unit test : ``extensions/tests/test_autoreload.py:test_autoload_newly_added_objects``
599
663
600 Auto formatting with black in the CLI
664 Auto formatting with black in the CLI
601 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
665 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
602
666
603 This feature was present in 7.x, but disabled by default.
667 This feature was present in 7.x, but disabled by default.
604
668
605 In 8.0, input was automatically reformatted with Black when black was installed.
669 In 8.0, input was automatically reformatted with Black when black was installed.
606 This feature has been reverted for the time being.
670 This feature has been reverted for the time being.
607 You can re-enable it by setting ``TerminalInteractiveShell.autoformatter`` to ``"black"``
671 You can re-enable it by setting ``TerminalInteractiveShell.autoformatter`` to ``"black"``
608
672
609 History Range Glob feature
673 History Range Glob feature
610 ~~~~~~~~~~~~~~~~~~~~~~~~~~
674 ~~~~~~~~~~~~~~~~~~~~~~~~~~
611
675
612 Previously, when using ``%history``, users could specify either
676 Previously, when using ``%history``, users could specify either
613 a range of sessions and lines, for example:
677 a range of sessions and lines, for example:
614
678
615 .. code-block:: python
679 .. code-block:: python
616
680
617 ~8/1-~6/5 # see history from the first line of 8 sessions ago,
681 ~8/1-~6/5 # see history from the first line of 8 sessions ago,
618 # to the fifth line of 6 sessions ago.``
682 # to the fifth line of 6 sessions ago.``
619
683
620 Or users could specify a glob pattern:
684 Or users could specify a glob pattern:
621
685
622 .. code-block:: python
686 .. code-block:: python
623
687
624 -g <pattern> # glob ALL history for the specified pattern.
688 -g <pattern> # glob ALL history for the specified pattern.
625
689
626 However users could *not* specify both.
690 However users could *not* specify both.
627
691
628 If a user *did* specify both a range and a glob pattern,
692 If a user *did* specify both a range and a glob pattern,
629 then the glob pattern would be used (globbing *all* history) *and the range would be ignored*.
693 then the glob pattern would be used (globbing *all* history) *and the range would be ignored*.
630
694
631 With this enhancement, if a user specifies both a range and a glob pattern, then the glob pattern will be applied to the specified range of history.
695 With this enhancement, if a user specifies both a range and a glob pattern, then the glob pattern will be applied to the specified range of history.
632
696
633 Don't start a multi-line cell with sunken parenthesis
697 Don't start a multi-line cell with sunken parenthesis
634 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
698 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
635
699
636 From now on, IPython will not ask for the next line of input when given a single
700 From now on, IPython will not ask for the next line of input when given a single
637 line with more closing than opening brackets. For example, this means that if
701 line with more closing than opening brackets. For example, this means that if
638 you (mis)type ``]]`` instead of ``[]``, a ``SyntaxError`` will show up, instead of
702 you (mis)type ``]]`` instead of ``[]``, a ``SyntaxError`` will show up, instead of
639 the ``...:`` prompt continuation.
703 the ``...:`` prompt continuation.
640
704
641 IPython shell for ipdb interact
705 IPython shell for ipdb interact
642 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
706 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
643
707
644 The ipdb ``interact`` starts an IPython shell instead of Python's built-in ``code.interact()``.
708 The ipdb ``interact`` starts an IPython shell instead of Python's built-in ``code.interact()``.
645
709
646 Automatic Vi prompt stripping
710 Automatic Vi prompt stripping
647 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
711 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
648
712
649 When pasting code into IPython, it will strip the leading prompt characters if
713 When pasting code into IPython, it will strip the leading prompt characters if
650 there are any. For example, you can paste the following code into the console -
714 there are any. For example, you can paste the following code into the console -
651 it will still work, even though each line is prefixed with prompts (``In``,
715 it will still work, even though each line is prefixed with prompts (``In``,
652 ``Out``)::
716 ``Out``)::
653
717
654 In [1]: 2 * 2 == 4
718 In [1]: 2 * 2 == 4
655 Out[1]: True
719 Out[1]: True
656
720
657 In [2]: print("This still works as pasted")
721 In [2]: print("This still works as pasted")
658
722
659
723
660 Previously, this was not the case for the Vi-mode prompts::
724 Previously, this was not the case for the Vi-mode prompts::
661
725
662 In [1]: [ins] In [13]: 2 * 2 == 4
726 In [1]: [ins] In [13]: 2 * 2 == 4
663 ...: Out[13]: True
727 ...: Out[13]: True
664 ...:
728 ...:
665 File "<ipython-input-1-727bb88eaf33>", line 1
729 File "<ipython-input-1-727bb88eaf33>", line 1
666 [ins] In [13]: 2 * 2 == 4
730 [ins] In [13]: 2 * 2 == 4
667 ^
731 ^
668 SyntaxError: invalid syntax
732 SyntaxError: invalid syntax
669
733
670 This is now fixed, and Vi prompt prefixes - ``[ins]`` and ``[nav]`` - are
734 This is now fixed, and Vi prompt prefixes - ``[ins]`` and ``[nav]`` - are
671 skipped just as the normal ``In`` would be.
735 skipped just as the normal ``In`` would be.
672
736
673 IPython shell can be started in the Vi mode using ``ipython --TerminalInteractiveShell.editing_mode=vi``,
737 IPython shell can be started in the Vi mode using ``ipython --TerminalInteractiveShell.editing_mode=vi``,
674 You should be able to change mode dynamically with ``%config TerminalInteractiveShell.editing_mode='vi'``
738 You should be able to change mode dynamically with ``%config TerminalInteractiveShell.editing_mode='vi'``
675
739
676 Empty History Ranges
740 Empty History Ranges
677 ~~~~~~~~~~~~~~~~~~~~
741 ~~~~~~~~~~~~~~~~~~~~
678
742
679 A number of magics that take history ranges can now be used with an empty
743 A number of magics that take history ranges can now be used with an empty
680 range. These magics are:
744 range. These magics are:
681
745
682 * ``%save``
746 * ``%save``
683 * ``%load``
747 * ``%load``
684 * ``%pastebin``
748 * ``%pastebin``
685 * ``%pycat``
749 * ``%pycat``
686
750
687 Using them this way will make them take the history of the current session up
751 Using them this way will make them take the history of the current session up
688 to the point of the magic call (such that the magic itself will not be
752 to the point of the magic call (such that the magic itself will not be
689 included).
753 included).
690
754
691 Therefore it is now possible to save the whole history to a file using
755 Therefore it is now possible to save the whole history to a file using
692 ``%save <filename>``, load and edit it using ``%load`` (makes for a nice usage
756 ``%save <filename>``, load and edit it using ``%load`` (makes for a nice usage
693 when followed with :kbd:`F2`), send it to `dpaste.org <http://dpast.org>`_ using
757 when followed with :kbd:`F2`), send it to `dpaste.org <http://dpast.org>`_ using
694 ``%pastebin``, or view the whole thing syntax-highlighted with a single
758 ``%pastebin``, or view the whole thing syntax-highlighted with a single
695 ``%pycat``.
759 ``%pycat``.
696
760
697
761
698 Windows timing implementation: Switch to process_time
762 Windows timing implementation: Switch to process_time
699 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
763 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
700 Timing on Windows, for example with ``%%time``, was changed from being based on ``time.perf_counter``
764 Timing on Windows, for example with ``%%time``, was changed from being based on ``time.perf_counter``
701 (which counted time even when the process was sleeping) to being based on ``time.process_time`` instead
765 (which counted time even when the process was sleeping) to being based on ``time.process_time`` instead
702 (which only counts CPU time). This brings it closer to the behavior on Linux. See :ghpull:`12984`.
766 (which only counts CPU time). This brings it closer to the behavior on Linux. See :ghpull:`12984`.
703
767
704 Miscellaneous
768 Miscellaneous
705 ~~~~~~~~~~~~~
769 ~~~~~~~~~~~~~
706 - Non-text formatters are not disabled in the terminal, which should simplify
770 - Non-text formatters are not disabled in the terminal, which should simplify
707 writing extensions displaying images or other mimetypes in supporting terminals.
771 writing extensions displaying images or other mimetypes in supporting terminals.
708 :ghpull:`12315`
772 :ghpull:`12315`
709 - It is now possible to automatically insert matching brackets in Terminal IPython using the
773 - It is now possible to automatically insert matching brackets in Terminal IPython using the
710 ``TerminalInteractiveShell.auto_match=True`` option. :ghpull:`12586`
774 ``TerminalInteractiveShell.auto_match=True`` option. :ghpull:`12586`
711 - We are thinking of deprecating the current ``%%javascript`` magic in favor of a better replacement. See :ghpull:`13376`.
775 - We are thinking of deprecating the current ``%%javascript`` magic in favor of a better replacement. See :ghpull:`13376`.
712 - ``~`` is now expanded when part of a path in most magics :ghpull:`13385`
776 - ``~`` is now expanded when part of a path in most magics :ghpull:`13385`
713 - ``%/%%timeit`` magic now adds a comma every thousands to make reading a long number easier :ghpull:`13379`
777 - ``%/%%timeit`` magic now adds a comma every thousands to make reading a long number easier :ghpull:`13379`
714 - ``"info"`` messages can now be customised to hide some fields :ghpull:`13343`
778 - ``"info"`` messages can now be customised to hide some fields :ghpull:`13343`
715 - ``collections.UserList`` now pretty-prints :ghpull:`13320`
779 - ``collections.UserList`` now pretty-prints :ghpull:`13320`
716 - The debugger now has a persistent history, which should make it less
780 - The debugger now has a persistent history, which should make it less
717 annoying to retype commands :ghpull:`13246`
781 annoying to retype commands :ghpull:`13246`
718 - ``!pip`` ``!conda`` ``!cd`` or ``!ls`` are likely doing the wrong thing. We
782 - ``!pip`` ``!conda`` ``!cd`` or ``!ls`` are likely doing the wrong thing. We
719 now warn users if they use one of those commands. :ghpull:`12954`
783 now warn users if they use one of those commands. :ghpull:`12954`
720 - Make ``%precision`` work for ``numpy.float64`` type :ghpull:`12902`
784 - Make ``%precision`` work for ``numpy.float64`` type :ghpull:`12902`
721
785
722 Re-added support for XDG config directories
786 Re-added support for XDG config directories
723 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
787 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
724
788
725 XDG support through the years comes and goes. There is a tension between having
789 XDG support through the years comes and goes. There is a tension between having
726 an identical location for configuration in all platforms versus having simple instructions.
790 an identical location for configuration in all platforms versus having simple instructions.
727 After initial failures a couple of years ago, IPython was modified to automatically migrate XDG
791 After initial failures a couple of years ago, IPython was modified to automatically migrate XDG
728 config files back into ``~/.ipython``. That migration code has now been removed.
792 config files back into ``~/.ipython``. That migration code has now been removed.
729 IPython now checks the XDG locations, so if you _manually_ move your config
793 IPython now checks the XDG locations, so if you _manually_ move your config
730 files to your preferred location, IPython will not move them back.
794 files to your preferred location, IPython will not move them back.
731
795
732
796
733 Preparing for Python 3.10
797 Preparing for Python 3.10
734 -------------------------
798 -------------------------
735
799
736 To prepare for Python 3.10, we have started working on removing reliance and
800 To prepare for Python 3.10, we have started working on removing reliance and
737 any dependency that is not compatible with Python 3.10. This includes migrating our
801 any dependency that is not compatible with Python 3.10. This includes migrating our
738 test suite to pytest and starting to remove nose. This also means that the
802 test suite to pytest and starting to remove nose. This also means that the
739 ``iptest`` command is now gone and all testing is via pytest.
803 ``iptest`` command is now gone and all testing is via pytest.
740
804
741 This was in large part thanks to the NumFOCUS Small Developer grant, which enabled us to
805 This was in large part thanks to the NumFOCUS Small Developer grant, which enabled us to
742 allocate \$4000 to hire `Nikita Kniazev (@Kojoley) <https://github.com/Kojoley>`_,
806 allocate \$4000 to hire `Nikita Kniazev (@Kojoley) <https://github.com/Kojoley>`_,
743 who did a fantastic job at updating our code base, migrating to pytest, pushing
807 who did a fantastic job at updating our code base, migrating to pytest, pushing
744 our coverage, and fixing a large number of bugs. I highly recommend contacting
808 our coverage, and fixing a large number of bugs. I highly recommend contacting
745 them if you need help with C++ and Python projects.
809 them if you need help with C++ and Python projects.
746
810
747 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+>`__
811 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+>`__
748
812
749 Removing support for older Python versions
813 Removing support for older Python versions
750 ------------------------------------------
814 ------------------------------------------
751
815
752
816
753 We are removing support for Python up through 3.7, allowing internal code to use the more
817 We are removing support for Python up through 3.7, allowing internal code to use the more
754 efficient ``pathlib`` and to make better use of type annotations.
818 efficient ``pathlib`` and to make better use of type annotations.
755
819
756 .. image:: ../_images/8.0/pathlib_pathlib_everywhere.jpg
820 .. image:: ../_images/8.0/pathlib_pathlib_everywhere.jpg
757 :alt: "Meme image of Toy Story with Woody and Buzz, with the text 'pathlib, pathlib everywhere'"
821 :alt: "Meme image of Toy Story with Woody and Buzz, with the text 'pathlib, pathlib everywhere'"
758
822
759
823
760 We had about 34 PRs only to update some logic to update some functions from managing strings to
824 We had about 34 PRs only to update some logic to update some functions from managing strings to
761 using Pathlib.
825 using Pathlib.
762
826
763 The completer has also seen significant updates and now makes use of newer Jedi APIs,
827 The completer has also seen significant updates and now makes use of newer Jedi APIs,
764 offering faster and more reliable tab completion.
828 offering faster and more reliable tab completion.
765
829
766 Misc Statistics
830 Misc Statistics
767 ---------------
831 ---------------
768
832
769 Here are some numbers::
833 Here are some numbers::
770
834
771 7.x: 296 files, 12561 blank lines, 20282 comments, 35142 line of code.
835 7.x: 296 files, 12561 blank lines, 20282 comments, 35142 line of code.
772 8.0: 252 files, 12053 blank lines, 19232 comments, 34505 line of code.
836 8.0: 252 files, 12053 blank lines, 19232 comments, 34505 line of code.
773
837
774 $ git diff --stat 7.x...master | tail -1
838 $ git diff --stat 7.x...master | tail -1
775 340 files changed, 13399 insertions(+), 12421 deletions(-)
839 340 files changed, 13399 insertions(+), 12421 deletions(-)
776
840
777 We have commits from 162 authors, who contributed 1916 commits in 23 month, excluding merges (to not bias toward
841 We have commits from 162 authors, who contributed 1916 commits in 23 month, excluding merges (to not bias toward
778 maintainers pushing buttons).::
842 maintainers pushing buttons).::
779
843
780 $ git shortlog -s --no-merges 7.x...master | sort -nr
844 $ git shortlog -s --no-merges 7.x...master | sort -nr
781 535 Matthias Bussonnier
845 535 Matthias Bussonnier
782 86 Nikita Kniazev
846 86 Nikita Kniazev
783 69 Blazej Michalik
847 69 Blazej Michalik
784 49 Samuel Gaist
848 49 Samuel Gaist
785 27 Itamar Turner-Trauring
849 27 Itamar Turner-Trauring
786 18 Spas Kalaydzhisyki
850 18 Spas Kalaydzhisyki
787 17 Thomas Kluyver
851 17 Thomas Kluyver
788 17 Quentin Peter
852 17 Quentin Peter
789 17 James Morris
853 17 James Morris
790 17 Artur Svistunov
854 17 Artur Svistunov
791 15 Bart Skowron
855 15 Bart Skowron
792 14 Alex Hall
856 14 Alex Hall
793 13 rushabh-v
857 13 rushabh-v
794 13 Terry Davis
858 13 Terry Davis
795 13 Benjamin Ragan-Kelley
859 13 Benjamin Ragan-Kelley
796 8 martinRenou
860 8 martinRenou
797 8 farisachugthai
861 8 farisachugthai
798 7 dswij
862 7 dswij
799 7 Gal B
863 7 Gal B
800 7 Corentin Cadiou
864 7 Corentin Cadiou
801 6 yuji96
865 6 yuji96
802 6 Martin Skarzynski
866 6 Martin Skarzynski
803 6 Justin Palmer
867 6 Justin Palmer
804 6 Daniel Goldfarb
868 6 Daniel Goldfarb
805 6 Ben Greiner
869 6 Ben Greiner
806 5 Sammy Al Hashemi
870 5 Sammy Al Hashemi
807 5 Paul Ivanov
871 5 Paul Ivanov
808 5 Inception95
872 5 Inception95
809 5 Eyenpi
873 5 Eyenpi
810 5 Douglas Blank
874 5 Douglas Blank
811 5 Coco Mishra
875 5 Coco Mishra
812 5 Bibo Hao
876 5 Bibo Hao
813 5 André A. Gomes
877 5 André A. Gomes
814 5 Ahmed Fasih
878 5 Ahmed Fasih
815 4 takuya fujiwara
879 4 takuya fujiwara
816 4 palewire
880 4 palewire
817 4 Thomas A Caswell
881 4 Thomas A Caswell
818 4 Talley Lambert
882 4 Talley Lambert
819 4 Scott Sanderson
883 4 Scott Sanderson
820 4 Ram Rachum
884 4 Ram Rachum
821 4 Nick Muoh
885 4 Nick Muoh
822 4 Nathan Goldbaum
886 4 Nathan Goldbaum
823 4 Mithil Poojary
887 4 Mithil Poojary
824 4 Michael T
888 4 Michael T
825 4 Jakub Klus
889 4 Jakub Klus
826 4 Ian Castleden
890 4 Ian Castleden
827 4 Eli Rykoff
891 4 Eli Rykoff
828 4 Ashwin Vishnu
892 4 Ashwin Vishnu
829 3 谭九鼎
893 3 谭九鼎
830 3 sleeping
894 3 sleeping
831 3 Sylvain Corlay
895 3 Sylvain Corlay
832 3 Peter Corke
896 3 Peter Corke
833 3 Paul Bissex
897 3 Paul Bissex
834 3 Matthew Feickert
898 3 Matthew Feickert
835 3 Fernando Perez
899 3 Fernando Perez
836 3 Eric Wieser
900 3 Eric Wieser
837 3 Daniel Mietchen
901 3 Daniel Mietchen
838 3 Aditya Sathe
902 3 Aditya Sathe
839 3 007vedant
903 3 007vedant
840 2 rchiodo
904 2 rchiodo
841 2 nicolaslazo
905 2 nicolaslazo
842 2 luttik
906 2 luttik
843 2 gorogoroumaru
907 2 gorogoroumaru
844 2 foobarbyte
908 2 foobarbyte
845 2 bar-hen
909 2 bar-hen
846 2 Theo Ouzhinski
910 2 Theo Ouzhinski
847 2 Strawkage
911 2 Strawkage
848 2 Samreen Zarroug
912 2 Samreen Zarroug
849 2 Pete Blois
913 2 Pete Blois
850 2 Meysam Azad
914 2 Meysam Azad
851 2 Matthieu Ancellin
915 2 Matthieu Ancellin
852 2 Mark Schmitz
916 2 Mark Schmitz
853 2 Maor Kleinberger
917 2 Maor Kleinberger
854 2 MRCWirtz
918 2 MRCWirtz
855 2 Lumir Balhar
919 2 Lumir Balhar
856 2 Julien Rabinow
920 2 Julien Rabinow
857 2 Juan Luis Cano Rodríguez
921 2 Juan Luis Cano Rodríguez
858 2 Joyce Er
922 2 Joyce Er
859 2 Jakub
923 2 Jakub
860 2 Faris A Chugthai
924 2 Faris A Chugthai
861 2 Ethan Madden
925 2 Ethan Madden
862 2 Dimitri Papadopoulos
926 2 Dimitri Papadopoulos
863 2 Diego Fernandez
927 2 Diego Fernandez
864 2 Daniel Shimon
928 2 Daniel Shimon
865 2 Coco Bennett
929 2 Coco Bennett
866 2 Carlos Cordoba
930 2 Carlos Cordoba
867 2 Boyuan Liu
931 2 Boyuan Liu
868 2 BaoGiang HoangVu
932 2 BaoGiang HoangVu
869 2 Augusto
933 2 Augusto
870 2 Arthur Svistunov
934 2 Arthur Svistunov
871 2 Arthur Moreira
935 2 Arthur Moreira
872 2 Ali Nabipour
936 2 Ali Nabipour
873 2 Adam Hackbarth
937 2 Adam Hackbarth
874 1 richard
938 1 richard
875 1 linar-jether
939 1 linar-jether
876 1 lbennett
940 1 lbennett
877 1 juacrumar
941 1 juacrumar
878 1 gpotter2
942 1 gpotter2
879 1 digitalvirtuoso
943 1 digitalvirtuoso
880 1 dalthviz
944 1 dalthviz
881 1 Yonatan Goldschmidt
945 1 Yonatan Goldschmidt
882 1 Tomasz Kłoczko
946 1 Tomasz Kłoczko
883 1 Tobias Bengfort
947 1 Tobias Bengfort
884 1 Timur Kushukov
948 1 Timur Kushukov
885 1 Thomas
949 1 Thomas
886 1 Snir Broshi
950 1 Snir Broshi
887 1 Shao Yang Hong
951 1 Shao Yang Hong
888 1 Sanjana-03
952 1 Sanjana-03
889 1 Romulo Filho
953 1 Romulo Filho
890 1 Rodolfo Carvalho
954 1 Rodolfo Carvalho
891 1 Richard Shadrach
955 1 Richard Shadrach
892 1 Reilly Tucker Siemens
956 1 Reilly Tucker Siemens
893 1 Rakessh Roshan
957 1 Rakessh Roshan
894 1 Piers Titus van der Torren
958 1 Piers Titus van der Torren
895 1 PhanatosZou
959 1 PhanatosZou
896 1 Pavel Safronov
960 1 Pavel Safronov
897 1 Paulo S. Costa
961 1 Paulo S. Costa
898 1 Paul McCarthy
962 1 Paul McCarthy
899 1 NotWearingPants
963 1 NotWearingPants
900 1 Naelson Douglas
964 1 Naelson Douglas
901 1 Michael Tiemann
965 1 Michael Tiemann
902 1 Matt Wozniski
966 1 Matt Wozniski
903 1 Markus Wageringel
967 1 Markus Wageringel
904 1 Marcus Wirtz
968 1 Marcus Wirtz
905 1 Marcio Mazza
969 1 Marcio Mazza
906 1 Lumír 'Frenzy' Balhar
970 1 Lumír 'Frenzy' Balhar
907 1 Lightyagami1
971 1 Lightyagami1
908 1 Leon Anavi
972 1 Leon Anavi
909 1 LeafyLi
973 1 LeafyLi
910 1 L0uisJ0shua
974 1 L0uisJ0shua
911 1 Kyle Cutler
975 1 Kyle Cutler
912 1 Krzysztof Cybulski
976 1 Krzysztof Cybulski
913 1 Kevin Kirsche
977 1 Kevin Kirsche
914 1 KIU Shueng Chuan
978 1 KIU Shueng Chuan
915 1 Jonathan Slenders
979 1 Jonathan Slenders
916 1 Jay Qi
980 1 Jay Qi
917 1 Jake VanderPlas
981 1 Jake VanderPlas
918 1 Iwan Briquemont
982 1 Iwan Briquemont
919 1 Hussaina Begum Nandyala
983 1 Hussaina Begum Nandyala
920 1 Gordon Ball
984 1 Gordon Ball
921 1 Gabriel Simonetto
985 1 Gabriel Simonetto
922 1 Frank Tobia
986 1 Frank Tobia
923 1 Erik
987 1 Erik
924 1 Elliott Sales de Andrade
988 1 Elliott Sales de Andrade
925 1 Daniel Hahler
989 1 Daniel Hahler
926 1 Dan Green-Leipciger
990 1 Dan Green-Leipciger
927 1 Dan Green
991 1 Dan Green
928 1 Damian Yurzola
992 1 Damian Yurzola
929 1 Coon, Ethan T
993 1 Coon, Ethan T
930 1 Carol Willing
994 1 Carol Willing
931 1 Brian Lee
995 1 Brian Lee
932 1 Brendan Gerrity
996 1 Brendan Gerrity
933 1 Blake Griffin
997 1 Blake Griffin
934 1 Bastian Ebeling
998 1 Bastian Ebeling
935 1 Bartosz Telenczuk
999 1 Bartosz Telenczuk
936 1 Ankitsingh6299
1000 1 Ankitsingh6299
937 1 Andrew Port
1001 1 Andrew Port
938 1 Andrew J. Hesford
1002 1 Andrew J. Hesford
939 1 Albert Zhang
1003 1 Albert Zhang
940 1 Adam Johnson
1004 1 Adam Johnson
941
1005
942 This does not, of course, represent non-code contributions, for which we are also grateful.
1006 This does not, of course, represent non-code contributions, for which we are also grateful.
943
1007
944
1008
945 API Changes using Frappuccino
1009 API Changes using Frappuccino
946 -----------------------------
1010 -----------------------------
947
1011
948 This is an experimental exhaustive API difference using `Frappuccino <https://pypi.org/project/frappuccino/>`_
1012 This is an experimental exhaustive API difference using `Frappuccino <https://pypi.org/project/frappuccino/>`_
949
1013
950
1014
951 The following items are new in IPython 8.0 ::
1015 The following items are new in IPython 8.0 ::
952
1016
953 + IPython.core.async_helpers.get_asyncio_loop()
1017 + IPython.core.async_helpers.get_asyncio_loop()
954 + IPython.core.completer.Dict
1018 + IPython.core.completer.Dict
955 + IPython.core.completer.Pattern
1019 + IPython.core.completer.Pattern
956 + IPython.core.completer.Sequence
1020 + IPython.core.completer.Sequence
957 + IPython.core.completer.__skip_doctest__
1021 + IPython.core.completer.__skip_doctest__
958 + IPython.core.debugger.Pdb.precmd(self, line)
1022 + IPython.core.debugger.Pdb.precmd(self, line)
959 + IPython.core.debugger.__skip_doctest__
1023 + IPython.core.debugger.__skip_doctest__
960 + IPython.core.display.__getattr__(name)
1024 + IPython.core.display.__getattr__(name)
961 + IPython.core.display.warn
1025 + IPython.core.display.warn
962 + IPython.core.display_functions
1026 + IPython.core.display_functions
963 + IPython.core.display_functions.DisplayHandle
1027 + IPython.core.display_functions.DisplayHandle
964 + IPython.core.display_functions.DisplayHandle.display(self, obj, **kwargs)
1028 + IPython.core.display_functions.DisplayHandle.display(self, obj, **kwargs)
965 + IPython.core.display_functions.DisplayHandle.update(self, obj, **kwargs)
1029 + IPython.core.display_functions.DisplayHandle.update(self, obj, **kwargs)
966 + IPython.core.display_functions.__all__
1030 + IPython.core.display_functions.__all__
967 + IPython.core.display_functions.__builtins__
1031 + IPython.core.display_functions.__builtins__
968 + IPython.core.display_functions.__cached__
1032 + IPython.core.display_functions.__cached__
969 + IPython.core.display_functions.__doc__
1033 + IPython.core.display_functions.__doc__
970 + IPython.core.display_functions.__file__
1034 + IPython.core.display_functions.__file__
971 + IPython.core.display_functions.__loader__
1035 + IPython.core.display_functions.__loader__
972 + IPython.core.display_functions.__name__
1036 + IPython.core.display_functions.__name__
973 + IPython.core.display_functions.__package__
1037 + IPython.core.display_functions.__package__
974 + IPython.core.display_functions.__spec__
1038 + IPython.core.display_functions.__spec__
975 + IPython.core.display_functions.b2a_hex
1039 + IPython.core.display_functions.b2a_hex
976 + IPython.core.display_functions.clear_output(wait=False)
1040 + IPython.core.display_functions.clear_output(wait=False)
977 + IPython.core.display_functions.display(*objs, include='None', exclude='None', metadata='None', transient='None', display_id='None', raw=False, clear=False, **kwargs)
1041 + IPython.core.display_functions.display(*objs, include='None', exclude='None', metadata='None', transient='None', display_id='None', raw=False, clear=False, **kwargs)
978 + IPython.core.display_functions.publish_display_data(data, metadata='None', source='<deprecated>', *, transient='None', **kwargs)
1042 + IPython.core.display_functions.publish_display_data(data, metadata='None', source='<deprecated>', *, transient='None', **kwargs)
979 + IPython.core.display_functions.update_display(obj, *, display_id, **kwargs)
1043 + IPython.core.display_functions.update_display(obj, *, display_id, **kwargs)
980 + IPython.core.extensions.BUILTINS_EXTS
1044 + IPython.core.extensions.BUILTINS_EXTS
981 + IPython.core.inputtransformer2.has_sunken_brackets(tokens)
1045 + IPython.core.inputtransformer2.has_sunken_brackets(tokens)
982 + IPython.core.interactiveshell.Callable
1046 + IPython.core.interactiveshell.Callable
983 + IPython.core.interactiveshell.__annotations__
1047 + IPython.core.interactiveshell.__annotations__
984 + IPython.core.ultratb.List
1048 + IPython.core.ultratb.List
985 + IPython.core.ultratb.Tuple
1049 + IPython.core.ultratb.Tuple
986 + IPython.lib.pretty.CallExpression
1050 + IPython.lib.pretty.CallExpression
987 + IPython.lib.pretty.CallExpression.factory(name)
1051 + IPython.lib.pretty.CallExpression.factory(name)
988 + IPython.lib.pretty.RawStringLiteral
1052 + IPython.lib.pretty.RawStringLiteral
989 + IPython.lib.pretty.RawText
1053 + IPython.lib.pretty.RawText
990 + IPython.terminal.debugger.TerminalPdb.do_interact(self, arg)
1054 + IPython.terminal.debugger.TerminalPdb.do_interact(self, arg)
991 + IPython.terminal.embed.Set
1055 + IPython.terminal.embed.Set
992
1056
993 The following items have been removed (or moved to superclass)::
1057 The following items have been removed (or moved to superclass)::
994
1058
995 - IPython.core.application.BaseIPythonApplication.initialize_subcommand
1059 - IPython.core.application.BaseIPythonApplication.initialize_subcommand
996 - IPython.core.completer.Sentinel
1060 - IPython.core.completer.Sentinel
997 - IPython.core.completer.skip_doctest
1061 - IPython.core.completer.skip_doctest
998 - IPython.core.debugger.Tracer
1062 - IPython.core.debugger.Tracer
999 - IPython.core.display.DisplayHandle
1063 - IPython.core.display.DisplayHandle
1000 - IPython.core.display.DisplayHandle.display
1064 - IPython.core.display.DisplayHandle.display
1001 - IPython.core.display.DisplayHandle.update
1065 - IPython.core.display.DisplayHandle.update
1002 - IPython.core.display.b2a_hex
1066 - IPython.core.display.b2a_hex
1003 - IPython.core.display.clear_output
1067 - IPython.core.display.clear_output
1004 - IPython.core.display.display
1068 - IPython.core.display.display
1005 - IPython.core.display.publish_display_data
1069 - IPython.core.display.publish_display_data
1006 - IPython.core.display.update_display
1070 - IPython.core.display.update_display
1007 - IPython.core.excolors.Deprec
1071 - IPython.core.excolors.Deprec
1008 - IPython.core.excolors.ExceptionColors
1072 - IPython.core.excolors.ExceptionColors
1009 - IPython.core.history.warn
1073 - IPython.core.history.warn
1010 - IPython.core.hooks.late_startup_hook
1074 - IPython.core.hooks.late_startup_hook
1011 - IPython.core.hooks.pre_run_code_hook
1075 - IPython.core.hooks.pre_run_code_hook
1012 - IPython.core.hooks.shutdown_hook
1076 - IPython.core.hooks.shutdown_hook
1013 - IPython.core.interactiveshell.InteractiveShell.init_deprecation_warnings
1077 - IPython.core.interactiveshell.InteractiveShell.init_deprecation_warnings
1014 - IPython.core.interactiveshell.InteractiveShell.init_readline
1078 - IPython.core.interactiveshell.InteractiveShell.init_readline
1015 - IPython.core.interactiveshell.InteractiveShell.write
1079 - IPython.core.interactiveshell.InteractiveShell.write
1016 - IPython.core.interactiveshell.InteractiveShell.write_err
1080 - IPython.core.interactiveshell.InteractiveShell.write_err
1017 - IPython.core.interactiveshell.get_default_colors
1081 - IPython.core.interactiveshell.get_default_colors
1018 - IPython.core.interactiveshell.removed_co_newlocals
1082 - IPython.core.interactiveshell.removed_co_newlocals
1019 - IPython.core.magics.execution.ExecutionMagics.profile_missing_notice
1083 - IPython.core.magics.execution.ExecutionMagics.profile_missing_notice
1020 - IPython.core.magics.script.PIPE
1084 - IPython.core.magics.script.PIPE
1021 - IPython.core.prefilter.PrefilterManager.init_transformers
1085 - IPython.core.prefilter.PrefilterManager.init_transformers
1022 - IPython.core.release.classifiers
1086 - IPython.core.release.classifiers
1023 - IPython.core.release.description
1087 - IPython.core.release.description
1024 - IPython.core.release.keywords
1088 - IPython.core.release.keywords
1025 - IPython.core.release.long_description
1089 - IPython.core.release.long_description
1026 - IPython.core.release.name
1090 - IPython.core.release.name
1027 - IPython.core.release.platforms
1091 - IPython.core.release.platforms
1028 - IPython.core.release.url
1092 - IPython.core.release.url
1029 - IPython.core.ultratb.VerboseTB.format_records
1093 - IPython.core.ultratb.VerboseTB.format_records
1030 - IPython.core.ultratb.find_recursion
1094 - IPython.core.ultratb.find_recursion
1031 - IPython.core.ultratb.findsource
1095 - IPython.core.ultratb.findsource
1032 - IPython.core.ultratb.fix_frame_records_filenames
1096 - IPython.core.ultratb.fix_frame_records_filenames
1033 - IPython.core.ultratb.inspect_error
1097 - IPython.core.ultratb.inspect_error
1034 - IPython.core.ultratb.is_recursion_error
1098 - IPython.core.ultratb.is_recursion_error
1035 - IPython.core.ultratb.with_patch_inspect
1099 - IPython.core.ultratb.with_patch_inspect
1036 - IPython.external.__all__
1100 - IPython.external.__all__
1037 - IPython.external.__builtins__
1101 - IPython.external.__builtins__
1038 - IPython.external.__cached__
1102 - IPython.external.__cached__
1039 - IPython.external.__doc__
1103 - IPython.external.__doc__
1040 - IPython.external.__file__
1104 - IPython.external.__file__
1041 - IPython.external.__loader__
1105 - IPython.external.__loader__
1042 - IPython.external.__name__
1106 - IPython.external.__name__
1043 - IPython.external.__package__
1107 - IPython.external.__package__
1044 - IPython.external.__path__
1108 - IPython.external.__path__
1045 - IPython.external.__spec__
1109 - IPython.external.__spec__
1046 - IPython.kernel.KernelConnectionInfo
1110 - IPython.kernel.KernelConnectionInfo
1047 - IPython.kernel.__builtins__
1111 - IPython.kernel.__builtins__
1048 - IPython.kernel.__cached__
1112 - IPython.kernel.__cached__
1049 - IPython.kernel.__warningregistry__
1113 - IPython.kernel.__warningregistry__
1050 - IPython.kernel.pkg
1114 - IPython.kernel.pkg
1051 - IPython.kernel.protocol_version
1115 - IPython.kernel.protocol_version
1052 - IPython.kernel.protocol_version_info
1116 - IPython.kernel.protocol_version_info
1053 - IPython.kernel.src
1117 - IPython.kernel.src
1054 - IPython.kernel.version_info
1118 - IPython.kernel.version_info
1055 - IPython.kernel.warn
1119 - IPython.kernel.warn
1056 - IPython.lib.backgroundjobs
1120 - IPython.lib.backgroundjobs
1057 - IPython.lib.backgroundjobs.BackgroundJobBase
1121 - IPython.lib.backgroundjobs.BackgroundJobBase
1058 - IPython.lib.backgroundjobs.BackgroundJobBase.run
1122 - IPython.lib.backgroundjobs.BackgroundJobBase.run
1059 - IPython.lib.backgroundjobs.BackgroundJobBase.traceback
1123 - IPython.lib.backgroundjobs.BackgroundJobBase.traceback
1060 - IPython.lib.backgroundjobs.BackgroundJobExpr
1124 - IPython.lib.backgroundjobs.BackgroundJobExpr
1061 - IPython.lib.backgroundjobs.BackgroundJobExpr.call
1125 - IPython.lib.backgroundjobs.BackgroundJobExpr.call
1062 - IPython.lib.backgroundjobs.BackgroundJobFunc
1126 - IPython.lib.backgroundjobs.BackgroundJobFunc
1063 - IPython.lib.backgroundjobs.BackgroundJobFunc.call
1127 - IPython.lib.backgroundjobs.BackgroundJobFunc.call
1064 - IPython.lib.backgroundjobs.BackgroundJobManager
1128 - IPython.lib.backgroundjobs.BackgroundJobManager
1065 - IPython.lib.backgroundjobs.BackgroundJobManager.flush
1129 - IPython.lib.backgroundjobs.BackgroundJobManager.flush
1066 - IPython.lib.backgroundjobs.BackgroundJobManager.new
1130 - IPython.lib.backgroundjobs.BackgroundJobManager.new
1067 - IPython.lib.backgroundjobs.BackgroundJobManager.remove
1131 - IPython.lib.backgroundjobs.BackgroundJobManager.remove
1068 - IPython.lib.backgroundjobs.BackgroundJobManager.result
1132 - IPython.lib.backgroundjobs.BackgroundJobManager.result
1069 - IPython.lib.backgroundjobs.BackgroundJobManager.status
1133 - IPython.lib.backgroundjobs.BackgroundJobManager.status
1070 - IPython.lib.backgroundjobs.BackgroundJobManager.traceback
1134 - IPython.lib.backgroundjobs.BackgroundJobManager.traceback
1071 - IPython.lib.backgroundjobs.__builtins__
1135 - IPython.lib.backgroundjobs.__builtins__
1072 - IPython.lib.backgroundjobs.__cached__
1136 - IPython.lib.backgroundjobs.__cached__
1073 - IPython.lib.backgroundjobs.__doc__
1137 - IPython.lib.backgroundjobs.__doc__
1074 - IPython.lib.backgroundjobs.__file__
1138 - IPython.lib.backgroundjobs.__file__
1075 - IPython.lib.backgroundjobs.__loader__
1139 - IPython.lib.backgroundjobs.__loader__
1076 - IPython.lib.backgroundjobs.__name__
1140 - IPython.lib.backgroundjobs.__name__
1077 - IPython.lib.backgroundjobs.__package__
1141 - IPython.lib.backgroundjobs.__package__
1078 - IPython.lib.backgroundjobs.__spec__
1142 - IPython.lib.backgroundjobs.__spec__
1079 - IPython.lib.kernel.__builtins__
1143 - IPython.lib.kernel.__builtins__
1080 - IPython.lib.kernel.__cached__
1144 - IPython.lib.kernel.__cached__
1081 - IPython.lib.kernel.__doc__
1145 - IPython.lib.kernel.__doc__
1082 - IPython.lib.kernel.__file__
1146 - IPython.lib.kernel.__file__
1083 - IPython.lib.kernel.__loader__
1147 - IPython.lib.kernel.__loader__
1084 - IPython.lib.kernel.__name__
1148 - IPython.lib.kernel.__name__
1085 - IPython.lib.kernel.__package__
1149 - IPython.lib.kernel.__package__
1086 - IPython.lib.kernel.__spec__
1150 - IPython.lib.kernel.__spec__
1087 - IPython.lib.kernel.__warningregistry__
1151 - IPython.lib.kernel.__warningregistry__
1088 - IPython.paths.fs_encoding
1152 - IPython.paths.fs_encoding
1089 - IPython.terminal.debugger.DEFAULT_BUFFER
1153 - IPython.terminal.debugger.DEFAULT_BUFFER
1090 - IPython.terminal.debugger.cursor_in_leading_ws
1154 - IPython.terminal.debugger.cursor_in_leading_ws
1091 - IPython.terminal.debugger.emacs_insert_mode
1155 - IPython.terminal.debugger.emacs_insert_mode
1092 - IPython.terminal.debugger.has_selection
1156 - IPython.terminal.debugger.has_selection
1093 - IPython.terminal.debugger.vi_insert_mode
1157 - IPython.terminal.debugger.vi_insert_mode
1094 - IPython.terminal.interactiveshell.DISPLAY_BANNER_DEPRECATED
1158 - IPython.terminal.interactiveshell.DISPLAY_BANNER_DEPRECATED
1095 - IPython.terminal.ipapp.TerminalIPythonApp.parse_command_line
1159 - IPython.terminal.ipapp.TerminalIPythonApp.parse_command_line
1096 - IPython.testing.test
1160 - IPython.testing.test
1097 - IPython.utils.contexts.NoOpContext
1161 - IPython.utils.contexts.NoOpContext
1098 - IPython.utils.io.IOStream
1162 - IPython.utils.io.IOStream
1099 - IPython.utils.io.IOStream.close
1163 - IPython.utils.io.IOStream.close
1100 - IPython.utils.io.IOStream.write
1164 - IPython.utils.io.IOStream.write
1101 - IPython.utils.io.IOStream.writelines
1165 - IPython.utils.io.IOStream.writelines
1102 - IPython.utils.io.__warningregistry__
1166 - IPython.utils.io.__warningregistry__
1103 - IPython.utils.io.atomic_writing
1167 - IPython.utils.io.atomic_writing
1104 - IPython.utils.io.stderr
1168 - IPython.utils.io.stderr
1105 - IPython.utils.io.stdin
1169 - IPython.utils.io.stdin
1106 - IPython.utils.io.stdout
1170 - IPython.utils.io.stdout
1107 - IPython.utils.io.unicode_std_stream
1171 - IPython.utils.io.unicode_std_stream
1108 - IPython.utils.path.get_ipython_cache_dir
1172 - IPython.utils.path.get_ipython_cache_dir
1109 - IPython.utils.path.get_ipython_dir
1173 - IPython.utils.path.get_ipython_dir
1110 - IPython.utils.path.get_ipython_module_path
1174 - IPython.utils.path.get_ipython_module_path
1111 - IPython.utils.path.get_ipython_package_dir
1175 - IPython.utils.path.get_ipython_package_dir
1112 - IPython.utils.path.locate_profile
1176 - IPython.utils.path.locate_profile
1113 - IPython.utils.path.unquote_filename
1177 - IPython.utils.path.unquote_filename
1114 - IPython.utils.py3compat.PY2
1178 - IPython.utils.py3compat.PY2
1115 - IPython.utils.py3compat.PY3
1179 - IPython.utils.py3compat.PY3
1116 - IPython.utils.py3compat.buffer_to_bytes
1180 - IPython.utils.py3compat.buffer_to_bytes
1117 - IPython.utils.py3compat.builtin_mod_name
1181 - IPython.utils.py3compat.builtin_mod_name
1118 - IPython.utils.py3compat.cast_bytes
1182 - IPython.utils.py3compat.cast_bytes
1119 - IPython.utils.py3compat.getcwd
1183 - IPython.utils.py3compat.getcwd
1120 - IPython.utils.py3compat.isidentifier
1184 - IPython.utils.py3compat.isidentifier
1121 - IPython.utils.py3compat.u_format
1185 - IPython.utils.py3compat.u_format
1122
1186
1123 The following signatures differ between 7.x and 8.0::
1187 The following signatures differ between 7.x and 8.0::
1124
1188
1125 - IPython.core.completer.IPCompleter.unicode_name_matches(self, text)
1189 - IPython.core.completer.IPCompleter.unicode_name_matches(self, text)
1126 + IPython.core.completer.IPCompleter.unicode_name_matches(text)
1190 + IPython.core.completer.IPCompleter.unicode_name_matches(text)
1127
1191
1128 - IPython.core.completer.match_dict_keys(keys, prefix, delims)
1192 - IPython.core.completer.match_dict_keys(keys, prefix, delims)
1129 + IPython.core.completer.match_dict_keys(keys, prefix, delims, extra_prefix='None')
1193 + IPython.core.completer.match_dict_keys(keys, prefix, delims, extra_prefix='None')
1130
1194
1131 - IPython.core.interactiveshell.InteractiveShell.object_inspect_mime(self, oname, detail_level=0)
1195 - IPython.core.interactiveshell.InteractiveShell.object_inspect_mime(self, oname, detail_level=0)
1132 + IPython.core.interactiveshell.InteractiveShell.object_inspect_mime(self, oname, detail_level=0, omit_sections='()')
1196 + IPython.core.interactiveshell.InteractiveShell.object_inspect_mime(self, oname, detail_level=0, omit_sections='()')
1133
1197
1134 - IPython.core.interactiveshell.InteractiveShell.set_hook(self, name, hook, priority=50, str_key='None', re_key='None', _warn_deprecated=True)
1198 - IPython.core.interactiveshell.InteractiveShell.set_hook(self, name, hook, priority=50, str_key='None', re_key='None', _warn_deprecated=True)
1135 + IPython.core.interactiveshell.InteractiveShell.set_hook(self, name, hook, priority=50, str_key='None', re_key='None')
1199 + IPython.core.interactiveshell.InteractiveShell.set_hook(self, name, hook, priority=50, str_key='None', re_key='None')
1136
1200
1137 - IPython.core.oinspect.Inspector.info(self, obj, oname='', formatter='None', info='None', detail_level=0)
1201 - IPython.core.oinspect.Inspector.info(self, obj, oname='', formatter='None', info='None', detail_level=0)
1138 + IPython.core.oinspect.Inspector.info(self, obj, oname='', info='None', detail_level=0)
1202 + IPython.core.oinspect.Inspector.info(self, obj, oname='', info='None', detail_level=0)
1139
1203
1140 - IPython.core.oinspect.Inspector.pinfo(self, obj, oname='', formatter='None', info='None', detail_level=0, enable_html_pager=True)
1204 - IPython.core.oinspect.Inspector.pinfo(self, obj, oname='', formatter='None', info='None', detail_level=0, enable_html_pager=True)
1141 + IPython.core.oinspect.Inspector.pinfo(self, obj, oname='', formatter='None', info='None', detail_level=0, enable_html_pager=True, omit_sections='()')
1205 + IPython.core.oinspect.Inspector.pinfo(self, obj, oname='', formatter='None', info='None', detail_level=0, enable_html_pager=True, omit_sections='()')
1142
1206
1143 - IPython.core.profiledir.ProfileDir.copy_config_file(self, config_file, path='None', overwrite=False)
1207 - IPython.core.profiledir.ProfileDir.copy_config_file(self, config_file, path='None', overwrite=False)
1144 + IPython.core.profiledir.ProfileDir.copy_config_file(self, config_file, path, overwrite=False)
1208 + IPython.core.profiledir.ProfileDir.copy_config_file(self, config_file, path, overwrite=False)
1145
1209
1146 - IPython.core.ultratb.VerboseTB.format_record(self, frame, file, lnum, func, lines, index)
1210 - IPython.core.ultratb.VerboseTB.format_record(self, frame, file, lnum, func, lines, index)
1147 + IPython.core.ultratb.VerboseTB.format_record(self, frame_info)
1211 + IPython.core.ultratb.VerboseTB.format_record(self, frame_info)
1148
1212
1149 - IPython.terminal.embed.InteractiveShellEmbed.mainloop(self, local_ns='None', module='None', stack_depth=0, display_banner='None', global_ns='None', compile_flags='None')
1213 - IPython.terminal.embed.InteractiveShellEmbed.mainloop(self, local_ns='None', module='None', stack_depth=0, display_banner='None', global_ns='None', compile_flags='None')
1150 + IPython.terminal.embed.InteractiveShellEmbed.mainloop(self, local_ns='None', module='None', stack_depth=0, compile_flags='None')
1214 + IPython.terminal.embed.InteractiveShellEmbed.mainloop(self, local_ns='None', module='None', stack_depth=0, compile_flags='None')
1151
1215
1152 - IPython.terminal.embed.embed(**kwargs)
1216 - IPython.terminal.embed.embed(**kwargs)
1153 + IPython.terminal.embed.embed(*, header='', compile_flags='None', **kwargs)
1217 + IPython.terminal.embed.embed(*, header='', compile_flags='None', **kwargs)
1154
1218
1155 - IPython.terminal.interactiveshell.TerminalInteractiveShell.interact(self, display_banner='<object object at 0xffffff>')
1219 - IPython.terminal.interactiveshell.TerminalInteractiveShell.interact(self, display_banner='<object object at 0xffffff>')
1156 + IPython.terminal.interactiveshell.TerminalInteractiveShell.interact(self)
1220 + IPython.terminal.interactiveshell.TerminalInteractiveShell.interact(self)
1157
1221
1158 - IPython.terminal.interactiveshell.TerminalInteractiveShell.mainloop(self, display_banner='<object object at 0xffffff>')
1222 - IPython.terminal.interactiveshell.TerminalInteractiveShell.mainloop(self, display_banner='<object object at 0xffffff>')
1159 + IPython.terminal.interactiveshell.TerminalInteractiveShell.mainloop(self)
1223 + IPython.terminal.interactiveshell.TerminalInteractiveShell.mainloop(self)
1160
1224
1161 - IPython.utils.path.get_py_filename(name, force_win32='None')
1225 - IPython.utils.path.get_py_filename(name, force_win32='None')
1162 + IPython.utils.path.get_py_filename(name)
1226 + IPython.utils.path.get_py_filename(name)
1163
1227
1164 The following are new attributes (that might be inherited)::
1228 The following are new attributes (that might be inherited)::
1165
1229
1166 + IPython.core.completer.IPCompleter.unicode_names
1230 + IPython.core.completer.IPCompleter.unicode_names
1167 + IPython.core.debugger.InterruptiblePdb.precmd
1231 + IPython.core.debugger.InterruptiblePdb.precmd
1168 + IPython.core.debugger.Pdb.precmd
1232 + IPython.core.debugger.Pdb.precmd
1169 + IPython.core.ultratb.AutoFormattedTB.has_colors
1233 + IPython.core.ultratb.AutoFormattedTB.has_colors
1170 + IPython.core.ultratb.ColorTB.has_colors
1234 + IPython.core.ultratb.ColorTB.has_colors
1171 + IPython.core.ultratb.FormattedTB.has_colors
1235 + IPython.core.ultratb.FormattedTB.has_colors
1172 + IPython.core.ultratb.ListTB.has_colors
1236 + IPython.core.ultratb.ListTB.has_colors
1173 + IPython.core.ultratb.SyntaxTB.has_colors
1237 + IPython.core.ultratb.SyntaxTB.has_colors
1174 + IPython.core.ultratb.TBTools.has_colors
1238 + IPython.core.ultratb.TBTools.has_colors
1175 + IPython.core.ultratb.VerboseTB.has_colors
1239 + IPython.core.ultratb.VerboseTB.has_colors
1176 + IPython.terminal.debugger.TerminalPdb.do_interact
1240 + IPython.terminal.debugger.TerminalPdb.do_interact
1177 + IPython.terminal.debugger.TerminalPdb.precmd
1241 + IPython.terminal.debugger.TerminalPdb.precmd
1178
1242
1179 The following attribute/methods have been removed::
1243 The following attribute/methods have been removed::
1180
1244
1181 - IPython.core.application.BaseIPythonApplication.deprecated_subcommands
1245 - IPython.core.application.BaseIPythonApplication.deprecated_subcommands
1182 - IPython.core.ultratb.AutoFormattedTB.format_records
1246 - IPython.core.ultratb.AutoFormattedTB.format_records
1183 - IPython.core.ultratb.ColorTB.format_records
1247 - IPython.core.ultratb.ColorTB.format_records
1184 - IPython.core.ultratb.FormattedTB.format_records
1248 - IPython.core.ultratb.FormattedTB.format_records
1185 - IPython.terminal.embed.InteractiveShellEmbed.init_deprecation_warnings
1249 - IPython.terminal.embed.InteractiveShellEmbed.init_deprecation_warnings
1186 - IPython.terminal.embed.InteractiveShellEmbed.init_readline
1250 - IPython.terminal.embed.InteractiveShellEmbed.init_readline
1187 - IPython.terminal.embed.InteractiveShellEmbed.write
1251 - IPython.terminal.embed.InteractiveShellEmbed.write
1188 - IPython.terminal.embed.InteractiveShellEmbed.write_err
1252 - IPython.terminal.embed.InteractiveShellEmbed.write_err
1189 - IPython.terminal.interactiveshell.TerminalInteractiveShell.init_deprecation_warnings
1253 - IPython.terminal.interactiveshell.TerminalInteractiveShell.init_deprecation_warnings
1190 - IPython.terminal.interactiveshell.TerminalInteractiveShell.init_readline
1254 - IPython.terminal.interactiveshell.TerminalInteractiveShell.init_readline
1191 - IPython.terminal.interactiveshell.TerminalInteractiveShell.write
1255 - IPython.terminal.interactiveshell.TerminalInteractiveShell.write
1192 - IPython.terminal.interactiveshell.TerminalInteractiveShell.write_err
1256 - IPython.terminal.interactiveshell.TerminalInteractiveShell.write_err
1193 - IPython.terminal.ipapp.LocateIPythonApp.deprecated_subcommands
1257 - IPython.terminal.ipapp.LocateIPythonApp.deprecated_subcommands
1194 - IPython.terminal.ipapp.LocateIPythonApp.initialize_subcommand
1258 - IPython.terminal.ipapp.LocateIPythonApp.initialize_subcommand
1195 - IPython.terminal.ipapp.TerminalIPythonApp.deprecated_subcommands
1259 - IPython.terminal.ipapp.TerminalIPythonApp.deprecated_subcommands
1196 - IPython.terminal.ipapp.TerminalIPythonApp.initialize_subcommand
1260 - IPython.terminal.ipapp.TerminalIPythonApp.initialize_subcommand
@@ -1,452 +1,463 b''
1 """Attempt to generate templates for module reference with Sphinx
1 """Attempt to generate templates for module reference with Sphinx
2
2
3 XXX - we exclude extension modules
3 XXX - we exclude extension modules
4
4
5 To include extension modules, first identify them as valid in the
5 To include extension modules, first identify them as valid in the
6 ``_uri2path`` method, then handle them in the ``_parse_module`` script.
6 ``_uri2path`` method, then handle them in the ``_parse_module`` script.
7
7
8 We get functions and classes by parsing the text of .py files.
8 We get functions and classes by parsing the text of .py files.
9 Alternatively we could import the modules for discovery, and we'd have
9 Alternatively we could import the modules for discovery, and we'd have
10 to do that for extension modules. This would involve changing the
10 to do that for extension modules. This would involve changing the
11 ``_parse_module`` method to work via import and introspection, and
11 ``_parse_module`` method to work via import and introspection, and
12 might involve changing ``discover_modules`` (which determines which
12 might involve changing ``discover_modules`` (which determines which
13 files are modules, and therefore which module URIs will be passed to
13 files are modules, and therefore which module URIs will be passed to
14 ``_parse_module``).
14 ``_parse_module``).
15
15
16 NOTE: this is a modified version of a script originally shipped with the
16 NOTE: this is a modified version of a script originally shipped with the
17 PyMVPA project, which we've adapted for NIPY use. PyMVPA is an MIT-licensed
17 PyMVPA project, which we've adapted for NIPY use. PyMVPA is an MIT-licensed
18 project."""
18 project."""
19
19
20
20
21 # Stdlib imports
21 # Stdlib imports
22 import ast
22 import ast
23 import inspect
23 import inspect
24 import os
24 import os
25 import re
25 import re
26 from importlib import import_module
26 from importlib import import_module
27 from types import SimpleNamespace as Obj
27
28
28
29
29 class Obj(object):
30 '''Namespace to hold arbitrary information.'''
31 def __init__(self, **kwargs):
32 for k, v in kwargs.items():
33 setattr(self, k, v)
34
35 class FuncClsScanner(ast.NodeVisitor):
30 class FuncClsScanner(ast.NodeVisitor):
36 """Scan a module for top-level functions and classes.
31 """Scan a module for top-level functions and classes.
37
32
38 Skips objects with an @undoc decorator, or a name starting with '_'.
33 Skips objects with an @undoc decorator, or a name starting with '_'.
39 """
34 """
40 def __init__(self):
35 def __init__(self):
41 ast.NodeVisitor.__init__(self)
36 ast.NodeVisitor.__init__(self)
42 self.classes = []
37 self.classes = []
43 self.classes_seen = set()
38 self.classes_seen = set()
44 self.functions = []
39 self.functions = []
45
40
46 @staticmethod
41 @staticmethod
47 def has_undoc_decorator(node):
42 def has_undoc_decorator(node):
48 return any(isinstance(d, ast.Name) and d.id == 'undoc' \
43 return any(isinstance(d, ast.Name) and d.id == 'undoc' \
49 for d in node.decorator_list)
44 for d in node.decorator_list)
50
45
51 def visit_If(self, node):
46 def visit_If(self, node):
52 if isinstance(node.test, ast.Compare) \
47 if isinstance(node.test, ast.Compare) \
53 and isinstance(node.test.left, ast.Name) \
48 and isinstance(node.test.left, ast.Name) \
54 and node.test.left.id == '__name__':
49 and node.test.left.id == '__name__':
55 return # Ignore classes defined in "if __name__ == '__main__':"
50 return # Ignore classes defined in "if __name__ == '__main__':"
56
51
57 self.generic_visit(node)
52 self.generic_visit(node)
58
53
59 def visit_FunctionDef(self, node):
54 def visit_FunctionDef(self, node):
60 if not (node.name.startswith('_') or self.has_undoc_decorator(node)) \
55 if not (node.name.startswith('_') or self.has_undoc_decorator(node)) \
61 and node.name not in self.functions:
56 and node.name not in self.functions:
62 self.functions.append(node.name)
57 self.functions.append(node.name)
63
58
64 def visit_ClassDef(self, node):
59 def visit_ClassDef(self, node):
65 if not (node.name.startswith('_') or self.has_undoc_decorator(node)) \
60 if (
66 and node.name not in self.classes_seen:
61 not (node.name.startswith("_") or self.has_undoc_decorator(node))
67 cls = Obj(name=node.name)
62 and node.name not in self.classes_seen
68 cls.has_init = any(isinstance(n, ast.FunctionDef) and \
63 ):
69 n.name=='__init__' for n in node.body)
64 cls = Obj(name=node.name, sphinx_options={})
65 cls.has_init = any(
66 isinstance(n, ast.FunctionDef) and n.name == "__init__"
67 for n in node.body
68 )
70 self.classes.append(cls)
69 self.classes.append(cls)
71 self.classes_seen.add(node.name)
70 self.classes_seen.add(node.name)
72
71
73 def scan(self, mod):
72 def scan(self, mod):
74 self.visit(mod)
73 self.visit(mod)
75 return self.functions, self.classes
74 return self.functions, self.classes
76
75
77 # Functions and classes
76 # Functions and classes
78 class ApiDocWriter(object):
77 class ApiDocWriter(object):
79 ''' Class for automatic detection and parsing of API docs
78 ''' Class for automatic detection and parsing of API docs
80 to Sphinx-parsable reST format'''
79 to Sphinx-parsable reST format'''
81
80
82 # only separating first two levels
81 # only separating first two levels
83 rst_section_levels = ['*', '=', '-', '~', '^']
82 rst_section_levels = ['*', '=', '-', '~', '^']
84
83
85 def __init__(self,
84 def __init__(self,
86 package_name,
85 package_name,
87 rst_extension='.rst',
86 rst_extension='.rst',
88 package_skip_patterns=None,
87 package_skip_patterns=None,
89 module_skip_patterns=None,
88 module_skip_patterns=None,
90 names_from__all__=None,
89 names_from__all__=None,
91 ):
90 ):
92 ''' Initialize package for parsing
91 ''' Initialize package for parsing
93
92
94 Parameters
93 Parameters
95 ----------
94 ----------
96 package_name : string
95 package_name : string
97 Name of the top-level package. *package_name* must be the
96 Name of the top-level package. *package_name* must be the
98 name of an importable package
97 name of an importable package
99 rst_extension : string, optional
98 rst_extension : string, optional
100 Extension for reST files, default '.rst'
99 Extension for reST files, default '.rst'
101 package_skip_patterns : None or sequence of {strings, regexps}
100 package_skip_patterns : None or sequence of {strings, regexps}
102 Sequence of strings giving URIs of packages to be excluded
101 Sequence of strings giving URIs of packages to be excluded
103 Operates on the package path, starting at (including) the
102 Operates on the package path, starting at (including) the
104 first dot in the package path, after *package_name* - so,
103 first dot in the package path, after *package_name* - so,
105 if *package_name* is ``sphinx``, then ``sphinx.util`` will
104 if *package_name* is ``sphinx``, then ``sphinx.util`` will
106 result in ``.util`` being passed for earching by these
105 result in ``.util`` being passed for earching by these
107 regexps. If is None, gives default. Default is:
106 regexps. If is None, gives default. Default is:
108 ['\\.tests$']
107 ['\\.tests$']
109 module_skip_patterns : None or sequence
108 module_skip_patterns : None or sequence
110 Sequence of strings giving URIs of modules to be excluded
109 Sequence of strings giving URIs of modules to be excluded
111 Operates on the module name including preceding URI path,
110 Operates on the module name including preceding URI path,
112 back to the first dot after *package_name*. For example
111 back to the first dot after *package_name*. For example
113 ``sphinx.util.console`` results in the string to search of
112 ``sphinx.util.console`` results in the string to search of
114 ``.util.console``
113 ``.util.console``
115 If is None, gives default. Default is:
114 If is None, gives default. Default is:
116 ['\\.setup$', '\\._']
115 ['\\.setup$', '\\._']
117 names_from__all__ : set, optional
116 names_from__all__ : set, optional
118 Modules listed in here will be scanned by doing ``from mod import *``,
117 Modules listed in here will be scanned by doing ``from mod import *``,
119 rather than finding function and class definitions by scanning the
118 rather than finding function and class definitions by scanning the
120 AST. This is intended for API modules which expose things defined in
119 AST. This is intended for API modules which expose things defined in
121 other files. Modules listed here must define ``__all__`` to avoid
120 other files. Modules listed here must define ``__all__`` to avoid
122 exposing everything they import.
121 exposing everything they import.
123 '''
122 '''
124 if package_skip_patterns is None:
123 if package_skip_patterns is None:
125 package_skip_patterns = ['\\.tests$']
124 package_skip_patterns = ['\\.tests$']
126 if module_skip_patterns is None:
125 if module_skip_patterns is None:
127 module_skip_patterns = ['\\.setup$', '\\._']
126 module_skip_patterns = ['\\.setup$', '\\._']
128 self.package_name = package_name
127 self.package_name = package_name
129 self.rst_extension = rst_extension
128 self.rst_extension = rst_extension
130 self.package_skip_patterns = package_skip_patterns
129 self.package_skip_patterns = package_skip_patterns
131 self.module_skip_patterns = module_skip_patterns
130 self.module_skip_patterns = module_skip_patterns
132 self.names_from__all__ = names_from__all__ or set()
131 self.names_from__all__ = names_from__all__ or set()
133
132
134 def get_package_name(self):
133 def get_package_name(self):
135 return self._package_name
134 return self._package_name
136
135
137 def set_package_name(self, package_name):
136 def set_package_name(self, package_name):
138 ''' Set package_name
137 ''' Set package_name
139
138
140 >>> docwriter = ApiDocWriter('sphinx')
139 >>> docwriter = ApiDocWriter('sphinx')
141 >>> import sphinx
140 >>> import sphinx
142 >>> docwriter.root_path == sphinx.__path__[0]
141 >>> docwriter.root_path == sphinx.__path__[0]
143 True
142 True
144 >>> docwriter.package_name = 'docutils'
143 >>> docwriter.package_name = 'docutils'
145 >>> import docutils
144 >>> import docutils
146 >>> docwriter.root_path == docutils.__path__[0]
145 >>> docwriter.root_path == docutils.__path__[0]
147 True
146 True
148 '''
147 '''
149 # It's also possible to imagine caching the module parsing here
148 # It's also possible to imagine caching the module parsing here
150 self._package_name = package_name
149 self._package_name = package_name
151 self.root_module = import_module(package_name)
150 self.root_module = import_module(package_name)
152 self.root_path = self.root_module.__path__[0]
151 self.root_path = self.root_module.__path__[0]
153 self.written_modules = None
152 self.written_modules = None
154
153
155 package_name = property(get_package_name, set_package_name, None,
154 package_name = property(get_package_name, set_package_name, None,
156 'get/set package_name')
155 'get/set package_name')
157
156
158 def _uri2path(self, uri):
157 def _uri2path(self, uri):
159 ''' Convert uri to absolute filepath
158 ''' Convert uri to absolute filepath
160
159
161 Parameters
160 Parameters
162 ----------
161 ----------
163 uri : string
162 uri : string
164 URI of python module to return path for
163 URI of python module to return path for
165
164
166 Returns
165 Returns
167 -------
166 -------
168 path : None or string
167 path : None or string
169 Returns None if there is no valid path for this URI
168 Returns None if there is no valid path for this URI
170 Otherwise returns absolute file system path for URI
169 Otherwise returns absolute file system path for URI
171
170
172 Examples
171 Examples
173 --------
172 --------
174 >>> docwriter = ApiDocWriter('sphinx')
173 >>> docwriter = ApiDocWriter('sphinx')
175 >>> import sphinx
174 >>> import sphinx
176 >>> modpath = sphinx.__path__[0]
175 >>> modpath = sphinx.__path__[0]
177 >>> res = docwriter._uri2path('sphinx.builder')
176 >>> res = docwriter._uri2path('sphinx.builder')
178 >>> res == os.path.join(modpath, 'builder.py')
177 >>> res == os.path.join(modpath, 'builder.py')
179 True
178 True
180 >>> res = docwriter._uri2path('sphinx')
179 >>> res = docwriter._uri2path('sphinx')
181 >>> res == os.path.join(modpath, '__init__.py')
180 >>> res == os.path.join(modpath, '__init__.py')
182 True
181 True
183 >>> docwriter._uri2path('sphinx.does_not_exist')
182 >>> docwriter._uri2path('sphinx.does_not_exist')
184
183
185 '''
184 '''
186 if uri == self.package_name:
185 if uri == self.package_name:
187 return os.path.join(self.root_path, '__init__.py')
186 return os.path.join(self.root_path, '__init__.py')
188 path = uri.replace('.', os.path.sep)
187 path = uri.replace('.', os.path.sep)
189 path = path.replace(self.package_name + os.path.sep, '')
188 path = path.replace(self.package_name + os.path.sep, '')
190 path = os.path.join(self.root_path, path)
189 path = os.path.join(self.root_path, path)
191 # XXX maybe check for extensions as well?
190 # XXX maybe check for extensions as well?
192 if os.path.exists(path + '.py'): # file
191 if os.path.exists(path + '.py'): # file
193 path += '.py'
192 path += '.py'
194 elif os.path.exists(os.path.join(path, '__init__.py')):
193 elif os.path.exists(os.path.join(path, '__init__.py')):
195 path = os.path.join(path, '__init__.py')
194 path = os.path.join(path, '__init__.py')
196 else:
195 else:
197 return None
196 return None
198 return path
197 return path
199
198
200 def _path2uri(self, dirpath):
199 def _path2uri(self, dirpath):
201 ''' Convert directory path to uri '''
200 ''' Convert directory path to uri '''
202 relpath = dirpath.replace(self.root_path, self.package_name)
201 relpath = dirpath.replace(self.root_path, self.package_name)
203 if relpath.startswith(os.path.sep):
202 if relpath.startswith(os.path.sep):
204 relpath = relpath[1:]
203 relpath = relpath[1:]
205 return relpath.replace(os.path.sep, '.')
204 return relpath.replace(os.path.sep, '.')
206
205
207 def _parse_module(self, uri):
206 def _parse_module(self, uri):
208 ''' Parse module defined in *uri* '''
207 ''' Parse module defined in *uri* '''
209 filename = self._uri2path(uri)
208 filename = self._uri2path(uri)
210 if filename is None:
209 if filename is None:
211 # nothing that we could handle here.
210 # nothing that we could handle here.
212 return ([],[])
211 return ([],[])
213 with open(filename, 'rb') as f:
212 with open(filename, 'rb') as f:
214 mod = ast.parse(f.read())
213 mod = ast.parse(f.read())
215 return FuncClsScanner().scan(mod)
214 return FuncClsScanner().scan(mod)
216
215
217 def _import_funcs_classes(self, uri):
216 def _import_funcs_classes(self, uri):
218 """Import * from uri, and separate out functions and classes."""
217 """Import * from uri, and separate out functions and classes."""
219 ns = {}
218 ns = {}
220 exec('from %s import *' % uri, ns)
219 exec('from %s import *' % uri, ns)
221 funcs, classes = [], []
220 funcs, classes = [], []
222 for name, obj in ns.items():
221 for name, obj in ns.items():
223 if inspect.isclass(obj):
222 if inspect.isclass(obj):
224 cls = Obj(name=name, has_init='__init__' in obj.__dict__)
223 cls = Obj(
224 name=name,
225 has_init="__init__" in obj.__dict__,
226 sphinx_options=getattr(obj, "_sphinx_options", {}),
227 )
225 classes.append(cls)
228 classes.append(cls)
226 elif inspect.isfunction(obj):
229 elif inspect.isfunction(obj):
227 funcs.append(name)
230 funcs.append(name)
228
231
229 return sorted(funcs), sorted(classes, key=lambda x: x.name)
232 return sorted(funcs), sorted(classes, key=lambda x: x.name)
230
233
231 def find_funcs_classes(self, uri):
234 def find_funcs_classes(self, uri):
232 """Find the functions and classes defined in the module ``uri``"""
235 """Find the functions and classes defined in the module ``uri``"""
233 if uri in self.names_from__all__:
236 if uri in self.names_from__all__:
234 # For API modules which expose things defined elsewhere, import them
237 # For API modules which expose things defined elsewhere, import them
235 return self._import_funcs_classes(uri)
238 return self._import_funcs_classes(uri)
236 else:
239 else:
237 # For other modules, scan their AST to see what they define
240 # For other modules, scan their AST to see what they define
238 return self._parse_module(uri)
241 return self._parse_module(uri)
239
242
240 def generate_api_doc(self, uri):
243 def generate_api_doc(self, uri):
241 '''Make autodoc documentation template string for a module
244 '''Make autodoc documentation template string for a module
242
245
243 Parameters
246 Parameters
244 ----------
247 ----------
245 uri : string
248 uri : string
246 python location of module - e.g 'sphinx.builder'
249 python location of module - e.g 'sphinx.builder'
247
250
248 Returns
251 Returns
249 -------
252 -------
250 S : string
253 S : string
251 Contents of API doc
254 Contents of API doc
252 '''
255 '''
253 # get the names of all classes and functions
256 # get the names of all classes and functions
254 functions, classes = self.find_funcs_classes(uri)
257 functions, classes = self.find_funcs_classes(uri)
255 if not len(functions) and not len(classes):
258 if not len(functions) and not len(classes):
256 #print ('WARNING: Empty -', uri) # dbg
259 #print ('WARNING: Empty -', uri) # dbg
257 return ''
260 return ''
258
261
259 # Make a shorter version of the uri that omits the package name for
262 # Make a shorter version of the uri that omits the package name for
260 # titles
263 # titles
261 uri_short = re.sub(r'^%s\.' % self.package_name,'',uri)
264 uri_short = re.sub(r'^%s\.' % self.package_name,'',uri)
262
265
263 ad = '.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n'
266 ad = '.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n'
264
267
265 # Set the chapter title to read 'Module:' for all modules except for the
268 # Set the chapter title to read 'Module:' for all modules except for the
266 # main packages
269 # main packages
267 if '.' in uri:
270 if '.' in uri:
268 chap_title = 'Module: :mod:`' + uri_short + '`'
271 chap_title = 'Module: :mod:`' + uri_short + '`'
269 else:
272 else:
270 chap_title = ':mod:`' + uri_short + '`'
273 chap_title = ':mod:`' + uri_short + '`'
271 ad += chap_title + '\n' + self.rst_section_levels[1] * len(chap_title)
274 ad += chap_title + '\n' + self.rst_section_levels[1] * len(chap_title)
272
275
273 ad += '\n.. automodule:: ' + uri + '\n'
276 ad += '\n.. automodule:: ' + uri + '\n'
274 ad += '\n.. currentmodule:: ' + uri + '\n'
277 ad += '\n.. currentmodule:: ' + uri + '\n'
275
278
276 if classes:
279 if classes:
277 subhead = str(len(classes)) + (' Classes' if len(classes) > 1 else ' Class')
280 subhead = str(len(classes)) + (' Classes' if len(classes) > 1 else ' Class')
278 ad += '\n'+ subhead + '\n' + \
281 ad += '\n'+ subhead + '\n' + \
279 self.rst_section_levels[2] * len(subhead) + '\n'
282 self.rst_section_levels[2] * len(subhead) + '\n'
280
283
281 for c in classes:
284 for c in classes:
282 ad += '\n.. autoclass:: ' + c.name + '\n'
285 opts = c.sphinx_options
286 ad += "\n.. autoclass:: " + c.name + "\n"
283 # must NOT exclude from index to keep cross-refs working
287 # must NOT exclude from index to keep cross-refs working
284 ad += ' :members:\n' \
288 ad += " :members:\n"
285 ' :show-inheritance:\n'
289 if opts.get("show_inheritance", True):
290 ad += " :show-inheritance:\n"
291 if opts.get("show_inherited_members", False):
292 exclusions_list = opts.get("exclude_inherited_from", [])
293 exclusions = (
294 (" " + " ".join(exclusions_list)) if exclusions_list else ""
295 )
296 ad += f" :inherited-members:{exclusions}\n"
286 if c.has_init:
297 if c.has_init:
287 ad += '\n .. automethod:: __init__\n'
298 ad += '\n .. automethod:: __init__\n'
288
299
289 if functions:
300 if functions:
290 subhead = str(len(functions)) + (' Functions' if len(functions) > 1 else ' Function')
301 subhead = str(len(functions)) + (' Functions' if len(functions) > 1 else ' Function')
291 ad += '\n'+ subhead + '\n' + \
302 ad += '\n'+ subhead + '\n' + \
292 self.rst_section_levels[2] * len(subhead) + '\n'
303 self.rst_section_levels[2] * len(subhead) + '\n'
293 for f in functions:
304 for f in functions:
294 # must NOT exclude from index to keep cross-refs working
305 # must NOT exclude from index to keep cross-refs working
295 ad += '\n.. autofunction:: ' + uri + '.' + f + '\n\n'
306 ad += '\n.. autofunction:: ' + uri + '.' + f + '\n\n'
296 return ad
307 return ad
297
308
298 def _survives_exclude(self, matchstr, match_type):
309 def _survives_exclude(self, matchstr, match_type):
299 ''' Returns True if *matchstr* does not match patterns
310 ''' Returns True if *matchstr* does not match patterns
300
311
301 ``self.package_name`` removed from front of string if present
312 ``self.package_name`` removed from front of string if present
302
313
303 Examples
314 Examples
304 --------
315 --------
305 >>> dw = ApiDocWriter('sphinx')
316 >>> dw = ApiDocWriter('sphinx')
306 >>> dw._survives_exclude('sphinx.okpkg', 'package')
317 >>> dw._survives_exclude('sphinx.okpkg', 'package')
307 True
318 True
308 >>> dw.package_skip_patterns.append('^\\.badpkg$')
319 >>> dw.package_skip_patterns.append('^\\.badpkg$')
309 >>> dw._survives_exclude('sphinx.badpkg', 'package')
320 >>> dw._survives_exclude('sphinx.badpkg', 'package')
310 False
321 False
311 >>> dw._survives_exclude('sphinx.badpkg', 'module')
322 >>> dw._survives_exclude('sphinx.badpkg', 'module')
312 True
323 True
313 >>> dw._survives_exclude('sphinx.badmod', 'module')
324 >>> dw._survives_exclude('sphinx.badmod', 'module')
314 True
325 True
315 >>> dw.module_skip_patterns.append('^\\.badmod$')
326 >>> dw.module_skip_patterns.append('^\\.badmod$')
316 >>> dw._survives_exclude('sphinx.badmod', 'module')
327 >>> dw._survives_exclude('sphinx.badmod', 'module')
317 False
328 False
318 '''
329 '''
319 if match_type == 'module':
330 if match_type == 'module':
320 patterns = self.module_skip_patterns
331 patterns = self.module_skip_patterns
321 elif match_type == 'package':
332 elif match_type == 'package':
322 patterns = self.package_skip_patterns
333 patterns = self.package_skip_patterns
323 else:
334 else:
324 raise ValueError('Cannot interpret match type "%s"'
335 raise ValueError('Cannot interpret match type "%s"'
325 % match_type)
336 % match_type)
326 # Match to URI without package name
337 # Match to URI without package name
327 L = len(self.package_name)
338 L = len(self.package_name)
328 if matchstr[:L] == self.package_name:
339 if matchstr[:L] == self.package_name:
329 matchstr = matchstr[L:]
340 matchstr = matchstr[L:]
330 for pat in patterns:
341 for pat in patterns:
331 try:
342 try:
332 pat.search
343 pat.search
333 except AttributeError:
344 except AttributeError:
334 pat = re.compile(pat)
345 pat = re.compile(pat)
335 if pat.search(matchstr):
346 if pat.search(matchstr):
336 return False
347 return False
337 return True
348 return True
338
349
339 def discover_modules(self):
350 def discover_modules(self):
340 ''' Return module sequence discovered from ``self.package_name``
351 ''' Return module sequence discovered from ``self.package_name``
341
352
342
353
343 Parameters
354 Parameters
344 ----------
355 ----------
345 None
356 None
346
357
347 Returns
358 Returns
348 -------
359 -------
349 mods : sequence
360 mods : sequence
350 Sequence of module names within ``self.package_name``
361 Sequence of module names within ``self.package_name``
351
362
352 Examples
363 Examples
353 --------
364 --------
354 >>> dw = ApiDocWriter('sphinx')
365 >>> dw = ApiDocWriter('sphinx')
355 >>> mods = dw.discover_modules()
366 >>> mods = dw.discover_modules()
356 >>> 'sphinx.util' in mods
367 >>> 'sphinx.util' in mods
357 True
368 True
358 >>> dw.package_skip_patterns.append('\\.util$')
369 >>> dw.package_skip_patterns.append('\\.util$')
359 >>> 'sphinx.util' in dw.discover_modules()
370 >>> 'sphinx.util' in dw.discover_modules()
360 False
371 False
361 >>>
372 >>>
362 '''
373 '''
363 modules = [self.package_name]
374 modules = [self.package_name]
364 # raw directory parsing
375 # raw directory parsing
365 for dirpath, dirnames, filenames in os.walk(self.root_path):
376 for dirpath, dirnames, filenames in os.walk(self.root_path):
366 # Check directory names for packages
377 # Check directory names for packages
367 root_uri = self._path2uri(os.path.join(self.root_path,
378 root_uri = self._path2uri(os.path.join(self.root_path,
368 dirpath))
379 dirpath))
369 for dirname in dirnames[:]: # copy list - we modify inplace
380 for dirname in dirnames[:]: # copy list - we modify inplace
370 package_uri = '.'.join((root_uri, dirname))
381 package_uri = '.'.join((root_uri, dirname))
371 if (self._uri2path(package_uri) and
382 if (self._uri2path(package_uri) and
372 self._survives_exclude(package_uri, 'package')):
383 self._survives_exclude(package_uri, 'package')):
373 modules.append(package_uri)
384 modules.append(package_uri)
374 else:
385 else:
375 dirnames.remove(dirname)
386 dirnames.remove(dirname)
376 # Check filenames for modules
387 # Check filenames for modules
377 for filename in filenames:
388 for filename in filenames:
378 module_name = filename[:-3]
389 module_name = filename[:-3]
379 module_uri = '.'.join((root_uri, module_name))
390 module_uri = '.'.join((root_uri, module_name))
380 if (self._uri2path(module_uri) and
391 if (self._uri2path(module_uri) and
381 self._survives_exclude(module_uri, 'module')):
392 self._survives_exclude(module_uri, 'module')):
382 modules.append(module_uri)
393 modules.append(module_uri)
383 return sorted(modules)
394 return sorted(modules)
384
395
385 def write_modules_api(self, modules,outdir):
396 def write_modules_api(self, modules,outdir):
386 # write the list
397 # write the list
387 written_modules = []
398 written_modules = []
388 for m in modules:
399 for m in modules:
389 api_str = self.generate_api_doc(m)
400 api_str = self.generate_api_doc(m)
390 if not api_str:
401 if not api_str:
391 continue
402 continue
392 # write out to file
403 # write out to file
393 outfile = os.path.join(outdir, m + self.rst_extension)
404 outfile = os.path.join(outdir, m + self.rst_extension)
394 with open(outfile, "wt", encoding="utf-8") as fileobj:
405 with open(outfile, "wt", encoding="utf-8") as fileobj:
395 fileobj.write(api_str)
406 fileobj.write(api_str)
396 written_modules.append(m)
407 written_modules.append(m)
397 self.written_modules = written_modules
408 self.written_modules = written_modules
398
409
399 def write_api_docs(self, outdir):
410 def write_api_docs(self, outdir):
400 """Generate API reST files.
411 """Generate API reST files.
401
412
402 Parameters
413 Parameters
403 ----------
414 ----------
404 outdir : string
415 outdir : string
405 Directory name in which to store files
416 Directory name in which to store files
406 We create automatic filenames for each module
417 We create automatic filenames for each module
407
418
408 Returns
419 Returns
409 -------
420 -------
410 None
421 None
411
422
412 Notes
423 Notes
413 -----
424 -----
414 Sets self.written_modules to list of written modules
425 Sets self.written_modules to list of written modules
415 """
426 """
416 if not os.path.exists(outdir):
427 if not os.path.exists(outdir):
417 os.mkdir(outdir)
428 os.mkdir(outdir)
418 # compose list of modules
429 # compose list of modules
419 modules = self.discover_modules()
430 modules = self.discover_modules()
420 self.write_modules_api(modules,outdir)
431 self.write_modules_api(modules,outdir)
421
432
422 def write_index(self, outdir, path='gen.rst', relative_to=None):
433 def write_index(self, outdir, path='gen.rst', relative_to=None):
423 """Make a reST API index file from written files
434 """Make a reST API index file from written files
424
435
425 Parameters
436 Parameters
426 ----------
437 ----------
427 outdir : string
438 outdir : string
428 Directory to which to write generated index file
439 Directory to which to write generated index file
429 path : string
440 path : string
430 Filename to write index to
441 Filename to write index to
431 relative_to : string
442 relative_to : string
432 path to which written filenames are relative. This
443 path to which written filenames are relative. This
433 component of the written file path will be removed from
444 component of the written file path will be removed from
434 outdir, in the generated index. Default is None, meaning,
445 outdir, in the generated index. Default is None, meaning,
435 leave path as it is.
446 leave path as it is.
436 """
447 """
437 if self.written_modules is None:
448 if self.written_modules is None:
438 raise ValueError('No modules written')
449 raise ValueError('No modules written')
439 # Get full filename path
450 # Get full filename path
440 path = os.path.join(outdir, path)
451 path = os.path.join(outdir, path)
441 # Path written into index is relative to rootpath
452 # Path written into index is relative to rootpath
442 if relative_to is not None:
453 if relative_to is not None:
443 relpath = outdir.replace(relative_to + os.path.sep, '')
454 relpath = outdir.replace(relative_to + os.path.sep, '')
444 else:
455 else:
445 relpath = outdir
456 relpath = outdir
446 with open(path, "wt", encoding="utf-8") as idx:
457 with open(path, "wt", encoding="utf-8") as idx:
447 w = idx.write
458 w = idx.write
448 w('.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n')
459 w('.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n')
449 w('.. autosummary::\n'
460 w('.. autosummary::\n'
450 ' :toctree: %s\n\n' % relpath)
461 ' :toctree: %s\n\n' % relpath)
451 for mod in self.written_modules:
462 for mod in self.written_modules:
452 w(' %s\n' % mod)
463 w(' %s\n' % mod)
@@ -1,122 +1,123 b''
1 [metadata]
1 [metadata]
2 name = ipython
2 name = ipython
3 version = attr: IPython.core.release.__version__
3 version = attr: IPython.core.release.__version__
4 url = https://ipython.org
4 url = https://ipython.org
5 description = IPython: Productive Interactive Computing
5 description = IPython: Productive Interactive Computing
6 long_description_content_type = text/x-rst
6 long_description_content_type = text/x-rst
7 long_description = file: long_description.rst
7 long_description = file: long_description.rst
8 license_file = LICENSE
8 license_file = LICENSE
9 project_urls =
9 project_urls =
10 Documentation = https://ipython.readthedocs.io/
10 Documentation = https://ipython.readthedocs.io/
11 Funding = https://numfocus.org/
11 Funding = https://numfocus.org/
12 Source = https://github.com/ipython/ipython
12 Source = https://github.com/ipython/ipython
13 Tracker = https://github.com/ipython/ipython/issues
13 Tracker = https://github.com/ipython/ipython/issues
14 keywords = Interactive, Interpreter, Shell, Embedding
14 keywords = Interactive, Interpreter, Shell, Embedding
15 platforms = Linux, Mac OSX, Windows
15 platforms = Linux, Mac OSX, Windows
16 classifiers =
16 classifiers =
17 Framework :: IPython
17 Framework :: IPython
18 Framework :: Jupyter
18 Framework :: Jupyter
19 Intended Audience :: Developers
19 Intended Audience :: Developers
20 Intended Audience :: Science/Research
20 Intended Audience :: Science/Research
21 License :: OSI Approved :: BSD License
21 License :: OSI Approved :: BSD License
22 Programming Language :: Python
22 Programming Language :: Python
23 Programming Language :: Python :: 3
23 Programming Language :: Python :: 3
24 Programming Language :: Python :: 3 :: Only
24 Programming Language :: Python :: 3 :: Only
25 Topic :: System :: Shells
25 Topic :: System :: Shells
26
26
27 [options]
27 [options]
28 packages = find:
28 packages = find:
29 python_requires = >=3.8
29 python_requires = >=3.8
30 zip_safe = False
30 zip_safe = False
31 install_requires =
31 install_requires =
32 appnope; sys_platform == "darwin"
32 appnope; sys_platform == "darwin"
33 backcall
33 backcall
34 colorama; sys_platform == "win32"
34 colorama; sys_platform == "win32"
35 decorator
35 decorator
36 jedi>=0.16
36 jedi>=0.16
37 matplotlib-inline
37 matplotlib-inline
38 pexpect>4.3; sys_platform != "win32"
38 pexpect>4.3; sys_platform != "win32"
39 pickleshare
39 pickleshare
40 prompt_toolkit>3.0.1,<3.1.0
40 prompt_toolkit>3.0.1,<3.1.0
41 pygments>=2.4.0
41 pygments>=2.4.0
42 stack_data
42 stack_data
43 traitlets>=5
43 traitlets>=5
44
44
45 [options.extras_require]
45 [options.extras_require]
46 black =
46 black =
47 black
47 black
48 doc =
48 doc =
49 ipykernel
49 ipykernel
50 setuptools>=18.5
50 setuptools>=18.5
51 sphinx>=1.3
51 sphinx>=1.3
52 sphinx-rtd-theme
52 sphinx-rtd-theme
53 docrepr
53 docrepr
54 matplotlib
54 matplotlib
55 stack_data
55 stack_data
56 pytest<7
56 pytest<7
57 typing_extensions
57 %(test)s
58 %(test)s
58 kernel =
59 kernel =
59 ipykernel
60 ipykernel
60 nbconvert =
61 nbconvert =
61 nbconvert
62 nbconvert
62 nbformat =
63 nbformat =
63 nbformat
64 nbformat
64 notebook =
65 notebook =
65 ipywidgets
66 ipywidgets
66 notebook
67 notebook
67 parallel =
68 parallel =
68 ipyparallel
69 ipyparallel
69 qtconsole =
70 qtconsole =
70 qtconsole
71 qtconsole
71 terminal =
72 terminal =
72 test =
73 test =
73 pytest<7.1
74 pytest<7.1
74 pytest-asyncio
75 pytest-asyncio
75 testpath
76 testpath
76 test_extra =
77 test_extra =
77 %(test)s
78 %(test)s
78 curio
79 curio
79 matplotlib!=3.2.0
80 matplotlib!=3.2.0
80 nbformat
81 nbformat
81 numpy>=1.19
82 numpy>=1.20
82 pandas
83 pandas
83 trio
84 trio
84 all =
85 all =
85 %(black)s
86 %(black)s
86 %(doc)s
87 %(doc)s
87 %(kernel)s
88 %(kernel)s
88 %(nbconvert)s
89 %(nbconvert)s
89 %(nbformat)s
90 %(nbformat)s
90 %(notebook)s
91 %(notebook)s
91 %(parallel)s
92 %(parallel)s
92 %(qtconsole)s
93 %(qtconsole)s
93 %(terminal)s
94 %(terminal)s
94 %(test_extra)s
95 %(test_extra)s
95 %(test)s
96 %(test)s
96
97
97 [options.packages.find]
98 [options.packages.find]
98 exclude =
99 exclude =
99 setupext
100 setupext
100
101
101 [options.package_data]
102 [options.package_data]
102 IPython.core = profile/README*
103 IPython.core = profile/README*
103 IPython.core.tests = *.png, *.jpg, daft_extension/*.py
104 IPython.core.tests = *.png, *.jpg, daft_extension/*.py
104 IPython.lib.tests = *.wav
105 IPython.lib.tests = *.wav
105 IPython.testing.plugin = *.txt
106 IPython.testing.plugin = *.txt
106
107
107 [options.entry_points]
108 [options.entry_points]
108 console_scripts =
109 console_scripts =
109 ipython = IPython:start_ipython
110 ipython = IPython:start_ipython
110 ipython3 = IPython:start_ipython
111 ipython3 = IPython:start_ipython
111 pygments.lexers =
112 pygments.lexers =
112 ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer
113 ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer
113 ipython = IPython.lib.lexers:IPythonLexer
114 ipython = IPython.lib.lexers:IPythonLexer
114 ipython3 = IPython.lib.lexers:IPython3Lexer
115 ipython3 = IPython.lib.lexers:IPython3Lexer
115
116
116 [velin]
117 [velin]
117 ignore_patterns =
118 ignore_patterns =
118 IPython/core/tests
119 IPython/core/tests
119 IPython/testing
120 IPython/testing
120
121
121 [tool.black]
122 [tool.black]
122 exclude = 'timing\.py'
123 exclude = 'timing\.py'
@@ -1,348 +1,354 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 This module defines the things that are used in setup.py for building IPython
3 This module defines the things that are used in setup.py for building IPython
4
4
5 This includes:
5 This includes:
6
6
7 * The basic arguments to setup
7 * The basic arguments to setup
8 * Functions for finding things like packages, package data, etc.
8 * Functions for finding things like packages, package data, etc.
9 * A function for checking dependencies.
9 * A function for checking dependencies.
10 """
10 """
11
11
12 # Copyright (c) IPython Development Team.
12 # Copyright (c) IPython Development Team.
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14
14
15 import os
15 import os
16 import re
16 import re
17 import sys
17 import sys
18 from glob import glob
18 from glob import glob
19 from logging import log
19 from logging import log
20
20
21 from setuptools import Command
21 from setuptools import Command
22 from setuptools.command.build_py import build_py
22 from setuptools.command.build_py import build_py
23
23
24 from setuptools.command.install import install
24 from setuptools.command.install import install
25 from setuptools.command.install_scripts import install_scripts
25 from setuptools.command.install_scripts import install_scripts
26
26
27
27
28 #-------------------------------------------------------------------------------
28 #-------------------------------------------------------------------------------
29 # Useful globals and utility functions
29 # Useful globals and utility functions
30 #-------------------------------------------------------------------------------
30 #-------------------------------------------------------------------------------
31
31
32 # A few handy globals
32 # A few handy globals
33 isfile = os.path.isfile
33 isfile = os.path.isfile
34 pjoin = os.path.join
34 pjoin = os.path.join
35 repo_root = os.path.dirname(os.path.abspath(__file__))
35 repo_root = os.path.dirname(os.path.abspath(__file__))
36
36
37 def execfile(fname, globs, locs=None):
37 def execfile(fname, globs, locs=None):
38 locs = locs or globs
38 locs = locs or globs
39 with open(fname, encoding="utf-8") as f:
39 with open(fname, encoding="utf-8") as f:
40 exec(compile(f.read(), fname, "exec"), globs, locs)
40 exec(compile(f.read(), fname, "exec"), globs, locs)
41
41
42 # A little utility we'll need below, since glob() does NOT allow you to do
42 # A little utility we'll need below, since glob() does NOT allow you to do
43 # exclusion on multiple endings!
43 # exclusion on multiple endings!
44 def file_doesnt_endwith(test,endings):
44 def file_doesnt_endwith(test,endings):
45 """Return true if test is a file and its name does NOT end with any
45 """Return true if test is a file and its name does NOT end with any
46 of the strings listed in endings."""
46 of the strings listed in endings."""
47 if not isfile(test):
47 if not isfile(test):
48 return False
48 return False
49 for e in endings:
49 for e in endings:
50 if test.endswith(e):
50 if test.endswith(e):
51 return False
51 return False
52 return True
52 return True
53
53
54 #---------------------------------------------------------------------------
54 #---------------------------------------------------------------------------
55 # Basic project information
55 # Basic project information
56 #---------------------------------------------------------------------------
56 #---------------------------------------------------------------------------
57
57
58 # release.py contains version, authors, license, url, keywords, etc.
58 # release.py contains version, authors, license, url, keywords, etc.
59 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
59 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
60
60
61 # Create a dict with the basic information
61 # Create a dict with the basic information
62 # This dict is eventually passed to setup after additional keys are added.
62 # This dict is eventually passed to setup after additional keys are added.
63 setup_args = dict(
63 setup_args = dict(
64 author = author,
64 author = author,
65 author_email = author_email,
65 author_email = author_email,
66 license = license,
66 license = license,
67 )
67 )
68
68
69
69
70 #---------------------------------------------------------------------------
70 #---------------------------------------------------------------------------
71 # Find packages
71 # Find packages
72 #---------------------------------------------------------------------------
72 #---------------------------------------------------------------------------
73
73
74 def find_packages():
74 def find_packages():
75 """
75 """
76 Find all of IPython's packages.
76 Find all of IPython's packages.
77 """
77 """
78 excludes = ['deathrow', 'quarantine']
78 excludes = ['deathrow', 'quarantine']
79 packages = []
79 packages = []
80 for directory, subdirs, files in os.walk("IPython"):
80 for directory, subdirs, files in os.walk("IPython"):
81 package = directory.replace(os.path.sep, ".")
81 package = directory.replace(os.path.sep, ".")
82 if any(package.startswith("IPython." + exc) for exc in excludes):
82 if any(package.startswith("IPython." + exc) for exc in excludes):
83 # package is to be excluded (e.g. deathrow)
83 # package is to be excluded (e.g. deathrow)
84 continue
84 continue
85 if '__init__.py' not in files:
85 if '__init__.py' not in files:
86 # not a package
86 # not a package
87 continue
87 continue
88 packages.append(package)
88 packages.append(package)
89 return packages
89 return packages
90
90
91 #---------------------------------------------------------------------------
91 #---------------------------------------------------------------------------
92 # Find package data
92 # Find package data
93 #---------------------------------------------------------------------------
93 #---------------------------------------------------------------------------
94
94
95 def find_package_data():
95 def find_package_data():
96 """
96 """
97 Find IPython's package_data.
97 Find IPython's package_data.
98 """
98 """
99 # This is not enough for these things to appear in an sdist.
99 # This is not enough for these things to appear in an sdist.
100 # We need to muck with the MANIFEST to get this to work
100 # We need to muck with the MANIFEST to get this to work
101
101
102 package_data = {
102 package_data = {
103 'IPython.core' : ['profile/README*'],
103 'IPython.core' : ['profile/README*'],
104 'IPython.core.tests' : ['*.png', '*.jpg', 'daft_extension/*.py'],
104 'IPython.core.tests' : ['*.png', '*.jpg', 'daft_extension/*.py'],
105 'IPython.lib.tests' : ['*.wav'],
105 'IPython.lib.tests' : ['*.wav'],
106 'IPython.testing.plugin' : ['*.txt'],
106 'IPython.testing.plugin' : ['*.txt'],
107 }
107 }
108
108
109 return package_data
109 return package_data
110
110
111
111
112 def check_package_data(package_data):
112 def check_package_data(package_data):
113 """verify that package_data globs make sense"""
113 """verify that package_data globs make sense"""
114 print("checking package data")
114 print("checking package data")
115 for pkg, data in package_data.items():
115 for pkg, data in package_data.items():
116 pkg_root = pjoin(*pkg.split('.'))
116 pkg_root = pjoin(*pkg.split('.'))
117 for d in data:
117 for d in data:
118 path = pjoin(pkg_root, d)
118 path = pjoin(pkg_root, d)
119 if '*' in path:
119 if '*' in path:
120 assert len(glob(path)) > 0, "No files match pattern %s" % path
120 assert len(glob(path)) > 0, "No files match pattern %s" % path
121 else:
121 else:
122 assert os.path.exists(path), "Missing package data: %s" % path
122 assert os.path.exists(path), "Missing package data: %s" % path
123
123
124
124
125 def check_package_data_first(command):
125 def check_package_data_first(command):
126 """decorator for checking package_data before running a given command
126 """decorator for checking package_data before running a given command
127
127
128 Probably only needs to wrap build_py
128 Probably only needs to wrap build_py
129 """
129 """
130 class DecoratedCommand(command):
130 class DecoratedCommand(command):
131 def run(self):
131 def run(self):
132 check_package_data(self.package_data)
132 check_package_data(self.package_data)
133 command.run(self)
133 command.run(self)
134 return DecoratedCommand
134 return DecoratedCommand
135
135
136
136
137 #---------------------------------------------------------------------------
137 #---------------------------------------------------------------------------
138 # Find data files
138 # Find data files
139 #---------------------------------------------------------------------------
139 #---------------------------------------------------------------------------
140
140
141 def find_data_files():
141 def find_data_files():
142 """
142 """
143 Find IPython's data_files.
143 Find IPython's data_files.
144
144
145 Just man pages at this point.
145 Just man pages at this point.
146 """
146 """
147
147
148 if "freebsd" in sys.platform:
148 if "freebsd" in sys.platform:
149 manpagebase = pjoin('man', 'man1')
149 manpagebase = pjoin('man', 'man1')
150 else:
150 else:
151 manpagebase = pjoin('share', 'man', 'man1')
151 manpagebase = pjoin('share', 'man', 'man1')
152
152
153 # Simple file lists can be made by hand
153 # Simple file lists can be made by hand
154 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
154 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
155 if not manpages:
155 if not manpages:
156 # When running from a source tree, the manpages aren't gzipped
156 # When running from a source tree, the manpages aren't gzipped
157 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
157 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
158
158
159 # And assemble the entire output list
159 # And assemble the entire output list
160 data_files = [ (manpagebase, manpages) ]
160 data_files = [ (manpagebase, manpages) ]
161
161
162 return data_files
162 return data_files
163
163
164
164
165 # The two functions below are copied from IPython.utils.path, so we don't need
165 # The two functions below are copied from IPython.utils.path, so we don't need
166 # to import IPython during setup, which fails on Python 3.
166 # to import IPython during setup, which fails on Python 3.
167
167
168 def target_outdated(target,deps):
168 def target_outdated(target,deps):
169 """Determine whether a target is out of date.
169 """Determine whether a target is out of date.
170
170
171 target_outdated(target,deps) -> 1/0
171 target_outdated(target,deps) -> 1/0
172
172
173 deps: list of filenames which MUST exist.
173 deps: list of filenames which MUST exist.
174 target: single filename which may or may not exist.
174 target: single filename which may or may not exist.
175
175
176 If target doesn't exist or is older than any file listed in deps, return
176 If target doesn't exist or is older than any file listed in deps, return
177 true, otherwise return false.
177 true, otherwise return false.
178 """
178 """
179 try:
179 try:
180 target_time = os.path.getmtime(target)
180 target_time = os.path.getmtime(target)
181 except os.error:
181 except os.error:
182 return 1
182 return 1
183 for dep in deps:
183 for dep in deps:
184 dep_time = os.path.getmtime(dep)
184 dep_time = os.path.getmtime(dep)
185 if dep_time > target_time:
185 if dep_time > target_time:
186 #print "For target",target,"Dep failed:",dep # dbg
186 #print "For target",target,"Dep failed:",dep # dbg
187 #print "times (dep,tar):",dep_time,target_time # dbg
187 #print "times (dep,tar):",dep_time,target_time # dbg
188 return 1
188 return 1
189 return 0
189 return 0
190
190
191
191
192 def target_update(target,deps,cmd):
192 def target_update(target,deps,cmd):
193 """Update a target with a given command given a list of dependencies.
193 """Update a target with a given command given a list of dependencies.
194
194
195 target_update(target,deps,cmd) -> runs cmd if target is outdated.
195 target_update(target,deps,cmd) -> runs cmd if target is outdated.
196
196
197 This is just a wrapper around target_outdated() which calls the given
197 This is just a wrapper around target_outdated() which calls the given
198 command if target is outdated."""
198 command if target is outdated."""
199
199
200 if target_outdated(target,deps):
200 if target_outdated(target,deps):
201 os.system(cmd)
201 os.system(cmd)
202
202
203 #---------------------------------------------------------------------------
203 #---------------------------------------------------------------------------
204 # Find scripts
204 # Find scripts
205 #---------------------------------------------------------------------------
205 #---------------------------------------------------------------------------
206
206
207 def find_entry_points():
207 def find_entry_points():
208 """Defines the command line entry points for IPython
208 """Defines the command line entry points for IPython
209
209
210 This always uses setuptools-style entry points. When setuptools is not in
210 This always uses setuptools-style entry points. When setuptools is not in
211 use, our own build_scripts_entrypt class below parses these and builds
211 use, our own build_scripts_entrypt class below parses these and builds
212 command line scripts.
212 command line scripts.
213
213
214 Each of our entry points gets both a plain name, e.g. ipython, and one
214 Each of our entry points gets a plain name, e.g. ipython, a name
215 suffixed with the Python major version number, e.g. ipython3.
215 suffixed with the Python major version number, e.g. ipython3, and
216 a name suffixed with the Python major.minor version number, eg. ipython3.8.
216 """
217 """
217 ep = [
218 ep = [
218 'ipython%s = IPython:start_ipython',
219 'ipython%s = IPython:start_ipython',
219 ]
220 ]
220 suffix = str(sys.version_info[0])
221 major_suffix = str(sys.version_info[0])
221 return [e % '' for e in ep] + [e % suffix for e in ep]
222 minor_suffix = ".".join([str(sys.version_info[0]), str(sys.version_info[1])])
223 return (
224 [e % "" for e in ep]
225 + [e % major_suffix for e in ep]
226 + [e % minor_suffix for e in ep]
227 )
222
228
223 class install_lib_symlink(Command):
229 class install_lib_symlink(Command):
224 user_options = [
230 user_options = [
225 ('install-dir=', 'd', "directory to install to"),
231 ('install-dir=', 'd', "directory to install to"),
226 ]
232 ]
227
233
228 def initialize_options(self):
234 def initialize_options(self):
229 self.install_dir = None
235 self.install_dir = None
230
236
231 def finalize_options(self):
237 def finalize_options(self):
232 self.set_undefined_options('symlink',
238 self.set_undefined_options('symlink',
233 ('install_lib', 'install_dir'),
239 ('install_lib', 'install_dir'),
234 )
240 )
235
241
236 def run(self):
242 def run(self):
237 if sys.platform == 'win32':
243 if sys.platform == 'win32':
238 raise Exception("This doesn't work on Windows.")
244 raise Exception("This doesn't work on Windows.")
239 pkg = os.path.join(os.getcwd(), 'IPython')
245 pkg = os.path.join(os.getcwd(), 'IPython')
240 dest = os.path.join(self.install_dir, 'IPython')
246 dest = os.path.join(self.install_dir, 'IPython')
241 if os.path.islink(dest):
247 if os.path.islink(dest):
242 print('removing existing symlink at %s' % dest)
248 print('removing existing symlink at %s' % dest)
243 os.unlink(dest)
249 os.unlink(dest)
244 print('symlinking %s -> %s' % (pkg, dest))
250 print('symlinking %s -> %s' % (pkg, dest))
245 os.symlink(pkg, dest)
251 os.symlink(pkg, dest)
246
252
247 class unsymlink(install):
253 class unsymlink(install):
248 def run(self):
254 def run(self):
249 dest = os.path.join(self.install_lib, 'IPython')
255 dest = os.path.join(self.install_lib, 'IPython')
250 if os.path.islink(dest):
256 if os.path.islink(dest):
251 print('removing symlink at %s' % dest)
257 print('removing symlink at %s' % dest)
252 os.unlink(dest)
258 os.unlink(dest)
253 else:
259 else:
254 print('No symlink exists at %s' % dest)
260 print('No symlink exists at %s' % dest)
255
261
256 class install_symlinked(install):
262 class install_symlinked(install):
257 def run(self):
263 def run(self):
258 if sys.platform == 'win32':
264 if sys.platform == 'win32':
259 raise Exception("This doesn't work on Windows.")
265 raise Exception("This doesn't work on Windows.")
260
266
261 # Run all sub-commands (at least those that need to be run)
267 # Run all sub-commands (at least those that need to be run)
262 for cmd_name in self.get_sub_commands():
268 for cmd_name in self.get_sub_commands():
263 self.run_command(cmd_name)
269 self.run_command(cmd_name)
264
270
265 # 'sub_commands': a list of commands this command might have to run to
271 # 'sub_commands': a list of commands this command might have to run to
266 # get its work done. See cmd.py for more info.
272 # get its work done. See cmd.py for more info.
267 sub_commands = [('install_lib_symlink', lambda self:True),
273 sub_commands = [('install_lib_symlink', lambda self:True),
268 ('install_scripts_sym', lambda self:True),
274 ('install_scripts_sym', lambda self:True),
269 ]
275 ]
270
276
271 class install_scripts_for_symlink(install_scripts):
277 class install_scripts_for_symlink(install_scripts):
272 """Redefined to get options from 'symlink' instead of 'install'.
278 """Redefined to get options from 'symlink' instead of 'install'.
273
279
274 I love distutils almost as much as I love setuptools.
280 I love distutils almost as much as I love setuptools.
275 """
281 """
276 def finalize_options(self):
282 def finalize_options(self):
277 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
283 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
278 self.set_undefined_options('symlink',
284 self.set_undefined_options('symlink',
279 ('install_scripts', 'install_dir'),
285 ('install_scripts', 'install_dir'),
280 ('force', 'force'),
286 ('force', 'force'),
281 ('skip_build', 'skip_build'),
287 ('skip_build', 'skip_build'),
282 )
288 )
283
289
284
290
285 #---------------------------------------------------------------------------
291 #---------------------------------------------------------------------------
286 # VCS related
292 # VCS related
287 #---------------------------------------------------------------------------
293 #---------------------------------------------------------------------------
288
294
289
295
290 def git_prebuild(pkg_dir, build_cmd=build_py):
296 def git_prebuild(pkg_dir, build_cmd=build_py):
291 """Return extended build or sdist command class for recording commit
297 """Return extended build or sdist command class for recording commit
292
298
293 records git commit in IPython.utils._sysinfo.commit
299 records git commit in IPython.utils._sysinfo.commit
294
300
295 for use in IPython.utils.sysinfo.sys_info() calls after installation.
301 for use in IPython.utils.sysinfo.sys_info() calls after installation.
296 """
302 """
297
303
298 class MyBuildPy(build_cmd):
304 class MyBuildPy(build_cmd):
299 ''' Subclass to write commit data into installation tree '''
305 ''' Subclass to write commit data into installation tree '''
300 def run(self):
306 def run(self):
301 # loose as `.dev` is suppose to be invalid
307 # loose as `.dev` is suppose to be invalid
302 print("check version number")
308 print("check version number")
303 loose_pep440re = re.compile(r'^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$')
309 loose_pep440re = re.compile(r'^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$')
304 if not loose_pep440re.match(version):
310 if not loose_pep440re.match(version):
305 raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % version)
311 raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % version)
306
312
307
313
308 build_cmd.run(self)
314 build_cmd.run(self)
309 # this one will only fire for build commands
315 # this one will only fire for build commands
310 if hasattr(self, 'build_lib'):
316 if hasattr(self, 'build_lib'):
311 self._record_commit(self.build_lib)
317 self._record_commit(self.build_lib)
312
318
313 def make_release_tree(self, base_dir, files):
319 def make_release_tree(self, base_dir, files):
314 # this one will fire for sdist
320 # this one will fire for sdist
315 build_cmd.make_release_tree(self, base_dir, files)
321 build_cmd.make_release_tree(self, base_dir, files)
316 self._record_commit(base_dir)
322 self._record_commit(base_dir)
317
323
318 def _record_commit(self, base_dir):
324 def _record_commit(self, base_dir):
319 import subprocess
325 import subprocess
320 proc = subprocess.Popen('git rev-parse --short HEAD',
326 proc = subprocess.Popen('git rev-parse --short HEAD',
321 stdout=subprocess.PIPE,
327 stdout=subprocess.PIPE,
322 stderr=subprocess.PIPE,
328 stderr=subprocess.PIPE,
323 shell=True)
329 shell=True)
324 repo_commit, _ = proc.communicate()
330 repo_commit, _ = proc.communicate()
325 repo_commit = repo_commit.strip().decode("ascii")
331 repo_commit = repo_commit.strip().decode("ascii")
326
332
327 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
333 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
328 if os.path.isfile(out_pth) and not repo_commit:
334 if os.path.isfile(out_pth) and not repo_commit:
329 # nothing to write, don't clobber
335 # nothing to write, don't clobber
330 return
336 return
331
337
332 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
338 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
333
339
334 # remove to avoid overwriting original via hard link
340 # remove to avoid overwriting original via hard link
335 try:
341 try:
336 os.remove(out_pth)
342 os.remove(out_pth)
337 except (IOError, OSError):
343 except (IOError, OSError):
338 pass
344 pass
339 with open(out_pth, "w", encoding="utf-8") as out_file:
345 with open(out_pth, "w", encoding="utf-8") as out_file:
340 out_file.writelines(
346 out_file.writelines(
341 [
347 [
342 "# GENERATED BY setup.py\n",
348 "# GENERATED BY setup.py\n",
343 'commit = u"%s"\n' % repo_commit,
349 'commit = "%s"\n' % repo_commit,
344 ]
350 ]
345 )
351 )
346
352
347 return MyBuildPy
353 return MyBuildPy
348
354
General Comments 0
You need to be logged in to leave comments. Login now