##// END OF EJS Templates
Merge branch 'master' into feature-add-autoreload-option-3
skalaydzhiyski -
r26415:aaf09dd1 merge
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,33 +1,33 b''
1 1 name: Run MyPy
2 2
3 3 on:
4 4 push:
5 branches: [ master ]
5 branches: [ master, 7.x]
6 6 pull_request:
7 branches: [ master ]
7 branches: [ master, 7.x]
8 8
9 9 jobs:
10 10 build:
11 11
12 12 runs-on: ubuntu-latest
13 13 strategy:
14 14 matrix:
15 15 python-version: [3.8]
16 16
17 17 steps:
18 18 - uses: actions/checkout@v2
19 19 - name: Set up Python ${{ matrix.python-version }}
20 20 uses: actions/setup-python@v2
21 21 with:
22 22 python-version: ${{ matrix.python-version }}
23 23 - name: Install dependencies
24 24 run: |
25 25 python -m pip install --upgrade pip
26 26 pip install mypy pyflakes flake8
27 27 - name: Lint with mypy
28 28 run: |
29 29 mypy IPython/terminal/ptutils.py
30 30 mypy IPython/core/c*.py
31 31 - name: Lint with pyflakes
32 32 run: |
33 33 flake8 IPython/core/magics/script.py
@@ -1,39 +1,39 b''
1 1 # This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2 2 # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3 3
4 4 name: Python package
5 5
6 6 on:
7 7 push:
8 branches: [ master ]
8 branches: [ master, 7.x ]
9 9 pull_request:
10 branches: [ master ]
10 branches: [ master, 7.x ]
11 11
12 12 jobs:
13 13 build:
14 14
15 15 runs-on: ubuntu-latest
16 16 strategy:
17 17 matrix:
18 18 python-version: [3.8]
19 19
20 20 steps:
21 21 - uses: actions/checkout@v2
22 22 with:
23 23 fetch-depth: 0
24 24 - name: Set up Python ${{ matrix.python-version }}
25 25 uses: actions/setup-python@v2
26 26 with:
27 27 python-version: ${{ matrix.python-version }}
28 28 - name: Install dependencies
29 29 run: |
30 30 python -m pip install --upgrade pip
31 31 pip install darker
32 32 - name: Lint with darker
33 33 run: |
34 34 darker -r 60625f241f298b5039cb2debc365db38aa7bb522 --check --diff . || (
35 35 echo "Changes need auto-formatting. Run:"
36 36 echo " darker -r 60625f241f298b5039cb2debc365db38aa7bb522"
37 37 echo "then commit and push changes to fix."
38 38 exit 1
39 39 )
@@ -1,105 +1,105 b''
1 1 # http://travis-ci.org/#!/ipython/ipython
2 2 language: python
3 3 os: linux
4 4
5 5 addons:
6 6 apt:
7 7 packages:
8 8 - graphviz
9 9
10 10 python:
11 11 - 3.8
12 12
13 13 env:
14 14 global:
15 15 - PATH=$TRAVIS_BUILD_DIR/pandoc:$PATH
16 16
17 17 group: edge
18 18
19 19 before_install:
20 20 - |
21 21 # install Python on macOS
22 22 if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
23 23 env | sort
24 24 if ! which python$TRAVIS_PYTHON_VERSION; then
25 25 HOMEBREW_NO_AUTO_UPDATE=1 brew tap minrk/homebrew-python-frameworks
26 26 HOMEBREW_NO_AUTO_UPDATE=1 brew cask install python-framework-${TRAVIS_PYTHON_VERSION/./}
27 27 fi
28 28 python3 -m pip install virtualenv
29 29 python3 -m virtualenv -p $(which python$TRAVIS_PYTHON_VERSION) ~/travis-env
30 30 source ~/travis-env/bin/activate
31 31 fi
32 32 - python --version
33 33
34 34 install:
35 35 - pip install pip --upgrade
36 36 - pip install setuptools --upgrade
37 37 - pip install -e file://$PWD#egg=ipython[test] --upgrade
38 38 - pip install trio curio --upgrade --upgrade-strategy eager
39 39 - pip install 'pytest' 'matplotlib !=3.2.0'
40 - pip install codecov check-manifest pytest-cov --upgrade anyio pytest-asyncio
40 - pip install codecov check-manifest pytest-cov --upgrade anyio pytest-trio
41 41
42 42
43 43 script:
44 44 - check-manifest
45 45 - |
46 46 if [[ "$TRAVIS_PYTHON_VERSION" == "nightly" ]]; then
47 47 # on nightly fake parso known the grammar
48 48 cp /home/travis/virtualenv/python3.9-dev/lib/python3.9/site-packages/parso/python/grammar38.txt /home/travis/virtualenv/python3.9-dev/lib/python3.9/site-packages/parso/python/grammar39.txt
49 49 fi
50 50 - |
51 51 if [[ "$TRAVIS_PYTHON_VERSION" == "3.8" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
52 52 cd /tmp && iptest --coverage xml && cd -
53 53 fi
54 54 - pytest --maxfail=10 IPython
55 55 # On the latest Python (on Linux) only, make sure that the docs build.
56 56 - |
57 57 if [[ "$TRAVIS_PYTHON_VERSION" == "3.8" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
58 58 pip install -r docs/requirements.txt
59 59 python tools/fixup_whats_new_pr.py
60 60 make -C docs/ html SPHINXOPTS="-W"
61 61 fi
62 62
63 63 after_success:
64 64 - cp /tmp/ipy_coverage.xml ./
65 65 - cp /tmp/.coverage ./
66 66 - codecov
67 67
68 68 matrix:
69 69 include:
70 70 - arch: amd64
71 71 python: "3.7"
72 72 dist: xenial
73 73 - arch: amd64
74 74 python: "3.8"
75 75 dist: xenial
76 76 - arch: amd64
77 77 python: "nightly"
78 78 dist: xenial
79 79 - arch: amd64
80 80 python: "3.9-dev"
81 81 - os: osx
82 82 language: generic
83 83 python: 3.7
84 84 env: TRAVIS_PYTHON_VERSION=3.7
85 85 allow_failures:
86 86 - python: nightly
87 87
88 88 before_deploy:
89 89 - rm -rf dist/
90 90 - python setup.py sdist
91 91 - python setup.py bdist_wheel
92 92
93 93 deploy:
94 94 provider: releases
95 95 api_key:
96 96 secure: Y/Ae9tYs5aoBU8bDjN2YrwGG6tCbezj/h3Lcmtx8HQavSbBgXnhnZVRb2snOKD7auqnqjfT/7QMm4ZyKvaOEgyggGktKqEKYHC8KOZ7yp8I5/UMDtk6j9TnXpSqqBxPiud4MDV76SfRYEQiaDoG4tGGvSfPJ9KcNjKrNvSyyxns=
97 97 file: dist/*
98 98 file_glob: true
99 99 cleanup: false
100 100 on:
101 101 repo: ipython/ipython
102 102 all_branches: true # Backports are released from e.g. 5.x branch
103 103 tags: true
104 104 python: 3.6 # Any version should work, but we only need one
105 105 condition: $TRAVIS_OS_NAME = "linux"
@@ -1,160 +1,188 b''
1 1 """Compiler tools with improved interactive support.
2 2
3 3 Provides compilation machinery similar to codeop, but with caching support so
4 4 we can provide interactive tracebacks.
5 5
6 6 Authors
7 7 -------
8 8 * Robert Kern
9 9 * Fernando Perez
10 10 * Thomas Kluyver
11 11 """
12 12
13 13 # Note: though it might be more natural to name this module 'compiler', that
14 14 # name is in the stdlib and name collisions with the stdlib tend to produce
15 15 # weird problems (often with third-party tools).
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Copyright (C) 2010-2011 The IPython Development Team.
19 19 #
20 20 # Distributed under the terms of the BSD License.
21 21 #
22 22 # The full license is in the file COPYING.txt, distributed with this software.
23 23 #-----------------------------------------------------------------------------
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Imports
27 27 #-----------------------------------------------------------------------------
28 28
29 29 # Stdlib imports
30 30 import __future__
31 31 from ast import PyCF_ONLY_AST
32 32 import codeop
33 33 import functools
34 34 import hashlib
35 35 import linecache
36 36 import operator
37 37 import time
38 38 from contextlib import contextmanager
39 39
40 40 #-----------------------------------------------------------------------------
41 41 # Constants
42 42 #-----------------------------------------------------------------------------
43 43
44 44 # Roughly equal to PyCF_MASK | PyCF_MASK_OBSOLETE as defined in pythonrun.h,
45 45 # this is used as a bitmask to extract future-related code flags.
46 46 PyCF_MASK = functools.reduce(operator.or_,
47 47 (getattr(__future__, fname).compiler_flag
48 48 for fname in __future__.all_feature_names))
49 49
50 50 #-----------------------------------------------------------------------------
51 51 # Local utilities
52 52 #-----------------------------------------------------------------------------
53 53
54 54 def code_name(code, number=0):
55 55 """ Compute a (probably) unique name for code for caching.
56 56
57 57 This now expects code to be unicode.
58 58 """
59 59 hash_digest = hashlib.sha1(code.encode("utf-8")).hexdigest()
60 60 # Include the number and 12 characters of the hash in the name. It's
61 61 # pretty much impossible that in a single session we'll have collisions
62 62 # even with truncated hashes, and the full one makes tracebacks too long
63 63 return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
64 64
65 65 #-----------------------------------------------------------------------------
66 66 # Classes and functions
67 67 #-----------------------------------------------------------------------------
68 68
69 69 class CachingCompiler(codeop.Compile):
70 70 """A compiler that caches code compiled from interactive statements.
71 71 """
72 72
73 73 def __init__(self):
74 74 codeop.Compile.__init__(self)
75 75
76 76 # This is ugly, but it must be done this way to allow multiple
77 77 # simultaneous ipython instances to coexist. Since Python itself
78 78 # directly accesses the data structures in the linecache module, and
79 79 # the cache therein is global, we must work with that data structure.
80 80 # We must hold a reference to the original checkcache routine and call
81 81 # that in our own check_cache() below, but the special IPython cache
82 82 # must also be shared by all IPython instances. If we were to hold
83 83 # separate caches (one in each CachingCompiler instance), any call made
84 84 # by Python itself to linecache.checkcache() would obliterate the
85 85 # cached data from the other IPython instances.
86 86 if not hasattr(linecache, '_ipython_cache'):
87 87 linecache._ipython_cache = {}
88 88 if not hasattr(linecache, '_checkcache_ori'):
89 89 linecache._checkcache_ori = linecache.checkcache
90 90 # Now, we must monkeypatch the linecache directly so that parts of the
91 91 # stdlib that call it outside our control go through our codepath
92 92 # (otherwise we'd lose our tracebacks).
93 93 linecache.checkcache = check_linecache_ipython
94 94
95 95
96 96 def ast_parse(self, source, filename='<unknown>', symbol='exec'):
97 97 """Parse code to an AST with the current compiler flags active.
98 98
99 99 Arguments are exactly the same as ast.parse (in the standard library),
100 100 and are passed to the built-in compile function."""
101 101 return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
102 102
103 103 def reset_compiler_flags(self):
104 104 """Reset compiler flags to default state."""
105 105 # This value is copied from codeop.Compile.__init__, so if that ever
106 106 # changes, it will need to be updated.
107 107 self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
108 108
109 109 @property
110 110 def compiler_flags(self):
111 111 """Flags currently active in the compilation process.
112 112 """
113 113 return self.flags
114 114
115 def cache(self, code, number=0):
115 def get_code_name(self, raw_code, transformed_code, number):
116 """Compute filename given the code, and the cell number.
117
118 Parameters
119 ----------
120 raw_code : str
121 The raw cell code.
122 transformed_code : str
123 The executable Python source code to cache and compile.
124 number : int
125 A number which forms part of the code's name. Used for the execution
126 counter.
127
128 Returns
129 -------
130 The computed filename.
131 """
132 return code_name(transformed_code, number)
133
134 def cache(self, transformed_code, number=0, raw_code=None):
116 135 """Make a name for a block of code, and cache the code.
117 136
118 137 Parameters
119 138 ----------
120 code : str
121 The Python source code to cache.
139 transformed_code : str
140 The executable Python source code to cache and compile.
122 141 number : int
123 142 A number which forms part of the code's name. Used for the execution
124 143 counter.
144 raw_code : str
145 The raw code before transformation, if None, set to `transformed_code`.
125 146
126 147 Returns
127 148 -------
128 149 The name of the cached code (as a string). Pass this as the filename
129 150 argument to compilation, so that tracebacks are correctly hooked up.
130 151 """
131 name = code_name(code, number)
132 entry = (len(code), time.time(),
133 [line+'\n' for line in code.splitlines()], name)
152 if raw_code is None:
153 raw_code = transformed_code
154
155 name = self.get_code_name(raw_code, transformed_code, number)
156 entry = (
157 len(transformed_code),
158 time.time(),
159 [line + "\n" for line in transformed_code.splitlines()],
160 name,
161 )
134 162 linecache.cache[name] = entry
135 163 linecache._ipython_cache[name] = entry
136 164 return name
137 165
138 166 @contextmanager
139 167 def extra_flags(self, flags):
140 168 ## bits that we'll set to 1
141 169 turn_on_bits = ~self.flags & flags
142 170
143 171
144 172 self.flags = self.flags | flags
145 173 try:
146 174 yield
147 175 finally:
148 176 # turn off only the bits we turned on so that something like
149 177 # __future__ that set flags stays.
150 178 self.flags &= ~turn_on_bits
151 179
152 180
153 181 def check_linecache_ipython(*args):
154 182 """Call linecache.checkcache() safely protecting our cached values.
155 183 """
156 184 # First call the original checkcache as intended
157 185 linecache._checkcache_ori(*args)
158 186 # Then, update back the cache with our data, so that tracebacks related
159 187 # to our compiled codes can be produced.
160 188 linecache.cache.update(linecache._ipython_cache)
@@ -1,2229 +1,2239 b''
1 1 """Completion for IPython.
2 2
3 3 This module started as fork of the rlcompleter module in the Python standard
4 4 library. The original enhancements made to rlcompleter have been sent
5 5 upstream and were accepted as of Python 2.3,
6 6
7 7 This module now support a wide variety of completion mechanism both available
8 8 for normal classic Python code, as well as completer for IPython specific
9 9 Syntax like magics.
10 10
11 11 Latex and Unicode completion
12 12 ============================
13 13
14 14 IPython and compatible frontends not only can complete your code, but can help
15 15 you to input a wide range of characters. In particular we allow you to insert
16 16 a unicode character using the tab completion mechanism.
17 17
18 18 Forward latex/unicode completion
19 19 --------------------------------
20 20
21 21 Forward completion allows you to easily type a unicode character using its latex
22 22 name, or unicode long description. To do so type a backslash follow by the
23 23 relevant name and press tab:
24 24
25 25
26 26 Using latex completion:
27 27
28 28 .. code::
29 29
30 30 \\alpha<tab>
31 31 α
32 32
33 33 or using unicode completion:
34 34
35 35
36 36 .. code::
37 37
38 38 \\GREEK SMALL LETTER ALPHA<tab>
39 39 α
40 40
41 41
42 42 Only valid Python identifiers will complete. Combining characters (like arrow or
43 43 dots) are also available, unlike latex they need to be put after the their
44 44 counterpart that is to say, `F\\\\vec<tab>` is correct, not `\\\\vec<tab>F`.
45 45
46 46 Some browsers are known to display combining characters incorrectly.
47 47
48 48 Backward latex completion
49 49 -------------------------
50 50
51 51 It is sometime challenging to know how to type a character, if you are using
52 52 IPython, or any compatible frontend you can prepend backslash to the character
53 53 and press `<tab>` to expand it to its latex form.
54 54
55 55 .. code::
56 56
57 57 \\α<tab>
58 58 \\alpha
59 59
60 60
61 61 Both forward and backward completions can be deactivated by setting the
62 62 ``Completer.backslash_combining_completions`` option to ``False``.
63 63
64 64
65 65 Experimental
66 66 ============
67 67
68 68 Starting with IPython 6.0, this module can make use of the Jedi library to
69 69 generate completions both using static analysis of the code, and dynamically
70 70 inspecting multiple namespaces. Jedi is an autocompletion and static analysis
71 71 for Python. The APIs attached to this new mechanism is unstable and will
72 72 raise unless use in an :any:`provisionalcompleter` context manager.
73 73
74 74 You will find that the following are experimental:
75 75
76 76 - :any:`provisionalcompleter`
77 77 - :any:`IPCompleter.completions`
78 78 - :any:`Completion`
79 79 - :any:`rectify_completions`
80 80
81 81 .. note::
82 82
83 83 better name for :any:`rectify_completions` ?
84 84
85 85 We welcome any feedback on these new API, and we also encourage you to try this
86 86 module in debug mode (start IPython with ``--Completer.debug=True``) in order
87 87 to have extra logging information if :any:`jedi` is crashing, or if current
88 88 IPython completer pending deprecations are returning results not yet handled
89 89 by :any:`jedi`
90 90
91 91 Using Jedi for tab completion allow snippets like the following to work without
92 92 having to execute any code:
93 93
94 94 >>> myvar = ['hello', 42]
95 95 ... myvar[1].bi<tab>
96 96
97 97 Tab completion will be able to infer that ``myvar[1]`` is a real number without
98 98 executing any code unlike the previously available ``IPCompleter.greedy``
99 99 option.
100 100
101 101 Be sure to update :any:`jedi` to the latest stable version or to try the
102 102 current development version to get better completions.
103 103 """
104 104
105 105
106 106 # Copyright (c) IPython Development Team.
107 107 # Distributed under the terms of the Modified BSD License.
108 108 #
109 109 # Some of this code originated from rlcompleter in the Python standard library
110 110 # Copyright (C) 2001 Python Software Foundation, www.python.org
111 111
112 112
113 113 import builtins as builtin_mod
114 114 import glob
115 115 import inspect
116 116 import itertools
117 117 import keyword
118 118 import os
119 119 import re
120 120 import string
121 121 import sys
122 122 import time
123 123 import unicodedata
124 124 import uuid
125 125 import warnings
126 126 from contextlib import contextmanager
127 127 from importlib import import_module
128 128 from types import SimpleNamespace
129 129 from typing import Iterable, Iterator, List, Tuple, Union, Any, Sequence, Dict, NamedTuple, Pattern, Optional
130 130
131 131 from IPython.core.error import TryNext
132 132 from IPython.core.inputtransformer2 import ESC_MAGIC
133 133 from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol
134 134 from IPython.core.oinspect import InspectColors
135 135 from IPython.utils import generics
136 136 from IPython.utils.dir2 import dir2, get_real_method
137 137 from IPython.utils.path import ensure_dir_exists
138 138 from IPython.utils.process import arg_split
139 139 from traitlets import Bool, Enum, Int, List as ListTrait, Unicode, default, observe
140 140 from traitlets.config.configurable import Configurable
141 141
142 142 import __main__
143 143
144 144 # skip module docstests
145 145 skip_doctest = True
146 146
147 147 try:
148 148 import jedi
149 149 jedi.settings.case_insensitive_completion = False
150 150 import jedi.api.helpers
151 151 import jedi.api.classes
152 152 JEDI_INSTALLED = True
153 153 except ImportError:
154 154 JEDI_INSTALLED = False
155 155 #-----------------------------------------------------------------------------
156 156 # Globals
157 157 #-----------------------------------------------------------------------------
158 158
159 159 # ranges where we have most of the valid unicode names. We could be more finer
160 160 # grained but is it worth it for performace While unicode have character in the
161 161 # rage 0, 0x110000, we seem to have name for about 10% of those. (131808 as I
162 162 # write this). With below range we cover them all, with a density of ~67%
163 163 # biggest next gap we consider only adds up about 1% density and there are 600
164 164 # gaps that would need hard coding.
165 165 _UNICODE_RANGES = [(32, 0x3134b), (0xe0001, 0xe01f0)]
166 166
167 167 # Public API
168 168 __all__ = ['Completer','IPCompleter']
169 169
170 170 if sys.platform == 'win32':
171 171 PROTECTABLES = ' '
172 172 else:
173 173 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
174 174
175 175 # Protect against returning an enormous number of completions which the frontend
176 176 # may have trouble processing.
177 177 MATCHES_LIMIT = 500
178 178
179 179 _deprecation_readline_sentinel = object()
180 180
181 181
182 182 class ProvisionalCompleterWarning(FutureWarning):
183 183 """
184 184 Exception raise by an experimental feature in this module.
185 185
186 186 Wrap code in :any:`provisionalcompleter` context manager if you
187 187 are certain you want to use an unstable feature.
188 188 """
189 189 pass
190 190
191 191 warnings.filterwarnings('error', category=ProvisionalCompleterWarning)
192 192
193 193 @contextmanager
194 194 def provisionalcompleter(action='ignore'):
195 195 """
196 196 This context manager has to be used in any place where unstable completer
197 197 behavior and API may be called.
198 198
199 199 >>> with provisionalcompleter():
200 200 ... completer.do_experimental_things() # works
201 201
202 202 >>> completer.do_experimental_things() # raises.
203 203
204 .. note:: Unstable
204 .. note::
205
206 Unstable
205 207
206 208 By using this context manager you agree that the API in use may change
207 209 without warning, and that you won't complain if they do so.
208 210
209 211 You also understand that, if the API is not to your liking, you should report
210 212 a bug to explain your use case upstream.
211 213
212 214 We'll be happy to get your feedback, feature requests, and improvements on
213 215 any of the unstable APIs!
214 216 """
215 217 with warnings.catch_warnings():
216 218 warnings.filterwarnings(action, category=ProvisionalCompleterWarning)
217 219 yield
218 220
219 221
220 222 def has_open_quotes(s):
221 223 """Return whether a string has open quotes.
222 224
223 225 This simply counts whether the number of quote characters of either type in
224 226 the string is odd.
225 227
226 228 Returns
227 229 -------
228 230 If there is an open quote, the quote character is returned. Else, return
229 231 False.
230 232 """
231 233 # We check " first, then ', so complex cases with nested quotes will get
232 234 # the " to take precedence.
233 235 if s.count('"') % 2:
234 236 return '"'
235 237 elif s.count("'") % 2:
236 238 return "'"
237 239 else:
238 240 return False
239 241
240 242
241 243 def protect_filename(s, protectables=PROTECTABLES):
242 244 """Escape a string to protect certain characters."""
243 245 if set(s) & set(protectables):
244 246 if sys.platform == "win32":
245 247 return '"' + s + '"'
246 248 else:
247 249 return "".join(("\\" + c if c in protectables else c) for c in s)
248 250 else:
249 251 return s
250 252
251 253
252 254 def expand_user(path:str) -> Tuple[str, bool, str]:
253 255 """Expand ``~``-style usernames in strings.
254 256
255 257 This is similar to :func:`os.path.expanduser`, but it computes and returns
256 258 extra information that will be useful if the input was being used in
257 259 computing completions, and you wish to return the completions with the
258 260 original '~' instead of its expanded value.
259 261
260 262 Parameters
261 263 ----------
262 264 path : str
263 265 String to be expanded. If no ~ is present, the output is the same as the
264 266 input.
265 267
266 268 Returns
267 269 -------
268 270 newpath : str
269 271 Result of ~ expansion in the input path.
270 272 tilde_expand : bool
271 273 Whether any expansion was performed or not.
272 274 tilde_val : str
273 275 The value that ~ was replaced with.
274 276 """
275 277 # Default values
276 278 tilde_expand = False
277 279 tilde_val = ''
278 280 newpath = path
279 281
280 282 if path.startswith('~'):
281 283 tilde_expand = True
282 284 rest = len(path)-1
283 285 newpath = os.path.expanduser(path)
284 286 if rest:
285 287 tilde_val = newpath[:-rest]
286 288 else:
287 289 tilde_val = newpath
288 290
289 291 return newpath, tilde_expand, tilde_val
290 292
291 293
292 294 def compress_user(path:str, tilde_expand:bool, tilde_val:str) -> str:
293 295 """Does the opposite of expand_user, with its outputs.
294 296 """
295 297 if tilde_expand:
296 298 return path.replace(tilde_val, '~')
297 299 else:
298 300 return path
299 301
300 302
301 303 def completions_sorting_key(word):
302 304 """key for sorting completions
303 305
304 306 This does several things:
305 307
306 308 - Demote any completions starting with underscores to the end
307 309 - Insert any %magic and %%cellmagic completions in the alphabetical order
308 310 by their name
309 311 """
310 312 prio1, prio2 = 0, 0
311 313
312 314 if word.startswith('__'):
313 315 prio1 = 2
314 316 elif word.startswith('_'):
315 317 prio1 = 1
316 318
317 319 if word.endswith('='):
318 320 prio1 = -1
319 321
320 322 if word.startswith('%%'):
321 323 # If there's another % in there, this is something else, so leave it alone
322 324 if not "%" in word[2:]:
323 325 word = word[2:]
324 326 prio2 = 2
325 327 elif word.startswith('%'):
326 328 if not "%" in word[1:]:
327 329 word = word[1:]
328 330 prio2 = 1
329 331
330 332 return prio1, word, prio2
331 333
332 334
333 335 class _FakeJediCompletion:
334 336 """
335 337 This is a workaround to communicate to the UI that Jedi has crashed and to
336 338 report a bug. Will be used only id :any:`IPCompleter.debug` is set to true.
337 339
338 340 Added in IPython 6.0 so should likely be removed for 7.0
339 341
340 342 """
341 343
342 344 def __init__(self, name):
343 345
344 346 self.name = name
345 347 self.complete = name
346 348 self.type = 'crashed'
347 349 self.name_with_symbols = name
348 350 self.signature = ''
349 351 self._origin = 'fake'
350 352
351 353 def __repr__(self):
352 354 return '<Fake completion object jedi has crashed>'
353 355
354 356
355 357 class Completion:
356 358 """
357 359 Completion object used and return by IPython completers.
358 360
359 .. warning:: Unstable
361 .. warning::
362
363 Unstable
360 364
361 365 This function is unstable, API may change without warning.
362 366 It will also raise unless use in proper context manager.
363 367
364 368 This act as a middle ground :any:`Completion` object between the
365 369 :any:`jedi.api.classes.Completion` object and the Prompt Toolkit completion
366 370 object. While Jedi need a lot of information about evaluator and how the
367 371 code should be ran/inspected, PromptToolkit (and other frontend) mostly
368 372 need user facing information.
369 373
370 374 - Which range should be replaced replaced by what.
371 375 - Some metadata (like completion type), or meta information to displayed to
372 376 the use user.
373 377
374 378 For debugging purpose we can also store the origin of the completion (``jedi``,
375 379 ``IPython.python_matches``, ``IPython.magics_matches``...).
376 380 """
377 381
378 382 __slots__ = ['start', 'end', 'text', 'type', 'signature', '_origin']
379 383
380 384 def __init__(self, start: int, end: int, text: str, *, type: str=None, _origin='', signature='') -> None:
381 385 warnings.warn("``Completion`` is a provisional API (as of IPython 6.0). "
382 386 "It may change without warnings. "
383 387 "Use in corresponding context manager.",
384 388 category=ProvisionalCompleterWarning, stacklevel=2)
385 389
386 390 self.start = start
387 391 self.end = end
388 392 self.text = text
389 393 self.type = type
390 394 self.signature = signature
391 395 self._origin = _origin
392 396
393 397 def __repr__(self):
394 398 return '<Completion start=%s end=%s text=%r type=%r, signature=%r,>' % \
395 399 (self.start, self.end, self.text, self.type or '?', self.signature or '?')
396 400
397 401 def __eq__(self, other)->Bool:
398 402 """
399 403 Equality and hash do not hash the type (as some completer may not be
400 404 able to infer the type), but are use to (partially) de-duplicate
401 405 completion.
402 406
403 407 Completely de-duplicating completion is a bit tricker that just
404 408 comparing as it depends on surrounding text, which Completions are not
405 409 aware of.
406 410 """
407 411 return self.start == other.start and \
408 412 self.end == other.end and \
409 413 self.text == other.text
410 414
411 415 def __hash__(self):
412 416 return hash((self.start, self.end, self.text))
413 417
414 418
415 419 _IC = Iterable[Completion]
416 420
417 421
418 422 def _deduplicate_completions(text: str, completions: _IC)-> _IC:
419 423 """
420 424 Deduplicate a set of completions.
421 425
422 .. warning:: Unstable
426 .. warning::
427
428 Unstable
423 429
424 430 This function is unstable, API may change without warning.
425 431
426 432 Parameters
427 433 ----------
428 434 text: str
429 435 text that should be completed.
430 436 completions: Iterator[Completion]
431 437 iterator over the completions to deduplicate
432 438
433 439 Yields
434 440 ------
435 441 `Completions` objects
436 442 Completions coming from multiple sources, may be different but end up having
437 443 the same effect when applied to ``text``. If this is the case, this will
438 444 consider completions as equal and only emit the first encountered.
439 445 Not folded in `completions()` yet for debugging purpose, and to detect when
440 446 the IPython completer does return things that Jedi does not, but should be
441 447 at some point.
442 448 """
443 449 completions = list(completions)
444 450 if not completions:
445 451 return
446 452
447 453 new_start = min(c.start for c in completions)
448 454 new_end = max(c.end for c in completions)
449 455
450 456 seen = set()
451 457 for c in completions:
452 458 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
453 459 if new_text not in seen:
454 460 yield c
455 461 seen.add(new_text)
456 462
457 463
458 464 def rectify_completions(text: str, completions: _IC, *, _debug=False)->_IC:
459 465 """
460 466 Rectify a set of completions to all have the same ``start`` and ``end``
461 467
462 .. warning:: Unstable
468 .. warning::
469
470 Unstable
463 471
464 472 This function is unstable, API may change without warning.
465 473 It will also raise unless use in proper context manager.
466 474
467 475 Parameters
468 476 ----------
469 477 text: str
470 478 text that should be completed.
471 479 completions: Iterator[Completion]
472 480 iterator over the completions to rectify
473 481
474 482 Notes
475 483 -----
476 484 :any:`jedi.api.classes.Completion` s returned by Jedi may not have the same start and end, though
477 485 the Jupyter Protocol requires them to behave like so. This will readjust
478 486 the completion to have the same ``start`` and ``end`` by padding both
479 487 extremities with surrounding text.
480 488
481 489 During stabilisation should support a ``_debug`` option to log which
482 490 completion are return by the IPython completer and not found in Jedi in
483 491 order to make upstream bug report.
484 492 """
485 493 warnings.warn("`rectify_completions` is a provisional API (as of IPython 6.0). "
486 494 "It may change without warnings. "
487 495 "Use in corresponding context manager.",
488 496 category=ProvisionalCompleterWarning, stacklevel=2)
489 497
490 498 completions = list(completions)
491 499 if not completions:
492 500 return
493 501 starts = (c.start for c in completions)
494 502 ends = (c.end for c in completions)
495 503
496 504 new_start = min(starts)
497 505 new_end = max(ends)
498 506
499 507 seen_jedi = set()
500 508 seen_python_matches = set()
501 509 for c in completions:
502 510 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
503 511 if c._origin == 'jedi':
504 512 seen_jedi.add(new_text)
505 513 elif c._origin == 'IPCompleter.python_matches':
506 514 seen_python_matches.add(new_text)
507 515 yield Completion(new_start, new_end, new_text, type=c.type, _origin=c._origin, signature=c.signature)
508 516 diff = seen_python_matches.difference(seen_jedi)
509 517 if diff and _debug:
510 518 print('IPython.python matches have extras:', diff)
511 519
512 520
513 521 if sys.platform == 'win32':
514 522 DELIMS = ' \t\n`!@#$^&*()=+[{]}|;\'",<>?'
515 523 else:
516 524 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
517 525
518 526 GREEDY_DELIMS = ' =\r\n'
519 527
520 528
521 529 class CompletionSplitter(object):
522 530 """An object to split an input line in a manner similar to readline.
523 531
524 532 By having our own implementation, we can expose readline-like completion in
525 533 a uniform manner to all frontends. This object only needs to be given the
526 534 line of text to be split and the cursor position on said line, and it
527 535 returns the 'word' to be completed on at the cursor after splitting the
528 536 entire line.
529 537
530 538 What characters are used as splitting delimiters can be controlled by
531 539 setting the ``delims`` attribute (this is a property that internally
532 540 automatically builds the necessary regular expression)"""
533 541
534 542 # Private interface
535 543
536 544 # A string of delimiter characters. The default value makes sense for
537 545 # IPython's most typical usage patterns.
538 546 _delims = DELIMS
539 547
540 548 # The expression (a normal string) to be compiled into a regular expression
541 549 # for actual splitting. We store it as an attribute mostly for ease of
542 550 # debugging, since this type of code can be so tricky to debug.
543 551 _delim_expr = None
544 552
545 553 # The regular expression that does the actual splitting
546 554 _delim_re = None
547 555
548 556 def __init__(self, delims=None):
549 557 delims = CompletionSplitter._delims if delims is None else delims
550 558 self.delims = delims
551 559
552 560 @property
553 561 def delims(self):
554 562 """Return the string of delimiter characters."""
555 563 return self._delims
556 564
557 565 @delims.setter
558 566 def delims(self, delims):
559 567 """Set the delimiters for line splitting."""
560 568 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
561 569 self._delim_re = re.compile(expr)
562 570 self._delims = delims
563 571 self._delim_expr = expr
564 572
565 573 def split_line(self, line, cursor_pos=None):
566 574 """Split a line of text with a cursor at the given position.
567 575 """
568 576 l = line if cursor_pos is None else line[:cursor_pos]
569 577 return self._delim_re.split(l)[-1]
570 578
571 579
572 580
573 581 class Completer(Configurable):
574 582
575 583 greedy = Bool(False,
576 584 help="""Activate greedy completion
577 585 PENDING DEPRECTION. this is now mostly taken care of with Jedi.
578 586
579 587 This will enable completion on elements of lists, results of function calls, etc.,
580 588 but can be unsafe because the code is actually evaluated on TAB.
581 589 """
582 590 ).tag(config=True)
583 591
584 592 use_jedi = Bool(default_value=JEDI_INSTALLED,
585 593 help="Experimental: Use Jedi to generate autocompletions. "
586 594 "Default to True if jedi is installed.").tag(config=True)
587 595
588 596 jedi_compute_type_timeout = Int(default_value=400,
589 597 help="""Experimental: restrict time (in milliseconds) during which Jedi can compute types.
590 598 Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt
591 599 performance by preventing jedi to build its cache.
592 600 """).tag(config=True)
593 601
594 602 debug = Bool(default_value=False,
595 603 help='Enable debug for the Completer. Mostly print extra '
596 604 'information for experimental jedi integration.')\
597 605 .tag(config=True)
598 606
599 607 backslash_combining_completions = Bool(True,
600 608 help="Enable unicode completions, e.g. \\alpha<tab> . "
601 609 "Includes completion of latex commands, unicode names, and expanding "
602 610 "unicode characters back to latex commands.").tag(config=True)
603 611
604 612
605 613
606 614 def __init__(self, namespace=None, global_namespace=None, **kwargs):
607 615 """Create a new completer for the command line.
608 616
609 617 Completer(namespace=ns, global_namespace=ns2) -> completer instance.
610 618
611 619 If unspecified, the default namespace where completions are performed
612 620 is __main__ (technically, __main__.__dict__). Namespaces should be
613 621 given as dictionaries.
614 622
615 623 An optional second namespace can be given. This allows the completer
616 624 to handle cases where both the local and global scopes need to be
617 625 distinguished.
618 626 """
619 627
620 628 # Don't bind to namespace quite yet, but flag whether the user wants a
621 629 # specific namespace or to use __main__.__dict__. This will allow us
622 630 # to bind to __main__.__dict__ at completion time, not now.
623 631 if namespace is None:
624 632 self.use_main_ns = True
625 633 else:
626 634 self.use_main_ns = False
627 635 self.namespace = namespace
628 636
629 637 # The global namespace, if given, can be bound directly
630 638 if global_namespace is None:
631 639 self.global_namespace = {}
632 640 else:
633 641 self.global_namespace = global_namespace
634 642
635 643 self.custom_matchers = []
636 644
637 645 super(Completer, self).__init__(**kwargs)
638 646
639 647 def complete(self, text, state):
640 648 """Return the next possible completion for 'text'.
641 649
642 650 This is called successively with state == 0, 1, 2, ... until it
643 651 returns None. The completion should begin with 'text'.
644 652
645 653 """
646 654 if self.use_main_ns:
647 655 self.namespace = __main__.__dict__
648 656
649 657 if state == 0:
650 658 if "." in text:
651 659 self.matches = self.attr_matches(text)
652 660 else:
653 661 self.matches = self.global_matches(text)
654 662 try:
655 663 return self.matches[state]
656 664 except IndexError:
657 665 return None
658 666
659 667 def global_matches(self, text):
660 668 """Compute matches when text is a simple name.
661 669
662 670 Return a list of all keywords, built-in functions and names currently
663 671 defined in self.namespace or self.global_namespace that match.
664 672
665 673 """
666 674 matches = []
667 675 match_append = matches.append
668 676 n = len(text)
669 677 for lst in [keyword.kwlist,
670 678 builtin_mod.__dict__.keys(),
671 679 self.namespace.keys(),
672 680 self.global_namespace.keys()]:
673 681 for word in lst:
674 682 if word[:n] == text and word != "__builtins__":
675 683 match_append(word)
676 684
677 685 snake_case_re = re.compile(r"[^_]+(_[^_]+)+?\Z")
678 686 for lst in [self.namespace.keys(),
679 687 self.global_namespace.keys()]:
680 688 shortened = {"_".join([sub[0] for sub in word.split('_')]) : word
681 689 for word in lst if snake_case_re.match(word)}
682 690 for word in shortened.keys():
683 691 if word[:n] == text and word != "__builtins__":
684 692 match_append(shortened[word])
685 693 return matches
686 694
687 695 def attr_matches(self, text):
688 696 """Compute matches when text contains a dot.
689 697
690 698 Assuming the text is of the form NAME.NAME....[NAME], and is
691 699 evaluatable in self.namespace or self.global_namespace, it will be
692 700 evaluated and its attributes (as revealed by dir()) are used as
693 701 possible completions. (For class instances, class members are
694 702 also considered.)
695 703
696 704 WARNING: this can still invoke arbitrary C code, if an object
697 705 with a __getattr__ hook is evaluated.
698 706
699 707 """
700 708
701 709 # Another option, seems to work great. Catches things like ''.<tab>
702 710 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
703 711
704 712 if m:
705 713 expr, attr = m.group(1, 3)
706 714 elif self.greedy:
707 715 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
708 716 if not m2:
709 717 return []
710 718 expr, attr = m2.group(1,2)
711 719 else:
712 720 return []
713 721
714 722 try:
715 723 obj = eval(expr, self.namespace)
716 724 except:
717 725 try:
718 726 obj = eval(expr, self.global_namespace)
719 727 except:
720 728 return []
721 729
722 730 if self.limit_to__all__ and hasattr(obj, '__all__'):
723 731 words = get__all__entries(obj)
724 732 else:
725 733 words = dir2(obj)
726 734
727 735 try:
728 736 words = generics.complete_object(obj, words)
729 737 except TryNext:
730 738 pass
731 739 except AssertionError:
732 740 raise
733 741 except Exception:
734 742 # Silence errors from completion function
735 743 #raise # dbg
736 744 pass
737 745 # Build match list to return
738 746 n = len(attr)
739 747 return [u"%s.%s" % (expr, w) for w in words if w[:n] == attr ]
740 748
741 749
742 750 def get__all__entries(obj):
743 751 """returns the strings in the __all__ attribute"""
744 752 try:
745 753 words = getattr(obj, '__all__')
746 754 except:
747 755 return []
748 756
749 757 return [w for w in words if isinstance(w, str)]
750 758
751 759
752 760 def match_dict_keys(keys: List[Union[str, bytes, Tuple[Union[str, bytes]]]], prefix: str, delims: str,
753 761 extra_prefix: Optional[Tuple[str, bytes]]=None) -> Tuple[str, int, List[str]]:
754 762 """Used by dict_key_matches, matching the prefix to a list of keys
755 763
756 764 Parameters
757 765 ----------
758 766 keys:
759 767 list of keys in dictionary currently being completed.
760 768 prefix:
761 769 Part of the text already typed by the user. E.g. `mydict[b'fo`
762 770 delims:
763 771 String of delimiters to consider when finding the current key.
764 772 extra_prefix: optional
765 773 Part of the text already typed in multi-key index cases. E.g. for
766 774 `mydict['foo', "bar", 'b`, this would be `('foo', 'bar')`.
767 775
768 776 Returns
769 777 -------
770 778 A tuple of three elements: ``quote``, ``token_start``, ``matched``, with
771 779 ``quote`` being the quote that need to be used to close current string.
772 780 ``token_start`` the position where the replacement should start occurring,
773 781 ``matches`` a list of replacement/completion
774 782
775 783 """
776 784 prefix_tuple = extra_prefix if extra_prefix else ()
777 785 Nprefix = len(prefix_tuple)
778 786 def filter_prefix_tuple(key):
779 787 # Reject too short keys
780 788 if len(key) <= Nprefix:
781 789 return False
782 790 # Reject keys with non str/bytes in it
783 791 for k in key:
784 792 if not isinstance(k, (str, bytes)):
785 793 return False
786 794 # Reject keys that do not match the prefix
787 795 for k, pt in zip(key, prefix_tuple):
788 796 if k != pt:
789 797 return False
790 798 # All checks passed!
791 799 return True
792 800
793 801 filtered_keys:List[Union[str,bytes]] = []
794 802 def _add_to_filtered_keys(key):
795 803 if isinstance(key, (str, bytes)):
796 804 filtered_keys.append(key)
797 805
798 806 for k in keys:
799 807 if isinstance(k, tuple):
800 808 if filter_prefix_tuple(k):
801 809 _add_to_filtered_keys(k[Nprefix])
802 810 else:
803 811 _add_to_filtered_keys(k)
804 812
805 813 if not prefix:
806 814 return '', 0, [repr(k) for k in filtered_keys]
807 815 quote_match = re.search('["\']', prefix)
808 816 assert quote_match is not None # silence mypy
809 817 quote = quote_match.group()
810 818 try:
811 819 prefix_str = eval(prefix + quote, {})
812 820 except Exception:
813 821 return '', 0, []
814 822
815 823 pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$'
816 824 token_match = re.search(pattern, prefix, re.UNICODE)
817 825 assert token_match is not None # silence mypy
818 826 token_start = token_match.start()
819 827 token_prefix = token_match.group()
820 828
821 829 matched:List[str] = []
822 830 for key in filtered_keys:
823 831 try:
824 832 if not key.startswith(prefix_str):
825 833 continue
826 834 except (AttributeError, TypeError, UnicodeError):
827 835 # Python 3+ TypeError on b'a'.startswith('a') or vice-versa
828 836 continue
829 837
830 838 # reformat remainder of key to begin with prefix
831 839 rem = key[len(prefix_str):]
832 840 # force repr wrapped in '
833 841 rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"')
834 842 rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
835 843 if quote == '"':
836 844 # The entered prefix is quoted with ",
837 845 # but the match is quoted with '.
838 846 # A contained " hence needs escaping for comparison:
839 847 rem_repr = rem_repr.replace('"', '\\"')
840 848
841 849 # then reinsert prefix from start of token
842 850 matched.append('%s%s' % (token_prefix, rem_repr))
843 851 return quote, token_start, matched
844 852
845 853
846 854 def cursor_to_position(text:str, line:int, column:int)->int:
847 855 """
848 856 Convert the (line,column) position of the cursor in text to an offset in a
849 857 string.
850 858
851 859 Parameters
852 860 ----------
853 861 text : str
854 862 The text in which to calculate the cursor offset
855 863 line : int
856 864 Line of the cursor; 0-indexed
857 865 column : int
858 866 Column of the cursor 0-indexed
859 867
860 868 Returns
861 869 -------
862 870 Position of the cursor in ``text``, 0-indexed.
863 871
864 872 See Also
865 873 --------
866 874 position_to_cursor : reciprocal of this function
867 875
868 876 """
869 877 lines = text.split('\n')
870 878 assert line <= len(lines), '{} <= {}'.format(str(line), str(len(lines)))
871 879
872 880 return sum(len(l) + 1 for l in lines[:line]) + column
873 881
874 882 def position_to_cursor(text:str, offset:int)->Tuple[int, int]:
875 883 """
876 884 Convert the position of the cursor in text (0 indexed) to a line
877 885 number(0-indexed) and a column number (0-indexed) pair
878 886
879 887 Position should be a valid position in ``text``.
880 888
881 889 Parameters
882 890 ----------
883 891 text : str
884 892 The text in which to calculate the cursor offset
885 893 offset : int
886 894 Position of the cursor in ``text``, 0-indexed.
887 895
888 896 Returns
889 897 -------
890 898 (line, column) : (int, int)
891 899 Line of the cursor; 0-indexed, column of the cursor 0-indexed
892 900
893 901 See Also
894 902 --------
895 903 cursor_to_position : reciprocal of this function
896 904
897 905 """
898 906
899 907 assert 0 <= offset <= len(text) , "0 <= %s <= %s" % (offset , len(text))
900 908
901 909 before = text[:offset]
902 910 blines = before.split('\n') # ! splitnes trim trailing \n
903 911 line = before.count('\n')
904 912 col = len(blines[-1])
905 913 return line, col
906 914
907 915
908 916 def _safe_isinstance(obj, module, class_name):
909 917 """Checks if obj is an instance of module.class_name if loaded
910 918 """
911 919 return (module in sys.modules and
912 920 isinstance(obj, getattr(import_module(module), class_name)))
913 921
914 922 def back_unicode_name_matches(text:str) -> Tuple[str, Sequence[str]]:
915 923 """Match Unicode characters back to Unicode name
916 924
917 925 This does ``☃`` -> ``\\snowman``
918 926
919 927 Note that snowman is not a valid python3 combining character but will be expanded.
920 928 Though it will not recombine back to the snowman character by the completion machinery.
921 929
922 930 This will not either back-complete standard sequences like \\n, \\b ...
923 931
924 932 Returns
925 933 =======
926 934
927 935 Return a tuple with two elements:
928 936
929 937 - The Unicode character that was matched (preceded with a backslash), or
930 938 empty string,
931 939 - a sequence (of 1), name for the match Unicode character, preceded by
932 940 backslash, or empty if no match.
933 941
934 942 """
935 943 if len(text)<2:
936 944 return '', ()
937 945 maybe_slash = text[-2]
938 946 if maybe_slash != '\\':
939 947 return '', ()
940 948
941 949 char = text[-1]
942 950 # no expand on quote for completion in strings.
943 951 # nor backcomplete standard ascii keys
944 952 if char in string.ascii_letters or char in ('"',"'"):
945 953 return '', ()
946 954 try :
947 955 unic = unicodedata.name(char)
948 956 return '\\'+char,('\\'+unic,)
949 957 except KeyError:
950 958 pass
951 959 return '', ()
952 960
953 961 def back_latex_name_matches(text:str) -> Tuple[str, Sequence[str]] :
954 962 """Match latex characters back to unicode name
955 963
956 964 This does ``\\ℵ`` -> ``\\aleph``
957 965
958 966 """
959 967 if len(text)<2:
960 968 return '', ()
961 969 maybe_slash = text[-2]
962 970 if maybe_slash != '\\':
963 971 return '', ()
964 972
965 973
966 974 char = text[-1]
967 975 # no expand on quote for completion in strings.
968 976 # nor backcomplete standard ascii keys
969 977 if char in string.ascii_letters or char in ('"',"'"):
970 978 return '', ()
971 979 try :
972 980 latex = reverse_latex_symbol[char]
973 981 # '\\' replace the \ as well
974 982 return '\\'+char,[latex]
975 983 except KeyError:
976 984 pass
977 985 return '', ()
978 986
979 987
980 988 def _formatparamchildren(parameter) -> str:
981 989 """
982 990 Get parameter name and value from Jedi Private API
983 991
984 992 Jedi does not expose a simple way to get `param=value` from its API.
985 993
986 994 Parameters
987 995 ----------
988 996 parameter:
989 997 Jedi's function `Param`
990 998
991 999 Returns
992 1000 -------
993 1001 A string like 'a', 'b=1', '*args', '**kwargs'
994 1002
995 1003 """
996 1004 description = parameter.description
997 1005 if not description.startswith('param '):
998 1006 raise ValueError('Jedi function parameter description have change format.'
999 1007 'Expected "param ...", found %r".' % description)
1000 1008 return description[6:]
1001 1009
1002 1010 def _make_signature(completion)-> str:
1003 1011 """
1004 1012 Make the signature from a jedi completion
1005 1013
1006 1014 Parameters
1007 1015 ----------
1008 1016 completion: jedi.Completion
1009 1017 object does not complete a function type
1010 1018
1011 1019 Returns
1012 1020 -------
1013 1021 a string consisting of the function signature, with the parenthesis but
1014 1022 without the function name. example:
1015 1023 `(a, *args, b=1, **kwargs)`
1016 1024
1017 1025 """
1018 1026
1019 1027 # it looks like this might work on jedi 0.17
1020 1028 if hasattr(completion, 'get_signatures'):
1021 1029 signatures = completion.get_signatures()
1022 1030 if not signatures:
1023 1031 return '(?)'
1024 1032
1025 1033 c0 = completion.get_signatures()[0]
1026 1034 return '('+c0.to_string().split('(', maxsplit=1)[1]
1027 1035
1028 1036 return '(%s)'% ', '.join([f for f in (_formatparamchildren(p) for signature in completion.get_signatures()
1029 1037 for p in signature.defined_names()) if f])
1030 1038
1031 1039
1032 1040 class _CompleteResult(NamedTuple):
1033 1041 matched_text : str
1034 1042 matches: Sequence[str]
1035 1043 matches_origin: Sequence[str]
1036 1044 jedi_matches: Any
1037 1045
1038 1046
1039 1047 class IPCompleter(Completer):
1040 1048 """Extension of the completer class with IPython-specific features"""
1041 1049
1042 1050 __dict_key_regexps: Optional[Dict[bool,Pattern]] = None
1043 1051
1044 1052 @observe('greedy')
1045 1053 def _greedy_changed(self, change):
1046 1054 """update the splitter and readline delims when greedy is changed"""
1047 1055 if change['new']:
1048 1056 self.splitter.delims = GREEDY_DELIMS
1049 1057 else:
1050 1058 self.splitter.delims = DELIMS
1051 1059
1052 1060 dict_keys_only = Bool(False,
1053 1061 help="""Whether to show dict key matches only""")
1054 1062
1055 1063 merge_completions = Bool(True,
1056 1064 help="""Whether to merge completion results into a single list
1057 1065
1058 1066 If False, only the completion results from the first non-empty
1059 1067 completer will be returned.
1060 1068 """
1061 1069 ).tag(config=True)
1062 1070 omit__names = Enum((0,1,2), default_value=2,
1063 1071 help="""Instruct the completer to omit private method names
1064 1072
1065 1073 Specifically, when completing on ``object.<tab>``.
1066 1074
1067 1075 When 2 [default]: all names that start with '_' will be excluded.
1068 1076
1069 1077 When 1: all 'magic' names (``__foo__``) will be excluded.
1070 1078
1071 1079 When 0: nothing will be excluded.
1072 1080 """
1073 1081 ).tag(config=True)
1074 1082 limit_to__all__ = Bool(False,
1075 1083 help="""
1076 1084 DEPRECATED as of version 5.0.
1077 1085
1078 1086 Instruct the completer to use __all__ for the completion
1079 1087
1080 1088 Specifically, when completing on ``object.<tab>``.
1081 1089
1082 1090 When True: only those names in obj.__all__ will be included.
1083 1091
1084 1092 When False [default]: the __all__ attribute is ignored
1085 1093 """,
1086 1094 ).tag(config=True)
1087 1095
1088 1096 profile_completions = Bool(
1089 1097 default_value=False,
1090 1098 help="If True, emit profiling data for completion subsystem using cProfile."
1091 1099 ).tag(config=True)
1092 1100
1093 1101 profiler_output_dir = Unicode(
1094 1102 default_value=".completion_profiles",
1095 1103 help="Template for path at which to output profile data for completions."
1096 1104 ).tag(config=True)
1097 1105
1098 1106 @observe('limit_to__all__')
1099 1107 def _limit_to_all_changed(self, change):
1100 1108 warnings.warn('`IPython.core.IPCompleter.limit_to__all__` configuration '
1101 1109 'value has been deprecated since IPython 5.0, will be made to have '
1102 1110 'no effects and then removed in future version of IPython.',
1103 1111 UserWarning)
1104 1112
1105 1113 def __init__(self, shell=None, namespace=None, global_namespace=None,
1106 1114 use_readline=_deprecation_readline_sentinel, config=None, **kwargs):
1107 1115 """IPCompleter() -> completer
1108 1116
1109 1117 Return a completer object.
1110 1118
1111 1119 Parameters
1112 1120 ----------
1113 1121 shell
1114 1122 a pointer to the ipython shell itself. This is needed
1115 1123 because this completer knows about magic functions, and those can
1116 1124 only be accessed via the ipython instance.
1117 1125 namespace : dict, optional
1118 1126 an optional dict where completions are performed.
1119 1127 global_namespace : dict, optional
1120 1128 secondary optional dict for completions, to
1121 1129 handle cases (such as IPython embedded inside functions) where
1122 1130 both Python scopes are visible.
1123 1131 use_readline : bool, optional
1124 1132 DEPRECATED, ignored since IPython 6.0, will have no effects
1125 1133 """
1126 1134
1127 1135 self.magic_escape = ESC_MAGIC
1128 1136 self.splitter = CompletionSplitter()
1129 1137
1130 1138 if use_readline is not _deprecation_readline_sentinel:
1131 1139 warnings.warn('The `use_readline` parameter is deprecated and ignored since IPython 6.0.',
1132 1140 DeprecationWarning, stacklevel=2)
1133 1141
1134 1142 # _greedy_changed() depends on splitter and readline being defined:
1135 1143 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
1136 1144 config=config, **kwargs)
1137 1145
1138 1146 # List where completion matches will be stored
1139 1147 self.matches = []
1140 1148 self.shell = shell
1141 1149 # Regexp to split filenames with spaces in them
1142 1150 self.space_name_re = re.compile(r'([^\\] )')
1143 1151 # Hold a local ref. to glob.glob for speed
1144 1152 self.glob = glob.glob
1145 1153
1146 1154 # Determine if we are running on 'dumb' terminals, like (X)Emacs
1147 1155 # buffers, to avoid completion problems.
1148 1156 term = os.environ.get('TERM','xterm')
1149 1157 self.dumb_terminal = term in ['dumb','emacs']
1150 1158
1151 1159 # Special handling of backslashes needed in win32 platforms
1152 1160 if sys.platform == "win32":
1153 1161 self.clean_glob = self._clean_glob_win32
1154 1162 else:
1155 1163 self.clean_glob = self._clean_glob
1156 1164
1157 1165 #regexp to parse docstring for function signature
1158 1166 self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1159 1167 self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1160 1168 #use this if positional argument name is also needed
1161 1169 #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)')
1162 1170
1163 1171 self.magic_arg_matchers = [
1164 1172 self.magic_config_matches,
1165 1173 self.magic_color_matches,
1166 1174 ]
1167 1175
1168 1176 # This is set externally by InteractiveShell
1169 1177 self.custom_completers = None
1170 1178
1171 1179 # This is a list of names of unicode characters that can be completed
1172 1180 # into their corresponding unicode value. The list is large, so we
1173 1181 # laziliy initialize it on first use. Consuming code should access this
1174 1182 # attribute through the `@unicode_names` property.
1175 1183 self._unicode_names = None
1176 1184
1177 1185 @property
1178 1186 def matchers(self) -> List[Any]:
1179 1187 """All active matcher routines for completion"""
1180 1188 if self.dict_keys_only:
1181 1189 return [self.dict_key_matches]
1182 1190
1183 1191 if self.use_jedi:
1184 1192 return [
1185 1193 *self.custom_matchers,
1186 1194 self.file_matches,
1187 1195 self.magic_matches,
1188 1196 self.dict_key_matches,
1189 1197 ]
1190 1198 else:
1191 1199 return [
1192 1200 *self.custom_matchers,
1193 1201 self.python_matches,
1194 1202 self.file_matches,
1195 1203 self.magic_matches,
1196 1204 self.python_func_kw_matches,
1197 1205 self.dict_key_matches,
1198 1206 ]
1199 1207
1200 1208 def all_completions(self, text:str) -> List[str]:
1201 1209 """
1202 1210 Wrapper around the completion methods for the benefit of emacs.
1203 1211 """
1204 1212 prefix = text.rpartition('.')[0]
1205 1213 with provisionalcompleter():
1206 1214 return ['.'.join([prefix, c.text]) if prefix and self.use_jedi else c.text
1207 1215 for c in self.completions(text, len(text))]
1208 1216
1209 1217 return self.complete(text)[1]
1210 1218
1211 1219 def _clean_glob(self, text:str):
1212 1220 return self.glob("%s*" % text)
1213 1221
1214 1222 def _clean_glob_win32(self, text:str):
1215 1223 return [f.replace("\\","/")
1216 1224 for f in self.glob("%s*" % text)]
1217 1225
1218 1226 def file_matches(self, text:str)->List[str]:
1219 1227 """Match filenames, expanding ~USER type strings.
1220 1228
1221 1229 Most of the seemingly convoluted logic in this completer is an
1222 1230 attempt to handle filenames with spaces in them. And yet it's not
1223 1231 quite perfect, because Python's readline doesn't expose all of the
1224 1232 GNU readline details needed for this to be done correctly.
1225 1233
1226 1234 For a filename with a space in it, the printed completions will be
1227 1235 only the parts after what's already been typed (instead of the
1228 1236 full completions, as is normally done). I don't think with the
1229 1237 current (as of Python 2.3) Python readline it's possible to do
1230 1238 better."""
1231 1239
1232 1240 # chars that require escaping with backslash - i.e. chars
1233 1241 # that readline treats incorrectly as delimiters, but we
1234 1242 # don't want to treat as delimiters in filename matching
1235 1243 # when escaped with backslash
1236 1244 if text.startswith('!'):
1237 1245 text = text[1:]
1238 1246 text_prefix = u'!'
1239 1247 else:
1240 1248 text_prefix = u''
1241 1249
1242 1250 text_until_cursor = self.text_until_cursor
1243 1251 # track strings with open quotes
1244 1252 open_quotes = has_open_quotes(text_until_cursor)
1245 1253
1246 1254 if '(' in text_until_cursor or '[' in text_until_cursor:
1247 1255 lsplit = text
1248 1256 else:
1249 1257 try:
1250 1258 # arg_split ~ shlex.split, but with unicode bugs fixed by us
1251 1259 lsplit = arg_split(text_until_cursor)[-1]
1252 1260 except ValueError:
1253 1261 # typically an unmatched ", or backslash without escaped char.
1254 1262 if open_quotes:
1255 1263 lsplit = text_until_cursor.split(open_quotes)[-1]
1256 1264 else:
1257 1265 return []
1258 1266 except IndexError:
1259 1267 # tab pressed on empty line
1260 1268 lsplit = ""
1261 1269
1262 1270 if not open_quotes and lsplit != protect_filename(lsplit):
1263 1271 # if protectables are found, do matching on the whole escaped name
1264 1272 has_protectables = True
1265 1273 text0,text = text,lsplit
1266 1274 else:
1267 1275 has_protectables = False
1268 1276 text = os.path.expanduser(text)
1269 1277
1270 1278 if text == "":
1271 1279 return [text_prefix + protect_filename(f) for f in self.glob("*")]
1272 1280
1273 1281 # Compute the matches from the filesystem
1274 1282 if sys.platform == 'win32':
1275 1283 m0 = self.clean_glob(text)
1276 1284 else:
1277 1285 m0 = self.clean_glob(text.replace('\\', ''))
1278 1286
1279 1287 if has_protectables:
1280 1288 # If we had protectables, we need to revert our changes to the
1281 1289 # beginning of filename so that we don't double-write the part
1282 1290 # of the filename we have so far
1283 1291 len_lsplit = len(lsplit)
1284 1292 matches = [text_prefix + text0 +
1285 1293 protect_filename(f[len_lsplit:]) for f in m0]
1286 1294 else:
1287 1295 if open_quotes:
1288 1296 # if we have a string with an open quote, we don't need to
1289 1297 # protect the names beyond the quote (and we _shouldn't_, as
1290 1298 # it would cause bugs when the filesystem call is made).
1291 1299 matches = m0 if sys.platform == "win32" else\
1292 1300 [protect_filename(f, open_quotes) for f in m0]
1293 1301 else:
1294 1302 matches = [text_prefix +
1295 1303 protect_filename(f) for f in m0]
1296 1304
1297 1305 # Mark directories in input list by appending '/' to their names.
1298 1306 return [x+'/' if os.path.isdir(x) else x for x in matches]
1299 1307
1300 1308 def magic_matches(self, text:str):
1301 1309 """Match magics"""
1302 1310 # Get all shell magics now rather than statically, so magics loaded at
1303 1311 # runtime show up too.
1304 1312 lsm = self.shell.magics_manager.lsmagic()
1305 1313 line_magics = lsm['line']
1306 1314 cell_magics = lsm['cell']
1307 1315 pre = self.magic_escape
1308 1316 pre2 = pre+pre
1309 1317
1310 1318 explicit_magic = text.startswith(pre)
1311 1319
1312 1320 # Completion logic:
1313 1321 # - user gives %%: only do cell magics
1314 1322 # - user gives %: do both line and cell magics
1315 1323 # - no prefix: do both
1316 1324 # In other words, line magics are skipped if the user gives %% explicitly
1317 1325 #
1318 1326 # We also exclude magics that match any currently visible names:
1319 1327 # https://github.com/ipython/ipython/issues/4877, unless the user has
1320 1328 # typed a %:
1321 1329 # https://github.com/ipython/ipython/issues/10754
1322 1330 bare_text = text.lstrip(pre)
1323 1331 global_matches = self.global_matches(bare_text)
1324 1332 if not explicit_magic:
1325 1333 def matches(magic):
1326 1334 """
1327 1335 Filter magics, in particular remove magics that match
1328 1336 a name present in global namespace.
1329 1337 """
1330 1338 return ( magic.startswith(bare_text) and
1331 1339 magic not in global_matches )
1332 1340 else:
1333 1341 def matches(magic):
1334 1342 return magic.startswith(bare_text)
1335 1343
1336 1344 comp = [ pre2+m for m in cell_magics if matches(m)]
1337 1345 if not text.startswith(pre2):
1338 1346 comp += [ pre+m for m in line_magics if matches(m)]
1339 1347
1340 1348 return comp
1341 1349
1342 1350 def magic_config_matches(self, text:str) -> List[str]:
1343 1351 """ Match class names and attributes for %config magic """
1344 1352 texts = text.strip().split()
1345 1353
1346 1354 if len(texts) > 0 and (texts[0] == 'config' or texts[0] == '%config'):
1347 1355 # get all configuration classes
1348 1356 classes = sorted(set([ c for c in self.shell.configurables
1349 1357 if c.__class__.class_traits(config=True)
1350 1358 ]), key=lambda x: x.__class__.__name__)
1351 1359 classnames = [ c.__class__.__name__ for c in classes ]
1352 1360
1353 1361 # return all classnames if config or %config is given
1354 1362 if len(texts) == 1:
1355 1363 return classnames
1356 1364
1357 1365 # match classname
1358 1366 classname_texts = texts[1].split('.')
1359 1367 classname = classname_texts[0]
1360 1368 classname_matches = [ c for c in classnames
1361 1369 if c.startswith(classname) ]
1362 1370
1363 1371 # return matched classes or the matched class with attributes
1364 1372 if texts[1].find('.') < 0:
1365 1373 return classname_matches
1366 1374 elif len(classname_matches) == 1 and \
1367 1375 classname_matches[0] == classname:
1368 1376 cls = classes[classnames.index(classname)].__class__
1369 1377 help = cls.class_get_help()
1370 1378 # strip leading '--' from cl-args:
1371 1379 help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
1372 1380 return [ attr.split('=')[0]
1373 1381 for attr in help.strip().splitlines()
1374 1382 if attr.startswith(texts[1]) ]
1375 1383 return []
1376 1384
1377 1385 def magic_color_matches(self, text:str) -> List[str] :
1378 1386 """ Match color schemes for %colors magic"""
1379 1387 texts = text.split()
1380 1388 if text.endswith(' '):
1381 1389 # .split() strips off the trailing whitespace. Add '' back
1382 1390 # so that: '%colors ' -> ['%colors', '']
1383 1391 texts.append('')
1384 1392
1385 1393 if len(texts) == 2 and (texts[0] == 'colors' or texts[0] == '%colors'):
1386 1394 prefix = texts[1]
1387 1395 return [ color for color in InspectColors.keys()
1388 1396 if color.startswith(prefix) ]
1389 1397 return []
1390 1398
1391 1399 def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str) -> Iterable[Any]:
1392 1400 """
1393 1401 Return a list of :any:`jedi.api.Completions` object from a ``text`` and
1394 1402 cursor position.
1395 1403
1396 1404 Parameters
1397 1405 ----------
1398 1406 cursor_column : int
1399 1407 column position of the cursor in ``text``, 0-indexed.
1400 1408 cursor_line : int
1401 1409 line position of the cursor in ``text``, 0-indexed
1402 1410 text : str
1403 1411 text to complete
1404 1412
1405 1413 Notes
1406 1414 -----
1407 1415 If ``IPCompleter.debug`` is ``True`` may return a :any:`_FakeJediCompletion`
1408 1416 object containing a string with the Jedi debug information attached.
1409 1417 """
1410 1418 namespaces = [self.namespace]
1411 1419 if self.global_namespace is not None:
1412 1420 namespaces.append(self.global_namespace)
1413 1421
1414 1422 completion_filter = lambda x:x
1415 1423 offset = cursor_to_position(text, cursor_line, cursor_column)
1416 1424 # filter output if we are completing for object members
1417 1425 if offset:
1418 1426 pre = text[offset-1]
1419 1427 if pre == '.':
1420 1428 if self.omit__names == 2:
1421 1429 completion_filter = lambda c:not c.name.startswith('_')
1422 1430 elif self.omit__names == 1:
1423 1431 completion_filter = lambda c:not (c.name.startswith('__') and c.name.endswith('__'))
1424 1432 elif self.omit__names == 0:
1425 1433 completion_filter = lambda x:x
1426 1434 else:
1427 1435 raise ValueError("Don't understand self.omit__names == {}".format(self.omit__names))
1428 1436
1429 1437 interpreter = jedi.Interpreter(text[:offset], namespaces)
1430 1438 try_jedi = True
1431 1439
1432 1440 try:
1433 1441 # find the first token in the current tree -- if it is a ' or " then we are in a string
1434 1442 completing_string = False
1435 1443 try:
1436 1444 first_child = next(c for c in interpreter._get_module().tree_node.children if hasattr(c, 'value'))
1437 1445 except StopIteration:
1438 1446 pass
1439 1447 else:
1440 1448 # note the value may be ', ", or it may also be ''' or """, or
1441 1449 # in some cases, """what/you/typed..., but all of these are
1442 1450 # strings.
1443 1451 completing_string = len(first_child.value) > 0 and first_child.value[0] in {"'", '"'}
1444 1452
1445 1453 # if we are in a string jedi is likely not the right candidate for
1446 1454 # now. Skip it.
1447 1455 try_jedi = not completing_string
1448 1456 except Exception as e:
1449 1457 # many of things can go wrong, we are using private API just don't crash.
1450 1458 if self.debug:
1451 1459 print("Error detecting if completing a non-finished string :", e, '|')
1452 1460
1453 1461 if not try_jedi:
1454 1462 return []
1455 1463 try:
1456 1464 return filter(completion_filter, interpreter.complete(column=cursor_column, line=cursor_line + 1))
1457 1465 except Exception as e:
1458 1466 if self.debug:
1459 1467 return [_FakeJediCompletion('Oops Jedi has crashed, please report a bug with the following:\n"""\n%s\ns"""' % (e))]
1460 1468 else:
1461 1469 return []
1462 1470
1463 1471 def python_matches(self, text:str)->List[str]:
1464 1472 """Match attributes or global python names"""
1465 1473 if "." in text:
1466 1474 try:
1467 1475 matches = self.attr_matches(text)
1468 1476 if text.endswith('.') and self.omit__names:
1469 1477 if self.omit__names == 1:
1470 1478 # true if txt is _not_ a __ name, false otherwise:
1471 1479 no__name = (lambda txt:
1472 1480 re.match(r'.*\.__.*?__',txt) is None)
1473 1481 else:
1474 1482 # true if txt is _not_ a _ name, false otherwise:
1475 1483 no__name = (lambda txt:
1476 1484 re.match(r'\._.*?',txt[txt.rindex('.'):]) is None)
1477 1485 matches = filter(no__name, matches)
1478 1486 except NameError:
1479 1487 # catches <undefined attributes>.<tab>
1480 1488 matches = []
1481 1489 else:
1482 1490 matches = self.global_matches(text)
1483 1491 return matches
1484 1492
1485 1493 def _default_arguments_from_docstring(self, doc):
1486 1494 """Parse the first line of docstring for call signature.
1487 1495
1488 1496 Docstring should be of the form 'min(iterable[, key=func])\n'.
1489 1497 It can also parse cython docstring of the form
1490 1498 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'.
1491 1499 """
1492 1500 if doc is None:
1493 1501 return []
1494 1502
1495 1503 #care only the firstline
1496 1504 line = doc.lstrip().splitlines()[0]
1497 1505
1498 1506 #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1499 1507 #'min(iterable[, key=func])\n' -> 'iterable[, key=func]'
1500 1508 sig = self.docstring_sig_re.search(line)
1501 1509 if sig is None:
1502 1510 return []
1503 1511 # iterable[, key=func]' -> ['iterable[' ,' key=func]']
1504 1512 sig = sig.groups()[0].split(',')
1505 1513 ret = []
1506 1514 for s in sig:
1507 1515 #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1508 1516 ret += self.docstring_kwd_re.findall(s)
1509 1517 return ret
1510 1518
1511 1519 def _default_arguments(self, obj):
1512 1520 """Return the list of default arguments of obj if it is callable,
1513 1521 or empty list otherwise."""
1514 1522 call_obj = obj
1515 1523 ret = []
1516 1524 if inspect.isbuiltin(obj):
1517 1525 pass
1518 1526 elif not (inspect.isfunction(obj) or inspect.ismethod(obj)):
1519 1527 if inspect.isclass(obj):
1520 1528 #for cython embedsignature=True the constructor docstring
1521 1529 #belongs to the object itself not __init__
1522 1530 ret += self._default_arguments_from_docstring(
1523 1531 getattr(obj, '__doc__', ''))
1524 1532 # for classes, check for __init__,__new__
1525 1533 call_obj = (getattr(obj, '__init__', None) or
1526 1534 getattr(obj, '__new__', None))
1527 1535 # for all others, check if they are __call__able
1528 1536 elif hasattr(obj, '__call__'):
1529 1537 call_obj = obj.__call__
1530 1538 ret += self._default_arguments_from_docstring(
1531 1539 getattr(call_obj, '__doc__', ''))
1532 1540
1533 1541 _keeps = (inspect.Parameter.KEYWORD_ONLY,
1534 1542 inspect.Parameter.POSITIONAL_OR_KEYWORD)
1535 1543
1536 1544 try:
1537 1545 sig = inspect.signature(call_obj)
1538 1546 ret.extend(k for k, v in sig.parameters.items() if
1539 1547 v.kind in _keeps)
1540 1548 except ValueError:
1541 1549 pass
1542 1550
1543 1551 return list(set(ret))
1544 1552
1545 1553 def python_func_kw_matches(self, text):
1546 1554 """Match named parameters (kwargs) of the last open function"""
1547 1555
1548 1556 if "." in text: # a parameter cannot be dotted
1549 1557 return []
1550 1558 try: regexp = self.__funcParamsRegex
1551 1559 except AttributeError:
1552 1560 regexp = self.__funcParamsRegex = re.compile(r'''
1553 1561 '.*?(?<!\\)' | # single quoted strings or
1554 1562 ".*?(?<!\\)" | # double quoted strings or
1555 1563 \w+ | # identifier
1556 1564 \S # other characters
1557 1565 ''', re.VERBOSE | re.DOTALL)
1558 1566 # 1. find the nearest identifier that comes before an unclosed
1559 1567 # parenthesis before the cursor
1560 1568 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
1561 1569 tokens = regexp.findall(self.text_until_cursor)
1562 1570 iterTokens = reversed(tokens); openPar = 0
1563 1571
1564 1572 for token in iterTokens:
1565 1573 if token == ')':
1566 1574 openPar -= 1
1567 1575 elif token == '(':
1568 1576 openPar += 1
1569 1577 if openPar > 0:
1570 1578 # found the last unclosed parenthesis
1571 1579 break
1572 1580 else:
1573 1581 return []
1574 1582 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
1575 1583 ids = []
1576 1584 isId = re.compile(r'\w+$').match
1577 1585
1578 1586 while True:
1579 1587 try:
1580 1588 ids.append(next(iterTokens))
1581 1589 if not isId(ids[-1]):
1582 1590 ids.pop(); break
1583 1591 if not next(iterTokens) == '.':
1584 1592 break
1585 1593 except StopIteration:
1586 1594 break
1587 1595
1588 1596 # Find all named arguments already assigned to, as to avoid suggesting
1589 1597 # them again
1590 1598 usedNamedArgs = set()
1591 1599 par_level = -1
1592 1600 for token, next_token in zip(tokens, tokens[1:]):
1593 1601 if token == '(':
1594 1602 par_level += 1
1595 1603 elif token == ')':
1596 1604 par_level -= 1
1597 1605
1598 1606 if par_level != 0:
1599 1607 continue
1600 1608
1601 1609 if next_token != '=':
1602 1610 continue
1603 1611
1604 1612 usedNamedArgs.add(token)
1605 1613
1606 1614 argMatches = []
1607 1615 try:
1608 1616 callableObj = '.'.join(ids[::-1])
1609 1617 namedArgs = self._default_arguments(eval(callableObj,
1610 1618 self.namespace))
1611 1619
1612 1620 # Remove used named arguments from the list, no need to show twice
1613 1621 for namedArg in set(namedArgs) - usedNamedArgs:
1614 1622 if namedArg.startswith(text):
1615 1623 argMatches.append("%s=" %namedArg)
1616 1624 except:
1617 1625 pass
1618 1626
1619 1627 return argMatches
1620 1628
1621 1629 @staticmethod
1622 1630 def _get_keys(obj: Any) -> List[Any]:
1623 1631 # Objects can define their own completions by defining an
1624 1632 # _ipy_key_completions_() method.
1625 1633 method = get_real_method(obj, '_ipython_key_completions_')
1626 1634 if method is not None:
1627 1635 return method()
1628 1636
1629 1637 # Special case some common in-memory dict-like types
1630 1638 if isinstance(obj, dict) or\
1631 1639 _safe_isinstance(obj, 'pandas', 'DataFrame'):
1632 1640 try:
1633 1641 return list(obj.keys())
1634 1642 except Exception:
1635 1643 return []
1636 1644 elif _safe_isinstance(obj, 'numpy', 'ndarray') or\
1637 1645 _safe_isinstance(obj, 'numpy', 'void'):
1638 1646 return obj.dtype.names or []
1639 1647 return []
1640 1648
1641 1649 def dict_key_matches(self, text:str) -> List[str]:
1642 1650 "Match string keys in a dictionary, after e.g. 'foo[' "
1643 1651
1644 1652
1645 1653 if self.__dict_key_regexps is not None:
1646 1654 regexps = self.__dict_key_regexps
1647 1655 else:
1648 1656 dict_key_re_fmt = r'''(?x)
1649 1657 ( # match dict-referring expression wrt greedy setting
1650 1658 %s
1651 1659 )
1652 1660 \[ # open bracket
1653 1661 \s* # and optional whitespace
1654 1662 # Capture any number of str-like objects (e.g. "a", "b", 'c')
1655 1663 ((?:[uUbB]? # string prefix (r not handled)
1656 1664 (?:
1657 1665 '(?:[^']|(?<!\\)\\')*'
1658 1666 |
1659 1667 "(?:[^"]|(?<!\\)\\")*"
1660 1668 )
1661 1669 \s*,\s*
1662 1670 )*)
1663 1671 ([uUbB]? # string prefix (r not handled)
1664 1672 (?: # unclosed string
1665 1673 '(?:[^']|(?<!\\)\\')*
1666 1674 |
1667 1675 "(?:[^"]|(?<!\\)\\")*
1668 1676 )
1669 1677 )?
1670 1678 $
1671 1679 '''
1672 1680 regexps = self.__dict_key_regexps = {
1673 1681 False: re.compile(dict_key_re_fmt % r'''
1674 1682 # identifiers separated by .
1675 1683 (?!\d)\w+
1676 1684 (?:\.(?!\d)\w+)*
1677 1685 '''),
1678 1686 True: re.compile(dict_key_re_fmt % '''
1679 1687 .+
1680 1688 ''')
1681 1689 }
1682 1690
1683 1691 match = regexps[self.greedy].search(self.text_until_cursor)
1684 1692
1685 1693 if match is None:
1686 1694 return []
1687 1695
1688 1696 expr, prefix0, prefix = match.groups()
1689 1697 try:
1690 1698 obj = eval(expr, self.namespace)
1691 1699 except Exception:
1692 1700 try:
1693 1701 obj = eval(expr, self.global_namespace)
1694 1702 except Exception:
1695 1703 return []
1696 1704
1697 1705 keys = self._get_keys(obj)
1698 1706 if not keys:
1699 1707 return keys
1700 1708
1701 1709 extra_prefix = eval(prefix0) if prefix0 != '' else None
1702 1710
1703 1711 closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims, extra_prefix=extra_prefix)
1704 1712 if not matches:
1705 1713 return matches
1706 1714
1707 1715 # get the cursor position of
1708 1716 # - the text being completed
1709 1717 # - the start of the key text
1710 1718 # - the start of the completion
1711 1719 text_start = len(self.text_until_cursor) - len(text)
1712 1720 if prefix:
1713 1721 key_start = match.start(3)
1714 1722 completion_start = key_start + token_offset
1715 1723 else:
1716 1724 key_start = completion_start = match.end()
1717 1725
1718 1726 # grab the leading prefix, to make sure all completions start with `text`
1719 1727 if text_start > key_start:
1720 1728 leading = ''
1721 1729 else:
1722 1730 leading = text[text_start:completion_start]
1723 1731
1724 1732 # the index of the `[` character
1725 1733 bracket_idx = match.end(1)
1726 1734
1727 1735 # append closing quote and bracket as appropriate
1728 1736 # this is *not* appropriate if the opening quote or bracket is outside
1729 1737 # the text given to this method
1730 1738 suf = ''
1731 1739 continuation = self.line_buffer[len(self.text_until_cursor):]
1732 1740 if key_start > text_start and closing_quote:
1733 1741 # quotes were opened inside text, maybe close them
1734 1742 if continuation.startswith(closing_quote):
1735 1743 continuation = continuation[len(closing_quote):]
1736 1744 else:
1737 1745 suf += closing_quote
1738 1746 if bracket_idx > text_start:
1739 1747 # brackets were opened inside text, maybe close them
1740 1748 if not continuation.startswith(']'):
1741 1749 suf += ']'
1742 1750
1743 1751 return [leading + k + suf for k in matches]
1744 1752
1745 1753 @staticmethod
1746 1754 def unicode_name_matches(text:str) -> Tuple[str, List[str]] :
1747 1755 """Match Latex-like syntax for unicode characters base
1748 1756 on the name of the character.
1749 1757
1750 1758 This does ``\\GREEK SMALL LETTER ETA`` -> ``η``
1751 1759
1752 1760 Works only on valid python 3 identifier, or on combining characters that
1753 1761 will combine to form a valid identifier.
1754 1762 """
1755 1763 slashpos = text.rfind('\\')
1756 1764 if slashpos > -1:
1757 1765 s = text[slashpos+1:]
1758 1766 try :
1759 1767 unic = unicodedata.lookup(s)
1760 1768 # allow combining chars
1761 1769 if ('a'+unic).isidentifier():
1762 1770 return '\\'+s,[unic]
1763 1771 except KeyError:
1764 1772 pass
1765 1773 return '', []
1766 1774
1767 1775
1768 1776 def latex_matches(self, text:str) -> Tuple[str, Sequence[str]]:
1769 1777 """Match Latex syntax for unicode characters.
1770 1778
1771 1779 This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``α``
1772 1780 """
1773 1781 slashpos = text.rfind('\\')
1774 1782 if slashpos > -1:
1775 1783 s = text[slashpos:]
1776 1784 if s in latex_symbols:
1777 1785 # Try to complete a full latex symbol to unicode
1778 1786 # \\alpha -> α
1779 1787 return s, [latex_symbols[s]]
1780 1788 else:
1781 1789 # If a user has partially typed a latex symbol, give them
1782 1790 # a full list of options \al -> [\aleph, \alpha]
1783 1791 matches = [k for k in latex_symbols if k.startswith(s)]
1784 1792 if matches:
1785 1793 return s, matches
1786 1794 return '', ()
1787 1795
1788 1796 def dispatch_custom_completer(self, text):
1789 1797 if not self.custom_completers:
1790 1798 return
1791 1799
1792 1800 line = self.line_buffer
1793 1801 if not line.strip():
1794 1802 return None
1795 1803
1796 1804 # Create a little structure to pass all the relevant information about
1797 1805 # the current completion to any custom completer.
1798 1806 event = SimpleNamespace()
1799 1807 event.line = line
1800 1808 event.symbol = text
1801 1809 cmd = line.split(None,1)[0]
1802 1810 event.command = cmd
1803 1811 event.text_until_cursor = self.text_until_cursor
1804 1812
1805 1813 # for foo etc, try also to find completer for %foo
1806 1814 if not cmd.startswith(self.magic_escape):
1807 1815 try_magic = self.custom_completers.s_matches(
1808 1816 self.magic_escape + cmd)
1809 1817 else:
1810 1818 try_magic = []
1811 1819
1812 1820 for c in itertools.chain(self.custom_completers.s_matches(cmd),
1813 1821 try_magic,
1814 1822 self.custom_completers.flat_matches(self.text_until_cursor)):
1815 1823 try:
1816 1824 res = c(event)
1817 1825 if res:
1818 1826 # first, try case sensitive match
1819 1827 withcase = [r for r in res if r.startswith(text)]
1820 1828 if withcase:
1821 1829 return withcase
1822 1830 # if none, then case insensitive ones are ok too
1823 1831 text_low = text.lower()
1824 1832 return [r for r in res if r.lower().startswith(text_low)]
1825 1833 except TryNext:
1826 1834 pass
1827 1835 except KeyboardInterrupt:
1828 1836 """
1829 1837 If custom completer take too long,
1830 1838 let keyboard interrupt abort and return nothing.
1831 1839 """
1832 1840 break
1833 1841
1834 1842 return None
1835 1843
1836 1844 def completions(self, text: str, offset: int)->Iterator[Completion]:
1837 1845 """
1838 1846 Returns an iterator over the possible completions
1839 1847
1840 .. warning:: Unstable
1848 .. warning::
1849
1850 Unstable
1841 1851
1842 1852 This function is unstable, API may change without warning.
1843 1853 It will also raise unless use in proper context manager.
1844 1854
1845 1855 Parameters
1846 1856 ----------
1847 1857 text:str
1848 1858 Full text of the current input, multi line string.
1849 1859 offset:int
1850 1860 Integer representing the position of the cursor in ``text``. Offset
1851 1861 is 0-based indexed.
1852 1862
1853 1863 Yields
1854 1864 ------
1855 1865 Completion
1856 1866
1857 1867 Notes
1858 1868 -----
1859 1869 The cursor on a text can either be seen as being "in between"
1860 1870 characters or "On" a character depending on the interface visible to
1861 1871 the user. For consistency the cursor being on "in between" characters X
1862 1872 and Y is equivalent to the cursor being "on" character Y, that is to say
1863 1873 the character the cursor is on is considered as being after the cursor.
1864 1874
1865 1875 Combining characters may span more that one position in the
1866 1876 text.
1867 1877
1868 1878 .. note::
1869 1879
1870 1880 If ``IPCompleter.debug`` is :any:`True` will yield a ``--jedi/ipython--``
1871 1881 fake Completion token to distinguish completion returned by Jedi
1872 1882 and usual IPython completion.
1873 1883
1874 1884 .. note::
1875 1885
1876 1886 Completions are not completely deduplicated yet. If identical
1877 1887 completions are coming from different sources this function does not
1878 1888 ensure that each completion object will only be present once.
1879 1889 """
1880 1890 warnings.warn("_complete is a provisional API (as of IPython 6.0). "
1881 1891 "It may change without warnings. "
1882 1892 "Use in corresponding context manager.",
1883 1893 category=ProvisionalCompleterWarning, stacklevel=2)
1884 1894
1885 1895 seen = set()
1886 1896 profiler:Optional[cProfile.Profile]
1887 1897 try:
1888 1898 if self.profile_completions:
1889 1899 import cProfile
1890 1900 profiler = cProfile.Profile()
1891 1901 profiler.enable()
1892 1902 else:
1893 1903 profiler = None
1894 1904
1895 1905 for c in self._completions(text, offset, _timeout=self.jedi_compute_type_timeout/1000):
1896 1906 if c and (c in seen):
1897 1907 continue
1898 1908 yield c
1899 1909 seen.add(c)
1900 1910 except KeyboardInterrupt:
1901 1911 """if completions take too long and users send keyboard interrupt,
1902 1912 do not crash and return ASAP. """
1903 1913 pass
1904 1914 finally:
1905 1915 if profiler is not None:
1906 1916 profiler.disable()
1907 1917 ensure_dir_exists(self.profiler_output_dir)
1908 1918 output_path = os.path.join(self.profiler_output_dir, str(uuid.uuid4()))
1909 1919 print("Writing profiler output to", output_path)
1910 1920 profiler.dump_stats(output_path)
1911 1921
1912 1922 def _completions(self, full_text: str, offset: int, *, _timeout) -> Iterator[Completion]:
1913 1923 """
1914 1924 Core completion module.Same signature as :any:`completions`, with the
1915 1925 extra `timeout` parameter (in seconds).
1916 1926
1917 1927 Computing jedi's completion ``.type`` can be quite expensive (it is a
1918 1928 lazy property) and can require some warm-up, more warm up than just
1919 1929 computing the ``name`` of a completion. The warm-up can be :
1920 1930
1921 1931 - Long warm-up the first time a module is encountered after
1922 1932 install/update: actually build parse/inference tree.
1923 1933
1924 1934 - first time the module is encountered in a session: load tree from
1925 1935 disk.
1926 1936
1927 1937 We don't want to block completions for tens of seconds so we give the
1928 1938 completer a "budget" of ``_timeout`` seconds per invocation to compute
1929 1939 completions types, the completions that have not yet been computed will
1930 1940 be marked as "unknown" an will have a chance to be computed next round
1931 1941 are things get cached.
1932 1942
1933 1943 Keep in mind that Jedi is not the only thing treating the completion so
1934 1944 keep the timeout short-ish as if we take more than 0.3 second we still
1935 1945 have lots of processing to do.
1936 1946
1937 1947 """
1938 1948 deadline = time.monotonic() + _timeout
1939 1949
1940 1950
1941 1951 before = full_text[:offset]
1942 1952 cursor_line, cursor_column = position_to_cursor(full_text, offset)
1943 1953
1944 1954 matched_text, matches, matches_origin, jedi_matches = self._complete(
1945 1955 full_text=full_text, cursor_line=cursor_line, cursor_pos=cursor_column)
1946 1956
1947 1957 iter_jm = iter(jedi_matches)
1948 1958 if _timeout:
1949 1959 for jm in iter_jm:
1950 1960 try:
1951 1961 type_ = jm.type
1952 1962 except Exception:
1953 1963 if self.debug:
1954 1964 print("Error in Jedi getting type of ", jm)
1955 1965 type_ = None
1956 1966 delta = len(jm.name_with_symbols) - len(jm.complete)
1957 1967 if type_ == 'function':
1958 1968 signature = _make_signature(jm)
1959 1969 else:
1960 1970 signature = ''
1961 1971 yield Completion(start=offset - delta,
1962 1972 end=offset,
1963 1973 text=jm.name_with_symbols,
1964 1974 type=type_,
1965 1975 signature=signature,
1966 1976 _origin='jedi')
1967 1977
1968 1978 if time.monotonic() > deadline:
1969 1979 break
1970 1980
1971 1981 for jm in iter_jm:
1972 1982 delta = len(jm.name_with_symbols) - len(jm.complete)
1973 1983 yield Completion(start=offset - delta,
1974 1984 end=offset,
1975 1985 text=jm.name_with_symbols,
1976 1986 type='<unknown>', # don't compute type for speed
1977 1987 _origin='jedi',
1978 1988 signature='')
1979 1989
1980 1990
1981 1991 start_offset = before.rfind(matched_text)
1982 1992
1983 1993 # TODO:
1984 1994 # Suppress this, right now just for debug.
1985 1995 if jedi_matches and matches and self.debug:
1986 1996 yield Completion(start=start_offset, end=offset, text='--jedi/ipython--',
1987 1997 _origin='debug', type='none', signature='')
1988 1998
1989 1999 # I'm unsure if this is always true, so let's assert and see if it
1990 2000 # crash
1991 2001 assert before.endswith(matched_text)
1992 2002 for m, t in zip(matches, matches_origin):
1993 2003 yield Completion(start=start_offset, end=offset, text=m, _origin=t, signature='', type='<unknown>')
1994 2004
1995 2005
1996 2006 def complete(self, text=None, line_buffer=None, cursor_pos=None) -> Tuple[str, Sequence[str]]:
1997 2007 """Find completions for the given text and line context.
1998 2008
1999 2009 Note that both the text and the line_buffer are optional, but at least
2000 2010 one of them must be given.
2001 2011
2002 2012 Parameters
2003 2013 ----------
2004 2014 text : string, optional
2005 2015 Text to perform the completion on. If not given, the line buffer
2006 2016 is split using the instance's CompletionSplitter object.
2007 2017 line_buffer : string, optional
2008 2018 If not given, the completer attempts to obtain the current line
2009 2019 buffer via readline. This keyword allows clients which are
2010 2020 requesting for text completions in non-readline contexts to inform
2011 2021 the completer of the entire text.
2012 2022 cursor_pos : int, optional
2013 2023 Index of the cursor in the full line buffer. Should be provided by
2014 2024 remote frontends where kernel has no access to frontend state.
2015 2025
2016 2026 Returns
2017 2027 -------
2018 2028 Tuple of two items:
2019 2029 text : str
2020 2030 Text that was actually used in the completion.
2021 2031 matches : list
2022 2032 A list of completion matches.
2023 2033
2024 2034 Notes
2025 2035 -----
2026 2036 This API is likely to be deprecated and replaced by
2027 2037 :any:`IPCompleter.completions` in the future.
2028 2038
2029 2039 """
2030 2040 warnings.warn('`Completer.complete` is pending deprecation since '
2031 2041 'IPython 6.0 and will be replaced by `Completer.completions`.',
2032 2042 PendingDeprecationWarning)
2033 2043 # potential todo, FOLD the 3rd throw away argument of _complete
2034 2044 # into the first 2 one.
2035 2045 return self._complete(line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0)[:2]
2036 2046
2037 2047 def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None,
2038 2048 full_text=None) -> _CompleteResult:
2039 2049 """
2040 2050 Like complete but can also returns raw jedi completions as well as the
2041 2051 origin of the completion text. This could (and should) be made much
2042 2052 cleaner but that will be simpler once we drop the old (and stateful)
2043 2053 :any:`complete` API.
2044 2054
2045 2055 With current provisional API, cursor_pos act both (depending on the
2046 2056 caller) as the offset in the ``text`` or ``line_buffer``, or as the
2047 2057 ``column`` when passing multiline strings this could/should be renamed
2048 2058 but would add extra noise.
2049 2059
2050 2060 Returns
2051 2061 -------
2052 2062 A tuple of N elements which are (likely):
2053 2063 matched_text: ? the text that the complete matched
2054 2064 matches: list of completions ?
2055 2065 matches_origin: ? list same lenght as matches, and where each completion came from
2056 2066 jedi_matches: list of Jedi matches, have it's own structure.
2057 2067 """
2058 2068
2059 2069
2060 2070 # if the cursor position isn't given, the only sane assumption we can
2061 2071 # make is that it's at the end of the line (the common case)
2062 2072 if cursor_pos is None:
2063 2073 cursor_pos = len(line_buffer) if text is None else len(text)
2064 2074
2065 2075 if self.use_main_ns:
2066 2076 self.namespace = __main__.__dict__
2067 2077
2068 2078 # if text is either None or an empty string, rely on the line buffer
2069 2079 if (not line_buffer) and full_text:
2070 2080 line_buffer = full_text.split('\n')[cursor_line]
2071 2081 if not text: # issue #11508: check line_buffer before calling split_line
2072 2082 text = self.splitter.split_line(line_buffer, cursor_pos) if line_buffer else ''
2073 2083
2074 2084 if self.backslash_combining_completions:
2075 2085 # allow deactivation of these on windows.
2076 2086 base_text = text if not line_buffer else line_buffer[:cursor_pos]
2077 2087
2078 2088 for meth in (self.latex_matches,
2079 2089 self.unicode_name_matches,
2080 2090 back_latex_name_matches,
2081 2091 back_unicode_name_matches,
2082 2092 self.fwd_unicode_match):
2083 2093 name_text, name_matches = meth(base_text)
2084 2094 if name_text:
2085 2095 return _CompleteResult(name_text, name_matches[:MATCHES_LIMIT], \
2086 2096 [meth.__qualname__]*min(len(name_matches), MATCHES_LIMIT), ())
2087 2097
2088 2098
2089 2099 # If no line buffer is given, assume the input text is all there was
2090 2100 if line_buffer is None:
2091 2101 line_buffer = text
2092 2102
2093 2103 self.line_buffer = line_buffer
2094 2104 self.text_until_cursor = self.line_buffer[:cursor_pos]
2095 2105
2096 2106 # Do magic arg matches
2097 2107 for matcher in self.magic_arg_matchers:
2098 2108 matches = list(matcher(line_buffer))[:MATCHES_LIMIT]
2099 2109 if matches:
2100 2110 origins = [matcher.__qualname__] * len(matches)
2101 2111 return _CompleteResult(text, matches, origins, ())
2102 2112
2103 2113 # Start with a clean slate of completions
2104 2114 matches = []
2105 2115
2106 2116 # FIXME: we should extend our api to return a dict with completions for
2107 2117 # different types of objects. The rlcomplete() method could then
2108 2118 # simply collapse the dict into a list for readline, but we'd have
2109 2119 # richer completion semantics in other environments.
2110 2120 completions:Iterable[Any] = []
2111 2121 if self.use_jedi:
2112 2122 if not full_text:
2113 2123 full_text = line_buffer
2114 2124 completions = self._jedi_matches(
2115 2125 cursor_pos, cursor_line, full_text)
2116 2126
2117 2127 if self.merge_completions:
2118 2128 matches = []
2119 2129 for matcher in self.matchers:
2120 2130 try:
2121 2131 matches.extend([(m, matcher.__qualname__)
2122 2132 for m in matcher(text)])
2123 2133 except:
2124 2134 # Show the ugly traceback if the matcher causes an
2125 2135 # exception, but do NOT crash the kernel!
2126 2136 sys.excepthook(*sys.exc_info())
2127 2137 else:
2128 2138 for matcher in self.matchers:
2129 2139 matches = [(m, matcher.__qualname__)
2130 2140 for m in matcher(text)]
2131 2141 if matches:
2132 2142 break
2133 2143
2134 2144 seen = set()
2135 2145 filtered_matches = set()
2136 2146 for m in matches:
2137 2147 t, c = m
2138 2148 if t not in seen:
2139 2149 filtered_matches.add(m)
2140 2150 seen.add(t)
2141 2151
2142 2152 _filtered_matches = sorted(filtered_matches, key=lambda x: completions_sorting_key(x[0]))
2143 2153
2144 2154 custom_res = [(m, 'custom') for m in self.dispatch_custom_completer(text) or []]
2145 2155
2146 2156 _filtered_matches = custom_res or _filtered_matches
2147 2157
2148 2158 _filtered_matches = _filtered_matches[:MATCHES_LIMIT]
2149 2159 _matches = [m[0] for m in _filtered_matches]
2150 2160 origins = [m[1] for m in _filtered_matches]
2151 2161
2152 2162 self.matches = _matches
2153 2163
2154 2164 return _CompleteResult(text, _matches, origins, completions)
2155 2165
2156 2166 def fwd_unicode_match(self, text:str) -> Tuple[str, Sequence[str]]:
2157 2167 """
2158 2168 Forward match a string starting with a backslash with a list of
2159 2169 potential Unicode completions.
2160 2170
2161 2171 Will compute list list of Unicode character names on first call and cache it.
2162 2172
2163 2173 Returns
2164 2174 -------
2165 2175 At tuple with:
2166 2176 - matched text (empty if no matches)
2167 2177 - list of potential completions, empty tuple otherwise)
2168 2178 """
2169 2179 # TODO: self.unicode_names is here a list we traverse each time with ~100k elements.
2170 2180 # We could do a faster match using a Trie.
2171 2181
2172 2182 # Using pygtrie the follwing seem to work:
2173 2183
2174 2184 # s = PrefixSet()
2175 2185
2176 2186 # for c in range(0,0x10FFFF + 1):
2177 2187 # try:
2178 2188 # s.add(unicodedata.name(chr(c)))
2179 2189 # except ValueError:
2180 2190 # pass
2181 2191 # [''.join(k) for k in s.iter(prefix)]
2182 2192
2183 2193 # But need to be timed and adds an extra dependency.
2184 2194
2185 2195 slashpos = text.rfind('\\')
2186 2196 # if text starts with slash
2187 2197 if slashpos > -1:
2188 2198 # PERF: It's important that we don't access self._unicode_names
2189 2199 # until we're inside this if-block. _unicode_names is lazily
2190 2200 # initialized, and it takes a user-noticeable amount of time to
2191 2201 # initialize it, so we don't want to initialize it unless we're
2192 2202 # actually going to use it.
2193 2203 s = text[slashpos+1:]
2194 2204 candidates = [x for x in self.unicode_names if x.startswith(s)]
2195 2205 if candidates:
2196 2206 return s, candidates
2197 2207 else:
2198 2208 return '', ()
2199 2209
2200 2210 # if text does not start with slash
2201 2211 else:
2202 2212 return '', ()
2203 2213
2204 2214 @property
2205 2215 def unicode_names(self) -> List[str]:
2206 2216 """List of names of unicode code points that can be completed.
2207 2217
2208 2218 The list is lazily initialized on first access.
2209 2219 """
2210 2220 if self._unicode_names is None:
2211 2221 names = []
2212 2222 for c in range(0,0x10FFFF + 1):
2213 2223 try:
2214 2224 names.append(unicodedata.name(chr(c)))
2215 2225 except ValueError:
2216 2226 pass
2217 2227 self._unicode_names = _unicode_name_compute(_UNICODE_RANGES)
2218 2228
2219 2229 return self._unicode_names
2220 2230
2221 2231 def _unicode_name_compute(ranges:List[Tuple[int,int]]) -> List[str]:
2222 2232 names = []
2223 2233 for start,stop in ranges:
2224 2234 for c in range(start, stop) :
2225 2235 try:
2226 2236 names.append(unicodedata.name(chr(c)))
2227 2237 except ValueError:
2228 2238 pass
2229 2239 return names
@@ -1,228 +1,229 b''
1 1 # encoding: utf-8
2 2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3 3
4 4 Authors:
5 5
6 6 * Fernando Perez
7 7 * Brian E. Granger
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
12 12 # Copyright (C) 2008-2011 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import os
23 23 import sys
24 24 import traceback
25 25 from pprint import pformat
26 from pathlib import Path
26 27
27 28 from IPython.core import ultratb
28 29 from IPython.core.release import author_email
29 30 from IPython.utils.sysinfo import sys_info
30 31 from IPython.utils.py3compat import input
31 32
32 33 from IPython.core.release import __version__ as version
33 34
34 35 #-----------------------------------------------------------------------------
35 36 # Code
36 37 #-----------------------------------------------------------------------------
37 38
38 39 # Template for the user message.
39 40 _default_message_template = """\
40 41 Oops, {app_name} crashed. We do our best to make it stable, but...
41 42
42 43 A crash report was automatically generated with the following information:
43 44 - A verbatim copy of the crash traceback.
44 45 - A copy of your input history during this session.
45 46 - Data on your current {app_name} configuration.
46 47
47 48 It was left in the file named:
48 49 \t'{crash_report_fname}'
49 50 If you can email this file to the developers, the information in it will help
50 51 them in understanding and correcting the problem.
51 52
52 53 You can mail it to: {contact_name} at {contact_email}
53 54 with the subject '{app_name} Crash Report'.
54 55
55 56 If you want to do it now, the following command will work (under Unix):
56 57 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
57 58
58 59 In your email, please also include information about:
59 60 - The operating system under which the crash happened: Linux, macOS, Windows,
60 61 other, and which exact version (for example: Ubuntu 16.04.3, macOS 10.13.2,
61 62 Windows 10 Pro), and whether it is 32-bit or 64-bit;
62 63 - How {app_name} was installed: using pip or conda, from GitHub, as part of
63 64 a Docker container, or other, providing more detail if possible;
64 65 - How to reproduce the crash: what exact sequence of instructions can one
65 66 input to get the same crash? Ideally, find a minimal yet complete sequence
66 67 of instructions that yields the crash.
67 68
68 69 To ensure accurate tracking of this issue, please file a report about it at:
69 70 {bug_tracker}
70 71 """
71 72
72 73 _lite_message_template = """
73 74 If you suspect this is an IPython {version} bug, please report it at:
74 75 https://github.com/ipython/ipython/issues
75 76 or send an email to the mailing list at {email}
76 77
77 78 You can print a more detailed traceback right now with "%tb", or use "%debug"
78 79 to interactively debug it.
79 80
80 81 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
81 82 {config}Application.verbose_crash=True
82 83 """
83 84
84 85
85 86 class CrashHandler(object):
86 87 """Customizable crash handlers for IPython applications.
87 88
88 89 Instances of this class provide a :meth:`__call__` method which can be
89 90 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
90 91
91 92 def __call__(self, etype, evalue, etb)
92 93 """
93 94
94 95 message_template = _default_message_template
95 96 section_sep = '\n\n'+'*'*75+'\n\n'
96 97
97 98 def __init__(self, app, contact_name=None, contact_email=None,
98 99 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
99 100 """Create a new crash handler
100 101
101 102 Parameters
102 103 ----------
103 104 app : Application
104 105 A running :class:`Application` instance, which will be queried at
105 106 crash time for internal information.
106 107
107 108 contact_name : str
108 109 A string with the name of the person to contact.
109 110
110 111 contact_email : str
111 112 A string with the email address of the contact.
112 113
113 114 bug_tracker : str
114 115 A string with the URL for your project's bug tracker.
115 116
116 117 show_crash_traceback : bool
117 118 If false, don't print the crash traceback on stderr, only generate
118 119 the on-disk report
119 120
120 121 Non-argument instance attributes:
121 122
122 123 These instances contain some non-argument attributes which allow for
123 124 further customization of the crash handler's behavior. Please see the
124 125 source for further details.
125 126 """
126 127 self.crash_report_fname = "Crash_report_%s.txt" % app.name
127 128 self.app = app
128 129 self.call_pdb = call_pdb
129 130 #self.call_pdb = True # dbg
130 131 self.show_crash_traceback = show_crash_traceback
131 132 self.info = dict(app_name = app.name,
132 133 contact_name = contact_name,
133 134 contact_email = contact_email,
134 135 bug_tracker = bug_tracker,
135 136 crash_report_fname = self.crash_report_fname)
136 137
137 138
138 139 def __call__(self, etype, evalue, etb):
139 140 """Handle an exception, call for compatible with sys.excepthook"""
140 141
141 142 # do not allow the crash handler to be called twice without reinstalling it
142 143 # this prevents unlikely errors in the crash handling from entering an
143 144 # infinite loop.
144 145 sys.excepthook = sys.__excepthook__
145 146
146 147 # Report tracebacks shouldn't use color in general (safer for users)
147 148 color_scheme = 'NoColor'
148 149
149 150 # Use this ONLY for developer debugging (keep commented out for release)
150 151 #color_scheme = 'Linux' # dbg
151 152 try:
152 153 rptdir = self.app.ipython_dir
153 154 except:
154 rptdir = os.getcwd()
155 if rptdir is None or not os.path.isdir(rptdir):
156 rptdir = os.getcwd()
157 report_name = os.path.join(rptdir,self.crash_report_fname)
155 rptdir = Path.cwd()
156 if rptdir is None or not Path.is_dir(rptdir):
157 rptdir = Path.cwd()
158 report_name = rptdir / self.crash_report_fname
158 159 # write the report filename into the instance dict so it can get
159 160 # properly expanded out in the user message template
160 161 self.crash_report_fname = report_name
161 162 self.info['crash_report_fname'] = report_name
162 163 TBhandler = ultratb.VerboseTB(
163 164 color_scheme=color_scheme,
164 165 long_header=1,
165 166 call_pdb=self.call_pdb,
166 167 )
167 168 if self.call_pdb:
168 169 TBhandler(etype,evalue,etb)
169 170 return
170 171 else:
171 172 traceback = TBhandler.text(etype,evalue,etb,context=31)
172 173
173 174 # print traceback to screen
174 175 if self.show_crash_traceback:
175 176 print(traceback, file=sys.stderr)
176 177
177 178 # and generate a complete report on disk
178 179 try:
179 180 report = open(report_name,'w')
180 181 except:
181 182 print('Could not create crash report on disk.', file=sys.stderr)
182 183 return
183 184
184 185 with report:
185 186 # Inform user on stderr of what happened
186 187 print('\n'+'*'*70+'\n', file=sys.stderr)
187 188 print(self.message_template.format(**self.info), file=sys.stderr)
188 189
189 190 # Construct report on disk
190 191 report.write(self.make_report(traceback))
191 192
192 193 input("Hit <Enter> to quit (your terminal may close):")
193 194
194 195 def make_report(self,traceback):
195 196 """Return a string containing a crash report."""
196 197
197 198 sec_sep = self.section_sep
198 199
199 200 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
200 201 rpt_add = report.append
201 202 rpt_add(sys_info())
202 203
203 204 try:
204 205 config = pformat(self.app.config)
205 206 rpt_add(sec_sep)
206 207 rpt_add('Application name: %s\n\n' % self.app_name)
207 208 rpt_add('Current user configuration structure:\n\n')
208 209 rpt_add(config)
209 210 except:
210 211 pass
211 212 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
212 213
213 214 return ''.join(report)
214 215
215 216
216 217 def crash_handler_lite(etype, evalue, tb):
217 218 """a light excepthook, adding a small message to the usual traceback"""
218 219 traceback.print_exception(etype, evalue, tb)
219 220
220 221 from IPython.core.interactiveshell import InteractiveShell
221 222 if InteractiveShell.initialized():
222 223 # we are in a Shell environment, give %magic example
223 224 config = "%config "
224 225 else:
225 226 # we are not in a shell, show generic config
226 227 config = "c."
227 228 print(_lite_message_template.format(email=author_email, config=config, version=version), file=sys.stderr)
228 229
@@ -1,833 +1,857 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Pdb debugger class.
4 4
5 5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 6 the command line completion of other programs which include this isn't
7 7 damaged.
8 8
9 9 In the future, this class will be expanded with improvements over the standard
10 10 pdb.
11 11
12 12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 13 changes. Licensing should therefore be under the standard Python terms. For
14 14 details on the PSF (Python Software Foundation) standard license, see:
15 15
16 16 https://docs.python.org/2/license.html
17 17 """
18 18
19 19 #*****************************************************************************
20 20 #
21 21 # This file is licensed under the PSF license.
22 22 #
23 23 # Copyright (C) 2001 Python Software Foundation, www.python.org
24 24 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
25 25 #
26 26 #
27 27 #*****************************************************************************
28 28
29 29 import bdb
30 30 import functools
31 31 import inspect
32 32 import linecache
33 33 import sys
34 34 import warnings
35 35 import re
36 36
37 37 from IPython import get_ipython
38 38 from IPython.utils import PyColorize
39 39 from IPython.utils import coloransi, py3compat
40 40 from IPython.core.excolors import exception_colors
41 41 from IPython.testing.skipdoctest import skip_doctest
42 42
43 43
44 44 prompt = 'ipdb> '
45 45
46 46 #We have to check this directly from sys.argv, config struct not yet available
47 47 from pdb import Pdb as OldPdb
48 48
49 49 # Allow the set_trace code to operate outside of an ipython instance, even if
50 50 # it does so with some limitations. The rest of this support is implemented in
51 51 # the Tracer constructor.
52 52
53
53 54 def make_arrow(pad):
54 55 """generate the leading arrow in front of traceback or debugger"""
55 56 if pad >= 2:
56 57 return '-'*(pad-2) + '> '
57 58 elif pad == 1:
58 59 return '>'
59 60 return ''
60 61
61 62
62 63 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
63 64 """Exception hook which handles `BdbQuit` exceptions.
64 65
65 66 All other exceptions are processed using the `excepthook`
66 67 parameter.
67 68 """
68 69 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
69 70 DeprecationWarning, stacklevel=2)
70 71 if et==bdb.BdbQuit:
71 72 print('Exiting Debugger.')
72 73 elif excepthook is not None:
73 74 excepthook(et, ev, tb)
74 75 else:
75 76 # Backwards compatibility. Raise deprecation warning?
76 77 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
77 78
78 79
79 80 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
80 81 warnings.warn(
81 82 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
82 83 DeprecationWarning, stacklevel=2)
83 84 print('Exiting Debugger.')
84 85
85 86
86 87 class Tracer(object):
87 88 """
88 89 DEPRECATED
89 90
90 91 Class for local debugging, similar to pdb.set_trace.
91 92
92 93 Instances of this class, when called, behave like pdb.set_trace, but
93 94 providing IPython's enhanced capabilities.
94 95
95 96 This is implemented as a class which must be initialized in your own code
96 97 and not as a standalone function because we need to detect at runtime
97 98 whether IPython is already active or not. That detection is done in the
98 99 constructor, ensuring that this code plays nicely with a running IPython,
99 100 while functioning acceptably (though with limitations) if outside of it.
100 101 """
101 102
102 103 @skip_doctest
103 104 def __init__(self, colors=None):
104 105 """
105 106 DEPRECATED
106 107
107 108 Create a local debugger instance.
108 109
109 110 Parameters
110 111 ----------
111 112
112 113 colors : str, optional
113 114 The name of the color scheme to use, it must be one of IPython's
114 115 valid color schemes. If not given, the function will default to
115 116 the current IPython scheme when running inside IPython, and to
116 117 'NoColor' otherwise.
117 118
118 119 Examples
119 120 --------
120 121 ::
121 122
122 123 from IPython.core.debugger import Tracer; debug_here = Tracer()
123 124
124 125 Later in your code::
125 126
126 127 debug_here() # -> will open up the debugger at that point.
127 128
128 129 Once the debugger activates, you can use all of its regular commands to
129 130 step through code, set breakpoints, etc. See the pdb documentation
130 131 from the Python standard library for usage details.
131 132 """
132 133 warnings.warn("`Tracer` is deprecated since version 5.1, directly use "
133 134 "`IPython.core.debugger.Pdb.set_trace()`",
134 135 DeprecationWarning, stacklevel=2)
135 136
136 137 ip = get_ipython()
137 138 if ip is None:
138 139 # Outside of ipython, we set our own exception hook manually
139 140 sys.excepthook = functools.partial(BdbQuit_excepthook,
140 141 excepthook=sys.excepthook)
141 142 def_colors = 'NoColor'
142 143 else:
143 144 # In ipython, we use its custom exception handler mechanism
144 145 def_colors = ip.colors
145 146 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
146 147
147 148 if colors is None:
148 149 colors = def_colors
149 150
150 151 # The stdlib debugger internally uses a modified repr from the `repr`
151 152 # module, that limits the length of printed strings to a hardcoded
152 153 # limit of 30 characters. That much trimming is too aggressive, let's
153 154 # at least raise that limit to 80 chars, which should be enough for
154 155 # most interactive uses.
155 156 try:
156 157 from reprlib import aRepr
157 158 aRepr.maxstring = 80
158 159 except:
159 160 # This is only a user-facing convenience, so any error we encounter
160 161 # here can be warned about but can be otherwise ignored. These
161 162 # printouts will tell us about problems if this API changes
162 163 import traceback
163 164 traceback.print_exc()
164 165
165 166 self.debugger = Pdb(colors)
166 167
167 168 def __call__(self):
168 169 """Starts an interactive debugger at the point where called.
169 170
170 171 This is similar to the pdb.set_trace() function from the std lib, but
171 172 using IPython's enhanced debugger."""
172 173
173 174 self.debugger.set_trace(sys._getframe().f_back)
174 175
175 176
176 177 RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+')
177 178
178 179
179 180 def strip_indentation(multiline_string):
180 181 return RGX_EXTRA_INDENT.sub('', multiline_string)
181 182
182 183
183 184 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
184 185 """Make new_fn have old_fn's doc string. This is particularly useful
185 186 for the ``do_...`` commands that hook into the help system.
186 187 Adapted from from a comp.lang.python posting
187 188 by Duncan Booth."""
188 189 def wrapper(*args, **kw):
189 190 return new_fn(*args, **kw)
190 191 if old_fn.__doc__:
191 192 wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text
192 193 return wrapper
193 194
194 195
195 196 class Pdb(OldPdb):
196 197 """Modified Pdb class, does not load readline.
197 198
198 199 for a standalone version that uses prompt_toolkit, see
199 200 `IPython.terminal.debugger.TerminalPdb` and
200 201 `IPython.terminal.debugger.set_trace()`
201 202 """
202 203
203 204 def __init__(self, color_scheme=None, completekey=None,
204 205 stdin=None, stdout=None, context=5, **kwargs):
205 206 """Create a new IPython debugger.
206 207
207 208 :param color_scheme: Deprecated, do not use.
208 209 :param completekey: Passed to pdb.Pdb.
209 210 :param stdin: Passed to pdb.Pdb.
210 211 :param stdout: Passed to pdb.Pdb.
211 212 :param context: Number of lines of source code context to show when
212 213 displaying stacktrace information.
213 214 :param kwargs: Passed to pdb.Pdb.
214 215 The possibilities are python version dependent, see the python
215 216 docs for more info.
216 217 """
217 218
218 219 # Parent constructor:
219 220 try:
220 221 self.context = int(context)
221 222 if self.context <= 0:
222 223 raise ValueError("Context must be a positive integer")
223 224 except (TypeError, ValueError) as e:
224 225 raise ValueError("Context must be a positive integer") from e
225 226
226 227 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
227 228 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
228 229
229 230 # IPython changes...
230 231 self.shell = get_ipython()
231 232
232 233 if self.shell is None:
233 234 save_main = sys.modules['__main__']
234 235 # No IPython instance running, we must create one
235 236 from IPython.terminal.interactiveshell import \
236 237 TerminalInteractiveShell
237 238 self.shell = TerminalInteractiveShell.instance()
238 239 # needed by any code which calls __import__("__main__") after
239 240 # the debugger was entered. See also #9941.
240 sys.modules['__main__'] = save_main
241 sys.modules["__main__"] = save_main
241 242
242 243 if color_scheme is not None:
243 244 warnings.warn(
244 245 "The `color_scheme` argument is deprecated since version 5.1",
245 246 DeprecationWarning, stacklevel=2)
246 247 else:
247 248 color_scheme = self.shell.colors
248 249
249 250 self.aliases = {}
250 251
251 252 # Create color table: we copy the default one from the traceback
252 253 # module and add a few attributes needed for debugging
253 254 self.color_scheme_table = exception_colors()
254 255
255 256 # shorthands
256 257 C = coloransi.TermColors
257 258 cst = self.color_scheme_table
258 259
259 260 cst['NoColor'].colors.prompt = C.NoColor
260 261 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
261 262 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
262 263
263 264 cst['Linux'].colors.prompt = C.Green
264 265 cst['Linux'].colors.breakpoint_enabled = C.LightRed
265 266 cst['Linux'].colors.breakpoint_disabled = C.Red
266 267
267 268 cst['LightBG'].colors.prompt = C.Blue
268 269 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
269 270 cst['LightBG'].colors.breakpoint_disabled = C.Red
270 271
271 272 cst['Neutral'].colors.prompt = C.Blue
272 273 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
273 274 cst['Neutral'].colors.breakpoint_disabled = C.Red
274 275
275
276 276 # Add a python parser so we can syntax highlight source while
277 277 # debugging.
278 278 self.parser = PyColorize.Parser(style=color_scheme)
279 279 self.set_colors(color_scheme)
280 280
281 281 # Set the prompt - the default prompt is '(Pdb)'
282 282 self.prompt = prompt
283 283 self.skip_hidden = True
284 284
285 285 def set_colors(self, scheme):
286 286 """Shorthand access to the color table scheme selector method."""
287 287 self.color_scheme_table.set_active_scheme(scheme)
288 288 self.parser.style = scheme
289 289
290 290 def set_trace(self, frame=None):
291 291 if frame is None:
292 292 frame = sys._getframe().f_back
293 293 self.initial_frame = frame
294 294 return super().set_trace(frame)
295 295
296 296 def hidden_frames(self, stack):
297 297 """
298 298 Given an index in the stack return whether it should be skipped.
299 299
300 300 This is used in up/down and where to skip frames.
301 301 """
302 302 # The f_locals dictionary is updated from the actual frame
303 303 # locals whenever the .f_locals accessor is called, so we
304 304 # avoid calling it here to preserve self.curframe_locals.
305 305 # Futhermore, there is no good reason to hide the current frame.
306 306 ip_hide = [
307 307 False
308 308 if s[0] in (self.curframe, getattr(self, "initial_frame", None))
309 309 else s[0].f_locals.get("__tracebackhide__", False)
310 310 for s in stack
311 311 ]
312 312 ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
313 313 if ip_start:
314 314 ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
315 315 return ip_hide
316 316
317 317 def interaction(self, frame, traceback):
318 318 try:
319 319 OldPdb.interaction(self, frame, traceback)
320 320 except KeyboardInterrupt:
321 321 self.stdout.write("\n" + self.shell.get_exception_only())
322 322
323 def precmd(self, line):
324 """Perform useful escapes on the command before it is executed."""
325
326 if line.endswith("??"):
327 line = "pinfo2 " + line[:-2]
328 elif line.endswith("?"):
329 line = "pinfo " + line[:-1]
330
331 line = super().precmd(line)
332
333 return line
334
323 335 def new_do_frame(self, arg):
324 336 OldPdb.do_frame(self, arg)
325 337
326 338 def new_do_quit(self, arg):
327 339
328 340 if hasattr(self, 'old_all_completions'):
329 341 self.shell.Completer.all_completions=self.old_all_completions
330 342
331 343 return OldPdb.do_quit(self, arg)
332 344
333 345 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
334 346
335 347 def new_do_restart(self, arg):
336 348 """Restart command. In the context of ipython this is exactly the same
337 349 thing as 'quit'."""
338 350 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
339 351 return self.do_quit(arg)
340 352
341 353 def print_stack_trace(self, context=None):
342 354 Colors = self.color_scheme_table.active_colors
343 355 ColorsNormal = Colors.Normal
344 356 if context is None:
345 357 context = self.context
346 358 try:
347 359 context=int(context)
348 360 if context <= 0:
349 361 raise ValueError("Context must be a positive integer")
350 362 except (TypeError, ValueError) as e:
351 363 raise ValueError("Context must be a positive integer") from e
352 364 try:
353 365 skipped = 0
354 366 for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
355 367 if hidden and self.skip_hidden:
356 368 skipped += 1
357 369 continue
358 370 if skipped:
359 371 print(
360 372 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
361 373 )
362 374 skipped = 0
363 375 self.print_stack_entry(frame_lineno, context=context)
364 376 if skipped:
365 377 print(
366 378 f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
367 379 )
368 380 except KeyboardInterrupt:
369 381 pass
370 382
371 383 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
372 384 context=None):
373 385 if context is None:
374 386 context = self.context
375 387 try:
376 388 context=int(context)
377 389 if context <= 0:
378 390 raise ValueError("Context must be a positive integer")
379 391 except (TypeError, ValueError) as e:
380 392 raise ValueError("Context must be a positive integer") from e
381 393 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
382 394
383 395 # vds: >>
384 396 frame, lineno = frame_lineno
385 397 filename = frame.f_code.co_filename
386 398 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
387 399 # vds: <<
388 400
389 401 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
390 402 if context is None:
391 403 context = self.context
392 404 try:
393 405 context=int(context)
394 406 if context <= 0:
395 407 print("Context must be a positive integer", file=self.stdout)
396 408 except (TypeError, ValueError):
397 409 print("Context must be a positive integer", file=self.stdout)
398 410
399 411 import reprlib
400 412
401 413 ret = []
402 414
403 415 Colors = self.color_scheme_table.active_colors
404 416 ColorsNormal = Colors.Normal
405 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
406 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
407 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
408 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
409 ColorsNormal)
417 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
418 tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal)
419 tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal)
420 tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal)
410 421
411 422 frame, lineno = frame_lineno
412 423
413 424 return_value = ''
414 425 if '__return__' in frame.f_locals:
415 426 rv = frame.f_locals['__return__']
416 427 #return_value += '->'
417 428 return_value += reprlib.repr(rv) + '\n'
418 429 ret.append(return_value)
419 430
420 431 #s = filename + '(' + `lineno` + ')'
421 432 filename = self.canonic(frame.f_code.co_filename)
422 433 link = tpl_link % py3compat.cast_unicode(filename)
423 434
424 435 if frame.f_code.co_name:
425 436 func = frame.f_code.co_name
426 437 else:
427 438 func = "<lambda>"
428 439
429 440 call = ''
430 441 if func != '?':
431 442 if '__args__' in frame.f_locals:
432 443 args = reprlib.repr(frame.f_locals['__args__'])
433 444 else:
434 445 args = '()'
435 446 call = tpl_call % (func, args)
436 447
437 448 # The level info should be generated in the same format pdb uses, to
438 449 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
439 450 if frame is self.curframe:
440 451 ret.append('> ')
441 452 else:
442 ret.append(' ')
443 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
453 ret.append(" ")
454 ret.append("%s(%s)%s\n" % (link, lineno, call))
444 455
445 456 start = lineno - 1 - context//2
446 457 lines = linecache.getlines(filename)
447 458 start = min(start, len(lines) - context)
448 459 start = max(start, 0)
449 460 lines = lines[start : start + context]
450 461
451 462 for i,line in enumerate(lines):
452 show_arrow = (start + 1 + i == lineno)
453 linetpl = (frame is self.curframe or show_arrow) \
454 and tpl_line_em \
455 or tpl_line
456 ret.append(self.__format_line(linetpl, filename,
457 start + 1 + i, line,
458 arrow = show_arrow) )
459 return ''.join(ret)
463 show_arrow = start + 1 + i == lineno
464 linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line
465 ret.append(
466 self.__format_line(
467 linetpl, filename, start + 1 + i, line, arrow=show_arrow
468 )
469 )
470 return "".join(ret)
460 471
461 472 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
462 473 bp_mark = ""
463 474 bp_mark_color = ""
464 475
465 476 new_line, err = self.parser.format2(line, 'str')
466 477 if not err:
467 478 line = new_line
468 479
469 480 bp = None
470 481 if lineno in self.get_file_breaks(filename):
471 482 bps = self.get_breaks(filename, lineno)
472 483 bp = bps[-1]
473 484
474 485 if bp:
475 486 Colors = self.color_scheme_table.active_colors
476 487 bp_mark = str(bp.number)
477 488 bp_mark_color = Colors.breakpoint_enabled
478 489 if not bp.enabled:
479 490 bp_mark_color = Colors.breakpoint_disabled
480 491
481 492 numbers_width = 7
482 493 if arrow:
483 494 # This is the line with the error
484 495 pad = numbers_width - len(str(lineno)) - len(bp_mark)
485 496 num = '%s%s' % (make_arrow(pad), str(lineno))
486 497 else:
487 498 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
488 499
489 500 return tpl_line % (bp_mark_color + bp_mark, num, line)
490 501
491
492 502 def print_list_lines(self, filename, first, last):
493 503 """The printing (as opposed to the parsing part of a 'list'
494 504 command."""
495 505 try:
496 506 Colors = self.color_scheme_table.active_colors
497 507 ColorsNormal = Colors.Normal
498 508 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
499 509 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
500 510 src = []
501 511 if filename == "<string>" and hasattr(self, "_exec_filename"):
502 512 filename = self._exec_filename
503 513
504 514 for lineno in range(first, last+1):
505 515 line = linecache.getline(filename, lineno)
506 516 if not line:
507 517 break
508 518
509 519 if lineno == self.curframe.f_lineno:
510 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
520 line = self.__format_line(
521 tpl_line_em, filename, lineno, line, arrow=True
522 )
511 523 else:
512 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
524 line = self.__format_line(
525 tpl_line, filename, lineno, line, arrow=False
526 )
513 527
514 528 src.append(line)
515 529 self.lineno = lineno
516 530
517 531 print(''.join(src), file=self.stdout)
518 532
519 533 except KeyboardInterrupt:
520 534 pass
521 535
522 536 def do_skip_hidden(self, arg):
523 537 """
524 538 Change whether or not we should skip frames with the
525 539 __tracebackhide__ attribute.
526 540 """
527 541 if arg.strip().lower() in ("true", "yes"):
528 542 self.skip_hidden = True
529 543 elif arg.strip().lower() in ("false", "no"):
530 544 self.skip_hidden = False
531 545
532 546 def do_list(self, arg):
533 547 """Print lines of code from the current stack frame
534 548 """
535 549 self.lastcmd = 'list'
536 550 last = None
537 551 if arg:
538 552 try:
539 553 x = eval(arg, {}, {})
540 554 if type(x) == type(()):
541 555 first, last = x
542 556 first = int(first)
543 557 last = int(last)
544 558 if last < first:
545 559 # Assume it's a count
546 560 last = first + last
547 561 else:
548 562 first = max(1, int(x) - 5)
549 563 except:
550 564 print('*** Error in argument:', repr(arg), file=self.stdout)
551 565 return
552 566 elif self.lineno is None:
553 567 first = max(1, self.curframe.f_lineno - 5)
554 568 else:
555 569 first = self.lineno + 1
556 570 if last is None:
557 571 last = first + 10
558 572 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
559 573
560 574 # vds: >>
561 575 lineno = first
562 576 filename = self.curframe.f_code.co_filename
563 577 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
564 578 # vds: <<
565 579
566 580 do_l = do_list
567 581
568 582 def getsourcelines(self, obj):
569 583 lines, lineno = inspect.findsource(obj)
570 584 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
571 585 # must be a module frame: do not try to cut a block out of it
572 586 return lines, 1
573 587 elif inspect.ismodule(obj):
574 588 return lines, 1
575 589 return inspect.getblock(lines[lineno:]), lineno+1
576 590
577 591 def do_longlist(self, arg):
578 592 """Print lines of code from the current stack frame.
579 593
580 594 Shows more lines than 'list' does.
581 595 """
582 596 self.lastcmd = 'longlist'
583 597 try:
584 598 lines, lineno = self.getsourcelines(self.curframe)
585 599 except OSError as err:
586 600 self.error(err)
587 601 return
588 602 last = lineno + len(lines)
589 603 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
590 604 do_ll = do_longlist
591 605
592 606 def do_debug(self, arg):
593 607 """debug code
594 608 Enter a recursive debugger that steps through the code
595 609 argument (which is an arbitrary expression or statement to be
596 610 executed in the current environment).
597 611 """
598 612 trace_function = sys.gettrace()
599 613 sys.settrace(None)
600 614 globals = self.curframe.f_globals
601 615 locals = self.curframe_locals
602 616 p = self.__class__(completekey=self.completekey,
603 617 stdin=self.stdin, stdout=self.stdout)
604 618 p.use_rawinput = self.use_rawinput
605 619 p.prompt = "(%s) " % self.prompt.strip()
606 620 self.message("ENTERING RECURSIVE DEBUGGER")
607 621 sys.call_tracing(p.run, (arg, globals, locals))
608 622 self.message("LEAVING RECURSIVE DEBUGGER")
609 623 sys.settrace(trace_function)
610 624 self.lastcmd = p.lastcmd
611 625
612 626 def do_pdef(self, arg):
613 627 """Print the call signature for any callable object.
614 628
615 629 The debugger interface to %pdef"""
616 630 namespaces = [
617 631 ("Locals", self.curframe_locals),
618 632 ("Globals", self.curframe.f_globals),
619 633 ]
620 634 self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
621 635
622 636 def do_pdoc(self, arg):
623 637 """Print the docstring for an object.
624 638
625 639 The debugger interface to %pdoc."""
626 640 namespaces = [
627 641 ("Locals", self.curframe_locals),
628 642 ("Globals", self.curframe.f_globals),
629 643 ]
630 644 self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
631 645
632 646 def do_pfile(self, arg):
633 647 """Print (or run through pager) the file where an object is defined.
634 648
635 649 The debugger interface to %pfile.
636 650 """
637 651 namespaces = [
638 652 ("Locals", self.curframe_locals),
639 653 ("Globals", self.curframe.f_globals),
640 654 ]
641 655 self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
642 656
643 657 def do_pinfo(self, arg):
644 658 """Provide detailed information about an object.
645 659
646 660 The debugger interface to %pinfo, i.e., obj?."""
647 661 namespaces = [
648 662 ("Locals", self.curframe_locals),
649 663 ("Globals", self.curframe.f_globals),
650 664 ]
651 665 self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
652 666
653 667 def do_pinfo2(self, arg):
654 668 """Provide extra detailed information about an object.
655 669
656 670 The debugger interface to %pinfo2, i.e., obj??."""
657 671 namespaces = [
658 672 ("Locals", self.curframe_locals),
659 673 ("Globals", self.curframe.f_globals),
660 674 ]
661 675 self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
662 676
663 677 def do_psource(self, arg):
664 678 """Print (or run through pager) the source code for an object."""
665 679 namespaces = [
666 680 ("Locals", self.curframe_locals),
667 681 ("Globals", self.curframe.f_globals),
668 682 ]
669 683 self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
670 684
671 685 def do_where(self, arg):
672 686 """w(here)
673 687 Print a stack trace, with the most recent frame at the bottom.
674 688 An arrow indicates the "current frame", which determines the
675 689 context of most commands. 'bt' is an alias for this command.
676 690
677 691 Take a number as argument as an (optional) number of context line to
678 692 print"""
679 693 if arg:
680 694 try:
681 695 context = int(arg)
682 696 except ValueError as err:
683 697 self.error(err)
684 698 return
685 699 self.print_stack_trace(context)
686 700 else:
687 701 self.print_stack_trace()
688 702
689 703 do_w = do_where
690 704
691 705 def stop_here(self, frame):
692 706 hidden = False
693 707 if self.skip_hidden:
694 708 hidden = frame.f_locals.get("__tracebackhide__", False)
695 709 if hidden:
696 710 Colors = self.color_scheme_table.active_colors
697 711 ColorsNormal = Colors.Normal
698 712 print(f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n")
699 713
700 714 return super().stop_here(frame)
701 715
702 716 def do_up(self, arg):
703 717 """u(p) [count]
704 718 Move the current frame count (default one) levels up in the
705 719 stack trace (to an older frame).
706 720
707 721 Will skip hidden frames.
708 722 """
709 ## modified version of upstream that skips
723 # modified version of upstream that skips
710 724 # frames with __tracebackide__
711 725 if self.curindex == 0:
712 726 self.error("Oldest frame")
713 727 return
714 728 try:
715 729 count = int(arg or 1)
716 730 except ValueError:
717 731 self.error("Invalid frame count (%s)" % arg)
718 732 return
719 733 skipped = 0
720 734 if count < 0:
721 735 _newframe = 0
722 736 else:
723 _newindex = self.curindex
724 737 counter = 0
725 738 hidden_frames = self.hidden_frames(self.stack)
726 739 for i in range(self.curindex - 1, -1, -1):
727 frame = self.stack[i][0]
728 740 if hidden_frames[i] and self.skip_hidden:
729 741 skipped += 1
730 742 continue
731 743 counter += 1
732 744 if counter >= count:
733 745 break
734 746 else:
735 747 # if no break occured.
736 748 self.error(
737 749 "all frames above hidden, use `skip_hidden False` to get get into those."
738 750 )
739 751 return
740 752
741 753 Colors = self.color_scheme_table.active_colors
742 754 ColorsNormal = Colors.Normal
743 755 _newframe = i
744 756 self._select_frame(_newframe)
745 757 if skipped:
746 758 print(
747 759 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
748 760 )
749 761
750 762 def do_down(self, arg):
751 763 """d(own) [count]
752 764 Move the current frame count (default one) levels down in the
753 765 stack trace (to a newer frame).
754 766
755 767 Will skip hidden frames.
756 768 """
757 769 if self.curindex + 1 == len(self.stack):
758 770 self.error("Newest frame")
759 771 return
760 772 try:
761 773 count = int(arg or 1)
762 774 except ValueError:
763 775 self.error("Invalid frame count (%s)" % arg)
764 776 return
765 777 if count < 0:
766 778 _newframe = len(self.stack) - 1
767 779 else:
768 _newindex = self.curindex
769 780 counter = 0
770 781 skipped = 0
771 782 hidden_frames = self.hidden_frames(self.stack)
772 783 for i in range(self.curindex + 1, len(self.stack)):
773 frame = self.stack[i][0]
774 784 if hidden_frames[i] and self.skip_hidden:
775 785 skipped += 1
776 786 continue
777 787 counter += 1
778 788 if counter >= count:
779 789 break
780 790 else:
781 791 self.error(
782 792 "all frames bellow hidden, use `skip_hidden False` to get get into those."
783 793 )
784 794 return
785 795
786 796 Colors = self.color_scheme_table.active_colors
787 797 ColorsNormal = Colors.Normal
788 798 if skipped:
789 799 print(
790 800 f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
791 801 )
792 802 _newframe = i
793 803
794 804 self._select_frame(_newframe)
795 805
796 806 do_d = do_down
797 807 do_u = do_up
798 808
809 def do_context(self, context):
810 """context number_of_lines
811 Set the number of lines of source code to show when displaying
812 stacktrace information.
813 """
814 try:
815 new_context = int(context)
816 if new_context <= 0:
817 raise ValueError()
818 self.context = new_context
819 except ValueError:
820 self.error("The 'context' command requires a positive integer argument.")
821
822
799 823 class InterruptiblePdb(Pdb):
800 824 """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
801 825
802 826 def cmdloop(self):
803 827 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
804 828 try:
805 829 return OldPdb.cmdloop(self)
806 830 except KeyboardInterrupt:
807 831 self.stop_here = lambda frame: False
808 832 self.do_quit("")
809 833 sys.settrace(None)
810 834 self.quitting = False
811 835 raise
812 836
813 837 def _cmdloop(self):
814 838 while True:
815 839 try:
816 840 # keyboard interrupts allow for an easy way to cancel
817 841 # the current command, so allow them during interactive input
818 842 self.allow_kbdint = True
819 843 self.cmdloop()
820 844 self.allow_kbdint = False
821 845 break
822 846 except KeyboardInterrupt:
823 847 self.message('--KeyboardInterrupt--')
824 848 raise
825 849
826 850
827 851 def set_trace(frame=None):
828 852 """
829 853 Start debugging from `frame`.
830 854
831 855 If frame is not specified, debugging starts from caller's frame.
832 856 """
833 857 Pdb().set_trace(frame or sys._getframe().f_back)
@@ -1,1206 +1,1211 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Top-level display functions for displaying object in different formats."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 from binascii import b2a_base64, hexlify
9 9 import json
10 10 import mimetypes
11 11 import os
12 12 import struct
13 13 import warnings
14 14 from copy import deepcopy
15 15 from os.path import splitext
16 16 from pathlib import Path, PurePath
17 17
18 18 from IPython.utils.py3compat import cast_unicode
19 19 from IPython.testing.skipdoctest import skip_doctest
20 20 from . import display_functions
21 21
22 22
23 23 __all__ = ['display_pretty', 'display_html', 'display_markdown',
24 24 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
25 25 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
26 26 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
27 27 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats',
28 28 'set_matplotlib_close',
29 29 'Video']
30 30
31 31 _deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
32 32
33 33 __all__ = __all__ + _deprecated_names
34 34
35 35
36 36 # ----- warn to import from IPython.display -----
37 37
38 38 from warnings import warn
39 39
40 40
41 41 def __getattr__(name):
42 42 if name in _deprecated_names:
43 43 warn(f"Importing {name} from IPython.core.display is deprecated since IPython 7.14, please import from IPython display", DeprecationWarning, stacklevel=2)
44 44 return getattr(display_functions, name)
45 45
46 46 if name in globals().keys():
47 47 return globals()[name]
48 48 else:
49 49 raise AttributeError(f"module {__name__} has no attribute {name}")
50 50
51 51
52 52 #-----------------------------------------------------------------------------
53 53 # utility functions
54 54 #-----------------------------------------------------------------------------
55 55
56 56 def _safe_exists(path):
57 57 """Check path, but don't let exceptions raise"""
58 58 try:
59 59 return os.path.exists(path)
60 60 except Exception:
61 61 return False
62 62
63 63
64 64 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
65 65 """internal implementation of all display_foo methods
66 66
67 67 Parameters
68 68 ----------
69 69 mimetype : str
70 70 The mimetype to be published (e.g. 'image/png')
71 71 *objs : object
72 72 The Python objects to display, or if raw=True raw text data to
73 73 display.
74 74 raw : bool
75 75 Are the data objects raw data or Python objects that need to be
76 76 formatted before display? [default: False]
77 77 metadata : dict (optional)
78 78 Metadata to be associated with the specific mimetype output.
79 79 """
80 80 if metadata:
81 81 metadata = {mimetype: metadata}
82 82 if raw:
83 83 # turn list of pngdata into list of { 'image/png': pngdata }
84 84 objs = [ {mimetype: obj} for obj in objs ]
85 85 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
86 86
87 87 #-----------------------------------------------------------------------------
88 88 # Main functions
89 89 #-----------------------------------------------------------------------------
90 90
91 91
92 92 def display_pretty(*objs, **kwargs):
93 93 """Display the pretty (default) representation of an object.
94 94
95 95 Parameters
96 96 ----------
97 97 *objs : object
98 98 The Python objects to display, or if raw=True raw text data to
99 99 display.
100 100 raw : bool
101 101 Are the data objects raw data or Python objects that need to be
102 102 formatted before display? [default: False]
103 103 metadata : dict (optional)
104 104 Metadata to be associated with the specific mimetype output.
105 105 """
106 106 _display_mimetype('text/plain', objs, **kwargs)
107 107
108 108
109 109 def display_html(*objs, **kwargs):
110 110 """Display the HTML representation of an object.
111 111
112 112 Note: If raw=False and the object does not have a HTML
113 113 representation, no HTML will be shown.
114 114
115 115 Parameters
116 116 ----------
117 117 *objs : object
118 118 The Python objects to display, or if raw=True raw HTML data to
119 119 display.
120 120 raw : bool
121 121 Are the data objects raw data or Python objects that need to be
122 122 formatted before display? [default: False]
123 123 metadata : dict (optional)
124 124 Metadata to be associated with the specific mimetype output.
125 125 """
126 126 _display_mimetype('text/html', objs, **kwargs)
127 127
128 128
129 129 def display_markdown(*objs, **kwargs):
130 130 """Displays the Markdown representation of an object.
131 131
132 132 Parameters
133 133 ----------
134 134 *objs : object
135 135 The Python objects to display, or if raw=True raw markdown data to
136 136 display.
137 137 raw : bool
138 138 Are the data objects raw data or Python objects that need to be
139 139 formatted before display? [default: False]
140 140 metadata : dict (optional)
141 141 Metadata to be associated with the specific mimetype output.
142 142 """
143 143
144 144 _display_mimetype('text/markdown', objs, **kwargs)
145 145
146 146
147 147 def display_svg(*objs, **kwargs):
148 148 """Display the SVG representation of an object.
149 149
150 150 Parameters
151 151 ----------
152 152 *objs : object
153 153 The Python objects to display, or if raw=True raw svg data to
154 154 display.
155 155 raw : bool
156 156 Are the data objects raw data or Python objects that need to be
157 157 formatted before display? [default: False]
158 158 metadata : dict (optional)
159 159 Metadata to be associated with the specific mimetype output.
160 160 """
161 161 _display_mimetype('image/svg+xml', objs, **kwargs)
162 162
163 163
164 164 def display_png(*objs, **kwargs):
165 165 """Display the PNG representation of an object.
166 166
167 167 Parameters
168 168 ----------
169 169 *objs : object
170 170 The Python objects to display, or if raw=True raw png data to
171 171 display.
172 172 raw : bool
173 173 Are the data objects raw data or Python objects that need to be
174 174 formatted before display? [default: False]
175 175 metadata : dict (optional)
176 176 Metadata to be associated with the specific mimetype output.
177 177 """
178 178 _display_mimetype('image/png', objs, **kwargs)
179 179
180 180
181 181 def display_jpeg(*objs, **kwargs):
182 182 """Display the JPEG representation of an object.
183 183
184 184 Parameters
185 185 ----------
186 186 *objs : object
187 187 The Python objects to display, or if raw=True raw JPEG data to
188 188 display.
189 189 raw : bool
190 190 Are the data objects raw data or Python objects that need to be
191 191 formatted before display? [default: False]
192 192 metadata : dict (optional)
193 193 Metadata to be associated with the specific mimetype output.
194 194 """
195 195 _display_mimetype('image/jpeg', objs, **kwargs)
196 196
197 197
198 198 def display_latex(*objs, **kwargs):
199 199 """Display the LaTeX representation of an object.
200 200
201 201 Parameters
202 202 ----------
203 203 *objs : object
204 204 The Python objects to display, or if raw=True raw latex data to
205 205 display.
206 206 raw : bool
207 207 Are the data objects raw data or Python objects that need to be
208 208 formatted before display? [default: False]
209 209 metadata : dict (optional)
210 210 Metadata to be associated with the specific mimetype output.
211 211 """
212 212 _display_mimetype('text/latex', objs, **kwargs)
213 213
214 214
215 215 def display_json(*objs, **kwargs):
216 216 """Display the JSON representation of an object.
217 217
218 218 Note that not many frontends support displaying JSON.
219 219
220 220 Parameters
221 221 ----------
222 222 *objs : object
223 223 The Python objects to display, or if raw=True raw json data to
224 224 display.
225 225 raw : bool
226 226 Are the data objects raw data or Python objects that need to be
227 227 formatted before display? [default: False]
228 228 metadata : dict (optional)
229 229 Metadata to be associated with the specific mimetype output.
230 230 """
231 231 _display_mimetype('application/json', objs, **kwargs)
232 232
233 233
234 234 def display_javascript(*objs, **kwargs):
235 235 """Display the Javascript representation of an object.
236 236
237 237 Parameters
238 238 ----------
239 239 *objs : object
240 240 The Python objects to display, or if raw=True raw javascript data to
241 241 display.
242 242 raw : bool
243 243 Are the data objects raw data or Python objects that need to be
244 244 formatted before display? [default: False]
245 245 metadata : dict (optional)
246 246 Metadata to be associated with the specific mimetype output.
247 247 """
248 248 _display_mimetype('application/javascript', objs, **kwargs)
249 249
250 250
251 251 def display_pdf(*objs, **kwargs):
252 252 """Display the PDF representation of an object.
253 253
254 254 Parameters
255 255 ----------
256 256 *objs : object
257 257 The Python objects to display, or if raw=True raw javascript data to
258 258 display.
259 259 raw : bool
260 260 Are the data objects raw data or Python objects that need to be
261 261 formatted before display? [default: False]
262 262 metadata : dict (optional)
263 263 Metadata to be associated with the specific mimetype output.
264 264 """
265 265 _display_mimetype('application/pdf', objs, **kwargs)
266 266
267 267
268 268 #-----------------------------------------------------------------------------
269 269 # Smart classes
270 270 #-----------------------------------------------------------------------------
271 271
272 272
273 273 class DisplayObject(object):
274 274 """An object that wraps data to be displayed."""
275 275
276 276 _read_flags = 'r'
277 277 _show_mem_addr = False
278 278 metadata = None
279 279
280 280 def __init__(self, data=None, url=None, filename=None, metadata=None):
281 281 """Create a display object given raw data.
282 282
283 283 When this object is returned by an expression or passed to the
284 284 display function, it will result in the data being displayed
285 285 in the frontend. The MIME type of the data should match the
286 286 subclasses used, so the Png subclass should be used for 'image/png'
287 287 data. If the data is a URL, the data will first be downloaded
288 288 and then displayed. If
289 289
290 290 Parameters
291 291 ----------
292 292 data : unicode, str or bytes
293 293 The raw data or a URL or file to load the data from
294 294 url : unicode
295 295 A URL to download the data from.
296 296 filename : unicode
297 297 Path to a local file to load the data from.
298 298 metadata : dict
299 299 Dict of metadata associated to be the object when displayed
300 300 """
301 301 if isinstance(data, (Path, PurePath)):
302 302 data = str(data)
303 303
304 304 if data is not None and isinstance(data, str):
305 305 if data.startswith('http') and url is None:
306 306 url = data
307 307 filename = None
308 308 data = None
309 309 elif _safe_exists(data) and filename is None:
310 310 url = None
311 311 filename = data
312 312 data = None
313 313
314 314 self.url = url
315 315 self.filename = filename
316 316 # because of @data.setter methods in
317 317 # subclasses ensure url and filename are set
318 318 # before assigning to self.data
319 319 self.data = data
320 320
321 321 if metadata is not None:
322 322 self.metadata = metadata
323 323 elif self.metadata is None:
324 324 self.metadata = {}
325 325
326 326 self.reload()
327 327 self._check_data()
328 328
329 329 def __repr__(self):
330 330 if not self._show_mem_addr:
331 331 cls = self.__class__
332 332 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
333 333 else:
334 334 r = super(DisplayObject, self).__repr__()
335 335 return r
336 336
337 337 def _check_data(self):
338 338 """Override in subclasses if there's something to check."""
339 339 pass
340 340
341 341 def _data_and_metadata(self):
342 342 """shortcut for returning metadata with shape information, if defined"""
343 343 if self.metadata:
344 344 return self.data, deepcopy(self.metadata)
345 345 else:
346 346 return self.data
347 347
348 348 def reload(self):
349 349 """Reload the raw data from file or URL."""
350 350 if self.filename is not None:
351 351 with open(self.filename, self._read_flags) as f:
352 352 self.data = f.read()
353 353 elif self.url is not None:
354 354 # Deferred import
355 355 from urllib.request import urlopen
356 356 response = urlopen(self.url)
357 357 data = response.read()
358 358 # extract encoding from header, if there is one:
359 359 encoding = None
360 360 if 'content-type' in response.headers:
361 361 for sub in response.headers['content-type'].split(';'):
362 362 sub = sub.strip()
363 363 if sub.startswith('charset'):
364 364 encoding = sub.split('=')[-1].strip()
365 365 break
366 366 if 'content-encoding' in response.headers:
367 367 # TODO: do deflate?
368 368 if 'gzip' in response.headers['content-encoding']:
369 369 import gzip
370 370 from io import BytesIO
371 371 with gzip.open(BytesIO(data), 'rt', encoding=encoding) as fp:
372 372 encoding = None
373 373 data = fp.read()
374 374
375 375 # decode data, if an encoding was specified
376 376 # We only touch self.data once since
377 377 # subclasses such as SVG have @data.setter methods
378 378 # that transform self.data into ... well svg.
379 379 if encoding:
380 380 self.data = data.decode(encoding, 'replace')
381 381 else:
382 382 self.data = data
383 383
384 384
385 385 class TextDisplayObject(DisplayObject):
386 386 """Validate that display data is text"""
387 387 def _check_data(self):
388 388 if self.data is not None and not isinstance(self.data, str):
389 389 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
390 390
391 391 class Pretty(TextDisplayObject):
392 392
393 393 def _repr_pretty_(self, pp, cycle):
394 394 return pp.text(self.data)
395 395
396 396
397 397 class HTML(TextDisplayObject):
398 398
399 399 def __init__(self, data=None, url=None, filename=None, metadata=None):
400 400 def warn():
401 401 if not data:
402 402 return False
403 403
404 404 #
405 405 # Avoid calling lower() on the entire data, because it could be a
406 406 # long string and we're only interested in its beginning and end.
407 407 #
408 408 prefix = data[:10].lower()
409 409 suffix = data[-10:].lower()
410 410 return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
411 411
412 412 if warn():
413 413 warnings.warn("Consider using IPython.display.IFrame instead")
414 414 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
415 415
416 416 def _repr_html_(self):
417 417 return self._data_and_metadata()
418 418
419 419 def __html__(self):
420 420 """
421 421 This method exists to inform other HTML-using modules (e.g. Markupsafe,
422 422 htmltag, etc) that this object is HTML and does not need things like
423 423 special characters (<>&) escaped.
424 424 """
425 425 return self._repr_html_()
426 426
427 427
428 428 class Markdown(TextDisplayObject):
429 429
430 430 def _repr_markdown_(self):
431 431 return self._data_and_metadata()
432 432
433 433
434 434 class Math(TextDisplayObject):
435 435
436 436 def _repr_latex_(self):
437 437 s = r"$\displaystyle %s$" % self.data.strip('$')
438 438 if self.metadata:
439 439 return s, deepcopy(self.metadata)
440 440 else:
441 441 return s
442 442
443 443
444 444 class Latex(TextDisplayObject):
445 445
446 446 def _repr_latex_(self):
447 447 return self._data_and_metadata()
448 448
449 449
450 450 class SVG(DisplayObject):
451 451 """Embed an SVG into the display.
452 452
453 453 Note if you just want to view a svg image via a URL use `:class:Image` with
454 454 a url=URL keyword argument.
455 455 """
456 456
457 457 _read_flags = 'rb'
458 458 # wrap data in a property, which extracts the <svg> tag, discarding
459 459 # document headers
460 460 _data = None
461 461
462 462 @property
463 463 def data(self):
464 464 return self._data
465 465
466 466 @data.setter
467 467 def data(self, svg):
468 468 if svg is None:
469 469 self._data = None
470 470 return
471 471 # parse into dom object
472 472 from xml.dom import minidom
473 473 x = minidom.parseString(svg)
474 474 # get svg tag (should be 1)
475 475 found_svg = x.getElementsByTagName('svg')
476 476 if found_svg:
477 477 svg = found_svg[0].toxml()
478 478 else:
479 479 # fallback on the input, trust the user
480 480 # but this is probably an error.
481 481 pass
482 482 svg = cast_unicode(svg)
483 483 self._data = svg
484 484
485 485 def _repr_svg_(self):
486 486 return self._data_and_metadata()
487 487
488 488 class ProgressBar(DisplayObject):
489 489 """Progressbar supports displaying a progressbar like element
490 490 """
491 491 def __init__(self, total):
492 492 """Creates a new progressbar
493 493
494 494 Parameters
495 495 ----------
496 496 total : int
497 497 maximum size of the progressbar
498 498 """
499 499 self.total = total
500 500 self._progress = 0
501 501 self.html_width = '60ex'
502 502 self.text_width = 60
503 503 self._display_id = hexlify(os.urandom(8)).decode('ascii')
504 504
505 505 def __repr__(self):
506 506 fraction = self.progress / self.total
507 507 filled = '=' * int(fraction * self.text_width)
508 508 rest = ' ' * (self.text_width - len(filled))
509 509 return '[{}{}] {}/{}'.format(
510 510 filled, rest,
511 511 self.progress, self.total,
512 512 )
513 513
514 514 def _repr_html_(self):
515 515 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
516 516 self.html_width, self.total, self.progress)
517 517
518 518 def display(self):
519 519 display(self, display_id=self._display_id)
520 520
521 521 def update(self):
522 522 display(self, display_id=self._display_id, update=True)
523 523
524 524 @property
525 525 def progress(self):
526 526 return self._progress
527 527
528 528 @progress.setter
529 529 def progress(self, value):
530 530 self._progress = value
531 531 self.update()
532 532
533 533 def __iter__(self):
534 534 self.display()
535 535 self._progress = -1 # First iteration is 0
536 536 return self
537 537
538 538 def __next__(self):
539 539 """Returns current value and increments display by one."""
540 540 self.progress += 1
541 541 if self.progress < self.total:
542 542 return self.progress
543 543 else:
544 544 raise StopIteration()
545 545
546 546 class JSON(DisplayObject):
547 547 """JSON expects a JSON-able dict or list
548 548
549 549 not an already-serialized JSON string.
550 550
551 551 Scalar types (None, number, string) are not allowed, only dict or list containers.
552 552 """
553 553 # wrap data in a property, which warns about passing already-serialized JSON
554 554 _data = None
555 555 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
556 556 """Create a JSON display object given raw data.
557 557
558 558 Parameters
559 559 ----------
560 560 data : dict or list
561 561 JSON data to display. Not an already-serialized JSON string.
562 562 Scalar types (None, number, string) are not allowed, only dict
563 563 or list containers.
564 564 url : unicode
565 565 A URL to download the data from.
566 566 filename : unicode
567 567 Path to a local file to load the data from.
568 568 expanded : boolean
569 569 Metadata to control whether a JSON display component is expanded.
570 570 metadata: dict
571 571 Specify extra metadata to attach to the json display object.
572 572 root : str
573 573 The name of the root element of the JSON tree
574 574 """
575 575 self.metadata = {
576 576 'expanded': expanded,
577 577 'root': root,
578 578 }
579 579 if metadata:
580 580 self.metadata.update(metadata)
581 581 if kwargs:
582 582 self.metadata.update(kwargs)
583 583 super(JSON, self).__init__(data=data, url=url, filename=filename)
584 584
585 585 def _check_data(self):
586 586 if self.data is not None and not isinstance(self.data, (dict, list)):
587 587 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
588 588
589 589 @property
590 590 def data(self):
591 591 return self._data
592 592
593 593 @data.setter
594 594 def data(self, data):
595 595 if isinstance(data, (Path, PurePath)):
596 596 data = str(data)
597 597
598 598 if isinstance(data, str):
599 599 if self.filename is None and self.url is None:
600 600 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
601 601 data = json.loads(data)
602 602 self._data = data
603 603
604 604 def _data_and_metadata(self):
605 605 return self.data, self.metadata
606 606
607 607 def _repr_json_(self):
608 608 return self._data_and_metadata()
609 609
610 610 _css_t = """var link = document.createElement("link");
611 611 link.ref = "stylesheet";
612 612 link.type = "text/css";
613 613 link.href = "%s";
614 614 document.head.appendChild(link);
615 615 """
616 616
617 617 _lib_t1 = """new Promise(function(resolve, reject) {
618 618 var script = document.createElement("script");
619 619 script.onload = resolve;
620 620 script.onerror = reject;
621 621 script.src = "%s";
622 622 document.head.appendChild(script);
623 623 }).then(() => {
624 624 """
625 625
626 626 _lib_t2 = """
627 627 });"""
628 628
629 629 class GeoJSON(JSON):
630 630 """GeoJSON expects JSON-able dict
631 631
632 632 not an already-serialized JSON string.
633 633
634 634 Scalar types (None, number, string) are not allowed, only dict containers.
635 635 """
636 636
637 637 def __init__(self, *args, **kwargs):
638 638 """Create a GeoJSON display object given raw data.
639 639
640 640 Parameters
641 641 ----------
642 642 data : dict or list
643 643 VegaLite data. Not an already-serialized JSON string.
644 644 Scalar types (None, number, string) are not allowed, only dict
645 645 or list containers.
646 646 url_template : string
647 647 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
648 648 layer_options : dict
649 649 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
650 650 url : unicode
651 651 A URL to download the data from.
652 652 filename : unicode
653 653 Path to a local file to load the data from.
654 654 metadata: dict
655 655 Specify extra metadata to attach to the json display object.
656 656
657 657 Examples
658 658 --------
659
660 659 The following will display an interactive map of Mars with a point of
661 660 interest on frontend that do support GeoJSON display.
662 661
663 662 >>> from IPython.display import GeoJSON
664 663
665 664 >>> GeoJSON(data={
666 665 ... "type": "Feature",
667 666 ... "geometry": {
668 667 ... "type": "Point",
669 668 ... "coordinates": [-81.327, 296.038]
670 669 ... }
671 670 ... },
672 671 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
673 672 ... layer_options={
674 673 ... "basemap_id": "celestia_mars-shaded-16k_global",
675 674 ... "attribution" : "Celestia/praesepe",
676 675 ... "minZoom" : 0,
677 676 ... "maxZoom" : 18,
678 677 ... })
679 678 <IPython.core.display.GeoJSON object>
680 679
681 680 In the terminal IPython, you will only see the text representation of
682 681 the GeoJSON object.
683 682
684 683 """
685 684
686 685 super(GeoJSON, self).__init__(*args, **kwargs)
687 686
688 687
689 688 def _ipython_display_(self):
690 689 bundle = {
691 690 'application/geo+json': self.data,
692 691 'text/plain': '<IPython.display.GeoJSON object>'
693 692 }
694 693 metadata = {
695 694 'application/geo+json': self.metadata
696 695 }
697 696 display(bundle, metadata=metadata, raw=True)
698 697
699 698 class Javascript(TextDisplayObject):
700 699
701 700 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
702 701 """Create a Javascript display object given raw data.
703 702
704 703 When this object is returned by an expression or passed to the
705 704 display function, it will result in the data being displayed
706 705 in the frontend. If the data is a URL, the data will first be
707 706 downloaded and then displayed.
708 707
709 708 In the Notebook, the containing element will be available as `element`,
710 709 and jQuery will be available. Content appended to `element` will be
711 710 visible in the output area.
712 711
713 712 Parameters
714 713 ----------
715 714 data : unicode, str or bytes
716 715 The Javascript source code or a URL to download it from.
717 716 url : unicode
718 717 A URL to download the data from.
719 718 filename : unicode
720 719 Path to a local file to load the data from.
721 720 lib : list or str
722 721 A sequence of Javascript library URLs to load asynchronously before
723 722 running the source code. The full URLs of the libraries should
724 723 be given. A single Javascript library URL can also be given as a
725 724 string.
726 css: : list or str
725 css : list or str
727 726 A sequence of css files to load before running the source code.
728 727 The full URLs of the css files should be given. A single css URL
729 728 can also be given as a string.
730 729 """
731 730 if isinstance(lib, str):
732 731 lib = [lib]
733 732 elif lib is None:
734 733 lib = []
735 734 if isinstance(css, str):
736 735 css = [css]
737 736 elif css is None:
738 737 css = []
739 738 if not isinstance(lib, (list,tuple)):
740 739 raise TypeError('expected sequence, got: %r' % lib)
741 740 if not isinstance(css, (list,tuple)):
742 741 raise TypeError('expected sequence, got: %r' % css)
743 742 self.lib = lib
744 743 self.css = css
745 744 super(Javascript, self).__init__(data=data, url=url, filename=filename)
746 745
747 746 def _repr_javascript_(self):
748 747 r = ''
749 748 for c in self.css:
750 749 r += _css_t % c
751 750 for l in self.lib:
752 751 r += _lib_t1 % l
753 752 r += self.data
754 753 r += _lib_t2*len(self.lib)
755 754 return r
756 755
757 756 # constants for identifying png/jpeg data
758 757 _PNG = b'\x89PNG\r\n\x1a\n'
759 758 _JPEG = b'\xff\xd8'
760 759
761 760 def _pngxy(data):
762 761 """read the (width, height) from a PNG header"""
763 762 ihdr = data.index(b'IHDR')
764 763 # next 8 bytes are width/height
765 764 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
766 765
767 766 def _jpegxy(data):
768 767 """read the (width, height) from a JPEG header"""
769 768 # adapted from http://www.64lines.com/jpeg-width-height
770 769
771 770 idx = 4
772 771 while True:
773 772 block_size = struct.unpack('>H', data[idx:idx+2])[0]
774 773 idx = idx + block_size
775 774 if data[idx:idx+2] == b'\xFF\xC0':
776 775 # found Start of Frame
777 776 iSOF = idx
778 777 break
779 778 else:
780 779 # read another block
781 780 idx += 2
782 781
783 782 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
784 783 return w, h
785 784
786 785 def _gifxy(data):
787 786 """read the (width, height) from a GIF header"""
788 787 return struct.unpack('<HH', data[6:10])
789 788
790 789
791 790 class Image(DisplayObject):
792 791
793 792 _read_flags = 'rb'
794 793 _FMT_JPEG = u'jpeg'
795 794 _FMT_PNG = u'png'
796 795 _FMT_GIF = u'gif'
797 796 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
798 797 _MIMETYPES = {
799 798 _FMT_PNG: 'image/png',
800 799 _FMT_JPEG: 'image/jpeg',
801 800 _FMT_GIF: 'image/gif',
802 801 }
803 802
804 803 def __init__(self, data=None, url=None, filename=None, format=None,
805 804 embed=None, width=None, height=None, retina=False,
806 805 unconfined=False, metadata=None):
807 806 """Create a PNG/JPEG/GIF image object given raw data.
808 807
809 808 When this object is returned by an input cell or passed to the
810 809 display function, it will result in the image being displayed
811 810 in the frontend.
812 811
813 812 Parameters
814 813 ----------
815 814 data : unicode, str or bytes
816 815 The raw image data or a URL or filename to load the data from.
817 816 This always results in embedded image data.
818 817 url : unicode
819 818 A URL to download the data from. If you specify `url=`,
820 819 the image data will not be embedded unless you also specify `embed=True`.
821 820 filename : unicode
822 821 Path to a local file to load the data from.
823 822 Images from a file are always embedded.
824 823 format : unicode
825 824 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
826 825 for format will be inferred from the filename extension.
827 826 embed : bool
828 827 Should the image data be embedded using a data URI (True) or be
829 828 loaded using an <img> tag. Set this to True if you want the image
830 829 to be viewable later with no internet connection in the notebook.
831 830
832 831 Default is `True`, unless the keyword argument `url` is set, then
833 832 default value is `False`.
834 833
835 834 Note that QtConsole is not able to display images if `embed` is set to `False`
836 835 width : int
837 836 Width in pixels to which to constrain the image in html
838 837 height : int
839 838 Height in pixels to which to constrain the image in html
840 839 retina : bool
841 840 Automatically set the width and height to half of the measured
842 841 width and height.
843 842 This only works for embedded images because it reads the width/height
844 843 from image data.
845 844 For non-embedded images, you can just set the desired display width
846 845 and height directly.
847 846 unconfined: bool
848 847 Set unconfined=True to disable max-width confinement of the image.
849 848 metadata: dict
850 849 Specify extra metadata to attach to the image.
851 850
852 851 Examples
853 852 --------
854 # embedded image data, works in qtconsole and notebook
855 # when passed positionally, the first arg can be any of raw image data,
856 # a URL, or a filename from which to load image data.
857 # The result is always embedding image data for inline images.
858 Image('http://www.google.fr/images/srpr/logo3w.png')
859 Image('/path/to/image.jpg')
860 Image(b'RAW_PNG_DATA...')
861
862 # Specifying Image(url=...) does not embed the image data,
863 # it only generates `<img>` tag with a link to the source.
864 # This will not work in the qtconsole or offline.
865 Image(url='http://www.google.fr/images/srpr/logo3w.png')
853 embedded image data, works in qtconsole and notebook
854 when passed positionally, the first arg can be any of raw image data,
855 a URL, or a filename from which to load image data.
856 The result is always embedding image data for inline images.
857
858 >>> Image('http://www.google.fr/images/srpr/logo3w.png')
859 <IPython.core.display.Image object>
860
861 >>> Image('/path/to/image.jpg')
862 <IPython.core.display.Image object>
863
864 >>> Image(b'RAW_PNG_DATA...')
865 <IPython.core.display.Image object>
866
867 Specifying Image(url=...) does not embed the image data,
868 it only generates ``<img>`` tag with a link to the source.
869 This will not work in the qtconsole or offline.
870
871 >>> Image(url='http://www.google.fr/images/srpr/logo3w.png')
872 <IPython.core.display.Image object>
866 873
867 874 """
868 875 if isinstance(data, (Path, PurePath)):
869 876 data = str(data)
870 877
871 878 if filename is not None:
872 879 ext = self._find_ext(filename)
873 880 elif url is not None:
874 881 ext = self._find_ext(url)
875 882 elif data is None:
876 883 raise ValueError("No image data found. Expecting filename, url, or data.")
877 884 elif isinstance(data, str) and (
878 885 data.startswith('http') or _safe_exists(data)
879 886 ):
880 887 ext = self._find_ext(data)
881 888 else:
882 889 ext = None
883 890
884 891 if format is None:
885 892 if ext is not None:
886 893 if ext == u'jpg' or ext == u'jpeg':
887 894 format = self._FMT_JPEG
888 895 elif ext == u'png':
889 896 format = self._FMT_PNG
890 897 elif ext == u'gif':
891 898 format = self._FMT_GIF
892 899 else:
893 900 format = ext.lower()
894 901 elif isinstance(data, bytes):
895 902 # infer image type from image data header,
896 903 # only if format has not been specified.
897 904 if data[:2] == _JPEG:
898 905 format = self._FMT_JPEG
899 906
900 907 # failed to detect format, default png
901 908 if format is None:
902 909 format = self._FMT_PNG
903 910
904 911 if format.lower() == 'jpg':
905 912 # jpg->jpeg
906 913 format = self._FMT_JPEG
907 914
908 915 self.format = format.lower()
909 916 self.embed = embed if embed is not None else (url is None)
910 917
911 918 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
912 919 raise ValueError("Cannot embed the '%s' image format" % (self.format))
913 920 if self.embed:
914 921 self._mimetype = self._MIMETYPES.get(self.format)
915 922
916 923 self.width = width
917 924 self.height = height
918 925 self.retina = retina
919 926 self.unconfined = unconfined
920 927 super(Image, self).__init__(data=data, url=url, filename=filename,
921 928 metadata=metadata)
922 929
923 930 if self.width is None and self.metadata.get('width', {}):
924 931 self.width = metadata['width']
925 932
926 933 if self.height is None and self.metadata.get('height', {}):
927 934 self.height = metadata['height']
928 935
929 936 if retina:
930 937 self._retina_shape()
931 938
932 939
933 940 def _retina_shape(self):
934 941 """load pixel-doubled width and height from image data"""
935 942 if not self.embed:
936 943 return
937 944 if self.format == self._FMT_PNG:
938 945 w, h = _pngxy(self.data)
939 946 elif self.format == self._FMT_JPEG:
940 947 w, h = _jpegxy(self.data)
941 948 elif self.format == self._FMT_GIF:
942 949 w, h = _gifxy(self.data)
943 950 else:
944 951 # retina only supports png
945 952 return
946 953 self.width = w // 2
947 954 self.height = h // 2
948 955
949 956 def reload(self):
950 957 """Reload the raw data from file or URL."""
951 958 if self.embed:
952 959 super(Image,self).reload()
953 960 if self.retina:
954 961 self._retina_shape()
955 962
956 963 def _repr_html_(self):
957 964 if not self.embed:
958 965 width = height = klass = ''
959 966 if self.width:
960 967 width = ' width="%d"' % self.width
961 968 if self.height:
962 969 height = ' height="%d"' % self.height
963 970 if self.unconfined:
964 971 klass = ' class="unconfined"'
965 972 return u'<img src="{url}"{width}{height}{klass}/>'.format(
966 973 url=self.url,
967 974 width=width,
968 975 height=height,
969 976 klass=klass,
970 977 )
971 978
972 979 def _repr_mimebundle_(self, include=None, exclude=None):
973 980 """Return the image as a mimebundle
974 981
975 982 Any new mimetype support should be implemented here.
976 983 """
977 984 if self.embed:
978 985 mimetype = self._mimetype
979 986 data, metadata = self._data_and_metadata(always_both=True)
980 987 if metadata:
981 988 metadata = {mimetype: metadata}
982 989 return {mimetype: data}, metadata
983 990 else:
984 991 return {'text/html': self._repr_html_()}
985 992
986 993 def _data_and_metadata(self, always_both=False):
987 994 """shortcut for returning metadata with shape information, if defined"""
988 995 try:
989 996 b64_data = b2a_base64(self.data).decode('ascii')
990 997 except TypeError as e:
991 998 raise FileNotFoundError(
992 999 "No such file or directory: '%s'" % (self.data)) from e
993 1000 md = {}
994 1001 if self.metadata:
995 1002 md.update(self.metadata)
996 1003 if self.width:
997 1004 md['width'] = self.width
998 1005 if self.height:
999 1006 md['height'] = self.height
1000 1007 if self.unconfined:
1001 1008 md['unconfined'] = self.unconfined
1002 1009 if md or always_both:
1003 1010 return b64_data, md
1004 1011 else:
1005 1012 return b64_data
1006 1013
1007 1014 def _repr_png_(self):
1008 1015 if self.embed and self.format == self._FMT_PNG:
1009 1016 return self._data_and_metadata()
1010 1017
1011 1018 def _repr_jpeg_(self):
1012 1019 if self.embed and self.format == self._FMT_JPEG:
1013 1020 return self._data_and_metadata()
1014 1021
1015 1022 def _find_ext(self, s):
1016 1023 base, ext = splitext(s)
1017 1024
1018 1025 if not ext:
1019 1026 return base
1020 1027
1021 1028 # `splitext` includes leading period, so we skip it
1022 1029 return ext[1:].lower()
1023 1030
1024 1031
1025 1032 class Video(DisplayObject):
1026 1033
1027 1034 def __init__(self, data=None, url=None, filename=None, embed=False,
1028 1035 mimetype=None, width=None, height=None, html_attributes="controls"):
1029 1036 """Create a video object given raw data or an URL.
1030 1037
1031 1038 When this object is returned by an input cell or passed to the
1032 1039 display function, it will result in the video being displayed
1033 1040 in the frontend.
1034 1041
1035 1042 Parameters
1036 1043 ----------
1037 1044 data : unicode, str or bytes
1038 1045 The raw video data or a URL or filename to load the data from.
1039 Raw data will require passing `embed=True`.
1046 Raw data will require passing ``embed=True``.
1040 1047 url : unicode
1041 A URL for the video. If you specify `url=`,
1048 A URL for the video. If you specify ``url=``,
1042 1049 the image data will not be embedded.
1043 1050 filename : unicode
1044 1051 Path to a local file containing the video.
1045 Will be interpreted as a local URL unless `embed=True`.
1052 Will be interpreted as a local URL unless ``embed=True``.
1046 1053 embed : bool
1047 1054 Should the video be embedded using a data URI (True) or be
1048 1055 loaded using a <video> tag (False).
1049 1056
1050 1057 Since videos are large, embedding them should be avoided, if possible.
1051 You must confirm embedding as your intention by passing `embed=True`.
1058 You must confirm embedding as your intention by passing ``embed=True``.
1052 1059
1053 1060 Local files can be displayed with URLs without embedding the content, via::
1054 1061
1055 1062 Video('./video.mp4')
1056
1057 1063 mimetype: unicode
1058 1064 Specify the mimetype for embedded videos.
1059 1065 Default will be guessed from file extension, if available.
1060 1066 width : int
1061 1067 Width in pixels to which to constrain the video in HTML.
1062 1068 If not supplied, defaults to the width of the video.
1063 1069 height : int
1064 1070 Height in pixels to which to constrain the video in html.
1065 1071 If not supplied, defaults to the height of the video.
1066 1072 html_attributes : str
1067 Attributes for the HTML `<video>` block.
1068 Default: `"controls"` to get video controls.
1069 Other examples: `"controls muted"` for muted video with controls,
1070 `"loop autoplay"` for looping autoplaying video without controls.
1073 Attributes for the HTML ``<video>`` block.
1074 Default: ``"controls"`` to get video controls.
1075 Other examples: ``"controls muted"`` for muted video with controls,
1076 ``"loop autoplay"`` for looping autoplaying video without controls.
1071 1077
1072 1078 Examples
1073 1079 --------
1074
1075 1080 ::
1076 1081
1077 1082 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1078 1083 Video('path/to/video.mp4')
1079 1084 Video('path/to/video.mp4', embed=True)
1080 1085 Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
1081 1086 Video(b'raw-videodata', embed=True)
1082 1087 """
1083 1088 if isinstance(data, (Path, PurePath)):
1084 1089 data = str(data)
1085 1090
1086 1091 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1087 1092 url = data
1088 1093 data = None
1089 1094 elif data is not None and os.path.exists(data):
1090 1095 filename = data
1091 1096 data = None
1092 1097
1093 1098 if data and not embed:
1094 1099 msg = ''.join([
1095 1100 "To embed videos, you must pass embed=True ",
1096 1101 "(this may make your notebook files huge)\n",
1097 1102 "Consider passing Video(url='...')",
1098 1103 ])
1099 1104 raise ValueError(msg)
1100 1105
1101 1106 self.mimetype = mimetype
1102 1107 self.embed = embed
1103 1108 self.width = width
1104 1109 self.height = height
1105 1110 self.html_attributes = html_attributes
1106 1111 super(Video, self).__init__(data=data, url=url, filename=filename)
1107 1112
1108 1113 def _repr_html_(self):
1109 1114 width = height = ''
1110 1115 if self.width:
1111 1116 width = ' width="%d"' % self.width
1112 1117 if self.height:
1113 1118 height = ' height="%d"' % self.height
1114 1119
1115 1120 # External URLs and potentially local files are not embedded into the
1116 1121 # notebook output.
1117 1122 if not self.embed:
1118 1123 url = self.url if self.url is not None else self.filename
1119 1124 output = """<video src="{0}" {1} {2} {3}>
1120 1125 Your browser does not support the <code>video</code> element.
1121 1126 </video>""".format(url, self.html_attributes, width, height)
1122 1127 return output
1123 1128
1124 1129 # Embedded videos are base64-encoded.
1125 1130 mimetype = self.mimetype
1126 1131 if self.filename is not None:
1127 1132 if not mimetype:
1128 1133 mimetype, _ = mimetypes.guess_type(self.filename)
1129 1134
1130 1135 with open(self.filename, 'rb') as f:
1131 1136 video = f.read()
1132 1137 else:
1133 1138 video = self.data
1134 1139 if isinstance(video, str):
1135 1140 # unicode input is already b64-encoded
1136 1141 b64_video = video
1137 1142 else:
1138 1143 b64_video = b2a_base64(video).decode('ascii').rstrip()
1139 1144
1140 1145 output = """<video {0} {1} {2}>
1141 1146 <source src="data:{3};base64,{4}" type="{3}">
1142 1147 Your browser does not support the video tag.
1143 1148 </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
1144 1149 return output
1145 1150
1146 1151 def reload(self):
1147 1152 # TODO
1148 1153 pass
1149 1154
1150 1155
1151 1156 @skip_doctest
1152 1157 def set_matplotlib_formats(*formats, **kwargs):
1153 1158 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1154 1159
1155 1160 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1156 1161
1157 1162 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1158 1163
1159 1164 To set this in your config files use the following::
1160 1165
1161 1166 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1162 1167 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1163 1168
1164 1169 Parameters
1165 1170 ----------
1166 1171 *formats : strs
1167 1172 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1168 **kwargs :
1173 **kwargs
1169 1174 Keyword args will be relayed to ``figure.canvas.print_figure``.
1170 1175 """
1171 1176 from IPython.core.interactiveshell import InteractiveShell
1172 1177 from IPython.core.pylabtools import select_figure_formats
1173 1178 # build kwargs, starting with InlineBackend config
1174 1179 kw = {}
1175 1180 from ipykernel.pylab.config import InlineBackend
1176 1181 cfg = InlineBackend.instance()
1177 1182 kw.update(cfg.print_figure_kwargs)
1178 1183 kw.update(**kwargs)
1179 1184 shell = InteractiveShell.instance()
1180 1185 select_figure_formats(shell, formats, **kw)
1181 1186
1182 1187 @skip_doctest
1183 1188 def set_matplotlib_close(close=True):
1184 1189 """Set whether the inline backend closes all figures automatically or not.
1185 1190
1186 1191 By default, the inline backend used in the IPython Notebook will close all
1187 1192 matplotlib figures automatically after each cell is run. This means that
1188 1193 plots in different cells won't interfere. Sometimes, you may want to make
1189 1194 a plot in one cell and then refine it in later cells. This can be accomplished
1190 1195 by::
1191 1196
1192 1197 In [1]: set_matplotlib_close(False)
1193 1198
1194 1199 To set this in your config files use the following::
1195 1200
1196 1201 c.InlineBackend.close_figures = False
1197 1202
1198 1203 Parameters
1199 1204 ----------
1200 1205 close : bool
1201 1206 Should all matplotlib figures be automatically closed after each cell is
1202 1207 run?
1203 1208 """
1204 1209 from ipykernel.pylab.config import InlineBackend
1205 1210 cfg = InlineBackend.instance()
1206 1211 cfg.close_figures = close
@@ -1,729 +1,752 b''
1 1 """Input transformer machinery to support IPython special syntax.
2 2
3 3 This includes the machinery to recognise and transform ``%magic`` commands,
4 4 ``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
5 5
6 6 Added: IPython 7.0. Replaces inputsplitter and inputtransformer which were
7 7 deprecated in 7.0.
8 8 """
9 9
10 10 # Copyright (c) IPython Development Team.
11 11 # Distributed under the terms of the Modified BSD License.
12 12
13 13 from codeop import compile_command
14 14 import re
15 15 import tokenize
16 16 from typing import List, Tuple, Optional, Any
17 17 import warnings
18 18
19 19 _indent_re = re.compile(r'^[ \t]+')
20 20
21 21 def leading_empty_lines(lines):
22 22 """Remove leading empty lines
23 23
24 24 If the leading lines are empty or contain only whitespace, they will be
25 25 removed.
26 26 """
27 27 if not lines:
28 28 return lines
29 29 for i, line in enumerate(lines):
30 30 if line and not line.isspace():
31 31 return lines[i:]
32 32 return lines
33 33
34 34 def leading_indent(lines):
35 35 """Remove leading indentation.
36 36
37 37 If the first line starts with a spaces or tabs, the same whitespace will be
38 38 removed from each following line in the cell.
39 39 """
40 40 if not lines:
41 41 return lines
42 42 m = _indent_re.match(lines[0])
43 43 if not m:
44 44 return lines
45 45 space = m.group(0)
46 46 n = len(space)
47 47 return [l[n:] if l.startswith(space) else l
48 48 for l in lines]
49 49
50 50 class PromptStripper:
51 51 """Remove matching input prompts from a block of input.
52 52
53 53 Parameters
54 54 ----------
55 55 prompt_re : regular expression
56 56 A regular expression matching any input prompt (including continuation,
57 57 e.g. ``...``)
58 58 initial_re : regular expression, optional
59 59 A regular expression matching only the initial prompt, but not continuation.
60 60 If no initial expression is given, prompt_re will be used everywhere.
61 61 Used mainly for plain Python prompts (``>>>``), where the continuation prompt
62 62 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
63 63
64 64 Notes
65 65 -----
66 66
67 67 If initial_re and prompt_re differ,
68 68 only initial_re will be tested against the first line.
69 69 If any prompt is found on the first two lines,
70 70 prompts will be stripped from the rest of the block.
71 71 """
72 72 def __init__(self, prompt_re, initial_re=None):
73 73 self.prompt_re = prompt_re
74 74 self.initial_re = initial_re or prompt_re
75 75
76 76 def _strip(self, lines):
77 77 return [self.prompt_re.sub('', l, count=1) for l in lines]
78 78
79 79 def __call__(self, lines):
80 80 if not lines:
81 81 return lines
82 82 if self.initial_re.match(lines[0]) or \
83 83 (len(lines) > 1 and self.prompt_re.match(lines[1])):
84 84 return self._strip(lines)
85 85 return lines
86 86
87 87 classic_prompt = PromptStripper(
88 88 prompt_re=re.compile(r'^(>>>|\.\.\.)( |$)'),
89 89 initial_re=re.compile(r'^>>>( |$)')
90 90 )
91 91
92 92 ipython_prompt = PromptStripper(re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)'))
93 93
94 94 def cell_magic(lines):
95 95 if not lines or not lines[0].startswith('%%'):
96 96 return lines
97 97 if re.match(r'%%\w+\?', lines[0]):
98 98 # This case will be handled by help_end
99 99 return lines
100 100 magic_name, _, first_line = lines[0][2:].rstrip().partition(' ')
101 101 body = ''.join(lines[1:])
102 102 return ['get_ipython().run_cell_magic(%r, %r, %r)\n'
103 103 % (magic_name, first_line, body)]
104 104
105 105
106 106 def _find_assign_op(token_line) -> Optional[int]:
107 107 """Get the index of the first assignment in the line ('=' not inside brackets)
108 108
109 109 Note: We don't try to support multiple special assignment (a = b = %foo)
110 110 """
111 111 paren_level = 0
112 112 for i, ti in enumerate(token_line):
113 113 s = ti.string
114 114 if s == '=' and paren_level == 0:
115 115 return i
116 116 if s in {'(','[','{'}:
117 117 paren_level += 1
118 118 elif s in {')', ']', '}'}:
119 119 if paren_level > 0:
120 120 paren_level -= 1
121 121 return None
122 122
123 123 def find_end_of_continued_line(lines, start_line: int):
124 124 """Find the last line of a line explicitly extended using backslashes.
125 125
126 126 Uses 0-indexed line numbers.
127 127 """
128 128 end_line = start_line
129 129 while lines[end_line].endswith('\\\n'):
130 130 end_line += 1
131 131 if end_line >= len(lines):
132 132 break
133 133 return end_line
134 134
135 135 def assemble_continued_line(lines, start: Tuple[int, int], end_line: int):
136 136 r"""Assemble a single line from multiple continued line pieces
137 137
138 138 Continued lines are lines ending in ``\``, and the line following the last
139 139 ``\`` in the block.
140 140
141 141 For example, this code continues over multiple lines::
142 142
143 143 if (assign_ix is not None) \
144 144 and (len(line) >= assign_ix + 2) \
145 145 and (line[assign_ix+1].string == '%') \
146 146 and (line[assign_ix+2].type == tokenize.NAME):
147 147
148 148 This statement contains four continued line pieces.
149 149 Assembling these pieces into a single line would give::
150 150
151 151 if (assign_ix is not None) and (len(line) >= assign_ix + 2) and (line[...
152 152
153 153 This uses 0-indexed line numbers. *start* is (lineno, colno).
154 154
155 155 Used to allow ``%magic`` and ``!system`` commands to be continued over
156 156 multiple lines.
157 157 """
158 158 parts = [lines[start[0]][start[1]:]] + lines[start[0]+1:end_line+1]
159 159 return ' '.join([p.rstrip()[:-1] for p in parts[:-1]] # Strip backslash+newline
160 160 + [parts[-1].rstrip()]) # Strip newline from last line
161 161
162 162 class TokenTransformBase:
163 163 """Base class for transformations which examine tokens.
164 164
165 165 Special syntax should not be transformed when it occurs inside strings or
166 166 comments. This is hard to reliably avoid with regexes. The solution is to
167 167 tokenise the code as Python, and recognise the special syntax in the tokens.
168 168
169 169 IPython's special syntax is not valid Python syntax, so tokenising may go
170 170 wrong after the special syntax starts. These classes therefore find and
171 171 transform *one* instance of special syntax at a time into regular Python
172 172 syntax. After each transformation, tokens are regenerated to find the next
173 173 piece of special syntax.
174 174
175 175 Subclasses need to implement one class method (find)
176 176 and one regular method (transform).
177 177
178 178 The priority attribute can select which transformation to apply if multiple
179 179 transformers match in the same place. Lower numbers have higher priority.
180 180 This allows "%magic?" to be turned into a help call rather than a magic call.
181 181 """
182 182 # Lower numbers -> higher priority (for matches in the same location)
183 183 priority = 10
184 184
185 185 def sortby(self):
186 186 return self.start_line, self.start_col, self.priority
187 187
188 188 def __init__(self, start):
189 189 self.start_line = start[0] - 1 # Shift from 1-index to 0-index
190 190 self.start_col = start[1]
191 191
192 192 @classmethod
193 193 def find(cls, tokens_by_line):
194 194 """Find one instance of special syntax in the provided tokens.
195 195
196 196 Tokens are grouped into logical lines for convenience,
197 197 so it is easy to e.g. look at the first token of each line.
198 198 *tokens_by_line* is a list of lists of tokenize.TokenInfo objects.
199 199
200 200 This should return an instance of its class, pointing to the start
201 201 position it has found, or None if it found no match.
202 202 """
203 203 raise NotImplementedError
204 204
205 205 def transform(self, lines: List[str]):
206 206 """Transform one instance of special syntax found by ``find()``
207 207
208 208 Takes a list of strings representing physical lines,
209 209 returns a similar list of transformed lines.
210 210 """
211 211 raise NotImplementedError
212 212
213 213 class MagicAssign(TokenTransformBase):
214 214 """Transformer for assignments from magics (a = %foo)"""
215 215 @classmethod
216 216 def find(cls, tokens_by_line):
217 217 """Find the first magic assignment (a = %foo) in the cell.
218 218 """
219 219 for line in tokens_by_line:
220 220 assign_ix = _find_assign_op(line)
221 221 if (assign_ix is not None) \
222 222 and (len(line) >= assign_ix + 2) \
223 223 and (line[assign_ix+1].string == '%') \
224 224 and (line[assign_ix+2].type == tokenize.NAME):
225 225 return cls(line[assign_ix+1].start)
226 226
227 227 def transform(self, lines: List[str]):
228 228 """Transform a magic assignment found by the ``find()`` classmethod.
229 229 """
230 230 start_line, start_col = self.start_line, self.start_col
231 231 lhs = lines[start_line][:start_col]
232 232 end_line = find_end_of_continued_line(lines, start_line)
233 233 rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
234 234 assert rhs.startswith('%'), rhs
235 235 magic_name, _, args = rhs[1:].partition(' ')
236 236
237 237 lines_before = lines[:start_line]
238 238 call = "get_ipython().run_line_magic({!r}, {!r})".format(magic_name, args)
239 239 new_line = lhs + call + '\n'
240 240 lines_after = lines[end_line+1:]
241 241
242 242 return lines_before + [new_line] + lines_after
243 243
244 244
245 245 class SystemAssign(TokenTransformBase):
246 246 """Transformer for assignments from system commands (a = !foo)"""
247 247 @classmethod
248 248 def find(cls, tokens_by_line):
249 249 """Find the first system assignment (a = !foo) in the cell.
250 250 """
251 251 for line in tokens_by_line:
252 252 assign_ix = _find_assign_op(line)
253 253 if (assign_ix is not None) \
254 254 and not line[assign_ix].line.strip().startswith('=') \
255 255 and (len(line) >= assign_ix + 2) \
256 256 and (line[assign_ix + 1].type == tokenize.ERRORTOKEN):
257 257 ix = assign_ix + 1
258 258
259 259 while ix < len(line) and line[ix].type == tokenize.ERRORTOKEN:
260 260 if line[ix].string == '!':
261 261 return cls(line[ix].start)
262 262 elif not line[ix].string.isspace():
263 263 break
264 264 ix += 1
265 265
266 266 def transform(self, lines: List[str]):
267 267 """Transform a system assignment found by the ``find()`` classmethod.
268 268 """
269 269 start_line, start_col = self.start_line, self.start_col
270 270
271 271 lhs = lines[start_line][:start_col]
272 272 end_line = find_end_of_continued_line(lines, start_line)
273 273 rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
274 274 assert rhs.startswith('!'), rhs
275 275 cmd = rhs[1:]
276 276
277 277 lines_before = lines[:start_line]
278 278 call = "get_ipython().getoutput({!r})".format(cmd)
279 279 new_line = lhs + call + '\n'
280 280 lines_after = lines[end_line + 1:]
281 281
282 282 return lines_before + [new_line] + lines_after
283 283
284 284 # The escape sequences that define the syntax transformations IPython will
285 285 # apply to user input. These can NOT be just changed here: many regular
286 286 # expressions and other parts of the code may use their hardcoded values, and
287 287 # for all intents and purposes they constitute the 'IPython syntax', so they
288 288 # should be considered fixed.
289 289
290 290 ESC_SHELL = '!' # Send line to underlying system shell
291 291 ESC_SH_CAP = '!!' # Send line to system shell and capture output
292 292 ESC_HELP = '?' # Find information about object
293 293 ESC_HELP2 = '??' # Find extra-detailed information about object
294 294 ESC_MAGIC = '%' # Call magic function
295 295 ESC_MAGIC2 = '%%' # Call cell-magic function
296 296 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
297 297 ESC_QUOTE2 = ';' # Quote all args as a single string, call
298 298 ESC_PAREN = '/' # Call first argument with rest of line as arguments
299 299
300 300 ESCAPE_SINGLES = {'!', '?', '%', ',', ';', '/'}
301 301 ESCAPE_DOUBLES = {'!!', '??'} # %% (cell magic) is handled separately
302 302
303 303 def _make_help_call(target, esc, next_input=None):
304 304 """Prepares a pinfo(2)/psearch call from a target name and the escape
305 305 (i.e. ? or ??)"""
306 306 method = 'pinfo2' if esc == '??' \
307 307 else 'psearch' if '*' in target \
308 308 else 'pinfo'
309 309 arg = " ".join([method, target])
310 310 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
311 311 t_magic_name, _, t_magic_arg_s = arg.partition(' ')
312 312 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
313 313 if next_input is None:
314 314 return 'get_ipython().run_line_magic(%r, %r)' % (t_magic_name, t_magic_arg_s)
315 315 else:
316 316 return 'get_ipython().set_next_input(%r);get_ipython().run_line_magic(%r, %r)' % \
317 317 (next_input, t_magic_name, t_magic_arg_s)
318 318
319 319 def _tr_help(content):
320 320 """Translate lines escaped with: ?
321 321
322 322 A naked help line should fire the intro help screen (shell.show_usage())
323 323 """
324 324 if not content:
325 325 return 'get_ipython().show_usage()'
326 326
327 327 return _make_help_call(content, '?')
328 328
329 329 def _tr_help2(content):
330 330 """Translate lines escaped with: ??
331 331
332 332 A naked help line should fire the intro help screen (shell.show_usage())
333 333 """
334 334 if not content:
335 335 return 'get_ipython().show_usage()'
336 336
337 337 return _make_help_call(content, '??')
338 338
339 339 def _tr_magic(content):
340 340 "Translate lines escaped with a percent sign: %"
341 341 name, _, args = content.partition(' ')
342 342 return 'get_ipython().run_line_magic(%r, %r)' % (name, args)
343 343
344 344 def _tr_quote(content):
345 345 "Translate lines escaped with a comma: ,"
346 346 name, _, args = content.partition(' ')
347 347 return '%s("%s")' % (name, '", "'.join(args.split()) )
348 348
349 349 def _tr_quote2(content):
350 350 "Translate lines escaped with a semicolon: ;"
351 351 name, _, args = content.partition(' ')
352 352 return '%s("%s")' % (name, args)
353 353
354 354 def _tr_paren(content):
355 355 "Translate lines escaped with a slash: /"
356 356 name, _, args = content.partition(' ')
357 357 return '%s(%s)' % (name, ", ".join(args.split()))
358 358
359 359 tr = { ESC_SHELL : 'get_ipython().system({!r})'.format,
360 360 ESC_SH_CAP : 'get_ipython().getoutput({!r})'.format,
361 361 ESC_HELP : _tr_help,
362 362 ESC_HELP2 : _tr_help2,
363 363 ESC_MAGIC : _tr_magic,
364 364 ESC_QUOTE : _tr_quote,
365 365 ESC_QUOTE2 : _tr_quote2,
366 366 ESC_PAREN : _tr_paren }
367 367
368 368 class EscapedCommand(TokenTransformBase):
369 369 """Transformer for escaped commands like %foo, !foo, or /foo"""
370 370 @classmethod
371 371 def find(cls, tokens_by_line):
372 372 """Find the first escaped command (%foo, !foo, etc.) in the cell.
373 373 """
374 374 for line in tokens_by_line:
375 375 if not line:
376 376 continue
377 377 ix = 0
378 378 ll = len(line)
379 379 while ll > ix and line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
380 380 ix += 1
381 381 if ix >= ll:
382 382 continue
383 383 if line[ix].string in ESCAPE_SINGLES:
384 384 return cls(line[ix].start)
385 385
386 386 def transform(self, lines):
387 387 """Transform an escaped line found by the ``find()`` classmethod.
388 388 """
389 389 start_line, start_col = self.start_line, self.start_col
390 390
391 391 indent = lines[start_line][:start_col]
392 392 end_line = find_end_of_continued_line(lines, start_line)
393 393 line = assemble_continued_line(lines, (start_line, start_col), end_line)
394 394
395 395 if len(line) > 1 and line[:2] in ESCAPE_DOUBLES:
396 396 escape, content = line[:2], line[2:]
397 397 else:
398 398 escape, content = line[:1], line[1:]
399 399
400 400 if escape in tr:
401 401 call = tr[escape](content)
402 402 else:
403 403 call = ''
404 404
405 405 lines_before = lines[:start_line]
406 406 new_line = indent + call + '\n'
407 407 lines_after = lines[end_line + 1:]
408 408
409 409 return lines_before + [new_line] + lines_after
410 410
411 411 _help_end_re = re.compile(r"""(%{0,2}
412 412 (?!\d)[\w*]+ # Variable name
413 413 (\.(?!\d)[\w*]+)* # .etc.etc
414 414 )
415 415 (\?\??)$ # ? or ??
416 416 """,
417 417 re.VERBOSE)
418 418
419 419 class HelpEnd(TokenTransformBase):
420 420 """Transformer for help syntax: obj? and obj??"""
421 421 # This needs to be higher priority (lower number) than EscapedCommand so
422 422 # that inspecting magics (%foo?) works.
423 423 priority = 5
424 424
425 425 def __init__(self, start, q_locn):
426 426 super().__init__(start)
427 427 self.q_line = q_locn[0] - 1 # Shift from 1-indexed to 0-indexed
428 428 self.q_col = q_locn[1]
429 429
430 430 @classmethod
431 431 def find(cls, tokens_by_line):
432 432 """Find the first help command (foo?) in the cell.
433 433 """
434 434 for line in tokens_by_line:
435 435 # Last token is NEWLINE; look at last but one
436 436 if len(line) > 2 and line[-2].string == '?':
437 437 # Find the first token that's not INDENT/DEDENT
438 438 ix = 0
439 439 while line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
440 440 ix += 1
441 441 return cls(line[ix].start, line[-2].start)
442 442
443 443 def transform(self, lines):
444 444 """Transform a help command found by the ``find()`` classmethod.
445 445 """
446 446 piece = ''.join(lines[self.start_line:self.q_line+1])
447 447 indent, content = piece[:self.start_col], piece[self.start_col:]
448 448 lines_before = lines[:self.start_line]
449 449 lines_after = lines[self.q_line + 1:]
450 450
451 451 m = _help_end_re.search(content)
452 452 if not m:
453 453 raise SyntaxError(content)
454 454 assert m is not None, content
455 455 target = m.group(1)
456 456 esc = m.group(3)
457 457
458 458 # If we're mid-command, put it back on the next prompt for the user.
459 459 next_input = None
460 460 if (not lines_before) and (not lines_after) \
461 461 and content.strip() != m.group(0):
462 462 next_input = content.rstrip('?\n')
463 463
464 464 call = _make_help_call(target, esc, next_input=next_input)
465 465 new_line = indent + call + '\n'
466 466
467 467 return lines_before + [new_line] + lines_after
468 468
469 469 def make_tokens_by_line(lines:List[str]):
470 470 """Tokenize a series of lines and group tokens by line.
471 471
472 472 The tokens for a multiline Python string or expression are grouped as one
473 473 line. All lines except the last lines should keep their line ending ('\\n',
474 474 '\\r\\n') for this to properly work. Use `.splitlines(keeplineending=True)`
475 475 for example when passing block of text to this function.
476 476
477 477 """
478 478 # NL tokens are used inside multiline expressions, but also after blank
479 479 # lines or comments. This is intentional - see https://bugs.python.org/issue17061
480 480 # We want to group the former case together but split the latter, so we
481 481 # track parentheses level, similar to the internals of tokenize.
482 482
483 483 # reexported from token on 3.7+
484 484 NEWLINE, NL = tokenize.NEWLINE, tokenize.NL # type: ignore
485 485 tokens_by_line:List[List[Any]] = [[]]
486 486 if len(lines) > 1 and not lines[0].endswith(('\n', '\r', '\r\n', '\x0b', '\x0c')):
487 487 warnings.warn("`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")
488 488 parenlev = 0
489 489 try:
490 490 for token in tokenize.generate_tokens(iter(lines).__next__):
491 491 tokens_by_line[-1].append(token)
492 492 if (token.type == NEWLINE) \
493 493 or ((token.type == NL) and (parenlev <= 0)):
494 494 tokens_by_line.append([])
495 495 elif token.string in {'(', '[', '{'}:
496 496 parenlev += 1
497 497 elif token.string in {')', ']', '}'}:
498 498 if parenlev > 0:
499 499 parenlev -= 1
500 500 except tokenize.TokenError:
501 501 # Input ended in a multiline string or expression. That's OK for us.
502 502 pass
503 503
504 504
505 505 if not tokens_by_line[-1]:
506 506 tokens_by_line.pop()
507 507
508 508
509 509 return tokens_by_line
510 510
511
512 def has_sunken_brackets(tokens: List[tokenize.TokenInfo]):
513 """Check if the depth of brackets in the list of tokens drops below 0"""
514 parenlev = 0
515 for token in tokens:
516 if token.string in {"(", "[", "{"}:
517 parenlev += 1
518 elif token.string in {")", "]", "}"}:
519 parenlev -= 1
520 if parenlev < 0:
521 return True
522 return False
523
524
511 525 def show_linewise_tokens(s: str):
512 526 """For investigation and debugging"""
513 527 if not s.endswith('\n'):
514 528 s += '\n'
515 529 lines = s.splitlines(keepends=True)
516 530 for line in make_tokens_by_line(lines):
517 531 print("Line -------")
518 532 for tokinfo in line:
519 533 print(" ", tokinfo)
520 534
521 535 # Arbitrary limit to prevent getting stuck in infinite loops
522 536 TRANSFORM_LOOP_LIMIT = 500
523 537
524 538 class TransformerManager:
525 539 """Applies various transformations to a cell or code block.
526 540
527 541 The key methods for external use are ``transform_cell()``
528 542 and ``check_complete()``.
529 543 """
530 544 def __init__(self):
531 545 self.cleanup_transforms = [
532 546 leading_empty_lines,
533 547 leading_indent,
534 548 classic_prompt,
535 549 ipython_prompt,
536 550 ]
537 551 self.line_transforms = [
538 552 cell_magic,
539 553 ]
540 554 self.token_transformers = [
541 555 MagicAssign,
542 556 SystemAssign,
543 557 EscapedCommand,
544 558 HelpEnd,
545 559 ]
546 560
547 561 def do_one_token_transform(self, lines):
548 562 """Find and run the transform earliest in the code.
549 563
550 564 Returns (changed, lines).
551 565
552 566 This method is called repeatedly until changed is False, indicating
553 567 that all available transformations are complete.
554 568
555 569 The tokens following IPython special syntax might not be valid, so
556 570 the transformed code is retokenised every time to identify the next
557 571 piece of special syntax. Hopefully long code cells are mostly valid
558 572 Python, not using lots of IPython special syntax, so this shouldn't be
559 573 a performance issue.
560 574 """
561 575 tokens_by_line = make_tokens_by_line(lines)
562 576 candidates = []
563 577 for transformer_cls in self.token_transformers:
564 578 transformer = transformer_cls.find(tokens_by_line)
565 579 if transformer:
566 580 candidates.append(transformer)
567 581
568 582 if not candidates:
569 583 # Nothing to transform
570 584 return False, lines
571 585 ordered_transformers = sorted(candidates, key=TokenTransformBase.sortby)
572 586 for transformer in ordered_transformers:
573 587 try:
574 588 return True, transformer.transform(lines)
575 589 except SyntaxError:
576 590 pass
577 591 return False, lines
578 592
579 593 def do_token_transforms(self, lines):
580 594 for _ in range(TRANSFORM_LOOP_LIMIT):
581 595 changed, lines = self.do_one_token_transform(lines)
582 596 if not changed:
583 597 return lines
584 598
585 599 raise RuntimeError("Input transformation still changing after "
586 600 "%d iterations. Aborting." % TRANSFORM_LOOP_LIMIT)
587 601
588 602 def transform_cell(self, cell: str) -> str:
589 603 """Transforms a cell of input code"""
590 604 if not cell.endswith('\n'):
591 605 cell += '\n' # Ensure the cell has a trailing newline
592 606 lines = cell.splitlines(keepends=True)
593 607 for transform in self.cleanup_transforms + self.line_transforms:
594 608 lines = transform(lines)
595 609
596 610 lines = self.do_token_transforms(lines)
597 611 return ''.join(lines)
598 612
599 613 def check_complete(self, cell: str):
600 614 """Return whether a block of code is ready to execute, or should be continued
601 615
602 616 Parameters
603 617 ----------
604 618 source : string
605 619 Python input code, which can be multiline.
606 620
607 621 Returns
608 622 -------
609 623 status : str
610 624 One of 'complete', 'incomplete', or 'invalid' if source is not a
611 625 prefix of valid code.
612 626 indent_spaces : int or None
613 627 The number of spaces by which to indent the next line of code. If
614 628 status is not 'incomplete', this is None.
615 629 """
616 630 # Remember if the lines ends in a new line.
617 631 ends_with_newline = False
618 632 for character in reversed(cell):
619 633 if character == '\n':
620 634 ends_with_newline = True
621 635 break
622 636 elif character.strip():
623 637 break
624 638 else:
625 639 continue
626 640
627 641 if not ends_with_newline:
628 642 # Append an newline for consistent tokenization
629 643 # See https://bugs.python.org/issue33899
630 644 cell += '\n'
631 645
632 646 lines = cell.splitlines(keepends=True)
633 647
634 648 if not lines:
635 649 return 'complete', None
636 650
637 651 if lines[-1].endswith('\\'):
638 652 # Explicit backslash continuation
639 653 return 'incomplete', find_last_indent(lines)
640 654
641 655 try:
642 656 for transform in self.cleanup_transforms:
643 657 if not getattr(transform, 'has_side_effects', False):
644 658 lines = transform(lines)
645 659 except SyntaxError:
646 660 return 'invalid', None
647 661
648 662 if lines[0].startswith('%%'):
649 663 # Special case for cell magics - completion marked by blank line
650 664 if lines[-1].strip():
651 665 return 'incomplete', find_last_indent(lines)
652 666 else:
653 667 return 'complete', None
654 668
655 669 try:
656 670 for transform in self.line_transforms:
657 671 if not getattr(transform, 'has_side_effects', False):
658 672 lines = transform(lines)
659 673 lines = self.do_token_transforms(lines)
660 674 except SyntaxError:
661 675 return 'invalid', None
662 676
663 677 tokens_by_line = make_tokens_by_line(lines)
664 678
679 # Bail if we got one line and there are more closing parentheses than
680 # the opening ones
681 if (
682 len(lines) == 1
683 and tokens_by_line
684 and has_sunken_brackets(tokens_by_line[0])
685 ):
686 return "invalid", None
687
665 688 if not tokens_by_line:
666 689 return 'incomplete', find_last_indent(lines)
667 690
668 691 if tokens_by_line[-1][-1].type != tokenize.ENDMARKER:
669 692 # We're in a multiline string or expression
670 693 return 'incomplete', find_last_indent(lines)
671 694
672 695 newline_types = {tokenize.NEWLINE, tokenize.COMMENT, tokenize.ENDMARKER} # type: ignore
673 696
674 697 # Pop the last line which only contains DEDENTs and ENDMARKER
675 698 last_token_line = None
676 699 if {t.type for t in tokens_by_line[-1]} in [
677 700 {tokenize.DEDENT, tokenize.ENDMARKER},
678 701 {tokenize.ENDMARKER}
679 702 ] and len(tokens_by_line) > 1:
680 703 last_token_line = tokens_by_line.pop()
681 704
682 705 while tokens_by_line[-1] and tokens_by_line[-1][-1].type in newline_types:
683 706 tokens_by_line[-1].pop()
684 707
685 708 if not tokens_by_line[-1]:
686 709 return 'incomplete', find_last_indent(lines)
687 710
688 711 if tokens_by_line[-1][-1].string == ':':
689 712 # The last line starts a block (e.g. 'if foo:')
690 713 ix = 0
691 714 while tokens_by_line[-1][ix].type in {tokenize.INDENT, tokenize.DEDENT}:
692 715 ix += 1
693 716
694 717 indent = tokens_by_line[-1][ix].start[1]
695 718 return 'incomplete', indent + 4
696 719
697 720 if tokens_by_line[-1][0].line.endswith('\\'):
698 721 return 'incomplete', None
699 722
700 723 # At this point, our checks think the code is complete (or invalid).
701 724 # We'll use codeop.compile_command to check this with the real parser
702 725 try:
703 726 with warnings.catch_warnings():
704 727 warnings.simplefilter('error', SyntaxWarning)
705 728 res = compile_command(''.join(lines), symbol='exec')
706 729 except (SyntaxError, OverflowError, ValueError, TypeError,
707 730 MemoryError, SyntaxWarning):
708 731 return 'invalid', None
709 732 else:
710 733 if res is None:
711 734 return 'incomplete', find_last_indent(lines)
712 735
713 736 if last_token_line and last_token_line[0].type == tokenize.DEDENT:
714 737 if ends_with_newline:
715 738 return 'complete', None
716 739 return 'incomplete', find_last_indent(lines)
717 740
718 741 # If there's a blank line at the end, assume we're ready to execute
719 742 if not lines[-1].strip():
720 743 return 'complete', None
721 744
722 745 return 'complete', None
723 746
724 747
725 748 def find_last_indent(lines):
726 749 m = _indent_re.match(lines[-1])
727 750 if not m:
728 751 return 0
729 752 return len(m.group(0).replace('\t', ' '*4))
@@ -1,3804 +1,3824 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Main IPython class."""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13
14 14 import abc
15 15 import ast
16 16 import atexit
17 17 import builtins as builtin_mod
18 18 import functools
19 19 import inspect
20 20 import os
21 21 import re
22 22 import runpy
23 23 import sys
24 24 import tempfile
25 25 import traceback
26 26 import types
27 27 import subprocess
28 28 import warnings
29 29 from io import open as io_open
30 30
31 31 from pathlib import Path
32 32 from pickleshare import PickleShareDB
33 33
34 34 from traitlets.config.configurable import SingletonConfigurable
35 35 from traitlets.utils.importstring import import_item
36 36 from IPython.core import oinspect
37 37 from IPython.core import magic
38 38 from IPython.core import page
39 39 from IPython.core import prefilter
40 40 from IPython.core import ultratb
41 41 from IPython.core.alias import Alias, AliasManager
42 42 from IPython.core.autocall import ExitAutocall
43 43 from IPython.core.builtin_trap import BuiltinTrap
44 44 from IPython.core.events import EventManager, available_events
45 45 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
46 46 from IPython.core.debugger import Pdb
47 47 from IPython.core.display_trap import DisplayTrap
48 48 from IPython.core.displayhook import DisplayHook
49 49 from IPython.core.displaypub import DisplayPublisher
50 50 from IPython.core.error import InputRejected, UsageError
51 51 from IPython.core.extensions import ExtensionManager
52 52 from IPython.core.formatters import DisplayFormatter
53 53 from IPython.core.history import HistoryManager
54 54 from IPython.core.inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
55 55 from IPython.core.logger import Logger
56 56 from IPython.core.macro import Macro
57 57 from IPython.core.payload import PayloadManager
58 58 from IPython.core.prefilter import PrefilterManager
59 59 from IPython.core.profiledir import ProfileDir
60 60 from IPython.core.usage import default_banner
61 61 from IPython.display import display
62 62 from IPython.testing.skipdoctest import skip_doctest
63 63 from IPython.utils import PyColorize
64 64 from IPython.utils import io
65 65 from IPython.utils import py3compat
66 66 from IPython.utils import openpy
67 67 from IPython.utils.decorators import undoc
68 68 from IPython.utils.io import ask_yes_no
69 69 from IPython.utils.ipstruct import Struct
70 70 from IPython.paths import get_ipython_dir
71 71 from IPython.utils.path import get_home_dir, get_py_filename, ensure_dir_exists
72 72 from IPython.utils.process import system, getoutput
73 73 from IPython.utils.strdispatch import StrDispatch
74 74 from IPython.utils.syspathcontext import prepended_to_syspath
75 75 from IPython.utils.text import format_screen, LSString, SList, DollarFormatter
76 76 from IPython.utils.tempdir import TemporaryDirectory
77 77 from traitlets import (
78 78 Integer, Bool, CaselessStrEnum, Enum, List, Dict, Unicode, Instance, Type,
79 79 observe, default, validate, Any
80 80 )
81 81 from warnings import warn
82 82 from logging import error
83 83 import IPython.core.hooks
84 84
85 85 from typing import List as ListType, Tuple, Optional
86 86 from ast import AST
87 87
88 88 # NoOpContext is deprecated, but ipykernel imports it from here.
89 89 # See https://github.com/ipython/ipykernel/issues/157
90 90 # (2016, let's try to remove than in IPython 8.0)
91 91 from IPython.utils.contexts import NoOpContext
92 92
93 93 try:
94 94 import docrepr.sphinxify as sphx
95 95
96 96 def sphinxify(doc):
97 97 with TemporaryDirectory() as dirname:
98 98 return {
99 99 'text/html': sphx.sphinxify(doc, dirname),
100 100 'text/plain': doc
101 101 }
102 102 except ImportError:
103 103 sphinxify = None
104 104
105 105
106 106 class ProvisionalWarning(DeprecationWarning):
107 107 """
108 108 Warning class for unstable features
109 109 """
110 110 pass
111 111
112 112 if sys.version_info > (3,8):
113 113 from ast import Module
114 114 else :
115 115 # mock the new API, ignore second argument
116 116 # see https://github.com/ipython/ipython/issues/11590
117 117 from ast import Module as OriginalModule
118 118 Module = lambda nodelist, type_ignores: OriginalModule(nodelist)
119 119
120 120 if sys.version_info > (3,6):
121 121 _assign_nodes = (ast.AugAssign, ast.AnnAssign, ast.Assign)
122 122 _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)
123 123 else:
124 124 _assign_nodes = (ast.AugAssign, ast.Assign )
125 125 _single_targets_nodes = (ast.AugAssign, )
126 126
127 127 #-----------------------------------------------------------------------------
128 128 # Await Helpers
129 129 #-----------------------------------------------------------------------------
130 130
131 131 def removed_co_newlocals(function:types.FunctionType) -> types.FunctionType:
132 132 """Return a function that do not create a new local scope.
133 133
134 134 Given a function, create a clone of this function where the co_newlocal flag
135 135 has been removed, making this function code actually run in the sourounding
136 136 scope.
137 137
138 138 We need this in order to run asynchronous code in user level namespace.
139 139 """
140 140 from types import CodeType, FunctionType
141 141 CO_NEWLOCALS = 0x0002
142 142 code = function.__code__
143 143 new_co_flags = code.co_flags & ~CO_NEWLOCALS
144 144 if sys.version_info > (3, 8, 0, 'alpha', 3):
145 145 new_code = code.replace(co_flags=new_co_flags)
146 146 else:
147 147 new_code = CodeType(
148 148 code.co_argcount,
149 149 code.co_kwonlyargcount,
150 150 code.co_nlocals,
151 151 code.co_stacksize,
152 152 new_co_flags,
153 153 code.co_code,
154 154 code.co_consts,
155 155 code.co_names,
156 156 code.co_varnames,
157 157 code.co_filename,
158 158 code.co_name,
159 159 code.co_firstlineno,
160 160 code.co_lnotab,
161 161 code.co_freevars,
162 162 code.co_cellvars
163 163 )
164 164 return FunctionType(new_code, globals(), function.__name__, function.__defaults__)
165 165
166 166
167 167 # we still need to run things using the asyncio eventloop, but there is no
168 168 # async integration
169 169 from .async_helpers import (_asyncio_runner, _asyncify, _pseudo_sync_runner)
170 170 from .async_helpers import _curio_runner, _trio_runner, _should_be_async
171 171
172 172
173 173 def _ast_asyncify(cell:str, wrapper_name:str) -> ast.Module:
174 174 """
175 175 Parse a cell with top-level await and modify the AST to be able to run it later.
176 176
177 177 Parameters
178 178 ----------
179 179 cell: str
180 180 The code cell to asyncronify
181 181 wrapper_name: str
182 182 The name of the function to be used to wrap the passed `cell`. It is
183 183 advised to **not** use a python identifier in order to not pollute the
184 184 global namespace in which the function will be ran.
185 185
186 186 Returns
187 187 -------
188 188 ModuleType:
189 189 A module object AST containing **one** function named `wrapper_name`.
190 190
191 191 The given code is wrapped in a async-def function, parsed into an AST, and
192 192 the resulting function definition AST is modified to return the last
193 193 expression.
194 194
195 195 The last expression or await node is moved into a return statement at the
196 196 end of the function, and removed from its original location. If the last
197 197 node is not Expr or Await nothing is done.
198 198
199 199 The function `__code__` will need to be later modified (by
200 200 ``removed_co_newlocals``) in a subsequent step to not create new `locals()`
201 201 meaning that the local and global scope are the same, ie as if the body of
202 202 the function was at module level.
203 203
204 204 Lastly a call to `locals()` is made just before the last expression of the
205 205 function, or just after the last assignment or statement to make sure the
206 206 global dict is updated as python function work with a local fast cache which
207 207 is updated only on `local()` calls.
208 208 """
209 209
210 210 from ast import Expr, Await, Return
211 211 if sys.version_info >= (3,8):
212 212 return ast.parse(cell)
213 213 tree = ast.parse(_asyncify(cell))
214 214
215 215 function_def = tree.body[0]
216 216 function_def.name = wrapper_name
217 217 try_block = function_def.body[0]
218 218 lastexpr = try_block.body[-1]
219 219 if isinstance(lastexpr, (Expr, Await)):
220 220 try_block.body[-1] = Return(lastexpr.value)
221 221 ast.fix_missing_locations(tree)
222 222 return tree
223 223 #-----------------------------------------------------------------------------
224 224 # Globals
225 225 #-----------------------------------------------------------------------------
226 226
227 227 # compiled regexps for autoindent management
228 228 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
229 229
230 230 #-----------------------------------------------------------------------------
231 231 # Utilities
232 232 #-----------------------------------------------------------------------------
233 233
234 234 @undoc
235 235 def softspace(file, newvalue):
236 236 """Copied from code.py, to remove the dependency"""
237 237
238 238 oldvalue = 0
239 239 try:
240 240 oldvalue = file.softspace
241 241 except AttributeError:
242 242 pass
243 243 try:
244 244 file.softspace = newvalue
245 245 except (AttributeError, TypeError):
246 246 # "attribute-less object" or "read-only attributes"
247 247 pass
248 248 return oldvalue
249 249
250 250 @undoc
251 251 def no_op(*a, **kw):
252 252 pass
253 253
254 254
255 255 class SpaceInInput(Exception): pass
256 256
257 257
258 258 def get_default_colors():
259 259 "DEPRECATED"
260 260 warn('get_default_color is deprecated since IPython 5.0, and returns `Neutral` on all platforms.',
261 261 DeprecationWarning, stacklevel=2)
262 262 return 'Neutral'
263 263
264 264
265 265 class SeparateUnicode(Unicode):
266 266 r"""A Unicode subclass to validate separate_in, separate_out, etc.
267 267
268 268 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
269 269 """
270 270
271 271 def validate(self, obj, value):
272 272 if value == '0': value = ''
273 273 value = value.replace('\\n','\n')
274 274 return super(SeparateUnicode, self).validate(obj, value)
275 275
276 276
277 277 @undoc
278 278 class DummyMod(object):
279 279 """A dummy module used for IPython's interactive module when
280 280 a namespace must be assigned to the module's __dict__."""
281 281 __spec__ = None
282 282
283 283
284 284 class ExecutionInfo(object):
285 285 """The arguments used for a call to :meth:`InteractiveShell.run_cell`
286 286
287 287 Stores information about what is going to happen.
288 288 """
289 289 raw_cell = None
290 290 store_history = False
291 291 silent = False
292 292 shell_futures = True
293 293
294 294 def __init__(self, raw_cell, store_history, silent, shell_futures):
295 295 self.raw_cell = raw_cell
296 296 self.store_history = store_history
297 297 self.silent = silent
298 298 self.shell_futures = shell_futures
299 299
300 300 def __repr__(self):
301 301 name = self.__class__.__qualname__
302 302 raw_cell = ((self.raw_cell[:50] + '..')
303 303 if len(self.raw_cell) > 50 else self.raw_cell)
304 304 return '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s>' %\
305 305 (name, id(self), raw_cell, self.store_history, self.silent, self.shell_futures)
306 306
307 307
308 308 class ExecutionResult(object):
309 309 """The result of a call to :meth:`InteractiveShell.run_cell`
310 310
311 311 Stores information about what took place.
312 312 """
313 313 execution_count = None
314 314 error_before_exec = None
315 315 error_in_exec = None
316 316 info = None
317 317 result = None
318 318
319 319 def __init__(self, info):
320 320 self.info = info
321 321
322 322 @property
323 323 def success(self):
324 324 return (self.error_before_exec is None) and (self.error_in_exec is None)
325 325
326 326 def raise_error(self):
327 327 """Reraises error if `success` is `False`, otherwise does nothing"""
328 328 if self.error_before_exec is not None:
329 329 raise self.error_before_exec
330 330 if self.error_in_exec is not None:
331 331 raise self.error_in_exec
332 332
333 333 def __repr__(self):
334 334 name = self.__class__.__qualname__
335 335 return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s info=%s result=%s>' %\
336 336 (name, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.info), repr(self.result))
337 337
338 338
339 339 class InteractiveShell(SingletonConfigurable):
340 340 """An enhanced, interactive shell for Python."""
341 341
342 342 _instance = None
343 343
344 344 ast_transformers = List([], help=
345 345 """
346 346 A list of ast.NodeTransformer subclass instances, which will be applied
347 347 to user input before code is run.
348 348 """
349 349 ).tag(config=True)
350 350
351 351 autocall = Enum((0,1,2), default_value=0, help=
352 352 """
353 353 Make IPython automatically call any callable object even if you didn't
354 354 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
355 355 automatically. The value can be '0' to disable the feature, '1' for
356 356 'smart' autocall, where it is not applied if there are no more
357 357 arguments on the line, and '2' for 'full' autocall, where all callable
358 358 objects are automatically called (even if no arguments are present).
359 359 """
360 360 ).tag(config=True)
361 361
362 362 autoindent = Bool(True, help=
363 363 """
364 364 Autoindent IPython code entered interactively.
365 365 """
366 366 ).tag(config=True)
367 367
368 368 autoawait = Bool(True, help=
369 369 """
370 370 Automatically run await statement in the top level repl.
371 371 """
372 372 ).tag(config=True)
373 373
374 374 loop_runner_map ={
375 375 'asyncio':(_asyncio_runner, True),
376 376 'curio':(_curio_runner, True),
377 377 'trio':(_trio_runner, True),
378 378 'sync': (_pseudo_sync_runner, False)
379 379 }
380 380
381 381 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
382 382 allow_none=True,
383 383 help="""Select the loop runner that will be used to execute top-level asynchronous code"""
384 384 ).tag(config=True)
385 385
386 386 @default('loop_runner')
387 387 def _default_loop_runner(self):
388 388 return import_item("IPython.core.interactiveshell._asyncio_runner")
389 389
390 390 @validate('loop_runner')
391 391 def _import_runner(self, proposal):
392 392 if isinstance(proposal.value, str):
393 393 if proposal.value in self.loop_runner_map:
394 394 runner, autoawait = self.loop_runner_map[proposal.value]
395 395 self.autoawait = autoawait
396 396 return runner
397 397 runner = import_item(proposal.value)
398 398 if not callable(runner):
399 399 raise ValueError('loop_runner must be callable')
400 400 return runner
401 401 if not callable(proposal.value):
402 402 raise ValueError('loop_runner must be callable')
403 403 return proposal.value
404 404
405 405 automagic = Bool(True, help=
406 406 """
407 407 Enable magic commands to be called without the leading %.
408 408 """
409 409 ).tag(config=True)
410 410
411 411 banner1 = Unicode(default_banner,
412 412 help="""The part of the banner to be printed before the profile"""
413 413 ).tag(config=True)
414 414 banner2 = Unicode('',
415 415 help="""The part of the banner to be printed after the profile"""
416 416 ).tag(config=True)
417 417
418 418 cache_size = Integer(1000, help=
419 419 """
420 420 Set the size of the output cache. The default is 1000, you can
421 421 change it permanently in your config file. Setting it to 0 completely
422 422 disables the caching system, and the minimum value accepted is 3 (if
423 423 you provide a value less than 3, it is reset to 0 and a warning is
424 424 issued). This limit is defined because otherwise you'll spend more
425 425 time re-flushing a too small cache than working
426 426 """
427 427 ).tag(config=True)
428 428 color_info = Bool(True, help=
429 429 """
430 430 Use colors for displaying information about objects. Because this
431 431 information is passed through a pager (like 'less'), and some pagers
432 432 get confused with color codes, this capability can be turned off.
433 433 """
434 434 ).tag(config=True)
435 435 colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'),
436 436 default_value='Neutral',
437 437 help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)."
438 438 ).tag(config=True)
439 439 debug = Bool(False).tag(config=True)
440 440 disable_failing_post_execute = Bool(False,
441 441 help="Don't call post-execute functions that have failed in the past."
442 442 ).tag(config=True)
443 443 display_formatter = Instance(DisplayFormatter, allow_none=True)
444 444 displayhook_class = Type(DisplayHook)
445 445 display_pub_class = Type(DisplayPublisher)
446 compiler_class = Type(CachingCompiler)
446 447
447 448 sphinxify_docstring = Bool(False, help=
448 449 """
449 450 Enables rich html representation of docstrings. (This requires the
450 451 docrepr module).
451 452 """).tag(config=True)
452 453
453 454 @observe("sphinxify_docstring")
454 455 def _sphinxify_docstring_changed(self, change):
455 456 if change['new']:
456 457 warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning)
457 458
458 459 enable_html_pager = Bool(False, help=
459 460 """
460 461 (Provisional API) enables html representation in mime bundles sent
461 462 to pagers.
462 463 """).tag(config=True)
463 464
464 465 @observe("enable_html_pager")
465 466 def _enable_html_pager_changed(self, change):
466 467 if change['new']:
467 468 warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning)
468 469
469 470 data_pub_class = None
470 471
471 472 exit_now = Bool(False)
472 473 exiter = Instance(ExitAutocall)
473 474 @default('exiter')
474 475 def _exiter_default(self):
475 476 return ExitAutocall(self)
476 477 # Monotonically increasing execution counter
477 478 execution_count = Integer(1)
478 479 filename = Unicode("<ipython console>")
479 480 ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__
480 481
481 482 # Used to transform cells before running them, and check whether code is complete
482 483 input_transformer_manager = Instance('IPython.core.inputtransformer2.TransformerManager',
483 484 ())
484 485
485 486 @property
486 487 def input_transformers_cleanup(self):
487 488 return self.input_transformer_manager.cleanup_transforms
488 489
489 490 input_transformers_post = List([],
490 491 help="A list of string input transformers, to be applied after IPython's "
491 492 "own input transformations."
492 493 )
493 494
494 495 @property
495 496 def input_splitter(self):
496 497 """Make this available for backward compatibility (pre-7.0 release) with existing code.
497 498
498 499 For example, ipykernel ipykernel currently uses
499 500 `shell.input_splitter.check_complete`
500 501 """
501 502 from warnings import warn
502 503 warn("`input_splitter` is deprecated since IPython 7.0, prefer `input_transformer_manager`.",
503 504 DeprecationWarning, stacklevel=2
504 505 )
505 506 return self.input_transformer_manager
506 507
507 508 logstart = Bool(False, help=
508 509 """
509 510 Start logging to the default log file in overwrite mode.
510 511 Use `logappend` to specify a log file to **append** logs to.
511 512 """
512 513 ).tag(config=True)
513 514 logfile = Unicode('', help=
514 515 """
515 516 The name of the logfile to use.
516 517 """
517 518 ).tag(config=True)
518 519 logappend = Unicode('', help=
519 520 """
520 521 Start logging to the given file in append mode.
521 522 Use `logfile` to specify a log file to **overwrite** logs to.
522 523 """
523 524 ).tag(config=True)
524 525 object_info_string_level = Enum((0,1,2), default_value=0,
525 526 ).tag(config=True)
526 527 pdb = Bool(False, help=
527 528 """
528 529 Automatically call the pdb debugger after every exception.
529 530 """
530 531 ).tag(config=True)
531 532 display_page = Bool(False,
532 533 help="""If True, anything that would be passed to the pager
533 534 will be displayed as regular output instead."""
534 535 ).tag(config=True)
535 536
536 537 # deprecated prompt traits:
537 538
538 539 prompt_in1 = Unicode('In [\\#]: ',
539 540 help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly."
540 541 ).tag(config=True)
541 542 prompt_in2 = Unicode(' .\\D.: ',
542 543 help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly."
543 544 ).tag(config=True)
544 545 prompt_out = Unicode('Out[\\#]: ',
545 546 help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly."
546 547 ).tag(config=True)
547 548 prompts_pad_left = Bool(True,
548 549 help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly."
549 550 ).tag(config=True)
550 551
551 552 @observe('prompt_in1', 'prompt_in2', 'prompt_out', 'prompt_pad_left')
552 553 def _prompt_trait_changed(self, change):
553 554 name = change['name']
554 555 warn("InteractiveShell.{name} is deprecated since IPython 4.0"
555 556 " and ignored since 5.0, set TerminalInteractiveShell.prompts"
556 557 " object directly.".format(name=name))
557 558
558 559 # protect against weird cases where self.config may not exist:
559 560
560 561 show_rewritten_input = Bool(True,
561 562 help="Show rewritten input, e.g. for autocall."
562 563 ).tag(config=True)
563 564
564 565 quiet = Bool(False).tag(config=True)
565 566
566 567 history_length = Integer(10000,
567 568 help='Total length of command history'
568 569 ).tag(config=True)
569 570
570 571 history_load_length = Integer(1000, help=
571 572 """
572 573 The number of saved history entries to be loaded
573 574 into the history buffer at startup.
574 575 """
575 576 ).tag(config=True)
576 577
577 578 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'],
578 579 default_value='last_expr',
579 580 help="""
580 581 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying
581 582 which nodes should be run interactively (displaying output from expressions).
582 583 """
583 584 ).tag(config=True)
584 585
585 586 # TODO: this part of prompt management should be moved to the frontends.
586 587 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
587 588 separate_in = SeparateUnicode('\n').tag(config=True)
588 589 separate_out = SeparateUnicode('').tag(config=True)
589 590 separate_out2 = SeparateUnicode('').tag(config=True)
590 591 wildcards_case_sensitive = Bool(True).tag(config=True)
591 592 xmode = CaselessStrEnum(('Context', 'Plain', 'Verbose', 'Minimal'),
592 593 default_value='Context',
593 594 help="Switch modes for the IPython exception handlers."
594 595 ).tag(config=True)
595 596
596 597 # Subcomponents of InteractiveShell
597 598 alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True)
598 599 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
599 600 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap', allow_none=True)
600 601 display_trap = Instance('IPython.core.display_trap.DisplayTrap', allow_none=True)
601 602 extension_manager = Instance('IPython.core.extensions.ExtensionManager', allow_none=True)
602 603 payload_manager = Instance('IPython.core.payload.PayloadManager', allow_none=True)
603 604 history_manager = Instance('IPython.core.history.HistoryAccessorBase', allow_none=True)
604 605 magics_manager = Instance('IPython.core.magic.MagicsManager', allow_none=True)
605 606
606 607 profile_dir = Instance('IPython.core.application.ProfileDir', allow_none=True)
607 608 @property
608 609 def profile(self):
609 610 if self.profile_dir is not None:
610 611 name = os.path.basename(self.profile_dir.location)
611 612 return name.replace('profile_','')
612 613
613 614
614 615 # Private interface
615 616 _post_execute = Dict()
616 617
617 618 # Tracks any GUI loop loaded for pylab
618 619 pylab_gui_select = None
619 620
620 621 last_execution_succeeded = Bool(True, help='Did last executed command succeeded')
621 622
622 623 last_execution_result = Instance('IPython.core.interactiveshell.ExecutionResult', help='Result of executing the last command', allow_none=True)
623 624
624 625 def __init__(self, ipython_dir=None, profile_dir=None,
625 626 user_module=None, user_ns=None,
626 627 custom_exceptions=((), None), **kwargs):
627 628
628 629 # This is where traits with a config_key argument are updated
629 630 # from the values on config.
630 631 super(InteractiveShell, self).__init__(**kwargs)
631 632 if 'PromptManager' in self.config:
632 633 warn('As of IPython 5.0 `PromptManager` config will have no effect'
633 634 ' and has been replaced by TerminalInteractiveShell.prompts_class')
634 635 self.configurables = [self]
635 636
636 637 # These are relatively independent and stateless
637 638 self.init_ipython_dir(ipython_dir)
638 639 self.init_profile_dir(profile_dir)
639 640 self.init_instance_attrs()
640 641 self.init_environment()
641 642
642 643 # Check if we're in a virtualenv, and set up sys.path.
643 644 self.init_virtualenv()
644 645
645 646 # Create namespaces (user_ns, user_global_ns, etc.)
646 647 self.init_create_namespaces(user_module, user_ns)
647 648 # This has to be done after init_create_namespaces because it uses
648 649 # something in self.user_ns, but before init_sys_modules, which
649 650 # is the first thing to modify sys.
650 651 # TODO: When we override sys.stdout and sys.stderr before this class
651 652 # is created, we are saving the overridden ones here. Not sure if this
652 653 # is what we want to do.
653 654 self.save_sys_module_state()
654 655 self.init_sys_modules()
655 656
656 657 # While we're trying to have each part of the code directly access what
657 658 # it needs without keeping redundant references to objects, we have too
658 659 # much legacy code that expects ip.db to exist.
659 660 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
660 661
661 662 self.init_history()
662 663 self.init_encoding()
663 664 self.init_prefilter()
664 665
665 666 self.init_syntax_highlighting()
666 667 self.init_hooks()
667 668 self.init_events()
668 669 self.init_pushd_popd_magic()
669 670 self.init_user_ns()
670 671 self.init_logger()
671 672 self.init_builtins()
672 673
673 674 # The following was in post_config_initialization
674 675 self.init_inspector()
675 676 self.raw_input_original = input
676 677 self.init_completer()
677 678 # TODO: init_io() needs to happen before init_traceback handlers
678 679 # because the traceback handlers hardcode the stdout/stderr streams.
679 680 # This logic in in debugger.Pdb and should eventually be changed.
680 681 self.init_io()
681 682 self.init_traceback_handlers(custom_exceptions)
682 683 self.init_prompts()
683 684 self.init_display_formatter()
684 685 self.init_display_pub()
685 686 self.init_data_pub()
686 687 self.init_displayhook()
687 688 self.init_magics()
688 689 self.init_alias()
689 690 self.init_logstart()
690 691 self.init_pdb()
691 692 self.init_extension_manager()
692 693 self.init_payload()
693 694 self.init_deprecation_warnings()
694 695 self.hooks.late_startup_hook()
695 696 self.events.trigger('shell_initialized', self)
696 697 atexit.register(self.atexit_operations)
697 698
698 699 # The trio runner is used for running Trio in the foreground thread. It
699 700 # is different from `_trio_runner(async_fn)` in `async_helpers.py`
700 701 # which calls `trio.run()` for every cell. This runner runs all cells
701 702 # inside a single Trio event loop. If used, it is set from
702 703 # `ipykernel.kernelapp`.
703 704 self.trio_runner = None
704 705
705 706 def get_ipython(self):
706 707 """Return the currently running IPython instance."""
707 708 return self
708 709
709 710 #-------------------------------------------------------------------------
710 711 # Trait changed handlers
711 712 #-------------------------------------------------------------------------
712 713 @observe('ipython_dir')
713 714 def _ipython_dir_changed(self, change):
714 715 ensure_dir_exists(change['new'])
715 716
716 717 def set_autoindent(self,value=None):
717 718 """Set the autoindent flag.
718 719
719 720 If called with no arguments, it acts as a toggle."""
720 721 if value is None:
721 722 self.autoindent = not self.autoindent
722 723 else:
723 724 self.autoindent = value
724 725
725 726 def set_trio_runner(self, tr):
726 727 self.trio_runner = tr
727 728
728 729 #-------------------------------------------------------------------------
729 730 # init_* methods called by __init__
730 731 #-------------------------------------------------------------------------
731 732
732 733 def init_ipython_dir(self, ipython_dir):
733 734 if ipython_dir is not None:
734 735 self.ipython_dir = ipython_dir
735 736 return
736 737
737 738 self.ipython_dir = get_ipython_dir()
738 739
739 740 def init_profile_dir(self, profile_dir):
740 741 if profile_dir is not None:
741 742 self.profile_dir = profile_dir
742 743 return
743 744 self.profile_dir = ProfileDir.create_profile_dir_by_name(
744 745 self.ipython_dir, "default"
745 746 )
746 747
747 748 def init_instance_attrs(self):
748 749 self.more = False
749 750
750 751 # command compiler
751 self.compile = CachingCompiler()
752 self.compile = self.compiler_class()
752 753
753 754 # Make an empty namespace, which extension writers can rely on both
754 755 # existing and NEVER being used by ipython itself. This gives them a
755 756 # convenient location for storing additional information and state
756 757 # their extensions may require, without fear of collisions with other
757 758 # ipython names that may develop later.
758 759 self.meta = Struct()
759 760
760 761 # Temporary files used for various purposes. Deleted at exit.
761 762 # The files here are stored with Path from Pathlib
762 763 self.tempfiles = []
763 764 self.tempdirs = []
764 765
765 766 # keep track of where we started running (mainly for crash post-mortem)
766 767 # This is not being used anywhere currently.
767 768 self.starting_dir = os.getcwd()
768 769
769 770 # Indentation management
770 771 self.indent_current_nsp = 0
771 772
772 773 # Dict to track post-execution functions that have been registered
773 774 self._post_execute = {}
774 775
775 776 def init_environment(self):
776 777 """Any changes we need to make to the user's environment."""
777 778 pass
778 779
779 780 def init_encoding(self):
780 781 # Get system encoding at startup time. Certain terminals (like Emacs
781 782 # under Win32 have it set to None, and we need to have a known valid
782 783 # encoding to use in the raw_input() method
783 784 try:
784 785 self.stdin_encoding = sys.stdin.encoding or 'ascii'
785 786 except AttributeError:
786 787 self.stdin_encoding = 'ascii'
787 788
788 789
789 790 @observe('colors')
790 791 def init_syntax_highlighting(self, changes=None):
791 792 # Python source parser/formatter for syntax highlighting
792 793 pyformat = PyColorize.Parser(style=self.colors, parent=self).format
793 794 self.pycolorize = lambda src: pyformat(src,'str')
794 795
795 796 def refresh_style(self):
796 797 # No-op here, used in subclass
797 798 pass
798 799
799 800 def init_pushd_popd_magic(self):
800 801 # for pushd/popd management
801 802 self.home_dir = get_home_dir()
802 803
803 804 self.dir_stack = []
804 805
805 806 def init_logger(self):
806 807 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
807 808 logmode='rotate')
808 809
809 810 def init_logstart(self):
810 811 """Initialize logging in case it was requested at the command line.
811 812 """
812 813 if self.logappend:
813 814 self.magic('logstart %s append' % self.logappend)
814 815 elif self.logfile:
815 816 self.magic('logstart %s' % self.logfile)
816 817 elif self.logstart:
817 818 self.magic('logstart')
818 819
819 820 def init_deprecation_warnings(self):
820 821 """
821 822 register default filter for deprecation warning.
822 823
823 824 This will allow deprecation warning of function used interactively to show
824 825 warning to users, and still hide deprecation warning from libraries import.
825 826 """
826 827 if sys.version_info < (3,7):
827 828 warnings.filterwarnings("default", category=DeprecationWarning, module=self.user_ns.get("__name__"))
828 829
829 830
830 831 def init_builtins(self):
831 832 # A single, static flag that we set to True. Its presence indicates
832 833 # that an IPython shell has been created, and we make no attempts at
833 834 # removing on exit or representing the existence of more than one
834 835 # IPython at a time.
835 836 builtin_mod.__dict__['__IPYTHON__'] = True
836 837 builtin_mod.__dict__['display'] = display
837 838
838 839 self.builtin_trap = BuiltinTrap(shell=self)
839 840
840 841 @observe('colors')
841 842 def init_inspector(self, changes=None):
842 843 # Object inspector
843 844 self.inspector = oinspect.Inspector(oinspect.InspectColors,
844 845 PyColorize.ANSICodeColors,
845 846 self.colors,
846 847 self.object_info_string_level)
847 848
848 849 def init_io(self):
849 850 # This will just use sys.stdout and sys.stderr. If you want to
850 851 # override sys.stdout and sys.stderr themselves, you need to do that
851 852 # *before* instantiating this class, because io holds onto
852 853 # references to the underlying streams.
853 854 # io.std* are deprecated, but don't show our own deprecation warnings
854 855 # during initialization of the deprecated API.
855 856 with warnings.catch_warnings():
856 857 warnings.simplefilter('ignore', DeprecationWarning)
857 858 io.stdout = io.IOStream(sys.stdout)
858 859 io.stderr = io.IOStream(sys.stderr)
859 860
860 861 def init_prompts(self):
861 862 # Set system prompts, so that scripts can decide if they are running
862 863 # interactively.
863 864 sys.ps1 = 'In : '
864 865 sys.ps2 = '...: '
865 866 sys.ps3 = 'Out: '
866 867
867 868 def init_display_formatter(self):
868 869 self.display_formatter = DisplayFormatter(parent=self)
869 870 self.configurables.append(self.display_formatter)
870 871
871 872 def init_display_pub(self):
872 873 self.display_pub = self.display_pub_class(parent=self, shell=self)
873 874 self.configurables.append(self.display_pub)
874 875
875 876 def init_data_pub(self):
876 877 if not self.data_pub_class:
877 878 self.data_pub = None
878 879 return
879 880 self.data_pub = self.data_pub_class(parent=self)
880 881 self.configurables.append(self.data_pub)
881 882
882 883 def init_displayhook(self):
883 884 # Initialize displayhook, set in/out prompts and printing system
884 885 self.displayhook = self.displayhook_class(
885 886 parent=self,
886 887 shell=self,
887 888 cache_size=self.cache_size,
888 889 )
889 890 self.configurables.append(self.displayhook)
890 891 # This is a context manager that installs/revmoes the displayhook at
891 892 # the appropriate time.
892 893 self.display_trap = DisplayTrap(hook=self.displayhook)
893 894
894 895 def init_virtualenv(self):
895 896 """Add the current virtualenv to sys.path so the user can import modules from it.
896 897 This isn't perfect: it doesn't use the Python interpreter with which the
897 898 virtualenv was built, and it ignores the --no-site-packages option. A
898 899 warning will appear suggesting the user installs IPython in the
899 900 virtualenv, but for many cases, it probably works well enough.
900 901
901 902 Adapted from code snippets online.
902 903
903 904 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
904 905 """
905 906 if 'VIRTUAL_ENV' not in os.environ:
906 907 # Not in a virtualenv
907 908 return
908 909 elif os.environ["VIRTUAL_ENV"] == "":
909 910 warn("Virtual env path set to '', please check if this is intended.")
910 911 return
911 912
912 913 p = Path(sys.executable)
913 914 p_venv = Path(os.environ["VIRTUAL_ENV"])
914 915
915 916 # fallback venv detection:
916 917 # stdlib venv may symlink sys.executable, so we can't use realpath.
917 918 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
918 919 # So we just check every item in the symlink tree (generally <= 3)
919 920 paths = [p]
920 921 while p.is_symlink():
921 922 p = Path(os.readlink(p))
922 923 paths.append(p.resolve())
923 924
924 925 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
925 926 if str(p_venv).startswith("\\cygdrive"):
926 927 p_venv = Path(str(p_venv)[11:])
927 928 elif len(str(p_venv)) >= 2 and str(p_venv)[1] == ":":
928 929 p_venv = Path(str(p_venv)[2:])
929 930
930 931 if any(os.fspath(p_venv) in os.fspath(p) for p in paths):
931 932 # Our exe is inside or has access to the virtualenv, don't need to do anything.
932 933 return
933 934
934 warn("Attempting to work in a virtualenv. If you encounter problems, please "
935 "install IPython inside the virtualenv.")
936 935 if sys.platform == "win32":
937 virtual_env = Path(os.environ["VIRTUAL_ENV"]).joinpath(
938 "Lib", "site-packages"
939 )
936 virtual_env = Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages")
940 937 else:
941 virtual_env = Path(os.environ["VIRTUAL_ENV"]).joinpath(
942 "lib", "python{}.{}".format(*sys.version_info[:2]), "site-packages"
938 virtual_env_path = Path(
939 os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
943 940 )
941 p_ver = sys.version_info[:2]
942
943 # Predict version from py[thon]-x.x in the $VIRTUAL_ENV
944 re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
945 if re_m:
946 predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
947 if predicted_path.exists():
948 p_ver = re_m.groups()
944 949
950 virtual_env = str(virtual_env_path).format(*p_ver)
951
952 warn(
953 "Attempting to work in a virtualenv. If you encounter problems, "
954 "please install IPython inside the virtualenv."
955 )
945 956 import site
946 957 sys.path.insert(0, virtual_env)
947 958 site.addsitedir(virtual_env)
948 959
949 960 #-------------------------------------------------------------------------
950 961 # Things related to injections into the sys module
951 962 #-------------------------------------------------------------------------
952 963
953 964 def save_sys_module_state(self):
954 965 """Save the state of hooks in the sys module.
955 966
956 967 This has to be called after self.user_module is created.
957 968 """
958 969 self._orig_sys_module_state = {'stdin': sys.stdin,
959 970 'stdout': sys.stdout,
960 971 'stderr': sys.stderr,
961 972 'excepthook': sys.excepthook}
962 973 self._orig_sys_modules_main_name = self.user_module.__name__
963 974 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
964 975
965 976 def restore_sys_module_state(self):
966 977 """Restore the state of the sys module."""
967 978 try:
968 979 for k, v in self._orig_sys_module_state.items():
969 980 setattr(sys, k, v)
970 981 except AttributeError:
971 982 pass
972 983 # Reset what what done in self.init_sys_modules
973 984 if self._orig_sys_modules_main_mod is not None:
974 985 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
975 986
976 987 #-------------------------------------------------------------------------
977 988 # Things related to the banner
978 989 #-------------------------------------------------------------------------
979 990
980 991 @property
981 992 def banner(self):
982 993 banner = self.banner1
983 994 if self.profile and self.profile != 'default':
984 995 banner += '\nIPython profile: %s\n' % self.profile
985 996 if self.banner2:
986 997 banner += '\n' + self.banner2
987 998 return banner
988 999
989 1000 def show_banner(self, banner=None):
990 1001 if banner is None:
991 1002 banner = self.banner
992 1003 sys.stdout.write(banner)
993 1004
994 1005 #-------------------------------------------------------------------------
995 1006 # Things related to hooks
996 1007 #-------------------------------------------------------------------------
997 1008
998 1009 def init_hooks(self):
999 1010 # hooks holds pointers used for user-side customizations
1000 1011 self.hooks = Struct()
1001 1012
1002 1013 self.strdispatchers = {}
1003 1014
1004 1015 # Set all default hooks, defined in the IPython.hooks module.
1005 1016 hooks = IPython.core.hooks
1006 1017 for hook_name in hooks.__all__:
1007 1018 # default hooks have priority 100, i.e. low; user hooks should have
1008 1019 # 0-100 priority
1009 1020 self.set_hook(hook_name,getattr(hooks,hook_name), 100, _warn_deprecated=False)
1010 1021
1011 1022 if self.display_page:
1012 1023 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
1013 1024
1014 1025 def set_hook(self,name,hook, priority=50, str_key=None, re_key=None,
1015 1026 _warn_deprecated=True):
1016 1027 """set_hook(name,hook) -> sets an internal IPython hook.
1017 1028
1018 1029 IPython exposes some of its internal API as user-modifiable hooks. By
1019 1030 adding your function to one of these hooks, you can modify IPython's
1020 1031 behavior to call at runtime your own routines."""
1021 1032
1022 1033 # At some point in the future, this should validate the hook before it
1023 1034 # accepts it. Probably at least check that the hook takes the number
1024 1035 # of args it's supposed to.
1025 1036
1026 1037 f = types.MethodType(hook,self)
1027 1038
1028 1039 # check if the hook is for strdispatcher first
1029 1040 if str_key is not None:
1030 1041 sdp = self.strdispatchers.get(name, StrDispatch())
1031 1042 sdp.add_s(str_key, f, priority )
1032 1043 self.strdispatchers[name] = sdp
1033 1044 return
1034 1045 if re_key is not None:
1035 1046 sdp = self.strdispatchers.get(name, StrDispatch())
1036 1047 sdp.add_re(re.compile(re_key), f, priority )
1037 1048 self.strdispatchers[name] = sdp
1038 1049 return
1039 1050
1040 1051 dp = getattr(self.hooks, name, None)
1041 1052 if name not in IPython.core.hooks.__all__:
1042 1053 print("Warning! Hook '%s' is not one of %s" % \
1043 1054 (name, IPython.core.hooks.__all__ ))
1044 1055
1045 1056 if _warn_deprecated and (name in IPython.core.hooks.deprecated):
1046 1057 alternative = IPython.core.hooks.deprecated[name]
1047 1058 warn("Hook {} is deprecated. Use {} instead.".format(name, alternative), stacklevel=2)
1048 1059
1049 1060 if not dp:
1050 1061 dp = IPython.core.hooks.CommandChainDispatcher()
1051 1062
1052 1063 try:
1053 1064 dp.add(f,priority)
1054 1065 except AttributeError:
1055 1066 # it was not commandchain, plain old func - replace
1056 1067 dp = f
1057 1068
1058 1069 setattr(self.hooks,name, dp)
1059 1070
1060 1071 #-------------------------------------------------------------------------
1061 1072 # Things related to events
1062 1073 #-------------------------------------------------------------------------
1063 1074
1064 1075 def init_events(self):
1065 1076 self.events = EventManager(self, available_events)
1066 1077
1067 1078 self.events.register("pre_execute", self._clear_warning_registry)
1068 1079
1069 1080 def register_post_execute(self, func):
1070 1081 """DEPRECATED: Use ip.events.register('post_run_cell', func)
1071 1082
1072 1083 Register a function for calling after code execution.
1073 1084 """
1074 1085 warn("ip.register_post_execute is deprecated, use "
1075 1086 "ip.events.register('post_run_cell', func) instead.", stacklevel=2)
1076 1087 self.events.register('post_run_cell', func)
1077 1088
1078 1089 def _clear_warning_registry(self):
1079 1090 # clear the warning registry, so that different code blocks with
1080 1091 # overlapping line number ranges don't cause spurious suppression of
1081 1092 # warnings (see gh-6611 for details)
1082 1093 if "__warningregistry__" in self.user_global_ns:
1083 1094 del self.user_global_ns["__warningregistry__"]
1084 1095
1085 1096 #-------------------------------------------------------------------------
1086 1097 # Things related to the "main" module
1087 1098 #-------------------------------------------------------------------------
1088 1099
1089 1100 def new_main_mod(self, filename, modname):
1090 1101 """Return a new 'main' module object for user code execution.
1091 1102
1092 1103 ``filename`` should be the path of the script which will be run in the
1093 1104 module. Requests with the same filename will get the same module, with
1094 1105 its namespace cleared.
1095 1106
1096 1107 ``modname`` should be the module name - normally either '__main__' or
1097 1108 the basename of the file without the extension.
1098 1109
1099 1110 When scripts are executed via %run, we must keep a reference to their
1100 1111 __main__ module around so that Python doesn't
1101 1112 clear it, rendering references to module globals useless.
1102 1113
1103 1114 This method keeps said reference in a private dict, keyed by the
1104 1115 absolute path of the script. This way, for multiple executions of the
1105 1116 same script we only keep one copy of the namespace (the last one),
1106 1117 thus preventing memory leaks from old references while allowing the
1107 1118 objects from the last execution to be accessible.
1108 1119 """
1109 1120 filename = os.path.abspath(filename)
1110 1121 try:
1111 1122 main_mod = self._main_mod_cache[filename]
1112 1123 except KeyError:
1113 1124 main_mod = self._main_mod_cache[filename] = types.ModuleType(
1114 1125 modname,
1115 1126 doc="Module created for script run in IPython")
1116 1127 else:
1117 1128 main_mod.__dict__.clear()
1118 1129 main_mod.__name__ = modname
1119 1130
1120 1131 main_mod.__file__ = filename
1121 1132 # It seems pydoc (and perhaps others) needs any module instance to
1122 1133 # implement a __nonzero__ method
1123 1134 main_mod.__nonzero__ = lambda : True
1124 1135
1125 1136 return main_mod
1126 1137
1127 1138 def clear_main_mod_cache(self):
1128 1139 """Clear the cache of main modules.
1129 1140
1130 1141 Mainly for use by utilities like %reset.
1131 1142
1132 1143 Examples
1133 1144 --------
1134 1145 In [15]: import IPython
1135 1146
1136 1147 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
1137 1148
1138 1149 In [17]: len(_ip._main_mod_cache) > 0
1139 1150 Out[17]: True
1140 1151
1141 1152 In [18]: _ip.clear_main_mod_cache()
1142 1153
1143 1154 In [19]: len(_ip._main_mod_cache) == 0
1144 1155 Out[19]: True
1145 1156 """
1146 1157 self._main_mod_cache.clear()
1147 1158
1148 1159 #-------------------------------------------------------------------------
1149 1160 # Things related to debugging
1150 1161 #-------------------------------------------------------------------------
1151 1162
1152 1163 def init_pdb(self):
1153 1164 # Set calling of pdb on exceptions
1154 1165 # self.call_pdb is a property
1155 1166 self.call_pdb = self.pdb
1156 1167
1157 1168 def _get_call_pdb(self):
1158 1169 return self._call_pdb
1159 1170
1160 1171 def _set_call_pdb(self,val):
1161 1172
1162 1173 if val not in (0,1,False,True):
1163 1174 raise ValueError('new call_pdb value must be boolean')
1164 1175
1165 1176 # store value in instance
1166 1177 self._call_pdb = val
1167 1178
1168 1179 # notify the actual exception handlers
1169 1180 self.InteractiveTB.call_pdb = val
1170 1181
1171 1182 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
1172 1183 'Control auto-activation of pdb at exceptions')
1173 1184
1174 1185 def debugger(self,force=False):
1175 1186 """Call the pdb debugger.
1176 1187
1177 1188 Keywords:
1178 1189
1179 1190 - force(False): by default, this routine checks the instance call_pdb
1180 1191 flag and does not actually invoke the debugger if the flag is false.
1181 1192 The 'force' option forces the debugger to activate even if the flag
1182 1193 is false.
1183 1194 """
1184 1195
1185 1196 if not (force or self.call_pdb):
1186 1197 return
1187 1198
1188 1199 if not hasattr(sys,'last_traceback'):
1189 1200 error('No traceback has been produced, nothing to debug.')
1190 1201 return
1191 1202
1192 1203 self.InteractiveTB.debugger(force=True)
1193 1204
1194 1205 #-------------------------------------------------------------------------
1195 1206 # Things related to IPython's various namespaces
1196 1207 #-------------------------------------------------------------------------
1197 1208 default_user_namespaces = True
1198 1209
1199 1210 def init_create_namespaces(self, user_module=None, user_ns=None):
1200 1211 # Create the namespace where the user will operate. user_ns is
1201 1212 # normally the only one used, and it is passed to the exec calls as
1202 1213 # the locals argument. But we do carry a user_global_ns namespace
1203 1214 # given as the exec 'globals' argument, This is useful in embedding
1204 1215 # situations where the ipython shell opens in a context where the
1205 1216 # distinction between locals and globals is meaningful. For
1206 1217 # non-embedded contexts, it is just the same object as the user_ns dict.
1207 1218
1208 1219 # FIXME. For some strange reason, __builtins__ is showing up at user
1209 1220 # level as a dict instead of a module. This is a manual fix, but I
1210 1221 # should really track down where the problem is coming from. Alex
1211 1222 # Schmolck reported this problem first.
1212 1223
1213 1224 # A useful post by Alex Martelli on this topic:
1214 1225 # Re: inconsistent value from __builtins__
1215 1226 # Von: Alex Martelli <aleaxit@yahoo.com>
1216 1227 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1217 1228 # Gruppen: comp.lang.python
1218 1229
1219 1230 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1220 1231 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1221 1232 # > <type 'dict'>
1222 1233 # > >>> print type(__builtins__)
1223 1234 # > <type 'module'>
1224 1235 # > Is this difference in return value intentional?
1225 1236
1226 1237 # Well, it's documented that '__builtins__' can be either a dictionary
1227 1238 # or a module, and it's been that way for a long time. Whether it's
1228 1239 # intentional (or sensible), I don't know. In any case, the idea is
1229 1240 # that if you need to access the built-in namespace directly, you
1230 1241 # should start with "import __builtin__" (note, no 's') which will
1231 1242 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1232 1243
1233 1244 # These routines return a properly built module and dict as needed by
1234 1245 # the rest of the code, and can also be used by extension writers to
1235 1246 # generate properly initialized namespaces.
1236 1247 if (user_ns is not None) or (user_module is not None):
1237 1248 self.default_user_namespaces = False
1238 1249 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1239 1250
1240 1251 # A record of hidden variables we have added to the user namespace, so
1241 1252 # we can list later only variables defined in actual interactive use.
1242 1253 self.user_ns_hidden = {}
1243 1254
1244 1255 # Now that FakeModule produces a real module, we've run into a nasty
1245 1256 # problem: after script execution (via %run), the module where the user
1246 1257 # code ran is deleted. Now that this object is a true module (needed
1247 1258 # so doctest and other tools work correctly), the Python module
1248 1259 # teardown mechanism runs over it, and sets to None every variable
1249 1260 # present in that module. Top-level references to objects from the
1250 1261 # script survive, because the user_ns is updated with them. However,
1251 1262 # calling functions defined in the script that use other things from
1252 1263 # the script will fail, because the function's closure had references
1253 1264 # to the original objects, which are now all None. So we must protect
1254 1265 # these modules from deletion by keeping a cache.
1255 1266 #
1256 1267 # To avoid keeping stale modules around (we only need the one from the
1257 1268 # last run), we use a dict keyed with the full path to the script, so
1258 1269 # only the last version of the module is held in the cache. Note,
1259 1270 # however, that we must cache the module *namespace contents* (their
1260 1271 # __dict__). Because if we try to cache the actual modules, old ones
1261 1272 # (uncached) could be destroyed while still holding references (such as
1262 1273 # those held by GUI objects that tend to be long-lived)>
1263 1274 #
1264 1275 # The %reset command will flush this cache. See the cache_main_mod()
1265 1276 # and clear_main_mod_cache() methods for details on use.
1266 1277
1267 1278 # This is the cache used for 'main' namespaces
1268 1279 self._main_mod_cache = {}
1269 1280
1270 1281 # A table holding all the namespaces IPython deals with, so that
1271 1282 # introspection facilities can search easily.
1272 1283 self.ns_table = {'user_global':self.user_module.__dict__,
1273 1284 'user_local':self.user_ns,
1274 1285 'builtin':builtin_mod.__dict__
1275 1286 }
1276 1287
1277 1288 @property
1278 1289 def user_global_ns(self):
1279 1290 return self.user_module.__dict__
1280 1291
1281 1292 def prepare_user_module(self, user_module=None, user_ns=None):
1282 1293 """Prepare the module and namespace in which user code will be run.
1283 1294
1284 1295 When IPython is started normally, both parameters are None: a new module
1285 1296 is created automatically, and its __dict__ used as the namespace.
1286 1297
1287 1298 If only user_module is provided, its __dict__ is used as the namespace.
1288 1299 If only user_ns is provided, a dummy module is created, and user_ns
1289 1300 becomes the global namespace. If both are provided (as they may be
1290 1301 when embedding), user_ns is the local namespace, and user_module
1291 1302 provides the global namespace.
1292 1303
1293 1304 Parameters
1294 1305 ----------
1295 1306 user_module : module, optional
1296 1307 The current user module in which IPython is being run. If None,
1297 1308 a clean module will be created.
1298 1309 user_ns : dict, optional
1299 1310 A namespace in which to run interactive commands.
1300 1311
1301 1312 Returns
1302 1313 -------
1303 1314 A tuple of user_module and user_ns, each properly initialised.
1304 1315 """
1305 1316 if user_module is None and user_ns is not None:
1306 1317 user_ns.setdefault("__name__", "__main__")
1307 1318 user_module = DummyMod()
1308 1319 user_module.__dict__ = user_ns
1309 1320
1310 1321 if user_module is None:
1311 1322 user_module = types.ModuleType("__main__",
1312 1323 doc="Automatically created module for IPython interactive environment")
1313 1324
1314 1325 # We must ensure that __builtin__ (without the final 's') is always
1315 1326 # available and pointing to the __builtin__ *module*. For more details:
1316 1327 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1317 1328 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1318 1329 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1319 1330
1320 1331 if user_ns is None:
1321 1332 user_ns = user_module.__dict__
1322 1333
1323 1334 return user_module, user_ns
1324 1335
1325 1336 def init_sys_modules(self):
1326 1337 # We need to insert into sys.modules something that looks like a
1327 1338 # module but which accesses the IPython namespace, for shelve and
1328 1339 # pickle to work interactively. Normally they rely on getting
1329 1340 # everything out of __main__, but for embedding purposes each IPython
1330 1341 # instance has its own private namespace, so we can't go shoving
1331 1342 # everything into __main__.
1332 1343
1333 1344 # note, however, that we should only do this for non-embedded
1334 1345 # ipythons, which really mimic the __main__.__dict__ with their own
1335 1346 # namespace. Embedded instances, on the other hand, should not do
1336 1347 # this because they need to manage the user local/global namespaces
1337 1348 # only, but they live within a 'normal' __main__ (meaning, they
1338 1349 # shouldn't overtake the execution environment of the script they're
1339 1350 # embedded in).
1340 1351
1341 1352 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1342 1353 main_name = self.user_module.__name__
1343 1354 sys.modules[main_name] = self.user_module
1344 1355
1345 1356 def init_user_ns(self):
1346 1357 """Initialize all user-visible namespaces to their minimum defaults.
1347 1358
1348 1359 Certain history lists are also initialized here, as they effectively
1349 1360 act as user namespaces.
1350 1361
1351 1362 Notes
1352 1363 -----
1353 1364 All data structures here are only filled in, they are NOT reset by this
1354 1365 method. If they were not empty before, data will simply be added to
1355 1366 them.
1356 1367 """
1357 1368 # This function works in two parts: first we put a few things in
1358 1369 # user_ns, and we sync that contents into user_ns_hidden so that these
1359 1370 # initial variables aren't shown by %who. After the sync, we add the
1360 1371 # rest of what we *do* want the user to see with %who even on a new
1361 1372 # session (probably nothing, so they really only see their own stuff)
1362 1373
1363 1374 # The user dict must *always* have a __builtin__ reference to the
1364 1375 # Python standard __builtin__ namespace, which must be imported.
1365 1376 # This is so that certain operations in prompt evaluation can be
1366 1377 # reliably executed with builtins. Note that we can NOT use
1367 1378 # __builtins__ (note the 's'), because that can either be a dict or a
1368 1379 # module, and can even mutate at runtime, depending on the context
1369 1380 # (Python makes no guarantees on it). In contrast, __builtin__ is
1370 1381 # always a module object, though it must be explicitly imported.
1371 1382
1372 1383 # For more details:
1373 1384 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1374 1385 ns = {}
1375 1386
1376 1387 # make global variables for user access to the histories
1377 1388 ns['_ih'] = self.history_manager.input_hist_parsed
1378 1389 ns['_oh'] = self.history_manager.output_hist
1379 1390 ns['_dh'] = self.history_manager.dir_hist
1380 1391
1381 1392 # user aliases to input and output histories. These shouldn't show up
1382 1393 # in %who, as they can have very large reprs.
1383 1394 ns['In'] = self.history_manager.input_hist_parsed
1384 1395 ns['Out'] = self.history_manager.output_hist
1385 1396
1386 1397 # Store myself as the public api!!!
1387 1398 ns['get_ipython'] = self.get_ipython
1388 1399
1389 1400 ns['exit'] = self.exiter
1390 1401 ns['quit'] = self.exiter
1391 1402
1392 1403 # Sync what we've added so far to user_ns_hidden so these aren't seen
1393 1404 # by %who
1394 1405 self.user_ns_hidden.update(ns)
1395 1406
1396 1407 # Anything put into ns now would show up in %who. Think twice before
1397 1408 # putting anything here, as we really want %who to show the user their
1398 1409 # stuff, not our variables.
1399 1410
1400 1411 # Finally, update the real user's namespace
1401 1412 self.user_ns.update(ns)
1402 1413
1403 1414 @property
1404 1415 def all_ns_refs(self):
1405 1416 """Get a list of references to all the namespace dictionaries in which
1406 1417 IPython might store a user-created object.
1407 1418
1408 1419 Note that this does not include the displayhook, which also caches
1409 1420 objects from the output."""
1410 1421 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1411 1422 [m.__dict__ for m in self._main_mod_cache.values()]
1412 1423
1413 1424 def reset(self, new_session=True, aggressive=False):
1414 1425 """Clear all internal namespaces, and attempt to release references to
1415 1426 user objects.
1416 1427
1417 1428 If new_session is True, a new history session will be opened.
1418 1429 """
1419 1430 # Clear histories
1420 1431 self.history_manager.reset(new_session)
1421 1432 # Reset counter used to index all histories
1422 1433 if new_session:
1423 1434 self.execution_count = 1
1424 1435
1425 1436 # Reset last execution result
1426 1437 self.last_execution_succeeded = True
1427 1438 self.last_execution_result = None
1428 1439
1429 1440 # Flush cached output items
1430 1441 if self.displayhook.do_full_cache:
1431 1442 self.displayhook.flush()
1432 1443
1433 1444 # The main execution namespaces must be cleared very carefully,
1434 1445 # skipping the deletion of the builtin-related keys, because doing so
1435 1446 # would cause errors in many object's __del__ methods.
1436 1447 if self.user_ns is not self.user_global_ns:
1437 1448 self.user_ns.clear()
1438 1449 ns = self.user_global_ns
1439 1450 drop_keys = set(ns.keys())
1440 1451 drop_keys.discard('__builtin__')
1441 1452 drop_keys.discard('__builtins__')
1442 1453 drop_keys.discard('__name__')
1443 1454 for k in drop_keys:
1444 1455 del ns[k]
1445 1456
1446 1457 self.user_ns_hidden.clear()
1447 1458
1448 1459 # Restore the user namespaces to minimal usability
1449 1460 self.init_user_ns()
1450 1461 if aggressive and not hasattr(self, "_sys_modules_keys"):
1451 1462 print("Cannot restore sys.module, no snapshot")
1452 1463 elif aggressive:
1453 1464 print("culling sys module...")
1454 1465 current_keys = set(sys.modules.keys())
1455 1466 for k in current_keys - self._sys_modules_keys:
1456 1467 if k.startswith("multiprocessing"):
1457 1468 continue
1458 1469 del sys.modules[k]
1459 1470
1460 1471 # Restore the default and user aliases
1461 1472 self.alias_manager.clear_aliases()
1462 1473 self.alias_manager.init_aliases()
1463 1474
1464 1475 # Now define aliases that only make sense on the terminal, because they
1465 1476 # need direct access to the console in a way that we can't emulate in
1466 1477 # GUI or web frontend
1467 1478 if os.name == 'posix':
1468 1479 for cmd in ('clear', 'more', 'less', 'man'):
1469 1480 if cmd not in self.magics_manager.magics['line']:
1470 1481 self.alias_manager.soft_define_alias(cmd, cmd)
1471 1482
1472 1483 # Flush the private list of module references kept for script
1473 1484 # execution protection
1474 1485 self.clear_main_mod_cache()
1475 1486
1476 1487 def del_var(self, varname, by_name=False):
1477 1488 """Delete a variable from the various namespaces, so that, as
1478 1489 far as possible, we're not keeping any hidden references to it.
1479 1490
1480 1491 Parameters
1481 1492 ----------
1482 1493 varname : str
1483 1494 The name of the variable to delete.
1484 1495 by_name : bool
1485 1496 If True, delete variables with the given name in each
1486 1497 namespace. If False (default), find the variable in the user
1487 1498 namespace, and delete references to it.
1488 1499 """
1489 1500 if varname in ('__builtin__', '__builtins__'):
1490 1501 raise ValueError("Refusing to delete %s" % varname)
1491 1502
1492 1503 ns_refs = self.all_ns_refs
1493 1504
1494 1505 if by_name: # Delete by name
1495 1506 for ns in ns_refs:
1496 1507 try:
1497 1508 del ns[varname]
1498 1509 except KeyError:
1499 1510 pass
1500 1511 else: # Delete by object
1501 1512 try:
1502 1513 obj = self.user_ns[varname]
1503 1514 except KeyError as e:
1504 1515 raise NameError("name '%s' is not defined" % varname) from e
1505 1516 # Also check in output history
1506 1517 ns_refs.append(self.history_manager.output_hist)
1507 1518 for ns in ns_refs:
1508 1519 to_delete = [n for n, o in ns.items() if o is obj]
1509 1520 for name in to_delete:
1510 1521 del ns[name]
1511 1522
1512 1523 # Ensure it is removed from the last execution result
1513 1524 if self.last_execution_result.result is obj:
1514 1525 self.last_execution_result = None
1515 1526
1516 1527 # displayhook keeps extra references, but not in a dictionary
1517 1528 for name in ('_', '__', '___'):
1518 1529 if getattr(self.displayhook, name) is obj:
1519 1530 setattr(self.displayhook, name, None)
1520 1531
1521 1532 def reset_selective(self, regex=None):
1522 1533 """Clear selective variables from internal namespaces based on a
1523 1534 specified regular expression.
1524 1535
1525 1536 Parameters
1526 1537 ----------
1527 1538 regex : string or compiled pattern, optional
1528 1539 A regular expression pattern that will be used in searching
1529 1540 variable names in the users namespaces.
1530 1541 """
1531 1542 if regex is not None:
1532 1543 try:
1533 1544 m = re.compile(regex)
1534 1545 except TypeError as e:
1535 1546 raise TypeError('regex must be a string or compiled pattern') from e
1536 1547 # Search for keys in each namespace that match the given regex
1537 1548 # If a match is found, delete the key/value pair.
1538 1549 for ns in self.all_ns_refs:
1539 1550 for var in ns:
1540 1551 if m.search(var):
1541 1552 del ns[var]
1542 1553
1543 1554 def push(self, variables, interactive=True):
1544 1555 """Inject a group of variables into the IPython user namespace.
1545 1556
1546 1557 Parameters
1547 1558 ----------
1548 1559 variables : dict, str or list/tuple of str
1549 1560 The variables to inject into the user's namespace. If a dict, a
1550 1561 simple update is done. If a str, the string is assumed to have
1551 1562 variable names separated by spaces. A list/tuple of str can also
1552 1563 be used to give the variable names. If just the variable names are
1553 1564 give (list/tuple/str) then the variable values looked up in the
1554 1565 callers frame.
1555 1566 interactive : bool
1556 1567 If True (default), the variables will be listed with the ``who``
1557 1568 magic.
1558 1569 """
1559 1570 vdict = None
1560 1571
1561 1572 # We need a dict of name/value pairs to do namespace updates.
1562 1573 if isinstance(variables, dict):
1563 1574 vdict = variables
1564 1575 elif isinstance(variables, (str, list, tuple)):
1565 1576 if isinstance(variables, str):
1566 1577 vlist = variables.split()
1567 1578 else:
1568 1579 vlist = variables
1569 1580 vdict = {}
1570 1581 cf = sys._getframe(1)
1571 1582 for name in vlist:
1572 1583 try:
1573 1584 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1574 1585 except:
1575 1586 print('Could not get variable %s from %s' %
1576 1587 (name,cf.f_code.co_name))
1577 1588 else:
1578 1589 raise ValueError('variables must be a dict/str/list/tuple')
1579 1590
1580 1591 # Propagate variables to user namespace
1581 1592 self.user_ns.update(vdict)
1582 1593
1583 1594 # And configure interactive visibility
1584 1595 user_ns_hidden = self.user_ns_hidden
1585 1596 if interactive:
1586 1597 for name in vdict:
1587 1598 user_ns_hidden.pop(name, None)
1588 1599 else:
1589 1600 user_ns_hidden.update(vdict)
1590 1601
1591 1602 def drop_by_id(self, variables):
1592 1603 """Remove a dict of variables from the user namespace, if they are the
1593 1604 same as the values in the dictionary.
1594 1605
1595 1606 This is intended for use by extensions: variables that they've added can
1596 1607 be taken back out if they are unloaded, without removing any that the
1597 1608 user has overwritten.
1598 1609
1599 1610 Parameters
1600 1611 ----------
1601 1612 variables : dict
1602 1613 A dictionary mapping object names (as strings) to the objects.
1603 1614 """
1604 1615 for name, obj in variables.items():
1605 1616 if name in self.user_ns and self.user_ns[name] is obj:
1606 1617 del self.user_ns[name]
1607 1618 self.user_ns_hidden.pop(name, None)
1608 1619
1609 1620 #-------------------------------------------------------------------------
1610 1621 # Things related to object introspection
1611 1622 #-------------------------------------------------------------------------
1612 1623
1613 1624 def _ofind(self, oname, namespaces=None):
1614 1625 """Find an object in the available namespaces.
1615 1626
1616 1627 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1617 1628
1618 1629 Has special code to detect magic functions.
1619 1630 """
1620 1631 oname = oname.strip()
1621 1632 if not oname.startswith(ESC_MAGIC) and \
1622 1633 not oname.startswith(ESC_MAGIC2) and \
1623 1634 not all(a.isidentifier() for a in oname.split(".")):
1624 1635 return {'found': False}
1625 1636
1626 1637 if namespaces is None:
1627 1638 # Namespaces to search in:
1628 1639 # Put them in a list. The order is important so that we
1629 1640 # find things in the same order that Python finds them.
1630 1641 namespaces = [ ('Interactive', self.user_ns),
1631 1642 ('Interactive (global)', self.user_global_ns),
1632 1643 ('Python builtin', builtin_mod.__dict__),
1633 1644 ]
1634 1645
1635 1646 ismagic = False
1636 1647 isalias = False
1637 1648 found = False
1638 1649 ospace = None
1639 1650 parent = None
1640 1651 obj = None
1641 1652
1642 1653
1643 1654 # Look for the given name by splitting it in parts. If the head is
1644 1655 # found, then we look for all the remaining parts as members, and only
1645 1656 # declare success if we can find them all.
1646 1657 oname_parts = oname.split('.')
1647 1658 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1648 1659 for nsname,ns in namespaces:
1649 1660 try:
1650 1661 obj = ns[oname_head]
1651 1662 except KeyError:
1652 1663 continue
1653 1664 else:
1654 1665 for idx, part in enumerate(oname_rest):
1655 1666 try:
1656 1667 parent = obj
1657 1668 # The last part is looked up in a special way to avoid
1658 1669 # descriptor invocation as it may raise or have side
1659 1670 # effects.
1660 1671 if idx == len(oname_rest) - 1:
1661 1672 obj = self._getattr_property(obj, part)
1662 1673 else:
1663 1674 obj = getattr(obj, part)
1664 1675 except:
1665 1676 # Blanket except b/c some badly implemented objects
1666 1677 # allow __getattr__ to raise exceptions other than
1667 1678 # AttributeError, which then crashes IPython.
1668 1679 break
1669 1680 else:
1670 1681 # If we finish the for loop (no break), we got all members
1671 1682 found = True
1672 1683 ospace = nsname
1673 1684 break # namespace loop
1674 1685
1675 1686 # Try to see if it's magic
1676 1687 if not found:
1677 1688 obj = None
1678 1689 if oname.startswith(ESC_MAGIC2):
1679 1690 oname = oname.lstrip(ESC_MAGIC2)
1680 1691 obj = self.find_cell_magic(oname)
1681 1692 elif oname.startswith(ESC_MAGIC):
1682 1693 oname = oname.lstrip(ESC_MAGIC)
1683 1694 obj = self.find_line_magic(oname)
1684 1695 else:
1685 1696 # search without prefix, so run? will find %run?
1686 1697 obj = self.find_line_magic(oname)
1687 1698 if obj is None:
1688 1699 obj = self.find_cell_magic(oname)
1689 1700 if obj is not None:
1690 1701 found = True
1691 1702 ospace = 'IPython internal'
1692 1703 ismagic = True
1693 1704 isalias = isinstance(obj, Alias)
1694 1705
1695 1706 # Last try: special-case some literals like '', [], {}, etc:
1696 1707 if not found and oname_head in ["''",'""','[]','{}','()']:
1697 1708 obj = eval(oname_head)
1698 1709 found = True
1699 1710 ospace = 'Interactive'
1700 1711
1701 1712 return {
1702 1713 'obj':obj,
1703 1714 'found':found,
1704 1715 'parent':parent,
1705 1716 'ismagic':ismagic,
1706 1717 'isalias':isalias,
1707 1718 'namespace':ospace
1708 1719 }
1709 1720
1710 1721 @staticmethod
1711 1722 def _getattr_property(obj, attrname):
1712 1723 """Property-aware getattr to use in object finding.
1713 1724
1714 1725 If attrname represents a property, return it unevaluated (in case it has
1715 1726 side effects or raises an error.
1716 1727
1717 1728 """
1718 1729 if not isinstance(obj, type):
1719 1730 try:
1720 1731 # `getattr(type(obj), attrname)` is not guaranteed to return
1721 1732 # `obj`, but does so for property:
1722 1733 #
1723 1734 # property.__get__(self, None, cls) -> self
1724 1735 #
1725 1736 # The universal alternative is to traverse the mro manually
1726 1737 # searching for attrname in class dicts.
1727 1738 attr = getattr(type(obj), attrname)
1728 1739 except AttributeError:
1729 1740 pass
1730 1741 else:
1731 1742 # This relies on the fact that data descriptors (with both
1732 1743 # __get__ & __set__ magic methods) take precedence over
1733 1744 # instance-level attributes:
1734 1745 #
1735 1746 # class A(object):
1736 1747 # @property
1737 1748 # def foobar(self): return 123
1738 1749 # a = A()
1739 1750 # a.__dict__['foobar'] = 345
1740 1751 # a.foobar # == 123
1741 1752 #
1742 1753 # So, a property may be returned right away.
1743 1754 if isinstance(attr, property):
1744 1755 return attr
1745 1756
1746 1757 # Nothing helped, fall back.
1747 1758 return getattr(obj, attrname)
1748 1759
1749 1760 def _object_find(self, oname, namespaces=None):
1750 1761 """Find an object and return a struct with info about it."""
1751 1762 return Struct(self._ofind(oname, namespaces))
1752 1763
1753 1764 def _inspect(self, meth, oname, namespaces=None, **kw):
1754 1765 """Generic interface to the inspector system.
1755 1766
1756 1767 This function is meant to be called by pdef, pdoc & friends.
1757 1768 """
1758 1769 info = self._object_find(oname, namespaces)
1759 1770 docformat = sphinxify if self.sphinxify_docstring else None
1760 1771 if info.found:
1761 1772 pmethod = getattr(self.inspector, meth)
1762 1773 # TODO: only apply format_screen to the plain/text repr of the mime
1763 1774 # bundle.
1764 1775 formatter = format_screen if info.ismagic else docformat
1765 1776 if meth == 'pdoc':
1766 1777 pmethod(info.obj, oname, formatter)
1767 1778 elif meth == 'pinfo':
1768 pmethod(info.obj, oname, formatter, info,
1769 enable_html_pager=self.enable_html_pager, **kw)
1779 pmethod(
1780 info.obj,
1781 oname,
1782 formatter,
1783 info,
1784 enable_html_pager=self.enable_html_pager,
1785 **kw
1786 )
1770 1787 else:
1771 1788 pmethod(info.obj, oname)
1772 1789 else:
1773 1790 print('Object `%s` not found.' % oname)
1774 1791 return 'not found' # so callers can take other action
1775 1792
1776 1793 def object_inspect(self, oname, detail_level=0):
1777 1794 """Get object info about oname"""
1778 1795 with self.builtin_trap:
1779 1796 info = self._object_find(oname)
1780 1797 if info.found:
1781 1798 return self.inspector.info(info.obj, oname, info=info,
1782 1799 detail_level=detail_level
1783 1800 )
1784 1801 else:
1785 1802 return oinspect.object_info(name=oname, found=False)
1786 1803
1787 1804 def object_inspect_text(self, oname, detail_level=0):
1788 1805 """Get object info as formatted text"""
1789 1806 return self.object_inspect_mime(oname, detail_level)['text/plain']
1790 1807
1791 1808 def object_inspect_mime(self, oname, detail_level=0):
1792 1809 """Get object info as a mimebundle of formatted representations.
1793 1810
1794 1811 A mimebundle is a dictionary, keyed by mime-type.
1795 1812 It must always have the key `'text/plain'`.
1796 1813 """
1797 1814 with self.builtin_trap:
1798 1815 info = self._object_find(oname)
1799 1816 if info.found:
1800 1817 return self.inspector._get_info(info.obj, oname, info=info,
1801 1818 detail_level=detail_level
1802 1819 )
1803 1820 else:
1804 1821 raise KeyError(oname)
1805 1822
1806 1823 #-------------------------------------------------------------------------
1807 1824 # Things related to history management
1808 1825 #-------------------------------------------------------------------------
1809 1826
1810 1827 def init_history(self):
1811 1828 """Sets up the command history, and starts regular autosaves."""
1812 1829 self.history_manager = HistoryManager(shell=self, parent=self)
1813 1830 self.configurables.append(self.history_manager)
1814 1831
1815 1832 #-------------------------------------------------------------------------
1816 1833 # Things related to exception handling and tracebacks (not debugging)
1817 1834 #-------------------------------------------------------------------------
1818 1835
1819 1836 debugger_cls = Pdb
1820 1837
1821 1838 def init_traceback_handlers(self, custom_exceptions):
1822 1839 # Syntax error handler.
1823 1840 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor', parent=self)
1824 1841
1825 1842 # The interactive one is initialized with an offset, meaning we always
1826 1843 # want to remove the topmost item in the traceback, which is our own
1827 1844 # internal code. Valid modes: ['Plain','Context','Verbose','Minimal']
1828 1845 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1829 1846 color_scheme='NoColor',
1830 1847 tb_offset = 1,
1831 1848 check_cache=check_linecache_ipython,
1832 1849 debugger_cls=self.debugger_cls, parent=self)
1833 1850
1834 1851 # The instance will store a pointer to the system-wide exception hook,
1835 1852 # so that runtime code (such as magics) can access it. This is because
1836 1853 # during the read-eval loop, it may get temporarily overwritten.
1837 1854 self.sys_excepthook = sys.excepthook
1838 1855
1839 1856 # and add any custom exception handlers the user may have specified
1840 1857 self.set_custom_exc(*custom_exceptions)
1841 1858
1842 1859 # Set the exception mode
1843 1860 self.InteractiveTB.set_mode(mode=self.xmode)
1844 1861
1845 1862 def set_custom_exc(self, exc_tuple, handler):
1846 1863 """set_custom_exc(exc_tuple, handler)
1847 1864
1848 1865 Set a custom exception handler, which will be called if any of the
1849 1866 exceptions in exc_tuple occur in the mainloop (specifically, in the
1850 1867 run_code() method).
1851 1868
1852 1869 Parameters
1853 1870 ----------
1854 1871
1855 1872 exc_tuple : tuple of exception classes
1856 1873 A *tuple* of exception classes, for which to call the defined
1857 1874 handler. It is very important that you use a tuple, and NOT A
1858 1875 LIST here, because of the way Python's except statement works. If
1859 1876 you only want to trap a single exception, use a singleton tuple::
1860 1877
1861 1878 exc_tuple == (MyCustomException,)
1862 1879
1863 1880 handler : callable
1864 1881 handler must have the following signature::
1865 1882
1866 1883 def my_handler(self, etype, value, tb, tb_offset=None):
1867 1884 ...
1868 1885 return structured_traceback
1869 1886
1870 1887 Your handler must return a structured traceback (a list of strings),
1871 1888 or None.
1872 1889
1873 1890 This will be made into an instance method (via types.MethodType)
1874 1891 of IPython itself, and it will be called if any of the exceptions
1875 1892 listed in the exc_tuple are caught. If the handler is None, an
1876 1893 internal basic one is used, which just prints basic info.
1877 1894
1878 1895 To protect IPython from crashes, if your handler ever raises an
1879 1896 exception or returns an invalid result, it will be immediately
1880 1897 disabled.
1881 1898
1882 1899 WARNING: by putting in your own exception handler into IPython's main
1883 1900 execution loop, you run a very good chance of nasty crashes. This
1884 1901 facility should only be used if you really know what you are doing."""
1885 1902 if not isinstance(exc_tuple, tuple):
1886 1903 raise TypeError("The custom exceptions must be given as a tuple.")
1887 1904
1888 1905 def dummy_handler(self, etype, value, tb, tb_offset=None):
1889 1906 print('*** Simple custom exception handler ***')
1890 1907 print('Exception type :', etype)
1891 1908 print('Exception value:', value)
1892 1909 print('Traceback :', tb)
1893 1910
1894 1911 def validate_stb(stb):
1895 1912 """validate structured traceback return type
1896 1913
1897 1914 return type of CustomTB *should* be a list of strings, but allow
1898 1915 single strings or None, which are harmless.
1899 1916
1900 1917 This function will *always* return a list of strings,
1901 1918 and will raise a TypeError if stb is inappropriate.
1902 1919 """
1903 1920 msg = "CustomTB must return list of strings, not %r" % stb
1904 1921 if stb is None:
1905 1922 return []
1906 1923 elif isinstance(stb, str):
1907 1924 return [stb]
1908 1925 elif not isinstance(stb, list):
1909 1926 raise TypeError(msg)
1910 1927 # it's a list
1911 1928 for line in stb:
1912 1929 # check every element
1913 1930 if not isinstance(line, str):
1914 1931 raise TypeError(msg)
1915 1932 return stb
1916 1933
1917 1934 if handler is None:
1918 1935 wrapped = dummy_handler
1919 1936 else:
1920 1937 def wrapped(self,etype,value,tb,tb_offset=None):
1921 1938 """wrap CustomTB handler, to protect IPython from user code
1922 1939
1923 1940 This makes it harder (but not impossible) for custom exception
1924 1941 handlers to crash IPython.
1925 1942 """
1926 1943 try:
1927 1944 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1928 1945 return validate_stb(stb)
1929 1946 except:
1930 1947 # clear custom handler immediately
1931 1948 self.set_custom_exc((), None)
1932 1949 print("Custom TB Handler failed, unregistering", file=sys.stderr)
1933 1950 # show the exception in handler first
1934 1951 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1935 1952 print(self.InteractiveTB.stb2text(stb))
1936 1953 print("The original exception:")
1937 1954 stb = self.InteractiveTB.structured_traceback(
1938 1955 (etype,value,tb), tb_offset=tb_offset
1939 1956 )
1940 1957 return stb
1941 1958
1942 1959 self.CustomTB = types.MethodType(wrapped,self)
1943 1960 self.custom_exceptions = exc_tuple
1944 1961
1945 1962 def excepthook(self, etype, value, tb):
1946 1963 """One more defense for GUI apps that call sys.excepthook.
1947 1964
1948 1965 GUI frameworks like wxPython trap exceptions and call
1949 1966 sys.excepthook themselves. I guess this is a feature that
1950 1967 enables them to keep running after exceptions that would
1951 1968 otherwise kill their mainloop. This is a bother for IPython
1952 1969 which excepts to catch all of the program exceptions with a try:
1953 1970 except: statement.
1954 1971
1955 1972 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1956 1973 any app directly invokes sys.excepthook, it will look to the user like
1957 1974 IPython crashed. In order to work around this, we can disable the
1958 1975 CrashHandler and replace it with this excepthook instead, which prints a
1959 1976 regular traceback using our InteractiveTB. In this fashion, apps which
1960 1977 call sys.excepthook will generate a regular-looking exception from
1961 1978 IPython, and the CrashHandler will only be triggered by real IPython
1962 1979 crashes.
1963 1980
1964 1981 This hook should be used sparingly, only in places which are not likely
1965 1982 to be true IPython errors.
1966 1983 """
1967 1984 self.showtraceback((etype, value, tb), tb_offset=0)
1968 1985
1969 1986 def _get_exc_info(self, exc_tuple=None):
1970 1987 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1971 1988
1972 1989 Ensures sys.last_type,value,traceback hold the exc_info we found,
1973 1990 from whichever source.
1974 1991
1975 1992 raises ValueError if none of these contain any information
1976 1993 """
1977 1994 if exc_tuple is None:
1978 1995 etype, value, tb = sys.exc_info()
1979 1996 else:
1980 1997 etype, value, tb = exc_tuple
1981 1998
1982 1999 if etype is None:
1983 2000 if hasattr(sys, 'last_type'):
1984 2001 etype, value, tb = sys.last_type, sys.last_value, \
1985 2002 sys.last_traceback
1986 2003
1987 2004 if etype is None:
1988 2005 raise ValueError("No exception to find")
1989 2006
1990 2007 # Now store the exception info in sys.last_type etc.
1991 2008 # WARNING: these variables are somewhat deprecated and not
1992 2009 # necessarily safe to use in a threaded environment, but tools
1993 2010 # like pdb depend on their existence, so let's set them. If we
1994 2011 # find problems in the field, we'll need to revisit their use.
1995 2012 sys.last_type = etype
1996 2013 sys.last_value = value
1997 2014 sys.last_traceback = tb
1998 2015
1999 2016 return etype, value, tb
2000 2017
2001 2018 def show_usage_error(self, exc):
2002 2019 """Show a short message for UsageErrors
2003 2020
2004 2021 These are special exceptions that shouldn't show a traceback.
2005 2022 """
2006 2023 print("UsageError: %s" % exc, file=sys.stderr)
2007 2024
2008 2025 def get_exception_only(self, exc_tuple=None):
2009 2026 """
2010 2027 Return as a string (ending with a newline) the exception that
2011 2028 just occurred, without any traceback.
2012 2029 """
2013 2030 etype, value, tb = self._get_exc_info(exc_tuple)
2014 2031 msg = traceback.format_exception_only(etype, value)
2015 2032 return ''.join(msg)
2016 2033
2017 2034 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
2018 2035 exception_only=False, running_compiled_code=False):
2019 2036 """Display the exception that just occurred.
2020 2037
2021 2038 If nothing is known about the exception, this is the method which
2022 2039 should be used throughout the code for presenting user tracebacks,
2023 2040 rather than directly invoking the InteractiveTB object.
2024 2041
2025 2042 A specific showsyntaxerror() also exists, but this method can take
2026 2043 care of calling it if needed, so unless you are explicitly catching a
2027 2044 SyntaxError exception, don't try to analyze the stack manually and
2028 2045 simply call this method."""
2029 2046
2030 2047 try:
2031 2048 try:
2032 2049 etype, value, tb = self._get_exc_info(exc_tuple)
2033 2050 except ValueError:
2034 2051 print('No traceback available to show.', file=sys.stderr)
2035 2052 return
2036 2053
2037 2054 if issubclass(etype, SyntaxError):
2038 2055 # Though this won't be called by syntax errors in the input
2039 2056 # line, there may be SyntaxError cases with imported code.
2040 2057 self.showsyntaxerror(filename, running_compiled_code)
2041 2058 elif etype is UsageError:
2042 2059 self.show_usage_error(value)
2043 2060 else:
2044 2061 if exception_only:
2045 2062 stb = ['An exception has occurred, use %tb to see '
2046 2063 'the full traceback.\n']
2047 2064 stb.extend(self.InteractiveTB.get_exception_only(etype,
2048 2065 value))
2049 2066 else:
2050 2067 try:
2051 2068 # Exception classes can customise their traceback - we
2052 2069 # use this in IPython.parallel for exceptions occurring
2053 2070 # in the engines. This should return a list of strings.
2054 2071 stb = value._render_traceback_()
2055 2072 except Exception:
2056 2073 stb = self.InteractiveTB.structured_traceback(etype,
2057 2074 value, tb, tb_offset=tb_offset)
2058 2075
2059 2076 self._showtraceback(etype, value, stb)
2060 2077 if self.call_pdb:
2061 2078 # drop into debugger
2062 2079 self.debugger(force=True)
2063 2080 return
2064 2081
2065 2082 # Actually show the traceback
2066 2083 self._showtraceback(etype, value, stb)
2067 2084
2068 2085 except KeyboardInterrupt:
2069 2086 print('\n' + self.get_exception_only(), file=sys.stderr)
2070 2087
2071 2088 def _showtraceback(self, etype, evalue, stb):
2072 2089 """Actually show a traceback.
2073 2090
2074 2091 Subclasses may override this method to put the traceback on a different
2075 2092 place, like a side channel.
2076 2093 """
2077 2094 print(self.InteractiveTB.stb2text(stb))
2078 2095
2079 2096 def showsyntaxerror(self, filename=None, running_compiled_code=False):
2080 2097 """Display the syntax error that just occurred.
2081 2098
2082 2099 This doesn't display a stack trace because there isn't one.
2083 2100
2084 2101 If a filename is given, it is stuffed in the exception instead
2085 2102 of what was there before (because Python's parser always uses
2086 2103 "<string>" when reading from a string).
2087 2104
2088 2105 If the syntax error occurred when running a compiled code (i.e. running_compile_code=True),
2089 2106 longer stack trace will be displayed.
2090 2107 """
2091 2108 etype, value, last_traceback = self._get_exc_info()
2092 2109
2093 2110 if filename and issubclass(etype, SyntaxError):
2094 2111 try:
2095 2112 value.filename = filename
2096 2113 except:
2097 2114 # Not the format we expect; leave it alone
2098 2115 pass
2099 2116
2100 2117 # If the error occurred when executing compiled code, we should provide full stacktrace.
2101 2118 elist = traceback.extract_tb(last_traceback) if running_compiled_code else []
2102 2119 stb = self.SyntaxTB.structured_traceback(etype, value, elist)
2103 2120 self._showtraceback(etype, value, stb)
2104 2121
2105 2122 # This is overridden in TerminalInteractiveShell to show a message about
2106 2123 # the %paste magic.
2107 2124 def showindentationerror(self):
2108 2125 """Called by _run_cell when there's an IndentationError in code entered
2109 2126 at the prompt.
2110 2127
2111 2128 This is overridden in TerminalInteractiveShell to show a message about
2112 2129 the %paste magic."""
2113 2130 self.showsyntaxerror()
2114 2131
2115 2132 #-------------------------------------------------------------------------
2116 2133 # Things related to readline
2117 2134 #-------------------------------------------------------------------------
2118 2135
2119 2136 def init_readline(self):
2120 2137 """DEPRECATED
2121 2138
2122 2139 Moved to terminal subclass, here only to simplify the init logic."""
2123 2140 # Set a number of methods that depend on readline to be no-op
2124 2141 warnings.warn('`init_readline` is no-op since IPython 5.0 and is Deprecated',
2125 2142 DeprecationWarning, stacklevel=2)
2126 2143 self.set_custom_completer = no_op
2127 2144
2128 2145 @skip_doctest
2129 2146 def set_next_input(self, s, replace=False):
2130 2147 """ Sets the 'default' input string for the next command line.
2131 2148
2132 2149 Example::
2133 2150
2134 2151 In [1]: _ip.set_next_input("Hello Word")
2135 2152 In [2]: Hello Word_ # cursor is here
2136 2153 """
2137 2154 self.rl_next_input = s
2138 2155
2139 2156 def _indent_current_str(self):
2140 2157 """return the current level of indentation as a string"""
2141 2158 return self.input_splitter.get_indent_spaces() * ' '
2142 2159
2143 2160 #-------------------------------------------------------------------------
2144 2161 # Things related to text completion
2145 2162 #-------------------------------------------------------------------------
2146 2163
2147 2164 def init_completer(self):
2148 2165 """Initialize the completion machinery.
2149 2166
2150 2167 This creates completion machinery that can be used by client code,
2151 2168 either interactively in-process (typically triggered by the readline
2152 2169 library), programmatically (such as in test suites) or out-of-process
2153 2170 (typically over the network by remote frontends).
2154 2171 """
2155 2172 from IPython.core.completer import IPCompleter
2156 2173 from IPython.core.completerlib import (module_completer,
2157 2174 magic_run_completer, cd_completer, reset_completer)
2158 2175
2159 2176 self.Completer = IPCompleter(shell=self,
2160 2177 namespace=self.user_ns,
2161 2178 global_namespace=self.user_global_ns,
2162 2179 parent=self,
2163 2180 )
2164 2181 self.configurables.append(self.Completer)
2165 2182
2166 2183 # Add custom completers to the basic ones built into IPCompleter
2167 2184 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2168 2185 self.strdispatchers['complete_command'] = sdisp
2169 2186 self.Completer.custom_completers = sdisp
2170 2187
2171 2188 self.set_hook('complete_command', module_completer, str_key = 'import')
2172 2189 self.set_hook('complete_command', module_completer, str_key = 'from')
2173 2190 self.set_hook('complete_command', module_completer, str_key = '%aimport')
2174 2191 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2175 2192 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2176 2193 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2177 2194
2178 2195 @skip_doctest
2179 2196 def complete(self, text, line=None, cursor_pos=None):
2180 2197 """Return the completed text and a list of completions.
2181 2198
2182 2199 Parameters
2183 2200 ----------
2184 2201
2185 2202 text : string
2186 2203 A string of text to be completed on. It can be given as empty and
2187 2204 instead a line/position pair are given. In this case, the
2188 2205 completer itself will split the line like readline does.
2189 2206
2190 2207 line : string, optional
2191 2208 The complete line that text is part of.
2192 2209
2193 2210 cursor_pos : int, optional
2194 2211 The position of the cursor on the input line.
2195 2212
2196 2213 Returns
2197 2214 -------
2198 2215 text : string
2199 2216 The actual text that was completed.
2200 2217
2201 2218 matches : list
2202 2219 A sorted list with all possible completions.
2203 2220
2204 2221 The optional arguments allow the completion to take more context into
2205 2222 account, and are part of the low-level completion API.
2206 2223
2207 2224 This is a wrapper around the completion mechanism, similar to what
2208 2225 readline does at the command line when the TAB key is hit. By
2209 2226 exposing it as a method, it can be used by other non-readline
2210 2227 environments (such as GUIs) for text completion.
2211 2228
2212 2229 Simple usage example:
2213 2230
2214 2231 In [1]: x = 'hello'
2215 2232
2216 2233 In [2]: _ip.complete('x.l')
2217 2234 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2218 2235 """
2219 2236
2220 2237 # Inject names into __builtin__ so we can complete on the added names.
2221 2238 with self.builtin_trap:
2222 2239 return self.Completer.complete(text, line, cursor_pos)
2223 2240
2224 2241 def set_custom_completer(self, completer, pos=0) -> None:
2225 2242 """Adds a new custom completer function.
2226 2243
2227 2244 The position argument (defaults to 0) is the index in the completers
2228 2245 list where you want the completer to be inserted.
2229 2246
2230 2247 `completer` should have the following signature::
2231 2248
2232 2249 def completion(self: Completer, text: string) -> List[str]:
2233 2250 raise NotImplementedError
2234 2251
2235 2252 It will be bound to the current Completer instance and pass some text
2236 2253 and return a list with current completions to suggest to the user.
2237 2254 """
2238 2255
2239 2256 newcomp = types.MethodType(completer, self.Completer)
2240 2257 self.Completer.custom_matchers.insert(pos,newcomp)
2241 2258
2242 2259 def set_completer_frame(self, frame=None):
2243 2260 """Set the frame of the completer."""
2244 2261 if frame:
2245 2262 self.Completer.namespace = frame.f_locals
2246 2263 self.Completer.global_namespace = frame.f_globals
2247 2264 else:
2248 2265 self.Completer.namespace = self.user_ns
2249 2266 self.Completer.global_namespace = self.user_global_ns
2250 2267
2251 2268 #-------------------------------------------------------------------------
2252 2269 # Things related to magics
2253 2270 #-------------------------------------------------------------------------
2254 2271
2255 2272 def init_magics(self):
2256 2273 from IPython.core import magics as m
2257 2274 self.magics_manager = magic.MagicsManager(shell=self,
2258 2275 parent=self,
2259 2276 user_magics=m.UserMagics(self))
2260 2277 self.configurables.append(self.magics_manager)
2261 2278
2262 2279 # Expose as public API from the magics manager
2263 2280 self.register_magics = self.magics_manager.register
2264 2281
2265 2282 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2266 2283 m.ConfigMagics, m.DisplayMagics, m.ExecutionMagics,
2267 2284 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2268 2285 m.NamespaceMagics, m.OSMagics, m.PackagingMagics,
2269 2286 m.PylabMagics, m.ScriptMagics,
2270 2287 )
2271 2288 self.register_magics(m.AsyncMagics)
2272 2289
2273 2290 # Register Magic Aliases
2274 2291 mman = self.magics_manager
2275 2292 # FIXME: magic aliases should be defined by the Magics classes
2276 2293 # or in MagicsManager, not here
2277 2294 mman.register_alias('ed', 'edit')
2278 2295 mman.register_alias('hist', 'history')
2279 2296 mman.register_alias('rep', 'recall')
2280 2297 mman.register_alias('SVG', 'svg', 'cell')
2281 2298 mman.register_alias('HTML', 'html', 'cell')
2282 2299 mman.register_alias('file', 'writefile', 'cell')
2283 2300
2284 2301 # FIXME: Move the color initialization to the DisplayHook, which
2285 2302 # should be split into a prompt manager and displayhook. We probably
2286 2303 # even need a centralize colors management object.
2287 2304 self.run_line_magic('colors', self.colors)
2288 2305
2289 2306 # Defined here so that it's included in the documentation
2290 2307 @functools.wraps(magic.MagicsManager.register_function)
2291 2308 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2292 self.magics_manager.register_function(func,
2293 magic_kind=magic_kind, magic_name=magic_name)
2309 self.magics_manager.register_function(
2310 func, magic_kind=magic_kind, magic_name=magic_name
2311 )
2294 2312
2295 2313 def run_line_magic(self, magic_name, line, _stack_depth=1):
2296 2314 """Execute the given line magic.
2297 2315
2298 2316 Parameters
2299 2317 ----------
2300 2318 magic_name : str
2301 2319 Name of the desired magic function, without '%' prefix.
2302 2320 line : str
2303 2321 The rest of the input line as a single string.
2304 2322 _stack_depth : int
2305 2323 If run_line_magic() is called from magic() then _stack_depth=2.
2306 2324 This is added to ensure backward compatibility for use of 'get_ipython().magic()'
2307 2325 """
2308 2326 fn = self.find_line_magic(magic_name)
2309 2327 if fn is None:
2310 2328 cm = self.find_cell_magic(magic_name)
2311 2329 etpl = "Line magic function `%%%s` not found%s."
2312 2330 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2313 2331 'did you mean that instead?)' % magic_name )
2314 2332 raise UsageError(etpl % (magic_name, extra))
2315 2333 else:
2316 2334 # Note: this is the distance in the stack to the user's frame.
2317 2335 # This will need to be updated if the internal calling logic gets
2318 2336 # refactored, or else we'll be expanding the wrong variables.
2319 2337
2320 2338 # Determine stack_depth depending on where run_line_magic() has been called
2321 2339 stack_depth = _stack_depth
2322 2340 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2323 2341 # magic has opted out of var_expand
2324 2342 magic_arg_s = line
2325 2343 else:
2326 2344 magic_arg_s = self.var_expand(line, stack_depth)
2327 2345 # Put magic args in a list so we can call with f(*a) syntax
2328 2346 args = [magic_arg_s]
2329 2347 kwargs = {}
2330 2348 # Grab local namespace if we need it:
2331 2349 if getattr(fn, "needs_local_scope", False):
2332 2350 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2333 2351 with self.builtin_trap:
2334 2352 result = fn(*args, **kwargs)
2335 2353 return result
2336 2354
2337 2355 def get_local_scope(self, stack_depth):
2338 2356 """Get local scope at given stack depth.
2339 2357
2340 2358 Parameters
2341 2359 ----------
2342 2360 stack_depth : int
2343 2361 Depth relative to calling frame
2344 2362 """
2345 2363 return sys._getframe(stack_depth + 1).f_locals
2346 2364
2347 2365 def run_cell_magic(self, magic_name, line, cell):
2348 2366 """Execute the given cell magic.
2349 2367
2350 2368 Parameters
2351 2369 ----------
2352 2370 magic_name : str
2353 2371 Name of the desired magic function, without '%' prefix.
2354 2372 line : str
2355 2373 The rest of the first input line as a single string.
2356 2374 cell : str
2357 2375 The body of the cell as a (possibly multiline) string.
2358 2376 """
2359 2377 fn = self.find_cell_magic(magic_name)
2360 2378 if fn is None:
2361 2379 lm = self.find_line_magic(magic_name)
2362 2380 etpl = "Cell magic `%%{0}` not found{1}."
2363 2381 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2364 2382 'did you mean that instead?)'.format(magic_name))
2365 2383 raise UsageError(etpl.format(magic_name, extra))
2366 2384 elif cell == '':
2367 2385 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2368 2386 if self.find_line_magic(magic_name) is not None:
2369 2387 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2370 2388 raise UsageError(message)
2371 2389 else:
2372 2390 # Note: this is the distance in the stack to the user's frame.
2373 2391 # This will need to be updated if the internal calling logic gets
2374 2392 # refactored, or else we'll be expanding the wrong variables.
2375 2393 stack_depth = 2
2376 2394 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2377 2395 # magic has opted out of var_expand
2378 2396 magic_arg_s = line
2379 2397 else:
2380 2398 magic_arg_s = self.var_expand(line, stack_depth)
2381 2399 kwargs = {}
2382 2400 if getattr(fn, "needs_local_scope", False):
2383 2401 kwargs['local_ns'] = self.user_ns
2384 2402
2385 2403 with self.builtin_trap:
2386 2404 args = (magic_arg_s, cell)
2387 2405 result = fn(*args, **kwargs)
2388 2406 return result
2389 2407
2390 2408 def find_line_magic(self, magic_name):
2391 2409 """Find and return a line magic by name.
2392 2410
2393 2411 Returns None if the magic isn't found."""
2394 2412 return self.magics_manager.magics['line'].get(magic_name)
2395 2413
2396 2414 def find_cell_magic(self, magic_name):
2397 2415 """Find and return a cell magic by name.
2398 2416
2399 2417 Returns None if the magic isn't found."""
2400 2418 return self.magics_manager.magics['cell'].get(magic_name)
2401 2419
2402 2420 def find_magic(self, magic_name, magic_kind='line'):
2403 2421 """Find and return a magic of the given type by name.
2404 2422
2405 2423 Returns None if the magic isn't found."""
2406 2424 return self.magics_manager.magics[magic_kind].get(magic_name)
2407 2425
2408 2426 def magic(self, arg_s):
2409 2427 """DEPRECATED. Use run_line_magic() instead.
2410 2428
2411 2429 Call a magic function by name.
2412 2430
2413 2431 Input: a string containing the name of the magic function to call and
2414 2432 any additional arguments to be passed to the magic.
2415 2433
2416 2434 magic('name -opt foo bar') is equivalent to typing at the ipython
2417 2435 prompt:
2418 2436
2419 2437 In[1]: %name -opt foo bar
2420 2438
2421 2439 To call a magic without arguments, simply use magic('name').
2422 2440
2423 2441 This provides a proper Python function to call IPython's magics in any
2424 2442 valid Python code you can type at the interpreter, including loops and
2425 2443 compound statements.
2426 2444 """
2427 2445 # TODO: should we issue a loud deprecation warning here?
2428 2446 magic_name, _, magic_arg_s = arg_s.partition(' ')
2429 2447 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2430 2448 return self.run_line_magic(magic_name, magic_arg_s, _stack_depth=2)
2431 2449
2432 2450 #-------------------------------------------------------------------------
2433 2451 # Things related to macros
2434 2452 #-------------------------------------------------------------------------
2435 2453
2436 2454 def define_macro(self, name, themacro):
2437 2455 """Define a new macro
2438 2456
2439 2457 Parameters
2440 2458 ----------
2441 2459 name : str
2442 2460 The name of the macro.
2443 2461 themacro : str or Macro
2444 2462 The action to do upon invoking the macro. If a string, a new
2445 2463 Macro object is created by passing the string to it.
2446 2464 """
2447 2465
2448 2466 from IPython.core import macro
2449 2467
2450 2468 if isinstance(themacro, str):
2451 2469 themacro = macro.Macro(themacro)
2452 2470 if not isinstance(themacro, macro.Macro):
2453 2471 raise ValueError('A macro must be a string or a Macro instance.')
2454 2472 self.user_ns[name] = themacro
2455 2473
2456 2474 #-------------------------------------------------------------------------
2457 2475 # Things related to the running of system commands
2458 2476 #-------------------------------------------------------------------------
2459 2477
2460 2478 def system_piped(self, cmd):
2461 2479 """Call the given cmd in a subprocess, piping stdout/err
2462 2480
2463 2481 Parameters
2464 2482 ----------
2465 2483 cmd : str
2466 2484 Command to execute (can not end in '&', as background processes are
2467 2485 not supported. Should not be a command that expects input
2468 2486 other than simple text.
2469 2487 """
2470 2488 if cmd.rstrip().endswith('&'):
2471 2489 # this is *far* from a rigorous test
2472 2490 # We do not support backgrounding processes because we either use
2473 2491 # pexpect or pipes to read from. Users can always just call
2474 2492 # os.system() or use ip.system=ip.system_raw
2475 2493 # if they really want a background process.
2476 2494 raise OSError("Background processes not supported.")
2477 2495
2478 2496 # we explicitly do NOT return the subprocess status code, because
2479 2497 # a non-None value would trigger :func:`sys.displayhook` calls.
2480 2498 # Instead, we store the exit_code in user_ns.
2481 2499 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2482 2500
2483 2501 def system_raw(self, cmd):
2484 2502 """Call the given cmd in a subprocess using os.system on Windows or
2485 2503 subprocess.call using the system shell on other platforms.
2486 2504
2487 2505 Parameters
2488 2506 ----------
2489 2507 cmd : str
2490 2508 Command to execute.
2491 2509 """
2492 2510 cmd = self.var_expand(cmd, depth=1)
2493 2511 # protect os.system from UNC paths on Windows, which it can't handle:
2494 2512 if sys.platform == 'win32':
2495 2513 from IPython.utils._process_win32 import AvoidUNCPath
2496 2514 with AvoidUNCPath() as path:
2497 2515 if path is not None:
2498 2516 cmd = '"pushd %s &&"%s' % (path, cmd)
2499 2517 try:
2500 2518 ec = os.system(cmd)
2501 2519 except KeyboardInterrupt:
2502 2520 print('\n' + self.get_exception_only(), file=sys.stderr)
2503 2521 ec = -2
2504 2522 else:
2505 2523 # For posix the result of the subprocess.call() below is an exit
2506 2524 # code, which by convention is zero for success, positive for
2507 2525 # program failure. Exit codes above 128 are reserved for signals,
2508 2526 # and the formula for converting a signal to an exit code is usually
2509 2527 # signal_number+128. To more easily differentiate between exit
2510 2528 # codes and signals, ipython uses negative numbers. For instance
2511 2529 # since control-c is signal 2 but exit code 130, ipython's
2512 2530 # _exit_code variable will read -2. Note that some shells like
2513 2531 # csh and fish don't follow sh/bash conventions for exit codes.
2514 2532 executable = os.environ.get('SHELL', None)
2515 2533 try:
2516 2534 # Use env shell instead of default /bin/sh
2517 2535 ec = subprocess.call(cmd, shell=True, executable=executable)
2518 2536 except KeyboardInterrupt:
2519 2537 # intercept control-C; a long traceback is not useful here
2520 2538 print('\n' + self.get_exception_only(), file=sys.stderr)
2521 2539 ec = 130
2522 2540 if ec > 128:
2523 2541 ec = -(ec - 128)
2524 2542
2525 2543 # We explicitly do NOT return the subprocess status code, because
2526 2544 # a non-None value would trigger :func:`sys.displayhook` calls.
2527 2545 # Instead, we store the exit_code in user_ns. Note the semantics
2528 2546 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2529 2547 # but raising SystemExit(_exit_code) will give status 254!
2530 2548 self.user_ns['_exit_code'] = ec
2531 2549
2532 2550 # use piped system by default, because it is better behaved
2533 2551 system = system_piped
2534 2552
2535 2553 def getoutput(self, cmd, split=True, depth=0):
2536 2554 """Get output (possibly including stderr) from a subprocess.
2537 2555
2538 2556 Parameters
2539 2557 ----------
2540 2558 cmd : str
2541 2559 Command to execute (can not end in '&', as background processes are
2542 2560 not supported.
2543 2561 split : bool, optional
2544 2562 If True, split the output into an IPython SList. Otherwise, an
2545 2563 IPython LSString is returned. These are objects similar to normal
2546 2564 lists and strings, with a few convenience attributes for easier
2547 2565 manipulation of line-based output. You can use '?' on them for
2548 2566 details.
2549 2567 depth : int, optional
2550 2568 How many frames above the caller are the local variables which should
2551 2569 be expanded in the command string? The default (0) assumes that the
2552 2570 expansion variables are in the stack frame calling this function.
2553 2571 """
2554 2572 if cmd.rstrip().endswith('&'):
2555 2573 # this is *far* from a rigorous test
2556 2574 raise OSError("Background processes not supported.")
2557 2575 out = getoutput(self.var_expand(cmd, depth=depth+1))
2558 2576 if split:
2559 2577 out = SList(out.splitlines())
2560 2578 else:
2561 2579 out = LSString(out)
2562 2580 return out
2563 2581
2564 2582 #-------------------------------------------------------------------------
2565 2583 # Things related to aliases
2566 2584 #-------------------------------------------------------------------------
2567 2585
2568 2586 def init_alias(self):
2569 2587 self.alias_manager = AliasManager(shell=self, parent=self)
2570 2588 self.configurables.append(self.alias_manager)
2571 2589
2572 2590 #-------------------------------------------------------------------------
2573 2591 # Things related to extensions
2574 2592 #-------------------------------------------------------------------------
2575 2593
2576 2594 def init_extension_manager(self):
2577 2595 self.extension_manager = ExtensionManager(shell=self, parent=self)
2578 2596 self.configurables.append(self.extension_manager)
2579 2597
2580 2598 #-------------------------------------------------------------------------
2581 2599 # Things related to payloads
2582 2600 #-------------------------------------------------------------------------
2583 2601
2584 2602 def init_payload(self):
2585 2603 self.payload_manager = PayloadManager(parent=self)
2586 2604 self.configurables.append(self.payload_manager)
2587 2605
2588 2606 #-------------------------------------------------------------------------
2589 2607 # Things related to the prefilter
2590 2608 #-------------------------------------------------------------------------
2591 2609
2592 2610 def init_prefilter(self):
2593 2611 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2594 2612 self.configurables.append(self.prefilter_manager)
2595 2613 # Ultimately this will be refactored in the new interpreter code, but
2596 2614 # for now, we should expose the main prefilter method (there's legacy
2597 2615 # code out there that may rely on this).
2598 2616 self.prefilter = self.prefilter_manager.prefilter_lines
2599 2617
2600 2618 def auto_rewrite_input(self, cmd):
2601 2619 """Print to the screen the rewritten form of the user's command.
2602 2620
2603 2621 This shows visual feedback by rewriting input lines that cause
2604 2622 automatic calling to kick in, like::
2605 2623
2606 2624 /f x
2607 2625
2608 2626 into::
2609 2627
2610 2628 ------> f(x)
2611 2629
2612 2630 after the user's input prompt. This helps the user understand that the
2613 2631 input line was transformed automatically by IPython.
2614 2632 """
2615 2633 if not self.show_rewritten_input:
2616 2634 return
2617 2635
2618 2636 # This is overridden in TerminalInteractiveShell to use fancy prompts
2619 2637 print("------> " + cmd)
2620 2638
2621 2639 #-------------------------------------------------------------------------
2622 2640 # Things related to extracting values/expressions from kernel and user_ns
2623 2641 #-------------------------------------------------------------------------
2624 2642
2625 2643 def _user_obj_error(self):
2626 2644 """return simple exception dict
2627 2645
2628 2646 for use in user_expressions
2629 2647 """
2630 2648
2631 2649 etype, evalue, tb = self._get_exc_info()
2632 2650 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2633 2651
2634 2652 exc_info = {
2635 2653 "status": "error",
2636 2654 "traceback": stb,
2637 2655 "ename": etype.__name__,
2638 2656 "evalue": py3compat.safe_unicode(evalue),
2639 2657 }
2640 2658
2641 2659 return exc_info
2642 2660
2643 2661 def _format_user_obj(self, obj):
2644 2662 """format a user object to display dict
2645 2663
2646 2664 for use in user_expressions
2647 2665 """
2648 2666
2649 2667 data, md = self.display_formatter.format(obj)
2650 2668 value = {
2651 2669 'status' : 'ok',
2652 2670 'data' : data,
2653 2671 'metadata' : md,
2654 2672 }
2655 2673 return value
2656 2674
2657 2675 def user_expressions(self, expressions):
2658 2676 """Evaluate a dict of expressions in the user's namespace.
2659 2677
2660 2678 Parameters
2661 2679 ----------
2662 2680 expressions : dict
2663 2681 A dict with string keys and string values. The expression values
2664 2682 should be valid Python expressions, each of which will be evaluated
2665 2683 in the user namespace.
2666 2684
2667 2685 Returns
2668 2686 -------
2669 2687 A dict, keyed like the input expressions dict, with the rich mime-typed
2670 2688 display_data of each value.
2671 2689 """
2672 2690 out = {}
2673 2691 user_ns = self.user_ns
2674 2692 global_ns = self.user_global_ns
2675 2693
2676 2694 for key, expr in expressions.items():
2677 2695 try:
2678 2696 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2679 2697 except:
2680 2698 value = self._user_obj_error()
2681 2699 out[key] = value
2682 2700 return out
2683 2701
2684 2702 #-------------------------------------------------------------------------
2685 2703 # Things related to the running of code
2686 2704 #-------------------------------------------------------------------------
2687 2705
2688 2706 def ex(self, cmd):
2689 2707 """Execute a normal python statement in user namespace."""
2690 2708 with self.builtin_trap:
2691 2709 exec(cmd, self.user_global_ns, self.user_ns)
2692 2710
2693 2711 def ev(self, expr):
2694 2712 """Evaluate python expression expr in user namespace.
2695 2713
2696 2714 Returns the result of evaluation
2697 2715 """
2698 2716 with self.builtin_trap:
2699 2717 return eval(expr, self.user_global_ns, self.user_ns)
2700 2718
2701 2719 def safe_execfile(self, fname, *where, exit_ignore=False, raise_exceptions=False, shell_futures=False):
2702 2720 """A safe version of the builtin execfile().
2703 2721
2704 2722 This version will never throw an exception, but instead print
2705 2723 helpful error messages to the screen. This only works on pure
2706 2724 Python files with the .py extension.
2707 2725
2708 2726 Parameters
2709 2727 ----------
2710 2728 fname : string
2711 2729 The name of the file to be executed.
2712 2730 where : tuple
2713 2731 One or two namespaces, passed to execfile() as (globals,locals).
2714 2732 If only one is given, it is passed as both.
2715 2733 exit_ignore : bool (False)
2716 2734 If True, then silence SystemExit for non-zero status (it is always
2717 2735 silenced for zero status, as it is so common).
2718 2736 raise_exceptions : bool (False)
2719 2737 If True raise exceptions everywhere. Meant for testing.
2720 2738 shell_futures : bool (False)
2721 2739 If True, the code will share future statements with the interactive
2722 2740 shell. It will both be affected by previous __future__ imports, and
2723 2741 any __future__ imports in the code will affect the shell. If False,
2724 2742 __future__ imports are not shared in either direction.
2725 2743
2726 2744 """
2727 2745 fname = Path(fname).expanduser().resolve()
2728 2746
2729 2747 # Make sure we can open the file
2730 2748 try:
2731 2749 with fname.open():
2732 2750 pass
2733 2751 except:
2734 2752 warn('Could not open file <%s> for safe execution.' % fname)
2735 2753 return
2736 2754
2737 2755 # Find things also in current directory. This is needed to mimic the
2738 2756 # behavior of running a script from the system command line, where
2739 2757 # Python inserts the script's directory into sys.path
2740 2758 dname = str(fname.parent)
2741 2759
2742 2760 with prepended_to_syspath(dname), self.builtin_trap:
2743 2761 try:
2744 2762 glob, loc = (where + (None, ))[:2]
2745 2763 py3compat.execfile(
2746 2764 fname, glob, loc,
2747 2765 self.compile if shell_futures else None)
2748 2766 except SystemExit as status:
2749 2767 # If the call was made with 0 or None exit status (sys.exit(0)
2750 2768 # or sys.exit() ), don't bother showing a traceback, as both of
2751 2769 # these are considered normal by the OS:
2752 2770 # > python -c'import sys;sys.exit(0)'; echo $?
2753 2771 # 0
2754 2772 # > python -c'import sys;sys.exit()'; echo $?
2755 2773 # 0
2756 2774 # For other exit status, we show the exception unless
2757 2775 # explicitly silenced, but only in short form.
2758 2776 if status.code:
2759 2777 if raise_exceptions:
2760 2778 raise
2761 2779 if not exit_ignore:
2762 2780 self.showtraceback(exception_only=True)
2763 2781 except:
2764 2782 if raise_exceptions:
2765 2783 raise
2766 2784 # tb offset is 2 because we wrap execfile
2767 2785 self.showtraceback(tb_offset=2)
2768 2786
2769 2787 def safe_execfile_ipy(self, fname, shell_futures=False, raise_exceptions=False):
2770 2788 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2771 2789
2772 2790 Parameters
2773 2791 ----------
2774 2792 fname : str
2775 2793 The name of the file to execute. The filename must have a
2776 2794 .ipy or .ipynb extension.
2777 2795 shell_futures : bool (False)
2778 2796 If True, the code will share future statements with the interactive
2779 2797 shell. It will both be affected by previous __future__ imports, and
2780 2798 any __future__ imports in the code will affect the shell. If False,
2781 2799 __future__ imports are not shared in either direction.
2782 2800 raise_exceptions : bool (False)
2783 2801 If True raise exceptions everywhere. Meant for testing.
2784 2802 """
2785 2803 fname = Path(fname).expanduser().resolve()
2786 2804
2787 2805 # Make sure we can open the file
2788 2806 try:
2789 2807 with fname.open():
2790 2808 pass
2791 2809 except:
2792 2810 warn('Could not open file <%s> for safe execution.' % fname)
2793 2811 return
2794 2812
2795 2813 # Find things also in current directory. This is needed to mimic the
2796 2814 # behavior of running a script from the system command line, where
2797 2815 # Python inserts the script's directory into sys.path
2798 2816 dname = str(fname.parent)
2799 2817
2800 2818 def get_cells():
2801 2819 """generator for sequence of code blocks to run"""
2802 2820 if fname.suffix == ".ipynb":
2803 2821 from nbformat import read
2804 2822 nb = read(fname, as_version=4)
2805 2823 if not nb.cells:
2806 2824 return
2807 2825 for cell in nb.cells:
2808 2826 if cell.cell_type == 'code':
2809 2827 yield cell.source
2810 2828 else:
2811 2829 yield fname.read_text()
2812 2830
2813 2831 with prepended_to_syspath(dname):
2814 2832 try:
2815 2833 for cell in get_cells():
2816 2834 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2817 2835 if raise_exceptions:
2818 2836 result.raise_error()
2819 2837 elif not result.success:
2820 2838 break
2821 2839 except:
2822 2840 if raise_exceptions:
2823 2841 raise
2824 2842 self.showtraceback()
2825 2843 warn('Unknown failure executing file: <%s>' % fname)
2826 2844
2827 2845 def safe_run_module(self, mod_name, where):
2828 2846 """A safe version of runpy.run_module().
2829 2847
2830 2848 This version will never throw an exception, but instead print
2831 2849 helpful error messages to the screen.
2832 2850
2833 2851 `SystemExit` exceptions with status code 0 or None are ignored.
2834 2852
2835 2853 Parameters
2836 2854 ----------
2837 2855 mod_name : string
2838 2856 The name of the module to be executed.
2839 2857 where : dict
2840 2858 The globals namespace.
2841 2859 """
2842 2860 try:
2843 2861 try:
2844 2862 where.update(
2845 2863 runpy.run_module(str(mod_name), run_name="__main__",
2846 2864 alter_sys=True)
2847 2865 )
2848 2866 except SystemExit as status:
2849 2867 if status.code:
2850 2868 raise
2851 2869 except:
2852 2870 self.showtraceback()
2853 2871 warn('Unknown failure executing module: <%s>' % mod_name)
2854 2872
2855 2873 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2856 2874 """Run a complete IPython cell.
2857 2875
2858 2876 Parameters
2859 2877 ----------
2860 2878 raw_cell : str
2861 2879 The code (including IPython code such as %magic functions) to run.
2862 2880 store_history : bool
2863 2881 If True, the raw and translated cell will be stored in IPython's
2864 2882 history. For user code calling back into IPython's machinery, this
2865 2883 should be set to False.
2866 2884 silent : bool
2867 2885 If True, avoid side-effects, such as implicit displayhooks and
2868 2886 and logging. silent=True forces store_history=False.
2869 2887 shell_futures : bool
2870 2888 If True, the code will share future statements with the interactive
2871 2889 shell. It will both be affected by previous __future__ imports, and
2872 2890 any __future__ imports in the code will affect the shell. If False,
2873 2891 __future__ imports are not shared in either direction.
2874 2892
2875 2893 Returns
2876 2894 -------
2877 2895 result : :class:`ExecutionResult`
2878 2896 """
2879 2897 result = None
2880 2898 try:
2881 2899 result = self._run_cell(
2882 2900 raw_cell, store_history, silent, shell_futures)
2883 2901 finally:
2884 2902 self.events.trigger('post_execute')
2885 2903 if not silent:
2886 2904 self.events.trigger('post_run_cell', result)
2887 2905 return result
2888 2906
2889 2907 def _run_cell(self, raw_cell:str, store_history:bool, silent:bool, shell_futures:bool) -> ExecutionResult:
2890 2908 """Internal method to run a complete IPython cell."""
2891 2909
2892 2910 # we need to avoid calling self.transform_cell multiple time on the same thing
2893 2911 # so we need to store some results:
2894 2912 preprocessing_exc_tuple = None
2895 2913 try:
2896 2914 transformed_cell = self.transform_cell(raw_cell)
2897 2915 except Exception:
2898 2916 transformed_cell = raw_cell
2899 2917 preprocessing_exc_tuple = sys.exc_info()
2900 2918
2901 2919 assert transformed_cell is not None
2902 2920 coro = self.run_cell_async(
2903 2921 raw_cell,
2904 2922 store_history=store_history,
2905 2923 silent=silent,
2906 2924 shell_futures=shell_futures,
2907 2925 transformed_cell=transformed_cell,
2908 2926 preprocessing_exc_tuple=preprocessing_exc_tuple,
2909 2927 )
2910 2928
2911 2929 # run_cell_async is async, but may not actually need an eventloop.
2912 2930 # when this is the case, we want to run it using the pseudo_sync_runner
2913 2931 # so that code can invoke eventloops (for example via the %run , and
2914 2932 # `%paste` magic.
2915 2933 if self.trio_runner:
2916 2934 runner = self.trio_runner
2917 2935 elif self.should_run_async(
2918 2936 raw_cell,
2919 2937 transformed_cell=transformed_cell,
2920 2938 preprocessing_exc_tuple=preprocessing_exc_tuple,
2921 2939 ):
2922 2940 runner = self.loop_runner
2923 2941 else:
2924 2942 runner = _pseudo_sync_runner
2925 2943
2926 2944 try:
2927 2945 return runner(coro)
2928 2946 except BaseException as e:
2929 2947 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures)
2930 2948 result = ExecutionResult(info)
2931 2949 result.error_in_exec = e
2932 2950 self.showtraceback(running_compiled_code=True)
2933 2951 return result
2934 2952
2935 2953 def should_run_async(
2936 2954 self, raw_cell: str, *, transformed_cell=None, preprocessing_exc_tuple=None
2937 2955 ) -> bool:
2938 2956 """Return whether a cell should be run asynchronously via a coroutine runner
2939 2957
2940 2958 Parameters
2941 2959 ----------
2942 2960 raw_cell: str
2943 2961 The code to be executed
2944 2962
2945 2963 Returns
2946 2964 -------
2947 2965 result: bool
2948 2966 Whether the code needs to be run with a coroutine runner or not
2949 2967
2950 2968 .. versionadded: 7.0
2951 2969 """
2952 2970 if not self.autoawait:
2953 2971 return False
2954 2972 if preprocessing_exc_tuple is not None:
2955 2973 return False
2956 2974 assert preprocessing_exc_tuple is None
2957 2975 if transformed_cell is None:
2958 2976 warnings.warn(
2959 2977 "`should_run_async` will not call `transform_cell`"
2960 2978 " automatically in the future. Please pass the result to"
2961 2979 " `transformed_cell` argument and any exception that happen"
2962 2980 " during the"
2963 2981 "transform in `preprocessing_exc_tuple` in"
2964 2982 " IPython 7.17 and above.",
2965 2983 DeprecationWarning,
2966 2984 stacklevel=2,
2967 2985 )
2968 2986 try:
2969 2987 cell = self.transform_cell(raw_cell)
2970 2988 except Exception:
2971 2989 # any exception during transform will be raised
2972 2990 # prior to execution
2973 2991 return False
2974 2992 else:
2975 2993 cell = transformed_cell
2976 2994 return _should_be_async(cell)
2977 2995
2978 2996 async def run_cell_async(
2979 2997 self,
2980 2998 raw_cell: str,
2981 2999 store_history=False,
2982 3000 silent=False,
2983 3001 shell_futures=True,
2984 3002 *,
2985 3003 transformed_cell: Optional[str] = None,
2986 3004 preprocessing_exc_tuple: Optional[Any] = None
2987 3005 ) -> ExecutionResult:
2988 3006 """Run a complete IPython cell asynchronously.
2989 3007
2990 3008 Parameters
2991 3009 ----------
2992 3010 raw_cell : str
2993 3011 The code (including IPython code such as %magic functions) to run.
2994 3012 store_history : bool
2995 3013 If True, the raw and translated cell will be stored in IPython's
2996 3014 history. For user code calling back into IPython's machinery, this
2997 3015 should be set to False.
2998 3016 silent : bool
2999 3017 If True, avoid side-effects, such as implicit displayhooks and
3000 3018 and logging. silent=True forces store_history=False.
3001 3019 shell_futures : bool
3002 3020 If True, the code will share future statements with the interactive
3003 3021 shell. It will both be affected by previous __future__ imports, and
3004 3022 any __future__ imports in the code will affect the shell. If False,
3005 3023 __future__ imports are not shared in either direction.
3006 3024 transformed_cell: str
3007 3025 cell that was passed through transformers
3008 3026 preprocessing_exc_tuple:
3009 3027 trace if the transformation failed.
3010 3028
3011 3029 Returns
3012 3030 -------
3013 3031 result : :class:`ExecutionResult`
3014 3032
3015 3033 .. versionadded: 7.0
3016 3034 """
3017 3035 info = ExecutionInfo(
3018 3036 raw_cell, store_history, silent, shell_futures)
3019 3037 result = ExecutionResult(info)
3020 3038
3021 3039 if (not raw_cell) or raw_cell.isspace():
3022 3040 self.last_execution_succeeded = True
3023 3041 self.last_execution_result = result
3024 3042 return result
3025 3043
3026 3044 if silent:
3027 3045 store_history = False
3028 3046
3029 3047 if store_history:
3030 3048 result.execution_count = self.execution_count
3031 3049
3032 3050 def error_before_exec(value):
3033 3051 if store_history:
3034 3052 self.execution_count += 1
3035 3053 result.error_before_exec = value
3036 3054 self.last_execution_succeeded = False
3037 3055 self.last_execution_result = result
3038 3056 return result
3039 3057
3040 3058 self.events.trigger('pre_execute')
3041 3059 if not silent:
3042 3060 self.events.trigger('pre_run_cell', info)
3043 3061
3044 3062 if transformed_cell is None:
3045 3063 warnings.warn(
3046 3064 "`run_cell_async` will not call `transform_cell`"
3047 3065 " automatically in the future. Please pass the result to"
3048 3066 " `transformed_cell` argument and any exception that happen"
3049 3067 " during the"
3050 3068 "transform in `preprocessing_exc_tuple` in"
3051 3069 " IPython 7.17 and above.",
3052 3070 DeprecationWarning,
3053 3071 stacklevel=2,
3054 3072 )
3055 3073 # If any of our input transformation (input_transformer_manager or
3056 3074 # prefilter_manager) raises an exception, we store it in this variable
3057 3075 # so that we can display the error after logging the input and storing
3058 3076 # it in the history.
3059 3077 try:
3060 3078 cell = self.transform_cell(raw_cell)
3061 3079 except Exception:
3062 3080 preprocessing_exc_tuple = sys.exc_info()
3063 3081 cell = raw_cell # cell has to exist so it can be stored/logged
3064 3082 else:
3065 3083 preprocessing_exc_tuple = None
3066 3084 else:
3067 3085 if preprocessing_exc_tuple is None:
3068 3086 cell = transformed_cell
3069 3087 else:
3070 3088 cell = raw_cell
3071 3089
3072 3090 # Store raw and processed history
3073 3091 if store_history:
3074 3092 self.history_manager.store_inputs(self.execution_count,
3075 3093 cell, raw_cell)
3076 3094 if not silent:
3077 3095 self.logger.log(cell, raw_cell)
3078 3096
3079 3097 # Display the exception if input processing failed.
3080 3098 if preprocessing_exc_tuple is not None:
3081 3099 self.showtraceback(preprocessing_exc_tuple)
3082 3100 if store_history:
3083 3101 self.execution_count += 1
3084 3102 return error_before_exec(preprocessing_exc_tuple[1])
3085 3103
3086 3104 # Our own compiler remembers the __future__ environment. If we want to
3087 3105 # run code with a separate __future__ environment, use the default
3088 3106 # compiler
3089 compiler = self.compile if shell_futures else CachingCompiler()
3107 compiler = self.compile if shell_futures else self.compiler_class()
3090 3108
3091 3109 _run_async = False
3092 3110
3093 3111 with self.builtin_trap:
3094 cell_name = self.compile.cache(cell, self.execution_count)
3112 cell_name = self.compile.cache(
3113 cell, self.execution_count, raw_code=raw_cell
3114 )
3095 3115
3096 3116 with self.display_trap:
3097 3117 # Compile to bytecode
3098 3118 try:
3099 3119 if sys.version_info < (3,8) and self.autoawait:
3100 3120 if _should_be_async(cell):
3101 3121 # the code AST below will not be user code: we wrap it
3102 3122 # in an `async def`. This will likely make some AST
3103 3123 # transformer below miss some transform opportunity and
3104 3124 # introduce a small coupling to run_code (in which we
3105 3125 # bake some assumptions of what _ast_asyncify returns.
3106 3126 # they are ways around (like grafting part of the ast
3107 3127 # later:
3108 3128 # - Here, return code_ast.body[0].body[1:-1], as well
3109 3129 # as last expression in return statement which is
3110 3130 # the user code part.
3111 3131 # - Let it go through the AST transformers, and graft
3112 3132 # - it back after the AST transform
3113 3133 # But that seem unreasonable, at least while we
3114 3134 # do not need it.
3115 3135 code_ast = _ast_asyncify(cell, 'async-def-wrapper')
3116 3136 _run_async = True
3117 3137 else:
3118 3138 code_ast = compiler.ast_parse(cell, filename=cell_name)
3119 3139 else:
3120 3140 code_ast = compiler.ast_parse(cell, filename=cell_name)
3121 3141 except self.custom_exceptions as e:
3122 3142 etype, value, tb = sys.exc_info()
3123 3143 self.CustomTB(etype, value, tb)
3124 3144 return error_before_exec(e)
3125 3145 except IndentationError as e:
3126 3146 self.showindentationerror()
3127 3147 return error_before_exec(e)
3128 3148 except (OverflowError, SyntaxError, ValueError, TypeError,
3129 3149 MemoryError) as e:
3130 3150 self.showsyntaxerror()
3131 3151 return error_before_exec(e)
3132 3152
3133 3153 # Apply AST transformations
3134 3154 try:
3135 3155 code_ast = self.transform_ast(code_ast)
3136 3156 except InputRejected as e:
3137 3157 self.showtraceback()
3138 3158 return error_before_exec(e)
3139 3159
3140 3160 # Give the displayhook a reference to our ExecutionResult so it
3141 3161 # can fill in the output value.
3142 3162 self.displayhook.exec_result = result
3143 3163
3144 3164 # Execute the user code
3145 3165 interactivity = "none" if silent else self.ast_node_interactivity
3146 3166 if _run_async:
3147 3167 interactivity = 'async'
3148 3168
3149 3169 has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
3150 3170 interactivity=interactivity, compiler=compiler, result=result)
3151 3171
3152 3172 self.last_execution_succeeded = not has_raised
3153 3173 self.last_execution_result = result
3154 3174
3155 3175 # Reset this so later displayed values do not modify the
3156 3176 # ExecutionResult
3157 3177 self.displayhook.exec_result = None
3158 3178
3159 3179 if store_history:
3160 3180 # Write output to the database. Does nothing unless
3161 3181 # history output logging is enabled.
3162 3182 self.history_manager.store_output(self.execution_count)
3163 3183 # Each cell is a *single* input, regardless of how many lines it has
3164 3184 self.execution_count += 1
3165 3185
3166 3186 return result
3167 3187
3168 3188 def transform_cell(self, raw_cell):
3169 3189 """Transform an input cell before parsing it.
3170 3190
3171 3191 Static transformations, implemented in IPython.core.inputtransformer2,
3172 3192 deal with things like ``%magic`` and ``!system`` commands.
3173 3193 These run on all input.
3174 3194 Dynamic transformations, for things like unescaped magics and the exit
3175 3195 autocall, depend on the state of the interpreter.
3176 3196 These only apply to single line inputs.
3177 3197
3178 3198 These string-based transformations are followed by AST transformations;
3179 3199 see :meth:`transform_ast`.
3180 3200 """
3181 3201 # Static input transformations
3182 3202 cell = self.input_transformer_manager.transform_cell(raw_cell)
3183 3203
3184 3204 if len(cell.splitlines()) == 1:
3185 3205 # Dynamic transformations - only applied for single line commands
3186 3206 with self.builtin_trap:
3187 3207 # use prefilter_lines to handle trailing newlines
3188 3208 # restore trailing newline for ast.parse
3189 3209 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
3190 3210
3191 3211 lines = cell.splitlines(keepends=True)
3192 3212 for transform in self.input_transformers_post:
3193 3213 lines = transform(lines)
3194 3214 cell = ''.join(lines)
3195 3215
3196 3216 return cell
3197 3217
3198 3218 def transform_ast(self, node):
3199 3219 """Apply the AST transformations from self.ast_transformers
3200 3220
3201 3221 Parameters
3202 3222 ----------
3203 3223 node : ast.Node
3204 3224 The root node to be transformed. Typically called with the ast.Module
3205 3225 produced by parsing user input.
3206 3226
3207 3227 Returns
3208 3228 -------
3209 3229 An ast.Node corresponding to the node it was called with. Note that it
3210 3230 may also modify the passed object, so don't rely on references to the
3211 3231 original AST.
3212 3232 """
3213 3233 for transformer in self.ast_transformers:
3214 3234 try:
3215 3235 node = transformer.visit(node)
3216 3236 except InputRejected:
3217 3237 # User-supplied AST transformers can reject an input by raising
3218 3238 # an InputRejected. Short-circuit in this case so that we
3219 3239 # don't unregister the transform.
3220 3240 raise
3221 3241 except Exception:
3222 3242 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
3223 3243 self.ast_transformers.remove(transformer)
3224 3244
3225 3245 if self.ast_transformers:
3226 3246 ast.fix_missing_locations(node)
3227 3247 return node
3228 3248
3229 3249 async def run_ast_nodes(self, nodelist:ListType[AST], cell_name:str, interactivity='last_expr',
3230 3250 compiler=compile, result=None):
3231 3251 """Run a sequence of AST nodes. The execution mode depends on the
3232 3252 interactivity parameter.
3233 3253
3234 3254 Parameters
3235 3255 ----------
3236 3256 nodelist : list
3237 3257 A sequence of AST nodes to run.
3238 3258 cell_name : str
3239 3259 Will be passed to the compiler as the filename of the cell. Typically
3240 3260 the value returned by ip.compile.cache(cell).
3241 3261 interactivity : str
3242 3262 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none',
3243 3263 specifying which nodes should be run interactively (displaying output
3244 3264 from expressions). 'last_expr' will run the last node interactively
3245 3265 only if it is an expression (i.e. expressions in loops or other blocks
3246 3266 are not displayed) 'last_expr_or_assign' will run the last expression
3247 3267 or the last assignment. Other values for this parameter will raise a
3248 3268 ValueError.
3249 3269
3250 3270 Experimental value: 'async' Will try to run top level interactive
3251 3271 async/await code in default runner, this will not respect the
3252 3272 interactivity setting and will only run the last node if it is an
3253 3273 expression.
3254 3274
3255 3275 compiler : callable
3256 3276 A function with the same interface as the built-in compile(), to turn
3257 3277 the AST nodes into code objects. Default is the built-in compile().
3258 3278 result : ExecutionResult, optional
3259 3279 An object to store exceptions that occur during execution.
3260 3280
3261 3281 Returns
3262 3282 -------
3263 3283 True if an exception occurred while running code, False if it finished
3264 3284 running.
3265 3285 """
3266 3286 if not nodelist:
3267 3287 return
3268 3288
3269 3289 if interactivity == 'last_expr_or_assign':
3270 3290 if isinstance(nodelist[-1], _assign_nodes):
3271 3291 asg = nodelist[-1]
3272 3292 if isinstance(asg, ast.Assign) and len(asg.targets) == 1:
3273 3293 target = asg.targets[0]
3274 3294 elif isinstance(asg, _single_targets_nodes):
3275 3295 target = asg.target
3276 3296 else:
3277 3297 target = None
3278 3298 if isinstance(target, ast.Name):
3279 3299 nnode = ast.Expr(ast.Name(target.id, ast.Load()))
3280 3300 ast.fix_missing_locations(nnode)
3281 3301 nodelist.append(nnode)
3282 3302 interactivity = 'last_expr'
3283 3303
3284 3304 _async = False
3285 3305 if interactivity == 'last_expr':
3286 3306 if isinstance(nodelist[-1], ast.Expr):
3287 3307 interactivity = "last"
3288 3308 else:
3289 3309 interactivity = "none"
3290 3310
3291 3311 if interactivity == 'none':
3292 3312 to_run_exec, to_run_interactive = nodelist, []
3293 3313 elif interactivity == 'last':
3294 3314 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
3295 3315 elif interactivity == 'all':
3296 3316 to_run_exec, to_run_interactive = [], nodelist
3297 3317 elif interactivity == 'async':
3298 3318 to_run_exec, to_run_interactive = [], nodelist
3299 3319 _async = True
3300 3320 else:
3301 3321 raise ValueError("Interactivity was %r" % interactivity)
3302 3322
3303 3323 try:
3304 3324 if _async and sys.version_info > (3,8):
3305 3325 raise ValueError("This branch should never happen on Python 3.8 and above, "
3306 3326 "please try to upgrade IPython and open a bug report with your case.")
3307 3327 if _async:
3308 3328 # If interactivity is async the semantics of run_code are
3309 3329 # completely different Skip usual machinery.
3310 3330 mod = Module(nodelist, [])
3311 3331 async_wrapper_code = compiler(mod, cell_name, 'exec')
3312 3332 exec(async_wrapper_code, self.user_global_ns, self.user_ns)
3313 3333 async_code = removed_co_newlocals(self.user_ns.pop('async-def-wrapper')).__code__
3314 3334 if (await self.run_code(async_code, result, async_=True)):
3315 3335 return True
3316 3336 else:
3317 3337 if sys.version_info > (3, 8):
3318 3338 def compare(code):
3319 3339 is_async = (inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE)
3320 3340 return is_async
3321 3341 else:
3322 3342 def compare(code):
3323 3343 return _async
3324 3344
3325 3345 # refactor that to just change the mod constructor.
3326 3346 to_run = []
3327 3347 for node in to_run_exec:
3328 3348 to_run.append((node, 'exec'))
3329 3349
3330 3350 for node in to_run_interactive:
3331 3351 to_run.append((node, 'single'))
3332 3352
3333 3353 for node,mode in to_run:
3334 3354 if mode == 'exec':
3335 3355 mod = Module([node], [])
3336 3356 elif mode == 'single':
3337 3357 mod = ast.Interactive([node])
3338 3358 with compiler.extra_flags(getattr(ast, 'PyCF_ALLOW_TOP_LEVEL_AWAIT', 0x0) if self.autoawait else 0x0):
3339 3359 code = compiler(mod, cell_name, mode)
3340 3360 asy = compare(code)
3341 3361 if (await self.run_code(code, result, async_=asy)):
3342 3362 return True
3343 3363
3344 3364 # Flush softspace
3345 3365 if softspace(sys.stdout, 0):
3346 3366 print()
3347 3367
3348 3368 except:
3349 3369 # It's possible to have exceptions raised here, typically by
3350 3370 # compilation of odd code (such as a naked 'return' outside a
3351 3371 # function) that did parse but isn't valid. Typically the exception
3352 3372 # is a SyntaxError, but it's safest just to catch anything and show
3353 3373 # the user a traceback.
3354 3374
3355 3375 # We do only one try/except outside the loop to minimize the impact
3356 3376 # on runtime, and also because if any node in the node list is
3357 3377 # broken, we should stop execution completely.
3358 3378 if result:
3359 3379 result.error_before_exec = sys.exc_info()[1]
3360 3380 self.showtraceback()
3361 3381 return True
3362 3382
3363 3383 return False
3364 3384
3365 3385 def _async_exec(self, code_obj: types.CodeType, user_ns: dict):
3366 3386 """
3367 3387 Evaluate an asynchronous code object using a code runner
3368 3388
3369 3389 Fake asynchronous execution of code_object in a namespace via a proxy namespace.
3370 3390
3371 3391 Returns coroutine object, which can be executed via async loop runner
3372 3392
3373 3393 WARNING: The semantics of `async_exec` are quite different from `exec`,
3374 3394 in particular you can only pass a single namespace. It also return a
3375 3395 handle to the value of the last things returned by code_object.
3376 3396 """
3377 3397
3378 3398 return eval(code_obj, user_ns)
3379 3399
3380 3400 async def run_code(self, code_obj, result=None, *, async_=False):
3381 3401 """Execute a code object.
3382 3402
3383 3403 When an exception occurs, self.showtraceback() is called to display a
3384 3404 traceback.
3385 3405
3386 3406 Parameters
3387 3407 ----------
3388 3408 code_obj : code object
3389 3409 A compiled code object, to be executed
3390 3410 result : ExecutionResult, optional
3391 3411 An object to store exceptions that occur during execution.
3392 3412 async_ : Bool (Experimental)
3393 3413 Attempt to run top-level asynchronous code in a default loop.
3394 3414
3395 3415 Returns
3396 3416 -------
3397 3417 False : successful execution.
3398 3418 True : an error occurred.
3399 3419 """
3400 3420 # special value to say that anything above is IPython and should be
3401 3421 # hidden.
3402 3422 __tracebackhide__ = "__ipython_bottom__"
3403 3423 # Set our own excepthook in case the user code tries to call it
3404 3424 # directly, so that the IPython crash handler doesn't get triggered
3405 3425 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3406 3426
3407 3427 # we save the original sys.excepthook in the instance, in case config
3408 3428 # code (such as magics) needs access to it.
3409 3429 self.sys_excepthook = old_excepthook
3410 3430 outflag = True # happens in more places, so it's easier as default
3411 3431 try:
3412 3432 try:
3413 3433 self.hooks.pre_run_code_hook()
3414 3434 if async_ and sys.version_info < (3,8):
3415 3435 last_expr = (await self._async_exec(code_obj, self.user_ns))
3416 3436 code = compile('last_expr', 'fake', "single")
3417 3437 exec(code, {'last_expr': last_expr})
3418 3438 elif async_ :
3419 3439 await eval(code_obj, self.user_global_ns, self.user_ns)
3420 3440 else:
3421 3441 exec(code_obj, self.user_global_ns, self.user_ns)
3422 3442 finally:
3423 3443 # Reset our crash handler in place
3424 3444 sys.excepthook = old_excepthook
3425 3445 except SystemExit as e:
3426 3446 if result is not None:
3427 3447 result.error_in_exec = e
3428 3448 self.showtraceback(exception_only=True)
3429 3449 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3430 3450 except self.custom_exceptions:
3431 3451 etype, value, tb = sys.exc_info()
3432 3452 if result is not None:
3433 3453 result.error_in_exec = value
3434 3454 self.CustomTB(etype, value, tb)
3435 3455 except:
3436 3456 if result is not None:
3437 3457 result.error_in_exec = sys.exc_info()[1]
3438 3458 self.showtraceback(running_compiled_code=True)
3439 3459 else:
3440 3460 outflag = False
3441 3461 return outflag
3442 3462
3443 3463 # For backwards compatibility
3444 3464 runcode = run_code
3445 3465
3446 3466 def check_complete(self, code: str) -> Tuple[str, str]:
3447 3467 """Return whether a block of code is ready to execute, or should be continued
3448 3468
3449 3469 Parameters
3450 3470 ----------
3451 3471 source : string
3452 3472 Python input code, which can be multiline.
3453 3473
3454 3474 Returns
3455 3475 -------
3456 3476 status : str
3457 3477 One of 'complete', 'incomplete', or 'invalid' if source is not a
3458 3478 prefix of valid code.
3459 3479 indent : str
3460 3480 When status is 'incomplete', this is some whitespace to insert on
3461 3481 the next line of the prompt.
3462 3482 """
3463 3483 status, nspaces = self.input_transformer_manager.check_complete(code)
3464 3484 return status, ' ' * (nspaces or 0)
3465 3485
3466 3486 #-------------------------------------------------------------------------
3467 3487 # Things related to GUI support and pylab
3468 3488 #-------------------------------------------------------------------------
3469 3489
3470 3490 active_eventloop = None
3471 3491
3472 3492 def enable_gui(self, gui=None):
3473 3493 raise NotImplementedError('Implement enable_gui in a subclass')
3474 3494
3475 3495 def enable_matplotlib(self, gui=None):
3476 3496 """Enable interactive matplotlib and inline figure support.
3477 3497
3478 3498 This takes the following steps:
3479 3499
3480 3500 1. select the appropriate eventloop and matplotlib backend
3481 3501 2. set up matplotlib for interactive use with that backend
3482 3502 3. configure formatters for inline figure display
3483 3503 4. enable the selected gui eventloop
3484 3504
3485 3505 Parameters
3486 3506 ----------
3487 3507 gui : optional, string
3488 3508 If given, dictates the choice of matplotlib GUI backend to use
3489 3509 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3490 3510 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3491 3511 matplotlib (as dictated by the matplotlib build-time options plus the
3492 3512 user's matplotlibrc configuration file). Note that not all backends
3493 3513 make sense in all contexts, for example a terminal ipython can't
3494 3514 display figures inline.
3495 3515 """
3496 3516 from IPython.core import pylabtools as pt
3497 3517 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3498 3518
3499 3519 if gui != 'inline':
3500 3520 # If we have our first gui selection, store it
3501 3521 if self.pylab_gui_select is None:
3502 3522 self.pylab_gui_select = gui
3503 3523 # Otherwise if they are different
3504 3524 elif gui != self.pylab_gui_select:
3505 3525 print('Warning: Cannot change to a different GUI toolkit: %s.'
3506 3526 ' Using %s instead.' % (gui, self.pylab_gui_select))
3507 3527 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3508 3528
3509 3529 pt.activate_matplotlib(backend)
3510 3530 pt.configure_inline_support(self, backend)
3511 3531
3512 3532 # Now we must activate the gui pylab wants to use, and fix %run to take
3513 3533 # plot updates into account
3514 3534 self.enable_gui(gui)
3515 3535 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3516 3536 pt.mpl_runner(self.safe_execfile)
3517 3537
3518 3538 return gui, backend
3519 3539
3520 3540 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3521 3541 """Activate pylab support at runtime.
3522 3542
3523 3543 This turns on support for matplotlib, preloads into the interactive
3524 3544 namespace all of numpy and pylab, and configures IPython to correctly
3525 3545 interact with the GUI event loop. The GUI backend to be used can be
3526 3546 optionally selected with the optional ``gui`` argument.
3527 3547
3528 3548 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3529 3549
3530 3550 Parameters
3531 3551 ----------
3532 3552 gui : optional, string
3533 3553 If given, dictates the choice of matplotlib GUI backend to use
3534 3554 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3535 3555 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3536 3556 matplotlib (as dictated by the matplotlib build-time options plus the
3537 3557 user's matplotlibrc configuration file). Note that not all backends
3538 3558 make sense in all contexts, for example a terminal ipython can't
3539 3559 display figures inline.
3540 3560 import_all : optional, bool, default: True
3541 3561 Whether to do `from numpy import *` and `from pylab import *`
3542 3562 in addition to module imports.
3543 3563 welcome_message : deprecated
3544 3564 This argument is ignored, no welcome message will be displayed.
3545 3565 """
3546 3566 from IPython.core.pylabtools import import_pylab
3547 3567
3548 3568 gui, backend = self.enable_matplotlib(gui)
3549 3569
3550 3570 # We want to prevent the loading of pylab to pollute the user's
3551 3571 # namespace as shown by the %who* magics, so we execute the activation
3552 3572 # code in an empty namespace, and we update *both* user_ns and
3553 3573 # user_ns_hidden with this information.
3554 3574 ns = {}
3555 3575 import_pylab(ns, import_all)
3556 3576 # warn about clobbered names
3557 3577 ignored = {"__builtins__"}
3558 3578 both = set(ns).intersection(self.user_ns).difference(ignored)
3559 3579 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3560 3580 self.user_ns.update(ns)
3561 3581 self.user_ns_hidden.update(ns)
3562 3582 return gui, backend, clobbered
3563 3583
3564 3584 #-------------------------------------------------------------------------
3565 3585 # Utilities
3566 3586 #-------------------------------------------------------------------------
3567 3587
3568 3588 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3569 3589 """Expand python variables in a string.
3570 3590
3571 3591 The depth argument indicates how many frames above the caller should
3572 3592 be walked to look for the local namespace where to expand variables.
3573 3593
3574 3594 The global namespace for expansion is always the user's interactive
3575 3595 namespace.
3576 3596 """
3577 3597 ns = self.user_ns.copy()
3578 3598 try:
3579 3599 frame = sys._getframe(depth+1)
3580 3600 except ValueError:
3581 3601 # This is thrown if there aren't that many frames on the stack,
3582 3602 # e.g. if a script called run_line_magic() directly.
3583 3603 pass
3584 3604 else:
3585 3605 ns.update(frame.f_locals)
3586 3606
3587 3607 try:
3588 3608 # We have to use .vformat() here, because 'self' is a valid and common
3589 3609 # name, and expanding **ns for .format() would make it collide with
3590 3610 # the 'self' argument of the method.
3591 3611 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3592 3612 except Exception:
3593 3613 # if formatter couldn't format, just let it go untransformed
3594 3614 pass
3595 3615 return cmd
3596 3616
3597 3617 def mktempfile(self, data=None, prefix='ipython_edit_'):
3598 3618 """Make a new tempfile and return its filename.
3599 3619
3600 3620 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3601 3621 but it registers the created filename internally so ipython cleans it up
3602 3622 at exit time.
3603 3623
3604 3624 Optional inputs:
3605 3625
3606 3626 - data(None): if data is given, it gets written out to the temp file
3607 3627 immediately, and the file is closed again."""
3608 3628
3609 3629 dir_path = Path(tempfile.mkdtemp(prefix=prefix))
3610 3630 self.tempdirs.append(dir_path)
3611 3631
3612 3632 handle, filename = tempfile.mkstemp(".py", prefix, dir=str(dir_path))
3613 3633 os.close(handle) # On Windows, there can only be one open handle on a file
3614 3634
3615 3635 file_path = Path(filename)
3616 3636 self.tempfiles.append(file_path)
3617 3637
3618 3638 if data:
3619 3639 file_path.write_text(data)
3620 3640 return filename
3621 3641
3622 3642 @undoc
3623 3643 def write(self,data):
3624 3644 """DEPRECATED: Write a string to the default output"""
3625 3645 warn('InteractiveShell.write() is deprecated, use sys.stdout instead',
3626 3646 DeprecationWarning, stacklevel=2)
3627 3647 sys.stdout.write(data)
3628 3648
3629 3649 @undoc
3630 3650 def write_err(self,data):
3631 3651 """DEPRECATED: Write a string to the default error output"""
3632 3652 warn('InteractiveShell.write_err() is deprecated, use sys.stderr instead',
3633 3653 DeprecationWarning, stacklevel=2)
3634 3654 sys.stderr.write(data)
3635 3655
3636 3656 def ask_yes_no(self, prompt, default=None, interrupt=None):
3637 3657 if self.quiet:
3638 3658 return True
3639 3659 return ask_yes_no(prompt,default,interrupt)
3640 3660
3641 3661 def show_usage(self):
3642 3662 """Show a usage message"""
3643 3663 page.page(IPython.core.usage.interactive_usage)
3644 3664
3645 3665 def extract_input_lines(self, range_str, raw=False):
3646 3666 """Return as a string a set of input history slices.
3647 3667
3648 3668 Parameters
3649 3669 ----------
3650 3670 range_str : string
3651 3671 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3652 3672 since this function is for use by magic functions which get their
3653 3673 arguments as strings. The number before the / is the session
3654 3674 number: ~n goes n back from the current session.
3655 3675
3656 3676 raw : bool, optional
3657 3677 By default, the processed input is used. If this is true, the raw
3658 3678 input history is used instead.
3659 3679
3660 3680 Notes
3661 3681 -----
3662 3682
3663 3683 Slices can be described with two notations:
3664 3684
3665 3685 * ``N:M`` -> standard python form, means including items N...(M-1).
3666 3686 * ``N-M`` -> include items N..M (closed endpoint).
3667 3687 """
3668 3688 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3669 3689 return "\n".join(x for _, _, x in lines)
3670 3690
3671 3691 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3672 3692 """Get a code string from history, file, url, or a string or macro.
3673 3693
3674 3694 This is mainly used by magic functions.
3675 3695
3676 3696 Parameters
3677 3697 ----------
3678 3698
3679 3699 target : str
3680 3700
3681 3701 A string specifying code to retrieve. This will be tried respectively
3682 3702 as: ranges of input history (see %history for syntax), url,
3683 3703 corresponding .py file, filename, or an expression evaluating to a
3684 3704 string or Macro in the user namespace.
3685 3705
3686 3706 raw : bool
3687 3707 If true (default), retrieve raw history. Has no effect on the other
3688 3708 retrieval mechanisms.
3689 3709
3690 3710 py_only : bool (default False)
3691 3711 Only try to fetch python code, do not try alternative methods to decode file
3692 3712 if unicode fails.
3693 3713
3694 3714 Returns
3695 3715 -------
3696 3716 A string of code.
3697 3717
3698 3718 ValueError is raised if nothing is found, and TypeError if it evaluates
3699 3719 to an object of another type. In each case, .args[0] is a printable
3700 3720 message.
3701 3721 """
3702 3722 code = self.extract_input_lines(target, raw=raw) # Grab history
3703 3723 if code:
3704 3724 return code
3705 3725 try:
3706 3726 if target.startswith(('http://', 'https://')):
3707 3727 return openpy.read_py_url(target, skip_encoding_cookie=skip_encoding_cookie)
3708 3728 except UnicodeDecodeError as e:
3709 3729 if not py_only :
3710 3730 # Deferred import
3711 3731 from urllib.request import urlopen
3712 3732 response = urlopen(target)
3713 3733 return response.read().decode('latin1')
3714 3734 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3715 3735
3716 3736 potential_target = [target]
3717 3737 try :
3718 3738 potential_target.insert(0,get_py_filename(target))
3719 3739 except IOError:
3720 3740 pass
3721 3741
3722 3742 for tgt in potential_target :
3723 3743 if os.path.isfile(tgt): # Read file
3724 3744 try :
3725 3745 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3726 3746 except UnicodeDecodeError as e:
3727 3747 if not py_only :
3728 3748 with io_open(tgt,'r', encoding='latin1') as f :
3729 3749 return f.read()
3730 3750 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3731 3751 elif os.path.isdir(os.path.expanduser(tgt)):
3732 3752 raise ValueError("'%s' is a directory, not a regular file." % target)
3733 3753
3734 3754 if search_ns:
3735 3755 # Inspect namespace to load object source
3736 3756 object_info = self.object_inspect(target, detail_level=1)
3737 3757 if object_info['found'] and object_info['source']:
3738 3758 return object_info['source']
3739 3759
3740 3760 try: # User namespace
3741 3761 codeobj = eval(target, self.user_ns)
3742 3762 except Exception as e:
3743 3763 raise ValueError(("'%s' was not found in history, as a file, url, "
3744 3764 "nor in the user namespace.") % target) from e
3745 3765
3746 3766 if isinstance(codeobj, str):
3747 3767 return codeobj
3748 3768 elif isinstance(codeobj, Macro):
3749 3769 return codeobj.value
3750 3770
3751 3771 raise TypeError("%s is neither a string nor a macro." % target,
3752 3772 codeobj)
3753 3773
3754 3774 #-------------------------------------------------------------------------
3755 3775 # Things related to IPython exiting
3756 3776 #-------------------------------------------------------------------------
3757 3777 def atexit_operations(self):
3758 3778 """This will be executed at the time of exit.
3759 3779
3760 3780 Cleanup operations and saving of persistent data that is done
3761 3781 unconditionally by IPython should be performed here.
3762 3782
3763 3783 For things that may depend on startup flags or platform specifics (such
3764 3784 as having readline or not), register a separate atexit function in the
3765 3785 code that has the appropriate information, rather than trying to
3766 3786 clutter
3767 3787 """
3768 3788 # Close the history session (this stores the end time and line count)
3769 3789 # this must be *before* the tempfile cleanup, in case of temporary
3770 3790 # history db
3771 3791 self.history_manager.end_session()
3772 3792
3773 3793 # Cleanup all tempfiles and folders left around
3774 3794 for tfile in self.tempfiles:
3775 3795 try:
3776 3796 tfile.unlink()
3777 3797 except FileNotFoundError:
3778 3798 pass
3779 3799
3780 3800 for tdir in self.tempdirs:
3781 3801 try:
3782 3802 tdir.rmdir()
3783 3803 except FileNotFoundError:
3784 3804 pass
3785 3805
3786 3806 # Clear all user namespaces to release all references cleanly.
3787 3807 self.reset(new_session=False)
3788 3808
3789 3809 # Run user hooks
3790 3810 self.hooks.shutdown_hook()
3791 3811
3792 3812 def cleanup(self):
3793 3813 self.restore_sys_module_state()
3794 3814
3795 3815
3796 3816 # Overridden in terminal subclass to change prompts
3797 3817 def switch_doctest_mode(self, mode):
3798 3818 pass
3799 3819
3800 3820
3801 3821 class InteractiveShellABC(metaclass=abc.ABCMeta):
3802 3822 """An abstract base class for InteractiveShell."""
3803 3823
3804 3824 InteractiveShellABC.register(InteractiveShell)
@@ -1,730 +1,737 b''
1 1 """Implementation of code management magic functions.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2012 The IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 # Stdlib
16 16 import inspect
17 17 import io
18 18 import os
19 19 import re
20 20 import sys
21 21 import ast
22 22 from itertools import chain
23 from urllib.request import urlopen
23 from urllib.request import Request, urlopen
24 24 from urllib.parse import urlencode
25 25 from pathlib import Path
26 26
27 27 # Our own packages
28 28 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
29 29 from IPython.core.macro import Macro
30 30 from IPython.core.magic import Magics, magics_class, line_magic
31 31 from IPython.core.oinspect import find_file, find_source_lines
32 from IPython.core.release import version
32 33 from IPython.testing.skipdoctest import skip_doctest
33 34 from IPython.utils.contexts import preserve_keys
34 35 from IPython.utils.path import get_py_filename
35 36 from warnings import warn
36 37 from logging import error
37 38 from IPython.utils.text import get_text_list
38 39
39 40 #-----------------------------------------------------------------------------
40 41 # Magic implementation classes
41 42 #-----------------------------------------------------------------------------
42 43
43 44 # Used for exception handling in magic_edit
44 45 class MacroToEdit(ValueError): pass
45 46
46 47 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
47 48
48 49 # To match, e.g. 8-10 1:5 :10 3-
49 50 range_re = re.compile(r"""
50 51 (?P<start>\d+)?
51 52 ((?P<sep>[\-:])
52 53 (?P<end>\d+)?)?
53 54 $""", re.VERBOSE)
54 55
55 56
56 57 def extract_code_ranges(ranges_str):
57 58 """Turn a string of range for %%load into 2-tuples of (start, stop)
58 59 ready to use as a slice of the content split by lines.
59 60
60 61 Examples
61 62 --------
62 63 list(extract_input_ranges("5-10 2"))
63 64 [(4, 10), (1, 2)]
64 65 """
65 66 for range_str in ranges_str.split():
66 67 rmatch = range_re.match(range_str)
67 68 if not rmatch:
68 69 continue
69 70 sep = rmatch.group("sep")
70 71 start = rmatch.group("start")
71 72 end = rmatch.group("end")
72 73
73 74 if sep == '-':
74 75 start = int(start) - 1 if start else None
75 76 end = int(end) if end else None
76 77 elif sep == ':':
77 78 start = int(start) - 1 if start else None
78 79 end = int(end) - 1 if end else None
79 80 else:
80 81 end = int(start)
81 82 start = int(start) - 1
82 83 yield (start, end)
83 84
84 85
85 86 def extract_symbols(code, symbols):
86 87 """
87 88 Return a tuple (blocks, not_found)
88 89 where ``blocks`` is a list of code fragments
89 90 for each symbol parsed from code, and ``not_found`` are
90 91 symbols not found in the code.
91 92
92 93 For example::
93 94
94 95 In [1]: code = '''a = 10
95 96 ...: def b(): return 42
96 97 ...: class A: pass'''
97 98
98 99 In [2]: extract_symbols(code, 'A,b,z')
99 100 Out[2]: (['class A: pass\\n', 'def b(): return 42\\n'], ['z'])
100 101 """
101 102 symbols = symbols.split(',')
102 103
103 104 # this will raise SyntaxError if code isn't valid Python
104 105 py_code = ast.parse(code)
105 106
106 107 marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
107 108 code = code.split('\n')
108 109
109 110 symbols_lines = {}
110 111
111 112 # we already know the start_lineno of each symbol (marks).
112 113 # To find each end_lineno, we traverse in reverse order until each
113 114 # non-blank line
114 115 end = len(code)
115 116 for name, start in reversed(marks):
116 117 while not code[end - 1].strip():
117 118 end -= 1
118 119 if name:
119 120 symbols_lines[name] = (start - 1, end)
120 121 end = start - 1
121 122
122 123 # Now symbols_lines is a map
123 124 # {'symbol_name': (start_lineno, end_lineno), ...}
124 125
125 126 # fill a list with chunks of codes for each requested symbol
126 127 blocks = []
127 128 not_found = []
128 129 for symbol in symbols:
129 130 if symbol in symbols_lines:
130 131 start, end = symbols_lines[symbol]
131 132 blocks.append('\n'.join(code[start:end]) + '\n')
132 133 else:
133 134 not_found.append(symbol)
134 135
135 136 return blocks, not_found
136 137
137 138 def strip_initial_indent(lines):
138 139 """For %load, strip indent from lines until finding an unindented line.
139 140
140 141 https://github.com/ipython/ipython/issues/9775
141 142 """
142 143 indent_re = re.compile(r'\s+')
143 144
144 145 it = iter(lines)
145 146 first_line = next(it)
146 147 indent_match = indent_re.match(first_line)
147 148
148 149 if indent_match:
149 150 # First line was indented
150 151 indent = indent_match.group()
151 152 yield first_line[len(indent):]
152 153
153 154 for line in it:
154 155 if line.startswith(indent):
155 156 yield line[len(indent):]
156 157 else:
157 158 # Less indented than the first line - stop dedenting
158 159 yield line
159 160 break
160 161 else:
161 162 yield first_line
162 163
163 164 # Pass the remaining lines through without dedenting
164 165 for line in it:
165 166 yield line
166 167
167 168
168 169 class InteractivelyDefined(Exception):
169 170 """Exception for interactively defined variable in magic_edit"""
170 171 def __init__(self, index):
171 172 self.index = index
172 173
173 174
174 175 @magics_class
175 176 class CodeMagics(Magics):
176 177 """Magics related to code management (loading, saving, editing, ...)."""
177 178
178 179 def __init__(self, *args, **kwargs):
179 180 self._knowntemps = set()
180 181 super(CodeMagics, self).__init__(*args, **kwargs)
181 182
182 183 @line_magic
183 184 def save(self, parameter_s=''):
184 185 """Save a set of lines or a macro to a given filename.
185 186
186 187 Usage:\\
187 188 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
188 189
189 190 Options:
190 191
191 192 -r: use 'raw' input. By default, the 'processed' history is used,
192 193 so that magics are loaded in their transformed version to valid
193 194 Python. If this option is given, the raw input as typed as the
194 195 command line is used instead.
195 196
196 197 -f: force overwrite. If file exists, %save will prompt for overwrite
197 198 unless -f is given.
198 199
199 200 -a: append to the file instead of overwriting it.
200 201
201 202 This function uses the same syntax as %history for input ranges,
202 203 then saves the lines to the filename you specify.
203 204
204 205 It adds a '.py' extension to the file if you don't do so yourself, and
205 206 it asks for confirmation before overwriting existing files.
206 207
207 208 If `-r` option is used, the default extension is `.ipy`.
208 209 """
209 210
210 211 opts,args = self.parse_options(parameter_s,'fra',mode='list')
211 212 if not args:
212 213 raise UsageError('Missing filename.')
213 214 raw = 'r' in opts
214 215 force = 'f' in opts
215 216 append = 'a' in opts
216 217 mode = 'a' if append else 'w'
217 218 ext = '.ipy' if raw else '.py'
218 219 fname, codefrom = args[0], " ".join(args[1:])
219 220 if not fname.endswith(('.py','.ipy')):
220 221 fname += ext
221 222 file_exists = os.path.isfile(fname)
222 223 if file_exists and not force and not append:
223 224 try:
224 225 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
225 226 except StdinNotImplementedError:
226 227 print("File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s))
227 228 return
228 229 if not overwrite :
229 230 print('Operation cancelled.')
230 231 return
231 232 try:
232 233 cmds = self.shell.find_user_code(codefrom,raw)
233 234 except (TypeError, ValueError) as e:
234 235 print(e.args[0])
235 236 return
236 237 with io.open(fname, mode, encoding="utf-8") as f:
237 238 if not file_exists or not append:
238 239 f.write("# coding: utf-8\n")
239 240 f.write(cmds)
240 241 # make sure we end on a newline
241 242 if not cmds.endswith('\n'):
242 243 f.write('\n')
243 244 print('The following commands were written to file `%s`:' % fname)
244 245 print(cmds)
245 246
246 247 @line_magic
247 248 def pastebin(self, parameter_s=''):
248 """Upload code to dpaste's paste bin, returning the URL.
249 """Upload code to dpaste.com, returning the URL.
249 250
250 251 Usage:\\
251 252 %pastebin [-d "Custom description"] 1-7
252 253
253 254 The argument can be an input history range, a filename, or the name of a
254 255 string or macro.
255 256
256 257 Options:
257 258
258 -d: Pass a custom description for the gist. The default will say
259 -d: Pass a custom description. The default will say
259 260 "Pasted from IPython".
260 261 """
261 262 opts, args = self.parse_options(parameter_s, 'd:')
262 263
263 264 try:
264 265 code = self.shell.find_user_code(args)
265 266 except (ValueError, TypeError) as e:
266 267 print(e.args[0])
267 268 return
268 269
269 post_data = urlencode({
270 "title": opts.get('d', "Pasted from IPython"),
271 "syntax": "python3",
272 "content": code
273 }).encode('utf-8')
274
275 response = urlopen("http://dpaste.com/api/v2/", post_data)
270 post_data = urlencode(
271 {
272 "title": opts.get("d", "Pasted from IPython"),
273 "syntax": "python",
274 "content": code,
275 }
276 ).encode("utf-8")
277
278 request = Request(
279 "http://dpaste.com/api/v2/",
280 headers={"User-Agent": "IPython v{}".format(version)},
281 )
282 response = urlopen(request, post_data)
276 283 return response.headers.get('Location')
277 284
278 285 @line_magic
279 286 def loadpy(self, arg_s):
280 287 """Alias of `%load`
281 288
282 289 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
283 290 extension. So it has been renamed simply into %load. You can look at
284 291 `%load`'s docstring for more info.
285 292 """
286 293 self.load(arg_s)
287 294
288 295 @line_magic
289 296 def load(self, arg_s):
290 297 """Load code into the current frontend.
291 298
292 299 Usage:\\
293 300 %load [options] source
294 301
295 302 where source can be a filename, URL, input history range, macro, or
296 303 element in the user namespace
297 304
298 305 Options:
299 306
300 307 -r <lines>: Specify lines or ranges of lines to load from the source.
301 308 Ranges could be specified as x-y (x..y) or in python-style x:y
302 309 (x..(y-1)). Both limits x and y can be left blank (meaning the
303 310 beginning and end of the file, respectively).
304 311
305 312 -s <symbols>: Specify function or classes to load from python source.
306 313
307 314 -y : Don't ask confirmation for loading source above 200 000 characters.
308 315
309 316 -n : Include the user's namespace when searching for source code.
310 317
311 318 This magic command can either take a local filename, a URL, an history
312 319 range (see %history) or a macro as argument, it will prompt for
313 320 confirmation before loading source with more than 200 000 characters, unless
314 321 -y flag is passed or if the frontend does not support raw_input::
315 322
316 323 %load myscript.py
317 324 %load 7-27
318 325 %load myMacro
319 326 %load http://www.example.com/myscript.py
320 327 %load -r 5-10 myscript.py
321 328 %load -r 10-20,30,40: foo.py
322 329 %load -s MyClass,wonder_function myscript.py
323 330 %load -n MyClass
324 331 %load -n my_module.wonder_function
325 332 """
326 333 opts,args = self.parse_options(arg_s,'yns:r:')
327 334
328 335 if not args:
329 336 raise UsageError('Missing filename, URL, input history range, '
330 337 'macro, or element in the user namespace.')
331 338
332 339 search_ns = 'n' in opts
333 340
334 341 contents = self.shell.find_user_code(args, search_ns=search_ns)
335 342
336 343 if 's' in opts:
337 344 try:
338 345 blocks, not_found = extract_symbols(contents, opts['s'])
339 346 except SyntaxError:
340 347 # non python code
341 348 error("Unable to parse the input as valid Python code")
342 349 return
343 350
344 351 if len(not_found) == 1:
345 352 warn('The symbol `%s` was not found' % not_found[0])
346 353 elif len(not_found) > 1:
347 354 warn('The symbols %s were not found' % get_text_list(not_found,
348 355 wrap_item_with='`')
349 356 )
350 357
351 358 contents = '\n'.join(blocks)
352 359
353 360 if 'r' in opts:
354 361 ranges = opts['r'].replace(',', ' ')
355 362 lines = contents.split('\n')
356 363 slices = extract_code_ranges(ranges)
357 364 contents = [lines[slice(*slc)] for slc in slices]
358 365 contents = '\n'.join(strip_initial_indent(chain.from_iterable(contents)))
359 366
360 367 l = len(contents)
361 368
362 369 # 200 000 is ~ 2500 full 80 character lines
363 370 # so in average, more than 5000 lines
364 371 if l > 200000 and 'y' not in opts:
365 372 try:
366 373 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
367 374 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
368 375 except StdinNotImplementedError:
369 376 #assume yes if raw input not implemented
370 377 ans = True
371 378
372 379 if ans is False :
373 380 print('Operation cancelled.')
374 381 return
375 382
376 383 contents = "# %load {}\n".format(arg_s) + contents
377 384
378 385 self.shell.set_next_input(contents, replace=True)
379 386
380 387 @staticmethod
381 388 def _find_edit_target(shell, args, opts, last_call):
382 389 """Utility method used by magic_edit to find what to edit."""
383 390
384 391 def make_filename(arg):
385 392 "Make a filename from the given args"
386 393 try:
387 394 filename = get_py_filename(arg)
388 395 except IOError:
389 396 # If it ends with .py but doesn't already exist, assume we want
390 397 # a new file.
391 398 if arg.endswith('.py'):
392 399 filename = arg
393 400 else:
394 401 filename = None
395 402 return filename
396 403
397 404 # Set a few locals from the options for convenience:
398 405 opts_prev = 'p' in opts
399 406 opts_raw = 'r' in opts
400 407
401 408 # custom exceptions
402 409 class DataIsObject(Exception): pass
403 410
404 411 # Default line number value
405 412 lineno = opts.get('n',None)
406 413
407 414 if opts_prev:
408 415 args = '_%s' % last_call[0]
409 416 if args not in shell.user_ns:
410 417 args = last_call[1]
411 418
412 419 # by default this is done with temp files, except when the given
413 420 # arg is a filename
414 421 use_temp = True
415 422
416 423 data = ''
417 424
418 425 # First, see if the arguments should be a filename.
419 426 filename = make_filename(args)
420 427 if filename:
421 428 use_temp = False
422 429 elif args:
423 430 # Mode where user specifies ranges of lines, like in %macro.
424 431 data = shell.extract_input_lines(args, opts_raw)
425 432 if not data:
426 433 try:
427 434 # Load the parameter given as a variable. If not a string,
428 435 # process it as an object instead (below)
429 436
430 437 #print '*** args',args,'type',type(args) # dbg
431 438 data = eval(args, shell.user_ns)
432 439 if not isinstance(data, str):
433 440 raise DataIsObject
434 441
435 442 except (NameError,SyntaxError):
436 443 # given argument is not a variable, try as a filename
437 444 filename = make_filename(args)
438 445 if filename is None:
439 446 warn("Argument given (%s) can't be found as a variable "
440 447 "or as a filename." % args)
441 448 return (None, None, None)
442 449 use_temp = False
443 450
444 451 except DataIsObject as e:
445 452 # macros have a special edit function
446 453 if isinstance(data, Macro):
447 454 raise MacroToEdit(data) from e
448 455
449 456 # For objects, try to edit the file where they are defined
450 457 filename = find_file(data)
451 458 if filename:
452 459 if 'fakemodule' in filename.lower() and \
453 460 inspect.isclass(data):
454 461 # class created by %edit? Try to find source
455 462 # by looking for method definitions instead, the
456 463 # __module__ in those classes is FakeModule.
457 464 attrs = [getattr(data, aname) for aname in dir(data)]
458 465 for attr in attrs:
459 466 if not inspect.ismethod(attr):
460 467 continue
461 468 filename = find_file(attr)
462 469 if filename and \
463 470 'fakemodule' not in filename.lower():
464 471 # change the attribute to be the edit
465 472 # target instead
466 473 data = attr
467 474 break
468 475
469 476 m = ipython_input_pat.match(os.path.basename(filename))
470 477 if m:
471 478 raise InteractivelyDefined(int(m.groups()[0])) from e
472 479
473 480 datafile = 1
474 481 if filename is None:
475 482 filename = make_filename(args)
476 483 datafile = 1
477 484 if filename is not None:
478 485 # only warn about this if we get a real name
479 486 warn('Could not find file where `%s` is defined.\n'
480 487 'Opening a file named `%s`' % (args, filename))
481 488 # Now, make sure we can actually read the source (if it was
482 489 # in a temp file it's gone by now).
483 490 if datafile:
484 491 if lineno is None:
485 492 lineno = find_source_lines(data)
486 493 if lineno is None:
487 494 filename = make_filename(args)
488 495 if filename is None:
489 496 warn('The file where `%s` was defined '
490 497 'cannot be read or found.' % data)
491 498 return (None, None, None)
492 499 use_temp = False
493 500
494 501 if use_temp:
495 502 filename = shell.mktempfile(data)
496 503 print('IPython will make a temporary file named:',filename)
497 504
498 505 # use last_call to remember the state of the previous call, but don't
499 506 # let it be clobbered by successive '-p' calls.
500 507 try:
501 508 last_call[0] = shell.displayhook.prompt_count
502 509 if not opts_prev:
503 510 last_call[1] = args
504 511 except:
505 512 pass
506 513
507 514
508 515 return filename, lineno, use_temp
509 516
510 517 def _edit_macro(self,mname,macro):
511 518 """open an editor with the macro data in a file"""
512 519 filename = self.shell.mktempfile(macro.value)
513 520 self.shell.hooks.editor(filename)
514 521
515 522 # and make a new macro object, to replace the old one
516 523 mvalue = Path(filename).read_text()
517 524 self.shell.user_ns[mname] = Macro(mvalue)
518 525
519 526 @skip_doctest
520 527 @line_magic
521 528 def edit(self, parameter_s='',last_call=['','']):
522 529 """Bring up an editor and execute the resulting code.
523 530
524 531 Usage:
525 532 %edit [options] [args]
526 533
527 534 %edit runs IPython's editor hook. The default version of this hook is
528 535 set to call the editor specified by your $EDITOR environment variable.
529 536 If this isn't found, it will default to vi under Linux/Unix and to
530 537 notepad under Windows. See the end of this docstring for how to change
531 538 the editor hook.
532 539
533 540 You can also set the value of this editor via the
534 541 ``TerminalInteractiveShell.editor`` option in your configuration file.
535 542 This is useful if you wish to use a different editor from your typical
536 543 default with IPython (and for Windows users who typically don't set
537 544 environment variables).
538 545
539 546 This command allows you to conveniently edit multi-line code right in
540 547 your IPython session.
541 548
542 549 If called without arguments, %edit opens up an empty editor with a
543 550 temporary file and will execute the contents of this file when you
544 551 close it (don't forget to save it!).
545 552
546 553
547 554 Options:
548 555
549 556 -n <number>: open the editor at a specified line number. By default,
550 557 the IPython editor hook uses the unix syntax 'editor +N filename', but
551 558 you can configure this by providing your own modified hook if your
552 559 favorite editor supports line-number specifications with a different
553 560 syntax.
554 561
555 562 -p: this will call the editor with the same data as the previous time
556 563 it was used, regardless of how long ago (in your current session) it
557 564 was.
558 565
559 566 -r: use 'raw' input. This option only applies to input taken from the
560 567 user's history. By default, the 'processed' history is used, so that
561 568 magics are loaded in their transformed version to valid Python. If
562 569 this option is given, the raw input as typed as the command line is
563 570 used instead. When you exit the editor, it will be executed by
564 571 IPython's own processor.
565 572
566 573 -x: do not execute the edited code immediately upon exit. This is
567 574 mainly useful if you are editing programs which need to be called with
568 575 command line arguments, which you can then do using %run.
569 576
570 577
571 578 Arguments:
572 579
573 580 If arguments are given, the following possibilities exist:
574 581
575 582 - If the argument is a filename, IPython will load that into the
576 583 editor. It will execute its contents with execfile() when you exit,
577 584 loading any code in the file into your interactive namespace.
578 585
579 586 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
580 587 The syntax is the same as in the %history magic.
581 588
582 589 - If the argument is a string variable, its contents are loaded
583 590 into the editor. You can thus edit any string which contains
584 591 python code (including the result of previous edits).
585 592
586 593 - If the argument is the name of an object (other than a string),
587 594 IPython will try to locate the file where it was defined and open the
588 595 editor at the point where it is defined. You can use `%edit function`
589 596 to load an editor exactly at the point where 'function' is defined,
590 597 edit it and have the file be executed automatically.
591 598
592 599 - If the object is a macro (see %macro for details), this opens up your
593 600 specified editor with a temporary file containing the macro's data.
594 601 Upon exit, the macro is reloaded with the contents of the file.
595 602
596 603 Note: opening at an exact line is only supported under Unix, and some
597 604 editors (like kedit and gedit up to Gnome 2.8) do not understand the
598 605 '+NUMBER' parameter necessary for this feature. Good editors like
599 606 (X)Emacs, vi, jed, pico and joe all do.
600 607
601 608 After executing your code, %edit will return as output the code you
602 609 typed in the editor (except when it was an existing file). This way
603 610 you can reload the code in further invocations of %edit as a variable,
604 611 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
605 612 the output.
606 613
607 614 Note that %edit is also available through the alias %ed.
608 615
609 616 This is an example of creating a simple function inside the editor and
610 617 then modifying it. First, start up the editor::
611 618
612 619 In [1]: edit
613 620 Editing... done. Executing edited code...
614 621 Out[1]: 'def foo():\\n print "foo() was defined in an editing
615 622 session"\\n'
616 623
617 624 We can then call the function foo()::
618 625
619 626 In [2]: foo()
620 627 foo() was defined in an editing session
621 628
622 629 Now we edit foo. IPython automatically loads the editor with the
623 630 (temporary) file where foo() was previously defined::
624 631
625 632 In [3]: edit foo
626 633 Editing... done. Executing edited code...
627 634
628 635 And if we call foo() again we get the modified version::
629 636
630 637 In [4]: foo()
631 638 foo() has now been changed!
632 639
633 640 Here is an example of how to edit a code snippet successive
634 641 times. First we call the editor::
635 642
636 643 In [5]: edit
637 644 Editing... done. Executing edited code...
638 645 hello
639 646 Out[5]: "print 'hello'\\n"
640 647
641 648 Now we call it again with the previous output (stored in _)::
642 649
643 650 In [6]: edit _
644 651 Editing... done. Executing edited code...
645 652 hello world
646 653 Out[6]: "print 'hello world'\\n"
647 654
648 655 Now we call it with the output #8 (stored in _8, also as Out[8])::
649 656
650 657 In [7]: edit _8
651 658 Editing... done. Executing edited code...
652 659 hello again
653 660 Out[7]: "print 'hello again'\\n"
654 661
655 662
656 663 Changing the default editor hook:
657 664
658 665 If you wish to write your own editor hook, you can put it in a
659 666 configuration file which you load at startup time. The default hook
660 667 is defined in the IPython.core.hooks module, and you can use that as a
661 668 starting example for further modifications. That file also has
662 669 general instructions on how to set a new hook for use once you've
663 670 defined it."""
664 671 opts,args = self.parse_options(parameter_s,'prxn:')
665 672
666 673 try:
667 674 filename, lineno, is_temp = self._find_edit_target(self.shell,
668 675 args, opts, last_call)
669 676 except MacroToEdit as e:
670 677 self._edit_macro(args, e.args[0])
671 678 return
672 679 except InteractivelyDefined as e:
673 680 print("Editing In[%i]" % e.index)
674 681 args = str(e.index)
675 682 filename, lineno, is_temp = self._find_edit_target(self.shell,
676 683 args, opts, last_call)
677 684 if filename is None:
678 685 # nothing was found, warnings have already been issued,
679 686 # just give up.
680 687 return
681 688
682 689 if is_temp:
683 690 self._knowntemps.add(filename)
684 691 elif (filename in self._knowntemps):
685 692 is_temp = True
686 693
687 694
688 695 # do actual editing here
689 696 print('Editing...', end=' ')
690 697 sys.stdout.flush()
691 698 filepath = Path(filename)
692 699 try:
693 700 # Quote filenames that may have spaces in them when opening
694 701 # the editor
695 702 quoted = filename = str(filepath.absolute())
696 703 if " " in quoted:
697 704 quoted = "'%s'" % quoted
698 705 self.shell.hooks.editor(quoted, lineno)
699 706 except TryNext:
700 707 warn('Could not open editor')
701 708 return
702 709
703 710 # XXX TODO: should this be generalized for all string vars?
704 711 # For now, this is special-cased to blocks created by cpaste
705 712 if args.strip() == "pasted_block":
706 713 self.shell.user_ns["pasted_block"] = filepath.read_text()
707 714
708 715 if 'x' in opts: # -x prevents actual execution
709 716 print()
710 717 else:
711 718 print('done. Executing edited code...')
712 719 with preserve_keys(self.shell.user_ns, '__file__'):
713 720 if not is_temp:
714 721 self.shell.user_ns['__file__'] = filename
715 722 if 'r' in opts: # Untranslated IPython code
716 723 source = filepath.read_text()
717 724 self.shell.run_cell(source, store_history=False)
718 725 else:
719 726 self.shell.safe_execfile(filename, self.shell.user_ns,
720 727 self.shell.user_ns)
721 728
722 729 if is_temp:
723 730 try:
724 731 return filepath.read_text()
725 732 except IOError as msg:
726 733 if Path(msg.filename) == filepath:
727 734 warn('File not found. Did you forget to save?')
728 735 return
729 736 else:
730 737 self.shell.showtraceback()
@@ -1,318 +1,326 b''
1 1 """Implementation of magic functions related to History.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2012, IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 # Stdlib
16 16 import os
17 17 import sys
18 18 from io import open as io_open
19 import fnmatch
19 20
20 21 # Our own packages
21 22 from IPython.core.error import StdinNotImplementedError
22 23 from IPython.core.magic import Magics, magics_class, line_magic
23 24 from IPython.core.magic_arguments import (argument, magic_arguments,
24 25 parse_argstring)
25 26 from IPython.testing.skipdoctest import skip_doctest
26 27 from IPython.utils import io
27 28
28 29 #-----------------------------------------------------------------------------
29 30 # Magics class implementation
30 31 #-----------------------------------------------------------------------------
31 32
32 33
33 34 _unspecified = object()
34 35
35 36
36 37 @magics_class
37 38 class HistoryMagics(Magics):
38 39
39 40 @magic_arguments()
40 41 @argument(
41 42 '-n', dest='print_nums', action='store_true', default=False,
42 43 help="""
43 44 print line numbers for each input.
44 45 This feature is only available if numbered prompts are in use.
45 46 """)
46 47 @argument(
47 48 '-o', dest='get_output', action='store_true', default=False,
48 49 help="also print outputs for each input.")
49 50 @argument(
50 51 '-p', dest='pyprompts', action='store_true', default=False,
51 52 help="""
52 53 print classic '>>>' python prompts before each input.
53 54 This is useful for making documentation, and in conjunction
54 55 with -o, for producing doctest-ready output.
55 56 """)
56 57 @argument(
57 58 '-t', dest='raw', action='store_false', default=True,
58 59 help="""
59 60 print the 'translated' history, as IPython understands it.
60 61 IPython filters your input and converts it all into valid Python
61 62 source before executing it (things like magics or aliases are turned
62 63 into function calls, for example). With this option, you'll see the
63 64 native history instead of the user-entered version: '%%cd /' will be
64 65 seen as 'get_ipython().run_line_magic("cd", "/")' instead of '%%cd /'.
65 66 """)
66 67 @argument(
67 68 '-f', dest='filename',
68 69 help="""
69 70 FILENAME: instead of printing the output to the screen, redirect
70 71 it to the given file. The file is always overwritten, though *when
71 72 it can*, IPython asks for confirmation first. In particular, running
72 73 the command 'history -f FILENAME' from the IPython Notebook
73 74 interface will replace FILENAME even if it already exists *without*
74 75 confirmation.
75 76 """)
76 77 @argument(
77 78 '-g', dest='pattern', nargs='*', default=None,
78 79 help="""
79 80 treat the arg as a glob pattern to search for in (full) history.
80 81 This includes the saved history (almost all commands ever written).
81 82 The pattern may contain '?' to match one unknown character and '*'
82 83 to match any number of unknown characters. Use '%%hist -g' to show
83 84 full saved history (may be very long).
84 85 """)
85 86 @argument(
86 87 '-l', dest='limit', type=int, nargs='?', default=_unspecified,
87 88 help="""
88 89 get the last n lines from all sessions. Specify n as a single
89 90 arg, or the default is the last 10 lines.
90 91 """)
91 92 @argument(
92 93 '-u', dest='unique', action='store_true',
93 94 help="""
94 95 when searching history using `-g`, show only unique history.
95 96 """)
96 97 @argument('range', nargs='*')
97 98 @skip_doctest
98 99 @line_magic
99 100 def history(self, parameter_s = ''):
100 101 """Print input history (_i<n> variables), with most recent last.
101 102
102 103 By default, input history is printed without line numbers so it can be
103 104 directly pasted into an editor. Use -n to show them.
104 105
105 106 By default, all input history from the current session is displayed.
106 107 Ranges of history can be indicated using the syntax:
107 108
108 109 ``4``
109 110 Line 4, current session
110 111 ``4-6``
111 112 Lines 4-6, current session
112 113 ``243/1-5``
113 114 Lines 1-5, session 243
114 115 ``~2/7``
115 116 Line 7, session 2 before current
116 117 ``~8/1-~6/5``
117 118 From the first line of 8 sessions ago, to the fifth line of 6
118 119 sessions ago.
119 120
120 121 Multiple ranges can be entered, separated by spaces
121 122
122 123 The same syntax is used by %macro, %save, %edit, %rerun
123 124
124 125 Examples
125 126 --------
126 127 ::
127 128
128 129 In [6]: %history -n 4-6
129 130 4:a = 12
130 131 5:print a**2
131 132 6:%history -n 4-6
132 133
133 134 """
134 135
135 136 args = parse_argstring(self.history, parameter_s)
136 137
137 138 # For brevity
138 139 history_manager = self.shell.history_manager
139 140
140 141 def _format_lineno(session, line):
141 142 """Helper function to format line numbers properly."""
142 143 if session in (0, history_manager.session_number):
143 144 return str(line)
144 145 return "%s/%s" % (session, line)
145 146
146 147 # Check if output to specific file was requested.
147 148 outfname = args.filename
148 149 if not outfname:
149 150 outfile = sys.stdout # default
150 151 # We don't want to close stdout at the end!
151 152 close_at_end = False
152 153 else:
153 154 if os.path.exists(outfname):
154 155 try:
155 156 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
156 157 except StdinNotImplementedError:
157 158 ans = True
158 159 if not ans:
159 160 print('Aborting.')
160 161 return
161 162 print("Overwriting file.")
162 163 outfile = io_open(outfname, 'w', encoding='utf-8')
163 164 close_at_end = True
164 165
165 166 print_nums = args.print_nums
166 167 get_output = args.get_output
167 168 pyprompts = args.pyprompts
168 169 raw = args.raw
169 170
170 171 pattern = None
171 172 limit = None if args.limit is _unspecified else args.limit
172 173
173 if args.pattern is not None:
174 range_pattern = False
175 if args.pattern is not None and not args.range:
174 176 if args.pattern:
175 177 pattern = "*" + " ".join(args.pattern) + "*"
176 178 else:
177 179 pattern = "*"
178 180 hist = history_manager.search(pattern, raw=raw, output=get_output,
179 181 n=limit, unique=args.unique)
180 182 print_nums = True
181 183 elif args.limit is not _unspecified:
182 184 n = 10 if limit is None else limit
183 185 hist = history_manager.get_tail(n, raw=raw, output=get_output)
184 186 else:
185 187 if args.range: # Get history by ranges
188 if args.pattern:
189 range_pattern = "*" + " ".join(args.pattern) + "*"
190 print_nums = True
186 191 hist = history_manager.get_range_by_str(" ".join(args.range),
187 192 raw, get_output)
188 193 else: # Just get history for the current session
189 194 hist = history_manager.get_range(raw=raw, output=get_output)
190 195
191 196 # We could be displaying the entire history, so let's not try to pull
192 197 # it into a list in memory. Anything that needs more space will just
193 198 # misalign.
194 199 width = 4
195 200
196 201 for session, lineno, inline in hist:
197 202 # Print user history with tabs expanded to 4 spaces. The GUI
198 203 # clients use hard tabs for easier usability in auto-indented code,
199 204 # but we want to produce PEP-8 compliant history for safe pasting
200 205 # into an editor.
201 206 if get_output:
202 207 inline, output = inline
208 if range_pattern:
209 if not fnmatch.fnmatch(inline, range_pattern):
210 continue
203 211 inline = inline.expandtabs(4).rstrip()
204 212
205 213 multiline = "\n" in inline
206 214 line_sep = '\n' if multiline else ' '
207 215 if print_nums:
208 216 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
209 217 line_sep), file=outfile, end=u'')
210 218 if pyprompts:
211 219 print(u">>> ", end=u"", file=outfile)
212 220 if multiline:
213 221 inline = "\n... ".join(inline.splitlines()) + "\n..."
214 222 print(inline, file=outfile)
215 223 if get_output and output:
216 224 print(output, file=outfile)
217 225
218 226 if close_at_end:
219 227 outfile.close()
220 228
221 229 @line_magic
222 230 def recall(self, arg):
223 231 r"""Repeat a command, or get command to input line for editing.
224 232
225 233 %recall and %rep are equivalent.
226 234
227 235 - %recall (no arguments):
228 236
229 237 Place a string version of last computation result (stored in the
230 238 special '_' variable) to the next input prompt. Allows you to create
231 239 elaborate command lines without using copy-paste::
232 240
233 241 In[1]: l = ["hei", "vaan"]
234 242 In[2]: "".join(l)
235 243 Out[2]: heivaan
236 244 In[3]: %recall
237 245 In[4]: heivaan_ <== cursor blinking
238 246
239 247 %recall 45
240 248
241 249 Place history line 45 on the next input prompt. Use %hist to find
242 250 out the number.
243 251
244 252 %recall 1-4
245 253
246 254 Combine the specified lines into one cell, and place it on the next
247 255 input prompt. See %history for the slice syntax.
248 256
249 257 %recall foo+bar
250 258
251 259 If foo+bar can be evaluated in the user namespace, the result is
252 260 placed at the next input prompt. Otherwise, the history is searched
253 261 for lines which contain that substring, and the most recent one is
254 262 placed at the next input prompt.
255 263 """
256 264 if not arg: # Last output
257 265 self.shell.set_next_input(str(self.shell.user_ns["_"]))
258 266 return
259 267 # Get history range
260 268 histlines = self.shell.history_manager.get_range_by_str(arg)
261 269 cmd = "\n".join(x[2] for x in histlines)
262 270 if cmd:
263 271 self.shell.set_next_input(cmd.rstrip())
264 272 return
265 273
266 274 try: # Variable in user namespace
267 275 cmd = str(eval(arg, self.shell.user_ns))
268 276 except Exception: # Search for term in history
269 277 histlines = self.shell.history_manager.search("*"+arg+"*")
270 278 for h in reversed([x[2] for x in histlines]):
271 279 if 'recall' in h or 'rep' in h:
272 280 continue
273 281 self.shell.set_next_input(h.rstrip())
274 282 return
275 283 else:
276 284 self.shell.set_next_input(cmd.rstrip())
277 285 print("Couldn't evaluate or find in history:", arg)
278 286
279 287 @line_magic
280 288 def rerun(self, parameter_s=''):
281 289 """Re-run previous input
282 290
283 291 By default, you can specify ranges of input history to be repeated
284 292 (as with %history). With no arguments, it will repeat the last line.
285 293
286 294 Options:
287 295
288 296 -l <n> : Repeat the last n lines of input, not including the
289 297 current command.
290 298
291 299 -g foo : Repeat the most recent line which contains foo
292 300 """
293 301 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
294 302 if "l" in opts: # Last n lines
295 303 n = int(opts['l'])
296 304 hist = self.shell.history_manager.get_tail(n)
297 305 elif "g" in opts: # Search
298 306 p = "*"+opts['g']+"*"
299 307 hist = list(self.shell.history_manager.search(p))
300 308 for l in reversed(hist):
301 309 if "rerun" not in l[2]:
302 310 hist = [l] # The last match which isn't a %rerun
303 311 break
304 312 else:
305 313 hist = [] # No matches except %rerun
306 314 elif args: # Specify history ranges
307 315 hist = self.shell.history_manager.get_range_by_str(args)
308 316 else: # Last line
309 317 hist = self.shell.history_manager.get_tail(1)
310 318 hist = [x[2] for x in hist]
311 319 if not hist:
312 320 print("No lines in history match specification")
313 321 return
314 322 histlines = "\n".join(hist)
315 323 print("=== Executing: ===")
316 324 print(histlines)
317 325 print("=== Output: ===")
318 326 self.shell.run_cell("\n".join(hist), store_history=False)
@@ -1,105 +1,105 b''
1 1 """Implementation of packaging-related magic functions.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2018 The IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 import re
12 12 import shlex
13 13 import sys
14 14 from pathlib import Path
15 15
16 from pathlib import Path
17 16 from IPython.core.magic import Magics, magics_class, line_magic
18 17
19 18
20 19 def _is_conda_environment():
21 20 """Return True if the current Python executable is in a conda env"""
22 21 # TODO: does this need to change on windows?
23 22 return Path(sys.prefix, "conda-meta", "history").exists()
24 23
25 24
26 25 def _get_conda_executable():
27 26 """Find the path to the conda executable"""
28 27 # Check if there is a conda executable in the same directory as the Python executable.
29 28 # This is the case within conda's root environment.
30 29 conda = Path(sys.executable).parent / "conda"
31 if conda.isfile():
30 if conda.is_file():
32 31 return str(conda)
33 32
34 33 # Otherwise, attempt to extract the executable from conda history.
35 34 # This applies in any conda environment.
36 35 history = Path(sys.prefix, "conda-meta", "history").read_text()
37 36 match = re.search(
38 37 r"^#\s*cmd:\s*(?P<command>.*conda)\s[create|install]",
39 38 history,
40 39 flags=re.MULTILINE,
41 40 )
42 41 if match:
43 42 return match.groupdict()["command"]
44 43
45 44 # Fallback: assume conda is available on the system path.
46 45 return "conda"
47 46
48 47
49 48 CONDA_COMMANDS_REQUIRING_PREFIX = {
50 49 'install', 'list', 'remove', 'uninstall', 'update', 'upgrade',
51 50 }
52 51 CONDA_COMMANDS_REQUIRING_YES = {
53 52 'install', 'remove', 'uninstall', 'update', 'upgrade',
54 53 }
55 54 CONDA_ENV_FLAGS = {'-p', '--prefix', '-n', '--name'}
56 55 CONDA_YES_FLAGS = {'-y', '--y'}
57 56
58 57
59 58 @magics_class
60 59 class PackagingMagics(Magics):
61 60 """Magics related to packaging & installation"""
62 61
63 62 @line_magic
64 63 def pip(self, line):
65 64 """Run the pip package manager within the current kernel.
66 65
67 66 Usage:
68 67 %pip install [pkgs]
69 68 """
70 69 self.shell.system(' '.join([sys.executable, '-m', 'pip', line]))
71 70 print("Note: you may need to restart the kernel to use updated packages.")
72 71
73 72 @line_magic
74 73 def conda(self, line):
75 74 """Run the conda package manager within the current kernel.
76 75
77 76 Usage:
78 77 %conda install [pkgs]
79 78 """
80 79 if not _is_conda_environment():
81 80 raise ValueError("The python kernel does not appear to be a conda environment. "
82 81 "Please use ``%pip install`` instead.")
83 82
84 83 conda = _get_conda_executable()
85 84 args = shlex.split(line)
86 command = args[0]
87 args = args[1:]
85 command = args[0] if len(args) > 0 else ""
86 args = args[1:] if len(args) > 1 else [""]
87
88 88 extra_args = []
89 89
90 90 # When the subprocess does not allow us to respond "yes" during the installation,
91 91 # we need to insert --yes in the argument list for some commands
92 92 stdin_disabled = getattr(self.shell, 'kernel', None) is not None
93 93 needs_yes = command in CONDA_COMMANDS_REQUIRING_YES
94 94 has_yes = set(args).intersection(CONDA_YES_FLAGS)
95 95 if stdin_disabled and needs_yes and not has_yes:
96 96 extra_args.append("--yes")
97 97
98 98 # Add --prefix to point conda installation to the current environment
99 99 needs_prefix = command in CONDA_COMMANDS_REQUIRING_PREFIX
100 100 has_prefix = set(args).intersection(CONDA_ENV_FLAGS)
101 101 if needs_prefix and not has_prefix:
102 102 extra_args.extend(["--prefix", sys.prefix])
103 103
104 104 self.shell.system(' '.join([conda, command] + extra_args + args))
105 105 print("\nNote: you may need to restart the kernel to use updated packages.")
@@ -1,459 +1,459 b''
1 1 # Copyright (c) IPython Development Team.
2 2 # Distributed under the terms of the Modified BSD License.
3 3
4 4 import json
5 5 import os
6 6 import warnings
7 7
8 8 from unittest import mock
9 9
10 10 import nose.tools as nt
11 11
12 12 from IPython import display
13 13 from IPython.core.getipython import get_ipython
14 14 from IPython.utils.io import capture_output
15 15 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
16 16 from IPython import paths as ipath
17 17 from IPython.testing.tools import AssertNotPrints
18 18
19 19 import IPython.testing.decorators as dec
20 20
21 21 def test_image_size():
22 22 """Simple test for display.Image(args, width=x,height=y)"""
23 23 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
24 24 img = display.Image(url=thisurl, width=200, height=200)
25 25 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
26 26 img = display.Image(url=thisurl, metadata={'width':200, 'height':200})
27 27 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
28 28 img = display.Image(url=thisurl, width=200)
29 29 nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
30 30 img = display.Image(url=thisurl)
31 31 nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
32 32 img = display.Image(url=thisurl, unconfined=True)
33 33 nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
34 34
35 35
36 36 def test_image_mimes():
37 37 fmt = get_ipython().display_formatter.format
38 38 for format in display.Image._ACCEPTABLE_EMBEDDINGS:
39 39 mime = display.Image._MIMETYPES[format]
40 40 img = display.Image(b'garbage', format=format)
41 41 data, metadata = fmt(img)
42 42 nt.assert_equal(sorted(data), sorted([mime, 'text/plain']))
43 43
44 44
45 45 def test_geojson():
46 46
47 47 gj = display.GeoJSON(data={
48 48 "type": "Feature",
49 49 "geometry": {
50 50 "type": "Point",
51 51 "coordinates": [-81.327, 296.038]
52 52 },
53 53 "properties": {
54 54 "name": "Inca City"
55 55 }
56 56 },
57 57 url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
58 58 layer_options={
59 59 "basemap_id": "celestia_mars-shaded-16k_global",
60 60 "attribution": "Celestia/praesepe",
61 61 "minZoom": 0,
62 62 "maxZoom": 18,
63 63 })
64 64 nt.assert_equal(u'<IPython.core.display.GeoJSON object>', str(gj))
65 65
66 66 def test_retina_png():
67 67 here = os.path.dirname(__file__)
68 68 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
69 69 nt.assert_equal(img.height, 1)
70 70 nt.assert_equal(img.width, 1)
71 71 data, md = img._repr_png_()
72 72 nt.assert_equal(md['width'], 1)
73 73 nt.assert_equal(md['height'], 1)
74 74
75 75 def test_embed_svg_url():
76 76 import gzip
77 77 from io import BytesIO
78 78 svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>'
79 79 url = 'http://test.com/circle.svg'
80 80
81 81 gzip_svg = BytesIO()
82 82 with gzip.open(gzip_svg, 'wb') as fp:
83 83 fp.write(svg_data)
84 84 gzip_svg = gzip_svg.getvalue()
85 85
86 86 def mocked_urlopen(*args, **kwargs):
87 87 class MockResponse:
88 88 def __init__(self, svg):
89 89 self._svg_data = svg
90 90 self.headers = {'content-type': 'image/svg+xml'}
91 91
92 92 def read(self):
93 93 return self._svg_data
94 94
95 95 if args[0] == url:
96 96 return MockResponse(svg_data)
97 97 elif args[0] == url + 'z':
98 98 ret= MockResponse(gzip_svg)
99 99 ret.headers['content-encoding']= 'gzip'
100 100 return ret
101 101 return MockResponse(None)
102 102
103 103 with mock.patch('urllib.request.urlopen', side_effect=mocked_urlopen):
104 104 svg = display.SVG(url=url)
105 105 nt.assert_true(svg._repr_svg_().startswith('<svg'))
106 106 svg = display.SVG(url=url + 'z')
107 107 nt.assert_true(svg._repr_svg_().startswith('<svg'))
108 108
109 109 def test_retina_jpeg():
110 110 here = os.path.dirname(__file__)
111 111 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
112 112 nt.assert_equal(img.height, 1)
113 113 nt.assert_equal(img.width, 1)
114 114 data, md = img._repr_jpeg_()
115 115 nt.assert_equal(md['width'], 1)
116 116 nt.assert_equal(md['height'], 1)
117 117
118 118 def test_base64image():
119 119 display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
120 120
121 121 def test_image_filename_defaults():
122 122 '''test format constraint, and validity of jpeg and png'''
123 123 tpath = ipath.get_ipython_package_dir()
124 124 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.zip'),
125 125 embed=True)
126 126 nt.assert_raises(ValueError, display.Image)
127 127 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
128 128 # check boths paths to allow packages to test at build and install time
129 129 imgfile = os.path.join(tpath, 'core/tests/2x2.png')
130 130 img = display.Image(filename=imgfile)
131 131 nt.assert_equal('png', img.format)
132 132 nt.assert_is_not_none(img._repr_png_())
133 133 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
134 134 nt.assert_equal('jpeg', img.format)
135 135 nt.assert_is_none(img._repr_jpeg_())
136 136
137 137 def _get_inline_config():
138 138 from ipykernel.pylab.config import InlineBackend
139 139 return InlineBackend.instance()
140 140
141 141
142 142 @dec.skip_without("ipykernel")
143 143 @dec.skip_without("matplotlib")
144 144 def test_set_matplotlib_close():
145 145 cfg = _get_inline_config()
146 146 cfg.close_figures = False
147 147 display.set_matplotlib_close()
148 148 assert cfg.close_figures
149 149 display.set_matplotlib_close(False)
150 150 assert not cfg.close_figures
151 151
152 152 _fmt_mime_map = {
153 153 'png': 'image/png',
154 154 'jpeg': 'image/jpeg',
155 155 'pdf': 'application/pdf',
156 156 'retina': 'image/png',
157 157 'svg': 'image/svg+xml',
158 158 }
159 159
160 160 @dec.skip_without('matplotlib')
161 161 def test_set_matplotlib_formats():
162 162 from matplotlib.figure import Figure
163 163 formatters = get_ipython().display_formatter.formatters
164 164 for formats in [
165 165 ('png',),
166 166 ('pdf', 'svg'),
167 167 ('jpeg', 'retina', 'png'),
168 168 (),
169 169 ]:
170 170 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
171 171 display.set_matplotlib_formats(*formats)
172 172 for mime, f in formatters.items():
173 173 if mime in active_mimes:
174 174 nt.assert_in(Figure, f)
175 175 else:
176 176 nt.assert_not_in(Figure, f)
177 177
178 178
179 179 @dec.skip_without("ipykernel")
180 180 @dec.skip_without("matplotlib")
181 181 def test_set_matplotlib_formats_kwargs():
182 182 from matplotlib.figure import Figure
183 183 ip = get_ipython()
184 184 cfg = _get_inline_config()
185 185 cfg.print_figure_kwargs.update(dict(foo='bar'))
186 kwargs = dict(quality=10)
186 kwargs = dict(dpi=150)
187 187 display.set_matplotlib_formats('png', **kwargs)
188 188 formatter = ip.display_formatter.formatters['image/png']
189 189 f = formatter.lookup_by_type(Figure)
190 190 cell = f.__closure__[0].cell_contents
191 191 expected = kwargs
192 192 expected.update(cfg.print_figure_kwargs)
193 193 nt.assert_equal(cell, expected)
194 194
195 195 def test_display_available():
196 196 """
197 197 Test that display is available without import
198 198
199 199 We don't really care if it's in builtin or anything else, but it should
200 200 always be available.
201 201 """
202 202 ip = get_ipython()
203 203 with AssertNotPrints('NameError'):
204 204 ip.run_cell('display')
205 205 try:
206 206 ip.run_cell('del display')
207 207 except NameError:
208 208 pass # it's ok, it might be in builtins
209 209 # even if deleted it should be back
210 210 with AssertNotPrints('NameError'):
211 211 ip.run_cell('display')
212 212
213 213 def test_textdisplayobj_pretty_repr():
214 214 p = display.Pretty("This is a simple test")
215 215 nt.assert_equal(repr(p), '<IPython.core.display.Pretty object>')
216 216 nt.assert_equal(p.data, 'This is a simple test')
217 217
218 218 p._show_mem_addr = True
219 219 nt.assert_equal(repr(p), object.__repr__(p))
220 220
221 221 def test_displayobject_repr():
222 222 h = display.HTML('<br />')
223 223 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
224 224 h._show_mem_addr = True
225 225 nt.assert_equal(repr(h), object.__repr__(h))
226 226 h._show_mem_addr = False
227 227 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
228 228
229 229 j = display.Javascript('')
230 230 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
231 231 j._show_mem_addr = True
232 232 nt.assert_equal(repr(j), object.__repr__(j))
233 233 j._show_mem_addr = False
234 234 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
235 235
236 236 @mock.patch('warnings.warn')
237 237 def test_encourage_iframe_over_html(m_warn):
238 238 display.HTML()
239 239 m_warn.assert_not_called()
240 240
241 241 display.HTML('<br />')
242 242 m_warn.assert_not_called()
243 243
244 244 display.HTML('<html><p>Lots of content here</p><iframe src="http://a.com"></iframe>')
245 245 m_warn.assert_not_called()
246 246
247 247 display.HTML('<iframe src="http://a.com"></iframe>')
248 248 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
249 249
250 250 m_warn.reset_mock()
251 251 display.HTML('<IFRAME SRC="http://a.com"></IFRAME>')
252 252 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
253 253
254 254 def test_progress():
255 255 p = display.ProgressBar(10)
256 256 nt.assert_in('0/10',repr(p))
257 257 p.html_width = '100%'
258 258 p.progress = 5
259 259 nt.assert_equal(p._repr_html_(), "<progress style='width:100%' max='10' value='5'></progress>")
260 260
261 261 def test_progress_iter():
262 262 with capture_output(display=False) as captured:
263 263 for i in display.ProgressBar(5):
264 264 out = captured.stdout
265 265 nt.assert_in('{0}/5'.format(i), out)
266 266 out = captured.stdout
267 267 nt.assert_in('5/5', out)
268 268
269 269 def test_json():
270 270 d = {'a': 5}
271 271 lis = [d]
272 272 metadata = [
273 273 {'expanded': False, 'root': 'root'},
274 274 {'expanded': True, 'root': 'root'},
275 275 {'expanded': False, 'root': 'custom'},
276 276 {'expanded': True, 'root': 'custom'},
277 277 ]
278 278 json_objs = [
279 279 display.JSON(d),
280 280 display.JSON(d, expanded=True),
281 281 display.JSON(d, root='custom'),
282 282 display.JSON(d, expanded=True, root='custom'),
283 283 ]
284 284 for j, md in zip(json_objs, metadata):
285 285 nt.assert_equal(j._repr_json_(), (d, md))
286 286
287 287 with warnings.catch_warnings(record=True) as w:
288 288 warnings.simplefilter("always")
289 289 j = display.JSON(json.dumps(d))
290 290 nt.assert_equal(len(w), 1)
291 291 nt.assert_equal(j._repr_json_(), (d, metadata[0]))
292 292
293 293 json_objs = [
294 294 display.JSON(lis),
295 295 display.JSON(lis, expanded=True),
296 296 display.JSON(lis, root='custom'),
297 297 display.JSON(lis, expanded=True, root='custom'),
298 298 ]
299 299 for j, md in zip(json_objs, metadata):
300 300 nt.assert_equal(j._repr_json_(), (lis, md))
301 301
302 302 with warnings.catch_warnings(record=True) as w:
303 303 warnings.simplefilter("always")
304 304 j = display.JSON(json.dumps(lis))
305 305 nt.assert_equal(len(w), 1)
306 306 nt.assert_equal(j._repr_json_(), (lis, metadata[0]))
307 307
308 308 def test_video_embedding():
309 309 """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash"""
310 310 v = display.Video("http://ignored")
311 311 assert not v.embed
312 312 html = v._repr_html_()
313 313 nt.assert_not_in('src="data:', html)
314 314 nt.assert_in('src="http://ignored"', html)
315 315
316 316 with nt.assert_raises(ValueError):
317 317 v = display.Video(b'abc')
318 318
319 319 with NamedFileInTemporaryDirectory('test.mp4') as f:
320 320 f.write(b'abc')
321 321 f.close()
322 322
323 323 v = display.Video(f.name)
324 324 assert not v.embed
325 325 html = v._repr_html_()
326 326 nt.assert_not_in('src="data:', html)
327 327
328 328 v = display.Video(f.name, embed=True)
329 329 html = v._repr_html_()
330 330 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
331 331
332 332 v = display.Video(f.name, embed=True, mimetype='video/other')
333 333 html = v._repr_html_()
334 334 nt.assert_in('src="data:video/other;base64,YWJj"',html)
335 335
336 336 v = display.Video(b'abc', embed=True, mimetype='video/mp4')
337 337 html = v._repr_html_()
338 338 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
339 339
340 340 v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
341 341 html = v._repr_html_()
342 342 nt.assert_in('src="data:video/xyz;base64,YWJj"',html)
343 343
344 344 def test_html_metadata():
345 345 s = "<h1>Test</h1>"
346 346 h = display.HTML(s, metadata={"isolated": True})
347 347 nt.assert_equal(h._repr_html_(), (s, {"isolated": True}))
348 348
349 349 def test_display_id():
350 350 ip = get_ipython()
351 351 with mock.patch.object(ip.display_pub, 'publish') as pub:
352 352 handle = display.display('x')
353 353 nt.assert_is(handle, None)
354 354 handle = display.display('y', display_id='secret')
355 355 nt.assert_is_instance(handle, display.DisplayHandle)
356 356 handle2 = display.display('z', display_id=True)
357 357 nt.assert_is_instance(handle2, display.DisplayHandle)
358 358 nt.assert_not_equal(handle.display_id, handle2.display_id)
359 359
360 360 nt.assert_equal(pub.call_count, 3)
361 361 args, kwargs = pub.call_args_list[0]
362 362 nt.assert_equal(args, ())
363 363 nt.assert_equal(kwargs, {
364 364 'data': {
365 365 'text/plain': repr('x')
366 366 },
367 367 'metadata': {},
368 368 })
369 369 args, kwargs = pub.call_args_list[1]
370 370 nt.assert_equal(args, ())
371 371 nt.assert_equal(kwargs, {
372 372 'data': {
373 373 'text/plain': repr('y')
374 374 },
375 375 'metadata': {},
376 376 'transient': {
377 377 'display_id': handle.display_id,
378 378 },
379 379 })
380 380 args, kwargs = pub.call_args_list[2]
381 381 nt.assert_equal(args, ())
382 382 nt.assert_equal(kwargs, {
383 383 'data': {
384 384 'text/plain': repr('z')
385 385 },
386 386 'metadata': {},
387 387 'transient': {
388 388 'display_id': handle2.display_id,
389 389 },
390 390 })
391 391
392 392
393 393 def test_update_display():
394 394 ip = get_ipython()
395 395 with mock.patch.object(ip.display_pub, 'publish') as pub:
396 396 with nt.assert_raises(TypeError):
397 397 display.update_display('x')
398 398 display.update_display('x', display_id='1')
399 399 display.update_display('y', display_id='2')
400 400 args, kwargs = pub.call_args_list[0]
401 401 nt.assert_equal(args, ())
402 402 nt.assert_equal(kwargs, {
403 403 'data': {
404 404 'text/plain': repr('x')
405 405 },
406 406 'metadata': {},
407 407 'transient': {
408 408 'display_id': '1',
409 409 },
410 410 'update': True,
411 411 })
412 412 args, kwargs = pub.call_args_list[1]
413 413 nt.assert_equal(args, ())
414 414 nt.assert_equal(kwargs, {
415 415 'data': {
416 416 'text/plain': repr('y')
417 417 },
418 418 'metadata': {},
419 419 'transient': {
420 420 'display_id': '2',
421 421 },
422 422 'update': True,
423 423 })
424 424
425 425
426 426 def test_display_handle():
427 427 ip = get_ipython()
428 428 handle = display.DisplayHandle()
429 429 nt.assert_is_instance(handle.display_id, str)
430 430 handle = display.DisplayHandle('my-id')
431 431 nt.assert_equal(handle.display_id, 'my-id')
432 432 with mock.patch.object(ip.display_pub, 'publish') as pub:
433 433 handle.display('x')
434 434 handle.update('y')
435 435
436 436 args, kwargs = pub.call_args_list[0]
437 437 nt.assert_equal(args, ())
438 438 nt.assert_equal(kwargs, {
439 439 'data': {
440 440 'text/plain': repr('x')
441 441 },
442 442 'metadata': {},
443 443 'transient': {
444 444 'display_id': handle.display_id,
445 445 }
446 446 })
447 447 args, kwargs = pub.call_args_list[1]
448 448 nt.assert_equal(args, ())
449 449 nt.assert_equal(kwargs, {
450 450 'data': {
451 451 'text/plain': repr('y')
452 452 },
453 453 'metadata': {},
454 454 'transient': {
455 455 'display_id': handle.display_id,
456 456 },
457 457 'update': True,
458 458 })
459 459
@@ -1,337 +1,355 b''
1 1 """Tests for the token-based transformers in IPython.core.inputtransformer2
2 2
3 3 Line-based transformers are the simpler ones; token-based transformers are
4 4 more complex. See test_inputtransformer2_line for tests for line-based
5 5 transformations.
6 6 """
7 7 import nose.tools as nt
8 8 import string
9 9
10 10 from IPython.core import inputtransformer2 as ipt2
11 11 from IPython.core.inputtransformer2 import make_tokens_by_line, _find_assign_op
12 12
13 13 from textwrap import dedent
14 14
15 15 MULTILINE_MAGIC = ("""\
16 16 a = f()
17 17 %foo \\
18 18 bar
19 19 g()
20 20 """.splitlines(keepends=True), (2, 0), """\
21 21 a = f()
22 22 get_ipython().run_line_magic('foo', ' bar')
23 23 g()
24 24 """.splitlines(keepends=True))
25 25
26 26 INDENTED_MAGIC = ("""\
27 27 for a in range(5):
28 28 %ls
29 29 """.splitlines(keepends=True), (2, 4), """\
30 30 for a in range(5):
31 31 get_ipython().run_line_magic('ls', '')
32 32 """.splitlines(keepends=True))
33 33
34 34 CRLF_MAGIC = ([
35 35 "a = f()\n",
36 36 "%ls\r\n",
37 37 "g()\n"
38 38 ], (2, 0), [
39 39 "a = f()\n",
40 40 "get_ipython().run_line_magic('ls', '')\n",
41 41 "g()\n"
42 42 ])
43 43
44 44 MULTILINE_MAGIC_ASSIGN = ("""\
45 45 a = f()
46 46 b = %foo \\
47 47 bar
48 48 g()
49 49 """.splitlines(keepends=True), (2, 4), """\
50 50 a = f()
51 51 b = get_ipython().run_line_magic('foo', ' bar')
52 52 g()
53 53 """.splitlines(keepends=True))
54 54
55 55 MULTILINE_SYSTEM_ASSIGN = ("""\
56 56 a = f()
57 57 b = !foo \\
58 58 bar
59 59 g()
60 60 """.splitlines(keepends=True), (2, 4), """\
61 61 a = f()
62 62 b = get_ipython().getoutput('foo bar')
63 63 g()
64 64 """.splitlines(keepends=True))
65 65
66 66 #####
67 67
68 68 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
69 69 def test():
70 70 for i in range(1):
71 71 print(i)
72 72 res =! ls
73 73 """.splitlines(keepends=True), (4, 7), '''\
74 74 def test():
75 75 for i in range(1):
76 76 print(i)
77 77 res =get_ipython().getoutput(\' ls\')
78 78 '''.splitlines(keepends=True))
79 79
80 80 ######
81 81
82 82 AUTOCALL_QUOTE = (
83 83 [",f 1 2 3\n"], (1, 0),
84 84 ['f("1", "2", "3")\n']
85 85 )
86 86
87 87 AUTOCALL_QUOTE2 = (
88 88 [";f 1 2 3\n"], (1, 0),
89 89 ['f("1 2 3")\n']
90 90 )
91 91
92 92 AUTOCALL_PAREN = (
93 93 ["/f 1 2 3\n"], (1, 0),
94 94 ['f(1, 2, 3)\n']
95 95 )
96 96
97 97 SIMPLE_HELP = (
98 98 ["foo?\n"], (1, 0),
99 99 ["get_ipython().run_line_magic('pinfo', 'foo')\n"]
100 100 )
101 101
102 102 DETAILED_HELP = (
103 103 ["foo??\n"], (1, 0),
104 104 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
105 105 )
106 106
107 107 MAGIC_HELP = (
108 108 ["%foo?\n"], (1, 0),
109 109 ["get_ipython().run_line_magic('pinfo', '%foo')\n"]
110 110 )
111 111
112 112 HELP_IN_EXPR = (
113 113 ["a = b + c?\n"], (1, 0),
114 114 ["get_ipython().set_next_input('a = b + c');"
115 115 "get_ipython().run_line_magic('pinfo', 'c')\n"]
116 116 )
117 117
118 118 HELP_CONTINUED_LINE = ("""\
119 119 a = \\
120 120 zip?
121 121 """.splitlines(keepends=True), (1, 0),
122 122 [r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
123 123 )
124 124
125 125 HELP_MULTILINE = ("""\
126 126 (a,
127 127 b) = zip?
128 128 """.splitlines(keepends=True), (1, 0),
129 129 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
130 130 )
131 131
132 132 HELP_UNICODE = (
133 133 ["π.foo?\n"], (1, 0),
134 134 ["get_ipython().run_line_magic('pinfo', 'π.foo')\n"]
135 135 )
136 136
137 137
138 138 def null_cleanup_transformer(lines):
139 139 """
140 140 A cleanup transform that returns an empty list.
141 141 """
142 142 return []
143 143
144 144 def check_make_token_by_line_never_ends_empty():
145 145 """
146 146 Check that not sequence of single or double characters ends up leading to en empty list of tokens
147 147 """
148 148 from string import printable
149 149 for c in printable:
150 150 nt.assert_not_equal(make_tokens_by_line(c)[-1], [])
151 151 for k in printable:
152 152 nt.assert_not_equal(make_tokens_by_line(c+k)[-1], [])
153 153
154 154 def check_find(transformer, case, match=True):
155 155 sample, expected_start, _ = case
156 156 tbl = make_tokens_by_line(sample)
157 157 res = transformer.find(tbl)
158 158 if match:
159 159 # start_line is stored 0-indexed, expected values are 1-indexed
160 160 nt.assert_equal((res.start_line+1, res.start_col), expected_start)
161 161 return res
162 162 else:
163 163 nt.assert_is(res, None)
164 164
165 165 def check_transform(transformer_cls, case):
166 166 lines, start, expected = case
167 167 transformer = transformer_cls(start)
168 168 nt.assert_equal(transformer.transform(lines), expected)
169 169
170 170 def test_continued_line():
171 171 lines = MULTILINE_MAGIC_ASSIGN[0]
172 172 nt.assert_equal(ipt2.find_end_of_continued_line(lines, 1), 2)
173 173
174 174 nt.assert_equal(ipt2.assemble_continued_line(lines, (1, 5), 2), "foo bar")
175 175
176 176 def test_find_assign_magic():
177 177 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
178 178 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
179 179 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
180 180
181 181 def test_transform_assign_magic():
182 182 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
183 183
184 184 def test_find_assign_system():
185 185 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
186 186 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
187 187 check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None))
188 188 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
189 189 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
190 190
191 191 def test_transform_assign_system():
192 192 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
193 193 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
194 194
195 195 def test_find_magic_escape():
196 196 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
197 197 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
198 198 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
199 199
200 200 def test_transform_magic_escape():
201 201 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
202 202 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
203 203 check_transform(ipt2.EscapedCommand, CRLF_MAGIC)
204 204
205 205 def test_find_autocalls():
206 206 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
207 207 print("Testing %r" % case[0])
208 208 check_find(ipt2.EscapedCommand, case)
209 209
210 210 def test_transform_autocall():
211 211 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
212 212 print("Testing %r" % case[0])
213 213 check_transform(ipt2.EscapedCommand, case)
214 214
215 215 def test_find_help():
216 216 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
217 217 check_find(ipt2.HelpEnd, case)
218 218
219 219 tf = check_find(ipt2.HelpEnd, HELP_CONTINUED_LINE)
220 220 nt.assert_equal(tf.q_line, 1)
221 221 nt.assert_equal(tf.q_col, 3)
222 222
223 223 tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
224 224 nt.assert_equal(tf.q_line, 1)
225 225 nt.assert_equal(tf.q_col, 8)
226 226
227 227 # ? in a comment does not trigger help
228 228 check_find(ipt2.HelpEnd, (["foo # bar?\n"], None, None), match=False)
229 229 # Nor in a string
230 230 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
231 231
232 232 def test_transform_help():
233 233 tf = ipt2.HelpEnd((1, 0), (1, 9))
234 234 nt.assert_equal(tf.transform(HELP_IN_EXPR[0]), HELP_IN_EXPR[2])
235 235
236 236 tf = ipt2.HelpEnd((1, 0), (2, 3))
237 237 nt.assert_equal(tf.transform(HELP_CONTINUED_LINE[0]), HELP_CONTINUED_LINE[2])
238 238
239 239 tf = ipt2.HelpEnd((1, 0), (2, 8))
240 240 nt.assert_equal(tf.transform(HELP_MULTILINE[0]), HELP_MULTILINE[2])
241 241
242 242 tf = ipt2.HelpEnd((1, 0), (1, 0))
243 243 nt.assert_equal(tf.transform(HELP_UNICODE[0]), HELP_UNICODE[2])
244 244
245 245 def test_find_assign_op_dedent():
246 246 """
247 247 be careful that empty token like dedent are not counted as parens
248 248 """
249 249 class Tk:
250 250 def __init__(self, s):
251 251 self.string = s
252 252
253 253 nt.assert_equal(_find_assign_op([Tk(s) for s in ('','a','=','b')]), 2)
254 254 nt.assert_equal(_find_assign_op([Tk(s) for s in ('','(', 'a','=','b', ')', '=' ,'5')]), 6)
255 255
256 256 def test_check_complete():
257 257 cc = ipt2.TransformerManager().check_complete
258 nt.assert_equal(cc("a = 1"), ('complete', None))
259 nt.assert_equal(cc("for a in range(5):"), ('incomplete', 4))
260 nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ('incomplete', 8))
261 nt.assert_equal(cc("raise = 2"), ('invalid', None))
262 nt.assert_equal(cc("a = [1,\n2,"), ('incomplete', 0))
263 nt.assert_equal(cc(")"), ('incomplete', 0))
264 nt.assert_equal(cc("\\\r\n"), ('incomplete', 0))
265 nt.assert_equal(cc("a = '''\n hi"), ('incomplete', 3))
266 nt.assert_equal(cc("def a():\n x=1\n global x"), ('invalid', None))
267 nt.assert_equal(cc("a \\ "), ('invalid', None)) # Nothing allowed after backslash
268 nt.assert_equal(cc("1\\\n+2"), ('complete', None))
269 nt.assert_equal(cc("exit"), ('complete', None))
258 nt.assert_equal(cc("a = 1"), ("complete", None))
259 nt.assert_equal(cc("for a in range(5):"), ("incomplete", 4))
260 nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ("incomplete", 8))
261 nt.assert_equal(cc("raise = 2"), ("invalid", None))
262 nt.assert_equal(cc("a = [1,\n2,"), ("incomplete", 0))
263 nt.assert_equal(cc("(\n))"), ("incomplete", 0))
264 nt.assert_equal(cc("\\\r\n"), ("incomplete", 0))
265 nt.assert_equal(cc("a = '''\n hi"), ("incomplete", 3))
266 nt.assert_equal(cc("def a():\n x=1\n global x"), ("invalid", None))
267 nt.assert_equal(cc("a \\ "), ("invalid", None)) # Nothing allowed after backslash
268 nt.assert_equal(cc("1\\\n+2"), ("complete", None))
269 nt.assert_equal(cc("exit"), ("complete", None))
270 270
271 271 example = dedent("""
272 272 if True:
273 273 a=1""" )
274 274
275 275 nt.assert_equal(cc(example), ('incomplete', 4))
276 276 nt.assert_equal(cc(example+'\n'), ('complete', None))
277 277 nt.assert_equal(cc(example+'\n '), ('complete', None))
278 278
279 279 # no need to loop on all the letters/numbers.
280 280 short = '12abAB'+string.printable[62:]
281 281 for c in short:
282 282 # test does not raise:
283 283 cc(c)
284 284 for k in short:
285 285 cc(c+k)
286 286
287 287 nt.assert_equal(cc("def f():\n x=0\n \\\n "), ('incomplete', 2))
288 288
289 289 def test_check_complete_II():
290 290 """
291 291 Test that multiple line strings are properly handled.
292 292
293 293 Separate test function for convenience
294 294
295 295 """
296 296 cc = ipt2.TransformerManager().check_complete
297 297 nt.assert_equal(cc('''def foo():\n """'''), ('incomplete', 4))
298 298
299 299
300 def test_check_complete_invalidates_sunken_brackets():
301 """
302 Test that a single line with more closing brackets than the opening ones is
303 interpretted as invalid
304 """
305 cc = ipt2.TransformerManager().check_complete
306 nt.assert_equal(cc(")"), ("invalid", None))
307 nt.assert_equal(cc("]"), ("invalid", None))
308 nt.assert_equal(cc("}"), ("invalid", None))
309 nt.assert_equal(cc(")("), ("invalid", None))
310 nt.assert_equal(cc("]["), ("invalid", None))
311 nt.assert_equal(cc("}{"), ("invalid", None))
312 nt.assert_equal(cc("]()("), ("invalid", None))
313 nt.assert_equal(cc("())("), ("invalid", None))
314 nt.assert_equal(cc(")[]("), ("invalid", None))
315 nt.assert_equal(cc("()]("), ("invalid", None))
316
317
300 318 def test_null_cleanup_transformer():
301 319 manager = ipt2.TransformerManager()
302 320 manager.cleanup_transforms.insert(0, null_cleanup_transformer)
303 321 assert manager.transform_cell("") == ""
304 322
305 323
306 324
307 325
308 326 def test_side_effects_I():
309 327 count = 0
310 328 def counter(lines):
311 329 nonlocal count
312 330 count += 1
313 331 return lines
314 332
315 333 counter.has_side_effects = True
316 334
317 335 manager = ipt2.TransformerManager()
318 336 manager.cleanup_transforms.insert(0, counter)
319 337 assert manager.check_complete("a=1\n") == ('complete', None)
320 338 assert count == 0
321 339
322 340
323 341
324 342
325 343 def test_side_effects_II():
326 344 count = 0
327 345 def counter(lines):
328 346 nonlocal count
329 347 count += 1
330 348 return lines
331 349
332 350 counter.has_side_effects = True
333 351
334 352 manager = ipt2.TransformerManager()
335 353 manager.line_transforms.insert(0, counter)
336 354 assert manager.check_complete("b=1\n") == ('complete', None)
337 355 assert count == 0
@@ -1,231 +1,238 b''
1 1 """Tests for the key interactiveshell module, where the main ipython class is defined.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Module imports
5 5 #-----------------------------------------------------------------------------
6 6
7 7 # third party
8 8 import nose.tools as nt
9 9
10 10 # our own packages
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Test functions
14 14 #-----------------------------------------------------------------------------
15 15
16 16 def test_reset():
17 17 """reset must clear most namespaces."""
18 18
19 19 # Check that reset runs without error
20 20 ip.reset()
21 21
22 22 # Once we've reset it (to clear of any junk that might have been there from
23 23 # other tests, we can count how many variables are in the user's namespace
24 24 nvars_user_ns = len(ip.user_ns)
25 25 nvars_hidden = len(ip.user_ns_hidden)
26 26
27 27 # Now add a few variables to user_ns, and check that reset clears them
28 28 ip.user_ns['x'] = 1
29 29 ip.user_ns['y'] = 1
30 30 ip.reset()
31 31
32 32 # Finally, check that all namespaces have only as many variables as we
33 33 # expect to find in them:
34 34 nt.assert_equal(len(ip.user_ns), nvars_user_ns)
35 35 nt.assert_equal(len(ip.user_ns_hidden), nvars_hidden)
36 36
37 37
38 38 # Tests for reporting of exceptions in various modes, handling of SystemExit,
39 39 # and %tb functionality. This is really a mix of testing ultraTB and interactiveshell.
40 40
41 41 def doctest_tb_plain():
42 42 """
43 43 In [18]: xmode plain
44 44 Exception reporting mode: Plain
45 45
46 46 In [19]: run simpleerr.py
47 47 Traceback (most recent call last):
48 48 ...line 32, in <module>
49 49 bar(mode)
50 50 ...line 16, in bar
51 51 div0()
52 52 ...line 8, in div0
53 53 x/y
54 54 ZeroDivisionError: ...
55 55 """
56 56
57 57
58 58 def doctest_tb_context():
59 59 """
60 60 In [3]: xmode context
61 61 Exception reporting mode: Context
62 62
63 63 In [4]: run simpleerr.py
64 64 ---------------------------------------------------------------------------
65 65 ZeroDivisionError Traceback (most recent call last)
66 66 <BLANKLINE>
67 67 ... in <module>
68 68 29 except IndexError:
69 69 30 mode = 'div'
70 70 ---> 32 bar(mode)
71 71 <BLANKLINE>
72 72 ... in bar(mode)
73 73 14 "bar"
74 74 15 if mode=='div':
75 75 ---> 16 div0()
76 76 17 elif mode=='exit':
77 77 18 try:
78 78 <BLANKLINE>
79 79 ... in div0()
80 80 6 x = 1
81 81 7 y = 0
82 82 ----> 8 x/y
83 83 <BLANKLINE>
84 84 ZeroDivisionError: ...
85 85 """
86 86
87 87
88 88 def doctest_tb_verbose():
89 89 """
90 90 In [5]: xmode verbose
91 91 Exception reporting mode: Verbose
92 92
93 93 In [6]: run simpleerr.py
94 94 ---------------------------------------------------------------------------
95 95 ZeroDivisionError Traceback (most recent call last)
96 96 <BLANKLINE>
97 97 ... in <module>
98 98 29 except IndexError:
99 99 30 mode = 'div'
100 100 ---> 32 bar(mode)
101 101 mode = 'div'
102 102 <BLANKLINE>
103 103 ... in bar(mode='div')
104 104 14 "bar"
105 105 15 if mode=='div':
106 106 ---> 16 div0()
107 107 17 elif mode=='exit':
108 108 18 try:
109 109 <BLANKLINE>
110 110 ... in div0()
111 111 6 x = 1
112 112 7 y = 0
113 113 ----> 8 x/y
114 114 x = 1
115 115 y = 0
116 116 <BLANKLINE>
117 117 ZeroDivisionError: ...
118 118 """
119 119
120 def doctest_tb_sysexit():
121 """
122 In [17]: %xmode plain
123 Exception reporting mode: Plain
124
125 In [18]: %run simpleerr.py exit
126 An exception has occurred, use %tb to see the full traceback.
127 SystemExit: (1, 'Mode = exit')
128
129 In [19]: %run simpleerr.py exit 2
130 An exception has occurred, use %tb to see the full traceback.
131 SystemExit: (2, 'Mode = exit')
132
133 In [20]: %tb
134 Traceback (most recent call last):
135 File ... in <module>
136 bar(mode)
137 File ... line 22, in bar
138 sysexit(stat, mode)
139 File ... line 11, in sysexit
140 raise SystemExit(stat, 'Mode = %s' % mode)
141 SystemExit: (2, 'Mode = exit')
142
143 In [21]: %xmode context
144 Exception reporting mode: Context
145
146 In [22]: %tb
147 ---------------------------------------------------------------------------
148 SystemExit Traceback (most recent call last)
149 <BLANKLINE>
150 ...<module>
151 29 except IndexError:
152 30 mode = 'div'
153 ---> 32 bar(mode)
154 <BLANKLINE>
155 ...bar(mode)
156 20 except:
157 21 stat = 1
158 ---> 22 sysexit(stat, mode)
159 23 else:
160 24 raise ValueError('Unknown mode')
161 <BLANKLINE>
162 ...sysexit(stat, mode)
163 10 def sysexit(stat, mode):
164 ---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
165 <BLANKLINE>
166 SystemExit: (2, 'Mode = exit')
167
168 In [23]: %xmode verbose
169 Exception reporting mode: Verbose
170
171 In [24]: %tb
172 ---------------------------------------------------------------------------
173 SystemExit Traceback (most recent call last)
174 <BLANKLINE>
175 ... in <module>
176 29 except IndexError:
177 30 mode = 'div'
178 ---> 32 bar(mode)
179 mode = 'exit'
180 <BLANKLINE>
181 ... in bar(mode='exit')
182 20 except:
183 21 stat = 1
184 ---> 22 sysexit(stat, mode)
185 mode = 'exit'
186 stat = 2
187 23 else:
188 24 raise ValueError('Unknown mode')
189 <BLANKLINE>
190 ... in sysexit(stat=2, mode='exit')
191 10 def sysexit(stat, mode):
192 ---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
193 stat = 2
194 mode = 'exit'
195 <BLANKLINE>
196 SystemExit: (2, 'Mode = exit')
197 """
120 # TODO : Marc 2021 – this seem to fail due
121 # to upstream changes in CI for whatever reason.
122 # Commenting for now, to revive someday (maybe?)
123 # nose won't work in 3.10 anyway and we'll have to disable iptest.
124 # thus this likely need to bemigrated to pytest.
125
126
127 # def doctest_tb_sysexit():
128 # """
129 # In [17]: %xmode plain
130 # Exception reporting mode: Plain
131 #
132 # In [18]: %run simpleerr.py exit
133 # An exception has occurred, use %tb to see the full traceback.
134 # SystemExit: (1, 'Mode = exit')
135 #
136 # In [19]: %run simpleerr.py exit 2
137 # An exception has occurred, use %tb to see the full traceback.
138 # SystemExit: (2, 'Mode = exit')
139 #
140 # In [20]: %tb
141 # Traceback (most recent call last):
142 # File ... in <module>
143 # bar(mode)
144 # File ... line 22, in bar
145 # sysexit(stat, mode)
146 # File ... line 11, in sysexit
147 # raise SystemExit(stat, 'Mode = %s' % mode)
148 # SystemExit: (2, 'Mode = exit')
149 #
150 # In [21]: %xmode context
151 # Exception reporting mode: Context
152 #
153 # In [22]: %tb
154 # ---------------------------------------------------------------------------
155 # SystemExit Traceback (most recent call last)
156 # <BLANKLINE>
157 # ...<module>
158 # 29 except IndexError:
159 # 30 mode = 'div'
160 # ---> 32 bar(mode)
161 # <BLANKLINE>
162 # ...bar(mode)
163 # 20 except:
164 # 21 stat = 1
165 # ---> 22 sysexit(stat, mode)
166 # 23 else:
167 # 24 raise ValueError('Unknown mode')
168 # <BLANKLINE>
169 # ...sysexit(stat, mode)
170 # 10 def sysexit(stat, mode):
171 # ---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
172 # <BLANKLINE>
173 # SystemExit: (2, 'Mode = exit')
174 #
175 # In [23]: %xmode verbose
176 # Exception reporting mode: Verbose
177 #
178 # In [24]: %tb
179 # ---------------------------------------------------------------------------
180 # SystemExit Traceback (most recent call last)
181 # <BLANKLINE>
182 # ... in <module>
183 # 29 except IndexError:
184 # 30 mode = 'div'
185 # ---> 32 bar(mode)
186 # mode = 'exit'
187 # <BLANKLINE>
188 # ... in bar(mode='exit')
189 # 20 except:
190 # 21 stat = 1
191 # ---> 22 sysexit(stat, mode)
192 # mode = 'exit'
193 # stat = 2
194 # 23 else:
195 # 24 raise ValueError('Unknown mode')
196 # <BLANKLINE>
197 # ... in sysexit(stat=2, mode='exit')
198 # 10 def sysexit(stat, mode):
199 # ---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
200 # stat = 2
201 # mode = 'exit'
202 # <BLANKLINE>
203 # SystemExit: (2, 'Mode = exit')
204 # """
198 205
199 206
200 207 def test_run_cell():
201 208 import textwrap
202 209 ip.run_cell('a = 10\na+=1')
203 210 ip.run_cell('assert a == 11\nassert 1')
204 211
205 212 nt.assert_equal(ip.user_ns['a'], 11)
206 213 complex = textwrap.dedent("""
207 214 if 1:
208 215 print "hello"
209 216 if 1:
210 217 print "world"
211 218
212 219 if 2:
213 220 print "foo"
214 221
215 222 if 3:
216 223 print "bar"
217 224
218 225 if 4:
219 226 print "bar"
220 227
221 228 """)
222 229 # Simply verifies that this kind of input is run
223 230 ip.run_cell(complex)
224 231
225 232
226 233 def test_db():
227 234 """Test the internal database used for variable persistence."""
228 235 ip.db['__unittest_'] = 12
229 236 nt.assert_equal(ip.db['__unittest_'], 12)
230 237 del ip.db['__unittest_']
231 238 assert '__unittest_' not in ip.db
@@ -1,1261 +1,1262 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for various magic functions.
3 3
4 4 Needs to be run by nose (to make ipython session available).
5 5 """
6 6
7 7 import io
8 8 import os
9 9 import re
10 10 import sys
11 11 import warnings
12 12 from textwrap import dedent
13 13 from unittest import TestCase
14 14 from unittest import mock
15 15 from importlib import invalidate_caches
16 16 from io import StringIO
17 17 from pathlib import Path
18 18
19 19 import nose.tools as nt
20 20
21 21 import shlex
22 22
23 23 from IPython import get_ipython
24 24 from IPython.core import magic
25 25 from IPython.core.error import UsageError
26 26 from IPython.core.magic import (Magics, magics_class, line_magic,
27 27 cell_magic,
28 28 register_line_magic, register_cell_magic)
29 29 from IPython.core.magics import execution, script, code, logging, osm
30 30 from IPython.testing import decorators as dec
31 31 from IPython.testing import tools as tt
32 32 from IPython.utils.io import capture_output
33 33 from IPython.utils.tempdir import (TemporaryDirectory,
34 34 TemporaryWorkingDirectory)
35 35 from IPython.utils.process import find_cmd
36 36 from .test_debugger import PdbTestInput
37 37
38 import pytest
39
38 40
39 41 @magic.magics_class
40 42 class DummyMagics(magic.Magics): pass
41 43
42 44 def test_extract_code_ranges():
43 45 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
44 46 expected = [(0, 1),
45 47 (2, 3),
46 48 (4, 6),
47 49 (6, 9),
48 50 (9, 14),
49 51 (16, None),
50 52 (None, 9),
51 53 (9, None),
52 54 (None, 13),
53 55 (None, None)]
54 56 actual = list(code.extract_code_ranges(instr))
55 57 nt.assert_equal(actual, expected)
56 58
57 59 def test_extract_symbols():
58 60 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
59 61 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
60 62 expected = [([], ['a']),
61 63 (["def b():\n return 42\n"], []),
62 64 (["class A: pass\n"], []),
63 65 (["class A: pass\n", "def b():\n return 42\n"], []),
64 66 (["class A: pass\n"], ['a']),
65 67 ([], ['z'])]
66 68 for symbols, exp in zip(symbols_args, expected):
67 69 nt.assert_equal(code.extract_symbols(source, symbols), exp)
68 70
69 71
70 72 def test_extract_symbols_raises_exception_with_non_python_code():
71 73 source = ("=begin A Ruby program :)=end\n"
72 74 "def hello\n"
73 75 "puts 'Hello world'\n"
74 76 "end")
75 77 with nt.assert_raises(SyntaxError):
76 78 code.extract_symbols(source, "hello")
77 79
78 80
79 81 def test_magic_not_found():
80 82 # magic not found raises UsageError
81 83 with nt.assert_raises(UsageError):
82 84 _ip.magic('doesntexist')
83 85
84 86 # ensure result isn't success when a magic isn't found
85 87 result = _ip.run_cell('%doesntexist')
86 88 assert isinstance(result.error_in_exec, UsageError)
87 89
88 90
89 91 def test_cell_magic_not_found():
90 92 # magic not found raises UsageError
91 93 with nt.assert_raises(UsageError):
92 94 _ip.run_cell_magic('doesntexist', 'line', 'cell')
93 95
94 96 # ensure result isn't success when a magic isn't found
95 97 result = _ip.run_cell('%%doesntexist')
96 98 assert isinstance(result.error_in_exec, UsageError)
97 99
98 100
99 101 def test_magic_error_status():
100 102 def fail(shell):
101 103 1/0
102 104 _ip.register_magic_function(fail)
103 105 result = _ip.run_cell('%fail')
104 106 assert isinstance(result.error_in_exec, ZeroDivisionError)
105 107
106 108
107 109 def test_config():
108 110 """ test that config magic does not raise
109 111 can happen if Configurable init is moved too early into
110 112 Magics.__init__ as then a Config object will be registered as a
111 113 magic.
112 114 """
113 115 ## should not raise.
114 116 _ip.magic('config')
115 117
116 118 def test_config_available_configs():
117 119 """ test that config magic prints available configs in unique and
118 120 sorted order. """
119 121 with capture_output() as captured:
120 122 _ip.magic('config')
121 123
122 124 stdout = captured.stdout
123 125 config_classes = stdout.strip().split('\n')[1:]
124 126 nt.assert_list_equal(config_classes, sorted(set(config_classes)))
125 127
126 128 def test_config_print_class():
127 129 """ test that config with a classname prints the class's options. """
128 130 with capture_output() as captured:
129 131 _ip.magic('config TerminalInteractiveShell')
130 132
131 133 stdout = captured.stdout
132 134 if not re.match("TerminalInteractiveShell.* options", stdout.splitlines()[0]):
133 135 print(stdout)
134 136 raise AssertionError("1st line of stdout not like "
135 137 "'TerminalInteractiveShell.* options'")
136 138
137 139 def test_rehashx():
138 140 # clear up everything
139 141 _ip.alias_manager.clear_aliases()
140 142 del _ip.db['syscmdlist']
141 143
142 144 _ip.magic('rehashx')
143 145 # Practically ALL ipython development systems will have more than 10 aliases
144 146
145 147 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
146 148 for name, cmd in _ip.alias_manager.aliases:
147 149 # we must strip dots from alias names
148 150 nt.assert_not_in('.', name)
149 151
150 152 # rehashx must fill up syscmdlist
151 153 scoms = _ip.db['syscmdlist']
152 154 nt.assert_true(len(scoms) > 10)
153 155
154 156
155 157
156 158 def test_magic_parse_options():
157 159 """Test that we don't mangle paths when parsing magic options."""
158 160 ip = get_ipython()
159 161 path = 'c:\\x'
160 162 m = DummyMagics(ip)
161 163 opts = m.parse_options('-f %s' % path,'f:')[0]
162 164 # argv splitting is os-dependent
163 165 if os.name == 'posix':
164 166 expected = 'c:x'
165 167 else:
166 168 expected = path
167 169 nt.assert_equal(opts['f'], expected)
168 170
169 171 def test_magic_parse_long_options():
170 172 """Magic.parse_options can handle --foo=bar long options"""
171 173 ip = get_ipython()
172 174 m = DummyMagics(ip)
173 175 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
174 176 nt.assert_in('foo', opts)
175 177 nt.assert_in('bar', opts)
176 178 nt.assert_equal(opts['bar'], "bubble")
177 179
178 180
179 181 def doctest_hist_f():
180 182 """Test %hist -f with temporary filename.
181 183
182 184 In [9]: import tempfile
183 185
184 186 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
185 187
186 188 In [11]: %hist -nl -f $tfile 3
187 189
188 190 In [13]: import os; os.unlink(tfile)
189 191 """
190 192
191 193
192 194 def doctest_hist_op():
193 195 """Test %hist -op
194 196
195 197 In [1]: class b(float):
196 198 ...: pass
197 199 ...:
198 200
199 201 In [2]: class s(object):
200 202 ...: def __str__(self):
201 203 ...: return 's'
202 204 ...:
203 205
204 206 In [3]:
205 207
206 208 In [4]: class r(b):
207 209 ...: def __repr__(self):
208 210 ...: return 'r'
209 211 ...:
210 212
211 213 In [5]: class sr(s,r): pass
212 214 ...:
213 215
214 216 In [6]:
215 217
216 218 In [7]: bb=b()
217 219
218 220 In [8]: ss=s()
219 221
220 222 In [9]: rr=r()
221 223
222 224 In [10]: ssrr=sr()
223 225
224 226 In [11]: 4.5
225 227 Out[11]: 4.5
226 228
227 229 In [12]: str(ss)
228 230 Out[12]: 's'
229 231
230 232 In [13]:
231 233
232 234 In [14]: %hist -op
233 235 >>> class b:
234 236 ... pass
235 237 ...
236 238 >>> class s(b):
237 239 ... def __str__(self):
238 240 ... return 's'
239 241 ...
240 242 >>>
241 243 >>> class r(b):
242 244 ... def __repr__(self):
243 245 ... return 'r'
244 246 ...
245 247 >>> class sr(s,r): pass
246 248 >>>
247 249 >>> bb=b()
248 250 >>> ss=s()
249 251 >>> rr=r()
250 252 >>> ssrr=sr()
251 253 >>> 4.5
252 254 4.5
253 255 >>> str(ss)
254 256 's'
255 257 >>>
256 258 """
257 259
258 260 def test_hist_pof():
259 261 ip = get_ipython()
260 262 ip.run_cell(u"1+2", store_history=True)
261 263 #raise Exception(ip.history_manager.session_number)
262 264 #raise Exception(list(ip.history_manager._get_range_session()))
263 265 with TemporaryDirectory() as td:
264 266 tf = os.path.join(td, 'hist.py')
265 267 ip.run_line_magic('history', '-pof %s' % tf)
266 268 assert os.path.isfile(tf)
267 269
268 270
269 271 def test_macro():
270 272 ip = get_ipython()
271 273 ip.history_manager.reset() # Clear any existing history.
272 274 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
273 275 for i, cmd in enumerate(cmds, start=1):
274 276 ip.history_manager.store_inputs(i, cmd)
275 277 ip.magic("macro test 1-3")
276 278 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
277 279
278 280 # List macros
279 281 nt.assert_in("test", ip.magic("macro"))
280 282
281 283
282 284 def test_macro_run():
283 285 """Test that we can run a multi-line macro successfully."""
284 286 ip = get_ipython()
285 287 ip.history_manager.reset()
286 288 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
287 289 for cmd in cmds:
288 290 ip.run_cell(cmd, store_history=True)
289 291 nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint(a)\n")
290 292 with tt.AssertPrints("12"):
291 293 ip.run_cell("test")
292 294 with tt.AssertPrints("13"):
293 295 ip.run_cell("test")
294 296
295 297
296 298 def test_magic_magic():
297 299 """Test %magic"""
298 300 ip = get_ipython()
299 301 with capture_output() as captured:
300 302 ip.magic("magic")
301 303
302 304 stdout = captured.stdout
303 305 nt.assert_in('%magic', stdout)
304 306 nt.assert_in('IPython', stdout)
305 307 nt.assert_in('Available', stdout)
306 308
307 309
308 310 @dec.skipif_not_numpy
309 311 def test_numpy_reset_array_undec():
310 312 "Test '%reset array' functionality"
311 313 _ip.ex('import numpy as np')
312 314 _ip.ex('a = np.empty(2)')
313 315 nt.assert_in('a', _ip.user_ns)
314 316 _ip.magic('reset -f array')
315 317 nt.assert_not_in('a', _ip.user_ns)
316 318
317 319 def test_reset_out():
318 320 "Test '%reset out' magic"
319 321 _ip.run_cell("parrot = 'dead'", store_history=True)
320 322 # test '%reset -f out', make an Out prompt
321 323 _ip.run_cell("parrot", store_history=True)
322 324 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
323 325 _ip.magic('reset -f out')
324 326 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
325 327 nt.assert_equal(len(_ip.user_ns['Out']), 0)
326 328
327 329 def test_reset_in():
328 330 "Test '%reset in' magic"
329 331 # test '%reset -f in'
330 332 _ip.run_cell("parrot", store_history=True)
331 333 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
332 334 _ip.magic('%reset -f in')
333 335 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
334 336 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
335 337
336 338 def test_reset_dhist():
337 339 "Test '%reset dhist' magic"
338 340 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
339 341 _ip.magic('cd ' + os.path.dirname(nt.__file__))
340 342 _ip.magic('cd -')
341 343 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
342 344 _ip.magic('reset -f dhist')
343 345 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
344 346 _ip.run_cell("_dh = [d for d in tmp]") #restore
345 347
346 348 def test_reset_in_length():
347 349 "Test that '%reset in' preserves In[] length"
348 350 _ip.run_cell("print 'foo'")
349 351 _ip.run_cell("reset -f in")
350 352 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
351 353
352 354 class TestResetErrors(TestCase):
353 355
354 356 def test_reset_redefine(self):
355 357
356 358 @magics_class
357 359 class KernelMagics(Magics):
358 360 @line_magic
359 361 def less(self, shell): pass
360 362
361 363 _ip.register_magics(KernelMagics)
362 364
363 365 with self.assertLogs() as cm:
364 366 # hack, we want to just capture logs, but assertLogs fails if not
365 367 # logs get produce.
366 368 # so log one things we ignore.
367 369 import logging as log_mod
368 370 log = log_mod.getLogger()
369 371 log.info('Nothing')
370 372 # end hack.
371 373 _ip.run_cell("reset -f")
372 374
373 375 assert len(cm.output) == 1
374 376 for out in cm.output:
375 377 assert "Invalid alias" not in out
376 378
377 379 def test_tb_syntaxerror():
378 380 """test %tb after a SyntaxError"""
379 381 ip = get_ipython()
380 382 ip.run_cell("for")
381 383
382 384 # trap and validate stdout
383 385 save_stdout = sys.stdout
384 386 try:
385 387 sys.stdout = StringIO()
386 388 ip.run_cell("%tb")
387 389 out = sys.stdout.getvalue()
388 390 finally:
389 391 sys.stdout = save_stdout
390 392 # trim output, and only check the last line
391 393 last_line = out.rstrip().splitlines()[-1].strip()
392 394 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
393 395
394 396
395 397 def test_time():
396 398 ip = get_ipython()
397 399
398 400 with tt.AssertPrints("Wall time: "):
399 401 ip.run_cell("%time None")
400 402
401 403 ip.run_cell("def f(kmjy):\n"
402 404 " %time print (2*kmjy)")
403 405
404 406 with tt.AssertPrints("Wall time: "):
405 407 with tt.AssertPrints("hihi", suppress=False):
406 408 ip.run_cell("f('hi')")
407 409
408 410 def test_time_last_not_expression():
409 411 ip.run_cell("%%time\n"
410 412 "var_1 = 1\n"
411 413 "var_2 = 2\n")
412 414 assert ip.user_ns['var_1'] == 1
413 415 del ip.user_ns['var_1']
414 416 assert ip.user_ns['var_2'] == 2
415 417 del ip.user_ns['var_2']
416 418
417 419
418 420 @dec.skip_win32
419 421 def test_time2():
420 422 ip = get_ipython()
421 423
422 424 with tt.AssertPrints("CPU times: user "):
423 425 ip.run_cell("%time None")
424 426
425 427 def test_time3():
426 428 """Erroneous magic function calls, issue gh-3334"""
427 429 ip = get_ipython()
428 430 ip.user_ns.pop('run', None)
429 431
430 432 with tt.AssertNotPrints("not found", channel='stderr'):
431 433 ip.run_cell("%%time\n"
432 434 "run = 0\n"
433 435 "run += 1")
434 436
435 437 def test_multiline_time():
436 438 """Make sure last statement from time return a value."""
437 439 ip = get_ipython()
438 440 ip.user_ns.pop('run', None)
439 441
440 442 ip.run_cell(dedent("""\
441 443 %%time
442 444 a = "ho"
443 445 b = "hey"
444 446 a+b
445 447 """))
446 448 nt.assert_equal(ip.user_ns_hidden['_'], 'hohey')
447 449
448 450 def test_time_local_ns():
449 451 """
450 452 Test that local_ns is actually global_ns when running a cell magic
451 453 """
452 454 ip = get_ipython()
453 455 ip.run_cell("%%time\n"
454 456 "myvar = 1")
455 457 nt.assert_equal(ip.user_ns['myvar'], 1)
456 458 del ip.user_ns['myvar']
457 459
458 460 def test_doctest_mode():
459 461 "Toggle doctest_mode twice, it should be a no-op and run without error"
460 462 _ip.magic('doctest_mode')
461 463 _ip.magic('doctest_mode')
462 464
463 465
464 466 def test_parse_options():
465 467 """Tests for basic options parsing in magics."""
466 468 # These are only the most minimal of tests, more should be added later. At
467 469 # the very least we check that basic text/unicode calls work OK.
468 470 m = DummyMagics(_ip)
469 471 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
470 472 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
471 473
472 474
473 475 def test_dirops():
474 476 """Test various directory handling operations."""
475 477 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
476 478 curpath = os.getcwd
477 479 startdir = os.getcwd()
478 480 ipdir = os.path.realpath(_ip.ipython_dir)
479 481 try:
480 482 _ip.magic('cd "%s"' % ipdir)
481 483 nt.assert_equal(curpath(), ipdir)
482 484 _ip.magic('cd -')
483 485 nt.assert_equal(curpath(), startdir)
484 486 _ip.magic('pushd "%s"' % ipdir)
485 487 nt.assert_equal(curpath(), ipdir)
486 488 _ip.magic('popd')
487 489 nt.assert_equal(curpath(), startdir)
488 490 finally:
489 491 os.chdir(startdir)
490 492
491 493
492 494 def test_cd_force_quiet():
493 495 """Test OSMagics.cd_force_quiet option"""
494 496 _ip.config.OSMagics.cd_force_quiet = True
495 497 osmagics = osm.OSMagics(shell=_ip)
496 498
497 499 startdir = os.getcwd()
498 500 ipdir = os.path.realpath(_ip.ipython_dir)
499 501
500 502 try:
501 503 with tt.AssertNotPrints(ipdir):
502 504 osmagics.cd('"%s"' % ipdir)
503 505 with tt.AssertNotPrints(startdir):
504 506 osmagics.cd('-')
505 507 finally:
506 508 os.chdir(startdir)
507 509
508 510
509 511 def test_xmode():
510 512 # Calling xmode three times should be a no-op
511 513 xmode = _ip.InteractiveTB.mode
512 514 for i in range(4):
513 515 _ip.magic("xmode")
514 516 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
515 517
516 518 def test_reset_hard():
517 519 monitor = []
518 520 class A(object):
519 521 def __del__(self):
520 522 monitor.append(1)
521 523 def __repr__(self):
522 524 return "<A instance>"
523 525
524 526 _ip.user_ns["a"] = A()
525 527 _ip.run_cell("a")
526 528
527 529 nt.assert_equal(monitor, [])
528 530 _ip.magic("reset -f")
529 531 nt.assert_equal(monitor, [1])
530 532
531 533 class TestXdel(tt.TempFileMixin):
532 534 def test_xdel(self):
533 535 """Test that references from %run are cleared by xdel."""
534 536 src = ("class A(object):\n"
535 537 " monitor = []\n"
536 538 " def __del__(self):\n"
537 539 " self.monitor.append(1)\n"
538 540 "a = A()\n")
539 541 self.mktmp(src)
540 542 # %run creates some hidden references...
541 543 _ip.magic("run %s" % self.fname)
542 544 # ... as does the displayhook.
543 545 _ip.run_cell("a")
544 546
545 547 monitor = _ip.user_ns["A"].monitor
546 548 nt.assert_equal(monitor, [])
547 549
548 550 _ip.magic("xdel a")
549 551
550 552 # Check that a's __del__ method has been called.
551 553 nt.assert_equal(monitor, [1])
552 554
553 555 def doctest_who():
554 556 """doctest for %who
555 557
556 558 In [1]: %reset -f
557 559
558 560 In [2]: alpha = 123
559 561
560 562 In [3]: beta = 'beta'
561 563
562 564 In [4]: %who int
563 565 alpha
564 566
565 567 In [5]: %who str
566 568 beta
567 569
568 570 In [6]: %whos
569 571 Variable Type Data/Info
570 572 ----------------------------
571 573 alpha int 123
572 574 beta str beta
573 575
574 576 In [7]: %who_ls
575 577 Out[7]: ['alpha', 'beta']
576 578 """
577 579
578 580 def test_whos():
579 581 """Check that whos is protected against objects where repr() fails."""
580 582 class A(object):
581 583 def __repr__(self):
582 584 raise Exception()
583 585 _ip.user_ns['a'] = A()
584 586 _ip.magic("whos")
585 587
586 588 def doctest_precision():
587 589 """doctest for %precision
588 590
589 591 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
590 592
591 593 In [2]: %precision 5
592 594 Out[2]: '%.5f'
593 595
594 596 In [3]: f.float_format
595 597 Out[3]: '%.5f'
596 598
597 599 In [4]: %precision %e
598 600 Out[4]: '%e'
599 601
600 602 In [5]: f(3.1415927)
601 603 Out[5]: '3.141593e+00'
602 604 """
603 605
604 606 def test_debug_magic():
605 607 """Test debugging a small code with %debug
606 608
607 609 In [1]: with PdbTestInput(['c']):
608 610 ...: %debug print("a b") #doctest: +ELLIPSIS
609 611 ...:
610 612 ...
611 613 ipdb> c
612 614 a b
613 615 In [2]:
614 616 """
615 617
616 618 def test_psearch():
617 619 with tt.AssertPrints("dict.fromkeys"):
618 620 _ip.run_cell("dict.fr*?")
619 621 with tt.AssertPrints("π.is_integer"):
620 622 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
621 623
622 624 def test_timeit_shlex():
623 625 """test shlex issues with timeit (#1109)"""
624 626 _ip.ex("def f(*a,**kw): pass")
625 627 _ip.magic('timeit -n1 "this is a bug".count(" ")')
626 628 _ip.magic('timeit -r1 -n1 f(" ", 1)')
627 629 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
628 630 _ip.magic('timeit -r1 -n1 ("a " + "b")')
629 631 _ip.magic('timeit -r1 -n1 f("a " + "b")')
630 632 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
631 633
632 634
633 635 def test_timeit_special_syntax():
634 636 "Test %%timeit with IPython special syntax"
635 637 @register_line_magic
636 638 def lmagic(line):
637 639 ip = get_ipython()
638 640 ip.user_ns['lmagic_out'] = line
639 641
640 642 # line mode test
641 643 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
642 644 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
643 645 # cell mode test
644 646 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
645 647 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
646 648
647 649 def test_timeit_return():
648 650 """
649 651 test whether timeit -o return object
650 652 """
651 653
652 654 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
653 655 assert(res is not None)
654 656
655 657 def test_timeit_quiet():
656 658 """
657 659 test quiet option of timeit magic
658 660 """
659 661 with tt.AssertNotPrints("loops"):
660 662 _ip.run_cell("%timeit -n1 -r1 -q 1")
661 663
662 664 def test_timeit_return_quiet():
663 665 with tt.AssertNotPrints("loops"):
664 666 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
665 667 assert (res is not None)
666 668
667 669 def test_timeit_invalid_return():
668 670 with nt.assert_raises_regex(SyntaxError, "outside function"):
669 671 _ip.run_line_magic('timeit', 'return')
670 672
671 673 @dec.skipif(execution.profile is None)
672 674 def test_prun_special_syntax():
673 675 "Test %%prun with IPython special syntax"
674 676 @register_line_magic
675 677 def lmagic(line):
676 678 ip = get_ipython()
677 679 ip.user_ns['lmagic_out'] = line
678 680
679 681 # line mode test
680 682 _ip.run_line_magic('prun', '-q %lmagic my line')
681 683 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
682 684 # cell mode test
683 685 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
684 686 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
685 687
686 688 @dec.skipif(execution.profile is None)
687 689 def test_prun_quotes():
688 690 "Test that prun does not clobber string escapes (GH #1302)"
689 691 _ip.magic(r"prun -q x = '\t'")
690 692 nt.assert_equal(_ip.user_ns['x'], '\t')
691 693
692 694 def test_extension():
693 695 # Debugging information for failures of this test
694 696 print('sys.path:')
695 697 for p in sys.path:
696 698 print(' ', p)
697 699 print('CWD', os.getcwd())
698 700
699 701 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
700 702 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
701 703 sys.path.insert(0, daft_path)
702 704 try:
703 705 _ip.user_ns.pop('arq', None)
704 706 invalidate_caches() # Clear import caches
705 707 _ip.magic("load_ext daft_extension")
706 708 nt.assert_equal(_ip.user_ns['arq'], 185)
707 709 _ip.magic("unload_ext daft_extension")
708 710 assert 'arq' not in _ip.user_ns
709 711 finally:
710 712 sys.path.remove(daft_path)
711 713
712 714
713 715 def test_notebook_export_json():
714 716 _ip = get_ipython()
715 717 _ip.history_manager.reset() # Clear any existing history.
716 718 cmds = [u"a=1", u"def b():\n return a**2", u"print('noël, été', b())"]
717 719 for i, cmd in enumerate(cmds, start=1):
718 720 _ip.history_manager.store_inputs(i, cmd)
719 721 with TemporaryDirectory() as td:
720 722 outfile = os.path.join(td, "nb.ipynb")
721 723 _ip.magic("notebook -e %s" % outfile)
722 724
723 725
724 726 class TestEnv(TestCase):
725 727
726 728 def test_env(self):
727 729 env = _ip.magic("env")
728 730 self.assertTrue(isinstance(env, dict))
729 731
730 732 def test_env_secret(self):
731 733 env = _ip.magic("env")
732 734 hidden = "<hidden>"
733 735 with mock.patch.dict(
734 736 os.environ,
735 737 {
736 738 "API_KEY": "abc123",
737 739 "SECRET_THING": "ssshhh",
738 740 "JUPYTER_TOKEN": "",
739 741 "VAR": "abc"
740 742 }
741 743 ):
742 744 env = _ip.magic("env")
743 745 assert env["API_KEY"] == hidden
744 746 assert env["SECRET_THING"] == hidden
745 747 assert env["JUPYTER_TOKEN"] == hidden
746 748 assert env["VAR"] == "abc"
747 749
748 750 def test_env_get_set_simple(self):
749 751 env = _ip.magic("env var val1")
750 752 self.assertEqual(env, None)
751 753 self.assertEqual(os.environ['var'], 'val1')
752 754 self.assertEqual(_ip.magic("env var"), 'val1')
753 755 env = _ip.magic("env var=val2")
754 756 self.assertEqual(env, None)
755 757 self.assertEqual(os.environ['var'], 'val2')
756 758
757 759 def test_env_get_set_complex(self):
758 760 env = _ip.magic("env var 'val1 '' 'val2")
759 761 self.assertEqual(env, None)
760 762 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
761 763 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
762 764 env = _ip.magic('env var=val2 val3="val4')
763 765 self.assertEqual(env, None)
764 766 self.assertEqual(os.environ['var'], 'val2 val3="val4')
765 767
766 768 def test_env_set_bad_input(self):
767 769 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
768 770
769 771 def test_env_set_whitespace(self):
770 772 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
771 773
772 774
773 775 class CellMagicTestCase(TestCase):
774 776
775 777 def check_ident(self, magic):
776 778 # Manually called, we get the result
777 779 out = _ip.run_cell_magic(magic, 'a', 'b')
778 780 nt.assert_equal(out, ('a','b'))
779 781 # Via run_cell, it goes into the user's namespace via displayhook
780 782 _ip.run_cell('%%' + magic +' c\nd\n')
781 783 nt.assert_equal(_ip.user_ns['_'], ('c','d\n'))
782 784
783 785 def test_cell_magic_func_deco(self):
784 786 "Cell magic using simple decorator"
785 787 @register_cell_magic
786 788 def cellm(line, cell):
787 789 return line, cell
788 790
789 791 self.check_ident('cellm')
790 792
791 793 def test_cell_magic_reg(self):
792 794 "Cell magic manually registered"
793 795 def cellm(line, cell):
794 796 return line, cell
795 797
796 798 _ip.register_magic_function(cellm, 'cell', 'cellm2')
797 799 self.check_ident('cellm2')
798 800
799 801 def test_cell_magic_class(self):
800 802 "Cell magics declared via a class"
801 803 @magics_class
802 804 class MyMagics(Magics):
803 805
804 806 @cell_magic
805 807 def cellm3(self, line, cell):
806 808 return line, cell
807 809
808 810 _ip.register_magics(MyMagics)
809 811 self.check_ident('cellm3')
810 812
811 813 def test_cell_magic_class2(self):
812 814 "Cell magics declared via a class, #2"
813 815 @magics_class
814 816 class MyMagics2(Magics):
815 817
816 818 @cell_magic('cellm4')
817 819 def cellm33(self, line, cell):
818 820 return line, cell
819 821
820 822 _ip.register_magics(MyMagics2)
821 823 self.check_ident('cellm4')
822 824 # Check that nothing is registered as 'cellm33'
823 825 c33 = _ip.find_cell_magic('cellm33')
824 826 nt.assert_equal(c33, None)
825 827
826 828 def test_file():
827 829 """Basic %%writefile"""
828 830 ip = get_ipython()
829 831 with TemporaryDirectory() as td:
830 832 fname = os.path.join(td, 'file1')
831 833 ip.run_cell_magic("writefile", fname, u'\n'.join([
832 834 'line1',
833 835 'line2',
834 836 ]))
835 837 s = Path(fname).read_text()
836 838 nt.assert_in('line1\n', s)
837 839 nt.assert_in('line2', s)
838 840
839 841 @dec.skip_win32
840 842 def test_file_single_quote():
841 843 """Basic %%writefile with embedded single quotes"""
842 844 ip = get_ipython()
843 845 with TemporaryDirectory() as td:
844 846 fname = os.path.join(td, '\'file1\'')
845 847 ip.run_cell_magic("writefile", fname, u'\n'.join([
846 848 'line1',
847 849 'line2',
848 850 ]))
849 851 s = Path(fname).read_text()
850 852 nt.assert_in('line1\n', s)
851 853 nt.assert_in('line2', s)
852 854
853 855 @dec.skip_win32
854 856 def test_file_double_quote():
855 857 """Basic %%writefile with embedded double quotes"""
856 858 ip = get_ipython()
857 859 with TemporaryDirectory() as td:
858 860 fname = os.path.join(td, '"file1"')
859 861 ip.run_cell_magic("writefile", fname, u'\n'.join([
860 862 'line1',
861 863 'line2',
862 864 ]))
863 865 s = Path(fname).read_text()
864 866 nt.assert_in('line1\n', s)
865 867 nt.assert_in('line2', s)
866 868
867 869 def test_file_var_expand():
868 870 """%%writefile $filename"""
869 871 ip = get_ipython()
870 872 with TemporaryDirectory() as td:
871 873 fname = os.path.join(td, 'file1')
872 874 ip.user_ns['filename'] = fname
873 875 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
874 876 'line1',
875 877 'line2',
876 878 ]))
877 879 s = Path(fname).read_text()
878 880 nt.assert_in('line1\n', s)
879 881 nt.assert_in('line2', s)
880 882
881 883 def test_file_unicode():
882 884 """%%writefile with unicode cell"""
883 885 ip = get_ipython()
884 886 with TemporaryDirectory() as td:
885 887 fname = os.path.join(td, 'file1')
886 888 ip.run_cell_magic("writefile", fname, u'\n'.join([
887 889 u'liné1',
888 890 u'liné2',
889 891 ]))
890 892 with io.open(fname, encoding='utf-8') as f:
891 893 s = f.read()
892 894 nt.assert_in(u'liné1\n', s)
893 895 nt.assert_in(u'liné2', s)
894 896
895 897 def test_file_amend():
896 898 """%%writefile -a amends files"""
897 899 ip = get_ipython()
898 900 with TemporaryDirectory() as td:
899 901 fname = os.path.join(td, 'file2')
900 902 ip.run_cell_magic("writefile", fname, u'\n'.join([
901 903 'line1',
902 904 'line2',
903 905 ]))
904 906 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
905 907 'line3',
906 908 'line4',
907 909 ]))
908 910 s = Path(fname).read_text()
909 911 nt.assert_in('line1\n', s)
910 912 nt.assert_in('line3\n', s)
911 913
912 914 def test_file_spaces():
913 915 """%%file with spaces in filename"""
914 916 ip = get_ipython()
915 917 with TemporaryWorkingDirectory() as td:
916 918 fname = "file name"
917 919 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
918 920 'line1',
919 921 'line2',
920 922 ]))
921 923 s = Path(fname).read_text()
922 924 nt.assert_in('line1\n', s)
923 925 nt.assert_in('line2', s)
924 926
925 927 def test_script_config():
926 928 ip = get_ipython()
927 929 ip.config.ScriptMagics.script_magics = ['whoda']
928 930 sm = script.ScriptMagics(shell=ip)
929 931 nt.assert_in('whoda', sm.magics['cell'])
930 932
931 933 @dec.skip_win32
932 934 def test_script_out():
933 935 ip = get_ipython()
934 936 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
935 937 nt.assert_equal(ip.user_ns['output'], 'hi\n')
936 938
937 939 @dec.skip_win32
938 940 def test_script_err():
939 941 ip = get_ipython()
940 942 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
941 943 nt.assert_equal(ip.user_ns['error'], 'hello\n')
942 944
943 945 @dec.skip_win32
944 946 def test_script_out_err():
945 947 ip = get_ipython()
946 948 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
947 949 nt.assert_equal(ip.user_ns['output'], 'hi\n')
948 950 nt.assert_equal(ip.user_ns['error'], 'hello\n')
949 951
950 952 @dec.skip_win32
951 953 async def test_script_bg_out():
952 954 ip = get_ipython()
953 955 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
954 956 nt.assert_equal((await ip.user_ns["output"].read()), b"hi\n")
955 957 ip.user_ns['output'].close()
956 958
957
958 959 @dec.skip_win32
959 960 async def test_script_bg_err():
960 961 ip = get_ipython()
961 962 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
962 963 nt.assert_equal((await ip.user_ns["error"].read()), b"hello\n")
963 964 ip.user_ns["error"].close()
964 965
965 966
966 967 @dec.skip_win32
967 968 async def test_script_bg_out_err():
968 969 ip = get_ipython()
969 970 ip.run_cell_magic(
970 971 "script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2"
971 972 )
972 973 nt.assert_equal((await ip.user_ns["output"].read()), b"hi\n")
973 974 nt.assert_equal((await ip.user_ns["error"].read()), b"hello\n")
974 975 ip.user_ns["output"].close()
975 976 ip.user_ns["error"].close()
976 977
977 978
978 979 def test_script_defaults():
979 980 ip = get_ipython()
980 981 for cmd in ['sh', 'bash', 'perl', 'ruby']:
981 982 try:
982 983 find_cmd(cmd)
983 984 except Exception:
984 985 pass
985 986 else:
986 987 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
987 988
988 989
989 990 @magics_class
990 991 class FooFoo(Magics):
991 992 """class with both %foo and %%foo magics"""
992 993 @line_magic('foo')
993 994 def line_foo(self, line):
994 995 "I am line foo"
995 996 pass
996 997
997 998 @cell_magic("foo")
998 999 def cell_foo(self, line, cell):
999 1000 "I am cell foo, not line foo"
1000 1001 pass
1001 1002
1002 1003 def test_line_cell_info():
1003 1004 """%%foo and %foo magics are distinguishable to inspect"""
1004 1005 ip = get_ipython()
1005 1006 ip.magics_manager.register(FooFoo)
1006 1007 oinfo = ip.object_inspect('foo')
1007 1008 nt.assert_true(oinfo['found'])
1008 1009 nt.assert_true(oinfo['ismagic'])
1009 1010
1010 1011 oinfo = ip.object_inspect('%%foo')
1011 1012 nt.assert_true(oinfo['found'])
1012 1013 nt.assert_true(oinfo['ismagic'])
1013 1014 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
1014 1015
1015 1016 oinfo = ip.object_inspect('%foo')
1016 1017 nt.assert_true(oinfo['found'])
1017 1018 nt.assert_true(oinfo['ismagic'])
1018 1019 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
1019 1020
1020 1021 def test_multiple_magics():
1021 1022 ip = get_ipython()
1022 1023 foo1 = FooFoo(ip)
1023 1024 foo2 = FooFoo(ip)
1024 1025 mm = ip.magics_manager
1025 1026 mm.register(foo1)
1026 1027 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
1027 1028 mm.register(foo2)
1028 1029 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
1029 1030
1030 1031 def test_alias_magic():
1031 1032 """Test %alias_magic."""
1032 1033 ip = get_ipython()
1033 1034 mm = ip.magics_manager
1034 1035
1035 1036 # Basic operation: both cell and line magics are created, if possible.
1036 1037 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
1037 1038 nt.assert_in('timeit_alias', mm.magics['line'])
1038 1039 nt.assert_in('timeit_alias', mm.magics['cell'])
1039 1040
1040 1041 # --cell is specified, line magic not created.
1041 1042 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
1042 1043 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
1043 1044 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
1044 1045
1045 1046 # Test that line alias is created successfully.
1046 1047 ip.run_line_magic('alias_magic', '--line env_alias env')
1047 1048 nt.assert_equal(ip.run_line_magic('env', ''),
1048 1049 ip.run_line_magic('env_alias', ''))
1049 1050
1050 1051 # Test that line alias with parameters passed in is created successfully.
1051 1052 ip.run_line_magic('alias_magic', '--line history_alias history --params ' + shlex.quote('3'))
1052 1053 nt.assert_in('history_alias', mm.magics['line'])
1053 1054
1054 1055
1055 1056 def test_save():
1056 1057 """Test %save."""
1057 1058 ip = get_ipython()
1058 1059 ip.history_manager.reset() # Clear any existing history.
1059 1060 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
1060 1061 for i, cmd in enumerate(cmds, start=1):
1061 1062 ip.history_manager.store_inputs(i, cmd)
1062 1063 with TemporaryDirectory() as tmpdir:
1063 1064 file = os.path.join(tmpdir, "testsave.py")
1064 1065 ip.run_line_magic("save", "%s 1-10" % file)
1065 1066 content = Path(file).read_text()
1066 1067 nt.assert_equal(content.count(cmds[0]), 1)
1067 1068 nt.assert_in("coding: utf-8", content)
1068 1069 ip.run_line_magic("save", "-a %s 1-10" % file)
1069 1070 content = Path(file).read_text()
1070 1071 nt.assert_equal(content.count(cmds[0]), 2)
1071 1072 nt.assert_in("coding: utf-8", content)
1072 1073
1073 1074
1074 1075 def test_store():
1075 1076 """Test %store."""
1076 1077 ip = get_ipython()
1077 1078 ip.run_line_magic('load_ext', 'storemagic')
1078 1079
1079 1080 # make sure the storage is empty
1080 1081 ip.run_line_magic('store', '-z')
1081 1082 ip.user_ns['var'] = 42
1082 1083 ip.run_line_magic('store', 'var')
1083 1084 ip.user_ns['var'] = 39
1084 1085 ip.run_line_magic('store', '-r')
1085 1086 nt.assert_equal(ip.user_ns['var'], 42)
1086 1087
1087 1088 ip.run_line_magic('store', '-d var')
1088 1089 ip.user_ns['var'] = 39
1089 1090 ip.run_line_magic('store' , '-r')
1090 1091 nt.assert_equal(ip.user_ns['var'], 39)
1091 1092
1092 1093
1093 1094 def _run_edit_test(arg_s, exp_filename=None,
1094 1095 exp_lineno=-1,
1095 1096 exp_contents=None,
1096 1097 exp_is_temp=None):
1097 1098 ip = get_ipython()
1098 1099 M = code.CodeMagics(ip)
1099 1100 last_call = ['','']
1100 1101 opts,args = M.parse_options(arg_s,'prxn:')
1101 1102 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1102 1103
1103 1104 if exp_filename is not None:
1104 1105 nt.assert_equal(exp_filename, filename)
1105 1106 if exp_contents is not None:
1106 1107 with io.open(filename, 'r', encoding='utf-8') as f:
1107 1108 contents = f.read()
1108 1109 nt.assert_equal(exp_contents, contents)
1109 1110 if exp_lineno != -1:
1110 1111 nt.assert_equal(exp_lineno, lineno)
1111 1112 if exp_is_temp is not None:
1112 1113 nt.assert_equal(exp_is_temp, is_temp)
1113 1114
1114 1115
1115 1116 def test_edit_interactive():
1116 1117 """%edit on interactively defined objects"""
1117 1118 ip = get_ipython()
1118 1119 n = ip.execution_count
1119 1120 ip.run_cell(u"def foo(): return 1", store_history=True)
1120 1121
1121 1122 try:
1122 1123 _run_edit_test("foo")
1123 1124 except code.InteractivelyDefined as e:
1124 1125 nt.assert_equal(e.index, n)
1125 1126 else:
1126 1127 raise AssertionError("Should have raised InteractivelyDefined")
1127 1128
1128 1129
1129 1130 def test_edit_cell():
1130 1131 """%edit [cell id]"""
1131 1132 ip = get_ipython()
1132 1133
1133 1134 ip.run_cell(u"def foo(): return 1", store_history=True)
1134 1135
1135 1136 # test
1136 1137 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1137 1138
1138 1139 def test_edit_fname():
1139 1140 """%edit file"""
1140 1141 # test
1141 1142 _run_edit_test("test file.py", exp_filename="test file.py")
1142 1143
1143 1144 def test_bookmark():
1144 1145 ip = get_ipython()
1145 1146 ip.run_line_magic('bookmark', 'bmname')
1146 1147 with tt.AssertPrints('bmname'):
1147 1148 ip.run_line_magic('bookmark', '-l')
1148 1149 ip.run_line_magic('bookmark', '-d bmname')
1149 1150
1150 1151 def test_ls_magic():
1151 1152 ip = get_ipython()
1152 1153 json_formatter = ip.display_formatter.formatters['application/json']
1153 1154 json_formatter.enabled = True
1154 1155 lsmagic = ip.magic('lsmagic')
1155 1156 with warnings.catch_warnings(record=True) as w:
1156 1157 j = json_formatter(lsmagic)
1157 1158 nt.assert_equal(sorted(j), ['cell', 'line'])
1158 1159 nt.assert_equal(w, []) # no warnings
1159 1160
1160 1161 def test_strip_initial_indent():
1161 1162 def sii(s):
1162 1163 lines = s.splitlines()
1163 1164 return '\n'.join(code.strip_initial_indent(lines))
1164 1165
1165 1166 nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2")
1166 1167 nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc")
1167 1168 nt.assert_equal(sii("a\n b"), "a\n b")
1168 1169
1169 1170 def test_logging_magic_quiet_from_arg():
1170 1171 _ip.config.LoggingMagics.quiet = False
1171 1172 lm = logging.LoggingMagics(shell=_ip)
1172 1173 with TemporaryDirectory() as td:
1173 1174 try:
1174 1175 with tt.AssertNotPrints(re.compile("Activating.*")):
1175 1176 lm.logstart('-q {}'.format(
1176 1177 os.path.join(td, "quiet_from_arg.log")))
1177 1178 finally:
1178 1179 _ip.logger.logstop()
1179 1180
1180 1181 def test_logging_magic_quiet_from_config():
1181 1182 _ip.config.LoggingMagics.quiet = True
1182 1183 lm = logging.LoggingMagics(shell=_ip)
1183 1184 with TemporaryDirectory() as td:
1184 1185 try:
1185 1186 with tt.AssertNotPrints(re.compile("Activating.*")):
1186 1187 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1187 1188 finally:
1188 1189 _ip.logger.logstop()
1189 1190
1190 1191
1191 1192 def test_logging_magic_not_quiet():
1192 1193 _ip.config.LoggingMagics.quiet = False
1193 1194 lm = logging.LoggingMagics(shell=_ip)
1194 1195 with TemporaryDirectory() as td:
1195 1196 try:
1196 1197 with tt.AssertPrints(re.compile("Activating.*")):
1197 1198 lm.logstart(os.path.join(td, "not_quiet.log"))
1198 1199 finally:
1199 1200 _ip.logger.logstop()
1200 1201
1201 1202
1202 1203 def test_time_no_var_expand():
1203 1204 _ip.user_ns['a'] = 5
1204 1205 _ip.user_ns['b'] = []
1205 1206 _ip.magic('time b.append("{a}")')
1206 1207 assert _ip.user_ns['b'] == ['{a}']
1207 1208
1208 1209
1209 1210 # this is slow, put at the end for local testing.
1210 1211 def test_timeit_arguments():
1211 1212 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1212 1213 if sys.version_info < (3,7):
1213 1214 _ip.magic("timeit -n1 -r1 ('#')")
1214 1215 else:
1215 1216 # 3.7 optimize no-op statement like above out, and complain there is
1216 1217 # nothing in the for loop.
1217 1218 _ip.magic("timeit -n1 -r1 a=('#')")
1218 1219
1219 1220
1220 1221 TEST_MODULE = """
1221 1222 print('Loaded my_tmp')
1222 1223 if __name__ == "__main__":
1223 1224 print('I just ran a script')
1224 1225 """
1225 1226
1226 1227
1227 1228 def test_run_module_from_import_hook():
1228 1229 "Test that a module can be loaded via an import hook"
1229 1230 with TemporaryDirectory() as tmpdir:
1230 1231 fullpath = os.path.join(tmpdir, 'my_tmp.py')
1231 1232 Path(fullpath).write_text(TEST_MODULE)
1232 1233
1233 1234 class MyTempImporter(object):
1234 1235 def __init__(self):
1235 1236 pass
1236 1237
1237 1238 def find_module(self, fullname, path=None):
1238 1239 if 'my_tmp' in fullname:
1239 1240 return self
1240 1241 return None
1241 1242
1242 1243 def load_module(self, name):
1243 1244 import imp
1244 1245 return imp.load_source('my_tmp', fullpath)
1245 1246
1246 1247 def get_code(self, fullname):
1247 1248 return compile(Path(fullpath).read_text(), "foo", "exec")
1248 1249
1249 1250 def is_package(self, __):
1250 1251 return False
1251 1252
1252 1253 sys.meta_path.insert(0, MyTempImporter())
1253 1254
1254 1255 with capture_output() as captured:
1255 1256 _ip.magic("run -m my_tmp")
1256 1257 _ip.run_cell("import my_tmp")
1257 1258
1258 1259 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1259 1260 nt.assert_equal(output, captured.stdout)
1260 1261
1261 1262 sys.meta_path.pop(0)
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now