##// END OF EJS Templates
Merge branch 'main' into enhancement/cover-cases-where-frame-is-built-object
HoonCheol Shin -
r28169:49925522 merge
parent child Browse files
Show More

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

@@ -1,83 +1,89 b''
1 name: Run tests
1 name: Run tests
2
2
3 on:
3 on:
4 push:
4 push:
5 branches:
5 branches:
6 - main
6 - main
7 - '*.x'
7 - '*.x'
8 pull_request:
8 pull_request:
9 # Run weekly on Monday at 1:23 UTC
9 # Run weekly on Monday at 1:23 UTC
10 schedule:
10 schedule:
11 - cron: '23 1 * * 1'
11 - cron: '23 1 * * 1'
12 workflow_dispatch:
12 workflow_dispatch:
13
13
14
14
15 jobs:
15 jobs:
16 test:
16 test:
17 runs-on: ${{ matrix.os }}
17 runs-on: ${{ matrix.os }}
18 strategy:
18 strategy:
19 fail-fast: false
19 fail-fast: false
20 matrix:
20 matrix:
21 os: [ubuntu-latest, windows-latest]
21 os: [ubuntu-latest, windows-latest]
22 python-version: ["3.8", "3.9", "3.10", "3.11"]
22 python-version: ["3.8", "3.9", "3.10", "3.11"]
23 deps: [test_extra]
23 deps: [test_extra]
24 # Test all on ubuntu, test ends on macos
24 # Test all on ubuntu, test ends on macos
25 include:
25 include:
26 - os: macos-latest
26 - os: macos-latest
27 python-version: "3.8"
27 python-version: "3.8"
28 deps: test_extra
28 deps: test_extra
29 - os: macos-latest
29 - os: macos-latest
30 python-version: "3.11"
30 python-version: "3.11"
31 deps: test_extra
31 deps: test_extra
32 # Tests minimal dependencies set
32 # Tests minimal dependencies set
33 - os: ubuntu-latest
33 - os: ubuntu-latest
34 python-version: "3.11"
34 python-version: "3.11"
35 deps: test
35 deps: test
36 # Tests latest development Python version
36 # Tests latest development Python version
37 - os: ubuntu-latest
37 - os: ubuntu-latest
38 python-version: "3.12-dev"
38 python-version: "3.12-dev"
39 deps: test
39 deps: test
40 # Installing optional dependencies stuff takes ages on PyPy
40 # Installing optional dependencies stuff takes ages on PyPy
41 - os: ubuntu-latest
41 - os: ubuntu-latest
42 python-version: "pypy-3.8"
42 python-version: "pypy-3.8"
43 deps: test
43 deps: test
44 - os: windows-latest
44 - os: windows-latest
45 python-version: "pypy-3.8"
45 python-version: "pypy-3.8"
46 deps: test
46 deps: test
47 - os: macos-latest
47 - os: macos-latest
48 python-version: "pypy-3.8"
48 python-version: "pypy-3.8"
49 deps: test
49 deps: test
50
50
51 steps:
51 steps:
52 - uses: actions/checkout@v3
52 - uses: actions/checkout@v3
53 - name: Set up Python ${{ matrix.python-version }}
53 - name: Set up Python ${{ matrix.python-version }}
54 uses: actions/setup-python@v4
54 uses: actions/setup-python@v4
55 with:
55 with:
56 python-version: ${{ matrix.python-version }}
56 python-version: ${{ matrix.python-version }}
57 cache: pip
57 cache: pip
58 - name: Install latex
58 - name: Install latex
59 if: runner.os == 'Linux' && matrix.deps == 'test_extra'
59 if: runner.os == 'Linux' && matrix.deps == 'test_extra'
60 run: echo "disable latex for now, issues in mirros" #sudo apt-get -yq -o Acquire::Retries=3 --no-install-suggests --no-install-recommends install texlive dvipng
60 run: echo "disable latex for now, issues in mirros" #sudo apt-get -yq -o Acquire::Retries=3 --no-install-suggests --no-install-recommends install texlive dvipng
61 - name: Install and update Python dependencies
61 - name: Install and update Python dependencies
62 run: |
62 run: |
63 python -m pip install --upgrade pip setuptools wheel build
63 python -m pip install --upgrade pip setuptools wheel build
64 python -m pip install --upgrade -e .[${{ matrix.deps }}]
64 python -m pip install --upgrade -e .[${{ matrix.deps }}]
65 python -m pip install --upgrade check-manifest pytest-cov
65 python -m pip install --upgrade check-manifest pytest-cov pytest-json-report
66 - name: Try building with Python build
66 - name: Try building with Python build
67 if: runner.os != 'Windows' # setup.py does not support sdist on Windows
67 if: runner.os != 'Windows' # setup.py does not support sdist on Windows
68 run: |
68 run: |
69 python -m build
69 python -m build
70 shasum -a 256 dist/*
70 shasum -a 256 dist/*
71 - name: Check manifest
71 - name: Check manifest
72 if: runner.os != 'Windows' # setup.py does not support sdist on Windows
72 if: runner.os != 'Windows' # setup.py does not support sdist on Windows
73 run: check-manifest
73 run: check-manifest
74 - name: pytest
74 - name: pytest
75 env:
75 env:
76 COLUMNS: 120
76 COLUMNS: 120
77 run: |
77 run: |
78 pytest --color=yes -raXxs ${{ startsWith(matrix.python-version, 'pypy') && ' ' || '--cov --cov-report=xml' }}
78 pytest --color=yes -raXxs ${{ startsWith(matrix.python-version, 'pypy') && ' ' || '--cov --cov-report=xml' }} --json-report --json-report-file=./report-${{ matrix.python-version }}-${{runner.os}}.json
79 - uses: actions/upload-artifact@v3
80 with:
81 name: upload pytest timing reports as json
82 path: |
83 ./report-*.json
84
79 - name: Upload coverage to Codecov
85 - name: Upload coverage to Codecov
80 uses: codecov/codecov-action@v3
86 uses: codecov/codecov-action@v3
81 with:
87 with:
82 name: Test
88 name: Test
83 files: /home/runner/work/ipython/ipython/coverage.xml
89 files: /home/runner/work/ipython/ipython/coverage.xml
@@ -1,965 +1,968 b''
1 """ History related magics and functionality """
1 """ History related magics and functionality """
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6
6
7 import atexit
7 import atexit
8 import datetime
8 import datetime
9 from pathlib import Path
9 from pathlib import Path
10 import re
10 import re
11 import sqlite3
11 import sqlite3
12 import threading
12 import threading
13
13
14 from traitlets.config.configurable import LoggingConfigurable
14 from traitlets.config.configurable import LoggingConfigurable
15 from decorator import decorator
15 from decorator import decorator
16 from IPython.utils.decorators import undoc
16 from IPython.utils.decorators import undoc
17 from IPython.paths import locate_profile
17 from IPython.paths import locate_profile
18 from traitlets import (
18 from traitlets import (
19 Any,
19 Any,
20 Bool,
20 Bool,
21 Dict,
21 Dict,
22 Instance,
22 Instance,
23 Integer,
23 Integer,
24 List,
24 List,
25 Unicode,
25 Unicode,
26 Union,
26 Union,
27 TraitError,
27 TraitError,
28 default,
28 default,
29 observe,
29 observe,
30 )
30 )
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Classes and functions
33 # Classes and functions
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36 @undoc
36 @undoc
37 class DummyDB(object):
37 class DummyDB(object):
38 """Dummy DB that will act as a black hole for history.
38 """Dummy DB that will act as a black hole for history.
39
39
40 Only used in the absence of sqlite"""
40 Only used in the absence of sqlite"""
41 def execute(*args, **kwargs):
41 def execute(*args, **kwargs):
42 return []
42 return []
43
43
44 def commit(self, *args, **kwargs):
44 def commit(self, *args, **kwargs):
45 pass
45 pass
46
46
47 def __enter__(self, *args, **kwargs):
47 def __enter__(self, *args, **kwargs):
48 pass
48 pass
49
49
50 def __exit__(self, *args, **kwargs):
50 def __exit__(self, *args, **kwargs):
51 pass
51 pass
52
52
53
53
54 @decorator
54 @decorator
55 def only_when_enabled(f, self, *a, **kw):
55 def only_when_enabled(f, self, *a, **kw):
56 """Decorator: return an empty list in the absence of sqlite."""
56 """Decorator: return an empty list in the absence of sqlite."""
57 if not self.enabled:
57 if not self.enabled:
58 return []
58 return []
59 else:
59 else:
60 return f(self, *a, **kw)
60 return f(self, *a, **kw)
61
61
62
62
63 # use 16kB as threshold for whether a corrupt history db should be saved
63 # use 16kB as threshold for whether a corrupt history db should be saved
64 # that should be at least 100 entries or so
64 # that should be at least 100 entries or so
65 _SAVE_DB_SIZE = 16384
65 _SAVE_DB_SIZE = 16384
66
66
67 @decorator
67 @decorator
68 def catch_corrupt_db(f, self, *a, **kw):
68 def catch_corrupt_db(f, self, *a, **kw):
69 """A decorator which wraps HistoryAccessor method calls to catch errors from
69 """A decorator which wraps HistoryAccessor method calls to catch errors from
70 a corrupt SQLite database, move the old database out of the way, and create
70 a corrupt SQLite database, move the old database out of the way, and create
71 a new one.
71 a new one.
72
72
73 We avoid clobbering larger databases because this may be triggered due to filesystem issues,
73 We avoid clobbering larger databases because this may be triggered due to filesystem issues,
74 not just a corrupt file.
74 not just a corrupt file.
75 """
75 """
76 try:
76 try:
77 return f(self, *a, **kw)
77 return f(self, *a, **kw)
78 except (sqlite3.DatabaseError, sqlite3.OperationalError) as e:
78 except (sqlite3.DatabaseError, sqlite3.OperationalError) as e:
79 self._corrupt_db_counter += 1
79 self._corrupt_db_counter += 1
80 self.log.error("Failed to open SQLite history %s (%s).", self.hist_file, e)
80 self.log.error("Failed to open SQLite history %s (%s).", self.hist_file, e)
81 if self.hist_file != ':memory:':
81 if self.hist_file != ':memory:':
82 if self._corrupt_db_counter > self._corrupt_db_limit:
82 if self._corrupt_db_counter > self._corrupt_db_limit:
83 self.hist_file = ':memory:'
83 self.hist_file = ':memory:'
84 self.log.error("Failed to load history too many times, history will not be saved.")
84 self.log.error("Failed to load history too many times, history will not be saved.")
85 elif self.hist_file.is_file():
85 elif self.hist_file.is_file():
86 # move the file out of the way
86 # move the file out of the way
87 base = str(self.hist_file.parent / self.hist_file.stem)
87 base = str(self.hist_file.parent / self.hist_file.stem)
88 ext = self.hist_file.suffix
88 ext = self.hist_file.suffix
89 size = self.hist_file.stat().st_size
89 size = self.hist_file.stat().st_size
90 if size >= _SAVE_DB_SIZE:
90 if size >= _SAVE_DB_SIZE:
91 # if there's significant content, avoid clobbering
91 # if there's significant content, avoid clobbering
92 now = datetime.datetime.now().isoformat().replace(':', '.')
92 now = datetime.datetime.now().isoformat().replace(':', '.')
93 newpath = base + '-corrupt-' + now + ext
93 newpath = base + '-corrupt-' + now + ext
94 # don't clobber previous corrupt backups
94 # don't clobber previous corrupt backups
95 for i in range(100):
95 for i in range(100):
96 if not Path(newpath).exists():
96 if not Path(newpath).exists():
97 break
97 break
98 else:
98 else:
99 newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext
99 newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext
100 else:
100 else:
101 # not much content, possibly empty; don't worry about clobbering
101 # not much content, possibly empty; don't worry about clobbering
102 # maybe we should just delete it?
102 # maybe we should just delete it?
103 newpath = base + '-corrupt' + ext
103 newpath = base + '-corrupt' + ext
104 self.hist_file.rename(newpath)
104 self.hist_file.rename(newpath)
105 self.log.error("History file was moved to %s and a new file created.", newpath)
105 self.log.error("History file was moved to %s and a new file created.", newpath)
106 self.init_db()
106 self.init_db()
107 return []
107 return []
108 else:
108 else:
109 # Failed with :memory:, something serious is wrong
109 # Failed with :memory:, something serious is wrong
110 raise
110 raise
111
111
112
112
113 class HistoryAccessorBase(LoggingConfigurable):
113 class HistoryAccessorBase(LoggingConfigurable):
114 """An abstract class for History Accessors """
114 """An abstract class for History Accessors """
115
115
116 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
116 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
117 raise NotImplementedError
117 raise NotImplementedError
118
118
119 def search(self, pattern="*", raw=True, search_raw=True,
119 def search(self, pattern="*", raw=True, search_raw=True,
120 output=False, n=None, unique=False):
120 output=False, n=None, unique=False):
121 raise NotImplementedError
121 raise NotImplementedError
122
122
123 def get_range(self, session, start=1, stop=None, raw=True,output=False):
123 def get_range(self, session, start=1, stop=None, raw=True,output=False):
124 raise NotImplementedError
124 raise NotImplementedError
125
125
126 def get_range_by_str(self, rangestr, raw=True, output=False):
126 def get_range_by_str(self, rangestr, raw=True, output=False):
127 raise NotImplementedError
127 raise NotImplementedError
128
128
129
129
130 class HistoryAccessor(HistoryAccessorBase):
130 class HistoryAccessor(HistoryAccessorBase):
131 """Access the history database without adding to it.
131 """Access the history database without adding to it.
132
132
133 This is intended for use by standalone history tools. IPython shells use
133 This is intended for use by standalone history tools. IPython shells use
134 HistoryManager, below, which is a subclass of this."""
134 HistoryManager, below, which is a subclass of this."""
135
135
136 # counter for init_db retries, so we don't keep trying over and over
136 # counter for init_db retries, so we don't keep trying over and over
137 _corrupt_db_counter = 0
137 _corrupt_db_counter = 0
138 # after two failures, fallback on :memory:
138 # after two failures, fallback on :memory:
139 _corrupt_db_limit = 2
139 _corrupt_db_limit = 2
140
140
141 # String holding the path to the history file
141 # String holding the path to the history file
142 hist_file = Union(
142 hist_file = Union(
143 [Instance(Path), Unicode()],
143 [Instance(Path), Unicode()],
144 help="""Path to file to use for SQLite history database.
144 help="""Path to file to use for SQLite history database.
145
145
146 By default, IPython will put the history database in the IPython
146 By default, IPython will put the history database in the IPython
147 profile directory. If you would rather share one history among
147 profile directory. If you would rather share one history among
148 profiles, you can set this value in each, so that they are consistent.
148 profiles, you can set this value in each, so that they are consistent.
149
149
150 Due to an issue with fcntl, SQLite is known to misbehave on some NFS
150 Due to an issue with fcntl, SQLite is known to misbehave on some NFS
151 mounts. If you see IPython hanging, try setting this to something on a
151 mounts. If you see IPython hanging, try setting this to something on a
152 local disk, e.g::
152 local disk, e.g::
153
153
154 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
154 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
155
155
156 you can also use the specific value `:memory:` (including the colon
156 you can also use the specific value `:memory:` (including the colon
157 at both end but not the back ticks), to avoid creating an history file.
157 at both end but not the back ticks), to avoid creating an history file.
158
158
159 """,
159 """,
160 ).tag(config=True)
160 ).tag(config=True)
161
161
162 enabled = Bool(True,
162 enabled = Bool(True,
163 help="""enable the SQLite history
163 help="""enable the SQLite history
164
164
165 set enabled=False to disable the SQLite history,
165 set enabled=False to disable the SQLite history,
166 in which case there will be no stored history, no SQLite connection,
166 in which case there will be no stored history, no SQLite connection,
167 and no background saving thread. This may be necessary in some
167 and no background saving thread. This may be necessary in some
168 threaded environments where IPython is embedded.
168 threaded environments where IPython is embedded.
169 """,
169 """,
170 ).tag(config=True)
170 ).tag(config=True)
171
171
172 connection_options = Dict(
172 connection_options = Dict(
173 help="""Options for configuring the SQLite connection
173 help="""Options for configuring the SQLite connection
174
174
175 These options are passed as keyword args to sqlite3.connect
175 These options are passed as keyword args to sqlite3.connect
176 when establishing database connections.
176 when establishing database connections.
177 """
177 """
178 ).tag(config=True)
178 ).tag(config=True)
179
179
180 # The SQLite database
180 # The SQLite database
181 db = Any()
181 db = Any()
182 @observe('db')
182 @observe('db')
183 def _db_changed(self, change):
183 def _db_changed(self, change):
184 """validate the db, since it can be an Instance of two different types"""
184 """validate the db, since it can be an Instance of two different types"""
185 new = change['new']
185 new = change['new']
186 connection_types = (DummyDB, sqlite3.Connection)
186 connection_types = (DummyDB, sqlite3.Connection)
187 if not isinstance(new, connection_types):
187 if not isinstance(new, connection_types):
188 msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
188 msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
189 (self.__class__.__name__, new)
189 (self.__class__.__name__, new)
190 raise TraitError(msg)
190 raise TraitError(msg)
191
191
192 def __init__(self, profile="default", hist_file="", **traits):
192 def __init__(self, profile="default", hist_file="", **traits):
193 """Create a new history accessor.
193 """Create a new history accessor.
194
194
195 Parameters
195 Parameters
196 ----------
196 ----------
197 profile : str
197 profile : str
198 The name of the profile from which to open history.
198 The name of the profile from which to open history.
199 hist_file : str
199 hist_file : str
200 Path to an SQLite history database stored by IPython. If specified,
200 Path to an SQLite history database stored by IPython. If specified,
201 hist_file overrides profile.
201 hist_file overrides profile.
202 config : :class:`~traitlets.config.loader.Config`
202 config : :class:`~traitlets.config.loader.Config`
203 Config object. hist_file can also be set through this.
203 Config object. hist_file can also be set through this.
204 """
204 """
205 super(HistoryAccessor, self).__init__(**traits)
205 super(HistoryAccessor, self).__init__(**traits)
206 # defer setting hist_file from kwarg until after init,
206 # defer setting hist_file from kwarg until after init,
207 # otherwise the default kwarg value would clobber any value
207 # otherwise the default kwarg value would clobber any value
208 # set by config
208 # set by config
209 if hist_file:
209 if hist_file:
210 self.hist_file = hist_file
210 self.hist_file = hist_file
211
211
212 try:
212 try:
213 self.hist_file
213 self.hist_file
214 except TraitError:
214 except TraitError:
215 # No one has set the hist_file, yet.
215 # No one has set the hist_file, yet.
216 self.hist_file = self._get_hist_file_name(profile)
216 self.hist_file = self._get_hist_file_name(profile)
217
217
218 self.init_db()
218 self.init_db()
219
219
220 def _get_hist_file_name(self, profile='default'):
220 def _get_hist_file_name(self, profile='default'):
221 """Find the history file for the given profile name.
221 """Find the history file for the given profile name.
222
222
223 This is overridden by the HistoryManager subclass, to use the shell's
223 This is overridden by the HistoryManager subclass, to use the shell's
224 active profile.
224 active profile.
225
225
226 Parameters
226 Parameters
227 ----------
227 ----------
228 profile : str
228 profile : str
229 The name of a profile which has a history file.
229 The name of a profile which has a history file.
230 """
230 """
231 return Path(locate_profile(profile)) / "history.sqlite"
231 return Path(locate_profile(profile)) / "history.sqlite"
232
232
233 @catch_corrupt_db
233 @catch_corrupt_db
234 def init_db(self):
234 def init_db(self):
235 """Connect to the database, and create tables if necessary."""
235 """Connect to the database, and create tables if necessary."""
236 if not self.enabled:
236 if not self.enabled:
237 self.db = DummyDB()
237 self.db = DummyDB()
238 return
238 return
239
239
240 # use detect_types so that timestamps return datetime objects
240 # use detect_types so that timestamps return datetime objects
241 kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
241 kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
242 kwargs.update(self.connection_options)
242 kwargs.update(self.connection_options)
243 self.db = sqlite3.connect(str(self.hist_file), **kwargs)
243 self.db = sqlite3.connect(str(self.hist_file), **kwargs)
244 with self.db:
244 with self.db:
245 self.db.execute(
245 self.db.execute(
246 """CREATE TABLE IF NOT EXISTS sessions (session integer
246 """CREATE TABLE IF NOT EXISTS sessions (session integer
247 primary key autoincrement, start timestamp,
247 primary key autoincrement, start timestamp,
248 end timestamp, num_cmds integer, remark text)"""
248 end timestamp, num_cmds integer, remark text)"""
249 )
249 )
250 self.db.execute(
250 self.db.execute(
251 """CREATE TABLE IF NOT EXISTS history
251 """CREATE TABLE IF NOT EXISTS history
252 (session integer, line integer, source text, source_raw text,
252 (session integer, line integer, source text, source_raw text,
253 PRIMARY KEY (session, line))"""
253 PRIMARY KEY (session, line))"""
254 )
254 )
255 # Output history is optional, but ensure the table's there so it can be
255 # Output history is optional, but ensure the table's there so it can be
256 # enabled later.
256 # enabled later.
257 self.db.execute(
257 self.db.execute(
258 """CREATE TABLE IF NOT EXISTS output_history
258 """CREATE TABLE IF NOT EXISTS output_history
259 (session integer, line integer, output text,
259 (session integer, line integer, output text,
260 PRIMARY KEY (session, line))"""
260 PRIMARY KEY (session, line))"""
261 )
261 )
262 # success! reset corrupt db count
262 # success! reset corrupt db count
263 self._corrupt_db_counter = 0
263 self._corrupt_db_counter = 0
264
264
265 def writeout_cache(self):
265 def writeout_cache(self):
266 """Overridden by HistoryManager to dump the cache before certain
266 """Overridden by HistoryManager to dump the cache before certain
267 database lookups."""
267 database lookups."""
268 pass
268 pass
269
269
270 ## -------------------------------
270 ## -------------------------------
271 ## Methods for retrieving history:
271 ## Methods for retrieving history:
272 ## -------------------------------
272 ## -------------------------------
273 def _run_sql(self, sql, params, raw=True, output=False, latest=False):
273 def _run_sql(self, sql, params, raw=True, output=False, latest=False):
274 """Prepares and runs an SQL query for the history database.
274 """Prepares and runs an SQL query for the history database.
275
275
276 Parameters
276 Parameters
277 ----------
277 ----------
278 sql : str
278 sql : str
279 Any filtering expressions to go after SELECT ... FROM ...
279 Any filtering expressions to go after SELECT ... FROM ...
280 params : tuple
280 params : tuple
281 Parameters passed to the SQL query (to replace "?")
281 Parameters passed to the SQL query (to replace "?")
282 raw, output : bool
282 raw, output : bool
283 See :meth:`get_range`
283 See :meth:`get_range`
284 latest : bool
284 latest : bool
285 Select rows with max (session, line)
285 Select rows with max (session, line)
286
286
287 Returns
287 Returns
288 -------
288 -------
289 Tuples as :meth:`get_range`
289 Tuples as :meth:`get_range`
290 """
290 """
291 toget = 'source_raw' if raw else 'source'
291 toget = 'source_raw' if raw else 'source'
292 sqlfrom = "history"
292 sqlfrom = "history"
293 if output:
293 if output:
294 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
294 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
295 toget = "history.%s, output_history.output" % toget
295 toget = "history.%s, output_history.output" % toget
296 if latest:
296 if latest:
297 toget += ", MAX(session * 128 * 1024 + line)"
297 toget += ", MAX(session * 128 * 1024 + line)"
298 this_querry = "SELECT session, line, %s FROM %s " % (toget, sqlfrom) + sql
298 this_querry = "SELECT session, line, %s FROM %s " % (toget, sqlfrom) + sql
299 cur = self.db.execute(this_querry, params)
299 cur = self.db.execute(this_querry, params)
300 if latest:
300 if latest:
301 cur = (row[:-1] for row in cur)
301 cur = (row[:-1] for row in cur)
302 if output: # Regroup into 3-tuples, and parse JSON
302 if output: # Regroup into 3-tuples, and parse JSON
303 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
303 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
304 return cur
304 return cur
305
305
306 @only_when_enabled
306 @only_when_enabled
307 @catch_corrupt_db
307 @catch_corrupt_db
308 def get_session_info(self, session):
308 def get_session_info(self, session):
309 """Get info about a session.
309 """Get info about a session.
310
310
311 Parameters
311 Parameters
312 ----------
312 ----------
313 session : int
313 session : int
314 Session number to retrieve.
314 Session number to retrieve.
315
315
316 Returns
316 Returns
317 -------
317 -------
318 session_id : int
318 session_id : int
319 Session ID number
319 Session ID number
320 start : datetime
320 start : datetime
321 Timestamp for the start of the session.
321 Timestamp for the start of the session.
322 end : datetime
322 end : datetime
323 Timestamp for the end of the session, or None if IPython crashed.
323 Timestamp for the end of the session, or None if IPython crashed.
324 num_cmds : int
324 num_cmds : int
325 Number of commands run, or None if IPython crashed.
325 Number of commands run, or None if IPython crashed.
326 remark : unicode
326 remark : unicode
327 A manually set description.
327 A manually set description.
328 """
328 """
329 query = "SELECT * from sessions where session == ?"
329 query = "SELECT * from sessions where session == ?"
330 return self.db.execute(query, (session,)).fetchone()
330 return self.db.execute(query, (session,)).fetchone()
331
331
332 @catch_corrupt_db
332 @catch_corrupt_db
333 def get_last_session_id(self):
333 def get_last_session_id(self):
334 """Get the last session ID currently in the database.
334 """Get the last session ID currently in the database.
335
335
336 Within IPython, this should be the same as the value stored in
336 Within IPython, this should be the same as the value stored in
337 :attr:`HistoryManager.session_number`.
337 :attr:`HistoryManager.session_number`.
338 """
338 """
339 for record in self.get_tail(n=1, include_latest=True):
339 for record in self.get_tail(n=1, include_latest=True):
340 return record[0]
340 return record[0]
341
341
342 @catch_corrupt_db
342 @catch_corrupt_db
343 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
343 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
344 """Get the last n lines from the history database.
344 """Get the last n lines from the history database.
345
345
346 Parameters
346 Parameters
347 ----------
347 ----------
348 n : int
348 n : int
349 The number of lines to get
349 The number of lines to get
350 raw, output : bool
350 raw, output : bool
351 See :meth:`get_range`
351 See :meth:`get_range`
352 include_latest : bool
352 include_latest : bool
353 If False (default), n+1 lines are fetched, and the latest one
353 If False (default), n+1 lines are fetched, and the latest one
354 is discarded. This is intended to be used where the function
354 is discarded. This is intended to be used where the function
355 is called by a user command, which it should not return.
355 is called by a user command, which it should not return.
356
356
357 Returns
357 Returns
358 -------
358 -------
359 Tuples as :meth:`get_range`
359 Tuples as :meth:`get_range`
360 """
360 """
361 self.writeout_cache()
361 self.writeout_cache()
362 if not include_latest:
362 if not include_latest:
363 n += 1
363 n += 1
364 cur = self._run_sql(
364 cur = self._run_sql(
365 "ORDER BY session DESC, line DESC LIMIT ?", (n,), raw=raw, output=output
365 "ORDER BY session DESC, line DESC LIMIT ?", (n,), raw=raw, output=output
366 )
366 )
367 if not include_latest:
367 if not include_latest:
368 return reversed(list(cur)[1:])
368 return reversed(list(cur)[1:])
369 return reversed(list(cur))
369 return reversed(list(cur))
370
370
371 @catch_corrupt_db
371 @catch_corrupt_db
372 def search(self, pattern="*", raw=True, search_raw=True,
372 def search(self, pattern="*", raw=True, search_raw=True,
373 output=False, n=None, unique=False):
373 output=False, n=None, unique=False):
374 """Search the database using unix glob-style matching (wildcards
374 """Search the database using unix glob-style matching (wildcards
375 * and ?).
375 * and ?).
376
376
377 Parameters
377 Parameters
378 ----------
378 ----------
379 pattern : str
379 pattern : str
380 The wildcarded pattern to match when searching
380 The wildcarded pattern to match when searching
381 search_raw : bool
381 search_raw : bool
382 If True, search the raw input, otherwise, the parsed input
382 If True, search the raw input, otherwise, the parsed input
383 raw, output : bool
383 raw, output : bool
384 See :meth:`get_range`
384 See :meth:`get_range`
385 n : None or int
385 n : None or int
386 If an integer is given, it defines the limit of
386 If an integer is given, it defines the limit of
387 returned entries.
387 returned entries.
388 unique : bool
388 unique : bool
389 When it is true, return only unique entries.
389 When it is true, return only unique entries.
390
390
391 Returns
391 Returns
392 -------
392 -------
393 Tuples as :meth:`get_range`
393 Tuples as :meth:`get_range`
394 """
394 """
395 tosearch = "source_raw" if search_raw else "source"
395 tosearch = "source_raw" if search_raw else "source"
396 if output:
396 if output:
397 tosearch = "history." + tosearch
397 tosearch = "history." + tosearch
398 self.writeout_cache()
398 self.writeout_cache()
399 sqlform = "WHERE %s GLOB ?" % tosearch
399 sqlform = "WHERE %s GLOB ?" % tosearch
400 params = (pattern,)
400 params = (pattern,)
401 if unique:
401 if unique:
402 sqlform += ' GROUP BY {0}'.format(tosearch)
402 sqlform += ' GROUP BY {0}'.format(tosearch)
403 if n is not None:
403 if n is not None:
404 sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
404 sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
405 params += (n,)
405 params += (n,)
406 elif unique:
406 elif unique:
407 sqlform += " ORDER BY session, line"
407 sqlform += " ORDER BY session, line"
408 cur = self._run_sql(sqlform, params, raw=raw, output=output, latest=unique)
408 cur = self._run_sql(sqlform, params, raw=raw, output=output, latest=unique)
409 if n is not None:
409 if n is not None:
410 return reversed(list(cur))
410 return reversed(list(cur))
411 return cur
411 return cur
412
412
413 @catch_corrupt_db
413 @catch_corrupt_db
414 def get_range(self, session, start=1, stop=None, raw=True,output=False):
414 def get_range(self, session, start=1, stop=None, raw=True,output=False):
415 """Retrieve input by session.
415 """Retrieve input by session.
416
416
417 Parameters
417 Parameters
418 ----------
418 ----------
419 session : int
419 session : int
420 Session number to retrieve.
420 Session number to retrieve.
421 start : int
421 start : int
422 First line to retrieve.
422 First line to retrieve.
423 stop : int
423 stop : int
424 End of line range (excluded from output itself). If None, retrieve
424 End of line range (excluded from output itself). If None, retrieve
425 to the end of the session.
425 to the end of the session.
426 raw : bool
426 raw : bool
427 If True, return untranslated input
427 If True, return untranslated input
428 output : bool
428 output : bool
429 If True, attempt to include output. This will be 'real' Python
429 If True, attempt to include output. This will be 'real' Python
430 objects for the current session, or text reprs from previous
430 objects for the current session, or text reprs from previous
431 sessions if db_log_output was enabled at the time. Where no output
431 sessions if db_log_output was enabled at the time. Where no output
432 is found, None is used.
432 is found, None is used.
433
433
434 Returns
434 Returns
435 -------
435 -------
436 entries
436 entries
437 An iterator over the desired lines. Each line is a 3-tuple, either
437 An iterator over the desired lines. Each line is a 3-tuple, either
438 (session, line, input) if output is False, or
438 (session, line, input) if output is False, or
439 (session, line, (input, output)) if output is True.
439 (session, line, (input, output)) if output is True.
440 """
440 """
441 if stop:
441 if stop:
442 lineclause = "line >= ? AND line < ?"
442 lineclause = "line >= ? AND line < ?"
443 params = (session, start, stop)
443 params = (session, start, stop)
444 else:
444 else:
445 lineclause = "line>=?"
445 lineclause = "line>=?"
446 params = (session, start)
446 params = (session, start)
447
447
448 return self._run_sql("WHERE session==? AND %s" % lineclause,
448 return self._run_sql("WHERE session==? AND %s" % lineclause,
449 params, raw=raw, output=output)
449 params, raw=raw, output=output)
450
450
451 def get_range_by_str(self, rangestr, raw=True, output=False):
451 def get_range_by_str(self, rangestr, raw=True, output=False):
452 """Get lines of history from a string of ranges, as used by magic
452 """Get lines of history from a string of ranges, as used by magic
453 commands %hist, %save, %macro, etc.
453 commands %hist, %save, %macro, etc.
454
454
455 Parameters
455 Parameters
456 ----------
456 ----------
457 rangestr : str
457 rangestr : str
458 A string specifying ranges, e.g. "5 ~2/1-4". If empty string is used,
458 A string specifying ranges, e.g. "5 ~2/1-4". If empty string is used,
459 this will return everything from current session's history.
459 this will return everything from current session's history.
460
460
461 See the documentation of :func:`%history` for the full details.
461 See the documentation of :func:`%history` for the full details.
462
462
463 raw, output : bool
463 raw, output : bool
464 As :meth:`get_range`
464 As :meth:`get_range`
465
465
466 Returns
466 Returns
467 -------
467 -------
468 Tuples as :meth:`get_range`
468 Tuples as :meth:`get_range`
469 """
469 """
470 for sess, s, e in extract_hist_ranges(rangestr):
470 for sess, s, e in extract_hist_ranges(rangestr):
471 for line in self.get_range(sess, s, e, raw=raw, output=output):
471 for line in self.get_range(sess, s, e, raw=raw, output=output):
472 yield line
472 yield line
473
473
474
474
475 class HistoryManager(HistoryAccessor):
475 class HistoryManager(HistoryAccessor):
476 """A class to organize all history-related functionality in one place.
476 """A class to organize all history-related functionality in one place.
477 """
477 """
478 # Public interface
478 # Public interface
479
479
480 # An instance of the IPython shell we are attached to
480 # An instance of the IPython shell we are attached to
481 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
481 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
482 allow_none=True)
482 allow_none=True)
483 # Lists to hold processed and raw history. These start with a blank entry
483 # Lists to hold processed and raw history. These start with a blank entry
484 # so that we can index them starting from 1
484 # so that we can index them starting from 1
485 input_hist_parsed = List([""])
485 input_hist_parsed = List([""])
486 input_hist_raw = List([""])
486 input_hist_raw = List([""])
487 # A list of directories visited during session
487 # A list of directories visited during session
488 dir_hist = List()
488 dir_hist = List()
489 @default('dir_hist')
489 @default('dir_hist')
490 def _dir_hist_default(self):
490 def _dir_hist_default(self):
491 try:
491 try:
492 return [Path.cwd()]
492 return [Path.cwd()]
493 except OSError:
493 except OSError:
494 return []
494 return []
495
495
496 # A dict of output history, keyed with ints from the shell's
496 # A dict of output history, keyed with ints from the shell's
497 # execution count.
497 # execution count.
498 output_hist = Dict()
498 output_hist = Dict()
499 # The text/plain repr of outputs.
499 # The text/plain repr of outputs.
500 output_hist_reprs = Dict()
500 output_hist_reprs = Dict()
501
501
502 # The number of the current session in the history database
502 # The number of the current session in the history database
503 session_number = Integer()
503 session_number = Integer()
504
504
505 db_log_output = Bool(False,
505 db_log_output = Bool(False,
506 help="Should the history database include output? (default: no)"
506 help="Should the history database include output? (default: no)"
507 ).tag(config=True)
507 ).tag(config=True)
508 db_cache_size = Integer(0,
508 db_cache_size = Integer(0,
509 help="Write to database every x commands (higher values save disk access & power).\n"
509 help="Write to database every x commands (higher values save disk access & power).\n"
510 "Values of 1 or less effectively disable caching."
510 "Values of 1 or less effectively disable caching."
511 ).tag(config=True)
511 ).tag(config=True)
512 # The input and output caches
512 # The input and output caches
513 db_input_cache = List()
513 db_input_cache = List()
514 db_output_cache = List()
514 db_output_cache = List()
515
515
516 # History saving in separate thread
516 # History saving in separate thread
517 save_thread = Instance('IPython.core.history.HistorySavingThread',
517 save_thread = Instance('IPython.core.history.HistorySavingThread',
518 allow_none=True)
518 allow_none=True)
519 save_flag = Instance(threading.Event, allow_none=True)
519 save_flag = Instance(threading.Event, allow_none=True)
520
520
521 # Private interface
521 # Private interface
522 # Variables used to store the three last inputs from the user. On each new
522 # Variables used to store the three last inputs from the user. On each new
523 # history update, we populate the user's namespace with these, shifted as
523 # history update, we populate the user's namespace with these, shifted as
524 # necessary.
524 # necessary.
525 _i00 = Unicode(u'')
525 _i00 = Unicode(u'')
526 _i = Unicode(u'')
526 _i = Unicode(u'')
527 _ii = Unicode(u'')
527 _ii = Unicode(u'')
528 _iii = Unicode(u'')
528 _iii = Unicode(u'')
529
529
530 # A regex matching all forms of the exit command, so that we don't store
530 # A regex matching all forms of the exit command, so that we don't store
531 # them in the history (it's annoying to rewind the first entry and land on
531 # them in the history (it's annoying to rewind the first entry and land on
532 # an exit call).
532 # an exit call).
533 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
533 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
534
534
535 def __init__(self, shell=None, config=None, **traits):
535 def __init__(self, shell=None, config=None, **traits):
536 """Create a new history manager associated with a shell instance.
536 """Create a new history manager associated with a shell instance.
537 """
537 """
538 super(HistoryManager, self).__init__(shell=shell, config=config,
538 super(HistoryManager, self).__init__(shell=shell, config=config,
539 **traits)
539 **traits)
540 self.save_flag = threading.Event()
540 self.save_flag = threading.Event()
541 self.db_input_cache_lock = threading.Lock()
541 self.db_input_cache_lock = threading.Lock()
542 self.db_output_cache_lock = threading.Lock()
542 self.db_output_cache_lock = threading.Lock()
543
543
544 try:
544 try:
545 self.new_session()
545 self.new_session()
546 except sqlite3.OperationalError:
546 except sqlite3.OperationalError:
547 self.log.error("Failed to create history session in %s. History will not be saved.",
547 self.log.error("Failed to create history session in %s. History will not be saved.",
548 self.hist_file, exc_info=True)
548 self.hist_file, exc_info=True)
549 self.hist_file = ':memory:'
549 self.hist_file = ':memory:'
550
550
551 if self.enabled and self.hist_file != ':memory:':
551 if self.enabled and self.hist_file != ':memory:':
552 self.save_thread = HistorySavingThread(self)
552 self.save_thread = HistorySavingThread(self)
553 self.save_thread.start()
553 self.save_thread.start()
554
554
555 def _get_hist_file_name(self, profile=None):
555 def _get_hist_file_name(self, profile=None):
556 """Get default history file name based on the Shell's profile.
556 """Get default history file name based on the Shell's profile.
557
557
558 The profile parameter is ignored, but must exist for compatibility with
558 The profile parameter is ignored, but must exist for compatibility with
559 the parent class."""
559 the parent class."""
560 profile_dir = self.shell.profile_dir.location
560 profile_dir = self.shell.profile_dir.location
561 return Path(profile_dir) / "history.sqlite"
561 return Path(profile_dir) / "history.sqlite"
562
562
563 @only_when_enabled
563 @only_when_enabled
564 def new_session(self, conn=None):
564 def new_session(self, conn=None):
565 """Get a new session number."""
565 """Get a new session number."""
566 if conn is None:
566 if conn is None:
567 conn = self.db
567 conn = self.db
568
568
569 with conn:
569 with conn:
570 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
570 cur = conn.execute(
571 NULL, "") """, (datetime.datetime.now(),))
571 """INSERT INTO sessions VALUES (NULL, ?, NULL,
572 NULL, '') """,
573 (datetime.datetime.now(),),
574 )
572 self.session_number = cur.lastrowid
575 self.session_number = cur.lastrowid
573
576
574 def end_session(self):
577 def end_session(self):
575 """Close the database session, filling in the end time and line count."""
578 """Close the database session, filling in the end time and line count."""
576 self.writeout_cache()
579 self.writeout_cache()
577 with self.db:
580 with self.db:
578 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
581 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
579 session==?""", (datetime.datetime.now(),
582 session==?""", (datetime.datetime.now(),
580 len(self.input_hist_parsed)-1, self.session_number))
583 len(self.input_hist_parsed)-1, self.session_number))
581 self.session_number = 0
584 self.session_number = 0
582
585
583 def name_session(self, name):
586 def name_session(self, name):
584 """Give the current session a name in the history database."""
587 """Give the current session a name in the history database."""
585 with self.db:
588 with self.db:
586 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
589 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
587 (name, self.session_number))
590 (name, self.session_number))
588
591
589 def reset(self, new_session=True):
592 def reset(self, new_session=True):
590 """Clear the session history, releasing all object references, and
593 """Clear the session history, releasing all object references, and
591 optionally open a new session."""
594 optionally open a new session."""
592 self.output_hist.clear()
595 self.output_hist.clear()
593 # The directory history can't be completely empty
596 # The directory history can't be completely empty
594 self.dir_hist[:] = [Path.cwd()]
597 self.dir_hist[:] = [Path.cwd()]
595
598
596 if new_session:
599 if new_session:
597 if self.session_number:
600 if self.session_number:
598 self.end_session()
601 self.end_session()
599 self.input_hist_parsed[:] = [""]
602 self.input_hist_parsed[:] = [""]
600 self.input_hist_raw[:] = [""]
603 self.input_hist_raw[:] = [""]
601 self.new_session()
604 self.new_session()
602
605
603 # ------------------------------
606 # ------------------------------
604 # Methods for retrieving history
607 # Methods for retrieving history
605 # ------------------------------
608 # ------------------------------
606 def get_session_info(self, session=0):
609 def get_session_info(self, session=0):
607 """Get info about a session.
610 """Get info about a session.
608
611
609 Parameters
612 Parameters
610 ----------
613 ----------
611 session : int
614 session : int
612 Session number to retrieve. The current session is 0, and negative
615 Session number to retrieve. The current session is 0, and negative
613 numbers count back from current session, so -1 is the previous session.
616 numbers count back from current session, so -1 is the previous session.
614
617
615 Returns
618 Returns
616 -------
619 -------
617 session_id : int
620 session_id : int
618 Session ID number
621 Session ID number
619 start : datetime
622 start : datetime
620 Timestamp for the start of the session.
623 Timestamp for the start of the session.
621 end : datetime
624 end : datetime
622 Timestamp for the end of the session, or None if IPython crashed.
625 Timestamp for the end of the session, or None if IPython crashed.
623 num_cmds : int
626 num_cmds : int
624 Number of commands run, or None if IPython crashed.
627 Number of commands run, or None if IPython crashed.
625 remark : unicode
628 remark : unicode
626 A manually set description.
629 A manually set description.
627 """
630 """
628 if session <= 0:
631 if session <= 0:
629 session += self.session_number
632 session += self.session_number
630
633
631 return super(HistoryManager, self).get_session_info(session=session)
634 return super(HistoryManager, self).get_session_info(session=session)
632
635
633 @catch_corrupt_db
636 @catch_corrupt_db
634 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
637 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
635 """Get the last n lines from the history database.
638 """Get the last n lines from the history database.
636
639
637 Most recent entry last.
640 Most recent entry last.
638
641
639 Completion will be reordered so that that the last ones are when
642 Completion will be reordered so that that the last ones are when
640 possible from current session.
643 possible from current session.
641
644
642 Parameters
645 Parameters
643 ----------
646 ----------
644 n : int
647 n : int
645 The number of lines to get
648 The number of lines to get
646 raw, output : bool
649 raw, output : bool
647 See :meth:`get_range`
650 See :meth:`get_range`
648 include_latest : bool
651 include_latest : bool
649 If False (default), n+1 lines are fetched, and the latest one
652 If False (default), n+1 lines are fetched, and the latest one
650 is discarded. This is intended to be used where the function
653 is discarded. This is intended to be used where the function
651 is called by a user command, which it should not return.
654 is called by a user command, which it should not return.
652
655
653 Returns
656 Returns
654 -------
657 -------
655 Tuples as :meth:`get_range`
658 Tuples as :meth:`get_range`
656 """
659 """
657 self.writeout_cache()
660 self.writeout_cache()
658 if not include_latest:
661 if not include_latest:
659 n += 1
662 n += 1
660 # cursor/line/entry
663 # cursor/line/entry
661 this_cur = list(
664 this_cur = list(
662 self._run_sql(
665 self._run_sql(
663 "WHERE session == ? ORDER BY line DESC LIMIT ? ",
666 "WHERE session == ? ORDER BY line DESC LIMIT ? ",
664 (self.session_number, n),
667 (self.session_number, n),
665 raw=raw,
668 raw=raw,
666 output=output,
669 output=output,
667 )
670 )
668 )
671 )
669 other_cur = list(
672 other_cur = list(
670 self._run_sql(
673 self._run_sql(
671 "WHERE session != ? ORDER BY session DESC, line DESC LIMIT ?",
674 "WHERE session != ? ORDER BY session DESC, line DESC LIMIT ?",
672 (self.session_number, n),
675 (self.session_number, n),
673 raw=raw,
676 raw=raw,
674 output=output,
677 output=output,
675 )
678 )
676 )
679 )
677
680
678 everything = this_cur + other_cur
681 everything = this_cur + other_cur
679
682
680 everything = everything[:n]
683 everything = everything[:n]
681
684
682 if not include_latest:
685 if not include_latest:
683 return list(everything)[:0:-1]
686 return list(everything)[:0:-1]
684 return list(everything)[::-1]
687 return list(everything)[::-1]
685
688
686 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
689 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
687 """Get input and output history from the current session. Called by
690 """Get input and output history from the current session. Called by
688 get_range, and takes similar parameters."""
691 get_range, and takes similar parameters."""
689 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
692 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
690
693
691 n = len(input_hist)
694 n = len(input_hist)
692 if start < 0:
695 if start < 0:
693 start += n
696 start += n
694 if not stop or (stop > n):
697 if not stop or (stop > n):
695 stop = n
698 stop = n
696 elif stop < 0:
699 elif stop < 0:
697 stop += n
700 stop += n
698
701
699 for i in range(start, stop):
702 for i in range(start, stop):
700 if output:
703 if output:
701 line = (input_hist[i], self.output_hist_reprs.get(i))
704 line = (input_hist[i], self.output_hist_reprs.get(i))
702 else:
705 else:
703 line = input_hist[i]
706 line = input_hist[i]
704 yield (0, i, line)
707 yield (0, i, line)
705
708
706 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
709 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
707 """Retrieve input by session.
710 """Retrieve input by session.
708
711
709 Parameters
712 Parameters
710 ----------
713 ----------
711 session : int
714 session : int
712 Session number to retrieve. The current session is 0, and negative
715 Session number to retrieve. The current session is 0, and negative
713 numbers count back from current session, so -1 is previous session.
716 numbers count back from current session, so -1 is previous session.
714 start : int
717 start : int
715 First line to retrieve.
718 First line to retrieve.
716 stop : int
719 stop : int
717 End of line range (excluded from output itself). If None, retrieve
720 End of line range (excluded from output itself). If None, retrieve
718 to the end of the session.
721 to the end of the session.
719 raw : bool
722 raw : bool
720 If True, return untranslated input
723 If True, return untranslated input
721 output : bool
724 output : bool
722 If True, attempt to include output. This will be 'real' Python
725 If True, attempt to include output. This will be 'real' Python
723 objects for the current session, or text reprs from previous
726 objects for the current session, or text reprs from previous
724 sessions if db_log_output was enabled at the time. Where no output
727 sessions if db_log_output was enabled at the time. Where no output
725 is found, None is used.
728 is found, None is used.
726
729
727 Returns
730 Returns
728 -------
731 -------
729 entries
732 entries
730 An iterator over the desired lines. Each line is a 3-tuple, either
733 An iterator over the desired lines. Each line is a 3-tuple, either
731 (session, line, input) if output is False, or
734 (session, line, input) if output is False, or
732 (session, line, (input, output)) if output is True.
735 (session, line, (input, output)) if output is True.
733 """
736 """
734 if session <= 0:
737 if session <= 0:
735 session += self.session_number
738 session += self.session_number
736 if session==self.session_number: # Current session
739 if session==self.session_number: # Current session
737 return self._get_range_session(start, stop, raw, output)
740 return self._get_range_session(start, stop, raw, output)
738 return super(HistoryManager, self).get_range(session, start, stop, raw,
741 return super(HistoryManager, self).get_range(session, start, stop, raw,
739 output)
742 output)
740
743
741 ## ----------------------------
744 ## ----------------------------
742 ## Methods for storing history:
745 ## Methods for storing history:
743 ## ----------------------------
746 ## ----------------------------
744 def store_inputs(self, line_num, source, source_raw=None):
747 def store_inputs(self, line_num, source, source_raw=None):
745 """Store source and raw input in history and create input cache
748 """Store source and raw input in history and create input cache
746 variables ``_i*``.
749 variables ``_i*``.
747
750
748 Parameters
751 Parameters
749 ----------
752 ----------
750 line_num : int
753 line_num : int
751 The prompt number of this input.
754 The prompt number of this input.
752 source : str
755 source : str
753 Python input.
756 Python input.
754 source_raw : str, optional
757 source_raw : str, optional
755 If given, this is the raw input without any IPython transformations
758 If given, this is the raw input without any IPython transformations
756 applied to it. If not given, ``source`` is used.
759 applied to it. If not given, ``source`` is used.
757 """
760 """
758 if source_raw is None:
761 if source_raw is None:
759 source_raw = source
762 source_raw = source
760 source = source.rstrip('\n')
763 source = source.rstrip('\n')
761 source_raw = source_raw.rstrip('\n')
764 source_raw = source_raw.rstrip('\n')
762
765
763 # do not store exit/quit commands
766 # do not store exit/quit commands
764 if self._exit_re.match(source_raw.strip()):
767 if self._exit_re.match(source_raw.strip()):
765 return
768 return
766
769
767 self.input_hist_parsed.append(source)
770 self.input_hist_parsed.append(source)
768 self.input_hist_raw.append(source_raw)
771 self.input_hist_raw.append(source_raw)
769
772
770 with self.db_input_cache_lock:
773 with self.db_input_cache_lock:
771 self.db_input_cache.append((line_num, source, source_raw))
774 self.db_input_cache.append((line_num, source, source_raw))
772 # Trigger to flush cache and write to DB.
775 # Trigger to flush cache and write to DB.
773 if len(self.db_input_cache) >= self.db_cache_size:
776 if len(self.db_input_cache) >= self.db_cache_size:
774 self.save_flag.set()
777 self.save_flag.set()
775
778
776 # update the auto _i variables
779 # update the auto _i variables
777 self._iii = self._ii
780 self._iii = self._ii
778 self._ii = self._i
781 self._ii = self._i
779 self._i = self._i00
782 self._i = self._i00
780 self._i00 = source_raw
783 self._i00 = source_raw
781
784
782 # hackish access to user namespace to create _i1,_i2... dynamically
785 # hackish access to user namespace to create _i1,_i2... dynamically
783 new_i = '_i%s' % line_num
786 new_i = '_i%s' % line_num
784 to_main = {'_i': self._i,
787 to_main = {'_i': self._i,
785 '_ii': self._ii,
788 '_ii': self._ii,
786 '_iii': self._iii,
789 '_iii': self._iii,
787 new_i : self._i00 }
790 new_i : self._i00 }
788
791
789 if self.shell is not None:
792 if self.shell is not None:
790 self.shell.push(to_main, interactive=False)
793 self.shell.push(to_main, interactive=False)
791
794
792 def store_output(self, line_num):
795 def store_output(self, line_num):
793 """If database output logging is enabled, this saves all the
796 """If database output logging is enabled, this saves all the
794 outputs from the indicated prompt number to the database. It's
797 outputs from the indicated prompt number to the database. It's
795 called by run_cell after code has been executed.
798 called by run_cell after code has been executed.
796
799
797 Parameters
800 Parameters
798 ----------
801 ----------
799 line_num : int
802 line_num : int
800 The line number from which to save outputs
803 The line number from which to save outputs
801 """
804 """
802 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
805 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
803 return
806 return
804 output = self.output_hist_reprs[line_num]
807 output = self.output_hist_reprs[line_num]
805
808
806 with self.db_output_cache_lock:
809 with self.db_output_cache_lock:
807 self.db_output_cache.append((line_num, output))
810 self.db_output_cache.append((line_num, output))
808 if self.db_cache_size <= 1:
811 if self.db_cache_size <= 1:
809 self.save_flag.set()
812 self.save_flag.set()
810
813
811 def _writeout_input_cache(self, conn):
814 def _writeout_input_cache(self, conn):
812 with conn:
815 with conn:
813 for line in self.db_input_cache:
816 for line in self.db_input_cache:
814 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
817 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
815 (self.session_number,)+line)
818 (self.session_number,)+line)
816
819
817 def _writeout_output_cache(self, conn):
820 def _writeout_output_cache(self, conn):
818 with conn:
821 with conn:
819 for line in self.db_output_cache:
822 for line in self.db_output_cache:
820 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
823 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
821 (self.session_number,)+line)
824 (self.session_number,)+line)
822
825
823 @only_when_enabled
826 @only_when_enabled
824 def writeout_cache(self, conn=None):
827 def writeout_cache(self, conn=None):
825 """Write any entries in the cache to the database."""
828 """Write any entries in the cache to the database."""
826 if conn is None:
829 if conn is None:
827 conn = self.db
830 conn = self.db
828
831
829 with self.db_input_cache_lock:
832 with self.db_input_cache_lock:
830 try:
833 try:
831 self._writeout_input_cache(conn)
834 self._writeout_input_cache(conn)
832 except sqlite3.IntegrityError:
835 except sqlite3.IntegrityError:
833 self.new_session(conn)
836 self.new_session(conn)
834 print("ERROR! Session/line number was not unique in",
837 print("ERROR! Session/line number was not unique in",
835 "database. History logging moved to new session",
838 "database. History logging moved to new session",
836 self.session_number)
839 self.session_number)
837 try:
840 try:
838 # Try writing to the new session. If this fails, don't
841 # Try writing to the new session. If this fails, don't
839 # recurse
842 # recurse
840 self._writeout_input_cache(conn)
843 self._writeout_input_cache(conn)
841 except sqlite3.IntegrityError:
844 except sqlite3.IntegrityError:
842 pass
845 pass
843 finally:
846 finally:
844 self.db_input_cache = []
847 self.db_input_cache = []
845
848
846 with self.db_output_cache_lock:
849 with self.db_output_cache_lock:
847 try:
850 try:
848 self._writeout_output_cache(conn)
851 self._writeout_output_cache(conn)
849 except sqlite3.IntegrityError:
852 except sqlite3.IntegrityError:
850 print("!! Session/line number for output was not unique",
853 print("!! Session/line number for output was not unique",
851 "in database. Output will not be stored.")
854 "in database. Output will not be stored.")
852 finally:
855 finally:
853 self.db_output_cache = []
856 self.db_output_cache = []
854
857
855
858
856 class HistorySavingThread(threading.Thread):
859 class HistorySavingThread(threading.Thread):
857 """This thread takes care of writing history to the database, so that
860 """This thread takes care of writing history to the database, so that
858 the UI isn't held up while that happens.
861 the UI isn't held up while that happens.
859
862
860 It waits for the HistoryManager's save_flag to be set, then writes out
863 It waits for the HistoryManager's save_flag to be set, then writes out
861 the history cache. The main thread is responsible for setting the flag when
864 the history cache. The main thread is responsible for setting the flag when
862 the cache size reaches a defined threshold."""
865 the cache size reaches a defined threshold."""
863 daemon = True
866 daemon = True
864 stop_now = False
867 stop_now = False
865 enabled = True
868 enabled = True
866 def __init__(self, history_manager):
869 def __init__(self, history_manager):
867 super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
870 super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
868 self.history_manager = history_manager
871 self.history_manager = history_manager
869 self.enabled = history_manager.enabled
872 self.enabled = history_manager.enabled
870 atexit.register(self.stop)
873 atexit.register(self.stop)
871
874
872 @only_when_enabled
875 @only_when_enabled
873 def run(self):
876 def run(self):
874 # We need a separate db connection per thread:
877 # We need a separate db connection per thread:
875 try:
878 try:
876 self.db = sqlite3.connect(
879 self.db = sqlite3.connect(
877 str(self.history_manager.hist_file),
880 str(self.history_manager.hist_file),
878 **self.history_manager.connection_options,
881 **self.history_manager.connection_options,
879 )
882 )
880 while True:
883 while True:
881 self.history_manager.save_flag.wait()
884 self.history_manager.save_flag.wait()
882 if self.stop_now:
885 if self.stop_now:
883 self.db.close()
886 self.db.close()
884 return
887 return
885 self.history_manager.save_flag.clear()
888 self.history_manager.save_flag.clear()
886 self.history_manager.writeout_cache(self.db)
889 self.history_manager.writeout_cache(self.db)
887 except Exception as e:
890 except Exception as e:
888 print(("The history saving thread hit an unexpected error (%s)."
891 print(("The history saving thread hit an unexpected error (%s)."
889 "History will not be written to the database.") % repr(e))
892 "History will not be written to the database.") % repr(e))
890
893
891 def stop(self):
894 def stop(self):
892 """This can be called from the main thread to safely stop this thread.
895 """This can be called from the main thread to safely stop this thread.
893
896
894 Note that it does not attempt to write out remaining history before
897 Note that it does not attempt to write out remaining history before
895 exiting. That should be done by calling the HistoryManager's
898 exiting. That should be done by calling the HistoryManager's
896 end_session method."""
899 end_session method."""
897 self.stop_now = True
900 self.stop_now = True
898 self.history_manager.save_flag.set()
901 self.history_manager.save_flag.set()
899 self.join()
902 self.join()
900
903
901
904
902 # To match, e.g. ~5/8-~2/3
905 # To match, e.g. ~5/8-~2/3
903 range_re = re.compile(r"""
906 range_re = re.compile(r"""
904 ((?P<startsess>~?\d+)/)?
907 ((?P<startsess>~?\d+)/)?
905 (?P<start>\d+)?
908 (?P<start>\d+)?
906 ((?P<sep>[\-:])
909 ((?P<sep>[\-:])
907 ((?P<endsess>~?\d+)/)?
910 ((?P<endsess>~?\d+)/)?
908 (?P<end>\d+))?
911 (?P<end>\d+))?
909 $""", re.VERBOSE)
912 $""", re.VERBOSE)
910
913
911
914
912 def extract_hist_ranges(ranges_str):
915 def extract_hist_ranges(ranges_str):
913 """Turn a string of history ranges into 3-tuples of (session, start, stop).
916 """Turn a string of history ranges into 3-tuples of (session, start, stop).
914
917
915 Empty string results in a `[(0, 1, None)]`, i.e. "everything from current
918 Empty string results in a `[(0, 1, None)]`, i.e. "everything from current
916 session".
919 session".
917
920
918 Examples
921 Examples
919 --------
922 --------
920 >>> list(extract_hist_ranges("~8/5-~7/4 2"))
923 >>> list(extract_hist_ranges("~8/5-~7/4 2"))
921 [(-8, 5, None), (-7, 1, 5), (0, 2, 3)]
924 [(-8, 5, None), (-7, 1, 5), (0, 2, 3)]
922 """
925 """
923 if ranges_str == "":
926 if ranges_str == "":
924 yield (0, 1, None) # Everything from current session
927 yield (0, 1, None) # Everything from current session
925 return
928 return
926
929
927 for range_str in ranges_str.split():
930 for range_str in ranges_str.split():
928 rmatch = range_re.match(range_str)
931 rmatch = range_re.match(range_str)
929 if not rmatch:
932 if not rmatch:
930 continue
933 continue
931 start = rmatch.group("start")
934 start = rmatch.group("start")
932 if start:
935 if start:
933 start = int(start)
936 start = int(start)
934 end = rmatch.group("end")
937 end = rmatch.group("end")
935 # If no end specified, get (a, a + 1)
938 # If no end specified, get (a, a + 1)
936 end = int(end) if end else start + 1
939 end = int(end) if end else start + 1
937 else: # start not specified
940 else: # start not specified
938 if not rmatch.group('startsess'): # no startsess
941 if not rmatch.group('startsess'): # no startsess
939 continue
942 continue
940 start = 1
943 start = 1
941 end = None # provide the entire session hist
944 end = None # provide the entire session hist
942
945
943 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
946 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
944 end += 1
947 end += 1
945 startsess = rmatch.group("startsess") or "0"
948 startsess = rmatch.group("startsess") or "0"
946 endsess = rmatch.group("endsess") or startsess
949 endsess = rmatch.group("endsess") or startsess
947 startsess = int(startsess.replace("~","-"))
950 startsess = int(startsess.replace("~","-"))
948 endsess = int(endsess.replace("~","-"))
951 endsess = int(endsess.replace("~","-"))
949 assert endsess >= startsess, "start session must be earlier than end session"
952 assert endsess >= startsess, "start session must be earlier than end session"
950
953
951 if endsess == startsess:
954 if endsess == startsess:
952 yield (startsess, start, end)
955 yield (startsess, start, end)
953 continue
956 continue
954 # Multiple sessions in one range:
957 # Multiple sessions in one range:
955 yield (startsess, start, None)
958 yield (startsess, start, None)
956 for sess in range(startsess+1, endsess):
959 for sess in range(startsess+1, endsess):
957 yield (sess, 1, None)
960 yield (sess, 1, None)
958 yield (endsess, 1, end)
961 yield (endsess, 1, end)
959
962
960
963
961 def _format_lineno(session, line):
964 def _format_lineno(session, line):
962 """Helper function to format line numbers properly."""
965 """Helper function to format line numbers properly."""
963 if session == 0:
966 if session == 0:
964 return str(line)
967 return str(line)
965 return "%s#%s" % (session, line)
968 return "%s#%s" % (session, line)
@@ -1,3862 +1,3898 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Main IPython class."""
2 """Main IPython class."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13
13
14 import abc
14 import abc
15 import ast
15 import ast
16 import atexit
16 import atexit
17 import bdb
17 import bdb
18 import builtins as builtin_mod
18 import builtins as builtin_mod
19 import functools
19 import functools
20 import inspect
20 import inspect
21 import os
21 import os
22 import re
22 import re
23 import runpy
23 import runpy
24 import subprocess
24 import subprocess
25 import sys
25 import sys
26 import tempfile
26 import tempfile
27 import traceback
27 import traceback
28 import types
28 import types
29 import warnings
29 import warnings
30 from ast import stmt
30 from ast import stmt
31 from io import open as io_open
31 from io import open as io_open
32 from logging import error
32 from logging import error
33 from pathlib import Path
33 from pathlib import Path
34 from typing import Callable
34 from typing import Callable
35 from typing import List as ListType
35 from typing import List as ListType, Dict as DictType, Any as AnyType
36 from typing import Optional, Tuple
36 from typing import Optional, Tuple
37 from warnings import warn
37 from warnings import warn
38
38
39 from pickleshare import PickleShareDB
39 from pickleshare import PickleShareDB
40 from tempfile import TemporaryDirectory
40 from tempfile import TemporaryDirectory
41 from traitlets import (
41 from traitlets import (
42 Any,
42 Any,
43 Bool,
43 Bool,
44 CaselessStrEnum,
44 CaselessStrEnum,
45 Dict,
45 Dict,
46 Enum,
46 Enum,
47 Instance,
47 Instance,
48 Integer,
48 Integer,
49 List,
49 List,
50 Type,
50 Type,
51 Unicode,
51 Unicode,
52 default,
52 default,
53 observe,
53 observe,
54 validate,
54 validate,
55 )
55 )
56 from traitlets.config.configurable import SingletonConfigurable
56 from traitlets.config.configurable import SingletonConfigurable
57 from traitlets.utils.importstring import import_item
57 from traitlets.utils.importstring import import_item
58
58
59 import IPython.core.hooks
59 import IPython.core.hooks
60 from IPython.core import magic, oinspect, page, prefilter, ultratb
60 from IPython.core import magic, oinspect, page, prefilter, ultratb
61 from IPython.core.alias import Alias, AliasManager
61 from IPython.core.alias import Alias, AliasManager
62 from IPython.core.autocall import ExitAutocall
62 from IPython.core.autocall import ExitAutocall
63 from IPython.core.builtin_trap import BuiltinTrap
63 from IPython.core.builtin_trap import BuiltinTrap
64 from IPython.core.compilerop import CachingCompiler
64 from IPython.core.compilerop import CachingCompiler
65 from IPython.core.debugger import InterruptiblePdb
65 from IPython.core.debugger import InterruptiblePdb
66 from IPython.core.display_trap import DisplayTrap
66 from IPython.core.display_trap import DisplayTrap
67 from IPython.core.displayhook import DisplayHook
67 from IPython.core.displayhook import DisplayHook
68 from IPython.core.displaypub import DisplayPublisher
68 from IPython.core.displaypub import DisplayPublisher
69 from IPython.core.error import InputRejected, UsageError
69 from IPython.core.error import InputRejected, UsageError
70 from IPython.core.events import EventManager, available_events
70 from IPython.core.events import EventManager, available_events
71 from IPython.core.extensions import ExtensionManager
71 from IPython.core.extensions import ExtensionManager
72 from IPython.core.formatters import DisplayFormatter
72 from IPython.core.formatters import DisplayFormatter
73 from IPython.core.history import HistoryManager
73 from IPython.core.history import HistoryManager
74 from IPython.core.inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
74 from IPython.core.inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
75 from IPython.core.logger import Logger
75 from IPython.core.logger import Logger
76 from IPython.core.macro import Macro
76 from IPython.core.macro import Macro
77 from IPython.core.payload import PayloadManager
77 from IPython.core.payload import PayloadManager
78 from IPython.core.prefilter import PrefilterManager
78 from IPython.core.prefilter import PrefilterManager
79 from IPython.core.profiledir import ProfileDir
79 from IPython.core.profiledir import ProfileDir
80 from IPython.core.usage import default_banner
80 from IPython.core.usage import default_banner
81 from IPython.display import display
81 from IPython.display import display
82 from IPython.paths import get_ipython_dir
82 from IPython.paths import get_ipython_dir
83 from IPython.testing.skipdoctest import skip_doctest
83 from IPython.testing.skipdoctest import skip_doctest
84 from IPython.utils import PyColorize, io, openpy, py3compat
84 from IPython.utils import PyColorize, io, openpy, py3compat
85 from IPython.utils.decorators import undoc
85 from IPython.utils.decorators import undoc
86 from IPython.utils.io import ask_yes_no
86 from IPython.utils.io import ask_yes_no
87 from IPython.utils.ipstruct import Struct
87 from IPython.utils.ipstruct import Struct
88 from IPython.utils.path import ensure_dir_exists, get_home_dir, get_py_filename
88 from IPython.utils.path import ensure_dir_exists, get_home_dir, get_py_filename
89 from IPython.utils.process import getoutput, system
89 from IPython.utils.process import getoutput, system
90 from IPython.utils.strdispatch import StrDispatch
90 from IPython.utils.strdispatch import StrDispatch
91 from IPython.utils.syspathcontext import prepended_to_syspath
91 from IPython.utils.syspathcontext import prepended_to_syspath
92 from IPython.utils.text import DollarFormatter, LSString, SList, format_screen
92 from IPython.utils.text import DollarFormatter, LSString, SList, format_screen
93 from IPython.core.oinspect import OInfo
94
93
95
94 sphinxify: Optional[Callable]
96 sphinxify: Optional[Callable]
95
97
96 try:
98 try:
97 import docrepr.sphinxify as sphx
99 import docrepr.sphinxify as sphx
98
100
99 def sphinxify(oinfo):
101 def sphinxify(oinfo):
100 wrapped_docstring = sphx.wrap_main_docstring(oinfo)
102 wrapped_docstring = sphx.wrap_main_docstring(oinfo)
101
103
102 def sphinxify_docstring(docstring):
104 def sphinxify_docstring(docstring):
103 with TemporaryDirectory() as dirname:
105 with TemporaryDirectory() as dirname:
104 return {
106 return {
105 "text/html": sphx.sphinxify(wrapped_docstring, dirname),
107 "text/html": sphx.sphinxify(wrapped_docstring, dirname),
106 "text/plain": docstring,
108 "text/plain": docstring,
107 }
109 }
108
110
109 return sphinxify_docstring
111 return sphinxify_docstring
110 except ImportError:
112 except ImportError:
111 sphinxify = None
113 sphinxify = None
112
114
113
115
114 class ProvisionalWarning(DeprecationWarning):
116 class ProvisionalWarning(DeprecationWarning):
115 """
117 """
116 Warning class for unstable features
118 Warning class for unstable features
117 """
119 """
118 pass
120 pass
119
121
120 from ast import Module
122 from ast import Module
121
123
122 _assign_nodes = (ast.AugAssign, ast.AnnAssign, ast.Assign)
124 _assign_nodes = (ast.AugAssign, ast.AnnAssign, ast.Assign)
123 _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)
125 _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)
124
126
125 #-----------------------------------------------------------------------------
127 #-----------------------------------------------------------------------------
126 # Await Helpers
128 # Await Helpers
127 #-----------------------------------------------------------------------------
129 #-----------------------------------------------------------------------------
128
130
129 # we still need to run things using the asyncio eventloop, but there is no
131 # we still need to run things using the asyncio eventloop, but there is no
130 # async integration
132 # async integration
131 from .async_helpers import (
133 from .async_helpers import (
132 _asyncio_runner,
134 _asyncio_runner,
133 _curio_runner,
135 _curio_runner,
134 _pseudo_sync_runner,
136 _pseudo_sync_runner,
135 _should_be_async,
137 _should_be_async,
136 _trio_runner,
138 _trio_runner,
137 )
139 )
138
140
139 #-----------------------------------------------------------------------------
141 #-----------------------------------------------------------------------------
140 # Globals
142 # Globals
141 #-----------------------------------------------------------------------------
143 #-----------------------------------------------------------------------------
142
144
143 # compiled regexps for autoindent management
145 # compiled regexps for autoindent management
144 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
146 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
145
147
146 #-----------------------------------------------------------------------------
148 #-----------------------------------------------------------------------------
147 # Utilities
149 # Utilities
148 #-----------------------------------------------------------------------------
150 #-----------------------------------------------------------------------------
149
151
150
152
151 def is_integer_string(s: str):
153 def is_integer_string(s: str):
152 """
154 """
153 Variant of "str.isnumeric()" that allow negative values and other ints.
155 Variant of "str.isnumeric()" that allow negative values and other ints.
154 """
156 """
155 try:
157 try:
156 int(s)
158 int(s)
157 return True
159 return True
158 except ValueError:
160 except ValueError:
159 return False
161 return False
160 raise ValueError("Unexpected error")
162 raise ValueError("Unexpected error")
161
163
162
164
163 @undoc
165 @undoc
164 def softspace(file, newvalue):
166 def softspace(file, newvalue):
165 """Copied from code.py, to remove the dependency"""
167 """Copied from code.py, to remove the dependency"""
166
168
167 oldvalue = 0
169 oldvalue = 0
168 try:
170 try:
169 oldvalue = file.softspace
171 oldvalue = file.softspace
170 except AttributeError:
172 except AttributeError:
171 pass
173 pass
172 try:
174 try:
173 file.softspace = newvalue
175 file.softspace = newvalue
174 except (AttributeError, TypeError):
176 except (AttributeError, TypeError):
175 # "attribute-less object" or "read-only attributes"
177 # "attribute-less object" or "read-only attributes"
176 pass
178 pass
177 return oldvalue
179 return oldvalue
178
180
179 @undoc
181 @undoc
180 def no_op(*a, **kw):
182 def no_op(*a, **kw):
181 pass
183 pass
182
184
183
185
184 class SpaceInInput(Exception): pass
186 class SpaceInInput(Exception): pass
185
187
186
188
187 class SeparateUnicode(Unicode):
189 class SeparateUnicode(Unicode):
188 r"""A Unicode subclass to validate separate_in, separate_out, etc.
190 r"""A Unicode subclass to validate separate_in, separate_out, etc.
189
191
190 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
192 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
191 """
193 """
192
194
193 def validate(self, obj, value):
195 def validate(self, obj, value):
194 if value == '0': value = ''
196 if value == '0': value = ''
195 value = value.replace('\\n','\n')
197 value = value.replace('\\n','\n')
196 return super(SeparateUnicode, self).validate(obj, value)
198 return super(SeparateUnicode, self).validate(obj, value)
197
199
198
200
199 @undoc
201 @undoc
200 class DummyMod(object):
202 class DummyMod(object):
201 """A dummy module used for IPython's interactive module when
203 """A dummy module used for IPython's interactive module when
202 a namespace must be assigned to the module's __dict__."""
204 a namespace must be assigned to the module's __dict__."""
203 __spec__ = None
205 __spec__ = None
204
206
205
207
206 class ExecutionInfo(object):
208 class ExecutionInfo(object):
207 """The arguments used for a call to :meth:`InteractiveShell.run_cell`
209 """The arguments used for a call to :meth:`InteractiveShell.run_cell`
208
210
209 Stores information about what is going to happen.
211 Stores information about what is going to happen.
210 """
212 """
211 raw_cell = None
213 raw_cell = None
212 store_history = False
214 store_history = False
213 silent = False
215 silent = False
214 shell_futures = True
216 shell_futures = True
215 cell_id = None
217 cell_id = None
216
218
217 def __init__(self, raw_cell, store_history, silent, shell_futures, cell_id):
219 def __init__(self, raw_cell, store_history, silent, shell_futures, cell_id):
218 self.raw_cell = raw_cell
220 self.raw_cell = raw_cell
219 self.store_history = store_history
221 self.store_history = store_history
220 self.silent = silent
222 self.silent = silent
221 self.shell_futures = shell_futures
223 self.shell_futures = shell_futures
222 self.cell_id = cell_id
224 self.cell_id = cell_id
223
225
224 def __repr__(self):
226 def __repr__(self):
225 name = self.__class__.__qualname__
227 name = self.__class__.__qualname__
226 raw_cell = (
228 raw_cell = (
227 (self.raw_cell[:50] + "..") if len(self.raw_cell) > 50 else self.raw_cell
229 (self.raw_cell[:50] + "..") if len(self.raw_cell) > 50 else self.raw_cell
228 )
230 )
229 return (
231 return (
230 '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s cell_id=%s>'
232 '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s cell_id=%s>'
231 % (
233 % (
232 name,
234 name,
233 id(self),
235 id(self),
234 raw_cell,
236 raw_cell,
235 self.store_history,
237 self.store_history,
236 self.silent,
238 self.silent,
237 self.shell_futures,
239 self.shell_futures,
238 self.cell_id,
240 self.cell_id,
239 )
241 )
240 )
242 )
241
243
242
244
243 class ExecutionResult(object):
245 class ExecutionResult(object):
244 """The result of a call to :meth:`InteractiveShell.run_cell`
246 """The result of a call to :meth:`InteractiveShell.run_cell`
245
247
246 Stores information about what took place.
248 Stores information about what took place.
247 """
249 """
248 execution_count = None
250 execution_count = None
249 error_before_exec = None
251 error_before_exec = None
250 error_in_exec: Optional[BaseException] = None
252 error_in_exec: Optional[BaseException] = None
251 info = None
253 info = None
252 result = None
254 result = None
253
255
254 def __init__(self, info):
256 def __init__(self, info):
255 self.info = info
257 self.info = info
256
258
257 @property
259 @property
258 def success(self):
260 def success(self):
259 return (self.error_before_exec is None) and (self.error_in_exec is None)
261 return (self.error_before_exec is None) and (self.error_in_exec is None)
260
262
261 def raise_error(self):
263 def raise_error(self):
262 """Reraises error if `success` is `False`, otherwise does nothing"""
264 """Reraises error if `success` is `False`, otherwise does nothing"""
263 if self.error_before_exec is not None:
265 if self.error_before_exec is not None:
264 raise self.error_before_exec
266 raise self.error_before_exec
265 if self.error_in_exec is not None:
267 if self.error_in_exec is not None:
266 raise self.error_in_exec
268 raise self.error_in_exec
267
269
268 def __repr__(self):
270 def __repr__(self):
269 name = self.__class__.__qualname__
271 name = self.__class__.__qualname__
270 return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s info=%s result=%s>' %\
272 return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s info=%s result=%s>' %\
271 (name, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.info), repr(self.result))
273 (name, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.info), repr(self.result))
272
274
273 @functools.wraps(io_open)
275 @functools.wraps(io_open)
274 def _modified_open(file, *args, **kwargs):
276 def _modified_open(file, *args, **kwargs):
275 if file in {0, 1, 2}:
277 if file in {0, 1, 2}:
276 raise ValueError(
278 raise ValueError(
277 f"IPython won't let you open fd={file} by default "
279 f"IPython won't let you open fd={file} by default "
278 "as it is likely to crash IPython. If you know what you are doing, "
280 "as it is likely to crash IPython. If you know what you are doing, "
279 "you can use builtins' open."
281 "you can use builtins' open."
280 )
282 )
281
283
282 return io_open(file, *args, **kwargs)
284 return io_open(file, *args, **kwargs)
283
285
284 class InteractiveShell(SingletonConfigurable):
286 class InteractiveShell(SingletonConfigurable):
285 """An enhanced, interactive shell for Python."""
287 """An enhanced, interactive shell for Python."""
286
288
287 _instance = None
289 _instance = None
288
290
289 ast_transformers = List([], help=
291 ast_transformers = List([], help=
290 """
292 """
291 A list of ast.NodeTransformer subclass instances, which will be applied
293 A list of ast.NodeTransformer subclass instances, which will be applied
292 to user input before code is run.
294 to user input before code is run.
293 """
295 """
294 ).tag(config=True)
296 ).tag(config=True)
295
297
296 autocall = Enum((0,1,2), default_value=0, help=
298 autocall = Enum((0,1,2), default_value=0, help=
297 """
299 """
298 Make IPython automatically call any callable object even if you didn't
300 Make IPython automatically call any callable object even if you didn't
299 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
301 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
300 automatically. The value can be '0' to disable the feature, '1' for
302 automatically. The value can be '0' to disable the feature, '1' for
301 'smart' autocall, where it is not applied if there are no more
303 'smart' autocall, where it is not applied if there are no more
302 arguments on the line, and '2' for 'full' autocall, where all callable
304 arguments on the line, and '2' for 'full' autocall, where all callable
303 objects are automatically called (even if no arguments are present).
305 objects are automatically called (even if no arguments are present).
304 """
306 """
305 ).tag(config=True)
307 ).tag(config=True)
306
308
307 autoindent = Bool(True, help=
309 autoindent = Bool(True, help=
308 """
310 """
309 Autoindent IPython code entered interactively.
311 Autoindent IPython code entered interactively.
310 """
312 """
311 ).tag(config=True)
313 ).tag(config=True)
312
314
313 autoawait = Bool(True, help=
315 autoawait = Bool(True, help=
314 """
316 """
315 Automatically run await statement in the top level repl.
317 Automatically run await statement in the top level repl.
316 """
318 """
317 ).tag(config=True)
319 ).tag(config=True)
318
320
319 loop_runner_map ={
321 loop_runner_map ={
320 'asyncio':(_asyncio_runner, True),
322 'asyncio':(_asyncio_runner, True),
321 'curio':(_curio_runner, True),
323 'curio':(_curio_runner, True),
322 'trio':(_trio_runner, True),
324 'trio':(_trio_runner, True),
323 'sync': (_pseudo_sync_runner, False)
325 'sync': (_pseudo_sync_runner, False)
324 }
326 }
325
327
326 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
328 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
327 allow_none=True,
329 allow_none=True,
328 help="""Select the loop runner that will be used to execute top-level asynchronous code"""
330 help="""Select the loop runner that will be used to execute top-level asynchronous code"""
329 ).tag(config=True)
331 ).tag(config=True)
330
332
331 @default('loop_runner')
333 @default('loop_runner')
332 def _default_loop_runner(self):
334 def _default_loop_runner(self):
333 return import_item("IPython.core.interactiveshell._asyncio_runner")
335 return import_item("IPython.core.interactiveshell._asyncio_runner")
334
336
335 @validate('loop_runner')
337 @validate('loop_runner')
336 def _import_runner(self, proposal):
338 def _import_runner(self, proposal):
337 if isinstance(proposal.value, str):
339 if isinstance(proposal.value, str):
338 if proposal.value in self.loop_runner_map:
340 if proposal.value in self.loop_runner_map:
339 runner, autoawait = self.loop_runner_map[proposal.value]
341 runner, autoawait = self.loop_runner_map[proposal.value]
340 self.autoawait = autoawait
342 self.autoawait = autoawait
341 return runner
343 return runner
342 runner = import_item(proposal.value)
344 runner = import_item(proposal.value)
343 if not callable(runner):
345 if not callable(runner):
344 raise ValueError('loop_runner must be callable')
346 raise ValueError('loop_runner must be callable')
345 return runner
347 return runner
346 if not callable(proposal.value):
348 if not callable(proposal.value):
347 raise ValueError('loop_runner must be callable')
349 raise ValueError('loop_runner must be callable')
348 return proposal.value
350 return proposal.value
349
351
350 automagic = Bool(True, help=
352 automagic = Bool(True, help=
351 """
353 """
352 Enable magic commands to be called without the leading %.
354 Enable magic commands to be called without the leading %.
353 """
355 """
354 ).tag(config=True)
356 ).tag(config=True)
355
357
356 banner1 = Unicode(default_banner,
358 banner1 = Unicode(default_banner,
357 help="""The part of the banner to be printed before the profile"""
359 help="""The part of the banner to be printed before the profile"""
358 ).tag(config=True)
360 ).tag(config=True)
359 banner2 = Unicode('',
361 banner2 = Unicode('',
360 help="""The part of the banner to be printed after the profile"""
362 help="""The part of the banner to be printed after the profile"""
361 ).tag(config=True)
363 ).tag(config=True)
362
364
363 cache_size = Integer(1000, help=
365 cache_size = Integer(1000, help=
364 """
366 """
365 Set the size of the output cache. The default is 1000, you can
367 Set the size of the output cache. The default is 1000, you can
366 change it permanently in your config file. Setting it to 0 completely
368 change it permanently in your config file. Setting it to 0 completely
367 disables the caching system, and the minimum value accepted is 3 (if
369 disables the caching system, and the minimum value accepted is 3 (if
368 you provide a value less than 3, it is reset to 0 and a warning is
370 you provide a value less than 3, it is reset to 0 and a warning is
369 issued). This limit is defined because otherwise you'll spend more
371 issued). This limit is defined because otherwise you'll spend more
370 time re-flushing a too small cache than working
372 time re-flushing a too small cache than working
371 """
373 """
372 ).tag(config=True)
374 ).tag(config=True)
373 color_info = Bool(True, help=
375 color_info = Bool(True, help=
374 """
376 """
375 Use colors for displaying information about objects. Because this
377 Use colors for displaying information about objects. Because this
376 information is passed through a pager (like 'less'), and some pagers
378 information is passed through a pager (like 'less'), and some pagers
377 get confused with color codes, this capability can be turned off.
379 get confused with color codes, this capability can be turned off.
378 """
380 """
379 ).tag(config=True)
381 ).tag(config=True)
380 colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'),
382 colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'),
381 default_value='Neutral',
383 default_value='Neutral',
382 help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)."
384 help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)."
383 ).tag(config=True)
385 ).tag(config=True)
384 debug = Bool(False).tag(config=True)
386 debug = Bool(False).tag(config=True)
385 disable_failing_post_execute = Bool(False,
387 disable_failing_post_execute = Bool(False,
386 help="Don't call post-execute functions that have failed in the past."
388 help="Don't call post-execute functions that have failed in the past."
387 ).tag(config=True)
389 ).tag(config=True)
388 display_formatter = Instance(DisplayFormatter, allow_none=True)
390 display_formatter = Instance(DisplayFormatter, allow_none=True)
389 displayhook_class = Type(DisplayHook)
391 displayhook_class = Type(DisplayHook)
390 display_pub_class = Type(DisplayPublisher)
392 display_pub_class = Type(DisplayPublisher)
391 compiler_class = Type(CachingCompiler)
393 compiler_class = Type(CachingCompiler)
392 inspector_class = Type(
394 inspector_class = Type(
393 oinspect.Inspector, help="Class to use to instantiate the shell inspector"
395 oinspect.Inspector, help="Class to use to instantiate the shell inspector"
394 ).tag(config=True)
396 ).tag(config=True)
395
397
396 sphinxify_docstring = Bool(False, help=
398 sphinxify_docstring = Bool(False, help=
397 """
399 """
398 Enables rich html representation of docstrings. (This requires the
400 Enables rich html representation of docstrings. (This requires the
399 docrepr module).
401 docrepr module).
400 """).tag(config=True)
402 """).tag(config=True)
401
403
402 @observe("sphinxify_docstring")
404 @observe("sphinxify_docstring")
403 def _sphinxify_docstring_changed(self, change):
405 def _sphinxify_docstring_changed(self, change):
404 if change['new']:
406 if change['new']:
405 warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning)
407 warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning)
406
408
407 enable_html_pager = Bool(False, help=
409 enable_html_pager = Bool(False, help=
408 """
410 """
409 (Provisional API) enables html representation in mime bundles sent
411 (Provisional API) enables html representation in mime bundles sent
410 to pagers.
412 to pagers.
411 """).tag(config=True)
413 """).tag(config=True)
412
414
413 @observe("enable_html_pager")
415 @observe("enable_html_pager")
414 def _enable_html_pager_changed(self, change):
416 def _enable_html_pager_changed(self, change):
415 if change['new']:
417 if change['new']:
416 warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning)
418 warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning)
417
419
418 data_pub_class = None
420 data_pub_class = None
419
421
420 exit_now = Bool(False)
422 exit_now = Bool(False)
421 exiter = Instance(ExitAutocall)
423 exiter = Instance(ExitAutocall)
422 @default('exiter')
424 @default('exiter')
423 def _exiter_default(self):
425 def _exiter_default(self):
424 return ExitAutocall(self)
426 return ExitAutocall(self)
425 # Monotonically increasing execution counter
427 # Monotonically increasing execution counter
426 execution_count = Integer(1)
428 execution_count = Integer(1)
427 filename = Unicode("<ipython console>")
429 filename = Unicode("<ipython console>")
428 ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__
430 ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__
429
431
430 # Used to transform cells before running them, and check whether code is complete
432 # Used to transform cells before running them, and check whether code is complete
431 input_transformer_manager = Instance('IPython.core.inputtransformer2.TransformerManager',
433 input_transformer_manager = Instance('IPython.core.inputtransformer2.TransformerManager',
432 ())
434 ())
433
435
434 @property
436 @property
435 def input_transformers_cleanup(self):
437 def input_transformers_cleanup(self):
436 return self.input_transformer_manager.cleanup_transforms
438 return self.input_transformer_manager.cleanup_transforms
437
439
438 input_transformers_post = List([],
440 input_transformers_post = List([],
439 help="A list of string input transformers, to be applied after IPython's "
441 help="A list of string input transformers, to be applied after IPython's "
440 "own input transformations."
442 "own input transformations."
441 )
443 )
442
444
443 @property
445 @property
444 def input_splitter(self):
446 def input_splitter(self):
445 """Make this available for backward compatibility (pre-7.0 release) with existing code.
447 """Make this available for backward compatibility (pre-7.0 release) with existing code.
446
448
447 For example, ipykernel ipykernel currently uses
449 For example, ipykernel ipykernel currently uses
448 `shell.input_splitter.check_complete`
450 `shell.input_splitter.check_complete`
449 """
451 """
450 from warnings import warn
452 from warnings import warn
451 warn("`input_splitter` is deprecated since IPython 7.0, prefer `input_transformer_manager`.",
453 warn("`input_splitter` is deprecated since IPython 7.0, prefer `input_transformer_manager`.",
452 DeprecationWarning, stacklevel=2
454 DeprecationWarning, stacklevel=2
453 )
455 )
454 return self.input_transformer_manager
456 return self.input_transformer_manager
455
457
456 logstart = Bool(False, help=
458 logstart = Bool(False, help=
457 """
459 """
458 Start logging to the default log file in overwrite mode.
460 Start logging to the default log file in overwrite mode.
459 Use `logappend` to specify a log file to **append** logs to.
461 Use `logappend` to specify a log file to **append** logs to.
460 """
462 """
461 ).tag(config=True)
463 ).tag(config=True)
462 logfile = Unicode('', help=
464 logfile = Unicode('', help=
463 """
465 """
464 The name of the logfile to use.
466 The name of the logfile to use.
465 """
467 """
466 ).tag(config=True)
468 ).tag(config=True)
467 logappend = Unicode('', help=
469 logappend = Unicode('', help=
468 """
470 """
469 Start logging to the given file in append mode.
471 Start logging to the given file in append mode.
470 Use `logfile` to specify a log file to **overwrite** logs to.
472 Use `logfile` to specify a log file to **overwrite** logs to.
471 """
473 """
472 ).tag(config=True)
474 ).tag(config=True)
473 object_info_string_level = Enum((0,1,2), default_value=0,
475 object_info_string_level = Enum((0,1,2), default_value=0,
474 ).tag(config=True)
476 ).tag(config=True)
475 pdb = Bool(False, help=
477 pdb = Bool(False, help=
476 """
478 """
477 Automatically call the pdb debugger after every exception.
479 Automatically call the pdb debugger after every exception.
478 """
480 """
479 ).tag(config=True)
481 ).tag(config=True)
480 display_page = Bool(False,
482 display_page = Bool(False,
481 help="""If True, anything that would be passed to the pager
483 help="""If True, anything that would be passed to the pager
482 will be displayed as regular output instead."""
484 will be displayed as regular output instead."""
483 ).tag(config=True)
485 ).tag(config=True)
484
486
485
487
486 show_rewritten_input = Bool(True,
488 show_rewritten_input = Bool(True,
487 help="Show rewritten input, e.g. for autocall."
489 help="Show rewritten input, e.g. for autocall."
488 ).tag(config=True)
490 ).tag(config=True)
489
491
490 quiet = Bool(False).tag(config=True)
492 quiet = Bool(False).tag(config=True)
491
493
492 history_length = Integer(10000,
494 history_length = Integer(10000,
493 help='Total length of command history'
495 help='Total length of command history'
494 ).tag(config=True)
496 ).tag(config=True)
495
497
496 history_load_length = Integer(1000, help=
498 history_load_length = Integer(1000, help=
497 """
499 """
498 The number of saved history entries to be loaded
500 The number of saved history entries to be loaded
499 into the history buffer at startup.
501 into the history buffer at startup.
500 """
502 """
501 ).tag(config=True)
503 ).tag(config=True)
502
504
503 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'],
505 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'],
504 default_value='last_expr',
506 default_value='last_expr',
505 help="""
507 help="""
506 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying
508 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying
507 which nodes should be run interactively (displaying output from expressions).
509 which nodes should be run interactively (displaying output from expressions).
508 """
510 """
509 ).tag(config=True)
511 ).tag(config=True)
510
512
511 warn_venv = Bool(
513 warn_venv = Bool(
512 True,
514 True,
513 help="Warn if running in a virtual environment with no IPython installed (so IPython from the global environment is used).",
515 help="Warn if running in a virtual environment with no IPython installed (so IPython from the global environment is used).",
514 ).tag(config=True)
516 ).tag(config=True)
515
517
516 # TODO: this part of prompt management should be moved to the frontends.
518 # TODO: this part of prompt management should be moved to the frontends.
517 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
519 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
518 separate_in = SeparateUnicode('\n').tag(config=True)
520 separate_in = SeparateUnicode('\n').tag(config=True)
519 separate_out = SeparateUnicode('').tag(config=True)
521 separate_out = SeparateUnicode('').tag(config=True)
520 separate_out2 = SeparateUnicode('').tag(config=True)
522 separate_out2 = SeparateUnicode('').tag(config=True)
521 wildcards_case_sensitive = Bool(True).tag(config=True)
523 wildcards_case_sensitive = Bool(True).tag(config=True)
522 xmode = CaselessStrEnum(('Context', 'Plain', 'Verbose', 'Minimal'),
524 xmode = CaselessStrEnum(('Context', 'Plain', 'Verbose', 'Minimal'),
523 default_value='Context',
525 default_value='Context',
524 help="Switch modes for the IPython exception handlers."
526 help="Switch modes for the IPython exception handlers."
525 ).tag(config=True)
527 ).tag(config=True)
526
528
527 # Subcomponents of InteractiveShell
529 # Subcomponents of InteractiveShell
528 alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True)
530 alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True)
529 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
531 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
530 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap', allow_none=True)
532 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap', allow_none=True)
531 display_trap = Instance('IPython.core.display_trap.DisplayTrap', allow_none=True)
533 display_trap = Instance('IPython.core.display_trap.DisplayTrap', allow_none=True)
532 extension_manager = Instance('IPython.core.extensions.ExtensionManager', allow_none=True)
534 extension_manager = Instance('IPython.core.extensions.ExtensionManager', allow_none=True)
533 payload_manager = Instance('IPython.core.payload.PayloadManager', allow_none=True)
535 payload_manager = Instance('IPython.core.payload.PayloadManager', allow_none=True)
534 history_manager = Instance('IPython.core.history.HistoryAccessorBase', allow_none=True)
536 history_manager = Instance('IPython.core.history.HistoryAccessorBase', allow_none=True)
535 magics_manager = Instance('IPython.core.magic.MagicsManager', allow_none=True)
537 magics_manager = Instance('IPython.core.magic.MagicsManager', allow_none=True)
536
538
537 profile_dir = Instance('IPython.core.application.ProfileDir', allow_none=True)
539 profile_dir = Instance('IPython.core.application.ProfileDir', allow_none=True)
538 @property
540 @property
539 def profile(self):
541 def profile(self):
540 if self.profile_dir is not None:
542 if self.profile_dir is not None:
541 name = os.path.basename(self.profile_dir.location)
543 name = os.path.basename(self.profile_dir.location)
542 return name.replace('profile_','')
544 return name.replace('profile_','')
543
545
544
546
545 # Private interface
547 # Private interface
546 _post_execute = Dict()
548 _post_execute = Dict()
547
549
548 # Tracks any GUI loop loaded for pylab
550 # Tracks any GUI loop loaded for pylab
549 pylab_gui_select = None
551 pylab_gui_select = None
550
552
551 last_execution_succeeded = Bool(True, help='Did last executed command succeeded')
553 last_execution_succeeded = Bool(True, help='Did last executed command succeeded')
552
554
553 last_execution_result = Instance('IPython.core.interactiveshell.ExecutionResult', help='Result of executing the last command', allow_none=True)
555 last_execution_result = Instance('IPython.core.interactiveshell.ExecutionResult', help='Result of executing the last command', allow_none=True)
554
556
555 def __init__(self, ipython_dir=None, profile_dir=None,
557 def __init__(self, ipython_dir=None, profile_dir=None,
556 user_module=None, user_ns=None,
558 user_module=None, user_ns=None,
557 custom_exceptions=((), None), **kwargs):
559 custom_exceptions=((), None), **kwargs):
558 # This is where traits with a config_key argument are updated
560 # This is where traits with a config_key argument are updated
559 # from the values on config.
561 # from the values on config.
560 super(InteractiveShell, self).__init__(**kwargs)
562 super(InteractiveShell, self).__init__(**kwargs)
561 if 'PromptManager' in self.config:
563 if 'PromptManager' in self.config:
562 warn('As of IPython 5.0 `PromptManager` config will have no effect'
564 warn('As of IPython 5.0 `PromptManager` config will have no effect'
563 ' and has been replaced by TerminalInteractiveShell.prompts_class')
565 ' and has been replaced by TerminalInteractiveShell.prompts_class')
564 self.configurables = [self]
566 self.configurables = [self]
565
567
566 # These are relatively independent and stateless
568 # These are relatively independent and stateless
567 self.init_ipython_dir(ipython_dir)
569 self.init_ipython_dir(ipython_dir)
568 self.init_profile_dir(profile_dir)
570 self.init_profile_dir(profile_dir)
569 self.init_instance_attrs()
571 self.init_instance_attrs()
570 self.init_environment()
572 self.init_environment()
571
573
572 # Check if we're in a virtualenv, and set up sys.path.
574 # Check if we're in a virtualenv, and set up sys.path.
573 self.init_virtualenv()
575 self.init_virtualenv()
574
576
575 # Create namespaces (user_ns, user_global_ns, etc.)
577 # Create namespaces (user_ns, user_global_ns, etc.)
576 self.init_create_namespaces(user_module, user_ns)
578 self.init_create_namespaces(user_module, user_ns)
577 # This has to be done after init_create_namespaces because it uses
579 # This has to be done after init_create_namespaces because it uses
578 # something in self.user_ns, but before init_sys_modules, which
580 # something in self.user_ns, but before init_sys_modules, which
579 # is the first thing to modify sys.
581 # is the first thing to modify sys.
580 # TODO: When we override sys.stdout and sys.stderr before this class
582 # TODO: When we override sys.stdout and sys.stderr before this class
581 # is created, we are saving the overridden ones here. Not sure if this
583 # is created, we are saving the overridden ones here. Not sure if this
582 # is what we want to do.
584 # is what we want to do.
583 self.save_sys_module_state()
585 self.save_sys_module_state()
584 self.init_sys_modules()
586 self.init_sys_modules()
585
587
586 # While we're trying to have each part of the code directly access what
588 # While we're trying to have each part of the code directly access what
587 # it needs without keeping redundant references to objects, we have too
589 # it needs without keeping redundant references to objects, we have too
588 # much legacy code that expects ip.db to exist.
590 # much legacy code that expects ip.db to exist.
589 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
591 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
590
592
591 self.init_history()
593 self.init_history()
592 self.init_encoding()
594 self.init_encoding()
593 self.init_prefilter()
595 self.init_prefilter()
594
596
595 self.init_syntax_highlighting()
597 self.init_syntax_highlighting()
596 self.init_hooks()
598 self.init_hooks()
597 self.init_events()
599 self.init_events()
598 self.init_pushd_popd_magic()
600 self.init_pushd_popd_magic()
599 self.init_user_ns()
601 self.init_user_ns()
600 self.init_logger()
602 self.init_logger()
601 self.init_builtins()
603 self.init_builtins()
602
604
603 # The following was in post_config_initialization
605 # The following was in post_config_initialization
604 self.init_inspector()
606 self.init_inspector()
605 self.raw_input_original = input
607 self.raw_input_original = input
606 self.init_completer()
608 self.init_completer()
607 # TODO: init_io() needs to happen before init_traceback handlers
609 # TODO: init_io() needs to happen before init_traceback handlers
608 # because the traceback handlers hardcode the stdout/stderr streams.
610 # because the traceback handlers hardcode the stdout/stderr streams.
609 # This logic in in debugger.Pdb and should eventually be changed.
611 # This logic in in debugger.Pdb and should eventually be changed.
610 self.init_io()
612 self.init_io()
611 self.init_traceback_handlers(custom_exceptions)
613 self.init_traceback_handlers(custom_exceptions)
612 self.init_prompts()
614 self.init_prompts()
613 self.init_display_formatter()
615 self.init_display_formatter()
614 self.init_display_pub()
616 self.init_display_pub()
615 self.init_data_pub()
617 self.init_data_pub()
616 self.init_displayhook()
618 self.init_displayhook()
617 self.init_magics()
619 self.init_magics()
618 self.init_alias()
620 self.init_alias()
619 self.init_logstart()
621 self.init_logstart()
620 self.init_pdb()
622 self.init_pdb()
621 self.init_extension_manager()
623 self.init_extension_manager()
622 self.init_payload()
624 self.init_payload()
623 self.events.trigger('shell_initialized', self)
625 self.events.trigger('shell_initialized', self)
624 atexit.register(self.atexit_operations)
626 atexit.register(self.atexit_operations)
625
627
626 # The trio runner is used for running Trio in the foreground thread. It
628 # The trio runner is used for running Trio in the foreground thread. It
627 # is different from `_trio_runner(async_fn)` in `async_helpers.py`
629 # is different from `_trio_runner(async_fn)` in `async_helpers.py`
628 # which calls `trio.run()` for every cell. This runner runs all cells
630 # which calls `trio.run()` for every cell. This runner runs all cells
629 # inside a single Trio event loop. If used, it is set from
631 # inside a single Trio event loop. If used, it is set from
630 # `ipykernel.kernelapp`.
632 # `ipykernel.kernelapp`.
631 self.trio_runner = None
633 self.trio_runner = None
632
634
633 def get_ipython(self):
635 def get_ipython(self):
634 """Return the currently running IPython instance."""
636 """Return the currently running IPython instance."""
635 return self
637 return self
636
638
637 #-------------------------------------------------------------------------
639 #-------------------------------------------------------------------------
638 # Trait changed handlers
640 # Trait changed handlers
639 #-------------------------------------------------------------------------
641 #-------------------------------------------------------------------------
640 @observe('ipython_dir')
642 @observe('ipython_dir')
641 def _ipython_dir_changed(self, change):
643 def _ipython_dir_changed(self, change):
642 ensure_dir_exists(change['new'])
644 ensure_dir_exists(change['new'])
643
645
644 def set_autoindent(self,value=None):
646 def set_autoindent(self,value=None):
645 """Set the autoindent flag.
647 """Set the autoindent flag.
646
648
647 If called with no arguments, it acts as a toggle."""
649 If called with no arguments, it acts as a toggle."""
648 if value is None:
650 if value is None:
649 self.autoindent = not self.autoindent
651 self.autoindent = not self.autoindent
650 else:
652 else:
651 self.autoindent = value
653 self.autoindent = value
652
654
653 def set_trio_runner(self, tr):
655 def set_trio_runner(self, tr):
654 self.trio_runner = tr
656 self.trio_runner = tr
655
657
656 #-------------------------------------------------------------------------
658 #-------------------------------------------------------------------------
657 # init_* methods called by __init__
659 # init_* methods called by __init__
658 #-------------------------------------------------------------------------
660 #-------------------------------------------------------------------------
659
661
660 def init_ipython_dir(self, ipython_dir):
662 def init_ipython_dir(self, ipython_dir):
661 if ipython_dir is not None:
663 if ipython_dir is not None:
662 self.ipython_dir = ipython_dir
664 self.ipython_dir = ipython_dir
663 return
665 return
664
666
665 self.ipython_dir = get_ipython_dir()
667 self.ipython_dir = get_ipython_dir()
666
668
667 def init_profile_dir(self, profile_dir):
669 def init_profile_dir(self, profile_dir):
668 if profile_dir is not None:
670 if profile_dir is not None:
669 self.profile_dir = profile_dir
671 self.profile_dir = profile_dir
670 return
672 return
671 self.profile_dir = ProfileDir.create_profile_dir_by_name(
673 self.profile_dir = ProfileDir.create_profile_dir_by_name(
672 self.ipython_dir, "default"
674 self.ipython_dir, "default"
673 )
675 )
674
676
675 def init_instance_attrs(self):
677 def init_instance_attrs(self):
676 self.more = False
678 self.more = False
677
679
678 # command compiler
680 # command compiler
679 self.compile = self.compiler_class()
681 self.compile = self.compiler_class()
680
682
681 # Make an empty namespace, which extension writers can rely on both
683 # Make an empty namespace, which extension writers can rely on both
682 # existing and NEVER being used by ipython itself. This gives them a
684 # existing and NEVER being used by ipython itself. This gives them a
683 # convenient location for storing additional information and state
685 # convenient location for storing additional information and state
684 # their extensions may require, without fear of collisions with other
686 # their extensions may require, without fear of collisions with other
685 # ipython names that may develop later.
687 # ipython names that may develop later.
686 self.meta = Struct()
688 self.meta = Struct()
687
689
688 # Temporary files used for various purposes. Deleted at exit.
690 # Temporary files used for various purposes. Deleted at exit.
689 # The files here are stored with Path from Pathlib
691 # The files here are stored with Path from Pathlib
690 self.tempfiles = []
692 self.tempfiles = []
691 self.tempdirs = []
693 self.tempdirs = []
692
694
693 # keep track of where we started running (mainly for crash post-mortem)
695 # keep track of where we started running (mainly for crash post-mortem)
694 # This is not being used anywhere currently.
696 # This is not being used anywhere currently.
695 self.starting_dir = os.getcwd()
697 self.starting_dir = os.getcwd()
696
698
697 # Indentation management
699 # Indentation management
698 self.indent_current_nsp = 0
700 self.indent_current_nsp = 0
699
701
700 # Dict to track post-execution functions that have been registered
702 # Dict to track post-execution functions that have been registered
701 self._post_execute = {}
703 self._post_execute = {}
702
704
703 def init_environment(self):
705 def init_environment(self):
704 """Any changes we need to make to the user's environment."""
706 """Any changes we need to make to the user's environment."""
705 pass
707 pass
706
708
707 def init_encoding(self):
709 def init_encoding(self):
708 # Get system encoding at startup time. Certain terminals (like Emacs
710 # Get system encoding at startup time. Certain terminals (like Emacs
709 # under Win32 have it set to None, and we need to have a known valid
711 # under Win32 have it set to None, and we need to have a known valid
710 # encoding to use in the raw_input() method
712 # encoding to use in the raw_input() method
711 try:
713 try:
712 self.stdin_encoding = sys.stdin.encoding or 'ascii'
714 self.stdin_encoding = sys.stdin.encoding or 'ascii'
713 except AttributeError:
715 except AttributeError:
714 self.stdin_encoding = 'ascii'
716 self.stdin_encoding = 'ascii'
715
717
716
718
717 @observe('colors')
719 @observe('colors')
718 def init_syntax_highlighting(self, changes=None):
720 def init_syntax_highlighting(self, changes=None):
719 # Python source parser/formatter for syntax highlighting
721 # Python source parser/formatter for syntax highlighting
720 pyformat = PyColorize.Parser(style=self.colors, parent=self).format
722 pyformat = PyColorize.Parser(style=self.colors, parent=self).format
721 self.pycolorize = lambda src: pyformat(src,'str')
723 self.pycolorize = lambda src: pyformat(src,'str')
722
724
723 def refresh_style(self):
725 def refresh_style(self):
724 # No-op here, used in subclass
726 # No-op here, used in subclass
725 pass
727 pass
726
728
727 def init_pushd_popd_magic(self):
729 def init_pushd_popd_magic(self):
728 # for pushd/popd management
730 # for pushd/popd management
729 self.home_dir = get_home_dir()
731 self.home_dir = get_home_dir()
730
732
731 self.dir_stack = []
733 self.dir_stack = []
732
734
733 def init_logger(self):
735 def init_logger(self):
734 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
736 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
735 logmode='rotate')
737 logmode='rotate')
736
738
737 def init_logstart(self):
739 def init_logstart(self):
738 """Initialize logging in case it was requested at the command line.
740 """Initialize logging in case it was requested at the command line.
739 """
741 """
740 if self.logappend:
742 if self.logappend:
741 self.magic('logstart %s append' % self.logappend)
743 self.magic('logstart %s append' % self.logappend)
742 elif self.logfile:
744 elif self.logfile:
743 self.magic('logstart %s' % self.logfile)
745 self.magic('logstart %s' % self.logfile)
744 elif self.logstart:
746 elif self.logstart:
745 self.magic('logstart')
747 self.magic('logstart')
746
748
747
749
748 def init_builtins(self):
750 def init_builtins(self):
749 # A single, static flag that we set to True. Its presence indicates
751 # A single, static flag that we set to True. Its presence indicates
750 # that an IPython shell has been created, and we make no attempts at
752 # that an IPython shell has been created, and we make no attempts at
751 # removing on exit or representing the existence of more than one
753 # removing on exit or representing the existence of more than one
752 # IPython at a time.
754 # IPython at a time.
753 builtin_mod.__dict__['__IPYTHON__'] = True
755 builtin_mod.__dict__['__IPYTHON__'] = True
754 builtin_mod.__dict__['display'] = display
756 builtin_mod.__dict__['display'] = display
755
757
756 self.builtin_trap = BuiltinTrap(shell=self)
758 self.builtin_trap = BuiltinTrap(shell=self)
757
759
758 @observe('colors')
760 @observe('colors')
759 def init_inspector(self, changes=None):
761 def init_inspector(self, changes=None):
760 # Object inspector
762 # Object inspector
761 self.inspector = self.inspector_class(
763 self.inspector = self.inspector_class(
762 oinspect.InspectColors,
764 oinspect.InspectColors,
763 PyColorize.ANSICodeColors,
765 PyColorize.ANSICodeColors,
764 self.colors,
766 self.colors,
765 self.object_info_string_level,
767 self.object_info_string_level,
766 )
768 )
767
769
768 def init_io(self):
770 def init_io(self):
769 # implemented in subclasses, TerminalInteractiveShell does call
771 # implemented in subclasses, TerminalInteractiveShell does call
770 # colorama.init().
772 # colorama.init().
771 pass
773 pass
772
774
773 def init_prompts(self):
775 def init_prompts(self):
774 # Set system prompts, so that scripts can decide if they are running
776 # Set system prompts, so that scripts can decide if they are running
775 # interactively.
777 # interactively.
776 sys.ps1 = 'In : '
778 sys.ps1 = 'In : '
777 sys.ps2 = '...: '
779 sys.ps2 = '...: '
778 sys.ps3 = 'Out: '
780 sys.ps3 = 'Out: '
779
781
780 def init_display_formatter(self):
782 def init_display_formatter(self):
781 self.display_formatter = DisplayFormatter(parent=self)
783 self.display_formatter = DisplayFormatter(parent=self)
782 self.configurables.append(self.display_formatter)
784 self.configurables.append(self.display_formatter)
783
785
784 def init_display_pub(self):
786 def init_display_pub(self):
785 self.display_pub = self.display_pub_class(parent=self, shell=self)
787 self.display_pub = self.display_pub_class(parent=self, shell=self)
786 self.configurables.append(self.display_pub)
788 self.configurables.append(self.display_pub)
787
789
788 def init_data_pub(self):
790 def init_data_pub(self):
789 if not self.data_pub_class:
791 if not self.data_pub_class:
790 self.data_pub = None
792 self.data_pub = None
791 return
793 return
792 self.data_pub = self.data_pub_class(parent=self)
794 self.data_pub = self.data_pub_class(parent=self)
793 self.configurables.append(self.data_pub)
795 self.configurables.append(self.data_pub)
794
796
795 def init_displayhook(self):
797 def init_displayhook(self):
796 # Initialize displayhook, set in/out prompts and printing system
798 # Initialize displayhook, set in/out prompts and printing system
797 self.displayhook = self.displayhook_class(
799 self.displayhook = self.displayhook_class(
798 parent=self,
800 parent=self,
799 shell=self,
801 shell=self,
800 cache_size=self.cache_size,
802 cache_size=self.cache_size,
801 )
803 )
802 self.configurables.append(self.displayhook)
804 self.configurables.append(self.displayhook)
803 # This is a context manager that installs/revmoes the displayhook at
805 # This is a context manager that installs/revmoes the displayhook at
804 # the appropriate time.
806 # the appropriate time.
805 self.display_trap = DisplayTrap(hook=self.displayhook)
807 self.display_trap = DisplayTrap(hook=self.displayhook)
806
808
807 @staticmethod
809 @staticmethod
808 def get_path_links(p: Path):
810 def get_path_links(p: Path):
809 """Gets path links including all symlinks
811 """Gets path links including all symlinks
810
812
811 Examples
813 Examples
812 --------
814 --------
813 In [1]: from IPython.core.interactiveshell import InteractiveShell
815 In [1]: from IPython.core.interactiveshell import InteractiveShell
814
816
815 In [2]: import sys, pathlib
817 In [2]: import sys, pathlib
816
818
817 In [3]: paths = InteractiveShell.get_path_links(pathlib.Path(sys.executable))
819 In [3]: paths = InteractiveShell.get_path_links(pathlib.Path(sys.executable))
818
820
819 In [4]: len(paths) == len(set(paths))
821 In [4]: len(paths) == len(set(paths))
820 Out[4]: True
822 Out[4]: True
821
823
822 In [5]: bool(paths)
824 In [5]: bool(paths)
823 Out[5]: True
825 Out[5]: True
824 """
826 """
825 paths = [p]
827 paths = [p]
826 while p.is_symlink():
828 while p.is_symlink():
827 new_path = Path(os.readlink(p))
829 new_path = Path(os.readlink(p))
828 if not new_path.is_absolute():
830 if not new_path.is_absolute():
829 new_path = p.parent / new_path
831 new_path = p.parent / new_path
830 p = new_path
832 p = new_path
831 paths.append(p)
833 paths.append(p)
832 return paths
834 return paths
833
835
834 def init_virtualenv(self):
836 def init_virtualenv(self):
835 """Add the current virtualenv to sys.path so the user can import modules from it.
837 """Add the current virtualenv to sys.path so the user can import modules from it.
836 This isn't perfect: it doesn't use the Python interpreter with which the
838 This isn't perfect: it doesn't use the Python interpreter with which the
837 virtualenv was built, and it ignores the --no-site-packages option. A
839 virtualenv was built, and it ignores the --no-site-packages option. A
838 warning will appear suggesting the user installs IPython in the
840 warning will appear suggesting the user installs IPython in the
839 virtualenv, but for many cases, it probably works well enough.
841 virtualenv, but for many cases, it probably works well enough.
840
842
841 Adapted from code snippets online.
843 Adapted from code snippets online.
842
844
843 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
845 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
844 """
846 """
845 if 'VIRTUAL_ENV' not in os.environ:
847 if 'VIRTUAL_ENV' not in os.environ:
846 # Not in a virtualenv
848 # Not in a virtualenv
847 return
849 return
848 elif os.environ["VIRTUAL_ENV"] == "":
850 elif os.environ["VIRTUAL_ENV"] == "":
849 warn("Virtual env path set to '', please check if this is intended.")
851 warn("Virtual env path set to '', please check if this is intended.")
850 return
852 return
851
853
852 p = Path(sys.executable)
854 p = Path(sys.executable)
853 p_venv = Path(os.environ["VIRTUAL_ENV"])
855 p_venv = Path(os.environ["VIRTUAL_ENV"])
854
856
855 # fallback venv detection:
857 # fallback venv detection:
856 # stdlib venv may symlink sys.executable, so we can't use realpath.
858 # stdlib venv may symlink sys.executable, so we can't use realpath.
857 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
859 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
858 # So we just check every item in the symlink tree (generally <= 3)
860 # So we just check every item in the symlink tree (generally <= 3)
859 paths = self.get_path_links(p)
861 paths = self.get_path_links(p)
860
862
861 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
863 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
862 if p_venv.parts[1] == "cygdrive":
864 if p_venv.parts[1] == "cygdrive":
863 drive_name = p_venv.parts[2]
865 drive_name = p_venv.parts[2]
864 p_venv = (drive_name + ":/") / Path(*p_venv.parts[3:])
866 p_venv = (drive_name + ":/") / Path(*p_venv.parts[3:])
865
867
866 if any(p_venv == p.parents[1] for p in paths):
868 if any(p_venv == p.parents[1] for p in paths):
867 # Our exe is inside or has access to the virtualenv, don't need to do anything.
869 # Our exe is inside or has access to the virtualenv, don't need to do anything.
868 return
870 return
869
871
870 if sys.platform == "win32":
872 if sys.platform == "win32":
871 virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages"))
873 virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages"))
872 else:
874 else:
873 virtual_env_path = Path(
875 virtual_env_path = Path(
874 os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
876 os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
875 )
877 )
876 p_ver = sys.version_info[:2]
878 p_ver = sys.version_info[:2]
877
879
878 # Predict version from py[thon]-x.x in the $VIRTUAL_ENV
880 # Predict version from py[thon]-x.x in the $VIRTUAL_ENV
879 re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
881 re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
880 if re_m:
882 if re_m:
881 predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
883 predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
882 if predicted_path.exists():
884 if predicted_path.exists():
883 p_ver = re_m.groups()
885 p_ver = re_m.groups()
884
886
885 virtual_env = str(virtual_env_path).format(*p_ver)
887 virtual_env = str(virtual_env_path).format(*p_ver)
886 if self.warn_venv:
888 if self.warn_venv:
887 warn(
889 warn(
888 "Attempting to work in a virtualenv. If you encounter problems, "
890 "Attempting to work in a virtualenv. If you encounter problems, "
889 "please install IPython inside the virtualenv."
891 "please install IPython inside the virtualenv."
890 )
892 )
891 import site
893 import site
892 sys.path.insert(0, virtual_env)
894 sys.path.insert(0, virtual_env)
893 site.addsitedir(virtual_env)
895 site.addsitedir(virtual_env)
894
896
895 #-------------------------------------------------------------------------
897 #-------------------------------------------------------------------------
896 # Things related to injections into the sys module
898 # Things related to injections into the sys module
897 #-------------------------------------------------------------------------
899 #-------------------------------------------------------------------------
898
900
899 def save_sys_module_state(self):
901 def save_sys_module_state(self):
900 """Save the state of hooks in the sys module.
902 """Save the state of hooks in the sys module.
901
903
902 This has to be called after self.user_module is created.
904 This has to be called after self.user_module is created.
903 """
905 """
904 self._orig_sys_module_state = {'stdin': sys.stdin,
906 self._orig_sys_module_state = {'stdin': sys.stdin,
905 'stdout': sys.stdout,
907 'stdout': sys.stdout,
906 'stderr': sys.stderr,
908 'stderr': sys.stderr,
907 'excepthook': sys.excepthook}
909 'excepthook': sys.excepthook}
908 self._orig_sys_modules_main_name = self.user_module.__name__
910 self._orig_sys_modules_main_name = self.user_module.__name__
909 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
911 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
910
912
911 def restore_sys_module_state(self):
913 def restore_sys_module_state(self):
912 """Restore the state of the sys module."""
914 """Restore the state of the sys module."""
913 try:
915 try:
914 for k, v in self._orig_sys_module_state.items():
916 for k, v in self._orig_sys_module_state.items():
915 setattr(sys, k, v)
917 setattr(sys, k, v)
916 except AttributeError:
918 except AttributeError:
917 pass
919 pass
918 # Reset what what done in self.init_sys_modules
920 # Reset what what done in self.init_sys_modules
919 if self._orig_sys_modules_main_mod is not None:
921 if self._orig_sys_modules_main_mod is not None:
920 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
922 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
921
923
922 #-------------------------------------------------------------------------
924 #-------------------------------------------------------------------------
923 # Things related to the banner
925 # Things related to the banner
924 #-------------------------------------------------------------------------
926 #-------------------------------------------------------------------------
925
927
926 @property
928 @property
927 def banner(self):
929 def banner(self):
928 banner = self.banner1
930 banner = self.banner1
929 if self.profile and self.profile != 'default':
931 if self.profile and self.profile != 'default':
930 banner += '\nIPython profile: %s\n' % self.profile
932 banner += '\nIPython profile: %s\n' % self.profile
931 if self.banner2:
933 if self.banner2:
932 banner += '\n' + self.banner2
934 banner += '\n' + self.banner2
933 return banner
935 return banner
934
936
935 def show_banner(self, banner=None):
937 def show_banner(self, banner=None):
936 if banner is None:
938 if banner is None:
937 banner = self.banner
939 banner = self.banner
938 sys.stdout.write(banner)
940 sys.stdout.write(banner)
939
941
940 #-------------------------------------------------------------------------
942 #-------------------------------------------------------------------------
941 # Things related to hooks
943 # Things related to hooks
942 #-------------------------------------------------------------------------
944 #-------------------------------------------------------------------------
943
945
944 def init_hooks(self):
946 def init_hooks(self):
945 # hooks holds pointers used for user-side customizations
947 # hooks holds pointers used for user-side customizations
946 self.hooks = Struct()
948 self.hooks = Struct()
947
949
948 self.strdispatchers = {}
950 self.strdispatchers = {}
949
951
950 # Set all default hooks, defined in the IPython.hooks module.
952 # Set all default hooks, defined in the IPython.hooks module.
951 hooks = IPython.core.hooks
953 hooks = IPython.core.hooks
952 for hook_name in hooks.__all__:
954 for hook_name in hooks.__all__:
953 # default hooks have priority 100, i.e. low; user hooks should have
955 # default hooks have priority 100, i.e. low; user hooks should have
954 # 0-100 priority
956 # 0-100 priority
955 self.set_hook(hook_name, getattr(hooks, hook_name), 100)
957 self.set_hook(hook_name, getattr(hooks, hook_name), 100)
956
958
957 if self.display_page:
959 if self.display_page:
958 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
960 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
959
961
960 def set_hook(self, name, hook, priority=50, str_key=None, re_key=None):
962 def set_hook(self, name, hook, priority=50, str_key=None, re_key=None):
961 """set_hook(name,hook) -> sets an internal IPython hook.
963 """set_hook(name,hook) -> sets an internal IPython hook.
962
964
963 IPython exposes some of its internal API as user-modifiable hooks. By
965 IPython exposes some of its internal API as user-modifiable hooks. By
964 adding your function to one of these hooks, you can modify IPython's
966 adding your function to one of these hooks, you can modify IPython's
965 behavior to call at runtime your own routines."""
967 behavior to call at runtime your own routines."""
966
968
967 # At some point in the future, this should validate the hook before it
969 # At some point in the future, this should validate the hook before it
968 # accepts it. Probably at least check that the hook takes the number
970 # accepts it. Probably at least check that the hook takes the number
969 # of args it's supposed to.
971 # of args it's supposed to.
970
972
971 f = types.MethodType(hook,self)
973 f = types.MethodType(hook,self)
972
974
973 # check if the hook is for strdispatcher first
975 # check if the hook is for strdispatcher first
974 if str_key is not None:
976 if str_key is not None:
975 sdp = self.strdispatchers.get(name, StrDispatch())
977 sdp = self.strdispatchers.get(name, StrDispatch())
976 sdp.add_s(str_key, f, priority )
978 sdp.add_s(str_key, f, priority )
977 self.strdispatchers[name] = sdp
979 self.strdispatchers[name] = sdp
978 return
980 return
979 if re_key is not None:
981 if re_key is not None:
980 sdp = self.strdispatchers.get(name, StrDispatch())
982 sdp = self.strdispatchers.get(name, StrDispatch())
981 sdp.add_re(re.compile(re_key), f, priority )
983 sdp.add_re(re.compile(re_key), f, priority )
982 self.strdispatchers[name] = sdp
984 self.strdispatchers[name] = sdp
983 return
985 return
984
986
985 dp = getattr(self.hooks, name, None)
987 dp = getattr(self.hooks, name, None)
986 if name not in IPython.core.hooks.__all__:
988 if name not in IPython.core.hooks.__all__:
987 print("Warning! Hook '%s' is not one of %s" % \
989 print("Warning! Hook '%s' is not one of %s" % \
988 (name, IPython.core.hooks.__all__ ))
990 (name, IPython.core.hooks.__all__ ))
989
991
990 if name in IPython.core.hooks.deprecated:
992 if name in IPython.core.hooks.deprecated:
991 alternative = IPython.core.hooks.deprecated[name]
993 alternative = IPython.core.hooks.deprecated[name]
992 raise ValueError(
994 raise ValueError(
993 "Hook {} has been deprecated since IPython 5.0. Use {} instead.".format(
995 "Hook {} has been deprecated since IPython 5.0. Use {} instead.".format(
994 name, alternative
996 name, alternative
995 )
997 )
996 )
998 )
997
999
998 if not dp:
1000 if not dp:
999 dp = IPython.core.hooks.CommandChainDispatcher()
1001 dp = IPython.core.hooks.CommandChainDispatcher()
1000
1002
1001 try:
1003 try:
1002 dp.add(f,priority)
1004 dp.add(f,priority)
1003 except AttributeError:
1005 except AttributeError:
1004 # it was not commandchain, plain old func - replace
1006 # it was not commandchain, plain old func - replace
1005 dp = f
1007 dp = f
1006
1008
1007 setattr(self.hooks,name, dp)
1009 setattr(self.hooks,name, dp)
1008
1010
1009 #-------------------------------------------------------------------------
1011 #-------------------------------------------------------------------------
1010 # Things related to events
1012 # Things related to events
1011 #-------------------------------------------------------------------------
1013 #-------------------------------------------------------------------------
1012
1014
1013 def init_events(self):
1015 def init_events(self):
1014 self.events = EventManager(self, available_events)
1016 self.events = EventManager(self, available_events)
1015
1017
1016 self.events.register("pre_execute", self._clear_warning_registry)
1018 self.events.register("pre_execute", self._clear_warning_registry)
1017
1019
1018 def register_post_execute(self, func):
1020 def register_post_execute(self, func):
1019 """DEPRECATED: Use ip.events.register('post_run_cell', func)
1021 """DEPRECATED: Use ip.events.register('post_run_cell', func)
1020
1022
1021 Register a function for calling after code execution.
1023 Register a function for calling after code execution.
1022 """
1024 """
1023 raise ValueError(
1025 raise ValueError(
1024 "ip.register_post_execute is deprecated since IPython 1.0, use "
1026 "ip.register_post_execute is deprecated since IPython 1.0, use "
1025 "ip.events.register('post_run_cell', func) instead."
1027 "ip.events.register('post_run_cell', func) instead."
1026 )
1028 )
1027
1029
1028 def _clear_warning_registry(self):
1030 def _clear_warning_registry(self):
1029 # clear the warning registry, so that different code blocks with
1031 # clear the warning registry, so that different code blocks with
1030 # overlapping line number ranges don't cause spurious suppression of
1032 # overlapping line number ranges don't cause spurious suppression of
1031 # warnings (see gh-6611 for details)
1033 # warnings (see gh-6611 for details)
1032 if "__warningregistry__" in self.user_global_ns:
1034 if "__warningregistry__" in self.user_global_ns:
1033 del self.user_global_ns["__warningregistry__"]
1035 del self.user_global_ns["__warningregistry__"]
1034
1036
1035 #-------------------------------------------------------------------------
1037 #-------------------------------------------------------------------------
1036 # Things related to the "main" module
1038 # Things related to the "main" module
1037 #-------------------------------------------------------------------------
1039 #-------------------------------------------------------------------------
1038
1040
1039 def new_main_mod(self, filename, modname):
1041 def new_main_mod(self, filename, modname):
1040 """Return a new 'main' module object for user code execution.
1042 """Return a new 'main' module object for user code execution.
1041
1043
1042 ``filename`` should be the path of the script which will be run in the
1044 ``filename`` should be the path of the script which will be run in the
1043 module. Requests with the same filename will get the same module, with
1045 module. Requests with the same filename will get the same module, with
1044 its namespace cleared.
1046 its namespace cleared.
1045
1047
1046 ``modname`` should be the module name - normally either '__main__' or
1048 ``modname`` should be the module name - normally either '__main__' or
1047 the basename of the file without the extension.
1049 the basename of the file without the extension.
1048
1050
1049 When scripts are executed via %run, we must keep a reference to their
1051 When scripts are executed via %run, we must keep a reference to their
1050 __main__ module around so that Python doesn't
1052 __main__ module around so that Python doesn't
1051 clear it, rendering references to module globals useless.
1053 clear it, rendering references to module globals useless.
1052
1054
1053 This method keeps said reference in a private dict, keyed by the
1055 This method keeps said reference in a private dict, keyed by the
1054 absolute path of the script. This way, for multiple executions of the
1056 absolute path of the script. This way, for multiple executions of the
1055 same script we only keep one copy of the namespace (the last one),
1057 same script we only keep one copy of the namespace (the last one),
1056 thus preventing memory leaks from old references while allowing the
1058 thus preventing memory leaks from old references while allowing the
1057 objects from the last execution to be accessible.
1059 objects from the last execution to be accessible.
1058 """
1060 """
1059 filename = os.path.abspath(filename)
1061 filename = os.path.abspath(filename)
1060 try:
1062 try:
1061 main_mod = self._main_mod_cache[filename]
1063 main_mod = self._main_mod_cache[filename]
1062 except KeyError:
1064 except KeyError:
1063 main_mod = self._main_mod_cache[filename] = types.ModuleType(
1065 main_mod = self._main_mod_cache[filename] = types.ModuleType(
1064 modname,
1066 modname,
1065 doc="Module created for script run in IPython")
1067 doc="Module created for script run in IPython")
1066 else:
1068 else:
1067 main_mod.__dict__.clear()
1069 main_mod.__dict__.clear()
1068 main_mod.__name__ = modname
1070 main_mod.__name__ = modname
1069
1071
1070 main_mod.__file__ = filename
1072 main_mod.__file__ = filename
1071 # It seems pydoc (and perhaps others) needs any module instance to
1073 # It seems pydoc (and perhaps others) needs any module instance to
1072 # implement a __nonzero__ method
1074 # implement a __nonzero__ method
1073 main_mod.__nonzero__ = lambda : True
1075 main_mod.__nonzero__ = lambda : True
1074
1076
1075 return main_mod
1077 return main_mod
1076
1078
1077 def clear_main_mod_cache(self):
1079 def clear_main_mod_cache(self):
1078 """Clear the cache of main modules.
1080 """Clear the cache of main modules.
1079
1081
1080 Mainly for use by utilities like %reset.
1082 Mainly for use by utilities like %reset.
1081
1083
1082 Examples
1084 Examples
1083 --------
1085 --------
1084 In [15]: import IPython
1086 In [15]: import IPython
1085
1087
1086 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
1088 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
1087
1089
1088 In [17]: len(_ip._main_mod_cache) > 0
1090 In [17]: len(_ip._main_mod_cache) > 0
1089 Out[17]: True
1091 Out[17]: True
1090
1092
1091 In [18]: _ip.clear_main_mod_cache()
1093 In [18]: _ip.clear_main_mod_cache()
1092
1094
1093 In [19]: len(_ip._main_mod_cache) == 0
1095 In [19]: len(_ip._main_mod_cache) == 0
1094 Out[19]: True
1096 Out[19]: True
1095 """
1097 """
1096 self._main_mod_cache.clear()
1098 self._main_mod_cache.clear()
1097
1099
1098 #-------------------------------------------------------------------------
1100 #-------------------------------------------------------------------------
1099 # Things related to debugging
1101 # Things related to debugging
1100 #-------------------------------------------------------------------------
1102 #-------------------------------------------------------------------------
1101
1103
1102 def init_pdb(self):
1104 def init_pdb(self):
1103 # Set calling of pdb on exceptions
1105 # Set calling of pdb on exceptions
1104 # self.call_pdb is a property
1106 # self.call_pdb is a property
1105 self.call_pdb = self.pdb
1107 self.call_pdb = self.pdb
1106
1108
1107 def _get_call_pdb(self):
1109 def _get_call_pdb(self):
1108 return self._call_pdb
1110 return self._call_pdb
1109
1111
1110 def _set_call_pdb(self,val):
1112 def _set_call_pdb(self,val):
1111
1113
1112 if val not in (0,1,False,True):
1114 if val not in (0,1,False,True):
1113 raise ValueError('new call_pdb value must be boolean')
1115 raise ValueError('new call_pdb value must be boolean')
1114
1116
1115 # store value in instance
1117 # store value in instance
1116 self._call_pdb = val
1118 self._call_pdb = val
1117
1119
1118 # notify the actual exception handlers
1120 # notify the actual exception handlers
1119 self.InteractiveTB.call_pdb = val
1121 self.InteractiveTB.call_pdb = val
1120
1122
1121 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
1123 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
1122 'Control auto-activation of pdb at exceptions')
1124 'Control auto-activation of pdb at exceptions')
1123
1125
1124 def debugger(self,force=False):
1126 def debugger(self,force=False):
1125 """Call the pdb debugger.
1127 """Call the pdb debugger.
1126
1128
1127 Keywords:
1129 Keywords:
1128
1130
1129 - force(False): by default, this routine checks the instance call_pdb
1131 - force(False): by default, this routine checks the instance call_pdb
1130 flag and does not actually invoke the debugger if the flag is false.
1132 flag and does not actually invoke the debugger if the flag is false.
1131 The 'force' option forces the debugger to activate even if the flag
1133 The 'force' option forces the debugger to activate even if the flag
1132 is false.
1134 is false.
1133 """
1135 """
1134
1136
1135 if not (force or self.call_pdb):
1137 if not (force or self.call_pdb):
1136 return
1138 return
1137
1139
1138 if not hasattr(sys,'last_traceback'):
1140 if not hasattr(sys,'last_traceback'):
1139 error('No traceback has been produced, nothing to debug.')
1141 error('No traceback has been produced, nothing to debug.')
1140 return
1142 return
1141
1143
1142 self.InteractiveTB.debugger(force=True)
1144 self.InteractiveTB.debugger(force=True)
1143
1145
1144 #-------------------------------------------------------------------------
1146 #-------------------------------------------------------------------------
1145 # Things related to IPython's various namespaces
1147 # Things related to IPython's various namespaces
1146 #-------------------------------------------------------------------------
1148 #-------------------------------------------------------------------------
1147 default_user_namespaces = True
1149 default_user_namespaces = True
1148
1150
1149 def init_create_namespaces(self, user_module=None, user_ns=None):
1151 def init_create_namespaces(self, user_module=None, user_ns=None):
1150 # Create the namespace where the user will operate. user_ns is
1152 # Create the namespace where the user will operate. user_ns is
1151 # normally the only one used, and it is passed to the exec calls as
1153 # normally the only one used, and it is passed to the exec calls as
1152 # the locals argument. But we do carry a user_global_ns namespace
1154 # the locals argument. But we do carry a user_global_ns namespace
1153 # given as the exec 'globals' argument, This is useful in embedding
1155 # given as the exec 'globals' argument, This is useful in embedding
1154 # situations where the ipython shell opens in a context where the
1156 # situations where the ipython shell opens in a context where the
1155 # distinction between locals and globals is meaningful. For
1157 # distinction between locals and globals is meaningful. For
1156 # non-embedded contexts, it is just the same object as the user_ns dict.
1158 # non-embedded contexts, it is just the same object as the user_ns dict.
1157
1159
1158 # FIXME. For some strange reason, __builtins__ is showing up at user
1160 # FIXME. For some strange reason, __builtins__ is showing up at user
1159 # level as a dict instead of a module. This is a manual fix, but I
1161 # level as a dict instead of a module. This is a manual fix, but I
1160 # should really track down where the problem is coming from. Alex
1162 # should really track down where the problem is coming from. Alex
1161 # Schmolck reported this problem first.
1163 # Schmolck reported this problem first.
1162
1164
1163 # A useful post by Alex Martelli on this topic:
1165 # A useful post by Alex Martelli on this topic:
1164 # Re: inconsistent value from __builtins__
1166 # Re: inconsistent value from __builtins__
1165 # Von: Alex Martelli <aleaxit@yahoo.com>
1167 # Von: Alex Martelli <aleaxit@yahoo.com>
1166 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1168 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1167 # Gruppen: comp.lang.python
1169 # Gruppen: comp.lang.python
1168
1170
1169 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1171 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1170 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1172 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1171 # > <type 'dict'>
1173 # > <type 'dict'>
1172 # > >>> print type(__builtins__)
1174 # > >>> print type(__builtins__)
1173 # > <type 'module'>
1175 # > <type 'module'>
1174 # > Is this difference in return value intentional?
1176 # > Is this difference in return value intentional?
1175
1177
1176 # Well, it's documented that '__builtins__' can be either a dictionary
1178 # Well, it's documented that '__builtins__' can be either a dictionary
1177 # or a module, and it's been that way for a long time. Whether it's
1179 # or a module, and it's been that way for a long time. Whether it's
1178 # intentional (or sensible), I don't know. In any case, the idea is
1180 # intentional (or sensible), I don't know. In any case, the idea is
1179 # that if you need to access the built-in namespace directly, you
1181 # that if you need to access the built-in namespace directly, you
1180 # should start with "import __builtin__" (note, no 's') which will
1182 # should start with "import __builtin__" (note, no 's') which will
1181 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1183 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1182
1184
1183 # These routines return a properly built module and dict as needed by
1185 # These routines return a properly built module and dict as needed by
1184 # the rest of the code, and can also be used by extension writers to
1186 # the rest of the code, and can also be used by extension writers to
1185 # generate properly initialized namespaces.
1187 # generate properly initialized namespaces.
1186 if (user_ns is not None) or (user_module is not None):
1188 if (user_ns is not None) or (user_module is not None):
1187 self.default_user_namespaces = False
1189 self.default_user_namespaces = False
1188 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1190 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1189
1191
1190 # A record of hidden variables we have added to the user namespace, so
1192 # A record of hidden variables we have added to the user namespace, so
1191 # we can list later only variables defined in actual interactive use.
1193 # we can list later only variables defined in actual interactive use.
1192 self.user_ns_hidden = {}
1194 self.user_ns_hidden = {}
1193
1195
1194 # Now that FakeModule produces a real module, we've run into a nasty
1196 # Now that FakeModule produces a real module, we've run into a nasty
1195 # problem: after script execution (via %run), the module where the user
1197 # problem: after script execution (via %run), the module where the user
1196 # code ran is deleted. Now that this object is a true module (needed
1198 # code ran is deleted. Now that this object is a true module (needed
1197 # so doctest and other tools work correctly), the Python module
1199 # so doctest and other tools work correctly), the Python module
1198 # teardown mechanism runs over it, and sets to None every variable
1200 # teardown mechanism runs over it, and sets to None every variable
1199 # present in that module. Top-level references to objects from the
1201 # present in that module. Top-level references to objects from the
1200 # script survive, because the user_ns is updated with them. However,
1202 # script survive, because the user_ns is updated with them. However,
1201 # calling functions defined in the script that use other things from
1203 # calling functions defined in the script that use other things from
1202 # the script will fail, because the function's closure had references
1204 # the script will fail, because the function's closure had references
1203 # to the original objects, which are now all None. So we must protect
1205 # to the original objects, which are now all None. So we must protect
1204 # these modules from deletion by keeping a cache.
1206 # these modules from deletion by keeping a cache.
1205 #
1207 #
1206 # To avoid keeping stale modules around (we only need the one from the
1208 # To avoid keeping stale modules around (we only need the one from the
1207 # last run), we use a dict keyed with the full path to the script, so
1209 # last run), we use a dict keyed with the full path to the script, so
1208 # only the last version of the module is held in the cache. Note,
1210 # only the last version of the module is held in the cache. Note,
1209 # however, that we must cache the module *namespace contents* (their
1211 # however, that we must cache the module *namespace contents* (their
1210 # __dict__). Because if we try to cache the actual modules, old ones
1212 # __dict__). Because if we try to cache the actual modules, old ones
1211 # (uncached) could be destroyed while still holding references (such as
1213 # (uncached) could be destroyed while still holding references (such as
1212 # those held by GUI objects that tend to be long-lived)>
1214 # those held by GUI objects that tend to be long-lived)>
1213 #
1215 #
1214 # The %reset command will flush this cache. See the cache_main_mod()
1216 # The %reset command will flush this cache. See the cache_main_mod()
1215 # and clear_main_mod_cache() methods for details on use.
1217 # and clear_main_mod_cache() methods for details on use.
1216
1218
1217 # This is the cache used for 'main' namespaces
1219 # This is the cache used for 'main' namespaces
1218 self._main_mod_cache = {}
1220 self._main_mod_cache = {}
1219
1221
1220 # A table holding all the namespaces IPython deals with, so that
1222 # A table holding all the namespaces IPython deals with, so that
1221 # introspection facilities can search easily.
1223 # introspection facilities can search easily.
1222 self.ns_table = {'user_global':self.user_module.__dict__,
1224 self.ns_table = {'user_global':self.user_module.__dict__,
1223 'user_local':self.user_ns,
1225 'user_local':self.user_ns,
1224 'builtin':builtin_mod.__dict__
1226 'builtin':builtin_mod.__dict__
1225 }
1227 }
1226
1228
1227 @property
1229 @property
1228 def user_global_ns(self):
1230 def user_global_ns(self):
1229 return self.user_module.__dict__
1231 return self.user_module.__dict__
1230
1232
1231 def prepare_user_module(self, user_module=None, user_ns=None):
1233 def prepare_user_module(self, user_module=None, user_ns=None):
1232 """Prepare the module and namespace in which user code will be run.
1234 """Prepare the module and namespace in which user code will be run.
1233
1235
1234 When IPython is started normally, both parameters are None: a new module
1236 When IPython is started normally, both parameters are None: a new module
1235 is created automatically, and its __dict__ used as the namespace.
1237 is created automatically, and its __dict__ used as the namespace.
1236
1238
1237 If only user_module is provided, its __dict__ is used as the namespace.
1239 If only user_module is provided, its __dict__ is used as the namespace.
1238 If only user_ns is provided, a dummy module is created, and user_ns
1240 If only user_ns is provided, a dummy module is created, and user_ns
1239 becomes the global namespace. If both are provided (as they may be
1241 becomes the global namespace. If both are provided (as they may be
1240 when embedding), user_ns is the local namespace, and user_module
1242 when embedding), user_ns is the local namespace, and user_module
1241 provides the global namespace.
1243 provides the global namespace.
1242
1244
1243 Parameters
1245 Parameters
1244 ----------
1246 ----------
1245 user_module : module, optional
1247 user_module : module, optional
1246 The current user module in which IPython is being run. If None,
1248 The current user module in which IPython is being run. If None,
1247 a clean module will be created.
1249 a clean module will be created.
1248 user_ns : dict, optional
1250 user_ns : dict, optional
1249 A namespace in which to run interactive commands.
1251 A namespace in which to run interactive commands.
1250
1252
1251 Returns
1253 Returns
1252 -------
1254 -------
1253 A tuple of user_module and user_ns, each properly initialised.
1255 A tuple of user_module and user_ns, each properly initialised.
1254 """
1256 """
1255 if user_module is None and user_ns is not None:
1257 if user_module is None and user_ns is not None:
1256 user_ns.setdefault("__name__", "__main__")
1258 user_ns.setdefault("__name__", "__main__")
1257 user_module = DummyMod()
1259 user_module = DummyMod()
1258 user_module.__dict__ = user_ns
1260 user_module.__dict__ = user_ns
1259
1261
1260 if user_module is None:
1262 if user_module is None:
1261 user_module = types.ModuleType("__main__",
1263 user_module = types.ModuleType("__main__",
1262 doc="Automatically created module for IPython interactive environment")
1264 doc="Automatically created module for IPython interactive environment")
1263
1265
1264 # We must ensure that __builtin__ (without the final 's') is always
1266 # We must ensure that __builtin__ (without the final 's') is always
1265 # available and pointing to the __builtin__ *module*. For more details:
1267 # available and pointing to the __builtin__ *module*. For more details:
1266 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1268 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1267 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1269 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1268 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1270 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1269
1271
1270 if user_ns is None:
1272 if user_ns is None:
1271 user_ns = user_module.__dict__
1273 user_ns = user_module.__dict__
1272
1274
1273 return user_module, user_ns
1275 return user_module, user_ns
1274
1276
1275 def init_sys_modules(self):
1277 def init_sys_modules(self):
1276 # We need to insert into sys.modules something that looks like a
1278 # We need to insert into sys.modules something that looks like a
1277 # module but which accesses the IPython namespace, for shelve and
1279 # module but which accesses the IPython namespace, for shelve and
1278 # pickle to work interactively. Normally they rely on getting
1280 # pickle to work interactively. Normally they rely on getting
1279 # everything out of __main__, but for embedding purposes each IPython
1281 # everything out of __main__, but for embedding purposes each IPython
1280 # instance has its own private namespace, so we can't go shoving
1282 # instance has its own private namespace, so we can't go shoving
1281 # everything into __main__.
1283 # everything into __main__.
1282
1284
1283 # note, however, that we should only do this for non-embedded
1285 # note, however, that we should only do this for non-embedded
1284 # ipythons, which really mimic the __main__.__dict__ with their own
1286 # ipythons, which really mimic the __main__.__dict__ with their own
1285 # namespace. Embedded instances, on the other hand, should not do
1287 # namespace. Embedded instances, on the other hand, should not do
1286 # this because they need to manage the user local/global namespaces
1288 # this because they need to manage the user local/global namespaces
1287 # only, but they live within a 'normal' __main__ (meaning, they
1289 # only, but they live within a 'normal' __main__ (meaning, they
1288 # shouldn't overtake the execution environment of the script they're
1290 # shouldn't overtake the execution environment of the script they're
1289 # embedded in).
1291 # embedded in).
1290
1292
1291 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1293 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1292 main_name = self.user_module.__name__
1294 main_name = self.user_module.__name__
1293 sys.modules[main_name] = self.user_module
1295 sys.modules[main_name] = self.user_module
1294
1296
1295 def init_user_ns(self):
1297 def init_user_ns(self):
1296 """Initialize all user-visible namespaces to their minimum defaults.
1298 """Initialize all user-visible namespaces to their minimum defaults.
1297
1299
1298 Certain history lists are also initialized here, as they effectively
1300 Certain history lists are also initialized here, as they effectively
1299 act as user namespaces.
1301 act as user namespaces.
1300
1302
1301 Notes
1303 Notes
1302 -----
1304 -----
1303 All data structures here are only filled in, they are NOT reset by this
1305 All data structures here are only filled in, they are NOT reset by this
1304 method. If they were not empty before, data will simply be added to
1306 method. If they were not empty before, data will simply be added to
1305 them.
1307 them.
1306 """
1308 """
1307 # This function works in two parts: first we put a few things in
1309 # This function works in two parts: first we put a few things in
1308 # user_ns, and we sync that contents into user_ns_hidden so that these
1310 # user_ns, and we sync that contents into user_ns_hidden so that these
1309 # initial variables aren't shown by %who. After the sync, we add the
1311 # initial variables aren't shown by %who. After the sync, we add the
1310 # rest of what we *do* want the user to see with %who even on a new
1312 # rest of what we *do* want the user to see with %who even on a new
1311 # session (probably nothing, so they really only see their own stuff)
1313 # session (probably nothing, so they really only see their own stuff)
1312
1314
1313 # The user dict must *always* have a __builtin__ reference to the
1315 # The user dict must *always* have a __builtin__ reference to the
1314 # Python standard __builtin__ namespace, which must be imported.
1316 # Python standard __builtin__ namespace, which must be imported.
1315 # This is so that certain operations in prompt evaluation can be
1317 # This is so that certain operations in prompt evaluation can be
1316 # reliably executed with builtins. Note that we can NOT use
1318 # reliably executed with builtins. Note that we can NOT use
1317 # __builtins__ (note the 's'), because that can either be a dict or a
1319 # __builtins__ (note the 's'), because that can either be a dict or a
1318 # module, and can even mutate at runtime, depending on the context
1320 # module, and can even mutate at runtime, depending on the context
1319 # (Python makes no guarantees on it). In contrast, __builtin__ is
1321 # (Python makes no guarantees on it). In contrast, __builtin__ is
1320 # always a module object, though it must be explicitly imported.
1322 # always a module object, though it must be explicitly imported.
1321
1323
1322 # For more details:
1324 # For more details:
1323 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1325 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1324 ns = {}
1326 ns = {}
1325
1327
1326 # make global variables for user access to the histories
1328 # make global variables for user access to the histories
1327 ns['_ih'] = self.history_manager.input_hist_parsed
1329 ns['_ih'] = self.history_manager.input_hist_parsed
1328 ns['_oh'] = self.history_manager.output_hist
1330 ns['_oh'] = self.history_manager.output_hist
1329 ns['_dh'] = self.history_manager.dir_hist
1331 ns['_dh'] = self.history_manager.dir_hist
1330
1332
1331 # user aliases to input and output histories. These shouldn't show up
1333 # user aliases to input and output histories. These shouldn't show up
1332 # in %who, as they can have very large reprs.
1334 # in %who, as they can have very large reprs.
1333 ns['In'] = self.history_manager.input_hist_parsed
1335 ns['In'] = self.history_manager.input_hist_parsed
1334 ns['Out'] = self.history_manager.output_hist
1336 ns['Out'] = self.history_manager.output_hist
1335
1337
1336 # Store myself as the public api!!!
1338 # Store myself as the public api!!!
1337 ns['get_ipython'] = self.get_ipython
1339 ns['get_ipython'] = self.get_ipython
1338
1340
1339 ns['exit'] = self.exiter
1341 ns['exit'] = self.exiter
1340 ns['quit'] = self.exiter
1342 ns['quit'] = self.exiter
1341 ns["open"] = _modified_open
1343 ns["open"] = _modified_open
1342
1344
1343 # Sync what we've added so far to user_ns_hidden so these aren't seen
1345 # Sync what we've added so far to user_ns_hidden so these aren't seen
1344 # by %who
1346 # by %who
1345 self.user_ns_hidden.update(ns)
1347 self.user_ns_hidden.update(ns)
1346
1348
1347 # Anything put into ns now would show up in %who. Think twice before
1349 # Anything put into ns now would show up in %who. Think twice before
1348 # putting anything here, as we really want %who to show the user their
1350 # putting anything here, as we really want %who to show the user their
1349 # stuff, not our variables.
1351 # stuff, not our variables.
1350
1352
1351 # Finally, update the real user's namespace
1353 # Finally, update the real user's namespace
1352 self.user_ns.update(ns)
1354 self.user_ns.update(ns)
1353
1355
1354 @property
1356 @property
1355 def all_ns_refs(self):
1357 def all_ns_refs(self):
1356 """Get a list of references to all the namespace dictionaries in which
1358 """Get a list of references to all the namespace dictionaries in which
1357 IPython might store a user-created object.
1359 IPython might store a user-created object.
1358
1360
1359 Note that this does not include the displayhook, which also caches
1361 Note that this does not include the displayhook, which also caches
1360 objects from the output."""
1362 objects from the output."""
1361 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1363 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1362 [m.__dict__ for m in self._main_mod_cache.values()]
1364 [m.__dict__ for m in self._main_mod_cache.values()]
1363
1365
1364 def reset(self, new_session=True, aggressive=False):
1366 def reset(self, new_session=True, aggressive=False):
1365 """Clear all internal namespaces, and attempt to release references to
1367 """Clear all internal namespaces, and attempt to release references to
1366 user objects.
1368 user objects.
1367
1369
1368 If new_session is True, a new history session will be opened.
1370 If new_session is True, a new history session will be opened.
1369 """
1371 """
1370 # Clear histories
1372 # Clear histories
1371 self.history_manager.reset(new_session)
1373 self.history_manager.reset(new_session)
1372 # Reset counter used to index all histories
1374 # Reset counter used to index all histories
1373 if new_session:
1375 if new_session:
1374 self.execution_count = 1
1376 self.execution_count = 1
1375
1377
1376 # Reset last execution result
1378 # Reset last execution result
1377 self.last_execution_succeeded = True
1379 self.last_execution_succeeded = True
1378 self.last_execution_result = None
1380 self.last_execution_result = None
1379
1381
1380 # Flush cached output items
1382 # Flush cached output items
1381 if self.displayhook.do_full_cache:
1383 if self.displayhook.do_full_cache:
1382 self.displayhook.flush()
1384 self.displayhook.flush()
1383
1385
1384 # The main execution namespaces must be cleared very carefully,
1386 # The main execution namespaces must be cleared very carefully,
1385 # skipping the deletion of the builtin-related keys, because doing so
1387 # skipping the deletion of the builtin-related keys, because doing so
1386 # would cause errors in many object's __del__ methods.
1388 # would cause errors in many object's __del__ methods.
1387 if self.user_ns is not self.user_global_ns:
1389 if self.user_ns is not self.user_global_ns:
1388 self.user_ns.clear()
1390 self.user_ns.clear()
1389 ns = self.user_global_ns
1391 ns = self.user_global_ns
1390 drop_keys = set(ns.keys())
1392 drop_keys = set(ns.keys())
1391 drop_keys.discard('__builtin__')
1393 drop_keys.discard('__builtin__')
1392 drop_keys.discard('__builtins__')
1394 drop_keys.discard('__builtins__')
1393 drop_keys.discard('__name__')
1395 drop_keys.discard('__name__')
1394 for k in drop_keys:
1396 for k in drop_keys:
1395 del ns[k]
1397 del ns[k]
1396
1398
1397 self.user_ns_hidden.clear()
1399 self.user_ns_hidden.clear()
1398
1400
1399 # Restore the user namespaces to minimal usability
1401 # Restore the user namespaces to minimal usability
1400 self.init_user_ns()
1402 self.init_user_ns()
1401 if aggressive and not hasattr(self, "_sys_modules_keys"):
1403 if aggressive and not hasattr(self, "_sys_modules_keys"):
1402 print("Cannot restore sys.module, no snapshot")
1404 print("Cannot restore sys.module, no snapshot")
1403 elif aggressive:
1405 elif aggressive:
1404 print("culling sys module...")
1406 print("culling sys module...")
1405 current_keys = set(sys.modules.keys())
1407 current_keys = set(sys.modules.keys())
1406 for k in current_keys - self._sys_modules_keys:
1408 for k in current_keys - self._sys_modules_keys:
1407 if k.startswith("multiprocessing"):
1409 if k.startswith("multiprocessing"):
1408 continue
1410 continue
1409 del sys.modules[k]
1411 del sys.modules[k]
1410
1412
1411 # Restore the default and user aliases
1413 # Restore the default and user aliases
1412 self.alias_manager.clear_aliases()
1414 self.alias_manager.clear_aliases()
1413 self.alias_manager.init_aliases()
1415 self.alias_manager.init_aliases()
1414
1416
1415 # Now define aliases that only make sense on the terminal, because they
1417 # Now define aliases that only make sense on the terminal, because they
1416 # need direct access to the console in a way that we can't emulate in
1418 # need direct access to the console in a way that we can't emulate in
1417 # GUI or web frontend
1419 # GUI or web frontend
1418 if os.name == 'posix':
1420 if os.name == 'posix':
1419 for cmd in ('clear', 'more', 'less', 'man'):
1421 for cmd in ('clear', 'more', 'less', 'man'):
1420 if cmd not in self.magics_manager.magics['line']:
1422 if cmd not in self.magics_manager.magics['line']:
1421 self.alias_manager.soft_define_alias(cmd, cmd)
1423 self.alias_manager.soft_define_alias(cmd, cmd)
1422
1424
1423 # Flush the private list of module references kept for script
1425 # Flush the private list of module references kept for script
1424 # execution protection
1426 # execution protection
1425 self.clear_main_mod_cache()
1427 self.clear_main_mod_cache()
1426
1428
1427 def del_var(self, varname, by_name=False):
1429 def del_var(self, varname, by_name=False):
1428 """Delete a variable from the various namespaces, so that, as
1430 """Delete a variable from the various namespaces, so that, as
1429 far as possible, we're not keeping any hidden references to it.
1431 far as possible, we're not keeping any hidden references to it.
1430
1432
1431 Parameters
1433 Parameters
1432 ----------
1434 ----------
1433 varname : str
1435 varname : str
1434 The name of the variable to delete.
1436 The name of the variable to delete.
1435 by_name : bool
1437 by_name : bool
1436 If True, delete variables with the given name in each
1438 If True, delete variables with the given name in each
1437 namespace. If False (default), find the variable in the user
1439 namespace. If False (default), find the variable in the user
1438 namespace, and delete references to it.
1440 namespace, and delete references to it.
1439 """
1441 """
1440 if varname in ('__builtin__', '__builtins__'):
1442 if varname in ('__builtin__', '__builtins__'):
1441 raise ValueError("Refusing to delete %s" % varname)
1443 raise ValueError("Refusing to delete %s" % varname)
1442
1444
1443 ns_refs = self.all_ns_refs
1445 ns_refs = self.all_ns_refs
1444
1446
1445 if by_name: # Delete by name
1447 if by_name: # Delete by name
1446 for ns in ns_refs:
1448 for ns in ns_refs:
1447 try:
1449 try:
1448 del ns[varname]
1450 del ns[varname]
1449 except KeyError:
1451 except KeyError:
1450 pass
1452 pass
1451 else: # Delete by object
1453 else: # Delete by object
1452 try:
1454 try:
1453 obj = self.user_ns[varname]
1455 obj = self.user_ns[varname]
1454 except KeyError as e:
1456 except KeyError as e:
1455 raise NameError("name '%s' is not defined" % varname) from e
1457 raise NameError("name '%s' is not defined" % varname) from e
1456 # Also check in output history
1458 # Also check in output history
1457 ns_refs.append(self.history_manager.output_hist)
1459 ns_refs.append(self.history_manager.output_hist)
1458 for ns in ns_refs:
1460 for ns in ns_refs:
1459 to_delete = [n for n, o in ns.items() if o is obj]
1461 to_delete = [n for n, o in ns.items() if o is obj]
1460 for name in to_delete:
1462 for name in to_delete:
1461 del ns[name]
1463 del ns[name]
1462
1464
1463 # Ensure it is removed from the last execution result
1465 # Ensure it is removed from the last execution result
1464 if self.last_execution_result.result is obj:
1466 if self.last_execution_result.result is obj:
1465 self.last_execution_result = None
1467 self.last_execution_result = None
1466
1468
1467 # displayhook keeps extra references, but not in a dictionary
1469 # displayhook keeps extra references, but not in a dictionary
1468 for name in ('_', '__', '___'):
1470 for name in ('_', '__', '___'):
1469 if getattr(self.displayhook, name) is obj:
1471 if getattr(self.displayhook, name) is obj:
1470 setattr(self.displayhook, name, None)
1472 setattr(self.displayhook, name, None)
1471
1473
1472 def reset_selective(self, regex=None):
1474 def reset_selective(self, regex=None):
1473 """Clear selective variables from internal namespaces based on a
1475 """Clear selective variables from internal namespaces based on a
1474 specified regular expression.
1476 specified regular expression.
1475
1477
1476 Parameters
1478 Parameters
1477 ----------
1479 ----------
1478 regex : string or compiled pattern, optional
1480 regex : string or compiled pattern, optional
1479 A regular expression pattern that will be used in searching
1481 A regular expression pattern that will be used in searching
1480 variable names in the users namespaces.
1482 variable names in the users namespaces.
1481 """
1483 """
1482 if regex is not None:
1484 if regex is not None:
1483 try:
1485 try:
1484 m = re.compile(regex)
1486 m = re.compile(regex)
1485 except TypeError as e:
1487 except TypeError as e:
1486 raise TypeError('regex must be a string or compiled pattern') from e
1488 raise TypeError('regex must be a string or compiled pattern') from e
1487 # Search for keys in each namespace that match the given regex
1489 # Search for keys in each namespace that match the given regex
1488 # If a match is found, delete the key/value pair.
1490 # If a match is found, delete the key/value pair.
1489 for ns in self.all_ns_refs:
1491 for ns in self.all_ns_refs:
1490 for var in ns:
1492 for var in ns:
1491 if m.search(var):
1493 if m.search(var):
1492 del ns[var]
1494 del ns[var]
1493
1495
1494 def push(self, variables, interactive=True):
1496 def push(self, variables, interactive=True):
1495 """Inject a group of variables into the IPython user namespace.
1497 """Inject a group of variables into the IPython user namespace.
1496
1498
1497 Parameters
1499 Parameters
1498 ----------
1500 ----------
1499 variables : dict, str or list/tuple of str
1501 variables : dict, str or list/tuple of str
1500 The variables to inject into the user's namespace. If a dict, a
1502 The variables to inject into the user's namespace. If a dict, a
1501 simple update is done. If a str, the string is assumed to have
1503 simple update is done. If a str, the string is assumed to have
1502 variable names separated by spaces. A list/tuple of str can also
1504 variable names separated by spaces. A list/tuple of str can also
1503 be used to give the variable names. If just the variable names are
1505 be used to give the variable names. If just the variable names are
1504 give (list/tuple/str) then the variable values looked up in the
1506 give (list/tuple/str) then the variable values looked up in the
1505 callers frame.
1507 callers frame.
1506 interactive : bool
1508 interactive : bool
1507 If True (default), the variables will be listed with the ``who``
1509 If True (default), the variables will be listed with the ``who``
1508 magic.
1510 magic.
1509 """
1511 """
1510 vdict = None
1512 vdict = None
1511
1513
1512 # We need a dict of name/value pairs to do namespace updates.
1514 # We need a dict of name/value pairs to do namespace updates.
1513 if isinstance(variables, dict):
1515 if isinstance(variables, dict):
1514 vdict = variables
1516 vdict = variables
1515 elif isinstance(variables, (str, list, tuple)):
1517 elif isinstance(variables, (str, list, tuple)):
1516 if isinstance(variables, str):
1518 if isinstance(variables, str):
1517 vlist = variables.split()
1519 vlist = variables.split()
1518 else:
1520 else:
1519 vlist = variables
1521 vlist = variables
1520 vdict = {}
1522 vdict = {}
1521 cf = sys._getframe(1)
1523 cf = sys._getframe(1)
1522 for name in vlist:
1524 for name in vlist:
1523 try:
1525 try:
1524 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1526 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1525 except:
1527 except:
1526 print('Could not get variable %s from %s' %
1528 print('Could not get variable %s from %s' %
1527 (name,cf.f_code.co_name))
1529 (name,cf.f_code.co_name))
1528 else:
1530 else:
1529 raise ValueError('variables must be a dict/str/list/tuple')
1531 raise ValueError('variables must be a dict/str/list/tuple')
1530
1532
1531 # Propagate variables to user namespace
1533 # Propagate variables to user namespace
1532 self.user_ns.update(vdict)
1534 self.user_ns.update(vdict)
1533
1535
1534 # And configure interactive visibility
1536 # And configure interactive visibility
1535 user_ns_hidden = self.user_ns_hidden
1537 user_ns_hidden = self.user_ns_hidden
1536 if interactive:
1538 if interactive:
1537 for name in vdict:
1539 for name in vdict:
1538 user_ns_hidden.pop(name, None)
1540 user_ns_hidden.pop(name, None)
1539 else:
1541 else:
1540 user_ns_hidden.update(vdict)
1542 user_ns_hidden.update(vdict)
1541
1543
1542 def drop_by_id(self, variables):
1544 def drop_by_id(self, variables):
1543 """Remove a dict of variables from the user namespace, if they are the
1545 """Remove a dict of variables from the user namespace, if they are the
1544 same as the values in the dictionary.
1546 same as the values in the dictionary.
1545
1547
1546 This is intended for use by extensions: variables that they've added can
1548 This is intended for use by extensions: variables that they've added can
1547 be taken back out if they are unloaded, without removing any that the
1549 be taken back out if they are unloaded, without removing any that the
1548 user has overwritten.
1550 user has overwritten.
1549
1551
1550 Parameters
1552 Parameters
1551 ----------
1553 ----------
1552 variables : dict
1554 variables : dict
1553 A dictionary mapping object names (as strings) to the objects.
1555 A dictionary mapping object names (as strings) to the objects.
1554 """
1556 """
1555 for name, obj in variables.items():
1557 for name, obj in variables.items():
1556 if name in self.user_ns and self.user_ns[name] is obj:
1558 if name in self.user_ns and self.user_ns[name] is obj:
1557 del self.user_ns[name]
1559 del self.user_ns[name]
1558 self.user_ns_hidden.pop(name, None)
1560 self.user_ns_hidden.pop(name, None)
1559
1561
1560 #-------------------------------------------------------------------------
1562 #-------------------------------------------------------------------------
1561 # Things related to object introspection
1563 # Things related to object introspection
1562 #-------------------------------------------------------------------------
1564 #-------------------------------------------------------------------------
1565 @staticmethod
1566 def _find_parts(oname: str) -> ListType[str]:
1567 """
1568 Given an object name, return a list of parts of this object name.
1569
1570 Basically split on docs when using attribute access,
1571 and extract the value when using square bracket.
1572
1573
1574 For example foo.bar[3].baz[x] -> foo, bar, 3, baz, x
1575
1576
1577 Returns
1578 -------
1579 parts_ok: bool
1580 wether we were properly able to parse parts.
1581 parts: list of str
1582 extracted parts
1563
1583
1564 def _ofind(self, oname, namespaces=None):
1565 """Find an object in the available namespaces.
1566
1584
1567 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1568
1585
1569 Has special code to detect magic functions.
1570 """
1586 """
1571 oname = oname.strip()
1572 raw_parts = oname.split(".")
1587 raw_parts = oname.split(".")
1573 parts = []
1588 parts = []
1574 parts_ok = True
1589 parts_ok = True
1575 for p in raw_parts:
1590 for p in raw_parts:
1576 if p.endswith("]"):
1591 if p.endswith("]"):
1577 var, *indices = p.split("[")
1592 var, *indices = p.split("[")
1578 if not var.isidentifier():
1593 if not var.isidentifier():
1579 parts_ok = False
1594 parts_ok = False
1580 break
1595 break
1581 parts.append(var)
1596 parts.append(var)
1582 for ind in indices:
1597 for ind in indices:
1583 if ind[-1] != "]" and not is_integer_string(ind[:-1]):
1598 if ind[-1] != "]" and not is_integer_string(ind[:-1]):
1584 parts_ok = False
1599 parts_ok = False
1585 break
1600 break
1586 parts.append(ind[:-1])
1601 parts.append(ind[:-1])
1587 continue
1602 continue
1588
1603
1589 if not p.isidentifier():
1604 if not p.isidentifier():
1590 parts_ok = False
1605 parts_ok = False
1591 parts.append(p)
1606 parts.append(p)
1592
1607
1608 return parts_ok, parts
1609
1610 def _ofind(self, oname: str, namespaces: DictType[str, AnyType] = None):
1611 """Find an object in the available namespaces.
1612
1613 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1614
1615 Has special code to detect magic functions.
1616 """
1617 oname = oname.strip()
1618 parts_ok, parts = self._find_parts(oname)
1619
1593 if (
1620 if (
1594 not oname.startswith(ESC_MAGIC)
1621 not oname.startswith(ESC_MAGIC)
1595 and not oname.startswith(ESC_MAGIC2)
1622 and not oname.startswith(ESC_MAGIC2)
1596 and not parts_ok
1623 and not parts_ok
1597 ):
1624 ):
1598 return {"found": False}
1625 return OInfo(
1626 ismagic=False,
1627 isalias=False,
1628 found=False,
1629 obj=None,
1630 namespace="",
1631 parent=None,
1632 )
1599
1633
1600 if namespaces is None:
1634 if namespaces is None:
1601 # Namespaces to search in:
1635 # Namespaces to search in:
1602 # Put them in a list. The order is important so that we
1636 # Put them in a list. The order is important so that we
1603 # find things in the same order that Python finds them.
1637 # find things in the same order that Python finds them.
1604 namespaces = [ ('Interactive', self.user_ns),
1638 namespaces = [ ('Interactive', self.user_ns),
1605 ('Interactive (global)', self.user_global_ns),
1639 ('Interactive (global)', self.user_global_ns),
1606 ('Python builtin', builtin_mod.__dict__),
1640 ('Python builtin', builtin_mod.__dict__),
1607 ]
1641 ]
1608
1642
1609 ismagic = False
1643 ismagic = False
1610 isalias = False
1644 isalias = False
1611 found = False
1645 found = False
1612 ospace = None
1646 ospace = None
1613 parent = None
1647 parent = None
1614 obj = None
1648 obj = None
1615
1649
1616
1650
1617 # Look for the given name by splitting it in parts. If the head is
1651 # Look for the given name by splitting it in parts. If the head is
1618 # found, then we look for all the remaining parts as members, and only
1652 # found, then we look for all the remaining parts as members, and only
1619 # declare success if we can find them all.
1653 # declare success if we can find them all.
1620 oname_parts = parts
1654 oname_parts = parts
1621 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1655 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1622 for nsname,ns in namespaces:
1656 for nsname,ns in namespaces:
1623 try:
1657 try:
1624 obj = ns[oname_head]
1658 obj = ns[oname_head]
1625 except KeyError:
1659 except KeyError:
1626 continue
1660 continue
1627 else:
1661 else:
1628 for idx, part in enumerate(oname_rest):
1662 for idx, part in enumerate(oname_rest):
1629 try:
1663 try:
1630 parent = obj
1664 parent = obj
1631 # The last part is looked up in a special way to avoid
1665 # The last part is looked up in a special way to avoid
1632 # descriptor invocation as it may raise or have side
1666 # descriptor invocation as it may raise or have side
1633 # effects.
1667 # effects.
1634 if idx == len(oname_rest) - 1:
1668 if idx == len(oname_rest) - 1:
1635 obj = self._getattr_property(obj, part)
1669 obj = self._getattr_property(obj, part)
1636 else:
1670 else:
1637 if is_integer_string(part):
1671 if is_integer_string(part):
1638 obj = obj[int(part)]
1672 obj = obj[int(part)]
1639 else:
1673 else:
1640 obj = getattr(obj, part)
1674 obj = getattr(obj, part)
1641 except:
1675 except:
1642 # Blanket except b/c some badly implemented objects
1676 # Blanket except b/c some badly implemented objects
1643 # allow __getattr__ to raise exceptions other than
1677 # allow __getattr__ to raise exceptions other than
1644 # AttributeError, which then crashes IPython.
1678 # AttributeError, which then crashes IPython.
1645 break
1679 break
1646 else:
1680 else:
1647 # If we finish the for loop (no break), we got all members
1681 # If we finish the for loop (no break), we got all members
1648 found = True
1682 found = True
1649 ospace = nsname
1683 ospace = nsname
1650 break # namespace loop
1684 break # namespace loop
1651
1685
1652 # Try to see if it's magic
1686 # Try to see if it's magic
1653 if not found:
1687 if not found:
1654 obj = None
1688 obj = None
1655 if oname.startswith(ESC_MAGIC2):
1689 if oname.startswith(ESC_MAGIC2):
1656 oname = oname.lstrip(ESC_MAGIC2)
1690 oname = oname.lstrip(ESC_MAGIC2)
1657 obj = self.find_cell_magic(oname)
1691 obj = self.find_cell_magic(oname)
1658 elif oname.startswith(ESC_MAGIC):
1692 elif oname.startswith(ESC_MAGIC):
1659 oname = oname.lstrip(ESC_MAGIC)
1693 oname = oname.lstrip(ESC_MAGIC)
1660 obj = self.find_line_magic(oname)
1694 obj = self.find_line_magic(oname)
1661 else:
1695 else:
1662 # search without prefix, so run? will find %run?
1696 # search without prefix, so run? will find %run?
1663 obj = self.find_line_magic(oname)
1697 obj = self.find_line_magic(oname)
1664 if obj is None:
1698 if obj is None:
1665 obj = self.find_cell_magic(oname)
1699 obj = self.find_cell_magic(oname)
1666 if obj is not None:
1700 if obj is not None:
1667 found = True
1701 found = True
1668 ospace = 'IPython internal'
1702 ospace = 'IPython internal'
1669 ismagic = True
1703 ismagic = True
1670 isalias = isinstance(obj, Alias)
1704 isalias = isinstance(obj, Alias)
1671
1705
1672 # Last try: special-case some literals like '', [], {}, etc:
1706 # Last try: special-case some literals like '', [], {}, etc:
1673 if not found and oname_head in ["''",'""','[]','{}','()']:
1707 if not found and oname_head in ["''",'""','[]','{}','()']:
1674 obj = eval(oname_head)
1708 obj = eval(oname_head)
1675 found = True
1709 found = True
1676 ospace = 'Interactive'
1710 ospace = 'Interactive'
1677
1711
1678 return {
1712 return OInfo(
1679 'obj':obj,
1713 **{
1680 'found':found,
1714 "obj": obj,
1681 'parent':parent,
1715 "found": found,
1682 'ismagic':ismagic,
1716 "parent": parent,
1683 'isalias':isalias,
1717 "ismagic": ismagic,
1684 'namespace':ospace
1718 "isalias": isalias,
1685 }
1719 "namespace": ospace,
1720 }
1721 )
1686
1722
1687 @staticmethod
1723 @staticmethod
1688 def _getattr_property(obj, attrname):
1724 def _getattr_property(obj, attrname):
1689 """Property-aware getattr to use in object finding.
1725 """Property-aware getattr to use in object finding.
1690
1726
1691 If attrname represents a property, return it unevaluated (in case it has
1727 If attrname represents a property, return it unevaluated (in case it has
1692 side effects or raises an error.
1728 side effects or raises an error.
1693
1729
1694 """
1730 """
1695 if not isinstance(obj, type):
1731 if not isinstance(obj, type):
1696 try:
1732 try:
1697 # `getattr(type(obj), attrname)` is not guaranteed to return
1733 # `getattr(type(obj), attrname)` is not guaranteed to return
1698 # `obj`, but does so for property:
1734 # `obj`, but does so for property:
1699 #
1735 #
1700 # property.__get__(self, None, cls) -> self
1736 # property.__get__(self, None, cls) -> self
1701 #
1737 #
1702 # The universal alternative is to traverse the mro manually
1738 # The universal alternative is to traverse the mro manually
1703 # searching for attrname in class dicts.
1739 # searching for attrname in class dicts.
1704 if is_integer_string(attrname):
1740 if is_integer_string(attrname):
1705 return obj[int(attrname)]
1741 return obj[int(attrname)]
1706 else:
1742 else:
1707 attr = getattr(type(obj), attrname)
1743 attr = getattr(type(obj), attrname)
1708 except AttributeError:
1744 except AttributeError:
1709 pass
1745 pass
1710 else:
1746 else:
1711 # This relies on the fact that data descriptors (with both
1747 # This relies on the fact that data descriptors (with both
1712 # __get__ & __set__ magic methods) take precedence over
1748 # __get__ & __set__ magic methods) take precedence over
1713 # instance-level attributes:
1749 # instance-level attributes:
1714 #
1750 #
1715 # class A(object):
1751 # class A(object):
1716 # @property
1752 # @property
1717 # def foobar(self): return 123
1753 # def foobar(self): return 123
1718 # a = A()
1754 # a = A()
1719 # a.__dict__['foobar'] = 345
1755 # a.__dict__['foobar'] = 345
1720 # a.foobar # == 123
1756 # a.foobar # == 123
1721 #
1757 #
1722 # So, a property may be returned right away.
1758 # So, a property may be returned right away.
1723 if isinstance(attr, property):
1759 if isinstance(attr, property):
1724 return attr
1760 return attr
1725
1761
1726 # Nothing helped, fall back.
1762 # Nothing helped, fall back.
1727 return getattr(obj, attrname)
1763 return getattr(obj, attrname)
1728
1764
1729 def _object_find(self, oname, namespaces=None):
1765 def _object_find(self, oname, namespaces=None) -> OInfo:
1730 """Find an object and return a struct with info about it."""
1766 """Find an object and return a struct with info about it."""
1731 return Struct(self._ofind(oname, namespaces))
1767 return self._ofind(oname, namespaces)
1732
1768
1733 def _inspect(self, meth, oname, namespaces=None, **kw):
1769 def _inspect(self, meth, oname, namespaces=None, **kw):
1734 """Generic interface to the inspector system.
1770 """Generic interface to the inspector system.
1735
1771
1736 This function is meant to be called by pdef, pdoc & friends.
1772 This function is meant to be called by pdef, pdoc & friends.
1737 """
1773 """
1738 info = self._object_find(oname, namespaces)
1774 info = self._object_find(oname, namespaces)
1739 docformat = (
1775 docformat = (
1740 sphinxify(self.object_inspect(oname)) if self.sphinxify_docstring else None
1776 sphinxify(self.object_inspect(oname)) if self.sphinxify_docstring else None
1741 )
1777 )
1742 if info.found:
1778 if info.found:
1743 pmethod = getattr(self.inspector, meth)
1779 pmethod = getattr(self.inspector, meth)
1744 # TODO: only apply format_screen to the plain/text repr of the mime
1780 # TODO: only apply format_screen to the plain/text repr of the mime
1745 # bundle.
1781 # bundle.
1746 formatter = format_screen if info.ismagic else docformat
1782 formatter = format_screen if info.ismagic else docformat
1747 if meth == 'pdoc':
1783 if meth == 'pdoc':
1748 pmethod(info.obj, oname, formatter)
1784 pmethod(info.obj, oname, formatter)
1749 elif meth == 'pinfo':
1785 elif meth == 'pinfo':
1750 pmethod(
1786 pmethod(
1751 info.obj,
1787 info.obj,
1752 oname,
1788 oname,
1753 formatter,
1789 formatter,
1754 info,
1790 info,
1755 enable_html_pager=self.enable_html_pager,
1791 enable_html_pager=self.enable_html_pager,
1756 **kw,
1792 **kw,
1757 )
1793 )
1758 else:
1794 else:
1759 pmethod(info.obj, oname)
1795 pmethod(info.obj, oname)
1760 else:
1796 else:
1761 print('Object `%s` not found.' % oname)
1797 print('Object `%s` not found.' % oname)
1762 return 'not found' # so callers can take other action
1798 return 'not found' # so callers can take other action
1763
1799
1764 def object_inspect(self, oname, detail_level=0):
1800 def object_inspect(self, oname, detail_level=0):
1765 """Get object info about oname"""
1801 """Get object info about oname"""
1766 with self.builtin_trap:
1802 with self.builtin_trap:
1767 info = self._object_find(oname)
1803 info = self._object_find(oname)
1768 if info.found:
1804 if info.found:
1769 return self.inspector.info(info.obj, oname, info=info,
1805 return self.inspector.info(info.obj, oname, info=info,
1770 detail_level=detail_level
1806 detail_level=detail_level
1771 )
1807 )
1772 else:
1808 else:
1773 return oinspect.object_info(name=oname, found=False)
1809 return oinspect.object_info(name=oname, found=False)
1774
1810
1775 def object_inspect_text(self, oname, detail_level=0):
1811 def object_inspect_text(self, oname, detail_level=0):
1776 """Get object info as formatted text"""
1812 """Get object info as formatted text"""
1777 return self.object_inspect_mime(oname, detail_level)['text/plain']
1813 return self.object_inspect_mime(oname, detail_level)['text/plain']
1778
1814
1779 def object_inspect_mime(self, oname, detail_level=0, omit_sections=()):
1815 def object_inspect_mime(self, oname, detail_level=0, omit_sections=()):
1780 """Get object info as a mimebundle of formatted representations.
1816 """Get object info as a mimebundle of formatted representations.
1781
1817
1782 A mimebundle is a dictionary, keyed by mime-type.
1818 A mimebundle is a dictionary, keyed by mime-type.
1783 It must always have the key `'text/plain'`.
1819 It must always have the key `'text/plain'`.
1784 """
1820 """
1785 with self.builtin_trap:
1821 with self.builtin_trap:
1786 info = self._object_find(oname)
1822 info = self._object_find(oname)
1787 if info.found:
1823 if info.found:
1788 docformat = (
1824 docformat = (
1789 sphinxify(self.object_inspect(oname))
1825 sphinxify(self.object_inspect(oname))
1790 if self.sphinxify_docstring
1826 if self.sphinxify_docstring
1791 else None
1827 else None
1792 )
1828 )
1793 return self.inspector._get_info(
1829 return self.inspector._get_info(
1794 info.obj,
1830 info.obj,
1795 oname,
1831 oname,
1796 info=info,
1832 info=info,
1797 detail_level=detail_level,
1833 detail_level=detail_level,
1798 formatter=docformat,
1834 formatter=docformat,
1799 omit_sections=omit_sections,
1835 omit_sections=omit_sections,
1800 )
1836 )
1801 else:
1837 else:
1802 raise KeyError(oname)
1838 raise KeyError(oname)
1803
1839
1804 #-------------------------------------------------------------------------
1840 #-------------------------------------------------------------------------
1805 # Things related to history management
1841 # Things related to history management
1806 #-------------------------------------------------------------------------
1842 #-------------------------------------------------------------------------
1807
1843
1808 def init_history(self):
1844 def init_history(self):
1809 """Sets up the command history, and starts regular autosaves."""
1845 """Sets up the command history, and starts regular autosaves."""
1810 self.history_manager = HistoryManager(shell=self, parent=self)
1846 self.history_manager = HistoryManager(shell=self, parent=self)
1811 self.configurables.append(self.history_manager)
1847 self.configurables.append(self.history_manager)
1812
1848
1813 #-------------------------------------------------------------------------
1849 #-------------------------------------------------------------------------
1814 # Things related to exception handling and tracebacks (not debugging)
1850 # Things related to exception handling and tracebacks (not debugging)
1815 #-------------------------------------------------------------------------
1851 #-------------------------------------------------------------------------
1816
1852
1817 debugger_cls = InterruptiblePdb
1853 debugger_cls = InterruptiblePdb
1818
1854
1819 def init_traceback_handlers(self, custom_exceptions):
1855 def init_traceback_handlers(self, custom_exceptions):
1820 # Syntax error handler.
1856 # Syntax error handler.
1821 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor', parent=self)
1857 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor', parent=self)
1822
1858
1823 # The interactive one is initialized with an offset, meaning we always
1859 # The interactive one is initialized with an offset, meaning we always
1824 # want to remove the topmost item in the traceback, which is our own
1860 # want to remove the topmost item in the traceback, which is our own
1825 # internal code. Valid modes: ['Plain','Context','Verbose','Minimal']
1861 # internal code. Valid modes: ['Plain','Context','Verbose','Minimal']
1826 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1862 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1827 color_scheme='NoColor',
1863 color_scheme='NoColor',
1828 tb_offset = 1,
1864 tb_offset = 1,
1829 debugger_cls=self.debugger_cls, parent=self)
1865 debugger_cls=self.debugger_cls, parent=self)
1830
1866
1831 # The instance will store a pointer to the system-wide exception hook,
1867 # The instance will store a pointer to the system-wide exception hook,
1832 # so that runtime code (such as magics) can access it. This is because
1868 # so that runtime code (such as magics) can access it. This is because
1833 # during the read-eval loop, it may get temporarily overwritten.
1869 # during the read-eval loop, it may get temporarily overwritten.
1834 self.sys_excepthook = sys.excepthook
1870 self.sys_excepthook = sys.excepthook
1835
1871
1836 # and add any custom exception handlers the user may have specified
1872 # and add any custom exception handlers the user may have specified
1837 self.set_custom_exc(*custom_exceptions)
1873 self.set_custom_exc(*custom_exceptions)
1838
1874
1839 # Set the exception mode
1875 # Set the exception mode
1840 self.InteractiveTB.set_mode(mode=self.xmode)
1876 self.InteractiveTB.set_mode(mode=self.xmode)
1841
1877
1842 def set_custom_exc(self, exc_tuple, handler):
1878 def set_custom_exc(self, exc_tuple, handler):
1843 """set_custom_exc(exc_tuple, handler)
1879 """set_custom_exc(exc_tuple, handler)
1844
1880
1845 Set a custom exception handler, which will be called if any of the
1881 Set a custom exception handler, which will be called if any of the
1846 exceptions in exc_tuple occur in the mainloop (specifically, in the
1882 exceptions in exc_tuple occur in the mainloop (specifically, in the
1847 run_code() method).
1883 run_code() method).
1848
1884
1849 Parameters
1885 Parameters
1850 ----------
1886 ----------
1851 exc_tuple : tuple of exception classes
1887 exc_tuple : tuple of exception classes
1852 A *tuple* of exception classes, for which to call the defined
1888 A *tuple* of exception classes, for which to call the defined
1853 handler. It is very important that you use a tuple, and NOT A
1889 handler. It is very important that you use a tuple, and NOT A
1854 LIST here, because of the way Python's except statement works. If
1890 LIST here, because of the way Python's except statement works. If
1855 you only want to trap a single exception, use a singleton tuple::
1891 you only want to trap a single exception, use a singleton tuple::
1856
1892
1857 exc_tuple == (MyCustomException,)
1893 exc_tuple == (MyCustomException,)
1858
1894
1859 handler : callable
1895 handler : callable
1860 handler must have the following signature::
1896 handler must have the following signature::
1861
1897
1862 def my_handler(self, etype, value, tb, tb_offset=None):
1898 def my_handler(self, etype, value, tb, tb_offset=None):
1863 ...
1899 ...
1864 return structured_traceback
1900 return structured_traceback
1865
1901
1866 Your handler must return a structured traceback (a list of strings),
1902 Your handler must return a structured traceback (a list of strings),
1867 or None.
1903 or None.
1868
1904
1869 This will be made into an instance method (via types.MethodType)
1905 This will be made into an instance method (via types.MethodType)
1870 of IPython itself, and it will be called if any of the exceptions
1906 of IPython itself, and it will be called if any of the exceptions
1871 listed in the exc_tuple are caught. If the handler is None, an
1907 listed in the exc_tuple are caught. If the handler is None, an
1872 internal basic one is used, which just prints basic info.
1908 internal basic one is used, which just prints basic info.
1873
1909
1874 To protect IPython from crashes, if your handler ever raises an
1910 To protect IPython from crashes, if your handler ever raises an
1875 exception or returns an invalid result, it will be immediately
1911 exception or returns an invalid result, it will be immediately
1876 disabled.
1912 disabled.
1877
1913
1878 Notes
1914 Notes
1879 -----
1915 -----
1880 WARNING: by putting in your own exception handler into IPython's main
1916 WARNING: by putting in your own exception handler into IPython's main
1881 execution loop, you run a very good chance of nasty crashes. This
1917 execution loop, you run a very good chance of nasty crashes. This
1882 facility should only be used if you really know what you are doing.
1918 facility should only be used if you really know what you are doing.
1883 """
1919 """
1884
1920
1885 if not isinstance(exc_tuple, tuple):
1921 if not isinstance(exc_tuple, tuple):
1886 raise TypeError("The custom exceptions must be given as a tuple.")
1922 raise TypeError("The custom exceptions must be given as a tuple.")
1887
1923
1888 def dummy_handler(self, etype, value, tb, tb_offset=None):
1924 def dummy_handler(self, etype, value, tb, tb_offset=None):
1889 print('*** Simple custom exception handler ***')
1925 print('*** Simple custom exception handler ***')
1890 print('Exception type :', etype)
1926 print('Exception type :', etype)
1891 print('Exception value:', value)
1927 print('Exception value:', value)
1892 print('Traceback :', tb)
1928 print('Traceback :', tb)
1893
1929
1894 def validate_stb(stb):
1930 def validate_stb(stb):
1895 """validate structured traceback return type
1931 """validate structured traceback return type
1896
1932
1897 return type of CustomTB *should* be a list of strings, but allow
1933 return type of CustomTB *should* be a list of strings, but allow
1898 single strings or None, which are harmless.
1934 single strings or None, which are harmless.
1899
1935
1900 This function will *always* return a list of strings,
1936 This function will *always* return a list of strings,
1901 and will raise a TypeError if stb is inappropriate.
1937 and will raise a TypeError if stb is inappropriate.
1902 """
1938 """
1903 msg = "CustomTB must return list of strings, not %r" % stb
1939 msg = "CustomTB must return list of strings, not %r" % stb
1904 if stb is None:
1940 if stb is None:
1905 return []
1941 return []
1906 elif isinstance(stb, str):
1942 elif isinstance(stb, str):
1907 return [stb]
1943 return [stb]
1908 elif not isinstance(stb, list):
1944 elif not isinstance(stb, list):
1909 raise TypeError(msg)
1945 raise TypeError(msg)
1910 # it's a list
1946 # it's a list
1911 for line in stb:
1947 for line in stb:
1912 # check every element
1948 # check every element
1913 if not isinstance(line, str):
1949 if not isinstance(line, str):
1914 raise TypeError(msg)
1950 raise TypeError(msg)
1915 return stb
1951 return stb
1916
1952
1917 if handler is None:
1953 if handler is None:
1918 wrapped = dummy_handler
1954 wrapped = dummy_handler
1919 else:
1955 else:
1920 def wrapped(self,etype,value,tb,tb_offset=None):
1956 def wrapped(self,etype,value,tb,tb_offset=None):
1921 """wrap CustomTB handler, to protect IPython from user code
1957 """wrap CustomTB handler, to protect IPython from user code
1922
1958
1923 This makes it harder (but not impossible) for custom exception
1959 This makes it harder (but not impossible) for custom exception
1924 handlers to crash IPython.
1960 handlers to crash IPython.
1925 """
1961 """
1926 try:
1962 try:
1927 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1963 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1928 return validate_stb(stb)
1964 return validate_stb(stb)
1929 except:
1965 except:
1930 # clear custom handler immediately
1966 # clear custom handler immediately
1931 self.set_custom_exc((), None)
1967 self.set_custom_exc((), None)
1932 print("Custom TB Handler failed, unregistering", file=sys.stderr)
1968 print("Custom TB Handler failed, unregistering", file=sys.stderr)
1933 # show the exception in handler first
1969 # show the exception in handler first
1934 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1970 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1935 print(self.InteractiveTB.stb2text(stb))
1971 print(self.InteractiveTB.stb2text(stb))
1936 print("The original exception:")
1972 print("The original exception:")
1937 stb = self.InteractiveTB.structured_traceback(
1973 stb = self.InteractiveTB.structured_traceback(
1938 (etype,value,tb), tb_offset=tb_offset
1974 (etype,value,tb), tb_offset=tb_offset
1939 )
1975 )
1940 return stb
1976 return stb
1941
1977
1942 self.CustomTB = types.MethodType(wrapped,self)
1978 self.CustomTB = types.MethodType(wrapped,self)
1943 self.custom_exceptions = exc_tuple
1979 self.custom_exceptions = exc_tuple
1944
1980
1945 def excepthook(self, etype, value, tb):
1981 def excepthook(self, etype, value, tb):
1946 """One more defense for GUI apps that call sys.excepthook.
1982 """One more defense for GUI apps that call sys.excepthook.
1947
1983
1948 GUI frameworks like wxPython trap exceptions and call
1984 GUI frameworks like wxPython trap exceptions and call
1949 sys.excepthook themselves. I guess this is a feature that
1985 sys.excepthook themselves. I guess this is a feature that
1950 enables them to keep running after exceptions that would
1986 enables them to keep running after exceptions that would
1951 otherwise kill their mainloop. This is a bother for IPython
1987 otherwise kill their mainloop. This is a bother for IPython
1952 which expects to catch all of the program exceptions with a try:
1988 which expects to catch all of the program exceptions with a try:
1953 except: statement.
1989 except: statement.
1954
1990
1955 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1991 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1956 any app directly invokes sys.excepthook, it will look to the user like
1992 any app directly invokes sys.excepthook, it will look to the user like
1957 IPython crashed. In order to work around this, we can disable the
1993 IPython crashed. In order to work around this, we can disable the
1958 CrashHandler and replace it with this excepthook instead, which prints a
1994 CrashHandler and replace it with this excepthook instead, which prints a
1959 regular traceback using our InteractiveTB. In this fashion, apps which
1995 regular traceback using our InteractiveTB. In this fashion, apps which
1960 call sys.excepthook will generate a regular-looking exception from
1996 call sys.excepthook will generate a regular-looking exception from
1961 IPython, and the CrashHandler will only be triggered by real IPython
1997 IPython, and the CrashHandler will only be triggered by real IPython
1962 crashes.
1998 crashes.
1963
1999
1964 This hook should be used sparingly, only in places which are not likely
2000 This hook should be used sparingly, only in places which are not likely
1965 to be true IPython errors.
2001 to be true IPython errors.
1966 """
2002 """
1967 self.showtraceback((etype, value, tb), tb_offset=0)
2003 self.showtraceback((etype, value, tb), tb_offset=0)
1968
2004
1969 def _get_exc_info(self, exc_tuple=None):
2005 def _get_exc_info(self, exc_tuple=None):
1970 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
2006 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1971
2007
1972 Ensures sys.last_type,value,traceback hold the exc_info we found,
2008 Ensures sys.last_type,value,traceback hold the exc_info we found,
1973 from whichever source.
2009 from whichever source.
1974
2010
1975 raises ValueError if none of these contain any information
2011 raises ValueError if none of these contain any information
1976 """
2012 """
1977 if exc_tuple is None:
2013 if exc_tuple is None:
1978 etype, value, tb = sys.exc_info()
2014 etype, value, tb = sys.exc_info()
1979 else:
2015 else:
1980 etype, value, tb = exc_tuple
2016 etype, value, tb = exc_tuple
1981
2017
1982 if etype is None:
2018 if etype is None:
1983 if hasattr(sys, 'last_type'):
2019 if hasattr(sys, 'last_type'):
1984 etype, value, tb = sys.last_type, sys.last_value, \
2020 etype, value, tb = sys.last_type, sys.last_value, \
1985 sys.last_traceback
2021 sys.last_traceback
1986
2022
1987 if etype is None:
2023 if etype is None:
1988 raise ValueError("No exception to find")
2024 raise ValueError("No exception to find")
1989
2025
1990 # Now store the exception info in sys.last_type etc.
2026 # Now store the exception info in sys.last_type etc.
1991 # WARNING: these variables are somewhat deprecated and not
2027 # WARNING: these variables are somewhat deprecated and not
1992 # necessarily safe to use in a threaded environment, but tools
2028 # necessarily safe to use in a threaded environment, but tools
1993 # like pdb depend on their existence, so let's set them. If we
2029 # like pdb depend on their existence, so let's set them. If we
1994 # find problems in the field, we'll need to revisit their use.
2030 # find problems in the field, we'll need to revisit their use.
1995 sys.last_type = etype
2031 sys.last_type = etype
1996 sys.last_value = value
2032 sys.last_value = value
1997 sys.last_traceback = tb
2033 sys.last_traceback = tb
1998
2034
1999 return etype, value, tb
2035 return etype, value, tb
2000
2036
2001 def show_usage_error(self, exc):
2037 def show_usage_error(self, exc):
2002 """Show a short message for UsageErrors
2038 """Show a short message for UsageErrors
2003
2039
2004 These are special exceptions that shouldn't show a traceback.
2040 These are special exceptions that shouldn't show a traceback.
2005 """
2041 """
2006 print("UsageError: %s" % exc, file=sys.stderr)
2042 print("UsageError: %s" % exc, file=sys.stderr)
2007
2043
2008 def get_exception_only(self, exc_tuple=None):
2044 def get_exception_only(self, exc_tuple=None):
2009 """
2045 """
2010 Return as a string (ending with a newline) the exception that
2046 Return as a string (ending with a newline) the exception that
2011 just occurred, without any traceback.
2047 just occurred, without any traceback.
2012 """
2048 """
2013 etype, value, tb = self._get_exc_info(exc_tuple)
2049 etype, value, tb = self._get_exc_info(exc_tuple)
2014 msg = traceback.format_exception_only(etype, value)
2050 msg = traceback.format_exception_only(etype, value)
2015 return ''.join(msg)
2051 return ''.join(msg)
2016
2052
2017 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
2053 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
2018 exception_only=False, running_compiled_code=False):
2054 exception_only=False, running_compiled_code=False):
2019 """Display the exception that just occurred.
2055 """Display the exception that just occurred.
2020
2056
2021 If nothing is known about the exception, this is the method which
2057 If nothing is known about the exception, this is the method which
2022 should be used throughout the code for presenting user tracebacks,
2058 should be used throughout the code for presenting user tracebacks,
2023 rather than directly invoking the InteractiveTB object.
2059 rather than directly invoking the InteractiveTB object.
2024
2060
2025 A specific showsyntaxerror() also exists, but this method can take
2061 A specific showsyntaxerror() also exists, but this method can take
2026 care of calling it if needed, so unless you are explicitly catching a
2062 care of calling it if needed, so unless you are explicitly catching a
2027 SyntaxError exception, don't try to analyze the stack manually and
2063 SyntaxError exception, don't try to analyze the stack manually and
2028 simply call this method."""
2064 simply call this method."""
2029
2065
2030 try:
2066 try:
2031 try:
2067 try:
2032 etype, value, tb = self._get_exc_info(exc_tuple)
2068 etype, value, tb = self._get_exc_info(exc_tuple)
2033 except ValueError:
2069 except ValueError:
2034 print('No traceback available to show.', file=sys.stderr)
2070 print('No traceback available to show.', file=sys.stderr)
2035 return
2071 return
2036
2072
2037 if issubclass(etype, SyntaxError):
2073 if issubclass(etype, SyntaxError):
2038 # Though this won't be called by syntax errors in the input
2074 # Though this won't be called by syntax errors in the input
2039 # line, there may be SyntaxError cases with imported code.
2075 # line, there may be SyntaxError cases with imported code.
2040 self.showsyntaxerror(filename, running_compiled_code)
2076 self.showsyntaxerror(filename, running_compiled_code)
2041 elif etype is UsageError:
2077 elif etype is UsageError:
2042 self.show_usage_error(value)
2078 self.show_usage_error(value)
2043 else:
2079 else:
2044 if exception_only:
2080 if exception_only:
2045 stb = ['An exception has occurred, use %tb to see '
2081 stb = ['An exception has occurred, use %tb to see '
2046 'the full traceback.\n']
2082 'the full traceback.\n']
2047 stb.extend(self.InteractiveTB.get_exception_only(etype,
2083 stb.extend(self.InteractiveTB.get_exception_only(etype,
2048 value))
2084 value))
2049 else:
2085 else:
2050 try:
2086 try:
2051 # Exception classes can customise their traceback - we
2087 # Exception classes can customise their traceback - we
2052 # use this in IPython.parallel for exceptions occurring
2088 # use this in IPython.parallel for exceptions occurring
2053 # in the engines. This should return a list of strings.
2089 # in the engines. This should return a list of strings.
2054 if hasattr(value, "_render_traceback_"):
2090 if hasattr(value, "_render_traceback_"):
2055 stb = value._render_traceback_()
2091 stb = value._render_traceback_()
2056 else:
2092 else:
2057 stb = self.InteractiveTB.structured_traceback(
2093 stb = self.InteractiveTB.structured_traceback(
2058 etype, value, tb, tb_offset=tb_offset
2094 etype, value, tb, tb_offset=tb_offset
2059 )
2095 )
2060
2096
2061 except Exception:
2097 except Exception:
2062 print(
2098 print(
2063 "Unexpected exception formatting exception. Falling back to standard exception"
2099 "Unexpected exception formatting exception. Falling back to standard exception"
2064 )
2100 )
2065 traceback.print_exc()
2101 traceback.print_exc()
2066 return None
2102 return None
2067
2103
2068 self._showtraceback(etype, value, stb)
2104 self._showtraceback(etype, value, stb)
2069 if self.call_pdb:
2105 if self.call_pdb:
2070 # drop into debugger
2106 # drop into debugger
2071 self.debugger(force=True)
2107 self.debugger(force=True)
2072 return
2108 return
2073
2109
2074 # Actually show the traceback
2110 # Actually show the traceback
2075 self._showtraceback(etype, value, stb)
2111 self._showtraceback(etype, value, stb)
2076
2112
2077 except KeyboardInterrupt:
2113 except KeyboardInterrupt:
2078 print('\n' + self.get_exception_only(), file=sys.stderr)
2114 print('\n' + self.get_exception_only(), file=sys.stderr)
2079
2115
2080 def _showtraceback(self, etype, evalue, stb: str):
2116 def _showtraceback(self, etype, evalue, stb: str):
2081 """Actually show a traceback.
2117 """Actually show a traceback.
2082
2118
2083 Subclasses may override this method to put the traceback on a different
2119 Subclasses may override this method to put the traceback on a different
2084 place, like a side channel.
2120 place, like a side channel.
2085 """
2121 """
2086 val = self.InteractiveTB.stb2text(stb)
2122 val = self.InteractiveTB.stb2text(stb)
2087 try:
2123 try:
2088 print(val)
2124 print(val)
2089 except UnicodeEncodeError:
2125 except UnicodeEncodeError:
2090 print(val.encode("utf-8", "backslashreplace").decode())
2126 print(val.encode("utf-8", "backslashreplace").decode())
2091
2127
2092 def showsyntaxerror(self, filename=None, running_compiled_code=False):
2128 def showsyntaxerror(self, filename=None, running_compiled_code=False):
2093 """Display the syntax error that just occurred.
2129 """Display the syntax error that just occurred.
2094
2130
2095 This doesn't display a stack trace because there isn't one.
2131 This doesn't display a stack trace because there isn't one.
2096
2132
2097 If a filename is given, it is stuffed in the exception instead
2133 If a filename is given, it is stuffed in the exception instead
2098 of what was there before (because Python's parser always uses
2134 of what was there before (because Python's parser always uses
2099 "<string>" when reading from a string).
2135 "<string>" when reading from a string).
2100
2136
2101 If the syntax error occurred when running a compiled code (i.e. running_compile_code=True),
2137 If the syntax error occurred when running a compiled code (i.e. running_compile_code=True),
2102 longer stack trace will be displayed.
2138 longer stack trace will be displayed.
2103 """
2139 """
2104 etype, value, last_traceback = self._get_exc_info()
2140 etype, value, last_traceback = self._get_exc_info()
2105
2141
2106 if filename and issubclass(etype, SyntaxError):
2142 if filename and issubclass(etype, SyntaxError):
2107 try:
2143 try:
2108 value.filename = filename
2144 value.filename = filename
2109 except:
2145 except:
2110 # Not the format we expect; leave it alone
2146 # Not the format we expect; leave it alone
2111 pass
2147 pass
2112
2148
2113 # If the error occurred when executing compiled code, we should provide full stacktrace.
2149 # If the error occurred when executing compiled code, we should provide full stacktrace.
2114 elist = traceback.extract_tb(last_traceback) if running_compiled_code else []
2150 elist = traceback.extract_tb(last_traceback) if running_compiled_code else []
2115 stb = self.SyntaxTB.structured_traceback(etype, value, elist)
2151 stb = self.SyntaxTB.structured_traceback(etype, value, elist)
2116 self._showtraceback(etype, value, stb)
2152 self._showtraceback(etype, value, stb)
2117
2153
2118 # This is overridden in TerminalInteractiveShell to show a message about
2154 # This is overridden in TerminalInteractiveShell to show a message about
2119 # the %paste magic.
2155 # the %paste magic.
2120 def showindentationerror(self):
2156 def showindentationerror(self):
2121 """Called by _run_cell when there's an IndentationError in code entered
2157 """Called by _run_cell when there's an IndentationError in code entered
2122 at the prompt.
2158 at the prompt.
2123
2159
2124 This is overridden in TerminalInteractiveShell to show a message about
2160 This is overridden in TerminalInteractiveShell to show a message about
2125 the %paste magic."""
2161 the %paste magic."""
2126 self.showsyntaxerror()
2162 self.showsyntaxerror()
2127
2163
2128 @skip_doctest
2164 @skip_doctest
2129 def set_next_input(self, s, replace=False):
2165 def set_next_input(self, s, replace=False):
2130 """ Sets the 'default' input string for the next command line.
2166 """ Sets the 'default' input string for the next command line.
2131
2167
2132 Example::
2168 Example::
2133
2169
2134 In [1]: _ip.set_next_input("Hello Word")
2170 In [1]: _ip.set_next_input("Hello Word")
2135 In [2]: Hello Word_ # cursor is here
2171 In [2]: Hello Word_ # cursor is here
2136 """
2172 """
2137 self.rl_next_input = s
2173 self.rl_next_input = s
2138
2174
2139 def _indent_current_str(self):
2175 def _indent_current_str(self):
2140 """return the current level of indentation as a string"""
2176 """return the current level of indentation as a string"""
2141 return self.input_splitter.get_indent_spaces() * ' '
2177 return self.input_splitter.get_indent_spaces() * ' '
2142
2178
2143 #-------------------------------------------------------------------------
2179 #-------------------------------------------------------------------------
2144 # Things related to text completion
2180 # Things related to text completion
2145 #-------------------------------------------------------------------------
2181 #-------------------------------------------------------------------------
2146
2182
2147 def init_completer(self):
2183 def init_completer(self):
2148 """Initialize the completion machinery.
2184 """Initialize the completion machinery.
2149
2185
2150 This creates completion machinery that can be used by client code,
2186 This creates completion machinery that can be used by client code,
2151 either interactively in-process (typically triggered by the readline
2187 either interactively in-process (typically triggered by the readline
2152 library), programmatically (such as in test suites) or out-of-process
2188 library), programmatically (such as in test suites) or out-of-process
2153 (typically over the network by remote frontends).
2189 (typically over the network by remote frontends).
2154 """
2190 """
2155 from IPython.core.completer import IPCompleter
2191 from IPython.core.completer import IPCompleter
2156 from IPython.core.completerlib import (
2192 from IPython.core.completerlib import (
2157 cd_completer,
2193 cd_completer,
2158 magic_run_completer,
2194 magic_run_completer,
2159 module_completer,
2195 module_completer,
2160 reset_completer,
2196 reset_completer,
2161 )
2197 )
2162
2198
2163 self.Completer = IPCompleter(shell=self,
2199 self.Completer = IPCompleter(shell=self,
2164 namespace=self.user_ns,
2200 namespace=self.user_ns,
2165 global_namespace=self.user_global_ns,
2201 global_namespace=self.user_global_ns,
2166 parent=self,
2202 parent=self,
2167 )
2203 )
2168 self.configurables.append(self.Completer)
2204 self.configurables.append(self.Completer)
2169
2205
2170 # Add custom completers to the basic ones built into IPCompleter
2206 # Add custom completers to the basic ones built into IPCompleter
2171 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2207 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2172 self.strdispatchers['complete_command'] = sdisp
2208 self.strdispatchers['complete_command'] = sdisp
2173 self.Completer.custom_completers = sdisp
2209 self.Completer.custom_completers = sdisp
2174
2210
2175 self.set_hook('complete_command', module_completer, str_key = 'import')
2211 self.set_hook('complete_command', module_completer, str_key = 'import')
2176 self.set_hook('complete_command', module_completer, str_key = 'from')
2212 self.set_hook('complete_command', module_completer, str_key = 'from')
2177 self.set_hook('complete_command', module_completer, str_key = '%aimport')
2213 self.set_hook('complete_command', module_completer, str_key = '%aimport')
2178 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2214 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2179 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2215 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2180 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2216 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2181
2217
2182 @skip_doctest
2218 @skip_doctest
2183 def complete(self, text, line=None, cursor_pos=None):
2219 def complete(self, text, line=None, cursor_pos=None):
2184 """Return the completed text and a list of completions.
2220 """Return the completed text and a list of completions.
2185
2221
2186 Parameters
2222 Parameters
2187 ----------
2223 ----------
2188 text : string
2224 text : string
2189 A string of text to be completed on. It can be given as empty and
2225 A string of text to be completed on. It can be given as empty and
2190 instead a line/position pair are given. In this case, the
2226 instead a line/position pair are given. In this case, the
2191 completer itself will split the line like readline does.
2227 completer itself will split the line like readline does.
2192 line : string, optional
2228 line : string, optional
2193 The complete line that text is part of.
2229 The complete line that text is part of.
2194 cursor_pos : int, optional
2230 cursor_pos : int, optional
2195 The position of the cursor on the input line.
2231 The position of the cursor on the input line.
2196
2232
2197 Returns
2233 Returns
2198 -------
2234 -------
2199 text : string
2235 text : string
2200 The actual text that was completed.
2236 The actual text that was completed.
2201 matches : list
2237 matches : list
2202 A sorted list with all possible completions.
2238 A sorted list with all possible completions.
2203
2239
2204 Notes
2240 Notes
2205 -----
2241 -----
2206 The optional arguments allow the completion to take more context into
2242 The optional arguments allow the completion to take more context into
2207 account, and are part of the low-level completion API.
2243 account, and are part of the low-level completion API.
2208
2244
2209 This is a wrapper around the completion mechanism, similar to what
2245 This is a wrapper around the completion mechanism, similar to what
2210 readline does at the command line when the TAB key is hit. By
2246 readline does at the command line when the TAB key is hit. By
2211 exposing it as a method, it can be used by other non-readline
2247 exposing it as a method, it can be used by other non-readline
2212 environments (such as GUIs) for text completion.
2248 environments (such as GUIs) for text completion.
2213
2249
2214 Examples
2250 Examples
2215 --------
2251 --------
2216 In [1]: x = 'hello'
2252 In [1]: x = 'hello'
2217
2253
2218 In [2]: _ip.complete('x.l')
2254 In [2]: _ip.complete('x.l')
2219 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2255 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2220 """
2256 """
2221
2257
2222 # Inject names into __builtin__ so we can complete on the added names.
2258 # Inject names into __builtin__ so we can complete on the added names.
2223 with self.builtin_trap:
2259 with self.builtin_trap:
2224 return self.Completer.complete(text, line, cursor_pos)
2260 return self.Completer.complete(text, line, cursor_pos)
2225
2261
2226 def set_custom_completer(self, completer, pos=0) -> None:
2262 def set_custom_completer(self, completer, pos=0) -> None:
2227 """Adds a new custom completer function.
2263 """Adds a new custom completer function.
2228
2264
2229 The position argument (defaults to 0) is the index in the completers
2265 The position argument (defaults to 0) is the index in the completers
2230 list where you want the completer to be inserted.
2266 list where you want the completer to be inserted.
2231
2267
2232 `completer` should have the following signature::
2268 `completer` should have the following signature::
2233
2269
2234 def completion(self: Completer, text: string) -> List[str]:
2270 def completion(self: Completer, text: string) -> List[str]:
2235 raise NotImplementedError
2271 raise NotImplementedError
2236
2272
2237 It will be bound to the current Completer instance and pass some text
2273 It will be bound to the current Completer instance and pass some text
2238 and return a list with current completions to suggest to the user.
2274 and return a list with current completions to suggest to the user.
2239 """
2275 """
2240
2276
2241 newcomp = types.MethodType(completer, self.Completer)
2277 newcomp = types.MethodType(completer, self.Completer)
2242 self.Completer.custom_matchers.insert(pos,newcomp)
2278 self.Completer.custom_matchers.insert(pos,newcomp)
2243
2279
2244 def set_completer_frame(self, frame=None):
2280 def set_completer_frame(self, frame=None):
2245 """Set the frame of the completer."""
2281 """Set the frame of the completer."""
2246 if frame:
2282 if frame:
2247 self.Completer.namespace = frame.f_locals
2283 self.Completer.namespace = frame.f_locals
2248 self.Completer.global_namespace = frame.f_globals
2284 self.Completer.global_namespace = frame.f_globals
2249 else:
2285 else:
2250 self.Completer.namespace = self.user_ns
2286 self.Completer.namespace = self.user_ns
2251 self.Completer.global_namespace = self.user_global_ns
2287 self.Completer.global_namespace = self.user_global_ns
2252
2288
2253 #-------------------------------------------------------------------------
2289 #-------------------------------------------------------------------------
2254 # Things related to magics
2290 # Things related to magics
2255 #-------------------------------------------------------------------------
2291 #-------------------------------------------------------------------------
2256
2292
2257 def init_magics(self):
2293 def init_magics(self):
2258 from IPython.core import magics as m
2294 from IPython.core import magics as m
2259 self.magics_manager = magic.MagicsManager(shell=self,
2295 self.magics_manager = magic.MagicsManager(shell=self,
2260 parent=self,
2296 parent=self,
2261 user_magics=m.UserMagics(self))
2297 user_magics=m.UserMagics(self))
2262 self.configurables.append(self.magics_manager)
2298 self.configurables.append(self.magics_manager)
2263
2299
2264 # Expose as public API from the magics manager
2300 # Expose as public API from the magics manager
2265 self.register_magics = self.magics_manager.register
2301 self.register_magics = self.magics_manager.register
2266
2302
2267 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2303 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2268 m.ConfigMagics, m.DisplayMagics, m.ExecutionMagics,
2304 m.ConfigMagics, m.DisplayMagics, m.ExecutionMagics,
2269 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2305 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2270 m.NamespaceMagics, m.OSMagics, m.PackagingMagics,
2306 m.NamespaceMagics, m.OSMagics, m.PackagingMagics,
2271 m.PylabMagics, m.ScriptMagics,
2307 m.PylabMagics, m.ScriptMagics,
2272 )
2308 )
2273 self.register_magics(m.AsyncMagics)
2309 self.register_magics(m.AsyncMagics)
2274
2310
2275 # Register Magic Aliases
2311 # Register Magic Aliases
2276 mman = self.magics_manager
2312 mman = self.magics_manager
2277 # FIXME: magic aliases should be defined by the Magics classes
2313 # FIXME: magic aliases should be defined by the Magics classes
2278 # or in MagicsManager, not here
2314 # or in MagicsManager, not here
2279 mman.register_alias('ed', 'edit')
2315 mman.register_alias('ed', 'edit')
2280 mman.register_alias('hist', 'history')
2316 mman.register_alias('hist', 'history')
2281 mman.register_alias('rep', 'recall')
2317 mman.register_alias('rep', 'recall')
2282 mman.register_alias('SVG', 'svg', 'cell')
2318 mman.register_alias('SVG', 'svg', 'cell')
2283 mman.register_alias('HTML', 'html', 'cell')
2319 mman.register_alias('HTML', 'html', 'cell')
2284 mman.register_alias('file', 'writefile', 'cell')
2320 mman.register_alias('file', 'writefile', 'cell')
2285
2321
2286 # FIXME: Move the color initialization to the DisplayHook, which
2322 # FIXME: Move the color initialization to the DisplayHook, which
2287 # should be split into a prompt manager and displayhook. We probably
2323 # should be split into a prompt manager and displayhook. We probably
2288 # even need a centralize colors management object.
2324 # even need a centralize colors management object.
2289 self.run_line_magic('colors', self.colors)
2325 self.run_line_magic('colors', self.colors)
2290
2326
2291 # Defined here so that it's included in the documentation
2327 # Defined here so that it's included in the documentation
2292 @functools.wraps(magic.MagicsManager.register_function)
2328 @functools.wraps(magic.MagicsManager.register_function)
2293 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2329 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2294 self.magics_manager.register_function(
2330 self.magics_manager.register_function(
2295 func, magic_kind=magic_kind, magic_name=magic_name
2331 func, magic_kind=magic_kind, magic_name=magic_name
2296 )
2332 )
2297
2333
2298 def _find_with_lazy_load(self, /, type_, magic_name: str):
2334 def _find_with_lazy_load(self, /, type_, magic_name: str):
2299 """
2335 """
2300 Try to find a magic potentially lazy-loading it.
2336 Try to find a magic potentially lazy-loading it.
2301
2337
2302 Parameters
2338 Parameters
2303 ----------
2339 ----------
2304
2340
2305 type_: "line"|"cell"
2341 type_: "line"|"cell"
2306 the type of magics we are trying to find/lazy load.
2342 the type of magics we are trying to find/lazy load.
2307 magic_name: str
2343 magic_name: str
2308 The name of the magic we are trying to find/lazy load
2344 The name of the magic we are trying to find/lazy load
2309
2345
2310
2346
2311 Note that this may have any side effects
2347 Note that this may have any side effects
2312 """
2348 """
2313 finder = {"line": self.find_line_magic, "cell": self.find_cell_magic}[type_]
2349 finder = {"line": self.find_line_magic, "cell": self.find_cell_magic}[type_]
2314 fn = finder(magic_name)
2350 fn = finder(magic_name)
2315 if fn is not None:
2351 if fn is not None:
2316 return fn
2352 return fn
2317 lazy = self.magics_manager.lazy_magics.get(magic_name)
2353 lazy = self.magics_manager.lazy_magics.get(magic_name)
2318 if lazy is None:
2354 if lazy is None:
2319 return None
2355 return None
2320
2356
2321 self.run_line_magic("load_ext", lazy)
2357 self.run_line_magic("load_ext", lazy)
2322 res = finder(magic_name)
2358 res = finder(magic_name)
2323 return res
2359 return res
2324
2360
2325 def run_line_magic(self, magic_name: str, line, _stack_depth=1):
2361 def run_line_magic(self, magic_name: str, line, _stack_depth=1):
2326 """Execute the given line magic.
2362 """Execute the given line magic.
2327
2363
2328 Parameters
2364 Parameters
2329 ----------
2365 ----------
2330 magic_name : str
2366 magic_name : str
2331 Name of the desired magic function, without '%' prefix.
2367 Name of the desired magic function, without '%' prefix.
2332 line : str
2368 line : str
2333 The rest of the input line as a single string.
2369 The rest of the input line as a single string.
2334 _stack_depth : int
2370 _stack_depth : int
2335 If run_line_magic() is called from magic() then _stack_depth=2.
2371 If run_line_magic() is called from magic() then _stack_depth=2.
2336 This is added to ensure backward compatibility for use of 'get_ipython().magic()'
2372 This is added to ensure backward compatibility for use of 'get_ipython().magic()'
2337 """
2373 """
2338 fn = self._find_with_lazy_load("line", magic_name)
2374 fn = self._find_with_lazy_load("line", magic_name)
2339 if fn is None:
2375 if fn is None:
2340 lazy = self.magics_manager.lazy_magics.get(magic_name)
2376 lazy = self.magics_manager.lazy_magics.get(magic_name)
2341 if lazy:
2377 if lazy:
2342 self.run_line_magic("load_ext", lazy)
2378 self.run_line_magic("load_ext", lazy)
2343 fn = self.find_line_magic(magic_name)
2379 fn = self.find_line_magic(magic_name)
2344 if fn is None:
2380 if fn is None:
2345 cm = self.find_cell_magic(magic_name)
2381 cm = self.find_cell_magic(magic_name)
2346 etpl = "Line magic function `%%%s` not found%s."
2382 etpl = "Line magic function `%%%s` not found%s."
2347 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2383 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2348 'did you mean that instead?)' % magic_name )
2384 'did you mean that instead?)' % magic_name )
2349 raise UsageError(etpl % (magic_name, extra))
2385 raise UsageError(etpl % (magic_name, extra))
2350 else:
2386 else:
2351 # Note: this is the distance in the stack to the user's frame.
2387 # Note: this is the distance in the stack to the user's frame.
2352 # This will need to be updated if the internal calling logic gets
2388 # This will need to be updated if the internal calling logic gets
2353 # refactored, or else we'll be expanding the wrong variables.
2389 # refactored, or else we'll be expanding the wrong variables.
2354
2390
2355 # Determine stack_depth depending on where run_line_magic() has been called
2391 # Determine stack_depth depending on where run_line_magic() has been called
2356 stack_depth = _stack_depth
2392 stack_depth = _stack_depth
2357 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2393 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2358 # magic has opted out of var_expand
2394 # magic has opted out of var_expand
2359 magic_arg_s = line
2395 magic_arg_s = line
2360 else:
2396 else:
2361 magic_arg_s = self.var_expand(line, stack_depth)
2397 magic_arg_s = self.var_expand(line, stack_depth)
2362 # Put magic args in a list so we can call with f(*a) syntax
2398 # Put magic args in a list so we can call with f(*a) syntax
2363 args = [magic_arg_s]
2399 args = [magic_arg_s]
2364 kwargs = {}
2400 kwargs = {}
2365 # Grab local namespace if we need it:
2401 # Grab local namespace if we need it:
2366 if getattr(fn, "needs_local_scope", False):
2402 if getattr(fn, "needs_local_scope", False):
2367 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2403 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2368 with self.builtin_trap:
2404 with self.builtin_trap:
2369 result = fn(*args, **kwargs)
2405 result = fn(*args, **kwargs)
2370
2406
2371 # The code below prevents the output from being displayed
2407 # The code below prevents the output from being displayed
2372 # when using magics with decodator @output_can_be_silenced
2408 # when using magics with decodator @output_can_be_silenced
2373 # when the last Python token in the expression is a ';'.
2409 # when the last Python token in the expression is a ';'.
2374 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):
2410 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):
2375 if DisplayHook.semicolon_at_end_of_expression(magic_arg_s):
2411 if DisplayHook.semicolon_at_end_of_expression(magic_arg_s):
2376 return None
2412 return None
2377
2413
2378 return result
2414 return result
2379
2415
2380 def get_local_scope(self, stack_depth):
2416 def get_local_scope(self, stack_depth):
2381 """Get local scope at given stack depth.
2417 """Get local scope at given stack depth.
2382
2418
2383 Parameters
2419 Parameters
2384 ----------
2420 ----------
2385 stack_depth : int
2421 stack_depth : int
2386 Depth relative to calling frame
2422 Depth relative to calling frame
2387 """
2423 """
2388 return sys._getframe(stack_depth + 1).f_locals
2424 return sys._getframe(stack_depth + 1).f_locals
2389
2425
2390 def run_cell_magic(self, magic_name, line, cell):
2426 def run_cell_magic(self, magic_name, line, cell):
2391 """Execute the given cell magic.
2427 """Execute the given cell magic.
2392
2428
2393 Parameters
2429 Parameters
2394 ----------
2430 ----------
2395 magic_name : str
2431 magic_name : str
2396 Name of the desired magic function, without '%' prefix.
2432 Name of the desired magic function, without '%' prefix.
2397 line : str
2433 line : str
2398 The rest of the first input line as a single string.
2434 The rest of the first input line as a single string.
2399 cell : str
2435 cell : str
2400 The body of the cell as a (possibly multiline) string.
2436 The body of the cell as a (possibly multiline) string.
2401 """
2437 """
2402 fn = self._find_with_lazy_load("cell", magic_name)
2438 fn = self._find_with_lazy_load("cell", magic_name)
2403 if fn is None:
2439 if fn is None:
2404 lm = self.find_line_magic(magic_name)
2440 lm = self.find_line_magic(magic_name)
2405 etpl = "Cell magic `%%{0}` not found{1}."
2441 etpl = "Cell magic `%%{0}` not found{1}."
2406 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2442 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2407 'did you mean that instead?)'.format(magic_name))
2443 'did you mean that instead?)'.format(magic_name))
2408 raise UsageError(etpl.format(magic_name, extra))
2444 raise UsageError(etpl.format(magic_name, extra))
2409 elif cell == '':
2445 elif cell == '':
2410 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2446 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2411 if self.find_line_magic(magic_name) is not None:
2447 if self.find_line_magic(magic_name) is not None:
2412 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2448 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2413 raise UsageError(message)
2449 raise UsageError(message)
2414 else:
2450 else:
2415 # Note: this is the distance in the stack to the user's frame.
2451 # Note: this is the distance in the stack to the user's frame.
2416 # This will need to be updated if the internal calling logic gets
2452 # This will need to be updated if the internal calling logic gets
2417 # refactored, or else we'll be expanding the wrong variables.
2453 # refactored, or else we'll be expanding the wrong variables.
2418 stack_depth = 2
2454 stack_depth = 2
2419 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2455 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2420 # magic has opted out of var_expand
2456 # magic has opted out of var_expand
2421 magic_arg_s = line
2457 magic_arg_s = line
2422 else:
2458 else:
2423 magic_arg_s = self.var_expand(line, stack_depth)
2459 magic_arg_s = self.var_expand(line, stack_depth)
2424 kwargs = {}
2460 kwargs = {}
2425 if getattr(fn, "needs_local_scope", False):
2461 if getattr(fn, "needs_local_scope", False):
2426 kwargs['local_ns'] = self.user_ns
2462 kwargs['local_ns'] = self.user_ns
2427
2463
2428 with self.builtin_trap:
2464 with self.builtin_trap:
2429 args = (magic_arg_s, cell)
2465 args = (magic_arg_s, cell)
2430 result = fn(*args, **kwargs)
2466 result = fn(*args, **kwargs)
2431
2467
2432 # The code below prevents the output from being displayed
2468 # The code below prevents the output from being displayed
2433 # when using magics with decodator @output_can_be_silenced
2469 # when using magics with decodator @output_can_be_silenced
2434 # when the last Python token in the expression is a ';'.
2470 # when the last Python token in the expression is a ';'.
2435 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):
2471 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):
2436 if DisplayHook.semicolon_at_end_of_expression(cell):
2472 if DisplayHook.semicolon_at_end_of_expression(cell):
2437 return None
2473 return None
2438
2474
2439 return result
2475 return result
2440
2476
2441 def find_line_magic(self, magic_name):
2477 def find_line_magic(self, magic_name):
2442 """Find and return a line magic by name.
2478 """Find and return a line magic by name.
2443
2479
2444 Returns None if the magic isn't found."""
2480 Returns None if the magic isn't found."""
2445 return self.magics_manager.magics['line'].get(magic_name)
2481 return self.magics_manager.magics['line'].get(magic_name)
2446
2482
2447 def find_cell_magic(self, magic_name):
2483 def find_cell_magic(self, magic_name):
2448 """Find and return a cell magic by name.
2484 """Find and return a cell magic by name.
2449
2485
2450 Returns None if the magic isn't found."""
2486 Returns None if the magic isn't found."""
2451 return self.magics_manager.magics['cell'].get(magic_name)
2487 return self.magics_manager.magics['cell'].get(magic_name)
2452
2488
2453 def find_magic(self, magic_name, magic_kind='line'):
2489 def find_magic(self, magic_name, magic_kind='line'):
2454 """Find and return a magic of the given type by name.
2490 """Find and return a magic of the given type by name.
2455
2491
2456 Returns None if the magic isn't found."""
2492 Returns None if the magic isn't found."""
2457 return self.magics_manager.magics[magic_kind].get(magic_name)
2493 return self.magics_manager.magics[magic_kind].get(magic_name)
2458
2494
2459 def magic(self, arg_s):
2495 def magic(self, arg_s):
2460 """
2496 """
2461 DEPRECATED
2497 DEPRECATED
2462
2498
2463 Deprecated since IPython 0.13 (warning added in
2499 Deprecated since IPython 0.13 (warning added in
2464 8.1), use run_line_magic(magic_name, parameter_s).
2500 8.1), use run_line_magic(magic_name, parameter_s).
2465
2501
2466 Call a magic function by name.
2502 Call a magic function by name.
2467
2503
2468 Input: a string containing the name of the magic function to call and
2504 Input: a string containing the name of the magic function to call and
2469 any additional arguments to be passed to the magic.
2505 any additional arguments to be passed to the magic.
2470
2506
2471 magic('name -opt foo bar') is equivalent to typing at the ipython
2507 magic('name -opt foo bar') is equivalent to typing at the ipython
2472 prompt:
2508 prompt:
2473
2509
2474 In[1]: %name -opt foo bar
2510 In[1]: %name -opt foo bar
2475
2511
2476 To call a magic without arguments, simply use magic('name').
2512 To call a magic without arguments, simply use magic('name').
2477
2513
2478 This provides a proper Python function to call IPython's magics in any
2514 This provides a proper Python function to call IPython's magics in any
2479 valid Python code you can type at the interpreter, including loops and
2515 valid Python code you can type at the interpreter, including loops and
2480 compound statements.
2516 compound statements.
2481 """
2517 """
2482 warnings.warn(
2518 warnings.warn(
2483 "`magic(...)` is deprecated since IPython 0.13 (warning added in "
2519 "`magic(...)` is deprecated since IPython 0.13 (warning added in "
2484 "8.1), use run_line_magic(magic_name, parameter_s).",
2520 "8.1), use run_line_magic(magic_name, parameter_s).",
2485 DeprecationWarning,
2521 DeprecationWarning,
2486 stacklevel=2,
2522 stacklevel=2,
2487 )
2523 )
2488 # TODO: should we issue a loud deprecation warning here?
2524 # TODO: should we issue a loud deprecation warning here?
2489 magic_name, _, magic_arg_s = arg_s.partition(' ')
2525 magic_name, _, magic_arg_s = arg_s.partition(' ')
2490 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2526 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2491 return self.run_line_magic(magic_name, magic_arg_s, _stack_depth=2)
2527 return self.run_line_magic(magic_name, magic_arg_s, _stack_depth=2)
2492
2528
2493 #-------------------------------------------------------------------------
2529 #-------------------------------------------------------------------------
2494 # Things related to macros
2530 # Things related to macros
2495 #-------------------------------------------------------------------------
2531 #-------------------------------------------------------------------------
2496
2532
2497 def define_macro(self, name, themacro):
2533 def define_macro(self, name, themacro):
2498 """Define a new macro
2534 """Define a new macro
2499
2535
2500 Parameters
2536 Parameters
2501 ----------
2537 ----------
2502 name : str
2538 name : str
2503 The name of the macro.
2539 The name of the macro.
2504 themacro : str or Macro
2540 themacro : str or Macro
2505 The action to do upon invoking the macro. If a string, a new
2541 The action to do upon invoking the macro. If a string, a new
2506 Macro object is created by passing the string to it.
2542 Macro object is created by passing the string to it.
2507 """
2543 """
2508
2544
2509 from IPython.core import macro
2545 from IPython.core import macro
2510
2546
2511 if isinstance(themacro, str):
2547 if isinstance(themacro, str):
2512 themacro = macro.Macro(themacro)
2548 themacro = macro.Macro(themacro)
2513 if not isinstance(themacro, macro.Macro):
2549 if not isinstance(themacro, macro.Macro):
2514 raise ValueError('A macro must be a string or a Macro instance.')
2550 raise ValueError('A macro must be a string or a Macro instance.')
2515 self.user_ns[name] = themacro
2551 self.user_ns[name] = themacro
2516
2552
2517 #-------------------------------------------------------------------------
2553 #-------------------------------------------------------------------------
2518 # Things related to the running of system commands
2554 # Things related to the running of system commands
2519 #-------------------------------------------------------------------------
2555 #-------------------------------------------------------------------------
2520
2556
2521 def system_piped(self, cmd):
2557 def system_piped(self, cmd):
2522 """Call the given cmd in a subprocess, piping stdout/err
2558 """Call the given cmd in a subprocess, piping stdout/err
2523
2559
2524 Parameters
2560 Parameters
2525 ----------
2561 ----------
2526 cmd : str
2562 cmd : str
2527 Command to execute (can not end in '&', as background processes are
2563 Command to execute (can not end in '&', as background processes are
2528 not supported. Should not be a command that expects input
2564 not supported. Should not be a command that expects input
2529 other than simple text.
2565 other than simple text.
2530 """
2566 """
2531 if cmd.rstrip().endswith('&'):
2567 if cmd.rstrip().endswith('&'):
2532 # this is *far* from a rigorous test
2568 # this is *far* from a rigorous test
2533 # We do not support backgrounding processes because we either use
2569 # We do not support backgrounding processes because we either use
2534 # pexpect or pipes to read from. Users can always just call
2570 # pexpect or pipes to read from. Users can always just call
2535 # os.system() or use ip.system=ip.system_raw
2571 # os.system() or use ip.system=ip.system_raw
2536 # if they really want a background process.
2572 # if they really want a background process.
2537 raise OSError("Background processes not supported.")
2573 raise OSError("Background processes not supported.")
2538
2574
2539 # we explicitly do NOT return the subprocess status code, because
2575 # we explicitly do NOT return the subprocess status code, because
2540 # a non-None value would trigger :func:`sys.displayhook` calls.
2576 # a non-None value would trigger :func:`sys.displayhook` calls.
2541 # Instead, we store the exit_code in user_ns.
2577 # Instead, we store the exit_code in user_ns.
2542 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2578 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2543
2579
2544 def system_raw(self, cmd):
2580 def system_raw(self, cmd):
2545 """Call the given cmd in a subprocess using os.system on Windows or
2581 """Call the given cmd in a subprocess using os.system on Windows or
2546 subprocess.call using the system shell on other platforms.
2582 subprocess.call using the system shell on other platforms.
2547
2583
2548 Parameters
2584 Parameters
2549 ----------
2585 ----------
2550 cmd : str
2586 cmd : str
2551 Command to execute.
2587 Command to execute.
2552 """
2588 """
2553 cmd = self.var_expand(cmd, depth=1)
2589 cmd = self.var_expand(cmd, depth=1)
2554 # warn if there is an IPython magic alternative.
2590 # warn if there is an IPython magic alternative.
2555 main_cmd = cmd.split()[0]
2591 main_cmd = cmd.split()[0]
2556 has_magic_alternatives = ("pip", "conda", "cd")
2592 has_magic_alternatives = ("pip", "conda", "cd")
2557
2593
2558 if main_cmd in has_magic_alternatives:
2594 if main_cmd in has_magic_alternatives:
2559 warnings.warn(
2595 warnings.warn(
2560 (
2596 (
2561 "You executed the system command !{0} which may not work "
2597 "You executed the system command !{0} which may not work "
2562 "as expected. Try the IPython magic %{0} instead."
2598 "as expected. Try the IPython magic %{0} instead."
2563 ).format(main_cmd)
2599 ).format(main_cmd)
2564 )
2600 )
2565
2601
2566 # protect os.system from UNC paths on Windows, which it can't handle:
2602 # protect os.system from UNC paths on Windows, which it can't handle:
2567 if sys.platform == 'win32':
2603 if sys.platform == 'win32':
2568 from IPython.utils._process_win32 import AvoidUNCPath
2604 from IPython.utils._process_win32 import AvoidUNCPath
2569 with AvoidUNCPath() as path:
2605 with AvoidUNCPath() as path:
2570 if path is not None:
2606 if path is not None:
2571 cmd = '"pushd %s &&"%s' % (path, cmd)
2607 cmd = '"pushd %s &&"%s' % (path, cmd)
2572 try:
2608 try:
2573 ec = os.system(cmd)
2609 ec = os.system(cmd)
2574 except KeyboardInterrupt:
2610 except KeyboardInterrupt:
2575 print('\n' + self.get_exception_only(), file=sys.stderr)
2611 print('\n' + self.get_exception_only(), file=sys.stderr)
2576 ec = -2
2612 ec = -2
2577 else:
2613 else:
2578 # For posix the result of the subprocess.call() below is an exit
2614 # For posix the result of the subprocess.call() below is an exit
2579 # code, which by convention is zero for success, positive for
2615 # code, which by convention is zero for success, positive for
2580 # program failure. Exit codes above 128 are reserved for signals,
2616 # program failure. Exit codes above 128 are reserved for signals,
2581 # and the formula for converting a signal to an exit code is usually
2617 # and the formula for converting a signal to an exit code is usually
2582 # signal_number+128. To more easily differentiate between exit
2618 # signal_number+128. To more easily differentiate between exit
2583 # codes and signals, ipython uses negative numbers. For instance
2619 # codes and signals, ipython uses negative numbers. For instance
2584 # since control-c is signal 2 but exit code 130, ipython's
2620 # since control-c is signal 2 but exit code 130, ipython's
2585 # _exit_code variable will read -2. Note that some shells like
2621 # _exit_code variable will read -2. Note that some shells like
2586 # csh and fish don't follow sh/bash conventions for exit codes.
2622 # csh and fish don't follow sh/bash conventions for exit codes.
2587 executable = os.environ.get('SHELL', None)
2623 executable = os.environ.get('SHELL', None)
2588 try:
2624 try:
2589 # Use env shell instead of default /bin/sh
2625 # Use env shell instead of default /bin/sh
2590 ec = subprocess.call(cmd, shell=True, executable=executable)
2626 ec = subprocess.call(cmd, shell=True, executable=executable)
2591 except KeyboardInterrupt:
2627 except KeyboardInterrupt:
2592 # intercept control-C; a long traceback is not useful here
2628 # intercept control-C; a long traceback is not useful here
2593 print('\n' + self.get_exception_only(), file=sys.stderr)
2629 print('\n' + self.get_exception_only(), file=sys.stderr)
2594 ec = 130
2630 ec = 130
2595 if ec > 128:
2631 if ec > 128:
2596 ec = -(ec - 128)
2632 ec = -(ec - 128)
2597
2633
2598 # We explicitly do NOT return the subprocess status code, because
2634 # We explicitly do NOT return the subprocess status code, because
2599 # a non-None value would trigger :func:`sys.displayhook` calls.
2635 # a non-None value would trigger :func:`sys.displayhook` calls.
2600 # Instead, we store the exit_code in user_ns. Note the semantics
2636 # Instead, we store the exit_code in user_ns. Note the semantics
2601 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2637 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2602 # but raising SystemExit(_exit_code) will give status 254!
2638 # but raising SystemExit(_exit_code) will give status 254!
2603 self.user_ns['_exit_code'] = ec
2639 self.user_ns['_exit_code'] = ec
2604
2640
2605 # use piped system by default, because it is better behaved
2641 # use piped system by default, because it is better behaved
2606 system = system_piped
2642 system = system_piped
2607
2643
2608 def getoutput(self, cmd, split=True, depth=0):
2644 def getoutput(self, cmd, split=True, depth=0):
2609 """Get output (possibly including stderr) from a subprocess.
2645 """Get output (possibly including stderr) from a subprocess.
2610
2646
2611 Parameters
2647 Parameters
2612 ----------
2648 ----------
2613 cmd : str
2649 cmd : str
2614 Command to execute (can not end in '&', as background processes are
2650 Command to execute (can not end in '&', as background processes are
2615 not supported.
2651 not supported.
2616 split : bool, optional
2652 split : bool, optional
2617 If True, split the output into an IPython SList. Otherwise, an
2653 If True, split the output into an IPython SList. Otherwise, an
2618 IPython LSString is returned. These are objects similar to normal
2654 IPython LSString is returned. These are objects similar to normal
2619 lists and strings, with a few convenience attributes for easier
2655 lists and strings, with a few convenience attributes for easier
2620 manipulation of line-based output. You can use '?' on them for
2656 manipulation of line-based output. You can use '?' on them for
2621 details.
2657 details.
2622 depth : int, optional
2658 depth : int, optional
2623 How many frames above the caller are the local variables which should
2659 How many frames above the caller are the local variables which should
2624 be expanded in the command string? The default (0) assumes that the
2660 be expanded in the command string? The default (0) assumes that the
2625 expansion variables are in the stack frame calling this function.
2661 expansion variables are in the stack frame calling this function.
2626 """
2662 """
2627 if cmd.rstrip().endswith('&'):
2663 if cmd.rstrip().endswith('&'):
2628 # this is *far* from a rigorous test
2664 # this is *far* from a rigorous test
2629 raise OSError("Background processes not supported.")
2665 raise OSError("Background processes not supported.")
2630 out = getoutput(self.var_expand(cmd, depth=depth+1))
2666 out = getoutput(self.var_expand(cmd, depth=depth+1))
2631 if split:
2667 if split:
2632 out = SList(out.splitlines())
2668 out = SList(out.splitlines())
2633 else:
2669 else:
2634 out = LSString(out)
2670 out = LSString(out)
2635 return out
2671 return out
2636
2672
2637 #-------------------------------------------------------------------------
2673 #-------------------------------------------------------------------------
2638 # Things related to aliases
2674 # Things related to aliases
2639 #-------------------------------------------------------------------------
2675 #-------------------------------------------------------------------------
2640
2676
2641 def init_alias(self):
2677 def init_alias(self):
2642 self.alias_manager = AliasManager(shell=self, parent=self)
2678 self.alias_manager = AliasManager(shell=self, parent=self)
2643 self.configurables.append(self.alias_manager)
2679 self.configurables.append(self.alias_manager)
2644
2680
2645 #-------------------------------------------------------------------------
2681 #-------------------------------------------------------------------------
2646 # Things related to extensions
2682 # Things related to extensions
2647 #-------------------------------------------------------------------------
2683 #-------------------------------------------------------------------------
2648
2684
2649 def init_extension_manager(self):
2685 def init_extension_manager(self):
2650 self.extension_manager = ExtensionManager(shell=self, parent=self)
2686 self.extension_manager = ExtensionManager(shell=self, parent=self)
2651 self.configurables.append(self.extension_manager)
2687 self.configurables.append(self.extension_manager)
2652
2688
2653 #-------------------------------------------------------------------------
2689 #-------------------------------------------------------------------------
2654 # Things related to payloads
2690 # Things related to payloads
2655 #-------------------------------------------------------------------------
2691 #-------------------------------------------------------------------------
2656
2692
2657 def init_payload(self):
2693 def init_payload(self):
2658 self.payload_manager = PayloadManager(parent=self)
2694 self.payload_manager = PayloadManager(parent=self)
2659 self.configurables.append(self.payload_manager)
2695 self.configurables.append(self.payload_manager)
2660
2696
2661 #-------------------------------------------------------------------------
2697 #-------------------------------------------------------------------------
2662 # Things related to the prefilter
2698 # Things related to the prefilter
2663 #-------------------------------------------------------------------------
2699 #-------------------------------------------------------------------------
2664
2700
2665 def init_prefilter(self):
2701 def init_prefilter(self):
2666 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2702 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2667 self.configurables.append(self.prefilter_manager)
2703 self.configurables.append(self.prefilter_manager)
2668 # Ultimately this will be refactored in the new interpreter code, but
2704 # Ultimately this will be refactored in the new interpreter code, but
2669 # for now, we should expose the main prefilter method (there's legacy
2705 # for now, we should expose the main prefilter method (there's legacy
2670 # code out there that may rely on this).
2706 # code out there that may rely on this).
2671 self.prefilter = self.prefilter_manager.prefilter_lines
2707 self.prefilter = self.prefilter_manager.prefilter_lines
2672
2708
2673 def auto_rewrite_input(self, cmd):
2709 def auto_rewrite_input(self, cmd):
2674 """Print to the screen the rewritten form of the user's command.
2710 """Print to the screen the rewritten form of the user's command.
2675
2711
2676 This shows visual feedback by rewriting input lines that cause
2712 This shows visual feedback by rewriting input lines that cause
2677 automatic calling to kick in, like::
2713 automatic calling to kick in, like::
2678
2714
2679 /f x
2715 /f x
2680
2716
2681 into::
2717 into::
2682
2718
2683 ------> f(x)
2719 ------> f(x)
2684
2720
2685 after the user's input prompt. This helps the user understand that the
2721 after the user's input prompt. This helps the user understand that the
2686 input line was transformed automatically by IPython.
2722 input line was transformed automatically by IPython.
2687 """
2723 """
2688 if not self.show_rewritten_input:
2724 if not self.show_rewritten_input:
2689 return
2725 return
2690
2726
2691 # This is overridden in TerminalInteractiveShell to use fancy prompts
2727 # This is overridden in TerminalInteractiveShell to use fancy prompts
2692 print("------> " + cmd)
2728 print("------> " + cmd)
2693
2729
2694 #-------------------------------------------------------------------------
2730 #-------------------------------------------------------------------------
2695 # Things related to extracting values/expressions from kernel and user_ns
2731 # Things related to extracting values/expressions from kernel and user_ns
2696 #-------------------------------------------------------------------------
2732 #-------------------------------------------------------------------------
2697
2733
2698 def _user_obj_error(self):
2734 def _user_obj_error(self):
2699 """return simple exception dict
2735 """return simple exception dict
2700
2736
2701 for use in user_expressions
2737 for use in user_expressions
2702 """
2738 """
2703
2739
2704 etype, evalue, tb = self._get_exc_info()
2740 etype, evalue, tb = self._get_exc_info()
2705 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2741 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2706
2742
2707 exc_info = {
2743 exc_info = {
2708 "status": "error",
2744 "status": "error",
2709 "traceback": stb,
2745 "traceback": stb,
2710 "ename": etype.__name__,
2746 "ename": etype.__name__,
2711 "evalue": py3compat.safe_unicode(evalue),
2747 "evalue": py3compat.safe_unicode(evalue),
2712 }
2748 }
2713
2749
2714 return exc_info
2750 return exc_info
2715
2751
2716 def _format_user_obj(self, obj):
2752 def _format_user_obj(self, obj):
2717 """format a user object to display dict
2753 """format a user object to display dict
2718
2754
2719 for use in user_expressions
2755 for use in user_expressions
2720 """
2756 """
2721
2757
2722 data, md = self.display_formatter.format(obj)
2758 data, md = self.display_formatter.format(obj)
2723 value = {
2759 value = {
2724 'status' : 'ok',
2760 'status' : 'ok',
2725 'data' : data,
2761 'data' : data,
2726 'metadata' : md,
2762 'metadata' : md,
2727 }
2763 }
2728 return value
2764 return value
2729
2765
2730 def user_expressions(self, expressions):
2766 def user_expressions(self, expressions):
2731 """Evaluate a dict of expressions in the user's namespace.
2767 """Evaluate a dict of expressions in the user's namespace.
2732
2768
2733 Parameters
2769 Parameters
2734 ----------
2770 ----------
2735 expressions : dict
2771 expressions : dict
2736 A dict with string keys and string values. The expression values
2772 A dict with string keys and string values. The expression values
2737 should be valid Python expressions, each of which will be evaluated
2773 should be valid Python expressions, each of which will be evaluated
2738 in the user namespace.
2774 in the user namespace.
2739
2775
2740 Returns
2776 Returns
2741 -------
2777 -------
2742 A dict, keyed like the input expressions dict, with the rich mime-typed
2778 A dict, keyed like the input expressions dict, with the rich mime-typed
2743 display_data of each value.
2779 display_data of each value.
2744 """
2780 """
2745 out = {}
2781 out = {}
2746 user_ns = self.user_ns
2782 user_ns = self.user_ns
2747 global_ns = self.user_global_ns
2783 global_ns = self.user_global_ns
2748
2784
2749 for key, expr in expressions.items():
2785 for key, expr in expressions.items():
2750 try:
2786 try:
2751 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2787 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2752 except:
2788 except:
2753 value = self._user_obj_error()
2789 value = self._user_obj_error()
2754 out[key] = value
2790 out[key] = value
2755 return out
2791 return out
2756
2792
2757 #-------------------------------------------------------------------------
2793 #-------------------------------------------------------------------------
2758 # Things related to the running of code
2794 # Things related to the running of code
2759 #-------------------------------------------------------------------------
2795 #-------------------------------------------------------------------------
2760
2796
2761 def ex(self, cmd):
2797 def ex(self, cmd):
2762 """Execute a normal python statement in user namespace."""
2798 """Execute a normal python statement in user namespace."""
2763 with self.builtin_trap:
2799 with self.builtin_trap:
2764 exec(cmd, self.user_global_ns, self.user_ns)
2800 exec(cmd, self.user_global_ns, self.user_ns)
2765
2801
2766 def ev(self, expr):
2802 def ev(self, expr):
2767 """Evaluate python expression expr in user namespace.
2803 """Evaluate python expression expr in user namespace.
2768
2804
2769 Returns the result of evaluation
2805 Returns the result of evaluation
2770 """
2806 """
2771 with self.builtin_trap:
2807 with self.builtin_trap:
2772 return eval(expr, self.user_global_ns, self.user_ns)
2808 return eval(expr, self.user_global_ns, self.user_ns)
2773
2809
2774 def safe_execfile(self, fname, *where, exit_ignore=False, raise_exceptions=False, shell_futures=False):
2810 def safe_execfile(self, fname, *where, exit_ignore=False, raise_exceptions=False, shell_futures=False):
2775 """A safe version of the builtin execfile().
2811 """A safe version of the builtin execfile().
2776
2812
2777 This version will never throw an exception, but instead print
2813 This version will never throw an exception, but instead print
2778 helpful error messages to the screen. This only works on pure
2814 helpful error messages to the screen. This only works on pure
2779 Python files with the .py extension.
2815 Python files with the .py extension.
2780
2816
2781 Parameters
2817 Parameters
2782 ----------
2818 ----------
2783 fname : string
2819 fname : string
2784 The name of the file to be executed.
2820 The name of the file to be executed.
2785 *where : tuple
2821 *where : tuple
2786 One or two namespaces, passed to execfile() as (globals,locals).
2822 One or two namespaces, passed to execfile() as (globals,locals).
2787 If only one is given, it is passed as both.
2823 If only one is given, it is passed as both.
2788 exit_ignore : bool (False)
2824 exit_ignore : bool (False)
2789 If True, then silence SystemExit for non-zero status (it is always
2825 If True, then silence SystemExit for non-zero status (it is always
2790 silenced for zero status, as it is so common).
2826 silenced for zero status, as it is so common).
2791 raise_exceptions : bool (False)
2827 raise_exceptions : bool (False)
2792 If True raise exceptions everywhere. Meant for testing.
2828 If True raise exceptions everywhere. Meant for testing.
2793 shell_futures : bool (False)
2829 shell_futures : bool (False)
2794 If True, the code will share future statements with the interactive
2830 If True, the code will share future statements with the interactive
2795 shell. It will both be affected by previous __future__ imports, and
2831 shell. It will both be affected by previous __future__ imports, and
2796 any __future__ imports in the code will affect the shell. If False,
2832 any __future__ imports in the code will affect the shell. If False,
2797 __future__ imports are not shared in either direction.
2833 __future__ imports are not shared in either direction.
2798
2834
2799 """
2835 """
2800 fname = Path(fname).expanduser().resolve()
2836 fname = Path(fname).expanduser().resolve()
2801
2837
2802 # Make sure we can open the file
2838 # Make sure we can open the file
2803 try:
2839 try:
2804 with fname.open("rb"):
2840 with fname.open("rb"):
2805 pass
2841 pass
2806 except:
2842 except:
2807 warn('Could not open file <%s> for safe execution.' % fname)
2843 warn('Could not open file <%s> for safe execution.' % fname)
2808 return
2844 return
2809
2845
2810 # Find things also in current directory. This is needed to mimic the
2846 # Find things also in current directory. This is needed to mimic the
2811 # behavior of running a script from the system command line, where
2847 # behavior of running a script from the system command line, where
2812 # Python inserts the script's directory into sys.path
2848 # Python inserts the script's directory into sys.path
2813 dname = str(fname.parent)
2849 dname = str(fname.parent)
2814
2850
2815 with prepended_to_syspath(dname), self.builtin_trap:
2851 with prepended_to_syspath(dname), self.builtin_trap:
2816 try:
2852 try:
2817 glob, loc = (where + (None, ))[:2]
2853 glob, loc = (where + (None, ))[:2]
2818 py3compat.execfile(
2854 py3compat.execfile(
2819 fname, glob, loc,
2855 fname, glob, loc,
2820 self.compile if shell_futures else None)
2856 self.compile if shell_futures else None)
2821 except SystemExit as status:
2857 except SystemExit as status:
2822 # If the call was made with 0 or None exit status (sys.exit(0)
2858 # If the call was made with 0 or None exit status (sys.exit(0)
2823 # or sys.exit() ), don't bother showing a traceback, as both of
2859 # or sys.exit() ), don't bother showing a traceback, as both of
2824 # these are considered normal by the OS:
2860 # these are considered normal by the OS:
2825 # > python -c'import sys;sys.exit(0)'; echo $?
2861 # > python -c'import sys;sys.exit(0)'; echo $?
2826 # 0
2862 # 0
2827 # > python -c'import sys;sys.exit()'; echo $?
2863 # > python -c'import sys;sys.exit()'; echo $?
2828 # 0
2864 # 0
2829 # For other exit status, we show the exception unless
2865 # For other exit status, we show the exception unless
2830 # explicitly silenced, but only in short form.
2866 # explicitly silenced, but only in short form.
2831 if status.code:
2867 if status.code:
2832 if raise_exceptions:
2868 if raise_exceptions:
2833 raise
2869 raise
2834 if not exit_ignore:
2870 if not exit_ignore:
2835 self.showtraceback(exception_only=True)
2871 self.showtraceback(exception_only=True)
2836 except:
2872 except:
2837 if raise_exceptions:
2873 if raise_exceptions:
2838 raise
2874 raise
2839 # tb offset is 2 because we wrap execfile
2875 # tb offset is 2 because we wrap execfile
2840 self.showtraceback(tb_offset=2)
2876 self.showtraceback(tb_offset=2)
2841
2877
2842 def safe_execfile_ipy(self, fname, shell_futures=False, raise_exceptions=False):
2878 def safe_execfile_ipy(self, fname, shell_futures=False, raise_exceptions=False):
2843 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2879 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2844
2880
2845 Parameters
2881 Parameters
2846 ----------
2882 ----------
2847 fname : str
2883 fname : str
2848 The name of the file to execute. The filename must have a
2884 The name of the file to execute. The filename must have a
2849 .ipy or .ipynb extension.
2885 .ipy or .ipynb extension.
2850 shell_futures : bool (False)
2886 shell_futures : bool (False)
2851 If True, the code will share future statements with the interactive
2887 If True, the code will share future statements with the interactive
2852 shell. It will both be affected by previous __future__ imports, and
2888 shell. It will both be affected by previous __future__ imports, and
2853 any __future__ imports in the code will affect the shell. If False,
2889 any __future__ imports in the code will affect the shell. If False,
2854 __future__ imports are not shared in either direction.
2890 __future__ imports are not shared in either direction.
2855 raise_exceptions : bool (False)
2891 raise_exceptions : bool (False)
2856 If True raise exceptions everywhere. Meant for testing.
2892 If True raise exceptions everywhere. Meant for testing.
2857 """
2893 """
2858 fname = Path(fname).expanduser().resolve()
2894 fname = Path(fname).expanduser().resolve()
2859
2895
2860 # Make sure we can open the file
2896 # Make sure we can open the file
2861 try:
2897 try:
2862 with fname.open("rb"):
2898 with fname.open("rb"):
2863 pass
2899 pass
2864 except:
2900 except:
2865 warn('Could not open file <%s> for safe execution.' % fname)
2901 warn('Could not open file <%s> for safe execution.' % fname)
2866 return
2902 return
2867
2903
2868 # Find things also in current directory. This is needed to mimic the
2904 # Find things also in current directory. This is needed to mimic the
2869 # behavior of running a script from the system command line, where
2905 # behavior of running a script from the system command line, where
2870 # Python inserts the script's directory into sys.path
2906 # Python inserts the script's directory into sys.path
2871 dname = str(fname.parent)
2907 dname = str(fname.parent)
2872
2908
2873 def get_cells():
2909 def get_cells():
2874 """generator for sequence of code blocks to run"""
2910 """generator for sequence of code blocks to run"""
2875 if fname.suffix == ".ipynb":
2911 if fname.suffix == ".ipynb":
2876 from nbformat import read
2912 from nbformat import read
2877 nb = read(fname, as_version=4)
2913 nb = read(fname, as_version=4)
2878 if not nb.cells:
2914 if not nb.cells:
2879 return
2915 return
2880 for cell in nb.cells:
2916 for cell in nb.cells:
2881 if cell.cell_type == 'code':
2917 if cell.cell_type == 'code':
2882 yield cell.source
2918 yield cell.source
2883 else:
2919 else:
2884 yield fname.read_text(encoding="utf-8")
2920 yield fname.read_text(encoding="utf-8")
2885
2921
2886 with prepended_to_syspath(dname):
2922 with prepended_to_syspath(dname):
2887 try:
2923 try:
2888 for cell in get_cells():
2924 for cell in get_cells():
2889 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2925 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2890 if raise_exceptions:
2926 if raise_exceptions:
2891 result.raise_error()
2927 result.raise_error()
2892 elif not result.success:
2928 elif not result.success:
2893 break
2929 break
2894 except:
2930 except:
2895 if raise_exceptions:
2931 if raise_exceptions:
2896 raise
2932 raise
2897 self.showtraceback()
2933 self.showtraceback()
2898 warn('Unknown failure executing file: <%s>' % fname)
2934 warn('Unknown failure executing file: <%s>' % fname)
2899
2935
2900 def safe_run_module(self, mod_name, where):
2936 def safe_run_module(self, mod_name, where):
2901 """A safe version of runpy.run_module().
2937 """A safe version of runpy.run_module().
2902
2938
2903 This version will never throw an exception, but instead print
2939 This version will never throw an exception, but instead print
2904 helpful error messages to the screen.
2940 helpful error messages to the screen.
2905
2941
2906 `SystemExit` exceptions with status code 0 or None are ignored.
2942 `SystemExit` exceptions with status code 0 or None are ignored.
2907
2943
2908 Parameters
2944 Parameters
2909 ----------
2945 ----------
2910 mod_name : string
2946 mod_name : string
2911 The name of the module to be executed.
2947 The name of the module to be executed.
2912 where : dict
2948 where : dict
2913 The globals namespace.
2949 The globals namespace.
2914 """
2950 """
2915 try:
2951 try:
2916 try:
2952 try:
2917 where.update(
2953 where.update(
2918 runpy.run_module(str(mod_name), run_name="__main__",
2954 runpy.run_module(str(mod_name), run_name="__main__",
2919 alter_sys=True)
2955 alter_sys=True)
2920 )
2956 )
2921 except SystemExit as status:
2957 except SystemExit as status:
2922 if status.code:
2958 if status.code:
2923 raise
2959 raise
2924 except:
2960 except:
2925 self.showtraceback()
2961 self.showtraceback()
2926 warn('Unknown failure executing module: <%s>' % mod_name)
2962 warn('Unknown failure executing module: <%s>' % mod_name)
2927
2963
2928 def run_cell(
2964 def run_cell(
2929 self,
2965 self,
2930 raw_cell,
2966 raw_cell,
2931 store_history=False,
2967 store_history=False,
2932 silent=False,
2968 silent=False,
2933 shell_futures=True,
2969 shell_futures=True,
2934 cell_id=None,
2970 cell_id=None,
2935 ):
2971 ):
2936 """Run a complete IPython cell.
2972 """Run a complete IPython cell.
2937
2973
2938 Parameters
2974 Parameters
2939 ----------
2975 ----------
2940 raw_cell : str
2976 raw_cell : str
2941 The code (including IPython code such as %magic functions) to run.
2977 The code (including IPython code such as %magic functions) to run.
2942 store_history : bool
2978 store_history : bool
2943 If True, the raw and translated cell will be stored in IPython's
2979 If True, the raw and translated cell will be stored in IPython's
2944 history. For user code calling back into IPython's machinery, this
2980 history. For user code calling back into IPython's machinery, this
2945 should be set to False.
2981 should be set to False.
2946 silent : bool
2982 silent : bool
2947 If True, avoid side-effects, such as implicit displayhooks and
2983 If True, avoid side-effects, such as implicit displayhooks and
2948 and logging. silent=True forces store_history=False.
2984 and logging. silent=True forces store_history=False.
2949 shell_futures : bool
2985 shell_futures : bool
2950 If True, the code will share future statements with the interactive
2986 If True, the code will share future statements with the interactive
2951 shell. It will both be affected by previous __future__ imports, and
2987 shell. It will both be affected by previous __future__ imports, and
2952 any __future__ imports in the code will affect the shell. If False,
2988 any __future__ imports in the code will affect the shell. If False,
2953 __future__ imports are not shared in either direction.
2989 __future__ imports are not shared in either direction.
2954
2990
2955 Returns
2991 Returns
2956 -------
2992 -------
2957 result : :class:`ExecutionResult`
2993 result : :class:`ExecutionResult`
2958 """
2994 """
2959 result = None
2995 result = None
2960 try:
2996 try:
2961 result = self._run_cell(
2997 result = self._run_cell(
2962 raw_cell, store_history, silent, shell_futures, cell_id
2998 raw_cell, store_history, silent, shell_futures, cell_id
2963 )
2999 )
2964 finally:
3000 finally:
2965 self.events.trigger('post_execute')
3001 self.events.trigger('post_execute')
2966 if not silent:
3002 if not silent:
2967 self.events.trigger('post_run_cell', result)
3003 self.events.trigger('post_run_cell', result)
2968 return result
3004 return result
2969
3005
2970 def _run_cell(
3006 def _run_cell(
2971 self,
3007 self,
2972 raw_cell: str,
3008 raw_cell: str,
2973 store_history: bool,
3009 store_history: bool,
2974 silent: bool,
3010 silent: bool,
2975 shell_futures: bool,
3011 shell_futures: bool,
2976 cell_id: str,
3012 cell_id: str,
2977 ) -> ExecutionResult:
3013 ) -> ExecutionResult:
2978 """Internal method to run a complete IPython cell."""
3014 """Internal method to run a complete IPython cell."""
2979
3015
2980 # we need to avoid calling self.transform_cell multiple time on the same thing
3016 # we need to avoid calling self.transform_cell multiple time on the same thing
2981 # so we need to store some results:
3017 # so we need to store some results:
2982 preprocessing_exc_tuple = None
3018 preprocessing_exc_tuple = None
2983 try:
3019 try:
2984 transformed_cell = self.transform_cell(raw_cell)
3020 transformed_cell = self.transform_cell(raw_cell)
2985 except Exception:
3021 except Exception:
2986 transformed_cell = raw_cell
3022 transformed_cell = raw_cell
2987 preprocessing_exc_tuple = sys.exc_info()
3023 preprocessing_exc_tuple = sys.exc_info()
2988
3024
2989 assert transformed_cell is not None
3025 assert transformed_cell is not None
2990 coro = self.run_cell_async(
3026 coro = self.run_cell_async(
2991 raw_cell,
3027 raw_cell,
2992 store_history=store_history,
3028 store_history=store_history,
2993 silent=silent,
3029 silent=silent,
2994 shell_futures=shell_futures,
3030 shell_futures=shell_futures,
2995 transformed_cell=transformed_cell,
3031 transformed_cell=transformed_cell,
2996 preprocessing_exc_tuple=preprocessing_exc_tuple,
3032 preprocessing_exc_tuple=preprocessing_exc_tuple,
2997 cell_id=cell_id,
3033 cell_id=cell_id,
2998 )
3034 )
2999
3035
3000 # run_cell_async is async, but may not actually need an eventloop.
3036 # run_cell_async is async, but may not actually need an eventloop.
3001 # when this is the case, we want to run it using the pseudo_sync_runner
3037 # when this is the case, we want to run it using the pseudo_sync_runner
3002 # so that code can invoke eventloops (for example via the %run , and
3038 # so that code can invoke eventloops (for example via the %run , and
3003 # `%paste` magic.
3039 # `%paste` magic.
3004 if self.trio_runner:
3040 if self.trio_runner:
3005 runner = self.trio_runner
3041 runner = self.trio_runner
3006 elif self.should_run_async(
3042 elif self.should_run_async(
3007 raw_cell,
3043 raw_cell,
3008 transformed_cell=transformed_cell,
3044 transformed_cell=transformed_cell,
3009 preprocessing_exc_tuple=preprocessing_exc_tuple,
3045 preprocessing_exc_tuple=preprocessing_exc_tuple,
3010 ):
3046 ):
3011 runner = self.loop_runner
3047 runner = self.loop_runner
3012 else:
3048 else:
3013 runner = _pseudo_sync_runner
3049 runner = _pseudo_sync_runner
3014
3050
3015 try:
3051 try:
3016 result = runner(coro)
3052 result = runner(coro)
3017 except BaseException as e:
3053 except BaseException as e:
3018 info = ExecutionInfo(
3054 info = ExecutionInfo(
3019 raw_cell, store_history, silent, shell_futures, cell_id
3055 raw_cell, store_history, silent, shell_futures, cell_id
3020 )
3056 )
3021 result = ExecutionResult(info)
3057 result = ExecutionResult(info)
3022 result.error_in_exec = e
3058 result.error_in_exec = e
3023 self.showtraceback(running_compiled_code=True)
3059 self.showtraceback(running_compiled_code=True)
3024 finally:
3060 finally:
3025 return result
3061 return result
3026
3062
3027 def should_run_async(
3063 def should_run_async(
3028 self, raw_cell: str, *, transformed_cell=None, preprocessing_exc_tuple=None
3064 self, raw_cell: str, *, transformed_cell=None, preprocessing_exc_tuple=None
3029 ) -> bool:
3065 ) -> bool:
3030 """Return whether a cell should be run asynchronously via a coroutine runner
3066 """Return whether a cell should be run asynchronously via a coroutine runner
3031
3067
3032 Parameters
3068 Parameters
3033 ----------
3069 ----------
3034 raw_cell : str
3070 raw_cell : str
3035 The code to be executed
3071 The code to be executed
3036
3072
3037 Returns
3073 Returns
3038 -------
3074 -------
3039 result: bool
3075 result: bool
3040 Whether the code needs to be run with a coroutine runner or not
3076 Whether the code needs to be run with a coroutine runner or not
3041 .. versionadded:: 7.0
3077 .. versionadded:: 7.0
3042 """
3078 """
3043 if not self.autoawait:
3079 if not self.autoawait:
3044 return False
3080 return False
3045 if preprocessing_exc_tuple is not None:
3081 if preprocessing_exc_tuple is not None:
3046 return False
3082 return False
3047 assert preprocessing_exc_tuple is None
3083 assert preprocessing_exc_tuple is None
3048 if transformed_cell is None:
3084 if transformed_cell is None:
3049 warnings.warn(
3085 warnings.warn(
3050 "`should_run_async` will not call `transform_cell`"
3086 "`should_run_async` will not call `transform_cell`"
3051 " automatically in the future. Please pass the result to"
3087 " automatically in the future. Please pass the result to"
3052 " `transformed_cell` argument and any exception that happen"
3088 " `transformed_cell` argument and any exception that happen"
3053 " during the"
3089 " during the"
3054 "transform in `preprocessing_exc_tuple` in"
3090 "transform in `preprocessing_exc_tuple` in"
3055 " IPython 7.17 and above.",
3091 " IPython 7.17 and above.",
3056 DeprecationWarning,
3092 DeprecationWarning,
3057 stacklevel=2,
3093 stacklevel=2,
3058 )
3094 )
3059 try:
3095 try:
3060 cell = self.transform_cell(raw_cell)
3096 cell = self.transform_cell(raw_cell)
3061 except Exception:
3097 except Exception:
3062 # any exception during transform will be raised
3098 # any exception during transform will be raised
3063 # prior to execution
3099 # prior to execution
3064 return False
3100 return False
3065 else:
3101 else:
3066 cell = transformed_cell
3102 cell = transformed_cell
3067 return _should_be_async(cell)
3103 return _should_be_async(cell)
3068
3104
3069 async def run_cell_async(
3105 async def run_cell_async(
3070 self,
3106 self,
3071 raw_cell: str,
3107 raw_cell: str,
3072 store_history=False,
3108 store_history=False,
3073 silent=False,
3109 silent=False,
3074 shell_futures=True,
3110 shell_futures=True,
3075 *,
3111 *,
3076 transformed_cell: Optional[str] = None,
3112 transformed_cell: Optional[str] = None,
3077 preprocessing_exc_tuple: Optional[Any] = None,
3113 preprocessing_exc_tuple: Optional[Any] = None,
3078 cell_id=None,
3114 cell_id=None,
3079 ) -> ExecutionResult:
3115 ) -> ExecutionResult:
3080 """Run a complete IPython cell asynchronously.
3116 """Run a complete IPython cell asynchronously.
3081
3117
3082 Parameters
3118 Parameters
3083 ----------
3119 ----------
3084 raw_cell : str
3120 raw_cell : str
3085 The code (including IPython code such as %magic functions) to run.
3121 The code (including IPython code such as %magic functions) to run.
3086 store_history : bool
3122 store_history : bool
3087 If True, the raw and translated cell will be stored in IPython's
3123 If True, the raw and translated cell will be stored in IPython's
3088 history. For user code calling back into IPython's machinery, this
3124 history. For user code calling back into IPython's machinery, this
3089 should be set to False.
3125 should be set to False.
3090 silent : bool
3126 silent : bool
3091 If True, avoid side-effects, such as implicit displayhooks and
3127 If True, avoid side-effects, such as implicit displayhooks and
3092 and logging. silent=True forces store_history=False.
3128 and logging. silent=True forces store_history=False.
3093 shell_futures : bool
3129 shell_futures : bool
3094 If True, the code will share future statements with the interactive
3130 If True, the code will share future statements with the interactive
3095 shell. It will both be affected by previous __future__ imports, and
3131 shell. It will both be affected by previous __future__ imports, and
3096 any __future__ imports in the code will affect the shell. If False,
3132 any __future__ imports in the code will affect the shell. If False,
3097 __future__ imports are not shared in either direction.
3133 __future__ imports are not shared in either direction.
3098 transformed_cell: str
3134 transformed_cell: str
3099 cell that was passed through transformers
3135 cell that was passed through transformers
3100 preprocessing_exc_tuple:
3136 preprocessing_exc_tuple:
3101 trace if the transformation failed.
3137 trace if the transformation failed.
3102
3138
3103 Returns
3139 Returns
3104 -------
3140 -------
3105 result : :class:`ExecutionResult`
3141 result : :class:`ExecutionResult`
3106
3142
3107 .. versionadded:: 7.0
3143 .. versionadded:: 7.0
3108 """
3144 """
3109 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures, cell_id)
3145 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures, cell_id)
3110 result = ExecutionResult(info)
3146 result = ExecutionResult(info)
3111
3147
3112 if (not raw_cell) or raw_cell.isspace():
3148 if (not raw_cell) or raw_cell.isspace():
3113 self.last_execution_succeeded = True
3149 self.last_execution_succeeded = True
3114 self.last_execution_result = result
3150 self.last_execution_result = result
3115 return result
3151 return result
3116
3152
3117 if silent:
3153 if silent:
3118 store_history = False
3154 store_history = False
3119
3155
3120 if store_history:
3156 if store_history:
3121 result.execution_count = self.execution_count
3157 result.execution_count = self.execution_count
3122
3158
3123 def error_before_exec(value):
3159 def error_before_exec(value):
3124 if store_history:
3160 if store_history:
3125 self.execution_count += 1
3161 self.execution_count += 1
3126 result.error_before_exec = value
3162 result.error_before_exec = value
3127 self.last_execution_succeeded = False
3163 self.last_execution_succeeded = False
3128 self.last_execution_result = result
3164 self.last_execution_result = result
3129 return result
3165 return result
3130
3166
3131 self.events.trigger('pre_execute')
3167 self.events.trigger('pre_execute')
3132 if not silent:
3168 if not silent:
3133 self.events.trigger('pre_run_cell', info)
3169 self.events.trigger('pre_run_cell', info)
3134
3170
3135 if transformed_cell is None:
3171 if transformed_cell is None:
3136 warnings.warn(
3172 warnings.warn(
3137 "`run_cell_async` will not call `transform_cell`"
3173 "`run_cell_async` will not call `transform_cell`"
3138 " automatically in the future. Please pass the result to"
3174 " automatically in the future. Please pass the result to"
3139 " `transformed_cell` argument and any exception that happen"
3175 " `transformed_cell` argument and any exception that happen"
3140 " during the"
3176 " during the"
3141 "transform in `preprocessing_exc_tuple` in"
3177 "transform in `preprocessing_exc_tuple` in"
3142 " IPython 7.17 and above.",
3178 " IPython 7.17 and above.",
3143 DeprecationWarning,
3179 DeprecationWarning,
3144 stacklevel=2,
3180 stacklevel=2,
3145 )
3181 )
3146 # If any of our input transformation (input_transformer_manager or
3182 # If any of our input transformation (input_transformer_manager or
3147 # prefilter_manager) raises an exception, we store it in this variable
3183 # prefilter_manager) raises an exception, we store it in this variable
3148 # so that we can display the error after logging the input and storing
3184 # so that we can display the error after logging the input and storing
3149 # it in the history.
3185 # it in the history.
3150 try:
3186 try:
3151 cell = self.transform_cell(raw_cell)
3187 cell = self.transform_cell(raw_cell)
3152 except Exception:
3188 except Exception:
3153 preprocessing_exc_tuple = sys.exc_info()
3189 preprocessing_exc_tuple = sys.exc_info()
3154 cell = raw_cell # cell has to exist so it can be stored/logged
3190 cell = raw_cell # cell has to exist so it can be stored/logged
3155 else:
3191 else:
3156 preprocessing_exc_tuple = None
3192 preprocessing_exc_tuple = None
3157 else:
3193 else:
3158 if preprocessing_exc_tuple is None:
3194 if preprocessing_exc_tuple is None:
3159 cell = transformed_cell
3195 cell = transformed_cell
3160 else:
3196 else:
3161 cell = raw_cell
3197 cell = raw_cell
3162
3198
3163 # Do NOT store paste/cpaste magic history
3199 # Do NOT store paste/cpaste magic history
3164 if "get_ipython().run_line_magic(" in cell and "paste" in cell:
3200 if "get_ipython().run_line_magic(" in cell and "paste" in cell:
3165 store_history = False
3201 store_history = False
3166
3202
3167 # Store raw and processed history
3203 # Store raw and processed history
3168 if store_history:
3204 if store_history:
3169 self.history_manager.store_inputs(self.execution_count, cell, raw_cell)
3205 self.history_manager.store_inputs(self.execution_count, cell, raw_cell)
3170 if not silent:
3206 if not silent:
3171 self.logger.log(cell, raw_cell)
3207 self.logger.log(cell, raw_cell)
3172
3208
3173 # Display the exception if input processing failed.
3209 # Display the exception if input processing failed.
3174 if preprocessing_exc_tuple is not None:
3210 if preprocessing_exc_tuple is not None:
3175 self.showtraceback(preprocessing_exc_tuple)
3211 self.showtraceback(preprocessing_exc_tuple)
3176 if store_history:
3212 if store_history:
3177 self.execution_count += 1
3213 self.execution_count += 1
3178 return error_before_exec(preprocessing_exc_tuple[1])
3214 return error_before_exec(preprocessing_exc_tuple[1])
3179
3215
3180 # Our own compiler remembers the __future__ environment. If we want to
3216 # Our own compiler remembers the __future__ environment. If we want to
3181 # run code with a separate __future__ environment, use the default
3217 # run code with a separate __future__ environment, use the default
3182 # compiler
3218 # compiler
3183 compiler = self.compile if shell_futures else self.compiler_class()
3219 compiler = self.compile if shell_futures else self.compiler_class()
3184
3220
3185 _run_async = False
3221 _run_async = False
3186
3222
3187 with self.builtin_trap:
3223 with self.builtin_trap:
3188 cell_name = compiler.cache(cell, self.execution_count, raw_code=raw_cell)
3224 cell_name = compiler.cache(cell, self.execution_count, raw_code=raw_cell)
3189
3225
3190 with self.display_trap:
3226 with self.display_trap:
3191 # Compile to bytecode
3227 # Compile to bytecode
3192 try:
3228 try:
3193 code_ast = compiler.ast_parse(cell, filename=cell_name)
3229 code_ast = compiler.ast_parse(cell, filename=cell_name)
3194 except self.custom_exceptions as e:
3230 except self.custom_exceptions as e:
3195 etype, value, tb = sys.exc_info()
3231 etype, value, tb = sys.exc_info()
3196 self.CustomTB(etype, value, tb)
3232 self.CustomTB(etype, value, tb)
3197 return error_before_exec(e)
3233 return error_before_exec(e)
3198 except IndentationError as e:
3234 except IndentationError as e:
3199 self.showindentationerror()
3235 self.showindentationerror()
3200 return error_before_exec(e)
3236 return error_before_exec(e)
3201 except (OverflowError, SyntaxError, ValueError, TypeError,
3237 except (OverflowError, SyntaxError, ValueError, TypeError,
3202 MemoryError) as e:
3238 MemoryError) as e:
3203 self.showsyntaxerror()
3239 self.showsyntaxerror()
3204 return error_before_exec(e)
3240 return error_before_exec(e)
3205
3241
3206 # Apply AST transformations
3242 # Apply AST transformations
3207 try:
3243 try:
3208 code_ast = self.transform_ast(code_ast)
3244 code_ast = self.transform_ast(code_ast)
3209 except InputRejected as e:
3245 except InputRejected as e:
3210 self.showtraceback()
3246 self.showtraceback()
3211 return error_before_exec(e)
3247 return error_before_exec(e)
3212
3248
3213 # Give the displayhook a reference to our ExecutionResult so it
3249 # Give the displayhook a reference to our ExecutionResult so it
3214 # can fill in the output value.
3250 # can fill in the output value.
3215 self.displayhook.exec_result = result
3251 self.displayhook.exec_result = result
3216
3252
3217 # Execute the user code
3253 # Execute the user code
3218 interactivity = "none" if silent else self.ast_node_interactivity
3254 interactivity = "none" if silent else self.ast_node_interactivity
3219
3255
3220
3256
3221 has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
3257 has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
3222 interactivity=interactivity, compiler=compiler, result=result)
3258 interactivity=interactivity, compiler=compiler, result=result)
3223
3259
3224 self.last_execution_succeeded = not has_raised
3260 self.last_execution_succeeded = not has_raised
3225 self.last_execution_result = result
3261 self.last_execution_result = result
3226
3262
3227 # Reset this so later displayed values do not modify the
3263 # Reset this so later displayed values do not modify the
3228 # ExecutionResult
3264 # ExecutionResult
3229 self.displayhook.exec_result = None
3265 self.displayhook.exec_result = None
3230
3266
3231 if store_history:
3267 if store_history:
3232 # Write output to the database. Does nothing unless
3268 # Write output to the database. Does nothing unless
3233 # history output logging is enabled.
3269 # history output logging is enabled.
3234 self.history_manager.store_output(self.execution_count)
3270 self.history_manager.store_output(self.execution_count)
3235 # Each cell is a *single* input, regardless of how many lines it has
3271 # Each cell is a *single* input, regardless of how many lines it has
3236 self.execution_count += 1
3272 self.execution_count += 1
3237
3273
3238 return result
3274 return result
3239
3275
3240 def transform_cell(self, raw_cell):
3276 def transform_cell(self, raw_cell):
3241 """Transform an input cell before parsing it.
3277 """Transform an input cell before parsing it.
3242
3278
3243 Static transformations, implemented in IPython.core.inputtransformer2,
3279 Static transformations, implemented in IPython.core.inputtransformer2,
3244 deal with things like ``%magic`` and ``!system`` commands.
3280 deal with things like ``%magic`` and ``!system`` commands.
3245 These run on all input.
3281 These run on all input.
3246 Dynamic transformations, for things like unescaped magics and the exit
3282 Dynamic transformations, for things like unescaped magics and the exit
3247 autocall, depend on the state of the interpreter.
3283 autocall, depend on the state of the interpreter.
3248 These only apply to single line inputs.
3284 These only apply to single line inputs.
3249
3285
3250 These string-based transformations are followed by AST transformations;
3286 These string-based transformations are followed by AST transformations;
3251 see :meth:`transform_ast`.
3287 see :meth:`transform_ast`.
3252 """
3288 """
3253 # Static input transformations
3289 # Static input transformations
3254 cell = self.input_transformer_manager.transform_cell(raw_cell)
3290 cell = self.input_transformer_manager.transform_cell(raw_cell)
3255
3291
3256 if len(cell.splitlines()) == 1:
3292 if len(cell.splitlines()) == 1:
3257 # Dynamic transformations - only applied for single line commands
3293 # Dynamic transformations - only applied for single line commands
3258 with self.builtin_trap:
3294 with self.builtin_trap:
3259 # use prefilter_lines to handle trailing newlines
3295 # use prefilter_lines to handle trailing newlines
3260 # restore trailing newline for ast.parse
3296 # restore trailing newline for ast.parse
3261 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
3297 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
3262
3298
3263 lines = cell.splitlines(keepends=True)
3299 lines = cell.splitlines(keepends=True)
3264 for transform in self.input_transformers_post:
3300 for transform in self.input_transformers_post:
3265 lines = transform(lines)
3301 lines = transform(lines)
3266 cell = ''.join(lines)
3302 cell = ''.join(lines)
3267
3303
3268 return cell
3304 return cell
3269
3305
3270 def transform_ast(self, node):
3306 def transform_ast(self, node):
3271 """Apply the AST transformations from self.ast_transformers
3307 """Apply the AST transformations from self.ast_transformers
3272
3308
3273 Parameters
3309 Parameters
3274 ----------
3310 ----------
3275 node : ast.Node
3311 node : ast.Node
3276 The root node to be transformed. Typically called with the ast.Module
3312 The root node to be transformed. Typically called with the ast.Module
3277 produced by parsing user input.
3313 produced by parsing user input.
3278
3314
3279 Returns
3315 Returns
3280 -------
3316 -------
3281 An ast.Node corresponding to the node it was called with. Note that it
3317 An ast.Node corresponding to the node it was called with. Note that it
3282 may also modify the passed object, so don't rely on references to the
3318 may also modify the passed object, so don't rely on references to the
3283 original AST.
3319 original AST.
3284 """
3320 """
3285 for transformer in self.ast_transformers:
3321 for transformer in self.ast_transformers:
3286 try:
3322 try:
3287 node = transformer.visit(node)
3323 node = transformer.visit(node)
3288 except InputRejected:
3324 except InputRejected:
3289 # User-supplied AST transformers can reject an input by raising
3325 # User-supplied AST transformers can reject an input by raising
3290 # an InputRejected. Short-circuit in this case so that we
3326 # an InputRejected. Short-circuit in this case so that we
3291 # don't unregister the transform.
3327 # don't unregister the transform.
3292 raise
3328 raise
3293 except Exception:
3329 except Exception:
3294 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
3330 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
3295 self.ast_transformers.remove(transformer)
3331 self.ast_transformers.remove(transformer)
3296
3332
3297 if self.ast_transformers:
3333 if self.ast_transformers:
3298 ast.fix_missing_locations(node)
3334 ast.fix_missing_locations(node)
3299 return node
3335 return node
3300
3336
3301 async def run_ast_nodes(
3337 async def run_ast_nodes(
3302 self,
3338 self,
3303 nodelist: ListType[stmt],
3339 nodelist: ListType[stmt],
3304 cell_name: str,
3340 cell_name: str,
3305 interactivity="last_expr",
3341 interactivity="last_expr",
3306 compiler=compile,
3342 compiler=compile,
3307 result=None,
3343 result=None,
3308 ):
3344 ):
3309 """Run a sequence of AST nodes. The execution mode depends on the
3345 """Run a sequence of AST nodes. The execution mode depends on the
3310 interactivity parameter.
3346 interactivity parameter.
3311
3347
3312 Parameters
3348 Parameters
3313 ----------
3349 ----------
3314 nodelist : list
3350 nodelist : list
3315 A sequence of AST nodes to run.
3351 A sequence of AST nodes to run.
3316 cell_name : str
3352 cell_name : str
3317 Will be passed to the compiler as the filename of the cell. Typically
3353 Will be passed to the compiler as the filename of the cell. Typically
3318 the value returned by ip.compile.cache(cell).
3354 the value returned by ip.compile.cache(cell).
3319 interactivity : str
3355 interactivity : str
3320 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none',
3356 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none',
3321 specifying which nodes should be run interactively (displaying output
3357 specifying which nodes should be run interactively (displaying output
3322 from expressions). 'last_expr' will run the last node interactively
3358 from expressions). 'last_expr' will run the last node interactively
3323 only if it is an expression (i.e. expressions in loops or other blocks
3359 only if it is an expression (i.e. expressions in loops or other blocks
3324 are not displayed) 'last_expr_or_assign' will run the last expression
3360 are not displayed) 'last_expr_or_assign' will run the last expression
3325 or the last assignment. Other values for this parameter will raise a
3361 or the last assignment. Other values for this parameter will raise a
3326 ValueError.
3362 ValueError.
3327
3363
3328 compiler : callable
3364 compiler : callable
3329 A function with the same interface as the built-in compile(), to turn
3365 A function with the same interface as the built-in compile(), to turn
3330 the AST nodes into code objects. Default is the built-in compile().
3366 the AST nodes into code objects. Default is the built-in compile().
3331 result : ExecutionResult, optional
3367 result : ExecutionResult, optional
3332 An object to store exceptions that occur during execution.
3368 An object to store exceptions that occur during execution.
3333
3369
3334 Returns
3370 Returns
3335 -------
3371 -------
3336 True if an exception occurred while running code, False if it finished
3372 True if an exception occurred while running code, False if it finished
3337 running.
3373 running.
3338 """
3374 """
3339 if not nodelist:
3375 if not nodelist:
3340 return
3376 return
3341
3377
3342
3378
3343 if interactivity == 'last_expr_or_assign':
3379 if interactivity == 'last_expr_or_assign':
3344 if isinstance(nodelist[-1], _assign_nodes):
3380 if isinstance(nodelist[-1], _assign_nodes):
3345 asg = nodelist[-1]
3381 asg = nodelist[-1]
3346 if isinstance(asg, ast.Assign) and len(asg.targets) == 1:
3382 if isinstance(asg, ast.Assign) and len(asg.targets) == 1:
3347 target = asg.targets[0]
3383 target = asg.targets[0]
3348 elif isinstance(asg, _single_targets_nodes):
3384 elif isinstance(asg, _single_targets_nodes):
3349 target = asg.target
3385 target = asg.target
3350 else:
3386 else:
3351 target = None
3387 target = None
3352 if isinstance(target, ast.Name):
3388 if isinstance(target, ast.Name):
3353 nnode = ast.Expr(ast.Name(target.id, ast.Load()))
3389 nnode = ast.Expr(ast.Name(target.id, ast.Load()))
3354 ast.fix_missing_locations(nnode)
3390 ast.fix_missing_locations(nnode)
3355 nodelist.append(nnode)
3391 nodelist.append(nnode)
3356 interactivity = 'last_expr'
3392 interactivity = 'last_expr'
3357
3393
3358 _async = False
3394 _async = False
3359 if interactivity == 'last_expr':
3395 if interactivity == 'last_expr':
3360 if isinstance(nodelist[-1], ast.Expr):
3396 if isinstance(nodelist[-1], ast.Expr):
3361 interactivity = "last"
3397 interactivity = "last"
3362 else:
3398 else:
3363 interactivity = "none"
3399 interactivity = "none"
3364
3400
3365 if interactivity == 'none':
3401 if interactivity == 'none':
3366 to_run_exec, to_run_interactive = nodelist, []
3402 to_run_exec, to_run_interactive = nodelist, []
3367 elif interactivity == 'last':
3403 elif interactivity == 'last':
3368 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
3404 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
3369 elif interactivity == 'all':
3405 elif interactivity == 'all':
3370 to_run_exec, to_run_interactive = [], nodelist
3406 to_run_exec, to_run_interactive = [], nodelist
3371 else:
3407 else:
3372 raise ValueError("Interactivity was %r" % interactivity)
3408 raise ValueError("Interactivity was %r" % interactivity)
3373
3409
3374 try:
3410 try:
3375
3411
3376 def compare(code):
3412 def compare(code):
3377 is_async = inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE
3413 is_async = inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE
3378 return is_async
3414 return is_async
3379
3415
3380 # refactor that to just change the mod constructor.
3416 # refactor that to just change the mod constructor.
3381 to_run = []
3417 to_run = []
3382 for node in to_run_exec:
3418 for node in to_run_exec:
3383 to_run.append((node, "exec"))
3419 to_run.append((node, "exec"))
3384
3420
3385 for node in to_run_interactive:
3421 for node in to_run_interactive:
3386 to_run.append((node, "single"))
3422 to_run.append((node, "single"))
3387
3423
3388 for node, mode in to_run:
3424 for node, mode in to_run:
3389 if mode == "exec":
3425 if mode == "exec":
3390 mod = Module([node], [])
3426 mod = Module([node], [])
3391 elif mode == "single":
3427 elif mode == "single":
3392 mod = ast.Interactive([node])
3428 mod = ast.Interactive([node])
3393 with compiler.extra_flags(
3429 with compiler.extra_flags(
3394 getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
3430 getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
3395 if self.autoawait
3431 if self.autoawait
3396 else 0x0
3432 else 0x0
3397 ):
3433 ):
3398 code = compiler(mod, cell_name, mode)
3434 code = compiler(mod, cell_name, mode)
3399 asy = compare(code)
3435 asy = compare(code)
3400 if await self.run_code(code, result, async_=asy):
3436 if await self.run_code(code, result, async_=asy):
3401 return True
3437 return True
3402
3438
3403 # Flush softspace
3439 # Flush softspace
3404 if softspace(sys.stdout, 0):
3440 if softspace(sys.stdout, 0):
3405 print()
3441 print()
3406
3442
3407 except:
3443 except:
3408 # It's possible to have exceptions raised here, typically by
3444 # It's possible to have exceptions raised here, typically by
3409 # compilation of odd code (such as a naked 'return' outside a
3445 # compilation of odd code (such as a naked 'return' outside a
3410 # function) that did parse but isn't valid. Typically the exception
3446 # function) that did parse but isn't valid. Typically the exception
3411 # is a SyntaxError, but it's safest just to catch anything and show
3447 # is a SyntaxError, but it's safest just to catch anything and show
3412 # the user a traceback.
3448 # the user a traceback.
3413
3449
3414 # We do only one try/except outside the loop to minimize the impact
3450 # We do only one try/except outside the loop to minimize the impact
3415 # on runtime, and also because if any node in the node list is
3451 # on runtime, and also because if any node in the node list is
3416 # broken, we should stop execution completely.
3452 # broken, we should stop execution completely.
3417 if result:
3453 if result:
3418 result.error_before_exec = sys.exc_info()[1]
3454 result.error_before_exec = sys.exc_info()[1]
3419 self.showtraceback()
3455 self.showtraceback()
3420 return True
3456 return True
3421
3457
3422 return False
3458 return False
3423
3459
3424 async def run_code(self, code_obj, result=None, *, async_=False):
3460 async def run_code(self, code_obj, result=None, *, async_=False):
3425 """Execute a code object.
3461 """Execute a code object.
3426
3462
3427 When an exception occurs, self.showtraceback() is called to display a
3463 When an exception occurs, self.showtraceback() is called to display a
3428 traceback.
3464 traceback.
3429
3465
3430 Parameters
3466 Parameters
3431 ----------
3467 ----------
3432 code_obj : code object
3468 code_obj : code object
3433 A compiled code object, to be executed
3469 A compiled code object, to be executed
3434 result : ExecutionResult, optional
3470 result : ExecutionResult, optional
3435 An object to store exceptions that occur during execution.
3471 An object to store exceptions that occur during execution.
3436 async_ : Bool (Experimental)
3472 async_ : Bool (Experimental)
3437 Attempt to run top-level asynchronous code in a default loop.
3473 Attempt to run top-level asynchronous code in a default loop.
3438
3474
3439 Returns
3475 Returns
3440 -------
3476 -------
3441 False : successful execution.
3477 False : successful execution.
3442 True : an error occurred.
3478 True : an error occurred.
3443 """
3479 """
3444 # special value to say that anything above is IPython and should be
3480 # special value to say that anything above is IPython and should be
3445 # hidden.
3481 # hidden.
3446 __tracebackhide__ = "__ipython_bottom__"
3482 __tracebackhide__ = "__ipython_bottom__"
3447 # Set our own excepthook in case the user code tries to call it
3483 # Set our own excepthook in case the user code tries to call it
3448 # directly, so that the IPython crash handler doesn't get triggered
3484 # directly, so that the IPython crash handler doesn't get triggered
3449 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3485 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3450
3486
3451 # we save the original sys.excepthook in the instance, in case config
3487 # we save the original sys.excepthook in the instance, in case config
3452 # code (such as magics) needs access to it.
3488 # code (such as magics) needs access to it.
3453 self.sys_excepthook = old_excepthook
3489 self.sys_excepthook = old_excepthook
3454 outflag = True # happens in more places, so it's easier as default
3490 outflag = True # happens in more places, so it's easier as default
3455 try:
3491 try:
3456 try:
3492 try:
3457 if async_:
3493 if async_:
3458 await eval(code_obj, self.user_global_ns, self.user_ns)
3494 await eval(code_obj, self.user_global_ns, self.user_ns)
3459 else:
3495 else:
3460 exec(code_obj, self.user_global_ns, self.user_ns)
3496 exec(code_obj, self.user_global_ns, self.user_ns)
3461 finally:
3497 finally:
3462 # Reset our crash handler in place
3498 # Reset our crash handler in place
3463 sys.excepthook = old_excepthook
3499 sys.excepthook = old_excepthook
3464 except SystemExit as e:
3500 except SystemExit as e:
3465 if result is not None:
3501 if result is not None:
3466 result.error_in_exec = e
3502 result.error_in_exec = e
3467 self.showtraceback(exception_only=True)
3503 self.showtraceback(exception_only=True)
3468 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3504 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3469 except bdb.BdbQuit:
3505 except bdb.BdbQuit:
3470 etype, value, tb = sys.exc_info()
3506 etype, value, tb = sys.exc_info()
3471 if result is not None:
3507 if result is not None:
3472 result.error_in_exec = value
3508 result.error_in_exec = value
3473 # the BdbQuit stops here
3509 # the BdbQuit stops here
3474 except self.custom_exceptions:
3510 except self.custom_exceptions:
3475 etype, value, tb = sys.exc_info()
3511 etype, value, tb = sys.exc_info()
3476 if result is not None:
3512 if result is not None:
3477 result.error_in_exec = value
3513 result.error_in_exec = value
3478 self.CustomTB(etype, value, tb)
3514 self.CustomTB(etype, value, tb)
3479 except:
3515 except:
3480 if result is not None:
3516 if result is not None:
3481 result.error_in_exec = sys.exc_info()[1]
3517 result.error_in_exec = sys.exc_info()[1]
3482 self.showtraceback(running_compiled_code=True)
3518 self.showtraceback(running_compiled_code=True)
3483 else:
3519 else:
3484 outflag = False
3520 outflag = False
3485 return outflag
3521 return outflag
3486
3522
3487 # For backwards compatibility
3523 # For backwards compatibility
3488 runcode = run_code
3524 runcode = run_code
3489
3525
3490 def check_complete(self, code: str) -> Tuple[str, str]:
3526 def check_complete(self, code: str) -> Tuple[str, str]:
3491 """Return whether a block of code is ready to execute, or should be continued
3527 """Return whether a block of code is ready to execute, or should be continued
3492
3528
3493 Parameters
3529 Parameters
3494 ----------
3530 ----------
3495 code : string
3531 code : string
3496 Python input code, which can be multiline.
3532 Python input code, which can be multiline.
3497
3533
3498 Returns
3534 Returns
3499 -------
3535 -------
3500 status : str
3536 status : str
3501 One of 'complete', 'incomplete', or 'invalid' if source is not a
3537 One of 'complete', 'incomplete', or 'invalid' if source is not a
3502 prefix of valid code.
3538 prefix of valid code.
3503 indent : str
3539 indent : str
3504 When status is 'incomplete', this is some whitespace to insert on
3540 When status is 'incomplete', this is some whitespace to insert on
3505 the next line of the prompt.
3541 the next line of the prompt.
3506 """
3542 """
3507 status, nspaces = self.input_transformer_manager.check_complete(code)
3543 status, nspaces = self.input_transformer_manager.check_complete(code)
3508 return status, ' ' * (nspaces or 0)
3544 return status, ' ' * (nspaces or 0)
3509
3545
3510 #-------------------------------------------------------------------------
3546 #-------------------------------------------------------------------------
3511 # Things related to GUI support and pylab
3547 # Things related to GUI support and pylab
3512 #-------------------------------------------------------------------------
3548 #-------------------------------------------------------------------------
3513
3549
3514 active_eventloop = None
3550 active_eventloop = None
3515
3551
3516 def enable_gui(self, gui=None):
3552 def enable_gui(self, gui=None):
3517 raise NotImplementedError('Implement enable_gui in a subclass')
3553 raise NotImplementedError('Implement enable_gui in a subclass')
3518
3554
3519 def enable_matplotlib(self, gui=None):
3555 def enable_matplotlib(self, gui=None):
3520 """Enable interactive matplotlib and inline figure support.
3556 """Enable interactive matplotlib and inline figure support.
3521
3557
3522 This takes the following steps:
3558 This takes the following steps:
3523
3559
3524 1. select the appropriate eventloop and matplotlib backend
3560 1. select the appropriate eventloop and matplotlib backend
3525 2. set up matplotlib for interactive use with that backend
3561 2. set up matplotlib for interactive use with that backend
3526 3. configure formatters for inline figure display
3562 3. configure formatters for inline figure display
3527 4. enable the selected gui eventloop
3563 4. enable the selected gui eventloop
3528
3564
3529 Parameters
3565 Parameters
3530 ----------
3566 ----------
3531 gui : optional, string
3567 gui : optional, string
3532 If given, dictates the choice of matplotlib GUI backend to use
3568 If given, dictates the choice of matplotlib GUI backend to use
3533 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3569 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3534 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3570 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3535 matplotlib (as dictated by the matplotlib build-time options plus the
3571 matplotlib (as dictated by the matplotlib build-time options plus the
3536 user's matplotlibrc configuration file). Note that not all backends
3572 user's matplotlibrc configuration file). Note that not all backends
3537 make sense in all contexts, for example a terminal ipython can't
3573 make sense in all contexts, for example a terminal ipython can't
3538 display figures inline.
3574 display figures inline.
3539 """
3575 """
3540 from matplotlib_inline.backend_inline import configure_inline_support
3576 from matplotlib_inline.backend_inline import configure_inline_support
3541
3577
3542 from IPython.core import pylabtools as pt
3578 from IPython.core import pylabtools as pt
3543 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3579 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3544
3580
3545 if gui != 'inline':
3581 if gui != 'inline':
3546 # If we have our first gui selection, store it
3582 # If we have our first gui selection, store it
3547 if self.pylab_gui_select is None:
3583 if self.pylab_gui_select is None:
3548 self.pylab_gui_select = gui
3584 self.pylab_gui_select = gui
3549 # Otherwise if they are different
3585 # Otherwise if they are different
3550 elif gui != self.pylab_gui_select:
3586 elif gui != self.pylab_gui_select:
3551 print('Warning: Cannot change to a different GUI toolkit: %s.'
3587 print('Warning: Cannot change to a different GUI toolkit: %s.'
3552 ' Using %s instead.' % (gui, self.pylab_gui_select))
3588 ' Using %s instead.' % (gui, self.pylab_gui_select))
3553 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3589 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3554
3590
3555 pt.activate_matplotlib(backend)
3591 pt.activate_matplotlib(backend)
3556 configure_inline_support(self, backend)
3592 configure_inline_support(self, backend)
3557
3593
3558 # Now we must activate the gui pylab wants to use, and fix %run to take
3594 # Now we must activate the gui pylab wants to use, and fix %run to take
3559 # plot updates into account
3595 # plot updates into account
3560 self.enable_gui(gui)
3596 self.enable_gui(gui)
3561 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3597 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3562 pt.mpl_runner(self.safe_execfile)
3598 pt.mpl_runner(self.safe_execfile)
3563
3599
3564 return gui, backend
3600 return gui, backend
3565
3601
3566 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3602 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3567 """Activate pylab support at runtime.
3603 """Activate pylab support at runtime.
3568
3604
3569 This turns on support for matplotlib, preloads into the interactive
3605 This turns on support for matplotlib, preloads into the interactive
3570 namespace all of numpy and pylab, and configures IPython to correctly
3606 namespace all of numpy and pylab, and configures IPython to correctly
3571 interact with the GUI event loop. The GUI backend to be used can be
3607 interact with the GUI event loop. The GUI backend to be used can be
3572 optionally selected with the optional ``gui`` argument.
3608 optionally selected with the optional ``gui`` argument.
3573
3609
3574 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3610 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3575
3611
3576 Parameters
3612 Parameters
3577 ----------
3613 ----------
3578 gui : optional, string
3614 gui : optional, string
3579 If given, dictates the choice of matplotlib GUI backend to use
3615 If given, dictates the choice of matplotlib GUI backend to use
3580 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3616 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3581 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3617 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3582 matplotlib (as dictated by the matplotlib build-time options plus the
3618 matplotlib (as dictated by the matplotlib build-time options plus the
3583 user's matplotlibrc configuration file). Note that not all backends
3619 user's matplotlibrc configuration file). Note that not all backends
3584 make sense in all contexts, for example a terminal ipython can't
3620 make sense in all contexts, for example a terminal ipython can't
3585 display figures inline.
3621 display figures inline.
3586 import_all : optional, bool, default: True
3622 import_all : optional, bool, default: True
3587 Whether to do `from numpy import *` and `from pylab import *`
3623 Whether to do `from numpy import *` and `from pylab import *`
3588 in addition to module imports.
3624 in addition to module imports.
3589 welcome_message : deprecated
3625 welcome_message : deprecated
3590 This argument is ignored, no welcome message will be displayed.
3626 This argument is ignored, no welcome message will be displayed.
3591 """
3627 """
3592 from IPython.core.pylabtools import import_pylab
3628 from IPython.core.pylabtools import import_pylab
3593
3629
3594 gui, backend = self.enable_matplotlib(gui)
3630 gui, backend = self.enable_matplotlib(gui)
3595
3631
3596 # We want to prevent the loading of pylab to pollute the user's
3632 # We want to prevent the loading of pylab to pollute the user's
3597 # namespace as shown by the %who* magics, so we execute the activation
3633 # namespace as shown by the %who* magics, so we execute the activation
3598 # code in an empty namespace, and we update *both* user_ns and
3634 # code in an empty namespace, and we update *both* user_ns and
3599 # user_ns_hidden with this information.
3635 # user_ns_hidden with this information.
3600 ns = {}
3636 ns = {}
3601 import_pylab(ns, import_all)
3637 import_pylab(ns, import_all)
3602 # warn about clobbered names
3638 # warn about clobbered names
3603 ignored = {"__builtins__"}
3639 ignored = {"__builtins__"}
3604 both = set(ns).intersection(self.user_ns).difference(ignored)
3640 both = set(ns).intersection(self.user_ns).difference(ignored)
3605 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3641 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3606 self.user_ns.update(ns)
3642 self.user_ns.update(ns)
3607 self.user_ns_hidden.update(ns)
3643 self.user_ns_hidden.update(ns)
3608 return gui, backend, clobbered
3644 return gui, backend, clobbered
3609
3645
3610 #-------------------------------------------------------------------------
3646 #-------------------------------------------------------------------------
3611 # Utilities
3647 # Utilities
3612 #-------------------------------------------------------------------------
3648 #-------------------------------------------------------------------------
3613
3649
3614 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3650 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3615 """Expand python variables in a string.
3651 """Expand python variables in a string.
3616
3652
3617 The depth argument indicates how many frames above the caller should
3653 The depth argument indicates how many frames above the caller should
3618 be walked to look for the local namespace where to expand variables.
3654 be walked to look for the local namespace where to expand variables.
3619
3655
3620 The global namespace for expansion is always the user's interactive
3656 The global namespace for expansion is always the user's interactive
3621 namespace.
3657 namespace.
3622 """
3658 """
3623 ns = self.user_ns.copy()
3659 ns = self.user_ns.copy()
3624 try:
3660 try:
3625 frame = sys._getframe(depth+1)
3661 frame = sys._getframe(depth+1)
3626 except ValueError:
3662 except ValueError:
3627 # This is thrown if there aren't that many frames on the stack,
3663 # This is thrown if there aren't that many frames on the stack,
3628 # e.g. if a script called run_line_magic() directly.
3664 # e.g. if a script called run_line_magic() directly.
3629 pass
3665 pass
3630 else:
3666 else:
3631 ns.update(frame.f_locals)
3667 ns.update(frame.f_locals)
3632
3668
3633 try:
3669 try:
3634 # We have to use .vformat() here, because 'self' is a valid and common
3670 # We have to use .vformat() here, because 'self' is a valid and common
3635 # name, and expanding **ns for .format() would make it collide with
3671 # name, and expanding **ns for .format() would make it collide with
3636 # the 'self' argument of the method.
3672 # the 'self' argument of the method.
3637 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3673 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3638 except Exception:
3674 except Exception:
3639 # if formatter couldn't format, just let it go untransformed
3675 # if formatter couldn't format, just let it go untransformed
3640 pass
3676 pass
3641 return cmd
3677 return cmd
3642
3678
3643 def mktempfile(self, data=None, prefix='ipython_edit_'):
3679 def mktempfile(self, data=None, prefix='ipython_edit_'):
3644 """Make a new tempfile and return its filename.
3680 """Make a new tempfile and return its filename.
3645
3681
3646 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3682 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3647 but it registers the created filename internally so ipython cleans it up
3683 but it registers the created filename internally so ipython cleans it up
3648 at exit time.
3684 at exit time.
3649
3685
3650 Optional inputs:
3686 Optional inputs:
3651
3687
3652 - data(None): if data is given, it gets written out to the temp file
3688 - data(None): if data is given, it gets written out to the temp file
3653 immediately, and the file is closed again."""
3689 immediately, and the file is closed again."""
3654
3690
3655 dir_path = Path(tempfile.mkdtemp(prefix=prefix))
3691 dir_path = Path(tempfile.mkdtemp(prefix=prefix))
3656 self.tempdirs.append(dir_path)
3692 self.tempdirs.append(dir_path)
3657
3693
3658 handle, filename = tempfile.mkstemp(".py", prefix, dir=str(dir_path))
3694 handle, filename = tempfile.mkstemp(".py", prefix, dir=str(dir_path))
3659 os.close(handle) # On Windows, there can only be one open handle on a file
3695 os.close(handle) # On Windows, there can only be one open handle on a file
3660
3696
3661 file_path = Path(filename)
3697 file_path = Path(filename)
3662 self.tempfiles.append(file_path)
3698 self.tempfiles.append(file_path)
3663
3699
3664 if data:
3700 if data:
3665 file_path.write_text(data, encoding="utf-8")
3701 file_path.write_text(data, encoding="utf-8")
3666 return filename
3702 return filename
3667
3703
3668 def ask_yes_no(self, prompt, default=None, interrupt=None):
3704 def ask_yes_no(self, prompt, default=None, interrupt=None):
3669 if self.quiet:
3705 if self.quiet:
3670 return True
3706 return True
3671 return ask_yes_no(prompt,default,interrupt)
3707 return ask_yes_no(prompt,default,interrupt)
3672
3708
3673 def show_usage(self):
3709 def show_usage(self):
3674 """Show a usage message"""
3710 """Show a usage message"""
3675 page.page(IPython.core.usage.interactive_usage)
3711 page.page(IPython.core.usage.interactive_usage)
3676
3712
3677 def extract_input_lines(self, range_str, raw=False):
3713 def extract_input_lines(self, range_str, raw=False):
3678 """Return as a string a set of input history slices.
3714 """Return as a string a set of input history slices.
3679
3715
3680 Parameters
3716 Parameters
3681 ----------
3717 ----------
3682 range_str : str
3718 range_str : str
3683 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3719 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3684 since this function is for use by magic functions which get their
3720 since this function is for use by magic functions which get their
3685 arguments as strings. The number before the / is the session
3721 arguments as strings. The number before the / is the session
3686 number: ~n goes n back from the current session.
3722 number: ~n goes n back from the current session.
3687
3723
3688 If empty string is given, returns history of current session
3724 If empty string is given, returns history of current session
3689 without the last input.
3725 without the last input.
3690
3726
3691 raw : bool, optional
3727 raw : bool, optional
3692 By default, the processed input is used. If this is true, the raw
3728 By default, the processed input is used. If this is true, the raw
3693 input history is used instead.
3729 input history is used instead.
3694
3730
3695 Notes
3731 Notes
3696 -----
3732 -----
3697 Slices can be described with two notations:
3733 Slices can be described with two notations:
3698
3734
3699 * ``N:M`` -> standard python form, means including items N...(M-1).
3735 * ``N:M`` -> standard python form, means including items N...(M-1).
3700 * ``N-M`` -> include items N..M (closed endpoint).
3736 * ``N-M`` -> include items N..M (closed endpoint).
3701 """
3737 """
3702 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3738 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3703 text = "\n".join(x for _, _, x in lines)
3739 text = "\n".join(x for _, _, x in lines)
3704
3740
3705 # Skip the last line, as it's probably the magic that called this
3741 # Skip the last line, as it's probably the magic that called this
3706 if not range_str:
3742 if not range_str:
3707 if "\n" not in text:
3743 if "\n" not in text:
3708 text = ""
3744 text = ""
3709 else:
3745 else:
3710 text = text[: text.rfind("\n")]
3746 text = text[: text.rfind("\n")]
3711
3747
3712 return text
3748 return text
3713
3749
3714 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3750 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3715 """Get a code string from history, file, url, or a string or macro.
3751 """Get a code string from history, file, url, or a string or macro.
3716
3752
3717 This is mainly used by magic functions.
3753 This is mainly used by magic functions.
3718
3754
3719 Parameters
3755 Parameters
3720 ----------
3756 ----------
3721 target : str
3757 target : str
3722 A string specifying code to retrieve. This will be tried respectively
3758 A string specifying code to retrieve. This will be tried respectively
3723 as: ranges of input history (see %history for syntax), url,
3759 as: ranges of input history (see %history for syntax), url,
3724 corresponding .py file, filename, or an expression evaluating to a
3760 corresponding .py file, filename, or an expression evaluating to a
3725 string or Macro in the user namespace.
3761 string or Macro in the user namespace.
3726
3762
3727 If empty string is given, returns complete history of current
3763 If empty string is given, returns complete history of current
3728 session, without the last line.
3764 session, without the last line.
3729
3765
3730 raw : bool
3766 raw : bool
3731 If true (default), retrieve raw history. Has no effect on the other
3767 If true (default), retrieve raw history. Has no effect on the other
3732 retrieval mechanisms.
3768 retrieval mechanisms.
3733
3769
3734 py_only : bool (default False)
3770 py_only : bool (default False)
3735 Only try to fetch python code, do not try alternative methods to decode file
3771 Only try to fetch python code, do not try alternative methods to decode file
3736 if unicode fails.
3772 if unicode fails.
3737
3773
3738 Returns
3774 Returns
3739 -------
3775 -------
3740 A string of code.
3776 A string of code.
3741 ValueError is raised if nothing is found, and TypeError if it evaluates
3777 ValueError is raised if nothing is found, and TypeError if it evaluates
3742 to an object of another type. In each case, .args[0] is a printable
3778 to an object of another type. In each case, .args[0] is a printable
3743 message.
3779 message.
3744 """
3780 """
3745 code = self.extract_input_lines(target, raw=raw) # Grab history
3781 code = self.extract_input_lines(target, raw=raw) # Grab history
3746 if code:
3782 if code:
3747 return code
3783 return code
3748 try:
3784 try:
3749 if target.startswith(('http://', 'https://')):
3785 if target.startswith(('http://', 'https://')):
3750 return openpy.read_py_url(target, skip_encoding_cookie=skip_encoding_cookie)
3786 return openpy.read_py_url(target, skip_encoding_cookie=skip_encoding_cookie)
3751 except UnicodeDecodeError as e:
3787 except UnicodeDecodeError as e:
3752 if not py_only :
3788 if not py_only :
3753 # Deferred import
3789 # Deferred import
3754 from urllib.request import urlopen
3790 from urllib.request import urlopen
3755 response = urlopen(target)
3791 response = urlopen(target)
3756 return response.read().decode('latin1')
3792 return response.read().decode('latin1')
3757 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3793 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3758
3794
3759 potential_target = [target]
3795 potential_target = [target]
3760 try :
3796 try :
3761 potential_target.insert(0,get_py_filename(target))
3797 potential_target.insert(0,get_py_filename(target))
3762 except IOError:
3798 except IOError:
3763 pass
3799 pass
3764
3800
3765 for tgt in potential_target :
3801 for tgt in potential_target :
3766 if os.path.isfile(tgt): # Read file
3802 if os.path.isfile(tgt): # Read file
3767 try :
3803 try :
3768 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3804 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3769 except UnicodeDecodeError as e:
3805 except UnicodeDecodeError as e:
3770 if not py_only :
3806 if not py_only :
3771 with io_open(tgt,'r', encoding='latin1') as f :
3807 with io_open(tgt,'r', encoding='latin1') as f :
3772 return f.read()
3808 return f.read()
3773 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3809 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3774 elif os.path.isdir(os.path.expanduser(tgt)):
3810 elif os.path.isdir(os.path.expanduser(tgt)):
3775 raise ValueError("'%s' is a directory, not a regular file." % target)
3811 raise ValueError("'%s' is a directory, not a regular file." % target)
3776
3812
3777 if search_ns:
3813 if search_ns:
3778 # Inspect namespace to load object source
3814 # Inspect namespace to load object source
3779 object_info = self.object_inspect(target, detail_level=1)
3815 object_info = self.object_inspect(target, detail_level=1)
3780 if object_info['found'] and object_info['source']:
3816 if object_info['found'] and object_info['source']:
3781 return object_info['source']
3817 return object_info['source']
3782
3818
3783 try: # User namespace
3819 try: # User namespace
3784 codeobj = eval(target, self.user_ns)
3820 codeobj = eval(target, self.user_ns)
3785 except Exception as e:
3821 except Exception as e:
3786 raise ValueError(("'%s' was not found in history, as a file, url, "
3822 raise ValueError(("'%s' was not found in history, as a file, url, "
3787 "nor in the user namespace.") % target) from e
3823 "nor in the user namespace.") % target) from e
3788
3824
3789 if isinstance(codeobj, str):
3825 if isinstance(codeobj, str):
3790 return codeobj
3826 return codeobj
3791 elif isinstance(codeobj, Macro):
3827 elif isinstance(codeobj, Macro):
3792 return codeobj.value
3828 return codeobj.value
3793
3829
3794 raise TypeError("%s is neither a string nor a macro." % target,
3830 raise TypeError("%s is neither a string nor a macro." % target,
3795 codeobj)
3831 codeobj)
3796
3832
3797 def _atexit_once(self):
3833 def _atexit_once(self):
3798 """
3834 """
3799 At exist operation that need to be called at most once.
3835 At exist operation that need to be called at most once.
3800 Second call to this function per instance will do nothing.
3836 Second call to this function per instance will do nothing.
3801 """
3837 """
3802
3838
3803 if not getattr(self, "_atexit_once_called", False):
3839 if not getattr(self, "_atexit_once_called", False):
3804 self._atexit_once_called = True
3840 self._atexit_once_called = True
3805 # Clear all user namespaces to release all references cleanly.
3841 # Clear all user namespaces to release all references cleanly.
3806 self.reset(new_session=False)
3842 self.reset(new_session=False)
3807 # Close the history session (this stores the end time and line count)
3843 # Close the history session (this stores the end time and line count)
3808 # this must be *before* the tempfile cleanup, in case of temporary
3844 # this must be *before* the tempfile cleanup, in case of temporary
3809 # history db
3845 # history db
3810 self.history_manager.end_session()
3846 self.history_manager.end_session()
3811 self.history_manager = None
3847 self.history_manager = None
3812
3848
3813 #-------------------------------------------------------------------------
3849 #-------------------------------------------------------------------------
3814 # Things related to IPython exiting
3850 # Things related to IPython exiting
3815 #-------------------------------------------------------------------------
3851 #-------------------------------------------------------------------------
3816 def atexit_operations(self):
3852 def atexit_operations(self):
3817 """This will be executed at the time of exit.
3853 """This will be executed at the time of exit.
3818
3854
3819 Cleanup operations and saving of persistent data that is done
3855 Cleanup operations and saving of persistent data that is done
3820 unconditionally by IPython should be performed here.
3856 unconditionally by IPython should be performed here.
3821
3857
3822 For things that may depend on startup flags or platform specifics (such
3858 For things that may depend on startup flags or platform specifics (such
3823 as having readline or not), register a separate atexit function in the
3859 as having readline or not), register a separate atexit function in the
3824 code that has the appropriate information, rather than trying to
3860 code that has the appropriate information, rather than trying to
3825 clutter
3861 clutter
3826 """
3862 """
3827 self._atexit_once()
3863 self._atexit_once()
3828
3864
3829 # Cleanup all tempfiles and folders left around
3865 # Cleanup all tempfiles and folders left around
3830 for tfile in self.tempfiles:
3866 for tfile in self.tempfiles:
3831 try:
3867 try:
3832 tfile.unlink()
3868 tfile.unlink()
3833 self.tempfiles.remove(tfile)
3869 self.tempfiles.remove(tfile)
3834 except FileNotFoundError:
3870 except FileNotFoundError:
3835 pass
3871 pass
3836 del self.tempfiles
3872 del self.tempfiles
3837 for tdir in self.tempdirs:
3873 for tdir in self.tempdirs:
3838 try:
3874 try:
3839 tdir.rmdir()
3875 tdir.rmdir()
3840 self.tempdirs.remove(tdir)
3876 self.tempdirs.remove(tdir)
3841 except FileNotFoundError:
3877 except FileNotFoundError:
3842 pass
3878 pass
3843 del self.tempdirs
3879 del self.tempdirs
3844
3880
3845 # Restore user's cursor
3881 # Restore user's cursor
3846 if hasattr(self, "editing_mode") and self.editing_mode == "vi":
3882 if hasattr(self, "editing_mode") and self.editing_mode == "vi":
3847 sys.stdout.write("\x1b[0 q")
3883 sys.stdout.write("\x1b[0 q")
3848 sys.stdout.flush()
3884 sys.stdout.flush()
3849
3885
3850 def cleanup(self):
3886 def cleanup(self):
3851 self.restore_sys_module_state()
3887 self.restore_sys_module_state()
3852
3888
3853
3889
3854 # Overridden in terminal subclass to change prompts
3890 # Overridden in terminal subclass to change prompts
3855 def switch_doctest_mode(self, mode):
3891 def switch_doctest_mode(self, mode):
3856 pass
3892 pass
3857
3893
3858
3894
3859 class InteractiveShellABC(metaclass=abc.ABCMeta):
3895 class InteractiveShellABC(metaclass=abc.ABCMeta):
3860 """An abstract base class for InteractiveShell."""
3896 """An abstract base class for InteractiveShell."""
3861
3897
3862 InteractiveShellABC.register(InteractiveShell)
3898 InteractiveShellABC.register(InteractiveShell)
@@ -1,1516 +1,1522 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Implementation of execution-related magic functions."""
2 """Implementation of execution-related magic functions."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 import ast
8 import ast
9 import bdb
9 import bdb
10 import builtins as builtin_mod
10 import builtins as builtin_mod
11 import cProfile as profile
11 import cProfile as profile
12 import gc
12 import gc
13 import itertools
13 import itertools
14 import math
14 import math
15 import os
15 import os
16 import pstats
16 import pstats
17 import re
17 import re
18 import shlex
18 import shlex
19 import sys
19 import sys
20 import time
20 import time
21 import timeit
21 import timeit
22 from ast import Module
22 from ast import Module
23 from io import StringIO
23 from io import StringIO
24 from logging import error
24 from logging import error
25 from pathlib import Path
25 from pathlib import Path
26 from pdb import Restart
26 from pdb import Restart
27 from warnings import warn
27 from warnings import warn
28
28
29 from IPython.core import magic_arguments, oinspect, page
29 from IPython.core import magic_arguments, oinspect, page
30 from IPython.core.error import UsageError
30 from IPython.core.error import UsageError
31 from IPython.core.macro import Macro
31 from IPython.core.macro import Macro
32 from IPython.core.magic import (
32 from IPython.core.magic import (
33 Magics,
33 Magics,
34 cell_magic,
34 cell_magic,
35 line_cell_magic,
35 line_cell_magic,
36 line_magic,
36 line_magic,
37 magics_class,
37 magics_class,
38 needs_local_scope,
38 needs_local_scope,
39 no_var_expand,
39 no_var_expand,
40 output_can_be_silenced,
40 output_can_be_silenced,
41 on_off,
41 on_off,
42 )
42 )
43 from IPython.testing.skipdoctest import skip_doctest
43 from IPython.testing.skipdoctest import skip_doctest
44 from IPython.utils.capture import capture_output
44 from IPython.utils.capture import capture_output
45 from IPython.utils.contexts import preserve_keys
45 from IPython.utils.contexts import preserve_keys
46 from IPython.utils.ipstruct import Struct
46 from IPython.utils.ipstruct import Struct
47 from IPython.utils.module_paths import find_mod
47 from IPython.utils.module_paths import find_mod
48 from IPython.utils.path import get_py_filename, shellglob
48 from IPython.utils.path import get_py_filename, shellglob
49 from IPython.utils.timing import clock, clock2
49 from IPython.utils.timing import clock, clock2
50 from IPython.core.displayhook import DisplayHook
50 from IPython.core.displayhook import DisplayHook
51
51
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53 # Magic implementation classes
53 # Magic implementation classes
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55
55
56
56
57 class TimeitResult(object):
57 class TimeitResult(object):
58 """
58 """
59 Object returned by the timeit magic with info about the run.
59 Object returned by the timeit magic with info about the run.
60
60
61 Contains the following attributes :
61 Contains the following attributes :
62
62
63 loops: (int) number of loops done per measurement
63 loops: (int) number of loops done per measurement
64 repeat: (int) number of times the measurement has been repeated
64 repeat: (int) number of times the measurement has been repeated
65 best: (float) best execution time / number
65 best: (float) best execution time / number
66 all_runs: (list of float) execution time of each run (in s)
66 all_runs: (list of float) execution time of each run (in s)
67 compile_time: (float) time of statement compilation (s)
67 compile_time: (float) time of statement compilation (s)
68
68
69 """
69 """
70 def __init__(self, loops, repeat, best, worst, all_runs, compile_time, precision):
70 def __init__(self, loops, repeat, best, worst, all_runs, compile_time, precision):
71 self.loops = loops
71 self.loops = loops
72 self.repeat = repeat
72 self.repeat = repeat
73 self.best = best
73 self.best = best
74 self.worst = worst
74 self.worst = worst
75 self.all_runs = all_runs
75 self.all_runs = all_runs
76 self.compile_time = compile_time
76 self.compile_time = compile_time
77 self._precision = precision
77 self._precision = precision
78 self.timings = [ dt / self.loops for dt in all_runs]
78 self.timings = [ dt / self.loops for dt in all_runs]
79
79
80 @property
80 @property
81 def average(self):
81 def average(self):
82 return math.fsum(self.timings) / len(self.timings)
82 return math.fsum(self.timings) / len(self.timings)
83
83
84 @property
84 @property
85 def stdev(self):
85 def stdev(self):
86 mean = self.average
86 mean = self.average
87 return (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5
87 return (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5
88
88
89 def __str__(self):
89 def __str__(self):
90 pm = '+-'
90 pm = '+-'
91 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
91 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
92 try:
92 try:
93 u'\xb1'.encode(sys.stdout.encoding)
93 u'\xb1'.encode(sys.stdout.encoding)
94 pm = u'\xb1'
94 pm = u'\xb1'
95 except:
95 except:
96 pass
96 pass
97 return "{mean} {pm} {std} per loop (mean {pm} std. dev. of {runs} run{run_plural}, {loops:,} loop{loop_plural} each)".format(
97 return "{mean} {pm} {std} per loop (mean {pm} std. dev. of {runs} run{run_plural}, {loops:,} loop{loop_plural} each)".format(
98 pm=pm,
98 pm=pm,
99 runs=self.repeat,
99 runs=self.repeat,
100 loops=self.loops,
100 loops=self.loops,
101 loop_plural="" if self.loops == 1 else "s",
101 loop_plural="" if self.loops == 1 else "s",
102 run_plural="" if self.repeat == 1 else "s",
102 run_plural="" if self.repeat == 1 else "s",
103 mean=_format_time(self.average, self._precision),
103 mean=_format_time(self.average, self._precision),
104 std=_format_time(self.stdev, self._precision),
104 std=_format_time(self.stdev, self._precision),
105 )
105 )
106
106
107 def _repr_pretty_(self, p , cycle):
107 def _repr_pretty_(self, p , cycle):
108 unic = self.__str__()
108 unic = self.__str__()
109 p.text(u'<TimeitResult : '+unic+u'>')
109 p.text(u'<TimeitResult : '+unic+u'>')
110
110
111
111
112 class TimeitTemplateFiller(ast.NodeTransformer):
112 class TimeitTemplateFiller(ast.NodeTransformer):
113 """Fill in the AST template for timing execution.
113 """Fill in the AST template for timing execution.
114
114
115 This is quite closely tied to the template definition, which is in
115 This is quite closely tied to the template definition, which is in
116 :meth:`ExecutionMagics.timeit`.
116 :meth:`ExecutionMagics.timeit`.
117 """
117 """
118 def __init__(self, ast_setup, ast_stmt):
118 def __init__(self, ast_setup, ast_stmt):
119 self.ast_setup = ast_setup
119 self.ast_setup = ast_setup
120 self.ast_stmt = ast_stmt
120 self.ast_stmt = ast_stmt
121
121
122 def visit_FunctionDef(self, node):
122 def visit_FunctionDef(self, node):
123 "Fill in the setup statement"
123 "Fill in the setup statement"
124 self.generic_visit(node)
124 self.generic_visit(node)
125 if node.name == "inner":
125 if node.name == "inner":
126 node.body[:1] = self.ast_setup.body
126 node.body[:1] = self.ast_setup.body
127
127
128 return node
128 return node
129
129
130 def visit_For(self, node):
130 def visit_For(self, node):
131 "Fill in the statement to be timed"
131 "Fill in the statement to be timed"
132 if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
132 if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
133 node.body = self.ast_stmt.body
133 node.body = self.ast_stmt.body
134 return node
134 return node
135
135
136
136
137 class Timer(timeit.Timer):
137 class Timer(timeit.Timer):
138 """Timer class that explicitly uses self.inner
138 """Timer class that explicitly uses self.inner
139
139
140 which is an undocumented implementation detail of CPython,
140 which is an undocumented implementation detail of CPython,
141 not shared by PyPy.
141 not shared by PyPy.
142 """
142 """
143 # Timer.timeit copied from CPython 3.4.2
143 # Timer.timeit copied from CPython 3.4.2
144 def timeit(self, number=timeit.default_number):
144 def timeit(self, number=timeit.default_number):
145 """Time 'number' executions of the main statement.
145 """Time 'number' executions of the main statement.
146
146
147 To be precise, this executes the setup statement once, and
147 To be precise, this executes the setup statement once, and
148 then returns the time it takes to execute the main statement
148 then returns the time it takes to execute the main statement
149 a number of times, as a float measured in seconds. The
149 a number of times, as a float measured in seconds. The
150 argument is the number of times through the loop, defaulting
150 argument is the number of times through the loop, defaulting
151 to one million. The main statement, the setup statement and
151 to one million. The main statement, the setup statement and
152 the timer function to be used are passed to the constructor.
152 the timer function to be used are passed to the constructor.
153 """
153 """
154 it = itertools.repeat(None, number)
154 it = itertools.repeat(None, number)
155 gcold = gc.isenabled()
155 gcold = gc.isenabled()
156 gc.disable()
156 gc.disable()
157 try:
157 try:
158 timing = self.inner(it, self.timer)
158 timing = self.inner(it, self.timer)
159 finally:
159 finally:
160 if gcold:
160 if gcold:
161 gc.enable()
161 gc.enable()
162 return timing
162 return timing
163
163
164
164
165 @magics_class
165 @magics_class
166 class ExecutionMagics(Magics):
166 class ExecutionMagics(Magics):
167 """Magics related to code execution, debugging, profiling, etc.
167 """Magics related to code execution, debugging, profiling, etc.
168
168
169 """
169 """
170
170
171 def __init__(self, shell):
171 def __init__(self, shell):
172 super(ExecutionMagics, self).__init__(shell)
172 super(ExecutionMagics, self).__init__(shell)
173 # Default execution function used to actually run user code.
173 # Default execution function used to actually run user code.
174 self.default_runner = None
174 self.default_runner = None
175
175
176 @skip_doctest
176 @skip_doctest
177 @no_var_expand
177 @no_var_expand
178 @line_cell_magic
178 @line_cell_magic
179 def prun(self, parameter_s='', cell=None):
179 def prun(self, parameter_s='', cell=None):
180
180
181 """Run a statement through the python code profiler.
181 """Run a statement through the python code profiler.
182
182
183 Usage, in line mode:
183 Usage, in line mode:
184 %prun [options] statement
184 %prun [options] statement
185
185
186 Usage, in cell mode:
186 Usage, in cell mode:
187 %%prun [options] [statement]
187 %%prun [options] [statement]
188 code...
188 code...
189 code...
189 code...
190
190
191 In cell mode, the additional code lines are appended to the (possibly
191 In cell mode, the additional code lines are appended to the (possibly
192 empty) statement in the first line. Cell mode allows you to easily
192 empty) statement in the first line. Cell mode allows you to easily
193 profile multiline blocks without having to put them in a separate
193 profile multiline blocks without having to put them in a separate
194 function.
194 function.
195
195
196 The given statement (which doesn't require quote marks) is run via the
196 The given statement (which doesn't require quote marks) is run via the
197 python profiler in a manner similar to the profile.run() function.
197 python profiler in a manner similar to the profile.run() function.
198 Namespaces are internally managed to work correctly; profile.run
198 Namespaces are internally managed to work correctly; profile.run
199 cannot be used in IPython because it makes certain assumptions about
199 cannot be used in IPython because it makes certain assumptions about
200 namespaces which do not hold under IPython.
200 namespaces which do not hold under IPython.
201
201
202 Options:
202 Options:
203
203
204 -l <limit>
204 -l <limit>
205 you can place restrictions on what or how much of the
205 you can place restrictions on what or how much of the
206 profile gets printed. The limit value can be:
206 profile gets printed. The limit value can be:
207
207
208 * A string: only information for function names containing this string
208 * A string: only information for function names containing this string
209 is printed.
209 is printed.
210
210
211 * An integer: only these many lines are printed.
211 * An integer: only these many lines are printed.
212
212
213 * A float (between 0 and 1): this fraction of the report is printed
213 * A float (between 0 and 1): this fraction of the report is printed
214 (for example, use a limit of 0.4 to see the topmost 40% only).
214 (for example, use a limit of 0.4 to see the topmost 40% only).
215
215
216 You can combine several limits with repeated use of the option. For
216 You can combine several limits with repeated use of the option. For
217 example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
217 example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
218 information about class constructors.
218 information about class constructors.
219
219
220 -r
220 -r
221 return the pstats.Stats object generated by the profiling. This
221 return the pstats.Stats object generated by the profiling. This
222 object has all the information about the profile in it, and you can
222 object has all the information about the profile in it, and you can
223 later use it for further analysis or in other functions.
223 later use it for further analysis or in other functions.
224
224
225 -s <key>
225 -s <key>
226 sort profile by given key. You can provide more than one key
226 sort profile by given key. You can provide more than one key
227 by using the option several times: '-s key1 -s key2 -s key3...'. The
227 by using the option several times: '-s key1 -s key2 -s key3...'. The
228 default sorting key is 'time'.
228 default sorting key is 'time'.
229
229
230 The following is copied verbatim from the profile documentation
230 The following is copied verbatim from the profile documentation
231 referenced below:
231 referenced below:
232
232
233 When more than one key is provided, additional keys are used as
233 When more than one key is provided, additional keys are used as
234 secondary criteria when the there is equality in all keys selected
234 secondary criteria when the there is equality in all keys selected
235 before them.
235 before them.
236
236
237 Abbreviations can be used for any key names, as long as the
237 Abbreviations can be used for any key names, as long as the
238 abbreviation is unambiguous. The following are the keys currently
238 abbreviation is unambiguous. The following are the keys currently
239 defined:
239 defined:
240
240
241 ============ =====================
241 ============ =====================
242 Valid Arg Meaning
242 Valid Arg Meaning
243 ============ =====================
243 ============ =====================
244 "calls" call count
244 "calls" call count
245 "cumulative" cumulative time
245 "cumulative" cumulative time
246 "file" file name
246 "file" file name
247 "module" file name
247 "module" file name
248 "pcalls" primitive call count
248 "pcalls" primitive call count
249 "line" line number
249 "line" line number
250 "name" function name
250 "name" function name
251 "nfl" name/file/line
251 "nfl" name/file/line
252 "stdname" standard name
252 "stdname" standard name
253 "time" internal time
253 "time" internal time
254 ============ =====================
254 ============ =====================
255
255
256 Note that all sorts on statistics are in descending order (placing
256 Note that all sorts on statistics are in descending order (placing
257 most time consuming items first), where as name, file, and line number
257 most time consuming items first), where as name, file, and line number
258 searches are in ascending order (i.e., alphabetical). The subtle
258 searches are in ascending order (i.e., alphabetical). The subtle
259 distinction between "nfl" and "stdname" is that the standard name is a
259 distinction between "nfl" and "stdname" is that the standard name is a
260 sort of the name as printed, which means that the embedded line
260 sort of the name as printed, which means that the embedded line
261 numbers get compared in an odd way. For example, lines 3, 20, and 40
261 numbers get compared in an odd way. For example, lines 3, 20, and 40
262 would (if the file names were the same) appear in the string order
262 would (if the file names were the same) appear in the string order
263 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
263 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
264 line numbers. In fact, sort_stats("nfl") is the same as
264 line numbers. In fact, sort_stats("nfl") is the same as
265 sort_stats("name", "file", "line").
265 sort_stats("name", "file", "line").
266
266
267 -T <filename>
267 -T <filename>
268 save profile results as shown on screen to a text
268 save profile results as shown on screen to a text
269 file. The profile is still shown on screen.
269 file. The profile is still shown on screen.
270
270
271 -D <filename>
271 -D <filename>
272 save (via dump_stats) profile statistics to given
272 save (via dump_stats) profile statistics to given
273 filename. This data is in a format understood by the pstats module, and
273 filename. This data is in a format understood by the pstats module, and
274 is generated by a call to the dump_stats() method of profile
274 is generated by a call to the dump_stats() method of profile
275 objects. The profile is still shown on screen.
275 objects. The profile is still shown on screen.
276
276
277 -q
277 -q
278 suppress output to the pager. Best used with -T and/or -D above.
278 suppress output to the pager. Best used with -T and/or -D above.
279
279
280 If you want to run complete programs under the profiler's control, use
280 If you want to run complete programs under the profiler's control, use
281 ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
281 ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
282 contains profiler specific options as described here.
282 contains profiler specific options as described here.
283
283
284 You can read the complete documentation for the profile module with::
284 You can read the complete documentation for the profile module with::
285
285
286 In [1]: import profile; profile.help()
286 In [1]: import profile; profile.help()
287
287
288 .. versionchanged:: 7.3
288 .. versionchanged:: 7.3
289 User variables are no longer expanded,
289 User variables are no longer expanded,
290 the magic line is always left unmodified.
290 the magic line is always left unmodified.
291
291
292 """
292 """
293 opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
293 opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
294 list_all=True, posix=False)
294 list_all=True, posix=False)
295 if cell is not None:
295 if cell is not None:
296 arg_str += '\n' + cell
296 arg_str += '\n' + cell
297 arg_str = self.shell.transform_cell(arg_str)
297 arg_str = self.shell.transform_cell(arg_str)
298 return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
298 return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
299
299
300 def _run_with_profiler(self, code, opts, namespace):
300 def _run_with_profiler(self, code, opts, namespace):
301 """
301 """
302 Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
302 Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
303
303
304 Parameters
304 Parameters
305 ----------
305 ----------
306 code : str
306 code : str
307 Code to be executed.
307 Code to be executed.
308 opts : Struct
308 opts : Struct
309 Options parsed by `self.parse_options`.
309 Options parsed by `self.parse_options`.
310 namespace : dict
310 namespace : dict
311 A dictionary for Python namespace (e.g., `self.shell.user_ns`).
311 A dictionary for Python namespace (e.g., `self.shell.user_ns`).
312
312
313 """
313 """
314
314
315 # Fill default values for unspecified options:
315 # Fill default values for unspecified options:
316 opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
316 opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
317
317
318 prof = profile.Profile()
318 prof = profile.Profile()
319 try:
319 try:
320 prof = prof.runctx(code, namespace, namespace)
320 prof = prof.runctx(code, namespace, namespace)
321 sys_exit = ''
321 sys_exit = ''
322 except SystemExit:
322 except SystemExit:
323 sys_exit = """*** SystemExit exception caught in code being profiled."""
323 sys_exit = """*** SystemExit exception caught in code being profiled."""
324
324
325 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
325 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
326
326
327 lims = opts.l
327 lims = opts.l
328 if lims:
328 if lims:
329 lims = [] # rebuild lims with ints/floats/strings
329 lims = [] # rebuild lims with ints/floats/strings
330 for lim in opts.l:
330 for lim in opts.l:
331 try:
331 try:
332 lims.append(int(lim))
332 lims.append(int(lim))
333 except ValueError:
333 except ValueError:
334 try:
334 try:
335 lims.append(float(lim))
335 lims.append(float(lim))
336 except ValueError:
336 except ValueError:
337 lims.append(lim)
337 lims.append(lim)
338
338
339 # Trap output.
339 # Trap output.
340 stdout_trap = StringIO()
340 stdout_trap = StringIO()
341 stats_stream = stats.stream
341 stats_stream = stats.stream
342 try:
342 try:
343 stats.stream = stdout_trap
343 stats.stream = stdout_trap
344 stats.print_stats(*lims)
344 stats.print_stats(*lims)
345 finally:
345 finally:
346 stats.stream = stats_stream
346 stats.stream = stats_stream
347
347
348 output = stdout_trap.getvalue()
348 output = stdout_trap.getvalue()
349 output = output.rstrip()
349 output = output.rstrip()
350
350
351 if 'q' not in opts:
351 if 'q' not in opts:
352 page.page(output)
352 page.page(output)
353 print(sys_exit, end=' ')
353 print(sys_exit, end=' ')
354
354
355 dump_file = opts.D[0]
355 dump_file = opts.D[0]
356 text_file = opts.T[0]
356 text_file = opts.T[0]
357 if dump_file:
357 if dump_file:
358 prof.dump_stats(dump_file)
358 prof.dump_stats(dump_file)
359 print(
359 print(
360 f"\n*** Profile stats marshalled to file {repr(dump_file)}.{sys_exit}"
360 f"\n*** Profile stats marshalled to file {repr(dump_file)}.{sys_exit}"
361 )
361 )
362 if text_file:
362 if text_file:
363 pfile = Path(text_file)
363 pfile = Path(text_file)
364 pfile.touch(exist_ok=True)
364 pfile.touch(exist_ok=True)
365 pfile.write_text(output, encoding="utf-8")
365 pfile.write_text(output, encoding="utf-8")
366
366
367 print(
367 print(
368 f"\n*** Profile printout saved to text file {repr(text_file)}.{sys_exit}"
368 f"\n*** Profile printout saved to text file {repr(text_file)}.{sys_exit}"
369 )
369 )
370
370
371 if 'r' in opts:
371 if 'r' in opts:
372 return stats
372 return stats
373
373
374 return None
374 return None
375
375
376 @line_magic
376 @line_magic
377 def pdb(self, parameter_s=''):
377 def pdb(self, parameter_s=''):
378 """Control the automatic calling of the pdb interactive debugger.
378 """Control the automatic calling of the pdb interactive debugger.
379
379
380 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
380 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
381 argument it works as a toggle.
381 argument it works as a toggle.
382
382
383 When an exception is triggered, IPython can optionally call the
383 When an exception is triggered, IPython can optionally call the
384 interactive pdb debugger after the traceback printout. %pdb toggles
384 interactive pdb debugger after the traceback printout. %pdb toggles
385 this feature on and off.
385 this feature on and off.
386
386
387 The initial state of this feature is set in your configuration
387 The initial state of this feature is set in your configuration
388 file (the option is ``InteractiveShell.pdb``).
388 file (the option is ``InteractiveShell.pdb``).
389
389
390 If you want to just activate the debugger AFTER an exception has fired,
390 If you want to just activate the debugger AFTER an exception has fired,
391 without having to type '%pdb on' and rerunning your code, you can use
391 without having to type '%pdb on' and rerunning your code, you can use
392 the %debug magic."""
392 the %debug magic."""
393
393
394 par = parameter_s.strip().lower()
394 par = parameter_s.strip().lower()
395
395
396 if par:
396 if par:
397 try:
397 try:
398 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
398 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
399 except KeyError:
399 except KeyError:
400 print ('Incorrect argument. Use on/1, off/0, '
400 print ('Incorrect argument. Use on/1, off/0, '
401 'or nothing for a toggle.')
401 'or nothing for a toggle.')
402 return
402 return
403 else:
403 else:
404 # toggle
404 # toggle
405 new_pdb = not self.shell.call_pdb
405 new_pdb = not self.shell.call_pdb
406
406
407 # set on the shell
407 # set on the shell
408 self.shell.call_pdb = new_pdb
408 self.shell.call_pdb = new_pdb
409 print('Automatic pdb calling has been turned',on_off(new_pdb))
409 print('Automatic pdb calling has been turned',on_off(new_pdb))
410
410
411 @magic_arguments.magic_arguments()
411 @magic_arguments.magic_arguments()
412 @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
412 @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
413 help="""
413 help="""
414 Set break point at LINE in FILE.
414 Set break point at LINE in FILE.
415 """
415 """
416 )
416 )
417 @magic_arguments.argument('statement', nargs='*',
417 @magic_arguments.argument('statement', nargs='*',
418 help="""
418 help="""
419 Code to run in debugger.
419 Code to run in debugger.
420 You can omit this in cell magic mode.
420 You can omit this in cell magic mode.
421 """
421 """
422 )
422 )
423 @no_var_expand
423 @no_var_expand
424 @line_cell_magic
424 @line_cell_magic
425 def debug(self, line='', cell=None):
425 @needs_local_scope
426 def debug(self, line="", cell=None, local_ns=None):
426 """Activate the interactive debugger.
427 """Activate the interactive debugger.
427
428
428 This magic command support two ways of activating debugger.
429 This magic command support two ways of activating debugger.
429 One is to activate debugger before executing code. This way, you
430 One is to activate debugger before executing code. This way, you
430 can set a break point, to step through the code from the point.
431 can set a break point, to step through the code from the point.
431 You can use this mode by giving statements to execute and optionally
432 You can use this mode by giving statements to execute and optionally
432 a breakpoint.
433 a breakpoint.
433
434
434 The other one is to activate debugger in post-mortem mode. You can
435 The other one is to activate debugger in post-mortem mode. You can
435 activate this mode simply running %debug without any argument.
436 activate this mode simply running %debug without any argument.
436 If an exception has just occurred, this lets you inspect its stack
437 If an exception has just occurred, this lets you inspect its stack
437 frames interactively. Note that this will always work only on the last
438 frames interactively. Note that this will always work only on the last
438 traceback that occurred, so you must call this quickly after an
439 traceback that occurred, so you must call this quickly after an
439 exception that you wish to inspect has fired, because if another one
440 exception that you wish to inspect has fired, because if another one
440 occurs, it clobbers the previous one.
441 occurs, it clobbers the previous one.
441
442
442 If you want IPython to automatically do this on every exception, see
443 If you want IPython to automatically do this on every exception, see
443 the %pdb magic for more details.
444 the %pdb magic for more details.
444
445
445 .. versionchanged:: 7.3
446 .. versionchanged:: 7.3
446 When running code, user variables are no longer expanded,
447 When running code, user variables are no longer expanded,
447 the magic line is always left unmodified.
448 the magic line is always left unmodified.
448
449
449 """
450 """
450 args = magic_arguments.parse_argstring(self.debug, line)
451 args = magic_arguments.parse_argstring(self.debug, line)
451
452
452 if not (args.breakpoint or args.statement or cell):
453 if not (args.breakpoint or args.statement or cell):
453 self._debug_post_mortem()
454 self._debug_post_mortem()
454 elif not (args.breakpoint or cell):
455 elif not (args.breakpoint or cell):
455 # If there is no breakpoints, the line is just code to execute
456 # If there is no breakpoints, the line is just code to execute
456 self._debug_exec(line, None)
457 self._debug_exec(line, None, local_ns)
457 else:
458 else:
458 # Here we try to reconstruct the code from the output of
459 # Here we try to reconstruct the code from the output of
459 # parse_argstring. This might not work if the code has spaces
460 # parse_argstring. This might not work if the code has spaces
460 # For example this fails for `print("a b")`
461 # For example this fails for `print("a b")`
461 code = "\n".join(args.statement)
462 code = "\n".join(args.statement)
462 if cell:
463 if cell:
463 code += "\n" + cell
464 code += "\n" + cell
464 self._debug_exec(code, args.breakpoint)
465 self._debug_exec(code, args.breakpoint, local_ns)
465
466
466 def _debug_post_mortem(self):
467 def _debug_post_mortem(self):
467 self.shell.debugger(force=True)
468 self.shell.debugger(force=True)
468
469
469 def _debug_exec(self, code, breakpoint):
470 def _debug_exec(self, code, breakpoint, local_ns=None):
470 if breakpoint:
471 if breakpoint:
471 (filename, bp_line) = breakpoint.rsplit(':', 1)
472 (filename, bp_line) = breakpoint.rsplit(':', 1)
472 bp_line = int(bp_line)
473 bp_line = int(bp_line)
473 else:
474 else:
474 (filename, bp_line) = (None, None)
475 (filename, bp_line) = (None, None)
475 self._run_with_debugger(code, self.shell.user_ns, filename, bp_line)
476 self._run_with_debugger(
477 code, self.shell.user_ns, filename, bp_line, local_ns=local_ns
478 )
476
479
477 @line_magic
480 @line_magic
478 def tb(self, s):
481 def tb(self, s):
479 """Print the last traceback.
482 """Print the last traceback.
480
483
481 Optionally, specify an exception reporting mode, tuning the
484 Optionally, specify an exception reporting mode, tuning the
482 verbosity of the traceback. By default the currently-active exception
485 verbosity of the traceback. By default the currently-active exception
483 mode is used. See %xmode for changing exception reporting modes.
486 mode is used. See %xmode for changing exception reporting modes.
484
487
485 Valid modes: Plain, Context, Verbose, and Minimal.
488 Valid modes: Plain, Context, Verbose, and Minimal.
486 """
489 """
487 interactive_tb = self.shell.InteractiveTB
490 interactive_tb = self.shell.InteractiveTB
488 if s:
491 if s:
489 # Switch exception reporting mode for this one call.
492 # Switch exception reporting mode for this one call.
490 # Ensure it is switched back.
493 # Ensure it is switched back.
491 def xmode_switch_err(name):
494 def xmode_switch_err(name):
492 warn('Error changing %s exception modes.\n%s' %
495 warn('Error changing %s exception modes.\n%s' %
493 (name,sys.exc_info()[1]))
496 (name,sys.exc_info()[1]))
494
497
495 new_mode = s.strip().capitalize()
498 new_mode = s.strip().capitalize()
496 original_mode = interactive_tb.mode
499 original_mode = interactive_tb.mode
497 try:
500 try:
498 try:
501 try:
499 interactive_tb.set_mode(mode=new_mode)
502 interactive_tb.set_mode(mode=new_mode)
500 except Exception:
503 except Exception:
501 xmode_switch_err('user')
504 xmode_switch_err('user')
502 else:
505 else:
503 self.shell.showtraceback()
506 self.shell.showtraceback()
504 finally:
507 finally:
505 interactive_tb.set_mode(mode=original_mode)
508 interactive_tb.set_mode(mode=original_mode)
506 else:
509 else:
507 self.shell.showtraceback()
510 self.shell.showtraceback()
508
511
509 @skip_doctest
512 @skip_doctest
510 @line_magic
513 @line_magic
511 def run(self, parameter_s='', runner=None,
514 def run(self, parameter_s='', runner=None,
512 file_finder=get_py_filename):
515 file_finder=get_py_filename):
513 """Run the named file inside IPython as a program.
516 """Run the named file inside IPython as a program.
514
517
515 Usage::
518 Usage::
516
519
517 %run [-n -i -e -G]
520 %run [-n -i -e -G]
518 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
521 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
519 ( -m mod | filename ) [args]
522 ( -m mod | filename ) [args]
520
523
521 The filename argument should be either a pure Python script (with
524 The filename argument should be either a pure Python script (with
522 extension ``.py``), or a file with custom IPython syntax (such as
525 extension ``.py``), or a file with custom IPython syntax (such as
523 magics). If the latter, the file can be either a script with ``.ipy``
526 magics). If the latter, the file can be either a script with ``.ipy``
524 extension, or a Jupyter notebook with ``.ipynb`` extension. When running
527 extension, or a Jupyter notebook with ``.ipynb`` extension. When running
525 a Jupyter notebook, the output from print statements and other
528 a Jupyter notebook, the output from print statements and other
526 displayed objects will appear in the terminal (even matplotlib figures
529 displayed objects will appear in the terminal (even matplotlib figures
527 will open, if a terminal-compliant backend is being used). Note that,
530 will open, if a terminal-compliant backend is being used). Note that,
528 at the system command line, the ``jupyter run`` command offers similar
531 at the system command line, the ``jupyter run`` command offers similar
529 functionality for executing notebooks (albeit currently with some
532 functionality for executing notebooks (albeit currently with some
530 differences in supported options).
533 differences in supported options).
531
534
532 Parameters after the filename are passed as command-line arguments to
535 Parameters after the filename are passed as command-line arguments to
533 the program (put in sys.argv). Then, control returns to IPython's
536 the program (put in sys.argv). Then, control returns to IPython's
534 prompt.
537 prompt.
535
538
536 This is similar to running at a system prompt ``python file args``,
539 This is similar to running at a system prompt ``python file args``,
537 but with the advantage of giving you IPython's tracebacks, and of
540 but with the advantage of giving you IPython's tracebacks, and of
538 loading all variables into your interactive namespace for further use
541 loading all variables into your interactive namespace for further use
539 (unless -p is used, see below).
542 (unless -p is used, see below).
540
543
541 The file is executed in a namespace initially consisting only of
544 The file is executed in a namespace initially consisting only of
542 ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
545 ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
543 sees its environment as if it were being run as a stand-alone program
546 sees its environment as if it were being run as a stand-alone program
544 (except for sharing global objects such as previously imported
547 (except for sharing global objects such as previously imported
545 modules). But after execution, the IPython interactive namespace gets
548 modules). But after execution, the IPython interactive namespace gets
546 updated with all variables defined in the program (except for __name__
549 updated with all variables defined in the program (except for __name__
547 and sys.argv). This allows for very convenient loading of code for
550 and sys.argv). This allows for very convenient loading of code for
548 interactive work, while giving each program a 'clean sheet' to run in.
551 interactive work, while giving each program a 'clean sheet' to run in.
549
552
550 Arguments are expanded using shell-like glob match. Patterns
553 Arguments are expanded using shell-like glob match. Patterns
551 '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
554 '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
552 tilde '~' will be expanded into user's home directory. Unlike
555 tilde '~' will be expanded into user's home directory. Unlike
553 real shells, quotation does not suppress expansions. Use
556 real shells, quotation does not suppress expansions. Use
554 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
557 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
555 To completely disable these expansions, you can use -G flag.
558 To completely disable these expansions, you can use -G flag.
556
559
557 On Windows systems, the use of single quotes `'` when specifying
560 On Windows systems, the use of single quotes `'` when specifying
558 a file is not supported. Use double quotes `"`.
561 a file is not supported. Use double quotes `"`.
559
562
560 Options:
563 Options:
561
564
562 -n
565 -n
563 __name__ is NOT set to '__main__', but to the running file's name
566 __name__ is NOT set to '__main__', but to the running file's name
564 without extension (as python does under import). This allows running
567 without extension (as python does under import). This allows running
565 scripts and reloading the definitions in them without calling code
568 scripts and reloading the definitions in them without calling code
566 protected by an ``if __name__ == "__main__"`` clause.
569 protected by an ``if __name__ == "__main__"`` clause.
567
570
568 -i
571 -i
569 run the file in IPython's namespace instead of an empty one. This
572 run the file in IPython's namespace instead of an empty one. This
570 is useful if you are experimenting with code written in a text editor
573 is useful if you are experimenting with code written in a text editor
571 which depends on variables defined interactively.
574 which depends on variables defined interactively.
572
575
573 -e
576 -e
574 ignore sys.exit() calls or SystemExit exceptions in the script
577 ignore sys.exit() calls or SystemExit exceptions in the script
575 being run. This is particularly useful if IPython is being used to
578 being run. This is particularly useful if IPython is being used to
576 run unittests, which always exit with a sys.exit() call. In such
579 run unittests, which always exit with a sys.exit() call. In such
577 cases you are interested in the output of the test results, not in
580 cases you are interested in the output of the test results, not in
578 seeing a traceback of the unittest module.
581 seeing a traceback of the unittest module.
579
582
580 -t
583 -t
581 print timing information at the end of the run. IPython will give
584 print timing information at the end of the run. IPython will give
582 you an estimated CPU time consumption for your script, which under
585 you an estimated CPU time consumption for your script, which under
583 Unix uses the resource module to avoid the wraparound problems of
586 Unix uses the resource module to avoid the wraparound problems of
584 time.clock(). Under Unix, an estimate of time spent on system tasks
587 time.clock(). Under Unix, an estimate of time spent on system tasks
585 is also given (for Windows platforms this is reported as 0.0).
588 is also given (for Windows platforms this is reported as 0.0).
586
589
587 If -t is given, an additional ``-N<N>`` option can be given, where <N>
590 If -t is given, an additional ``-N<N>`` option can be given, where <N>
588 must be an integer indicating how many times you want the script to
591 must be an integer indicating how many times you want the script to
589 run. The final timing report will include total and per run results.
592 run. The final timing report will include total and per run results.
590
593
591 For example (testing the script uniq_stable.py)::
594 For example (testing the script uniq_stable.py)::
592
595
593 In [1]: run -t uniq_stable
596 In [1]: run -t uniq_stable
594
597
595 IPython CPU timings (estimated):
598 IPython CPU timings (estimated):
596 User : 0.19597 s.
599 User : 0.19597 s.
597 System: 0.0 s.
600 System: 0.0 s.
598
601
599 In [2]: run -t -N5 uniq_stable
602 In [2]: run -t -N5 uniq_stable
600
603
601 IPython CPU timings (estimated):
604 IPython CPU timings (estimated):
602 Total runs performed: 5
605 Total runs performed: 5
603 Times : Total Per run
606 Times : Total Per run
604 User : 0.910862 s, 0.1821724 s.
607 User : 0.910862 s, 0.1821724 s.
605 System: 0.0 s, 0.0 s.
608 System: 0.0 s, 0.0 s.
606
609
607 -d
610 -d
608 run your program under the control of pdb, the Python debugger.
611 run your program under the control of pdb, the Python debugger.
609 This allows you to execute your program step by step, watch variables,
612 This allows you to execute your program step by step, watch variables,
610 etc. Internally, what IPython does is similar to calling::
613 etc. Internally, what IPython does is similar to calling::
611
614
612 pdb.run('execfile("YOURFILENAME")')
615 pdb.run('execfile("YOURFILENAME")')
613
616
614 with a breakpoint set on line 1 of your file. You can change the line
617 with a breakpoint set on line 1 of your file. You can change the line
615 number for this automatic breakpoint to be <N> by using the -bN option
618 number for this automatic breakpoint to be <N> by using the -bN option
616 (where N must be an integer). For example::
619 (where N must be an integer). For example::
617
620
618 %run -d -b40 myscript
621 %run -d -b40 myscript
619
622
620 will set the first breakpoint at line 40 in myscript.py. Note that
623 will set the first breakpoint at line 40 in myscript.py. Note that
621 the first breakpoint must be set on a line which actually does
624 the first breakpoint must be set on a line which actually does
622 something (not a comment or docstring) for it to stop execution.
625 something (not a comment or docstring) for it to stop execution.
623
626
624 Or you can specify a breakpoint in a different file::
627 Or you can specify a breakpoint in a different file::
625
628
626 %run -d -b myotherfile.py:20 myscript
629 %run -d -b myotherfile.py:20 myscript
627
630
628 When the pdb debugger starts, you will see a (Pdb) prompt. You must
631 When the pdb debugger starts, you will see a (Pdb) prompt. You must
629 first enter 'c' (without quotes) to start execution up to the first
632 first enter 'c' (without quotes) to start execution up to the first
630 breakpoint.
633 breakpoint.
631
634
632 Entering 'help' gives information about the use of the debugger. You
635 Entering 'help' gives information about the use of the debugger. You
633 can easily see pdb's full documentation with "import pdb;pdb.help()"
636 can easily see pdb's full documentation with "import pdb;pdb.help()"
634 at a prompt.
637 at a prompt.
635
638
636 -p
639 -p
637 run program under the control of the Python profiler module (which
640 run program under the control of the Python profiler module (which
638 prints a detailed report of execution times, function calls, etc).
641 prints a detailed report of execution times, function calls, etc).
639
642
640 You can pass other options after -p which affect the behavior of the
643 You can pass other options after -p which affect the behavior of the
641 profiler itself. See the docs for %prun for details.
644 profiler itself. See the docs for %prun for details.
642
645
643 In this mode, the program's variables do NOT propagate back to the
646 In this mode, the program's variables do NOT propagate back to the
644 IPython interactive namespace (because they remain in the namespace
647 IPython interactive namespace (because they remain in the namespace
645 where the profiler executes them).
648 where the profiler executes them).
646
649
647 Internally this triggers a call to %prun, see its documentation for
650 Internally this triggers a call to %prun, see its documentation for
648 details on the options available specifically for profiling.
651 details on the options available specifically for profiling.
649
652
650 There is one special usage for which the text above doesn't apply:
653 There is one special usage for which the text above doesn't apply:
651 if the filename ends with .ipy[nb], the file is run as ipython script,
654 if the filename ends with .ipy[nb], the file is run as ipython script,
652 just as if the commands were written on IPython prompt.
655 just as if the commands were written on IPython prompt.
653
656
654 -m
657 -m
655 specify module name to load instead of script path. Similar to
658 specify module name to load instead of script path. Similar to
656 the -m option for the python interpreter. Use this option last if you
659 the -m option for the python interpreter. Use this option last if you
657 want to combine with other %run options. Unlike the python interpreter
660 want to combine with other %run options. Unlike the python interpreter
658 only source modules are allowed no .pyc or .pyo files.
661 only source modules are allowed no .pyc or .pyo files.
659 For example::
662 For example::
660
663
661 %run -m example
664 %run -m example
662
665
663 will run the example module.
666 will run the example module.
664
667
665 -G
668 -G
666 disable shell-like glob expansion of arguments.
669 disable shell-like glob expansion of arguments.
667
670
668 """
671 """
669
672
670 # Logic to handle issue #3664
673 # Logic to handle issue #3664
671 # Add '--' after '-m <module_name>' to ignore additional args passed to a module.
674 # Add '--' after '-m <module_name>' to ignore additional args passed to a module.
672 if '-m' in parameter_s and '--' not in parameter_s:
675 if '-m' in parameter_s and '--' not in parameter_s:
673 argv = shlex.split(parameter_s, posix=(os.name == 'posix'))
676 argv = shlex.split(parameter_s, posix=(os.name == 'posix'))
674 for idx, arg in enumerate(argv):
677 for idx, arg in enumerate(argv):
675 if arg and arg.startswith('-') and arg != '-':
678 if arg and arg.startswith('-') and arg != '-':
676 if arg == '-m':
679 if arg == '-m':
677 argv.insert(idx + 2, '--')
680 argv.insert(idx + 2, '--')
678 break
681 break
679 else:
682 else:
680 # Positional arg, break
683 # Positional arg, break
681 break
684 break
682 parameter_s = ' '.join(shlex.quote(arg) for arg in argv)
685 parameter_s = ' '.join(shlex.quote(arg) for arg in argv)
683
686
684 # get arguments and set sys.argv for program to be run.
687 # get arguments and set sys.argv for program to be run.
685 opts, arg_lst = self.parse_options(parameter_s,
688 opts, arg_lst = self.parse_options(parameter_s,
686 'nidtN:b:pD:l:rs:T:em:G',
689 'nidtN:b:pD:l:rs:T:em:G',
687 mode='list', list_all=1)
690 mode='list', list_all=1)
688 if "m" in opts:
691 if "m" in opts:
689 modulename = opts["m"][0]
692 modulename = opts["m"][0]
690 modpath = find_mod(modulename)
693 modpath = find_mod(modulename)
691 if modpath is None:
694 if modpath is None:
692 msg = '%r is not a valid modulename on sys.path'%modulename
695 msg = '%r is not a valid modulename on sys.path'%modulename
693 raise Exception(msg)
696 raise Exception(msg)
694 arg_lst = [modpath] + arg_lst
697 arg_lst = [modpath] + arg_lst
695 try:
698 try:
696 fpath = None # initialize to make sure fpath is in scope later
699 fpath = None # initialize to make sure fpath is in scope later
697 fpath = arg_lst[0]
700 fpath = arg_lst[0]
698 filename = file_finder(fpath)
701 filename = file_finder(fpath)
699 except IndexError as e:
702 except IndexError as e:
700 msg = 'you must provide at least a filename.'
703 msg = 'you must provide at least a filename.'
701 raise Exception(msg) from e
704 raise Exception(msg) from e
702 except IOError as e:
705 except IOError as e:
703 try:
706 try:
704 msg = str(e)
707 msg = str(e)
705 except UnicodeError:
708 except UnicodeError:
706 msg = e.message
709 msg = e.message
707 if os.name == 'nt' and re.match(r"^'.*'$",fpath):
710 if os.name == 'nt' and re.match(r"^'.*'$",fpath):
708 warn('For Windows, use double quotes to wrap a filename: %run "mypath\\myfile.py"')
711 warn('For Windows, use double quotes to wrap a filename: %run "mypath\\myfile.py"')
709 raise Exception(msg) from e
712 raise Exception(msg) from e
710 except TypeError:
713 except TypeError:
711 if fpath in sys.meta_path:
714 if fpath in sys.meta_path:
712 filename = ""
715 filename = ""
713 else:
716 else:
714 raise
717 raise
715
718
716 if filename.lower().endswith(('.ipy', '.ipynb')):
719 if filename.lower().endswith(('.ipy', '.ipynb')):
717 with preserve_keys(self.shell.user_ns, '__file__'):
720 with preserve_keys(self.shell.user_ns, '__file__'):
718 self.shell.user_ns['__file__'] = filename
721 self.shell.user_ns['__file__'] = filename
719 self.shell.safe_execfile_ipy(filename, raise_exceptions=True)
722 self.shell.safe_execfile_ipy(filename, raise_exceptions=True)
720 return
723 return
721
724
722 # Control the response to exit() calls made by the script being run
725 # Control the response to exit() calls made by the script being run
723 exit_ignore = 'e' in opts
726 exit_ignore = 'e' in opts
724
727
725 # Make sure that the running script gets a proper sys.argv as if it
728 # Make sure that the running script gets a proper sys.argv as if it
726 # were run from a system shell.
729 # were run from a system shell.
727 save_argv = sys.argv # save it for later restoring
730 save_argv = sys.argv # save it for later restoring
728
731
729 if 'G' in opts:
732 if 'G' in opts:
730 args = arg_lst[1:]
733 args = arg_lst[1:]
731 else:
734 else:
732 # tilde and glob expansion
735 # tilde and glob expansion
733 args = shellglob(map(os.path.expanduser, arg_lst[1:]))
736 args = shellglob(map(os.path.expanduser, arg_lst[1:]))
734
737
735 sys.argv = [filename] + args # put in the proper filename
738 sys.argv = [filename] + args # put in the proper filename
736
739
737 if 'n' in opts:
740 if 'n' in opts:
738 name = Path(filename).stem
741 name = Path(filename).stem
739 else:
742 else:
740 name = '__main__'
743 name = '__main__'
741
744
742 if 'i' in opts:
745 if 'i' in opts:
743 # Run in user's interactive namespace
746 # Run in user's interactive namespace
744 prog_ns = self.shell.user_ns
747 prog_ns = self.shell.user_ns
745 __name__save = self.shell.user_ns['__name__']
748 __name__save = self.shell.user_ns['__name__']
746 prog_ns['__name__'] = name
749 prog_ns['__name__'] = name
747 main_mod = self.shell.user_module
750 main_mod = self.shell.user_module
748
751
749 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
752 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
750 # set the __file__ global in the script's namespace
753 # set the __file__ global in the script's namespace
751 # TK: Is this necessary in interactive mode?
754 # TK: Is this necessary in interactive mode?
752 prog_ns['__file__'] = filename
755 prog_ns['__file__'] = filename
753 else:
756 else:
754 # Run in a fresh, empty namespace
757 # Run in a fresh, empty namespace
755
758
756 # The shell MUST hold a reference to prog_ns so after %run
759 # The shell MUST hold a reference to prog_ns so after %run
757 # exits, the python deletion mechanism doesn't zero it out
760 # exits, the python deletion mechanism doesn't zero it out
758 # (leaving dangling references). See interactiveshell for details
761 # (leaving dangling references). See interactiveshell for details
759 main_mod = self.shell.new_main_mod(filename, name)
762 main_mod = self.shell.new_main_mod(filename, name)
760 prog_ns = main_mod.__dict__
763 prog_ns = main_mod.__dict__
761
764
762 # pickle fix. See interactiveshell for an explanation. But we need to
765 # pickle fix. See interactiveshell for an explanation. But we need to
763 # make sure that, if we overwrite __main__, we replace it at the end
766 # make sure that, if we overwrite __main__, we replace it at the end
764 main_mod_name = prog_ns['__name__']
767 main_mod_name = prog_ns['__name__']
765
768
766 if main_mod_name == '__main__':
769 if main_mod_name == '__main__':
767 restore_main = sys.modules['__main__']
770 restore_main = sys.modules['__main__']
768 else:
771 else:
769 restore_main = False
772 restore_main = False
770
773
771 # This needs to be undone at the end to prevent holding references to
774 # This needs to be undone at the end to prevent holding references to
772 # every single object ever created.
775 # every single object ever created.
773 sys.modules[main_mod_name] = main_mod
776 sys.modules[main_mod_name] = main_mod
774
777
775 if 'p' in opts or 'd' in opts:
778 if 'p' in opts or 'd' in opts:
776 if 'm' in opts:
779 if 'm' in opts:
777 code = 'run_module(modulename, prog_ns)'
780 code = 'run_module(modulename, prog_ns)'
778 code_ns = {
781 code_ns = {
779 'run_module': self.shell.safe_run_module,
782 'run_module': self.shell.safe_run_module,
780 'prog_ns': prog_ns,
783 'prog_ns': prog_ns,
781 'modulename': modulename,
784 'modulename': modulename,
782 }
785 }
783 else:
786 else:
784 if 'd' in opts:
787 if 'd' in opts:
785 # allow exceptions to raise in debug mode
788 # allow exceptions to raise in debug mode
786 code = 'execfile(filename, prog_ns, raise_exceptions=True)'
789 code = 'execfile(filename, prog_ns, raise_exceptions=True)'
787 else:
790 else:
788 code = 'execfile(filename, prog_ns)'
791 code = 'execfile(filename, prog_ns)'
789 code_ns = {
792 code_ns = {
790 'execfile': self.shell.safe_execfile,
793 'execfile': self.shell.safe_execfile,
791 'prog_ns': prog_ns,
794 'prog_ns': prog_ns,
792 'filename': get_py_filename(filename),
795 'filename': get_py_filename(filename),
793 }
796 }
794
797
795 try:
798 try:
796 stats = None
799 stats = None
797 if 'p' in opts:
800 if 'p' in opts:
798 stats = self._run_with_profiler(code, opts, code_ns)
801 stats = self._run_with_profiler(code, opts, code_ns)
799 else:
802 else:
800 if 'd' in opts:
803 if 'd' in opts:
801 bp_file, bp_line = parse_breakpoint(
804 bp_file, bp_line = parse_breakpoint(
802 opts.get('b', ['1'])[0], filename)
805 opts.get('b', ['1'])[0], filename)
803 self._run_with_debugger(
806 self._run_with_debugger(
804 code, code_ns, filename, bp_line, bp_file)
807 code, code_ns, filename, bp_line, bp_file)
805 else:
808 else:
806 if 'm' in opts:
809 if 'm' in opts:
807 def run():
810 def run():
808 self.shell.safe_run_module(modulename, prog_ns)
811 self.shell.safe_run_module(modulename, prog_ns)
809 else:
812 else:
810 if runner is None:
813 if runner is None:
811 runner = self.default_runner
814 runner = self.default_runner
812 if runner is None:
815 if runner is None:
813 runner = self.shell.safe_execfile
816 runner = self.shell.safe_execfile
814
817
815 def run():
818 def run():
816 runner(filename, prog_ns, prog_ns,
819 runner(filename, prog_ns, prog_ns,
817 exit_ignore=exit_ignore)
820 exit_ignore=exit_ignore)
818
821
819 if 't' in opts:
822 if 't' in opts:
820 # timed execution
823 # timed execution
821 try:
824 try:
822 nruns = int(opts['N'][0])
825 nruns = int(opts['N'][0])
823 if nruns < 1:
826 if nruns < 1:
824 error('Number of runs must be >=1')
827 error('Number of runs must be >=1')
825 return
828 return
826 except (KeyError):
829 except (KeyError):
827 nruns = 1
830 nruns = 1
828 self._run_with_timing(run, nruns)
831 self._run_with_timing(run, nruns)
829 else:
832 else:
830 # regular execution
833 # regular execution
831 run()
834 run()
832
835
833 if 'i' in opts:
836 if 'i' in opts:
834 self.shell.user_ns['__name__'] = __name__save
837 self.shell.user_ns['__name__'] = __name__save
835 else:
838 else:
836 # update IPython interactive namespace
839 # update IPython interactive namespace
837
840
838 # Some forms of read errors on the file may mean the
841 # Some forms of read errors on the file may mean the
839 # __name__ key was never set; using pop we don't have to
842 # __name__ key was never set; using pop we don't have to
840 # worry about a possible KeyError.
843 # worry about a possible KeyError.
841 prog_ns.pop('__name__', None)
844 prog_ns.pop('__name__', None)
842
845
843 with preserve_keys(self.shell.user_ns, '__file__'):
846 with preserve_keys(self.shell.user_ns, '__file__'):
844 self.shell.user_ns.update(prog_ns)
847 self.shell.user_ns.update(prog_ns)
845 finally:
848 finally:
846 # It's a bit of a mystery why, but __builtins__ can change from
849 # It's a bit of a mystery why, but __builtins__ can change from
847 # being a module to becoming a dict missing some key data after
850 # being a module to becoming a dict missing some key data after
848 # %run. As best I can see, this is NOT something IPython is doing
851 # %run. As best I can see, this is NOT something IPython is doing
849 # at all, and similar problems have been reported before:
852 # at all, and similar problems have been reported before:
850 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
853 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
851 # Since this seems to be done by the interpreter itself, the best
854 # Since this seems to be done by the interpreter itself, the best
852 # we can do is to at least restore __builtins__ for the user on
855 # we can do is to at least restore __builtins__ for the user on
853 # exit.
856 # exit.
854 self.shell.user_ns['__builtins__'] = builtin_mod
857 self.shell.user_ns['__builtins__'] = builtin_mod
855
858
856 # Ensure key global structures are restored
859 # Ensure key global structures are restored
857 sys.argv = save_argv
860 sys.argv = save_argv
858 if restore_main:
861 if restore_main:
859 sys.modules['__main__'] = restore_main
862 sys.modules['__main__'] = restore_main
860 if '__mp_main__' in sys.modules:
863 if '__mp_main__' in sys.modules:
861 sys.modules['__mp_main__'] = restore_main
864 sys.modules['__mp_main__'] = restore_main
862 else:
865 else:
863 # Remove from sys.modules the reference to main_mod we'd
866 # Remove from sys.modules the reference to main_mod we'd
864 # added. Otherwise it will trap references to objects
867 # added. Otherwise it will trap references to objects
865 # contained therein.
868 # contained therein.
866 del sys.modules[main_mod_name]
869 del sys.modules[main_mod_name]
867
870
868 return stats
871 return stats
869
872
870 def _run_with_debugger(self, code, code_ns, filename=None,
873 def _run_with_debugger(
871 bp_line=None, bp_file=None):
874 self, code, code_ns, filename=None, bp_line=None, bp_file=None, local_ns=None
875 ):
872 """
876 """
873 Run `code` in debugger with a break point.
877 Run `code` in debugger with a break point.
874
878
875 Parameters
879 Parameters
876 ----------
880 ----------
877 code : str
881 code : str
878 Code to execute.
882 Code to execute.
879 code_ns : dict
883 code_ns : dict
880 A namespace in which `code` is executed.
884 A namespace in which `code` is executed.
881 filename : str
885 filename : str
882 `code` is ran as if it is in `filename`.
886 `code` is ran as if it is in `filename`.
883 bp_line : int, optional
887 bp_line : int, optional
884 Line number of the break point.
888 Line number of the break point.
885 bp_file : str, optional
889 bp_file : str, optional
886 Path to the file in which break point is specified.
890 Path to the file in which break point is specified.
887 `filename` is used if not given.
891 `filename` is used if not given.
892 local_ns : dict, optional
893 A local namespace in which `code` is executed.
888
894
889 Raises
895 Raises
890 ------
896 ------
891 UsageError
897 UsageError
892 If the break point given by `bp_line` is not valid.
898 If the break point given by `bp_line` is not valid.
893
899
894 """
900 """
895 deb = self.shell.InteractiveTB.pdb
901 deb = self.shell.InteractiveTB.pdb
896 if not deb:
902 if not deb:
897 self.shell.InteractiveTB.pdb = self.shell.InteractiveTB.debugger_cls()
903 self.shell.InteractiveTB.pdb = self.shell.InteractiveTB.debugger_cls()
898 deb = self.shell.InteractiveTB.pdb
904 deb = self.shell.InteractiveTB.pdb
899
905
900 # deb.checkline() fails if deb.curframe exists but is None; it can
906 # deb.checkline() fails if deb.curframe exists but is None; it can
901 # handle it not existing. https://github.com/ipython/ipython/issues/10028
907 # handle it not existing. https://github.com/ipython/ipython/issues/10028
902 if hasattr(deb, 'curframe'):
908 if hasattr(deb, 'curframe'):
903 del deb.curframe
909 del deb.curframe
904
910
905 # reset Breakpoint state, which is moronically kept
911 # reset Breakpoint state, which is moronically kept
906 # in a class
912 # in a class
907 bdb.Breakpoint.next = 1
913 bdb.Breakpoint.next = 1
908 bdb.Breakpoint.bplist = {}
914 bdb.Breakpoint.bplist = {}
909 bdb.Breakpoint.bpbynumber = [None]
915 bdb.Breakpoint.bpbynumber = [None]
910 deb.clear_all_breaks()
916 deb.clear_all_breaks()
911 if bp_line is not None:
917 if bp_line is not None:
912 # Set an initial breakpoint to stop execution
918 # Set an initial breakpoint to stop execution
913 maxtries = 10
919 maxtries = 10
914 bp_file = bp_file or filename
920 bp_file = bp_file or filename
915 checkline = deb.checkline(bp_file, bp_line)
921 checkline = deb.checkline(bp_file, bp_line)
916 if not checkline:
922 if not checkline:
917 for bp in range(bp_line + 1, bp_line + maxtries + 1):
923 for bp in range(bp_line + 1, bp_line + maxtries + 1):
918 if deb.checkline(bp_file, bp):
924 if deb.checkline(bp_file, bp):
919 break
925 break
920 else:
926 else:
921 msg = ("\nI failed to find a valid line to set "
927 msg = ("\nI failed to find a valid line to set "
922 "a breakpoint\n"
928 "a breakpoint\n"
923 "after trying up to line: %s.\n"
929 "after trying up to line: %s.\n"
924 "Please set a valid breakpoint manually "
930 "Please set a valid breakpoint manually "
925 "with the -b option." % bp)
931 "with the -b option." % bp)
926 raise UsageError(msg)
932 raise UsageError(msg)
927 # if we find a good linenumber, set the breakpoint
933 # if we find a good linenumber, set the breakpoint
928 deb.do_break('%s:%s' % (bp_file, bp_line))
934 deb.do_break('%s:%s' % (bp_file, bp_line))
929
935
930 if filename:
936 if filename:
931 # Mimic Pdb._runscript(...)
937 # Mimic Pdb._runscript(...)
932 deb._wait_for_mainpyfile = True
938 deb._wait_for_mainpyfile = True
933 deb.mainpyfile = deb.canonic(filename)
939 deb.mainpyfile = deb.canonic(filename)
934
940
935 # Start file run
941 # Start file run
936 print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
942 print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
937 try:
943 try:
938 if filename:
944 if filename:
939 # save filename so it can be used by methods on the deb object
945 # save filename so it can be used by methods on the deb object
940 deb._exec_filename = filename
946 deb._exec_filename = filename
941 while True:
947 while True:
942 try:
948 try:
943 trace = sys.gettrace()
949 trace = sys.gettrace()
944 deb.run(code, code_ns)
950 deb.run(code, code_ns, local_ns)
945 except Restart:
951 except Restart:
946 print("Restarting")
952 print("Restarting")
947 if filename:
953 if filename:
948 deb._wait_for_mainpyfile = True
954 deb._wait_for_mainpyfile = True
949 deb.mainpyfile = deb.canonic(filename)
955 deb.mainpyfile = deb.canonic(filename)
950 continue
956 continue
951 else:
957 else:
952 break
958 break
953 finally:
959 finally:
954 sys.settrace(trace)
960 sys.settrace(trace)
955
961
956
962
957 except:
963 except:
958 etype, value, tb = sys.exc_info()
964 etype, value, tb = sys.exc_info()
959 # Skip three frames in the traceback: the %run one,
965 # Skip three frames in the traceback: the %run one,
960 # one inside bdb.py, and the command-line typed by the
966 # one inside bdb.py, and the command-line typed by the
961 # user (run by exec in pdb itself).
967 # user (run by exec in pdb itself).
962 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
968 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
963
969
964 @staticmethod
970 @staticmethod
965 def _run_with_timing(run, nruns):
971 def _run_with_timing(run, nruns):
966 """
972 """
967 Run function `run` and print timing information.
973 Run function `run` and print timing information.
968
974
969 Parameters
975 Parameters
970 ----------
976 ----------
971 run : callable
977 run : callable
972 Any callable object which takes no argument.
978 Any callable object which takes no argument.
973 nruns : int
979 nruns : int
974 Number of times to execute `run`.
980 Number of times to execute `run`.
975
981
976 """
982 """
977 twall0 = time.perf_counter()
983 twall0 = time.perf_counter()
978 if nruns == 1:
984 if nruns == 1:
979 t0 = clock2()
985 t0 = clock2()
980 run()
986 run()
981 t1 = clock2()
987 t1 = clock2()
982 t_usr = t1[0] - t0[0]
988 t_usr = t1[0] - t0[0]
983 t_sys = t1[1] - t0[1]
989 t_sys = t1[1] - t0[1]
984 print("\nIPython CPU timings (estimated):")
990 print("\nIPython CPU timings (estimated):")
985 print(" User : %10.2f s." % t_usr)
991 print(" User : %10.2f s." % t_usr)
986 print(" System : %10.2f s." % t_sys)
992 print(" System : %10.2f s." % t_sys)
987 else:
993 else:
988 runs = range(nruns)
994 runs = range(nruns)
989 t0 = clock2()
995 t0 = clock2()
990 for nr in runs:
996 for nr in runs:
991 run()
997 run()
992 t1 = clock2()
998 t1 = clock2()
993 t_usr = t1[0] - t0[0]
999 t_usr = t1[0] - t0[0]
994 t_sys = t1[1] - t0[1]
1000 t_sys = t1[1] - t0[1]
995 print("\nIPython CPU timings (estimated):")
1001 print("\nIPython CPU timings (estimated):")
996 print("Total runs performed:", nruns)
1002 print("Total runs performed:", nruns)
997 print(" Times : %10s %10s" % ('Total', 'Per run'))
1003 print(" Times : %10s %10s" % ('Total', 'Per run'))
998 print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
1004 print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
999 print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
1005 print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
1000 twall1 = time.perf_counter()
1006 twall1 = time.perf_counter()
1001 print("Wall time: %10.2f s." % (twall1 - twall0))
1007 print("Wall time: %10.2f s." % (twall1 - twall0))
1002
1008
1003 @skip_doctest
1009 @skip_doctest
1004 @no_var_expand
1010 @no_var_expand
1005 @line_cell_magic
1011 @line_cell_magic
1006 @needs_local_scope
1012 @needs_local_scope
1007 def timeit(self, line='', cell=None, local_ns=None):
1013 def timeit(self, line='', cell=None, local_ns=None):
1008 """Time execution of a Python statement or expression
1014 """Time execution of a Python statement or expression
1009
1015
1010 Usage, in line mode:
1016 Usage, in line mode:
1011 %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
1017 %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
1012 or in cell mode:
1018 or in cell mode:
1013 %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
1019 %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
1014 code
1020 code
1015 code...
1021 code...
1016
1022
1017 Time execution of a Python statement or expression using the timeit
1023 Time execution of a Python statement or expression using the timeit
1018 module. This function can be used both as a line and cell magic:
1024 module. This function can be used both as a line and cell magic:
1019
1025
1020 - In line mode you can time a single-line statement (though multiple
1026 - In line mode you can time a single-line statement (though multiple
1021 ones can be chained with using semicolons).
1027 ones can be chained with using semicolons).
1022
1028
1023 - In cell mode, the statement in the first line is used as setup code
1029 - In cell mode, the statement in the first line is used as setup code
1024 (executed but not timed) and the body of the cell is timed. The cell
1030 (executed but not timed) and the body of the cell is timed. The cell
1025 body has access to any variables created in the setup code.
1031 body has access to any variables created in the setup code.
1026
1032
1027 Options:
1033 Options:
1028 -n<N>: execute the given statement <N> times in a loop. If <N> is not
1034 -n<N>: execute the given statement <N> times in a loop. If <N> is not
1029 provided, <N> is determined so as to get sufficient accuracy.
1035 provided, <N> is determined so as to get sufficient accuracy.
1030
1036
1031 -r<R>: number of repeats <R>, each consisting of <N> loops, and take the
1037 -r<R>: number of repeats <R>, each consisting of <N> loops, and take the
1032 best result.
1038 best result.
1033 Default: 7
1039 Default: 7
1034
1040
1035 -t: use time.time to measure the time, which is the default on Unix.
1041 -t: use time.time to measure the time, which is the default on Unix.
1036 This function measures wall time.
1042 This function measures wall time.
1037
1043
1038 -c: use time.clock to measure the time, which is the default on
1044 -c: use time.clock to measure the time, which is the default on
1039 Windows and measures wall time. On Unix, resource.getrusage is used
1045 Windows and measures wall time. On Unix, resource.getrusage is used
1040 instead and returns the CPU user time.
1046 instead and returns the CPU user time.
1041
1047
1042 -p<P>: use a precision of <P> digits to display the timing result.
1048 -p<P>: use a precision of <P> digits to display the timing result.
1043 Default: 3
1049 Default: 3
1044
1050
1045 -q: Quiet, do not print result.
1051 -q: Quiet, do not print result.
1046
1052
1047 -o: return a TimeitResult that can be stored in a variable to inspect
1053 -o: return a TimeitResult that can be stored in a variable to inspect
1048 the result in more details.
1054 the result in more details.
1049
1055
1050 .. versionchanged:: 7.3
1056 .. versionchanged:: 7.3
1051 User variables are no longer expanded,
1057 User variables are no longer expanded,
1052 the magic line is always left unmodified.
1058 the magic line is always left unmodified.
1053
1059
1054 Examples
1060 Examples
1055 --------
1061 --------
1056 ::
1062 ::
1057
1063
1058 In [1]: %timeit pass
1064 In [1]: %timeit pass
1059 8.26 ns ± 0.12 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
1065 8.26 ns ± 0.12 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
1060
1066
1061 In [2]: u = None
1067 In [2]: u = None
1062
1068
1063 In [3]: %timeit u is None
1069 In [3]: %timeit u is None
1064 29.9 ns ± 0.643 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
1070 29.9 ns ± 0.643 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
1065
1071
1066 In [4]: %timeit -r 4 u == None
1072 In [4]: %timeit -r 4 u == None
1067
1073
1068 In [5]: import time
1074 In [5]: import time
1069
1075
1070 In [6]: %timeit -n1 time.sleep(2)
1076 In [6]: %timeit -n1 time.sleep(2)
1071
1077
1072 The times reported by %timeit will be slightly higher than those
1078 The times reported by %timeit will be slightly higher than those
1073 reported by the timeit.py script when variables are accessed. This is
1079 reported by the timeit.py script when variables are accessed. This is
1074 due to the fact that %timeit executes the statement in the namespace
1080 due to the fact that %timeit executes the statement in the namespace
1075 of the shell, compared with timeit.py, which uses a single setup
1081 of the shell, compared with timeit.py, which uses a single setup
1076 statement to import function or create variables. Generally, the bias
1082 statement to import function or create variables. Generally, the bias
1077 does not matter as long as results from timeit.py are not mixed with
1083 does not matter as long as results from timeit.py are not mixed with
1078 those from %timeit."""
1084 those from %timeit."""
1079
1085
1080 opts, stmt = self.parse_options(
1086 opts, stmt = self.parse_options(
1081 line, "n:r:tcp:qo", posix=False, strict=False, preserve_non_opts=True
1087 line, "n:r:tcp:qo", posix=False, strict=False, preserve_non_opts=True
1082 )
1088 )
1083 if stmt == "" and cell is None:
1089 if stmt == "" and cell is None:
1084 return
1090 return
1085
1091
1086 timefunc = timeit.default_timer
1092 timefunc = timeit.default_timer
1087 number = int(getattr(opts, "n", 0))
1093 number = int(getattr(opts, "n", 0))
1088 default_repeat = 7 if timeit.default_repeat < 7 else timeit.default_repeat
1094 default_repeat = 7 if timeit.default_repeat < 7 else timeit.default_repeat
1089 repeat = int(getattr(opts, "r", default_repeat))
1095 repeat = int(getattr(opts, "r", default_repeat))
1090 precision = int(getattr(opts, "p", 3))
1096 precision = int(getattr(opts, "p", 3))
1091 quiet = 'q' in opts
1097 quiet = 'q' in opts
1092 return_result = 'o' in opts
1098 return_result = 'o' in opts
1093 if hasattr(opts, "t"):
1099 if hasattr(opts, "t"):
1094 timefunc = time.time
1100 timefunc = time.time
1095 if hasattr(opts, "c"):
1101 if hasattr(opts, "c"):
1096 timefunc = clock
1102 timefunc = clock
1097
1103
1098 timer = Timer(timer=timefunc)
1104 timer = Timer(timer=timefunc)
1099 # this code has tight coupling to the inner workings of timeit.Timer,
1105 # this code has tight coupling to the inner workings of timeit.Timer,
1100 # but is there a better way to achieve that the code stmt has access
1106 # but is there a better way to achieve that the code stmt has access
1101 # to the shell namespace?
1107 # to the shell namespace?
1102 transform = self.shell.transform_cell
1108 transform = self.shell.transform_cell
1103
1109
1104 if cell is None:
1110 if cell is None:
1105 # called as line magic
1111 # called as line magic
1106 ast_setup = self.shell.compile.ast_parse("pass")
1112 ast_setup = self.shell.compile.ast_parse("pass")
1107 ast_stmt = self.shell.compile.ast_parse(transform(stmt))
1113 ast_stmt = self.shell.compile.ast_parse(transform(stmt))
1108 else:
1114 else:
1109 ast_setup = self.shell.compile.ast_parse(transform(stmt))
1115 ast_setup = self.shell.compile.ast_parse(transform(stmt))
1110 ast_stmt = self.shell.compile.ast_parse(transform(cell))
1116 ast_stmt = self.shell.compile.ast_parse(transform(cell))
1111
1117
1112 ast_setup = self.shell.transform_ast(ast_setup)
1118 ast_setup = self.shell.transform_ast(ast_setup)
1113 ast_stmt = self.shell.transform_ast(ast_stmt)
1119 ast_stmt = self.shell.transform_ast(ast_stmt)
1114
1120
1115 # Check that these compile to valid Python code *outside* the timer func
1121 # Check that these compile to valid Python code *outside* the timer func
1116 # Invalid code may become valid when put inside the function & loop,
1122 # Invalid code may become valid when put inside the function & loop,
1117 # which messes up error messages.
1123 # which messes up error messages.
1118 # https://github.com/ipython/ipython/issues/10636
1124 # https://github.com/ipython/ipython/issues/10636
1119 self.shell.compile(ast_setup, "<magic-timeit-setup>", "exec")
1125 self.shell.compile(ast_setup, "<magic-timeit-setup>", "exec")
1120 self.shell.compile(ast_stmt, "<magic-timeit-stmt>", "exec")
1126 self.shell.compile(ast_stmt, "<magic-timeit-stmt>", "exec")
1121
1127
1122 # This codestring is taken from timeit.template - we fill it in as an
1128 # This codestring is taken from timeit.template - we fill it in as an
1123 # AST, so that we can apply our AST transformations to the user code
1129 # AST, so that we can apply our AST transformations to the user code
1124 # without affecting the timing code.
1130 # without affecting the timing code.
1125 timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
1131 timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
1126 ' setup\n'
1132 ' setup\n'
1127 ' _t0 = _timer()\n'
1133 ' _t0 = _timer()\n'
1128 ' for _i in _it:\n'
1134 ' for _i in _it:\n'
1129 ' stmt\n'
1135 ' stmt\n'
1130 ' _t1 = _timer()\n'
1136 ' _t1 = _timer()\n'
1131 ' return _t1 - _t0\n')
1137 ' return _t1 - _t0\n')
1132
1138
1133 timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
1139 timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
1134 timeit_ast = ast.fix_missing_locations(timeit_ast)
1140 timeit_ast = ast.fix_missing_locations(timeit_ast)
1135
1141
1136 # Track compilation time so it can be reported if too long
1142 # Track compilation time so it can be reported if too long
1137 # Minimum time above which compilation time will be reported
1143 # Minimum time above which compilation time will be reported
1138 tc_min = 0.1
1144 tc_min = 0.1
1139
1145
1140 t0 = clock()
1146 t0 = clock()
1141 code = self.shell.compile(timeit_ast, "<magic-timeit>", "exec")
1147 code = self.shell.compile(timeit_ast, "<magic-timeit>", "exec")
1142 tc = clock()-t0
1148 tc = clock()-t0
1143
1149
1144 ns = {}
1150 ns = {}
1145 glob = self.shell.user_ns
1151 glob = self.shell.user_ns
1146 # handles global vars with same name as local vars. We store them in conflict_globs.
1152 # handles global vars with same name as local vars. We store them in conflict_globs.
1147 conflict_globs = {}
1153 conflict_globs = {}
1148 if local_ns and cell is None:
1154 if local_ns and cell is None:
1149 for var_name, var_val in glob.items():
1155 for var_name, var_val in glob.items():
1150 if var_name in local_ns:
1156 if var_name in local_ns:
1151 conflict_globs[var_name] = var_val
1157 conflict_globs[var_name] = var_val
1152 glob.update(local_ns)
1158 glob.update(local_ns)
1153
1159
1154 exec(code, glob, ns)
1160 exec(code, glob, ns)
1155 timer.inner = ns["inner"]
1161 timer.inner = ns["inner"]
1156
1162
1157 # This is used to check if there is a huge difference between the
1163 # This is used to check if there is a huge difference between the
1158 # best and worst timings.
1164 # best and worst timings.
1159 # Issue: https://github.com/ipython/ipython/issues/6471
1165 # Issue: https://github.com/ipython/ipython/issues/6471
1160 if number == 0:
1166 if number == 0:
1161 # determine number so that 0.2 <= total time < 2.0
1167 # determine number so that 0.2 <= total time < 2.0
1162 for index in range(0, 10):
1168 for index in range(0, 10):
1163 number = 10 ** index
1169 number = 10 ** index
1164 time_number = timer.timeit(number)
1170 time_number = timer.timeit(number)
1165 if time_number >= 0.2:
1171 if time_number >= 0.2:
1166 break
1172 break
1167
1173
1168 all_runs = timer.repeat(repeat, number)
1174 all_runs = timer.repeat(repeat, number)
1169 best = min(all_runs) / number
1175 best = min(all_runs) / number
1170 worst = max(all_runs) / number
1176 worst = max(all_runs) / number
1171 timeit_result = TimeitResult(number, repeat, best, worst, all_runs, tc, precision)
1177 timeit_result = TimeitResult(number, repeat, best, worst, all_runs, tc, precision)
1172
1178
1173 # Restore global vars from conflict_globs
1179 # Restore global vars from conflict_globs
1174 if conflict_globs:
1180 if conflict_globs:
1175 glob.update(conflict_globs)
1181 glob.update(conflict_globs)
1176
1182
1177 if not quiet :
1183 if not quiet :
1178 # Check best timing is greater than zero to avoid a
1184 # Check best timing is greater than zero to avoid a
1179 # ZeroDivisionError.
1185 # ZeroDivisionError.
1180 # In cases where the slowest timing is lesser than a microsecond
1186 # In cases where the slowest timing is lesser than a microsecond
1181 # we assume that it does not really matter if the fastest
1187 # we assume that it does not really matter if the fastest
1182 # timing is 4 times faster than the slowest timing or not.
1188 # timing is 4 times faster than the slowest timing or not.
1183 if worst > 4 * best and best > 0 and worst > 1e-6:
1189 if worst > 4 * best and best > 0 and worst > 1e-6:
1184 print("The slowest run took %0.2f times longer than the "
1190 print("The slowest run took %0.2f times longer than the "
1185 "fastest. This could mean that an intermediate result "
1191 "fastest. This could mean that an intermediate result "
1186 "is being cached." % (worst / best))
1192 "is being cached." % (worst / best))
1187
1193
1188 print( timeit_result )
1194 print( timeit_result )
1189
1195
1190 if tc > tc_min:
1196 if tc > tc_min:
1191 print("Compiler time: %.2f s" % tc)
1197 print("Compiler time: %.2f s" % tc)
1192 if return_result:
1198 if return_result:
1193 return timeit_result
1199 return timeit_result
1194
1200
1195 @skip_doctest
1201 @skip_doctest
1196 @no_var_expand
1202 @no_var_expand
1197 @needs_local_scope
1203 @needs_local_scope
1198 @line_cell_magic
1204 @line_cell_magic
1199 @output_can_be_silenced
1205 @output_can_be_silenced
1200 def time(self,line='', cell=None, local_ns=None):
1206 def time(self,line='', cell=None, local_ns=None):
1201 """Time execution of a Python statement or expression.
1207 """Time execution of a Python statement or expression.
1202
1208
1203 The CPU and wall clock times are printed, and the value of the
1209 The CPU and wall clock times are printed, and the value of the
1204 expression (if any) is returned. Note that under Win32, system time
1210 expression (if any) is returned. Note that under Win32, system time
1205 is always reported as 0, since it can not be measured.
1211 is always reported as 0, since it can not be measured.
1206
1212
1207 This function can be used both as a line and cell magic:
1213 This function can be used both as a line and cell magic:
1208
1214
1209 - In line mode you can time a single-line statement (though multiple
1215 - In line mode you can time a single-line statement (though multiple
1210 ones can be chained with using semicolons).
1216 ones can be chained with using semicolons).
1211
1217
1212 - In cell mode, you can time the cell body (a directly
1218 - In cell mode, you can time the cell body (a directly
1213 following statement raises an error).
1219 following statement raises an error).
1214
1220
1215 This function provides very basic timing functionality. Use the timeit
1221 This function provides very basic timing functionality. Use the timeit
1216 magic for more control over the measurement.
1222 magic for more control over the measurement.
1217
1223
1218 .. versionchanged:: 7.3
1224 .. versionchanged:: 7.3
1219 User variables are no longer expanded,
1225 User variables are no longer expanded,
1220 the magic line is always left unmodified.
1226 the magic line is always left unmodified.
1221
1227
1222 Examples
1228 Examples
1223 --------
1229 --------
1224 ::
1230 ::
1225
1231
1226 In [1]: %time 2**128
1232 In [1]: %time 2**128
1227 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1233 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1228 Wall time: 0.00
1234 Wall time: 0.00
1229 Out[1]: 340282366920938463463374607431768211456L
1235 Out[1]: 340282366920938463463374607431768211456L
1230
1236
1231 In [2]: n = 1000000
1237 In [2]: n = 1000000
1232
1238
1233 In [3]: %time sum(range(n))
1239 In [3]: %time sum(range(n))
1234 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1240 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1235 Wall time: 1.37
1241 Wall time: 1.37
1236 Out[3]: 499999500000L
1242 Out[3]: 499999500000L
1237
1243
1238 In [4]: %time print 'hello world'
1244 In [4]: %time print 'hello world'
1239 hello world
1245 hello world
1240 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1246 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1241 Wall time: 0.00
1247 Wall time: 0.00
1242
1248
1243 .. note::
1249 .. note::
1244 The time needed by Python to compile the given expression will be
1250 The time needed by Python to compile the given expression will be
1245 reported if it is more than 0.1s.
1251 reported if it is more than 0.1s.
1246
1252
1247 In the example below, the actual exponentiation is done by Python
1253 In the example below, the actual exponentiation is done by Python
1248 at compilation time, so while the expression can take a noticeable
1254 at compilation time, so while the expression can take a noticeable
1249 amount of time to compute, that time is purely due to the
1255 amount of time to compute, that time is purely due to the
1250 compilation::
1256 compilation::
1251
1257
1252 In [5]: %time 3**9999;
1258 In [5]: %time 3**9999;
1253 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1259 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1254 Wall time: 0.00 s
1260 Wall time: 0.00 s
1255
1261
1256 In [6]: %time 3**999999;
1262 In [6]: %time 3**999999;
1257 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1263 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1258 Wall time: 0.00 s
1264 Wall time: 0.00 s
1259 Compiler : 0.78 s
1265 Compiler : 0.78 s
1260 """
1266 """
1261 # fail immediately if the given expression can't be compiled
1267 # fail immediately if the given expression can't be compiled
1262
1268
1263 if line and cell:
1269 if line and cell:
1264 raise UsageError("Can't use statement directly after '%%time'!")
1270 raise UsageError("Can't use statement directly after '%%time'!")
1265
1271
1266 if cell:
1272 if cell:
1267 expr = self.shell.transform_cell(cell)
1273 expr = self.shell.transform_cell(cell)
1268 else:
1274 else:
1269 expr = self.shell.transform_cell(line)
1275 expr = self.shell.transform_cell(line)
1270
1276
1271 # Minimum time above which parse time will be reported
1277 # Minimum time above which parse time will be reported
1272 tp_min = 0.1
1278 tp_min = 0.1
1273
1279
1274 t0 = clock()
1280 t0 = clock()
1275 expr_ast = self.shell.compile.ast_parse(expr)
1281 expr_ast = self.shell.compile.ast_parse(expr)
1276 tp = clock()-t0
1282 tp = clock()-t0
1277
1283
1278 # Apply AST transformations
1284 # Apply AST transformations
1279 expr_ast = self.shell.transform_ast(expr_ast)
1285 expr_ast = self.shell.transform_ast(expr_ast)
1280
1286
1281 # Minimum time above which compilation time will be reported
1287 # Minimum time above which compilation time will be reported
1282 tc_min = 0.1
1288 tc_min = 0.1
1283
1289
1284 expr_val=None
1290 expr_val=None
1285 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
1291 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
1286 mode = 'eval'
1292 mode = 'eval'
1287 source = '<timed eval>'
1293 source = '<timed eval>'
1288 expr_ast = ast.Expression(expr_ast.body[0].value)
1294 expr_ast = ast.Expression(expr_ast.body[0].value)
1289 else:
1295 else:
1290 mode = 'exec'
1296 mode = 'exec'
1291 source = '<timed exec>'
1297 source = '<timed exec>'
1292 # multi-line %%time case
1298 # multi-line %%time case
1293 if len(expr_ast.body) > 1 and isinstance(expr_ast.body[-1], ast.Expr):
1299 if len(expr_ast.body) > 1 and isinstance(expr_ast.body[-1], ast.Expr):
1294 expr_val= expr_ast.body[-1]
1300 expr_val= expr_ast.body[-1]
1295 expr_ast = expr_ast.body[:-1]
1301 expr_ast = expr_ast.body[:-1]
1296 expr_ast = Module(expr_ast, [])
1302 expr_ast = Module(expr_ast, [])
1297 expr_val = ast.Expression(expr_val.value)
1303 expr_val = ast.Expression(expr_val.value)
1298
1304
1299 t0 = clock()
1305 t0 = clock()
1300 code = self.shell.compile(expr_ast, source, mode)
1306 code = self.shell.compile(expr_ast, source, mode)
1301 tc = clock()-t0
1307 tc = clock()-t0
1302
1308
1303 # skew measurement as little as possible
1309 # skew measurement as little as possible
1304 glob = self.shell.user_ns
1310 glob = self.shell.user_ns
1305 wtime = time.time
1311 wtime = time.time
1306 # time execution
1312 # time execution
1307 wall_st = wtime()
1313 wall_st = wtime()
1308 if mode=='eval':
1314 if mode=='eval':
1309 st = clock2()
1315 st = clock2()
1310 try:
1316 try:
1311 out = eval(code, glob, local_ns)
1317 out = eval(code, glob, local_ns)
1312 except:
1318 except:
1313 self.shell.showtraceback()
1319 self.shell.showtraceback()
1314 return
1320 return
1315 end = clock2()
1321 end = clock2()
1316 else:
1322 else:
1317 st = clock2()
1323 st = clock2()
1318 try:
1324 try:
1319 exec(code, glob, local_ns)
1325 exec(code, glob, local_ns)
1320 out=None
1326 out=None
1321 # multi-line %%time case
1327 # multi-line %%time case
1322 if expr_val is not None:
1328 if expr_val is not None:
1323 code_2 = self.shell.compile(expr_val, source, 'eval')
1329 code_2 = self.shell.compile(expr_val, source, 'eval')
1324 out = eval(code_2, glob, local_ns)
1330 out = eval(code_2, glob, local_ns)
1325 except:
1331 except:
1326 self.shell.showtraceback()
1332 self.shell.showtraceback()
1327 return
1333 return
1328 end = clock2()
1334 end = clock2()
1329
1335
1330 wall_end = wtime()
1336 wall_end = wtime()
1331 # Compute actual times and report
1337 # Compute actual times and report
1332 wall_time = wall_end - wall_st
1338 wall_time = wall_end - wall_st
1333 cpu_user = end[0] - st[0]
1339 cpu_user = end[0] - st[0]
1334 cpu_sys = end[1] - st[1]
1340 cpu_sys = end[1] - st[1]
1335 cpu_tot = cpu_user + cpu_sys
1341 cpu_tot = cpu_user + cpu_sys
1336 # On windows cpu_sys is always zero, so only total is displayed
1342 # On windows cpu_sys is always zero, so only total is displayed
1337 if sys.platform != "win32":
1343 if sys.platform != "win32":
1338 print(
1344 print(
1339 f"CPU times: user {_format_time(cpu_user)}, sys: {_format_time(cpu_sys)}, total: {_format_time(cpu_tot)}"
1345 f"CPU times: user {_format_time(cpu_user)}, sys: {_format_time(cpu_sys)}, total: {_format_time(cpu_tot)}"
1340 )
1346 )
1341 else:
1347 else:
1342 print(f"CPU times: total: {_format_time(cpu_tot)}")
1348 print(f"CPU times: total: {_format_time(cpu_tot)}")
1343 print(f"Wall time: {_format_time(wall_time)}")
1349 print(f"Wall time: {_format_time(wall_time)}")
1344 if tc > tc_min:
1350 if tc > tc_min:
1345 print(f"Compiler : {_format_time(tc)}")
1351 print(f"Compiler : {_format_time(tc)}")
1346 if tp > tp_min:
1352 if tp > tp_min:
1347 print(f"Parser : {_format_time(tp)}")
1353 print(f"Parser : {_format_time(tp)}")
1348 return out
1354 return out
1349
1355
1350 @skip_doctest
1356 @skip_doctest
1351 @line_magic
1357 @line_magic
1352 def macro(self, parameter_s=''):
1358 def macro(self, parameter_s=''):
1353 """Define a macro for future re-execution. It accepts ranges of history,
1359 """Define a macro for future re-execution. It accepts ranges of history,
1354 filenames or string objects.
1360 filenames or string objects.
1355
1361
1356 Usage:\\
1362 Usage:\\
1357 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1363 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1358
1364
1359 Options:
1365 Options:
1360
1366
1361 -r: use 'raw' input. By default, the 'processed' history is used,
1367 -r: use 'raw' input. By default, the 'processed' history is used,
1362 so that magics are loaded in their transformed version to valid
1368 so that magics are loaded in their transformed version to valid
1363 Python. If this option is given, the raw input as typed at the
1369 Python. If this option is given, the raw input as typed at the
1364 command line is used instead.
1370 command line is used instead.
1365
1371
1366 -q: quiet macro definition. By default, a tag line is printed
1372 -q: quiet macro definition. By default, a tag line is printed
1367 to indicate the macro has been created, and then the contents of
1373 to indicate the macro has been created, and then the contents of
1368 the macro are printed. If this option is given, then no printout
1374 the macro are printed. If this option is given, then no printout
1369 is produced once the macro is created.
1375 is produced once the macro is created.
1370
1376
1371 This will define a global variable called `name` which is a string
1377 This will define a global variable called `name` which is a string
1372 made of joining the slices and lines you specify (n1,n2,... numbers
1378 made of joining the slices and lines you specify (n1,n2,... numbers
1373 above) from your input history into a single string. This variable
1379 above) from your input history into a single string. This variable
1374 acts like an automatic function which re-executes those lines as if
1380 acts like an automatic function which re-executes those lines as if
1375 you had typed them. You just type 'name' at the prompt and the code
1381 you had typed them. You just type 'name' at the prompt and the code
1376 executes.
1382 executes.
1377
1383
1378 The syntax for indicating input ranges is described in %history.
1384 The syntax for indicating input ranges is described in %history.
1379
1385
1380 Note: as a 'hidden' feature, you can also use traditional python slice
1386 Note: as a 'hidden' feature, you can also use traditional python slice
1381 notation, where N:M means numbers N through M-1.
1387 notation, where N:M means numbers N through M-1.
1382
1388
1383 For example, if your history contains (print using %hist -n )::
1389 For example, if your history contains (print using %hist -n )::
1384
1390
1385 44: x=1
1391 44: x=1
1386 45: y=3
1392 45: y=3
1387 46: z=x+y
1393 46: z=x+y
1388 47: print x
1394 47: print x
1389 48: a=5
1395 48: a=5
1390 49: print 'x',x,'y',y
1396 49: print 'x',x,'y',y
1391
1397
1392 you can create a macro with lines 44 through 47 (included) and line 49
1398 you can create a macro with lines 44 through 47 (included) and line 49
1393 called my_macro with::
1399 called my_macro with::
1394
1400
1395 In [55]: %macro my_macro 44-47 49
1401 In [55]: %macro my_macro 44-47 49
1396
1402
1397 Now, typing `my_macro` (without quotes) will re-execute all this code
1403 Now, typing `my_macro` (without quotes) will re-execute all this code
1398 in one pass.
1404 in one pass.
1399
1405
1400 You don't need to give the line-numbers in order, and any given line
1406 You don't need to give the line-numbers in order, and any given line
1401 number can appear multiple times. You can assemble macros with any
1407 number can appear multiple times. You can assemble macros with any
1402 lines from your input history in any order.
1408 lines from your input history in any order.
1403
1409
1404 The macro is a simple object which holds its value in an attribute,
1410 The macro is a simple object which holds its value in an attribute,
1405 but IPython's display system checks for macros and executes them as
1411 but IPython's display system checks for macros and executes them as
1406 code instead of printing them when you type their name.
1412 code instead of printing them when you type their name.
1407
1413
1408 You can view a macro's contents by explicitly printing it with::
1414 You can view a macro's contents by explicitly printing it with::
1409
1415
1410 print macro_name
1416 print macro_name
1411
1417
1412 """
1418 """
1413 opts,args = self.parse_options(parameter_s,'rq',mode='list')
1419 opts,args = self.parse_options(parameter_s,'rq',mode='list')
1414 if not args: # List existing macros
1420 if not args: # List existing macros
1415 return sorted(k for k,v in self.shell.user_ns.items() if isinstance(v, Macro))
1421 return sorted(k for k,v in self.shell.user_ns.items() if isinstance(v, Macro))
1416 if len(args) == 1:
1422 if len(args) == 1:
1417 raise UsageError(
1423 raise UsageError(
1418 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1424 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1419 name, codefrom = args[0], " ".join(args[1:])
1425 name, codefrom = args[0], " ".join(args[1:])
1420
1426
1421 #print 'rng',ranges # dbg
1427 #print 'rng',ranges # dbg
1422 try:
1428 try:
1423 lines = self.shell.find_user_code(codefrom, 'r' in opts)
1429 lines = self.shell.find_user_code(codefrom, 'r' in opts)
1424 except (ValueError, TypeError) as e:
1430 except (ValueError, TypeError) as e:
1425 print(e.args[0])
1431 print(e.args[0])
1426 return
1432 return
1427 macro = Macro(lines)
1433 macro = Macro(lines)
1428 self.shell.define_macro(name, macro)
1434 self.shell.define_macro(name, macro)
1429 if not ( 'q' in opts) :
1435 if not ( 'q' in opts) :
1430 print('Macro `%s` created. To execute, type its name (without quotes).' % name)
1436 print('Macro `%s` created. To execute, type its name (without quotes).' % name)
1431 print('=== Macro contents: ===')
1437 print('=== Macro contents: ===')
1432 print(macro, end=' ')
1438 print(macro, end=' ')
1433
1439
1434 @magic_arguments.magic_arguments()
1440 @magic_arguments.magic_arguments()
1435 @magic_arguments.argument('output', type=str, default='', nargs='?',
1441 @magic_arguments.argument('output', type=str, default='', nargs='?',
1436 help="""The name of the variable in which to store output.
1442 help="""The name of the variable in which to store output.
1437 This is a utils.io.CapturedIO object with stdout/err attributes
1443 This is a utils.io.CapturedIO object with stdout/err attributes
1438 for the text of the captured output.
1444 for the text of the captured output.
1439
1445
1440 CapturedOutput also has a show() method for displaying the output,
1446 CapturedOutput also has a show() method for displaying the output,
1441 and __call__ as well, so you can use that to quickly display the
1447 and __call__ as well, so you can use that to quickly display the
1442 output.
1448 output.
1443
1449
1444 If unspecified, captured output is discarded.
1450 If unspecified, captured output is discarded.
1445 """
1451 """
1446 )
1452 )
1447 @magic_arguments.argument('--no-stderr', action="store_true",
1453 @magic_arguments.argument('--no-stderr', action="store_true",
1448 help="""Don't capture stderr."""
1454 help="""Don't capture stderr."""
1449 )
1455 )
1450 @magic_arguments.argument('--no-stdout', action="store_true",
1456 @magic_arguments.argument('--no-stdout', action="store_true",
1451 help="""Don't capture stdout."""
1457 help="""Don't capture stdout."""
1452 )
1458 )
1453 @magic_arguments.argument('--no-display', action="store_true",
1459 @magic_arguments.argument('--no-display', action="store_true",
1454 help="""Don't capture IPython's rich display."""
1460 help="""Don't capture IPython's rich display."""
1455 )
1461 )
1456 @cell_magic
1462 @cell_magic
1457 def capture(self, line, cell):
1463 def capture(self, line, cell):
1458 """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1464 """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1459 args = magic_arguments.parse_argstring(self.capture, line)
1465 args = magic_arguments.parse_argstring(self.capture, line)
1460 out = not args.no_stdout
1466 out = not args.no_stdout
1461 err = not args.no_stderr
1467 err = not args.no_stderr
1462 disp = not args.no_display
1468 disp = not args.no_display
1463 with capture_output(out, err, disp) as io:
1469 with capture_output(out, err, disp) as io:
1464 self.shell.run_cell(cell)
1470 self.shell.run_cell(cell)
1465 if DisplayHook.semicolon_at_end_of_expression(cell):
1471 if DisplayHook.semicolon_at_end_of_expression(cell):
1466 if args.output in self.shell.user_ns:
1472 if args.output in self.shell.user_ns:
1467 del self.shell.user_ns[args.output]
1473 del self.shell.user_ns[args.output]
1468 elif args.output:
1474 elif args.output:
1469 self.shell.user_ns[args.output] = io
1475 self.shell.user_ns[args.output] = io
1470
1476
1471 def parse_breakpoint(text, current_file):
1477 def parse_breakpoint(text, current_file):
1472 '''Returns (file, line) for file:line and (current_file, line) for line'''
1478 '''Returns (file, line) for file:line and (current_file, line) for line'''
1473 colon = text.find(':')
1479 colon = text.find(':')
1474 if colon == -1:
1480 if colon == -1:
1475 return current_file, int(text)
1481 return current_file, int(text)
1476 else:
1482 else:
1477 return text[:colon], int(text[colon+1:])
1483 return text[:colon], int(text[colon+1:])
1478
1484
1479 def _format_time(timespan, precision=3):
1485 def _format_time(timespan, precision=3):
1480 """Formats the timespan in a human readable form"""
1486 """Formats the timespan in a human readable form"""
1481
1487
1482 if timespan >= 60.0:
1488 if timespan >= 60.0:
1483 # we have more than a minute, format that in a human readable form
1489 # we have more than a minute, format that in a human readable form
1484 # Idea from http://snipplr.com/view/5713/
1490 # Idea from http://snipplr.com/view/5713/
1485 parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
1491 parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
1486 time = []
1492 time = []
1487 leftover = timespan
1493 leftover = timespan
1488 for suffix, length in parts:
1494 for suffix, length in parts:
1489 value = int(leftover / length)
1495 value = int(leftover / length)
1490 if value > 0:
1496 if value > 0:
1491 leftover = leftover % length
1497 leftover = leftover % length
1492 time.append(u'%s%s' % (str(value), suffix))
1498 time.append(u'%s%s' % (str(value), suffix))
1493 if leftover < 1:
1499 if leftover < 1:
1494 break
1500 break
1495 return " ".join(time)
1501 return " ".join(time)
1496
1502
1497
1503
1498 # Unfortunately the unicode 'micro' symbol can cause problems in
1504 # Unfortunately the unicode 'micro' symbol can cause problems in
1499 # certain terminals.
1505 # certain terminals.
1500 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1506 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1501 # Try to prevent crashes by being more secure than it needs to
1507 # Try to prevent crashes by being more secure than it needs to
1502 # E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set.
1508 # E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set.
1503 units = [u"s", u"ms",u'us',"ns"] # the save value
1509 units = [u"s", u"ms",u'us',"ns"] # the save value
1504 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
1510 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
1505 try:
1511 try:
1506 u'\xb5'.encode(sys.stdout.encoding)
1512 u'\xb5'.encode(sys.stdout.encoding)
1507 units = [u"s", u"ms",u'\xb5s',"ns"]
1513 units = [u"s", u"ms",u'\xb5s',"ns"]
1508 except:
1514 except:
1509 pass
1515 pass
1510 scaling = [1, 1e3, 1e6, 1e9]
1516 scaling = [1, 1e3, 1e6, 1e9]
1511
1517
1512 if timespan > 0.0:
1518 if timespan > 0.0:
1513 order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1519 order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1514 else:
1520 else:
1515 order = 3
1521 order = 3
1516 return u"%.*g %s" % (precision, timespan * scaling[order], units[order])
1522 return u"%.*g %s" % (precision, timespan * scaling[order], units[order])
@@ -1,1080 +1,1093 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tools for inspecting Python objects.
2 """Tools for inspecting Python objects.
3
3
4 Uses syntax highlighting for presenting the various information elements.
4 Uses syntax highlighting for presenting the various information elements.
5
5
6 Similar in spirit to the inspect module, but all calls take a name argument to
6 Similar in spirit to the inspect module, but all calls take a name argument to
7 reference the name under which an object is being read.
7 reference the name under which an object is being read.
8 """
8 """
9
9
10 # Copyright (c) IPython Development Team.
10 # Copyright (c) IPython Development Team.
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12
12
13 __all__ = ['Inspector','InspectColors']
13 __all__ = ['Inspector','InspectColors']
14
14
15 # stdlib modules
15 # stdlib modules
16 import ast
16 import ast
17 import inspect
17 import inspect
18 from inspect import signature
18 from inspect import signature
19 import html
19 import html
20 import linecache
20 import linecache
21 import warnings
21 import warnings
22 import os
22 import os
23 from textwrap import dedent
23 from textwrap import dedent
24 import types
24 import types
25 import io as stdlib_io
25 import io as stdlib_io
26
26
27 from typing import Union
27 from typing import Union
28
28
29 # IPython's own
29 # IPython's own
30 from IPython.core import page
30 from IPython.core import page
31 from IPython.lib.pretty import pretty
31 from IPython.lib.pretty import pretty
32 from IPython.testing.skipdoctest import skip_doctest
32 from IPython.testing.skipdoctest import skip_doctest
33 from IPython.utils import PyColorize
33 from IPython.utils import PyColorize
34 from IPython.utils import openpy
34 from IPython.utils import openpy
35 from IPython.utils.dir2 import safe_hasattr
35 from IPython.utils.dir2 import safe_hasattr
36 from IPython.utils.path import compress_user
36 from IPython.utils.path import compress_user
37 from IPython.utils.text import indent
37 from IPython.utils.text import indent
38 from IPython.utils.wildcard import list_namespace
38 from IPython.utils.wildcard import list_namespace
39 from IPython.utils.wildcard import typestr2type
39 from IPython.utils.wildcard import typestr2type
40 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
40 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
41 from IPython.utils.py3compat import cast_unicode
41 from IPython.utils.py3compat import cast_unicode
42 from IPython.utils.colorable import Colorable
42 from IPython.utils.colorable import Colorable
43 from IPython.utils.decorators import undoc
43 from IPython.utils.decorators import undoc
44
44
45 from pygments import highlight
45 from pygments import highlight
46 from pygments.lexers import PythonLexer
46 from pygments.lexers import PythonLexer
47 from pygments.formatters import HtmlFormatter
47 from pygments.formatters import HtmlFormatter
48
48
49 from typing import Any
50 from dataclasses import dataclass
51
52
53 @dataclass
54 class OInfo:
55 ismagic: bool
56 isalias: bool
57 found: bool
58 namespace: str
59 parent: Any
60 obj: Any
61
49 def pylight(code):
62 def pylight(code):
50 return highlight(code, PythonLexer(), HtmlFormatter(noclasses=True))
63 return highlight(code, PythonLexer(), HtmlFormatter(noclasses=True))
51
64
52 # builtin docstrings to ignore
65 # builtin docstrings to ignore
53 _func_call_docstring = types.FunctionType.__call__.__doc__
66 _func_call_docstring = types.FunctionType.__call__.__doc__
54 _object_init_docstring = object.__init__.__doc__
67 _object_init_docstring = object.__init__.__doc__
55 _builtin_type_docstrings = {
68 _builtin_type_docstrings = {
56 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
69 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
57 types.FunctionType, property)
70 types.FunctionType, property)
58 }
71 }
59
72
60 _builtin_func_type = type(all)
73 _builtin_func_type = type(all)
61 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
74 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
62 #****************************************************************************
75 #****************************************************************************
63 # Builtin color schemes
76 # Builtin color schemes
64
77
65 Colors = TermColors # just a shorthand
78 Colors = TermColors # just a shorthand
66
79
67 InspectColors = PyColorize.ANSICodeColors
80 InspectColors = PyColorize.ANSICodeColors
68
81
69 #****************************************************************************
82 #****************************************************************************
70 # Auxiliary functions and objects
83 # Auxiliary functions and objects
71
84
72 # See the messaging spec for the definition of all these fields. This list
85 # See the messaging spec for the definition of all these fields. This list
73 # effectively defines the order of display
86 # effectively defines the order of display
74 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
87 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
75 'length', 'file', 'definition', 'docstring', 'source',
88 'length', 'file', 'definition', 'docstring', 'source',
76 'init_definition', 'class_docstring', 'init_docstring',
89 'init_definition', 'class_docstring', 'init_docstring',
77 'call_def', 'call_docstring',
90 'call_def', 'call_docstring',
78 # These won't be printed but will be used to determine how to
91 # These won't be printed but will be used to determine how to
79 # format the object
92 # format the object
80 'ismagic', 'isalias', 'isclass', 'found', 'name'
93 'ismagic', 'isalias', 'isclass', 'found', 'name'
81 ]
94 ]
82
95
83
96
84 def object_info(**kw):
97 def object_info(**kw):
85 """Make an object info dict with all fields present."""
98 """Make an object info dict with all fields present."""
86 infodict = {k:None for k in info_fields}
99 infodict = {k:None for k in info_fields}
87 infodict.update(kw)
100 infodict.update(kw)
88 return infodict
101 return infodict
89
102
90
103
91 def get_encoding(obj):
104 def get_encoding(obj):
92 """Get encoding for python source file defining obj
105 """Get encoding for python source file defining obj
93
106
94 Returns None if obj is not defined in a sourcefile.
107 Returns None if obj is not defined in a sourcefile.
95 """
108 """
96 ofile = find_file(obj)
109 ofile = find_file(obj)
97 # run contents of file through pager starting at line where the object
110 # run contents of file through pager starting at line where the object
98 # is defined, as long as the file isn't binary and is actually on the
111 # is defined, as long as the file isn't binary and is actually on the
99 # filesystem.
112 # filesystem.
100 if ofile is None:
113 if ofile is None:
101 return None
114 return None
102 elif ofile.endswith(('.so', '.dll', '.pyd')):
115 elif ofile.endswith(('.so', '.dll', '.pyd')):
103 return None
116 return None
104 elif not os.path.isfile(ofile):
117 elif not os.path.isfile(ofile):
105 return None
118 return None
106 else:
119 else:
107 # Print only text files, not extension binaries. Note that
120 # Print only text files, not extension binaries. Note that
108 # getsourcelines returns lineno with 1-offset and page() uses
121 # getsourcelines returns lineno with 1-offset and page() uses
109 # 0-offset, so we must adjust.
122 # 0-offset, so we must adjust.
110 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
123 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
111 encoding, lines = openpy.detect_encoding(buffer.readline)
124 encoding, lines = openpy.detect_encoding(buffer.readline)
112 return encoding
125 return encoding
113
126
114 def getdoc(obj) -> Union[str,None]:
127 def getdoc(obj) -> Union[str,None]:
115 """Stable wrapper around inspect.getdoc.
128 """Stable wrapper around inspect.getdoc.
116
129
117 This can't crash because of attribute problems.
130 This can't crash because of attribute problems.
118
131
119 It also attempts to call a getdoc() method on the given object. This
132 It also attempts to call a getdoc() method on the given object. This
120 allows objects which provide their docstrings via non-standard mechanisms
133 allows objects which provide their docstrings via non-standard mechanisms
121 (like Pyro proxies) to still be inspected by ipython's ? system.
134 (like Pyro proxies) to still be inspected by ipython's ? system.
122 """
135 """
123 # Allow objects to offer customized documentation via a getdoc method:
136 # Allow objects to offer customized documentation via a getdoc method:
124 try:
137 try:
125 ds = obj.getdoc()
138 ds = obj.getdoc()
126 except Exception:
139 except Exception:
127 pass
140 pass
128 else:
141 else:
129 if isinstance(ds, str):
142 if isinstance(ds, str):
130 return inspect.cleandoc(ds)
143 return inspect.cleandoc(ds)
131 docstr = inspect.getdoc(obj)
144 docstr = inspect.getdoc(obj)
132 return docstr
145 return docstr
133
146
134
147
135 def getsource(obj, oname='') -> Union[str,None]:
148 def getsource(obj, oname='') -> Union[str,None]:
136 """Wrapper around inspect.getsource.
149 """Wrapper around inspect.getsource.
137
150
138 This can be modified by other projects to provide customized source
151 This can be modified by other projects to provide customized source
139 extraction.
152 extraction.
140
153
141 Parameters
154 Parameters
142 ----------
155 ----------
143 obj : object
156 obj : object
144 an object whose source code we will attempt to extract
157 an object whose source code we will attempt to extract
145 oname : str
158 oname : str
146 (optional) a name under which the object is known
159 (optional) a name under which the object is known
147
160
148 Returns
161 Returns
149 -------
162 -------
150 src : unicode or None
163 src : unicode or None
151
164
152 """
165 """
153
166
154 if isinstance(obj, property):
167 if isinstance(obj, property):
155 sources = []
168 sources = []
156 for attrname in ['fget', 'fset', 'fdel']:
169 for attrname in ['fget', 'fset', 'fdel']:
157 fn = getattr(obj, attrname)
170 fn = getattr(obj, attrname)
158 if fn is not None:
171 if fn is not None:
159 encoding = get_encoding(fn)
172 encoding = get_encoding(fn)
160 oname_prefix = ('%s.' % oname) if oname else ''
173 oname_prefix = ('%s.' % oname) if oname else ''
161 sources.append(''.join(('# ', oname_prefix, attrname)))
174 sources.append(''.join(('# ', oname_prefix, attrname)))
162 if inspect.isfunction(fn):
175 if inspect.isfunction(fn):
163 sources.append(dedent(getsource(fn)))
176 sources.append(dedent(getsource(fn)))
164 else:
177 else:
165 # Default str/repr only prints function name,
178 # Default str/repr only prints function name,
166 # pretty.pretty prints module name too.
179 # pretty.pretty prints module name too.
167 sources.append(
180 sources.append(
168 '%s%s = %s\n' % (oname_prefix, attrname, pretty(fn))
181 '%s%s = %s\n' % (oname_prefix, attrname, pretty(fn))
169 )
182 )
170 if sources:
183 if sources:
171 return '\n'.join(sources)
184 return '\n'.join(sources)
172 else:
185 else:
173 return None
186 return None
174
187
175 else:
188 else:
176 # Get source for non-property objects.
189 # Get source for non-property objects.
177
190
178 obj = _get_wrapped(obj)
191 obj = _get_wrapped(obj)
179
192
180 try:
193 try:
181 src = inspect.getsource(obj)
194 src = inspect.getsource(obj)
182 except TypeError:
195 except TypeError:
183 # The object itself provided no meaningful source, try looking for
196 # The object itself provided no meaningful source, try looking for
184 # its class definition instead.
197 # its class definition instead.
185 try:
198 try:
186 src = inspect.getsource(obj.__class__)
199 src = inspect.getsource(obj.__class__)
187 except (OSError, TypeError):
200 except (OSError, TypeError):
188 return None
201 return None
189 except OSError:
202 except OSError:
190 return None
203 return None
191
204
192 return src
205 return src
193
206
194
207
195 def is_simple_callable(obj):
208 def is_simple_callable(obj):
196 """True if obj is a function ()"""
209 """True if obj is a function ()"""
197 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
210 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
198 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
211 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
199
212
200 @undoc
213 @undoc
201 def getargspec(obj):
214 def getargspec(obj):
202 """Wrapper around :func:`inspect.getfullargspec`
215 """Wrapper around :func:`inspect.getfullargspec`
203
216
204 In addition to functions and methods, this can also handle objects with a
217 In addition to functions and methods, this can also handle objects with a
205 ``__call__`` attribute.
218 ``__call__`` attribute.
206
219
207 DEPRECATED: Deprecated since 7.10. Do not use, will be removed.
220 DEPRECATED: Deprecated since 7.10. Do not use, will be removed.
208 """
221 """
209
222
210 warnings.warn('`getargspec` function is deprecated as of IPython 7.10'
223 warnings.warn('`getargspec` function is deprecated as of IPython 7.10'
211 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
224 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
212
225
213 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
226 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
214 obj = obj.__call__
227 obj = obj.__call__
215
228
216 return inspect.getfullargspec(obj)
229 return inspect.getfullargspec(obj)
217
230
218 @undoc
231 @undoc
219 def format_argspec(argspec):
232 def format_argspec(argspec):
220 """Format argspect, convenience wrapper around inspect's.
233 """Format argspect, convenience wrapper around inspect's.
221
234
222 This takes a dict instead of ordered arguments and calls
235 This takes a dict instead of ordered arguments and calls
223 inspect.format_argspec with the arguments in the necessary order.
236 inspect.format_argspec with the arguments in the necessary order.
224
237
225 DEPRECATED (since 7.10): Do not use; will be removed in future versions.
238 DEPRECATED (since 7.10): Do not use; will be removed in future versions.
226 """
239 """
227
240
228 warnings.warn('`format_argspec` function is deprecated as of IPython 7.10'
241 warnings.warn('`format_argspec` function is deprecated as of IPython 7.10'
229 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
242 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
230
243
231
244
232 return inspect.formatargspec(argspec['args'], argspec['varargs'],
245 return inspect.formatargspec(argspec['args'], argspec['varargs'],
233 argspec['varkw'], argspec['defaults'])
246 argspec['varkw'], argspec['defaults'])
234
247
235 @undoc
248 @undoc
236 def call_tip(oinfo, format_call=True):
249 def call_tip(oinfo, format_call=True):
237 """DEPRECATED since 6.0. Extract call tip data from an oinfo dict."""
250 """DEPRECATED since 6.0. Extract call tip data from an oinfo dict."""
238 warnings.warn(
251 warnings.warn(
239 "`call_tip` function is deprecated as of IPython 6.0"
252 "`call_tip` function is deprecated as of IPython 6.0"
240 "and will be removed in future versions.",
253 "and will be removed in future versions.",
241 DeprecationWarning,
254 DeprecationWarning,
242 stacklevel=2,
255 stacklevel=2,
243 )
256 )
244 # Get call definition
257 # Get call definition
245 argspec = oinfo.get('argspec')
258 argspec = oinfo.get('argspec')
246 if argspec is None:
259 if argspec is None:
247 call_line = None
260 call_line = None
248 else:
261 else:
249 # Callable objects will have 'self' as their first argument, prune
262 # Callable objects will have 'self' as their first argument, prune
250 # it out if it's there for clarity (since users do *not* pass an
263 # it out if it's there for clarity (since users do *not* pass an
251 # extra first argument explicitly).
264 # extra first argument explicitly).
252 try:
265 try:
253 has_self = argspec['args'][0] == 'self'
266 has_self = argspec['args'][0] == 'self'
254 except (KeyError, IndexError):
267 except (KeyError, IndexError):
255 pass
268 pass
256 else:
269 else:
257 if has_self:
270 if has_self:
258 argspec['args'] = argspec['args'][1:]
271 argspec['args'] = argspec['args'][1:]
259
272
260 call_line = oinfo['name']+format_argspec(argspec)
273 call_line = oinfo['name']+format_argspec(argspec)
261
274
262 # Now get docstring.
275 # Now get docstring.
263 # The priority is: call docstring, constructor docstring, main one.
276 # The priority is: call docstring, constructor docstring, main one.
264 doc = oinfo.get('call_docstring')
277 doc = oinfo.get('call_docstring')
265 if doc is None:
278 if doc is None:
266 doc = oinfo.get('init_docstring')
279 doc = oinfo.get('init_docstring')
267 if doc is None:
280 if doc is None:
268 doc = oinfo.get('docstring','')
281 doc = oinfo.get('docstring','')
269
282
270 return call_line, doc
283 return call_line, doc
271
284
272
285
273 def _get_wrapped(obj):
286 def _get_wrapped(obj):
274 """Get the original object if wrapped in one or more @decorators
287 """Get the original object if wrapped in one or more @decorators
275
288
276 Some objects automatically construct similar objects on any unrecognised
289 Some objects automatically construct similar objects on any unrecognised
277 attribute access (e.g. unittest.mock.call). To protect against infinite loops,
290 attribute access (e.g. unittest.mock.call). To protect against infinite loops,
278 this will arbitrarily cut off after 100 levels of obj.__wrapped__
291 this will arbitrarily cut off after 100 levels of obj.__wrapped__
279 attribute access. --TK, Jan 2016
292 attribute access. --TK, Jan 2016
280 """
293 """
281 orig_obj = obj
294 orig_obj = obj
282 i = 0
295 i = 0
283 while safe_hasattr(obj, '__wrapped__'):
296 while safe_hasattr(obj, '__wrapped__'):
284 obj = obj.__wrapped__
297 obj = obj.__wrapped__
285 i += 1
298 i += 1
286 if i > 100:
299 if i > 100:
287 # __wrapped__ is probably a lie, so return the thing we started with
300 # __wrapped__ is probably a lie, so return the thing we started with
288 return orig_obj
301 return orig_obj
289 return obj
302 return obj
290
303
291 def find_file(obj) -> str:
304 def find_file(obj) -> str:
292 """Find the absolute path to the file where an object was defined.
305 """Find the absolute path to the file where an object was defined.
293
306
294 This is essentially a robust wrapper around `inspect.getabsfile`.
307 This is essentially a robust wrapper around `inspect.getabsfile`.
295
308
296 Returns None if no file can be found.
309 Returns None if no file can be found.
297
310
298 Parameters
311 Parameters
299 ----------
312 ----------
300 obj : any Python object
313 obj : any Python object
301
314
302 Returns
315 Returns
303 -------
316 -------
304 fname : str
317 fname : str
305 The absolute path to the file where the object was defined.
318 The absolute path to the file where the object was defined.
306 """
319 """
307 obj = _get_wrapped(obj)
320 obj = _get_wrapped(obj)
308
321
309 fname = None
322 fname = None
310 try:
323 try:
311 fname = inspect.getabsfile(obj)
324 fname = inspect.getabsfile(obj)
312 except TypeError:
325 except TypeError:
313 # For an instance, the file that matters is where its class was
326 # For an instance, the file that matters is where its class was
314 # declared.
327 # declared.
315 try:
328 try:
316 fname = inspect.getabsfile(obj.__class__)
329 fname = inspect.getabsfile(obj.__class__)
317 except (OSError, TypeError):
330 except (OSError, TypeError):
318 # Can happen for builtins
331 # Can happen for builtins
319 pass
332 pass
320 except OSError:
333 except OSError:
321 pass
334 pass
322
335
323 return cast_unicode(fname)
336 return cast_unicode(fname)
324
337
325
338
326 def find_source_lines(obj):
339 def find_source_lines(obj):
327 """Find the line number in a file where an object was defined.
340 """Find the line number in a file where an object was defined.
328
341
329 This is essentially a robust wrapper around `inspect.getsourcelines`.
342 This is essentially a robust wrapper around `inspect.getsourcelines`.
330
343
331 Returns None if no file can be found.
344 Returns None if no file can be found.
332
345
333 Parameters
346 Parameters
334 ----------
347 ----------
335 obj : any Python object
348 obj : any Python object
336
349
337 Returns
350 Returns
338 -------
351 -------
339 lineno : int
352 lineno : int
340 The line number where the object definition starts.
353 The line number where the object definition starts.
341 """
354 """
342 obj = _get_wrapped(obj)
355 obj = _get_wrapped(obj)
343
356
344 try:
357 try:
345 lineno = inspect.getsourcelines(obj)[1]
358 lineno = inspect.getsourcelines(obj)[1]
346 except TypeError:
359 except TypeError:
347 # For instances, try the class object like getsource() does
360 # For instances, try the class object like getsource() does
348 try:
361 try:
349 lineno = inspect.getsourcelines(obj.__class__)[1]
362 lineno = inspect.getsourcelines(obj.__class__)[1]
350 except (OSError, TypeError):
363 except (OSError, TypeError):
351 return None
364 return None
352 except OSError:
365 except OSError:
353 return None
366 return None
354
367
355 return lineno
368 return lineno
356
369
357 class Inspector(Colorable):
370 class Inspector(Colorable):
358
371
359 def __init__(self, color_table=InspectColors,
372 def __init__(self, color_table=InspectColors,
360 code_color_table=PyColorize.ANSICodeColors,
373 code_color_table=PyColorize.ANSICodeColors,
361 scheme=None,
374 scheme=None,
362 str_detail_level=0,
375 str_detail_level=0,
363 parent=None, config=None):
376 parent=None, config=None):
364 super(Inspector, self).__init__(parent=parent, config=config)
377 super(Inspector, self).__init__(parent=parent, config=config)
365 self.color_table = color_table
378 self.color_table = color_table
366 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
379 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
367 self.format = self.parser.format
380 self.format = self.parser.format
368 self.str_detail_level = str_detail_level
381 self.str_detail_level = str_detail_level
369 self.set_active_scheme(scheme)
382 self.set_active_scheme(scheme)
370
383
371 def _getdef(self,obj,oname='') -> Union[str,None]:
384 def _getdef(self,obj,oname='') -> Union[str,None]:
372 """Return the call signature for any callable object.
385 """Return the call signature for any callable object.
373
386
374 If any exception is generated, None is returned instead and the
387 If any exception is generated, None is returned instead and the
375 exception is suppressed."""
388 exception is suppressed."""
376 try:
389 try:
377 return _render_signature(signature(obj), oname)
390 return _render_signature(signature(obj), oname)
378 except:
391 except:
379 return None
392 return None
380
393
381 def __head(self,h) -> str:
394 def __head(self,h) -> str:
382 """Return a header string with proper colors."""
395 """Return a header string with proper colors."""
383 return '%s%s%s' % (self.color_table.active_colors.header,h,
396 return '%s%s%s' % (self.color_table.active_colors.header,h,
384 self.color_table.active_colors.normal)
397 self.color_table.active_colors.normal)
385
398
386 def set_active_scheme(self, scheme):
399 def set_active_scheme(self, scheme):
387 if scheme is not None:
400 if scheme is not None:
388 self.color_table.set_active_scheme(scheme)
401 self.color_table.set_active_scheme(scheme)
389 self.parser.color_table.set_active_scheme(scheme)
402 self.parser.color_table.set_active_scheme(scheme)
390
403
391 def noinfo(self, msg, oname):
404 def noinfo(self, msg, oname):
392 """Generic message when no information is found."""
405 """Generic message when no information is found."""
393 print('No %s found' % msg, end=' ')
406 print('No %s found' % msg, end=' ')
394 if oname:
407 if oname:
395 print('for %s' % oname)
408 print('for %s' % oname)
396 else:
409 else:
397 print()
410 print()
398
411
399 def pdef(self, obj, oname=''):
412 def pdef(self, obj, oname=''):
400 """Print the call signature for any callable object.
413 """Print the call signature for any callable object.
401
414
402 If the object is a class, print the constructor information."""
415 If the object is a class, print the constructor information."""
403
416
404 if not callable(obj):
417 if not callable(obj):
405 print('Object is not callable.')
418 print('Object is not callable.')
406 return
419 return
407
420
408 header = ''
421 header = ''
409
422
410 if inspect.isclass(obj):
423 if inspect.isclass(obj):
411 header = self.__head('Class constructor information:\n')
424 header = self.__head('Class constructor information:\n')
412
425
413
426
414 output = self._getdef(obj,oname)
427 output = self._getdef(obj,oname)
415 if output is None:
428 if output is None:
416 self.noinfo('definition header',oname)
429 self.noinfo('definition header',oname)
417 else:
430 else:
418 print(header,self.format(output), end=' ')
431 print(header,self.format(output), end=' ')
419
432
420 # In Python 3, all classes are new-style, so they all have __init__.
433 # In Python 3, all classes are new-style, so they all have __init__.
421 @skip_doctest
434 @skip_doctest
422 def pdoc(self, obj, oname='', formatter=None):
435 def pdoc(self, obj, oname='', formatter=None):
423 """Print the docstring for any object.
436 """Print the docstring for any object.
424
437
425 Optional:
438 Optional:
426 -formatter: a function to run the docstring through for specially
439 -formatter: a function to run the docstring through for specially
427 formatted docstrings.
440 formatted docstrings.
428
441
429 Examples
442 Examples
430 --------
443 --------
431 In [1]: class NoInit:
444 In [1]: class NoInit:
432 ...: pass
445 ...: pass
433
446
434 In [2]: class NoDoc:
447 In [2]: class NoDoc:
435 ...: def __init__(self):
448 ...: def __init__(self):
436 ...: pass
449 ...: pass
437
450
438 In [3]: %pdoc NoDoc
451 In [3]: %pdoc NoDoc
439 No documentation found for NoDoc
452 No documentation found for NoDoc
440
453
441 In [4]: %pdoc NoInit
454 In [4]: %pdoc NoInit
442 No documentation found for NoInit
455 No documentation found for NoInit
443
456
444 In [5]: obj = NoInit()
457 In [5]: obj = NoInit()
445
458
446 In [6]: %pdoc obj
459 In [6]: %pdoc obj
447 No documentation found for obj
460 No documentation found for obj
448
461
449 In [5]: obj2 = NoDoc()
462 In [5]: obj2 = NoDoc()
450
463
451 In [6]: %pdoc obj2
464 In [6]: %pdoc obj2
452 No documentation found for obj2
465 No documentation found for obj2
453 """
466 """
454
467
455 head = self.__head # For convenience
468 head = self.__head # For convenience
456 lines = []
469 lines = []
457 ds = getdoc(obj)
470 ds = getdoc(obj)
458 if formatter:
471 if formatter:
459 ds = formatter(ds).get('plain/text', ds)
472 ds = formatter(ds).get('plain/text', ds)
460 if ds:
473 if ds:
461 lines.append(head("Class docstring:"))
474 lines.append(head("Class docstring:"))
462 lines.append(indent(ds))
475 lines.append(indent(ds))
463 if inspect.isclass(obj) and hasattr(obj, '__init__'):
476 if inspect.isclass(obj) and hasattr(obj, '__init__'):
464 init_ds = getdoc(obj.__init__)
477 init_ds = getdoc(obj.__init__)
465 if init_ds is not None:
478 if init_ds is not None:
466 lines.append(head("Init docstring:"))
479 lines.append(head("Init docstring:"))
467 lines.append(indent(init_ds))
480 lines.append(indent(init_ds))
468 elif hasattr(obj,'__call__'):
481 elif hasattr(obj,'__call__'):
469 call_ds = getdoc(obj.__call__)
482 call_ds = getdoc(obj.__call__)
470 if call_ds:
483 if call_ds:
471 lines.append(head("Call docstring:"))
484 lines.append(head("Call docstring:"))
472 lines.append(indent(call_ds))
485 lines.append(indent(call_ds))
473
486
474 if not lines:
487 if not lines:
475 self.noinfo('documentation',oname)
488 self.noinfo('documentation',oname)
476 else:
489 else:
477 page.page('\n'.join(lines))
490 page.page('\n'.join(lines))
478
491
479 def psource(self, obj, oname=''):
492 def psource(self, obj, oname=''):
480 """Print the source code for an object."""
493 """Print the source code for an object."""
481
494
482 # Flush the source cache because inspect can return out-of-date source
495 # Flush the source cache because inspect can return out-of-date source
483 linecache.checkcache()
496 linecache.checkcache()
484 try:
497 try:
485 src = getsource(obj, oname=oname)
498 src = getsource(obj, oname=oname)
486 except Exception:
499 except Exception:
487 src = None
500 src = None
488
501
489 if src is None:
502 if src is None:
490 self.noinfo('source', oname)
503 self.noinfo('source', oname)
491 else:
504 else:
492 page.page(self.format(src))
505 page.page(self.format(src))
493
506
494 def pfile(self, obj, oname=''):
507 def pfile(self, obj, oname=''):
495 """Show the whole file where an object was defined."""
508 """Show the whole file where an object was defined."""
496
509
497 lineno = find_source_lines(obj)
510 lineno = find_source_lines(obj)
498 if lineno is None:
511 if lineno is None:
499 self.noinfo('file', oname)
512 self.noinfo('file', oname)
500 return
513 return
501
514
502 ofile = find_file(obj)
515 ofile = find_file(obj)
503 # run contents of file through pager starting at line where the object
516 # run contents of file through pager starting at line where the object
504 # is defined, as long as the file isn't binary and is actually on the
517 # is defined, as long as the file isn't binary and is actually on the
505 # filesystem.
518 # filesystem.
506 if ofile.endswith(('.so', '.dll', '.pyd')):
519 if ofile.endswith(('.so', '.dll', '.pyd')):
507 print('File %r is binary, not printing.' % ofile)
520 print('File %r is binary, not printing.' % ofile)
508 elif not os.path.isfile(ofile):
521 elif not os.path.isfile(ofile):
509 print('File %r does not exist, not printing.' % ofile)
522 print('File %r does not exist, not printing.' % ofile)
510 else:
523 else:
511 # Print only text files, not extension binaries. Note that
524 # Print only text files, not extension binaries. Note that
512 # getsourcelines returns lineno with 1-offset and page() uses
525 # getsourcelines returns lineno with 1-offset and page() uses
513 # 0-offset, so we must adjust.
526 # 0-offset, so we must adjust.
514 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
527 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
515
528
516
529
517 def _mime_format(self, text:str, formatter=None) -> dict:
530 def _mime_format(self, text:str, formatter=None) -> dict:
518 """Return a mime bundle representation of the input text.
531 """Return a mime bundle representation of the input text.
519
532
520 - if `formatter` is None, the returned mime bundle has
533 - if `formatter` is None, the returned mime bundle has
521 a ``text/plain`` field, with the input text.
534 a ``text/plain`` field, with the input text.
522 a ``text/html`` field with a ``<pre>`` tag containing the input text.
535 a ``text/html`` field with a ``<pre>`` tag containing the input text.
523
536
524 - if ``formatter`` is not None, it must be a callable transforming the
537 - if ``formatter`` is not None, it must be a callable transforming the
525 input text into a mime bundle. Default values for ``text/plain`` and
538 input text into a mime bundle. Default values for ``text/plain`` and
526 ``text/html`` representations are the ones described above.
539 ``text/html`` representations are the ones described above.
527
540
528 Note:
541 Note:
529
542
530 Formatters returning strings are supported but this behavior is deprecated.
543 Formatters returning strings are supported but this behavior is deprecated.
531
544
532 """
545 """
533 defaults = {
546 defaults = {
534 "text/plain": text,
547 "text/plain": text,
535 "text/html": f"<pre>{html.escape(text)}</pre>",
548 "text/html": f"<pre>{html.escape(text)}</pre>",
536 }
549 }
537
550
538 if formatter is None:
551 if formatter is None:
539 return defaults
552 return defaults
540 else:
553 else:
541 formatted = formatter(text)
554 formatted = formatter(text)
542
555
543 if not isinstance(formatted, dict):
556 if not isinstance(formatted, dict):
544 # Handle the deprecated behavior of a formatter returning
557 # Handle the deprecated behavior of a formatter returning
545 # a string instead of a mime bundle.
558 # a string instead of a mime bundle.
546 return {"text/plain": formatted, "text/html": f"<pre>{formatted}</pre>"}
559 return {"text/plain": formatted, "text/html": f"<pre>{formatted}</pre>"}
547
560
548 else:
561 else:
549 return dict(defaults, **formatted)
562 return dict(defaults, **formatted)
550
563
551
564
552 def format_mime(self, bundle):
565 def format_mime(self, bundle):
553 """Format a mimebundle being created by _make_info_unformatted into a real mimebundle"""
566 """Format a mimebundle being created by _make_info_unformatted into a real mimebundle"""
554 # Format text/plain mimetype
567 # Format text/plain mimetype
555 if isinstance(bundle["text/plain"], (list, tuple)):
568 if isinstance(bundle["text/plain"], (list, tuple)):
556 # bundle['text/plain'] is a list of (head, formatted body) pairs
569 # bundle['text/plain'] is a list of (head, formatted body) pairs
557 lines = []
570 lines = []
558 _len = max(len(h) for h, _ in bundle["text/plain"])
571 _len = max(len(h) for h, _ in bundle["text/plain"])
559
572
560 for head, body in bundle["text/plain"]:
573 for head, body in bundle["text/plain"]:
561 body = body.strip("\n")
574 body = body.strip("\n")
562 delim = "\n" if "\n" in body else " "
575 delim = "\n" if "\n" in body else " "
563 lines.append(
576 lines.append(
564 f"{self.__head(head+':')}{(_len - len(head))*' '}{delim}{body}"
577 f"{self.__head(head+':')}{(_len - len(head))*' '}{delim}{body}"
565 )
578 )
566
579
567 bundle["text/plain"] = "\n".join(lines)
580 bundle["text/plain"] = "\n".join(lines)
568
581
569 # Format the text/html mimetype
582 # Format the text/html mimetype
570 if isinstance(bundle["text/html"], (list, tuple)):
583 if isinstance(bundle["text/html"], (list, tuple)):
571 # bundle['text/html'] is a list of (head, formatted body) pairs
584 # bundle['text/html'] is a list of (head, formatted body) pairs
572 bundle["text/html"] = "\n".join(
585 bundle["text/html"] = "\n".join(
573 (f"<h1>{head}</h1>\n{body}" for (head, body) in bundle["text/html"])
586 (f"<h1>{head}</h1>\n{body}" for (head, body) in bundle["text/html"])
574 )
587 )
575 return bundle
588 return bundle
576
589
577 def _append_info_field(
590 def _append_info_field(
578 self, bundle, title: str, key: str, info, omit_sections, formatter
591 self, bundle, title: str, key: str, info, omit_sections, formatter
579 ):
592 ):
580 """Append an info value to the unformatted mimebundle being constructed by _make_info_unformatted"""
593 """Append an info value to the unformatted mimebundle being constructed by _make_info_unformatted"""
581 if title in omit_sections or key in omit_sections:
594 if title in omit_sections or key in omit_sections:
582 return
595 return
583 field = info[key]
596 field = info[key]
584 if field is not None:
597 if field is not None:
585 formatted_field = self._mime_format(field, formatter)
598 formatted_field = self._mime_format(field, formatter)
586 bundle["text/plain"].append((title, formatted_field["text/plain"]))
599 bundle["text/plain"].append((title, formatted_field["text/plain"]))
587 bundle["text/html"].append((title, formatted_field["text/html"]))
600 bundle["text/html"].append((title, formatted_field["text/html"]))
588
601
589 def _make_info_unformatted(self, obj, info, formatter, detail_level, omit_sections):
602 def _make_info_unformatted(self, obj, info, formatter, detail_level, omit_sections):
590 """Assemble the mimebundle as unformatted lists of information"""
603 """Assemble the mimebundle as unformatted lists of information"""
591 bundle = {
604 bundle = {
592 "text/plain": [],
605 "text/plain": [],
593 "text/html": [],
606 "text/html": [],
594 }
607 }
595
608
596 # A convenience function to simplify calls below
609 # A convenience function to simplify calls below
597 def append_field(bundle, title: str, key: str, formatter=None):
610 def append_field(bundle, title: str, key: str, formatter=None):
598 self._append_info_field(
611 self._append_info_field(
599 bundle,
612 bundle,
600 title=title,
613 title=title,
601 key=key,
614 key=key,
602 info=info,
615 info=info,
603 omit_sections=omit_sections,
616 omit_sections=omit_sections,
604 formatter=formatter,
617 formatter=formatter,
605 )
618 )
606
619
607 def code_formatter(text):
620 def code_formatter(text):
608 return {
621 return {
609 'text/plain': self.format(text),
622 'text/plain': self.format(text),
610 'text/html': pylight(text)
623 'text/html': pylight(text)
611 }
624 }
612
625
613 if info["isalias"]:
626 if info["isalias"]:
614 append_field(bundle, "Repr", "string_form")
627 append_field(bundle, "Repr", "string_form")
615
628
616 elif info['ismagic']:
629 elif info['ismagic']:
617 if detail_level > 0:
630 if detail_level > 0:
618 append_field(bundle, "Source", "source", code_formatter)
631 append_field(bundle, "Source", "source", code_formatter)
619 else:
632 else:
620 append_field(bundle, "Docstring", "docstring", formatter)
633 append_field(bundle, "Docstring", "docstring", formatter)
621 append_field(bundle, "File", "file")
634 append_field(bundle, "File", "file")
622
635
623 elif info['isclass'] or is_simple_callable(obj):
636 elif info['isclass'] or is_simple_callable(obj):
624 # Functions, methods, classes
637 # Functions, methods, classes
625 append_field(bundle, "Signature", "definition", code_formatter)
638 append_field(bundle, "Signature", "definition", code_formatter)
626 append_field(bundle, "Init signature", "init_definition", code_formatter)
639 append_field(bundle, "Init signature", "init_definition", code_formatter)
627 append_field(bundle, "Docstring", "docstring", formatter)
640 append_field(bundle, "Docstring", "docstring", formatter)
628 if detail_level > 0 and info["source"]:
641 if detail_level > 0 and info["source"]:
629 append_field(bundle, "Source", "source", code_formatter)
642 append_field(bundle, "Source", "source", code_formatter)
630 else:
643 else:
631 append_field(bundle, "Init docstring", "init_docstring", formatter)
644 append_field(bundle, "Init docstring", "init_docstring", formatter)
632
645
633 append_field(bundle, "File", "file")
646 append_field(bundle, "File", "file")
634 append_field(bundle, "Type", "type_name")
647 append_field(bundle, "Type", "type_name")
635 append_field(bundle, "Subclasses", "subclasses")
648 append_field(bundle, "Subclasses", "subclasses")
636
649
637 else:
650 else:
638 # General Python objects
651 # General Python objects
639 append_field(bundle, "Signature", "definition", code_formatter)
652 append_field(bundle, "Signature", "definition", code_formatter)
640 append_field(bundle, "Call signature", "call_def", code_formatter)
653 append_field(bundle, "Call signature", "call_def", code_formatter)
641 append_field(bundle, "Type", "type_name")
654 append_field(bundle, "Type", "type_name")
642 append_field(bundle, "String form", "string_form")
655 append_field(bundle, "String form", "string_form")
643
656
644 # Namespace
657 # Namespace
645 if info["namespace"] != "Interactive":
658 if info["namespace"] != "Interactive":
646 append_field(bundle, "Namespace", "namespace")
659 append_field(bundle, "Namespace", "namespace")
647
660
648 append_field(bundle, "Length", "length")
661 append_field(bundle, "Length", "length")
649 append_field(bundle, "File", "file")
662 append_field(bundle, "File", "file")
650
663
651 # Source or docstring, depending on detail level and whether
664 # Source or docstring, depending on detail level and whether
652 # source found.
665 # source found.
653 if detail_level > 0 and info["source"]:
666 if detail_level > 0 and info["source"]:
654 append_field(bundle, "Source", "source", code_formatter)
667 append_field(bundle, "Source", "source", code_formatter)
655 else:
668 else:
656 append_field(bundle, "Docstring", "docstring", formatter)
669 append_field(bundle, "Docstring", "docstring", formatter)
657
670
658 append_field(bundle, "Class docstring", "class_docstring", formatter)
671 append_field(bundle, "Class docstring", "class_docstring", formatter)
659 append_field(bundle, "Init docstring", "init_docstring", formatter)
672 append_field(bundle, "Init docstring", "init_docstring", formatter)
660 append_field(bundle, "Call docstring", "call_docstring", formatter)
673 append_field(bundle, "Call docstring", "call_docstring", formatter)
661 return bundle
674 return bundle
662
675
663
676
664 def _get_info(
677 def _get_info(
665 self, obj, oname="", formatter=None, info=None, detail_level=0, omit_sections=()
678 self, obj, oname="", formatter=None, info=None, detail_level=0, omit_sections=()
666 ):
679 ):
667 """Retrieve an info dict and format it.
680 """Retrieve an info dict and format it.
668
681
669 Parameters
682 Parameters
670 ----------
683 ----------
671 obj : any
684 obj : any
672 Object to inspect and return info from
685 Object to inspect and return info from
673 oname : str (default: ''):
686 oname : str (default: ''):
674 Name of the variable pointing to `obj`.
687 Name of the variable pointing to `obj`.
675 formatter : callable
688 formatter : callable
676 info
689 info
677 already computed information
690 already computed information
678 detail_level : integer
691 detail_level : integer
679 Granularity of detail level, if set to 1, give more information.
692 Granularity of detail level, if set to 1, give more information.
680 omit_sections : container[str]
693 omit_sections : container[str]
681 Titles or keys to omit from output (can be set, tuple, etc., anything supporting `in`)
694 Titles or keys to omit from output (can be set, tuple, etc., anything supporting `in`)
682 """
695 """
683
696
684 info = self.info(obj, oname=oname, info=info, detail_level=detail_level)
697 info = self.info(obj, oname=oname, info=info, detail_level=detail_level)
685 bundle = self._make_info_unformatted(
698 bundle = self._make_info_unformatted(
686 obj, info, formatter, detail_level=detail_level, omit_sections=omit_sections
699 obj, info, formatter, detail_level=detail_level, omit_sections=omit_sections
687 )
700 )
688 return self.format_mime(bundle)
701 return self.format_mime(bundle)
689
702
690 def pinfo(
703 def pinfo(
691 self,
704 self,
692 obj,
705 obj,
693 oname="",
706 oname="",
694 formatter=None,
707 formatter=None,
695 info=None,
708 info=None,
696 detail_level=0,
709 detail_level=0,
697 enable_html_pager=True,
710 enable_html_pager=True,
698 omit_sections=(),
711 omit_sections=(),
699 ):
712 ):
700 """Show detailed information about an object.
713 """Show detailed information about an object.
701
714
702 Optional arguments:
715 Optional arguments:
703
716
704 - oname: name of the variable pointing to the object.
717 - oname: name of the variable pointing to the object.
705
718
706 - formatter: callable (optional)
719 - formatter: callable (optional)
707 A special formatter for docstrings.
720 A special formatter for docstrings.
708
721
709 The formatter is a callable that takes a string as an input
722 The formatter is a callable that takes a string as an input
710 and returns either a formatted string or a mime type bundle
723 and returns either a formatted string or a mime type bundle
711 in the form of a dictionary.
724 in the form of a dictionary.
712
725
713 Although the support of custom formatter returning a string
726 Although the support of custom formatter returning a string
714 instead of a mime type bundle is deprecated.
727 instead of a mime type bundle is deprecated.
715
728
716 - info: a structure with some information fields which may have been
729 - info: a structure with some information fields which may have been
717 precomputed already.
730 precomputed already.
718
731
719 - detail_level: if set to 1, more information is given.
732 - detail_level: if set to 1, more information is given.
720
733
721 - omit_sections: set of section keys and titles to omit
734 - omit_sections: set of section keys and titles to omit
722 """
735 """
723 info = self._get_info(
736 info = self._get_info(
724 obj, oname, formatter, info, detail_level, omit_sections=omit_sections
737 obj, oname, formatter, info, detail_level, omit_sections=omit_sections
725 )
738 )
726 if not enable_html_pager:
739 if not enable_html_pager:
727 del info['text/html']
740 del info['text/html']
728 page.page(info)
741 page.page(info)
729
742
730 def _info(self, obj, oname="", info=None, detail_level=0):
743 def _info(self, obj, oname="", info=None, detail_level=0):
731 """
744 """
732 Inspector.info() was likely improperly marked as deprecated
745 Inspector.info() was likely improperly marked as deprecated
733 while only a parameter was deprecated. We "un-deprecate" it.
746 while only a parameter was deprecated. We "un-deprecate" it.
734 """
747 """
735
748
736 warnings.warn(
749 warnings.warn(
737 "The `Inspector.info()` method has been un-deprecated as of 8.0 "
750 "The `Inspector.info()` method has been un-deprecated as of 8.0 "
738 "and the `formatter=` keyword removed. `Inspector._info` is now "
751 "and the `formatter=` keyword removed. `Inspector._info` is now "
739 "an alias, and you can just call `.info()` directly.",
752 "an alias, and you can just call `.info()` directly.",
740 DeprecationWarning,
753 DeprecationWarning,
741 stacklevel=2,
754 stacklevel=2,
742 )
755 )
743 return self.info(obj, oname=oname, info=info, detail_level=detail_level)
756 return self.info(obj, oname=oname, info=info, detail_level=detail_level)
744
757
745 def info(self, obj, oname="", info=None, detail_level=0) -> dict:
758 def info(self, obj, oname="", info=None, detail_level=0) -> dict:
746 """Compute a dict with detailed information about an object.
759 """Compute a dict with detailed information about an object.
747
760
748 Parameters
761 Parameters
749 ----------
762 ----------
750 obj : any
763 obj : any
751 An object to find information about
764 An object to find information about
752 oname : str (default: '')
765 oname : str (default: '')
753 Name of the variable pointing to `obj`.
766 Name of the variable pointing to `obj`.
754 info : (default: None)
767 info : (default: None)
755 A struct (dict like with attr access) with some information fields
768 A struct (dict like with attr access) with some information fields
756 which may have been precomputed already.
769 which may have been precomputed already.
757 detail_level : int (default:0)
770 detail_level : int (default:0)
758 If set to 1, more information is given.
771 If set to 1, more information is given.
759
772
760 Returns
773 Returns
761 -------
774 -------
762 An object info dict with known fields from `info_fields`. Keys are
775 An object info dict with known fields from `info_fields`. Keys are
763 strings, values are string or None.
776 strings, values are string or None.
764 """
777 """
765
778
766 if info is None:
779 if info is None:
767 ismagic = False
780 ismagic = False
768 isalias = False
781 isalias = False
769 ospace = ''
782 ospace = ''
770 else:
783 else:
771 ismagic = info.ismagic
784 ismagic = info.ismagic
772 isalias = info.isalias
785 isalias = info.isalias
773 ospace = info.namespace
786 ospace = info.namespace
774
787
775 # Get docstring, special-casing aliases:
788 # Get docstring, special-casing aliases:
776 if isalias:
789 if isalias:
777 if not callable(obj):
790 if not callable(obj):
778 try:
791 try:
779 ds = "Alias to the system command:\n %s" % obj[1]
792 ds = "Alias to the system command:\n %s" % obj[1]
780 except:
793 except:
781 ds = "Alias: " + str(obj)
794 ds = "Alias: " + str(obj)
782 else:
795 else:
783 ds = "Alias to " + str(obj)
796 ds = "Alias to " + str(obj)
784 if obj.__doc__:
797 if obj.__doc__:
785 ds += "\nDocstring:\n" + obj.__doc__
798 ds += "\nDocstring:\n" + obj.__doc__
786 else:
799 else:
787 ds = getdoc(obj)
800 ds = getdoc(obj)
788 if ds is None:
801 if ds is None:
789 ds = '<no docstring>'
802 ds = '<no docstring>'
790
803
791 # store output in a dict, we initialize it here and fill it as we go
804 # store output in a dict, we initialize it here and fill it as we go
792 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic, subclasses=None)
805 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic, subclasses=None)
793
806
794 string_max = 200 # max size of strings to show (snipped if longer)
807 string_max = 200 # max size of strings to show (snipped if longer)
795 shalf = int((string_max - 5) / 2)
808 shalf = int((string_max - 5) / 2)
796
809
797 if ismagic:
810 if ismagic:
798 out['type_name'] = 'Magic function'
811 out['type_name'] = 'Magic function'
799 elif isalias:
812 elif isalias:
800 out['type_name'] = 'System alias'
813 out['type_name'] = 'System alias'
801 else:
814 else:
802 out['type_name'] = type(obj).__name__
815 out['type_name'] = type(obj).__name__
803
816
804 try:
817 try:
805 bclass = obj.__class__
818 bclass = obj.__class__
806 out['base_class'] = str(bclass)
819 out['base_class'] = str(bclass)
807 except:
820 except:
808 pass
821 pass
809
822
810 # String form, but snip if too long in ? form (full in ??)
823 # String form, but snip if too long in ? form (full in ??)
811 if detail_level >= self.str_detail_level:
824 if detail_level >= self.str_detail_level:
812 try:
825 try:
813 ostr = str(obj)
826 ostr = str(obj)
814 str_head = 'string_form'
827 str_head = 'string_form'
815 if not detail_level and len(ostr)>string_max:
828 if not detail_level and len(ostr)>string_max:
816 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
829 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
817 ostr = ("\n" + " " * len(str_head.expandtabs())).\
830 ostr = ("\n" + " " * len(str_head.expandtabs())).\
818 join(q.strip() for q in ostr.split("\n"))
831 join(q.strip() for q in ostr.split("\n"))
819 out[str_head] = ostr
832 out[str_head] = ostr
820 except:
833 except:
821 pass
834 pass
822
835
823 if ospace:
836 if ospace:
824 out['namespace'] = ospace
837 out['namespace'] = ospace
825
838
826 # Length (for strings and lists)
839 # Length (for strings and lists)
827 try:
840 try:
828 out['length'] = str(len(obj))
841 out['length'] = str(len(obj))
829 except Exception:
842 except Exception:
830 pass
843 pass
831
844
832 # Filename where object was defined
845 # Filename where object was defined
833 binary_file = False
846 binary_file = False
834 fname = find_file(obj)
847 fname = find_file(obj)
835 if fname is None:
848 if fname is None:
836 # if anything goes wrong, we don't want to show source, so it's as
849 # if anything goes wrong, we don't want to show source, so it's as
837 # if the file was binary
850 # if the file was binary
838 binary_file = True
851 binary_file = True
839 else:
852 else:
840 if fname.endswith(('.so', '.dll', '.pyd')):
853 if fname.endswith(('.so', '.dll', '.pyd')):
841 binary_file = True
854 binary_file = True
842 elif fname.endswith('<string>'):
855 elif fname.endswith('<string>'):
843 fname = 'Dynamically generated function. No source code available.'
856 fname = 'Dynamically generated function. No source code available.'
844 out['file'] = compress_user(fname)
857 out['file'] = compress_user(fname)
845
858
846 # Original source code for a callable, class or property.
859 # Original source code for a callable, class or property.
847 if detail_level:
860 if detail_level:
848 # Flush the source cache because inspect can return out-of-date
861 # Flush the source cache because inspect can return out-of-date
849 # source
862 # source
850 linecache.checkcache()
863 linecache.checkcache()
851 try:
864 try:
852 if isinstance(obj, property) or not binary_file:
865 if isinstance(obj, property) or not binary_file:
853 src = getsource(obj, oname)
866 src = getsource(obj, oname)
854 if src is not None:
867 if src is not None:
855 src = src.rstrip()
868 src = src.rstrip()
856 out['source'] = src
869 out['source'] = src
857
870
858 except Exception:
871 except Exception:
859 pass
872 pass
860
873
861 # Add docstring only if no source is to be shown (avoid repetitions).
874 # Add docstring only if no source is to be shown (avoid repetitions).
862 if ds and not self._source_contains_docstring(out.get('source'), ds):
875 if ds and not self._source_contains_docstring(out.get('source'), ds):
863 out['docstring'] = ds
876 out['docstring'] = ds
864
877
865 # Constructor docstring for classes
878 # Constructor docstring for classes
866 if inspect.isclass(obj):
879 if inspect.isclass(obj):
867 out['isclass'] = True
880 out['isclass'] = True
868
881
869 # get the init signature:
882 # get the init signature:
870 try:
883 try:
871 init_def = self._getdef(obj, oname)
884 init_def = self._getdef(obj, oname)
872 except AttributeError:
885 except AttributeError:
873 init_def = None
886 init_def = None
874
887
875 # get the __init__ docstring
888 # get the __init__ docstring
876 try:
889 try:
877 obj_init = obj.__init__
890 obj_init = obj.__init__
878 except AttributeError:
891 except AttributeError:
879 init_ds = None
892 init_ds = None
880 else:
893 else:
881 if init_def is None:
894 if init_def is None:
882 # Get signature from init if top-level sig failed.
895 # Get signature from init if top-level sig failed.
883 # Can happen for built-in types (list, etc.).
896 # Can happen for built-in types (list, etc.).
884 try:
897 try:
885 init_def = self._getdef(obj_init, oname)
898 init_def = self._getdef(obj_init, oname)
886 except AttributeError:
899 except AttributeError:
887 pass
900 pass
888 init_ds = getdoc(obj_init)
901 init_ds = getdoc(obj_init)
889 # Skip Python's auto-generated docstrings
902 # Skip Python's auto-generated docstrings
890 if init_ds == _object_init_docstring:
903 if init_ds == _object_init_docstring:
891 init_ds = None
904 init_ds = None
892
905
893 if init_def:
906 if init_def:
894 out['init_definition'] = init_def
907 out['init_definition'] = init_def
895
908
896 if init_ds:
909 if init_ds:
897 out['init_docstring'] = init_ds
910 out['init_docstring'] = init_ds
898
911
899 names = [sub.__name__ for sub in type.__subclasses__(obj)]
912 names = [sub.__name__ for sub in type.__subclasses__(obj)]
900 if len(names) < 10:
913 if len(names) < 10:
901 all_names = ', '.join(names)
914 all_names = ', '.join(names)
902 else:
915 else:
903 all_names = ', '.join(names[:10]+['...'])
916 all_names = ', '.join(names[:10]+['...'])
904 out['subclasses'] = all_names
917 out['subclasses'] = all_names
905 # and class docstring for instances:
918 # and class docstring for instances:
906 else:
919 else:
907 # reconstruct the function definition and print it:
920 # reconstruct the function definition and print it:
908 defln = self._getdef(obj, oname)
921 defln = self._getdef(obj, oname)
909 if defln:
922 if defln:
910 out['definition'] = defln
923 out['definition'] = defln
911
924
912 # First, check whether the instance docstring is identical to the
925 # First, check whether the instance docstring is identical to the
913 # class one, and print it separately if they don't coincide. In
926 # class one, and print it separately if they don't coincide. In
914 # most cases they will, but it's nice to print all the info for
927 # most cases they will, but it's nice to print all the info for
915 # objects which use instance-customized docstrings.
928 # objects which use instance-customized docstrings.
916 if ds:
929 if ds:
917 try:
930 try:
918 cls = getattr(obj,'__class__')
931 cls = getattr(obj,'__class__')
919 except:
932 except:
920 class_ds = None
933 class_ds = None
921 else:
934 else:
922 class_ds = getdoc(cls)
935 class_ds = getdoc(cls)
923 # Skip Python's auto-generated docstrings
936 # Skip Python's auto-generated docstrings
924 if class_ds in _builtin_type_docstrings:
937 if class_ds in _builtin_type_docstrings:
925 class_ds = None
938 class_ds = None
926 if class_ds and ds != class_ds:
939 if class_ds and ds != class_ds:
927 out['class_docstring'] = class_ds
940 out['class_docstring'] = class_ds
928
941
929 # Next, try to show constructor docstrings
942 # Next, try to show constructor docstrings
930 try:
943 try:
931 init_ds = getdoc(obj.__init__)
944 init_ds = getdoc(obj.__init__)
932 # Skip Python's auto-generated docstrings
945 # Skip Python's auto-generated docstrings
933 if init_ds == _object_init_docstring:
946 if init_ds == _object_init_docstring:
934 init_ds = None
947 init_ds = None
935 except AttributeError:
948 except AttributeError:
936 init_ds = None
949 init_ds = None
937 if init_ds:
950 if init_ds:
938 out['init_docstring'] = init_ds
951 out['init_docstring'] = init_ds
939
952
940 # Call form docstring for callable instances
953 # Call form docstring for callable instances
941 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
954 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
942 call_def = self._getdef(obj.__call__, oname)
955 call_def = self._getdef(obj.__call__, oname)
943 if call_def and (call_def != out.get('definition')):
956 if call_def and (call_def != out.get('definition')):
944 # it may never be the case that call def and definition differ,
957 # it may never be the case that call def and definition differ,
945 # but don't include the same signature twice
958 # but don't include the same signature twice
946 out['call_def'] = call_def
959 out['call_def'] = call_def
947 call_ds = getdoc(obj.__call__)
960 call_ds = getdoc(obj.__call__)
948 # Skip Python's auto-generated docstrings
961 # Skip Python's auto-generated docstrings
949 if call_ds == _func_call_docstring:
962 if call_ds == _func_call_docstring:
950 call_ds = None
963 call_ds = None
951 if call_ds:
964 if call_ds:
952 out['call_docstring'] = call_ds
965 out['call_docstring'] = call_ds
953
966
954 return object_info(**out)
967 return object_info(**out)
955
968
956 @staticmethod
969 @staticmethod
957 def _source_contains_docstring(src, doc):
970 def _source_contains_docstring(src, doc):
958 """
971 """
959 Check whether the source *src* contains the docstring *doc*.
972 Check whether the source *src* contains the docstring *doc*.
960
973
961 This is is helper function to skip displaying the docstring if the
974 This is is helper function to skip displaying the docstring if the
962 source already contains it, avoiding repetition of information.
975 source already contains it, avoiding repetition of information.
963 """
976 """
964 try:
977 try:
965 def_node, = ast.parse(dedent(src)).body
978 def_node, = ast.parse(dedent(src)).body
966 return ast.get_docstring(def_node) == doc
979 return ast.get_docstring(def_node) == doc
967 except Exception:
980 except Exception:
968 # The source can become invalid or even non-existent (because it
981 # The source can become invalid or even non-existent (because it
969 # is re-fetched from the source file) so the above code fail in
982 # is re-fetched from the source file) so the above code fail in
970 # arbitrary ways.
983 # arbitrary ways.
971 return False
984 return False
972
985
973 def psearch(self,pattern,ns_table,ns_search=[],
986 def psearch(self,pattern,ns_table,ns_search=[],
974 ignore_case=False,show_all=False, *, list_types=False):
987 ignore_case=False,show_all=False, *, list_types=False):
975 """Search namespaces with wildcards for objects.
988 """Search namespaces with wildcards for objects.
976
989
977 Arguments:
990 Arguments:
978
991
979 - pattern: string containing shell-like wildcards to use in namespace
992 - pattern: string containing shell-like wildcards to use in namespace
980 searches and optionally a type specification to narrow the search to
993 searches and optionally a type specification to narrow the search to
981 objects of that type.
994 objects of that type.
982
995
983 - ns_table: dict of name->namespaces for search.
996 - ns_table: dict of name->namespaces for search.
984
997
985 Optional arguments:
998 Optional arguments:
986
999
987 - ns_search: list of namespace names to include in search.
1000 - ns_search: list of namespace names to include in search.
988
1001
989 - ignore_case(False): make the search case-insensitive.
1002 - ignore_case(False): make the search case-insensitive.
990
1003
991 - show_all(False): show all names, including those starting with
1004 - show_all(False): show all names, including those starting with
992 underscores.
1005 underscores.
993
1006
994 - list_types(False): list all available object types for object matching.
1007 - list_types(False): list all available object types for object matching.
995 """
1008 """
996 #print 'ps pattern:<%r>' % pattern # dbg
1009 #print 'ps pattern:<%r>' % pattern # dbg
997
1010
998 # defaults
1011 # defaults
999 type_pattern = 'all'
1012 type_pattern = 'all'
1000 filter = ''
1013 filter = ''
1001
1014
1002 # list all object types
1015 # list all object types
1003 if list_types:
1016 if list_types:
1004 page.page('\n'.join(sorted(typestr2type)))
1017 page.page('\n'.join(sorted(typestr2type)))
1005 return
1018 return
1006
1019
1007 cmds = pattern.split()
1020 cmds = pattern.split()
1008 len_cmds = len(cmds)
1021 len_cmds = len(cmds)
1009 if len_cmds == 1:
1022 if len_cmds == 1:
1010 # Only filter pattern given
1023 # Only filter pattern given
1011 filter = cmds[0]
1024 filter = cmds[0]
1012 elif len_cmds == 2:
1025 elif len_cmds == 2:
1013 # Both filter and type specified
1026 # Both filter and type specified
1014 filter,type_pattern = cmds
1027 filter,type_pattern = cmds
1015 else:
1028 else:
1016 raise ValueError('invalid argument string for psearch: <%s>' %
1029 raise ValueError('invalid argument string for psearch: <%s>' %
1017 pattern)
1030 pattern)
1018
1031
1019 # filter search namespaces
1032 # filter search namespaces
1020 for name in ns_search:
1033 for name in ns_search:
1021 if name not in ns_table:
1034 if name not in ns_table:
1022 raise ValueError('invalid namespace <%s>. Valid names: %s' %
1035 raise ValueError('invalid namespace <%s>. Valid names: %s' %
1023 (name,ns_table.keys()))
1036 (name,ns_table.keys()))
1024
1037
1025 #print 'type_pattern:',type_pattern # dbg
1038 #print 'type_pattern:',type_pattern # dbg
1026 search_result, namespaces_seen = set(), set()
1039 search_result, namespaces_seen = set(), set()
1027 for ns_name in ns_search:
1040 for ns_name in ns_search:
1028 ns = ns_table[ns_name]
1041 ns = ns_table[ns_name]
1029 # Normally, locals and globals are the same, so we just check one.
1042 # Normally, locals and globals are the same, so we just check one.
1030 if id(ns) in namespaces_seen:
1043 if id(ns) in namespaces_seen:
1031 continue
1044 continue
1032 namespaces_seen.add(id(ns))
1045 namespaces_seen.add(id(ns))
1033 tmp_res = list_namespace(ns, type_pattern, filter,
1046 tmp_res = list_namespace(ns, type_pattern, filter,
1034 ignore_case=ignore_case, show_all=show_all)
1047 ignore_case=ignore_case, show_all=show_all)
1035 search_result.update(tmp_res)
1048 search_result.update(tmp_res)
1036
1049
1037 page.page('\n'.join(sorted(search_result)))
1050 page.page('\n'.join(sorted(search_result)))
1038
1051
1039
1052
1040 def _render_signature(obj_signature, obj_name) -> str:
1053 def _render_signature(obj_signature, obj_name) -> str:
1041 """
1054 """
1042 This was mostly taken from inspect.Signature.__str__.
1055 This was mostly taken from inspect.Signature.__str__.
1043 Look there for the comments.
1056 Look there for the comments.
1044 The only change is to add linebreaks when this gets too long.
1057 The only change is to add linebreaks when this gets too long.
1045 """
1058 """
1046 result = []
1059 result = []
1047 pos_only = False
1060 pos_only = False
1048 kw_only = True
1061 kw_only = True
1049 for param in obj_signature.parameters.values():
1062 for param in obj_signature.parameters.values():
1050 if param.kind == inspect._POSITIONAL_ONLY:
1063 if param.kind == inspect._POSITIONAL_ONLY:
1051 pos_only = True
1064 pos_only = True
1052 elif pos_only:
1065 elif pos_only:
1053 result.append('/')
1066 result.append('/')
1054 pos_only = False
1067 pos_only = False
1055
1068
1056 if param.kind == inspect._VAR_POSITIONAL:
1069 if param.kind == inspect._VAR_POSITIONAL:
1057 kw_only = False
1070 kw_only = False
1058 elif param.kind == inspect._KEYWORD_ONLY and kw_only:
1071 elif param.kind == inspect._KEYWORD_ONLY and kw_only:
1059 result.append('*')
1072 result.append('*')
1060 kw_only = False
1073 kw_only = False
1061
1074
1062 result.append(str(param))
1075 result.append(str(param))
1063
1076
1064 if pos_only:
1077 if pos_only:
1065 result.append('/')
1078 result.append('/')
1066
1079
1067 # add up name, parameters, braces (2), and commas
1080 # add up name, parameters, braces (2), and commas
1068 if len(obj_name) + sum(len(r) + 2 for r in result) > 75:
1081 if len(obj_name) + sum(len(r) + 2 for r in result) > 75:
1069 # This doesn’t fit behind “Signature: ” in an inspect window.
1082 # This doesn’t fit behind “Signature: ” in an inspect window.
1070 rendered = '{}(\n{})'.format(obj_name, ''.join(
1083 rendered = '{}(\n{})'.format(obj_name, ''.join(
1071 ' {},\n'.format(r) for r in result)
1084 ' {},\n'.format(r) for r in result)
1072 )
1085 )
1073 else:
1086 else:
1074 rendered = '{}({})'.format(obj_name, ', '.join(result))
1087 rendered = '{}({})'.format(obj_name, ', '.join(result))
1075
1088
1076 if obj_signature.return_annotation is not inspect._empty:
1089 if obj_signature.return_annotation is not inspect._empty:
1077 anno = inspect.formatannotation(obj_signature.return_annotation)
1090 anno = inspect.formatannotation(obj_signature.return_annotation)
1078 rendered += ' -> {}'.format(anno)
1091 rendered += ' -> {}'.format(anno)
1079
1092
1080 return rendered
1093 return rendered
@@ -1,698 +1,700 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Prefiltering components.
3 Prefiltering components.
4
4
5 Prefilters transform user input before it is exec'd by Python. These
5 Prefilters transform user input before it is exec'd by Python. These
6 transforms are used to implement additional syntax such as !ls and %magic.
6 transforms are used to implement additional syntax such as !ls and %magic.
7 """
7 """
8
8
9 # Copyright (c) IPython Development Team.
9 # Copyright (c) IPython Development Team.
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11
11
12 from keyword import iskeyword
12 from keyword import iskeyword
13 import re
13 import re
14
14
15 from .autocall import IPyAutocall
15 from .autocall import IPyAutocall
16 from traitlets.config.configurable import Configurable
16 from traitlets.config.configurable import Configurable
17 from .inputtransformer2 import (
17 from .inputtransformer2 import (
18 ESC_MAGIC,
18 ESC_MAGIC,
19 ESC_QUOTE,
19 ESC_QUOTE,
20 ESC_QUOTE2,
20 ESC_QUOTE2,
21 ESC_PAREN,
21 ESC_PAREN,
22 )
22 )
23 from .macro import Macro
23 from .macro import Macro
24 from .splitinput import LineInfo
24 from .splitinput import LineInfo
25
25
26 from traitlets import (
26 from traitlets import (
27 List, Integer, Unicode, Bool, Instance, CRegExp
27 List, Integer, Unicode, Bool, Instance, CRegExp
28 )
28 )
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Global utilities, errors and constants
31 # Global utilities, errors and constants
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34
34
35 class PrefilterError(Exception):
35 class PrefilterError(Exception):
36 pass
36 pass
37
37
38
38
39 # RegExp to identify potential function names
39 # RegExp to identify potential function names
40 re_fun_name = re.compile(r'[^\W\d]([\w.]*) *$')
40 re_fun_name = re.compile(r'[^\W\d]([\w.]*) *$')
41
41
42 # RegExp to exclude strings with this start from autocalling. In
42 # RegExp to exclude strings with this start from autocalling. In
43 # particular, all binary operators should be excluded, so that if foo is
43 # particular, all binary operators should be excluded, so that if foo is
44 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
44 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
45 # characters '!=()' don't need to be checked for, as the checkPythonChars
45 # characters '!=()' don't need to be checked for, as the checkPythonChars
46 # routine explicitly does so, to catch direct calls and rebindings of
46 # routine explicitly does so, to catch direct calls and rebindings of
47 # existing names.
47 # existing names.
48
48
49 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
49 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
50 # it affects the rest of the group in square brackets.
50 # it affects the rest of the group in square brackets.
51 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
51 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
52 r'|^is |^not |^in |^and |^or ')
52 r'|^is |^not |^in |^and |^or ')
53
53
54 # try to catch also methods for stuff in lists/tuples/dicts: off
54 # try to catch also methods for stuff in lists/tuples/dicts: off
55 # (experimental). For this to work, the line_split regexp would need
55 # (experimental). For this to work, the line_split regexp would need
56 # to be modified so it wouldn't break things at '['. That line is
56 # to be modified so it wouldn't break things at '['. That line is
57 # nasty enough that I shouldn't change it until I can test it _well_.
57 # nasty enough that I shouldn't change it until I can test it _well_.
58 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
58 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
59
59
60
60
61 # Handler Check Utilities
61 # Handler Check Utilities
62 def is_shadowed(identifier, ip):
62 def is_shadowed(identifier, ip):
63 """Is the given identifier defined in one of the namespaces which shadow
63 """Is the given identifier defined in one of the namespaces which shadow
64 the alias and magic namespaces? Note that an identifier is different
64 the alias and magic namespaces? Note that an identifier is different
65 than ifun, because it can not contain a '.' character."""
65 than ifun, because it can not contain a '.' character."""
66 # This is much safer than calling ofind, which can change state
66 # This is much safer than calling ofind, which can change state
67 return (identifier in ip.user_ns \
67 return (identifier in ip.user_ns \
68 or identifier in ip.user_global_ns \
68 or identifier in ip.user_global_ns \
69 or identifier in ip.ns_table['builtin']\
69 or identifier in ip.ns_table['builtin']\
70 or iskeyword(identifier))
70 or iskeyword(identifier))
71
71
72
72
73 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
74 # Main Prefilter manager
74 # Main Prefilter manager
75 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
76
76
77
77
78 class PrefilterManager(Configurable):
78 class PrefilterManager(Configurable):
79 """Main prefilter component.
79 """Main prefilter component.
80
80
81 The IPython prefilter is run on all user input before it is run. The
81 The IPython prefilter is run on all user input before it is run. The
82 prefilter consumes lines of input and produces transformed lines of
82 prefilter consumes lines of input and produces transformed lines of
83 input.
83 input.
84
84
85 The implementation consists of two phases:
85 The implementation consists of two phases:
86
86
87 1. Transformers
87 1. Transformers
88 2. Checkers and handlers
88 2. Checkers and handlers
89
89
90 Over time, we plan on deprecating the checkers and handlers and doing
90 Over time, we plan on deprecating the checkers and handlers and doing
91 everything in the transformers.
91 everything in the transformers.
92
92
93 The transformers are instances of :class:`PrefilterTransformer` and have
93 The transformers are instances of :class:`PrefilterTransformer` and have
94 a single method :meth:`transform` that takes a line and returns a
94 a single method :meth:`transform` that takes a line and returns a
95 transformed line. The transformation can be accomplished using any
95 transformed line. The transformation can be accomplished using any
96 tool, but our current ones use regular expressions for speed.
96 tool, but our current ones use regular expressions for speed.
97
97
98 After all the transformers have been run, the line is fed to the checkers,
98 After all the transformers have been run, the line is fed to the checkers,
99 which are instances of :class:`PrefilterChecker`. The line is passed to
99 which are instances of :class:`PrefilterChecker`. The line is passed to
100 the :meth:`check` method, which either returns `None` or a
100 the :meth:`check` method, which either returns `None` or a
101 :class:`PrefilterHandler` instance. If `None` is returned, the other
101 :class:`PrefilterHandler` instance. If `None` is returned, the other
102 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
102 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
103 the line is passed to the :meth:`handle` method of the returned
103 the line is passed to the :meth:`handle` method of the returned
104 handler and no further checkers are tried.
104 handler and no further checkers are tried.
105
105
106 Both transformers and checkers have a `priority` attribute, that determines
106 Both transformers and checkers have a `priority` attribute, that determines
107 the order in which they are called. Smaller priorities are tried first.
107 the order in which they are called. Smaller priorities are tried first.
108
108
109 Both transformers and checkers also have `enabled` attribute, which is
109 Both transformers and checkers also have `enabled` attribute, which is
110 a boolean that determines if the instance is used.
110 a boolean that determines if the instance is used.
111
111
112 Users or developers can change the priority or enabled attribute of
112 Users or developers can change the priority or enabled attribute of
113 transformers or checkers, but they must call the :meth:`sort_checkers`
113 transformers or checkers, but they must call the :meth:`sort_checkers`
114 or :meth:`sort_transformers` method after changing the priority.
114 or :meth:`sort_transformers` method after changing the priority.
115 """
115 """
116
116
117 multi_line_specials = Bool(True).tag(config=True)
117 multi_line_specials = Bool(True).tag(config=True)
118 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
118 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
119
119
120 def __init__(self, shell=None, **kwargs):
120 def __init__(self, shell=None, **kwargs):
121 super(PrefilterManager, self).__init__(shell=shell, **kwargs)
121 super(PrefilterManager, self).__init__(shell=shell, **kwargs)
122 self.shell = shell
122 self.shell = shell
123 self._transformers = []
123 self._transformers = []
124 self.init_handlers()
124 self.init_handlers()
125 self.init_checkers()
125 self.init_checkers()
126
126
127 #-------------------------------------------------------------------------
127 #-------------------------------------------------------------------------
128 # API for managing transformers
128 # API for managing transformers
129 #-------------------------------------------------------------------------
129 #-------------------------------------------------------------------------
130
130
131 def sort_transformers(self):
131 def sort_transformers(self):
132 """Sort the transformers by priority.
132 """Sort the transformers by priority.
133
133
134 This must be called after the priority of a transformer is changed.
134 This must be called after the priority of a transformer is changed.
135 The :meth:`register_transformer` method calls this automatically.
135 The :meth:`register_transformer` method calls this automatically.
136 """
136 """
137 self._transformers.sort(key=lambda x: x.priority)
137 self._transformers.sort(key=lambda x: x.priority)
138
138
139 @property
139 @property
140 def transformers(self):
140 def transformers(self):
141 """Return a list of checkers, sorted by priority."""
141 """Return a list of checkers, sorted by priority."""
142 return self._transformers
142 return self._transformers
143
143
144 def register_transformer(self, transformer):
144 def register_transformer(self, transformer):
145 """Register a transformer instance."""
145 """Register a transformer instance."""
146 if transformer not in self._transformers:
146 if transformer not in self._transformers:
147 self._transformers.append(transformer)
147 self._transformers.append(transformer)
148 self.sort_transformers()
148 self.sort_transformers()
149
149
150 def unregister_transformer(self, transformer):
150 def unregister_transformer(self, transformer):
151 """Unregister a transformer instance."""
151 """Unregister a transformer instance."""
152 if transformer in self._transformers:
152 if transformer in self._transformers:
153 self._transformers.remove(transformer)
153 self._transformers.remove(transformer)
154
154
155 #-------------------------------------------------------------------------
155 #-------------------------------------------------------------------------
156 # API for managing checkers
156 # API for managing checkers
157 #-------------------------------------------------------------------------
157 #-------------------------------------------------------------------------
158
158
159 def init_checkers(self):
159 def init_checkers(self):
160 """Create the default checkers."""
160 """Create the default checkers."""
161 self._checkers = []
161 self._checkers = []
162 for checker in _default_checkers:
162 for checker in _default_checkers:
163 checker(
163 checker(
164 shell=self.shell, prefilter_manager=self, parent=self
164 shell=self.shell, prefilter_manager=self, parent=self
165 )
165 )
166
166
167 def sort_checkers(self):
167 def sort_checkers(self):
168 """Sort the checkers by priority.
168 """Sort the checkers by priority.
169
169
170 This must be called after the priority of a checker is changed.
170 This must be called after the priority of a checker is changed.
171 The :meth:`register_checker` method calls this automatically.
171 The :meth:`register_checker` method calls this automatically.
172 """
172 """
173 self._checkers.sort(key=lambda x: x.priority)
173 self._checkers.sort(key=lambda x: x.priority)
174
174
175 @property
175 @property
176 def checkers(self):
176 def checkers(self):
177 """Return a list of checkers, sorted by priority."""
177 """Return a list of checkers, sorted by priority."""
178 return self._checkers
178 return self._checkers
179
179
180 def register_checker(self, checker):
180 def register_checker(self, checker):
181 """Register a checker instance."""
181 """Register a checker instance."""
182 if checker not in self._checkers:
182 if checker not in self._checkers:
183 self._checkers.append(checker)
183 self._checkers.append(checker)
184 self.sort_checkers()
184 self.sort_checkers()
185
185
186 def unregister_checker(self, checker):
186 def unregister_checker(self, checker):
187 """Unregister a checker instance."""
187 """Unregister a checker instance."""
188 if checker in self._checkers:
188 if checker in self._checkers:
189 self._checkers.remove(checker)
189 self._checkers.remove(checker)
190
190
191 #-------------------------------------------------------------------------
191 #-------------------------------------------------------------------------
192 # API for managing handlers
192 # API for managing handlers
193 #-------------------------------------------------------------------------
193 #-------------------------------------------------------------------------
194
194
195 def init_handlers(self):
195 def init_handlers(self):
196 """Create the default handlers."""
196 """Create the default handlers."""
197 self._handlers = {}
197 self._handlers = {}
198 self._esc_handlers = {}
198 self._esc_handlers = {}
199 for handler in _default_handlers:
199 for handler in _default_handlers:
200 handler(
200 handler(
201 shell=self.shell, prefilter_manager=self, parent=self
201 shell=self.shell, prefilter_manager=self, parent=self
202 )
202 )
203
203
204 @property
204 @property
205 def handlers(self):
205 def handlers(self):
206 """Return a dict of all the handlers."""
206 """Return a dict of all the handlers."""
207 return self._handlers
207 return self._handlers
208
208
209 def register_handler(self, name, handler, esc_strings):
209 def register_handler(self, name, handler, esc_strings):
210 """Register a handler instance by name with esc_strings."""
210 """Register a handler instance by name with esc_strings."""
211 self._handlers[name] = handler
211 self._handlers[name] = handler
212 for esc_str in esc_strings:
212 for esc_str in esc_strings:
213 self._esc_handlers[esc_str] = handler
213 self._esc_handlers[esc_str] = handler
214
214
215 def unregister_handler(self, name, handler, esc_strings):
215 def unregister_handler(self, name, handler, esc_strings):
216 """Unregister a handler instance by name with esc_strings."""
216 """Unregister a handler instance by name with esc_strings."""
217 try:
217 try:
218 del self._handlers[name]
218 del self._handlers[name]
219 except KeyError:
219 except KeyError:
220 pass
220 pass
221 for esc_str in esc_strings:
221 for esc_str in esc_strings:
222 h = self._esc_handlers.get(esc_str)
222 h = self._esc_handlers.get(esc_str)
223 if h is handler:
223 if h is handler:
224 del self._esc_handlers[esc_str]
224 del self._esc_handlers[esc_str]
225
225
226 def get_handler_by_name(self, name):
226 def get_handler_by_name(self, name):
227 """Get a handler by its name."""
227 """Get a handler by its name."""
228 return self._handlers.get(name)
228 return self._handlers.get(name)
229
229
230 def get_handler_by_esc(self, esc_str):
230 def get_handler_by_esc(self, esc_str):
231 """Get a handler by its escape string."""
231 """Get a handler by its escape string."""
232 return self._esc_handlers.get(esc_str)
232 return self._esc_handlers.get(esc_str)
233
233
234 #-------------------------------------------------------------------------
234 #-------------------------------------------------------------------------
235 # Main prefiltering API
235 # Main prefiltering API
236 #-------------------------------------------------------------------------
236 #-------------------------------------------------------------------------
237
237
238 def prefilter_line_info(self, line_info):
238 def prefilter_line_info(self, line_info):
239 """Prefilter a line that has been converted to a LineInfo object.
239 """Prefilter a line that has been converted to a LineInfo object.
240
240
241 This implements the checker/handler part of the prefilter pipe.
241 This implements the checker/handler part of the prefilter pipe.
242 """
242 """
243 # print "prefilter_line_info: ", line_info
243 # print "prefilter_line_info: ", line_info
244 handler = self.find_handler(line_info)
244 handler = self.find_handler(line_info)
245 return handler.handle(line_info)
245 return handler.handle(line_info)
246
246
247 def find_handler(self, line_info):
247 def find_handler(self, line_info):
248 """Find a handler for the line_info by trying checkers."""
248 """Find a handler for the line_info by trying checkers."""
249 for checker in self.checkers:
249 for checker in self.checkers:
250 if checker.enabled:
250 if checker.enabled:
251 handler = checker.check(line_info)
251 handler = checker.check(line_info)
252 if handler:
252 if handler:
253 return handler
253 return handler
254 return self.get_handler_by_name('normal')
254 return self.get_handler_by_name('normal')
255
255
256 def transform_line(self, line, continue_prompt):
256 def transform_line(self, line, continue_prompt):
257 """Calls the enabled transformers in order of increasing priority."""
257 """Calls the enabled transformers in order of increasing priority."""
258 for transformer in self.transformers:
258 for transformer in self.transformers:
259 if transformer.enabled:
259 if transformer.enabled:
260 line = transformer.transform(line, continue_prompt)
260 line = transformer.transform(line, continue_prompt)
261 return line
261 return line
262
262
263 def prefilter_line(self, line, continue_prompt=False):
263 def prefilter_line(self, line, continue_prompt=False):
264 """Prefilter a single input line as text.
264 """Prefilter a single input line as text.
265
265
266 This method prefilters a single line of text by calling the
266 This method prefilters a single line of text by calling the
267 transformers and then the checkers/handlers.
267 transformers and then the checkers/handlers.
268 """
268 """
269
269
270 # print "prefilter_line: ", line, continue_prompt
270 # print "prefilter_line: ", line, continue_prompt
271 # All handlers *must* return a value, even if it's blank ('').
271 # All handlers *must* return a value, even if it's blank ('').
272
272
273 # save the line away in case we crash, so the post-mortem handler can
273 # save the line away in case we crash, so the post-mortem handler can
274 # record it
274 # record it
275 self.shell._last_input_line = line
275 self.shell._last_input_line = line
276
276
277 if not line:
277 if not line:
278 # Return immediately on purely empty lines, so that if the user
278 # Return immediately on purely empty lines, so that if the user
279 # previously typed some whitespace that started a continuation
279 # previously typed some whitespace that started a continuation
280 # prompt, he can break out of that loop with just an empty line.
280 # prompt, he can break out of that loop with just an empty line.
281 # This is how the default python prompt works.
281 # This is how the default python prompt works.
282 return ''
282 return ''
283
283
284 # At this point, we invoke our transformers.
284 # At this point, we invoke our transformers.
285 if not continue_prompt or (continue_prompt and self.multi_line_specials):
285 if not continue_prompt or (continue_prompt and self.multi_line_specials):
286 line = self.transform_line(line, continue_prompt)
286 line = self.transform_line(line, continue_prompt)
287
287
288 # Now we compute line_info for the checkers and handlers
288 # Now we compute line_info for the checkers and handlers
289 line_info = LineInfo(line, continue_prompt)
289 line_info = LineInfo(line, continue_prompt)
290
290
291 # the input history needs to track even empty lines
291 # the input history needs to track even empty lines
292 stripped = line.strip()
292 stripped = line.strip()
293
293
294 normal_handler = self.get_handler_by_name('normal')
294 normal_handler = self.get_handler_by_name('normal')
295 if not stripped:
295 if not stripped:
296 return normal_handler.handle(line_info)
296 return normal_handler.handle(line_info)
297
297
298 # special handlers are only allowed for single line statements
298 # special handlers are only allowed for single line statements
299 if continue_prompt and not self.multi_line_specials:
299 if continue_prompt and not self.multi_line_specials:
300 return normal_handler.handle(line_info)
300 return normal_handler.handle(line_info)
301
301
302 prefiltered = self.prefilter_line_info(line_info)
302 prefiltered = self.prefilter_line_info(line_info)
303 # print "prefiltered line: %r" % prefiltered
303 # print "prefiltered line: %r" % prefiltered
304 return prefiltered
304 return prefiltered
305
305
306 def prefilter_lines(self, lines, continue_prompt=False):
306 def prefilter_lines(self, lines, continue_prompt=False):
307 """Prefilter multiple input lines of text.
307 """Prefilter multiple input lines of text.
308
308
309 This is the main entry point for prefiltering multiple lines of
309 This is the main entry point for prefiltering multiple lines of
310 input. This simply calls :meth:`prefilter_line` for each line of
310 input. This simply calls :meth:`prefilter_line` for each line of
311 input.
311 input.
312
312
313 This covers cases where there are multiple lines in the user entry,
313 This covers cases where there are multiple lines in the user entry,
314 which is the case when the user goes back to a multiline history
314 which is the case when the user goes back to a multiline history
315 entry and presses enter.
315 entry and presses enter.
316 """
316 """
317 llines = lines.rstrip('\n').split('\n')
317 llines = lines.rstrip('\n').split('\n')
318 # We can get multiple lines in one shot, where multiline input 'blends'
318 # We can get multiple lines in one shot, where multiline input 'blends'
319 # into one line, in cases like recalling from the readline history
319 # into one line, in cases like recalling from the readline history
320 # buffer. We need to make sure that in such cases, we correctly
320 # buffer. We need to make sure that in such cases, we correctly
321 # communicate downstream which line is first and which are continuation
321 # communicate downstream which line is first and which are continuation
322 # ones.
322 # ones.
323 if len(llines) > 1:
323 if len(llines) > 1:
324 out = '\n'.join([self.prefilter_line(line, lnum>0)
324 out = '\n'.join([self.prefilter_line(line, lnum>0)
325 for lnum, line in enumerate(llines) ])
325 for lnum, line in enumerate(llines) ])
326 else:
326 else:
327 out = self.prefilter_line(llines[0], continue_prompt)
327 out = self.prefilter_line(llines[0], continue_prompt)
328
328
329 return out
329 return out
330
330
331 #-----------------------------------------------------------------------------
331 #-----------------------------------------------------------------------------
332 # Prefilter transformers
332 # Prefilter transformers
333 #-----------------------------------------------------------------------------
333 #-----------------------------------------------------------------------------
334
334
335
335
336 class PrefilterTransformer(Configurable):
336 class PrefilterTransformer(Configurable):
337 """Transform a line of user input."""
337 """Transform a line of user input."""
338
338
339 priority = Integer(100).tag(config=True)
339 priority = Integer(100).tag(config=True)
340 # Transformers don't currently use shell or prefilter_manager, but as we
340 # Transformers don't currently use shell or prefilter_manager, but as we
341 # move away from checkers and handlers, they will need them.
341 # move away from checkers and handlers, they will need them.
342 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
342 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
343 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
343 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
344 enabled = Bool(True).tag(config=True)
344 enabled = Bool(True).tag(config=True)
345
345
346 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
346 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
347 super(PrefilterTransformer, self).__init__(
347 super(PrefilterTransformer, self).__init__(
348 shell=shell, prefilter_manager=prefilter_manager, **kwargs
348 shell=shell, prefilter_manager=prefilter_manager, **kwargs
349 )
349 )
350 self.prefilter_manager.register_transformer(self)
350 self.prefilter_manager.register_transformer(self)
351
351
352 def transform(self, line, continue_prompt):
352 def transform(self, line, continue_prompt):
353 """Transform a line, returning the new one."""
353 """Transform a line, returning the new one."""
354 return None
354 return None
355
355
356 def __repr__(self):
356 def __repr__(self):
357 return "<%s(priority=%r, enabled=%r)>" % (
357 return "<%s(priority=%r, enabled=%r)>" % (
358 self.__class__.__name__, self.priority, self.enabled)
358 self.__class__.__name__, self.priority, self.enabled)
359
359
360
360
361 #-----------------------------------------------------------------------------
361 #-----------------------------------------------------------------------------
362 # Prefilter checkers
362 # Prefilter checkers
363 #-----------------------------------------------------------------------------
363 #-----------------------------------------------------------------------------
364
364
365
365
366 class PrefilterChecker(Configurable):
366 class PrefilterChecker(Configurable):
367 """Inspect an input line and return a handler for that line."""
367 """Inspect an input line and return a handler for that line."""
368
368
369 priority = Integer(100).tag(config=True)
369 priority = Integer(100).tag(config=True)
370 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
370 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
371 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
371 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
372 enabled = Bool(True).tag(config=True)
372 enabled = Bool(True).tag(config=True)
373
373
374 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
374 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
375 super(PrefilterChecker, self).__init__(
375 super(PrefilterChecker, self).__init__(
376 shell=shell, prefilter_manager=prefilter_manager, **kwargs
376 shell=shell, prefilter_manager=prefilter_manager, **kwargs
377 )
377 )
378 self.prefilter_manager.register_checker(self)
378 self.prefilter_manager.register_checker(self)
379
379
380 def check(self, line_info):
380 def check(self, line_info):
381 """Inspect line_info and return a handler instance or None."""
381 """Inspect line_info and return a handler instance or None."""
382 return None
382 return None
383
383
384 def __repr__(self):
384 def __repr__(self):
385 return "<%s(priority=%r, enabled=%r)>" % (
385 return "<%s(priority=%r, enabled=%r)>" % (
386 self.__class__.__name__, self.priority, self.enabled)
386 self.__class__.__name__, self.priority, self.enabled)
387
387
388
388
389 class EmacsChecker(PrefilterChecker):
389 class EmacsChecker(PrefilterChecker):
390
390
391 priority = Integer(100).tag(config=True)
391 priority = Integer(100).tag(config=True)
392 enabled = Bool(False).tag(config=True)
392 enabled = Bool(False).tag(config=True)
393
393
394 def check(self, line_info):
394 def check(self, line_info):
395 "Emacs ipython-mode tags certain input lines."
395 "Emacs ipython-mode tags certain input lines."
396 if line_info.line.endswith('# PYTHON-MODE'):
396 if line_info.line.endswith('# PYTHON-MODE'):
397 return self.prefilter_manager.get_handler_by_name('emacs')
397 return self.prefilter_manager.get_handler_by_name('emacs')
398 else:
398 else:
399 return None
399 return None
400
400
401
401
402 class MacroChecker(PrefilterChecker):
402 class MacroChecker(PrefilterChecker):
403
403
404 priority = Integer(250).tag(config=True)
404 priority = Integer(250).tag(config=True)
405
405
406 def check(self, line_info):
406 def check(self, line_info):
407 obj = self.shell.user_ns.get(line_info.ifun)
407 obj = self.shell.user_ns.get(line_info.ifun)
408 if isinstance(obj, Macro):
408 if isinstance(obj, Macro):
409 return self.prefilter_manager.get_handler_by_name('macro')
409 return self.prefilter_manager.get_handler_by_name('macro')
410 else:
410 else:
411 return None
411 return None
412
412
413
413
414 class IPyAutocallChecker(PrefilterChecker):
414 class IPyAutocallChecker(PrefilterChecker):
415
415
416 priority = Integer(300).tag(config=True)
416 priority = Integer(300).tag(config=True)
417
417
418 def check(self, line_info):
418 def check(self, line_info):
419 "Instances of IPyAutocall in user_ns get autocalled immediately"
419 "Instances of IPyAutocall in user_ns get autocalled immediately"
420 obj = self.shell.user_ns.get(line_info.ifun, None)
420 obj = self.shell.user_ns.get(line_info.ifun, None)
421 if isinstance(obj, IPyAutocall):
421 if isinstance(obj, IPyAutocall):
422 obj.set_ip(self.shell)
422 obj.set_ip(self.shell)
423 return self.prefilter_manager.get_handler_by_name('auto')
423 return self.prefilter_manager.get_handler_by_name('auto')
424 else:
424 else:
425 return None
425 return None
426
426
427
427
428 class AssignmentChecker(PrefilterChecker):
428 class AssignmentChecker(PrefilterChecker):
429
429
430 priority = Integer(600).tag(config=True)
430 priority = Integer(600).tag(config=True)
431
431
432 def check(self, line_info):
432 def check(self, line_info):
433 """Check to see if user is assigning to a var for the first time, in
433 """Check to see if user is assigning to a var for the first time, in
434 which case we want to avoid any sort of automagic / autocall games.
434 which case we want to avoid any sort of automagic / autocall games.
435
435
436 This allows users to assign to either alias or magic names true python
436 This allows users to assign to either alias or magic names true python
437 variables (the magic/alias systems always take second seat to true
437 variables (the magic/alias systems always take second seat to true
438 python code). E.g. ls='hi', or ls,that=1,2"""
438 python code). E.g. ls='hi', or ls,that=1,2"""
439 if line_info.the_rest:
439 if line_info.the_rest:
440 if line_info.the_rest[0] in '=,':
440 if line_info.the_rest[0] in '=,':
441 return self.prefilter_manager.get_handler_by_name('normal')
441 return self.prefilter_manager.get_handler_by_name('normal')
442 else:
442 else:
443 return None
443 return None
444
444
445
445
446 class AutoMagicChecker(PrefilterChecker):
446 class AutoMagicChecker(PrefilterChecker):
447
447
448 priority = Integer(700).tag(config=True)
448 priority = Integer(700).tag(config=True)
449
449
450 def check(self, line_info):
450 def check(self, line_info):
451 """If the ifun is magic, and automagic is on, run it. Note: normal,
451 """If the ifun is magic, and automagic is on, run it. Note: normal,
452 non-auto magic would already have been triggered via '%' in
452 non-auto magic would already have been triggered via '%' in
453 check_esc_chars. This just checks for automagic. Also, before
453 check_esc_chars. This just checks for automagic. Also, before
454 triggering the magic handler, make sure that there is nothing in the
454 triggering the magic handler, make sure that there is nothing in the
455 user namespace which could shadow it."""
455 user namespace which could shadow it."""
456 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
456 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
457 return None
457 return None
458
458
459 # We have a likely magic method. Make sure we should actually call it.
459 # We have a likely magic method. Make sure we should actually call it.
460 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
460 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
461 return None
461 return None
462
462
463 head = line_info.ifun.split('.',1)[0]
463 head = line_info.ifun.split('.',1)[0]
464 if is_shadowed(head, self.shell):
464 if is_shadowed(head, self.shell):
465 return None
465 return None
466
466
467 return self.prefilter_manager.get_handler_by_name('magic')
467 return self.prefilter_manager.get_handler_by_name('magic')
468
468
469
469
470 class PythonOpsChecker(PrefilterChecker):
470 class PythonOpsChecker(PrefilterChecker):
471
471
472 priority = Integer(900).tag(config=True)
472 priority = Integer(900).tag(config=True)
473
473
474 def check(self, line_info):
474 def check(self, line_info):
475 """If the 'rest' of the line begins with a function call or pretty much
475 """If the 'rest' of the line begins with a function call or pretty much
476 any python operator, we should simply execute the line (regardless of
476 any python operator, we should simply execute the line (regardless of
477 whether or not there's a possible autocall expansion). This avoids
477 whether or not there's a possible autocall expansion). This avoids
478 spurious (and very confusing) geattr() accesses."""
478 spurious (and very confusing) geattr() accesses."""
479 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
479 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
480 return self.prefilter_manager.get_handler_by_name('normal')
480 return self.prefilter_manager.get_handler_by_name('normal')
481 else:
481 else:
482 return None
482 return None
483
483
484
484
485 class AutocallChecker(PrefilterChecker):
485 class AutocallChecker(PrefilterChecker):
486
486
487 priority = Integer(1000).tag(config=True)
487 priority = Integer(1000).tag(config=True)
488
488
489 function_name_regexp = CRegExp(re_fun_name,
489 function_name_regexp = CRegExp(re_fun_name,
490 help="RegExp to identify potential function names."
490 help="RegExp to identify potential function names."
491 ).tag(config=True)
491 ).tag(config=True)
492 exclude_regexp = CRegExp(re_exclude_auto,
492 exclude_regexp = CRegExp(re_exclude_auto,
493 help="RegExp to exclude strings with this start from autocalling."
493 help="RegExp to exclude strings with this start from autocalling."
494 ).tag(config=True)
494 ).tag(config=True)
495
495
496 def check(self, line_info):
496 def check(self, line_info):
497 "Check if the initial word/function is callable and autocall is on."
497 "Check if the initial word/function is callable and autocall is on."
498 if not self.shell.autocall:
498 if not self.shell.autocall:
499 return None
499 return None
500
500
501 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
501 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
502 if not oinfo['found']:
502 if not oinfo.found:
503 return None
503 return None
504
504
505 ignored_funs = ['b', 'f', 'r', 'u', 'br', 'rb', 'fr', 'rf']
505 ignored_funs = ['b', 'f', 'r', 'u', 'br', 'rb', 'fr', 'rf']
506 ifun = line_info.ifun
506 ifun = line_info.ifun
507 line = line_info.line
507 line = line_info.line
508 if ifun.lower() in ignored_funs and (line.startswith(ifun + "'") or line.startswith(ifun + '"')):
508 if ifun.lower() in ignored_funs and (line.startswith(ifun + "'") or line.startswith(ifun + '"')):
509 return None
509 return None
510
510
511 if callable(oinfo['obj']) \
511 if (
512 and (not self.exclude_regexp.match(line_info.the_rest)) \
512 callable(oinfo.obj)
513 and self.function_name_regexp.match(line_info.ifun):
513 and (not self.exclude_regexp.match(line_info.the_rest))
514 return self.prefilter_manager.get_handler_by_name('auto')
514 and self.function_name_regexp.match(line_info.ifun)
515 ):
516 return self.prefilter_manager.get_handler_by_name("auto")
515 else:
517 else:
516 return None
518 return None
517
519
518
520
519 #-----------------------------------------------------------------------------
521 #-----------------------------------------------------------------------------
520 # Prefilter handlers
522 # Prefilter handlers
521 #-----------------------------------------------------------------------------
523 #-----------------------------------------------------------------------------
522
524
523
525
524 class PrefilterHandler(Configurable):
526 class PrefilterHandler(Configurable):
525
527
526 handler_name = Unicode('normal')
528 handler_name = Unicode('normal')
527 esc_strings = List([])
529 esc_strings = List([])
528 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
530 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
529 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
531 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
530
532
531 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
533 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
532 super(PrefilterHandler, self).__init__(
534 super(PrefilterHandler, self).__init__(
533 shell=shell, prefilter_manager=prefilter_manager, **kwargs
535 shell=shell, prefilter_manager=prefilter_manager, **kwargs
534 )
536 )
535 self.prefilter_manager.register_handler(
537 self.prefilter_manager.register_handler(
536 self.handler_name,
538 self.handler_name,
537 self,
539 self,
538 self.esc_strings
540 self.esc_strings
539 )
541 )
540
542
541 def handle(self, line_info):
543 def handle(self, line_info):
542 # print "normal: ", line_info
544 # print "normal: ", line_info
543 """Handle normal input lines. Use as a template for handlers."""
545 """Handle normal input lines. Use as a template for handlers."""
544
546
545 # With autoindent on, we need some way to exit the input loop, and I
547 # With autoindent on, we need some way to exit the input loop, and I
546 # don't want to force the user to have to backspace all the way to
548 # don't want to force the user to have to backspace all the way to
547 # clear the line. The rule will be in this case, that either two
549 # clear the line. The rule will be in this case, that either two
548 # lines of pure whitespace in a row, or a line of pure whitespace but
550 # lines of pure whitespace in a row, or a line of pure whitespace but
549 # of a size different to the indent level, will exit the input loop.
551 # of a size different to the indent level, will exit the input loop.
550 line = line_info.line
552 line = line_info.line
551 continue_prompt = line_info.continue_prompt
553 continue_prompt = line_info.continue_prompt
552
554
553 if (continue_prompt and
555 if (continue_prompt and
554 self.shell.autoindent and
556 self.shell.autoindent and
555 line.isspace() and
557 line.isspace() and
556 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
558 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
557 line = ''
559 line = ''
558
560
559 return line
561 return line
560
562
561 def __str__(self):
563 def __str__(self):
562 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
564 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
563
565
564
566
565 class MacroHandler(PrefilterHandler):
567 class MacroHandler(PrefilterHandler):
566 handler_name = Unicode("macro")
568 handler_name = Unicode("macro")
567
569
568 def handle(self, line_info):
570 def handle(self, line_info):
569 obj = self.shell.user_ns.get(line_info.ifun)
571 obj = self.shell.user_ns.get(line_info.ifun)
570 pre_space = line_info.pre_whitespace
572 pre_space = line_info.pre_whitespace
571 line_sep = "\n" + pre_space
573 line_sep = "\n" + pre_space
572 return pre_space + line_sep.join(obj.value.splitlines())
574 return pre_space + line_sep.join(obj.value.splitlines())
573
575
574
576
575 class MagicHandler(PrefilterHandler):
577 class MagicHandler(PrefilterHandler):
576
578
577 handler_name = Unicode('magic')
579 handler_name = Unicode('magic')
578 esc_strings = List([ESC_MAGIC])
580 esc_strings = List([ESC_MAGIC])
579
581
580 def handle(self, line_info):
582 def handle(self, line_info):
581 """Execute magic functions."""
583 """Execute magic functions."""
582 ifun = line_info.ifun
584 ifun = line_info.ifun
583 the_rest = line_info.the_rest
585 the_rest = line_info.the_rest
584 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
586 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
585 t_arg_s = ifun + " " + the_rest
587 t_arg_s = ifun + " " + the_rest
586 t_magic_name, _, t_magic_arg_s = t_arg_s.partition(' ')
588 t_magic_name, _, t_magic_arg_s = t_arg_s.partition(' ')
587 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
589 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
588 cmd = '%sget_ipython().run_line_magic(%r, %r)' % (line_info.pre_whitespace, t_magic_name, t_magic_arg_s)
590 cmd = '%sget_ipython().run_line_magic(%r, %r)' % (line_info.pre_whitespace, t_magic_name, t_magic_arg_s)
589 return cmd
591 return cmd
590
592
591
593
592 class AutoHandler(PrefilterHandler):
594 class AutoHandler(PrefilterHandler):
593
595
594 handler_name = Unicode('auto')
596 handler_name = Unicode('auto')
595 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
597 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
596
598
597 def handle(self, line_info):
599 def handle(self, line_info):
598 """Handle lines which can be auto-executed, quoting if requested."""
600 """Handle lines which can be auto-executed, quoting if requested."""
599 line = line_info.line
601 line = line_info.line
600 ifun = line_info.ifun
602 ifun = line_info.ifun
601 the_rest = line_info.the_rest
603 the_rest = line_info.the_rest
602 esc = line_info.esc
604 esc = line_info.esc
603 continue_prompt = line_info.continue_prompt
605 continue_prompt = line_info.continue_prompt
604 obj = line_info.ofind(self.shell)['obj']
606 obj = line_info.ofind(self.shell).obj
605
607
606 # This should only be active for single-line input!
608 # This should only be active for single-line input!
607 if continue_prompt:
609 if continue_prompt:
608 return line
610 return line
609
611
610 force_auto = isinstance(obj, IPyAutocall)
612 force_auto = isinstance(obj, IPyAutocall)
611
613
612 # User objects sometimes raise exceptions on attribute access other
614 # User objects sometimes raise exceptions on attribute access other
613 # than AttributeError (we've seen it in the past), so it's safest to be
615 # than AttributeError (we've seen it in the past), so it's safest to be
614 # ultra-conservative here and catch all.
616 # ultra-conservative here and catch all.
615 try:
617 try:
616 auto_rewrite = obj.rewrite
618 auto_rewrite = obj.rewrite
617 except Exception:
619 except Exception:
618 auto_rewrite = True
620 auto_rewrite = True
619
621
620 if esc == ESC_QUOTE:
622 if esc == ESC_QUOTE:
621 # Auto-quote splitting on whitespace
623 # Auto-quote splitting on whitespace
622 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
624 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
623 elif esc == ESC_QUOTE2:
625 elif esc == ESC_QUOTE2:
624 # Auto-quote whole string
626 # Auto-quote whole string
625 newcmd = '%s("%s")' % (ifun,the_rest)
627 newcmd = '%s("%s")' % (ifun,the_rest)
626 elif esc == ESC_PAREN:
628 elif esc == ESC_PAREN:
627 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
629 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
628 else:
630 else:
629 # Auto-paren.
631 # Auto-paren.
630 if force_auto:
632 if force_auto:
631 # Don't rewrite if it is already a call.
633 # Don't rewrite if it is already a call.
632 do_rewrite = not the_rest.startswith('(')
634 do_rewrite = not the_rest.startswith('(')
633 else:
635 else:
634 if not the_rest:
636 if not the_rest:
635 # We only apply it to argument-less calls if the autocall
637 # We only apply it to argument-less calls if the autocall
636 # parameter is set to 2.
638 # parameter is set to 2.
637 do_rewrite = (self.shell.autocall >= 2)
639 do_rewrite = (self.shell.autocall >= 2)
638 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
640 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
639 # Don't autocall in this case: item access for an object
641 # Don't autocall in this case: item access for an object
640 # which is BOTH callable and implements __getitem__.
642 # which is BOTH callable and implements __getitem__.
641 do_rewrite = False
643 do_rewrite = False
642 else:
644 else:
643 do_rewrite = True
645 do_rewrite = True
644
646
645 # Figure out the rewritten command
647 # Figure out the rewritten command
646 if do_rewrite:
648 if do_rewrite:
647 if the_rest.endswith(';'):
649 if the_rest.endswith(';'):
648 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
650 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
649 else:
651 else:
650 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
652 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
651 else:
653 else:
652 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
654 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
653 return normal_handler.handle(line_info)
655 return normal_handler.handle(line_info)
654
656
655 # Display the rewritten call
657 # Display the rewritten call
656 if auto_rewrite:
658 if auto_rewrite:
657 self.shell.auto_rewrite_input(newcmd)
659 self.shell.auto_rewrite_input(newcmd)
658
660
659 return newcmd
661 return newcmd
660
662
661
663
662 class EmacsHandler(PrefilterHandler):
664 class EmacsHandler(PrefilterHandler):
663
665
664 handler_name = Unicode('emacs')
666 handler_name = Unicode('emacs')
665 esc_strings = List([])
667 esc_strings = List([])
666
668
667 def handle(self, line_info):
669 def handle(self, line_info):
668 """Handle input lines marked by python-mode."""
670 """Handle input lines marked by python-mode."""
669
671
670 # Currently, nothing is done. Later more functionality can be added
672 # Currently, nothing is done. Later more functionality can be added
671 # here if needed.
673 # here if needed.
672
674
673 # The input cache shouldn't be updated
675 # The input cache shouldn't be updated
674 return line_info.line
676 return line_info.line
675
677
676
678
677 #-----------------------------------------------------------------------------
679 #-----------------------------------------------------------------------------
678 # Defaults
680 # Defaults
679 #-----------------------------------------------------------------------------
681 #-----------------------------------------------------------------------------
680
682
681
683
682 _default_checkers = [
684 _default_checkers = [
683 EmacsChecker,
685 EmacsChecker,
684 MacroChecker,
686 MacroChecker,
685 IPyAutocallChecker,
687 IPyAutocallChecker,
686 AssignmentChecker,
688 AssignmentChecker,
687 AutoMagicChecker,
689 AutoMagicChecker,
688 PythonOpsChecker,
690 PythonOpsChecker,
689 AutocallChecker
691 AutocallChecker
690 ]
692 ]
691
693
692 _default_handlers = [
694 _default_handlers = [
693 PrefilterHandler,
695 PrefilterHandler,
694 MacroHandler,
696 MacroHandler,
695 MagicHandler,
697 MagicHandler,
696 AutoHandler,
698 AutoHandler,
697 EmacsHandler
699 EmacsHandler
698 ]
700 ]
@@ -1,137 +1,138 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Simple utility for splitting user input. This is used by both inputsplitter and
3 Simple utility for splitting user input. This is used by both inputsplitter and
4 prefilter.
4 prefilter.
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 * Fernando Perez
9 * Fernando Perez
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2011 The IPython Development Team
13 # Copyright (C) 2008-2011 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import re
23 import re
24 import sys
24 import sys
25
25
26 from IPython.utils import py3compat
26 from IPython.utils import py3compat
27 from IPython.utils.encoding import get_stream_enc
27 from IPython.utils.encoding import get_stream_enc
28 from IPython.core.oinspect import OInfo
28
29
29 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
30 # Main function
31 # Main function
31 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
32
33
33 # RegExp for splitting line contents into pre-char//first word-method//rest.
34 # RegExp for splitting line contents into pre-char//first word-method//rest.
34 # For clarity, each group in on one line.
35 # For clarity, each group in on one line.
35
36
36 # WARNING: update the regexp if the escapes in interactiveshell are changed, as
37 # WARNING: update the regexp if the escapes in interactiveshell are changed, as
37 # they are hardwired in.
38 # they are hardwired in.
38
39
39 # Although it's not solely driven by the regex, note that:
40 # Although it's not solely driven by the regex, note that:
40 # ,;/% only trigger if they are the first character on the line
41 # ,;/% only trigger if they are the first character on the line
41 # ! and !! trigger if they are first char(s) *or* follow an indent
42 # ! and !! trigger if they are first char(s) *or* follow an indent
42 # ? triggers as first or last char.
43 # ? triggers as first or last char.
43
44
44 line_split = re.compile(r"""
45 line_split = re.compile(r"""
45 ^(\s*) # any leading space
46 ^(\s*) # any leading space
46 ([,;/%]|!!?|\?\??)? # escape character or characters
47 ([,;/%]|!!?|\?\??)? # escape character or characters
47 \s*(%{0,2}[\w\.\*]*) # function/method, possibly with leading %
48 \s*(%{0,2}[\w\.\*]*) # function/method, possibly with leading %
48 # to correctly treat things like '?%magic'
49 # to correctly treat things like '?%magic'
49 (.*?$|$) # rest of line
50 (.*?$|$) # rest of line
50 """, re.VERBOSE)
51 """, re.VERBOSE)
51
52
52
53
53 def split_user_input(line, pattern=None):
54 def split_user_input(line, pattern=None):
54 """Split user input into initial whitespace, escape character, function part
55 """Split user input into initial whitespace, escape character, function part
55 and the rest.
56 and the rest.
56 """
57 """
57 # We need to ensure that the rest of this routine deals only with unicode
58 # We need to ensure that the rest of this routine deals only with unicode
58 encoding = get_stream_enc(sys.stdin, 'utf-8')
59 encoding = get_stream_enc(sys.stdin, 'utf-8')
59 line = py3compat.cast_unicode(line, encoding)
60 line = py3compat.cast_unicode(line, encoding)
60
61
61 if pattern is None:
62 if pattern is None:
62 pattern = line_split
63 pattern = line_split
63 match = pattern.match(line)
64 match = pattern.match(line)
64 if not match:
65 if not match:
65 # print "match failed for line '%s'" % line
66 # print "match failed for line '%s'" % line
66 try:
67 try:
67 ifun, the_rest = line.split(None,1)
68 ifun, the_rest = line.split(None,1)
68 except ValueError:
69 except ValueError:
69 # print "split failed for line '%s'" % line
70 # print "split failed for line '%s'" % line
70 ifun, the_rest = line, u''
71 ifun, the_rest = line, u''
71 pre = re.match(r'^(\s*)(.*)',line).groups()[0]
72 pre = re.match(r'^(\s*)(.*)',line).groups()[0]
72 esc = ""
73 esc = ""
73 else:
74 else:
74 pre, esc, ifun, the_rest = match.groups()
75 pre, esc, ifun, the_rest = match.groups()
75
76
76 #print 'line:<%s>' % line # dbg
77 #print 'line:<%s>' % line # dbg
77 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest) # dbg
78 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest) # dbg
78 return pre, esc or '', ifun.strip(), the_rest.lstrip()
79 return pre, esc or '', ifun.strip(), the_rest.lstrip()
79
80
80
81
81 class LineInfo(object):
82 class LineInfo(object):
82 """A single line of input and associated info.
83 """A single line of input and associated info.
83
84
84 Includes the following as properties:
85 Includes the following as properties:
85
86
86 line
87 line
87 The original, raw line
88 The original, raw line
88
89
89 continue_prompt
90 continue_prompt
90 Is this line a continuation in a sequence of multiline input?
91 Is this line a continuation in a sequence of multiline input?
91
92
92 pre
93 pre
93 Any leading whitespace.
94 Any leading whitespace.
94
95
95 esc
96 esc
96 The escape character(s) in pre or the empty string if there isn't one.
97 The escape character(s) in pre or the empty string if there isn't one.
97 Note that '!!' and '??' are possible values for esc. Otherwise it will
98 Note that '!!' and '??' are possible values for esc. Otherwise it will
98 always be a single character.
99 always be a single character.
99
100
100 ifun
101 ifun
101 The 'function part', which is basically the maximal initial sequence
102 The 'function part', which is basically the maximal initial sequence
102 of valid python identifiers and the '.' character. This is what is
103 of valid python identifiers and the '.' character. This is what is
103 checked for alias and magic transformations, used for auto-calling,
104 checked for alias and magic transformations, used for auto-calling,
104 etc. In contrast to Python identifiers, it may start with "%" and contain
105 etc. In contrast to Python identifiers, it may start with "%" and contain
105 "*".
106 "*".
106
107
107 the_rest
108 the_rest
108 Everything else on the line.
109 Everything else on the line.
109 """
110 """
110 def __init__(self, line, continue_prompt=False):
111 def __init__(self, line, continue_prompt=False):
111 self.line = line
112 self.line = line
112 self.continue_prompt = continue_prompt
113 self.continue_prompt = continue_prompt
113 self.pre, self.esc, self.ifun, self.the_rest = split_user_input(line)
114 self.pre, self.esc, self.ifun, self.the_rest = split_user_input(line)
114
115
115 self.pre_char = self.pre.strip()
116 self.pre_char = self.pre.strip()
116 if self.pre_char:
117 if self.pre_char:
117 self.pre_whitespace = '' # No whitespace allowed before esc chars
118 self.pre_whitespace = '' # No whitespace allowed before esc chars
118 else:
119 else:
119 self.pre_whitespace = self.pre
120 self.pre_whitespace = self.pre
120
121
121 def ofind(self, ip):
122 def ofind(self, ip) -> OInfo:
122 """Do a full, attribute-walking lookup of the ifun in the various
123 """Do a full, attribute-walking lookup of the ifun in the various
123 namespaces for the given IPython InteractiveShell instance.
124 namespaces for the given IPython InteractiveShell instance.
124
125
125 Return a dict with keys: {found, obj, ospace, ismagic}
126 Return a dict with keys: {found, obj, ospace, ismagic}
126
127
127 Note: can cause state changes because of calling getattr, but should
128 Note: can cause state changes because of calling getattr, but should
128 only be run if autocall is on and if the line hasn't matched any
129 only be run if autocall is on and if the line hasn't matched any
129 other, less dangerous handlers.
130 other, less dangerous handlers.
130
131
131 Does cache the results of the call, so can be called multiple times
132 Does cache the results of the call, so can be called multiple times
132 without worrying about *further* damaging state.
133 without worrying about *further* damaging state.
133 """
134 """
134 return ip._ofind(self.ifun)
135 return ip._ofind(self.ifun)
135
136
136 def __str__(self):
137 def __str__(self):
137 return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest)
138 return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest)
@@ -1,193 +1,193 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for completerlib.
2 """Tests for completerlib.
3
3
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Imports
7 # Imports
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 import os
10 import os
11 import shutil
11 import shutil
12 import sys
12 import sys
13 import tempfile
13 import tempfile
14 import unittest
14 import unittest
15 from os.path import join
15 from os.path import join
16
16
17 from tempfile import TemporaryDirectory
17 from tempfile import TemporaryDirectory
18
18
19 from IPython.core.completerlib import magic_run_completer, module_completion, try_import
19 from IPython.core.completerlib import magic_run_completer, module_completion, try_import
20 from IPython.testing.decorators import onlyif_unicode_paths
20 from IPython.testing.decorators import onlyif_unicode_paths
21
21
22
22
23 class MockEvent(object):
23 class MockEvent(object):
24 def __init__(self, line):
24 def __init__(self, line):
25 self.line = line
25 self.line = line
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Test functions begin
28 # Test functions begin
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 class Test_magic_run_completer(unittest.TestCase):
30 class Test_magic_run_completer(unittest.TestCase):
31 files = [u"aao.py", u"a.py", u"b.py", u"aao.txt"]
31 files = [u"aao.py", u"a.py", u"b.py", u"aao.txt"]
32 dirs = [u"adir/", "bdir/"]
32 dirs = [u"adir/", "bdir/"]
33
33
34 def setUp(self):
34 def setUp(self):
35 self.BASETESTDIR = tempfile.mkdtemp()
35 self.BASETESTDIR = tempfile.mkdtemp()
36 for fil in self.files:
36 for fil in self.files:
37 with open(join(self.BASETESTDIR, fil), "w", encoding="utf-8") as sfile:
37 with open(join(self.BASETESTDIR, fil), "w", encoding="utf-8") as sfile:
38 sfile.write("pass\n")
38 sfile.write("pass\n")
39 for d in self.dirs:
39 for d in self.dirs:
40 os.mkdir(join(self.BASETESTDIR, d))
40 os.mkdir(join(self.BASETESTDIR, d))
41
41
42 self.oldpath = os.getcwd()
42 self.oldpath = os.getcwd()
43 os.chdir(self.BASETESTDIR)
43 os.chdir(self.BASETESTDIR)
44
44
45 def tearDown(self):
45 def tearDown(self):
46 os.chdir(self.oldpath)
46 os.chdir(self.oldpath)
47 shutil.rmtree(self.BASETESTDIR)
47 shutil.rmtree(self.BASETESTDIR)
48
48
49 def test_1(self):
49 def test_1(self):
50 """Test magic_run_completer, should match two alternatives
50 """Test magic_run_completer, should match two alternatives
51 """
51 """
52 event = MockEvent(u"%run a")
52 event = MockEvent(u"%run a")
53 mockself = None
53 mockself = None
54 match = set(magic_run_completer(mockself, event))
54 match = set(magic_run_completer(mockself, event))
55 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
55 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
56
56
57 def test_2(self):
57 def test_2(self):
58 """Test magic_run_completer, should match one alternative
58 """Test magic_run_completer, should match one alternative
59 """
59 """
60 event = MockEvent(u"%run aa")
60 event = MockEvent(u"%run aa")
61 mockself = None
61 mockself = None
62 match = set(magic_run_completer(mockself, event))
62 match = set(magic_run_completer(mockself, event))
63 self.assertEqual(match, {u"aao.py"})
63 self.assertEqual(match, {u"aao.py"})
64
64
65 def test_3(self):
65 def test_3(self):
66 """Test magic_run_completer with unterminated " """
66 """Test magic_run_completer with unterminated " """
67 event = MockEvent(u'%run "a')
67 event = MockEvent(u'%run "a')
68 mockself = None
68 mockself = None
69 match = set(magic_run_completer(mockself, event))
69 match = set(magic_run_completer(mockself, event))
70 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
70 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
71
71
72 def test_completion_more_args(self):
72 def test_completion_more_args(self):
73 event = MockEvent(u'%run a.py ')
73 event = MockEvent(u'%run a.py ')
74 match = set(magic_run_completer(None, event))
74 match = set(magic_run_completer(None, event))
75 self.assertEqual(match, set(self.files + self.dirs))
75 self.assertEqual(match, set(self.files + self.dirs))
76
76
77 def test_completion_in_dir(self):
77 def test_completion_in_dir(self):
78 # Github issue #3459
78 # Github issue #3459
79 event = MockEvent(u'%run a.py {}'.format(join(self.BASETESTDIR, 'a')))
79 event = MockEvent(u'%run a.py {}'.format(join(self.BASETESTDIR, 'a')))
80 print(repr(event.line))
80 print(repr(event.line))
81 match = set(magic_run_completer(None, event))
81 match = set(magic_run_completer(None, event))
82 # We specifically use replace here rather than normpath, because
82 # We specifically use replace here rather than normpath, because
83 # at one point there were duplicates 'adir' and 'adir/', and normpath
83 # at one point there were duplicates 'adir' and 'adir/', and normpath
84 # would hide the failure for that.
84 # would hide the failure for that.
85 self.assertEqual(match, {join(self.BASETESTDIR, f).replace('\\','/')
85 self.assertEqual(match, {join(self.BASETESTDIR, f).replace('\\','/')
86 for f in (u'a.py', u'aao.py', u'aao.txt', u'adir/')})
86 for f in (u'a.py', u'aao.py', u'aao.txt', u'adir/')})
87
87
88 class Test_magic_run_completer_nonascii(unittest.TestCase):
88 class Test_magic_run_completer_nonascii(unittest.TestCase):
89 @onlyif_unicode_paths
89 @onlyif_unicode_paths
90 def setUp(self):
90 def setUp(self):
91 self.BASETESTDIR = tempfile.mkdtemp()
91 self.BASETESTDIR = tempfile.mkdtemp()
92 for fil in [u"aaø.py", u"a.py", u"b.py"]:
92 for fil in [u"aaø.py", u"a.py", u"b.py"]:
93 with open(join(self.BASETESTDIR, fil), "w", encoding="utf-8") as sfile:
93 with open(join(self.BASETESTDIR, fil), "w", encoding="utf-8") as sfile:
94 sfile.write("pass\n")
94 sfile.write("pass\n")
95 self.oldpath = os.getcwd()
95 self.oldpath = os.getcwd()
96 os.chdir(self.BASETESTDIR)
96 os.chdir(self.BASETESTDIR)
97
97
98 def tearDown(self):
98 def tearDown(self):
99 os.chdir(self.oldpath)
99 os.chdir(self.oldpath)
100 shutil.rmtree(self.BASETESTDIR)
100 shutil.rmtree(self.BASETESTDIR)
101
101
102 @onlyif_unicode_paths
102 @onlyif_unicode_paths
103 def test_1(self):
103 def test_1(self):
104 """Test magic_run_completer, should match two alternatives
104 """Test magic_run_completer, should match two alternatives
105 """
105 """
106 event = MockEvent(u"%run a")
106 event = MockEvent(u"%run a")
107 mockself = None
107 mockself = None
108 match = set(magic_run_completer(mockself, event))
108 match = set(magic_run_completer(mockself, event))
109 self.assertEqual(match, {u"a.py", u"aaø.py"})
109 self.assertEqual(match, {u"a.py", u"aaø.py"})
110
110
111 @onlyif_unicode_paths
111 @onlyif_unicode_paths
112 def test_2(self):
112 def test_2(self):
113 """Test magic_run_completer, should match one alternative
113 """Test magic_run_completer, should match one alternative
114 """
114 """
115 event = MockEvent(u"%run aa")
115 event = MockEvent(u"%run aa")
116 mockself = None
116 mockself = None
117 match = set(magic_run_completer(mockself, event))
117 match = set(magic_run_completer(mockself, event))
118 self.assertEqual(match, {u"aaø.py"})
118 self.assertEqual(match, {u"aaø.py"})
119
119
120 @onlyif_unicode_paths
120 @onlyif_unicode_paths
121 def test_3(self):
121 def test_3(self):
122 """Test magic_run_completer with unterminated " """
122 """Test magic_run_completer with unterminated " """
123 event = MockEvent(u'%run "a')
123 event = MockEvent(u'%run "a')
124 mockself = None
124 mockself = None
125 match = set(magic_run_completer(mockself, event))
125 match = set(magic_run_completer(mockself, event))
126 self.assertEqual(match, {u"a.py", u"aaø.py"})
126 self.assertEqual(match, {u"a.py", u"aaø.py"})
127
127
128 # module_completer:
128 # module_completer:
129
129
130 def test_import_invalid_module():
130 def test_import_invalid_module():
131 """Testing of issue https://github.com/ipython/ipython/issues/1107"""
131 """Testing of issue https://github.com/ipython/ipython/issues/1107"""
132 invalid_module_names = {'foo-bar', 'foo:bar', '10foo'}
132 invalid_module_names = {'foo-bar', 'foo:bar', '10foo'}
133 valid_module_names = {'foobar'}
133 valid_module_names = {'foobar'}
134 with TemporaryDirectory() as tmpdir:
134 with TemporaryDirectory() as tmpdir:
135 sys.path.insert( 0, tmpdir )
135 sys.path.insert( 0, tmpdir )
136 for name in invalid_module_names | valid_module_names:
136 for name in invalid_module_names | valid_module_names:
137 filename = os.path.join(tmpdir, name + ".py")
137 filename = os.path.join(tmpdir, name + ".py")
138 open(filename, "w", encoding="utf-8").close()
138 open(filename, "w", encoding="utf-8").close()
139
139
140 s = set( module_completion('import foo') )
140 s = set( module_completion('import foo') )
141 intersection = s.intersection(invalid_module_names)
141 intersection = s.intersection(invalid_module_names)
142 assert intersection == set()
142 assert intersection == set()
143
143
144 assert valid_module_names.issubset(s), valid_module_names.intersection(s)
144 assert valid_module_names.issubset(s), valid_module_names.intersection(s)
145
145
146
146
147 def test_bad_module_all():
147 def test_bad_module_all():
148 """Test module with invalid __all__
148 """Test module with invalid __all__
149
149
150 https://github.com/ipython/ipython/issues/9678
150 https://github.com/ipython/ipython/issues/9678
151 """
151 """
152 testsdir = os.path.dirname(__file__)
152 testsdir = os.path.dirname(__file__)
153 sys.path.insert(0, testsdir)
153 sys.path.insert(0, testsdir)
154 try:
154 try:
155 results = module_completion("from bad_all import ")
155 results = module_completion("from bad_all import ")
156 assert "puppies" in results
156 assert "puppies" in results
157 for r in results:
157 for r in results:
158 assert isinstance(r, str)
158 assert isinstance(r, str)
159
159
160 # bad_all doesn't contain submodules, but this completion
160 # bad_all doesn't contain submodules, but this completion
161 # should finish without raising an exception:
161 # should finish without raising an exception:
162 results = module_completion("import bad_all.")
162 results = module_completion("import bad_all.")
163 assert results == []
163 assert results == []
164 finally:
164 finally:
165 sys.path.remove(testsdir)
165 sys.path.remove(testsdir)
166
166
167
167
168 def test_module_without_init():
168 def test_module_without_init():
169 """
169 """
170 Test module without __init__.py.
170 Test module without __init__.py.
171
171
172 https://github.com/ipython/ipython/issues/11226
172 https://github.com/ipython/ipython/issues/11226
173 """
173 """
174 fake_module_name = "foo"
174 fake_module_name = "foo"
175 with TemporaryDirectory() as tmpdir:
175 with TemporaryDirectory() as tmpdir:
176 sys.path.insert(0, tmpdir)
176 sys.path.insert(0, tmpdir)
177 try:
177 try:
178 os.makedirs(os.path.join(tmpdir, fake_module_name))
178 os.makedirs(os.path.join(tmpdir, fake_module_name))
179 s = try_import(mod=fake_module_name)
179 s = try_import(mod=fake_module_name)
180 assert s == []
180 assert s == [], f"for module {fake_module_name}"
181 finally:
181 finally:
182 sys.path.remove(tmpdir)
182 sys.path.remove(tmpdir)
183
183
184
184
185 def test_valid_exported_submodules():
185 def test_valid_exported_submodules():
186 """
186 """
187 Test checking exported (__all__) objects are submodules
187 Test checking exported (__all__) objects are submodules
188 """
188 """
189 results = module_completion("import os.pa")
189 results = module_completion("import os.pa")
190 # ensure we get a valid submodule:
190 # ensure we get a valid submodule:
191 assert "os.path" in results
191 assert "os.path" in results
192 # ensure we don't get objects that aren't submodules:
192 # ensure we don't get objects that aren't submodules:
193 assert "os.pathconf" not in results
193 assert "os.pathconf" not in results
@@ -1,1175 +1,1200 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the key interactiveshell module.
2 """Tests for the key interactiveshell module.
3
3
4 Historically the main classes in interactiveshell have been under-tested. This
4 Historically the main classes in interactiveshell have been under-tested. This
5 module should grow as many single-method tests as possible to trap many of the
5 module should grow as many single-method tests as possible to trap many of the
6 recurring bugs we seem to encounter with high-level interaction.
6 recurring bugs we seem to encounter with high-level interaction.
7 """
7 """
8
8
9 # Copyright (c) IPython Development Team.
9 # Copyright (c) IPython Development Team.
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11
11
12 import asyncio
12 import asyncio
13 import ast
13 import ast
14 import os
14 import os
15 import signal
15 import signal
16 import shutil
16 import shutil
17 import sys
17 import sys
18 import tempfile
18 import tempfile
19 import unittest
19 import unittest
20 import pytest
20 import pytest
21 from unittest import mock
21 from unittest import mock
22
22
23 from os.path import join
23 from os.path import join
24
24
25 from IPython.core.error import InputRejected
25 from IPython.core.error import InputRejected
26 from IPython.core.inputtransformer import InputTransformer
26 from IPython.core.inputtransformer import InputTransformer
27 from IPython.core import interactiveshell
27 from IPython.core import interactiveshell
28 from IPython.core.oinspect import OInfo
28 from IPython.testing.decorators import (
29 from IPython.testing.decorators import (
29 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
30 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
30 )
31 )
31 from IPython.testing import tools as tt
32 from IPython.testing import tools as tt
32 from IPython.utils.process import find_cmd
33 from IPython.utils.process import find_cmd
33
34
34 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
35 # Globals
36 # Globals
36 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
37 # This is used by every single test, no point repeating it ad nauseam
38 # This is used by every single test, no point repeating it ad nauseam
38
39
39 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
40 # Tests
41 # Tests
41 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
42
43
43 class DerivedInterrupt(KeyboardInterrupt):
44 class DerivedInterrupt(KeyboardInterrupt):
44 pass
45 pass
45
46
46 class InteractiveShellTestCase(unittest.TestCase):
47 class InteractiveShellTestCase(unittest.TestCase):
47 def test_naked_string_cells(self):
48 def test_naked_string_cells(self):
48 """Test that cells with only naked strings are fully executed"""
49 """Test that cells with only naked strings are fully executed"""
49 # First, single-line inputs
50 # First, single-line inputs
50 ip.run_cell('"a"\n')
51 ip.run_cell('"a"\n')
51 self.assertEqual(ip.user_ns['_'], 'a')
52 self.assertEqual(ip.user_ns['_'], 'a')
52 # And also multi-line cells
53 # And also multi-line cells
53 ip.run_cell('"""a\nb"""\n')
54 ip.run_cell('"""a\nb"""\n')
54 self.assertEqual(ip.user_ns['_'], 'a\nb')
55 self.assertEqual(ip.user_ns['_'], 'a\nb')
55
56
56 def test_run_empty_cell(self):
57 def test_run_empty_cell(self):
57 """Just make sure we don't get a horrible error with a blank
58 """Just make sure we don't get a horrible error with a blank
58 cell of input. Yes, I did overlook that."""
59 cell of input. Yes, I did overlook that."""
59 old_xc = ip.execution_count
60 old_xc = ip.execution_count
60 res = ip.run_cell('')
61 res = ip.run_cell('')
61 self.assertEqual(ip.execution_count, old_xc)
62 self.assertEqual(ip.execution_count, old_xc)
62 self.assertEqual(res.execution_count, None)
63 self.assertEqual(res.execution_count, None)
63
64
64 def test_run_cell_multiline(self):
65 def test_run_cell_multiline(self):
65 """Multi-block, multi-line cells must execute correctly.
66 """Multi-block, multi-line cells must execute correctly.
66 """
67 """
67 src = '\n'.join(["x=1",
68 src = '\n'.join(["x=1",
68 "y=2",
69 "y=2",
69 "if 1:",
70 "if 1:",
70 " x += 1",
71 " x += 1",
71 " y += 1",])
72 " y += 1",])
72 res = ip.run_cell(src)
73 res = ip.run_cell(src)
73 self.assertEqual(ip.user_ns['x'], 2)
74 self.assertEqual(ip.user_ns['x'], 2)
74 self.assertEqual(ip.user_ns['y'], 3)
75 self.assertEqual(ip.user_ns['y'], 3)
75 self.assertEqual(res.success, True)
76 self.assertEqual(res.success, True)
76 self.assertEqual(res.result, None)
77 self.assertEqual(res.result, None)
77
78
78 def test_multiline_string_cells(self):
79 def test_multiline_string_cells(self):
79 "Code sprinkled with multiline strings should execute (GH-306)"
80 "Code sprinkled with multiline strings should execute (GH-306)"
80 ip.run_cell('tmp=0')
81 ip.run_cell('tmp=0')
81 self.assertEqual(ip.user_ns['tmp'], 0)
82 self.assertEqual(ip.user_ns['tmp'], 0)
82 res = ip.run_cell('tmp=1;"""a\nb"""\n')
83 res = ip.run_cell('tmp=1;"""a\nb"""\n')
83 self.assertEqual(ip.user_ns['tmp'], 1)
84 self.assertEqual(ip.user_ns['tmp'], 1)
84 self.assertEqual(res.success, True)
85 self.assertEqual(res.success, True)
85 self.assertEqual(res.result, "a\nb")
86 self.assertEqual(res.result, "a\nb")
86
87
87 def test_dont_cache_with_semicolon(self):
88 def test_dont_cache_with_semicolon(self):
88 "Ending a line with semicolon should not cache the returned object (GH-307)"
89 "Ending a line with semicolon should not cache the returned object (GH-307)"
89 oldlen = len(ip.user_ns['Out'])
90 oldlen = len(ip.user_ns['Out'])
90 for cell in ['1;', '1;1;']:
91 for cell in ['1;', '1;1;']:
91 res = ip.run_cell(cell, store_history=True)
92 res = ip.run_cell(cell, store_history=True)
92 newlen = len(ip.user_ns['Out'])
93 newlen = len(ip.user_ns['Out'])
93 self.assertEqual(oldlen, newlen)
94 self.assertEqual(oldlen, newlen)
94 self.assertIsNone(res.result)
95 self.assertIsNone(res.result)
95 i = 0
96 i = 0
96 #also test the default caching behavior
97 #also test the default caching behavior
97 for cell in ['1', '1;1']:
98 for cell in ['1', '1;1']:
98 ip.run_cell(cell, store_history=True)
99 ip.run_cell(cell, store_history=True)
99 newlen = len(ip.user_ns['Out'])
100 newlen = len(ip.user_ns['Out'])
100 i += 1
101 i += 1
101 self.assertEqual(oldlen+i, newlen)
102 self.assertEqual(oldlen+i, newlen)
102
103
103 def test_syntax_error(self):
104 def test_syntax_error(self):
104 res = ip.run_cell("raise = 3")
105 res = ip.run_cell("raise = 3")
105 self.assertIsInstance(res.error_before_exec, SyntaxError)
106 self.assertIsInstance(res.error_before_exec, SyntaxError)
106
107
107 def test_open_standard_input_stream(self):
108 def test_open_standard_input_stream(self):
108 res = ip.run_cell("open(0)")
109 res = ip.run_cell("open(0)")
109 self.assertIsInstance(res.error_in_exec, ValueError)
110 self.assertIsInstance(res.error_in_exec, ValueError)
110
111
111 def test_open_standard_output_stream(self):
112 def test_open_standard_output_stream(self):
112 res = ip.run_cell("open(1)")
113 res = ip.run_cell("open(1)")
113 self.assertIsInstance(res.error_in_exec, ValueError)
114 self.assertIsInstance(res.error_in_exec, ValueError)
114
115
115 def test_open_standard_error_stream(self):
116 def test_open_standard_error_stream(self):
116 res = ip.run_cell("open(2)")
117 res = ip.run_cell("open(2)")
117 self.assertIsInstance(res.error_in_exec, ValueError)
118 self.assertIsInstance(res.error_in_exec, ValueError)
118
119
119 def test_In_variable(self):
120 def test_In_variable(self):
120 "Verify that In variable grows with user input (GH-284)"
121 "Verify that In variable grows with user input (GH-284)"
121 oldlen = len(ip.user_ns['In'])
122 oldlen = len(ip.user_ns['In'])
122 ip.run_cell('1;', store_history=True)
123 ip.run_cell('1;', store_history=True)
123 newlen = len(ip.user_ns['In'])
124 newlen = len(ip.user_ns['In'])
124 self.assertEqual(oldlen+1, newlen)
125 self.assertEqual(oldlen+1, newlen)
125 self.assertEqual(ip.user_ns['In'][-1],'1;')
126 self.assertEqual(ip.user_ns['In'][-1],'1;')
126
127
127 def test_magic_names_in_string(self):
128 def test_magic_names_in_string(self):
128 ip.run_cell('a = """\n%exit\n"""')
129 ip.run_cell('a = """\n%exit\n"""')
129 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
130 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
130
131
131 def test_trailing_newline(self):
132 def test_trailing_newline(self):
132 """test that running !(command) does not raise a SyntaxError"""
133 """test that running !(command) does not raise a SyntaxError"""
133 ip.run_cell('!(true)\n', False)
134 ip.run_cell('!(true)\n', False)
134 ip.run_cell('!(true)\n\n\n', False)
135 ip.run_cell('!(true)\n\n\n', False)
135
136
136 def test_gh_597(self):
137 def test_gh_597(self):
137 """Pretty-printing lists of objects with non-ascii reprs may cause
138 """Pretty-printing lists of objects with non-ascii reprs may cause
138 problems."""
139 problems."""
139 class Spam(object):
140 class Spam(object):
140 def __repr__(self):
141 def __repr__(self):
141 return "\xe9"*50
142 return "\xe9"*50
142 import IPython.core.formatters
143 import IPython.core.formatters
143 f = IPython.core.formatters.PlainTextFormatter()
144 f = IPython.core.formatters.PlainTextFormatter()
144 f([Spam(),Spam()])
145 f([Spam(),Spam()])
145
146
146
147
147 def test_future_flags(self):
148 def test_future_flags(self):
148 """Check that future flags are used for parsing code (gh-777)"""
149 """Check that future flags are used for parsing code (gh-777)"""
149 ip.run_cell('from __future__ import barry_as_FLUFL')
150 ip.run_cell('from __future__ import barry_as_FLUFL')
150 try:
151 try:
151 ip.run_cell('prfunc_return_val = 1 <> 2')
152 ip.run_cell('prfunc_return_val = 1 <> 2')
152 assert 'prfunc_return_val' in ip.user_ns
153 assert 'prfunc_return_val' in ip.user_ns
153 finally:
154 finally:
154 # Reset compiler flags so we don't mess up other tests.
155 # Reset compiler flags so we don't mess up other tests.
155 ip.compile.reset_compiler_flags()
156 ip.compile.reset_compiler_flags()
156
157
157 def test_can_pickle(self):
158 def test_can_pickle(self):
158 "Can we pickle objects defined interactively (GH-29)"
159 "Can we pickle objects defined interactively (GH-29)"
159 ip = get_ipython()
160 ip = get_ipython()
160 ip.reset()
161 ip.reset()
161 ip.run_cell(("class Mylist(list):\n"
162 ip.run_cell(("class Mylist(list):\n"
162 " def __init__(self,x=[]):\n"
163 " def __init__(self,x=[]):\n"
163 " list.__init__(self,x)"))
164 " list.__init__(self,x)"))
164 ip.run_cell("w=Mylist([1,2,3])")
165 ip.run_cell("w=Mylist([1,2,3])")
165
166
166 from pickle import dumps
167 from pickle import dumps
167
168
168 # We need to swap in our main module - this is only necessary
169 # We need to swap in our main module - this is only necessary
169 # inside the test framework, because IPython puts the interactive module
170 # inside the test framework, because IPython puts the interactive module
170 # in place (but the test framework undoes this).
171 # in place (but the test framework undoes this).
171 _main = sys.modules['__main__']
172 _main = sys.modules['__main__']
172 sys.modules['__main__'] = ip.user_module
173 sys.modules['__main__'] = ip.user_module
173 try:
174 try:
174 res = dumps(ip.user_ns["w"])
175 res = dumps(ip.user_ns["w"])
175 finally:
176 finally:
176 sys.modules['__main__'] = _main
177 sys.modules['__main__'] = _main
177 self.assertTrue(isinstance(res, bytes))
178 self.assertTrue(isinstance(res, bytes))
178
179
179 def test_global_ns(self):
180 def test_global_ns(self):
180 "Code in functions must be able to access variables outside them."
181 "Code in functions must be able to access variables outside them."
181 ip = get_ipython()
182 ip = get_ipython()
182 ip.run_cell("a = 10")
183 ip.run_cell("a = 10")
183 ip.run_cell(("def f(x):\n"
184 ip.run_cell(("def f(x):\n"
184 " return x + a"))
185 " return x + a"))
185 ip.run_cell("b = f(12)")
186 ip.run_cell("b = f(12)")
186 self.assertEqual(ip.user_ns["b"], 22)
187 self.assertEqual(ip.user_ns["b"], 22)
187
188
188 def test_bad_custom_tb(self):
189 def test_bad_custom_tb(self):
189 """Check that InteractiveShell is protected from bad custom exception handlers"""
190 """Check that InteractiveShell is protected from bad custom exception handlers"""
190 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
191 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
191 self.assertEqual(ip.custom_exceptions, (IOError,))
192 self.assertEqual(ip.custom_exceptions, (IOError,))
192 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
193 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
193 ip.run_cell(u'raise IOError("foo")')
194 ip.run_cell(u'raise IOError("foo")')
194 self.assertEqual(ip.custom_exceptions, ())
195 self.assertEqual(ip.custom_exceptions, ())
195
196
196 def test_bad_custom_tb_return(self):
197 def test_bad_custom_tb_return(self):
197 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
198 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
198 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
199 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
199 self.assertEqual(ip.custom_exceptions, (NameError,))
200 self.assertEqual(ip.custom_exceptions, (NameError,))
200 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
201 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
201 ip.run_cell(u'a=abracadabra')
202 ip.run_cell(u'a=abracadabra')
202 self.assertEqual(ip.custom_exceptions, ())
203 self.assertEqual(ip.custom_exceptions, ())
203
204
204 def test_drop_by_id(self):
205 def test_drop_by_id(self):
205 myvars = {"a":object(), "b":object(), "c": object()}
206 myvars = {"a":object(), "b":object(), "c": object()}
206 ip.push(myvars, interactive=False)
207 ip.push(myvars, interactive=False)
207 for name in myvars:
208 for name in myvars:
208 assert name in ip.user_ns, name
209 assert name in ip.user_ns, name
209 assert name in ip.user_ns_hidden, name
210 assert name in ip.user_ns_hidden, name
210 ip.user_ns['b'] = 12
211 ip.user_ns['b'] = 12
211 ip.drop_by_id(myvars)
212 ip.drop_by_id(myvars)
212 for name in ["a", "c"]:
213 for name in ["a", "c"]:
213 assert name not in ip.user_ns, name
214 assert name not in ip.user_ns, name
214 assert name not in ip.user_ns_hidden, name
215 assert name not in ip.user_ns_hidden, name
215 assert ip.user_ns['b'] == 12
216 assert ip.user_ns['b'] == 12
216 ip.reset()
217 ip.reset()
217
218
218 def test_var_expand(self):
219 def test_var_expand(self):
219 ip.user_ns['f'] = u'Ca\xf1o'
220 ip.user_ns['f'] = u'Ca\xf1o'
220 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
221 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
221 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
222 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
222 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
223 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
223 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
224 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
224
225
225 self.assertEqual(ip.var_expand(u"grep x | awk '{print $1}'"), u"grep x | awk '{print $1}'")
226 self.assertEqual(ip.var_expand(u"grep x | awk '{print $1}'"), u"grep x | awk '{print $1}'")
226
227
227 ip.user_ns['f'] = b'Ca\xc3\xb1o'
228 ip.user_ns['f'] = b'Ca\xc3\xb1o'
228 # This should not raise any exception:
229 # This should not raise any exception:
229 ip.var_expand(u'echo $f')
230 ip.var_expand(u'echo $f')
230
231
231 def test_var_expand_local(self):
232 def test_var_expand_local(self):
232 """Test local variable expansion in !system and %magic calls"""
233 """Test local variable expansion in !system and %magic calls"""
233 # !system
234 # !system
234 ip.run_cell(
235 ip.run_cell(
235 "def test():\n"
236 "def test():\n"
236 ' lvar = "ttt"\n'
237 ' lvar = "ttt"\n'
237 " ret = !echo {lvar}\n"
238 " ret = !echo {lvar}\n"
238 " return ret[0]\n"
239 " return ret[0]\n"
239 )
240 )
240 res = ip.user_ns["test"]()
241 res = ip.user_ns["test"]()
241 self.assertIn("ttt", res)
242 self.assertIn("ttt", res)
242
243
243 # %magic
244 # %magic
244 ip.run_cell(
245 ip.run_cell(
245 "def makemacro():\n"
246 "def makemacro():\n"
246 ' macroname = "macro_var_expand_locals"\n'
247 ' macroname = "macro_var_expand_locals"\n'
247 " %macro {macroname} codestr\n"
248 " %macro {macroname} codestr\n"
248 )
249 )
249 ip.user_ns["codestr"] = "str(12)"
250 ip.user_ns["codestr"] = "str(12)"
250 ip.run_cell("makemacro()")
251 ip.run_cell("makemacro()")
251 self.assertIn("macro_var_expand_locals", ip.user_ns)
252 self.assertIn("macro_var_expand_locals", ip.user_ns)
252
253
253 def test_var_expand_self(self):
254 def test_var_expand_self(self):
254 """Test variable expansion with the name 'self', which was failing.
255 """Test variable expansion with the name 'self', which was failing.
255
256
256 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
257 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
257 """
258 """
258 ip.run_cell(
259 ip.run_cell(
259 "class cTest:\n"
260 "class cTest:\n"
260 ' classvar="see me"\n'
261 ' classvar="see me"\n'
261 " def test(self):\n"
262 " def test(self):\n"
262 " res = !echo Variable: {self.classvar}\n"
263 " res = !echo Variable: {self.classvar}\n"
263 " return res[0]\n"
264 " return res[0]\n"
264 )
265 )
265 self.assertIn("see me", ip.user_ns["cTest"]().test())
266 self.assertIn("see me", ip.user_ns["cTest"]().test())
266
267
267 def test_bad_var_expand(self):
268 def test_bad_var_expand(self):
268 """var_expand on invalid formats shouldn't raise"""
269 """var_expand on invalid formats shouldn't raise"""
269 # SyntaxError
270 # SyntaxError
270 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
271 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
271 # NameError
272 # NameError
272 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
273 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
273 # ZeroDivisionError
274 # ZeroDivisionError
274 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
275 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
275
276
276 def test_silent_postexec(self):
277 def test_silent_postexec(self):
277 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
278 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
278 pre_explicit = mock.Mock()
279 pre_explicit = mock.Mock()
279 pre_always = mock.Mock()
280 pre_always = mock.Mock()
280 post_explicit = mock.Mock()
281 post_explicit = mock.Mock()
281 post_always = mock.Mock()
282 post_always = mock.Mock()
282 all_mocks = [pre_explicit, pre_always, post_explicit, post_always]
283 all_mocks = [pre_explicit, pre_always, post_explicit, post_always]
283
284
284 ip.events.register('pre_run_cell', pre_explicit)
285 ip.events.register('pre_run_cell', pre_explicit)
285 ip.events.register('pre_execute', pre_always)
286 ip.events.register('pre_execute', pre_always)
286 ip.events.register('post_run_cell', post_explicit)
287 ip.events.register('post_run_cell', post_explicit)
287 ip.events.register('post_execute', post_always)
288 ip.events.register('post_execute', post_always)
288
289
289 try:
290 try:
290 ip.run_cell("1", silent=True)
291 ip.run_cell("1", silent=True)
291 assert pre_always.called
292 assert pre_always.called
292 assert not pre_explicit.called
293 assert not pre_explicit.called
293 assert post_always.called
294 assert post_always.called
294 assert not post_explicit.called
295 assert not post_explicit.called
295 # double-check that non-silent exec did what we expected
296 # double-check that non-silent exec did what we expected
296 # silent to avoid
297 # silent to avoid
297 ip.run_cell("1")
298 ip.run_cell("1")
298 assert pre_explicit.called
299 assert pre_explicit.called
299 assert post_explicit.called
300 assert post_explicit.called
300 info, = pre_explicit.call_args[0]
301 info, = pre_explicit.call_args[0]
301 result, = post_explicit.call_args[0]
302 result, = post_explicit.call_args[0]
302 self.assertEqual(info, result.info)
303 self.assertEqual(info, result.info)
303 # check that post hooks are always called
304 # check that post hooks are always called
304 [m.reset_mock() for m in all_mocks]
305 [m.reset_mock() for m in all_mocks]
305 ip.run_cell("syntax error")
306 ip.run_cell("syntax error")
306 assert pre_always.called
307 assert pre_always.called
307 assert pre_explicit.called
308 assert pre_explicit.called
308 assert post_always.called
309 assert post_always.called
309 assert post_explicit.called
310 assert post_explicit.called
310 info, = pre_explicit.call_args[0]
311 info, = pre_explicit.call_args[0]
311 result, = post_explicit.call_args[0]
312 result, = post_explicit.call_args[0]
312 self.assertEqual(info, result.info)
313 self.assertEqual(info, result.info)
313 finally:
314 finally:
314 # remove post-exec
315 # remove post-exec
315 ip.events.unregister('pre_run_cell', pre_explicit)
316 ip.events.unregister('pre_run_cell', pre_explicit)
316 ip.events.unregister('pre_execute', pre_always)
317 ip.events.unregister('pre_execute', pre_always)
317 ip.events.unregister('post_run_cell', post_explicit)
318 ip.events.unregister('post_run_cell', post_explicit)
318 ip.events.unregister('post_execute', post_always)
319 ip.events.unregister('post_execute', post_always)
319
320
320 def test_silent_noadvance(self):
321 def test_silent_noadvance(self):
321 """run_cell(silent=True) doesn't advance execution_count"""
322 """run_cell(silent=True) doesn't advance execution_count"""
322 ec = ip.execution_count
323 ec = ip.execution_count
323 # silent should force store_history=False
324 # silent should force store_history=False
324 ip.run_cell("1", store_history=True, silent=True)
325 ip.run_cell("1", store_history=True, silent=True)
325
326
326 self.assertEqual(ec, ip.execution_count)
327 self.assertEqual(ec, ip.execution_count)
327 # double-check that non-silent exec did what we expected
328 # double-check that non-silent exec did what we expected
328 # silent to avoid
329 # silent to avoid
329 ip.run_cell("1", store_history=True)
330 ip.run_cell("1", store_history=True)
330 self.assertEqual(ec+1, ip.execution_count)
331 self.assertEqual(ec+1, ip.execution_count)
331
332
332 def test_silent_nodisplayhook(self):
333 def test_silent_nodisplayhook(self):
333 """run_cell(silent=True) doesn't trigger displayhook"""
334 """run_cell(silent=True) doesn't trigger displayhook"""
334 d = dict(called=False)
335 d = dict(called=False)
335
336
336 trap = ip.display_trap
337 trap = ip.display_trap
337 save_hook = trap.hook
338 save_hook = trap.hook
338
339
339 def failing_hook(*args, **kwargs):
340 def failing_hook(*args, **kwargs):
340 d['called'] = True
341 d['called'] = True
341
342
342 try:
343 try:
343 trap.hook = failing_hook
344 trap.hook = failing_hook
344 res = ip.run_cell("1", silent=True)
345 res = ip.run_cell("1", silent=True)
345 self.assertFalse(d['called'])
346 self.assertFalse(d['called'])
346 self.assertIsNone(res.result)
347 self.assertIsNone(res.result)
347 # double-check that non-silent exec did what we expected
348 # double-check that non-silent exec did what we expected
348 # silent to avoid
349 # silent to avoid
349 ip.run_cell("1")
350 ip.run_cell("1")
350 self.assertTrue(d['called'])
351 self.assertTrue(d['called'])
351 finally:
352 finally:
352 trap.hook = save_hook
353 trap.hook = save_hook
353
354
354 def test_ofind_line_magic(self):
355 def test_ofind_line_magic(self):
355 from IPython.core.magic import register_line_magic
356 from IPython.core.magic import register_line_magic
356
357
357 @register_line_magic
358 @register_line_magic
358 def lmagic(line):
359 def lmagic(line):
359 "A line magic"
360 "A line magic"
360
361
361 # Get info on line magic
362 # Get info on line magic
362 lfind = ip._ofind("lmagic")
363 lfind = ip._ofind("lmagic")
363 info = dict(
364 info = OInfo(
364 found=True,
365 found=True,
365 isalias=False,
366 isalias=False,
366 ismagic=True,
367 ismagic=True,
367 namespace="IPython internal",
368 namespace="IPython internal",
368 obj=lmagic,
369 obj=lmagic,
369 parent=None,
370 parent=None,
370 )
371 )
371 self.assertEqual(lfind, info)
372 self.assertEqual(lfind, info)
372
373
373 def test_ofind_cell_magic(self):
374 def test_ofind_cell_magic(self):
374 from IPython.core.magic import register_cell_magic
375 from IPython.core.magic import register_cell_magic
375
376
376 @register_cell_magic
377 @register_cell_magic
377 def cmagic(line, cell):
378 def cmagic(line, cell):
378 "A cell magic"
379 "A cell magic"
379
380
380 # Get info on cell magic
381 # Get info on cell magic
381 find = ip._ofind("cmagic")
382 find = ip._ofind("cmagic")
382 info = dict(
383 info = OInfo(
383 found=True,
384 found=True,
384 isalias=False,
385 isalias=False,
385 ismagic=True,
386 ismagic=True,
386 namespace="IPython internal",
387 namespace="IPython internal",
387 obj=cmagic,
388 obj=cmagic,
388 parent=None,
389 parent=None,
389 )
390 )
390 self.assertEqual(find, info)
391 self.assertEqual(find, info)
391
392
392 def test_ofind_property_with_error(self):
393 def test_ofind_property_with_error(self):
393 class A(object):
394 class A(object):
394 @property
395 @property
395 def foo(self):
396 def foo(self):
396 raise NotImplementedError() # pragma: no cover
397 raise NotImplementedError() # pragma: no cover
397
398
398 a = A()
399 a = A()
399
400
400 found = ip._ofind('a.foo', [('locals', locals())])
401 found = ip._ofind("a.foo", [("locals", locals())])
401 info = dict(found=True, isalias=False, ismagic=False,
402 info = OInfo(
402 namespace='locals', obj=A.foo, parent=a)
403 found=True,
404 isalias=False,
405 ismagic=False,
406 namespace="locals",
407 obj=A.foo,
408 parent=a,
409 )
403 self.assertEqual(found, info)
410 self.assertEqual(found, info)
404
411
405 def test_ofind_multiple_attribute_lookups(self):
412 def test_ofind_multiple_attribute_lookups(self):
406 class A(object):
413 class A(object):
407 @property
414 @property
408 def foo(self):
415 def foo(self):
409 raise NotImplementedError() # pragma: no cover
416 raise NotImplementedError() # pragma: no cover
410
417
411 a = A()
418 a = A()
412 a.a = A()
419 a.a = A()
413 a.a.a = A()
420 a.a.a = A()
414
421
415 found = ip._ofind('a.a.a.foo', [('locals', locals())])
422 found = ip._ofind("a.a.a.foo", [("locals", locals())])
416 info = dict(found=True, isalias=False, ismagic=False,
423 info = OInfo(
417 namespace='locals', obj=A.foo, parent=a.a.a)
424 found=True,
425 isalias=False,
426 ismagic=False,
427 namespace="locals",
428 obj=A.foo,
429 parent=a.a.a,
430 )
418 self.assertEqual(found, info)
431 self.assertEqual(found, info)
419
432
420 def test_ofind_slotted_attributes(self):
433 def test_ofind_slotted_attributes(self):
421 class A(object):
434 class A(object):
422 __slots__ = ['foo']
435 __slots__ = ['foo']
423 def __init__(self):
436 def __init__(self):
424 self.foo = 'bar'
437 self.foo = 'bar'
425
438
426 a = A()
439 a = A()
427 found = ip._ofind('a.foo', [('locals', locals())])
440 found = ip._ofind("a.foo", [("locals", locals())])
428 info = dict(found=True, isalias=False, ismagic=False,
441 info = OInfo(
429 namespace='locals', obj=a.foo, parent=a)
442 found=True,
443 isalias=False,
444 ismagic=False,
445 namespace="locals",
446 obj=a.foo,
447 parent=a,
448 )
430 self.assertEqual(found, info)
449 self.assertEqual(found, info)
431
450
432 found = ip._ofind('a.bar', [('locals', locals())])
451 found = ip._ofind("a.bar", [("locals", locals())])
433 info = dict(found=False, isalias=False, ismagic=False,
452 info = OInfo(
434 namespace=None, obj=None, parent=a)
453 found=False,
454 isalias=False,
455 ismagic=False,
456 namespace=None,
457 obj=None,
458 parent=a,
459 )
435 self.assertEqual(found, info)
460 self.assertEqual(found, info)
436
461
437 def test_ofind_prefers_property_to_instance_level_attribute(self):
462 def test_ofind_prefers_property_to_instance_level_attribute(self):
438 class A(object):
463 class A(object):
439 @property
464 @property
440 def foo(self):
465 def foo(self):
441 return 'bar'
466 return 'bar'
442 a = A()
467 a = A()
443 a.__dict__["foo"] = "baz"
468 a.__dict__["foo"] = "baz"
444 self.assertEqual(a.foo, "bar")
469 self.assertEqual(a.foo, "bar")
445 found = ip._ofind("a.foo", [("locals", locals())])
470 found = ip._ofind("a.foo", [("locals", locals())])
446 self.assertIs(found["obj"], A.foo)
471 self.assertIs(found.obj, A.foo)
447
472
448 def test_custom_syntaxerror_exception(self):
473 def test_custom_syntaxerror_exception(self):
449 called = []
474 called = []
450 def my_handler(shell, etype, value, tb, tb_offset=None):
475 def my_handler(shell, etype, value, tb, tb_offset=None):
451 called.append(etype)
476 called.append(etype)
452 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
477 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
453
478
454 ip.set_custom_exc((SyntaxError,), my_handler)
479 ip.set_custom_exc((SyntaxError,), my_handler)
455 try:
480 try:
456 ip.run_cell("1f")
481 ip.run_cell("1f")
457 # Check that this was called, and only once.
482 # Check that this was called, and only once.
458 self.assertEqual(called, [SyntaxError])
483 self.assertEqual(called, [SyntaxError])
459 finally:
484 finally:
460 # Reset the custom exception hook
485 # Reset the custom exception hook
461 ip.set_custom_exc((), None)
486 ip.set_custom_exc((), None)
462
487
463 def test_custom_exception(self):
488 def test_custom_exception(self):
464 called = []
489 called = []
465 def my_handler(shell, etype, value, tb, tb_offset=None):
490 def my_handler(shell, etype, value, tb, tb_offset=None):
466 called.append(etype)
491 called.append(etype)
467 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
492 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
468
493
469 ip.set_custom_exc((ValueError,), my_handler)
494 ip.set_custom_exc((ValueError,), my_handler)
470 try:
495 try:
471 res = ip.run_cell("raise ValueError('test')")
496 res = ip.run_cell("raise ValueError('test')")
472 # Check that this was called, and only once.
497 # Check that this was called, and only once.
473 self.assertEqual(called, [ValueError])
498 self.assertEqual(called, [ValueError])
474 # Check that the error is on the result object
499 # Check that the error is on the result object
475 self.assertIsInstance(res.error_in_exec, ValueError)
500 self.assertIsInstance(res.error_in_exec, ValueError)
476 finally:
501 finally:
477 # Reset the custom exception hook
502 # Reset the custom exception hook
478 ip.set_custom_exc((), None)
503 ip.set_custom_exc((), None)
479
504
480 @mock.patch("builtins.print")
505 @mock.patch("builtins.print")
481 def test_showtraceback_with_surrogates(self, mocked_print):
506 def test_showtraceback_with_surrogates(self, mocked_print):
482 values = []
507 values = []
483
508
484 def mock_print_func(value, sep=" ", end="\n", file=sys.stdout, flush=False):
509 def mock_print_func(value, sep=" ", end="\n", file=sys.stdout, flush=False):
485 values.append(value)
510 values.append(value)
486 if value == chr(0xD8FF):
511 if value == chr(0xD8FF):
487 raise UnicodeEncodeError("utf-8", chr(0xD8FF), 0, 1, "")
512 raise UnicodeEncodeError("utf-8", chr(0xD8FF), 0, 1, "")
488
513
489 # mock builtins.print
514 # mock builtins.print
490 mocked_print.side_effect = mock_print_func
515 mocked_print.side_effect = mock_print_func
491
516
492 # ip._showtraceback() is replaced in globalipapp.py.
517 # ip._showtraceback() is replaced in globalipapp.py.
493 # Call original method to test.
518 # Call original method to test.
494 interactiveshell.InteractiveShell._showtraceback(ip, None, None, chr(0xD8FF))
519 interactiveshell.InteractiveShell._showtraceback(ip, None, None, chr(0xD8FF))
495
520
496 self.assertEqual(mocked_print.call_count, 2)
521 self.assertEqual(mocked_print.call_count, 2)
497 self.assertEqual(values, [chr(0xD8FF), "\\ud8ff"])
522 self.assertEqual(values, [chr(0xD8FF), "\\ud8ff"])
498
523
499 def test_mktempfile(self):
524 def test_mktempfile(self):
500 filename = ip.mktempfile()
525 filename = ip.mktempfile()
501 # Check that we can open the file again on Windows
526 # Check that we can open the file again on Windows
502 with open(filename, "w", encoding="utf-8") as f:
527 with open(filename, "w", encoding="utf-8") as f:
503 f.write("abc")
528 f.write("abc")
504
529
505 filename = ip.mktempfile(data="blah")
530 filename = ip.mktempfile(data="blah")
506 with open(filename, "r", encoding="utf-8") as f:
531 with open(filename, "r", encoding="utf-8") as f:
507 self.assertEqual(f.read(), "blah")
532 self.assertEqual(f.read(), "blah")
508
533
509 def test_new_main_mod(self):
534 def test_new_main_mod(self):
510 # Smoketest to check that this accepts a unicode module name
535 # Smoketest to check that this accepts a unicode module name
511 name = u'jiefmw'
536 name = u'jiefmw'
512 mod = ip.new_main_mod(u'%s.py' % name, name)
537 mod = ip.new_main_mod(u'%s.py' % name, name)
513 self.assertEqual(mod.__name__, name)
538 self.assertEqual(mod.__name__, name)
514
539
515 def test_get_exception_only(self):
540 def test_get_exception_only(self):
516 try:
541 try:
517 raise KeyboardInterrupt
542 raise KeyboardInterrupt
518 except KeyboardInterrupt:
543 except KeyboardInterrupt:
519 msg = ip.get_exception_only()
544 msg = ip.get_exception_only()
520 self.assertEqual(msg, 'KeyboardInterrupt\n')
545 self.assertEqual(msg, 'KeyboardInterrupt\n')
521
546
522 try:
547 try:
523 raise DerivedInterrupt("foo")
548 raise DerivedInterrupt("foo")
524 except KeyboardInterrupt:
549 except KeyboardInterrupt:
525 msg = ip.get_exception_only()
550 msg = ip.get_exception_only()
526 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
551 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
527
552
528 def test_inspect_text(self):
553 def test_inspect_text(self):
529 ip.run_cell('a = 5')
554 ip.run_cell('a = 5')
530 text = ip.object_inspect_text('a')
555 text = ip.object_inspect_text('a')
531 self.assertIsInstance(text, str)
556 self.assertIsInstance(text, str)
532
557
533 def test_last_execution_result(self):
558 def test_last_execution_result(self):
534 """ Check that last execution result gets set correctly (GH-10702) """
559 """ Check that last execution result gets set correctly (GH-10702) """
535 result = ip.run_cell('a = 5; a')
560 result = ip.run_cell('a = 5; a')
536 self.assertTrue(ip.last_execution_succeeded)
561 self.assertTrue(ip.last_execution_succeeded)
537 self.assertEqual(ip.last_execution_result.result, 5)
562 self.assertEqual(ip.last_execution_result.result, 5)
538
563
539 result = ip.run_cell('a = x_invalid_id_x')
564 result = ip.run_cell('a = x_invalid_id_x')
540 self.assertFalse(ip.last_execution_succeeded)
565 self.assertFalse(ip.last_execution_succeeded)
541 self.assertFalse(ip.last_execution_result.success)
566 self.assertFalse(ip.last_execution_result.success)
542 self.assertIsInstance(ip.last_execution_result.error_in_exec, NameError)
567 self.assertIsInstance(ip.last_execution_result.error_in_exec, NameError)
543
568
544 def test_reset_aliasing(self):
569 def test_reset_aliasing(self):
545 """ Check that standard posix aliases work after %reset. """
570 """ Check that standard posix aliases work after %reset. """
546 if os.name != 'posix':
571 if os.name != 'posix':
547 return
572 return
548
573
549 ip.reset()
574 ip.reset()
550 for cmd in ('clear', 'more', 'less', 'man'):
575 for cmd in ('clear', 'more', 'less', 'man'):
551 res = ip.run_cell('%' + cmd)
576 res = ip.run_cell('%' + cmd)
552 self.assertEqual(res.success, True)
577 self.assertEqual(res.success, True)
553
578
554
579
555 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
580 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
556
581
557 @onlyif_unicode_paths
582 @onlyif_unicode_paths
558 def setUp(self):
583 def setUp(self):
559 self.BASETESTDIR = tempfile.mkdtemp()
584 self.BASETESTDIR = tempfile.mkdtemp()
560 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
585 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
561 os.mkdir(self.TESTDIR)
586 os.mkdir(self.TESTDIR)
562 with open(
587 with open(
563 join(self.TESTDIR, "åäötestscript.py"), "w", encoding="utf-8"
588 join(self.TESTDIR, "åäötestscript.py"), "w", encoding="utf-8"
564 ) as sfile:
589 ) as sfile:
565 sfile.write("pass\n")
590 sfile.write("pass\n")
566 self.oldpath = os.getcwd()
591 self.oldpath = os.getcwd()
567 os.chdir(self.TESTDIR)
592 os.chdir(self.TESTDIR)
568 self.fname = u"åäötestscript.py"
593 self.fname = u"åäötestscript.py"
569
594
570 def tearDown(self):
595 def tearDown(self):
571 os.chdir(self.oldpath)
596 os.chdir(self.oldpath)
572 shutil.rmtree(self.BASETESTDIR)
597 shutil.rmtree(self.BASETESTDIR)
573
598
574 @onlyif_unicode_paths
599 @onlyif_unicode_paths
575 def test_1(self):
600 def test_1(self):
576 """Test safe_execfile with non-ascii path
601 """Test safe_execfile with non-ascii path
577 """
602 """
578 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
603 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
579
604
580 class ExitCodeChecks(tt.TempFileMixin):
605 class ExitCodeChecks(tt.TempFileMixin):
581
606
582 def setUp(self):
607 def setUp(self):
583 self.system = ip.system_raw
608 self.system = ip.system_raw
584
609
585 def test_exit_code_ok(self):
610 def test_exit_code_ok(self):
586 self.system('exit 0')
611 self.system('exit 0')
587 self.assertEqual(ip.user_ns['_exit_code'], 0)
612 self.assertEqual(ip.user_ns['_exit_code'], 0)
588
613
589 def test_exit_code_error(self):
614 def test_exit_code_error(self):
590 self.system('exit 1')
615 self.system('exit 1')
591 self.assertEqual(ip.user_ns['_exit_code'], 1)
616 self.assertEqual(ip.user_ns['_exit_code'], 1)
592
617
593 @skipif(not hasattr(signal, 'SIGALRM'))
618 @skipif(not hasattr(signal, 'SIGALRM'))
594 def test_exit_code_signal(self):
619 def test_exit_code_signal(self):
595 self.mktmp("import signal, time\n"
620 self.mktmp("import signal, time\n"
596 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
621 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
597 "time.sleep(1)\n")
622 "time.sleep(1)\n")
598 self.system("%s %s" % (sys.executable, self.fname))
623 self.system("%s %s" % (sys.executable, self.fname))
599 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
624 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
600
625
601 @onlyif_cmds_exist("csh")
626 @onlyif_cmds_exist("csh")
602 def test_exit_code_signal_csh(self): # pragma: no cover
627 def test_exit_code_signal_csh(self): # pragma: no cover
603 SHELL = os.environ.get("SHELL", None)
628 SHELL = os.environ.get("SHELL", None)
604 os.environ["SHELL"] = find_cmd("csh")
629 os.environ["SHELL"] = find_cmd("csh")
605 try:
630 try:
606 self.test_exit_code_signal()
631 self.test_exit_code_signal()
607 finally:
632 finally:
608 if SHELL is not None:
633 if SHELL is not None:
609 os.environ['SHELL'] = SHELL
634 os.environ['SHELL'] = SHELL
610 else:
635 else:
611 del os.environ['SHELL']
636 del os.environ['SHELL']
612
637
613
638
614 class TestSystemRaw(ExitCodeChecks):
639 class TestSystemRaw(ExitCodeChecks):
615
640
616 def setUp(self):
641 def setUp(self):
617 super().setUp()
642 super().setUp()
618 self.system = ip.system_raw
643 self.system = ip.system_raw
619
644
620 @onlyif_unicode_paths
645 @onlyif_unicode_paths
621 def test_1(self):
646 def test_1(self):
622 """Test system_raw with non-ascii cmd
647 """Test system_raw with non-ascii cmd
623 """
648 """
624 cmd = u'''python -c "'åäö'" '''
649 cmd = u'''python -c "'åäö'" '''
625 ip.system_raw(cmd)
650 ip.system_raw(cmd)
626
651
627 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
652 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
628 @mock.patch('os.system', side_effect=KeyboardInterrupt)
653 @mock.patch('os.system', side_effect=KeyboardInterrupt)
629 def test_control_c(self, *mocks):
654 def test_control_c(self, *mocks):
630 try:
655 try:
631 self.system("sleep 1 # wont happen")
656 self.system("sleep 1 # wont happen")
632 except KeyboardInterrupt: # pragma: no cove
657 except KeyboardInterrupt: # pragma: no cove
633 self.fail(
658 self.fail(
634 "system call should intercept "
659 "system call should intercept "
635 "keyboard interrupt from subprocess.call"
660 "keyboard interrupt from subprocess.call"
636 )
661 )
637 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
662 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
638
663
639
664
640 @pytest.mark.parametrize("magic_cmd", ["pip", "conda", "cd"])
665 @pytest.mark.parametrize("magic_cmd", ["pip", "conda", "cd"])
641 def test_magic_warnings(magic_cmd):
666 def test_magic_warnings(magic_cmd):
642 if sys.platform == "win32":
667 if sys.platform == "win32":
643 to_mock = "os.system"
668 to_mock = "os.system"
644 expected_arg, expected_kwargs = magic_cmd, dict()
669 expected_arg, expected_kwargs = magic_cmd, dict()
645 else:
670 else:
646 to_mock = "subprocess.call"
671 to_mock = "subprocess.call"
647 expected_arg, expected_kwargs = magic_cmd, dict(
672 expected_arg, expected_kwargs = magic_cmd, dict(
648 shell=True, executable=os.environ.get("SHELL", None)
673 shell=True, executable=os.environ.get("SHELL", None)
649 )
674 )
650
675
651 with mock.patch(to_mock, return_value=0) as mock_sub:
676 with mock.patch(to_mock, return_value=0) as mock_sub:
652 with pytest.warns(Warning, match=r"You executed the system command"):
677 with pytest.warns(Warning, match=r"You executed the system command"):
653 ip.system_raw(magic_cmd)
678 ip.system_raw(magic_cmd)
654 mock_sub.assert_called_once_with(expected_arg, **expected_kwargs)
679 mock_sub.assert_called_once_with(expected_arg, **expected_kwargs)
655
680
656
681
657 # TODO: Exit codes are currently ignored on Windows.
682 # TODO: Exit codes are currently ignored on Windows.
658 class TestSystemPipedExitCode(ExitCodeChecks):
683 class TestSystemPipedExitCode(ExitCodeChecks):
659
684
660 def setUp(self):
685 def setUp(self):
661 super().setUp()
686 super().setUp()
662 self.system = ip.system_piped
687 self.system = ip.system_piped
663
688
664 @skip_win32
689 @skip_win32
665 def test_exit_code_ok(self):
690 def test_exit_code_ok(self):
666 ExitCodeChecks.test_exit_code_ok(self)
691 ExitCodeChecks.test_exit_code_ok(self)
667
692
668 @skip_win32
693 @skip_win32
669 def test_exit_code_error(self):
694 def test_exit_code_error(self):
670 ExitCodeChecks.test_exit_code_error(self)
695 ExitCodeChecks.test_exit_code_error(self)
671
696
672 @skip_win32
697 @skip_win32
673 def test_exit_code_signal(self):
698 def test_exit_code_signal(self):
674 ExitCodeChecks.test_exit_code_signal(self)
699 ExitCodeChecks.test_exit_code_signal(self)
675
700
676 class TestModules(tt.TempFileMixin):
701 class TestModules(tt.TempFileMixin):
677 def test_extraneous_loads(self):
702 def test_extraneous_loads(self):
678 """Test we're not loading modules on startup that we shouldn't.
703 """Test we're not loading modules on startup that we shouldn't.
679 """
704 """
680 self.mktmp("import sys\n"
705 self.mktmp("import sys\n"
681 "print('numpy' in sys.modules)\n"
706 "print('numpy' in sys.modules)\n"
682 "print('ipyparallel' in sys.modules)\n"
707 "print('ipyparallel' in sys.modules)\n"
683 "print('ipykernel' in sys.modules)\n"
708 "print('ipykernel' in sys.modules)\n"
684 )
709 )
685 out = "False\nFalse\nFalse\n"
710 out = "False\nFalse\nFalse\n"
686 tt.ipexec_validate(self.fname, out)
711 tt.ipexec_validate(self.fname, out)
687
712
688 class Negator(ast.NodeTransformer):
713 class Negator(ast.NodeTransformer):
689 """Negates all number literals in an AST."""
714 """Negates all number literals in an AST."""
690
715
691 # for python 3.7 and earlier
716 # for python 3.7 and earlier
692 def visit_Num(self, node):
717 def visit_Num(self, node):
693 node.n = -node.n
718 node.n = -node.n
694 return node
719 return node
695
720
696 # for python 3.8+
721 # for python 3.8+
697 def visit_Constant(self, node):
722 def visit_Constant(self, node):
698 if isinstance(node.value, int):
723 if isinstance(node.value, int):
699 return self.visit_Num(node)
724 return self.visit_Num(node)
700 return node
725 return node
701
726
702 class TestAstTransform(unittest.TestCase):
727 class TestAstTransform(unittest.TestCase):
703 def setUp(self):
728 def setUp(self):
704 self.negator = Negator()
729 self.negator = Negator()
705 ip.ast_transformers.append(self.negator)
730 ip.ast_transformers.append(self.negator)
706
731
707 def tearDown(self):
732 def tearDown(self):
708 ip.ast_transformers.remove(self.negator)
733 ip.ast_transformers.remove(self.negator)
709
734
710 def test_non_int_const(self):
735 def test_non_int_const(self):
711 with tt.AssertPrints("hello"):
736 with tt.AssertPrints("hello"):
712 ip.run_cell('print("hello")')
737 ip.run_cell('print("hello")')
713
738
714 def test_run_cell(self):
739 def test_run_cell(self):
715 with tt.AssertPrints("-34"):
740 with tt.AssertPrints("-34"):
716 ip.run_cell("print(12 + 22)")
741 ip.run_cell("print(12 + 22)")
717
742
718 # A named reference to a number shouldn't be transformed.
743 # A named reference to a number shouldn't be transformed.
719 ip.user_ns["n"] = 55
744 ip.user_ns["n"] = 55
720 with tt.AssertNotPrints("-55"):
745 with tt.AssertNotPrints("-55"):
721 ip.run_cell("print(n)")
746 ip.run_cell("print(n)")
722
747
723 def test_timeit(self):
748 def test_timeit(self):
724 called = set()
749 called = set()
725 def f(x):
750 def f(x):
726 called.add(x)
751 called.add(x)
727 ip.push({'f':f})
752 ip.push({'f':f})
728
753
729 with tt.AssertPrints("std. dev. of"):
754 with tt.AssertPrints("std. dev. of"):
730 ip.run_line_magic("timeit", "-n1 f(1)")
755 ip.run_line_magic("timeit", "-n1 f(1)")
731 self.assertEqual(called, {-1})
756 self.assertEqual(called, {-1})
732 called.clear()
757 called.clear()
733
758
734 with tt.AssertPrints("std. dev. of"):
759 with tt.AssertPrints("std. dev. of"):
735 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
760 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
736 self.assertEqual(called, {-2, -3})
761 self.assertEqual(called, {-2, -3})
737
762
738 def test_time(self):
763 def test_time(self):
739 called = []
764 called = []
740 def f(x):
765 def f(x):
741 called.append(x)
766 called.append(x)
742 ip.push({'f':f})
767 ip.push({'f':f})
743
768
744 # Test with an expression
769 # Test with an expression
745 with tt.AssertPrints("Wall time: "):
770 with tt.AssertPrints("Wall time: "):
746 ip.run_line_magic("time", "f(5+9)")
771 ip.run_line_magic("time", "f(5+9)")
747 self.assertEqual(called, [-14])
772 self.assertEqual(called, [-14])
748 called[:] = []
773 called[:] = []
749
774
750 # Test with a statement (different code path)
775 # Test with a statement (different code path)
751 with tt.AssertPrints("Wall time: "):
776 with tt.AssertPrints("Wall time: "):
752 ip.run_line_magic("time", "a = f(-3 + -2)")
777 ip.run_line_magic("time", "a = f(-3 + -2)")
753 self.assertEqual(called, [5])
778 self.assertEqual(called, [5])
754
779
755 def test_macro(self):
780 def test_macro(self):
756 ip.push({'a':10})
781 ip.push({'a':10})
757 # The AST transformation makes this do a+=-1
782 # The AST transformation makes this do a+=-1
758 ip.define_macro("amacro", "a+=1\nprint(a)")
783 ip.define_macro("amacro", "a+=1\nprint(a)")
759
784
760 with tt.AssertPrints("9"):
785 with tt.AssertPrints("9"):
761 ip.run_cell("amacro")
786 ip.run_cell("amacro")
762 with tt.AssertPrints("8"):
787 with tt.AssertPrints("8"):
763 ip.run_cell("amacro")
788 ip.run_cell("amacro")
764
789
765 class TestMiscTransform(unittest.TestCase):
790 class TestMiscTransform(unittest.TestCase):
766
791
767
792
768 def test_transform_only_once(self):
793 def test_transform_only_once(self):
769 cleanup = 0
794 cleanup = 0
770 line_t = 0
795 line_t = 0
771 def count_cleanup(lines):
796 def count_cleanup(lines):
772 nonlocal cleanup
797 nonlocal cleanup
773 cleanup += 1
798 cleanup += 1
774 return lines
799 return lines
775
800
776 def count_line_t(lines):
801 def count_line_t(lines):
777 nonlocal line_t
802 nonlocal line_t
778 line_t += 1
803 line_t += 1
779 return lines
804 return lines
780
805
781 ip.input_transformer_manager.cleanup_transforms.append(count_cleanup)
806 ip.input_transformer_manager.cleanup_transforms.append(count_cleanup)
782 ip.input_transformer_manager.line_transforms.append(count_line_t)
807 ip.input_transformer_manager.line_transforms.append(count_line_t)
783
808
784 ip.run_cell('1')
809 ip.run_cell('1')
785
810
786 assert cleanup == 1
811 assert cleanup == 1
787 assert line_t == 1
812 assert line_t == 1
788
813
789 class IntegerWrapper(ast.NodeTransformer):
814 class IntegerWrapper(ast.NodeTransformer):
790 """Wraps all integers in a call to Integer()"""
815 """Wraps all integers in a call to Integer()"""
791
816
792 # for Python 3.7 and earlier
817 # for Python 3.7 and earlier
793
818
794 # for Python 3.7 and earlier
819 # for Python 3.7 and earlier
795 def visit_Num(self, node):
820 def visit_Num(self, node):
796 if isinstance(node.n, int):
821 if isinstance(node.n, int):
797 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
822 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
798 args=[node], keywords=[])
823 args=[node], keywords=[])
799 return node
824 return node
800
825
801 # For Python 3.8+
826 # For Python 3.8+
802 def visit_Constant(self, node):
827 def visit_Constant(self, node):
803 if isinstance(node.value, int):
828 if isinstance(node.value, int):
804 return self.visit_Num(node)
829 return self.visit_Num(node)
805 return node
830 return node
806
831
807
832
808 class TestAstTransform2(unittest.TestCase):
833 class TestAstTransform2(unittest.TestCase):
809 def setUp(self):
834 def setUp(self):
810 self.intwrapper = IntegerWrapper()
835 self.intwrapper = IntegerWrapper()
811 ip.ast_transformers.append(self.intwrapper)
836 ip.ast_transformers.append(self.intwrapper)
812
837
813 self.calls = []
838 self.calls = []
814 def Integer(*args):
839 def Integer(*args):
815 self.calls.append(args)
840 self.calls.append(args)
816 return args
841 return args
817 ip.push({"Integer": Integer})
842 ip.push({"Integer": Integer})
818
843
819 def tearDown(self):
844 def tearDown(self):
820 ip.ast_transformers.remove(self.intwrapper)
845 ip.ast_transformers.remove(self.intwrapper)
821 del ip.user_ns['Integer']
846 del ip.user_ns['Integer']
822
847
823 def test_run_cell(self):
848 def test_run_cell(self):
824 ip.run_cell("n = 2")
849 ip.run_cell("n = 2")
825 self.assertEqual(self.calls, [(2,)])
850 self.assertEqual(self.calls, [(2,)])
826
851
827 # This shouldn't throw an error
852 # This shouldn't throw an error
828 ip.run_cell("o = 2.0")
853 ip.run_cell("o = 2.0")
829 self.assertEqual(ip.user_ns['o'], 2.0)
854 self.assertEqual(ip.user_ns['o'], 2.0)
830
855
831 def test_run_cell_non_int(self):
856 def test_run_cell_non_int(self):
832 ip.run_cell("n = 'a'")
857 ip.run_cell("n = 'a'")
833 assert self.calls == []
858 assert self.calls == []
834
859
835 def test_timeit(self):
860 def test_timeit(self):
836 called = set()
861 called = set()
837 def f(x):
862 def f(x):
838 called.add(x)
863 called.add(x)
839 ip.push({'f':f})
864 ip.push({'f':f})
840
865
841 with tt.AssertPrints("std. dev. of"):
866 with tt.AssertPrints("std. dev. of"):
842 ip.run_line_magic("timeit", "-n1 f(1)")
867 ip.run_line_magic("timeit", "-n1 f(1)")
843 self.assertEqual(called, {(1,)})
868 self.assertEqual(called, {(1,)})
844 called.clear()
869 called.clear()
845
870
846 with tt.AssertPrints("std. dev. of"):
871 with tt.AssertPrints("std. dev. of"):
847 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
872 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
848 self.assertEqual(called, {(2,), (3,)})
873 self.assertEqual(called, {(2,), (3,)})
849
874
850 class ErrorTransformer(ast.NodeTransformer):
875 class ErrorTransformer(ast.NodeTransformer):
851 """Throws an error when it sees a number."""
876 """Throws an error when it sees a number."""
852
877
853 def visit_Constant(self, node):
878 def visit_Constant(self, node):
854 if isinstance(node.value, int):
879 if isinstance(node.value, int):
855 raise ValueError("test")
880 raise ValueError("test")
856 return node
881 return node
857
882
858
883
859 class TestAstTransformError(unittest.TestCase):
884 class TestAstTransformError(unittest.TestCase):
860 def test_unregistering(self):
885 def test_unregistering(self):
861 err_transformer = ErrorTransformer()
886 err_transformer = ErrorTransformer()
862 ip.ast_transformers.append(err_transformer)
887 ip.ast_transformers.append(err_transformer)
863
888
864 with self.assertWarnsRegex(UserWarning, "It will be unregistered"):
889 with self.assertWarnsRegex(UserWarning, "It will be unregistered"):
865 ip.run_cell("1 + 2")
890 ip.run_cell("1 + 2")
866
891
867 # This should have been removed.
892 # This should have been removed.
868 self.assertNotIn(err_transformer, ip.ast_transformers)
893 self.assertNotIn(err_transformer, ip.ast_transformers)
869
894
870
895
871 class StringRejector(ast.NodeTransformer):
896 class StringRejector(ast.NodeTransformer):
872 """Throws an InputRejected when it sees a string literal.
897 """Throws an InputRejected when it sees a string literal.
873
898
874 Used to verify that NodeTransformers can signal that a piece of code should
899 Used to verify that NodeTransformers can signal that a piece of code should
875 not be executed by throwing an InputRejected.
900 not be executed by throwing an InputRejected.
876 """
901 """
877
902
878 # 3.8 only
903 # 3.8 only
879 def visit_Constant(self, node):
904 def visit_Constant(self, node):
880 if isinstance(node.value, str):
905 if isinstance(node.value, str):
881 raise InputRejected("test")
906 raise InputRejected("test")
882 return node
907 return node
883
908
884
909
885 class TestAstTransformInputRejection(unittest.TestCase):
910 class TestAstTransformInputRejection(unittest.TestCase):
886
911
887 def setUp(self):
912 def setUp(self):
888 self.transformer = StringRejector()
913 self.transformer = StringRejector()
889 ip.ast_transformers.append(self.transformer)
914 ip.ast_transformers.append(self.transformer)
890
915
891 def tearDown(self):
916 def tearDown(self):
892 ip.ast_transformers.remove(self.transformer)
917 ip.ast_transformers.remove(self.transformer)
893
918
894 def test_input_rejection(self):
919 def test_input_rejection(self):
895 """Check that NodeTransformers can reject input."""
920 """Check that NodeTransformers can reject input."""
896
921
897 expect_exception_tb = tt.AssertPrints("InputRejected: test")
922 expect_exception_tb = tt.AssertPrints("InputRejected: test")
898 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
923 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
899
924
900 # Run the same check twice to verify that the transformer is not
925 # Run the same check twice to verify that the transformer is not
901 # disabled after raising.
926 # disabled after raising.
902 with expect_exception_tb, expect_no_cell_output:
927 with expect_exception_tb, expect_no_cell_output:
903 ip.run_cell("'unsafe'")
928 ip.run_cell("'unsafe'")
904
929
905 with expect_exception_tb, expect_no_cell_output:
930 with expect_exception_tb, expect_no_cell_output:
906 res = ip.run_cell("'unsafe'")
931 res = ip.run_cell("'unsafe'")
907
932
908 self.assertIsInstance(res.error_before_exec, InputRejected)
933 self.assertIsInstance(res.error_before_exec, InputRejected)
909
934
910 def test__IPYTHON__():
935 def test__IPYTHON__():
911 # This shouldn't raise a NameError, that's all
936 # This shouldn't raise a NameError, that's all
912 __IPYTHON__
937 __IPYTHON__
913
938
914
939
915 class DummyRepr(object):
940 class DummyRepr(object):
916 def __repr__(self):
941 def __repr__(self):
917 return "DummyRepr"
942 return "DummyRepr"
918
943
919 def _repr_html_(self):
944 def _repr_html_(self):
920 return "<b>dummy</b>"
945 return "<b>dummy</b>"
921
946
922 def _repr_javascript_(self):
947 def _repr_javascript_(self):
923 return "console.log('hi');", {'key': 'value'}
948 return "console.log('hi');", {'key': 'value'}
924
949
925
950
926 def test_user_variables():
951 def test_user_variables():
927 # enable all formatters
952 # enable all formatters
928 ip.display_formatter.active_types = ip.display_formatter.format_types
953 ip.display_formatter.active_types = ip.display_formatter.format_types
929
954
930 ip.user_ns['dummy'] = d = DummyRepr()
955 ip.user_ns['dummy'] = d = DummyRepr()
931 keys = {'dummy', 'doesnotexist'}
956 keys = {'dummy', 'doesnotexist'}
932 r = ip.user_expressions({ key:key for key in keys})
957 r = ip.user_expressions({ key:key for key in keys})
933
958
934 assert keys == set(r.keys())
959 assert keys == set(r.keys())
935 dummy = r["dummy"]
960 dummy = r["dummy"]
936 assert {"status", "data", "metadata"} == set(dummy.keys())
961 assert {"status", "data", "metadata"} == set(dummy.keys())
937 assert dummy["status"] == "ok"
962 assert dummy["status"] == "ok"
938 data = dummy["data"]
963 data = dummy["data"]
939 metadata = dummy["metadata"]
964 metadata = dummy["metadata"]
940 assert data.get("text/html") == d._repr_html_()
965 assert data.get("text/html") == d._repr_html_()
941 js, jsmd = d._repr_javascript_()
966 js, jsmd = d._repr_javascript_()
942 assert data.get("application/javascript") == js
967 assert data.get("application/javascript") == js
943 assert metadata.get("application/javascript") == jsmd
968 assert metadata.get("application/javascript") == jsmd
944
969
945 dne = r["doesnotexist"]
970 dne = r["doesnotexist"]
946 assert dne["status"] == "error"
971 assert dne["status"] == "error"
947 assert dne["ename"] == "NameError"
972 assert dne["ename"] == "NameError"
948
973
949 # back to text only
974 # back to text only
950 ip.display_formatter.active_types = ['text/plain']
975 ip.display_formatter.active_types = ['text/plain']
951
976
952 def test_user_expression():
977 def test_user_expression():
953 # enable all formatters
978 # enable all formatters
954 ip.display_formatter.active_types = ip.display_formatter.format_types
979 ip.display_formatter.active_types = ip.display_formatter.format_types
955 query = {
980 query = {
956 'a' : '1 + 2',
981 'a' : '1 + 2',
957 'b' : '1/0',
982 'b' : '1/0',
958 }
983 }
959 r = ip.user_expressions(query)
984 r = ip.user_expressions(query)
960 import pprint
985 import pprint
961 pprint.pprint(r)
986 pprint.pprint(r)
962 assert set(r.keys()) == set(query.keys())
987 assert set(r.keys()) == set(query.keys())
963 a = r["a"]
988 a = r["a"]
964 assert {"status", "data", "metadata"} == set(a.keys())
989 assert {"status", "data", "metadata"} == set(a.keys())
965 assert a["status"] == "ok"
990 assert a["status"] == "ok"
966 data = a["data"]
991 data = a["data"]
967 metadata = a["metadata"]
992 metadata = a["metadata"]
968 assert data.get("text/plain") == "3"
993 assert data.get("text/plain") == "3"
969
994
970 b = r["b"]
995 b = r["b"]
971 assert b["status"] == "error"
996 assert b["status"] == "error"
972 assert b["ename"] == "ZeroDivisionError"
997 assert b["ename"] == "ZeroDivisionError"
973
998
974 # back to text only
999 # back to text only
975 ip.display_formatter.active_types = ['text/plain']
1000 ip.display_formatter.active_types = ['text/plain']
976
1001
977
1002
978 class TestSyntaxErrorTransformer(unittest.TestCase):
1003 class TestSyntaxErrorTransformer(unittest.TestCase):
979 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
1004 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
980
1005
981 @staticmethod
1006 @staticmethod
982 def transformer(lines):
1007 def transformer(lines):
983 for line in lines:
1008 for line in lines:
984 pos = line.find('syntaxerror')
1009 pos = line.find('syntaxerror')
985 if pos >= 0:
1010 if pos >= 0:
986 e = SyntaxError('input contains "syntaxerror"')
1011 e = SyntaxError('input contains "syntaxerror"')
987 e.text = line
1012 e.text = line
988 e.offset = pos + 1
1013 e.offset = pos + 1
989 raise e
1014 raise e
990 return lines
1015 return lines
991
1016
992 def setUp(self):
1017 def setUp(self):
993 ip.input_transformers_post.append(self.transformer)
1018 ip.input_transformers_post.append(self.transformer)
994
1019
995 def tearDown(self):
1020 def tearDown(self):
996 ip.input_transformers_post.remove(self.transformer)
1021 ip.input_transformers_post.remove(self.transformer)
997
1022
998 def test_syntaxerror_input_transformer(self):
1023 def test_syntaxerror_input_transformer(self):
999 with tt.AssertPrints('1234'):
1024 with tt.AssertPrints('1234'):
1000 ip.run_cell('1234')
1025 ip.run_cell('1234')
1001 with tt.AssertPrints('SyntaxError: invalid syntax'):
1026 with tt.AssertPrints('SyntaxError: invalid syntax'):
1002 ip.run_cell('1 2 3') # plain python syntax error
1027 ip.run_cell('1 2 3') # plain python syntax error
1003 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
1028 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
1004 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
1029 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
1005 with tt.AssertPrints('3456'):
1030 with tt.AssertPrints('3456'):
1006 ip.run_cell('3456')
1031 ip.run_cell('3456')
1007
1032
1008
1033
1009 class TestWarningSuppression(unittest.TestCase):
1034 class TestWarningSuppression(unittest.TestCase):
1010 def test_warning_suppression(self):
1035 def test_warning_suppression(self):
1011 ip.run_cell("import warnings")
1036 ip.run_cell("import warnings")
1012 try:
1037 try:
1013 with self.assertWarnsRegex(UserWarning, "asdf"):
1038 with self.assertWarnsRegex(UserWarning, "asdf"):
1014 ip.run_cell("warnings.warn('asdf')")
1039 ip.run_cell("warnings.warn('asdf')")
1015 # Here's the real test -- if we run that again, we should get the
1040 # Here's the real test -- if we run that again, we should get the
1016 # warning again. Traditionally, each warning was only issued once per
1041 # warning again. Traditionally, each warning was only issued once per
1017 # IPython session (approximately), even if the user typed in new and
1042 # IPython session (approximately), even if the user typed in new and
1018 # different code that should have also triggered the warning, leading
1043 # different code that should have also triggered the warning, leading
1019 # to much confusion.
1044 # to much confusion.
1020 with self.assertWarnsRegex(UserWarning, "asdf"):
1045 with self.assertWarnsRegex(UserWarning, "asdf"):
1021 ip.run_cell("warnings.warn('asdf')")
1046 ip.run_cell("warnings.warn('asdf')")
1022 finally:
1047 finally:
1023 ip.run_cell("del warnings")
1048 ip.run_cell("del warnings")
1024
1049
1025
1050
1026 def test_deprecation_warning(self):
1051 def test_deprecation_warning(self):
1027 ip.run_cell("""
1052 ip.run_cell("""
1028 import warnings
1053 import warnings
1029 def wrn():
1054 def wrn():
1030 warnings.warn(
1055 warnings.warn(
1031 "I AM A WARNING",
1056 "I AM A WARNING",
1032 DeprecationWarning
1057 DeprecationWarning
1033 )
1058 )
1034 """)
1059 """)
1035 try:
1060 try:
1036 with self.assertWarnsRegex(DeprecationWarning, "I AM A WARNING"):
1061 with self.assertWarnsRegex(DeprecationWarning, "I AM A WARNING"):
1037 ip.run_cell("wrn()")
1062 ip.run_cell("wrn()")
1038 finally:
1063 finally:
1039 ip.run_cell("del warnings")
1064 ip.run_cell("del warnings")
1040 ip.run_cell("del wrn")
1065 ip.run_cell("del wrn")
1041
1066
1042
1067
1043 class TestImportNoDeprecate(tt.TempFileMixin):
1068 class TestImportNoDeprecate(tt.TempFileMixin):
1044
1069
1045 def setUp(self):
1070 def setUp(self):
1046 """Make a valid python temp file."""
1071 """Make a valid python temp file."""
1047 self.mktmp("""
1072 self.mktmp("""
1048 import warnings
1073 import warnings
1049 def wrn():
1074 def wrn():
1050 warnings.warn(
1075 warnings.warn(
1051 "I AM A WARNING",
1076 "I AM A WARNING",
1052 DeprecationWarning
1077 DeprecationWarning
1053 )
1078 )
1054 """)
1079 """)
1055 super().setUp()
1080 super().setUp()
1056
1081
1057 def test_no_dep(self):
1082 def test_no_dep(self):
1058 """
1083 """
1059 No deprecation warning should be raised from imported functions
1084 No deprecation warning should be raised from imported functions
1060 """
1085 """
1061 ip.run_cell("from {} import wrn".format(self.fname))
1086 ip.run_cell("from {} import wrn".format(self.fname))
1062
1087
1063 with tt.AssertNotPrints("I AM A WARNING"):
1088 with tt.AssertNotPrints("I AM A WARNING"):
1064 ip.run_cell("wrn()")
1089 ip.run_cell("wrn()")
1065 ip.run_cell("del wrn")
1090 ip.run_cell("del wrn")
1066
1091
1067
1092
1068 def test_custom_exc_count():
1093 def test_custom_exc_count():
1069 hook = mock.Mock(return_value=None)
1094 hook = mock.Mock(return_value=None)
1070 ip.set_custom_exc((SyntaxError,), hook)
1095 ip.set_custom_exc((SyntaxError,), hook)
1071 before = ip.execution_count
1096 before = ip.execution_count
1072 ip.run_cell("def foo()", store_history=True)
1097 ip.run_cell("def foo()", store_history=True)
1073 # restore default excepthook
1098 # restore default excepthook
1074 ip.set_custom_exc((), None)
1099 ip.set_custom_exc((), None)
1075 assert hook.call_count == 1
1100 assert hook.call_count == 1
1076 assert ip.execution_count == before + 1
1101 assert ip.execution_count == before + 1
1077
1102
1078
1103
1079 def test_run_cell_async():
1104 def test_run_cell_async():
1080 ip.run_cell("import asyncio")
1105 ip.run_cell("import asyncio")
1081 coro = ip.run_cell_async("await asyncio.sleep(0.01)\n5")
1106 coro = ip.run_cell_async("await asyncio.sleep(0.01)\n5")
1082 assert asyncio.iscoroutine(coro)
1107 assert asyncio.iscoroutine(coro)
1083 loop = asyncio.new_event_loop()
1108 loop = asyncio.new_event_loop()
1084 result = loop.run_until_complete(coro)
1109 result = loop.run_until_complete(coro)
1085 assert isinstance(result, interactiveshell.ExecutionResult)
1110 assert isinstance(result, interactiveshell.ExecutionResult)
1086 assert result.result == 5
1111 assert result.result == 5
1087
1112
1088
1113
1089 def test_run_cell_await():
1114 def test_run_cell_await():
1090 ip.run_cell("import asyncio")
1115 ip.run_cell("import asyncio")
1091 result = ip.run_cell("await asyncio.sleep(0.01); 10")
1116 result = ip.run_cell("await asyncio.sleep(0.01); 10")
1092 assert ip.user_ns["_"] == 10
1117 assert ip.user_ns["_"] == 10
1093
1118
1094
1119
1095 def test_run_cell_asyncio_run():
1120 def test_run_cell_asyncio_run():
1096 ip.run_cell("import asyncio")
1121 ip.run_cell("import asyncio")
1097 result = ip.run_cell("await asyncio.sleep(0.01); 1")
1122 result = ip.run_cell("await asyncio.sleep(0.01); 1")
1098 assert ip.user_ns["_"] == 1
1123 assert ip.user_ns["_"] == 1
1099 result = ip.run_cell("asyncio.run(asyncio.sleep(0.01)); 2")
1124 result = ip.run_cell("asyncio.run(asyncio.sleep(0.01)); 2")
1100 assert ip.user_ns["_"] == 2
1125 assert ip.user_ns["_"] == 2
1101 result = ip.run_cell("await asyncio.sleep(0.01); 3")
1126 result = ip.run_cell("await asyncio.sleep(0.01); 3")
1102 assert ip.user_ns["_"] == 3
1127 assert ip.user_ns["_"] == 3
1103
1128
1104
1129
1105 def test_should_run_async():
1130 def test_should_run_async():
1106 assert not ip.should_run_async("a = 5", transformed_cell="a = 5")
1131 assert not ip.should_run_async("a = 5", transformed_cell="a = 5")
1107 assert ip.should_run_async("await x", transformed_cell="await x")
1132 assert ip.should_run_async("await x", transformed_cell="await x")
1108 assert ip.should_run_async(
1133 assert ip.should_run_async(
1109 "import asyncio; await asyncio.sleep(1)",
1134 "import asyncio; await asyncio.sleep(1)",
1110 transformed_cell="import asyncio; await asyncio.sleep(1)",
1135 transformed_cell="import asyncio; await asyncio.sleep(1)",
1111 )
1136 )
1112
1137
1113
1138
1114 def test_set_custom_completer():
1139 def test_set_custom_completer():
1115 num_completers = len(ip.Completer.matchers)
1140 num_completers = len(ip.Completer.matchers)
1116
1141
1117 def foo(*args, **kwargs):
1142 def foo(*args, **kwargs):
1118 return "I'm a completer!"
1143 return "I'm a completer!"
1119
1144
1120 ip.set_custom_completer(foo, 0)
1145 ip.set_custom_completer(foo, 0)
1121
1146
1122 # check that we've really added a new completer
1147 # check that we've really added a new completer
1123 assert len(ip.Completer.matchers) == num_completers + 1
1148 assert len(ip.Completer.matchers) == num_completers + 1
1124
1149
1125 # check that the first completer is the function we defined
1150 # check that the first completer is the function we defined
1126 assert ip.Completer.matchers[0]() == "I'm a completer!"
1151 assert ip.Completer.matchers[0]() == "I'm a completer!"
1127
1152
1128 # clean up
1153 # clean up
1129 ip.Completer.custom_matchers.pop()
1154 ip.Completer.custom_matchers.pop()
1130
1155
1131
1156
1132 class TestShowTracebackAttack(unittest.TestCase):
1157 class TestShowTracebackAttack(unittest.TestCase):
1133 """Test that the interactive shell is resilient against the client attack of
1158 """Test that the interactive shell is resilient against the client attack of
1134 manipulating the showtracebacks method. These attacks shouldn't result in an
1159 manipulating the showtracebacks method. These attacks shouldn't result in an
1135 unhandled exception in the kernel."""
1160 unhandled exception in the kernel."""
1136
1161
1137 def setUp(self):
1162 def setUp(self):
1138 self.orig_showtraceback = interactiveshell.InteractiveShell.showtraceback
1163 self.orig_showtraceback = interactiveshell.InteractiveShell.showtraceback
1139
1164
1140 def tearDown(self):
1165 def tearDown(self):
1141 interactiveshell.InteractiveShell.showtraceback = self.orig_showtraceback
1166 interactiveshell.InteractiveShell.showtraceback = self.orig_showtraceback
1142
1167
1143 def test_set_show_tracebacks_none(self):
1168 def test_set_show_tracebacks_none(self):
1144 """Test the case of the client setting showtracebacks to None"""
1169 """Test the case of the client setting showtracebacks to None"""
1145
1170
1146 result = ip.run_cell(
1171 result = ip.run_cell(
1147 """
1172 """
1148 import IPython.core.interactiveshell
1173 import IPython.core.interactiveshell
1149 IPython.core.interactiveshell.InteractiveShell.showtraceback = None
1174 IPython.core.interactiveshell.InteractiveShell.showtraceback = None
1150
1175
1151 assert False, "This should not raise an exception"
1176 assert False, "This should not raise an exception"
1152 """
1177 """
1153 )
1178 )
1154 print(result)
1179 print(result)
1155
1180
1156 assert result.result is None
1181 assert result.result is None
1157 assert isinstance(result.error_in_exec, TypeError)
1182 assert isinstance(result.error_in_exec, TypeError)
1158 assert str(result.error_in_exec) == "'NoneType' object is not callable"
1183 assert str(result.error_in_exec) == "'NoneType' object is not callable"
1159
1184
1160 def test_set_show_tracebacks_noop(self):
1185 def test_set_show_tracebacks_noop(self):
1161 """Test the case of the client setting showtracebacks to a no op lambda"""
1186 """Test the case of the client setting showtracebacks to a no op lambda"""
1162
1187
1163 result = ip.run_cell(
1188 result = ip.run_cell(
1164 """
1189 """
1165 import IPython.core.interactiveshell
1190 import IPython.core.interactiveshell
1166 IPython.core.interactiveshell.InteractiveShell.showtraceback = lambda *args, **kwargs: None
1191 IPython.core.interactiveshell.InteractiveShell.showtraceback = lambda *args, **kwargs: None
1167
1192
1168 assert False, "This should not raise an exception"
1193 assert False, "This should not raise an exception"
1169 """
1194 """
1170 )
1195 )
1171 print(result)
1196 print(result)
1172
1197
1173 assert result.result is None
1198 assert result.result is None
1174 assert isinstance(result.error_in_exec, AssertionError)
1199 assert isinstance(result.error_in_exec, AssertionError)
1175 assert str(result.error_in_exec) == "This should not raise an exception"
1200 assert str(result.error_in_exec) == "This should not raise an exception"
@@ -1,1531 +1,1548 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions."""
2 """Tests for various magic functions."""
3
3
4 import gc
4 import gc
5 import io
5 import io
6 import os
6 import os
7 import re
7 import re
8 import shlex
8 import shlex
9 import sys
9 import sys
10 import warnings
10 import warnings
11 from importlib import invalidate_caches
11 from importlib import invalidate_caches
12 from io import StringIO
12 from io import StringIO
13 from pathlib import Path
13 from pathlib import Path
14 from textwrap import dedent
14 from textwrap import dedent
15 from unittest import TestCase, mock
15 from unittest import TestCase, mock
16
16
17 import pytest
17 import pytest
18
18
19 from IPython import get_ipython
19 from IPython import get_ipython
20 from IPython.core import magic
20 from IPython.core import magic
21 from IPython.core.error import UsageError
21 from IPython.core.error import UsageError
22 from IPython.core.magic import (
22 from IPython.core.magic import (
23 Magics,
23 Magics,
24 cell_magic,
24 cell_magic,
25 line_magic,
25 line_magic,
26 magics_class,
26 magics_class,
27 register_cell_magic,
27 register_cell_magic,
28 register_line_magic,
28 register_line_magic,
29 )
29 )
30 from IPython.core.magics import code, execution, logging, osm, script
30 from IPython.core.magics import code, execution, logging, osm, script
31 from IPython.testing import decorators as dec
31 from IPython.testing import decorators as dec
32 from IPython.testing import tools as tt
32 from IPython.testing import tools as tt
33 from IPython.utils.io import capture_output
33 from IPython.utils.io import capture_output
34 from IPython.utils.process import find_cmd
34 from IPython.utils.process import find_cmd
35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
36 from IPython.utils.syspathcontext import prepended_to_syspath
36 from IPython.utils.syspathcontext import prepended_to_syspath
37
37
38 from .test_debugger import PdbTestInput
38 from .test_debugger import PdbTestInput
39
39
40 from tempfile import NamedTemporaryFile
40 from tempfile import NamedTemporaryFile
41
41
42 @magic.magics_class
42 @magic.magics_class
43 class DummyMagics(magic.Magics): pass
43 class DummyMagics(magic.Magics): pass
44
44
45 def test_extract_code_ranges():
45 def test_extract_code_ranges():
46 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
46 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
47 expected = [
47 expected = [
48 (0, 1),
48 (0, 1),
49 (2, 3),
49 (2, 3),
50 (4, 6),
50 (4, 6),
51 (6, 9),
51 (6, 9),
52 (9, 14),
52 (9, 14),
53 (16, None),
53 (16, None),
54 (None, 9),
54 (None, 9),
55 (9, None),
55 (9, None),
56 (None, 13),
56 (None, 13),
57 (None, None),
57 (None, None),
58 ]
58 ]
59 actual = list(code.extract_code_ranges(instr))
59 actual = list(code.extract_code_ranges(instr))
60 assert actual == expected
60 assert actual == expected
61
61
62 def test_extract_symbols():
62 def test_extract_symbols():
63 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
63 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
64 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
64 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
65 expected = [([], ['a']),
65 expected = [([], ['a']),
66 (["def b():\n return 42\n"], []),
66 (["def b():\n return 42\n"], []),
67 (["class A: pass\n"], []),
67 (["class A: pass\n"], []),
68 (["class A: pass\n", "def b():\n return 42\n"], []),
68 (["class A: pass\n", "def b():\n return 42\n"], []),
69 (["class A: pass\n"], ['a']),
69 (["class A: pass\n"], ['a']),
70 ([], ['z'])]
70 ([], ['z'])]
71 for symbols, exp in zip(symbols_args, expected):
71 for symbols, exp in zip(symbols_args, expected):
72 assert code.extract_symbols(source, symbols) == exp
72 assert code.extract_symbols(source, symbols) == exp
73
73
74
74
75 def test_extract_symbols_raises_exception_with_non_python_code():
75 def test_extract_symbols_raises_exception_with_non_python_code():
76 source = ("=begin A Ruby program :)=end\n"
76 source = ("=begin A Ruby program :)=end\n"
77 "def hello\n"
77 "def hello\n"
78 "puts 'Hello world'\n"
78 "puts 'Hello world'\n"
79 "end")
79 "end")
80 with pytest.raises(SyntaxError):
80 with pytest.raises(SyntaxError):
81 code.extract_symbols(source, "hello")
81 code.extract_symbols(source, "hello")
82
82
83
83
84 def test_magic_not_found():
84 def test_magic_not_found():
85 # magic not found raises UsageError
85 # magic not found raises UsageError
86 with pytest.raises(UsageError):
86 with pytest.raises(UsageError):
87 _ip.run_line_magic("doesntexist", "")
87 _ip.run_line_magic("doesntexist", "")
88
88
89 # ensure result isn't success when a magic isn't found
89 # ensure result isn't success when a magic isn't found
90 result = _ip.run_cell('%doesntexist')
90 result = _ip.run_cell('%doesntexist')
91 assert isinstance(result.error_in_exec, UsageError)
91 assert isinstance(result.error_in_exec, UsageError)
92
92
93
93
94 def test_cell_magic_not_found():
94 def test_cell_magic_not_found():
95 # magic not found raises UsageError
95 # magic not found raises UsageError
96 with pytest.raises(UsageError):
96 with pytest.raises(UsageError):
97 _ip.run_cell_magic('doesntexist', 'line', 'cell')
97 _ip.run_cell_magic('doesntexist', 'line', 'cell')
98
98
99 # ensure result isn't success when a magic isn't found
99 # ensure result isn't success when a magic isn't found
100 result = _ip.run_cell('%%doesntexist')
100 result = _ip.run_cell('%%doesntexist')
101 assert isinstance(result.error_in_exec, UsageError)
101 assert isinstance(result.error_in_exec, UsageError)
102
102
103
103
104 def test_magic_error_status():
104 def test_magic_error_status():
105 def fail(shell):
105 def fail(shell):
106 1/0
106 1/0
107 _ip.register_magic_function(fail)
107 _ip.register_magic_function(fail)
108 result = _ip.run_cell('%fail')
108 result = _ip.run_cell('%fail')
109 assert isinstance(result.error_in_exec, ZeroDivisionError)
109 assert isinstance(result.error_in_exec, ZeroDivisionError)
110
110
111
111
112 def test_config():
112 def test_config():
113 """ test that config magic does not raise
113 """ test that config magic does not raise
114 can happen if Configurable init is moved too early into
114 can happen if Configurable init is moved too early into
115 Magics.__init__ as then a Config object will be registered as a
115 Magics.__init__ as then a Config object will be registered as a
116 magic.
116 magic.
117 """
117 """
118 ## should not raise.
118 ## should not raise.
119 _ip.run_line_magic("config", "")
119 _ip.run_line_magic("config", "")
120
120
121
121
122 def test_config_available_configs():
122 def test_config_available_configs():
123 """ test that config magic prints available configs in unique and
123 """ test that config magic prints available configs in unique and
124 sorted order. """
124 sorted order. """
125 with capture_output() as captured:
125 with capture_output() as captured:
126 _ip.run_line_magic("config", "")
126 _ip.run_line_magic("config", "")
127
127
128 stdout = captured.stdout
128 stdout = captured.stdout
129 config_classes = stdout.strip().split('\n')[1:]
129 config_classes = stdout.strip().split('\n')[1:]
130 assert config_classes == sorted(set(config_classes))
130 assert config_classes == sorted(set(config_classes))
131
131
132 def test_config_print_class():
132 def test_config_print_class():
133 """ test that config with a classname prints the class's options. """
133 """ test that config with a classname prints the class's options. """
134 with capture_output() as captured:
134 with capture_output() as captured:
135 _ip.run_line_magic("config", "TerminalInteractiveShell")
135 _ip.run_line_magic("config", "TerminalInteractiveShell")
136
136
137 stdout = captured.stdout
137 stdout = captured.stdout
138 assert re.match(
138 assert re.match(
139 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
139 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
140 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
140 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
141
141
142
142
143 def test_rehashx():
143 def test_rehashx():
144 # clear up everything
144 # clear up everything
145 _ip.alias_manager.clear_aliases()
145 _ip.alias_manager.clear_aliases()
146 del _ip.db['syscmdlist']
146 del _ip.db['syscmdlist']
147
147
148 _ip.run_line_magic("rehashx", "")
148 _ip.run_line_magic("rehashx", "")
149 # Practically ALL ipython development systems will have more than 10 aliases
149 # Practically ALL ipython development systems will have more than 10 aliases
150
150
151 assert len(_ip.alias_manager.aliases) > 10
151 assert len(_ip.alias_manager.aliases) > 10
152 for name, cmd in _ip.alias_manager.aliases:
152 for name, cmd in _ip.alias_manager.aliases:
153 # we must strip dots from alias names
153 # we must strip dots from alias names
154 assert "." not in name
154 assert "." not in name
155
155
156 # rehashx must fill up syscmdlist
156 # rehashx must fill up syscmdlist
157 scoms = _ip.db['syscmdlist']
157 scoms = _ip.db['syscmdlist']
158 assert len(scoms) > 10
158 assert len(scoms) > 10
159
159
160
160
161 def test_magic_parse_options():
161 def test_magic_parse_options():
162 """Test that we don't mangle paths when parsing magic options."""
162 """Test that we don't mangle paths when parsing magic options."""
163 ip = get_ipython()
163 ip = get_ipython()
164 path = 'c:\\x'
164 path = 'c:\\x'
165 m = DummyMagics(ip)
165 m = DummyMagics(ip)
166 opts = m.parse_options('-f %s' % path,'f:')[0]
166 opts = m.parse_options('-f %s' % path,'f:')[0]
167 # argv splitting is os-dependent
167 # argv splitting is os-dependent
168 if os.name == 'posix':
168 if os.name == 'posix':
169 expected = 'c:x'
169 expected = 'c:x'
170 else:
170 else:
171 expected = path
171 expected = path
172 assert opts["f"] == expected
172 assert opts["f"] == expected
173
173
174
174
175 def test_magic_parse_long_options():
175 def test_magic_parse_long_options():
176 """Magic.parse_options can handle --foo=bar long options"""
176 """Magic.parse_options can handle --foo=bar long options"""
177 ip = get_ipython()
177 ip = get_ipython()
178 m = DummyMagics(ip)
178 m = DummyMagics(ip)
179 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
179 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
180 assert "foo" in opts
180 assert "foo" in opts
181 assert "bar" in opts
181 assert "bar" in opts
182 assert opts["bar"] == "bubble"
182 assert opts["bar"] == "bubble"
183
183
184
184
185 def doctest_hist_f():
185 def doctest_hist_f():
186 """Test %hist -f with temporary filename.
186 """Test %hist -f with temporary filename.
187
187
188 In [9]: import tempfile
188 In [9]: import tempfile
189
189
190 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
190 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
191
191
192 In [11]: %hist -nl -f $tfile 3
192 In [11]: %hist -nl -f $tfile 3
193
193
194 In [13]: import os; os.unlink(tfile)
194 In [13]: import os; os.unlink(tfile)
195 """
195 """
196
196
197
197
198 def doctest_hist_op():
198 def doctest_hist_op():
199 """Test %hist -op
199 """Test %hist -op
200
200
201 In [1]: class b(float):
201 In [1]: class b(float):
202 ...: pass
202 ...: pass
203 ...:
203 ...:
204
204
205 In [2]: class s(object):
205 In [2]: class s(object):
206 ...: def __str__(self):
206 ...: def __str__(self):
207 ...: return 's'
207 ...: return 's'
208 ...:
208 ...:
209
209
210 In [3]:
210 In [3]:
211
211
212 In [4]: class r(b):
212 In [4]: class r(b):
213 ...: def __repr__(self):
213 ...: def __repr__(self):
214 ...: return 'r'
214 ...: return 'r'
215 ...:
215 ...:
216
216
217 In [5]: class sr(s,r): pass
217 In [5]: class sr(s,r): pass
218 ...:
218 ...:
219
219
220 In [6]:
220 In [6]:
221
221
222 In [7]: bb=b()
222 In [7]: bb=b()
223
223
224 In [8]: ss=s()
224 In [8]: ss=s()
225
225
226 In [9]: rr=r()
226 In [9]: rr=r()
227
227
228 In [10]: ssrr=sr()
228 In [10]: ssrr=sr()
229
229
230 In [11]: 4.5
230 In [11]: 4.5
231 Out[11]: 4.5
231 Out[11]: 4.5
232
232
233 In [12]: str(ss)
233 In [12]: str(ss)
234 Out[12]: 's'
234 Out[12]: 's'
235
235
236 In [13]:
236 In [13]:
237
237
238 In [14]: %hist -op
238 In [14]: %hist -op
239 >>> class b:
239 >>> class b:
240 ... pass
240 ... pass
241 ...
241 ...
242 >>> class s(b):
242 >>> class s(b):
243 ... def __str__(self):
243 ... def __str__(self):
244 ... return 's'
244 ... return 's'
245 ...
245 ...
246 >>>
246 >>>
247 >>> class r(b):
247 >>> class r(b):
248 ... def __repr__(self):
248 ... def __repr__(self):
249 ... return 'r'
249 ... return 'r'
250 ...
250 ...
251 >>> class sr(s,r): pass
251 >>> class sr(s,r): pass
252 >>>
252 >>>
253 >>> bb=b()
253 >>> bb=b()
254 >>> ss=s()
254 >>> ss=s()
255 >>> rr=r()
255 >>> rr=r()
256 >>> ssrr=sr()
256 >>> ssrr=sr()
257 >>> 4.5
257 >>> 4.5
258 4.5
258 4.5
259 >>> str(ss)
259 >>> str(ss)
260 's'
260 's'
261 >>>
261 >>>
262 """
262 """
263
263
264 def test_hist_pof():
264 def test_hist_pof():
265 ip = get_ipython()
265 ip = get_ipython()
266 ip.run_cell("1+2", store_history=True)
266 ip.run_cell("1+2", store_history=True)
267 #raise Exception(ip.history_manager.session_number)
267 #raise Exception(ip.history_manager.session_number)
268 #raise Exception(list(ip.history_manager._get_range_session()))
268 #raise Exception(list(ip.history_manager._get_range_session()))
269 with TemporaryDirectory() as td:
269 with TemporaryDirectory() as td:
270 tf = os.path.join(td, 'hist.py')
270 tf = os.path.join(td, 'hist.py')
271 ip.run_line_magic('history', '-pof %s' % tf)
271 ip.run_line_magic('history', '-pof %s' % tf)
272 assert os.path.isfile(tf)
272 assert os.path.isfile(tf)
273
273
274
274
275 def test_macro():
275 def test_macro():
276 ip = get_ipython()
276 ip = get_ipython()
277 ip.history_manager.reset() # Clear any existing history.
277 ip.history_manager.reset() # Clear any existing history.
278 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
278 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
279 for i, cmd in enumerate(cmds, start=1):
279 for i, cmd in enumerate(cmds, start=1):
280 ip.history_manager.store_inputs(i, cmd)
280 ip.history_manager.store_inputs(i, cmd)
281 ip.run_line_magic("macro", "test 1-3")
281 ip.run_line_magic("macro", "test 1-3")
282 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
282 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
283
283
284 # List macros
284 # List macros
285 assert "test" in ip.run_line_magic("macro", "")
285 assert "test" in ip.run_line_magic("macro", "")
286
286
287
287
288 def test_macro_run():
288 def test_macro_run():
289 """Test that we can run a multi-line macro successfully."""
289 """Test that we can run a multi-line macro successfully."""
290 ip = get_ipython()
290 ip = get_ipython()
291 ip.history_manager.reset()
291 ip.history_manager.reset()
292 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
292 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
293 for cmd in cmds:
293 for cmd in cmds:
294 ip.run_cell(cmd, store_history=True)
294 ip.run_cell(cmd, store_history=True)
295 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
295 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
296 with tt.AssertPrints("12"):
296 with tt.AssertPrints("12"):
297 ip.run_cell("test")
297 ip.run_cell("test")
298 with tt.AssertPrints("13"):
298 with tt.AssertPrints("13"):
299 ip.run_cell("test")
299 ip.run_cell("test")
300
300
301
301
302 def test_magic_magic():
302 def test_magic_magic():
303 """Test %magic"""
303 """Test %magic"""
304 ip = get_ipython()
304 ip = get_ipython()
305 with capture_output() as captured:
305 with capture_output() as captured:
306 ip.run_line_magic("magic", "")
306 ip.run_line_magic("magic", "")
307
307
308 stdout = captured.stdout
308 stdout = captured.stdout
309 assert "%magic" in stdout
309 assert "%magic" in stdout
310 assert "IPython" in stdout
310 assert "IPython" in stdout
311 assert "Available" in stdout
311 assert "Available" in stdout
312
312
313
313
314 @dec.skipif_not_numpy
314 @dec.skipif_not_numpy
315 def test_numpy_reset_array_undec():
315 def test_numpy_reset_array_undec():
316 "Test '%reset array' functionality"
316 "Test '%reset array' functionality"
317 _ip.ex("import numpy as np")
317 _ip.ex("import numpy as np")
318 _ip.ex("a = np.empty(2)")
318 _ip.ex("a = np.empty(2)")
319 assert "a" in _ip.user_ns
319 assert "a" in _ip.user_ns
320 _ip.run_line_magic("reset", "-f array")
320 _ip.run_line_magic("reset", "-f array")
321 assert "a" not in _ip.user_ns
321 assert "a" not in _ip.user_ns
322
322
323
323
324 def test_reset_out():
324 def test_reset_out():
325 "Test '%reset out' magic"
325 "Test '%reset out' magic"
326 _ip.run_cell("parrot = 'dead'", store_history=True)
326 _ip.run_cell("parrot = 'dead'", store_history=True)
327 # test '%reset -f out', make an Out prompt
327 # test '%reset -f out', make an Out prompt
328 _ip.run_cell("parrot", store_history=True)
328 _ip.run_cell("parrot", store_history=True)
329 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
329 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
330 _ip.run_line_magic("reset", "-f out")
330 _ip.run_line_magic("reset", "-f out")
331 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
331 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
332 assert len(_ip.user_ns["Out"]) == 0
332 assert len(_ip.user_ns["Out"]) == 0
333
333
334
334
335 def test_reset_in():
335 def test_reset_in():
336 "Test '%reset in' magic"
336 "Test '%reset in' magic"
337 # test '%reset -f in'
337 # test '%reset -f in'
338 _ip.run_cell("parrot", store_history=True)
338 _ip.run_cell("parrot", store_history=True)
339 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
339 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
340 _ip.run_line_magic("reset", "-f in")
340 _ip.run_line_magic("reset", "-f in")
341 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
341 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
342 assert len(set(_ip.user_ns["In"])) == 1
342 assert len(set(_ip.user_ns["In"])) == 1
343
343
344
344
345 def test_reset_dhist():
345 def test_reset_dhist():
346 "Test '%reset dhist' magic"
346 "Test '%reset dhist' magic"
347 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
347 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
348 _ip.run_line_magic("cd", os.path.dirname(pytest.__file__))
348 _ip.run_line_magic("cd", os.path.dirname(pytest.__file__))
349 _ip.run_line_magic("cd", "-")
349 _ip.run_line_magic("cd", "-")
350 assert len(_ip.user_ns["_dh"]) > 0
350 assert len(_ip.user_ns["_dh"]) > 0
351 _ip.run_line_magic("reset", "-f dhist")
351 _ip.run_line_magic("reset", "-f dhist")
352 assert len(_ip.user_ns["_dh"]) == 0
352 assert len(_ip.user_ns["_dh"]) == 0
353 _ip.run_cell("_dh = [d for d in tmp]") # restore
353 _ip.run_cell("_dh = [d for d in tmp]") # restore
354
354
355
355
356 def test_reset_in_length():
356 def test_reset_in_length():
357 "Test that '%reset in' preserves In[] length"
357 "Test that '%reset in' preserves In[] length"
358 _ip.run_cell("print 'foo'")
358 _ip.run_cell("print 'foo'")
359 _ip.run_cell("reset -f in")
359 _ip.run_cell("reset -f in")
360 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
360 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
361
361
362
362
363 class TestResetErrors(TestCase):
363 class TestResetErrors(TestCase):
364
364
365 def test_reset_redefine(self):
365 def test_reset_redefine(self):
366
366
367 @magics_class
367 @magics_class
368 class KernelMagics(Magics):
368 class KernelMagics(Magics):
369 @line_magic
369 @line_magic
370 def less(self, shell): pass
370 def less(self, shell): pass
371
371
372 _ip.register_magics(KernelMagics)
372 _ip.register_magics(KernelMagics)
373
373
374 with self.assertLogs() as cm:
374 with self.assertLogs() as cm:
375 # hack, we want to just capture logs, but assertLogs fails if not
375 # hack, we want to just capture logs, but assertLogs fails if not
376 # logs get produce.
376 # logs get produce.
377 # so log one things we ignore.
377 # so log one things we ignore.
378 import logging as log_mod
378 import logging as log_mod
379 log = log_mod.getLogger()
379 log = log_mod.getLogger()
380 log.info('Nothing')
380 log.info('Nothing')
381 # end hack.
381 # end hack.
382 _ip.run_cell("reset -f")
382 _ip.run_cell("reset -f")
383
383
384 assert len(cm.output) == 1
384 assert len(cm.output) == 1
385 for out in cm.output:
385 for out in cm.output:
386 assert "Invalid alias" not in out
386 assert "Invalid alias" not in out
387
387
388 def test_tb_syntaxerror():
388 def test_tb_syntaxerror():
389 """test %tb after a SyntaxError"""
389 """test %tb after a SyntaxError"""
390 ip = get_ipython()
390 ip = get_ipython()
391 ip.run_cell("for")
391 ip.run_cell("for")
392
392
393 # trap and validate stdout
393 # trap and validate stdout
394 save_stdout = sys.stdout
394 save_stdout = sys.stdout
395 try:
395 try:
396 sys.stdout = StringIO()
396 sys.stdout = StringIO()
397 ip.run_cell("%tb")
397 ip.run_cell("%tb")
398 out = sys.stdout.getvalue()
398 out = sys.stdout.getvalue()
399 finally:
399 finally:
400 sys.stdout = save_stdout
400 sys.stdout = save_stdout
401 # trim output, and only check the last line
401 # trim output, and only check the last line
402 last_line = out.rstrip().splitlines()[-1].strip()
402 last_line = out.rstrip().splitlines()[-1].strip()
403 assert last_line == "SyntaxError: invalid syntax"
403 assert last_line == "SyntaxError: invalid syntax"
404
404
405
405
406 def test_time():
406 def test_time():
407 ip = get_ipython()
407 ip = get_ipython()
408
408
409 with tt.AssertPrints("Wall time: "):
409 with tt.AssertPrints("Wall time: "):
410 ip.run_cell("%time None")
410 ip.run_cell("%time None")
411
411
412 ip.run_cell("def f(kmjy):\n"
412 ip.run_cell("def f(kmjy):\n"
413 " %time print (2*kmjy)")
413 " %time print (2*kmjy)")
414
414
415 with tt.AssertPrints("Wall time: "):
415 with tt.AssertPrints("Wall time: "):
416 with tt.AssertPrints("hihi", suppress=False):
416 with tt.AssertPrints("hihi", suppress=False):
417 ip.run_cell("f('hi')")
417 ip.run_cell("f('hi')")
418
418
419
419
420 # ';' at the end of %time prevents instruction value to be printed.
420 # ';' at the end of %time prevents instruction value to be printed.
421 # This tests fix for #13837.
421 # This tests fix for #13837.
422 def test_time_no_output_with_semicolon():
422 def test_time_no_output_with_semicolon():
423 ip = get_ipython()
423 ip = get_ipython()
424
424
425 # Test %time cases
425 # Test %time cases
426 with tt.AssertPrints(" 123456"):
426 with tt.AssertPrints(" 123456"):
427 with tt.AssertPrints("Wall time: ", suppress=False):
427 with tt.AssertPrints("Wall time: ", suppress=False):
428 with tt.AssertPrints("CPU times: ", suppress=False):
428 with tt.AssertPrints("CPU times: ", suppress=False):
429 ip.run_cell("%time 123000+456")
429 ip.run_cell("%time 123000+456")
430
430
431 with tt.AssertNotPrints(" 123456"):
431 with tt.AssertNotPrints(" 123456"):
432 with tt.AssertPrints("Wall time: ", suppress=False):
432 with tt.AssertPrints("Wall time: ", suppress=False):
433 with tt.AssertPrints("CPU times: ", suppress=False):
433 with tt.AssertPrints("CPU times: ", suppress=False):
434 ip.run_cell("%time 123000+456;")
434 ip.run_cell("%time 123000+456;")
435
435
436 with tt.AssertPrints(" 123456"):
436 with tt.AssertPrints(" 123456"):
437 with tt.AssertPrints("Wall time: ", suppress=False):
437 with tt.AssertPrints("Wall time: ", suppress=False):
438 with tt.AssertPrints("CPU times: ", suppress=False):
438 with tt.AssertPrints("CPU times: ", suppress=False):
439 ip.run_cell("%time 123000+456 # Comment")
439 ip.run_cell("%time 123000+456 # Comment")
440
440
441 with tt.AssertNotPrints(" 123456"):
441 with tt.AssertNotPrints(" 123456"):
442 with tt.AssertPrints("Wall time: ", suppress=False):
442 with tt.AssertPrints("Wall time: ", suppress=False):
443 with tt.AssertPrints("CPU times: ", suppress=False):
443 with tt.AssertPrints("CPU times: ", suppress=False):
444 ip.run_cell("%time 123000+456; # Comment")
444 ip.run_cell("%time 123000+456; # Comment")
445
445
446 with tt.AssertPrints(" 123456"):
446 with tt.AssertPrints(" 123456"):
447 with tt.AssertPrints("Wall time: ", suppress=False):
447 with tt.AssertPrints("Wall time: ", suppress=False):
448 with tt.AssertPrints("CPU times: ", suppress=False):
448 with tt.AssertPrints("CPU times: ", suppress=False):
449 ip.run_cell("%time 123000+456 # ;Comment")
449 ip.run_cell("%time 123000+456 # ;Comment")
450
450
451 # Test %%time cases
451 # Test %%time cases
452 with tt.AssertPrints("123456"):
452 with tt.AssertPrints("123456"):
453 with tt.AssertPrints("Wall time: ", suppress=False):
453 with tt.AssertPrints("Wall time: ", suppress=False):
454 with tt.AssertPrints("CPU times: ", suppress=False):
454 with tt.AssertPrints("CPU times: ", suppress=False):
455 ip.run_cell("%%time\n123000+456\n\n\n")
455 ip.run_cell("%%time\n123000+456\n\n\n")
456
456
457 with tt.AssertNotPrints("123456"):
457 with tt.AssertNotPrints("123456"):
458 with tt.AssertPrints("Wall time: ", suppress=False):
458 with tt.AssertPrints("Wall time: ", suppress=False):
459 with tt.AssertPrints("CPU times: ", suppress=False):
459 with tt.AssertPrints("CPU times: ", suppress=False):
460 ip.run_cell("%%time\n123000+456;\n\n\n")
460 ip.run_cell("%%time\n123000+456;\n\n\n")
461
461
462 with tt.AssertPrints("123456"):
462 with tt.AssertPrints("123456"):
463 with tt.AssertPrints("Wall time: ", suppress=False):
463 with tt.AssertPrints("Wall time: ", suppress=False):
464 with tt.AssertPrints("CPU times: ", suppress=False):
464 with tt.AssertPrints("CPU times: ", suppress=False):
465 ip.run_cell("%%time\n123000+456 # Comment\n\n\n")
465 ip.run_cell("%%time\n123000+456 # Comment\n\n\n")
466
466
467 with tt.AssertNotPrints("123456"):
467 with tt.AssertNotPrints("123456"):
468 with tt.AssertPrints("Wall time: ", suppress=False):
468 with tt.AssertPrints("Wall time: ", suppress=False):
469 with tt.AssertPrints("CPU times: ", suppress=False):
469 with tt.AssertPrints("CPU times: ", suppress=False):
470 ip.run_cell("%%time\n123000+456; # Comment\n\n\n")
470 ip.run_cell("%%time\n123000+456; # Comment\n\n\n")
471
471
472 with tt.AssertPrints("123456"):
472 with tt.AssertPrints("123456"):
473 with tt.AssertPrints("Wall time: ", suppress=False):
473 with tt.AssertPrints("Wall time: ", suppress=False):
474 with tt.AssertPrints("CPU times: ", suppress=False):
474 with tt.AssertPrints("CPU times: ", suppress=False):
475 ip.run_cell("%%time\n123000+456 # ;Comment\n\n\n")
475 ip.run_cell("%%time\n123000+456 # ;Comment\n\n\n")
476
476
477
477
478 def test_time_last_not_expression():
478 def test_time_last_not_expression():
479 ip.run_cell("%%time\n"
479 ip.run_cell("%%time\n"
480 "var_1 = 1\n"
480 "var_1 = 1\n"
481 "var_2 = 2\n")
481 "var_2 = 2\n")
482 assert ip.user_ns['var_1'] == 1
482 assert ip.user_ns['var_1'] == 1
483 del ip.user_ns['var_1']
483 del ip.user_ns['var_1']
484 assert ip.user_ns['var_2'] == 2
484 assert ip.user_ns['var_2'] == 2
485 del ip.user_ns['var_2']
485 del ip.user_ns['var_2']
486
486
487
487
488 @dec.skip_win32
488 @dec.skip_win32
489 def test_time2():
489 def test_time2():
490 ip = get_ipython()
490 ip = get_ipython()
491
491
492 with tt.AssertPrints("CPU times: user "):
492 with tt.AssertPrints("CPU times: user "):
493 ip.run_cell("%time None")
493 ip.run_cell("%time None")
494
494
495 def test_time3():
495 def test_time3():
496 """Erroneous magic function calls, issue gh-3334"""
496 """Erroneous magic function calls, issue gh-3334"""
497 ip = get_ipython()
497 ip = get_ipython()
498 ip.user_ns.pop('run', None)
498 ip.user_ns.pop('run', None)
499
499
500 with tt.AssertNotPrints("not found", channel='stderr'):
500 with tt.AssertNotPrints("not found", channel='stderr'):
501 ip.run_cell("%%time\n"
501 ip.run_cell("%%time\n"
502 "run = 0\n"
502 "run = 0\n"
503 "run += 1")
503 "run += 1")
504
504
505 def test_multiline_time():
505 def test_multiline_time():
506 """Make sure last statement from time return a value."""
506 """Make sure last statement from time return a value."""
507 ip = get_ipython()
507 ip = get_ipython()
508 ip.user_ns.pop('run', None)
508 ip.user_ns.pop('run', None)
509
509
510 ip.run_cell(
510 ip.run_cell(
511 dedent(
511 dedent(
512 """\
512 """\
513 %%time
513 %%time
514 a = "ho"
514 a = "ho"
515 b = "hey"
515 b = "hey"
516 a+b
516 a+b
517 """
517 """
518 )
518 )
519 )
519 )
520 assert ip.user_ns_hidden["_"] == "hohey"
520 assert ip.user_ns_hidden["_"] == "hohey"
521
521
522
522
523 def test_time_local_ns():
523 def test_time_local_ns():
524 """
524 """
525 Test that local_ns is actually global_ns when running a cell magic
525 Test that local_ns is actually global_ns when running a cell magic
526 """
526 """
527 ip = get_ipython()
527 ip = get_ipython()
528 ip.run_cell("%%time\n" "myvar = 1")
528 ip.run_cell("%%time\n" "myvar = 1")
529 assert ip.user_ns["myvar"] == 1
529 assert ip.user_ns["myvar"] == 1
530 del ip.user_ns["myvar"]
530 del ip.user_ns["myvar"]
531
531
532
532
533 # Test %%capture magic. Added to test issue #13926
533 # Test %%capture magic. Added to test issue #13926
534 def test_capture():
534 def test_capture():
535 ip = get_ipython()
535 ip = get_ipython()
536
536
537 # Test %%capture nominal case
537 # Test %%capture nominal case
538 ip.run_cell("%%capture abc\n1+2")
538 ip.run_cell("%%capture abc\n1+2")
539 with tt.AssertPrints("True", suppress=False):
539 with tt.AssertPrints("True", suppress=False):
540 ip.run_cell("'abc' in locals()")
540 ip.run_cell("'abc' in locals()")
541 with tt.AssertPrints("True", suppress=False):
541 with tt.AssertPrints("True", suppress=False):
542 ip.run_cell("'outputs' in dir(abc)")
542 ip.run_cell("'outputs' in dir(abc)")
543 with tt.AssertPrints("3", suppress=False):
543 with tt.AssertPrints("3", suppress=False):
544 ip.run_cell("abc.outputs[0]")
544 ip.run_cell("abc.outputs[0]")
545
545
546 # Test %%capture with ';' at end of expression
546 # Test %%capture with ';' at end of expression
547 ip.run_cell("%%capture abc\n7+8;")
547 ip.run_cell("%%capture abc\n7+8;")
548 with tt.AssertPrints("False", suppress=False):
548 with tt.AssertPrints("False", suppress=False):
549 ip.run_cell("'abc' in locals()")
549 ip.run_cell("'abc' in locals()")
550
550
551
551
552 def test_doctest_mode():
552 def test_doctest_mode():
553 "Toggle doctest_mode twice, it should be a no-op and run without error"
553 "Toggle doctest_mode twice, it should be a no-op and run without error"
554 _ip.run_line_magic("doctest_mode", "")
554 _ip.run_line_magic("doctest_mode", "")
555 _ip.run_line_magic("doctest_mode", "")
555 _ip.run_line_magic("doctest_mode", "")
556
556
557
557
558 def test_parse_options():
558 def test_parse_options():
559 """Tests for basic options parsing in magics."""
559 """Tests for basic options parsing in magics."""
560 # These are only the most minimal of tests, more should be added later. At
560 # These are only the most minimal of tests, more should be added later. At
561 # the very least we check that basic text/unicode calls work OK.
561 # the very least we check that basic text/unicode calls work OK.
562 m = DummyMagics(_ip)
562 m = DummyMagics(_ip)
563 assert m.parse_options("foo", "")[1] == "foo"
563 assert m.parse_options("foo", "")[1] == "foo"
564 assert m.parse_options("foo", "")[1] == "foo"
564 assert m.parse_options("foo", "")[1] == "foo"
565
565
566
566
567 def test_parse_options_preserve_non_option_string():
567 def test_parse_options_preserve_non_option_string():
568 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
568 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
569 m = DummyMagics(_ip)
569 m = DummyMagics(_ip)
570 opts, stmt = m.parse_options(
570 opts, stmt = m.parse_options(
571 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
571 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
572 )
572 )
573 assert opts == {"n": "1", "r": "13"}
573 assert opts == {"n": "1", "r": "13"}
574 assert stmt == "_ = 314 + foo"
574 assert stmt == "_ = 314 + foo"
575
575
576
576
577 def test_run_magic_preserve_code_block():
577 def test_run_magic_preserve_code_block():
578 """Test to assert preservation of non-option part of magic-block, while running magic."""
578 """Test to assert preservation of non-option part of magic-block, while running magic."""
579 _ip.user_ns["spaces"] = []
579 _ip.user_ns["spaces"] = []
580 _ip.run_line_magic(
580 _ip.run_line_magic(
581 "timeit", "-n1 -r1 spaces.append([s.count(' ') for s in ['document']])"
581 "timeit", "-n1 -r1 spaces.append([s.count(' ') for s in ['document']])"
582 )
582 )
583 assert _ip.user_ns["spaces"] == [[0]]
583 assert _ip.user_ns["spaces"] == [[0]]
584
584
585
585
586 def test_dirops():
586 def test_dirops():
587 """Test various directory handling operations."""
587 """Test various directory handling operations."""
588 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
588 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
589 curpath = os.getcwd
589 curpath = os.getcwd
590 startdir = os.getcwd()
590 startdir = os.getcwd()
591 ipdir = os.path.realpath(_ip.ipython_dir)
591 ipdir = os.path.realpath(_ip.ipython_dir)
592 try:
592 try:
593 _ip.run_line_magic("cd", '"%s"' % ipdir)
593 _ip.run_line_magic("cd", '"%s"' % ipdir)
594 assert curpath() == ipdir
594 assert curpath() == ipdir
595 _ip.run_line_magic("cd", "-")
595 _ip.run_line_magic("cd", "-")
596 assert curpath() == startdir
596 assert curpath() == startdir
597 _ip.run_line_magic("pushd", '"%s"' % ipdir)
597 _ip.run_line_magic("pushd", '"%s"' % ipdir)
598 assert curpath() == ipdir
598 assert curpath() == ipdir
599 _ip.run_line_magic("popd", "")
599 _ip.run_line_magic("popd", "")
600 assert curpath() == startdir
600 assert curpath() == startdir
601 finally:
601 finally:
602 os.chdir(startdir)
602 os.chdir(startdir)
603
603
604
604
605 def test_cd_force_quiet():
605 def test_cd_force_quiet():
606 """Test OSMagics.cd_force_quiet option"""
606 """Test OSMagics.cd_force_quiet option"""
607 _ip.config.OSMagics.cd_force_quiet = True
607 _ip.config.OSMagics.cd_force_quiet = True
608 osmagics = osm.OSMagics(shell=_ip)
608 osmagics = osm.OSMagics(shell=_ip)
609
609
610 startdir = os.getcwd()
610 startdir = os.getcwd()
611 ipdir = os.path.realpath(_ip.ipython_dir)
611 ipdir = os.path.realpath(_ip.ipython_dir)
612
612
613 try:
613 try:
614 with tt.AssertNotPrints(ipdir):
614 with tt.AssertNotPrints(ipdir):
615 osmagics.cd('"%s"' % ipdir)
615 osmagics.cd('"%s"' % ipdir)
616 with tt.AssertNotPrints(startdir):
616 with tt.AssertNotPrints(startdir):
617 osmagics.cd('-')
617 osmagics.cd('-')
618 finally:
618 finally:
619 os.chdir(startdir)
619 os.chdir(startdir)
620
620
621
621
622 def test_xmode():
622 def test_xmode():
623 # Calling xmode three times should be a no-op
623 # Calling xmode three times should be a no-op
624 xmode = _ip.InteractiveTB.mode
624 xmode = _ip.InteractiveTB.mode
625 for i in range(4):
625 for i in range(4):
626 _ip.run_line_magic("xmode", "")
626 _ip.run_line_magic("xmode", "")
627 assert _ip.InteractiveTB.mode == xmode
627 assert _ip.InteractiveTB.mode == xmode
628
628
629 def test_reset_hard():
629 def test_reset_hard():
630 monitor = []
630 monitor = []
631 class A(object):
631 class A(object):
632 def __del__(self):
632 def __del__(self):
633 monitor.append(1)
633 monitor.append(1)
634 def __repr__(self):
634 def __repr__(self):
635 return "<A instance>"
635 return "<A instance>"
636
636
637 _ip.user_ns["a"] = A()
637 _ip.user_ns["a"] = A()
638 _ip.run_cell("a")
638 _ip.run_cell("a")
639
639
640 assert monitor == []
640 assert monitor == []
641 _ip.run_line_magic("reset", "-f")
641 _ip.run_line_magic("reset", "-f")
642 assert monitor == [1]
642 assert monitor == [1]
643
643
644 class TestXdel(tt.TempFileMixin):
644 class TestXdel(tt.TempFileMixin):
645 def test_xdel(self):
645 def test_xdel(self):
646 """Test that references from %run are cleared by xdel."""
646 """Test that references from %run are cleared by xdel."""
647 src = ("class A(object):\n"
647 src = ("class A(object):\n"
648 " monitor = []\n"
648 " monitor = []\n"
649 " def __del__(self):\n"
649 " def __del__(self):\n"
650 " self.monitor.append(1)\n"
650 " self.monitor.append(1)\n"
651 "a = A()\n")
651 "a = A()\n")
652 self.mktmp(src)
652 self.mktmp(src)
653 # %run creates some hidden references...
653 # %run creates some hidden references...
654 _ip.run_line_magic("run", "%s" % self.fname)
654 _ip.run_line_magic("run", "%s" % self.fname)
655 # ... as does the displayhook.
655 # ... as does the displayhook.
656 _ip.run_cell("a")
656 _ip.run_cell("a")
657
657
658 monitor = _ip.user_ns["A"].monitor
658 monitor = _ip.user_ns["A"].monitor
659 assert monitor == []
659 assert monitor == []
660
660
661 _ip.run_line_magic("xdel", "a")
661 _ip.run_line_magic("xdel", "a")
662
662
663 # Check that a's __del__ method has been called.
663 # Check that a's __del__ method has been called.
664 gc.collect(0)
664 gc.collect(0)
665 assert monitor == [1]
665 assert monitor == [1]
666
666
667 def doctest_who():
667 def doctest_who():
668 """doctest for %who
668 """doctest for %who
669
669
670 In [1]: %reset -sf
670 In [1]: %reset -sf
671
671
672 In [2]: alpha = 123
672 In [2]: alpha = 123
673
673
674 In [3]: beta = 'beta'
674 In [3]: beta = 'beta'
675
675
676 In [4]: %who int
676 In [4]: %who int
677 alpha
677 alpha
678
678
679 In [5]: %who str
679 In [5]: %who str
680 beta
680 beta
681
681
682 In [6]: %whos
682 In [6]: %whos
683 Variable Type Data/Info
683 Variable Type Data/Info
684 ----------------------------
684 ----------------------------
685 alpha int 123
685 alpha int 123
686 beta str beta
686 beta str beta
687
687
688 In [7]: %who_ls
688 In [7]: %who_ls
689 Out[7]: ['alpha', 'beta']
689 Out[7]: ['alpha', 'beta']
690 """
690 """
691
691
692 def test_whos():
692 def test_whos():
693 """Check that whos is protected against objects where repr() fails."""
693 """Check that whos is protected against objects where repr() fails."""
694 class A(object):
694 class A(object):
695 def __repr__(self):
695 def __repr__(self):
696 raise Exception()
696 raise Exception()
697 _ip.user_ns['a'] = A()
697 _ip.user_ns['a'] = A()
698 _ip.run_line_magic("whos", "")
698 _ip.run_line_magic("whos", "")
699
699
700 def doctest_precision():
700 def doctest_precision():
701 """doctest for %precision
701 """doctest for %precision
702
702
703 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
703 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
704
704
705 In [2]: %precision 5
705 In [2]: %precision 5
706 Out[2]: '%.5f'
706 Out[2]: '%.5f'
707
707
708 In [3]: f.float_format
708 In [3]: f.float_format
709 Out[3]: '%.5f'
709 Out[3]: '%.5f'
710
710
711 In [4]: %precision %e
711 In [4]: %precision %e
712 Out[4]: '%e'
712 Out[4]: '%e'
713
713
714 In [5]: f(3.1415927)
714 In [5]: f(3.1415927)
715 Out[5]: '3.141593e+00'
715 Out[5]: '3.141593e+00'
716 """
716 """
717
717
718
718 def test_debug_magic():
719 def test_debug_magic():
719 """Test debugging a small code with %debug
720 """Test debugging a small code with %debug
720
721
721 In [1]: with PdbTestInput(['c']):
722 In [1]: with PdbTestInput(['c']):
722 ...: %debug print("a b") #doctest: +ELLIPSIS
723 ...: %debug print("a b") #doctest: +ELLIPSIS
723 ...:
724 ...:
724 ...
725 ...
725 ipdb> c
726 ipdb> c
726 a b
727 a b
727 In [2]:
728 In [2]:
728 """
729 """
729
730
731
732 def test_debug_magic_locals():
733 """Test debugging a small code with %debug with locals
734
735 In [1]: with PdbTestInput(['c']):
736 ...: def fun():
737 ...: res = 1
738 ...: %debug print(res)
739 ...: fun()
740 ...:
741 ...
742 ipdb> c
743 1
744 In [2]:
745 """
746
730 def test_psearch():
747 def test_psearch():
731 with tt.AssertPrints("dict.fromkeys"):
748 with tt.AssertPrints("dict.fromkeys"):
732 _ip.run_cell("dict.fr*?")
749 _ip.run_cell("dict.fr*?")
733 with tt.AssertPrints("π.is_integer"):
750 with tt.AssertPrints("π.is_integer"):
734 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
751 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
735
752
736 def test_timeit_shlex():
753 def test_timeit_shlex():
737 """test shlex issues with timeit (#1109)"""
754 """test shlex issues with timeit (#1109)"""
738 _ip.ex("def f(*a,**kw): pass")
755 _ip.ex("def f(*a,**kw): pass")
739 _ip.run_line_magic("timeit", '-n1 "this is a bug".count(" ")')
756 _ip.run_line_magic("timeit", '-n1 "this is a bug".count(" ")')
740 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1)')
757 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1)')
741 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1, " ", 2, " ")')
758 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1, " ", 2, " ")')
742 _ip.run_line_magic("timeit", '-r1 -n1 ("a " + "b")')
759 _ip.run_line_magic("timeit", '-r1 -n1 ("a " + "b")')
743 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b")')
760 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b")')
744 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b ")')
761 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b ")')
745
762
746
763
747 def test_timeit_special_syntax():
764 def test_timeit_special_syntax():
748 "Test %%timeit with IPython special syntax"
765 "Test %%timeit with IPython special syntax"
749 @register_line_magic
766 @register_line_magic
750 def lmagic(line):
767 def lmagic(line):
751 ip = get_ipython()
768 ip = get_ipython()
752 ip.user_ns['lmagic_out'] = line
769 ip.user_ns['lmagic_out'] = line
753
770
754 # line mode test
771 # line mode test
755 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
772 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
756 assert _ip.user_ns["lmagic_out"] == "my line"
773 assert _ip.user_ns["lmagic_out"] == "my line"
757 # cell mode test
774 # cell mode test
758 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
775 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
759 assert _ip.user_ns["lmagic_out"] == "my line2"
776 assert _ip.user_ns["lmagic_out"] == "my line2"
760
777
761
778
762 def test_timeit_return():
779 def test_timeit_return():
763 """
780 """
764 test whether timeit -o return object
781 test whether timeit -o return object
765 """
782 """
766
783
767 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
784 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
768 assert(res is not None)
785 assert(res is not None)
769
786
770 def test_timeit_quiet():
787 def test_timeit_quiet():
771 """
788 """
772 test quiet option of timeit magic
789 test quiet option of timeit magic
773 """
790 """
774 with tt.AssertNotPrints("loops"):
791 with tt.AssertNotPrints("loops"):
775 _ip.run_cell("%timeit -n1 -r1 -q 1")
792 _ip.run_cell("%timeit -n1 -r1 -q 1")
776
793
777 def test_timeit_return_quiet():
794 def test_timeit_return_quiet():
778 with tt.AssertNotPrints("loops"):
795 with tt.AssertNotPrints("loops"):
779 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
796 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
780 assert (res is not None)
797 assert (res is not None)
781
798
782 def test_timeit_invalid_return():
799 def test_timeit_invalid_return():
783 with pytest.raises(SyntaxError):
800 with pytest.raises(SyntaxError):
784 _ip.run_line_magic('timeit', 'return')
801 _ip.run_line_magic('timeit', 'return')
785
802
786 @dec.skipif(execution.profile is None)
803 @dec.skipif(execution.profile is None)
787 def test_prun_special_syntax():
804 def test_prun_special_syntax():
788 "Test %%prun with IPython special syntax"
805 "Test %%prun with IPython special syntax"
789 @register_line_magic
806 @register_line_magic
790 def lmagic(line):
807 def lmagic(line):
791 ip = get_ipython()
808 ip = get_ipython()
792 ip.user_ns['lmagic_out'] = line
809 ip.user_ns['lmagic_out'] = line
793
810
794 # line mode test
811 # line mode test
795 _ip.run_line_magic("prun", "-q %lmagic my line")
812 _ip.run_line_magic("prun", "-q %lmagic my line")
796 assert _ip.user_ns["lmagic_out"] == "my line"
813 assert _ip.user_ns["lmagic_out"] == "my line"
797 # cell mode test
814 # cell mode test
798 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
815 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
799 assert _ip.user_ns["lmagic_out"] == "my line2"
816 assert _ip.user_ns["lmagic_out"] == "my line2"
800
817
801
818
802 @dec.skipif(execution.profile is None)
819 @dec.skipif(execution.profile is None)
803 def test_prun_quotes():
820 def test_prun_quotes():
804 "Test that prun does not clobber string escapes (GH #1302)"
821 "Test that prun does not clobber string escapes (GH #1302)"
805 _ip.magic(r"prun -q x = '\t'")
822 _ip.magic(r"prun -q x = '\t'")
806 assert _ip.user_ns["x"] == "\t"
823 assert _ip.user_ns["x"] == "\t"
807
824
808
825
809 def test_extension():
826 def test_extension():
810 # Debugging information for failures of this test
827 # Debugging information for failures of this test
811 print('sys.path:')
828 print('sys.path:')
812 for p in sys.path:
829 for p in sys.path:
813 print(' ', p)
830 print(' ', p)
814 print('CWD', os.getcwd())
831 print('CWD', os.getcwd())
815
832
816 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
833 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
817 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
834 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
818 sys.path.insert(0, daft_path)
835 sys.path.insert(0, daft_path)
819 try:
836 try:
820 _ip.user_ns.pop('arq', None)
837 _ip.user_ns.pop('arq', None)
821 invalidate_caches() # Clear import caches
838 invalidate_caches() # Clear import caches
822 _ip.run_line_magic("load_ext", "daft_extension")
839 _ip.run_line_magic("load_ext", "daft_extension")
823 assert _ip.user_ns["arq"] == 185
840 assert _ip.user_ns["arq"] == 185
824 _ip.run_line_magic("unload_ext", "daft_extension")
841 _ip.run_line_magic("unload_ext", "daft_extension")
825 assert 'arq' not in _ip.user_ns
842 assert 'arq' not in _ip.user_ns
826 finally:
843 finally:
827 sys.path.remove(daft_path)
844 sys.path.remove(daft_path)
828
845
829
846
830 def test_notebook_export_json():
847 def test_notebook_export_json():
831 pytest.importorskip("nbformat")
848 pytest.importorskip("nbformat")
832 _ip = get_ipython()
849 _ip = get_ipython()
833 _ip.history_manager.reset() # Clear any existing history.
850 _ip.history_manager.reset() # Clear any existing history.
834 cmds = ["a=1", "def b():\n return a**2", "print('noël, été', b())"]
851 cmds = ["a=1", "def b():\n return a**2", "print('noël, été', b())"]
835 for i, cmd in enumerate(cmds, start=1):
852 for i, cmd in enumerate(cmds, start=1):
836 _ip.history_manager.store_inputs(i, cmd)
853 _ip.history_manager.store_inputs(i, cmd)
837 with TemporaryDirectory() as td:
854 with TemporaryDirectory() as td:
838 outfile = os.path.join(td, "nb.ipynb")
855 outfile = os.path.join(td, "nb.ipynb")
839 _ip.run_line_magic("notebook", "%s" % outfile)
856 _ip.run_line_magic("notebook", "%s" % outfile)
840
857
841
858
842 class TestEnv(TestCase):
859 class TestEnv(TestCase):
843
860
844 def test_env(self):
861 def test_env(self):
845 env = _ip.run_line_magic("env", "")
862 env = _ip.run_line_magic("env", "")
846 self.assertTrue(isinstance(env, dict))
863 self.assertTrue(isinstance(env, dict))
847
864
848 def test_env_secret(self):
865 def test_env_secret(self):
849 env = _ip.run_line_magic("env", "")
866 env = _ip.run_line_magic("env", "")
850 hidden = "<hidden>"
867 hidden = "<hidden>"
851 with mock.patch.dict(
868 with mock.patch.dict(
852 os.environ,
869 os.environ,
853 {
870 {
854 "API_KEY": "abc123",
871 "API_KEY": "abc123",
855 "SECRET_THING": "ssshhh",
872 "SECRET_THING": "ssshhh",
856 "JUPYTER_TOKEN": "",
873 "JUPYTER_TOKEN": "",
857 "VAR": "abc"
874 "VAR": "abc"
858 }
875 }
859 ):
876 ):
860 env = _ip.run_line_magic("env", "")
877 env = _ip.run_line_magic("env", "")
861 assert env["API_KEY"] == hidden
878 assert env["API_KEY"] == hidden
862 assert env["SECRET_THING"] == hidden
879 assert env["SECRET_THING"] == hidden
863 assert env["JUPYTER_TOKEN"] == hidden
880 assert env["JUPYTER_TOKEN"] == hidden
864 assert env["VAR"] == "abc"
881 assert env["VAR"] == "abc"
865
882
866 def test_env_get_set_simple(self):
883 def test_env_get_set_simple(self):
867 env = _ip.run_line_magic("env", "var val1")
884 env = _ip.run_line_magic("env", "var val1")
868 self.assertEqual(env, None)
885 self.assertEqual(env, None)
869 self.assertEqual(os.environ["var"], "val1")
886 self.assertEqual(os.environ["var"], "val1")
870 self.assertEqual(_ip.run_line_magic("env", "var"), "val1")
887 self.assertEqual(_ip.run_line_magic("env", "var"), "val1")
871 env = _ip.run_line_magic("env", "var=val2")
888 env = _ip.run_line_magic("env", "var=val2")
872 self.assertEqual(env, None)
889 self.assertEqual(env, None)
873 self.assertEqual(os.environ['var'], 'val2')
890 self.assertEqual(os.environ['var'], 'val2')
874
891
875 def test_env_get_set_complex(self):
892 def test_env_get_set_complex(self):
876 env = _ip.run_line_magic("env", "var 'val1 '' 'val2")
893 env = _ip.run_line_magic("env", "var 'val1 '' 'val2")
877 self.assertEqual(env, None)
894 self.assertEqual(env, None)
878 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
895 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
879 self.assertEqual(_ip.run_line_magic("env", "var"), "'val1 '' 'val2")
896 self.assertEqual(_ip.run_line_magic("env", "var"), "'val1 '' 'val2")
880 env = _ip.run_line_magic("env", 'var=val2 val3="val4')
897 env = _ip.run_line_magic("env", 'var=val2 val3="val4')
881 self.assertEqual(env, None)
898 self.assertEqual(env, None)
882 self.assertEqual(os.environ['var'], 'val2 val3="val4')
899 self.assertEqual(os.environ['var'], 'val2 val3="val4')
883
900
884 def test_env_set_bad_input(self):
901 def test_env_set_bad_input(self):
885 self.assertRaises(UsageError, lambda: _ip.run_line_magic("set_env", "var"))
902 self.assertRaises(UsageError, lambda: _ip.run_line_magic("set_env", "var"))
886
903
887 def test_env_set_whitespace(self):
904 def test_env_set_whitespace(self):
888 self.assertRaises(UsageError, lambda: _ip.run_line_magic("env", "var A=B"))
905 self.assertRaises(UsageError, lambda: _ip.run_line_magic("env", "var A=B"))
889
906
890
907
891 class CellMagicTestCase(TestCase):
908 class CellMagicTestCase(TestCase):
892
909
893 def check_ident(self, magic):
910 def check_ident(self, magic):
894 # Manually called, we get the result
911 # Manually called, we get the result
895 out = _ip.run_cell_magic(magic, "a", "b")
912 out = _ip.run_cell_magic(magic, "a", "b")
896 assert out == ("a", "b")
913 assert out == ("a", "b")
897 # Via run_cell, it goes into the user's namespace via displayhook
914 # Via run_cell, it goes into the user's namespace via displayhook
898 _ip.run_cell("%%" + magic + " c\nd\n")
915 _ip.run_cell("%%" + magic + " c\nd\n")
899 assert _ip.user_ns["_"] == ("c", "d\n")
916 assert _ip.user_ns["_"] == ("c", "d\n")
900
917
901 def test_cell_magic_func_deco(self):
918 def test_cell_magic_func_deco(self):
902 "Cell magic using simple decorator"
919 "Cell magic using simple decorator"
903 @register_cell_magic
920 @register_cell_magic
904 def cellm(line, cell):
921 def cellm(line, cell):
905 return line, cell
922 return line, cell
906
923
907 self.check_ident('cellm')
924 self.check_ident('cellm')
908
925
909 def test_cell_magic_reg(self):
926 def test_cell_magic_reg(self):
910 "Cell magic manually registered"
927 "Cell magic manually registered"
911 def cellm(line, cell):
928 def cellm(line, cell):
912 return line, cell
929 return line, cell
913
930
914 _ip.register_magic_function(cellm, 'cell', 'cellm2')
931 _ip.register_magic_function(cellm, 'cell', 'cellm2')
915 self.check_ident('cellm2')
932 self.check_ident('cellm2')
916
933
917 def test_cell_magic_class(self):
934 def test_cell_magic_class(self):
918 "Cell magics declared via a class"
935 "Cell magics declared via a class"
919 @magics_class
936 @magics_class
920 class MyMagics(Magics):
937 class MyMagics(Magics):
921
938
922 @cell_magic
939 @cell_magic
923 def cellm3(self, line, cell):
940 def cellm3(self, line, cell):
924 return line, cell
941 return line, cell
925
942
926 _ip.register_magics(MyMagics)
943 _ip.register_magics(MyMagics)
927 self.check_ident('cellm3')
944 self.check_ident('cellm3')
928
945
929 def test_cell_magic_class2(self):
946 def test_cell_magic_class2(self):
930 "Cell magics declared via a class, #2"
947 "Cell magics declared via a class, #2"
931 @magics_class
948 @magics_class
932 class MyMagics2(Magics):
949 class MyMagics2(Magics):
933
950
934 @cell_magic('cellm4')
951 @cell_magic('cellm4')
935 def cellm33(self, line, cell):
952 def cellm33(self, line, cell):
936 return line, cell
953 return line, cell
937
954
938 _ip.register_magics(MyMagics2)
955 _ip.register_magics(MyMagics2)
939 self.check_ident('cellm4')
956 self.check_ident('cellm4')
940 # Check that nothing is registered as 'cellm33'
957 # Check that nothing is registered as 'cellm33'
941 c33 = _ip.find_cell_magic('cellm33')
958 c33 = _ip.find_cell_magic('cellm33')
942 assert c33 == None
959 assert c33 == None
943
960
944 def test_file():
961 def test_file():
945 """Basic %%writefile"""
962 """Basic %%writefile"""
946 ip = get_ipython()
963 ip = get_ipython()
947 with TemporaryDirectory() as td:
964 with TemporaryDirectory() as td:
948 fname = os.path.join(td, "file1")
965 fname = os.path.join(td, "file1")
949 ip.run_cell_magic(
966 ip.run_cell_magic(
950 "writefile",
967 "writefile",
951 fname,
968 fname,
952 "\n".join(
969 "\n".join(
953 [
970 [
954 "line1",
971 "line1",
955 "line2",
972 "line2",
956 ]
973 ]
957 ),
974 ),
958 )
975 )
959 s = Path(fname).read_text(encoding="utf-8")
976 s = Path(fname).read_text(encoding="utf-8")
960 assert "line1\n" in s
977 assert "line1\n" in s
961 assert "line2" in s
978 assert "line2" in s
962
979
963
980
964 @dec.skip_win32
981 @dec.skip_win32
965 def test_file_single_quote():
982 def test_file_single_quote():
966 """Basic %%writefile with embedded single quotes"""
983 """Basic %%writefile with embedded single quotes"""
967 ip = get_ipython()
984 ip = get_ipython()
968 with TemporaryDirectory() as td:
985 with TemporaryDirectory() as td:
969 fname = os.path.join(td, "'file1'")
986 fname = os.path.join(td, "'file1'")
970 ip.run_cell_magic(
987 ip.run_cell_magic(
971 "writefile",
988 "writefile",
972 fname,
989 fname,
973 "\n".join(
990 "\n".join(
974 [
991 [
975 "line1",
992 "line1",
976 "line2",
993 "line2",
977 ]
994 ]
978 ),
995 ),
979 )
996 )
980 s = Path(fname).read_text(encoding="utf-8")
997 s = Path(fname).read_text(encoding="utf-8")
981 assert "line1\n" in s
998 assert "line1\n" in s
982 assert "line2" in s
999 assert "line2" in s
983
1000
984
1001
985 @dec.skip_win32
1002 @dec.skip_win32
986 def test_file_double_quote():
1003 def test_file_double_quote():
987 """Basic %%writefile with embedded double quotes"""
1004 """Basic %%writefile with embedded double quotes"""
988 ip = get_ipython()
1005 ip = get_ipython()
989 with TemporaryDirectory() as td:
1006 with TemporaryDirectory() as td:
990 fname = os.path.join(td, '"file1"')
1007 fname = os.path.join(td, '"file1"')
991 ip.run_cell_magic(
1008 ip.run_cell_magic(
992 "writefile",
1009 "writefile",
993 fname,
1010 fname,
994 "\n".join(
1011 "\n".join(
995 [
1012 [
996 "line1",
1013 "line1",
997 "line2",
1014 "line2",
998 ]
1015 ]
999 ),
1016 ),
1000 )
1017 )
1001 s = Path(fname).read_text(encoding="utf-8")
1018 s = Path(fname).read_text(encoding="utf-8")
1002 assert "line1\n" in s
1019 assert "line1\n" in s
1003 assert "line2" in s
1020 assert "line2" in s
1004
1021
1005
1022
1006 def test_file_var_expand():
1023 def test_file_var_expand():
1007 """%%writefile $filename"""
1024 """%%writefile $filename"""
1008 ip = get_ipython()
1025 ip = get_ipython()
1009 with TemporaryDirectory() as td:
1026 with TemporaryDirectory() as td:
1010 fname = os.path.join(td, "file1")
1027 fname = os.path.join(td, "file1")
1011 ip.user_ns["filename"] = fname
1028 ip.user_ns["filename"] = fname
1012 ip.run_cell_magic(
1029 ip.run_cell_magic(
1013 "writefile",
1030 "writefile",
1014 "$filename",
1031 "$filename",
1015 "\n".join(
1032 "\n".join(
1016 [
1033 [
1017 "line1",
1034 "line1",
1018 "line2",
1035 "line2",
1019 ]
1036 ]
1020 ),
1037 ),
1021 )
1038 )
1022 s = Path(fname).read_text(encoding="utf-8")
1039 s = Path(fname).read_text(encoding="utf-8")
1023 assert "line1\n" in s
1040 assert "line1\n" in s
1024 assert "line2" in s
1041 assert "line2" in s
1025
1042
1026
1043
1027 def test_file_unicode():
1044 def test_file_unicode():
1028 """%%writefile with unicode cell"""
1045 """%%writefile with unicode cell"""
1029 ip = get_ipython()
1046 ip = get_ipython()
1030 with TemporaryDirectory() as td:
1047 with TemporaryDirectory() as td:
1031 fname = os.path.join(td, 'file1')
1048 fname = os.path.join(td, 'file1')
1032 ip.run_cell_magic("writefile", fname, u'\n'.join([
1049 ip.run_cell_magic("writefile", fname, u'\n'.join([
1033 u'liné1',
1050 u'liné1',
1034 u'liné2',
1051 u'liné2',
1035 ]))
1052 ]))
1036 with io.open(fname, encoding='utf-8') as f:
1053 with io.open(fname, encoding='utf-8') as f:
1037 s = f.read()
1054 s = f.read()
1038 assert "liné1\n" in s
1055 assert "liné1\n" in s
1039 assert "liné2" in s
1056 assert "liné2" in s
1040
1057
1041
1058
1042 def test_file_amend():
1059 def test_file_amend():
1043 """%%writefile -a amends files"""
1060 """%%writefile -a amends files"""
1044 ip = get_ipython()
1061 ip = get_ipython()
1045 with TemporaryDirectory() as td:
1062 with TemporaryDirectory() as td:
1046 fname = os.path.join(td, "file2")
1063 fname = os.path.join(td, "file2")
1047 ip.run_cell_magic(
1064 ip.run_cell_magic(
1048 "writefile",
1065 "writefile",
1049 fname,
1066 fname,
1050 "\n".join(
1067 "\n".join(
1051 [
1068 [
1052 "line1",
1069 "line1",
1053 "line2",
1070 "line2",
1054 ]
1071 ]
1055 ),
1072 ),
1056 )
1073 )
1057 ip.run_cell_magic(
1074 ip.run_cell_magic(
1058 "writefile",
1075 "writefile",
1059 "-a %s" % fname,
1076 "-a %s" % fname,
1060 "\n".join(
1077 "\n".join(
1061 [
1078 [
1062 "line3",
1079 "line3",
1063 "line4",
1080 "line4",
1064 ]
1081 ]
1065 ),
1082 ),
1066 )
1083 )
1067 s = Path(fname).read_text(encoding="utf-8")
1084 s = Path(fname).read_text(encoding="utf-8")
1068 assert "line1\n" in s
1085 assert "line1\n" in s
1069 assert "line3\n" in s
1086 assert "line3\n" in s
1070
1087
1071
1088
1072 def test_file_spaces():
1089 def test_file_spaces():
1073 """%%file with spaces in filename"""
1090 """%%file with spaces in filename"""
1074 ip = get_ipython()
1091 ip = get_ipython()
1075 with TemporaryWorkingDirectory() as td:
1092 with TemporaryWorkingDirectory() as td:
1076 fname = "file name"
1093 fname = "file name"
1077 ip.run_cell_magic(
1094 ip.run_cell_magic(
1078 "file",
1095 "file",
1079 '"%s"' % fname,
1096 '"%s"' % fname,
1080 "\n".join(
1097 "\n".join(
1081 [
1098 [
1082 "line1",
1099 "line1",
1083 "line2",
1100 "line2",
1084 ]
1101 ]
1085 ),
1102 ),
1086 )
1103 )
1087 s = Path(fname).read_text(encoding="utf-8")
1104 s = Path(fname).read_text(encoding="utf-8")
1088 assert "line1\n" in s
1105 assert "line1\n" in s
1089 assert "line2" in s
1106 assert "line2" in s
1090
1107
1091
1108
1092 def test_script_config():
1109 def test_script_config():
1093 ip = get_ipython()
1110 ip = get_ipython()
1094 ip.config.ScriptMagics.script_magics = ['whoda']
1111 ip.config.ScriptMagics.script_magics = ['whoda']
1095 sm = script.ScriptMagics(shell=ip)
1112 sm = script.ScriptMagics(shell=ip)
1096 assert "whoda" in sm.magics["cell"]
1113 assert "whoda" in sm.magics["cell"]
1097
1114
1098
1115
1099 def test_script_out():
1116 def test_script_out():
1100 ip = get_ipython()
1117 ip = get_ipython()
1101 ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
1118 ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
1102 assert ip.user_ns["output"].strip() == "hi"
1119 assert ip.user_ns["output"].strip() == "hi"
1103
1120
1104
1121
1105 def test_script_err():
1122 def test_script_err():
1106 ip = get_ipython()
1123 ip = get_ipython()
1107 ip.run_cell_magic(
1124 ip.run_cell_magic(
1108 "script",
1125 "script",
1109 f"--err error {sys.executable}",
1126 f"--err error {sys.executable}",
1110 "import sys; print('hello', file=sys.stderr)",
1127 "import sys; print('hello', file=sys.stderr)",
1111 )
1128 )
1112 assert ip.user_ns["error"].strip() == "hello"
1129 assert ip.user_ns["error"].strip() == "hello"
1113
1130
1114
1131
1115 def test_script_out_err():
1132 def test_script_out_err():
1116 ip = get_ipython()
1133 ip = get_ipython()
1117 ip.run_cell_magic(
1134 ip.run_cell_magic(
1118 "script",
1135 "script",
1119 f"--out output --err error {sys.executable}",
1136 f"--out output --err error {sys.executable}",
1120 "\n".join(
1137 "\n".join(
1121 [
1138 [
1122 "import sys",
1139 "import sys",
1123 "print('hi')",
1140 "print('hi')",
1124 "print('hello', file=sys.stderr)",
1141 "print('hello', file=sys.stderr)",
1125 ]
1142 ]
1126 ),
1143 ),
1127 )
1144 )
1128 assert ip.user_ns["output"].strip() == "hi"
1145 assert ip.user_ns["output"].strip() == "hi"
1129 assert ip.user_ns["error"].strip() == "hello"
1146 assert ip.user_ns["error"].strip() == "hello"
1130
1147
1131
1148
1132 async def test_script_bg_out():
1149 async def test_script_bg_out():
1133 ip = get_ipython()
1150 ip = get_ipython()
1134 ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1151 ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1135 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1152 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1136 assert ip.user_ns["output"].at_eof()
1153 assert ip.user_ns["output"].at_eof()
1137
1154
1138
1155
1139 async def test_script_bg_err():
1156 async def test_script_bg_err():
1140 ip = get_ipython()
1157 ip = get_ipython()
1141 ip.run_cell_magic(
1158 ip.run_cell_magic(
1142 "script",
1159 "script",
1143 f"--bg --err error {sys.executable}",
1160 f"--bg --err error {sys.executable}",
1144 "import sys; print('hello', file=sys.stderr)",
1161 "import sys; print('hello', file=sys.stderr)",
1145 )
1162 )
1146 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1163 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1147 assert ip.user_ns["error"].at_eof()
1164 assert ip.user_ns["error"].at_eof()
1148
1165
1149
1166
1150 async def test_script_bg_out_err():
1167 async def test_script_bg_out_err():
1151 ip = get_ipython()
1168 ip = get_ipython()
1152 ip.run_cell_magic(
1169 ip.run_cell_magic(
1153 "script",
1170 "script",
1154 f"--bg --out output --err error {sys.executable}",
1171 f"--bg --out output --err error {sys.executable}",
1155 "\n".join(
1172 "\n".join(
1156 [
1173 [
1157 "import sys",
1174 "import sys",
1158 "print('hi')",
1175 "print('hi')",
1159 "print('hello', file=sys.stderr)",
1176 "print('hello', file=sys.stderr)",
1160 ]
1177 ]
1161 ),
1178 ),
1162 )
1179 )
1163 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1180 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1164 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1181 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1165 assert ip.user_ns["output"].at_eof()
1182 assert ip.user_ns["output"].at_eof()
1166 assert ip.user_ns["error"].at_eof()
1183 assert ip.user_ns["error"].at_eof()
1167
1184
1168
1185
1169 async def test_script_bg_proc():
1186 async def test_script_bg_proc():
1170 ip = get_ipython()
1187 ip = get_ipython()
1171 ip.run_cell_magic(
1188 ip.run_cell_magic(
1172 "script",
1189 "script",
1173 f"--bg --out output --proc p {sys.executable}",
1190 f"--bg --out output --proc p {sys.executable}",
1174 "\n".join(
1191 "\n".join(
1175 [
1192 [
1176 "import sys",
1193 "import sys",
1177 "print('hi')",
1194 "print('hi')",
1178 "print('hello', file=sys.stderr)",
1195 "print('hello', file=sys.stderr)",
1179 ]
1196 ]
1180 ),
1197 ),
1181 )
1198 )
1182 p = ip.user_ns["p"]
1199 p = ip.user_ns["p"]
1183 await p.wait()
1200 await p.wait()
1184 assert p.returncode == 0
1201 assert p.returncode == 0
1185 assert (await p.stdout.read()).strip() == b"hi"
1202 assert (await p.stdout.read()).strip() == b"hi"
1186 # not captured, so empty
1203 # not captured, so empty
1187 assert (await p.stderr.read()) == b""
1204 assert (await p.stderr.read()) == b""
1188 assert p.stdout.at_eof()
1205 assert p.stdout.at_eof()
1189 assert p.stderr.at_eof()
1206 assert p.stderr.at_eof()
1190
1207
1191
1208
1192 def test_script_defaults():
1209 def test_script_defaults():
1193 ip = get_ipython()
1210 ip = get_ipython()
1194 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1211 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1195 try:
1212 try:
1196 find_cmd(cmd)
1213 find_cmd(cmd)
1197 except Exception:
1214 except Exception:
1198 pass
1215 pass
1199 else:
1216 else:
1200 assert cmd in ip.magics_manager.magics["cell"]
1217 assert cmd in ip.magics_manager.magics["cell"]
1201
1218
1202
1219
1203 @magics_class
1220 @magics_class
1204 class FooFoo(Magics):
1221 class FooFoo(Magics):
1205 """class with both %foo and %%foo magics"""
1222 """class with both %foo and %%foo magics"""
1206 @line_magic('foo')
1223 @line_magic('foo')
1207 def line_foo(self, line):
1224 def line_foo(self, line):
1208 "I am line foo"
1225 "I am line foo"
1209 pass
1226 pass
1210
1227
1211 @cell_magic("foo")
1228 @cell_magic("foo")
1212 def cell_foo(self, line, cell):
1229 def cell_foo(self, line, cell):
1213 "I am cell foo, not line foo"
1230 "I am cell foo, not line foo"
1214 pass
1231 pass
1215
1232
1216 def test_line_cell_info():
1233 def test_line_cell_info():
1217 """%%foo and %foo magics are distinguishable to inspect"""
1234 """%%foo and %foo magics are distinguishable to inspect"""
1218 ip = get_ipython()
1235 ip = get_ipython()
1219 ip.magics_manager.register(FooFoo)
1236 ip.magics_manager.register(FooFoo)
1220 oinfo = ip.object_inspect("foo")
1237 oinfo = ip.object_inspect("foo")
1221 assert oinfo["found"] is True
1238 assert oinfo["found"] is True
1222 assert oinfo["ismagic"] is True
1239 assert oinfo["ismagic"] is True
1223
1240
1224 oinfo = ip.object_inspect("%%foo")
1241 oinfo = ip.object_inspect("%%foo")
1225 assert oinfo["found"] is True
1242 assert oinfo["found"] is True
1226 assert oinfo["ismagic"] is True
1243 assert oinfo["ismagic"] is True
1227 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1244 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1228
1245
1229 oinfo = ip.object_inspect("%foo")
1246 oinfo = ip.object_inspect("%foo")
1230 assert oinfo["found"] is True
1247 assert oinfo["found"] is True
1231 assert oinfo["ismagic"] is True
1248 assert oinfo["ismagic"] is True
1232 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1249 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1233
1250
1234
1251
1235 def test_multiple_magics():
1252 def test_multiple_magics():
1236 ip = get_ipython()
1253 ip = get_ipython()
1237 foo1 = FooFoo(ip)
1254 foo1 = FooFoo(ip)
1238 foo2 = FooFoo(ip)
1255 foo2 = FooFoo(ip)
1239 mm = ip.magics_manager
1256 mm = ip.magics_manager
1240 mm.register(foo1)
1257 mm.register(foo1)
1241 assert mm.magics["line"]["foo"].__self__ is foo1
1258 assert mm.magics["line"]["foo"].__self__ is foo1
1242 mm.register(foo2)
1259 mm.register(foo2)
1243 assert mm.magics["line"]["foo"].__self__ is foo2
1260 assert mm.magics["line"]["foo"].__self__ is foo2
1244
1261
1245
1262
1246 def test_alias_magic():
1263 def test_alias_magic():
1247 """Test %alias_magic."""
1264 """Test %alias_magic."""
1248 ip = get_ipython()
1265 ip = get_ipython()
1249 mm = ip.magics_manager
1266 mm = ip.magics_manager
1250
1267
1251 # Basic operation: both cell and line magics are created, if possible.
1268 # Basic operation: both cell and line magics are created, if possible.
1252 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1269 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1253 assert "timeit_alias" in mm.magics["line"]
1270 assert "timeit_alias" in mm.magics["line"]
1254 assert "timeit_alias" in mm.magics["cell"]
1271 assert "timeit_alias" in mm.magics["cell"]
1255
1272
1256 # --cell is specified, line magic not created.
1273 # --cell is specified, line magic not created.
1257 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1274 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1258 assert "timeit_cell_alias" not in mm.magics["line"]
1275 assert "timeit_cell_alias" not in mm.magics["line"]
1259 assert "timeit_cell_alias" in mm.magics["cell"]
1276 assert "timeit_cell_alias" in mm.magics["cell"]
1260
1277
1261 # Test that line alias is created successfully.
1278 # Test that line alias is created successfully.
1262 ip.run_line_magic("alias_magic", "--line env_alias env")
1279 ip.run_line_magic("alias_magic", "--line env_alias env")
1263 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1280 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1264
1281
1265 # Test that line alias with parameters passed in is created successfully.
1282 # Test that line alias with parameters passed in is created successfully.
1266 ip.run_line_magic(
1283 ip.run_line_magic(
1267 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1284 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1268 )
1285 )
1269 assert "history_alias" in mm.magics["line"]
1286 assert "history_alias" in mm.magics["line"]
1270
1287
1271
1288
1272 def test_save():
1289 def test_save():
1273 """Test %save."""
1290 """Test %save."""
1274 ip = get_ipython()
1291 ip = get_ipython()
1275 ip.history_manager.reset() # Clear any existing history.
1292 ip.history_manager.reset() # Clear any existing history.
1276 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1293 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1277 for i, cmd in enumerate(cmds, start=1):
1294 for i, cmd in enumerate(cmds, start=1):
1278 ip.history_manager.store_inputs(i, cmd)
1295 ip.history_manager.store_inputs(i, cmd)
1279 with TemporaryDirectory() as tmpdir:
1296 with TemporaryDirectory() as tmpdir:
1280 file = os.path.join(tmpdir, "testsave.py")
1297 file = os.path.join(tmpdir, "testsave.py")
1281 ip.run_line_magic("save", "%s 1-10" % file)
1298 ip.run_line_magic("save", "%s 1-10" % file)
1282 content = Path(file).read_text(encoding="utf-8")
1299 content = Path(file).read_text(encoding="utf-8")
1283 assert content.count(cmds[0]) == 1
1300 assert content.count(cmds[0]) == 1
1284 assert "coding: utf-8" in content
1301 assert "coding: utf-8" in content
1285 ip.run_line_magic("save", "-a %s 1-10" % file)
1302 ip.run_line_magic("save", "-a %s 1-10" % file)
1286 content = Path(file).read_text(encoding="utf-8")
1303 content = Path(file).read_text(encoding="utf-8")
1287 assert content.count(cmds[0]) == 2
1304 assert content.count(cmds[0]) == 2
1288 assert "coding: utf-8" in content
1305 assert "coding: utf-8" in content
1289
1306
1290
1307
1291 def test_save_with_no_args():
1308 def test_save_with_no_args():
1292 ip = get_ipython()
1309 ip = get_ipython()
1293 ip.history_manager.reset() # Clear any existing history.
1310 ip.history_manager.reset() # Clear any existing history.
1294 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1311 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1295 for i, cmd in enumerate(cmds, start=1):
1312 for i, cmd in enumerate(cmds, start=1):
1296 ip.history_manager.store_inputs(i, cmd)
1313 ip.history_manager.store_inputs(i, cmd)
1297
1314
1298 with TemporaryDirectory() as tmpdir:
1315 with TemporaryDirectory() as tmpdir:
1299 path = os.path.join(tmpdir, "testsave.py")
1316 path = os.path.join(tmpdir, "testsave.py")
1300 ip.run_line_magic("save", path)
1317 ip.run_line_magic("save", path)
1301 content = Path(path).read_text(encoding="utf-8")
1318 content = Path(path).read_text(encoding="utf-8")
1302 expected_content = dedent(
1319 expected_content = dedent(
1303 """\
1320 """\
1304 # coding: utf-8
1321 # coding: utf-8
1305 a=1
1322 a=1
1306 def b():
1323 def b():
1307 return a**2
1324 return a**2
1308 print(a, b())
1325 print(a, b())
1309 """
1326 """
1310 )
1327 )
1311 assert content == expected_content
1328 assert content == expected_content
1312
1329
1313
1330
1314 def test_store():
1331 def test_store():
1315 """Test %store."""
1332 """Test %store."""
1316 ip = get_ipython()
1333 ip = get_ipython()
1317 ip.run_line_magic('load_ext', 'storemagic')
1334 ip.run_line_magic('load_ext', 'storemagic')
1318
1335
1319 # make sure the storage is empty
1336 # make sure the storage is empty
1320 ip.run_line_magic("store", "-z")
1337 ip.run_line_magic("store", "-z")
1321 ip.user_ns["var"] = 42
1338 ip.user_ns["var"] = 42
1322 ip.run_line_magic("store", "var")
1339 ip.run_line_magic("store", "var")
1323 ip.user_ns["var"] = 39
1340 ip.user_ns["var"] = 39
1324 ip.run_line_magic("store", "-r")
1341 ip.run_line_magic("store", "-r")
1325 assert ip.user_ns["var"] == 42
1342 assert ip.user_ns["var"] == 42
1326
1343
1327 ip.run_line_magic("store", "-d var")
1344 ip.run_line_magic("store", "-d var")
1328 ip.user_ns["var"] = 39
1345 ip.user_ns["var"] = 39
1329 ip.run_line_magic("store", "-r")
1346 ip.run_line_magic("store", "-r")
1330 assert ip.user_ns["var"] == 39
1347 assert ip.user_ns["var"] == 39
1331
1348
1332
1349
1333 def _run_edit_test(arg_s, exp_filename=None,
1350 def _run_edit_test(arg_s, exp_filename=None,
1334 exp_lineno=-1,
1351 exp_lineno=-1,
1335 exp_contents=None,
1352 exp_contents=None,
1336 exp_is_temp=None):
1353 exp_is_temp=None):
1337 ip = get_ipython()
1354 ip = get_ipython()
1338 M = code.CodeMagics(ip)
1355 M = code.CodeMagics(ip)
1339 last_call = ['','']
1356 last_call = ['','']
1340 opts,args = M.parse_options(arg_s,'prxn:')
1357 opts,args = M.parse_options(arg_s,'prxn:')
1341 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1358 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1342
1359
1343 if exp_filename is not None:
1360 if exp_filename is not None:
1344 assert exp_filename == filename
1361 assert exp_filename == filename
1345 if exp_contents is not None:
1362 if exp_contents is not None:
1346 with io.open(filename, 'r', encoding='utf-8') as f:
1363 with io.open(filename, 'r', encoding='utf-8') as f:
1347 contents = f.read()
1364 contents = f.read()
1348 assert exp_contents == contents
1365 assert exp_contents == contents
1349 if exp_lineno != -1:
1366 if exp_lineno != -1:
1350 assert exp_lineno == lineno
1367 assert exp_lineno == lineno
1351 if exp_is_temp is not None:
1368 if exp_is_temp is not None:
1352 assert exp_is_temp == is_temp
1369 assert exp_is_temp == is_temp
1353
1370
1354
1371
1355 def test_edit_interactive():
1372 def test_edit_interactive():
1356 """%edit on interactively defined objects"""
1373 """%edit on interactively defined objects"""
1357 ip = get_ipython()
1374 ip = get_ipython()
1358 n = ip.execution_count
1375 n = ip.execution_count
1359 ip.run_cell("def foo(): return 1", store_history=True)
1376 ip.run_cell("def foo(): return 1", store_history=True)
1360
1377
1361 with pytest.raises(code.InteractivelyDefined) as e:
1378 with pytest.raises(code.InteractivelyDefined) as e:
1362 _run_edit_test("foo")
1379 _run_edit_test("foo")
1363 assert e.value.index == n
1380 assert e.value.index == n
1364
1381
1365
1382
1366 def test_edit_cell():
1383 def test_edit_cell():
1367 """%edit [cell id]"""
1384 """%edit [cell id]"""
1368 ip = get_ipython()
1385 ip = get_ipython()
1369
1386
1370 ip.run_cell("def foo(): return 1", store_history=True)
1387 ip.run_cell("def foo(): return 1", store_history=True)
1371
1388
1372 # test
1389 # test
1373 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1390 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1374
1391
1375 def test_edit_fname():
1392 def test_edit_fname():
1376 """%edit file"""
1393 """%edit file"""
1377 # test
1394 # test
1378 _run_edit_test("test file.py", exp_filename="test file.py")
1395 _run_edit_test("test file.py", exp_filename="test file.py")
1379
1396
1380 def test_bookmark():
1397 def test_bookmark():
1381 ip = get_ipython()
1398 ip = get_ipython()
1382 ip.run_line_magic('bookmark', 'bmname')
1399 ip.run_line_magic('bookmark', 'bmname')
1383 with tt.AssertPrints('bmname'):
1400 with tt.AssertPrints('bmname'):
1384 ip.run_line_magic('bookmark', '-l')
1401 ip.run_line_magic('bookmark', '-l')
1385 ip.run_line_magic('bookmark', '-d bmname')
1402 ip.run_line_magic('bookmark', '-d bmname')
1386
1403
1387 def test_ls_magic():
1404 def test_ls_magic():
1388 ip = get_ipython()
1405 ip = get_ipython()
1389 json_formatter = ip.display_formatter.formatters['application/json']
1406 json_formatter = ip.display_formatter.formatters['application/json']
1390 json_formatter.enabled = True
1407 json_formatter.enabled = True
1391 lsmagic = ip.run_line_magic("lsmagic", "")
1408 lsmagic = ip.run_line_magic("lsmagic", "")
1392 with warnings.catch_warnings(record=True) as w:
1409 with warnings.catch_warnings(record=True) as w:
1393 j = json_formatter(lsmagic)
1410 j = json_formatter(lsmagic)
1394 assert sorted(j) == ["cell", "line"]
1411 assert sorted(j) == ["cell", "line"]
1395 assert w == [] # no warnings
1412 assert w == [] # no warnings
1396
1413
1397
1414
1398 def test_strip_initial_indent():
1415 def test_strip_initial_indent():
1399 def sii(s):
1416 def sii(s):
1400 lines = s.splitlines()
1417 lines = s.splitlines()
1401 return '\n'.join(code.strip_initial_indent(lines))
1418 return '\n'.join(code.strip_initial_indent(lines))
1402
1419
1403 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1420 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1404 assert sii(" a\n b\nc") == "a\n b\nc"
1421 assert sii(" a\n b\nc") == "a\n b\nc"
1405 assert sii("a\n b") == "a\n b"
1422 assert sii("a\n b") == "a\n b"
1406
1423
1407 def test_logging_magic_quiet_from_arg():
1424 def test_logging_magic_quiet_from_arg():
1408 _ip.config.LoggingMagics.quiet = False
1425 _ip.config.LoggingMagics.quiet = False
1409 lm = logging.LoggingMagics(shell=_ip)
1426 lm = logging.LoggingMagics(shell=_ip)
1410 with TemporaryDirectory() as td:
1427 with TemporaryDirectory() as td:
1411 try:
1428 try:
1412 with tt.AssertNotPrints(re.compile("Activating.*")):
1429 with tt.AssertNotPrints(re.compile("Activating.*")):
1413 lm.logstart('-q {}'.format(
1430 lm.logstart('-q {}'.format(
1414 os.path.join(td, "quiet_from_arg.log")))
1431 os.path.join(td, "quiet_from_arg.log")))
1415 finally:
1432 finally:
1416 _ip.logger.logstop()
1433 _ip.logger.logstop()
1417
1434
1418 def test_logging_magic_quiet_from_config():
1435 def test_logging_magic_quiet_from_config():
1419 _ip.config.LoggingMagics.quiet = True
1436 _ip.config.LoggingMagics.quiet = True
1420 lm = logging.LoggingMagics(shell=_ip)
1437 lm = logging.LoggingMagics(shell=_ip)
1421 with TemporaryDirectory() as td:
1438 with TemporaryDirectory() as td:
1422 try:
1439 try:
1423 with tt.AssertNotPrints(re.compile("Activating.*")):
1440 with tt.AssertNotPrints(re.compile("Activating.*")):
1424 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1441 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1425 finally:
1442 finally:
1426 _ip.logger.logstop()
1443 _ip.logger.logstop()
1427
1444
1428
1445
1429 def test_logging_magic_not_quiet():
1446 def test_logging_magic_not_quiet():
1430 _ip.config.LoggingMagics.quiet = False
1447 _ip.config.LoggingMagics.quiet = False
1431 lm = logging.LoggingMagics(shell=_ip)
1448 lm = logging.LoggingMagics(shell=_ip)
1432 with TemporaryDirectory() as td:
1449 with TemporaryDirectory() as td:
1433 try:
1450 try:
1434 with tt.AssertPrints(re.compile("Activating.*")):
1451 with tt.AssertPrints(re.compile("Activating.*")):
1435 lm.logstart(os.path.join(td, "not_quiet.log"))
1452 lm.logstart(os.path.join(td, "not_quiet.log"))
1436 finally:
1453 finally:
1437 _ip.logger.logstop()
1454 _ip.logger.logstop()
1438
1455
1439
1456
1440 def test_time_no_var_expand():
1457 def test_time_no_var_expand():
1441 _ip.user_ns["a"] = 5
1458 _ip.user_ns["a"] = 5
1442 _ip.user_ns["b"] = []
1459 _ip.user_ns["b"] = []
1443 _ip.run_line_magic("time", 'b.append("{a}")')
1460 _ip.run_line_magic("time", 'b.append("{a}")')
1444 assert _ip.user_ns["b"] == ["{a}"]
1461 assert _ip.user_ns["b"] == ["{a}"]
1445
1462
1446
1463
1447 # this is slow, put at the end for local testing.
1464 # this is slow, put at the end for local testing.
1448 def test_timeit_arguments():
1465 def test_timeit_arguments():
1449 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1466 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1450 _ip.run_line_magic("timeit", "-n1 -r1 a=('#')")
1467 _ip.run_line_magic("timeit", "-n1 -r1 a=('#')")
1451
1468
1452
1469
1453 MINIMAL_LAZY_MAGIC = """
1470 MINIMAL_LAZY_MAGIC = """
1454 from IPython.core.magic import (
1471 from IPython.core.magic import (
1455 Magics,
1472 Magics,
1456 magics_class,
1473 magics_class,
1457 line_magic,
1474 line_magic,
1458 cell_magic,
1475 cell_magic,
1459 )
1476 )
1460
1477
1461
1478
1462 @magics_class
1479 @magics_class
1463 class LazyMagics(Magics):
1480 class LazyMagics(Magics):
1464 @line_magic
1481 @line_magic
1465 def lazy_line(self, line):
1482 def lazy_line(self, line):
1466 print("Lazy Line")
1483 print("Lazy Line")
1467
1484
1468 @cell_magic
1485 @cell_magic
1469 def lazy_cell(self, line, cell):
1486 def lazy_cell(self, line, cell):
1470 print("Lazy Cell")
1487 print("Lazy Cell")
1471
1488
1472
1489
1473 def load_ipython_extension(ipython):
1490 def load_ipython_extension(ipython):
1474 ipython.register_magics(LazyMagics)
1491 ipython.register_magics(LazyMagics)
1475 """
1492 """
1476
1493
1477
1494
1478 def test_lazy_magics():
1495 def test_lazy_magics():
1479 with pytest.raises(UsageError):
1496 with pytest.raises(UsageError):
1480 ip.run_line_magic("lazy_line", "")
1497 ip.run_line_magic("lazy_line", "")
1481
1498
1482 startdir = os.getcwd()
1499 startdir = os.getcwd()
1483
1500
1484 with TemporaryDirectory() as tmpdir:
1501 with TemporaryDirectory() as tmpdir:
1485 with prepended_to_syspath(tmpdir):
1502 with prepended_to_syspath(tmpdir):
1486 ptempdir = Path(tmpdir)
1503 ptempdir = Path(tmpdir)
1487 tf = ptempdir / "lazy_magic_module.py"
1504 tf = ptempdir / "lazy_magic_module.py"
1488 tf.write_text(MINIMAL_LAZY_MAGIC)
1505 tf.write_text(MINIMAL_LAZY_MAGIC)
1489 ip.magics_manager.register_lazy("lazy_line", Path(tf.name).name[:-3])
1506 ip.magics_manager.register_lazy("lazy_line", Path(tf.name).name[:-3])
1490 with tt.AssertPrints("Lazy Line"):
1507 with tt.AssertPrints("Lazy Line"):
1491 ip.run_line_magic("lazy_line", "")
1508 ip.run_line_magic("lazy_line", "")
1492
1509
1493
1510
1494 TEST_MODULE = """
1511 TEST_MODULE = """
1495 print('Loaded my_tmp')
1512 print('Loaded my_tmp')
1496 if __name__ == "__main__":
1513 if __name__ == "__main__":
1497 print('I just ran a script')
1514 print('I just ran a script')
1498 """
1515 """
1499
1516
1500 def test_run_module_from_import_hook():
1517 def test_run_module_from_import_hook():
1501 "Test that a module can be loaded via an import hook"
1518 "Test that a module can be loaded via an import hook"
1502 with TemporaryDirectory() as tmpdir:
1519 with TemporaryDirectory() as tmpdir:
1503 fullpath = os.path.join(tmpdir, "my_tmp.py")
1520 fullpath = os.path.join(tmpdir, "my_tmp.py")
1504 Path(fullpath).write_text(TEST_MODULE, encoding="utf-8")
1521 Path(fullpath).write_text(TEST_MODULE, encoding="utf-8")
1505
1522
1506 import importlib.abc
1523 import importlib.abc
1507 import importlib.util
1524 import importlib.util
1508
1525
1509 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1526 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1510 def find_spec(self, fullname, path, target=None):
1527 def find_spec(self, fullname, path, target=None):
1511 if fullname == "my_tmp":
1528 if fullname == "my_tmp":
1512 return importlib.util.spec_from_loader(fullname, self)
1529 return importlib.util.spec_from_loader(fullname, self)
1513
1530
1514 def get_filename(self, fullname):
1531 def get_filename(self, fullname):
1515 assert fullname == "my_tmp"
1532 assert fullname == "my_tmp"
1516 return fullpath
1533 return fullpath
1517
1534
1518 def get_data(self, path):
1535 def get_data(self, path):
1519 assert Path(path).samefile(fullpath)
1536 assert Path(path).samefile(fullpath)
1520 return Path(fullpath).read_text(encoding="utf-8")
1537 return Path(fullpath).read_text(encoding="utf-8")
1521
1538
1522 sys.meta_path.insert(0, MyTempImporter())
1539 sys.meta_path.insert(0, MyTempImporter())
1523
1540
1524 with capture_output() as captured:
1541 with capture_output() as captured:
1525 _ip.run_line_magic("run", "-m my_tmp")
1542 _ip.run_line_magic("run", "-m my_tmp")
1526 _ip.run_cell("import my_tmp")
1543 _ip.run_cell("import my_tmp")
1527
1544
1528 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1545 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1529 assert output == captured.stdout
1546 assert output == captured.stdout
1530
1547
1531 sys.meta_path.pop(0)
1548 sys.meta_path.pop(0)
@@ -1,1381 +1,1381 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Verbose and colourful traceback formatting.
3 Verbose and colourful traceback formatting.
4
4
5 **ColorTB**
5 **ColorTB**
6
6
7 I've always found it a bit hard to visually parse tracebacks in Python. The
7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 ColorTB class is a solution to that problem. It colors the different parts of a
8 ColorTB class is a solution to that problem. It colors the different parts of a
9 traceback in a manner similar to what you would expect from a syntax-highlighting
9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 text editor.
10 text editor.
11
11
12 Installation instructions for ColorTB::
12 Installation instructions for ColorTB::
13
13
14 import sys,ultratb
14 import sys,ultratb
15 sys.excepthook = ultratb.ColorTB()
15 sys.excepthook = ultratb.ColorTB()
16
16
17 **VerboseTB**
17 **VerboseTB**
18
18
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 and intended it for CGI programmers, but why should they have all the fun? I
21 and intended it for CGI programmers, but why should they have all the fun? I
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 but kind of neat, and maybe useful for long-running programs that you believe
23 but kind of neat, and maybe useful for long-running programs that you believe
24 are bug-free. If a crash *does* occur in that type of program you want details.
24 are bug-free. If a crash *does* occur in that type of program you want details.
25 Give it a shot--you'll love it or you'll hate it.
25 Give it a shot--you'll love it or you'll hate it.
26
26
27 .. note::
27 .. note::
28
28
29 The Verbose mode prints the variables currently visible where the exception
29 The Verbose mode prints the variables currently visible where the exception
30 happened (shortening their strings if too long). This can potentially be
30 happened (shortening their strings if too long). This can potentially be
31 very slow, if you happen to have a huge data structure whose string
31 very slow, if you happen to have a huge data structure whose string
32 representation is complex to compute. Your computer may appear to freeze for
32 representation is complex to compute. Your computer may appear to freeze for
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 with Ctrl-C (maybe hitting it more than once).
34 with Ctrl-C (maybe hitting it more than once).
35
35
36 If you encounter this kind of situation often, you may want to use the
36 If you encounter this kind of situation often, you may want to use the
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 variables (but otherwise includes the information and context given by
38 variables (but otherwise includes the information and context given by
39 Verbose).
39 Verbose).
40
40
41 .. note::
41 .. note::
42
42
43 The verbose mode print all variables in the stack, which means it can
43 The verbose mode print all variables in the stack, which means it can
44 potentially leak sensitive information like access keys, or unencrypted
44 potentially leak sensitive information like access keys, or unencrypted
45 password.
45 password.
46
46
47 Installation instructions for VerboseTB::
47 Installation instructions for VerboseTB::
48
48
49 import sys,ultratb
49 import sys,ultratb
50 sys.excepthook = ultratb.VerboseTB()
50 sys.excepthook = ultratb.VerboseTB()
51
51
52 Note: Much of the code in this module was lifted verbatim from the standard
52 Note: Much of the code in this module was lifted verbatim from the standard
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54
54
55 Color schemes
55 Color schemes
56 -------------
56 -------------
57
57
58 The colors are defined in the class TBTools through the use of the
58 The colors are defined in the class TBTools through the use of the
59 ColorSchemeTable class. Currently the following exist:
59 ColorSchemeTable class. Currently the following exist:
60
60
61 - NoColor: allows all of this module to be used in any terminal (the color
61 - NoColor: allows all of this module to be used in any terminal (the color
62 escapes are just dummy blank strings).
62 escapes are just dummy blank strings).
63
63
64 - Linux: is meant to look good in a terminal like the Linux console (black
64 - Linux: is meant to look good in a terminal like the Linux console (black
65 or very dark background).
65 or very dark background).
66
66
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 in light background terminals.
68 in light background terminals.
69
69
70 - Neutral: a neutral color scheme that should be readable on both light and
70 - Neutral: a neutral color scheme that should be readable on both light and
71 dark background
71 dark background
72
72
73 You can implement other color schemes easily, the syntax is fairly
73 You can implement other color schemes easily, the syntax is fairly
74 self-explanatory. Please send back new schemes you develop to the author for
74 self-explanatory. Please send back new schemes you develop to the author for
75 possible inclusion in future releases.
75 possible inclusion in future releases.
76
76
77 Inheritance diagram:
77 Inheritance diagram:
78
78
79 .. inheritance-diagram:: IPython.core.ultratb
79 .. inheritance-diagram:: IPython.core.ultratb
80 :parts: 3
80 :parts: 3
81 """
81 """
82
82
83 #*****************************************************************************
83 #*****************************************************************************
84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
86 #
86 #
87 # Distributed under the terms of the BSD License. The full license is in
87 # Distributed under the terms of the BSD License. The full license is in
88 # the file COPYING, distributed as part of this software.
88 # the file COPYING, distributed as part of this software.
89 #*****************************************************************************
89 #*****************************************************************************
90
90
91
91
92 import inspect
92 import inspect
93 import linecache
93 import linecache
94 import pydoc
94 import pydoc
95 import sys
95 import sys
96 import time
96 import time
97 import traceback
97 import traceback
98 from types import TracebackType
98 from types import TracebackType
99 from typing import Tuple, List, Any, Optional
99 from typing import Tuple, List, Any, Optional
100
100
101 import stack_data
101 import stack_data
102 from stack_data import FrameInfo as SDFrameInfo
102 from stack_data import FrameInfo as SDFrameInfo
103 from pygments.formatters.terminal256 import Terminal256Formatter
103 from pygments.formatters.terminal256 import Terminal256Formatter
104 from pygments.styles import get_style_by_name
104 from pygments.styles import get_style_by_name
105
105
106 # IPython's own modules
106 # IPython's own modules
107 from IPython import get_ipython
107 from IPython import get_ipython
108 from IPython.core import debugger
108 from IPython.core import debugger
109 from IPython.core.display_trap import DisplayTrap
109 from IPython.core.display_trap import DisplayTrap
110 from IPython.core.excolors import exception_colors
110 from IPython.core.excolors import exception_colors
111 from IPython.utils import PyColorize
111 from IPython.utils import PyColorize
112 from IPython.utils import path as util_path
112 from IPython.utils import path as util_path
113 from IPython.utils import py3compat
113 from IPython.utils import py3compat
114 from IPython.utils.terminal import get_terminal_size
114 from IPython.utils.terminal import get_terminal_size
115
115
116 import IPython.utils.colorable as colorable
116 import IPython.utils.colorable as colorable
117
117
118 # Globals
118 # Globals
119 # amount of space to put line numbers before verbose tracebacks
119 # amount of space to put line numbers before verbose tracebacks
120 INDENT_SIZE = 8
120 INDENT_SIZE = 8
121
121
122 # Default color scheme. This is used, for example, by the traceback
122 # Default color scheme. This is used, for example, by the traceback
123 # formatter. When running in an actual IPython instance, the user's rc.colors
123 # formatter. When running in an actual IPython instance, the user's rc.colors
124 # value is used, but having a module global makes this functionality available
124 # value is used, but having a module global makes this functionality available
125 # to users of ultratb who are NOT running inside ipython.
125 # to users of ultratb who are NOT running inside ipython.
126 DEFAULT_SCHEME = 'NoColor'
126 DEFAULT_SCHEME = 'NoColor'
127 FAST_THRESHOLD = 10_000
127 FAST_THRESHOLD = 10_000
128
128
129 # ---------------------------------------------------------------------------
129 # ---------------------------------------------------------------------------
130 # Code begins
130 # Code begins
131
131
132 # Helper function -- largely belongs to VerboseTB, but we need the same
132 # Helper function -- largely belongs to VerboseTB, but we need the same
133 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
133 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
134 # can be recognized properly by ipython.el's py-traceback-line-re
134 # can be recognized properly by ipython.el's py-traceback-line-re
135 # (SyntaxErrors have to be treated specially because they have no traceback)
135 # (SyntaxErrors have to be treated specially because they have no traceback)
136
136
137
137
138 def _format_traceback_lines(lines, Colors, has_colors: bool, lvals):
138 def _format_traceback_lines(lines, Colors, has_colors: bool, lvals):
139 """
139 """
140 Format tracebacks lines with pointing arrow, leading numbers...
140 Format tracebacks lines with pointing arrow, leading numbers...
141
141
142 Parameters
142 Parameters
143 ----------
143 ----------
144 lines : list[Line]
144 lines : list[Line]
145 Colors
145 Colors
146 ColorScheme used.
146 ColorScheme used.
147 lvals : str
147 lvals : str
148 Values of local variables, already colored, to inject just after the error line.
148 Values of local variables, already colored, to inject just after the error line.
149 """
149 """
150 numbers_width = INDENT_SIZE - 1
150 numbers_width = INDENT_SIZE - 1
151 res = []
151 res = []
152
152
153 for stack_line in lines:
153 for stack_line in lines:
154 if stack_line is stack_data.LINE_GAP:
154 if stack_line is stack_data.LINE_GAP:
155 res.append('%s (...)%s\n' % (Colors.linenoEm, Colors.Normal))
155 res.append('%s (...)%s\n' % (Colors.linenoEm, Colors.Normal))
156 continue
156 continue
157
157
158 line = stack_line.render(pygmented=has_colors).rstrip('\n') + '\n'
158 line = stack_line.render(pygmented=has_colors).rstrip('\n') + '\n'
159 lineno = stack_line.lineno
159 lineno = stack_line.lineno
160 if stack_line.is_current:
160 if stack_line.is_current:
161 # This is the line with the error
161 # This is the line with the error
162 pad = numbers_width - len(str(lineno))
162 pad = numbers_width - len(str(lineno))
163 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
163 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
164 start_color = Colors.linenoEm
164 start_color = Colors.linenoEm
165 else:
165 else:
166 num = '%*s' % (numbers_width, lineno)
166 num = '%*s' % (numbers_width, lineno)
167 start_color = Colors.lineno
167 start_color = Colors.lineno
168
168
169 line = '%s%s%s %s' % (start_color, num, Colors.Normal, line)
169 line = '%s%s%s %s' % (start_color, num, Colors.Normal, line)
170
170
171 res.append(line)
171 res.append(line)
172 if lvals and stack_line.is_current:
172 if lvals and stack_line.is_current:
173 res.append(lvals + '\n')
173 res.append(lvals + '\n')
174 return res
174 return res
175
175
176 def _simple_format_traceback_lines(lnum, index, lines, Colors, lvals, _line_format):
176 def _simple_format_traceback_lines(lnum, index, lines, Colors, lvals, _line_format):
177 """
177 """
178 Format tracebacks lines with pointing arrow, leading numbers...
178 Format tracebacks lines with pointing arrow, leading numbers...
179
179
180 Parameters
180 Parameters
181 ==========
181 ==========
182
182
183 lnum: int
183 lnum: int
184 number of the target line of code.
184 number of the target line of code.
185 index: int
185 index: int
186 which line in the list should be highlighted.
186 which line in the list should be highlighted.
187 lines: list[string]
187 lines: list[string]
188 Colors:
188 Colors:
189 ColorScheme used.
189 ColorScheme used.
190 lvals: bytes
190 lvals: bytes
191 Values of local variables, already colored, to inject just after the error line.
191 Values of local variables, already colored, to inject just after the error line.
192 _line_format: f (str) -> (str, bool)
192 _line_format: f (str) -> (str, bool)
193 return (colorized version of str, failure to do so)
193 return (colorized version of str, failure to do so)
194 """
194 """
195 numbers_width = INDENT_SIZE - 1
195 numbers_width = INDENT_SIZE - 1
196 res = []
196 res = []
197
197
198 for i, line in enumerate(lines, lnum - index):
198 for i, line in enumerate(lines, lnum - index):
199 line = py3compat.cast_unicode(line)
199 line = py3compat.cast_unicode(line)
200
200
201 new_line, err = _line_format(line, "str")
201 new_line, err = _line_format(line, "str")
202 if not err:
202 if not err:
203 line = new_line
203 line = new_line
204
204
205 if i == lnum:
205 if i == lnum:
206 # This is the line with the error
206 # This is the line with the error
207 pad = numbers_width - len(str(i))
207 pad = numbers_width - len(str(i))
208 num = "%s%s" % (debugger.make_arrow(pad), str(lnum))
208 num = "%s%s" % (debugger.make_arrow(pad), str(lnum))
209 line = "%s%s%s %s%s" % (
209 line = "%s%s%s %s%s" % (
210 Colors.linenoEm,
210 Colors.linenoEm,
211 num,
211 num,
212 Colors.line,
212 Colors.line,
213 line,
213 line,
214 Colors.Normal,
214 Colors.Normal,
215 )
215 )
216 else:
216 else:
217 num = "%*s" % (numbers_width, i)
217 num = "%*s" % (numbers_width, i)
218 line = "%s%s%s %s" % (Colors.lineno, num, Colors.Normal, line)
218 line = "%s%s%s %s" % (Colors.lineno, num, Colors.Normal, line)
219
219
220 res.append(line)
220 res.append(line)
221 if lvals and i == lnum:
221 if lvals and i == lnum:
222 res.append(lvals + "\n")
222 res.append(lvals + "\n")
223 return res
223 return res
224
224
225
225
226 def _format_filename(file, ColorFilename, ColorNormal, *, lineno=None):
226 def _format_filename(file, ColorFilename, ColorNormal, *, lineno=None):
227 """
227 """
228 Format filename lines with custom formatting from caching compiler or `File *.py` by default
228 Format filename lines with custom formatting from caching compiler or `File *.py` by default
229
229
230 Parameters
230 Parameters
231 ----------
231 ----------
232 file : str
232 file : str
233 ColorFilename
233 ColorFilename
234 ColorScheme's filename coloring to be used.
234 ColorScheme's filename coloring to be used.
235 ColorNormal
235 ColorNormal
236 ColorScheme's normal coloring to be used.
236 ColorScheme's normal coloring to be used.
237 """
237 """
238 ipinst = get_ipython()
238 ipinst = get_ipython()
239 if (
239 if (
240 ipinst is not None
240 ipinst is not None
241 and (data := ipinst.compile.format_code_name(file)) is not None
241 and (data := ipinst.compile.format_code_name(file)) is not None
242 ):
242 ):
243 label, name = data
243 label, name = data
244 if lineno is None:
244 if lineno is None:
245 tpl_link = f"{{label}} {ColorFilename}{{name}}{ColorNormal}"
245 tpl_link = f"{{label}} {ColorFilename}{{name}}{ColorNormal}"
246 else:
246 else:
247 tpl_link = (
247 tpl_link = (
248 f"{{label}} {ColorFilename}{{name}}, line {{lineno}}{ColorNormal}"
248 f"{{label}} {ColorFilename}{{name}}, line {{lineno}}{ColorNormal}"
249 )
249 )
250 else:
250 else:
251 label = "File"
251 label = "File"
252 name = util_path.compress_user(
252 name = util_path.compress_user(
253 py3compat.cast_unicode(file, util_path.fs_encoding)
253 py3compat.cast_unicode(file, util_path.fs_encoding)
254 )
254 )
255 if lineno is None:
255 if lineno is None:
256 tpl_link = f"{{label}} {ColorFilename}{{name}}{ColorNormal}"
256 tpl_link = f"{{label}} {ColorFilename}{{name}}{ColorNormal}"
257 else:
257 else:
258 # can we make this the more friendly ", line {{lineno}}", or do we need to preserve the formatting with the colon?
258 # can we make this the more friendly ", line {{lineno}}", or do we need to preserve the formatting with the colon?
259 tpl_link = f"{{label}} {ColorFilename}{{name}}:{{lineno}}{ColorNormal}"
259 tpl_link = f"{{label}} {ColorFilename}{{name}}:{{lineno}}{ColorNormal}"
260
260
261 return tpl_link.format(label=label, name=name, lineno=lineno)
261 return tpl_link.format(label=label, name=name, lineno=lineno)
262
262
263 #---------------------------------------------------------------------------
263 #---------------------------------------------------------------------------
264 # Module classes
264 # Module classes
265 class TBTools(colorable.Colorable):
265 class TBTools(colorable.Colorable):
266 """Basic tools used by all traceback printer classes."""
266 """Basic tools used by all traceback printer classes."""
267
267
268 # Number of frames to skip when reporting tracebacks
268 # Number of frames to skip when reporting tracebacks
269 tb_offset = 0
269 tb_offset = 0
270
270
271 def __init__(
271 def __init__(
272 self,
272 self,
273 color_scheme="NoColor",
273 color_scheme="NoColor",
274 call_pdb=False,
274 call_pdb=False,
275 ostream=None,
275 ostream=None,
276 parent=None,
276 parent=None,
277 config=None,
277 config=None,
278 *,
278 *,
279 debugger_cls=None,
279 debugger_cls=None,
280 ):
280 ):
281 # Whether to call the interactive pdb debugger after printing
281 # Whether to call the interactive pdb debugger after printing
282 # tracebacks or not
282 # tracebacks or not
283 super(TBTools, self).__init__(parent=parent, config=config)
283 super(TBTools, self).__init__(parent=parent, config=config)
284 self.call_pdb = call_pdb
284 self.call_pdb = call_pdb
285
285
286 # Output stream to write to. Note that we store the original value in
286 # Output stream to write to. Note that we store the original value in
287 # a private attribute and then make the public ostream a property, so
287 # a private attribute and then make the public ostream a property, so
288 # that we can delay accessing sys.stdout until runtime. The way
288 # that we can delay accessing sys.stdout until runtime. The way
289 # things are written now, the sys.stdout object is dynamically managed
289 # things are written now, the sys.stdout object is dynamically managed
290 # so a reference to it should NEVER be stored statically. This
290 # so a reference to it should NEVER be stored statically. This
291 # property approach confines this detail to a single location, and all
291 # property approach confines this detail to a single location, and all
292 # subclasses can simply access self.ostream for writing.
292 # subclasses can simply access self.ostream for writing.
293 self._ostream = ostream
293 self._ostream = ostream
294
294
295 # Create color table
295 # Create color table
296 self.color_scheme_table = exception_colors()
296 self.color_scheme_table = exception_colors()
297
297
298 self.set_colors(color_scheme)
298 self.set_colors(color_scheme)
299 self.old_scheme = color_scheme # save initial value for toggles
299 self.old_scheme = color_scheme # save initial value for toggles
300 self.debugger_cls = debugger_cls or debugger.Pdb
300 self.debugger_cls = debugger_cls or debugger.Pdb
301
301
302 if call_pdb:
302 if call_pdb:
303 self.pdb = self.debugger_cls()
303 self.pdb = self.debugger_cls()
304 else:
304 else:
305 self.pdb = None
305 self.pdb = None
306
306
307 def _get_ostream(self):
307 def _get_ostream(self):
308 """Output stream that exceptions are written to.
308 """Output stream that exceptions are written to.
309
309
310 Valid values are:
310 Valid values are:
311
311
312 - None: the default, which means that IPython will dynamically resolve
312 - None: the default, which means that IPython will dynamically resolve
313 to sys.stdout. This ensures compatibility with most tools, including
313 to sys.stdout. This ensures compatibility with most tools, including
314 Windows (where plain stdout doesn't recognize ANSI escapes).
314 Windows (where plain stdout doesn't recognize ANSI escapes).
315
315
316 - Any object with 'write' and 'flush' attributes.
316 - Any object with 'write' and 'flush' attributes.
317 """
317 """
318 return sys.stdout if self._ostream is None else self._ostream
318 return sys.stdout if self._ostream is None else self._ostream
319
319
320 def _set_ostream(self, val):
320 def _set_ostream(self, val):
321 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
321 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
322 self._ostream = val
322 self._ostream = val
323
323
324 ostream = property(_get_ostream, _set_ostream)
324 ostream = property(_get_ostream, _set_ostream)
325
325
326 @staticmethod
326 @staticmethod
327 def _get_chained_exception(exception_value):
327 def _get_chained_exception(exception_value):
328 cause = getattr(exception_value, "__cause__", None)
328 cause = getattr(exception_value, "__cause__", None)
329 if cause:
329 if cause:
330 return cause
330 return cause
331 if getattr(exception_value, "__suppress_context__", False):
331 if getattr(exception_value, "__suppress_context__", False):
332 return None
332 return None
333 return getattr(exception_value, "__context__", None)
333 return getattr(exception_value, "__context__", None)
334
334
335 def get_parts_of_chained_exception(
335 def get_parts_of_chained_exception(
336 self, evalue
336 self, evalue
337 ) -> Optional[Tuple[type, BaseException, TracebackType]]:
337 ) -> Optional[Tuple[type, BaseException, TracebackType]]:
338 chained_evalue = self._get_chained_exception(evalue)
338 chained_evalue = self._get_chained_exception(evalue)
339
339
340 if chained_evalue:
340 if chained_evalue:
341 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
341 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
342 return None
342 return None
343
343
344 def prepare_chained_exception_message(self, cause) -> List[Any]:
344 def prepare_chained_exception_message(self, cause) -> List[Any]:
345 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
345 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
346 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
346 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
347
347
348 if cause:
348 if cause:
349 message = [[direct_cause]]
349 message = [[direct_cause]]
350 else:
350 else:
351 message = [[exception_during_handling]]
351 message = [[exception_during_handling]]
352 return message
352 return message
353
353
354 @property
354 @property
355 def has_colors(self) -> bool:
355 def has_colors(self) -> bool:
356 return self.color_scheme_table.active_scheme_name.lower() != "nocolor"
356 return self.color_scheme_table.active_scheme_name.lower() != "nocolor"
357
357
358 def set_colors(self, *args, **kw):
358 def set_colors(self, *args, **kw):
359 """Shorthand access to the color table scheme selector method."""
359 """Shorthand access to the color table scheme selector method."""
360
360
361 # Set own color table
361 # Set own color table
362 self.color_scheme_table.set_active_scheme(*args, **kw)
362 self.color_scheme_table.set_active_scheme(*args, **kw)
363 # for convenience, set Colors to the active scheme
363 # for convenience, set Colors to the active scheme
364 self.Colors = self.color_scheme_table.active_colors
364 self.Colors = self.color_scheme_table.active_colors
365 # Also set colors of debugger
365 # Also set colors of debugger
366 if hasattr(self, 'pdb') and self.pdb is not None:
366 if hasattr(self, 'pdb') and self.pdb is not None:
367 self.pdb.set_colors(*args, **kw)
367 self.pdb.set_colors(*args, **kw)
368
368
369 def color_toggle(self):
369 def color_toggle(self):
370 """Toggle between the currently active color scheme and NoColor."""
370 """Toggle between the currently active color scheme and NoColor."""
371
371
372 if self.color_scheme_table.active_scheme_name == 'NoColor':
372 if self.color_scheme_table.active_scheme_name == 'NoColor':
373 self.color_scheme_table.set_active_scheme(self.old_scheme)
373 self.color_scheme_table.set_active_scheme(self.old_scheme)
374 self.Colors = self.color_scheme_table.active_colors
374 self.Colors = self.color_scheme_table.active_colors
375 else:
375 else:
376 self.old_scheme = self.color_scheme_table.active_scheme_name
376 self.old_scheme = self.color_scheme_table.active_scheme_name
377 self.color_scheme_table.set_active_scheme('NoColor')
377 self.color_scheme_table.set_active_scheme('NoColor')
378 self.Colors = self.color_scheme_table.active_colors
378 self.Colors = self.color_scheme_table.active_colors
379
379
380 def stb2text(self, stb):
380 def stb2text(self, stb):
381 """Convert a structured traceback (a list) to a string."""
381 """Convert a structured traceback (a list) to a string."""
382 return '\n'.join(stb)
382 return '\n'.join(stb)
383
383
384 def text(self, etype, value, tb, tb_offset: Optional[int] = None, context=5):
384 def text(self, etype, value, tb, tb_offset: Optional[int] = None, context=5):
385 """Return formatted traceback.
385 """Return formatted traceback.
386
386
387 Subclasses may override this if they add extra arguments.
387 Subclasses may override this if they add extra arguments.
388 """
388 """
389 tb_list = self.structured_traceback(etype, value, tb,
389 tb_list = self.structured_traceback(etype, value, tb,
390 tb_offset, context)
390 tb_offset, context)
391 return self.stb2text(tb_list)
391 return self.stb2text(tb_list)
392
392
393 def structured_traceback(
393 def structured_traceback(
394 self, etype, evalue, tb, tb_offset: Optional[int] = None, context=5, mode=None
394 self, etype, evalue, tb, tb_offset: Optional[int] = None, context=5, mode=None
395 ):
395 ):
396 """Return a list of traceback frames.
396 """Return a list of traceback frames.
397
397
398 Must be implemented by each class.
398 Must be implemented by each class.
399 """
399 """
400 raise NotImplementedError()
400 raise NotImplementedError()
401
401
402
402
403 #---------------------------------------------------------------------------
403 #---------------------------------------------------------------------------
404 class ListTB(TBTools):
404 class ListTB(TBTools):
405 """Print traceback information from a traceback list, with optional color.
405 """Print traceback information from a traceback list, with optional color.
406
406
407 Calling requires 3 arguments: (etype, evalue, elist)
407 Calling requires 3 arguments: (etype, evalue, elist)
408 as would be obtained by::
408 as would be obtained by::
409
409
410 etype, evalue, tb = sys.exc_info()
410 etype, evalue, tb = sys.exc_info()
411 if tb:
411 if tb:
412 elist = traceback.extract_tb(tb)
412 elist = traceback.extract_tb(tb)
413 else:
413 else:
414 elist = None
414 elist = None
415
415
416 It can thus be used by programs which need to process the traceback before
416 It can thus be used by programs which need to process the traceback before
417 printing (such as console replacements based on the code module from the
417 printing (such as console replacements based on the code module from the
418 standard library).
418 standard library).
419
419
420 Because they are meant to be called without a full traceback (only a
420 Because they are meant to be called without a full traceback (only a
421 list), instances of this class can't call the interactive pdb debugger."""
421 list), instances of this class can't call the interactive pdb debugger."""
422
422
423
423
424 def __call__(self, etype, value, elist):
424 def __call__(self, etype, value, elist):
425 self.ostream.flush()
425 self.ostream.flush()
426 self.ostream.write(self.text(etype, value, elist))
426 self.ostream.write(self.text(etype, value, elist))
427 self.ostream.write('\n')
427 self.ostream.write('\n')
428
428
429 def _extract_tb(self, tb):
429 def _extract_tb(self, tb):
430 if tb:
430 if tb:
431 return traceback.extract_tb(tb)
431 return traceback.extract_tb(tb)
432 else:
432 else:
433 return None
433 return None
434
434
435 def structured_traceback(
435 def structured_traceback(
436 self,
436 self,
437 etype: type,
437 etype: type,
438 evalue: BaseException,
438 evalue: BaseException,
439 etb: Optional[TracebackType] = None,
439 etb: Optional[TracebackType] = None,
440 tb_offset: Optional[int] = None,
440 tb_offset: Optional[int] = None,
441 context=5,
441 context=5,
442 ):
442 ):
443 """Return a color formatted string with the traceback info.
443 """Return a color formatted string with the traceback info.
444
444
445 Parameters
445 Parameters
446 ----------
446 ----------
447 etype : exception type
447 etype : exception type
448 Type of the exception raised.
448 Type of the exception raised.
449 evalue : object
449 evalue : object
450 Data stored in the exception
450 Data stored in the exception
451 etb : list | TracebackType | None
451 etb : list | TracebackType | None
452 If list: List of frames, see class docstring for details.
452 If list: List of frames, see class docstring for details.
453 If Traceback: Traceback of the exception.
453 If Traceback: Traceback of the exception.
454 tb_offset : int, optional
454 tb_offset : int, optional
455 Number of frames in the traceback to skip. If not given, the
455 Number of frames in the traceback to skip. If not given, the
456 instance evalue is used (set in constructor).
456 instance evalue is used (set in constructor).
457 context : int, optional
457 context : int, optional
458 Number of lines of context information to print.
458 Number of lines of context information to print.
459
459
460 Returns
460 Returns
461 -------
461 -------
462 String with formatted exception.
462 String with formatted exception.
463 """
463 """
464 # This is a workaround to get chained_exc_ids in recursive calls
464 # This is a workaround to get chained_exc_ids in recursive calls
465 # etb should not be a tuple if structured_traceback is not recursive
465 # etb should not be a tuple if structured_traceback is not recursive
466 if isinstance(etb, tuple):
466 if isinstance(etb, tuple):
467 etb, chained_exc_ids = etb
467 etb, chained_exc_ids = etb
468 else:
468 else:
469 chained_exc_ids = set()
469 chained_exc_ids = set()
470
470
471 if isinstance(etb, list):
471 if isinstance(etb, list):
472 elist = etb
472 elist = etb
473 elif etb is not None:
473 elif etb is not None:
474 elist = self._extract_tb(etb)
474 elist = self._extract_tb(etb)
475 else:
475 else:
476 elist = []
476 elist = []
477 tb_offset = self.tb_offset if tb_offset is None else tb_offset
477 tb_offset = self.tb_offset if tb_offset is None else tb_offset
478 assert isinstance(tb_offset, int)
478 assert isinstance(tb_offset, int)
479 Colors = self.Colors
479 Colors = self.Colors
480 out_list = []
480 out_list = []
481 if elist:
481 if elist:
482
482
483 if tb_offset and len(elist) > tb_offset:
483 if tb_offset and len(elist) > tb_offset:
484 elist = elist[tb_offset:]
484 elist = elist[tb_offset:]
485
485
486 out_list.append('Traceback %s(most recent call last)%s:' %
486 out_list.append('Traceback %s(most recent call last)%s:' %
487 (Colors.normalEm, Colors.Normal) + '\n')
487 (Colors.normalEm, Colors.Normal) + '\n')
488 out_list.extend(self._format_list(elist))
488 out_list.extend(self._format_list(elist))
489 # The exception info should be a single entry in the list.
489 # The exception info should be a single entry in the list.
490 lines = ''.join(self._format_exception_only(etype, evalue))
490 lines = ''.join(self._format_exception_only(etype, evalue))
491 out_list.append(lines)
491 out_list.append(lines)
492
492
493 exception = self.get_parts_of_chained_exception(evalue)
493 exception = self.get_parts_of_chained_exception(evalue)
494
494
495 if exception and not id(exception[1]) in chained_exc_ids:
495 if exception and not id(exception[1]) in chained_exc_ids:
496 chained_exception_message = self.prepare_chained_exception_message(
496 chained_exception_message = self.prepare_chained_exception_message(
497 evalue.__cause__)[0]
497 evalue.__cause__)[0]
498 etype, evalue, etb = exception
498 etype, evalue, etb = exception
499 # Trace exception to avoid infinite 'cause' loop
499 # Trace exception to avoid infinite 'cause' loop
500 chained_exc_ids.add(id(exception[1]))
500 chained_exc_ids.add(id(exception[1]))
501 chained_exceptions_tb_offset = 0
501 chained_exceptions_tb_offset = 0
502 out_list = (
502 out_list = (
503 self.structured_traceback(
503 self.structured_traceback(
504 etype, evalue, (etb, chained_exc_ids),
504 etype, evalue, (etb, chained_exc_ids),
505 chained_exceptions_tb_offset, context)
505 chained_exceptions_tb_offset, context)
506 + chained_exception_message
506 + chained_exception_message
507 + out_list)
507 + out_list)
508
508
509 return out_list
509 return out_list
510
510
511 def _format_list(self, extracted_list):
511 def _format_list(self, extracted_list):
512 """Format a list of traceback entry tuples for printing.
512 """Format a list of traceback entry tuples for printing.
513
513
514 Given a list of tuples as returned by extract_tb() or
514 Given a list of tuples as returned by extract_tb() or
515 extract_stack(), return a list of strings ready for printing.
515 extract_stack(), return a list of strings ready for printing.
516 Each string in the resulting list corresponds to the item with the
516 Each string in the resulting list corresponds to the item with the
517 same index in the argument list. Each string ends in a newline;
517 same index in the argument list. Each string ends in a newline;
518 the strings may contain internal newlines as well, for those items
518 the strings may contain internal newlines as well, for those items
519 whose source text line is not None.
519 whose source text line is not None.
520
520
521 Lifted almost verbatim from traceback.py
521 Lifted almost verbatim from traceback.py
522 """
522 """
523
523
524 Colors = self.Colors
524 Colors = self.Colors
525 list = []
525 list = []
526 for ind, (filename, lineno, name, line) in enumerate(extracted_list):
526 for ind, (filename, lineno, name, line) in enumerate(extracted_list):
527 normalCol, nameCol, fileCol, lineCol = (
527 normalCol, nameCol, fileCol, lineCol = (
528 # Emphasize the last entry
528 # Emphasize the last entry
529 (Colors.normalEm, Colors.nameEm, Colors.filenameEm, Colors.line)
529 (Colors.normalEm, Colors.nameEm, Colors.filenameEm, Colors.line)
530 if ind == len(extracted_list) - 1
530 if ind == len(extracted_list) - 1
531 else (Colors.Normal, Colors.name, Colors.filename, "")
531 else (Colors.Normal, Colors.name, Colors.filename, "")
532 )
532 )
533
533
534 fns = _format_filename(filename, fileCol, normalCol, lineno=lineno)
534 fns = _format_filename(filename, fileCol, normalCol, lineno=lineno)
535 item = f"{normalCol} {fns}"
535 item = f"{normalCol} {fns}"
536
536
537 if name != "<module>":
537 if name != "<module>":
538 item += f" in {nameCol}{name}{normalCol}\n"
538 item += f" in {nameCol}{name}{normalCol}\n"
539 else:
539 else:
540 item += "\n"
540 item += "\n"
541 if line:
541 if line:
542 item += f"{lineCol} {line.strip()}{normalCol}\n"
542 item += f"{lineCol} {line.strip()}{normalCol}\n"
543 list.append(item)
543 list.append(item)
544
544
545 return list
545 return list
546
546
547 def _format_exception_only(self, etype, value):
547 def _format_exception_only(self, etype, value):
548 """Format the exception part of a traceback.
548 """Format the exception part of a traceback.
549
549
550 The arguments are the exception type and value such as given by
550 The arguments are the exception type and value such as given by
551 sys.exc_info()[:2]. The return value is a list of strings, each ending
551 sys.exc_info()[:2]. The return value is a list of strings, each ending
552 in a newline. Normally, the list contains a single string; however,
552 in a newline. Normally, the list contains a single string; however,
553 for SyntaxError exceptions, it contains several lines that (when
553 for SyntaxError exceptions, it contains several lines that (when
554 printed) display detailed information about where the syntax error
554 printed) display detailed information about where the syntax error
555 occurred. The message indicating which exception occurred is the
555 occurred. The message indicating which exception occurred is the
556 always last string in the list.
556 always last string in the list.
557
557
558 Also lifted nearly verbatim from traceback.py
558 Also lifted nearly verbatim from traceback.py
559 """
559 """
560 have_filedata = False
560 have_filedata = False
561 Colors = self.Colors
561 Colors = self.Colors
562 list = []
562 list = []
563 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
563 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
564 if value is None:
564 if value is None:
565 # Not sure if this can still happen in Python 2.6 and above
565 # Not sure if this can still happen in Python 2.6 and above
566 list.append(stype + '\n')
566 list.append(stype + '\n')
567 else:
567 else:
568 if issubclass(etype, SyntaxError):
568 if issubclass(etype, SyntaxError):
569 have_filedata = True
569 have_filedata = True
570 if not value.filename: value.filename = "<string>"
570 if not value.filename: value.filename = "<string>"
571 if value.lineno:
571 if value.lineno:
572 lineno = value.lineno
572 lineno = value.lineno
573 textline = linecache.getline(value.filename, value.lineno)
573 textline = linecache.getline(value.filename, value.lineno)
574 else:
574 else:
575 lineno = "unknown"
575 lineno = "unknown"
576 textline = ""
576 textline = ""
577 list.append(
577 list.append(
578 "%s %s%s\n"
578 "%s %s%s\n"
579 % (
579 % (
580 Colors.normalEm,
580 Colors.normalEm,
581 _format_filename(
581 _format_filename(
582 value.filename,
582 value.filename,
583 Colors.filenameEm,
583 Colors.filenameEm,
584 Colors.normalEm,
584 Colors.normalEm,
585 lineno=(None if lineno == "unknown" else lineno),
585 lineno=(None if lineno == "unknown" else lineno),
586 ),
586 ),
587 Colors.Normal,
587 Colors.Normal,
588 )
588 )
589 )
589 )
590 if textline == "":
590 if textline == "":
591 textline = py3compat.cast_unicode(value.text, "utf-8")
591 textline = py3compat.cast_unicode(value.text, "utf-8")
592
592
593 if textline is not None:
593 if textline is not None:
594 i = 0
594 i = 0
595 while i < len(textline) and textline[i].isspace():
595 while i < len(textline) and textline[i].isspace():
596 i += 1
596 i += 1
597 list.append('%s %s%s\n' % (Colors.line,
597 list.append('%s %s%s\n' % (Colors.line,
598 textline.strip(),
598 textline.strip(),
599 Colors.Normal))
599 Colors.Normal))
600 if value.offset is not None:
600 if value.offset is not None:
601 s = ' '
601 s = ' '
602 for c in textline[i:value.offset - 1]:
602 for c in textline[i:value.offset - 1]:
603 if c.isspace():
603 if c.isspace():
604 s += c
604 s += c
605 else:
605 else:
606 s += ' '
606 s += ' '
607 list.append('%s%s^%s\n' % (Colors.caret, s,
607 list.append('%s%s^%s\n' % (Colors.caret, s,
608 Colors.Normal))
608 Colors.Normal))
609
609
610 try:
610 try:
611 s = value.msg
611 s = value.msg
612 except Exception:
612 except Exception:
613 s = self._some_str(value)
613 s = self._some_str(value)
614 if s:
614 if s:
615 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
615 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
616 Colors.Normal, s))
616 Colors.Normal, s))
617 else:
617 else:
618 list.append('%s\n' % stype)
618 list.append('%s\n' % stype)
619
619
620 # sync with user hooks
620 # sync with user hooks
621 if have_filedata:
621 if have_filedata:
622 ipinst = get_ipython()
622 ipinst = get_ipython()
623 if ipinst is not None:
623 if ipinst is not None:
624 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
624 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
625
625
626 return list
626 return list
627
627
628 def get_exception_only(self, etype, value):
628 def get_exception_only(self, etype, value):
629 """Only print the exception type and message, without a traceback.
629 """Only print the exception type and message, without a traceback.
630
630
631 Parameters
631 Parameters
632 ----------
632 ----------
633 etype : exception type
633 etype : exception type
634 value : exception value
634 value : exception value
635 """
635 """
636 return ListTB.structured_traceback(self, etype, value)
636 return ListTB.structured_traceback(self, etype, value)
637
637
638 def show_exception_only(self, etype, evalue):
638 def show_exception_only(self, etype, evalue):
639 """Only print the exception type and message, without a traceback.
639 """Only print the exception type and message, without a traceback.
640
640
641 Parameters
641 Parameters
642 ----------
642 ----------
643 etype : exception type
643 etype : exception type
644 evalue : exception value
644 evalue : exception value
645 """
645 """
646 # This method needs to use __call__ from *this* class, not the one from
646 # This method needs to use __call__ from *this* class, not the one from
647 # a subclass whose signature or behavior may be different
647 # a subclass whose signature or behavior may be different
648 ostream = self.ostream
648 ostream = self.ostream
649 ostream.flush()
649 ostream.flush()
650 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
650 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
651 ostream.flush()
651 ostream.flush()
652
652
653 def _some_str(self, value):
653 def _some_str(self, value):
654 # Lifted from traceback.py
654 # Lifted from traceback.py
655 try:
655 try:
656 return py3compat.cast_unicode(str(value))
656 return py3compat.cast_unicode(str(value))
657 except:
657 except:
658 return u'<unprintable %s object>' % type(value).__name__
658 return u'<unprintable %s object>' % type(value).__name__
659
659
660
660
661 class FrameInfo:
661 class FrameInfo:
662 """
662 """
663 Mirror of stack data's FrameInfo, but so that we can bypass highlighting on
663 Mirror of stack data's FrameInfo, but so that we can bypass highlighting on
664 really long frames.
664 really long frames.
665 """
665 """
666
666
667 description: Optional[str]
667 description: Optional[str]
668 filename: str
668 filename: str
669 lineno: int
669 lineno: int
670
670
671 @classmethod
671 @classmethod
672 def _from_stack_data_FrameInfo(cls, frame_info):
672 def _from_stack_data_FrameInfo(cls, frame_info):
673 return cls(
673 return cls(
674 getattr(frame_info, "description", None),
674 getattr(frame_info, "description", None),
675 getattr(frame_info, "filename", None),
675 getattr(frame_info, "filename", None),
676 getattr(frame_info, "lineno", None),
676 getattr(frame_info, "lineno", None),
677 getattr(frame_info, "frame", None),
677 getattr(frame_info, "frame", None),
678 getattr(frame_info, "code", None),
678 getattr(frame_info, "code", None),
679 sd=frame_info,
679 sd=frame_info,
680 )
680 )
681
681
682 def __init__(self, description, filename, lineno, frame, code, sd=None):
682 def __init__(self, description, filename, lineno, frame, code, sd=None):
683 self.description = description
683 self.description = description
684 self.filename = filename
684 self.filename = filename
685 self.lineno = lineno
685 self.lineno = lineno
686 self.frame = frame
686 self.frame = frame
687 self.code = code
687 self.code = code
688 self._sd = sd
688 self._sd = sd
689
689
690 # self.lines = []
690 # self.lines = []
691 if sd is None:
691 if sd is None:
692 ix = inspect.getsourcelines(frame)
692 ix = inspect.getsourcelines(frame)
693 self.raw_lines = ix[0]
693 self.raw_lines = ix[0]
694
694
695 @property
695 @property
696 def variables_in_executing_piece(self):
696 def variables_in_executing_piece(self):
697 if self._sd:
697 if self._sd:
698 return self._sd.variables_in_executing_piece
698 return self._sd.variables_in_executing_piece
699 else:
699 else:
700 return []
700 return []
701
701
702 @property
702 @property
703 def lines(self):
703 def lines(self):
704 return self._sd.lines
704 return self._sd.lines
705
705
706 @property
706 @property
707 def executing(self):
707 def executing(self):
708 if self._sd:
708 if self._sd:
709 return self._sd.executing
709 return self._sd.executing
710 else:
710 else:
711 return None
711 return None
712
712
713
713
714 # ----------------------------------------------------------------------------
714 # ----------------------------------------------------------------------------
715 class VerboseTB(TBTools):
715 class VerboseTB(TBTools):
716 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
716 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
717 of HTML. Requires inspect and pydoc. Crazy, man.
717 of HTML. Requires inspect and pydoc. Crazy, man.
718
718
719 Modified version which optionally strips the topmost entries from the
719 Modified version which optionally strips the topmost entries from the
720 traceback, to be used with alternate interpreters (because their own code
720 traceback, to be used with alternate interpreters (because their own code
721 would appear in the traceback)."""
721 would appear in the traceback)."""
722
722
723 _tb_highlight = "bg:ansiyellow"
723 _tb_highlight = "bg:ansiyellow"
724
724
725 def __init__(
725 def __init__(
726 self,
726 self,
727 color_scheme: str = "Linux",
727 color_scheme: str = "Linux",
728 call_pdb: bool = False,
728 call_pdb: bool = False,
729 ostream=None,
729 ostream=None,
730 tb_offset: int = 0,
730 tb_offset: int = 0,
731 long_header: bool = False,
731 long_header: bool = False,
732 include_vars: bool = True,
732 include_vars: bool = True,
733 check_cache=None,
733 check_cache=None,
734 debugger_cls=None,
734 debugger_cls=None,
735 parent=None,
735 parent=None,
736 config=None,
736 config=None,
737 ):
737 ):
738 """Specify traceback offset, headers and color scheme.
738 """Specify traceback offset, headers and color scheme.
739
739
740 Define how many frames to drop from the tracebacks. Calling it with
740 Define how many frames to drop from the tracebacks. Calling it with
741 tb_offset=1 allows use of this handler in interpreters which will have
741 tb_offset=1 allows use of this handler in interpreters which will have
742 their own code at the top of the traceback (VerboseTB will first
742 their own code at the top of the traceback (VerboseTB will first
743 remove that frame before printing the traceback info)."""
743 remove that frame before printing the traceback info)."""
744 TBTools.__init__(
744 TBTools.__init__(
745 self,
745 self,
746 color_scheme=color_scheme,
746 color_scheme=color_scheme,
747 call_pdb=call_pdb,
747 call_pdb=call_pdb,
748 ostream=ostream,
748 ostream=ostream,
749 parent=parent,
749 parent=parent,
750 config=config,
750 config=config,
751 debugger_cls=debugger_cls,
751 debugger_cls=debugger_cls,
752 )
752 )
753 self.tb_offset = tb_offset
753 self.tb_offset = tb_offset
754 self.long_header = long_header
754 self.long_header = long_header
755 self.include_vars = include_vars
755 self.include_vars = include_vars
756 # By default we use linecache.checkcache, but the user can provide a
756 # By default we use linecache.checkcache, but the user can provide a
757 # different check_cache implementation. This was formerly used by the
757 # different check_cache implementation. This was formerly used by the
758 # IPython kernel for interactive code, but is no longer necessary.
758 # IPython kernel for interactive code, but is no longer necessary.
759 if check_cache is None:
759 if check_cache is None:
760 check_cache = linecache.checkcache
760 check_cache = linecache.checkcache
761 self.check_cache = check_cache
761 self.check_cache = check_cache
762
762
763 self.skip_hidden = True
763 self.skip_hidden = True
764
764
765 def format_record(self, frame_info: FrameInfo):
765 def format_record(self, frame_info: FrameInfo):
766 """Format a single stack frame"""
766 """Format a single stack frame"""
767 assert isinstance(frame_info, FrameInfo)
767 assert isinstance(frame_info, FrameInfo)
768 Colors = self.Colors # just a shorthand + quicker name lookup
768 Colors = self.Colors # just a shorthand + quicker name lookup
769 ColorsNormal = Colors.Normal # used a lot
769 ColorsNormal = Colors.Normal # used a lot
770
770
771 if isinstance(frame_info._sd, stack_data.RepeatedFrames):
771 if isinstance(frame_info._sd, stack_data.RepeatedFrames):
772 return ' %s[... skipping similar frames: %s]%s\n' % (
772 return ' %s[... skipping similar frames: %s]%s\n' % (
773 Colors.excName, frame_info.description, ColorsNormal)
773 Colors.excName, frame_info.description, ColorsNormal)
774
774
775 indent = " " * INDENT_SIZE
775 indent = " " * INDENT_SIZE
776 em_normal = "%s\n%s%s" % (Colors.valEm, indent, ColorsNormal)
776 em_normal = "%s\n%s%s" % (Colors.valEm, indent, ColorsNormal)
777 tpl_call = f"in {Colors.vName}{{file}}{Colors.valEm}{{scope}}{ColorsNormal}"
777 tpl_call = f"in {Colors.vName}{{file}}{Colors.valEm}{{scope}}{ColorsNormal}"
778 tpl_call_fail = "in %s%%s%s(***failed resolving arguments***)%s" % (
778 tpl_call_fail = "in %s%%s%s(***failed resolving arguments***)%s" % (
779 Colors.vName,
779 Colors.vName,
780 Colors.valEm,
780 Colors.valEm,
781 ColorsNormal,
781 ColorsNormal,
782 )
782 )
783 tpl_name_val = "%%s %s= %%s%s" % (Colors.valEm, ColorsNormal)
783 tpl_name_val = "%%s %s= %%s%s" % (Colors.valEm, ColorsNormal)
784
784
785 link = _format_filename(
785 link = _format_filename(
786 frame_info.filename,
786 frame_info.filename,
787 Colors.filenameEm,
787 Colors.filenameEm,
788 ColorsNormal,
788 ColorsNormal,
789 lineno=frame_info.lineno,
789 lineno=frame_info.lineno,
790 )
790 )
791 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
791 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
792 if frame_info.executing is not None:
792 if frame_info.executing is not None:
793 func = frame_info.executing.code_qualname()
793 func = frame_info.executing.code_qualname()
794 else:
794 else:
795 func = "?"
795 func = "?"
796 if func == "<module>":
796 if func == "<module>":
797 call = ""
797 call = ""
798 else:
798 else:
799 # Decide whether to include variable details or not
799 # Decide whether to include variable details or not
800 var_repr = eqrepr if self.include_vars else nullrepr
800 var_repr = eqrepr if self.include_vars else nullrepr
801 try:
801 try:
802 scope = inspect.formatargvalues(
802 scope = inspect.formatargvalues(
803 args, varargs, varkw, locals_, formatvalue=var_repr
803 args, varargs, varkw, locals_, formatvalue=var_repr
804 )
804 )
805 call = tpl_call.format(file=func, scope=scope)
805 call = tpl_call.format(file=func, scope=scope)
806 except KeyError:
806 except KeyError:
807 # This happens in situations like errors inside generator
807 # This happens in situations like errors inside generator
808 # expressions, where local variables are listed in the
808 # expressions, where local variables are listed in the
809 # line, but can't be extracted from the frame. I'm not
809 # line, but can't be extracted from the frame. I'm not
810 # 100% sure this isn't actually a bug in inspect itself,
810 # 100% sure this isn't actually a bug in inspect itself,
811 # but since there's no info for us to compute with, the
811 # but since there's no info for us to compute with, the
812 # best we can do is report the failure and move on. Here
812 # best we can do is report the failure and move on. Here
813 # we must *not* call any traceback construction again,
813 # we must *not* call any traceback construction again,
814 # because that would mess up use of %debug later on. So we
814 # because that would mess up use of %debug later on. So we
815 # simply report the failure and move on. The only
815 # simply report the failure and move on. The only
816 # limitation will be that this frame won't have locals
816 # limitation will be that this frame won't have locals
817 # listed in the call signature. Quite subtle problem...
817 # listed in the call signature. Quite subtle problem...
818 # I can't think of a good way to validate this in a unit
818 # I can't think of a good way to validate this in a unit
819 # test, but running a script consisting of:
819 # test, but running a script consisting of:
820 # dict( (k,v.strip()) for (k,v) in range(10) )
820 # dict( (k,v.strip()) for (k,v) in range(10) )
821 # will illustrate the error, if this exception catch is
821 # will illustrate the error, if this exception catch is
822 # disabled.
822 # disabled.
823 call = tpl_call_fail % func
823 call = tpl_call_fail % func
824
824
825 lvals = ''
825 lvals = ''
826 lvals_list = []
826 lvals_list = []
827 if self.include_vars:
827 if self.include_vars:
828 try:
828 try:
829 # we likely want to fix stackdata at some point, but
829 # we likely want to fix stackdata at some point, but
830 # still need a workaround.
830 # still need a workaround.
831 fibp = frame_info.variables_in_executing_piece
831 fibp = frame_info.variables_in_executing_piece
832 for var in fibp:
832 for var in fibp:
833 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
833 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
834 except Exception:
834 except Exception:
835 lvals_list.append(
835 lvals_list.append(
836 "Exception trying to inspect frame. No more locals available."
836 "Exception trying to inspect frame. No more locals available."
837 )
837 )
838 if lvals_list:
838 if lvals_list:
839 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
839 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
840
840
841 result = f'{link}{", " if call else ""}{call}\n'
841 result = f'{link}{", " if call else ""}{call}\n'
842 if frame_info._sd is None:
842 if frame_info._sd is None:
843 assert False
843 assert False
844 # fast fallback if file is too long
844 # fast fallback if file is too long
845 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
845 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
846 link = tpl_link % util_path.compress_user(frame_info.filename)
846 link = tpl_link % util_path.compress_user(frame_info.filename)
847 level = "%s %s\n" % (link, call)
847 level = "%s %s\n" % (link, call)
848 _line_format = PyColorize.Parser(
848 _line_format = PyColorize.Parser(
849 style=self.color_scheme_table.active_scheme_name, parent=self
849 style=self.color_scheme_table.active_scheme_name, parent=self
850 ).format2
850 ).format2
851 first_line = frame_info.code.co_firstlineno
851 first_line = frame_info.code.co_firstlineno
852 current_line = frame_info.lineno[0]
852 current_line = frame_info.lineno[0]
853 return "%s%s" % (
853 return "%s%s" % (
854 level,
854 level,
855 "".join(
855 "".join(
856 _simple_format_traceback_lines(
856 _simple_format_traceback_lines(
857 current_line,
857 current_line,
858 current_line - first_line,
858 current_line - first_line,
859 frame_info.raw_lines,
859 frame_info.raw_lines,
860 Colors,
860 Colors,
861 lvals,
861 lvals,
862 _line_format,
862 _line_format,
863 )
863 )
864 ),
864 ),
865 )
865 )
866 # result += "\n".join(frame_info.raw_lines)
866 # result += "\n".join(frame_info.raw_lines)
867 else:
867 else:
868 result += "".join(
868 result += "".join(
869 _format_traceback_lines(
869 _format_traceback_lines(
870 frame_info.lines, Colors, self.has_colors, lvals
870 frame_info.lines, Colors, self.has_colors, lvals
871 )
871 )
872 )
872 )
873 return result
873 return result
874
874
875 def prepare_header(self, etype, long_version=False):
875 def prepare_header(self, etype, long_version=False):
876 colors = self.Colors # just a shorthand + quicker name lookup
876 colors = self.Colors # just a shorthand + quicker name lookup
877 colorsnormal = colors.Normal # used a lot
877 colorsnormal = colors.Normal # used a lot
878 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
878 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
879 width = min(75, get_terminal_size()[0])
879 width = min(75, get_terminal_size()[0])
880 if long_version:
880 if long_version:
881 # Header with the exception type, python version, and date
881 # Header with the exception type, python version, and date
882 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
882 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
883 date = time.ctime(time.time())
883 date = time.ctime(time.time())
884
884
885 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
885 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
886 exc, ' ' * (width - len(str(etype)) - len(pyver)),
886 exc, ' ' * (width - len(str(etype)) - len(pyver)),
887 pyver, date.rjust(width) )
887 pyver, date.rjust(width) )
888 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
888 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
889 "\ncalls leading up to the error, with the most recent (innermost) call last."
889 "\ncalls leading up to the error, with the most recent (innermost) call last."
890 else:
890 else:
891 # Simplified header
891 # Simplified header
892 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
892 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
893 rjust(width - len(str(etype))) )
893 rjust(width - len(str(etype))) )
894
894
895 return head
895 return head
896
896
897 def format_exception(self, etype, evalue):
897 def format_exception(self, etype, evalue):
898 colors = self.Colors # just a shorthand + quicker name lookup
898 colors = self.Colors # just a shorthand + quicker name lookup
899 colorsnormal = colors.Normal # used a lot
899 colorsnormal = colors.Normal # used a lot
900 # Get (safely) a string form of the exception info
900 # Get (safely) a string form of the exception info
901 try:
901 try:
902 etype_str, evalue_str = map(str, (etype, evalue))
902 etype_str, evalue_str = map(str, (etype, evalue))
903 except:
903 except:
904 # User exception is improperly defined.
904 # User exception is improperly defined.
905 etype, evalue = str, sys.exc_info()[:2]
905 etype, evalue = str, sys.exc_info()[:2]
906 etype_str, evalue_str = map(str, (etype, evalue))
906 etype_str, evalue_str = map(str, (etype, evalue))
907 # ... and format it
907 # ... and format it
908 return ['%s%s%s: %s' % (colors.excName, etype_str,
908 return ['%s%s%s: %s' % (colors.excName, etype_str,
909 colorsnormal, py3compat.cast_unicode(evalue_str))]
909 colorsnormal, py3compat.cast_unicode(evalue_str))]
910
910
911 def format_exception_as_a_whole(
911 def format_exception_as_a_whole(
912 self,
912 self,
913 etype: type,
913 etype: type,
914 evalue: BaseException,
914 evalue: BaseException,
915 etb: Optional[TracebackType],
915 etb: Optional[TracebackType],
916 number_of_lines_of_context,
916 number_of_lines_of_context,
917 tb_offset: Optional[int],
917 tb_offset: Optional[int],
918 ):
918 ):
919 """Formats the header, traceback and exception message for a single exception.
919 """Formats the header, traceback and exception message for a single exception.
920
920
921 This may be called multiple times by Python 3 exception chaining
921 This may be called multiple times by Python 3 exception chaining
922 (PEP 3134).
922 (PEP 3134).
923 """
923 """
924 # some locals
924 # some locals
925 orig_etype = etype
925 orig_etype = etype
926 try:
926 try:
927 etype = etype.__name__
927 etype = etype.__name__
928 except AttributeError:
928 except AttributeError:
929 pass
929 pass
930
930
931 tb_offset = self.tb_offset if tb_offset is None else tb_offset
931 tb_offset = self.tb_offset if tb_offset is None else tb_offset
932 assert isinstance(tb_offset, int)
932 assert isinstance(tb_offset, int)
933 head = self.prepare_header(etype, self.long_header)
933 head = self.prepare_header(etype, self.long_header)
934 records = (
934 records = (
935 self.get_records(etb, number_of_lines_of_context, tb_offset) if etb else []
935 self.get_records(etb, number_of_lines_of_context, tb_offset) if etb else []
936 )
936 )
937
937
938 frames = []
938 frames = []
939 skipped = 0
939 skipped = 0
940 lastrecord = len(records) - 1
940 lastrecord = len(records) - 1
941 for i, record in enumerate(records):
941 for i, record in enumerate(records):
942 if (
942 if (
943 not isinstance(record._sd, stack_data.RepeatedFrames)
943 not isinstance(record._sd, stack_data.RepeatedFrames)
944 and self.skip_hidden
944 and self.skip_hidden
945 ):
945 ):
946 if (
946 if (
947 record.frame.f_locals.get("__tracebackhide__", 0)
947 record.frame.f_locals.get("__tracebackhide__", 0)
948 and i != lastrecord
948 and i != lastrecord
949 ):
949 ):
950 skipped += 1
950 skipped += 1
951 continue
951 continue
952 if skipped:
952 if skipped:
953 Colors = self.Colors # just a shorthand + quicker name lookup
953 Colors = self.Colors # just a shorthand + quicker name lookup
954 ColorsNormal = Colors.Normal # used a lot
954 ColorsNormal = Colors.Normal # used a lot
955 frames.append(
955 frames.append(
956 " %s[... skipping hidden %s frame]%s\n"
956 " %s[... skipping hidden %s frame]%s\n"
957 % (Colors.excName, skipped, ColorsNormal)
957 % (Colors.excName, skipped, ColorsNormal)
958 )
958 )
959 skipped = 0
959 skipped = 0
960 frames.append(self.format_record(record))
960 frames.append(self.format_record(record))
961 if skipped:
961 if skipped:
962 Colors = self.Colors # just a shorthand + quicker name lookup
962 Colors = self.Colors # just a shorthand + quicker name lookup
963 ColorsNormal = Colors.Normal # used a lot
963 ColorsNormal = Colors.Normal # used a lot
964 frames.append(
964 frames.append(
965 " %s[... skipping hidden %s frame]%s\n"
965 " %s[... skipping hidden %s frame]%s\n"
966 % (Colors.excName, skipped, ColorsNormal)
966 % (Colors.excName, skipped, ColorsNormal)
967 )
967 )
968
968
969 formatted_exception = self.format_exception(etype, evalue)
969 formatted_exception = self.format_exception(etype, evalue)
970 if records:
970 if records:
971 frame_info = records[-1]
971 frame_info = records[-1]
972 ipinst = get_ipython()
972 ipinst = get_ipython()
973 if ipinst is not None:
973 if ipinst is not None:
974 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
974 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
975
975
976 return [[head] + frames + [''.join(formatted_exception[0])]]
976 return [[head] + frames + [''.join(formatted_exception[0])]]
977
977
978 def get_records(
978 def get_records(
979 self, etb: TracebackType, number_of_lines_of_context: int, tb_offset: int
979 self, etb: TracebackType, number_of_lines_of_context: int, tb_offset: int
980 ):
980 ):
981 assert etb is not None
981 assert etb is not None
982 context = number_of_lines_of_context - 1
982 context = number_of_lines_of_context - 1
983 after = context // 2
983 after = context // 2
984 before = context - after
984 before = context - after
985 if self.has_colors:
985 if self.has_colors:
986 style = get_style_by_name("default")
986 style = get_style_by_name("default")
987 style = stack_data.style_with_executing_node(style, self._tb_highlight)
987 style = stack_data.style_with_executing_node(style, self._tb_highlight)
988 formatter = Terminal256Formatter(style=style)
988 formatter = Terminal256Formatter(style=style)
989 else:
989 else:
990 formatter = None
990 formatter = None
991 options = stack_data.Options(
991 options = stack_data.Options(
992 before=before,
992 before=before,
993 after=after,
993 after=after,
994 pygments_formatter=formatter,
994 pygments_formatter=formatter,
995 )
995 )
996
996
997 # let's estimate the amount of code we eill have to parse/highlight.
997 # Let's estimate the amount of code we will have to parse/highlight.
998 cf = etb
998 cf = etb
999 max_len = 0
999 max_len = 0
1000 tbs = []
1000 tbs = []
1001 while cf is not None:
1001 while cf is not None:
1002 try:
1002 try:
1003 source_file = inspect.getsourcefile(etb.tb_frame)
1003 source_file = inspect.getsourcefile(etb.tb_frame)
1004 lines, first = inspect.getsourcelines(etb.tb_frame)
1004 lines, first = inspect.getsourcelines(etb.tb_frame)
1005 except OSError:
1005 except OSError:
1006 max_len = float("-inf")
1006 max_len = float("-inf")
1007 break
1007 break
1008 max_len = max(max_len, first + len(lines))
1008 max_len = max(max_len, first + len(lines))
1009 tbs.append(cf)
1009 tbs.append(cf)
1010 cf = cf.tb_next
1010 cf = cf.tb_next
1011
1011
1012 if max_len > FAST_THRESHOLD:
1012 if max_len > FAST_THRESHOLD:
1013 FIs = []
1013 FIs = []
1014 for tb in tbs:
1014 for tb in tbs:
1015 frame = tb.tb_frame
1015 frame = tb.tb_frame
1016 lineno = (frame.f_lineno,)
1016 lineno = (frame.f_lineno,)
1017 code = frame.f_code
1017 code = frame.f_code
1018 filename = code.co_filename
1018 filename = code.co_filename
1019 FIs.append(FrameInfo("Raw frame", filename, lineno, frame, code))
1019 FIs.append(FrameInfo("Raw frame", filename, lineno, frame, code))
1020 return FIs
1020 return FIs
1021 res = list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
1021 res = list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
1022 res = [FrameInfo._from_stack_data_FrameInfo(r) for r in res]
1022 res = [FrameInfo._from_stack_data_FrameInfo(r) for r in res]
1023 return res
1023 return res
1024
1024
1025 def structured_traceback(
1025 def structured_traceback(
1026 self,
1026 self,
1027 etype: type,
1027 etype: type,
1028 evalue: Optional[BaseException],
1028 evalue: Optional[BaseException],
1029 etb: Optional[TracebackType],
1029 etb: Optional[TracebackType],
1030 tb_offset: Optional[int] = None,
1030 tb_offset: Optional[int] = None,
1031 number_of_lines_of_context: int = 5,
1031 number_of_lines_of_context: int = 5,
1032 ):
1032 ):
1033 """Return a nice text document describing the traceback."""
1033 """Return a nice text document describing the traceback."""
1034 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1034 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1035 tb_offset)
1035 tb_offset)
1036
1036
1037 colors = self.Colors # just a shorthand + quicker name lookup
1037 colors = self.Colors # just a shorthand + quicker name lookup
1038 colorsnormal = colors.Normal # used a lot
1038 colorsnormal = colors.Normal # used a lot
1039 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1039 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1040 structured_traceback_parts = [head]
1040 structured_traceback_parts = [head]
1041 chained_exceptions_tb_offset = 0
1041 chained_exceptions_tb_offset = 0
1042 lines_of_context = 3
1042 lines_of_context = 3
1043 formatted_exceptions = formatted_exception
1043 formatted_exceptions = formatted_exception
1044 exception = self.get_parts_of_chained_exception(evalue)
1044 exception = self.get_parts_of_chained_exception(evalue)
1045 if exception:
1045 if exception:
1046 assert evalue is not None
1046 assert evalue is not None
1047 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1047 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1048 etype, evalue, etb = exception
1048 etype, evalue, etb = exception
1049 else:
1049 else:
1050 evalue = None
1050 evalue = None
1051 chained_exc_ids = set()
1051 chained_exc_ids = set()
1052 while evalue:
1052 while evalue:
1053 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1053 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1054 chained_exceptions_tb_offset)
1054 chained_exceptions_tb_offset)
1055 exception = self.get_parts_of_chained_exception(evalue)
1055 exception = self.get_parts_of_chained_exception(evalue)
1056
1056
1057 if exception and not id(exception[1]) in chained_exc_ids:
1057 if exception and not id(exception[1]) in chained_exc_ids:
1058 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1058 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1059 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1059 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1060 etype, evalue, etb = exception
1060 etype, evalue, etb = exception
1061 else:
1061 else:
1062 evalue = None
1062 evalue = None
1063
1063
1064 # we want to see exceptions in a reversed order:
1064 # we want to see exceptions in a reversed order:
1065 # the first exception should be on top
1065 # the first exception should be on top
1066 for formatted_exception in reversed(formatted_exceptions):
1066 for formatted_exception in reversed(formatted_exceptions):
1067 structured_traceback_parts += formatted_exception
1067 structured_traceback_parts += formatted_exception
1068
1068
1069 return structured_traceback_parts
1069 return structured_traceback_parts
1070
1070
1071 def debugger(self, force: bool = False):
1071 def debugger(self, force: bool = False):
1072 """Call up the pdb debugger if desired, always clean up the tb
1072 """Call up the pdb debugger if desired, always clean up the tb
1073 reference.
1073 reference.
1074
1074
1075 Keywords:
1075 Keywords:
1076
1076
1077 - force(False): by default, this routine checks the instance call_pdb
1077 - force(False): by default, this routine checks the instance call_pdb
1078 flag and does not actually invoke the debugger if the flag is false.
1078 flag and does not actually invoke the debugger if the flag is false.
1079 The 'force' option forces the debugger to activate even if the flag
1079 The 'force' option forces the debugger to activate even if the flag
1080 is false.
1080 is false.
1081
1081
1082 If the call_pdb flag is set, the pdb interactive debugger is
1082 If the call_pdb flag is set, the pdb interactive debugger is
1083 invoked. In all cases, the self.tb reference to the current traceback
1083 invoked. In all cases, the self.tb reference to the current traceback
1084 is deleted to prevent lingering references which hamper memory
1084 is deleted to prevent lingering references which hamper memory
1085 management.
1085 management.
1086
1086
1087 Note that each call to pdb() does an 'import readline', so if your app
1087 Note that each call to pdb() does an 'import readline', so if your app
1088 requires a special setup for the readline completers, you'll have to
1088 requires a special setup for the readline completers, you'll have to
1089 fix that by hand after invoking the exception handler."""
1089 fix that by hand after invoking the exception handler."""
1090
1090
1091 if force or self.call_pdb:
1091 if force or self.call_pdb:
1092 if self.pdb is None:
1092 if self.pdb is None:
1093 self.pdb = self.debugger_cls()
1093 self.pdb = self.debugger_cls()
1094 # the system displayhook may have changed, restore the original
1094 # the system displayhook may have changed, restore the original
1095 # for pdb
1095 # for pdb
1096 display_trap = DisplayTrap(hook=sys.__displayhook__)
1096 display_trap = DisplayTrap(hook=sys.__displayhook__)
1097 with display_trap:
1097 with display_trap:
1098 self.pdb.reset()
1098 self.pdb.reset()
1099 # Find the right frame so we don't pop up inside ipython itself
1099 # Find the right frame so we don't pop up inside ipython itself
1100 if hasattr(self, 'tb') and self.tb is not None:
1100 if hasattr(self, 'tb') and self.tb is not None:
1101 etb = self.tb
1101 etb = self.tb
1102 else:
1102 else:
1103 etb = self.tb = sys.last_traceback
1103 etb = self.tb = sys.last_traceback
1104 while self.tb is not None and self.tb.tb_next is not None:
1104 while self.tb is not None and self.tb.tb_next is not None:
1105 assert self.tb.tb_next is not None
1105 assert self.tb.tb_next is not None
1106 self.tb = self.tb.tb_next
1106 self.tb = self.tb.tb_next
1107 if etb and etb.tb_next:
1107 if etb and etb.tb_next:
1108 etb = etb.tb_next
1108 etb = etb.tb_next
1109 self.pdb.botframe = etb.tb_frame
1109 self.pdb.botframe = etb.tb_frame
1110 self.pdb.interaction(None, etb)
1110 self.pdb.interaction(None, etb)
1111
1111
1112 if hasattr(self, 'tb'):
1112 if hasattr(self, 'tb'):
1113 del self.tb
1113 del self.tb
1114
1114
1115 def handler(self, info=None):
1115 def handler(self, info=None):
1116 (etype, evalue, etb) = info or sys.exc_info()
1116 (etype, evalue, etb) = info or sys.exc_info()
1117 self.tb = etb
1117 self.tb = etb
1118 ostream = self.ostream
1118 ostream = self.ostream
1119 ostream.flush()
1119 ostream.flush()
1120 ostream.write(self.text(etype, evalue, etb))
1120 ostream.write(self.text(etype, evalue, etb))
1121 ostream.write('\n')
1121 ostream.write('\n')
1122 ostream.flush()
1122 ostream.flush()
1123
1123
1124 # Changed so an instance can just be called as VerboseTB_inst() and print
1124 # Changed so an instance can just be called as VerboseTB_inst() and print
1125 # out the right info on its own.
1125 # out the right info on its own.
1126 def __call__(self, etype=None, evalue=None, etb=None):
1126 def __call__(self, etype=None, evalue=None, etb=None):
1127 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1127 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1128 if etb is None:
1128 if etb is None:
1129 self.handler()
1129 self.handler()
1130 else:
1130 else:
1131 self.handler((etype, evalue, etb))
1131 self.handler((etype, evalue, etb))
1132 try:
1132 try:
1133 self.debugger()
1133 self.debugger()
1134 except KeyboardInterrupt:
1134 except KeyboardInterrupt:
1135 print("\nKeyboardInterrupt")
1135 print("\nKeyboardInterrupt")
1136
1136
1137
1137
1138 #----------------------------------------------------------------------------
1138 #----------------------------------------------------------------------------
1139 class FormattedTB(VerboseTB, ListTB):
1139 class FormattedTB(VerboseTB, ListTB):
1140 """Subclass ListTB but allow calling with a traceback.
1140 """Subclass ListTB but allow calling with a traceback.
1141
1141
1142 It can thus be used as a sys.excepthook for Python > 2.1.
1142 It can thus be used as a sys.excepthook for Python > 2.1.
1143
1143
1144 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1144 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1145
1145
1146 Allows a tb_offset to be specified. This is useful for situations where
1146 Allows a tb_offset to be specified. This is useful for situations where
1147 one needs to remove a number of topmost frames from the traceback (such as
1147 one needs to remove a number of topmost frames from the traceback (such as
1148 occurs with python programs that themselves execute other python code,
1148 occurs with python programs that themselves execute other python code,
1149 like Python shells). """
1149 like Python shells). """
1150
1150
1151 mode: str
1151 mode: str
1152
1152
1153 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1153 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1154 ostream=None,
1154 ostream=None,
1155 tb_offset=0, long_header=False, include_vars=False,
1155 tb_offset=0, long_header=False, include_vars=False,
1156 check_cache=None, debugger_cls=None,
1156 check_cache=None, debugger_cls=None,
1157 parent=None, config=None):
1157 parent=None, config=None):
1158
1158
1159 # NEVER change the order of this list. Put new modes at the end:
1159 # NEVER change the order of this list. Put new modes at the end:
1160 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
1160 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
1161 self.verbose_modes = self.valid_modes[1:3]
1161 self.verbose_modes = self.valid_modes[1:3]
1162
1162
1163 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1163 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1164 ostream=ostream, tb_offset=tb_offset,
1164 ostream=ostream, tb_offset=tb_offset,
1165 long_header=long_header, include_vars=include_vars,
1165 long_header=long_header, include_vars=include_vars,
1166 check_cache=check_cache, debugger_cls=debugger_cls,
1166 check_cache=check_cache, debugger_cls=debugger_cls,
1167 parent=parent, config=config)
1167 parent=parent, config=config)
1168
1168
1169 # Different types of tracebacks are joined with different separators to
1169 # Different types of tracebacks are joined with different separators to
1170 # form a single string. They are taken from this dict
1170 # form a single string. They are taken from this dict
1171 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
1171 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
1172 Minimal='')
1172 Minimal='')
1173 # set_mode also sets the tb_join_char attribute
1173 # set_mode also sets the tb_join_char attribute
1174 self.set_mode(mode)
1174 self.set_mode(mode)
1175
1175
1176 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1176 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1177 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1177 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1178 mode = self.mode
1178 mode = self.mode
1179 if mode in self.verbose_modes:
1179 if mode in self.verbose_modes:
1180 # Verbose modes need a full traceback
1180 # Verbose modes need a full traceback
1181 return VerboseTB.structured_traceback(
1181 return VerboseTB.structured_traceback(
1182 self, etype, value, tb, tb_offset, number_of_lines_of_context
1182 self, etype, value, tb, tb_offset, number_of_lines_of_context
1183 )
1183 )
1184 elif mode == 'Minimal':
1184 elif mode == 'Minimal':
1185 return ListTB.get_exception_only(self, etype, value)
1185 return ListTB.get_exception_only(self, etype, value)
1186 else:
1186 else:
1187 # We must check the source cache because otherwise we can print
1187 # We must check the source cache because otherwise we can print
1188 # out-of-date source code.
1188 # out-of-date source code.
1189 self.check_cache()
1189 self.check_cache()
1190 # Now we can extract and format the exception
1190 # Now we can extract and format the exception
1191 return ListTB.structured_traceback(
1191 return ListTB.structured_traceback(
1192 self, etype, value, tb, tb_offset, number_of_lines_of_context
1192 self, etype, value, tb, tb_offset, number_of_lines_of_context
1193 )
1193 )
1194
1194
1195 def stb2text(self, stb):
1195 def stb2text(self, stb):
1196 """Convert a structured traceback (a list) to a string."""
1196 """Convert a structured traceback (a list) to a string."""
1197 return self.tb_join_char.join(stb)
1197 return self.tb_join_char.join(stb)
1198
1198
1199 def set_mode(self, mode: Optional[str] = None):
1199 def set_mode(self, mode: Optional[str] = None):
1200 """Switch to the desired mode.
1200 """Switch to the desired mode.
1201
1201
1202 If mode is not specified, cycles through the available modes."""
1202 If mode is not specified, cycles through the available modes."""
1203
1203
1204 if not mode:
1204 if not mode:
1205 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1205 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1206 len(self.valid_modes)
1206 len(self.valid_modes)
1207 self.mode = self.valid_modes[new_idx]
1207 self.mode = self.valid_modes[new_idx]
1208 elif mode not in self.valid_modes:
1208 elif mode not in self.valid_modes:
1209 raise ValueError(
1209 raise ValueError(
1210 "Unrecognized mode in FormattedTB: <" + mode + ">\n"
1210 "Unrecognized mode in FormattedTB: <" + mode + ">\n"
1211 "Valid modes: " + str(self.valid_modes)
1211 "Valid modes: " + str(self.valid_modes)
1212 )
1212 )
1213 else:
1213 else:
1214 assert isinstance(mode, str)
1214 assert isinstance(mode, str)
1215 self.mode = mode
1215 self.mode = mode
1216 # include variable details only in 'Verbose' mode
1216 # include variable details only in 'Verbose' mode
1217 self.include_vars = (self.mode == self.valid_modes[2])
1217 self.include_vars = (self.mode == self.valid_modes[2])
1218 # Set the join character for generating text tracebacks
1218 # Set the join character for generating text tracebacks
1219 self.tb_join_char = self._join_chars[self.mode]
1219 self.tb_join_char = self._join_chars[self.mode]
1220
1220
1221 # some convenient shortcuts
1221 # some convenient shortcuts
1222 def plain(self):
1222 def plain(self):
1223 self.set_mode(self.valid_modes[0])
1223 self.set_mode(self.valid_modes[0])
1224
1224
1225 def context(self):
1225 def context(self):
1226 self.set_mode(self.valid_modes[1])
1226 self.set_mode(self.valid_modes[1])
1227
1227
1228 def verbose(self):
1228 def verbose(self):
1229 self.set_mode(self.valid_modes[2])
1229 self.set_mode(self.valid_modes[2])
1230
1230
1231 def minimal(self):
1231 def minimal(self):
1232 self.set_mode(self.valid_modes[3])
1232 self.set_mode(self.valid_modes[3])
1233
1233
1234
1234
1235 #----------------------------------------------------------------------------
1235 #----------------------------------------------------------------------------
1236 class AutoFormattedTB(FormattedTB):
1236 class AutoFormattedTB(FormattedTB):
1237 """A traceback printer which can be called on the fly.
1237 """A traceback printer which can be called on the fly.
1238
1238
1239 It will find out about exceptions by itself.
1239 It will find out about exceptions by itself.
1240
1240
1241 A brief example::
1241 A brief example::
1242
1242
1243 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1243 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1244 try:
1244 try:
1245 ...
1245 ...
1246 except:
1246 except:
1247 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1247 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1248 """
1248 """
1249
1249
1250 def __call__(self, etype=None, evalue=None, etb=None,
1250 def __call__(self, etype=None, evalue=None, etb=None,
1251 out=None, tb_offset=None):
1251 out=None, tb_offset=None):
1252 """Print out a formatted exception traceback.
1252 """Print out a formatted exception traceback.
1253
1253
1254 Optional arguments:
1254 Optional arguments:
1255 - out: an open file-like object to direct output to.
1255 - out: an open file-like object to direct output to.
1256
1256
1257 - tb_offset: the number of frames to skip over in the stack, on a
1257 - tb_offset: the number of frames to skip over in the stack, on a
1258 per-call basis (this overrides temporarily the instance's tb_offset
1258 per-call basis (this overrides temporarily the instance's tb_offset
1259 given at initialization time."""
1259 given at initialization time."""
1260
1260
1261 if out is None:
1261 if out is None:
1262 out = self.ostream
1262 out = self.ostream
1263 out.flush()
1263 out.flush()
1264 out.write(self.text(etype, evalue, etb, tb_offset))
1264 out.write(self.text(etype, evalue, etb, tb_offset))
1265 out.write('\n')
1265 out.write('\n')
1266 out.flush()
1266 out.flush()
1267 # FIXME: we should remove the auto pdb behavior from here and leave
1267 # FIXME: we should remove the auto pdb behavior from here and leave
1268 # that to the clients.
1268 # that to the clients.
1269 try:
1269 try:
1270 self.debugger()
1270 self.debugger()
1271 except KeyboardInterrupt:
1271 except KeyboardInterrupt:
1272 print("\nKeyboardInterrupt")
1272 print("\nKeyboardInterrupt")
1273
1273
1274 def structured_traceback(
1274 def structured_traceback(
1275 self,
1275 self,
1276 etype=None,
1276 etype=None,
1277 value=None,
1277 value=None,
1278 tb=None,
1278 tb=None,
1279 tb_offset=None,
1279 tb_offset=None,
1280 number_of_lines_of_context=5,
1280 number_of_lines_of_context=5,
1281 ):
1281 ):
1282 etype: type
1282 etype: type
1283 value: BaseException
1283 value: BaseException
1284 # tb: TracebackType or tupleof tb types ?
1284 # tb: TracebackType or tupleof tb types ?
1285 if etype is None:
1285 if etype is None:
1286 etype, value, tb = sys.exc_info()
1286 etype, value, tb = sys.exc_info()
1287 if isinstance(tb, tuple):
1287 if isinstance(tb, tuple):
1288 # tb is a tuple if this is a chained exception.
1288 # tb is a tuple if this is a chained exception.
1289 self.tb = tb[0]
1289 self.tb = tb[0]
1290 else:
1290 else:
1291 self.tb = tb
1291 self.tb = tb
1292 return FormattedTB.structured_traceback(
1292 return FormattedTB.structured_traceback(
1293 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1293 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1294
1294
1295
1295
1296 #---------------------------------------------------------------------------
1296 #---------------------------------------------------------------------------
1297
1297
1298 # A simple class to preserve Nathan's original functionality.
1298 # A simple class to preserve Nathan's original functionality.
1299 class ColorTB(FormattedTB):
1299 class ColorTB(FormattedTB):
1300 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1300 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1301
1301
1302 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1302 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1303 FormattedTB.__init__(self, color_scheme=color_scheme,
1303 FormattedTB.__init__(self, color_scheme=color_scheme,
1304 call_pdb=call_pdb, **kwargs)
1304 call_pdb=call_pdb, **kwargs)
1305
1305
1306
1306
1307 class SyntaxTB(ListTB):
1307 class SyntaxTB(ListTB):
1308 """Extension which holds some state: the last exception value"""
1308 """Extension which holds some state: the last exception value"""
1309
1309
1310 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1310 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1311 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1311 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1312 self.last_syntax_error = None
1312 self.last_syntax_error = None
1313
1313
1314 def __call__(self, etype, value, elist):
1314 def __call__(self, etype, value, elist):
1315 self.last_syntax_error = value
1315 self.last_syntax_error = value
1316
1316
1317 ListTB.__call__(self, etype, value, elist)
1317 ListTB.__call__(self, etype, value, elist)
1318
1318
1319 def structured_traceback(self, etype, value, elist, tb_offset=None,
1319 def structured_traceback(self, etype, value, elist, tb_offset=None,
1320 context=5):
1320 context=5):
1321 # If the source file has been edited, the line in the syntax error can
1321 # If the source file has been edited, the line in the syntax error can
1322 # be wrong (retrieved from an outdated cache). This replaces it with
1322 # be wrong (retrieved from an outdated cache). This replaces it with
1323 # the current value.
1323 # the current value.
1324 if isinstance(value, SyntaxError) \
1324 if isinstance(value, SyntaxError) \
1325 and isinstance(value.filename, str) \
1325 and isinstance(value.filename, str) \
1326 and isinstance(value.lineno, int):
1326 and isinstance(value.lineno, int):
1327 linecache.checkcache(value.filename)
1327 linecache.checkcache(value.filename)
1328 newtext = linecache.getline(value.filename, value.lineno)
1328 newtext = linecache.getline(value.filename, value.lineno)
1329 if newtext:
1329 if newtext:
1330 value.text = newtext
1330 value.text = newtext
1331 self.last_syntax_error = value
1331 self.last_syntax_error = value
1332 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1332 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1333 tb_offset=tb_offset, context=context)
1333 tb_offset=tb_offset, context=context)
1334
1334
1335 def clear_err_state(self):
1335 def clear_err_state(self):
1336 """Return the current error state and clear it"""
1336 """Return the current error state and clear it"""
1337 e = self.last_syntax_error
1337 e = self.last_syntax_error
1338 self.last_syntax_error = None
1338 self.last_syntax_error = None
1339 return e
1339 return e
1340
1340
1341 def stb2text(self, stb):
1341 def stb2text(self, stb):
1342 """Convert a structured traceback (a list) to a string."""
1342 """Convert a structured traceback (a list) to a string."""
1343 return ''.join(stb)
1343 return ''.join(stb)
1344
1344
1345
1345
1346 # some internal-use functions
1346 # some internal-use functions
1347 def text_repr(value):
1347 def text_repr(value):
1348 """Hopefully pretty robust repr equivalent."""
1348 """Hopefully pretty robust repr equivalent."""
1349 # this is pretty horrible but should always return *something*
1349 # this is pretty horrible but should always return *something*
1350 try:
1350 try:
1351 return pydoc.text.repr(value)
1351 return pydoc.text.repr(value)
1352 except KeyboardInterrupt:
1352 except KeyboardInterrupt:
1353 raise
1353 raise
1354 except:
1354 except:
1355 try:
1355 try:
1356 return repr(value)
1356 return repr(value)
1357 except KeyboardInterrupt:
1357 except KeyboardInterrupt:
1358 raise
1358 raise
1359 except:
1359 except:
1360 try:
1360 try:
1361 # all still in an except block so we catch
1361 # all still in an except block so we catch
1362 # getattr raising
1362 # getattr raising
1363 name = getattr(value, '__name__', None)
1363 name = getattr(value, '__name__', None)
1364 if name:
1364 if name:
1365 # ick, recursion
1365 # ick, recursion
1366 return text_repr(name)
1366 return text_repr(name)
1367 klass = getattr(value, '__class__', None)
1367 klass = getattr(value, '__class__', None)
1368 if klass:
1368 if klass:
1369 return '%s instance' % text_repr(klass)
1369 return '%s instance' % text_repr(klass)
1370 except KeyboardInterrupt:
1370 except KeyboardInterrupt:
1371 raise
1371 raise
1372 except:
1372 except:
1373 return 'UNRECOVERABLE REPR FAILURE'
1373 return 'UNRECOVERABLE REPR FAILURE'
1374
1374
1375
1375
1376 def eqrepr(value, repr=text_repr):
1376 def eqrepr(value, repr=text_repr):
1377 return '=%s' % repr(value)
1377 return '=%s' % repr(value)
1378
1378
1379
1379
1380 def nullrepr(value, repr=text_repr):
1380 def nullrepr(value, repr=text_repr):
1381 return ''
1381 return ''
@@ -1,405 +1,410 b''
1 """
1 """
2 This module contains factory functions that attempt
2 This module contains factory functions that attempt
3 to return Qt submodules from the various python Qt bindings.
3 to return Qt submodules from the various python Qt bindings.
4
4
5 It also protects against double-importing Qt with different
5 It also protects against double-importing Qt with different
6 bindings, which is unstable and likely to crash
6 bindings, which is unstable and likely to crash
7
7
8 This is used primarily by qt and qt_for_kernel, and shouldn't
8 This is used primarily by qt and qt_for_kernel, and shouldn't
9 be accessed directly from the outside
9 be accessed directly from the outside
10 """
10 """
11 import importlib.abc
11 import importlib.abc
12 import sys
12 import sys
13 import os
13 import types
14 import types
14 from functools import partial, lru_cache
15 from functools import partial, lru_cache
15 import operator
16 import operator
16
17
17 # ### Available APIs.
18 # ### Available APIs.
18 # Qt6
19 # Qt6
19 QT_API_PYQT6 = "pyqt6"
20 QT_API_PYQT6 = "pyqt6"
20 QT_API_PYSIDE6 = "pyside6"
21 QT_API_PYSIDE6 = "pyside6"
21
22
22 # Qt5
23 # Qt5
23 QT_API_PYQT5 = 'pyqt5'
24 QT_API_PYQT5 = 'pyqt5'
24 QT_API_PYSIDE2 = 'pyside2'
25 QT_API_PYSIDE2 = 'pyside2'
25
26
26 # Qt4
27 # Qt4
27 # NOTE: Here for legacy matplotlib compatibility, but not really supported on the IPython side.
28 # NOTE: Here for legacy matplotlib compatibility, but not really supported on the IPython side.
28 QT_API_PYQT = "pyqt" # Force version 2
29 QT_API_PYQT = "pyqt" # Force version 2
29 QT_API_PYQTv1 = "pyqtv1" # Force version 2
30 QT_API_PYQTv1 = "pyqtv1" # Force version 2
30 QT_API_PYSIDE = "pyside"
31 QT_API_PYSIDE = "pyside"
31
32
32 QT_API_PYQT_DEFAULT = "pyqtdefault" # use system default for version 1 vs. 2
33 QT_API_PYQT_DEFAULT = "pyqtdefault" # use system default for version 1 vs. 2
33
34
34 api_to_module = {
35 api_to_module = {
35 # Qt6
36 # Qt6
36 QT_API_PYQT6: "PyQt6",
37 QT_API_PYQT6: "PyQt6",
37 QT_API_PYSIDE6: "PySide6",
38 QT_API_PYSIDE6: "PySide6",
38 # Qt5
39 # Qt5
39 QT_API_PYQT5: "PyQt5",
40 QT_API_PYQT5: "PyQt5",
40 QT_API_PYSIDE2: "PySide2",
41 QT_API_PYSIDE2: "PySide2",
41 # Qt4
42 # Qt4
42 QT_API_PYSIDE: "PySide",
43 QT_API_PYSIDE: "PySide",
43 QT_API_PYQT: "PyQt4",
44 QT_API_PYQT: "PyQt4",
44 QT_API_PYQTv1: "PyQt4",
45 QT_API_PYQTv1: "PyQt4",
45 # default
46 # default
46 QT_API_PYQT_DEFAULT: "PyQt6",
47 QT_API_PYQT_DEFAULT: "PyQt6",
47 }
48 }
48
49
49
50
50 class ImportDenier(importlib.abc.MetaPathFinder):
51 class ImportDenier(importlib.abc.MetaPathFinder):
51 """Import Hook that will guard against bad Qt imports
52 """Import Hook that will guard against bad Qt imports
52 once IPython commits to a specific binding
53 once IPython commits to a specific binding
53 """
54 """
54
55
55 def __init__(self):
56 def __init__(self):
56 self.__forbidden = set()
57 self.__forbidden = set()
57
58
58 def forbid(self, module_name):
59 def forbid(self, module_name):
59 sys.modules.pop(module_name, None)
60 sys.modules.pop(module_name, None)
60 self.__forbidden.add(module_name)
61 self.__forbidden.add(module_name)
61
62
62 def find_spec(self, fullname, path, target=None):
63 def find_spec(self, fullname, path, target=None):
63 if path:
64 if path:
64 return
65 return
65 if fullname in self.__forbidden:
66 if fullname in self.__forbidden:
66 raise ImportError(
67 raise ImportError(
67 """
68 """
68 Importing %s disabled by IPython, which has
69 Importing %s disabled by IPython, which has
69 already imported an Incompatible QT Binding: %s
70 already imported an Incompatible QT Binding: %s
70 """
71 """
71 % (fullname, loaded_api())
72 % (fullname, loaded_api())
72 )
73 )
73
74
74
75
75 ID = ImportDenier()
76 ID = ImportDenier()
76 sys.meta_path.insert(0, ID)
77 sys.meta_path.insert(0, ID)
77
78
78
79
79 def commit_api(api):
80 def commit_api(api):
80 """Commit to a particular API, and trigger ImportErrors on subsequent
81 """Commit to a particular API, and trigger ImportErrors on subsequent
81 dangerous imports"""
82 dangerous imports"""
82 modules = set(api_to_module.values())
83 modules = set(api_to_module.values())
83
84
84 modules.remove(api_to_module[api])
85 modules.remove(api_to_module[api])
85 for mod in modules:
86 for mod in modules:
86 ID.forbid(mod)
87 ID.forbid(mod)
87
88
88
89
89 def loaded_api():
90 def loaded_api():
90 """Return which API is loaded, if any
91 """Return which API is loaded, if any
91
92
92 If this returns anything besides None,
93 If this returns anything besides None,
93 importing any other Qt binding is unsafe.
94 importing any other Qt binding is unsafe.
94
95
95 Returns
96 Returns
96 -------
97 -------
97 None, 'pyside6', 'pyqt6', 'pyside2', 'pyside', 'pyqt', 'pyqt5', 'pyqtv1'
98 None, 'pyside6', 'pyqt6', 'pyside2', 'pyside', 'pyqt', 'pyqt5', 'pyqtv1'
98 """
99 """
99 if sys.modules.get("PyQt6.QtCore"):
100 if sys.modules.get("PyQt6.QtCore"):
100 return QT_API_PYQT6
101 return QT_API_PYQT6
101 elif sys.modules.get("PySide6.QtCore"):
102 elif sys.modules.get("PySide6.QtCore"):
102 return QT_API_PYSIDE6
103 return QT_API_PYSIDE6
103 elif sys.modules.get("PyQt5.QtCore"):
104 elif sys.modules.get("PyQt5.QtCore"):
104 return QT_API_PYQT5
105 return QT_API_PYQT5
105 elif sys.modules.get("PySide2.QtCore"):
106 elif sys.modules.get("PySide2.QtCore"):
106 return QT_API_PYSIDE2
107 return QT_API_PYSIDE2
107 elif sys.modules.get("PyQt4.QtCore"):
108 elif sys.modules.get("PyQt4.QtCore"):
108 if qtapi_version() == 2:
109 if qtapi_version() == 2:
109 return QT_API_PYQT
110 return QT_API_PYQT
110 else:
111 else:
111 return QT_API_PYQTv1
112 return QT_API_PYQTv1
112 elif sys.modules.get("PySide.QtCore"):
113 elif sys.modules.get("PySide.QtCore"):
113 return QT_API_PYSIDE
114 return QT_API_PYSIDE
114
115
115 return None
116 return None
116
117
117
118
118 def has_binding(api):
119 def has_binding(api):
119 """Safely check for PyQt4/5, PySide or PySide2, without importing submodules
120 """Safely check for PyQt4/5, PySide or PySide2, without importing submodules
120
121
121 Parameters
122 Parameters
122 ----------
123 ----------
123 api : str [ 'pyqtv1' | 'pyqt' | 'pyqt5' | 'pyside' | 'pyside2' | 'pyqtdefault']
124 api : str [ 'pyqtv1' | 'pyqt' | 'pyqt5' | 'pyside' | 'pyside2' | 'pyqtdefault']
124 Which module to check for
125 Which module to check for
125
126
126 Returns
127 Returns
127 -------
128 -------
128 True if the relevant module appears to be importable
129 True if the relevant module appears to be importable
129 """
130 """
130 module_name = api_to_module[api]
131 module_name = api_to_module[api]
131 from importlib.util import find_spec
132 from importlib.util import find_spec
132
133
133 required = ['QtCore', 'QtGui', 'QtSvg']
134 required = ['QtCore', 'QtGui', 'QtSvg']
134 if api in (QT_API_PYQT5, QT_API_PYSIDE2, QT_API_PYQT6, QT_API_PYSIDE6):
135 if api in (QT_API_PYQT5, QT_API_PYSIDE2, QT_API_PYQT6, QT_API_PYSIDE6):
135 # QT5 requires QtWidgets too
136 # QT5 requires QtWidgets too
136 required.append('QtWidgets')
137 required.append('QtWidgets')
137
138
138 for submod in required:
139 for submod in required:
139 try:
140 try:
140 spec = find_spec('%s.%s' % (module_name, submod))
141 spec = find_spec('%s.%s' % (module_name, submod))
141 except ImportError:
142 except ImportError:
142 # Package (e.g. PyQt5) not found
143 # Package (e.g. PyQt5) not found
143 return False
144 return False
144 else:
145 else:
145 if spec is None:
146 if spec is None:
146 # Submodule (e.g. PyQt5.QtCore) not found
147 # Submodule (e.g. PyQt5.QtCore) not found
147 return False
148 return False
148
149
149 if api == QT_API_PYSIDE:
150 if api == QT_API_PYSIDE:
150 # We can also safely check PySide version
151 # We can also safely check PySide version
151 import PySide
152 import PySide
152
153
153 return PySide.__version_info__ >= (1, 0, 3)
154 return PySide.__version_info__ >= (1, 0, 3)
154
155
155 return True
156 return True
156
157
157
158
158 def qtapi_version():
159 def qtapi_version():
159 """Return which QString API has been set, if any
160 """Return which QString API has been set, if any
160
161
161 Returns
162 Returns
162 -------
163 -------
163 The QString API version (1 or 2), or None if not set
164 The QString API version (1 or 2), or None if not set
164 """
165 """
165 try:
166 try:
166 import sip
167 import sip
167 except ImportError:
168 except ImportError:
168 # as of PyQt5 5.11, sip is no longer available as a top-level
169 # as of PyQt5 5.11, sip is no longer available as a top-level
169 # module and needs to be imported from the PyQt5 namespace
170 # module and needs to be imported from the PyQt5 namespace
170 try:
171 try:
171 from PyQt5 import sip
172 from PyQt5 import sip
172 except ImportError:
173 except ImportError:
173 return
174 return
174 try:
175 try:
175 return sip.getapi('QString')
176 return sip.getapi('QString')
176 except ValueError:
177 except ValueError:
177 return
178 return
178
179
179
180
180 def can_import(api):
181 def can_import(api):
181 """Safely query whether an API is importable, without importing it"""
182 """Safely query whether an API is importable, without importing it"""
182 if not has_binding(api):
183 if not has_binding(api):
183 return False
184 return False
184
185
185 current = loaded_api()
186 current = loaded_api()
186 if api == QT_API_PYQT_DEFAULT:
187 if api == QT_API_PYQT_DEFAULT:
187 return current in [QT_API_PYQT6, None]
188 return current in [QT_API_PYQT6, None]
188 else:
189 else:
189 return current in [api, None]
190 return current in [api, None]
190
191
191
192
192 def import_pyqt4(version=2):
193 def import_pyqt4(version=2):
193 """
194 """
194 Import PyQt4
195 Import PyQt4
195
196
196 Parameters
197 Parameters
197 ----------
198 ----------
198 version : 1, 2, or None
199 version : 1, 2, or None
199 Which QString/QVariant API to use. Set to None to use the system
200 Which QString/QVariant API to use. Set to None to use the system
200 default
201 default
201 ImportErrors raised within this function are non-recoverable
202 ImportErrors raised within this function are non-recoverable
202 """
203 """
203 # The new-style string API (version=2) automatically
204 # The new-style string API (version=2) automatically
204 # converts QStrings to Unicode Python strings. Also, automatically unpacks
205 # converts QStrings to Unicode Python strings. Also, automatically unpacks
205 # QVariants to their underlying objects.
206 # QVariants to their underlying objects.
206 import sip
207 import sip
207
208
208 if version is not None:
209 if version is not None:
209 sip.setapi('QString', version)
210 sip.setapi('QString', version)
210 sip.setapi('QVariant', version)
211 sip.setapi('QVariant', version)
211
212
212 from PyQt4 import QtGui, QtCore, QtSvg
213 from PyQt4 import QtGui, QtCore, QtSvg
213
214
214 if QtCore.PYQT_VERSION < 0x040700:
215 if QtCore.PYQT_VERSION < 0x040700:
215 raise ImportError("IPython requires PyQt4 >= 4.7, found %s" %
216 raise ImportError("IPython requires PyQt4 >= 4.7, found %s" %
216 QtCore.PYQT_VERSION_STR)
217 QtCore.PYQT_VERSION_STR)
217
218
218 # Alias PyQt-specific functions for PySide compatibility.
219 # Alias PyQt-specific functions for PySide compatibility.
219 QtCore.Signal = QtCore.pyqtSignal
220 QtCore.Signal = QtCore.pyqtSignal
220 QtCore.Slot = QtCore.pyqtSlot
221 QtCore.Slot = QtCore.pyqtSlot
221
222
222 # query for the API version (in case version == None)
223 # query for the API version (in case version == None)
223 version = sip.getapi('QString')
224 version = sip.getapi('QString')
224 api = QT_API_PYQTv1 if version == 1 else QT_API_PYQT
225 api = QT_API_PYQTv1 if version == 1 else QT_API_PYQT
225 return QtCore, QtGui, QtSvg, api
226 return QtCore, QtGui, QtSvg, api
226
227
227
228
228 def import_pyqt5():
229 def import_pyqt5():
229 """
230 """
230 Import PyQt5
231 Import PyQt5
231
232
232 ImportErrors raised within this function are non-recoverable
233 ImportErrors raised within this function are non-recoverable
233 """
234 """
234
235
235 from PyQt5 import QtCore, QtSvg, QtWidgets, QtGui
236 from PyQt5 import QtCore, QtSvg, QtWidgets, QtGui
236
237
237 # Alias PyQt-specific functions for PySide compatibility.
238 # Alias PyQt-specific functions for PySide compatibility.
238 QtCore.Signal = QtCore.pyqtSignal
239 QtCore.Signal = QtCore.pyqtSignal
239 QtCore.Slot = QtCore.pyqtSlot
240 QtCore.Slot = QtCore.pyqtSlot
240
241
241 # Join QtGui and QtWidgets for Qt4 compatibility.
242 # Join QtGui and QtWidgets for Qt4 compatibility.
242 QtGuiCompat = types.ModuleType('QtGuiCompat')
243 QtGuiCompat = types.ModuleType('QtGuiCompat')
243 QtGuiCompat.__dict__.update(QtGui.__dict__)
244 QtGuiCompat.__dict__.update(QtGui.__dict__)
244 QtGuiCompat.__dict__.update(QtWidgets.__dict__)
245 QtGuiCompat.__dict__.update(QtWidgets.__dict__)
245
246
246 api = QT_API_PYQT5
247 api = QT_API_PYQT5
247 return QtCore, QtGuiCompat, QtSvg, api
248 return QtCore, QtGuiCompat, QtSvg, api
248
249
249
250
250 def import_pyqt6():
251 def import_pyqt6():
251 """
252 """
252 Import PyQt6
253 Import PyQt6
253
254
254 ImportErrors raised within this function are non-recoverable
255 ImportErrors raised within this function are non-recoverable
255 """
256 """
256
257
257 from PyQt6 import QtCore, QtSvg, QtWidgets, QtGui
258 from PyQt6 import QtCore, QtSvg, QtWidgets, QtGui
258
259
259 # Alias PyQt-specific functions for PySide compatibility.
260 # Alias PyQt-specific functions for PySide compatibility.
260 QtCore.Signal = QtCore.pyqtSignal
261 QtCore.Signal = QtCore.pyqtSignal
261 QtCore.Slot = QtCore.pyqtSlot
262 QtCore.Slot = QtCore.pyqtSlot
262
263
263 # Join QtGui and QtWidgets for Qt4 compatibility.
264 # Join QtGui and QtWidgets for Qt4 compatibility.
264 QtGuiCompat = types.ModuleType("QtGuiCompat")
265 QtGuiCompat = types.ModuleType("QtGuiCompat")
265 QtGuiCompat.__dict__.update(QtGui.__dict__)
266 QtGuiCompat.__dict__.update(QtGui.__dict__)
266 QtGuiCompat.__dict__.update(QtWidgets.__dict__)
267 QtGuiCompat.__dict__.update(QtWidgets.__dict__)
267
268
268 api = QT_API_PYQT6
269 api = QT_API_PYQT6
269 return QtCore, QtGuiCompat, QtSvg, api
270 return QtCore, QtGuiCompat, QtSvg, api
270
271
271
272
272 def import_pyside():
273 def import_pyside():
273 """
274 """
274 Import PySide
275 Import PySide
275
276
276 ImportErrors raised within this function are non-recoverable
277 ImportErrors raised within this function are non-recoverable
277 """
278 """
278 from PySide import QtGui, QtCore, QtSvg
279 from PySide import QtGui, QtCore, QtSvg
279 return QtCore, QtGui, QtSvg, QT_API_PYSIDE
280 return QtCore, QtGui, QtSvg, QT_API_PYSIDE
280
281
281 def import_pyside2():
282 def import_pyside2():
282 """
283 """
283 Import PySide2
284 Import PySide2
284
285
285 ImportErrors raised within this function are non-recoverable
286 ImportErrors raised within this function are non-recoverable
286 """
287 """
287 from PySide2 import QtGui, QtCore, QtSvg, QtWidgets, QtPrintSupport
288 from PySide2 import QtGui, QtCore, QtSvg, QtWidgets, QtPrintSupport
288
289
289 # Join QtGui and QtWidgets for Qt4 compatibility.
290 # Join QtGui and QtWidgets for Qt4 compatibility.
290 QtGuiCompat = types.ModuleType('QtGuiCompat')
291 QtGuiCompat = types.ModuleType('QtGuiCompat')
291 QtGuiCompat.__dict__.update(QtGui.__dict__)
292 QtGuiCompat.__dict__.update(QtGui.__dict__)
292 QtGuiCompat.__dict__.update(QtWidgets.__dict__)
293 QtGuiCompat.__dict__.update(QtWidgets.__dict__)
293 QtGuiCompat.__dict__.update(QtPrintSupport.__dict__)
294 QtGuiCompat.__dict__.update(QtPrintSupport.__dict__)
294
295
295 return QtCore, QtGuiCompat, QtSvg, QT_API_PYSIDE2
296 return QtCore, QtGuiCompat, QtSvg, QT_API_PYSIDE2
296
297
297
298
298 def import_pyside6():
299 def import_pyside6():
299 """
300 """
300 Import PySide6
301 Import PySide6
301
302
302 ImportErrors raised within this function are non-recoverable
303 ImportErrors raised within this function are non-recoverable
303 """
304 """
304 from PySide6 import QtGui, QtCore, QtSvg, QtWidgets, QtPrintSupport
305 from PySide6 import QtGui, QtCore, QtSvg, QtWidgets, QtPrintSupport
305
306
306 # Join QtGui and QtWidgets for Qt4 compatibility.
307 # Join QtGui and QtWidgets for Qt4 compatibility.
307 QtGuiCompat = types.ModuleType("QtGuiCompat")
308 QtGuiCompat = types.ModuleType("QtGuiCompat")
308 QtGuiCompat.__dict__.update(QtGui.__dict__)
309 QtGuiCompat.__dict__.update(QtGui.__dict__)
309 QtGuiCompat.__dict__.update(QtWidgets.__dict__)
310 QtGuiCompat.__dict__.update(QtWidgets.__dict__)
310 QtGuiCompat.__dict__.update(QtPrintSupport.__dict__)
311 QtGuiCompat.__dict__.update(QtPrintSupport.__dict__)
311
312
312 return QtCore, QtGuiCompat, QtSvg, QT_API_PYSIDE6
313 return QtCore, QtGuiCompat, QtSvg, QT_API_PYSIDE6
313
314
314
315
315 def load_qt(api_options):
316 def load_qt(api_options):
316 """
317 """
317 Attempt to import Qt, given a preference list
318 Attempt to import Qt, given a preference list
318 of permissible bindings
319 of permissible bindings
319
320
320 It is safe to call this function multiple times.
321 It is safe to call this function multiple times.
321
322
322 Parameters
323 Parameters
323 ----------
324 ----------
324 api_options : List of strings
325 api_options : List of strings
325 The order of APIs to try. Valid items are 'pyside', 'pyside2',
326 The order of APIs to try. Valid items are 'pyside', 'pyside2',
326 'pyqt', 'pyqt5', 'pyqtv1' and 'pyqtdefault'
327 'pyqt', 'pyqt5', 'pyqtv1' and 'pyqtdefault'
327
328
328 Returns
329 Returns
329 -------
330 -------
330 A tuple of QtCore, QtGui, QtSvg, QT_API
331 A tuple of QtCore, QtGui, QtSvg, QT_API
331 The first three are the Qt modules. The last is the
332 The first three are the Qt modules. The last is the
332 string indicating which module was loaded.
333 string indicating which module was loaded.
333
334
334 Raises
335 Raises
335 ------
336 ------
336 ImportError, if it isn't possible to import any requested
337 ImportError, if it isn't possible to import any requested
337 bindings (either because they aren't installed, or because
338 bindings (either because they aren't installed, or because
338 an incompatible library has already been installed)
339 an incompatible library has already been installed)
339 """
340 """
340 loaders = {
341 loaders = {
341 # Qt6
342 # Qt6
342 QT_API_PYQT6: import_pyqt6,
343 QT_API_PYQT6: import_pyqt6,
343 QT_API_PYSIDE6: import_pyside6,
344 QT_API_PYSIDE6: import_pyside6,
344 # Qt5
345 # Qt5
345 QT_API_PYQT5: import_pyqt5,
346 QT_API_PYQT5: import_pyqt5,
346 QT_API_PYSIDE2: import_pyside2,
347 QT_API_PYSIDE2: import_pyside2,
347 # Qt4
348 # Qt4
348 QT_API_PYSIDE: import_pyside,
349 QT_API_PYSIDE: import_pyside,
349 QT_API_PYQT: import_pyqt4,
350 QT_API_PYQT: import_pyqt4,
350 QT_API_PYQTv1: partial(import_pyqt4, version=1),
351 QT_API_PYQTv1: partial(import_pyqt4, version=1),
351 # default
352 # default
352 QT_API_PYQT_DEFAULT: import_pyqt6,
353 QT_API_PYQT_DEFAULT: import_pyqt6,
353 }
354 }
354
355
355 for api in api_options:
356 for api in api_options:
356
357
357 if api not in loaders:
358 if api not in loaders:
358 raise RuntimeError(
359 raise RuntimeError(
359 "Invalid Qt API %r, valid values are: %s" %
360 "Invalid Qt API %r, valid values are: %s" %
360 (api, ", ".join(["%r" % k for k in loaders.keys()])))
361 (api, ", ".join(["%r" % k for k in loaders.keys()])))
361
362
362 if not can_import(api):
363 if not can_import(api):
363 continue
364 continue
364
365
365 #cannot safely recover from an ImportError during this
366 #cannot safely recover from an ImportError during this
366 result = loaders[api]()
367 result = loaders[api]()
367 api = result[-1] # changed if api = QT_API_PYQT_DEFAULT
368 api = result[-1] # changed if api = QT_API_PYQT_DEFAULT
368 commit_api(api)
369 commit_api(api)
369 return result
370 return result
370 else:
371 else:
372 # Clear the environment variable since it doesn't work.
373 if "QT_API" in os.environ:
374 del os.environ["QT_API"]
375
371 raise ImportError(
376 raise ImportError(
372 """
377 """
373 Could not load requested Qt binding. Please ensure that
378 Could not load requested Qt binding. Please ensure that
374 PyQt4 >= 4.7, PyQt5, PyQt6, PySide >= 1.0.3, PySide2, or
379 PyQt4 >= 4.7, PyQt5, PyQt6, PySide >= 1.0.3, PySide2, or
375 PySide6 is available, and only one is imported per session.
380 PySide6 is available, and only one is imported per session.
376
381
377 Currently-imported Qt library: %r
382 Currently-imported Qt library: %r
378 PyQt5 available (requires QtCore, QtGui, QtSvg, QtWidgets): %s
383 PyQt5 available (requires QtCore, QtGui, QtSvg, QtWidgets): %s
379 PyQt6 available (requires QtCore, QtGui, QtSvg, QtWidgets): %s
384 PyQt6 available (requires QtCore, QtGui, QtSvg, QtWidgets): %s
380 PySide2 installed: %s
385 PySide2 installed: %s
381 PySide6 installed: %s
386 PySide6 installed: %s
382 Tried to load: %r
387 Tried to load: %r
383 """
388 """
384 % (
389 % (
385 loaded_api(),
390 loaded_api(),
386 has_binding(QT_API_PYQT5),
391 has_binding(QT_API_PYQT5),
387 has_binding(QT_API_PYQT6),
392 has_binding(QT_API_PYQT6),
388 has_binding(QT_API_PYSIDE2),
393 has_binding(QT_API_PYSIDE2),
389 has_binding(QT_API_PYSIDE6),
394 has_binding(QT_API_PYSIDE6),
390 api_options,
395 api_options,
391 )
396 )
392 )
397 )
393
398
394
399
395 def enum_factory(QT_API, QtCore):
400 def enum_factory(QT_API, QtCore):
396 """Construct an enum helper to account for PyQt5 <-> PyQt6 changes."""
401 """Construct an enum helper to account for PyQt5 <-> PyQt6 changes."""
397
402
398 @lru_cache(None)
403 @lru_cache(None)
399 def _enum(name):
404 def _enum(name):
400 # foo.bar.Enum.Entry (PyQt6) <=> foo.bar.Entry (non-PyQt6).
405 # foo.bar.Enum.Entry (PyQt6) <=> foo.bar.Entry (non-PyQt6).
401 return operator.attrgetter(
406 return operator.attrgetter(
402 name if QT_API == QT_API_PYQT6 else name.rpartition(".")[0]
407 name if QT_API == QT_API_PYQT6 else name.rpartition(".")[0]
403 )(sys.modules[QtCore.__package__])
408 )(sys.modules[QtCore.__package__])
404
409
405 return _enum
410 return _enum
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
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