##// 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 1 name: Run tests
2 2
3 3 on:
4 4 push:
5 5 branches:
6 6 - main
7 7 - '*.x'
8 8 pull_request:
9 9 # Run weekly on Monday at 1:23 UTC
10 10 schedule:
11 11 - cron: '23 1 * * 1'
12 12 workflow_dispatch:
13 13
14 14
15 15 jobs:
16 16 test:
17 17 runs-on: ${{ matrix.os }}
18 18 strategy:
19 19 fail-fast: false
20 20 matrix:
21 21 os: [ubuntu-latest, windows-latest]
22 22 python-version: ["3.8", "3.9", "3.10", "3.11"]
23 23 deps: [test_extra]
24 24 # Test all on ubuntu, test ends on macos
25 25 include:
26 26 - os: macos-latest
27 27 python-version: "3.8"
28 28 deps: test_extra
29 29 - os: macos-latest
30 30 python-version: "3.11"
31 31 deps: test_extra
32 32 # Tests minimal dependencies set
33 33 - os: ubuntu-latest
34 34 python-version: "3.11"
35 35 deps: test
36 36 # Tests latest development Python version
37 37 - os: ubuntu-latest
38 38 python-version: "3.12-dev"
39 39 deps: test
40 40 # Installing optional dependencies stuff takes ages on PyPy
41 41 - os: ubuntu-latest
42 42 python-version: "pypy-3.8"
43 43 deps: test
44 44 - os: windows-latest
45 45 python-version: "pypy-3.8"
46 46 deps: test
47 47 - os: macos-latest
48 48 python-version: "pypy-3.8"
49 49 deps: test
50 50
51 51 steps:
52 52 - uses: actions/checkout@v3
53 53 - name: Set up Python ${{ matrix.python-version }}
54 54 uses: actions/setup-python@v4
55 55 with:
56 56 python-version: ${{ matrix.python-version }}
57 57 cache: pip
58 58 - name: Install latex
59 59 if: runner.os == 'Linux' && matrix.deps == 'test_extra'
60 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 61 - name: Install and update Python dependencies
62 62 run: |
63 63 python -m pip install --upgrade pip setuptools wheel build
64 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 66 - name: Try building with Python build
67 67 if: runner.os != 'Windows' # setup.py does not support sdist on Windows
68 68 run: |
69 69 python -m build
70 70 shasum -a 256 dist/*
71 71 - name: Check manifest
72 72 if: runner.os != 'Windows' # setup.py does not support sdist on Windows
73 73 run: check-manifest
74 74 - name: pytest
75 75 env:
76 76 COLUMNS: 120
77 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 85 - name: Upload coverage to Codecov
80 86 uses: codecov/codecov-action@v3
81 87 with:
82 88 name: Test
83 89 files: /home/runner/work/ipython/ipython/coverage.xml
@@ -1,965 +1,968 b''
1 1 """ History related magics and functionality """
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6
7 7 import atexit
8 8 import datetime
9 9 from pathlib import Path
10 10 import re
11 11 import sqlite3
12 12 import threading
13 13
14 14 from traitlets.config.configurable import LoggingConfigurable
15 15 from decorator import decorator
16 16 from IPython.utils.decorators import undoc
17 17 from IPython.paths import locate_profile
18 18 from traitlets import (
19 19 Any,
20 20 Bool,
21 21 Dict,
22 22 Instance,
23 23 Integer,
24 24 List,
25 25 Unicode,
26 26 Union,
27 27 TraitError,
28 28 default,
29 29 observe,
30 30 )
31 31
32 32 #-----------------------------------------------------------------------------
33 33 # Classes and functions
34 34 #-----------------------------------------------------------------------------
35 35
36 36 @undoc
37 37 class DummyDB(object):
38 38 """Dummy DB that will act as a black hole for history.
39 39
40 40 Only used in the absence of sqlite"""
41 41 def execute(*args, **kwargs):
42 42 return []
43 43
44 44 def commit(self, *args, **kwargs):
45 45 pass
46 46
47 47 def __enter__(self, *args, **kwargs):
48 48 pass
49 49
50 50 def __exit__(self, *args, **kwargs):
51 51 pass
52 52
53 53
54 54 @decorator
55 55 def only_when_enabled(f, self, *a, **kw):
56 56 """Decorator: return an empty list in the absence of sqlite."""
57 57 if not self.enabled:
58 58 return []
59 59 else:
60 60 return f(self, *a, **kw)
61 61
62 62
63 63 # use 16kB as threshold for whether a corrupt history db should be saved
64 64 # that should be at least 100 entries or so
65 65 _SAVE_DB_SIZE = 16384
66 66
67 67 @decorator
68 68 def catch_corrupt_db(f, self, *a, **kw):
69 69 """A decorator which wraps HistoryAccessor method calls to catch errors from
70 70 a corrupt SQLite database, move the old database out of the way, and create
71 71 a new one.
72 72
73 73 We avoid clobbering larger databases because this may be triggered due to filesystem issues,
74 74 not just a corrupt file.
75 75 """
76 76 try:
77 77 return f(self, *a, **kw)
78 78 except (sqlite3.DatabaseError, sqlite3.OperationalError) as e:
79 79 self._corrupt_db_counter += 1
80 80 self.log.error("Failed to open SQLite history %s (%s).", self.hist_file, e)
81 81 if self.hist_file != ':memory:':
82 82 if self._corrupt_db_counter > self._corrupt_db_limit:
83 83 self.hist_file = ':memory:'
84 84 self.log.error("Failed to load history too many times, history will not be saved.")
85 85 elif self.hist_file.is_file():
86 86 # move the file out of the way
87 87 base = str(self.hist_file.parent / self.hist_file.stem)
88 88 ext = self.hist_file.suffix
89 89 size = self.hist_file.stat().st_size
90 90 if size >= _SAVE_DB_SIZE:
91 91 # if there's significant content, avoid clobbering
92 92 now = datetime.datetime.now().isoformat().replace(':', '.')
93 93 newpath = base + '-corrupt-' + now + ext
94 94 # don't clobber previous corrupt backups
95 95 for i in range(100):
96 96 if not Path(newpath).exists():
97 97 break
98 98 else:
99 99 newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext
100 100 else:
101 101 # not much content, possibly empty; don't worry about clobbering
102 102 # maybe we should just delete it?
103 103 newpath = base + '-corrupt' + ext
104 104 self.hist_file.rename(newpath)
105 105 self.log.error("History file was moved to %s and a new file created.", newpath)
106 106 self.init_db()
107 107 return []
108 108 else:
109 109 # Failed with :memory:, something serious is wrong
110 110 raise
111 111
112 112
113 113 class HistoryAccessorBase(LoggingConfigurable):
114 114 """An abstract class for History Accessors """
115 115
116 116 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
117 117 raise NotImplementedError
118 118
119 119 def search(self, pattern="*", raw=True, search_raw=True,
120 120 output=False, n=None, unique=False):
121 121 raise NotImplementedError
122 122
123 123 def get_range(self, session, start=1, stop=None, raw=True,output=False):
124 124 raise NotImplementedError
125 125
126 126 def get_range_by_str(self, rangestr, raw=True, output=False):
127 127 raise NotImplementedError
128 128
129 129
130 130 class HistoryAccessor(HistoryAccessorBase):
131 131 """Access the history database without adding to it.
132 132
133 133 This is intended for use by standalone history tools. IPython shells use
134 134 HistoryManager, below, which is a subclass of this."""
135 135
136 136 # counter for init_db retries, so we don't keep trying over and over
137 137 _corrupt_db_counter = 0
138 138 # after two failures, fallback on :memory:
139 139 _corrupt_db_limit = 2
140 140
141 141 # String holding the path to the history file
142 142 hist_file = Union(
143 143 [Instance(Path), Unicode()],
144 144 help="""Path to file to use for SQLite history database.
145 145
146 146 By default, IPython will put the history database in the IPython
147 147 profile directory. If you would rather share one history among
148 148 profiles, you can set this value in each, so that they are consistent.
149 149
150 150 Due to an issue with fcntl, SQLite is known to misbehave on some NFS
151 151 mounts. If you see IPython hanging, try setting this to something on a
152 152 local disk, e.g::
153 153
154 154 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
155 155
156 156 you can also use the specific value `:memory:` (including the colon
157 157 at both end but not the back ticks), to avoid creating an history file.
158 158
159 159 """,
160 160 ).tag(config=True)
161 161
162 162 enabled = Bool(True,
163 163 help="""enable the SQLite history
164 164
165 165 set enabled=False to disable the SQLite history,
166 166 in which case there will be no stored history, no SQLite connection,
167 167 and no background saving thread. This may be necessary in some
168 168 threaded environments where IPython is embedded.
169 169 """,
170 170 ).tag(config=True)
171 171
172 172 connection_options = Dict(
173 173 help="""Options for configuring the SQLite connection
174 174
175 175 These options are passed as keyword args to sqlite3.connect
176 176 when establishing database connections.
177 177 """
178 178 ).tag(config=True)
179 179
180 180 # The SQLite database
181 181 db = Any()
182 182 @observe('db')
183 183 def _db_changed(self, change):
184 184 """validate the db, since it can be an Instance of two different types"""
185 185 new = change['new']
186 186 connection_types = (DummyDB, sqlite3.Connection)
187 187 if not isinstance(new, connection_types):
188 188 msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
189 189 (self.__class__.__name__, new)
190 190 raise TraitError(msg)
191 191
192 192 def __init__(self, profile="default", hist_file="", **traits):
193 193 """Create a new history accessor.
194 194
195 195 Parameters
196 196 ----------
197 197 profile : str
198 198 The name of the profile from which to open history.
199 199 hist_file : str
200 200 Path to an SQLite history database stored by IPython. If specified,
201 201 hist_file overrides profile.
202 202 config : :class:`~traitlets.config.loader.Config`
203 203 Config object. hist_file can also be set through this.
204 204 """
205 205 super(HistoryAccessor, self).__init__(**traits)
206 206 # defer setting hist_file from kwarg until after init,
207 207 # otherwise the default kwarg value would clobber any value
208 208 # set by config
209 209 if hist_file:
210 210 self.hist_file = hist_file
211 211
212 212 try:
213 213 self.hist_file
214 214 except TraitError:
215 215 # No one has set the hist_file, yet.
216 216 self.hist_file = self._get_hist_file_name(profile)
217 217
218 218 self.init_db()
219 219
220 220 def _get_hist_file_name(self, profile='default'):
221 221 """Find the history file for the given profile name.
222 222
223 223 This is overridden by the HistoryManager subclass, to use the shell's
224 224 active profile.
225 225
226 226 Parameters
227 227 ----------
228 228 profile : str
229 229 The name of a profile which has a history file.
230 230 """
231 231 return Path(locate_profile(profile)) / "history.sqlite"
232 232
233 233 @catch_corrupt_db
234 234 def init_db(self):
235 235 """Connect to the database, and create tables if necessary."""
236 236 if not self.enabled:
237 237 self.db = DummyDB()
238 238 return
239 239
240 240 # use detect_types so that timestamps return datetime objects
241 241 kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
242 242 kwargs.update(self.connection_options)
243 243 self.db = sqlite3.connect(str(self.hist_file), **kwargs)
244 244 with self.db:
245 245 self.db.execute(
246 246 """CREATE TABLE IF NOT EXISTS sessions (session integer
247 247 primary key autoincrement, start timestamp,
248 248 end timestamp, num_cmds integer, remark text)"""
249 249 )
250 250 self.db.execute(
251 251 """CREATE TABLE IF NOT EXISTS history
252 252 (session integer, line integer, source text, source_raw text,
253 253 PRIMARY KEY (session, line))"""
254 254 )
255 255 # Output history is optional, but ensure the table's there so it can be
256 256 # enabled later.
257 257 self.db.execute(
258 258 """CREATE TABLE IF NOT EXISTS output_history
259 259 (session integer, line integer, output text,
260 260 PRIMARY KEY (session, line))"""
261 261 )
262 262 # success! reset corrupt db count
263 263 self._corrupt_db_counter = 0
264 264
265 265 def writeout_cache(self):
266 266 """Overridden by HistoryManager to dump the cache before certain
267 267 database lookups."""
268 268 pass
269 269
270 270 ## -------------------------------
271 271 ## Methods for retrieving history:
272 272 ## -------------------------------
273 273 def _run_sql(self, sql, params, raw=True, output=False, latest=False):
274 274 """Prepares and runs an SQL query for the history database.
275 275
276 276 Parameters
277 277 ----------
278 278 sql : str
279 279 Any filtering expressions to go after SELECT ... FROM ...
280 280 params : tuple
281 281 Parameters passed to the SQL query (to replace "?")
282 282 raw, output : bool
283 283 See :meth:`get_range`
284 284 latest : bool
285 285 Select rows with max (session, line)
286 286
287 287 Returns
288 288 -------
289 289 Tuples as :meth:`get_range`
290 290 """
291 291 toget = 'source_raw' if raw else 'source'
292 292 sqlfrom = "history"
293 293 if output:
294 294 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
295 295 toget = "history.%s, output_history.output" % toget
296 296 if latest:
297 297 toget += ", MAX(session * 128 * 1024 + line)"
298 298 this_querry = "SELECT session, line, %s FROM %s " % (toget, sqlfrom) + sql
299 299 cur = self.db.execute(this_querry, params)
300 300 if latest:
301 301 cur = (row[:-1] for row in cur)
302 302 if output: # Regroup into 3-tuples, and parse JSON
303 303 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
304 304 return cur
305 305
306 306 @only_when_enabled
307 307 @catch_corrupt_db
308 308 def get_session_info(self, session):
309 309 """Get info about a session.
310 310
311 311 Parameters
312 312 ----------
313 313 session : int
314 314 Session number to retrieve.
315 315
316 316 Returns
317 317 -------
318 318 session_id : int
319 319 Session ID number
320 320 start : datetime
321 321 Timestamp for the start of the session.
322 322 end : datetime
323 323 Timestamp for the end of the session, or None if IPython crashed.
324 324 num_cmds : int
325 325 Number of commands run, or None if IPython crashed.
326 326 remark : unicode
327 327 A manually set description.
328 328 """
329 329 query = "SELECT * from sessions where session == ?"
330 330 return self.db.execute(query, (session,)).fetchone()
331 331
332 332 @catch_corrupt_db
333 333 def get_last_session_id(self):
334 334 """Get the last session ID currently in the database.
335 335
336 336 Within IPython, this should be the same as the value stored in
337 337 :attr:`HistoryManager.session_number`.
338 338 """
339 339 for record in self.get_tail(n=1, include_latest=True):
340 340 return record[0]
341 341
342 342 @catch_corrupt_db
343 343 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
344 344 """Get the last n lines from the history database.
345 345
346 346 Parameters
347 347 ----------
348 348 n : int
349 349 The number of lines to get
350 350 raw, output : bool
351 351 See :meth:`get_range`
352 352 include_latest : bool
353 353 If False (default), n+1 lines are fetched, and the latest one
354 354 is discarded. This is intended to be used where the function
355 355 is called by a user command, which it should not return.
356 356
357 357 Returns
358 358 -------
359 359 Tuples as :meth:`get_range`
360 360 """
361 361 self.writeout_cache()
362 362 if not include_latest:
363 363 n += 1
364 364 cur = self._run_sql(
365 365 "ORDER BY session DESC, line DESC LIMIT ?", (n,), raw=raw, output=output
366 366 )
367 367 if not include_latest:
368 368 return reversed(list(cur)[1:])
369 369 return reversed(list(cur))
370 370
371 371 @catch_corrupt_db
372 372 def search(self, pattern="*", raw=True, search_raw=True,
373 373 output=False, n=None, unique=False):
374 374 """Search the database using unix glob-style matching (wildcards
375 375 * and ?).
376 376
377 377 Parameters
378 378 ----------
379 379 pattern : str
380 380 The wildcarded pattern to match when searching
381 381 search_raw : bool
382 382 If True, search the raw input, otherwise, the parsed input
383 383 raw, output : bool
384 384 See :meth:`get_range`
385 385 n : None or int
386 386 If an integer is given, it defines the limit of
387 387 returned entries.
388 388 unique : bool
389 389 When it is true, return only unique entries.
390 390
391 391 Returns
392 392 -------
393 393 Tuples as :meth:`get_range`
394 394 """
395 395 tosearch = "source_raw" if search_raw else "source"
396 396 if output:
397 397 tosearch = "history." + tosearch
398 398 self.writeout_cache()
399 399 sqlform = "WHERE %s GLOB ?" % tosearch
400 400 params = (pattern,)
401 401 if unique:
402 402 sqlform += ' GROUP BY {0}'.format(tosearch)
403 403 if n is not None:
404 404 sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
405 405 params += (n,)
406 406 elif unique:
407 407 sqlform += " ORDER BY session, line"
408 408 cur = self._run_sql(sqlform, params, raw=raw, output=output, latest=unique)
409 409 if n is not None:
410 410 return reversed(list(cur))
411 411 return cur
412 412
413 413 @catch_corrupt_db
414 414 def get_range(self, session, start=1, stop=None, raw=True,output=False):
415 415 """Retrieve input by session.
416 416
417 417 Parameters
418 418 ----------
419 419 session : int
420 420 Session number to retrieve.
421 421 start : int
422 422 First line to retrieve.
423 423 stop : int
424 424 End of line range (excluded from output itself). If None, retrieve
425 425 to the end of the session.
426 426 raw : bool
427 427 If True, return untranslated input
428 428 output : bool
429 429 If True, attempt to include output. This will be 'real' Python
430 430 objects for the current session, or text reprs from previous
431 431 sessions if db_log_output was enabled at the time. Where no output
432 432 is found, None is used.
433 433
434 434 Returns
435 435 -------
436 436 entries
437 437 An iterator over the desired lines. Each line is a 3-tuple, either
438 438 (session, line, input) if output is False, or
439 439 (session, line, (input, output)) if output is True.
440 440 """
441 441 if stop:
442 442 lineclause = "line >= ? AND line < ?"
443 443 params = (session, start, stop)
444 444 else:
445 445 lineclause = "line>=?"
446 446 params = (session, start)
447 447
448 448 return self._run_sql("WHERE session==? AND %s" % lineclause,
449 449 params, raw=raw, output=output)
450 450
451 451 def get_range_by_str(self, rangestr, raw=True, output=False):
452 452 """Get lines of history from a string of ranges, as used by magic
453 453 commands %hist, %save, %macro, etc.
454 454
455 455 Parameters
456 456 ----------
457 457 rangestr : str
458 458 A string specifying ranges, e.g. "5 ~2/1-4". If empty string is used,
459 459 this will return everything from current session's history.
460 460
461 461 See the documentation of :func:`%history` for the full details.
462 462
463 463 raw, output : bool
464 464 As :meth:`get_range`
465 465
466 466 Returns
467 467 -------
468 468 Tuples as :meth:`get_range`
469 469 """
470 470 for sess, s, e in extract_hist_ranges(rangestr):
471 471 for line in self.get_range(sess, s, e, raw=raw, output=output):
472 472 yield line
473 473
474 474
475 475 class HistoryManager(HistoryAccessor):
476 476 """A class to organize all history-related functionality in one place.
477 477 """
478 478 # Public interface
479 479
480 480 # An instance of the IPython shell we are attached to
481 481 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
482 482 allow_none=True)
483 483 # Lists to hold processed and raw history. These start with a blank entry
484 484 # so that we can index them starting from 1
485 485 input_hist_parsed = List([""])
486 486 input_hist_raw = List([""])
487 487 # A list of directories visited during session
488 488 dir_hist = List()
489 489 @default('dir_hist')
490 490 def _dir_hist_default(self):
491 491 try:
492 492 return [Path.cwd()]
493 493 except OSError:
494 494 return []
495 495
496 496 # A dict of output history, keyed with ints from the shell's
497 497 # execution count.
498 498 output_hist = Dict()
499 499 # The text/plain repr of outputs.
500 500 output_hist_reprs = Dict()
501 501
502 502 # The number of the current session in the history database
503 503 session_number = Integer()
504 504
505 505 db_log_output = Bool(False,
506 506 help="Should the history database include output? (default: no)"
507 507 ).tag(config=True)
508 508 db_cache_size = Integer(0,
509 509 help="Write to database every x commands (higher values save disk access & power).\n"
510 510 "Values of 1 or less effectively disable caching."
511 511 ).tag(config=True)
512 512 # The input and output caches
513 513 db_input_cache = List()
514 514 db_output_cache = List()
515 515
516 516 # History saving in separate thread
517 517 save_thread = Instance('IPython.core.history.HistorySavingThread',
518 518 allow_none=True)
519 519 save_flag = Instance(threading.Event, allow_none=True)
520 520
521 521 # Private interface
522 522 # Variables used to store the three last inputs from the user. On each new
523 523 # history update, we populate the user's namespace with these, shifted as
524 524 # necessary.
525 525 _i00 = Unicode(u'')
526 526 _i = Unicode(u'')
527 527 _ii = Unicode(u'')
528 528 _iii = Unicode(u'')
529 529
530 530 # A regex matching all forms of the exit command, so that we don't store
531 531 # them in the history (it's annoying to rewind the first entry and land on
532 532 # an exit call).
533 533 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
534 534
535 535 def __init__(self, shell=None, config=None, **traits):
536 536 """Create a new history manager associated with a shell instance.
537 537 """
538 538 super(HistoryManager, self).__init__(shell=shell, config=config,
539 539 **traits)
540 540 self.save_flag = threading.Event()
541 541 self.db_input_cache_lock = threading.Lock()
542 542 self.db_output_cache_lock = threading.Lock()
543 543
544 544 try:
545 545 self.new_session()
546 546 except sqlite3.OperationalError:
547 547 self.log.error("Failed to create history session in %s. History will not be saved.",
548 548 self.hist_file, exc_info=True)
549 549 self.hist_file = ':memory:'
550 550
551 551 if self.enabled and self.hist_file != ':memory:':
552 552 self.save_thread = HistorySavingThread(self)
553 553 self.save_thread.start()
554 554
555 555 def _get_hist_file_name(self, profile=None):
556 556 """Get default history file name based on the Shell's profile.
557 557
558 558 The profile parameter is ignored, but must exist for compatibility with
559 559 the parent class."""
560 560 profile_dir = self.shell.profile_dir.location
561 561 return Path(profile_dir) / "history.sqlite"
562 562
563 563 @only_when_enabled
564 564 def new_session(self, conn=None):
565 565 """Get a new session number."""
566 566 if conn is None:
567 567 conn = self.db
568 568
569 569 with conn:
570 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
571 NULL, "") """, (datetime.datetime.now(),))
570 cur = conn.execute(
571 """INSERT INTO sessions VALUES (NULL, ?, NULL,
572 NULL, '') """,
573 (datetime.datetime.now(),),
574 )
572 575 self.session_number = cur.lastrowid
573 576
574 577 def end_session(self):
575 578 """Close the database session, filling in the end time and line count."""
576 579 self.writeout_cache()
577 580 with self.db:
578 581 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
579 582 session==?""", (datetime.datetime.now(),
580 583 len(self.input_hist_parsed)-1, self.session_number))
581 584 self.session_number = 0
582 585
583 586 def name_session(self, name):
584 587 """Give the current session a name in the history database."""
585 588 with self.db:
586 589 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
587 590 (name, self.session_number))
588 591
589 592 def reset(self, new_session=True):
590 593 """Clear the session history, releasing all object references, and
591 594 optionally open a new session."""
592 595 self.output_hist.clear()
593 596 # The directory history can't be completely empty
594 597 self.dir_hist[:] = [Path.cwd()]
595 598
596 599 if new_session:
597 600 if self.session_number:
598 601 self.end_session()
599 602 self.input_hist_parsed[:] = [""]
600 603 self.input_hist_raw[:] = [""]
601 604 self.new_session()
602 605
603 606 # ------------------------------
604 607 # Methods for retrieving history
605 608 # ------------------------------
606 609 def get_session_info(self, session=0):
607 610 """Get info about a session.
608 611
609 612 Parameters
610 613 ----------
611 614 session : int
612 615 Session number to retrieve. The current session is 0, and negative
613 616 numbers count back from current session, so -1 is the previous session.
614 617
615 618 Returns
616 619 -------
617 620 session_id : int
618 621 Session ID number
619 622 start : datetime
620 623 Timestamp for the start of the session.
621 624 end : datetime
622 625 Timestamp for the end of the session, or None if IPython crashed.
623 626 num_cmds : int
624 627 Number of commands run, or None if IPython crashed.
625 628 remark : unicode
626 629 A manually set description.
627 630 """
628 631 if session <= 0:
629 632 session += self.session_number
630 633
631 634 return super(HistoryManager, self).get_session_info(session=session)
632 635
633 636 @catch_corrupt_db
634 637 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
635 638 """Get the last n lines from the history database.
636 639
637 640 Most recent entry last.
638 641
639 642 Completion will be reordered so that that the last ones are when
640 643 possible from current session.
641 644
642 645 Parameters
643 646 ----------
644 647 n : int
645 648 The number of lines to get
646 649 raw, output : bool
647 650 See :meth:`get_range`
648 651 include_latest : bool
649 652 If False (default), n+1 lines are fetched, and the latest one
650 653 is discarded. This is intended to be used where the function
651 654 is called by a user command, which it should not return.
652 655
653 656 Returns
654 657 -------
655 658 Tuples as :meth:`get_range`
656 659 """
657 660 self.writeout_cache()
658 661 if not include_latest:
659 662 n += 1
660 663 # cursor/line/entry
661 664 this_cur = list(
662 665 self._run_sql(
663 666 "WHERE session == ? ORDER BY line DESC LIMIT ? ",
664 667 (self.session_number, n),
665 668 raw=raw,
666 669 output=output,
667 670 )
668 671 )
669 672 other_cur = list(
670 673 self._run_sql(
671 674 "WHERE session != ? ORDER BY session DESC, line DESC LIMIT ?",
672 675 (self.session_number, n),
673 676 raw=raw,
674 677 output=output,
675 678 )
676 679 )
677 680
678 681 everything = this_cur + other_cur
679 682
680 683 everything = everything[:n]
681 684
682 685 if not include_latest:
683 686 return list(everything)[:0:-1]
684 687 return list(everything)[::-1]
685 688
686 689 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
687 690 """Get input and output history from the current session. Called by
688 691 get_range, and takes similar parameters."""
689 692 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
690 693
691 694 n = len(input_hist)
692 695 if start < 0:
693 696 start += n
694 697 if not stop or (stop > n):
695 698 stop = n
696 699 elif stop < 0:
697 700 stop += n
698 701
699 702 for i in range(start, stop):
700 703 if output:
701 704 line = (input_hist[i], self.output_hist_reprs.get(i))
702 705 else:
703 706 line = input_hist[i]
704 707 yield (0, i, line)
705 708
706 709 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
707 710 """Retrieve input by session.
708 711
709 712 Parameters
710 713 ----------
711 714 session : int
712 715 Session number to retrieve. The current session is 0, and negative
713 716 numbers count back from current session, so -1 is previous session.
714 717 start : int
715 718 First line to retrieve.
716 719 stop : int
717 720 End of line range (excluded from output itself). If None, retrieve
718 721 to the end of the session.
719 722 raw : bool
720 723 If True, return untranslated input
721 724 output : bool
722 725 If True, attempt to include output. This will be 'real' Python
723 726 objects for the current session, or text reprs from previous
724 727 sessions if db_log_output was enabled at the time. Where no output
725 728 is found, None is used.
726 729
727 730 Returns
728 731 -------
729 732 entries
730 733 An iterator over the desired lines. Each line is a 3-tuple, either
731 734 (session, line, input) if output is False, or
732 735 (session, line, (input, output)) if output is True.
733 736 """
734 737 if session <= 0:
735 738 session += self.session_number
736 739 if session==self.session_number: # Current session
737 740 return self._get_range_session(start, stop, raw, output)
738 741 return super(HistoryManager, self).get_range(session, start, stop, raw,
739 742 output)
740 743
741 744 ## ----------------------------
742 745 ## Methods for storing history:
743 746 ## ----------------------------
744 747 def store_inputs(self, line_num, source, source_raw=None):
745 748 """Store source and raw input in history and create input cache
746 749 variables ``_i*``.
747 750
748 751 Parameters
749 752 ----------
750 753 line_num : int
751 754 The prompt number of this input.
752 755 source : str
753 756 Python input.
754 757 source_raw : str, optional
755 758 If given, this is the raw input without any IPython transformations
756 759 applied to it. If not given, ``source`` is used.
757 760 """
758 761 if source_raw is None:
759 762 source_raw = source
760 763 source = source.rstrip('\n')
761 764 source_raw = source_raw.rstrip('\n')
762 765
763 766 # do not store exit/quit commands
764 767 if self._exit_re.match(source_raw.strip()):
765 768 return
766 769
767 770 self.input_hist_parsed.append(source)
768 771 self.input_hist_raw.append(source_raw)
769 772
770 773 with self.db_input_cache_lock:
771 774 self.db_input_cache.append((line_num, source, source_raw))
772 775 # Trigger to flush cache and write to DB.
773 776 if len(self.db_input_cache) >= self.db_cache_size:
774 777 self.save_flag.set()
775 778
776 779 # update the auto _i variables
777 780 self._iii = self._ii
778 781 self._ii = self._i
779 782 self._i = self._i00
780 783 self._i00 = source_raw
781 784
782 785 # hackish access to user namespace to create _i1,_i2... dynamically
783 786 new_i = '_i%s' % line_num
784 787 to_main = {'_i': self._i,
785 788 '_ii': self._ii,
786 789 '_iii': self._iii,
787 790 new_i : self._i00 }
788 791
789 792 if self.shell is not None:
790 793 self.shell.push(to_main, interactive=False)
791 794
792 795 def store_output(self, line_num):
793 796 """If database output logging is enabled, this saves all the
794 797 outputs from the indicated prompt number to the database. It's
795 798 called by run_cell after code has been executed.
796 799
797 800 Parameters
798 801 ----------
799 802 line_num : int
800 803 The line number from which to save outputs
801 804 """
802 805 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
803 806 return
804 807 output = self.output_hist_reprs[line_num]
805 808
806 809 with self.db_output_cache_lock:
807 810 self.db_output_cache.append((line_num, output))
808 811 if self.db_cache_size <= 1:
809 812 self.save_flag.set()
810 813
811 814 def _writeout_input_cache(self, conn):
812 815 with conn:
813 816 for line in self.db_input_cache:
814 817 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
815 818 (self.session_number,)+line)
816 819
817 820 def _writeout_output_cache(self, conn):
818 821 with conn:
819 822 for line in self.db_output_cache:
820 823 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
821 824 (self.session_number,)+line)
822 825
823 826 @only_when_enabled
824 827 def writeout_cache(self, conn=None):
825 828 """Write any entries in the cache to the database."""
826 829 if conn is None:
827 830 conn = self.db
828 831
829 832 with self.db_input_cache_lock:
830 833 try:
831 834 self._writeout_input_cache(conn)
832 835 except sqlite3.IntegrityError:
833 836 self.new_session(conn)
834 837 print("ERROR! Session/line number was not unique in",
835 838 "database. History logging moved to new session",
836 839 self.session_number)
837 840 try:
838 841 # Try writing to the new session. If this fails, don't
839 842 # recurse
840 843 self._writeout_input_cache(conn)
841 844 except sqlite3.IntegrityError:
842 845 pass
843 846 finally:
844 847 self.db_input_cache = []
845 848
846 849 with self.db_output_cache_lock:
847 850 try:
848 851 self._writeout_output_cache(conn)
849 852 except sqlite3.IntegrityError:
850 853 print("!! Session/line number for output was not unique",
851 854 "in database. Output will not be stored.")
852 855 finally:
853 856 self.db_output_cache = []
854 857
855 858
856 859 class HistorySavingThread(threading.Thread):
857 860 """This thread takes care of writing history to the database, so that
858 861 the UI isn't held up while that happens.
859 862
860 863 It waits for the HistoryManager's save_flag to be set, then writes out
861 864 the history cache. The main thread is responsible for setting the flag when
862 865 the cache size reaches a defined threshold."""
863 866 daemon = True
864 867 stop_now = False
865 868 enabled = True
866 869 def __init__(self, history_manager):
867 870 super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
868 871 self.history_manager = history_manager
869 872 self.enabled = history_manager.enabled
870 873 atexit.register(self.stop)
871 874
872 875 @only_when_enabled
873 876 def run(self):
874 877 # We need a separate db connection per thread:
875 878 try:
876 879 self.db = sqlite3.connect(
877 880 str(self.history_manager.hist_file),
878 881 **self.history_manager.connection_options,
879 882 )
880 883 while True:
881 884 self.history_manager.save_flag.wait()
882 885 if self.stop_now:
883 886 self.db.close()
884 887 return
885 888 self.history_manager.save_flag.clear()
886 889 self.history_manager.writeout_cache(self.db)
887 890 except Exception as e:
888 891 print(("The history saving thread hit an unexpected error (%s)."
889 892 "History will not be written to the database.") % repr(e))
890 893
891 894 def stop(self):
892 895 """This can be called from the main thread to safely stop this thread.
893 896
894 897 Note that it does not attempt to write out remaining history before
895 898 exiting. That should be done by calling the HistoryManager's
896 899 end_session method."""
897 900 self.stop_now = True
898 901 self.history_manager.save_flag.set()
899 902 self.join()
900 903
901 904
902 905 # To match, e.g. ~5/8-~2/3
903 906 range_re = re.compile(r"""
904 907 ((?P<startsess>~?\d+)/)?
905 908 (?P<start>\d+)?
906 909 ((?P<sep>[\-:])
907 910 ((?P<endsess>~?\d+)/)?
908 911 (?P<end>\d+))?
909 912 $""", re.VERBOSE)
910 913
911 914
912 915 def extract_hist_ranges(ranges_str):
913 916 """Turn a string of history ranges into 3-tuples of (session, start, stop).
914 917
915 918 Empty string results in a `[(0, 1, None)]`, i.e. "everything from current
916 919 session".
917 920
918 921 Examples
919 922 --------
920 923 >>> list(extract_hist_ranges("~8/5-~7/4 2"))
921 924 [(-8, 5, None), (-7, 1, 5), (0, 2, 3)]
922 925 """
923 926 if ranges_str == "":
924 927 yield (0, 1, None) # Everything from current session
925 928 return
926 929
927 930 for range_str in ranges_str.split():
928 931 rmatch = range_re.match(range_str)
929 932 if not rmatch:
930 933 continue
931 934 start = rmatch.group("start")
932 935 if start:
933 936 start = int(start)
934 937 end = rmatch.group("end")
935 938 # If no end specified, get (a, a + 1)
936 939 end = int(end) if end else start + 1
937 940 else: # start not specified
938 941 if not rmatch.group('startsess'): # no startsess
939 942 continue
940 943 start = 1
941 944 end = None # provide the entire session hist
942 945
943 946 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
944 947 end += 1
945 948 startsess = rmatch.group("startsess") or "0"
946 949 endsess = rmatch.group("endsess") or startsess
947 950 startsess = int(startsess.replace("~","-"))
948 951 endsess = int(endsess.replace("~","-"))
949 952 assert endsess >= startsess, "start session must be earlier than end session"
950 953
951 954 if endsess == startsess:
952 955 yield (startsess, start, end)
953 956 continue
954 957 # Multiple sessions in one range:
955 958 yield (startsess, start, None)
956 959 for sess in range(startsess+1, endsess):
957 960 yield (sess, 1, None)
958 961 yield (endsess, 1, end)
959 962
960 963
961 964 def _format_lineno(session, line):
962 965 """Helper function to format line numbers properly."""
963 966 if session == 0:
964 967 return str(line)
965 968 return "%s#%s" % (session, line)
@@ -1,3862 +1,3898 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Main IPython class."""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13
14 14 import abc
15 15 import ast
16 16 import atexit
17 17 import bdb
18 18 import builtins as builtin_mod
19 19 import functools
20 20 import inspect
21 21 import os
22 22 import re
23 23 import runpy
24 24 import subprocess
25 25 import sys
26 26 import tempfile
27 27 import traceback
28 28 import types
29 29 import warnings
30 30 from ast import stmt
31 31 from io import open as io_open
32 32 from logging import error
33 33 from pathlib import Path
34 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 36 from typing import Optional, Tuple
37 37 from warnings import warn
38 38
39 39 from pickleshare import PickleShareDB
40 40 from tempfile import TemporaryDirectory
41 41 from traitlets import (
42 42 Any,
43 43 Bool,
44 44 CaselessStrEnum,
45 45 Dict,
46 46 Enum,
47 47 Instance,
48 48 Integer,
49 49 List,
50 50 Type,
51 51 Unicode,
52 52 default,
53 53 observe,
54 54 validate,
55 55 )
56 56 from traitlets.config.configurable import SingletonConfigurable
57 57 from traitlets.utils.importstring import import_item
58 58
59 59 import IPython.core.hooks
60 60 from IPython.core import magic, oinspect, page, prefilter, ultratb
61 61 from IPython.core.alias import Alias, AliasManager
62 62 from IPython.core.autocall import ExitAutocall
63 63 from IPython.core.builtin_trap import BuiltinTrap
64 64 from IPython.core.compilerop import CachingCompiler
65 65 from IPython.core.debugger import InterruptiblePdb
66 66 from IPython.core.display_trap import DisplayTrap
67 67 from IPython.core.displayhook import DisplayHook
68 68 from IPython.core.displaypub import DisplayPublisher
69 69 from IPython.core.error import InputRejected, UsageError
70 70 from IPython.core.events import EventManager, available_events
71 71 from IPython.core.extensions import ExtensionManager
72 72 from IPython.core.formatters import DisplayFormatter
73 73 from IPython.core.history import HistoryManager
74 74 from IPython.core.inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
75 75 from IPython.core.logger import Logger
76 76 from IPython.core.macro import Macro
77 77 from IPython.core.payload import PayloadManager
78 78 from IPython.core.prefilter import PrefilterManager
79 79 from IPython.core.profiledir import ProfileDir
80 80 from IPython.core.usage import default_banner
81 81 from IPython.display import display
82 82 from IPython.paths import get_ipython_dir
83 83 from IPython.testing.skipdoctest import skip_doctest
84 84 from IPython.utils import PyColorize, io, openpy, py3compat
85 85 from IPython.utils.decorators import undoc
86 86 from IPython.utils.io import ask_yes_no
87 87 from IPython.utils.ipstruct import Struct
88 88 from IPython.utils.path import ensure_dir_exists, get_home_dir, get_py_filename
89 89 from IPython.utils.process import getoutput, system
90 90 from IPython.utils.strdispatch import StrDispatch
91 91 from IPython.utils.syspathcontext import prepended_to_syspath
92 92 from IPython.utils.text import DollarFormatter, LSString, SList, format_screen
93 from IPython.core.oinspect import OInfo
94
93 95
94 96 sphinxify: Optional[Callable]
95 97
96 98 try:
97 99 import docrepr.sphinxify as sphx
98 100
99 101 def sphinxify(oinfo):
100 102 wrapped_docstring = sphx.wrap_main_docstring(oinfo)
101 103
102 104 def sphinxify_docstring(docstring):
103 105 with TemporaryDirectory() as dirname:
104 106 return {
105 107 "text/html": sphx.sphinxify(wrapped_docstring, dirname),
106 108 "text/plain": docstring,
107 109 }
108 110
109 111 return sphinxify_docstring
110 112 except ImportError:
111 113 sphinxify = None
112 114
113 115
114 116 class ProvisionalWarning(DeprecationWarning):
115 117 """
116 118 Warning class for unstable features
117 119 """
118 120 pass
119 121
120 122 from ast import Module
121 123
122 124 _assign_nodes = (ast.AugAssign, ast.AnnAssign, ast.Assign)
123 125 _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)
124 126
125 127 #-----------------------------------------------------------------------------
126 128 # Await Helpers
127 129 #-----------------------------------------------------------------------------
128 130
129 131 # we still need to run things using the asyncio eventloop, but there is no
130 132 # async integration
131 133 from .async_helpers import (
132 134 _asyncio_runner,
133 135 _curio_runner,
134 136 _pseudo_sync_runner,
135 137 _should_be_async,
136 138 _trio_runner,
137 139 )
138 140
139 141 #-----------------------------------------------------------------------------
140 142 # Globals
141 143 #-----------------------------------------------------------------------------
142 144
143 145 # compiled regexps for autoindent management
144 146 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
145 147
146 148 #-----------------------------------------------------------------------------
147 149 # Utilities
148 150 #-----------------------------------------------------------------------------
149 151
150 152
151 153 def is_integer_string(s: str):
152 154 """
153 155 Variant of "str.isnumeric()" that allow negative values and other ints.
154 156 """
155 157 try:
156 158 int(s)
157 159 return True
158 160 except ValueError:
159 161 return False
160 162 raise ValueError("Unexpected error")
161 163
162 164
163 165 @undoc
164 166 def softspace(file, newvalue):
165 167 """Copied from code.py, to remove the dependency"""
166 168
167 169 oldvalue = 0
168 170 try:
169 171 oldvalue = file.softspace
170 172 except AttributeError:
171 173 pass
172 174 try:
173 175 file.softspace = newvalue
174 176 except (AttributeError, TypeError):
175 177 # "attribute-less object" or "read-only attributes"
176 178 pass
177 179 return oldvalue
178 180
179 181 @undoc
180 182 def no_op(*a, **kw):
181 183 pass
182 184
183 185
184 186 class SpaceInInput(Exception): pass
185 187
186 188
187 189 class SeparateUnicode(Unicode):
188 190 r"""A Unicode subclass to validate separate_in, separate_out, etc.
189 191
190 192 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
191 193 """
192 194
193 195 def validate(self, obj, value):
194 196 if value == '0': value = ''
195 197 value = value.replace('\\n','\n')
196 198 return super(SeparateUnicode, self).validate(obj, value)
197 199
198 200
199 201 @undoc
200 202 class DummyMod(object):
201 203 """A dummy module used for IPython's interactive module when
202 204 a namespace must be assigned to the module's __dict__."""
203 205 __spec__ = None
204 206
205 207
206 208 class ExecutionInfo(object):
207 209 """The arguments used for a call to :meth:`InteractiveShell.run_cell`
208 210
209 211 Stores information about what is going to happen.
210 212 """
211 213 raw_cell = None
212 214 store_history = False
213 215 silent = False
214 216 shell_futures = True
215 217 cell_id = None
216 218
217 219 def __init__(self, raw_cell, store_history, silent, shell_futures, cell_id):
218 220 self.raw_cell = raw_cell
219 221 self.store_history = store_history
220 222 self.silent = silent
221 223 self.shell_futures = shell_futures
222 224 self.cell_id = cell_id
223 225
224 226 def __repr__(self):
225 227 name = self.__class__.__qualname__
226 228 raw_cell = (
227 229 (self.raw_cell[:50] + "..") if len(self.raw_cell) > 50 else self.raw_cell
228 230 )
229 231 return (
230 232 '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s cell_id=%s>'
231 233 % (
232 234 name,
233 235 id(self),
234 236 raw_cell,
235 237 self.store_history,
236 238 self.silent,
237 239 self.shell_futures,
238 240 self.cell_id,
239 241 )
240 242 )
241 243
242 244
243 245 class ExecutionResult(object):
244 246 """The result of a call to :meth:`InteractiveShell.run_cell`
245 247
246 248 Stores information about what took place.
247 249 """
248 250 execution_count = None
249 251 error_before_exec = None
250 252 error_in_exec: Optional[BaseException] = None
251 253 info = None
252 254 result = None
253 255
254 256 def __init__(self, info):
255 257 self.info = info
256 258
257 259 @property
258 260 def success(self):
259 261 return (self.error_before_exec is None) and (self.error_in_exec is None)
260 262
261 263 def raise_error(self):
262 264 """Reraises error if `success` is `False`, otherwise does nothing"""
263 265 if self.error_before_exec is not None:
264 266 raise self.error_before_exec
265 267 if self.error_in_exec is not None:
266 268 raise self.error_in_exec
267 269
268 270 def __repr__(self):
269 271 name = self.__class__.__qualname__
270 272 return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s info=%s result=%s>' %\
271 273 (name, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.info), repr(self.result))
272 274
273 275 @functools.wraps(io_open)
274 276 def _modified_open(file, *args, **kwargs):
275 277 if file in {0, 1, 2}:
276 278 raise ValueError(
277 279 f"IPython won't let you open fd={file} by default "
278 280 "as it is likely to crash IPython. If you know what you are doing, "
279 281 "you can use builtins' open."
280 282 )
281 283
282 284 return io_open(file, *args, **kwargs)
283 285
284 286 class InteractiveShell(SingletonConfigurable):
285 287 """An enhanced, interactive shell for Python."""
286 288
287 289 _instance = None
288 290
289 291 ast_transformers = List([], help=
290 292 """
291 293 A list of ast.NodeTransformer subclass instances, which will be applied
292 294 to user input before code is run.
293 295 """
294 296 ).tag(config=True)
295 297
296 298 autocall = Enum((0,1,2), default_value=0, help=
297 299 """
298 300 Make IPython automatically call any callable object even if you didn't
299 301 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
300 302 automatically. The value can be '0' to disable the feature, '1' for
301 303 'smart' autocall, where it is not applied if there are no more
302 304 arguments on the line, and '2' for 'full' autocall, where all callable
303 305 objects are automatically called (even if no arguments are present).
304 306 """
305 307 ).tag(config=True)
306 308
307 309 autoindent = Bool(True, help=
308 310 """
309 311 Autoindent IPython code entered interactively.
310 312 """
311 313 ).tag(config=True)
312 314
313 315 autoawait = Bool(True, help=
314 316 """
315 317 Automatically run await statement in the top level repl.
316 318 """
317 319 ).tag(config=True)
318 320
319 321 loop_runner_map ={
320 322 'asyncio':(_asyncio_runner, True),
321 323 'curio':(_curio_runner, True),
322 324 'trio':(_trio_runner, True),
323 325 'sync': (_pseudo_sync_runner, False)
324 326 }
325 327
326 328 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
327 329 allow_none=True,
328 330 help="""Select the loop runner that will be used to execute top-level asynchronous code"""
329 331 ).tag(config=True)
330 332
331 333 @default('loop_runner')
332 334 def _default_loop_runner(self):
333 335 return import_item("IPython.core.interactiveshell._asyncio_runner")
334 336
335 337 @validate('loop_runner')
336 338 def _import_runner(self, proposal):
337 339 if isinstance(proposal.value, str):
338 340 if proposal.value in self.loop_runner_map:
339 341 runner, autoawait = self.loop_runner_map[proposal.value]
340 342 self.autoawait = autoawait
341 343 return runner
342 344 runner = import_item(proposal.value)
343 345 if not callable(runner):
344 346 raise ValueError('loop_runner must be callable')
345 347 return runner
346 348 if not callable(proposal.value):
347 349 raise ValueError('loop_runner must be callable')
348 350 return proposal.value
349 351
350 352 automagic = Bool(True, help=
351 353 """
352 354 Enable magic commands to be called without the leading %.
353 355 """
354 356 ).tag(config=True)
355 357
356 358 banner1 = Unicode(default_banner,
357 359 help="""The part of the banner to be printed before the profile"""
358 360 ).tag(config=True)
359 361 banner2 = Unicode('',
360 362 help="""The part of the banner to be printed after the profile"""
361 363 ).tag(config=True)
362 364
363 365 cache_size = Integer(1000, help=
364 366 """
365 367 Set the size of the output cache. The default is 1000, you can
366 368 change it permanently in your config file. Setting it to 0 completely
367 369 disables the caching system, and the minimum value accepted is 3 (if
368 370 you provide a value less than 3, it is reset to 0 and a warning is
369 371 issued). This limit is defined because otherwise you'll spend more
370 372 time re-flushing a too small cache than working
371 373 """
372 374 ).tag(config=True)
373 375 color_info = Bool(True, help=
374 376 """
375 377 Use colors for displaying information about objects. Because this
376 378 information is passed through a pager (like 'less'), and some pagers
377 379 get confused with color codes, this capability can be turned off.
378 380 """
379 381 ).tag(config=True)
380 382 colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'),
381 383 default_value='Neutral',
382 384 help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)."
383 385 ).tag(config=True)
384 386 debug = Bool(False).tag(config=True)
385 387 disable_failing_post_execute = Bool(False,
386 388 help="Don't call post-execute functions that have failed in the past."
387 389 ).tag(config=True)
388 390 display_formatter = Instance(DisplayFormatter, allow_none=True)
389 391 displayhook_class = Type(DisplayHook)
390 392 display_pub_class = Type(DisplayPublisher)
391 393 compiler_class = Type(CachingCompiler)
392 394 inspector_class = Type(
393 395 oinspect.Inspector, help="Class to use to instantiate the shell inspector"
394 396 ).tag(config=True)
395 397
396 398 sphinxify_docstring = Bool(False, help=
397 399 """
398 400 Enables rich html representation of docstrings. (This requires the
399 401 docrepr module).
400 402 """).tag(config=True)
401 403
402 404 @observe("sphinxify_docstring")
403 405 def _sphinxify_docstring_changed(self, change):
404 406 if change['new']:
405 407 warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning)
406 408
407 409 enable_html_pager = Bool(False, help=
408 410 """
409 411 (Provisional API) enables html representation in mime bundles sent
410 412 to pagers.
411 413 """).tag(config=True)
412 414
413 415 @observe("enable_html_pager")
414 416 def _enable_html_pager_changed(self, change):
415 417 if change['new']:
416 418 warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning)
417 419
418 420 data_pub_class = None
419 421
420 422 exit_now = Bool(False)
421 423 exiter = Instance(ExitAutocall)
422 424 @default('exiter')
423 425 def _exiter_default(self):
424 426 return ExitAutocall(self)
425 427 # Monotonically increasing execution counter
426 428 execution_count = Integer(1)
427 429 filename = Unicode("<ipython console>")
428 430 ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__
429 431
430 432 # Used to transform cells before running them, and check whether code is complete
431 433 input_transformer_manager = Instance('IPython.core.inputtransformer2.TransformerManager',
432 434 ())
433 435
434 436 @property
435 437 def input_transformers_cleanup(self):
436 438 return self.input_transformer_manager.cleanup_transforms
437 439
438 440 input_transformers_post = List([],
439 441 help="A list of string input transformers, to be applied after IPython's "
440 442 "own input transformations."
441 443 )
442 444
443 445 @property
444 446 def input_splitter(self):
445 447 """Make this available for backward compatibility (pre-7.0 release) with existing code.
446 448
447 449 For example, ipykernel ipykernel currently uses
448 450 `shell.input_splitter.check_complete`
449 451 """
450 452 from warnings import warn
451 453 warn("`input_splitter` is deprecated since IPython 7.0, prefer `input_transformer_manager`.",
452 454 DeprecationWarning, stacklevel=2
453 455 )
454 456 return self.input_transformer_manager
455 457
456 458 logstart = Bool(False, help=
457 459 """
458 460 Start logging to the default log file in overwrite mode.
459 461 Use `logappend` to specify a log file to **append** logs to.
460 462 """
461 463 ).tag(config=True)
462 464 logfile = Unicode('', help=
463 465 """
464 466 The name of the logfile to use.
465 467 """
466 468 ).tag(config=True)
467 469 logappend = Unicode('', help=
468 470 """
469 471 Start logging to the given file in append mode.
470 472 Use `logfile` to specify a log file to **overwrite** logs to.
471 473 """
472 474 ).tag(config=True)
473 475 object_info_string_level = Enum((0,1,2), default_value=0,
474 476 ).tag(config=True)
475 477 pdb = Bool(False, help=
476 478 """
477 479 Automatically call the pdb debugger after every exception.
478 480 """
479 481 ).tag(config=True)
480 482 display_page = Bool(False,
481 483 help="""If True, anything that would be passed to the pager
482 484 will be displayed as regular output instead."""
483 485 ).tag(config=True)
484 486
485 487
486 488 show_rewritten_input = Bool(True,
487 489 help="Show rewritten input, e.g. for autocall."
488 490 ).tag(config=True)
489 491
490 492 quiet = Bool(False).tag(config=True)
491 493
492 494 history_length = Integer(10000,
493 495 help='Total length of command history'
494 496 ).tag(config=True)
495 497
496 498 history_load_length = Integer(1000, help=
497 499 """
498 500 The number of saved history entries to be loaded
499 501 into the history buffer at startup.
500 502 """
501 503 ).tag(config=True)
502 504
503 505 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'],
504 506 default_value='last_expr',
505 507 help="""
506 508 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying
507 509 which nodes should be run interactively (displaying output from expressions).
508 510 """
509 511 ).tag(config=True)
510 512
511 513 warn_venv = Bool(
512 514 True,
513 515 help="Warn if running in a virtual environment with no IPython installed (so IPython from the global environment is used).",
514 516 ).tag(config=True)
515 517
516 518 # TODO: this part of prompt management should be moved to the frontends.
517 519 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
518 520 separate_in = SeparateUnicode('\n').tag(config=True)
519 521 separate_out = SeparateUnicode('').tag(config=True)
520 522 separate_out2 = SeparateUnicode('').tag(config=True)
521 523 wildcards_case_sensitive = Bool(True).tag(config=True)
522 524 xmode = CaselessStrEnum(('Context', 'Plain', 'Verbose', 'Minimal'),
523 525 default_value='Context',
524 526 help="Switch modes for the IPython exception handlers."
525 527 ).tag(config=True)
526 528
527 529 # Subcomponents of InteractiveShell
528 530 alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True)
529 531 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
530 532 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap', allow_none=True)
531 533 display_trap = Instance('IPython.core.display_trap.DisplayTrap', allow_none=True)
532 534 extension_manager = Instance('IPython.core.extensions.ExtensionManager', allow_none=True)
533 535 payload_manager = Instance('IPython.core.payload.PayloadManager', allow_none=True)
534 536 history_manager = Instance('IPython.core.history.HistoryAccessorBase', allow_none=True)
535 537 magics_manager = Instance('IPython.core.magic.MagicsManager', allow_none=True)
536 538
537 539 profile_dir = Instance('IPython.core.application.ProfileDir', allow_none=True)
538 540 @property
539 541 def profile(self):
540 542 if self.profile_dir is not None:
541 543 name = os.path.basename(self.profile_dir.location)
542 544 return name.replace('profile_','')
543 545
544 546
545 547 # Private interface
546 548 _post_execute = Dict()
547 549
548 550 # Tracks any GUI loop loaded for pylab
549 551 pylab_gui_select = None
550 552
551 553 last_execution_succeeded = Bool(True, help='Did last executed command succeeded')
552 554
553 555 last_execution_result = Instance('IPython.core.interactiveshell.ExecutionResult', help='Result of executing the last command', allow_none=True)
554 556
555 557 def __init__(self, ipython_dir=None, profile_dir=None,
556 558 user_module=None, user_ns=None,
557 559 custom_exceptions=((), None), **kwargs):
558 560 # This is where traits with a config_key argument are updated
559 561 # from the values on config.
560 562 super(InteractiveShell, self).__init__(**kwargs)
561 563 if 'PromptManager' in self.config:
562 564 warn('As of IPython 5.0 `PromptManager` config will have no effect'
563 565 ' and has been replaced by TerminalInteractiveShell.prompts_class')
564 566 self.configurables = [self]
565 567
566 568 # These are relatively independent and stateless
567 569 self.init_ipython_dir(ipython_dir)
568 570 self.init_profile_dir(profile_dir)
569 571 self.init_instance_attrs()
570 572 self.init_environment()
571 573
572 574 # Check if we're in a virtualenv, and set up sys.path.
573 575 self.init_virtualenv()
574 576
575 577 # Create namespaces (user_ns, user_global_ns, etc.)
576 578 self.init_create_namespaces(user_module, user_ns)
577 579 # This has to be done after init_create_namespaces because it uses
578 580 # something in self.user_ns, but before init_sys_modules, which
579 581 # is the first thing to modify sys.
580 582 # TODO: When we override sys.stdout and sys.stderr before this class
581 583 # is created, we are saving the overridden ones here. Not sure if this
582 584 # is what we want to do.
583 585 self.save_sys_module_state()
584 586 self.init_sys_modules()
585 587
586 588 # While we're trying to have each part of the code directly access what
587 589 # it needs without keeping redundant references to objects, we have too
588 590 # much legacy code that expects ip.db to exist.
589 591 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
590 592
591 593 self.init_history()
592 594 self.init_encoding()
593 595 self.init_prefilter()
594 596
595 597 self.init_syntax_highlighting()
596 598 self.init_hooks()
597 599 self.init_events()
598 600 self.init_pushd_popd_magic()
599 601 self.init_user_ns()
600 602 self.init_logger()
601 603 self.init_builtins()
602 604
603 605 # The following was in post_config_initialization
604 606 self.init_inspector()
605 607 self.raw_input_original = input
606 608 self.init_completer()
607 609 # TODO: init_io() needs to happen before init_traceback handlers
608 610 # because the traceback handlers hardcode the stdout/stderr streams.
609 611 # This logic in in debugger.Pdb and should eventually be changed.
610 612 self.init_io()
611 613 self.init_traceback_handlers(custom_exceptions)
612 614 self.init_prompts()
613 615 self.init_display_formatter()
614 616 self.init_display_pub()
615 617 self.init_data_pub()
616 618 self.init_displayhook()
617 619 self.init_magics()
618 620 self.init_alias()
619 621 self.init_logstart()
620 622 self.init_pdb()
621 623 self.init_extension_manager()
622 624 self.init_payload()
623 625 self.events.trigger('shell_initialized', self)
624 626 atexit.register(self.atexit_operations)
625 627
626 628 # The trio runner is used for running Trio in the foreground thread. It
627 629 # is different from `_trio_runner(async_fn)` in `async_helpers.py`
628 630 # which calls `trio.run()` for every cell. This runner runs all cells
629 631 # inside a single Trio event loop. If used, it is set from
630 632 # `ipykernel.kernelapp`.
631 633 self.trio_runner = None
632 634
633 635 def get_ipython(self):
634 636 """Return the currently running IPython instance."""
635 637 return self
636 638
637 639 #-------------------------------------------------------------------------
638 640 # Trait changed handlers
639 641 #-------------------------------------------------------------------------
640 642 @observe('ipython_dir')
641 643 def _ipython_dir_changed(self, change):
642 644 ensure_dir_exists(change['new'])
643 645
644 646 def set_autoindent(self,value=None):
645 647 """Set the autoindent flag.
646 648
647 649 If called with no arguments, it acts as a toggle."""
648 650 if value is None:
649 651 self.autoindent = not self.autoindent
650 652 else:
651 653 self.autoindent = value
652 654
653 655 def set_trio_runner(self, tr):
654 656 self.trio_runner = tr
655 657
656 658 #-------------------------------------------------------------------------
657 659 # init_* methods called by __init__
658 660 #-------------------------------------------------------------------------
659 661
660 662 def init_ipython_dir(self, ipython_dir):
661 663 if ipython_dir is not None:
662 664 self.ipython_dir = ipython_dir
663 665 return
664 666
665 667 self.ipython_dir = get_ipython_dir()
666 668
667 669 def init_profile_dir(self, profile_dir):
668 670 if profile_dir is not None:
669 671 self.profile_dir = profile_dir
670 672 return
671 673 self.profile_dir = ProfileDir.create_profile_dir_by_name(
672 674 self.ipython_dir, "default"
673 675 )
674 676
675 677 def init_instance_attrs(self):
676 678 self.more = False
677 679
678 680 # command compiler
679 681 self.compile = self.compiler_class()
680 682
681 683 # Make an empty namespace, which extension writers can rely on both
682 684 # existing and NEVER being used by ipython itself. This gives them a
683 685 # convenient location for storing additional information and state
684 686 # their extensions may require, without fear of collisions with other
685 687 # ipython names that may develop later.
686 688 self.meta = Struct()
687 689
688 690 # Temporary files used for various purposes. Deleted at exit.
689 691 # The files here are stored with Path from Pathlib
690 692 self.tempfiles = []
691 693 self.tempdirs = []
692 694
693 695 # keep track of where we started running (mainly for crash post-mortem)
694 696 # This is not being used anywhere currently.
695 697 self.starting_dir = os.getcwd()
696 698
697 699 # Indentation management
698 700 self.indent_current_nsp = 0
699 701
700 702 # Dict to track post-execution functions that have been registered
701 703 self._post_execute = {}
702 704
703 705 def init_environment(self):
704 706 """Any changes we need to make to the user's environment."""
705 707 pass
706 708
707 709 def init_encoding(self):
708 710 # Get system encoding at startup time. Certain terminals (like Emacs
709 711 # under Win32 have it set to None, and we need to have a known valid
710 712 # encoding to use in the raw_input() method
711 713 try:
712 714 self.stdin_encoding = sys.stdin.encoding or 'ascii'
713 715 except AttributeError:
714 716 self.stdin_encoding = 'ascii'
715 717
716 718
717 719 @observe('colors')
718 720 def init_syntax_highlighting(self, changes=None):
719 721 # Python source parser/formatter for syntax highlighting
720 722 pyformat = PyColorize.Parser(style=self.colors, parent=self).format
721 723 self.pycolorize = lambda src: pyformat(src,'str')
722 724
723 725 def refresh_style(self):
724 726 # No-op here, used in subclass
725 727 pass
726 728
727 729 def init_pushd_popd_magic(self):
728 730 # for pushd/popd management
729 731 self.home_dir = get_home_dir()
730 732
731 733 self.dir_stack = []
732 734
733 735 def init_logger(self):
734 736 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
735 737 logmode='rotate')
736 738
737 739 def init_logstart(self):
738 740 """Initialize logging in case it was requested at the command line.
739 741 """
740 742 if self.logappend:
741 743 self.magic('logstart %s append' % self.logappend)
742 744 elif self.logfile:
743 745 self.magic('logstart %s' % self.logfile)
744 746 elif self.logstart:
745 747 self.magic('logstart')
746 748
747 749
748 750 def init_builtins(self):
749 751 # A single, static flag that we set to True. Its presence indicates
750 752 # that an IPython shell has been created, and we make no attempts at
751 753 # removing on exit or representing the existence of more than one
752 754 # IPython at a time.
753 755 builtin_mod.__dict__['__IPYTHON__'] = True
754 756 builtin_mod.__dict__['display'] = display
755 757
756 758 self.builtin_trap = BuiltinTrap(shell=self)
757 759
758 760 @observe('colors')
759 761 def init_inspector(self, changes=None):
760 762 # Object inspector
761 763 self.inspector = self.inspector_class(
762 764 oinspect.InspectColors,
763 765 PyColorize.ANSICodeColors,
764 766 self.colors,
765 767 self.object_info_string_level,
766 768 )
767 769
768 770 def init_io(self):
769 771 # implemented in subclasses, TerminalInteractiveShell does call
770 772 # colorama.init().
771 773 pass
772 774
773 775 def init_prompts(self):
774 776 # Set system prompts, so that scripts can decide if they are running
775 777 # interactively.
776 778 sys.ps1 = 'In : '
777 779 sys.ps2 = '...: '
778 780 sys.ps3 = 'Out: '
779 781
780 782 def init_display_formatter(self):
781 783 self.display_formatter = DisplayFormatter(parent=self)
782 784 self.configurables.append(self.display_formatter)
783 785
784 786 def init_display_pub(self):
785 787 self.display_pub = self.display_pub_class(parent=self, shell=self)
786 788 self.configurables.append(self.display_pub)
787 789
788 790 def init_data_pub(self):
789 791 if not self.data_pub_class:
790 792 self.data_pub = None
791 793 return
792 794 self.data_pub = self.data_pub_class(parent=self)
793 795 self.configurables.append(self.data_pub)
794 796
795 797 def init_displayhook(self):
796 798 # Initialize displayhook, set in/out prompts and printing system
797 799 self.displayhook = self.displayhook_class(
798 800 parent=self,
799 801 shell=self,
800 802 cache_size=self.cache_size,
801 803 )
802 804 self.configurables.append(self.displayhook)
803 805 # This is a context manager that installs/revmoes the displayhook at
804 806 # the appropriate time.
805 807 self.display_trap = DisplayTrap(hook=self.displayhook)
806 808
807 809 @staticmethod
808 810 def get_path_links(p: Path):
809 811 """Gets path links including all symlinks
810 812
811 813 Examples
812 814 --------
813 815 In [1]: from IPython.core.interactiveshell import InteractiveShell
814 816
815 817 In [2]: import sys, pathlib
816 818
817 819 In [3]: paths = InteractiveShell.get_path_links(pathlib.Path(sys.executable))
818 820
819 821 In [4]: len(paths) == len(set(paths))
820 822 Out[4]: True
821 823
822 824 In [5]: bool(paths)
823 825 Out[5]: True
824 826 """
825 827 paths = [p]
826 828 while p.is_symlink():
827 829 new_path = Path(os.readlink(p))
828 830 if not new_path.is_absolute():
829 831 new_path = p.parent / new_path
830 832 p = new_path
831 833 paths.append(p)
832 834 return paths
833 835
834 836 def init_virtualenv(self):
835 837 """Add the current virtualenv to sys.path so the user can import modules from it.
836 838 This isn't perfect: it doesn't use the Python interpreter with which the
837 839 virtualenv was built, and it ignores the --no-site-packages option. A
838 840 warning will appear suggesting the user installs IPython in the
839 841 virtualenv, but for many cases, it probably works well enough.
840 842
841 843 Adapted from code snippets online.
842 844
843 845 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
844 846 """
845 847 if 'VIRTUAL_ENV' not in os.environ:
846 848 # Not in a virtualenv
847 849 return
848 850 elif os.environ["VIRTUAL_ENV"] == "":
849 851 warn("Virtual env path set to '', please check if this is intended.")
850 852 return
851 853
852 854 p = Path(sys.executable)
853 855 p_venv = Path(os.environ["VIRTUAL_ENV"])
854 856
855 857 # fallback venv detection:
856 858 # stdlib venv may symlink sys.executable, so we can't use realpath.
857 859 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
858 860 # So we just check every item in the symlink tree (generally <= 3)
859 861 paths = self.get_path_links(p)
860 862
861 863 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
862 864 if p_venv.parts[1] == "cygdrive":
863 865 drive_name = p_venv.parts[2]
864 866 p_venv = (drive_name + ":/") / Path(*p_venv.parts[3:])
865 867
866 868 if any(p_venv == p.parents[1] for p in paths):
867 869 # Our exe is inside or has access to the virtualenv, don't need to do anything.
868 870 return
869 871
870 872 if sys.platform == "win32":
871 873 virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages"))
872 874 else:
873 875 virtual_env_path = Path(
874 876 os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
875 877 )
876 878 p_ver = sys.version_info[:2]
877 879
878 880 # Predict version from py[thon]-x.x in the $VIRTUAL_ENV
879 881 re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
880 882 if re_m:
881 883 predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
882 884 if predicted_path.exists():
883 885 p_ver = re_m.groups()
884 886
885 887 virtual_env = str(virtual_env_path).format(*p_ver)
886 888 if self.warn_venv:
887 889 warn(
888 890 "Attempting to work in a virtualenv. If you encounter problems, "
889 891 "please install IPython inside the virtualenv."
890 892 )
891 893 import site
892 894 sys.path.insert(0, virtual_env)
893 895 site.addsitedir(virtual_env)
894 896
895 897 #-------------------------------------------------------------------------
896 898 # Things related to injections into the sys module
897 899 #-------------------------------------------------------------------------
898 900
899 901 def save_sys_module_state(self):
900 902 """Save the state of hooks in the sys module.
901 903
902 904 This has to be called after self.user_module is created.
903 905 """
904 906 self._orig_sys_module_state = {'stdin': sys.stdin,
905 907 'stdout': sys.stdout,
906 908 'stderr': sys.stderr,
907 909 'excepthook': sys.excepthook}
908 910 self._orig_sys_modules_main_name = self.user_module.__name__
909 911 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
910 912
911 913 def restore_sys_module_state(self):
912 914 """Restore the state of the sys module."""
913 915 try:
914 916 for k, v in self._orig_sys_module_state.items():
915 917 setattr(sys, k, v)
916 918 except AttributeError:
917 919 pass
918 920 # Reset what what done in self.init_sys_modules
919 921 if self._orig_sys_modules_main_mod is not None:
920 922 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
921 923
922 924 #-------------------------------------------------------------------------
923 925 # Things related to the banner
924 926 #-------------------------------------------------------------------------
925 927
926 928 @property
927 929 def banner(self):
928 930 banner = self.banner1
929 931 if self.profile and self.profile != 'default':
930 932 banner += '\nIPython profile: %s\n' % self.profile
931 933 if self.banner2:
932 934 banner += '\n' + self.banner2
933 935 return banner
934 936
935 937 def show_banner(self, banner=None):
936 938 if banner is None:
937 939 banner = self.banner
938 940 sys.stdout.write(banner)
939 941
940 942 #-------------------------------------------------------------------------
941 943 # Things related to hooks
942 944 #-------------------------------------------------------------------------
943 945
944 946 def init_hooks(self):
945 947 # hooks holds pointers used for user-side customizations
946 948 self.hooks = Struct()
947 949
948 950 self.strdispatchers = {}
949 951
950 952 # Set all default hooks, defined in the IPython.hooks module.
951 953 hooks = IPython.core.hooks
952 954 for hook_name in hooks.__all__:
953 955 # default hooks have priority 100, i.e. low; user hooks should have
954 956 # 0-100 priority
955 957 self.set_hook(hook_name, getattr(hooks, hook_name), 100)
956 958
957 959 if self.display_page:
958 960 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
959 961
960 962 def set_hook(self, name, hook, priority=50, str_key=None, re_key=None):
961 963 """set_hook(name,hook) -> sets an internal IPython hook.
962 964
963 965 IPython exposes some of its internal API as user-modifiable hooks. By
964 966 adding your function to one of these hooks, you can modify IPython's
965 967 behavior to call at runtime your own routines."""
966 968
967 969 # At some point in the future, this should validate the hook before it
968 970 # accepts it. Probably at least check that the hook takes the number
969 971 # of args it's supposed to.
970 972
971 973 f = types.MethodType(hook,self)
972 974
973 975 # check if the hook is for strdispatcher first
974 976 if str_key is not None:
975 977 sdp = self.strdispatchers.get(name, StrDispatch())
976 978 sdp.add_s(str_key, f, priority )
977 979 self.strdispatchers[name] = sdp
978 980 return
979 981 if re_key is not None:
980 982 sdp = self.strdispatchers.get(name, StrDispatch())
981 983 sdp.add_re(re.compile(re_key), f, priority )
982 984 self.strdispatchers[name] = sdp
983 985 return
984 986
985 987 dp = getattr(self.hooks, name, None)
986 988 if name not in IPython.core.hooks.__all__:
987 989 print("Warning! Hook '%s' is not one of %s" % \
988 990 (name, IPython.core.hooks.__all__ ))
989 991
990 992 if name in IPython.core.hooks.deprecated:
991 993 alternative = IPython.core.hooks.deprecated[name]
992 994 raise ValueError(
993 995 "Hook {} has been deprecated since IPython 5.0. Use {} instead.".format(
994 996 name, alternative
995 997 )
996 998 )
997 999
998 1000 if not dp:
999 1001 dp = IPython.core.hooks.CommandChainDispatcher()
1000 1002
1001 1003 try:
1002 1004 dp.add(f,priority)
1003 1005 except AttributeError:
1004 1006 # it was not commandchain, plain old func - replace
1005 1007 dp = f
1006 1008
1007 1009 setattr(self.hooks,name, dp)
1008 1010
1009 1011 #-------------------------------------------------------------------------
1010 1012 # Things related to events
1011 1013 #-------------------------------------------------------------------------
1012 1014
1013 1015 def init_events(self):
1014 1016 self.events = EventManager(self, available_events)
1015 1017
1016 1018 self.events.register("pre_execute", self._clear_warning_registry)
1017 1019
1018 1020 def register_post_execute(self, func):
1019 1021 """DEPRECATED: Use ip.events.register('post_run_cell', func)
1020 1022
1021 1023 Register a function for calling after code execution.
1022 1024 """
1023 1025 raise ValueError(
1024 1026 "ip.register_post_execute is deprecated since IPython 1.0, use "
1025 1027 "ip.events.register('post_run_cell', func) instead."
1026 1028 )
1027 1029
1028 1030 def _clear_warning_registry(self):
1029 1031 # clear the warning registry, so that different code blocks with
1030 1032 # overlapping line number ranges don't cause spurious suppression of
1031 1033 # warnings (see gh-6611 for details)
1032 1034 if "__warningregistry__" in self.user_global_ns:
1033 1035 del self.user_global_ns["__warningregistry__"]
1034 1036
1035 1037 #-------------------------------------------------------------------------
1036 1038 # Things related to the "main" module
1037 1039 #-------------------------------------------------------------------------
1038 1040
1039 1041 def new_main_mod(self, filename, modname):
1040 1042 """Return a new 'main' module object for user code execution.
1041 1043
1042 1044 ``filename`` should be the path of the script which will be run in the
1043 1045 module. Requests with the same filename will get the same module, with
1044 1046 its namespace cleared.
1045 1047
1046 1048 ``modname`` should be the module name - normally either '__main__' or
1047 1049 the basename of the file without the extension.
1048 1050
1049 1051 When scripts are executed via %run, we must keep a reference to their
1050 1052 __main__ module around so that Python doesn't
1051 1053 clear it, rendering references to module globals useless.
1052 1054
1053 1055 This method keeps said reference in a private dict, keyed by the
1054 1056 absolute path of the script. This way, for multiple executions of the
1055 1057 same script we only keep one copy of the namespace (the last one),
1056 1058 thus preventing memory leaks from old references while allowing the
1057 1059 objects from the last execution to be accessible.
1058 1060 """
1059 1061 filename = os.path.abspath(filename)
1060 1062 try:
1061 1063 main_mod = self._main_mod_cache[filename]
1062 1064 except KeyError:
1063 1065 main_mod = self._main_mod_cache[filename] = types.ModuleType(
1064 1066 modname,
1065 1067 doc="Module created for script run in IPython")
1066 1068 else:
1067 1069 main_mod.__dict__.clear()
1068 1070 main_mod.__name__ = modname
1069 1071
1070 1072 main_mod.__file__ = filename
1071 1073 # It seems pydoc (and perhaps others) needs any module instance to
1072 1074 # implement a __nonzero__ method
1073 1075 main_mod.__nonzero__ = lambda : True
1074 1076
1075 1077 return main_mod
1076 1078
1077 1079 def clear_main_mod_cache(self):
1078 1080 """Clear the cache of main modules.
1079 1081
1080 1082 Mainly for use by utilities like %reset.
1081 1083
1082 1084 Examples
1083 1085 --------
1084 1086 In [15]: import IPython
1085 1087
1086 1088 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
1087 1089
1088 1090 In [17]: len(_ip._main_mod_cache) > 0
1089 1091 Out[17]: True
1090 1092
1091 1093 In [18]: _ip.clear_main_mod_cache()
1092 1094
1093 1095 In [19]: len(_ip._main_mod_cache) == 0
1094 1096 Out[19]: True
1095 1097 """
1096 1098 self._main_mod_cache.clear()
1097 1099
1098 1100 #-------------------------------------------------------------------------
1099 1101 # Things related to debugging
1100 1102 #-------------------------------------------------------------------------
1101 1103
1102 1104 def init_pdb(self):
1103 1105 # Set calling of pdb on exceptions
1104 1106 # self.call_pdb is a property
1105 1107 self.call_pdb = self.pdb
1106 1108
1107 1109 def _get_call_pdb(self):
1108 1110 return self._call_pdb
1109 1111
1110 1112 def _set_call_pdb(self,val):
1111 1113
1112 1114 if val not in (0,1,False,True):
1113 1115 raise ValueError('new call_pdb value must be boolean')
1114 1116
1115 1117 # store value in instance
1116 1118 self._call_pdb = val
1117 1119
1118 1120 # notify the actual exception handlers
1119 1121 self.InteractiveTB.call_pdb = val
1120 1122
1121 1123 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
1122 1124 'Control auto-activation of pdb at exceptions')
1123 1125
1124 1126 def debugger(self,force=False):
1125 1127 """Call the pdb debugger.
1126 1128
1127 1129 Keywords:
1128 1130
1129 1131 - force(False): by default, this routine checks the instance call_pdb
1130 1132 flag and does not actually invoke the debugger if the flag is false.
1131 1133 The 'force' option forces the debugger to activate even if the flag
1132 1134 is false.
1133 1135 """
1134 1136
1135 1137 if not (force or self.call_pdb):
1136 1138 return
1137 1139
1138 1140 if not hasattr(sys,'last_traceback'):
1139 1141 error('No traceback has been produced, nothing to debug.')
1140 1142 return
1141 1143
1142 1144 self.InteractiveTB.debugger(force=True)
1143 1145
1144 1146 #-------------------------------------------------------------------------
1145 1147 # Things related to IPython's various namespaces
1146 1148 #-------------------------------------------------------------------------
1147 1149 default_user_namespaces = True
1148 1150
1149 1151 def init_create_namespaces(self, user_module=None, user_ns=None):
1150 1152 # Create the namespace where the user will operate. user_ns is
1151 1153 # normally the only one used, and it is passed to the exec calls as
1152 1154 # the locals argument. But we do carry a user_global_ns namespace
1153 1155 # given as the exec 'globals' argument, This is useful in embedding
1154 1156 # situations where the ipython shell opens in a context where the
1155 1157 # distinction between locals and globals is meaningful. For
1156 1158 # non-embedded contexts, it is just the same object as the user_ns dict.
1157 1159
1158 1160 # FIXME. For some strange reason, __builtins__ is showing up at user
1159 1161 # level as a dict instead of a module. This is a manual fix, but I
1160 1162 # should really track down where the problem is coming from. Alex
1161 1163 # Schmolck reported this problem first.
1162 1164
1163 1165 # A useful post by Alex Martelli on this topic:
1164 1166 # Re: inconsistent value from __builtins__
1165 1167 # Von: Alex Martelli <aleaxit@yahoo.com>
1166 1168 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1167 1169 # Gruppen: comp.lang.python
1168 1170
1169 1171 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1170 1172 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1171 1173 # > <type 'dict'>
1172 1174 # > >>> print type(__builtins__)
1173 1175 # > <type 'module'>
1174 1176 # > Is this difference in return value intentional?
1175 1177
1176 1178 # Well, it's documented that '__builtins__' can be either a dictionary
1177 1179 # or a module, and it's been that way for a long time. Whether it's
1178 1180 # intentional (or sensible), I don't know. In any case, the idea is
1179 1181 # that if you need to access the built-in namespace directly, you
1180 1182 # should start with "import __builtin__" (note, no 's') which will
1181 1183 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1182 1184
1183 1185 # These routines return a properly built module and dict as needed by
1184 1186 # the rest of the code, and can also be used by extension writers to
1185 1187 # generate properly initialized namespaces.
1186 1188 if (user_ns is not None) or (user_module is not None):
1187 1189 self.default_user_namespaces = False
1188 1190 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1189 1191
1190 1192 # A record of hidden variables we have added to the user namespace, so
1191 1193 # we can list later only variables defined in actual interactive use.
1192 1194 self.user_ns_hidden = {}
1193 1195
1194 1196 # Now that FakeModule produces a real module, we've run into a nasty
1195 1197 # problem: after script execution (via %run), the module where the user
1196 1198 # code ran is deleted. Now that this object is a true module (needed
1197 1199 # so doctest and other tools work correctly), the Python module
1198 1200 # teardown mechanism runs over it, and sets to None every variable
1199 1201 # present in that module. Top-level references to objects from the
1200 1202 # script survive, because the user_ns is updated with them. However,
1201 1203 # calling functions defined in the script that use other things from
1202 1204 # the script will fail, because the function's closure had references
1203 1205 # to the original objects, which are now all None. So we must protect
1204 1206 # these modules from deletion by keeping a cache.
1205 1207 #
1206 1208 # To avoid keeping stale modules around (we only need the one from the
1207 1209 # last run), we use a dict keyed with the full path to the script, so
1208 1210 # only the last version of the module is held in the cache. Note,
1209 1211 # however, that we must cache the module *namespace contents* (their
1210 1212 # __dict__). Because if we try to cache the actual modules, old ones
1211 1213 # (uncached) could be destroyed while still holding references (such as
1212 1214 # those held by GUI objects that tend to be long-lived)>
1213 1215 #
1214 1216 # The %reset command will flush this cache. See the cache_main_mod()
1215 1217 # and clear_main_mod_cache() methods for details on use.
1216 1218
1217 1219 # This is the cache used for 'main' namespaces
1218 1220 self._main_mod_cache = {}
1219 1221
1220 1222 # A table holding all the namespaces IPython deals with, so that
1221 1223 # introspection facilities can search easily.
1222 1224 self.ns_table = {'user_global':self.user_module.__dict__,
1223 1225 'user_local':self.user_ns,
1224 1226 'builtin':builtin_mod.__dict__
1225 1227 }
1226 1228
1227 1229 @property
1228 1230 def user_global_ns(self):
1229 1231 return self.user_module.__dict__
1230 1232
1231 1233 def prepare_user_module(self, user_module=None, user_ns=None):
1232 1234 """Prepare the module and namespace in which user code will be run.
1233 1235
1234 1236 When IPython is started normally, both parameters are None: a new module
1235 1237 is created automatically, and its __dict__ used as the namespace.
1236 1238
1237 1239 If only user_module is provided, its __dict__ is used as the namespace.
1238 1240 If only user_ns is provided, a dummy module is created, and user_ns
1239 1241 becomes the global namespace. If both are provided (as they may be
1240 1242 when embedding), user_ns is the local namespace, and user_module
1241 1243 provides the global namespace.
1242 1244
1243 1245 Parameters
1244 1246 ----------
1245 1247 user_module : module, optional
1246 1248 The current user module in which IPython is being run. If None,
1247 1249 a clean module will be created.
1248 1250 user_ns : dict, optional
1249 1251 A namespace in which to run interactive commands.
1250 1252
1251 1253 Returns
1252 1254 -------
1253 1255 A tuple of user_module and user_ns, each properly initialised.
1254 1256 """
1255 1257 if user_module is None and user_ns is not None:
1256 1258 user_ns.setdefault("__name__", "__main__")
1257 1259 user_module = DummyMod()
1258 1260 user_module.__dict__ = user_ns
1259 1261
1260 1262 if user_module is None:
1261 1263 user_module = types.ModuleType("__main__",
1262 1264 doc="Automatically created module for IPython interactive environment")
1263 1265
1264 1266 # We must ensure that __builtin__ (without the final 's') is always
1265 1267 # available and pointing to the __builtin__ *module*. For more details:
1266 1268 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1267 1269 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1268 1270 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1269 1271
1270 1272 if user_ns is None:
1271 1273 user_ns = user_module.__dict__
1272 1274
1273 1275 return user_module, user_ns
1274 1276
1275 1277 def init_sys_modules(self):
1276 1278 # We need to insert into sys.modules something that looks like a
1277 1279 # module but which accesses the IPython namespace, for shelve and
1278 1280 # pickle to work interactively. Normally they rely on getting
1279 1281 # everything out of __main__, but for embedding purposes each IPython
1280 1282 # instance has its own private namespace, so we can't go shoving
1281 1283 # everything into __main__.
1282 1284
1283 1285 # note, however, that we should only do this for non-embedded
1284 1286 # ipythons, which really mimic the __main__.__dict__ with their own
1285 1287 # namespace. Embedded instances, on the other hand, should not do
1286 1288 # this because they need to manage the user local/global namespaces
1287 1289 # only, but they live within a 'normal' __main__ (meaning, they
1288 1290 # shouldn't overtake the execution environment of the script they're
1289 1291 # embedded in).
1290 1292
1291 1293 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1292 1294 main_name = self.user_module.__name__
1293 1295 sys.modules[main_name] = self.user_module
1294 1296
1295 1297 def init_user_ns(self):
1296 1298 """Initialize all user-visible namespaces to their minimum defaults.
1297 1299
1298 1300 Certain history lists are also initialized here, as they effectively
1299 1301 act as user namespaces.
1300 1302
1301 1303 Notes
1302 1304 -----
1303 1305 All data structures here are only filled in, they are NOT reset by this
1304 1306 method. If they were not empty before, data will simply be added to
1305 1307 them.
1306 1308 """
1307 1309 # This function works in two parts: first we put a few things in
1308 1310 # user_ns, and we sync that contents into user_ns_hidden so that these
1309 1311 # initial variables aren't shown by %who. After the sync, we add the
1310 1312 # rest of what we *do* want the user to see with %who even on a new
1311 1313 # session (probably nothing, so they really only see their own stuff)
1312 1314
1313 1315 # The user dict must *always* have a __builtin__ reference to the
1314 1316 # Python standard __builtin__ namespace, which must be imported.
1315 1317 # This is so that certain operations in prompt evaluation can be
1316 1318 # reliably executed with builtins. Note that we can NOT use
1317 1319 # __builtins__ (note the 's'), because that can either be a dict or a
1318 1320 # module, and can even mutate at runtime, depending on the context
1319 1321 # (Python makes no guarantees on it). In contrast, __builtin__ is
1320 1322 # always a module object, though it must be explicitly imported.
1321 1323
1322 1324 # For more details:
1323 1325 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1324 1326 ns = {}
1325 1327
1326 1328 # make global variables for user access to the histories
1327 1329 ns['_ih'] = self.history_manager.input_hist_parsed
1328 1330 ns['_oh'] = self.history_manager.output_hist
1329 1331 ns['_dh'] = self.history_manager.dir_hist
1330 1332
1331 1333 # user aliases to input and output histories. These shouldn't show up
1332 1334 # in %who, as they can have very large reprs.
1333 1335 ns['In'] = self.history_manager.input_hist_parsed
1334 1336 ns['Out'] = self.history_manager.output_hist
1335 1337
1336 1338 # Store myself as the public api!!!
1337 1339 ns['get_ipython'] = self.get_ipython
1338 1340
1339 1341 ns['exit'] = self.exiter
1340 1342 ns['quit'] = self.exiter
1341 1343 ns["open"] = _modified_open
1342 1344
1343 1345 # Sync what we've added so far to user_ns_hidden so these aren't seen
1344 1346 # by %who
1345 1347 self.user_ns_hidden.update(ns)
1346 1348
1347 1349 # Anything put into ns now would show up in %who. Think twice before
1348 1350 # putting anything here, as we really want %who to show the user their
1349 1351 # stuff, not our variables.
1350 1352
1351 1353 # Finally, update the real user's namespace
1352 1354 self.user_ns.update(ns)
1353 1355
1354 1356 @property
1355 1357 def all_ns_refs(self):
1356 1358 """Get a list of references to all the namespace dictionaries in which
1357 1359 IPython might store a user-created object.
1358 1360
1359 1361 Note that this does not include the displayhook, which also caches
1360 1362 objects from the output."""
1361 1363 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1362 1364 [m.__dict__ for m in self._main_mod_cache.values()]
1363 1365
1364 1366 def reset(self, new_session=True, aggressive=False):
1365 1367 """Clear all internal namespaces, and attempt to release references to
1366 1368 user objects.
1367 1369
1368 1370 If new_session is True, a new history session will be opened.
1369 1371 """
1370 1372 # Clear histories
1371 1373 self.history_manager.reset(new_session)
1372 1374 # Reset counter used to index all histories
1373 1375 if new_session:
1374 1376 self.execution_count = 1
1375 1377
1376 1378 # Reset last execution result
1377 1379 self.last_execution_succeeded = True
1378 1380 self.last_execution_result = None
1379 1381
1380 1382 # Flush cached output items
1381 1383 if self.displayhook.do_full_cache:
1382 1384 self.displayhook.flush()
1383 1385
1384 1386 # The main execution namespaces must be cleared very carefully,
1385 1387 # skipping the deletion of the builtin-related keys, because doing so
1386 1388 # would cause errors in many object's __del__ methods.
1387 1389 if self.user_ns is not self.user_global_ns:
1388 1390 self.user_ns.clear()
1389 1391 ns = self.user_global_ns
1390 1392 drop_keys = set(ns.keys())
1391 1393 drop_keys.discard('__builtin__')
1392 1394 drop_keys.discard('__builtins__')
1393 1395 drop_keys.discard('__name__')
1394 1396 for k in drop_keys:
1395 1397 del ns[k]
1396 1398
1397 1399 self.user_ns_hidden.clear()
1398 1400
1399 1401 # Restore the user namespaces to minimal usability
1400 1402 self.init_user_ns()
1401 1403 if aggressive and not hasattr(self, "_sys_modules_keys"):
1402 1404 print("Cannot restore sys.module, no snapshot")
1403 1405 elif aggressive:
1404 1406 print("culling sys module...")
1405 1407 current_keys = set(sys.modules.keys())
1406 1408 for k in current_keys - self._sys_modules_keys:
1407 1409 if k.startswith("multiprocessing"):
1408 1410 continue
1409 1411 del sys.modules[k]
1410 1412
1411 1413 # Restore the default and user aliases
1412 1414 self.alias_manager.clear_aliases()
1413 1415 self.alias_manager.init_aliases()
1414 1416
1415 1417 # Now define aliases that only make sense on the terminal, because they
1416 1418 # need direct access to the console in a way that we can't emulate in
1417 1419 # GUI or web frontend
1418 1420 if os.name == 'posix':
1419 1421 for cmd in ('clear', 'more', 'less', 'man'):
1420 1422 if cmd not in self.magics_manager.magics['line']:
1421 1423 self.alias_manager.soft_define_alias(cmd, cmd)
1422 1424
1423 1425 # Flush the private list of module references kept for script
1424 1426 # execution protection
1425 1427 self.clear_main_mod_cache()
1426 1428
1427 1429 def del_var(self, varname, by_name=False):
1428 1430 """Delete a variable from the various namespaces, so that, as
1429 1431 far as possible, we're not keeping any hidden references to it.
1430 1432
1431 1433 Parameters
1432 1434 ----------
1433 1435 varname : str
1434 1436 The name of the variable to delete.
1435 1437 by_name : bool
1436 1438 If True, delete variables with the given name in each
1437 1439 namespace. If False (default), find the variable in the user
1438 1440 namespace, and delete references to it.
1439 1441 """
1440 1442 if varname in ('__builtin__', '__builtins__'):
1441 1443 raise ValueError("Refusing to delete %s" % varname)
1442 1444
1443 1445 ns_refs = self.all_ns_refs
1444 1446
1445 1447 if by_name: # Delete by name
1446 1448 for ns in ns_refs:
1447 1449 try:
1448 1450 del ns[varname]
1449 1451 except KeyError:
1450 1452 pass
1451 1453 else: # Delete by object
1452 1454 try:
1453 1455 obj = self.user_ns[varname]
1454 1456 except KeyError as e:
1455 1457 raise NameError("name '%s' is not defined" % varname) from e
1456 1458 # Also check in output history
1457 1459 ns_refs.append(self.history_manager.output_hist)
1458 1460 for ns in ns_refs:
1459 1461 to_delete = [n for n, o in ns.items() if o is obj]
1460 1462 for name in to_delete:
1461 1463 del ns[name]
1462 1464
1463 1465 # Ensure it is removed from the last execution result
1464 1466 if self.last_execution_result.result is obj:
1465 1467 self.last_execution_result = None
1466 1468
1467 1469 # displayhook keeps extra references, but not in a dictionary
1468 1470 for name in ('_', '__', '___'):
1469 1471 if getattr(self.displayhook, name) is obj:
1470 1472 setattr(self.displayhook, name, None)
1471 1473
1472 1474 def reset_selective(self, regex=None):
1473 1475 """Clear selective variables from internal namespaces based on a
1474 1476 specified regular expression.
1475 1477
1476 1478 Parameters
1477 1479 ----------
1478 1480 regex : string or compiled pattern, optional
1479 1481 A regular expression pattern that will be used in searching
1480 1482 variable names in the users namespaces.
1481 1483 """
1482 1484 if regex is not None:
1483 1485 try:
1484 1486 m = re.compile(regex)
1485 1487 except TypeError as e:
1486 1488 raise TypeError('regex must be a string or compiled pattern') from e
1487 1489 # Search for keys in each namespace that match the given regex
1488 1490 # If a match is found, delete the key/value pair.
1489 1491 for ns in self.all_ns_refs:
1490 1492 for var in ns:
1491 1493 if m.search(var):
1492 1494 del ns[var]
1493 1495
1494 1496 def push(self, variables, interactive=True):
1495 1497 """Inject a group of variables into the IPython user namespace.
1496 1498
1497 1499 Parameters
1498 1500 ----------
1499 1501 variables : dict, str or list/tuple of str
1500 1502 The variables to inject into the user's namespace. If a dict, a
1501 1503 simple update is done. If a str, the string is assumed to have
1502 1504 variable names separated by spaces. A list/tuple of str can also
1503 1505 be used to give the variable names. If just the variable names are
1504 1506 give (list/tuple/str) then the variable values looked up in the
1505 1507 callers frame.
1506 1508 interactive : bool
1507 1509 If True (default), the variables will be listed with the ``who``
1508 1510 magic.
1509 1511 """
1510 1512 vdict = None
1511 1513
1512 1514 # We need a dict of name/value pairs to do namespace updates.
1513 1515 if isinstance(variables, dict):
1514 1516 vdict = variables
1515 1517 elif isinstance(variables, (str, list, tuple)):
1516 1518 if isinstance(variables, str):
1517 1519 vlist = variables.split()
1518 1520 else:
1519 1521 vlist = variables
1520 1522 vdict = {}
1521 1523 cf = sys._getframe(1)
1522 1524 for name in vlist:
1523 1525 try:
1524 1526 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1525 1527 except:
1526 1528 print('Could not get variable %s from %s' %
1527 1529 (name,cf.f_code.co_name))
1528 1530 else:
1529 1531 raise ValueError('variables must be a dict/str/list/tuple')
1530 1532
1531 1533 # Propagate variables to user namespace
1532 1534 self.user_ns.update(vdict)
1533 1535
1534 1536 # And configure interactive visibility
1535 1537 user_ns_hidden = self.user_ns_hidden
1536 1538 if interactive:
1537 1539 for name in vdict:
1538 1540 user_ns_hidden.pop(name, None)
1539 1541 else:
1540 1542 user_ns_hidden.update(vdict)
1541 1543
1542 1544 def drop_by_id(self, variables):
1543 1545 """Remove a dict of variables from the user namespace, if they are the
1544 1546 same as the values in the dictionary.
1545 1547
1546 1548 This is intended for use by extensions: variables that they've added can
1547 1549 be taken back out if they are unloaded, without removing any that the
1548 1550 user has overwritten.
1549 1551
1550 1552 Parameters
1551 1553 ----------
1552 1554 variables : dict
1553 1555 A dictionary mapping object names (as strings) to the objects.
1554 1556 """
1555 1557 for name, obj in variables.items():
1556 1558 if name in self.user_ns and self.user_ns[name] is obj:
1557 1559 del self.user_ns[name]
1558 1560 self.user_ns_hidden.pop(name, None)
1559 1561
1560 1562 #-------------------------------------------------------------------------
1561 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 1587 raw_parts = oname.split(".")
1573 1588 parts = []
1574 1589 parts_ok = True
1575 1590 for p in raw_parts:
1576 1591 if p.endswith("]"):
1577 1592 var, *indices = p.split("[")
1578 1593 if not var.isidentifier():
1579 1594 parts_ok = False
1580 1595 break
1581 1596 parts.append(var)
1582 1597 for ind in indices:
1583 1598 if ind[-1] != "]" and not is_integer_string(ind[:-1]):
1584 1599 parts_ok = False
1585 1600 break
1586 1601 parts.append(ind[:-1])
1587 1602 continue
1588 1603
1589 1604 if not p.isidentifier():
1590 1605 parts_ok = False
1591 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 1620 if (
1594 1621 not oname.startswith(ESC_MAGIC)
1595 1622 and not oname.startswith(ESC_MAGIC2)
1596 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 1634 if namespaces is None:
1601 1635 # Namespaces to search in:
1602 1636 # Put them in a list. The order is important so that we
1603 1637 # find things in the same order that Python finds them.
1604 1638 namespaces = [ ('Interactive', self.user_ns),
1605 1639 ('Interactive (global)', self.user_global_ns),
1606 1640 ('Python builtin', builtin_mod.__dict__),
1607 1641 ]
1608 1642
1609 1643 ismagic = False
1610 1644 isalias = False
1611 1645 found = False
1612 1646 ospace = None
1613 1647 parent = None
1614 1648 obj = None
1615 1649
1616 1650
1617 1651 # Look for the given name by splitting it in parts. If the head is
1618 1652 # found, then we look for all the remaining parts as members, and only
1619 1653 # declare success if we can find them all.
1620 1654 oname_parts = parts
1621 1655 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1622 1656 for nsname,ns in namespaces:
1623 1657 try:
1624 1658 obj = ns[oname_head]
1625 1659 except KeyError:
1626 1660 continue
1627 1661 else:
1628 1662 for idx, part in enumerate(oname_rest):
1629 1663 try:
1630 1664 parent = obj
1631 1665 # The last part is looked up in a special way to avoid
1632 1666 # descriptor invocation as it may raise or have side
1633 1667 # effects.
1634 1668 if idx == len(oname_rest) - 1:
1635 1669 obj = self._getattr_property(obj, part)
1636 1670 else:
1637 1671 if is_integer_string(part):
1638 1672 obj = obj[int(part)]
1639 1673 else:
1640 1674 obj = getattr(obj, part)
1641 1675 except:
1642 1676 # Blanket except b/c some badly implemented objects
1643 1677 # allow __getattr__ to raise exceptions other than
1644 1678 # AttributeError, which then crashes IPython.
1645 1679 break
1646 1680 else:
1647 1681 # If we finish the for loop (no break), we got all members
1648 1682 found = True
1649 1683 ospace = nsname
1650 1684 break # namespace loop
1651 1685
1652 1686 # Try to see if it's magic
1653 1687 if not found:
1654 1688 obj = None
1655 1689 if oname.startswith(ESC_MAGIC2):
1656 1690 oname = oname.lstrip(ESC_MAGIC2)
1657 1691 obj = self.find_cell_magic(oname)
1658 1692 elif oname.startswith(ESC_MAGIC):
1659 1693 oname = oname.lstrip(ESC_MAGIC)
1660 1694 obj = self.find_line_magic(oname)
1661 1695 else:
1662 1696 # search without prefix, so run? will find %run?
1663 1697 obj = self.find_line_magic(oname)
1664 1698 if obj is None:
1665 1699 obj = self.find_cell_magic(oname)
1666 1700 if obj is not None:
1667 1701 found = True
1668 1702 ospace = 'IPython internal'
1669 1703 ismagic = True
1670 1704 isalias = isinstance(obj, Alias)
1671 1705
1672 1706 # Last try: special-case some literals like '', [], {}, etc:
1673 1707 if not found and oname_head in ["''",'""','[]','{}','()']:
1674 1708 obj = eval(oname_head)
1675 1709 found = True
1676 1710 ospace = 'Interactive'
1677 1711
1678 return {
1679 'obj':obj,
1680 'found':found,
1681 'parent':parent,
1682 'ismagic':ismagic,
1683 'isalias':isalias,
1684 'namespace':ospace
1685 }
1712 return OInfo(
1713 **{
1714 "obj": obj,
1715 "found": found,
1716 "parent": parent,
1717 "ismagic": ismagic,
1718 "isalias": isalias,
1719 "namespace": ospace,
1720 }
1721 )
1686 1722
1687 1723 @staticmethod
1688 1724 def _getattr_property(obj, attrname):
1689 1725 """Property-aware getattr to use in object finding.
1690 1726
1691 1727 If attrname represents a property, return it unevaluated (in case it has
1692 1728 side effects or raises an error.
1693 1729
1694 1730 """
1695 1731 if not isinstance(obj, type):
1696 1732 try:
1697 1733 # `getattr(type(obj), attrname)` is not guaranteed to return
1698 1734 # `obj`, but does so for property:
1699 1735 #
1700 1736 # property.__get__(self, None, cls) -> self
1701 1737 #
1702 1738 # The universal alternative is to traverse the mro manually
1703 1739 # searching for attrname in class dicts.
1704 1740 if is_integer_string(attrname):
1705 1741 return obj[int(attrname)]
1706 1742 else:
1707 1743 attr = getattr(type(obj), attrname)
1708 1744 except AttributeError:
1709 1745 pass
1710 1746 else:
1711 1747 # This relies on the fact that data descriptors (with both
1712 1748 # __get__ & __set__ magic methods) take precedence over
1713 1749 # instance-level attributes:
1714 1750 #
1715 1751 # class A(object):
1716 1752 # @property
1717 1753 # def foobar(self): return 123
1718 1754 # a = A()
1719 1755 # a.__dict__['foobar'] = 345
1720 1756 # a.foobar # == 123
1721 1757 #
1722 1758 # So, a property may be returned right away.
1723 1759 if isinstance(attr, property):
1724 1760 return attr
1725 1761
1726 1762 # Nothing helped, fall back.
1727 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 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 1769 def _inspect(self, meth, oname, namespaces=None, **kw):
1734 1770 """Generic interface to the inspector system.
1735 1771
1736 1772 This function is meant to be called by pdef, pdoc & friends.
1737 1773 """
1738 1774 info = self._object_find(oname, namespaces)
1739 1775 docformat = (
1740 1776 sphinxify(self.object_inspect(oname)) if self.sphinxify_docstring else None
1741 1777 )
1742 1778 if info.found:
1743 1779 pmethod = getattr(self.inspector, meth)
1744 1780 # TODO: only apply format_screen to the plain/text repr of the mime
1745 1781 # bundle.
1746 1782 formatter = format_screen if info.ismagic else docformat
1747 1783 if meth == 'pdoc':
1748 1784 pmethod(info.obj, oname, formatter)
1749 1785 elif meth == 'pinfo':
1750 1786 pmethod(
1751 1787 info.obj,
1752 1788 oname,
1753 1789 formatter,
1754 1790 info,
1755 1791 enable_html_pager=self.enable_html_pager,
1756 1792 **kw,
1757 1793 )
1758 1794 else:
1759 1795 pmethod(info.obj, oname)
1760 1796 else:
1761 1797 print('Object `%s` not found.' % oname)
1762 1798 return 'not found' # so callers can take other action
1763 1799
1764 1800 def object_inspect(self, oname, detail_level=0):
1765 1801 """Get object info about oname"""
1766 1802 with self.builtin_trap:
1767 1803 info = self._object_find(oname)
1768 1804 if info.found:
1769 1805 return self.inspector.info(info.obj, oname, info=info,
1770 1806 detail_level=detail_level
1771 1807 )
1772 1808 else:
1773 1809 return oinspect.object_info(name=oname, found=False)
1774 1810
1775 1811 def object_inspect_text(self, oname, detail_level=0):
1776 1812 """Get object info as formatted text"""
1777 1813 return self.object_inspect_mime(oname, detail_level)['text/plain']
1778 1814
1779 1815 def object_inspect_mime(self, oname, detail_level=0, omit_sections=()):
1780 1816 """Get object info as a mimebundle of formatted representations.
1781 1817
1782 1818 A mimebundle is a dictionary, keyed by mime-type.
1783 1819 It must always have the key `'text/plain'`.
1784 1820 """
1785 1821 with self.builtin_trap:
1786 1822 info = self._object_find(oname)
1787 1823 if info.found:
1788 1824 docformat = (
1789 1825 sphinxify(self.object_inspect(oname))
1790 1826 if self.sphinxify_docstring
1791 1827 else None
1792 1828 )
1793 1829 return self.inspector._get_info(
1794 1830 info.obj,
1795 1831 oname,
1796 1832 info=info,
1797 1833 detail_level=detail_level,
1798 1834 formatter=docformat,
1799 1835 omit_sections=omit_sections,
1800 1836 )
1801 1837 else:
1802 1838 raise KeyError(oname)
1803 1839
1804 1840 #-------------------------------------------------------------------------
1805 1841 # Things related to history management
1806 1842 #-------------------------------------------------------------------------
1807 1843
1808 1844 def init_history(self):
1809 1845 """Sets up the command history, and starts regular autosaves."""
1810 1846 self.history_manager = HistoryManager(shell=self, parent=self)
1811 1847 self.configurables.append(self.history_manager)
1812 1848
1813 1849 #-------------------------------------------------------------------------
1814 1850 # Things related to exception handling and tracebacks (not debugging)
1815 1851 #-------------------------------------------------------------------------
1816 1852
1817 1853 debugger_cls = InterruptiblePdb
1818 1854
1819 1855 def init_traceback_handlers(self, custom_exceptions):
1820 1856 # Syntax error handler.
1821 1857 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor', parent=self)
1822 1858
1823 1859 # The interactive one is initialized with an offset, meaning we always
1824 1860 # want to remove the topmost item in the traceback, which is our own
1825 1861 # internal code. Valid modes: ['Plain','Context','Verbose','Minimal']
1826 1862 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1827 1863 color_scheme='NoColor',
1828 1864 tb_offset = 1,
1829 1865 debugger_cls=self.debugger_cls, parent=self)
1830 1866
1831 1867 # The instance will store a pointer to the system-wide exception hook,
1832 1868 # so that runtime code (such as magics) can access it. This is because
1833 1869 # during the read-eval loop, it may get temporarily overwritten.
1834 1870 self.sys_excepthook = sys.excepthook
1835 1871
1836 1872 # and add any custom exception handlers the user may have specified
1837 1873 self.set_custom_exc(*custom_exceptions)
1838 1874
1839 1875 # Set the exception mode
1840 1876 self.InteractiveTB.set_mode(mode=self.xmode)
1841 1877
1842 1878 def set_custom_exc(self, exc_tuple, handler):
1843 1879 """set_custom_exc(exc_tuple, handler)
1844 1880
1845 1881 Set a custom exception handler, which will be called if any of the
1846 1882 exceptions in exc_tuple occur in the mainloop (specifically, in the
1847 1883 run_code() method).
1848 1884
1849 1885 Parameters
1850 1886 ----------
1851 1887 exc_tuple : tuple of exception classes
1852 1888 A *tuple* of exception classes, for which to call the defined
1853 1889 handler. It is very important that you use a tuple, and NOT A
1854 1890 LIST here, because of the way Python's except statement works. If
1855 1891 you only want to trap a single exception, use a singleton tuple::
1856 1892
1857 1893 exc_tuple == (MyCustomException,)
1858 1894
1859 1895 handler : callable
1860 1896 handler must have the following signature::
1861 1897
1862 1898 def my_handler(self, etype, value, tb, tb_offset=None):
1863 1899 ...
1864 1900 return structured_traceback
1865 1901
1866 1902 Your handler must return a structured traceback (a list of strings),
1867 1903 or None.
1868 1904
1869 1905 This will be made into an instance method (via types.MethodType)
1870 1906 of IPython itself, and it will be called if any of the exceptions
1871 1907 listed in the exc_tuple are caught. If the handler is None, an
1872 1908 internal basic one is used, which just prints basic info.
1873 1909
1874 1910 To protect IPython from crashes, if your handler ever raises an
1875 1911 exception or returns an invalid result, it will be immediately
1876 1912 disabled.
1877 1913
1878 1914 Notes
1879 1915 -----
1880 1916 WARNING: by putting in your own exception handler into IPython's main
1881 1917 execution loop, you run a very good chance of nasty crashes. This
1882 1918 facility should only be used if you really know what you are doing.
1883 1919 """
1884 1920
1885 1921 if not isinstance(exc_tuple, tuple):
1886 1922 raise TypeError("The custom exceptions must be given as a tuple.")
1887 1923
1888 1924 def dummy_handler(self, etype, value, tb, tb_offset=None):
1889 1925 print('*** Simple custom exception handler ***')
1890 1926 print('Exception type :', etype)
1891 1927 print('Exception value:', value)
1892 1928 print('Traceback :', tb)
1893 1929
1894 1930 def validate_stb(stb):
1895 1931 """validate structured traceback return type
1896 1932
1897 1933 return type of CustomTB *should* be a list of strings, but allow
1898 1934 single strings or None, which are harmless.
1899 1935
1900 1936 This function will *always* return a list of strings,
1901 1937 and will raise a TypeError if stb is inappropriate.
1902 1938 """
1903 1939 msg = "CustomTB must return list of strings, not %r" % stb
1904 1940 if stb is None:
1905 1941 return []
1906 1942 elif isinstance(stb, str):
1907 1943 return [stb]
1908 1944 elif not isinstance(stb, list):
1909 1945 raise TypeError(msg)
1910 1946 # it's a list
1911 1947 for line in stb:
1912 1948 # check every element
1913 1949 if not isinstance(line, str):
1914 1950 raise TypeError(msg)
1915 1951 return stb
1916 1952
1917 1953 if handler is None:
1918 1954 wrapped = dummy_handler
1919 1955 else:
1920 1956 def wrapped(self,etype,value,tb,tb_offset=None):
1921 1957 """wrap CustomTB handler, to protect IPython from user code
1922 1958
1923 1959 This makes it harder (but not impossible) for custom exception
1924 1960 handlers to crash IPython.
1925 1961 """
1926 1962 try:
1927 1963 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1928 1964 return validate_stb(stb)
1929 1965 except:
1930 1966 # clear custom handler immediately
1931 1967 self.set_custom_exc((), None)
1932 1968 print("Custom TB Handler failed, unregistering", file=sys.stderr)
1933 1969 # show the exception in handler first
1934 1970 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1935 1971 print(self.InteractiveTB.stb2text(stb))
1936 1972 print("The original exception:")
1937 1973 stb = self.InteractiveTB.structured_traceback(
1938 1974 (etype,value,tb), tb_offset=tb_offset
1939 1975 )
1940 1976 return stb
1941 1977
1942 1978 self.CustomTB = types.MethodType(wrapped,self)
1943 1979 self.custom_exceptions = exc_tuple
1944 1980
1945 1981 def excepthook(self, etype, value, tb):
1946 1982 """One more defense for GUI apps that call sys.excepthook.
1947 1983
1948 1984 GUI frameworks like wxPython trap exceptions and call
1949 1985 sys.excepthook themselves. I guess this is a feature that
1950 1986 enables them to keep running after exceptions that would
1951 1987 otherwise kill their mainloop. This is a bother for IPython
1952 1988 which expects to catch all of the program exceptions with a try:
1953 1989 except: statement.
1954 1990
1955 1991 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1956 1992 any app directly invokes sys.excepthook, it will look to the user like
1957 1993 IPython crashed. In order to work around this, we can disable the
1958 1994 CrashHandler and replace it with this excepthook instead, which prints a
1959 1995 regular traceback using our InteractiveTB. In this fashion, apps which
1960 1996 call sys.excepthook will generate a regular-looking exception from
1961 1997 IPython, and the CrashHandler will only be triggered by real IPython
1962 1998 crashes.
1963 1999
1964 2000 This hook should be used sparingly, only in places which are not likely
1965 2001 to be true IPython errors.
1966 2002 """
1967 2003 self.showtraceback((etype, value, tb), tb_offset=0)
1968 2004
1969 2005 def _get_exc_info(self, exc_tuple=None):
1970 2006 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1971 2007
1972 2008 Ensures sys.last_type,value,traceback hold the exc_info we found,
1973 2009 from whichever source.
1974 2010
1975 2011 raises ValueError if none of these contain any information
1976 2012 """
1977 2013 if exc_tuple is None:
1978 2014 etype, value, tb = sys.exc_info()
1979 2015 else:
1980 2016 etype, value, tb = exc_tuple
1981 2017
1982 2018 if etype is None:
1983 2019 if hasattr(sys, 'last_type'):
1984 2020 etype, value, tb = sys.last_type, sys.last_value, \
1985 2021 sys.last_traceback
1986 2022
1987 2023 if etype is None:
1988 2024 raise ValueError("No exception to find")
1989 2025
1990 2026 # Now store the exception info in sys.last_type etc.
1991 2027 # WARNING: these variables are somewhat deprecated and not
1992 2028 # necessarily safe to use in a threaded environment, but tools
1993 2029 # like pdb depend on their existence, so let's set them. If we
1994 2030 # find problems in the field, we'll need to revisit their use.
1995 2031 sys.last_type = etype
1996 2032 sys.last_value = value
1997 2033 sys.last_traceback = tb
1998 2034
1999 2035 return etype, value, tb
2000 2036
2001 2037 def show_usage_error(self, exc):
2002 2038 """Show a short message for UsageErrors
2003 2039
2004 2040 These are special exceptions that shouldn't show a traceback.
2005 2041 """
2006 2042 print("UsageError: %s" % exc, file=sys.stderr)
2007 2043
2008 2044 def get_exception_only(self, exc_tuple=None):
2009 2045 """
2010 2046 Return as a string (ending with a newline) the exception that
2011 2047 just occurred, without any traceback.
2012 2048 """
2013 2049 etype, value, tb = self._get_exc_info(exc_tuple)
2014 2050 msg = traceback.format_exception_only(etype, value)
2015 2051 return ''.join(msg)
2016 2052
2017 2053 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
2018 2054 exception_only=False, running_compiled_code=False):
2019 2055 """Display the exception that just occurred.
2020 2056
2021 2057 If nothing is known about the exception, this is the method which
2022 2058 should be used throughout the code for presenting user tracebacks,
2023 2059 rather than directly invoking the InteractiveTB object.
2024 2060
2025 2061 A specific showsyntaxerror() also exists, but this method can take
2026 2062 care of calling it if needed, so unless you are explicitly catching a
2027 2063 SyntaxError exception, don't try to analyze the stack manually and
2028 2064 simply call this method."""
2029 2065
2030 2066 try:
2031 2067 try:
2032 2068 etype, value, tb = self._get_exc_info(exc_tuple)
2033 2069 except ValueError:
2034 2070 print('No traceback available to show.', file=sys.stderr)
2035 2071 return
2036 2072
2037 2073 if issubclass(etype, SyntaxError):
2038 2074 # Though this won't be called by syntax errors in the input
2039 2075 # line, there may be SyntaxError cases with imported code.
2040 2076 self.showsyntaxerror(filename, running_compiled_code)
2041 2077 elif etype is UsageError:
2042 2078 self.show_usage_error(value)
2043 2079 else:
2044 2080 if exception_only:
2045 2081 stb = ['An exception has occurred, use %tb to see '
2046 2082 'the full traceback.\n']
2047 2083 stb.extend(self.InteractiveTB.get_exception_only(etype,
2048 2084 value))
2049 2085 else:
2050 2086 try:
2051 2087 # Exception classes can customise their traceback - we
2052 2088 # use this in IPython.parallel for exceptions occurring
2053 2089 # in the engines. This should return a list of strings.
2054 2090 if hasattr(value, "_render_traceback_"):
2055 2091 stb = value._render_traceback_()
2056 2092 else:
2057 2093 stb = self.InteractiveTB.structured_traceback(
2058 2094 etype, value, tb, tb_offset=tb_offset
2059 2095 )
2060 2096
2061 2097 except Exception:
2062 2098 print(
2063 2099 "Unexpected exception formatting exception. Falling back to standard exception"
2064 2100 )
2065 2101 traceback.print_exc()
2066 2102 return None
2067 2103
2068 2104 self._showtraceback(etype, value, stb)
2069 2105 if self.call_pdb:
2070 2106 # drop into debugger
2071 2107 self.debugger(force=True)
2072 2108 return
2073 2109
2074 2110 # Actually show the traceback
2075 2111 self._showtraceback(etype, value, stb)
2076 2112
2077 2113 except KeyboardInterrupt:
2078 2114 print('\n' + self.get_exception_only(), file=sys.stderr)
2079 2115
2080 2116 def _showtraceback(self, etype, evalue, stb: str):
2081 2117 """Actually show a traceback.
2082 2118
2083 2119 Subclasses may override this method to put the traceback on a different
2084 2120 place, like a side channel.
2085 2121 """
2086 2122 val = self.InteractiveTB.stb2text(stb)
2087 2123 try:
2088 2124 print(val)
2089 2125 except UnicodeEncodeError:
2090 2126 print(val.encode("utf-8", "backslashreplace").decode())
2091 2127
2092 2128 def showsyntaxerror(self, filename=None, running_compiled_code=False):
2093 2129 """Display the syntax error that just occurred.
2094 2130
2095 2131 This doesn't display a stack trace because there isn't one.
2096 2132
2097 2133 If a filename is given, it is stuffed in the exception instead
2098 2134 of what was there before (because Python's parser always uses
2099 2135 "<string>" when reading from a string).
2100 2136
2101 2137 If the syntax error occurred when running a compiled code (i.e. running_compile_code=True),
2102 2138 longer stack trace will be displayed.
2103 2139 """
2104 2140 etype, value, last_traceback = self._get_exc_info()
2105 2141
2106 2142 if filename and issubclass(etype, SyntaxError):
2107 2143 try:
2108 2144 value.filename = filename
2109 2145 except:
2110 2146 # Not the format we expect; leave it alone
2111 2147 pass
2112 2148
2113 2149 # If the error occurred when executing compiled code, we should provide full stacktrace.
2114 2150 elist = traceback.extract_tb(last_traceback) if running_compiled_code else []
2115 2151 stb = self.SyntaxTB.structured_traceback(etype, value, elist)
2116 2152 self._showtraceback(etype, value, stb)
2117 2153
2118 2154 # This is overridden in TerminalInteractiveShell to show a message about
2119 2155 # the %paste magic.
2120 2156 def showindentationerror(self):
2121 2157 """Called by _run_cell when there's an IndentationError in code entered
2122 2158 at the prompt.
2123 2159
2124 2160 This is overridden in TerminalInteractiveShell to show a message about
2125 2161 the %paste magic."""
2126 2162 self.showsyntaxerror()
2127 2163
2128 2164 @skip_doctest
2129 2165 def set_next_input(self, s, replace=False):
2130 2166 """ Sets the 'default' input string for the next command line.
2131 2167
2132 2168 Example::
2133 2169
2134 2170 In [1]: _ip.set_next_input("Hello Word")
2135 2171 In [2]: Hello Word_ # cursor is here
2136 2172 """
2137 2173 self.rl_next_input = s
2138 2174
2139 2175 def _indent_current_str(self):
2140 2176 """return the current level of indentation as a string"""
2141 2177 return self.input_splitter.get_indent_spaces() * ' '
2142 2178
2143 2179 #-------------------------------------------------------------------------
2144 2180 # Things related to text completion
2145 2181 #-------------------------------------------------------------------------
2146 2182
2147 2183 def init_completer(self):
2148 2184 """Initialize the completion machinery.
2149 2185
2150 2186 This creates completion machinery that can be used by client code,
2151 2187 either interactively in-process (typically triggered by the readline
2152 2188 library), programmatically (such as in test suites) or out-of-process
2153 2189 (typically over the network by remote frontends).
2154 2190 """
2155 2191 from IPython.core.completer import IPCompleter
2156 2192 from IPython.core.completerlib import (
2157 2193 cd_completer,
2158 2194 magic_run_completer,
2159 2195 module_completer,
2160 2196 reset_completer,
2161 2197 )
2162 2198
2163 2199 self.Completer = IPCompleter(shell=self,
2164 2200 namespace=self.user_ns,
2165 2201 global_namespace=self.user_global_ns,
2166 2202 parent=self,
2167 2203 )
2168 2204 self.configurables.append(self.Completer)
2169 2205
2170 2206 # Add custom completers to the basic ones built into IPCompleter
2171 2207 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2172 2208 self.strdispatchers['complete_command'] = sdisp
2173 2209 self.Completer.custom_completers = sdisp
2174 2210
2175 2211 self.set_hook('complete_command', module_completer, str_key = 'import')
2176 2212 self.set_hook('complete_command', module_completer, str_key = 'from')
2177 2213 self.set_hook('complete_command', module_completer, str_key = '%aimport')
2178 2214 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2179 2215 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2180 2216 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2181 2217
2182 2218 @skip_doctest
2183 2219 def complete(self, text, line=None, cursor_pos=None):
2184 2220 """Return the completed text and a list of completions.
2185 2221
2186 2222 Parameters
2187 2223 ----------
2188 2224 text : string
2189 2225 A string of text to be completed on. It can be given as empty and
2190 2226 instead a line/position pair are given. In this case, the
2191 2227 completer itself will split the line like readline does.
2192 2228 line : string, optional
2193 2229 The complete line that text is part of.
2194 2230 cursor_pos : int, optional
2195 2231 The position of the cursor on the input line.
2196 2232
2197 2233 Returns
2198 2234 -------
2199 2235 text : string
2200 2236 The actual text that was completed.
2201 2237 matches : list
2202 2238 A sorted list with all possible completions.
2203 2239
2204 2240 Notes
2205 2241 -----
2206 2242 The optional arguments allow the completion to take more context into
2207 2243 account, and are part of the low-level completion API.
2208 2244
2209 2245 This is a wrapper around the completion mechanism, similar to what
2210 2246 readline does at the command line when the TAB key is hit. By
2211 2247 exposing it as a method, it can be used by other non-readline
2212 2248 environments (such as GUIs) for text completion.
2213 2249
2214 2250 Examples
2215 2251 --------
2216 2252 In [1]: x = 'hello'
2217 2253
2218 2254 In [2]: _ip.complete('x.l')
2219 2255 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2220 2256 """
2221 2257
2222 2258 # Inject names into __builtin__ so we can complete on the added names.
2223 2259 with self.builtin_trap:
2224 2260 return self.Completer.complete(text, line, cursor_pos)
2225 2261
2226 2262 def set_custom_completer(self, completer, pos=0) -> None:
2227 2263 """Adds a new custom completer function.
2228 2264
2229 2265 The position argument (defaults to 0) is the index in the completers
2230 2266 list where you want the completer to be inserted.
2231 2267
2232 2268 `completer` should have the following signature::
2233 2269
2234 2270 def completion(self: Completer, text: string) -> List[str]:
2235 2271 raise NotImplementedError
2236 2272
2237 2273 It will be bound to the current Completer instance and pass some text
2238 2274 and return a list with current completions to suggest to the user.
2239 2275 """
2240 2276
2241 2277 newcomp = types.MethodType(completer, self.Completer)
2242 2278 self.Completer.custom_matchers.insert(pos,newcomp)
2243 2279
2244 2280 def set_completer_frame(self, frame=None):
2245 2281 """Set the frame of the completer."""
2246 2282 if frame:
2247 2283 self.Completer.namespace = frame.f_locals
2248 2284 self.Completer.global_namespace = frame.f_globals
2249 2285 else:
2250 2286 self.Completer.namespace = self.user_ns
2251 2287 self.Completer.global_namespace = self.user_global_ns
2252 2288
2253 2289 #-------------------------------------------------------------------------
2254 2290 # Things related to magics
2255 2291 #-------------------------------------------------------------------------
2256 2292
2257 2293 def init_magics(self):
2258 2294 from IPython.core import magics as m
2259 2295 self.magics_manager = magic.MagicsManager(shell=self,
2260 2296 parent=self,
2261 2297 user_magics=m.UserMagics(self))
2262 2298 self.configurables.append(self.magics_manager)
2263 2299
2264 2300 # Expose as public API from the magics manager
2265 2301 self.register_magics = self.magics_manager.register
2266 2302
2267 2303 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2268 2304 m.ConfigMagics, m.DisplayMagics, m.ExecutionMagics,
2269 2305 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2270 2306 m.NamespaceMagics, m.OSMagics, m.PackagingMagics,
2271 2307 m.PylabMagics, m.ScriptMagics,
2272 2308 )
2273 2309 self.register_magics(m.AsyncMagics)
2274 2310
2275 2311 # Register Magic Aliases
2276 2312 mman = self.magics_manager
2277 2313 # FIXME: magic aliases should be defined by the Magics classes
2278 2314 # or in MagicsManager, not here
2279 2315 mman.register_alias('ed', 'edit')
2280 2316 mman.register_alias('hist', 'history')
2281 2317 mman.register_alias('rep', 'recall')
2282 2318 mman.register_alias('SVG', 'svg', 'cell')
2283 2319 mman.register_alias('HTML', 'html', 'cell')
2284 2320 mman.register_alias('file', 'writefile', 'cell')
2285 2321
2286 2322 # FIXME: Move the color initialization to the DisplayHook, which
2287 2323 # should be split into a prompt manager and displayhook. We probably
2288 2324 # even need a centralize colors management object.
2289 2325 self.run_line_magic('colors', self.colors)
2290 2326
2291 2327 # Defined here so that it's included in the documentation
2292 2328 @functools.wraps(magic.MagicsManager.register_function)
2293 2329 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2294 2330 self.magics_manager.register_function(
2295 2331 func, magic_kind=magic_kind, magic_name=magic_name
2296 2332 )
2297 2333
2298 2334 def _find_with_lazy_load(self, /, type_, magic_name: str):
2299 2335 """
2300 2336 Try to find a magic potentially lazy-loading it.
2301 2337
2302 2338 Parameters
2303 2339 ----------
2304 2340
2305 2341 type_: "line"|"cell"
2306 2342 the type of magics we are trying to find/lazy load.
2307 2343 magic_name: str
2308 2344 The name of the magic we are trying to find/lazy load
2309 2345
2310 2346
2311 2347 Note that this may have any side effects
2312 2348 """
2313 2349 finder = {"line": self.find_line_magic, "cell": self.find_cell_magic}[type_]
2314 2350 fn = finder(magic_name)
2315 2351 if fn is not None:
2316 2352 return fn
2317 2353 lazy = self.magics_manager.lazy_magics.get(magic_name)
2318 2354 if lazy is None:
2319 2355 return None
2320 2356
2321 2357 self.run_line_magic("load_ext", lazy)
2322 2358 res = finder(magic_name)
2323 2359 return res
2324 2360
2325 2361 def run_line_magic(self, magic_name: str, line, _stack_depth=1):
2326 2362 """Execute the given line magic.
2327 2363
2328 2364 Parameters
2329 2365 ----------
2330 2366 magic_name : str
2331 2367 Name of the desired magic function, without '%' prefix.
2332 2368 line : str
2333 2369 The rest of the input line as a single string.
2334 2370 _stack_depth : int
2335 2371 If run_line_magic() is called from magic() then _stack_depth=2.
2336 2372 This is added to ensure backward compatibility for use of 'get_ipython().magic()'
2337 2373 """
2338 2374 fn = self._find_with_lazy_load("line", magic_name)
2339 2375 if fn is None:
2340 2376 lazy = self.magics_manager.lazy_magics.get(magic_name)
2341 2377 if lazy:
2342 2378 self.run_line_magic("load_ext", lazy)
2343 2379 fn = self.find_line_magic(magic_name)
2344 2380 if fn is None:
2345 2381 cm = self.find_cell_magic(magic_name)
2346 2382 etpl = "Line magic function `%%%s` not found%s."
2347 2383 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2348 2384 'did you mean that instead?)' % magic_name )
2349 2385 raise UsageError(etpl % (magic_name, extra))
2350 2386 else:
2351 2387 # Note: this is the distance in the stack to the user's frame.
2352 2388 # This will need to be updated if the internal calling logic gets
2353 2389 # refactored, or else we'll be expanding the wrong variables.
2354 2390
2355 2391 # Determine stack_depth depending on where run_line_magic() has been called
2356 2392 stack_depth = _stack_depth
2357 2393 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2358 2394 # magic has opted out of var_expand
2359 2395 magic_arg_s = line
2360 2396 else:
2361 2397 magic_arg_s = self.var_expand(line, stack_depth)
2362 2398 # Put magic args in a list so we can call with f(*a) syntax
2363 2399 args = [magic_arg_s]
2364 2400 kwargs = {}
2365 2401 # Grab local namespace if we need it:
2366 2402 if getattr(fn, "needs_local_scope", False):
2367 2403 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2368 2404 with self.builtin_trap:
2369 2405 result = fn(*args, **kwargs)
2370 2406
2371 2407 # The code below prevents the output from being displayed
2372 2408 # when using magics with decodator @output_can_be_silenced
2373 2409 # when the last Python token in the expression is a ';'.
2374 2410 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):
2375 2411 if DisplayHook.semicolon_at_end_of_expression(magic_arg_s):
2376 2412 return None
2377 2413
2378 2414 return result
2379 2415
2380 2416 def get_local_scope(self, stack_depth):
2381 2417 """Get local scope at given stack depth.
2382 2418
2383 2419 Parameters
2384 2420 ----------
2385 2421 stack_depth : int
2386 2422 Depth relative to calling frame
2387 2423 """
2388 2424 return sys._getframe(stack_depth + 1).f_locals
2389 2425
2390 2426 def run_cell_magic(self, magic_name, line, cell):
2391 2427 """Execute the given cell magic.
2392 2428
2393 2429 Parameters
2394 2430 ----------
2395 2431 magic_name : str
2396 2432 Name of the desired magic function, without '%' prefix.
2397 2433 line : str
2398 2434 The rest of the first input line as a single string.
2399 2435 cell : str
2400 2436 The body of the cell as a (possibly multiline) string.
2401 2437 """
2402 2438 fn = self._find_with_lazy_load("cell", magic_name)
2403 2439 if fn is None:
2404 2440 lm = self.find_line_magic(magic_name)
2405 2441 etpl = "Cell magic `%%{0}` not found{1}."
2406 2442 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2407 2443 'did you mean that instead?)'.format(magic_name))
2408 2444 raise UsageError(etpl.format(magic_name, extra))
2409 2445 elif cell == '':
2410 2446 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2411 2447 if self.find_line_magic(magic_name) is not None:
2412 2448 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2413 2449 raise UsageError(message)
2414 2450 else:
2415 2451 # Note: this is the distance in the stack to the user's frame.
2416 2452 # This will need to be updated if the internal calling logic gets
2417 2453 # refactored, or else we'll be expanding the wrong variables.
2418 2454 stack_depth = 2
2419 2455 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2420 2456 # magic has opted out of var_expand
2421 2457 magic_arg_s = line
2422 2458 else:
2423 2459 magic_arg_s = self.var_expand(line, stack_depth)
2424 2460 kwargs = {}
2425 2461 if getattr(fn, "needs_local_scope", False):
2426 2462 kwargs['local_ns'] = self.user_ns
2427 2463
2428 2464 with self.builtin_trap:
2429 2465 args = (magic_arg_s, cell)
2430 2466 result = fn(*args, **kwargs)
2431 2467
2432 2468 # The code below prevents the output from being displayed
2433 2469 # when using magics with decodator @output_can_be_silenced
2434 2470 # when the last Python token in the expression is a ';'.
2435 2471 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):
2436 2472 if DisplayHook.semicolon_at_end_of_expression(cell):
2437 2473 return None
2438 2474
2439 2475 return result
2440 2476
2441 2477 def find_line_magic(self, magic_name):
2442 2478 """Find and return a line magic by name.
2443 2479
2444 2480 Returns None if the magic isn't found."""
2445 2481 return self.magics_manager.magics['line'].get(magic_name)
2446 2482
2447 2483 def find_cell_magic(self, magic_name):
2448 2484 """Find and return a cell magic by name.
2449 2485
2450 2486 Returns None if the magic isn't found."""
2451 2487 return self.magics_manager.magics['cell'].get(magic_name)
2452 2488
2453 2489 def find_magic(self, magic_name, magic_kind='line'):
2454 2490 """Find and return a magic of the given type by name.
2455 2491
2456 2492 Returns None if the magic isn't found."""
2457 2493 return self.magics_manager.magics[magic_kind].get(magic_name)
2458 2494
2459 2495 def magic(self, arg_s):
2460 2496 """
2461 2497 DEPRECATED
2462 2498
2463 2499 Deprecated since IPython 0.13 (warning added in
2464 2500 8.1), use run_line_magic(magic_name, parameter_s).
2465 2501
2466 2502 Call a magic function by name.
2467 2503
2468 2504 Input: a string containing the name of the magic function to call and
2469 2505 any additional arguments to be passed to the magic.
2470 2506
2471 2507 magic('name -opt foo bar') is equivalent to typing at the ipython
2472 2508 prompt:
2473 2509
2474 2510 In[1]: %name -opt foo bar
2475 2511
2476 2512 To call a magic without arguments, simply use magic('name').
2477 2513
2478 2514 This provides a proper Python function to call IPython's magics in any
2479 2515 valid Python code you can type at the interpreter, including loops and
2480 2516 compound statements.
2481 2517 """
2482 2518 warnings.warn(
2483 2519 "`magic(...)` is deprecated since IPython 0.13 (warning added in "
2484 2520 "8.1), use run_line_magic(magic_name, parameter_s).",
2485 2521 DeprecationWarning,
2486 2522 stacklevel=2,
2487 2523 )
2488 2524 # TODO: should we issue a loud deprecation warning here?
2489 2525 magic_name, _, magic_arg_s = arg_s.partition(' ')
2490 2526 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2491 2527 return self.run_line_magic(magic_name, magic_arg_s, _stack_depth=2)
2492 2528
2493 2529 #-------------------------------------------------------------------------
2494 2530 # Things related to macros
2495 2531 #-------------------------------------------------------------------------
2496 2532
2497 2533 def define_macro(self, name, themacro):
2498 2534 """Define a new macro
2499 2535
2500 2536 Parameters
2501 2537 ----------
2502 2538 name : str
2503 2539 The name of the macro.
2504 2540 themacro : str or Macro
2505 2541 The action to do upon invoking the macro. If a string, a new
2506 2542 Macro object is created by passing the string to it.
2507 2543 """
2508 2544
2509 2545 from IPython.core import macro
2510 2546
2511 2547 if isinstance(themacro, str):
2512 2548 themacro = macro.Macro(themacro)
2513 2549 if not isinstance(themacro, macro.Macro):
2514 2550 raise ValueError('A macro must be a string or a Macro instance.')
2515 2551 self.user_ns[name] = themacro
2516 2552
2517 2553 #-------------------------------------------------------------------------
2518 2554 # Things related to the running of system commands
2519 2555 #-------------------------------------------------------------------------
2520 2556
2521 2557 def system_piped(self, cmd):
2522 2558 """Call the given cmd in a subprocess, piping stdout/err
2523 2559
2524 2560 Parameters
2525 2561 ----------
2526 2562 cmd : str
2527 2563 Command to execute (can not end in '&', as background processes are
2528 2564 not supported. Should not be a command that expects input
2529 2565 other than simple text.
2530 2566 """
2531 2567 if cmd.rstrip().endswith('&'):
2532 2568 # this is *far* from a rigorous test
2533 2569 # We do not support backgrounding processes because we either use
2534 2570 # pexpect or pipes to read from. Users can always just call
2535 2571 # os.system() or use ip.system=ip.system_raw
2536 2572 # if they really want a background process.
2537 2573 raise OSError("Background processes not supported.")
2538 2574
2539 2575 # we explicitly do NOT return the subprocess status code, because
2540 2576 # a non-None value would trigger :func:`sys.displayhook` calls.
2541 2577 # Instead, we store the exit_code in user_ns.
2542 2578 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2543 2579
2544 2580 def system_raw(self, cmd):
2545 2581 """Call the given cmd in a subprocess using os.system on Windows or
2546 2582 subprocess.call using the system shell on other platforms.
2547 2583
2548 2584 Parameters
2549 2585 ----------
2550 2586 cmd : str
2551 2587 Command to execute.
2552 2588 """
2553 2589 cmd = self.var_expand(cmd, depth=1)
2554 2590 # warn if there is an IPython magic alternative.
2555 2591 main_cmd = cmd.split()[0]
2556 2592 has_magic_alternatives = ("pip", "conda", "cd")
2557 2593
2558 2594 if main_cmd in has_magic_alternatives:
2559 2595 warnings.warn(
2560 2596 (
2561 2597 "You executed the system command !{0} which may not work "
2562 2598 "as expected. Try the IPython magic %{0} instead."
2563 2599 ).format(main_cmd)
2564 2600 )
2565 2601
2566 2602 # protect os.system from UNC paths on Windows, which it can't handle:
2567 2603 if sys.platform == 'win32':
2568 2604 from IPython.utils._process_win32 import AvoidUNCPath
2569 2605 with AvoidUNCPath() as path:
2570 2606 if path is not None:
2571 2607 cmd = '"pushd %s &&"%s' % (path, cmd)
2572 2608 try:
2573 2609 ec = os.system(cmd)
2574 2610 except KeyboardInterrupt:
2575 2611 print('\n' + self.get_exception_only(), file=sys.stderr)
2576 2612 ec = -2
2577 2613 else:
2578 2614 # For posix the result of the subprocess.call() below is an exit
2579 2615 # code, which by convention is zero for success, positive for
2580 2616 # program failure. Exit codes above 128 are reserved for signals,
2581 2617 # and the formula for converting a signal to an exit code is usually
2582 2618 # signal_number+128. To more easily differentiate between exit
2583 2619 # codes and signals, ipython uses negative numbers. For instance
2584 2620 # since control-c is signal 2 but exit code 130, ipython's
2585 2621 # _exit_code variable will read -2. Note that some shells like
2586 2622 # csh and fish don't follow sh/bash conventions for exit codes.
2587 2623 executable = os.environ.get('SHELL', None)
2588 2624 try:
2589 2625 # Use env shell instead of default /bin/sh
2590 2626 ec = subprocess.call(cmd, shell=True, executable=executable)
2591 2627 except KeyboardInterrupt:
2592 2628 # intercept control-C; a long traceback is not useful here
2593 2629 print('\n' + self.get_exception_only(), file=sys.stderr)
2594 2630 ec = 130
2595 2631 if ec > 128:
2596 2632 ec = -(ec - 128)
2597 2633
2598 2634 # We explicitly do NOT return the subprocess status code, because
2599 2635 # a non-None value would trigger :func:`sys.displayhook` calls.
2600 2636 # Instead, we store the exit_code in user_ns. Note the semantics
2601 2637 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2602 2638 # but raising SystemExit(_exit_code) will give status 254!
2603 2639 self.user_ns['_exit_code'] = ec
2604 2640
2605 2641 # use piped system by default, because it is better behaved
2606 2642 system = system_piped
2607 2643
2608 2644 def getoutput(self, cmd, split=True, depth=0):
2609 2645 """Get output (possibly including stderr) from a subprocess.
2610 2646
2611 2647 Parameters
2612 2648 ----------
2613 2649 cmd : str
2614 2650 Command to execute (can not end in '&', as background processes are
2615 2651 not supported.
2616 2652 split : bool, optional
2617 2653 If True, split the output into an IPython SList. Otherwise, an
2618 2654 IPython LSString is returned. These are objects similar to normal
2619 2655 lists and strings, with a few convenience attributes for easier
2620 2656 manipulation of line-based output. You can use '?' on them for
2621 2657 details.
2622 2658 depth : int, optional
2623 2659 How many frames above the caller are the local variables which should
2624 2660 be expanded in the command string? The default (0) assumes that the
2625 2661 expansion variables are in the stack frame calling this function.
2626 2662 """
2627 2663 if cmd.rstrip().endswith('&'):
2628 2664 # this is *far* from a rigorous test
2629 2665 raise OSError("Background processes not supported.")
2630 2666 out = getoutput(self.var_expand(cmd, depth=depth+1))
2631 2667 if split:
2632 2668 out = SList(out.splitlines())
2633 2669 else:
2634 2670 out = LSString(out)
2635 2671 return out
2636 2672
2637 2673 #-------------------------------------------------------------------------
2638 2674 # Things related to aliases
2639 2675 #-------------------------------------------------------------------------
2640 2676
2641 2677 def init_alias(self):
2642 2678 self.alias_manager = AliasManager(shell=self, parent=self)
2643 2679 self.configurables.append(self.alias_manager)
2644 2680
2645 2681 #-------------------------------------------------------------------------
2646 2682 # Things related to extensions
2647 2683 #-------------------------------------------------------------------------
2648 2684
2649 2685 def init_extension_manager(self):
2650 2686 self.extension_manager = ExtensionManager(shell=self, parent=self)
2651 2687 self.configurables.append(self.extension_manager)
2652 2688
2653 2689 #-------------------------------------------------------------------------
2654 2690 # Things related to payloads
2655 2691 #-------------------------------------------------------------------------
2656 2692
2657 2693 def init_payload(self):
2658 2694 self.payload_manager = PayloadManager(parent=self)
2659 2695 self.configurables.append(self.payload_manager)
2660 2696
2661 2697 #-------------------------------------------------------------------------
2662 2698 # Things related to the prefilter
2663 2699 #-------------------------------------------------------------------------
2664 2700
2665 2701 def init_prefilter(self):
2666 2702 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2667 2703 self.configurables.append(self.prefilter_manager)
2668 2704 # Ultimately this will be refactored in the new interpreter code, but
2669 2705 # for now, we should expose the main prefilter method (there's legacy
2670 2706 # code out there that may rely on this).
2671 2707 self.prefilter = self.prefilter_manager.prefilter_lines
2672 2708
2673 2709 def auto_rewrite_input(self, cmd):
2674 2710 """Print to the screen the rewritten form of the user's command.
2675 2711
2676 2712 This shows visual feedback by rewriting input lines that cause
2677 2713 automatic calling to kick in, like::
2678 2714
2679 2715 /f x
2680 2716
2681 2717 into::
2682 2718
2683 2719 ------> f(x)
2684 2720
2685 2721 after the user's input prompt. This helps the user understand that the
2686 2722 input line was transformed automatically by IPython.
2687 2723 """
2688 2724 if not self.show_rewritten_input:
2689 2725 return
2690 2726
2691 2727 # This is overridden in TerminalInteractiveShell to use fancy prompts
2692 2728 print("------> " + cmd)
2693 2729
2694 2730 #-------------------------------------------------------------------------
2695 2731 # Things related to extracting values/expressions from kernel and user_ns
2696 2732 #-------------------------------------------------------------------------
2697 2733
2698 2734 def _user_obj_error(self):
2699 2735 """return simple exception dict
2700 2736
2701 2737 for use in user_expressions
2702 2738 """
2703 2739
2704 2740 etype, evalue, tb = self._get_exc_info()
2705 2741 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2706 2742
2707 2743 exc_info = {
2708 2744 "status": "error",
2709 2745 "traceback": stb,
2710 2746 "ename": etype.__name__,
2711 2747 "evalue": py3compat.safe_unicode(evalue),
2712 2748 }
2713 2749
2714 2750 return exc_info
2715 2751
2716 2752 def _format_user_obj(self, obj):
2717 2753 """format a user object to display dict
2718 2754
2719 2755 for use in user_expressions
2720 2756 """
2721 2757
2722 2758 data, md = self.display_formatter.format(obj)
2723 2759 value = {
2724 2760 'status' : 'ok',
2725 2761 'data' : data,
2726 2762 'metadata' : md,
2727 2763 }
2728 2764 return value
2729 2765
2730 2766 def user_expressions(self, expressions):
2731 2767 """Evaluate a dict of expressions in the user's namespace.
2732 2768
2733 2769 Parameters
2734 2770 ----------
2735 2771 expressions : dict
2736 2772 A dict with string keys and string values. The expression values
2737 2773 should be valid Python expressions, each of which will be evaluated
2738 2774 in the user namespace.
2739 2775
2740 2776 Returns
2741 2777 -------
2742 2778 A dict, keyed like the input expressions dict, with the rich mime-typed
2743 2779 display_data of each value.
2744 2780 """
2745 2781 out = {}
2746 2782 user_ns = self.user_ns
2747 2783 global_ns = self.user_global_ns
2748 2784
2749 2785 for key, expr in expressions.items():
2750 2786 try:
2751 2787 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2752 2788 except:
2753 2789 value = self._user_obj_error()
2754 2790 out[key] = value
2755 2791 return out
2756 2792
2757 2793 #-------------------------------------------------------------------------
2758 2794 # Things related to the running of code
2759 2795 #-------------------------------------------------------------------------
2760 2796
2761 2797 def ex(self, cmd):
2762 2798 """Execute a normal python statement in user namespace."""
2763 2799 with self.builtin_trap:
2764 2800 exec(cmd, self.user_global_ns, self.user_ns)
2765 2801
2766 2802 def ev(self, expr):
2767 2803 """Evaluate python expression expr in user namespace.
2768 2804
2769 2805 Returns the result of evaluation
2770 2806 """
2771 2807 with self.builtin_trap:
2772 2808 return eval(expr, self.user_global_ns, self.user_ns)
2773 2809
2774 2810 def safe_execfile(self, fname, *where, exit_ignore=False, raise_exceptions=False, shell_futures=False):
2775 2811 """A safe version of the builtin execfile().
2776 2812
2777 2813 This version will never throw an exception, but instead print
2778 2814 helpful error messages to the screen. This only works on pure
2779 2815 Python files with the .py extension.
2780 2816
2781 2817 Parameters
2782 2818 ----------
2783 2819 fname : string
2784 2820 The name of the file to be executed.
2785 2821 *where : tuple
2786 2822 One or two namespaces, passed to execfile() as (globals,locals).
2787 2823 If only one is given, it is passed as both.
2788 2824 exit_ignore : bool (False)
2789 2825 If True, then silence SystemExit for non-zero status (it is always
2790 2826 silenced for zero status, as it is so common).
2791 2827 raise_exceptions : bool (False)
2792 2828 If True raise exceptions everywhere. Meant for testing.
2793 2829 shell_futures : bool (False)
2794 2830 If True, the code will share future statements with the interactive
2795 2831 shell. It will both be affected by previous __future__ imports, and
2796 2832 any __future__ imports in the code will affect the shell. If False,
2797 2833 __future__ imports are not shared in either direction.
2798 2834
2799 2835 """
2800 2836 fname = Path(fname).expanduser().resolve()
2801 2837
2802 2838 # Make sure we can open the file
2803 2839 try:
2804 2840 with fname.open("rb"):
2805 2841 pass
2806 2842 except:
2807 2843 warn('Could not open file <%s> for safe execution.' % fname)
2808 2844 return
2809 2845
2810 2846 # Find things also in current directory. This is needed to mimic the
2811 2847 # behavior of running a script from the system command line, where
2812 2848 # Python inserts the script's directory into sys.path
2813 2849 dname = str(fname.parent)
2814 2850
2815 2851 with prepended_to_syspath(dname), self.builtin_trap:
2816 2852 try:
2817 2853 glob, loc = (where + (None, ))[:2]
2818 2854 py3compat.execfile(
2819 2855 fname, glob, loc,
2820 2856 self.compile if shell_futures else None)
2821 2857 except SystemExit as status:
2822 2858 # If the call was made with 0 or None exit status (sys.exit(0)
2823 2859 # or sys.exit() ), don't bother showing a traceback, as both of
2824 2860 # these are considered normal by the OS:
2825 2861 # > python -c'import sys;sys.exit(0)'; echo $?
2826 2862 # 0
2827 2863 # > python -c'import sys;sys.exit()'; echo $?
2828 2864 # 0
2829 2865 # For other exit status, we show the exception unless
2830 2866 # explicitly silenced, but only in short form.
2831 2867 if status.code:
2832 2868 if raise_exceptions:
2833 2869 raise
2834 2870 if not exit_ignore:
2835 2871 self.showtraceback(exception_only=True)
2836 2872 except:
2837 2873 if raise_exceptions:
2838 2874 raise
2839 2875 # tb offset is 2 because we wrap execfile
2840 2876 self.showtraceback(tb_offset=2)
2841 2877
2842 2878 def safe_execfile_ipy(self, fname, shell_futures=False, raise_exceptions=False):
2843 2879 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2844 2880
2845 2881 Parameters
2846 2882 ----------
2847 2883 fname : str
2848 2884 The name of the file to execute. The filename must have a
2849 2885 .ipy or .ipynb extension.
2850 2886 shell_futures : bool (False)
2851 2887 If True, the code will share future statements with the interactive
2852 2888 shell. It will both be affected by previous __future__ imports, and
2853 2889 any __future__ imports in the code will affect the shell. If False,
2854 2890 __future__ imports are not shared in either direction.
2855 2891 raise_exceptions : bool (False)
2856 2892 If True raise exceptions everywhere. Meant for testing.
2857 2893 """
2858 2894 fname = Path(fname).expanduser().resolve()
2859 2895
2860 2896 # Make sure we can open the file
2861 2897 try:
2862 2898 with fname.open("rb"):
2863 2899 pass
2864 2900 except:
2865 2901 warn('Could not open file <%s> for safe execution.' % fname)
2866 2902 return
2867 2903
2868 2904 # Find things also in current directory. This is needed to mimic the
2869 2905 # behavior of running a script from the system command line, where
2870 2906 # Python inserts the script's directory into sys.path
2871 2907 dname = str(fname.parent)
2872 2908
2873 2909 def get_cells():
2874 2910 """generator for sequence of code blocks to run"""
2875 2911 if fname.suffix == ".ipynb":
2876 2912 from nbformat import read
2877 2913 nb = read(fname, as_version=4)
2878 2914 if not nb.cells:
2879 2915 return
2880 2916 for cell in nb.cells:
2881 2917 if cell.cell_type == 'code':
2882 2918 yield cell.source
2883 2919 else:
2884 2920 yield fname.read_text(encoding="utf-8")
2885 2921
2886 2922 with prepended_to_syspath(dname):
2887 2923 try:
2888 2924 for cell in get_cells():
2889 2925 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2890 2926 if raise_exceptions:
2891 2927 result.raise_error()
2892 2928 elif not result.success:
2893 2929 break
2894 2930 except:
2895 2931 if raise_exceptions:
2896 2932 raise
2897 2933 self.showtraceback()
2898 2934 warn('Unknown failure executing file: <%s>' % fname)
2899 2935
2900 2936 def safe_run_module(self, mod_name, where):
2901 2937 """A safe version of runpy.run_module().
2902 2938
2903 2939 This version will never throw an exception, but instead print
2904 2940 helpful error messages to the screen.
2905 2941
2906 2942 `SystemExit` exceptions with status code 0 or None are ignored.
2907 2943
2908 2944 Parameters
2909 2945 ----------
2910 2946 mod_name : string
2911 2947 The name of the module to be executed.
2912 2948 where : dict
2913 2949 The globals namespace.
2914 2950 """
2915 2951 try:
2916 2952 try:
2917 2953 where.update(
2918 2954 runpy.run_module(str(mod_name), run_name="__main__",
2919 2955 alter_sys=True)
2920 2956 )
2921 2957 except SystemExit as status:
2922 2958 if status.code:
2923 2959 raise
2924 2960 except:
2925 2961 self.showtraceback()
2926 2962 warn('Unknown failure executing module: <%s>' % mod_name)
2927 2963
2928 2964 def run_cell(
2929 2965 self,
2930 2966 raw_cell,
2931 2967 store_history=False,
2932 2968 silent=False,
2933 2969 shell_futures=True,
2934 2970 cell_id=None,
2935 2971 ):
2936 2972 """Run a complete IPython cell.
2937 2973
2938 2974 Parameters
2939 2975 ----------
2940 2976 raw_cell : str
2941 2977 The code (including IPython code such as %magic functions) to run.
2942 2978 store_history : bool
2943 2979 If True, the raw and translated cell will be stored in IPython's
2944 2980 history. For user code calling back into IPython's machinery, this
2945 2981 should be set to False.
2946 2982 silent : bool
2947 2983 If True, avoid side-effects, such as implicit displayhooks and
2948 2984 and logging. silent=True forces store_history=False.
2949 2985 shell_futures : bool
2950 2986 If True, the code will share future statements with the interactive
2951 2987 shell. It will both be affected by previous __future__ imports, and
2952 2988 any __future__ imports in the code will affect the shell. If False,
2953 2989 __future__ imports are not shared in either direction.
2954 2990
2955 2991 Returns
2956 2992 -------
2957 2993 result : :class:`ExecutionResult`
2958 2994 """
2959 2995 result = None
2960 2996 try:
2961 2997 result = self._run_cell(
2962 2998 raw_cell, store_history, silent, shell_futures, cell_id
2963 2999 )
2964 3000 finally:
2965 3001 self.events.trigger('post_execute')
2966 3002 if not silent:
2967 3003 self.events.trigger('post_run_cell', result)
2968 3004 return result
2969 3005
2970 3006 def _run_cell(
2971 3007 self,
2972 3008 raw_cell: str,
2973 3009 store_history: bool,
2974 3010 silent: bool,
2975 3011 shell_futures: bool,
2976 3012 cell_id: str,
2977 3013 ) -> ExecutionResult:
2978 3014 """Internal method to run a complete IPython cell."""
2979 3015
2980 3016 # we need to avoid calling self.transform_cell multiple time on the same thing
2981 3017 # so we need to store some results:
2982 3018 preprocessing_exc_tuple = None
2983 3019 try:
2984 3020 transformed_cell = self.transform_cell(raw_cell)
2985 3021 except Exception:
2986 3022 transformed_cell = raw_cell
2987 3023 preprocessing_exc_tuple = sys.exc_info()
2988 3024
2989 3025 assert transformed_cell is not None
2990 3026 coro = self.run_cell_async(
2991 3027 raw_cell,
2992 3028 store_history=store_history,
2993 3029 silent=silent,
2994 3030 shell_futures=shell_futures,
2995 3031 transformed_cell=transformed_cell,
2996 3032 preprocessing_exc_tuple=preprocessing_exc_tuple,
2997 3033 cell_id=cell_id,
2998 3034 )
2999 3035
3000 3036 # run_cell_async is async, but may not actually need an eventloop.
3001 3037 # when this is the case, we want to run it using the pseudo_sync_runner
3002 3038 # so that code can invoke eventloops (for example via the %run , and
3003 3039 # `%paste` magic.
3004 3040 if self.trio_runner:
3005 3041 runner = self.trio_runner
3006 3042 elif self.should_run_async(
3007 3043 raw_cell,
3008 3044 transformed_cell=transformed_cell,
3009 3045 preprocessing_exc_tuple=preprocessing_exc_tuple,
3010 3046 ):
3011 3047 runner = self.loop_runner
3012 3048 else:
3013 3049 runner = _pseudo_sync_runner
3014 3050
3015 3051 try:
3016 3052 result = runner(coro)
3017 3053 except BaseException as e:
3018 3054 info = ExecutionInfo(
3019 3055 raw_cell, store_history, silent, shell_futures, cell_id
3020 3056 )
3021 3057 result = ExecutionResult(info)
3022 3058 result.error_in_exec = e
3023 3059 self.showtraceback(running_compiled_code=True)
3024 3060 finally:
3025 3061 return result
3026 3062
3027 3063 def should_run_async(
3028 3064 self, raw_cell: str, *, transformed_cell=None, preprocessing_exc_tuple=None
3029 3065 ) -> bool:
3030 3066 """Return whether a cell should be run asynchronously via a coroutine runner
3031 3067
3032 3068 Parameters
3033 3069 ----------
3034 3070 raw_cell : str
3035 3071 The code to be executed
3036 3072
3037 3073 Returns
3038 3074 -------
3039 3075 result: bool
3040 3076 Whether the code needs to be run with a coroutine runner or not
3041 3077 .. versionadded:: 7.0
3042 3078 """
3043 3079 if not self.autoawait:
3044 3080 return False
3045 3081 if preprocessing_exc_tuple is not None:
3046 3082 return False
3047 3083 assert preprocessing_exc_tuple is None
3048 3084 if transformed_cell is None:
3049 3085 warnings.warn(
3050 3086 "`should_run_async` will not call `transform_cell`"
3051 3087 " automatically in the future. Please pass the result to"
3052 3088 " `transformed_cell` argument and any exception that happen"
3053 3089 " during the"
3054 3090 "transform in `preprocessing_exc_tuple` in"
3055 3091 " IPython 7.17 and above.",
3056 3092 DeprecationWarning,
3057 3093 stacklevel=2,
3058 3094 )
3059 3095 try:
3060 3096 cell = self.transform_cell(raw_cell)
3061 3097 except Exception:
3062 3098 # any exception during transform will be raised
3063 3099 # prior to execution
3064 3100 return False
3065 3101 else:
3066 3102 cell = transformed_cell
3067 3103 return _should_be_async(cell)
3068 3104
3069 3105 async def run_cell_async(
3070 3106 self,
3071 3107 raw_cell: str,
3072 3108 store_history=False,
3073 3109 silent=False,
3074 3110 shell_futures=True,
3075 3111 *,
3076 3112 transformed_cell: Optional[str] = None,
3077 3113 preprocessing_exc_tuple: Optional[Any] = None,
3078 3114 cell_id=None,
3079 3115 ) -> ExecutionResult:
3080 3116 """Run a complete IPython cell asynchronously.
3081 3117
3082 3118 Parameters
3083 3119 ----------
3084 3120 raw_cell : str
3085 3121 The code (including IPython code such as %magic functions) to run.
3086 3122 store_history : bool
3087 3123 If True, the raw and translated cell will be stored in IPython's
3088 3124 history. For user code calling back into IPython's machinery, this
3089 3125 should be set to False.
3090 3126 silent : bool
3091 3127 If True, avoid side-effects, such as implicit displayhooks and
3092 3128 and logging. silent=True forces store_history=False.
3093 3129 shell_futures : bool
3094 3130 If True, the code will share future statements with the interactive
3095 3131 shell. It will both be affected by previous __future__ imports, and
3096 3132 any __future__ imports in the code will affect the shell. If False,
3097 3133 __future__ imports are not shared in either direction.
3098 3134 transformed_cell: str
3099 3135 cell that was passed through transformers
3100 3136 preprocessing_exc_tuple:
3101 3137 trace if the transformation failed.
3102 3138
3103 3139 Returns
3104 3140 -------
3105 3141 result : :class:`ExecutionResult`
3106 3142
3107 3143 .. versionadded:: 7.0
3108 3144 """
3109 3145 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures, cell_id)
3110 3146 result = ExecutionResult(info)
3111 3147
3112 3148 if (not raw_cell) or raw_cell.isspace():
3113 3149 self.last_execution_succeeded = True
3114 3150 self.last_execution_result = result
3115 3151 return result
3116 3152
3117 3153 if silent:
3118 3154 store_history = False
3119 3155
3120 3156 if store_history:
3121 3157 result.execution_count = self.execution_count
3122 3158
3123 3159 def error_before_exec(value):
3124 3160 if store_history:
3125 3161 self.execution_count += 1
3126 3162 result.error_before_exec = value
3127 3163 self.last_execution_succeeded = False
3128 3164 self.last_execution_result = result
3129 3165 return result
3130 3166
3131 3167 self.events.trigger('pre_execute')
3132 3168 if not silent:
3133 3169 self.events.trigger('pre_run_cell', info)
3134 3170
3135 3171 if transformed_cell is None:
3136 3172 warnings.warn(
3137 3173 "`run_cell_async` will not call `transform_cell`"
3138 3174 " automatically in the future. Please pass the result to"
3139 3175 " `transformed_cell` argument and any exception that happen"
3140 3176 " during the"
3141 3177 "transform in `preprocessing_exc_tuple` in"
3142 3178 " IPython 7.17 and above.",
3143 3179 DeprecationWarning,
3144 3180 stacklevel=2,
3145 3181 )
3146 3182 # If any of our input transformation (input_transformer_manager or
3147 3183 # prefilter_manager) raises an exception, we store it in this variable
3148 3184 # so that we can display the error after logging the input and storing
3149 3185 # it in the history.
3150 3186 try:
3151 3187 cell = self.transform_cell(raw_cell)
3152 3188 except Exception:
3153 3189 preprocessing_exc_tuple = sys.exc_info()
3154 3190 cell = raw_cell # cell has to exist so it can be stored/logged
3155 3191 else:
3156 3192 preprocessing_exc_tuple = None
3157 3193 else:
3158 3194 if preprocessing_exc_tuple is None:
3159 3195 cell = transformed_cell
3160 3196 else:
3161 3197 cell = raw_cell
3162 3198
3163 3199 # Do NOT store paste/cpaste magic history
3164 3200 if "get_ipython().run_line_magic(" in cell and "paste" in cell:
3165 3201 store_history = False
3166 3202
3167 3203 # Store raw and processed history
3168 3204 if store_history:
3169 3205 self.history_manager.store_inputs(self.execution_count, cell, raw_cell)
3170 3206 if not silent:
3171 3207 self.logger.log(cell, raw_cell)
3172 3208
3173 3209 # Display the exception if input processing failed.
3174 3210 if preprocessing_exc_tuple is not None:
3175 3211 self.showtraceback(preprocessing_exc_tuple)
3176 3212 if store_history:
3177 3213 self.execution_count += 1
3178 3214 return error_before_exec(preprocessing_exc_tuple[1])
3179 3215
3180 3216 # Our own compiler remembers the __future__ environment. If we want to
3181 3217 # run code with a separate __future__ environment, use the default
3182 3218 # compiler
3183 3219 compiler = self.compile if shell_futures else self.compiler_class()
3184 3220
3185 3221 _run_async = False
3186 3222
3187 3223 with self.builtin_trap:
3188 3224 cell_name = compiler.cache(cell, self.execution_count, raw_code=raw_cell)
3189 3225
3190 3226 with self.display_trap:
3191 3227 # Compile to bytecode
3192 3228 try:
3193 3229 code_ast = compiler.ast_parse(cell, filename=cell_name)
3194 3230 except self.custom_exceptions as e:
3195 3231 etype, value, tb = sys.exc_info()
3196 3232 self.CustomTB(etype, value, tb)
3197 3233 return error_before_exec(e)
3198 3234 except IndentationError as e:
3199 3235 self.showindentationerror()
3200 3236 return error_before_exec(e)
3201 3237 except (OverflowError, SyntaxError, ValueError, TypeError,
3202 3238 MemoryError) as e:
3203 3239 self.showsyntaxerror()
3204 3240 return error_before_exec(e)
3205 3241
3206 3242 # Apply AST transformations
3207 3243 try:
3208 3244 code_ast = self.transform_ast(code_ast)
3209 3245 except InputRejected as e:
3210 3246 self.showtraceback()
3211 3247 return error_before_exec(e)
3212 3248
3213 3249 # Give the displayhook a reference to our ExecutionResult so it
3214 3250 # can fill in the output value.
3215 3251 self.displayhook.exec_result = result
3216 3252
3217 3253 # Execute the user code
3218 3254 interactivity = "none" if silent else self.ast_node_interactivity
3219 3255
3220 3256
3221 3257 has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
3222 3258 interactivity=interactivity, compiler=compiler, result=result)
3223 3259
3224 3260 self.last_execution_succeeded = not has_raised
3225 3261 self.last_execution_result = result
3226 3262
3227 3263 # Reset this so later displayed values do not modify the
3228 3264 # ExecutionResult
3229 3265 self.displayhook.exec_result = None
3230 3266
3231 3267 if store_history:
3232 3268 # Write output to the database. Does nothing unless
3233 3269 # history output logging is enabled.
3234 3270 self.history_manager.store_output(self.execution_count)
3235 3271 # Each cell is a *single* input, regardless of how many lines it has
3236 3272 self.execution_count += 1
3237 3273
3238 3274 return result
3239 3275
3240 3276 def transform_cell(self, raw_cell):
3241 3277 """Transform an input cell before parsing it.
3242 3278
3243 3279 Static transformations, implemented in IPython.core.inputtransformer2,
3244 3280 deal with things like ``%magic`` and ``!system`` commands.
3245 3281 These run on all input.
3246 3282 Dynamic transformations, for things like unescaped magics and the exit
3247 3283 autocall, depend on the state of the interpreter.
3248 3284 These only apply to single line inputs.
3249 3285
3250 3286 These string-based transformations are followed by AST transformations;
3251 3287 see :meth:`transform_ast`.
3252 3288 """
3253 3289 # Static input transformations
3254 3290 cell = self.input_transformer_manager.transform_cell(raw_cell)
3255 3291
3256 3292 if len(cell.splitlines()) == 1:
3257 3293 # Dynamic transformations - only applied for single line commands
3258 3294 with self.builtin_trap:
3259 3295 # use prefilter_lines to handle trailing newlines
3260 3296 # restore trailing newline for ast.parse
3261 3297 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
3262 3298
3263 3299 lines = cell.splitlines(keepends=True)
3264 3300 for transform in self.input_transformers_post:
3265 3301 lines = transform(lines)
3266 3302 cell = ''.join(lines)
3267 3303
3268 3304 return cell
3269 3305
3270 3306 def transform_ast(self, node):
3271 3307 """Apply the AST transformations from self.ast_transformers
3272 3308
3273 3309 Parameters
3274 3310 ----------
3275 3311 node : ast.Node
3276 3312 The root node to be transformed. Typically called with the ast.Module
3277 3313 produced by parsing user input.
3278 3314
3279 3315 Returns
3280 3316 -------
3281 3317 An ast.Node corresponding to the node it was called with. Note that it
3282 3318 may also modify the passed object, so don't rely on references to the
3283 3319 original AST.
3284 3320 """
3285 3321 for transformer in self.ast_transformers:
3286 3322 try:
3287 3323 node = transformer.visit(node)
3288 3324 except InputRejected:
3289 3325 # User-supplied AST transformers can reject an input by raising
3290 3326 # an InputRejected. Short-circuit in this case so that we
3291 3327 # don't unregister the transform.
3292 3328 raise
3293 3329 except Exception:
3294 3330 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
3295 3331 self.ast_transformers.remove(transformer)
3296 3332
3297 3333 if self.ast_transformers:
3298 3334 ast.fix_missing_locations(node)
3299 3335 return node
3300 3336
3301 3337 async def run_ast_nodes(
3302 3338 self,
3303 3339 nodelist: ListType[stmt],
3304 3340 cell_name: str,
3305 3341 interactivity="last_expr",
3306 3342 compiler=compile,
3307 3343 result=None,
3308 3344 ):
3309 3345 """Run a sequence of AST nodes. The execution mode depends on the
3310 3346 interactivity parameter.
3311 3347
3312 3348 Parameters
3313 3349 ----------
3314 3350 nodelist : list
3315 3351 A sequence of AST nodes to run.
3316 3352 cell_name : str
3317 3353 Will be passed to the compiler as the filename of the cell. Typically
3318 3354 the value returned by ip.compile.cache(cell).
3319 3355 interactivity : str
3320 3356 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none',
3321 3357 specifying which nodes should be run interactively (displaying output
3322 3358 from expressions). 'last_expr' will run the last node interactively
3323 3359 only if it is an expression (i.e. expressions in loops or other blocks
3324 3360 are not displayed) 'last_expr_or_assign' will run the last expression
3325 3361 or the last assignment. Other values for this parameter will raise a
3326 3362 ValueError.
3327 3363
3328 3364 compiler : callable
3329 3365 A function with the same interface as the built-in compile(), to turn
3330 3366 the AST nodes into code objects. Default is the built-in compile().
3331 3367 result : ExecutionResult, optional
3332 3368 An object to store exceptions that occur during execution.
3333 3369
3334 3370 Returns
3335 3371 -------
3336 3372 True if an exception occurred while running code, False if it finished
3337 3373 running.
3338 3374 """
3339 3375 if not nodelist:
3340 3376 return
3341 3377
3342 3378
3343 3379 if interactivity == 'last_expr_or_assign':
3344 3380 if isinstance(nodelist[-1], _assign_nodes):
3345 3381 asg = nodelist[-1]
3346 3382 if isinstance(asg, ast.Assign) and len(asg.targets) == 1:
3347 3383 target = asg.targets[0]
3348 3384 elif isinstance(asg, _single_targets_nodes):
3349 3385 target = asg.target
3350 3386 else:
3351 3387 target = None
3352 3388 if isinstance(target, ast.Name):
3353 3389 nnode = ast.Expr(ast.Name(target.id, ast.Load()))
3354 3390 ast.fix_missing_locations(nnode)
3355 3391 nodelist.append(nnode)
3356 3392 interactivity = 'last_expr'
3357 3393
3358 3394 _async = False
3359 3395 if interactivity == 'last_expr':
3360 3396 if isinstance(nodelist[-1], ast.Expr):
3361 3397 interactivity = "last"
3362 3398 else:
3363 3399 interactivity = "none"
3364 3400
3365 3401 if interactivity == 'none':
3366 3402 to_run_exec, to_run_interactive = nodelist, []
3367 3403 elif interactivity == 'last':
3368 3404 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
3369 3405 elif interactivity == 'all':
3370 3406 to_run_exec, to_run_interactive = [], nodelist
3371 3407 else:
3372 3408 raise ValueError("Interactivity was %r" % interactivity)
3373 3409
3374 3410 try:
3375 3411
3376 3412 def compare(code):
3377 3413 is_async = inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE
3378 3414 return is_async
3379 3415
3380 3416 # refactor that to just change the mod constructor.
3381 3417 to_run = []
3382 3418 for node in to_run_exec:
3383 3419 to_run.append((node, "exec"))
3384 3420
3385 3421 for node in to_run_interactive:
3386 3422 to_run.append((node, "single"))
3387 3423
3388 3424 for node, mode in to_run:
3389 3425 if mode == "exec":
3390 3426 mod = Module([node], [])
3391 3427 elif mode == "single":
3392 3428 mod = ast.Interactive([node])
3393 3429 with compiler.extra_flags(
3394 3430 getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
3395 3431 if self.autoawait
3396 3432 else 0x0
3397 3433 ):
3398 3434 code = compiler(mod, cell_name, mode)
3399 3435 asy = compare(code)
3400 3436 if await self.run_code(code, result, async_=asy):
3401 3437 return True
3402 3438
3403 3439 # Flush softspace
3404 3440 if softspace(sys.stdout, 0):
3405 3441 print()
3406 3442
3407 3443 except:
3408 3444 # It's possible to have exceptions raised here, typically by
3409 3445 # compilation of odd code (such as a naked 'return' outside a
3410 3446 # function) that did parse but isn't valid. Typically the exception
3411 3447 # is a SyntaxError, but it's safest just to catch anything and show
3412 3448 # the user a traceback.
3413 3449
3414 3450 # We do only one try/except outside the loop to minimize the impact
3415 3451 # on runtime, and also because if any node in the node list is
3416 3452 # broken, we should stop execution completely.
3417 3453 if result:
3418 3454 result.error_before_exec = sys.exc_info()[1]
3419 3455 self.showtraceback()
3420 3456 return True
3421 3457
3422 3458 return False
3423 3459
3424 3460 async def run_code(self, code_obj, result=None, *, async_=False):
3425 3461 """Execute a code object.
3426 3462
3427 3463 When an exception occurs, self.showtraceback() is called to display a
3428 3464 traceback.
3429 3465
3430 3466 Parameters
3431 3467 ----------
3432 3468 code_obj : code object
3433 3469 A compiled code object, to be executed
3434 3470 result : ExecutionResult, optional
3435 3471 An object to store exceptions that occur during execution.
3436 3472 async_ : Bool (Experimental)
3437 3473 Attempt to run top-level asynchronous code in a default loop.
3438 3474
3439 3475 Returns
3440 3476 -------
3441 3477 False : successful execution.
3442 3478 True : an error occurred.
3443 3479 """
3444 3480 # special value to say that anything above is IPython and should be
3445 3481 # hidden.
3446 3482 __tracebackhide__ = "__ipython_bottom__"
3447 3483 # Set our own excepthook in case the user code tries to call it
3448 3484 # directly, so that the IPython crash handler doesn't get triggered
3449 3485 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3450 3486
3451 3487 # we save the original sys.excepthook in the instance, in case config
3452 3488 # code (such as magics) needs access to it.
3453 3489 self.sys_excepthook = old_excepthook
3454 3490 outflag = True # happens in more places, so it's easier as default
3455 3491 try:
3456 3492 try:
3457 3493 if async_:
3458 3494 await eval(code_obj, self.user_global_ns, self.user_ns)
3459 3495 else:
3460 3496 exec(code_obj, self.user_global_ns, self.user_ns)
3461 3497 finally:
3462 3498 # Reset our crash handler in place
3463 3499 sys.excepthook = old_excepthook
3464 3500 except SystemExit as e:
3465 3501 if result is not None:
3466 3502 result.error_in_exec = e
3467 3503 self.showtraceback(exception_only=True)
3468 3504 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3469 3505 except bdb.BdbQuit:
3470 3506 etype, value, tb = sys.exc_info()
3471 3507 if result is not None:
3472 3508 result.error_in_exec = value
3473 3509 # the BdbQuit stops here
3474 3510 except self.custom_exceptions:
3475 3511 etype, value, tb = sys.exc_info()
3476 3512 if result is not None:
3477 3513 result.error_in_exec = value
3478 3514 self.CustomTB(etype, value, tb)
3479 3515 except:
3480 3516 if result is not None:
3481 3517 result.error_in_exec = sys.exc_info()[1]
3482 3518 self.showtraceback(running_compiled_code=True)
3483 3519 else:
3484 3520 outflag = False
3485 3521 return outflag
3486 3522
3487 3523 # For backwards compatibility
3488 3524 runcode = run_code
3489 3525
3490 3526 def check_complete(self, code: str) -> Tuple[str, str]:
3491 3527 """Return whether a block of code is ready to execute, or should be continued
3492 3528
3493 3529 Parameters
3494 3530 ----------
3495 3531 code : string
3496 3532 Python input code, which can be multiline.
3497 3533
3498 3534 Returns
3499 3535 -------
3500 3536 status : str
3501 3537 One of 'complete', 'incomplete', or 'invalid' if source is not a
3502 3538 prefix of valid code.
3503 3539 indent : str
3504 3540 When status is 'incomplete', this is some whitespace to insert on
3505 3541 the next line of the prompt.
3506 3542 """
3507 3543 status, nspaces = self.input_transformer_manager.check_complete(code)
3508 3544 return status, ' ' * (nspaces or 0)
3509 3545
3510 3546 #-------------------------------------------------------------------------
3511 3547 # Things related to GUI support and pylab
3512 3548 #-------------------------------------------------------------------------
3513 3549
3514 3550 active_eventloop = None
3515 3551
3516 3552 def enable_gui(self, gui=None):
3517 3553 raise NotImplementedError('Implement enable_gui in a subclass')
3518 3554
3519 3555 def enable_matplotlib(self, gui=None):
3520 3556 """Enable interactive matplotlib and inline figure support.
3521 3557
3522 3558 This takes the following steps:
3523 3559
3524 3560 1. select the appropriate eventloop and matplotlib backend
3525 3561 2. set up matplotlib for interactive use with that backend
3526 3562 3. configure formatters for inline figure display
3527 3563 4. enable the selected gui eventloop
3528 3564
3529 3565 Parameters
3530 3566 ----------
3531 3567 gui : optional, string
3532 3568 If given, dictates the choice of matplotlib GUI backend to use
3533 3569 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3534 3570 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3535 3571 matplotlib (as dictated by the matplotlib build-time options plus the
3536 3572 user's matplotlibrc configuration file). Note that not all backends
3537 3573 make sense in all contexts, for example a terminal ipython can't
3538 3574 display figures inline.
3539 3575 """
3540 3576 from matplotlib_inline.backend_inline import configure_inline_support
3541 3577
3542 3578 from IPython.core import pylabtools as pt
3543 3579 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3544 3580
3545 3581 if gui != 'inline':
3546 3582 # If we have our first gui selection, store it
3547 3583 if self.pylab_gui_select is None:
3548 3584 self.pylab_gui_select = gui
3549 3585 # Otherwise if they are different
3550 3586 elif gui != self.pylab_gui_select:
3551 3587 print('Warning: Cannot change to a different GUI toolkit: %s.'
3552 3588 ' Using %s instead.' % (gui, self.pylab_gui_select))
3553 3589 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3554 3590
3555 3591 pt.activate_matplotlib(backend)
3556 3592 configure_inline_support(self, backend)
3557 3593
3558 3594 # Now we must activate the gui pylab wants to use, and fix %run to take
3559 3595 # plot updates into account
3560 3596 self.enable_gui(gui)
3561 3597 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3562 3598 pt.mpl_runner(self.safe_execfile)
3563 3599
3564 3600 return gui, backend
3565 3601
3566 3602 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3567 3603 """Activate pylab support at runtime.
3568 3604
3569 3605 This turns on support for matplotlib, preloads into the interactive
3570 3606 namespace all of numpy and pylab, and configures IPython to correctly
3571 3607 interact with the GUI event loop. The GUI backend to be used can be
3572 3608 optionally selected with the optional ``gui`` argument.
3573 3609
3574 3610 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3575 3611
3576 3612 Parameters
3577 3613 ----------
3578 3614 gui : optional, string
3579 3615 If given, dictates the choice of matplotlib GUI backend to use
3580 3616 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3581 3617 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3582 3618 matplotlib (as dictated by the matplotlib build-time options plus the
3583 3619 user's matplotlibrc configuration file). Note that not all backends
3584 3620 make sense in all contexts, for example a terminal ipython can't
3585 3621 display figures inline.
3586 3622 import_all : optional, bool, default: True
3587 3623 Whether to do `from numpy import *` and `from pylab import *`
3588 3624 in addition to module imports.
3589 3625 welcome_message : deprecated
3590 3626 This argument is ignored, no welcome message will be displayed.
3591 3627 """
3592 3628 from IPython.core.pylabtools import import_pylab
3593 3629
3594 3630 gui, backend = self.enable_matplotlib(gui)
3595 3631
3596 3632 # We want to prevent the loading of pylab to pollute the user's
3597 3633 # namespace as shown by the %who* magics, so we execute the activation
3598 3634 # code in an empty namespace, and we update *both* user_ns and
3599 3635 # user_ns_hidden with this information.
3600 3636 ns = {}
3601 3637 import_pylab(ns, import_all)
3602 3638 # warn about clobbered names
3603 3639 ignored = {"__builtins__"}
3604 3640 both = set(ns).intersection(self.user_ns).difference(ignored)
3605 3641 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3606 3642 self.user_ns.update(ns)
3607 3643 self.user_ns_hidden.update(ns)
3608 3644 return gui, backend, clobbered
3609 3645
3610 3646 #-------------------------------------------------------------------------
3611 3647 # Utilities
3612 3648 #-------------------------------------------------------------------------
3613 3649
3614 3650 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3615 3651 """Expand python variables in a string.
3616 3652
3617 3653 The depth argument indicates how many frames above the caller should
3618 3654 be walked to look for the local namespace where to expand variables.
3619 3655
3620 3656 The global namespace for expansion is always the user's interactive
3621 3657 namespace.
3622 3658 """
3623 3659 ns = self.user_ns.copy()
3624 3660 try:
3625 3661 frame = sys._getframe(depth+1)
3626 3662 except ValueError:
3627 3663 # This is thrown if there aren't that many frames on the stack,
3628 3664 # e.g. if a script called run_line_magic() directly.
3629 3665 pass
3630 3666 else:
3631 3667 ns.update(frame.f_locals)
3632 3668
3633 3669 try:
3634 3670 # We have to use .vformat() here, because 'self' is a valid and common
3635 3671 # name, and expanding **ns for .format() would make it collide with
3636 3672 # the 'self' argument of the method.
3637 3673 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3638 3674 except Exception:
3639 3675 # if formatter couldn't format, just let it go untransformed
3640 3676 pass
3641 3677 return cmd
3642 3678
3643 3679 def mktempfile(self, data=None, prefix='ipython_edit_'):
3644 3680 """Make a new tempfile and return its filename.
3645 3681
3646 3682 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3647 3683 but it registers the created filename internally so ipython cleans it up
3648 3684 at exit time.
3649 3685
3650 3686 Optional inputs:
3651 3687
3652 3688 - data(None): if data is given, it gets written out to the temp file
3653 3689 immediately, and the file is closed again."""
3654 3690
3655 3691 dir_path = Path(tempfile.mkdtemp(prefix=prefix))
3656 3692 self.tempdirs.append(dir_path)
3657 3693
3658 3694 handle, filename = tempfile.mkstemp(".py", prefix, dir=str(dir_path))
3659 3695 os.close(handle) # On Windows, there can only be one open handle on a file
3660 3696
3661 3697 file_path = Path(filename)
3662 3698 self.tempfiles.append(file_path)
3663 3699
3664 3700 if data:
3665 3701 file_path.write_text(data, encoding="utf-8")
3666 3702 return filename
3667 3703
3668 3704 def ask_yes_no(self, prompt, default=None, interrupt=None):
3669 3705 if self.quiet:
3670 3706 return True
3671 3707 return ask_yes_no(prompt,default,interrupt)
3672 3708
3673 3709 def show_usage(self):
3674 3710 """Show a usage message"""
3675 3711 page.page(IPython.core.usage.interactive_usage)
3676 3712
3677 3713 def extract_input_lines(self, range_str, raw=False):
3678 3714 """Return as a string a set of input history slices.
3679 3715
3680 3716 Parameters
3681 3717 ----------
3682 3718 range_str : str
3683 3719 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3684 3720 since this function is for use by magic functions which get their
3685 3721 arguments as strings. The number before the / is the session
3686 3722 number: ~n goes n back from the current session.
3687 3723
3688 3724 If empty string is given, returns history of current session
3689 3725 without the last input.
3690 3726
3691 3727 raw : bool, optional
3692 3728 By default, the processed input is used. If this is true, the raw
3693 3729 input history is used instead.
3694 3730
3695 3731 Notes
3696 3732 -----
3697 3733 Slices can be described with two notations:
3698 3734
3699 3735 * ``N:M`` -> standard python form, means including items N...(M-1).
3700 3736 * ``N-M`` -> include items N..M (closed endpoint).
3701 3737 """
3702 3738 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3703 3739 text = "\n".join(x for _, _, x in lines)
3704 3740
3705 3741 # Skip the last line, as it's probably the magic that called this
3706 3742 if not range_str:
3707 3743 if "\n" not in text:
3708 3744 text = ""
3709 3745 else:
3710 3746 text = text[: text.rfind("\n")]
3711 3747
3712 3748 return text
3713 3749
3714 3750 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3715 3751 """Get a code string from history, file, url, or a string or macro.
3716 3752
3717 3753 This is mainly used by magic functions.
3718 3754
3719 3755 Parameters
3720 3756 ----------
3721 3757 target : str
3722 3758 A string specifying code to retrieve. This will be tried respectively
3723 3759 as: ranges of input history (see %history for syntax), url,
3724 3760 corresponding .py file, filename, or an expression evaluating to a
3725 3761 string or Macro in the user namespace.
3726 3762
3727 3763 If empty string is given, returns complete history of current
3728 3764 session, without the last line.
3729 3765
3730 3766 raw : bool
3731 3767 If true (default), retrieve raw history. Has no effect on the other
3732 3768 retrieval mechanisms.
3733 3769
3734 3770 py_only : bool (default False)
3735 3771 Only try to fetch python code, do not try alternative methods to decode file
3736 3772 if unicode fails.
3737 3773
3738 3774 Returns
3739 3775 -------
3740 3776 A string of code.
3741 3777 ValueError is raised if nothing is found, and TypeError if it evaluates
3742 3778 to an object of another type. In each case, .args[0] is a printable
3743 3779 message.
3744 3780 """
3745 3781 code = self.extract_input_lines(target, raw=raw) # Grab history
3746 3782 if code:
3747 3783 return code
3748 3784 try:
3749 3785 if target.startswith(('http://', 'https://')):
3750 3786 return openpy.read_py_url(target, skip_encoding_cookie=skip_encoding_cookie)
3751 3787 except UnicodeDecodeError as e:
3752 3788 if not py_only :
3753 3789 # Deferred import
3754 3790 from urllib.request import urlopen
3755 3791 response = urlopen(target)
3756 3792 return response.read().decode('latin1')
3757 3793 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3758 3794
3759 3795 potential_target = [target]
3760 3796 try :
3761 3797 potential_target.insert(0,get_py_filename(target))
3762 3798 except IOError:
3763 3799 pass
3764 3800
3765 3801 for tgt in potential_target :
3766 3802 if os.path.isfile(tgt): # Read file
3767 3803 try :
3768 3804 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3769 3805 except UnicodeDecodeError as e:
3770 3806 if not py_only :
3771 3807 with io_open(tgt,'r', encoding='latin1') as f :
3772 3808 return f.read()
3773 3809 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3774 3810 elif os.path.isdir(os.path.expanduser(tgt)):
3775 3811 raise ValueError("'%s' is a directory, not a regular file." % target)
3776 3812
3777 3813 if search_ns:
3778 3814 # Inspect namespace to load object source
3779 3815 object_info = self.object_inspect(target, detail_level=1)
3780 3816 if object_info['found'] and object_info['source']:
3781 3817 return object_info['source']
3782 3818
3783 3819 try: # User namespace
3784 3820 codeobj = eval(target, self.user_ns)
3785 3821 except Exception as e:
3786 3822 raise ValueError(("'%s' was not found in history, as a file, url, "
3787 3823 "nor in the user namespace.") % target) from e
3788 3824
3789 3825 if isinstance(codeobj, str):
3790 3826 return codeobj
3791 3827 elif isinstance(codeobj, Macro):
3792 3828 return codeobj.value
3793 3829
3794 3830 raise TypeError("%s is neither a string nor a macro." % target,
3795 3831 codeobj)
3796 3832
3797 3833 def _atexit_once(self):
3798 3834 """
3799 3835 At exist operation that need to be called at most once.
3800 3836 Second call to this function per instance will do nothing.
3801 3837 """
3802 3838
3803 3839 if not getattr(self, "_atexit_once_called", False):
3804 3840 self._atexit_once_called = True
3805 3841 # Clear all user namespaces to release all references cleanly.
3806 3842 self.reset(new_session=False)
3807 3843 # Close the history session (this stores the end time and line count)
3808 3844 # this must be *before* the tempfile cleanup, in case of temporary
3809 3845 # history db
3810 3846 self.history_manager.end_session()
3811 3847 self.history_manager = None
3812 3848
3813 3849 #-------------------------------------------------------------------------
3814 3850 # Things related to IPython exiting
3815 3851 #-------------------------------------------------------------------------
3816 3852 def atexit_operations(self):
3817 3853 """This will be executed at the time of exit.
3818 3854
3819 3855 Cleanup operations and saving of persistent data that is done
3820 3856 unconditionally by IPython should be performed here.
3821 3857
3822 3858 For things that may depend on startup flags or platform specifics (such
3823 3859 as having readline or not), register a separate atexit function in the
3824 3860 code that has the appropriate information, rather than trying to
3825 3861 clutter
3826 3862 """
3827 3863 self._atexit_once()
3828 3864
3829 3865 # Cleanup all tempfiles and folders left around
3830 3866 for tfile in self.tempfiles:
3831 3867 try:
3832 3868 tfile.unlink()
3833 3869 self.tempfiles.remove(tfile)
3834 3870 except FileNotFoundError:
3835 3871 pass
3836 3872 del self.tempfiles
3837 3873 for tdir in self.tempdirs:
3838 3874 try:
3839 3875 tdir.rmdir()
3840 3876 self.tempdirs.remove(tdir)
3841 3877 except FileNotFoundError:
3842 3878 pass
3843 3879 del self.tempdirs
3844 3880
3845 3881 # Restore user's cursor
3846 3882 if hasattr(self, "editing_mode") and self.editing_mode == "vi":
3847 3883 sys.stdout.write("\x1b[0 q")
3848 3884 sys.stdout.flush()
3849 3885
3850 3886 def cleanup(self):
3851 3887 self.restore_sys_module_state()
3852 3888
3853 3889
3854 3890 # Overridden in terminal subclass to change prompts
3855 3891 def switch_doctest_mode(self, mode):
3856 3892 pass
3857 3893
3858 3894
3859 3895 class InteractiveShellABC(metaclass=abc.ABCMeta):
3860 3896 """An abstract base class for InteractiveShell."""
3861 3897
3862 3898 InteractiveShellABC.register(InteractiveShell)
@@ -1,1516 +1,1522 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Implementation of execution-related magic functions."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 import ast
9 9 import bdb
10 10 import builtins as builtin_mod
11 11 import cProfile as profile
12 12 import gc
13 13 import itertools
14 14 import math
15 15 import os
16 16 import pstats
17 17 import re
18 18 import shlex
19 19 import sys
20 20 import time
21 21 import timeit
22 22 from ast import Module
23 23 from io import StringIO
24 24 from logging import error
25 25 from pathlib import Path
26 26 from pdb import Restart
27 27 from warnings import warn
28 28
29 29 from IPython.core import magic_arguments, oinspect, page
30 30 from IPython.core.error import UsageError
31 31 from IPython.core.macro import Macro
32 32 from IPython.core.magic import (
33 33 Magics,
34 34 cell_magic,
35 35 line_cell_magic,
36 36 line_magic,
37 37 magics_class,
38 38 needs_local_scope,
39 39 no_var_expand,
40 40 output_can_be_silenced,
41 41 on_off,
42 42 )
43 43 from IPython.testing.skipdoctest import skip_doctest
44 44 from IPython.utils.capture import capture_output
45 45 from IPython.utils.contexts import preserve_keys
46 46 from IPython.utils.ipstruct import Struct
47 47 from IPython.utils.module_paths import find_mod
48 48 from IPython.utils.path import get_py_filename, shellglob
49 49 from IPython.utils.timing import clock, clock2
50 50 from IPython.core.displayhook import DisplayHook
51 51
52 52 #-----------------------------------------------------------------------------
53 53 # Magic implementation classes
54 54 #-----------------------------------------------------------------------------
55 55
56 56
57 57 class TimeitResult(object):
58 58 """
59 59 Object returned by the timeit magic with info about the run.
60 60
61 61 Contains the following attributes :
62 62
63 63 loops: (int) number of loops done per measurement
64 64 repeat: (int) number of times the measurement has been repeated
65 65 best: (float) best execution time / number
66 66 all_runs: (list of float) execution time of each run (in s)
67 67 compile_time: (float) time of statement compilation (s)
68 68
69 69 """
70 70 def __init__(self, loops, repeat, best, worst, all_runs, compile_time, precision):
71 71 self.loops = loops
72 72 self.repeat = repeat
73 73 self.best = best
74 74 self.worst = worst
75 75 self.all_runs = all_runs
76 76 self.compile_time = compile_time
77 77 self._precision = precision
78 78 self.timings = [ dt / self.loops for dt in all_runs]
79 79
80 80 @property
81 81 def average(self):
82 82 return math.fsum(self.timings) / len(self.timings)
83 83
84 84 @property
85 85 def stdev(self):
86 86 mean = self.average
87 87 return (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5
88 88
89 89 def __str__(self):
90 90 pm = '+-'
91 91 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
92 92 try:
93 93 u'\xb1'.encode(sys.stdout.encoding)
94 94 pm = u'\xb1'
95 95 except:
96 96 pass
97 97 return "{mean} {pm} {std} per loop (mean {pm} std. dev. of {runs} run{run_plural}, {loops:,} loop{loop_plural} each)".format(
98 98 pm=pm,
99 99 runs=self.repeat,
100 100 loops=self.loops,
101 101 loop_plural="" if self.loops == 1 else "s",
102 102 run_plural="" if self.repeat == 1 else "s",
103 103 mean=_format_time(self.average, self._precision),
104 104 std=_format_time(self.stdev, self._precision),
105 105 )
106 106
107 107 def _repr_pretty_(self, p , cycle):
108 108 unic = self.__str__()
109 109 p.text(u'<TimeitResult : '+unic+u'>')
110 110
111 111
112 112 class TimeitTemplateFiller(ast.NodeTransformer):
113 113 """Fill in the AST template for timing execution.
114 114
115 115 This is quite closely tied to the template definition, which is in
116 116 :meth:`ExecutionMagics.timeit`.
117 117 """
118 118 def __init__(self, ast_setup, ast_stmt):
119 119 self.ast_setup = ast_setup
120 120 self.ast_stmt = ast_stmt
121 121
122 122 def visit_FunctionDef(self, node):
123 123 "Fill in the setup statement"
124 124 self.generic_visit(node)
125 125 if node.name == "inner":
126 126 node.body[:1] = self.ast_setup.body
127 127
128 128 return node
129 129
130 130 def visit_For(self, node):
131 131 "Fill in the statement to be timed"
132 132 if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
133 133 node.body = self.ast_stmt.body
134 134 return node
135 135
136 136
137 137 class Timer(timeit.Timer):
138 138 """Timer class that explicitly uses self.inner
139 139
140 140 which is an undocumented implementation detail of CPython,
141 141 not shared by PyPy.
142 142 """
143 143 # Timer.timeit copied from CPython 3.4.2
144 144 def timeit(self, number=timeit.default_number):
145 145 """Time 'number' executions of the main statement.
146 146
147 147 To be precise, this executes the setup statement once, and
148 148 then returns the time it takes to execute the main statement
149 149 a number of times, as a float measured in seconds. The
150 150 argument is the number of times through the loop, defaulting
151 151 to one million. The main statement, the setup statement and
152 152 the timer function to be used are passed to the constructor.
153 153 """
154 154 it = itertools.repeat(None, number)
155 155 gcold = gc.isenabled()
156 156 gc.disable()
157 157 try:
158 158 timing = self.inner(it, self.timer)
159 159 finally:
160 160 if gcold:
161 161 gc.enable()
162 162 return timing
163 163
164 164
165 165 @magics_class
166 166 class ExecutionMagics(Magics):
167 167 """Magics related to code execution, debugging, profiling, etc.
168 168
169 169 """
170 170
171 171 def __init__(self, shell):
172 172 super(ExecutionMagics, self).__init__(shell)
173 173 # Default execution function used to actually run user code.
174 174 self.default_runner = None
175 175
176 176 @skip_doctest
177 177 @no_var_expand
178 178 @line_cell_magic
179 179 def prun(self, parameter_s='', cell=None):
180 180
181 181 """Run a statement through the python code profiler.
182 182
183 183 Usage, in line mode:
184 184 %prun [options] statement
185 185
186 186 Usage, in cell mode:
187 187 %%prun [options] [statement]
188 188 code...
189 189 code...
190 190
191 191 In cell mode, the additional code lines are appended to the (possibly
192 192 empty) statement in the first line. Cell mode allows you to easily
193 193 profile multiline blocks without having to put them in a separate
194 194 function.
195 195
196 196 The given statement (which doesn't require quote marks) is run via the
197 197 python profiler in a manner similar to the profile.run() function.
198 198 Namespaces are internally managed to work correctly; profile.run
199 199 cannot be used in IPython because it makes certain assumptions about
200 200 namespaces which do not hold under IPython.
201 201
202 202 Options:
203 203
204 204 -l <limit>
205 205 you can place restrictions on what or how much of the
206 206 profile gets printed. The limit value can be:
207 207
208 208 * A string: only information for function names containing this string
209 209 is printed.
210 210
211 211 * An integer: only these many lines are printed.
212 212
213 213 * A float (between 0 and 1): this fraction of the report is printed
214 214 (for example, use a limit of 0.4 to see the topmost 40% only).
215 215
216 216 You can combine several limits with repeated use of the option. For
217 217 example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
218 218 information about class constructors.
219 219
220 220 -r
221 221 return the pstats.Stats object generated by the profiling. This
222 222 object has all the information about the profile in it, and you can
223 223 later use it for further analysis or in other functions.
224 224
225 225 -s <key>
226 226 sort profile by given key. You can provide more than one key
227 227 by using the option several times: '-s key1 -s key2 -s key3...'. The
228 228 default sorting key is 'time'.
229 229
230 230 The following is copied verbatim from the profile documentation
231 231 referenced below:
232 232
233 233 When more than one key is provided, additional keys are used as
234 234 secondary criteria when the there is equality in all keys selected
235 235 before them.
236 236
237 237 Abbreviations can be used for any key names, as long as the
238 238 abbreviation is unambiguous. The following are the keys currently
239 239 defined:
240 240
241 241 ============ =====================
242 242 Valid Arg Meaning
243 243 ============ =====================
244 244 "calls" call count
245 245 "cumulative" cumulative time
246 246 "file" file name
247 247 "module" file name
248 248 "pcalls" primitive call count
249 249 "line" line number
250 250 "name" function name
251 251 "nfl" name/file/line
252 252 "stdname" standard name
253 253 "time" internal time
254 254 ============ =====================
255 255
256 256 Note that all sorts on statistics are in descending order (placing
257 257 most time consuming items first), where as name, file, and line number
258 258 searches are in ascending order (i.e., alphabetical). The subtle
259 259 distinction between "nfl" and "stdname" is that the standard name is a
260 260 sort of the name as printed, which means that the embedded line
261 261 numbers get compared in an odd way. For example, lines 3, 20, and 40
262 262 would (if the file names were the same) appear in the string order
263 263 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
264 264 line numbers. In fact, sort_stats("nfl") is the same as
265 265 sort_stats("name", "file", "line").
266 266
267 267 -T <filename>
268 268 save profile results as shown on screen to a text
269 269 file. The profile is still shown on screen.
270 270
271 271 -D <filename>
272 272 save (via dump_stats) profile statistics to given
273 273 filename. This data is in a format understood by the pstats module, and
274 274 is generated by a call to the dump_stats() method of profile
275 275 objects. The profile is still shown on screen.
276 276
277 277 -q
278 278 suppress output to the pager. Best used with -T and/or -D above.
279 279
280 280 If you want to run complete programs under the profiler's control, use
281 281 ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
282 282 contains profiler specific options as described here.
283 283
284 284 You can read the complete documentation for the profile module with::
285 285
286 286 In [1]: import profile; profile.help()
287 287
288 288 .. versionchanged:: 7.3
289 289 User variables are no longer expanded,
290 290 the magic line is always left unmodified.
291 291
292 292 """
293 293 opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
294 294 list_all=True, posix=False)
295 295 if cell is not None:
296 296 arg_str += '\n' + cell
297 297 arg_str = self.shell.transform_cell(arg_str)
298 298 return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
299 299
300 300 def _run_with_profiler(self, code, opts, namespace):
301 301 """
302 302 Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
303 303
304 304 Parameters
305 305 ----------
306 306 code : str
307 307 Code to be executed.
308 308 opts : Struct
309 309 Options parsed by `self.parse_options`.
310 310 namespace : dict
311 311 A dictionary for Python namespace (e.g., `self.shell.user_ns`).
312 312
313 313 """
314 314
315 315 # Fill default values for unspecified options:
316 316 opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
317 317
318 318 prof = profile.Profile()
319 319 try:
320 320 prof = prof.runctx(code, namespace, namespace)
321 321 sys_exit = ''
322 322 except SystemExit:
323 323 sys_exit = """*** SystemExit exception caught in code being profiled."""
324 324
325 325 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
326 326
327 327 lims = opts.l
328 328 if lims:
329 329 lims = [] # rebuild lims with ints/floats/strings
330 330 for lim in opts.l:
331 331 try:
332 332 lims.append(int(lim))
333 333 except ValueError:
334 334 try:
335 335 lims.append(float(lim))
336 336 except ValueError:
337 337 lims.append(lim)
338 338
339 339 # Trap output.
340 340 stdout_trap = StringIO()
341 341 stats_stream = stats.stream
342 342 try:
343 343 stats.stream = stdout_trap
344 344 stats.print_stats(*lims)
345 345 finally:
346 346 stats.stream = stats_stream
347 347
348 348 output = stdout_trap.getvalue()
349 349 output = output.rstrip()
350 350
351 351 if 'q' not in opts:
352 352 page.page(output)
353 353 print(sys_exit, end=' ')
354 354
355 355 dump_file = opts.D[0]
356 356 text_file = opts.T[0]
357 357 if dump_file:
358 358 prof.dump_stats(dump_file)
359 359 print(
360 360 f"\n*** Profile stats marshalled to file {repr(dump_file)}.{sys_exit}"
361 361 )
362 362 if text_file:
363 363 pfile = Path(text_file)
364 364 pfile.touch(exist_ok=True)
365 365 pfile.write_text(output, encoding="utf-8")
366 366
367 367 print(
368 368 f"\n*** Profile printout saved to text file {repr(text_file)}.{sys_exit}"
369 369 )
370 370
371 371 if 'r' in opts:
372 372 return stats
373 373
374 374 return None
375 375
376 376 @line_magic
377 377 def pdb(self, parameter_s=''):
378 378 """Control the automatic calling of the pdb interactive debugger.
379 379
380 380 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
381 381 argument it works as a toggle.
382 382
383 383 When an exception is triggered, IPython can optionally call the
384 384 interactive pdb debugger after the traceback printout. %pdb toggles
385 385 this feature on and off.
386 386
387 387 The initial state of this feature is set in your configuration
388 388 file (the option is ``InteractiveShell.pdb``).
389 389
390 390 If you want to just activate the debugger AFTER an exception has fired,
391 391 without having to type '%pdb on' and rerunning your code, you can use
392 392 the %debug magic."""
393 393
394 394 par = parameter_s.strip().lower()
395 395
396 396 if par:
397 397 try:
398 398 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
399 399 except KeyError:
400 400 print ('Incorrect argument. Use on/1, off/0, '
401 401 'or nothing for a toggle.')
402 402 return
403 403 else:
404 404 # toggle
405 405 new_pdb = not self.shell.call_pdb
406 406
407 407 # set on the shell
408 408 self.shell.call_pdb = new_pdb
409 409 print('Automatic pdb calling has been turned',on_off(new_pdb))
410 410
411 411 @magic_arguments.magic_arguments()
412 412 @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
413 413 help="""
414 414 Set break point at LINE in FILE.
415 415 """
416 416 )
417 417 @magic_arguments.argument('statement', nargs='*',
418 418 help="""
419 419 Code to run in debugger.
420 420 You can omit this in cell magic mode.
421 421 """
422 422 )
423 423 @no_var_expand
424 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 427 """Activate the interactive debugger.
427 428
428 429 This magic command support two ways of activating debugger.
429 430 One is to activate debugger before executing code. This way, you
430 431 can set a break point, to step through the code from the point.
431 432 You can use this mode by giving statements to execute and optionally
432 433 a breakpoint.
433 434
434 435 The other one is to activate debugger in post-mortem mode. You can
435 436 activate this mode simply running %debug without any argument.
436 437 If an exception has just occurred, this lets you inspect its stack
437 438 frames interactively. Note that this will always work only on the last
438 439 traceback that occurred, so you must call this quickly after an
439 440 exception that you wish to inspect has fired, because if another one
440 441 occurs, it clobbers the previous one.
441 442
442 443 If you want IPython to automatically do this on every exception, see
443 444 the %pdb magic for more details.
444 445
445 446 .. versionchanged:: 7.3
446 447 When running code, user variables are no longer expanded,
447 448 the magic line is always left unmodified.
448 449
449 450 """
450 451 args = magic_arguments.parse_argstring(self.debug, line)
451 452
452 453 if not (args.breakpoint or args.statement or cell):
453 454 self._debug_post_mortem()
454 455 elif not (args.breakpoint or cell):
455 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 458 else:
458 459 # Here we try to reconstruct the code from the output of
459 460 # parse_argstring. This might not work if the code has spaces
460 461 # For example this fails for `print("a b")`
461 462 code = "\n".join(args.statement)
462 463 if cell:
463 464 code += "\n" + cell
464 self._debug_exec(code, args.breakpoint)
465 self._debug_exec(code, args.breakpoint, local_ns)
465 466
466 467 def _debug_post_mortem(self):
467 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 471 if breakpoint:
471 472 (filename, bp_line) = breakpoint.rsplit(':', 1)
472 473 bp_line = int(bp_line)
473 474 else:
474 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 480 @line_magic
478 481 def tb(self, s):
479 482 """Print the last traceback.
480 483
481 484 Optionally, specify an exception reporting mode, tuning the
482 485 verbosity of the traceback. By default the currently-active exception
483 486 mode is used. See %xmode for changing exception reporting modes.
484 487
485 488 Valid modes: Plain, Context, Verbose, and Minimal.
486 489 """
487 490 interactive_tb = self.shell.InteractiveTB
488 491 if s:
489 492 # Switch exception reporting mode for this one call.
490 493 # Ensure it is switched back.
491 494 def xmode_switch_err(name):
492 495 warn('Error changing %s exception modes.\n%s' %
493 496 (name,sys.exc_info()[1]))
494 497
495 498 new_mode = s.strip().capitalize()
496 499 original_mode = interactive_tb.mode
497 500 try:
498 501 try:
499 502 interactive_tb.set_mode(mode=new_mode)
500 503 except Exception:
501 504 xmode_switch_err('user')
502 505 else:
503 506 self.shell.showtraceback()
504 507 finally:
505 508 interactive_tb.set_mode(mode=original_mode)
506 509 else:
507 510 self.shell.showtraceback()
508 511
509 512 @skip_doctest
510 513 @line_magic
511 514 def run(self, parameter_s='', runner=None,
512 515 file_finder=get_py_filename):
513 516 """Run the named file inside IPython as a program.
514 517
515 518 Usage::
516 519
517 520 %run [-n -i -e -G]
518 521 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
519 522 ( -m mod | filename ) [args]
520 523
521 524 The filename argument should be either a pure Python script (with
522 525 extension ``.py``), or a file with custom IPython syntax (such as
523 526 magics). If the latter, the file can be either a script with ``.ipy``
524 527 extension, or a Jupyter notebook with ``.ipynb`` extension. When running
525 528 a Jupyter notebook, the output from print statements and other
526 529 displayed objects will appear in the terminal (even matplotlib figures
527 530 will open, if a terminal-compliant backend is being used). Note that,
528 531 at the system command line, the ``jupyter run`` command offers similar
529 532 functionality for executing notebooks (albeit currently with some
530 533 differences in supported options).
531 534
532 535 Parameters after the filename are passed as command-line arguments to
533 536 the program (put in sys.argv). Then, control returns to IPython's
534 537 prompt.
535 538
536 539 This is similar to running at a system prompt ``python file args``,
537 540 but with the advantage of giving you IPython's tracebacks, and of
538 541 loading all variables into your interactive namespace for further use
539 542 (unless -p is used, see below).
540 543
541 544 The file is executed in a namespace initially consisting only of
542 545 ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
543 546 sees its environment as if it were being run as a stand-alone program
544 547 (except for sharing global objects such as previously imported
545 548 modules). But after execution, the IPython interactive namespace gets
546 549 updated with all variables defined in the program (except for __name__
547 550 and sys.argv). This allows for very convenient loading of code for
548 551 interactive work, while giving each program a 'clean sheet' to run in.
549 552
550 553 Arguments are expanded using shell-like glob match. Patterns
551 554 '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
552 555 tilde '~' will be expanded into user's home directory. Unlike
553 556 real shells, quotation does not suppress expansions. Use
554 557 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
555 558 To completely disable these expansions, you can use -G flag.
556 559
557 560 On Windows systems, the use of single quotes `'` when specifying
558 561 a file is not supported. Use double quotes `"`.
559 562
560 563 Options:
561 564
562 565 -n
563 566 __name__ is NOT set to '__main__', but to the running file's name
564 567 without extension (as python does under import). This allows running
565 568 scripts and reloading the definitions in them without calling code
566 569 protected by an ``if __name__ == "__main__"`` clause.
567 570
568 571 -i
569 572 run the file in IPython's namespace instead of an empty one. This
570 573 is useful if you are experimenting with code written in a text editor
571 574 which depends on variables defined interactively.
572 575
573 576 -e
574 577 ignore sys.exit() calls or SystemExit exceptions in the script
575 578 being run. This is particularly useful if IPython is being used to
576 579 run unittests, which always exit with a sys.exit() call. In such
577 580 cases you are interested in the output of the test results, not in
578 581 seeing a traceback of the unittest module.
579 582
580 583 -t
581 584 print timing information at the end of the run. IPython will give
582 585 you an estimated CPU time consumption for your script, which under
583 586 Unix uses the resource module to avoid the wraparound problems of
584 587 time.clock(). Under Unix, an estimate of time spent on system tasks
585 588 is also given (for Windows platforms this is reported as 0.0).
586 589
587 590 If -t is given, an additional ``-N<N>`` option can be given, where <N>
588 591 must be an integer indicating how many times you want the script to
589 592 run. The final timing report will include total and per run results.
590 593
591 594 For example (testing the script uniq_stable.py)::
592 595
593 596 In [1]: run -t uniq_stable
594 597
595 598 IPython CPU timings (estimated):
596 599 User : 0.19597 s.
597 600 System: 0.0 s.
598 601
599 602 In [2]: run -t -N5 uniq_stable
600 603
601 604 IPython CPU timings (estimated):
602 605 Total runs performed: 5
603 606 Times : Total Per run
604 607 User : 0.910862 s, 0.1821724 s.
605 608 System: 0.0 s, 0.0 s.
606 609
607 610 -d
608 611 run your program under the control of pdb, the Python debugger.
609 612 This allows you to execute your program step by step, watch variables,
610 613 etc. Internally, what IPython does is similar to calling::
611 614
612 615 pdb.run('execfile("YOURFILENAME")')
613 616
614 617 with a breakpoint set on line 1 of your file. You can change the line
615 618 number for this automatic breakpoint to be <N> by using the -bN option
616 619 (where N must be an integer). For example::
617 620
618 621 %run -d -b40 myscript
619 622
620 623 will set the first breakpoint at line 40 in myscript.py. Note that
621 624 the first breakpoint must be set on a line which actually does
622 625 something (not a comment or docstring) for it to stop execution.
623 626
624 627 Or you can specify a breakpoint in a different file::
625 628
626 629 %run -d -b myotherfile.py:20 myscript
627 630
628 631 When the pdb debugger starts, you will see a (Pdb) prompt. You must
629 632 first enter 'c' (without quotes) to start execution up to the first
630 633 breakpoint.
631 634
632 635 Entering 'help' gives information about the use of the debugger. You
633 636 can easily see pdb's full documentation with "import pdb;pdb.help()"
634 637 at a prompt.
635 638
636 639 -p
637 640 run program under the control of the Python profiler module (which
638 641 prints a detailed report of execution times, function calls, etc).
639 642
640 643 You can pass other options after -p which affect the behavior of the
641 644 profiler itself. See the docs for %prun for details.
642 645
643 646 In this mode, the program's variables do NOT propagate back to the
644 647 IPython interactive namespace (because they remain in the namespace
645 648 where the profiler executes them).
646 649
647 650 Internally this triggers a call to %prun, see its documentation for
648 651 details on the options available specifically for profiling.
649 652
650 653 There is one special usage for which the text above doesn't apply:
651 654 if the filename ends with .ipy[nb], the file is run as ipython script,
652 655 just as if the commands were written on IPython prompt.
653 656
654 657 -m
655 658 specify module name to load instead of script path. Similar to
656 659 the -m option for the python interpreter. Use this option last if you
657 660 want to combine with other %run options. Unlike the python interpreter
658 661 only source modules are allowed no .pyc or .pyo files.
659 662 For example::
660 663
661 664 %run -m example
662 665
663 666 will run the example module.
664 667
665 668 -G
666 669 disable shell-like glob expansion of arguments.
667 670
668 671 """
669 672
670 673 # Logic to handle issue #3664
671 674 # Add '--' after '-m <module_name>' to ignore additional args passed to a module.
672 675 if '-m' in parameter_s and '--' not in parameter_s:
673 676 argv = shlex.split(parameter_s, posix=(os.name == 'posix'))
674 677 for idx, arg in enumerate(argv):
675 678 if arg and arg.startswith('-') and arg != '-':
676 679 if arg == '-m':
677 680 argv.insert(idx + 2, '--')
678 681 break
679 682 else:
680 683 # Positional arg, break
681 684 break
682 685 parameter_s = ' '.join(shlex.quote(arg) for arg in argv)
683 686
684 687 # get arguments and set sys.argv for program to be run.
685 688 opts, arg_lst = self.parse_options(parameter_s,
686 689 'nidtN:b:pD:l:rs:T:em:G',
687 690 mode='list', list_all=1)
688 691 if "m" in opts:
689 692 modulename = opts["m"][0]
690 693 modpath = find_mod(modulename)
691 694 if modpath is None:
692 695 msg = '%r is not a valid modulename on sys.path'%modulename
693 696 raise Exception(msg)
694 697 arg_lst = [modpath] + arg_lst
695 698 try:
696 699 fpath = None # initialize to make sure fpath is in scope later
697 700 fpath = arg_lst[0]
698 701 filename = file_finder(fpath)
699 702 except IndexError as e:
700 703 msg = 'you must provide at least a filename.'
701 704 raise Exception(msg) from e
702 705 except IOError as e:
703 706 try:
704 707 msg = str(e)
705 708 except UnicodeError:
706 709 msg = e.message
707 710 if os.name == 'nt' and re.match(r"^'.*'$",fpath):
708 711 warn('For Windows, use double quotes to wrap a filename: %run "mypath\\myfile.py"')
709 712 raise Exception(msg) from e
710 713 except TypeError:
711 714 if fpath in sys.meta_path:
712 715 filename = ""
713 716 else:
714 717 raise
715 718
716 719 if filename.lower().endswith(('.ipy', '.ipynb')):
717 720 with preserve_keys(self.shell.user_ns, '__file__'):
718 721 self.shell.user_ns['__file__'] = filename
719 722 self.shell.safe_execfile_ipy(filename, raise_exceptions=True)
720 723 return
721 724
722 725 # Control the response to exit() calls made by the script being run
723 726 exit_ignore = 'e' in opts
724 727
725 728 # Make sure that the running script gets a proper sys.argv as if it
726 729 # were run from a system shell.
727 730 save_argv = sys.argv # save it for later restoring
728 731
729 732 if 'G' in opts:
730 733 args = arg_lst[1:]
731 734 else:
732 735 # tilde and glob expansion
733 736 args = shellglob(map(os.path.expanduser, arg_lst[1:]))
734 737
735 738 sys.argv = [filename] + args # put in the proper filename
736 739
737 740 if 'n' in opts:
738 741 name = Path(filename).stem
739 742 else:
740 743 name = '__main__'
741 744
742 745 if 'i' in opts:
743 746 # Run in user's interactive namespace
744 747 prog_ns = self.shell.user_ns
745 748 __name__save = self.shell.user_ns['__name__']
746 749 prog_ns['__name__'] = name
747 750 main_mod = self.shell.user_module
748 751
749 752 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
750 753 # set the __file__ global in the script's namespace
751 754 # TK: Is this necessary in interactive mode?
752 755 prog_ns['__file__'] = filename
753 756 else:
754 757 # Run in a fresh, empty namespace
755 758
756 759 # The shell MUST hold a reference to prog_ns so after %run
757 760 # exits, the python deletion mechanism doesn't zero it out
758 761 # (leaving dangling references). See interactiveshell for details
759 762 main_mod = self.shell.new_main_mod(filename, name)
760 763 prog_ns = main_mod.__dict__
761 764
762 765 # pickle fix. See interactiveshell for an explanation. But we need to
763 766 # make sure that, if we overwrite __main__, we replace it at the end
764 767 main_mod_name = prog_ns['__name__']
765 768
766 769 if main_mod_name == '__main__':
767 770 restore_main = sys.modules['__main__']
768 771 else:
769 772 restore_main = False
770 773
771 774 # This needs to be undone at the end to prevent holding references to
772 775 # every single object ever created.
773 776 sys.modules[main_mod_name] = main_mod
774 777
775 778 if 'p' in opts or 'd' in opts:
776 779 if 'm' in opts:
777 780 code = 'run_module(modulename, prog_ns)'
778 781 code_ns = {
779 782 'run_module': self.shell.safe_run_module,
780 783 'prog_ns': prog_ns,
781 784 'modulename': modulename,
782 785 }
783 786 else:
784 787 if 'd' in opts:
785 788 # allow exceptions to raise in debug mode
786 789 code = 'execfile(filename, prog_ns, raise_exceptions=True)'
787 790 else:
788 791 code = 'execfile(filename, prog_ns)'
789 792 code_ns = {
790 793 'execfile': self.shell.safe_execfile,
791 794 'prog_ns': prog_ns,
792 795 'filename': get_py_filename(filename),
793 796 }
794 797
795 798 try:
796 799 stats = None
797 800 if 'p' in opts:
798 801 stats = self._run_with_profiler(code, opts, code_ns)
799 802 else:
800 803 if 'd' in opts:
801 804 bp_file, bp_line = parse_breakpoint(
802 805 opts.get('b', ['1'])[0], filename)
803 806 self._run_with_debugger(
804 807 code, code_ns, filename, bp_line, bp_file)
805 808 else:
806 809 if 'm' in opts:
807 810 def run():
808 811 self.shell.safe_run_module(modulename, prog_ns)
809 812 else:
810 813 if runner is None:
811 814 runner = self.default_runner
812 815 if runner is None:
813 816 runner = self.shell.safe_execfile
814 817
815 818 def run():
816 819 runner(filename, prog_ns, prog_ns,
817 820 exit_ignore=exit_ignore)
818 821
819 822 if 't' in opts:
820 823 # timed execution
821 824 try:
822 825 nruns = int(opts['N'][0])
823 826 if nruns < 1:
824 827 error('Number of runs must be >=1')
825 828 return
826 829 except (KeyError):
827 830 nruns = 1
828 831 self._run_with_timing(run, nruns)
829 832 else:
830 833 # regular execution
831 834 run()
832 835
833 836 if 'i' in opts:
834 837 self.shell.user_ns['__name__'] = __name__save
835 838 else:
836 839 # update IPython interactive namespace
837 840
838 841 # Some forms of read errors on the file may mean the
839 842 # __name__ key was never set; using pop we don't have to
840 843 # worry about a possible KeyError.
841 844 prog_ns.pop('__name__', None)
842 845
843 846 with preserve_keys(self.shell.user_ns, '__file__'):
844 847 self.shell.user_ns.update(prog_ns)
845 848 finally:
846 849 # It's a bit of a mystery why, but __builtins__ can change from
847 850 # being a module to becoming a dict missing some key data after
848 851 # %run. As best I can see, this is NOT something IPython is doing
849 852 # at all, and similar problems have been reported before:
850 853 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
851 854 # Since this seems to be done by the interpreter itself, the best
852 855 # we can do is to at least restore __builtins__ for the user on
853 856 # exit.
854 857 self.shell.user_ns['__builtins__'] = builtin_mod
855 858
856 859 # Ensure key global structures are restored
857 860 sys.argv = save_argv
858 861 if restore_main:
859 862 sys.modules['__main__'] = restore_main
860 863 if '__mp_main__' in sys.modules:
861 864 sys.modules['__mp_main__'] = restore_main
862 865 else:
863 866 # Remove from sys.modules the reference to main_mod we'd
864 867 # added. Otherwise it will trap references to objects
865 868 # contained therein.
866 869 del sys.modules[main_mod_name]
867 870
868 871 return stats
869 872
870 def _run_with_debugger(self, code, code_ns, filename=None,
871 bp_line=None, bp_file=None):
873 def _run_with_debugger(
874 self, code, code_ns, filename=None, bp_line=None, bp_file=None, local_ns=None
875 ):
872 876 """
873 877 Run `code` in debugger with a break point.
874 878
875 879 Parameters
876 880 ----------
877 881 code : str
878 882 Code to execute.
879 883 code_ns : dict
880 884 A namespace in which `code` is executed.
881 885 filename : str
882 886 `code` is ran as if it is in `filename`.
883 887 bp_line : int, optional
884 888 Line number of the break point.
885 889 bp_file : str, optional
886 890 Path to the file in which break point is specified.
887 891 `filename` is used if not given.
892 local_ns : dict, optional
893 A local namespace in which `code` is executed.
888 894
889 895 Raises
890 896 ------
891 897 UsageError
892 898 If the break point given by `bp_line` is not valid.
893 899
894 900 """
895 901 deb = self.shell.InteractiveTB.pdb
896 902 if not deb:
897 903 self.shell.InteractiveTB.pdb = self.shell.InteractiveTB.debugger_cls()
898 904 deb = self.shell.InteractiveTB.pdb
899 905
900 906 # deb.checkline() fails if deb.curframe exists but is None; it can
901 907 # handle it not existing. https://github.com/ipython/ipython/issues/10028
902 908 if hasattr(deb, 'curframe'):
903 909 del deb.curframe
904 910
905 911 # reset Breakpoint state, which is moronically kept
906 912 # in a class
907 913 bdb.Breakpoint.next = 1
908 914 bdb.Breakpoint.bplist = {}
909 915 bdb.Breakpoint.bpbynumber = [None]
910 916 deb.clear_all_breaks()
911 917 if bp_line is not None:
912 918 # Set an initial breakpoint to stop execution
913 919 maxtries = 10
914 920 bp_file = bp_file or filename
915 921 checkline = deb.checkline(bp_file, bp_line)
916 922 if not checkline:
917 923 for bp in range(bp_line + 1, bp_line + maxtries + 1):
918 924 if deb.checkline(bp_file, bp):
919 925 break
920 926 else:
921 927 msg = ("\nI failed to find a valid line to set "
922 928 "a breakpoint\n"
923 929 "after trying up to line: %s.\n"
924 930 "Please set a valid breakpoint manually "
925 931 "with the -b option." % bp)
926 932 raise UsageError(msg)
927 933 # if we find a good linenumber, set the breakpoint
928 934 deb.do_break('%s:%s' % (bp_file, bp_line))
929 935
930 936 if filename:
931 937 # Mimic Pdb._runscript(...)
932 938 deb._wait_for_mainpyfile = True
933 939 deb.mainpyfile = deb.canonic(filename)
934 940
935 941 # Start file run
936 942 print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
937 943 try:
938 944 if filename:
939 945 # save filename so it can be used by methods on the deb object
940 946 deb._exec_filename = filename
941 947 while True:
942 948 try:
943 949 trace = sys.gettrace()
944 deb.run(code, code_ns)
950 deb.run(code, code_ns, local_ns)
945 951 except Restart:
946 952 print("Restarting")
947 953 if filename:
948 954 deb._wait_for_mainpyfile = True
949 955 deb.mainpyfile = deb.canonic(filename)
950 956 continue
951 957 else:
952 958 break
953 959 finally:
954 960 sys.settrace(trace)
955 961
956 962
957 963 except:
958 964 etype, value, tb = sys.exc_info()
959 965 # Skip three frames in the traceback: the %run one,
960 966 # one inside bdb.py, and the command-line typed by the
961 967 # user (run by exec in pdb itself).
962 968 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
963 969
964 970 @staticmethod
965 971 def _run_with_timing(run, nruns):
966 972 """
967 973 Run function `run` and print timing information.
968 974
969 975 Parameters
970 976 ----------
971 977 run : callable
972 978 Any callable object which takes no argument.
973 979 nruns : int
974 980 Number of times to execute `run`.
975 981
976 982 """
977 983 twall0 = time.perf_counter()
978 984 if nruns == 1:
979 985 t0 = clock2()
980 986 run()
981 987 t1 = clock2()
982 988 t_usr = t1[0] - t0[0]
983 989 t_sys = t1[1] - t0[1]
984 990 print("\nIPython CPU timings (estimated):")
985 991 print(" User : %10.2f s." % t_usr)
986 992 print(" System : %10.2f s." % t_sys)
987 993 else:
988 994 runs = range(nruns)
989 995 t0 = clock2()
990 996 for nr in runs:
991 997 run()
992 998 t1 = clock2()
993 999 t_usr = t1[0] - t0[0]
994 1000 t_sys = t1[1] - t0[1]
995 1001 print("\nIPython CPU timings (estimated):")
996 1002 print("Total runs performed:", nruns)
997 1003 print(" Times : %10s %10s" % ('Total', 'Per run'))
998 1004 print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
999 1005 print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
1000 1006 twall1 = time.perf_counter()
1001 1007 print("Wall time: %10.2f s." % (twall1 - twall0))
1002 1008
1003 1009 @skip_doctest
1004 1010 @no_var_expand
1005 1011 @line_cell_magic
1006 1012 @needs_local_scope
1007 1013 def timeit(self, line='', cell=None, local_ns=None):
1008 1014 """Time execution of a Python statement or expression
1009 1015
1010 1016 Usage, in line mode:
1011 1017 %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
1012 1018 or in cell mode:
1013 1019 %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
1014 1020 code
1015 1021 code...
1016 1022
1017 1023 Time execution of a Python statement or expression using the timeit
1018 1024 module. This function can be used both as a line and cell magic:
1019 1025
1020 1026 - In line mode you can time a single-line statement (though multiple
1021 1027 ones can be chained with using semicolons).
1022 1028
1023 1029 - In cell mode, the statement in the first line is used as setup code
1024 1030 (executed but not timed) and the body of the cell is timed. The cell
1025 1031 body has access to any variables created in the setup code.
1026 1032
1027 1033 Options:
1028 1034 -n<N>: execute the given statement <N> times in a loop. If <N> is not
1029 1035 provided, <N> is determined so as to get sufficient accuracy.
1030 1036
1031 1037 -r<R>: number of repeats <R>, each consisting of <N> loops, and take the
1032 1038 best result.
1033 1039 Default: 7
1034 1040
1035 1041 -t: use time.time to measure the time, which is the default on Unix.
1036 1042 This function measures wall time.
1037 1043
1038 1044 -c: use time.clock to measure the time, which is the default on
1039 1045 Windows and measures wall time. On Unix, resource.getrusage is used
1040 1046 instead and returns the CPU user time.
1041 1047
1042 1048 -p<P>: use a precision of <P> digits to display the timing result.
1043 1049 Default: 3
1044 1050
1045 1051 -q: Quiet, do not print result.
1046 1052
1047 1053 -o: return a TimeitResult that can be stored in a variable to inspect
1048 1054 the result in more details.
1049 1055
1050 1056 .. versionchanged:: 7.3
1051 1057 User variables are no longer expanded,
1052 1058 the magic line is always left unmodified.
1053 1059
1054 1060 Examples
1055 1061 --------
1056 1062 ::
1057 1063
1058 1064 In [1]: %timeit pass
1059 1065 8.26 ns ± 0.12 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
1060 1066
1061 1067 In [2]: u = None
1062 1068
1063 1069 In [3]: %timeit u is None
1064 1070 29.9 ns ± 0.643 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
1065 1071
1066 1072 In [4]: %timeit -r 4 u == None
1067 1073
1068 1074 In [5]: import time
1069 1075
1070 1076 In [6]: %timeit -n1 time.sleep(2)
1071 1077
1072 1078 The times reported by %timeit will be slightly higher than those
1073 1079 reported by the timeit.py script when variables are accessed. This is
1074 1080 due to the fact that %timeit executes the statement in the namespace
1075 1081 of the shell, compared with timeit.py, which uses a single setup
1076 1082 statement to import function or create variables. Generally, the bias
1077 1083 does not matter as long as results from timeit.py are not mixed with
1078 1084 those from %timeit."""
1079 1085
1080 1086 opts, stmt = self.parse_options(
1081 1087 line, "n:r:tcp:qo", posix=False, strict=False, preserve_non_opts=True
1082 1088 )
1083 1089 if stmt == "" and cell is None:
1084 1090 return
1085 1091
1086 1092 timefunc = timeit.default_timer
1087 1093 number = int(getattr(opts, "n", 0))
1088 1094 default_repeat = 7 if timeit.default_repeat < 7 else timeit.default_repeat
1089 1095 repeat = int(getattr(opts, "r", default_repeat))
1090 1096 precision = int(getattr(opts, "p", 3))
1091 1097 quiet = 'q' in opts
1092 1098 return_result = 'o' in opts
1093 1099 if hasattr(opts, "t"):
1094 1100 timefunc = time.time
1095 1101 if hasattr(opts, "c"):
1096 1102 timefunc = clock
1097 1103
1098 1104 timer = Timer(timer=timefunc)
1099 1105 # this code has tight coupling to the inner workings of timeit.Timer,
1100 1106 # but is there a better way to achieve that the code stmt has access
1101 1107 # to the shell namespace?
1102 1108 transform = self.shell.transform_cell
1103 1109
1104 1110 if cell is None:
1105 1111 # called as line magic
1106 1112 ast_setup = self.shell.compile.ast_parse("pass")
1107 1113 ast_stmt = self.shell.compile.ast_parse(transform(stmt))
1108 1114 else:
1109 1115 ast_setup = self.shell.compile.ast_parse(transform(stmt))
1110 1116 ast_stmt = self.shell.compile.ast_parse(transform(cell))
1111 1117
1112 1118 ast_setup = self.shell.transform_ast(ast_setup)
1113 1119 ast_stmt = self.shell.transform_ast(ast_stmt)
1114 1120
1115 1121 # Check that these compile to valid Python code *outside* the timer func
1116 1122 # Invalid code may become valid when put inside the function & loop,
1117 1123 # which messes up error messages.
1118 1124 # https://github.com/ipython/ipython/issues/10636
1119 1125 self.shell.compile(ast_setup, "<magic-timeit-setup>", "exec")
1120 1126 self.shell.compile(ast_stmt, "<magic-timeit-stmt>", "exec")
1121 1127
1122 1128 # This codestring is taken from timeit.template - we fill it in as an
1123 1129 # AST, so that we can apply our AST transformations to the user code
1124 1130 # without affecting the timing code.
1125 1131 timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
1126 1132 ' setup\n'
1127 1133 ' _t0 = _timer()\n'
1128 1134 ' for _i in _it:\n'
1129 1135 ' stmt\n'
1130 1136 ' _t1 = _timer()\n'
1131 1137 ' return _t1 - _t0\n')
1132 1138
1133 1139 timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
1134 1140 timeit_ast = ast.fix_missing_locations(timeit_ast)
1135 1141
1136 1142 # Track compilation time so it can be reported if too long
1137 1143 # Minimum time above which compilation time will be reported
1138 1144 tc_min = 0.1
1139 1145
1140 1146 t0 = clock()
1141 1147 code = self.shell.compile(timeit_ast, "<magic-timeit>", "exec")
1142 1148 tc = clock()-t0
1143 1149
1144 1150 ns = {}
1145 1151 glob = self.shell.user_ns
1146 1152 # handles global vars with same name as local vars. We store them in conflict_globs.
1147 1153 conflict_globs = {}
1148 1154 if local_ns and cell is None:
1149 1155 for var_name, var_val in glob.items():
1150 1156 if var_name in local_ns:
1151 1157 conflict_globs[var_name] = var_val
1152 1158 glob.update(local_ns)
1153 1159
1154 1160 exec(code, glob, ns)
1155 1161 timer.inner = ns["inner"]
1156 1162
1157 1163 # This is used to check if there is a huge difference between the
1158 1164 # best and worst timings.
1159 1165 # Issue: https://github.com/ipython/ipython/issues/6471
1160 1166 if number == 0:
1161 1167 # determine number so that 0.2 <= total time < 2.0
1162 1168 for index in range(0, 10):
1163 1169 number = 10 ** index
1164 1170 time_number = timer.timeit(number)
1165 1171 if time_number >= 0.2:
1166 1172 break
1167 1173
1168 1174 all_runs = timer.repeat(repeat, number)
1169 1175 best = min(all_runs) / number
1170 1176 worst = max(all_runs) / number
1171 1177 timeit_result = TimeitResult(number, repeat, best, worst, all_runs, tc, precision)
1172 1178
1173 1179 # Restore global vars from conflict_globs
1174 1180 if conflict_globs:
1175 1181 glob.update(conflict_globs)
1176 1182
1177 1183 if not quiet :
1178 1184 # Check best timing is greater than zero to avoid a
1179 1185 # ZeroDivisionError.
1180 1186 # In cases where the slowest timing is lesser than a microsecond
1181 1187 # we assume that it does not really matter if the fastest
1182 1188 # timing is 4 times faster than the slowest timing or not.
1183 1189 if worst > 4 * best and best > 0 and worst > 1e-6:
1184 1190 print("The slowest run took %0.2f times longer than the "
1185 1191 "fastest. This could mean that an intermediate result "
1186 1192 "is being cached." % (worst / best))
1187 1193
1188 1194 print( timeit_result )
1189 1195
1190 1196 if tc > tc_min:
1191 1197 print("Compiler time: %.2f s" % tc)
1192 1198 if return_result:
1193 1199 return timeit_result
1194 1200
1195 1201 @skip_doctest
1196 1202 @no_var_expand
1197 1203 @needs_local_scope
1198 1204 @line_cell_magic
1199 1205 @output_can_be_silenced
1200 1206 def time(self,line='', cell=None, local_ns=None):
1201 1207 """Time execution of a Python statement or expression.
1202 1208
1203 1209 The CPU and wall clock times are printed, and the value of the
1204 1210 expression (if any) is returned. Note that under Win32, system time
1205 1211 is always reported as 0, since it can not be measured.
1206 1212
1207 1213 This function can be used both as a line and cell magic:
1208 1214
1209 1215 - In line mode you can time a single-line statement (though multiple
1210 1216 ones can be chained with using semicolons).
1211 1217
1212 1218 - In cell mode, you can time the cell body (a directly
1213 1219 following statement raises an error).
1214 1220
1215 1221 This function provides very basic timing functionality. Use the timeit
1216 1222 magic for more control over the measurement.
1217 1223
1218 1224 .. versionchanged:: 7.3
1219 1225 User variables are no longer expanded,
1220 1226 the magic line is always left unmodified.
1221 1227
1222 1228 Examples
1223 1229 --------
1224 1230 ::
1225 1231
1226 1232 In [1]: %time 2**128
1227 1233 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1228 1234 Wall time: 0.00
1229 1235 Out[1]: 340282366920938463463374607431768211456L
1230 1236
1231 1237 In [2]: n = 1000000
1232 1238
1233 1239 In [3]: %time sum(range(n))
1234 1240 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1235 1241 Wall time: 1.37
1236 1242 Out[3]: 499999500000L
1237 1243
1238 1244 In [4]: %time print 'hello world'
1239 1245 hello world
1240 1246 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1241 1247 Wall time: 0.00
1242 1248
1243 1249 .. note::
1244 1250 The time needed by Python to compile the given expression will be
1245 1251 reported if it is more than 0.1s.
1246 1252
1247 1253 In the example below, the actual exponentiation is done by Python
1248 1254 at compilation time, so while the expression can take a noticeable
1249 1255 amount of time to compute, that time is purely due to the
1250 1256 compilation::
1251 1257
1252 1258 In [5]: %time 3**9999;
1253 1259 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1254 1260 Wall time: 0.00 s
1255 1261
1256 1262 In [6]: %time 3**999999;
1257 1263 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1258 1264 Wall time: 0.00 s
1259 1265 Compiler : 0.78 s
1260 1266 """
1261 1267 # fail immediately if the given expression can't be compiled
1262 1268
1263 1269 if line and cell:
1264 1270 raise UsageError("Can't use statement directly after '%%time'!")
1265 1271
1266 1272 if cell:
1267 1273 expr = self.shell.transform_cell(cell)
1268 1274 else:
1269 1275 expr = self.shell.transform_cell(line)
1270 1276
1271 1277 # Minimum time above which parse time will be reported
1272 1278 tp_min = 0.1
1273 1279
1274 1280 t0 = clock()
1275 1281 expr_ast = self.shell.compile.ast_parse(expr)
1276 1282 tp = clock()-t0
1277 1283
1278 1284 # Apply AST transformations
1279 1285 expr_ast = self.shell.transform_ast(expr_ast)
1280 1286
1281 1287 # Minimum time above which compilation time will be reported
1282 1288 tc_min = 0.1
1283 1289
1284 1290 expr_val=None
1285 1291 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
1286 1292 mode = 'eval'
1287 1293 source = '<timed eval>'
1288 1294 expr_ast = ast.Expression(expr_ast.body[0].value)
1289 1295 else:
1290 1296 mode = 'exec'
1291 1297 source = '<timed exec>'
1292 1298 # multi-line %%time case
1293 1299 if len(expr_ast.body) > 1 and isinstance(expr_ast.body[-1], ast.Expr):
1294 1300 expr_val= expr_ast.body[-1]
1295 1301 expr_ast = expr_ast.body[:-1]
1296 1302 expr_ast = Module(expr_ast, [])
1297 1303 expr_val = ast.Expression(expr_val.value)
1298 1304
1299 1305 t0 = clock()
1300 1306 code = self.shell.compile(expr_ast, source, mode)
1301 1307 tc = clock()-t0
1302 1308
1303 1309 # skew measurement as little as possible
1304 1310 glob = self.shell.user_ns
1305 1311 wtime = time.time
1306 1312 # time execution
1307 1313 wall_st = wtime()
1308 1314 if mode=='eval':
1309 1315 st = clock2()
1310 1316 try:
1311 1317 out = eval(code, glob, local_ns)
1312 1318 except:
1313 1319 self.shell.showtraceback()
1314 1320 return
1315 1321 end = clock2()
1316 1322 else:
1317 1323 st = clock2()
1318 1324 try:
1319 1325 exec(code, glob, local_ns)
1320 1326 out=None
1321 1327 # multi-line %%time case
1322 1328 if expr_val is not None:
1323 1329 code_2 = self.shell.compile(expr_val, source, 'eval')
1324 1330 out = eval(code_2, glob, local_ns)
1325 1331 except:
1326 1332 self.shell.showtraceback()
1327 1333 return
1328 1334 end = clock2()
1329 1335
1330 1336 wall_end = wtime()
1331 1337 # Compute actual times and report
1332 1338 wall_time = wall_end - wall_st
1333 1339 cpu_user = end[0] - st[0]
1334 1340 cpu_sys = end[1] - st[1]
1335 1341 cpu_tot = cpu_user + cpu_sys
1336 1342 # On windows cpu_sys is always zero, so only total is displayed
1337 1343 if sys.platform != "win32":
1338 1344 print(
1339 1345 f"CPU times: user {_format_time(cpu_user)}, sys: {_format_time(cpu_sys)}, total: {_format_time(cpu_tot)}"
1340 1346 )
1341 1347 else:
1342 1348 print(f"CPU times: total: {_format_time(cpu_tot)}")
1343 1349 print(f"Wall time: {_format_time(wall_time)}")
1344 1350 if tc > tc_min:
1345 1351 print(f"Compiler : {_format_time(tc)}")
1346 1352 if tp > tp_min:
1347 1353 print(f"Parser : {_format_time(tp)}")
1348 1354 return out
1349 1355
1350 1356 @skip_doctest
1351 1357 @line_magic
1352 1358 def macro(self, parameter_s=''):
1353 1359 """Define a macro for future re-execution. It accepts ranges of history,
1354 1360 filenames or string objects.
1355 1361
1356 1362 Usage:\\
1357 1363 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1358 1364
1359 1365 Options:
1360 1366
1361 1367 -r: use 'raw' input. By default, the 'processed' history is used,
1362 1368 so that magics are loaded in their transformed version to valid
1363 1369 Python. If this option is given, the raw input as typed at the
1364 1370 command line is used instead.
1365 1371
1366 1372 -q: quiet macro definition. By default, a tag line is printed
1367 1373 to indicate the macro has been created, and then the contents of
1368 1374 the macro are printed. If this option is given, then no printout
1369 1375 is produced once the macro is created.
1370 1376
1371 1377 This will define a global variable called `name` which is a string
1372 1378 made of joining the slices and lines you specify (n1,n2,... numbers
1373 1379 above) from your input history into a single string. This variable
1374 1380 acts like an automatic function which re-executes those lines as if
1375 1381 you had typed them. You just type 'name' at the prompt and the code
1376 1382 executes.
1377 1383
1378 1384 The syntax for indicating input ranges is described in %history.
1379 1385
1380 1386 Note: as a 'hidden' feature, you can also use traditional python slice
1381 1387 notation, where N:M means numbers N through M-1.
1382 1388
1383 1389 For example, if your history contains (print using %hist -n )::
1384 1390
1385 1391 44: x=1
1386 1392 45: y=3
1387 1393 46: z=x+y
1388 1394 47: print x
1389 1395 48: a=5
1390 1396 49: print 'x',x,'y',y
1391 1397
1392 1398 you can create a macro with lines 44 through 47 (included) and line 49
1393 1399 called my_macro with::
1394 1400
1395 1401 In [55]: %macro my_macro 44-47 49
1396 1402
1397 1403 Now, typing `my_macro` (without quotes) will re-execute all this code
1398 1404 in one pass.
1399 1405
1400 1406 You don't need to give the line-numbers in order, and any given line
1401 1407 number can appear multiple times. You can assemble macros with any
1402 1408 lines from your input history in any order.
1403 1409
1404 1410 The macro is a simple object which holds its value in an attribute,
1405 1411 but IPython's display system checks for macros and executes them as
1406 1412 code instead of printing them when you type their name.
1407 1413
1408 1414 You can view a macro's contents by explicitly printing it with::
1409 1415
1410 1416 print macro_name
1411 1417
1412 1418 """
1413 1419 opts,args = self.parse_options(parameter_s,'rq',mode='list')
1414 1420 if not args: # List existing macros
1415 1421 return sorted(k for k,v in self.shell.user_ns.items() if isinstance(v, Macro))
1416 1422 if len(args) == 1:
1417 1423 raise UsageError(
1418 1424 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1419 1425 name, codefrom = args[0], " ".join(args[1:])
1420 1426
1421 1427 #print 'rng',ranges # dbg
1422 1428 try:
1423 1429 lines = self.shell.find_user_code(codefrom, 'r' in opts)
1424 1430 except (ValueError, TypeError) as e:
1425 1431 print(e.args[0])
1426 1432 return
1427 1433 macro = Macro(lines)
1428 1434 self.shell.define_macro(name, macro)
1429 1435 if not ( 'q' in opts) :
1430 1436 print('Macro `%s` created. To execute, type its name (without quotes).' % name)
1431 1437 print('=== Macro contents: ===')
1432 1438 print(macro, end=' ')
1433 1439
1434 1440 @magic_arguments.magic_arguments()
1435 1441 @magic_arguments.argument('output', type=str, default='', nargs='?',
1436 1442 help="""The name of the variable in which to store output.
1437 1443 This is a utils.io.CapturedIO object with stdout/err attributes
1438 1444 for the text of the captured output.
1439 1445
1440 1446 CapturedOutput also has a show() method for displaying the output,
1441 1447 and __call__ as well, so you can use that to quickly display the
1442 1448 output.
1443 1449
1444 1450 If unspecified, captured output is discarded.
1445 1451 """
1446 1452 )
1447 1453 @magic_arguments.argument('--no-stderr', action="store_true",
1448 1454 help="""Don't capture stderr."""
1449 1455 )
1450 1456 @magic_arguments.argument('--no-stdout', action="store_true",
1451 1457 help="""Don't capture stdout."""
1452 1458 )
1453 1459 @magic_arguments.argument('--no-display', action="store_true",
1454 1460 help="""Don't capture IPython's rich display."""
1455 1461 )
1456 1462 @cell_magic
1457 1463 def capture(self, line, cell):
1458 1464 """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1459 1465 args = magic_arguments.parse_argstring(self.capture, line)
1460 1466 out = not args.no_stdout
1461 1467 err = not args.no_stderr
1462 1468 disp = not args.no_display
1463 1469 with capture_output(out, err, disp) as io:
1464 1470 self.shell.run_cell(cell)
1465 1471 if DisplayHook.semicolon_at_end_of_expression(cell):
1466 1472 if args.output in self.shell.user_ns:
1467 1473 del self.shell.user_ns[args.output]
1468 1474 elif args.output:
1469 1475 self.shell.user_ns[args.output] = io
1470 1476
1471 1477 def parse_breakpoint(text, current_file):
1472 1478 '''Returns (file, line) for file:line and (current_file, line) for line'''
1473 1479 colon = text.find(':')
1474 1480 if colon == -1:
1475 1481 return current_file, int(text)
1476 1482 else:
1477 1483 return text[:colon], int(text[colon+1:])
1478 1484
1479 1485 def _format_time(timespan, precision=3):
1480 1486 """Formats the timespan in a human readable form"""
1481 1487
1482 1488 if timespan >= 60.0:
1483 1489 # we have more than a minute, format that in a human readable form
1484 1490 # Idea from http://snipplr.com/view/5713/
1485 1491 parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
1486 1492 time = []
1487 1493 leftover = timespan
1488 1494 for suffix, length in parts:
1489 1495 value = int(leftover / length)
1490 1496 if value > 0:
1491 1497 leftover = leftover % length
1492 1498 time.append(u'%s%s' % (str(value), suffix))
1493 1499 if leftover < 1:
1494 1500 break
1495 1501 return " ".join(time)
1496 1502
1497 1503
1498 1504 # Unfortunately the unicode 'micro' symbol can cause problems in
1499 1505 # certain terminals.
1500 1506 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1501 1507 # Try to prevent crashes by being more secure than it needs to
1502 1508 # E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set.
1503 1509 units = [u"s", u"ms",u'us',"ns"] # the save value
1504 1510 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
1505 1511 try:
1506 1512 u'\xb5'.encode(sys.stdout.encoding)
1507 1513 units = [u"s", u"ms",u'\xb5s',"ns"]
1508 1514 except:
1509 1515 pass
1510 1516 scaling = [1, 1e3, 1e6, 1e9]
1511 1517
1512 1518 if timespan > 0.0:
1513 1519 order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1514 1520 else:
1515 1521 order = 3
1516 1522 return u"%.*g %s" % (precision, timespan * scaling[order], units[order])
@@ -1,1080 +1,1093 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tools for inspecting Python objects.
3 3
4 4 Uses syntax highlighting for presenting the various information elements.
5 5
6 6 Similar in spirit to the inspect module, but all calls take a name argument to
7 7 reference the name under which an object is being read.
8 8 """
9 9
10 10 # Copyright (c) IPython Development Team.
11 11 # Distributed under the terms of the Modified BSD License.
12 12
13 13 __all__ = ['Inspector','InspectColors']
14 14
15 15 # stdlib modules
16 16 import ast
17 17 import inspect
18 18 from inspect import signature
19 19 import html
20 20 import linecache
21 21 import warnings
22 22 import os
23 23 from textwrap import dedent
24 24 import types
25 25 import io as stdlib_io
26 26
27 27 from typing import Union
28 28
29 29 # IPython's own
30 30 from IPython.core import page
31 31 from IPython.lib.pretty import pretty
32 32 from IPython.testing.skipdoctest import skip_doctest
33 33 from IPython.utils import PyColorize
34 34 from IPython.utils import openpy
35 35 from IPython.utils.dir2 import safe_hasattr
36 36 from IPython.utils.path import compress_user
37 37 from IPython.utils.text import indent
38 38 from IPython.utils.wildcard import list_namespace
39 39 from IPython.utils.wildcard import typestr2type
40 40 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
41 41 from IPython.utils.py3compat import cast_unicode
42 42 from IPython.utils.colorable import Colorable
43 43 from IPython.utils.decorators import undoc
44 44
45 45 from pygments import highlight
46 46 from pygments.lexers import PythonLexer
47 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 62 def pylight(code):
50 63 return highlight(code, PythonLexer(), HtmlFormatter(noclasses=True))
51 64
52 65 # builtin docstrings to ignore
53 66 _func_call_docstring = types.FunctionType.__call__.__doc__
54 67 _object_init_docstring = object.__init__.__doc__
55 68 _builtin_type_docstrings = {
56 69 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
57 70 types.FunctionType, property)
58 71 }
59 72
60 73 _builtin_func_type = type(all)
61 74 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
62 75 #****************************************************************************
63 76 # Builtin color schemes
64 77
65 78 Colors = TermColors # just a shorthand
66 79
67 80 InspectColors = PyColorize.ANSICodeColors
68 81
69 82 #****************************************************************************
70 83 # Auxiliary functions and objects
71 84
72 85 # See the messaging spec for the definition of all these fields. This list
73 86 # effectively defines the order of display
74 87 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
75 88 'length', 'file', 'definition', 'docstring', 'source',
76 89 'init_definition', 'class_docstring', 'init_docstring',
77 90 'call_def', 'call_docstring',
78 91 # These won't be printed but will be used to determine how to
79 92 # format the object
80 93 'ismagic', 'isalias', 'isclass', 'found', 'name'
81 94 ]
82 95
83 96
84 97 def object_info(**kw):
85 98 """Make an object info dict with all fields present."""
86 99 infodict = {k:None for k in info_fields}
87 100 infodict.update(kw)
88 101 return infodict
89 102
90 103
91 104 def get_encoding(obj):
92 105 """Get encoding for python source file defining obj
93 106
94 107 Returns None if obj is not defined in a sourcefile.
95 108 """
96 109 ofile = find_file(obj)
97 110 # run contents of file through pager starting at line where the object
98 111 # is defined, as long as the file isn't binary and is actually on the
99 112 # filesystem.
100 113 if ofile is None:
101 114 return None
102 115 elif ofile.endswith(('.so', '.dll', '.pyd')):
103 116 return None
104 117 elif not os.path.isfile(ofile):
105 118 return None
106 119 else:
107 120 # Print only text files, not extension binaries. Note that
108 121 # getsourcelines returns lineno with 1-offset and page() uses
109 122 # 0-offset, so we must adjust.
110 123 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
111 124 encoding, lines = openpy.detect_encoding(buffer.readline)
112 125 return encoding
113 126
114 127 def getdoc(obj) -> Union[str,None]:
115 128 """Stable wrapper around inspect.getdoc.
116 129
117 130 This can't crash because of attribute problems.
118 131
119 132 It also attempts to call a getdoc() method on the given object. This
120 133 allows objects which provide their docstrings via non-standard mechanisms
121 134 (like Pyro proxies) to still be inspected by ipython's ? system.
122 135 """
123 136 # Allow objects to offer customized documentation via a getdoc method:
124 137 try:
125 138 ds = obj.getdoc()
126 139 except Exception:
127 140 pass
128 141 else:
129 142 if isinstance(ds, str):
130 143 return inspect.cleandoc(ds)
131 144 docstr = inspect.getdoc(obj)
132 145 return docstr
133 146
134 147
135 148 def getsource(obj, oname='') -> Union[str,None]:
136 149 """Wrapper around inspect.getsource.
137 150
138 151 This can be modified by other projects to provide customized source
139 152 extraction.
140 153
141 154 Parameters
142 155 ----------
143 156 obj : object
144 157 an object whose source code we will attempt to extract
145 158 oname : str
146 159 (optional) a name under which the object is known
147 160
148 161 Returns
149 162 -------
150 163 src : unicode or None
151 164
152 165 """
153 166
154 167 if isinstance(obj, property):
155 168 sources = []
156 169 for attrname in ['fget', 'fset', 'fdel']:
157 170 fn = getattr(obj, attrname)
158 171 if fn is not None:
159 172 encoding = get_encoding(fn)
160 173 oname_prefix = ('%s.' % oname) if oname else ''
161 174 sources.append(''.join(('# ', oname_prefix, attrname)))
162 175 if inspect.isfunction(fn):
163 176 sources.append(dedent(getsource(fn)))
164 177 else:
165 178 # Default str/repr only prints function name,
166 179 # pretty.pretty prints module name too.
167 180 sources.append(
168 181 '%s%s = %s\n' % (oname_prefix, attrname, pretty(fn))
169 182 )
170 183 if sources:
171 184 return '\n'.join(sources)
172 185 else:
173 186 return None
174 187
175 188 else:
176 189 # Get source for non-property objects.
177 190
178 191 obj = _get_wrapped(obj)
179 192
180 193 try:
181 194 src = inspect.getsource(obj)
182 195 except TypeError:
183 196 # The object itself provided no meaningful source, try looking for
184 197 # its class definition instead.
185 198 try:
186 199 src = inspect.getsource(obj.__class__)
187 200 except (OSError, TypeError):
188 201 return None
189 202 except OSError:
190 203 return None
191 204
192 205 return src
193 206
194 207
195 208 def is_simple_callable(obj):
196 209 """True if obj is a function ()"""
197 210 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
198 211 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
199 212
200 213 @undoc
201 214 def getargspec(obj):
202 215 """Wrapper around :func:`inspect.getfullargspec`
203 216
204 217 In addition to functions and methods, this can also handle objects with a
205 218 ``__call__`` attribute.
206 219
207 220 DEPRECATED: Deprecated since 7.10. Do not use, will be removed.
208 221 """
209 222
210 223 warnings.warn('`getargspec` function is deprecated as of IPython 7.10'
211 224 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
212 225
213 226 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
214 227 obj = obj.__call__
215 228
216 229 return inspect.getfullargspec(obj)
217 230
218 231 @undoc
219 232 def format_argspec(argspec):
220 233 """Format argspect, convenience wrapper around inspect's.
221 234
222 235 This takes a dict instead of ordered arguments and calls
223 236 inspect.format_argspec with the arguments in the necessary order.
224 237
225 238 DEPRECATED (since 7.10): Do not use; will be removed in future versions.
226 239 """
227 240
228 241 warnings.warn('`format_argspec` function is deprecated as of IPython 7.10'
229 242 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
230 243
231 244
232 245 return inspect.formatargspec(argspec['args'], argspec['varargs'],
233 246 argspec['varkw'], argspec['defaults'])
234 247
235 248 @undoc
236 249 def call_tip(oinfo, format_call=True):
237 250 """DEPRECATED since 6.0. Extract call tip data from an oinfo dict."""
238 251 warnings.warn(
239 252 "`call_tip` function is deprecated as of IPython 6.0"
240 253 "and will be removed in future versions.",
241 254 DeprecationWarning,
242 255 stacklevel=2,
243 256 )
244 257 # Get call definition
245 258 argspec = oinfo.get('argspec')
246 259 if argspec is None:
247 260 call_line = None
248 261 else:
249 262 # Callable objects will have 'self' as their first argument, prune
250 263 # it out if it's there for clarity (since users do *not* pass an
251 264 # extra first argument explicitly).
252 265 try:
253 266 has_self = argspec['args'][0] == 'self'
254 267 except (KeyError, IndexError):
255 268 pass
256 269 else:
257 270 if has_self:
258 271 argspec['args'] = argspec['args'][1:]
259 272
260 273 call_line = oinfo['name']+format_argspec(argspec)
261 274
262 275 # Now get docstring.
263 276 # The priority is: call docstring, constructor docstring, main one.
264 277 doc = oinfo.get('call_docstring')
265 278 if doc is None:
266 279 doc = oinfo.get('init_docstring')
267 280 if doc is None:
268 281 doc = oinfo.get('docstring','')
269 282
270 283 return call_line, doc
271 284
272 285
273 286 def _get_wrapped(obj):
274 287 """Get the original object if wrapped in one or more @decorators
275 288
276 289 Some objects automatically construct similar objects on any unrecognised
277 290 attribute access (e.g. unittest.mock.call). To protect against infinite loops,
278 291 this will arbitrarily cut off after 100 levels of obj.__wrapped__
279 292 attribute access. --TK, Jan 2016
280 293 """
281 294 orig_obj = obj
282 295 i = 0
283 296 while safe_hasattr(obj, '__wrapped__'):
284 297 obj = obj.__wrapped__
285 298 i += 1
286 299 if i > 100:
287 300 # __wrapped__ is probably a lie, so return the thing we started with
288 301 return orig_obj
289 302 return obj
290 303
291 304 def find_file(obj) -> str:
292 305 """Find the absolute path to the file where an object was defined.
293 306
294 307 This is essentially a robust wrapper around `inspect.getabsfile`.
295 308
296 309 Returns None if no file can be found.
297 310
298 311 Parameters
299 312 ----------
300 313 obj : any Python object
301 314
302 315 Returns
303 316 -------
304 317 fname : str
305 318 The absolute path to the file where the object was defined.
306 319 """
307 320 obj = _get_wrapped(obj)
308 321
309 322 fname = None
310 323 try:
311 324 fname = inspect.getabsfile(obj)
312 325 except TypeError:
313 326 # For an instance, the file that matters is where its class was
314 327 # declared.
315 328 try:
316 329 fname = inspect.getabsfile(obj.__class__)
317 330 except (OSError, TypeError):
318 331 # Can happen for builtins
319 332 pass
320 333 except OSError:
321 334 pass
322 335
323 336 return cast_unicode(fname)
324 337
325 338
326 339 def find_source_lines(obj):
327 340 """Find the line number in a file where an object was defined.
328 341
329 342 This is essentially a robust wrapper around `inspect.getsourcelines`.
330 343
331 344 Returns None if no file can be found.
332 345
333 346 Parameters
334 347 ----------
335 348 obj : any Python object
336 349
337 350 Returns
338 351 -------
339 352 lineno : int
340 353 The line number where the object definition starts.
341 354 """
342 355 obj = _get_wrapped(obj)
343 356
344 357 try:
345 358 lineno = inspect.getsourcelines(obj)[1]
346 359 except TypeError:
347 360 # For instances, try the class object like getsource() does
348 361 try:
349 362 lineno = inspect.getsourcelines(obj.__class__)[1]
350 363 except (OSError, TypeError):
351 364 return None
352 365 except OSError:
353 366 return None
354 367
355 368 return lineno
356 369
357 370 class Inspector(Colorable):
358 371
359 372 def __init__(self, color_table=InspectColors,
360 373 code_color_table=PyColorize.ANSICodeColors,
361 374 scheme=None,
362 375 str_detail_level=0,
363 376 parent=None, config=None):
364 377 super(Inspector, self).__init__(parent=parent, config=config)
365 378 self.color_table = color_table
366 379 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
367 380 self.format = self.parser.format
368 381 self.str_detail_level = str_detail_level
369 382 self.set_active_scheme(scheme)
370 383
371 384 def _getdef(self,obj,oname='') -> Union[str,None]:
372 385 """Return the call signature for any callable object.
373 386
374 387 If any exception is generated, None is returned instead and the
375 388 exception is suppressed."""
376 389 try:
377 390 return _render_signature(signature(obj), oname)
378 391 except:
379 392 return None
380 393
381 394 def __head(self,h) -> str:
382 395 """Return a header string with proper colors."""
383 396 return '%s%s%s' % (self.color_table.active_colors.header,h,
384 397 self.color_table.active_colors.normal)
385 398
386 399 def set_active_scheme(self, scheme):
387 400 if scheme is not None:
388 401 self.color_table.set_active_scheme(scheme)
389 402 self.parser.color_table.set_active_scheme(scheme)
390 403
391 404 def noinfo(self, msg, oname):
392 405 """Generic message when no information is found."""
393 406 print('No %s found' % msg, end=' ')
394 407 if oname:
395 408 print('for %s' % oname)
396 409 else:
397 410 print()
398 411
399 412 def pdef(self, obj, oname=''):
400 413 """Print the call signature for any callable object.
401 414
402 415 If the object is a class, print the constructor information."""
403 416
404 417 if not callable(obj):
405 418 print('Object is not callable.')
406 419 return
407 420
408 421 header = ''
409 422
410 423 if inspect.isclass(obj):
411 424 header = self.__head('Class constructor information:\n')
412 425
413 426
414 427 output = self._getdef(obj,oname)
415 428 if output is None:
416 429 self.noinfo('definition header',oname)
417 430 else:
418 431 print(header,self.format(output), end=' ')
419 432
420 433 # In Python 3, all classes are new-style, so they all have __init__.
421 434 @skip_doctest
422 435 def pdoc(self, obj, oname='', formatter=None):
423 436 """Print the docstring for any object.
424 437
425 438 Optional:
426 439 -formatter: a function to run the docstring through for specially
427 440 formatted docstrings.
428 441
429 442 Examples
430 443 --------
431 444 In [1]: class NoInit:
432 445 ...: pass
433 446
434 447 In [2]: class NoDoc:
435 448 ...: def __init__(self):
436 449 ...: pass
437 450
438 451 In [3]: %pdoc NoDoc
439 452 No documentation found for NoDoc
440 453
441 454 In [4]: %pdoc NoInit
442 455 No documentation found for NoInit
443 456
444 457 In [5]: obj = NoInit()
445 458
446 459 In [6]: %pdoc obj
447 460 No documentation found for obj
448 461
449 462 In [5]: obj2 = NoDoc()
450 463
451 464 In [6]: %pdoc obj2
452 465 No documentation found for obj2
453 466 """
454 467
455 468 head = self.__head # For convenience
456 469 lines = []
457 470 ds = getdoc(obj)
458 471 if formatter:
459 472 ds = formatter(ds).get('plain/text', ds)
460 473 if ds:
461 474 lines.append(head("Class docstring:"))
462 475 lines.append(indent(ds))
463 476 if inspect.isclass(obj) and hasattr(obj, '__init__'):
464 477 init_ds = getdoc(obj.__init__)
465 478 if init_ds is not None:
466 479 lines.append(head("Init docstring:"))
467 480 lines.append(indent(init_ds))
468 481 elif hasattr(obj,'__call__'):
469 482 call_ds = getdoc(obj.__call__)
470 483 if call_ds:
471 484 lines.append(head("Call docstring:"))
472 485 lines.append(indent(call_ds))
473 486
474 487 if not lines:
475 488 self.noinfo('documentation',oname)
476 489 else:
477 490 page.page('\n'.join(lines))
478 491
479 492 def psource(self, obj, oname=''):
480 493 """Print the source code for an object."""
481 494
482 495 # Flush the source cache because inspect can return out-of-date source
483 496 linecache.checkcache()
484 497 try:
485 498 src = getsource(obj, oname=oname)
486 499 except Exception:
487 500 src = None
488 501
489 502 if src is None:
490 503 self.noinfo('source', oname)
491 504 else:
492 505 page.page(self.format(src))
493 506
494 507 def pfile(self, obj, oname=''):
495 508 """Show the whole file where an object was defined."""
496 509
497 510 lineno = find_source_lines(obj)
498 511 if lineno is None:
499 512 self.noinfo('file', oname)
500 513 return
501 514
502 515 ofile = find_file(obj)
503 516 # run contents of file through pager starting at line where the object
504 517 # is defined, as long as the file isn't binary and is actually on the
505 518 # filesystem.
506 519 if ofile.endswith(('.so', '.dll', '.pyd')):
507 520 print('File %r is binary, not printing.' % ofile)
508 521 elif not os.path.isfile(ofile):
509 522 print('File %r does not exist, not printing.' % ofile)
510 523 else:
511 524 # Print only text files, not extension binaries. Note that
512 525 # getsourcelines returns lineno with 1-offset and page() uses
513 526 # 0-offset, so we must adjust.
514 527 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
515 528
516 529
517 530 def _mime_format(self, text:str, formatter=None) -> dict:
518 531 """Return a mime bundle representation of the input text.
519 532
520 533 - if `formatter` is None, the returned mime bundle has
521 534 a ``text/plain`` field, with the input text.
522 535 a ``text/html`` field with a ``<pre>`` tag containing the input text.
523 536
524 537 - if ``formatter`` is not None, it must be a callable transforming the
525 538 input text into a mime bundle. Default values for ``text/plain`` and
526 539 ``text/html`` representations are the ones described above.
527 540
528 541 Note:
529 542
530 543 Formatters returning strings are supported but this behavior is deprecated.
531 544
532 545 """
533 546 defaults = {
534 547 "text/plain": text,
535 548 "text/html": f"<pre>{html.escape(text)}</pre>",
536 549 }
537 550
538 551 if formatter is None:
539 552 return defaults
540 553 else:
541 554 formatted = formatter(text)
542 555
543 556 if not isinstance(formatted, dict):
544 557 # Handle the deprecated behavior of a formatter returning
545 558 # a string instead of a mime bundle.
546 559 return {"text/plain": formatted, "text/html": f"<pre>{formatted}</pre>"}
547 560
548 561 else:
549 562 return dict(defaults, **formatted)
550 563
551 564
552 565 def format_mime(self, bundle):
553 566 """Format a mimebundle being created by _make_info_unformatted into a real mimebundle"""
554 567 # Format text/plain mimetype
555 568 if isinstance(bundle["text/plain"], (list, tuple)):
556 569 # bundle['text/plain'] is a list of (head, formatted body) pairs
557 570 lines = []
558 571 _len = max(len(h) for h, _ in bundle["text/plain"])
559 572
560 573 for head, body in bundle["text/plain"]:
561 574 body = body.strip("\n")
562 575 delim = "\n" if "\n" in body else " "
563 576 lines.append(
564 577 f"{self.__head(head+':')}{(_len - len(head))*' '}{delim}{body}"
565 578 )
566 579
567 580 bundle["text/plain"] = "\n".join(lines)
568 581
569 582 # Format the text/html mimetype
570 583 if isinstance(bundle["text/html"], (list, tuple)):
571 584 # bundle['text/html'] is a list of (head, formatted body) pairs
572 585 bundle["text/html"] = "\n".join(
573 586 (f"<h1>{head}</h1>\n{body}" for (head, body) in bundle["text/html"])
574 587 )
575 588 return bundle
576 589
577 590 def _append_info_field(
578 591 self, bundle, title: str, key: str, info, omit_sections, formatter
579 592 ):
580 593 """Append an info value to the unformatted mimebundle being constructed by _make_info_unformatted"""
581 594 if title in omit_sections or key in omit_sections:
582 595 return
583 596 field = info[key]
584 597 if field is not None:
585 598 formatted_field = self._mime_format(field, formatter)
586 599 bundle["text/plain"].append((title, formatted_field["text/plain"]))
587 600 bundle["text/html"].append((title, formatted_field["text/html"]))
588 601
589 602 def _make_info_unformatted(self, obj, info, formatter, detail_level, omit_sections):
590 603 """Assemble the mimebundle as unformatted lists of information"""
591 604 bundle = {
592 605 "text/plain": [],
593 606 "text/html": [],
594 607 }
595 608
596 609 # A convenience function to simplify calls below
597 610 def append_field(bundle, title: str, key: str, formatter=None):
598 611 self._append_info_field(
599 612 bundle,
600 613 title=title,
601 614 key=key,
602 615 info=info,
603 616 omit_sections=omit_sections,
604 617 formatter=formatter,
605 618 )
606 619
607 620 def code_formatter(text):
608 621 return {
609 622 'text/plain': self.format(text),
610 623 'text/html': pylight(text)
611 624 }
612 625
613 626 if info["isalias"]:
614 627 append_field(bundle, "Repr", "string_form")
615 628
616 629 elif info['ismagic']:
617 630 if detail_level > 0:
618 631 append_field(bundle, "Source", "source", code_formatter)
619 632 else:
620 633 append_field(bundle, "Docstring", "docstring", formatter)
621 634 append_field(bundle, "File", "file")
622 635
623 636 elif info['isclass'] or is_simple_callable(obj):
624 637 # Functions, methods, classes
625 638 append_field(bundle, "Signature", "definition", code_formatter)
626 639 append_field(bundle, "Init signature", "init_definition", code_formatter)
627 640 append_field(bundle, "Docstring", "docstring", formatter)
628 641 if detail_level > 0 and info["source"]:
629 642 append_field(bundle, "Source", "source", code_formatter)
630 643 else:
631 644 append_field(bundle, "Init docstring", "init_docstring", formatter)
632 645
633 646 append_field(bundle, "File", "file")
634 647 append_field(bundle, "Type", "type_name")
635 648 append_field(bundle, "Subclasses", "subclasses")
636 649
637 650 else:
638 651 # General Python objects
639 652 append_field(bundle, "Signature", "definition", code_formatter)
640 653 append_field(bundle, "Call signature", "call_def", code_formatter)
641 654 append_field(bundle, "Type", "type_name")
642 655 append_field(bundle, "String form", "string_form")
643 656
644 657 # Namespace
645 658 if info["namespace"] != "Interactive":
646 659 append_field(bundle, "Namespace", "namespace")
647 660
648 661 append_field(bundle, "Length", "length")
649 662 append_field(bundle, "File", "file")
650 663
651 664 # Source or docstring, depending on detail level and whether
652 665 # source found.
653 666 if detail_level > 0 and info["source"]:
654 667 append_field(bundle, "Source", "source", code_formatter)
655 668 else:
656 669 append_field(bundle, "Docstring", "docstring", formatter)
657 670
658 671 append_field(bundle, "Class docstring", "class_docstring", formatter)
659 672 append_field(bundle, "Init docstring", "init_docstring", formatter)
660 673 append_field(bundle, "Call docstring", "call_docstring", formatter)
661 674 return bundle
662 675
663 676
664 677 def _get_info(
665 678 self, obj, oname="", formatter=None, info=None, detail_level=0, omit_sections=()
666 679 ):
667 680 """Retrieve an info dict and format it.
668 681
669 682 Parameters
670 683 ----------
671 684 obj : any
672 685 Object to inspect and return info from
673 686 oname : str (default: ''):
674 687 Name of the variable pointing to `obj`.
675 688 formatter : callable
676 689 info
677 690 already computed information
678 691 detail_level : integer
679 692 Granularity of detail level, if set to 1, give more information.
680 693 omit_sections : container[str]
681 694 Titles or keys to omit from output (can be set, tuple, etc., anything supporting `in`)
682 695 """
683 696
684 697 info = self.info(obj, oname=oname, info=info, detail_level=detail_level)
685 698 bundle = self._make_info_unformatted(
686 699 obj, info, formatter, detail_level=detail_level, omit_sections=omit_sections
687 700 )
688 701 return self.format_mime(bundle)
689 702
690 703 def pinfo(
691 704 self,
692 705 obj,
693 706 oname="",
694 707 formatter=None,
695 708 info=None,
696 709 detail_level=0,
697 710 enable_html_pager=True,
698 711 omit_sections=(),
699 712 ):
700 713 """Show detailed information about an object.
701 714
702 715 Optional arguments:
703 716
704 717 - oname: name of the variable pointing to the object.
705 718
706 719 - formatter: callable (optional)
707 720 A special formatter for docstrings.
708 721
709 722 The formatter is a callable that takes a string as an input
710 723 and returns either a formatted string or a mime type bundle
711 724 in the form of a dictionary.
712 725
713 726 Although the support of custom formatter returning a string
714 727 instead of a mime type bundle is deprecated.
715 728
716 729 - info: a structure with some information fields which may have been
717 730 precomputed already.
718 731
719 732 - detail_level: if set to 1, more information is given.
720 733
721 734 - omit_sections: set of section keys and titles to omit
722 735 """
723 736 info = self._get_info(
724 737 obj, oname, formatter, info, detail_level, omit_sections=omit_sections
725 738 )
726 739 if not enable_html_pager:
727 740 del info['text/html']
728 741 page.page(info)
729 742
730 743 def _info(self, obj, oname="", info=None, detail_level=0):
731 744 """
732 745 Inspector.info() was likely improperly marked as deprecated
733 746 while only a parameter was deprecated. We "un-deprecate" it.
734 747 """
735 748
736 749 warnings.warn(
737 750 "The `Inspector.info()` method has been un-deprecated as of 8.0 "
738 751 "and the `formatter=` keyword removed. `Inspector._info` is now "
739 752 "an alias, and you can just call `.info()` directly.",
740 753 DeprecationWarning,
741 754 stacklevel=2,
742 755 )
743 756 return self.info(obj, oname=oname, info=info, detail_level=detail_level)
744 757
745 758 def info(self, obj, oname="", info=None, detail_level=0) -> dict:
746 759 """Compute a dict with detailed information about an object.
747 760
748 761 Parameters
749 762 ----------
750 763 obj : any
751 764 An object to find information about
752 765 oname : str (default: '')
753 766 Name of the variable pointing to `obj`.
754 767 info : (default: None)
755 768 A struct (dict like with attr access) with some information fields
756 769 which may have been precomputed already.
757 770 detail_level : int (default:0)
758 771 If set to 1, more information is given.
759 772
760 773 Returns
761 774 -------
762 775 An object info dict with known fields from `info_fields`. Keys are
763 776 strings, values are string or None.
764 777 """
765 778
766 779 if info is None:
767 780 ismagic = False
768 781 isalias = False
769 782 ospace = ''
770 783 else:
771 784 ismagic = info.ismagic
772 785 isalias = info.isalias
773 786 ospace = info.namespace
774 787
775 788 # Get docstring, special-casing aliases:
776 789 if isalias:
777 790 if not callable(obj):
778 791 try:
779 792 ds = "Alias to the system command:\n %s" % obj[1]
780 793 except:
781 794 ds = "Alias: " + str(obj)
782 795 else:
783 796 ds = "Alias to " + str(obj)
784 797 if obj.__doc__:
785 798 ds += "\nDocstring:\n" + obj.__doc__
786 799 else:
787 800 ds = getdoc(obj)
788 801 if ds is None:
789 802 ds = '<no docstring>'
790 803
791 804 # store output in a dict, we initialize it here and fill it as we go
792 805 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic, subclasses=None)
793 806
794 807 string_max = 200 # max size of strings to show (snipped if longer)
795 808 shalf = int((string_max - 5) / 2)
796 809
797 810 if ismagic:
798 811 out['type_name'] = 'Magic function'
799 812 elif isalias:
800 813 out['type_name'] = 'System alias'
801 814 else:
802 815 out['type_name'] = type(obj).__name__
803 816
804 817 try:
805 818 bclass = obj.__class__
806 819 out['base_class'] = str(bclass)
807 820 except:
808 821 pass
809 822
810 823 # String form, but snip if too long in ? form (full in ??)
811 824 if detail_level >= self.str_detail_level:
812 825 try:
813 826 ostr = str(obj)
814 827 str_head = 'string_form'
815 828 if not detail_level and len(ostr)>string_max:
816 829 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
817 830 ostr = ("\n" + " " * len(str_head.expandtabs())).\
818 831 join(q.strip() for q in ostr.split("\n"))
819 832 out[str_head] = ostr
820 833 except:
821 834 pass
822 835
823 836 if ospace:
824 837 out['namespace'] = ospace
825 838
826 839 # Length (for strings and lists)
827 840 try:
828 841 out['length'] = str(len(obj))
829 842 except Exception:
830 843 pass
831 844
832 845 # Filename where object was defined
833 846 binary_file = False
834 847 fname = find_file(obj)
835 848 if fname is None:
836 849 # if anything goes wrong, we don't want to show source, so it's as
837 850 # if the file was binary
838 851 binary_file = True
839 852 else:
840 853 if fname.endswith(('.so', '.dll', '.pyd')):
841 854 binary_file = True
842 855 elif fname.endswith('<string>'):
843 856 fname = 'Dynamically generated function. No source code available.'
844 857 out['file'] = compress_user(fname)
845 858
846 859 # Original source code for a callable, class or property.
847 860 if detail_level:
848 861 # Flush the source cache because inspect can return out-of-date
849 862 # source
850 863 linecache.checkcache()
851 864 try:
852 865 if isinstance(obj, property) or not binary_file:
853 866 src = getsource(obj, oname)
854 867 if src is not None:
855 868 src = src.rstrip()
856 869 out['source'] = src
857 870
858 871 except Exception:
859 872 pass
860 873
861 874 # Add docstring only if no source is to be shown (avoid repetitions).
862 875 if ds and not self._source_contains_docstring(out.get('source'), ds):
863 876 out['docstring'] = ds
864 877
865 878 # Constructor docstring for classes
866 879 if inspect.isclass(obj):
867 880 out['isclass'] = True
868 881
869 882 # get the init signature:
870 883 try:
871 884 init_def = self._getdef(obj, oname)
872 885 except AttributeError:
873 886 init_def = None
874 887
875 888 # get the __init__ docstring
876 889 try:
877 890 obj_init = obj.__init__
878 891 except AttributeError:
879 892 init_ds = None
880 893 else:
881 894 if init_def is None:
882 895 # Get signature from init if top-level sig failed.
883 896 # Can happen for built-in types (list, etc.).
884 897 try:
885 898 init_def = self._getdef(obj_init, oname)
886 899 except AttributeError:
887 900 pass
888 901 init_ds = getdoc(obj_init)
889 902 # Skip Python's auto-generated docstrings
890 903 if init_ds == _object_init_docstring:
891 904 init_ds = None
892 905
893 906 if init_def:
894 907 out['init_definition'] = init_def
895 908
896 909 if init_ds:
897 910 out['init_docstring'] = init_ds
898 911
899 912 names = [sub.__name__ for sub in type.__subclasses__(obj)]
900 913 if len(names) < 10:
901 914 all_names = ', '.join(names)
902 915 else:
903 916 all_names = ', '.join(names[:10]+['...'])
904 917 out['subclasses'] = all_names
905 918 # and class docstring for instances:
906 919 else:
907 920 # reconstruct the function definition and print it:
908 921 defln = self._getdef(obj, oname)
909 922 if defln:
910 923 out['definition'] = defln
911 924
912 925 # First, check whether the instance docstring is identical to the
913 926 # class one, and print it separately if they don't coincide. In
914 927 # most cases they will, but it's nice to print all the info for
915 928 # objects which use instance-customized docstrings.
916 929 if ds:
917 930 try:
918 931 cls = getattr(obj,'__class__')
919 932 except:
920 933 class_ds = None
921 934 else:
922 935 class_ds = getdoc(cls)
923 936 # Skip Python's auto-generated docstrings
924 937 if class_ds in _builtin_type_docstrings:
925 938 class_ds = None
926 939 if class_ds and ds != class_ds:
927 940 out['class_docstring'] = class_ds
928 941
929 942 # Next, try to show constructor docstrings
930 943 try:
931 944 init_ds = getdoc(obj.__init__)
932 945 # Skip Python's auto-generated docstrings
933 946 if init_ds == _object_init_docstring:
934 947 init_ds = None
935 948 except AttributeError:
936 949 init_ds = None
937 950 if init_ds:
938 951 out['init_docstring'] = init_ds
939 952
940 953 # Call form docstring for callable instances
941 954 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
942 955 call_def = self._getdef(obj.__call__, oname)
943 956 if call_def and (call_def != out.get('definition')):
944 957 # it may never be the case that call def and definition differ,
945 958 # but don't include the same signature twice
946 959 out['call_def'] = call_def
947 960 call_ds = getdoc(obj.__call__)
948 961 # Skip Python's auto-generated docstrings
949 962 if call_ds == _func_call_docstring:
950 963 call_ds = None
951 964 if call_ds:
952 965 out['call_docstring'] = call_ds
953 966
954 967 return object_info(**out)
955 968
956 969 @staticmethod
957 970 def _source_contains_docstring(src, doc):
958 971 """
959 972 Check whether the source *src* contains the docstring *doc*.
960 973
961 974 This is is helper function to skip displaying the docstring if the
962 975 source already contains it, avoiding repetition of information.
963 976 """
964 977 try:
965 978 def_node, = ast.parse(dedent(src)).body
966 979 return ast.get_docstring(def_node) == doc
967 980 except Exception:
968 981 # The source can become invalid or even non-existent (because it
969 982 # is re-fetched from the source file) so the above code fail in
970 983 # arbitrary ways.
971 984 return False
972 985
973 986 def psearch(self,pattern,ns_table,ns_search=[],
974 987 ignore_case=False,show_all=False, *, list_types=False):
975 988 """Search namespaces with wildcards for objects.
976 989
977 990 Arguments:
978 991
979 992 - pattern: string containing shell-like wildcards to use in namespace
980 993 searches and optionally a type specification to narrow the search to
981 994 objects of that type.
982 995
983 996 - ns_table: dict of name->namespaces for search.
984 997
985 998 Optional arguments:
986 999
987 1000 - ns_search: list of namespace names to include in search.
988 1001
989 1002 - ignore_case(False): make the search case-insensitive.
990 1003
991 1004 - show_all(False): show all names, including those starting with
992 1005 underscores.
993 1006
994 1007 - list_types(False): list all available object types for object matching.
995 1008 """
996 1009 #print 'ps pattern:<%r>' % pattern # dbg
997 1010
998 1011 # defaults
999 1012 type_pattern = 'all'
1000 1013 filter = ''
1001 1014
1002 1015 # list all object types
1003 1016 if list_types:
1004 1017 page.page('\n'.join(sorted(typestr2type)))
1005 1018 return
1006 1019
1007 1020 cmds = pattern.split()
1008 1021 len_cmds = len(cmds)
1009 1022 if len_cmds == 1:
1010 1023 # Only filter pattern given
1011 1024 filter = cmds[0]
1012 1025 elif len_cmds == 2:
1013 1026 # Both filter and type specified
1014 1027 filter,type_pattern = cmds
1015 1028 else:
1016 1029 raise ValueError('invalid argument string for psearch: <%s>' %
1017 1030 pattern)
1018 1031
1019 1032 # filter search namespaces
1020 1033 for name in ns_search:
1021 1034 if name not in ns_table:
1022 1035 raise ValueError('invalid namespace <%s>. Valid names: %s' %
1023 1036 (name,ns_table.keys()))
1024 1037
1025 1038 #print 'type_pattern:',type_pattern # dbg
1026 1039 search_result, namespaces_seen = set(), set()
1027 1040 for ns_name in ns_search:
1028 1041 ns = ns_table[ns_name]
1029 1042 # Normally, locals and globals are the same, so we just check one.
1030 1043 if id(ns) in namespaces_seen:
1031 1044 continue
1032 1045 namespaces_seen.add(id(ns))
1033 1046 tmp_res = list_namespace(ns, type_pattern, filter,
1034 1047 ignore_case=ignore_case, show_all=show_all)
1035 1048 search_result.update(tmp_res)
1036 1049
1037 1050 page.page('\n'.join(sorted(search_result)))
1038 1051
1039 1052
1040 1053 def _render_signature(obj_signature, obj_name) -> str:
1041 1054 """
1042 1055 This was mostly taken from inspect.Signature.__str__.
1043 1056 Look there for the comments.
1044 1057 The only change is to add linebreaks when this gets too long.
1045 1058 """
1046 1059 result = []
1047 1060 pos_only = False
1048 1061 kw_only = True
1049 1062 for param in obj_signature.parameters.values():
1050 1063 if param.kind == inspect._POSITIONAL_ONLY:
1051 1064 pos_only = True
1052 1065 elif pos_only:
1053 1066 result.append('/')
1054 1067 pos_only = False
1055 1068
1056 1069 if param.kind == inspect._VAR_POSITIONAL:
1057 1070 kw_only = False
1058 1071 elif param.kind == inspect._KEYWORD_ONLY and kw_only:
1059 1072 result.append('*')
1060 1073 kw_only = False
1061 1074
1062 1075 result.append(str(param))
1063 1076
1064 1077 if pos_only:
1065 1078 result.append('/')
1066 1079
1067 1080 # add up name, parameters, braces (2), and commas
1068 1081 if len(obj_name) + sum(len(r) + 2 for r in result) > 75:
1069 1082 # This doesn’t fit behind “Signature: ” in an inspect window.
1070 1083 rendered = '{}(\n{})'.format(obj_name, ''.join(
1071 1084 ' {},\n'.format(r) for r in result)
1072 1085 )
1073 1086 else:
1074 1087 rendered = '{}({})'.format(obj_name, ', '.join(result))
1075 1088
1076 1089 if obj_signature.return_annotation is not inspect._empty:
1077 1090 anno = inspect.formatannotation(obj_signature.return_annotation)
1078 1091 rendered += ' -> {}'.format(anno)
1079 1092
1080 1093 return rendered
@@ -1,698 +1,700 b''
1 1 # encoding: utf-8
2 2 """
3 3 Prefiltering components.
4 4
5 5 Prefilters transform user input before it is exec'd by Python. These
6 6 transforms are used to implement additional syntax such as !ls and %magic.
7 7 """
8 8
9 9 # Copyright (c) IPython Development Team.
10 10 # Distributed under the terms of the Modified BSD License.
11 11
12 12 from keyword import iskeyword
13 13 import re
14 14
15 15 from .autocall import IPyAutocall
16 16 from traitlets.config.configurable import Configurable
17 17 from .inputtransformer2 import (
18 18 ESC_MAGIC,
19 19 ESC_QUOTE,
20 20 ESC_QUOTE2,
21 21 ESC_PAREN,
22 22 )
23 23 from .macro import Macro
24 24 from .splitinput import LineInfo
25 25
26 26 from traitlets import (
27 27 List, Integer, Unicode, Bool, Instance, CRegExp
28 28 )
29 29
30 30 #-----------------------------------------------------------------------------
31 31 # Global utilities, errors and constants
32 32 #-----------------------------------------------------------------------------
33 33
34 34
35 35 class PrefilterError(Exception):
36 36 pass
37 37
38 38
39 39 # RegExp to identify potential function names
40 40 re_fun_name = re.compile(r'[^\W\d]([\w.]*) *$')
41 41
42 42 # RegExp to exclude strings with this start from autocalling. In
43 43 # particular, all binary operators should be excluded, so that if foo is
44 44 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
45 45 # characters '!=()' don't need to be checked for, as the checkPythonChars
46 46 # routine explicitly does so, to catch direct calls and rebindings of
47 47 # existing names.
48 48
49 49 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
50 50 # it affects the rest of the group in square brackets.
51 51 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
52 52 r'|^is |^not |^in |^and |^or ')
53 53
54 54 # try to catch also methods for stuff in lists/tuples/dicts: off
55 55 # (experimental). For this to work, the line_split regexp would need
56 56 # to be modified so it wouldn't break things at '['. That line is
57 57 # nasty enough that I shouldn't change it until I can test it _well_.
58 58 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
59 59
60 60
61 61 # Handler Check Utilities
62 62 def is_shadowed(identifier, ip):
63 63 """Is the given identifier defined in one of the namespaces which shadow
64 64 the alias and magic namespaces? Note that an identifier is different
65 65 than ifun, because it can not contain a '.' character."""
66 66 # This is much safer than calling ofind, which can change state
67 67 return (identifier in ip.user_ns \
68 68 or identifier in ip.user_global_ns \
69 69 or identifier in ip.ns_table['builtin']\
70 70 or iskeyword(identifier))
71 71
72 72
73 73 #-----------------------------------------------------------------------------
74 74 # Main Prefilter manager
75 75 #-----------------------------------------------------------------------------
76 76
77 77
78 78 class PrefilterManager(Configurable):
79 79 """Main prefilter component.
80 80
81 81 The IPython prefilter is run on all user input before it is run. The
82 82 prefilter consumes lines of input and produces transformed lines of
83 83 input.
84 84
85 85 The implementation consists of two phases:
86 86
87 87 1. Transformers
88 88 2. Checkers and handlers
89 89
90 90 Over time, we plan on deprecating the checkers and handlers and doing
91 91 everything in the transformers.
92 92
93 93 The transformers are instances of :class:`PrefilterTransformer` and have
94 94 a single method :meth:`transform` that takes a line and returns a
95 95 transformed line. The transformation can be accomplished using any
96 96 tool, but our current ones use regular expressions for speed.
97 97
98 98 After all the transformers have been run, the line is fed to the checkers,
99 99 which are instances of :class:`PrefilterChecker`. The line is passed to
100 100 the :meth:`check` method, which either returns `None` or a
101 101 :class:`PrefilterHandler` instance. If `None` is returned, the other
102 102 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
103 103 the line is passed to the :meth:`handle` method of the returned
104 104 handler and no further checkers are tried.
105 105
106 106 Both transformers and checkers have a `priority` attribute, that determines
107 107 the order in which they are called. Smaller priorities are tried first.
108 108
109 109 Both transformers and checkers also have `enabled` attribute, which is
110 110 a boolean that determines if the instance is used.
111 111
112 112 Users or developers can change the priority or enabled attribute of
113 113 transformers or checkers, but they must call the :meth:`sort_checkers`
114 114 or :meth:`sort_transformers` method after changing the priority.
115 115 """
116 116
117 117 multi_line_specials = Bool(True).tag(config=True)
118 118 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
119 119
120 120 def __init__(self, shell=None, **kwargs):
121 121 super(PrefilterManager, self).__init__(shell=shell, **kwargs)
122 122 self.shell = shell
123 123 self._transformers = []
124 124 self.init_handlers()
125 125 self.init_checkers()
126 126
127 127 #-------------------------------------------------------------------------
128 128 # API for managing transformers
129 129 #-------------------------------------------------------------------------
130 130
131 131 def sort_transformers(self):
132 132 """Sort the transformers by priority.
133 133
134 134 This must be called after the priority of a transformer is changed.
135 135 The :meth:`register_transformer` method calls this automatically.
136 136 """
137 137 self._transformers.sort(key=lambda x: x.priority)
138 138
139 139 @property
140 140 def transformers(self):
141 141 """Return a list of checkers, sorted by priority."""
142 142 return self._transformers
143 143
144 144 def register_transformer(self, transformer):
145 145 """Register a transformer instance."""
146 146 if transformer not in self._transformers:
147 147 self._transformers.append(transformer)
148 148 self.sort_transformers()
149 149
150 150 def unregister_transformer(self, transformer):
151 151 """Unregister a transformer instance."""
152 152 if transformer in self._transformers:
153 153 self._transformers.remove(transformer)
154 154
155 155 #-------------------------------------------------------------------------
156 156 # API for managing checkers
157 157 #-------------------------------------------------------------------------
158 158
159 159 def init_checkers(self):
160 160 """Create the default checkers."""
161 161 self._checkers = []
162 162 for checker in _default_checkers:
163 163 checker(
164 164 shell=self.shell, prefilter_manager=self, parent=self
165 165 )
166 166
167 167 def sort_checkers(self):
168 168 """Sort the checkers by priority.
169 169
170 170 This must be called after the priority of a checker is changed.
171 171 The :meth:`register_checker` method calls this automatically.
172 172 """
173 173 self._checkers.sort(key=lambda x: x.priority)
174 174
175 175 @property
176 176 def checkers(self):
177 177 """Return a list of checkers, sorted by priority."""
178 178 return self._checkers
179 179
180 180 def register_checker(self, checker):
181 181 """Register a checker instance."""
182 182 if checker not in self._checkers:
183 183 self._checkers.append(checker)
184 184 self.sort_checkers()
185 185
186 186 def unregister_checker(self, checker):
187 187 """Unregister a checker instance."""
188 188 if checker in self._checkers:
189 189 self._checkers.remove(checker)
190 190
191 191 #-------------------------------------------------------------------------
192 192 # API for managing handlers
193 193 #-------------------------------------------------------------------------
194 194
195 195 def init_handlers(self):
196 196 """Create the default handlers."""
197 197 self._handlers = {}
198 198 self._esc_handlers = {}
199 199 for handler in _default_handlers:
200 200 handler(
201 201 shell=self.shell, prefilter_manager=self, parent=self
202 202 )
203 203
204 204 @property
205 205 def handlers(self):
206 206 """Return a dict of all the handlers."""
207 207 return self._handlers
208 208
209 209 def register_handler(self, name, handler, esc_strings):
210 210 """Register a handler instance by name with esc_strings."""
211 211 self._handlers[name] = handler
212 212 for esc_str in esc_strings:
213 213 self._esc_handlers[esc_str] = handler
214 214
215 215 def unregister_handler(self, name, handler, esc_strings):
216 216 """Unregister a handler instance by name with esc_strings."""
217 217 try:
218 218 del self._handlers[name]
219 219 except KeyError:
220 220 pass
221 221 for esc_str in esc_strings:
222 222 h = self._esc_handlers.get(esc_str)
223 223 if h is handler:
224 224 del self._esc_handlers[esc_str]
225 225
226 226 def get_handler_by_name(self, name):
227 227 """Get a handler by its name."""
228 228 return self._handlers.get(name)
229 229
230 230 def get_handler_by_esc(self, esc_str):
231 231 """Get a handler by its escape string."""
232 232 return self._esc_handlers.get(esc_str)
233 233
234 234 #-------------------------------------------------------------------------
235 235 # Main prefiltering API
236 236 #-------------------------------------------------------------------------
237 237
238 238 def prefilter_line_info(self, line_info):
239 239 """Prefilter a line that has been converted to a LineInfo object.
240 240
241 241 This implements the checker/handler part of the prefilter pipe.
242 242 """
243 243 # print "prefilter_line_info: ", line_info
244 244 handler = self.find_handler(line_info)
245 245 return handler.handle(line_info)
246 246
247 247 def find_handler(self, line_info):
248 248 """Find a handler for the line_info by trying checkers."""
249 249 for checker in self.checkers:
250 250 if checker.enabled:
251 251 handler = checker.check(line_info)
252 252 if handler:
253 253 return handler
254 254 return self.get_handler_by_name('normal')
255 255
256 256 def transform_line(self, line, continue_prompt):
257 257 """Calls the enabled transformers in order of increasing priority."""
258 258 for transformer in self.transformers:
259 259 if transformer.enabled:
260 260 line = transformer.transform(line, continue_prompt)
261 261 return line
262 262
263 263 def prefilter_line(self, line, continue_prompt=False):
264 264 """Prefilter a single input line as text.
265 265
266 266 This method prefilters a single line of text by calling the
267 267 transformers and then the checkers/handlers.
268 268 """
269 269
270 270 # print "prefilter_line: ", line, continue_prompt
271 271 # All handlers *must* return a value, even if it's blank ('').
272 272
273 273 # save the line away in case we crash, so the post-mortem handler can
274 274 # record it
275 275 self.shell._last_input_line = line
276 276
277 277 if not line:
278 278 # Return immediately on purely empty lines, so that if the user
279 279 # previously typed some whitespace that started a continuation
280 280 # prompt, he can break out of that loop with just an empty line.
281 281 # This is how the default python prompt works.
282 282 return ''
283 283
284 284 # At this point, we invoke our transformers.
285 285 if not continue_prompt or (continue_prompt and self.multi_line_specials):
286 286 line = self.transform_line(line, continue_prompt)
287 287
288 288 # Now we compute line_info for the checkers and handlers
289 289 line_info = LineInfo(line, continue_prompt)
290 290
291 291 # the input history needs to track even empty lines
292 292 stripped = line.strip()
293 293
294 294 normal_handler = self.get_handler_by_name('normal')
295 295 if not stripped:
296 296 return normal_handler.handle(line_info)
297 297
298 298 # special handlers are only allowed for single line statements
299 299 if continue_prompt and not self.multi_line_specials:
300 300 return normal_handler.handle(line_info)
301 301
302 302 prefiltered = self.prefilter_line_info(line_info)
303 303 # print "prefiltered line: %r" % prefiltered
304 304 return prefiltered
305 305
306 306 def prefilter_lines(self, lines, continue_prompt=False):
307 307 """Prefilter multiple input lines of text.
308 308
309 309 This is the main entry point for prefiltering multiple lines of
310 310 input. This simply calls :meth:`prefilter_line` for each line of
311 311 input.
312 312
313 313 This covers cases where there are multiple lines in the user entry,
314 314 which is the case when the user goes back to a multiline history
315 315 entry and presses enter.
316 316 """
317 317 llines = lines.rstrip('\n').split('\n')
318 318 # We can get multiple lines in one shot, where multiline input 'blends'
319 319 # into one line, in cases like recalling from the readline history
320 320 # buffer. We need to make sure that in such cases, we correctly
321 321 # communicate downstream which line is first and which are continuation
322 322 # ones.
323 323 if len(llines) > 1:
324 324 out = '\n'.join([self.prefilter_line(line, lnum>0)
325 325 for lnum, line in enumerate(llines) ])
326 326 else:
327 327 out = self.prefilter_line(llines[0], continue_prompt)
328 328
329 329 return out
330 330
331 331 #-----------------------------------------------------------------------------
332 332 # Prefilter transformers
333 333 #-----------------------------------------------------------------------------
334 334
335 335
336 336 class PrefilterTransformer(Configurable):
337 337 """Transform a line of user input."""
338 338
339 339 priority = Integer(100).tag(config=True)
340 340 # Transformers don't currently use shell or prefilter_manager, but as we
341 341 # move away from checkers and handlers, they will need them.
342 342 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
343 343 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
344 344 enabled = Bool(True).tag(config=True)
345 345
346 346 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
347 347 super(PrefilterTransformer, self).__init__(
348 348 shell=shell, prefilter_manager=prefilter_manager, **kwargs
349 349 )
350 350 self.prefilter_manager.register_transformer(self)
351 351
352 352 def transform(self, line, continue_prompt):
353 353 """Transform a line, returning the new one."""
354 354 return None
355 355
356 356 def __repr__(self):
357 357 return "<%s(priority=%r, enabled=%r)>" % (
358 358 self.__class__.__name__, self.priority, self.enabled)
359 359
360 360
361 361 #-----------------------------------------------------------------------------
362 362 # Prefilter checkers
363 363 #-----------------------------------------------------------------------------
364 364
365 365
366 366 class PrefilterChecker(Configurable):
367 367 """Inspect an input line and return a handler for that line."""
368 368
369 369 priority = Integer(100).tag(config=True)
370 370 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
371 371 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
372 372 enabled = Bool(True).tag(config=True)
373 373
374 374 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
375 375 super(PrefilterChecker, self).__init__(
376 376 shell=shell, prefilter_manager=prefilter_manager, **kwargs
377 377 )
378 378 self.prefilter_manager.register_checker(self)
379 379
380 380 def check(self, line_info):
381 381 """Inspect line_info and return a handler instance or None."""
382 382 return None
383 383
384 384 def __repr__(self):
385 385 return "<%s(priority=%r, enabled=%r)>" % (
386 386 self.__class__.__name__, self.priority, self.enabled)
387 387
388 388
389 389 class EmacsChecker(PrefilterChecker):
390 390
391 391 priority = Integer(100).tag(config=True)
392 392 enabled = Bool(False).tag(config=True)
393 393
394 394 def check(self, line_info):
395 395 "Emacs ipython-mode tags certain input lines."
396 396 if line_info.line.endswith('# PYTHON-MODE'):
397 397 return self.prefilter_manager.get_handler_by_name('emacs')
398 398 else:
399 399 return None
400 400
401 401
402 402 class MacroChecker(PrefilterChecker):
403 403
404 404 priority = Integer(250).tag(config=True)
405 405
406 406 def check(self, line_info):
407 407 obj = self.shell.user_ns.get(line_info.ifun)
408 408 if isinstance(obj, Macro):
409 409 return self.prefilter_manager.get_handler_by_name('macro')
410 410 else:
411 411 return None
412 412
413 413
414 414 class IPyAutocallChecker(PrefilterChecker):
415 415
416 416 priority = Integer(300).tag(config=True)
417 417
418 418 def check(self, line_info):
419 419 "Instances of IPyAutocall in user_ns get autocalled immediately"
420 420 obj = self.shell.user_ns.get(line_info.ifun, None)
421 421 if isinstance(obj, IPyAutocall):
422 422 obj.set_ip(self.shell)
423 423 return self.prefilter_manager.get_handler_by_name('auto')
424 424 else:
425 425 return None
426 426
427 427
428 428 class AssignmentChecker(PrefilterChecker):
429 429
430 430 priority = Integer(600).tag(config=True)
431 431
432 432 def check(self, line_info):
433 433 """Check to see if user is assigning to a var for the first time, in
434 434 which case we want to avoid any sort of automagic / autocall games.
435 435
436 436 This allows users to assign to either alias or magic names true python
437 437 variables (the magic/alias systems always take second seat to true
438 438 python code). E.g. ls='hi', or ls,that=1,2"""
439 439 if line_info.the_rest:
440 440 if line_info.the_rest[0] in '=,':
441 441 return self.prefilter_manager.get_handler_by_name('normal')
442 442 else:
443 443 return None
444 444
445 445
446 446 class AutoMagicChecker(PrefilterChecker):
447 447
448 448 priority = Integer(700).tag(config=True)
449 449
450 450 def check(self, line_info):
451 451 """If the ifun is magic, and automagic is on, run it. Note: normal,
452 452 non-auto magic would already have been triggered via '%' in
453 453 check_esc_chars. This just checks for automagic. Also, before
454 454 triggering the magic handler, make sure that there is nothing in the
455 455 user namespace which could shadow it."""
456 456 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
457 457 return None
458 458
459 459 # We have a likely magic method. Make sure we should actually call it.
460 460 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
461 461 return None
462 462
463 463 head = line_info.ifun.split('.',1)[0]
464 464 if is_shadowed(head, self.shell):
465 465 return None
466 466
467 467 return self.prefilter_manager.get_handler_by_name('magic')
468 468
469 469
470 470 class PythonOpsChecker(PrefilterChecker):
471 471
472 472 priority = Integer(900).tag(config=True)
473 473
474 474 def check(self, line_info):
475 475 """If the 'rest' of the line begins with a function call or pretty much
476 476 any python operator, we should simply execute the line (regardless of
477 477 whether or not there's a possible autocall expansion). This avoids
478 478 spurious (and very confusing) geattr() accesses."""
479 479 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
480 480 return self.prefilter_manager.get_handler_by_name('normal')
481 481 else:
482 482 return None
483 483
484 484
485 485 class AutocallChecker(PrefilterChecker):
486 486
487 487 priority = Integer(1000).tag(config=True)
488 488
489 489 function_name_regexp = CRegExp(re_fun_name,
490 490 help="RegExp to identify potential function names."
491 491 ).tag(config=True)
492 492 exclude_regexp = CRegExp(re_exclude_auto,
493 493 help="RegExp to exclude strings with this start from autocalling."
494 494 ).tag(config=True)
495 495
496 496 def check(self, line_info):
497 497 "Check if the initial word/function is callable and autocall is on."
498 498 if not self.shell.autocall:
499 499 return None
500 500
501 501 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
502 if not oinfo['found']:
502 if not oinfo.found:
503 503 return None
504 504
505 505 ignored_funs = ['b', 'f', 'r', 'u', 'br', 'rb', 'fr', 'rf']
506 506 ifun = line_info.ifun
507 507 line = line_info.line
508 508 if ifun.lower() in ignored_funs and (line.startswith(ifun + "'") or line.startswith(ifun + '"')):
509 509 return None
510 510
511 if callable(oinfo['obj']) \
512 and (not self.exclude_regexp.match(line_info.the_rest)) \
513 and self.function_name_regexp.match(line_info.ifun):
514 return self.prefilter_manager.get_handler_by_name('auto')
511 if (
512 callable(oinfo.obj)
513 and (not self.exclude_regexp.match(line_info.the_rest))
514 and self.function_name_regexp.match(line_info.ifun)
515 ):
516 return self.prefilter_manager.get_handler_by_name("auto")
515 517 else:
516 518 return None
517 519
518 520
519 521 #-----------------------------------------------------------------------------
520 522 # Prefilter handlers
521 523 #-----------------------------------------------------------------------------
522 524
523 525
524 526 class PrefilterHandler(Configurable):
525 527
526 528 handler_name = Unicode('normal')
527 529 esc_strings = List([])
528 530 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
529 531 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
530 532
531 533 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
532 534 super(PrefilterHandler, self).__init__(
533 535 shell=shell, prefilter_manager=prefilter_manager, **kwargs
534 536 )
535 537 self.prefilter_manager.register_handler(
536 538 self.handler_name,
537 539 self,
538 540 self.esc_strings
539 541 )
540 542
541 543 def handle(self, line_info):
542 544 # print "normal: ", line_info
543 545 """Handle normal input lines. Use as a template for handlers."""
544 546
545 547 # With autoindent on, we need some way to exit the input loop, and I
546 548 # don't want to force the user to have to backspace all the way to
547 549 # clear the line. The rule will be in this case, that either two
548 550 # lines of pure whitespace in a row, or a line of pure whitespace but
549 551 # of a size different to the indent level, will exit the input loop.
550 552 line = line_info.line
551 553 continue_prompt = line_info.continue_prompt
552 554
553 555 if (continue_prompt and
554 556 self.shell.autoindent and
555 557 line.isspace() and
556 558 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
557 559 line = ''
558 560
559 561 return line
560 562
561 563 def __str__(self):
562 564 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
563 565
564 566
565 567 class MacroHandler(PrefilterHandler):
566 568 handler_name = Unicode("macro")
567 569
568 570 def handle(self, line_info):
569 571 obj = self.shell.user_ns.get(line_info.ifun)
570 572 pre_space = line_info.pre_whitespace
571 573 line_sep = "\n" + pre_space
572 574 return pre_space + line_sep.join(obj.value.splitlines())
573 575
574 576
575 577 class MagicHandler(PrefilterHandler):
576 578
577 579 handler_name = Unicode('magic')
578 580 esc_strings = List([ESC_MAGIC])
579 581
580 582 def handle(self, line_info):
581 583 """Execute magic functions."""
582 584 ifun = line_info.ifun
583 585 the_rest = line_info.the_rest
584 586 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
585 587 t_arg_s = ifun + " " + the_rest
586 588 t_magic_name, _, t_magic_arg_s = t_arg_s.partition(' ')
587 589 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
588 590 cmd = '%sget_ipython().run_line_magic(%r, %r)' % (line_info.pre_whitespace, t_magic_name, t_magic_arg_s)
589 591 return cmd
590 592
591 593
592 594 class AutoHandler(PrefilterHandler):
593 595
594 596 handler_name = Unicode('auto')
595 597 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
596 598
597 599 def handle(self, line_info):
598 600 """Handle lines which can be auto-executed, quoting if requested."""
599 601 line = line_info.line
600 602 ifun = line_info.ifun
601 603 the_rest = line_info.the_rest
602 604 esc = line_info.esc
603 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 608 # This should only be active for single-line input!
607 609 if continue_prompt:
608 610 return line
609 611
610 612 force_auto = isinstance(obj, IPyAutocall)
611 613
612 614 # User objects sometimes raise exceptions on attribute access other
613 615 # than AttributeError (we've seen it in the past), so it's safest to be
614 616 # ultra-conservative here and catch all.
615 617 try:
616 618 auto_rewrite = obj.rewrite
617 619 except Exception:
618 620 auto_rewrite = True
619 621
620 622 if esc == ESC_QUOTE:
621 623 # Auto-quote splitting on whitespace
622 624 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
623 625 elif esc == ESC_QUOTE2:
624 626 # Auto-quote whole string
625 627 newcmd = '%s("%s")' % (ifun,the_rest)
626 628 elif esc == ESC_PAREN:
627 629 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
628 630 else:
629 631 # Auto-paren.
630 632 if force_auto:
631 633 # Don't rewrite if it is already a call.
632 634 do_rewrite = not the_rest.startswith('(')
633 635 else:
634 636 if not the_rest:
635 637 # We only apply it to argument-less calls if the autocall
636 638 # parameter is set to 2.
637 639 do_rewrite = (self.shell.autocall >= 2)
638 640 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
639 641 # Don't autocall in this case: item access for an object
640 642 # which is BOTH callable and implements __getitem__.
641 643 do_rewrite = False
642 644 else:
643 645 do_rewrite = True
644 646
645 647 # Figure out the rewritten command
646 648 if do_rewrite:
647 649 if the_rest.endswith(';'):
648 650 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
649 651 else:
650 652 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
651 653 else:
652 654 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
653 655 return normal_handler.handle(line_info)
654 656
655 657 # Display the rewritten call
656 658 if auto_rewrite:
657 659 self.shell.auto_rewrite_input(newcmd)
658 660
659 661 return newcmd
660 662
661 663
662 664 class EmacsHandler(PrefilterHandler):
663 665
664 666 handler_name = Unicode('emacs')
665 667 esc_strings = List([])
666 668
667 669 def handle(self, line_info):
668 670 """Handle input lines marked by python-mode."""
669 671
670 672 # Currently, nothing is done. Later more functionality can be added
671 673 # here if needed.
672 674
673 675 # The input cache shouldn't be updated
674 676 return line_info.line
675 677
676 678
677 679 #-----------------------------------------------------------------------------
678 680 # Defaults
679 681 #-----------------------------------------------------------------------------
680 682
681 683
682 684 _default_checkers = [
683 685 EmacsChecker,
684 686 MacroChecker,
685 687 IPyAutocallChecker,
686 688 AssignmentChecker,
687 689 AutoMagicChecker,
688 690 PythonOpsChecker,
689 691 AutocallChecker
690 692 ]
691 693
692 694 _default_handlers = [
693 695 PrefilterHandler,
694 696 MacroHandler,
695 697 MagicHandler,
696 698 AutoHandler,
697 699 EmacsHandler
698 700 ]
@@ -1,137 +1,138 b''
1 1 # encoding: utf-8
2 2 """
3 3 Simple utility for splitting user input. This is used by both inputsplitter and
4 4 prefilter.
5 5
6 6 Authors:
7 7
8 8 * Brian Granger
9 9 * Fernando Perez
10 10 """
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (C) 2008-2011 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import re
24 24 import sys
25 25
26 26 from IPython.utils import py3compat
27 27 from IPython.utils.encoding import get_stream_enc
28 from IPython.core.oinspect import OInfo
28 29
29 30 #-----------------------------------------------------------------------------
30 31 # Main function
31 32 #-----------------------------------------------------------------------------
32 33
33 34 # RegExp for splitting line contents into pre-char//first word-method//rest.
34 35 # For clarity, each group in on one line.
35 36
36 37 # WARNING: update the regexp if the escapes in interactiveshell are changed, as
37 38 # they are hardwired in.
38 39
39 40 # Although it's not solely driven by the regex, note that:
40 41 # ,;/% only trigger if they are the first character on the line
41 42 # ! and !! trigger if they are first char(s) *or* follow an indent
42 43 # ? triggers as first or last char.
43 44
44 45 line_split = re.compile(r"""
45 46 ^(\s*) # any leading space
46 47 ([,;/%]|!!?|\?\??)? # escape character or characters
47 48 \s*(%{0,2}[\w\.\*]*) # function/method, possibly with leading %
48 49 # to correctly treat things like '?%magic'
49 50 (.*?$|$) # rest of line
50 51 """, re.VERBOSE)
51 52
52 53
53 54 def split_user_input(line, pattern=None):
54 55 """Split user input into initial whitespace, escape character, function part
55 56 and the rest.
56 57 """
57 58 # We need to ensure that the rest of this routine deals only with unicode
58 59 encoding = get_stream_enc(sys.stdin, 'utf-8')
59 60 line = py3compat.cast_unicode(line, encoding)
60 61
61 62 if pattern is None:
62 63 pattern = line_split
63 64 match = pattern.match(line)
64 65 if not match:
65 66 # print "match failed for line '%s'" % line
66 67 try:
67 68 ifun, the_rest = line.split(None,1)
68 69 except ValueError:
69 70 # print "split failed for line '%s'" % line
70 71 ifun, the_rest = line, u''
71 72 pre = re.match(r'^(\s*)(.*)',line).groups()[0]
72 73 esc = ""
73 74 else:
74 75 pre, esc, ifun, the_rest = match.groups()
75 76
76 77 #print 'line:<%s>' % line # dbg
77 78 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest) # dbg
78 79 return pre, esc or '', ifun.strip(), the_rest.lstrip()
79 80
80 81
81 82 class LineInfo(object):
82 83 """A single line of input and associated info.
83 84
84 85 Includes the following as properties:
85 86
86 87 line
87 88 The original, raw line
88 89
89 90 continue_prompt
90 91 Is this line a continuation in a sequence of multiline input?
91 92
92 93 pre
93 94 Any leading whitespace.
94 95
95 96 esc
96 97 The escape character(s) in pre or the empty string if there isn't one.
97 98 Note that '!!' and '??' are possible values for esc. Otherwise it will
98 99 always be a single character.
99 100
100 101 ifun
101 102 The 'function part', which is basically the maximal initial sequence
102 103 of valid python identifiers and the '.' character. This is what is
103 104 checked for alias and magic transformations, used for auto-calling,
104 105 etc. In contrast to Python identifiers, it may start with "%" and contain
105 106 "*".
106 107
107 108 the_rest
108 109 Everything else on the line.
109 110 """
110 111 def __init__(self, line, continue_prompt=False):
111 112 self.line = line
112 113 self.continue_prompt = continue_prompt
113 114 self.pre, self.esc, self.ifun, self.the_rest = split_user_input(line)
114 115
115 116 self.pre_char = self.pre.strip()
116 117 if self.pre_char:
117 118 self.pre_whitespace = '' # No whitespace allowed before esc chars
118 119 else:
119 120 self.pre_whitespace = self.pre
120 121
121 def ofind(self, ip):
122 def ofind(self, ip) -> OInfo:
122 123 """Do a full, attribute-walking lookup of the ifun in the various
123 124 namespaces for the given IPython InteractiveShell instance.
124 125
125 126 Return a dict with keys: {found, obj, ospace, ismagic}
126 127
127 128 Note: can cause state changes because of calling getattr, but should
128 129 only be run if autocall is on and if the line hasn't matched any
129 130 other, less dangerous handlers.
130 131
131 132 Does cache the results of the call, so can be called multiple times
132 133 without worrying about *further* damaging state.
133 134 """
134 135 return ip._ofind(self.ifun)
135 136
136 137 def __str__(self):
137 138 return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest)
@@ -1,193 +1,193 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for completerlib.
3 3
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Imports
8 8 #-----------------------------------------------------------------------------
9 9
10 10 import os
11 11 import shutil
12 12 import sys
13 13 import tempfile
14 14 import unittest
15 15 from os.path import join
16 16
17 17 from tempfile import TemporaryDirectory
18 18
19 19 from IPython.core.completerlib import magic_run_completer, module_completion, try_import
20 20 from IPython.testing.decorators import onlyif_unicode_paths
21 21
22 22
23 23 class MockEvent(object):
24 24 def __init__(self, line):
25 25 self.line = line
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Test functions begin
29 29 #-----------------------------------------------------------------------------
30 30 class Test_magic_run_completer(unittest.TestCase):
31 31 files = [u"aao.py", u"a.py", u"b.py", u"aao.txt"]
32 32 dirs = [u"adir/", "bdir/"]
33 33
34 34 def setUp(self):
35 35 self.BASETESTDIR = tempfile.mkdtemp()
36 36 for fil in self.files:
37 37 with open(join(self.BASETESTDIR, fil), "w", encoding="utf-8") as sfile:
38 38 sfile.write("pass\n")
39 39 for d in self.dirs:
40 40 os.mkdir(join(self.BASETESTDIR, d))
41 41
42 42 self.oldpath = os.getcwd()
43 43 os.chdir(self.BASETESTDIR)
44 44
45 45 def tearDown(self):
46 46 os.chdir(self.oldpath)
47 47 shutil.rmtree(self.BASETESTDIR)
48 48
49 49 def test_1(self):
50 50 """Test magic_run_completer, should match two alternatives
51 51 """
52 52 event = MockEvent(u"%run a")
53 53 mockself = None
54 54 match = set(magic_run_completer(mockself, event))
55 55 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
56 56
57 57 def test_2(self):
58 58 """Test magic_run_completer, should match one alternative
59 59 """
60 60 event = MockEvent(u"%run aa")
61 61 mockself = None
62 62 match = set(magic_run_completer(mockself, event))
63 63 self.assertEqual(match, {u"aao.py"})
64 64
65 65 def test_3(self):
66 66 """Test magic_run_completer with unterminated " """
67 67 event = MockEvent(u'%run "a')
68 68 mockself = None
69 69 match = set(magic_run_completer(mockself, event))
70 70 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
71 71
72 72 def test_completion_more_args(self):
73 73 event = MockEvent(u'%run a.py ')
74 74 match = set(magic_run_completer(None, event))
75 75 self.assertEqual(match, set(self.files + self.dirs))
76 76
77 77 def test_completion_in_dir(self):
78 78 # Github issue #3459
79 79 event = MockEvent(u'%run a.py {}'.format(join(self.BASETESTDIR, 'a')))
80 80 print(repr(event.line))
81 81 match = set(magic_run_completer(None, event))
82 82 # We specifically use replace here rather than normpath, because
83 83 # at one point there were duplicates 'adir' and 'adir/', and normpath
84 84 # would hide the failure for that.
85 85 self.assertEqual(match, {join(self.BASETESTDIR, f).replace('\\','/')
86 86 for f in (u'a.py', u'aao.py', u'aao.txt', u'adir/')})
87 87
88 88 class Test_magic_run_completer_nonascii(unittest.TestCase):
89 89 @onlyif_unicode_paths
90 90 def setUp(self):
91 91 self.BASETESTDIR = tempfile.mkdtemp()
92 92 for fil in [u"aaø.py", u"a.py", u"b.py"]:
93 93 with open(join(self.BASETESTDIR, fil), "w", encoding="utf-8") as sfile:
94 94 sfile.write("pass\n")
95 95 self.oldpath = os.getcwd()
96 96 os.chdir(self.BASETESTDIR)
97 97
98 98 def tearDown(self):
99 99 os.chdir(self.oldpath)
100 100 shutil.rmtree(self.BASETESTDIR)
101 101
102 102 @onlyif_unicode_paths
103 103 def test_1(self):
104 104 """Test magic_run_completer, should match two alternatives
105 105 """
106 106 event = MockEvent(u"%run a")
107 107 mockself = None
108 108 match = set(magic_run_completer(mockself, event))
109 109 self.assertEqual(match, {u"a.py", u"aaø.py"})
110 110
111 111 @onlyif_unicode_paths
112 112 def test_2(self):
113 113 """Test magic_run_completer, should match one alternative
114 114 """
115 115 event = MockEvent(u"%run aa")
116 116 mockself = None
117 117 match = set(magic_run_completer(mockself, event))
118 118 self.assertEqual(match, {u"aaø.py"})
119 119
120 120 @onlyif_unicode_paths
121 121 def test_3(self):
122 122 """Test magic_run_completer with unterminated " """
123 123 event = MockEvent(u'%run "a')
124 124 mockself = None
125 125 match = set(magic_run_completer(mockself, event))
126 126 self.assertEqual(match, {u"a.py", u"aaø.py"})
127 127
128 128 # module_completer:
129 129
130 130 def test_import_invalid_module():
131 131 """Testing of issue https://github.com/ipython/ipython/issues/1107"""
132 132 invalid_module_names = {'foo-bar', 'foo:bar', '10foo'}
133 133 valid_module_names = {'foobar'}
134 134 with TemporaryDirectory() as tmpdir:
135 135 sys.path.insert( 0, tmpdir )
136 136 for name in invalid_module_names | valid_module_names:
137 137 filename = os.path.join(tmpdir, name + ".py")
138 138 open(filename, "w", encoding="utf-8").close()
139 139
140 140 s = set( module_completion('import foo') )
141 141 intersection = s.intersection(invalid_module_names)
142 142 assert intersection == set()
143 143
144 144 assert valid_module_names.issubset(s), valid_module_names.intersection(s)
145 145
146 146
147 147 def test_bad_module_all():
148 148 """Test module with invalid __all__
149 149
150 150 https://github.com/ipython/ipython/issues/9678
151 151 """
152 152 testsdir = os.path.dirname(__file__)
153 153 sys.path.insert(0, testsdir)
154 154 try:
155 155 results = module_completion("from bad_all import ")
156 156 assert "puppies" in results
157 157 for r in results:
158 158 assert isinstance(r, str)
159 159
160 160 # bad_all doesn't contain submodules, but this completion
161 161 # should finish without raising an exception:
162 162 results = module_completion("import bad_all.")
163 163 assert results == []
164 164 finally:
165 165 sys.path.remove(testsdir)
166 166
167 167
168 168 def test_module_without_init():
169 169 """
170 170 Test module without __init__.py.
171 171
172 172 https://github.com/ipython/ipython/issues/11226
173 173 """
174 174 fake_module_name = "foo"
175 175 with TemporaryDirectory() as tmpdir:
176 176 sys.path.insert(0, tmpdir)
177 177 try:
178 178 os.makedirs(os.path.join(tmpdir, fake_module_name))
179 179 s = try_import(mod=fake_module_name)
180 assert s == []
180 assert s == [], f"for module {fake_module_name}"
181 181 finally:
182 182 sys.path.remove(tmpdir)
183 183
184 184
185 185 def test_valid_exported_submodules():
186 186 """
187 187 Test checking exported (__all__) objects are submodules
188 188 """
189 189 results = module_completion("import os.pa")
190 190 # ensure we get a valid submodule:
191 191 assert "os.path" in results
192 192 # ensure we don't get objects that aren't submodules:
193 193 assert "os.pathconf" not in results
@@ -1,1175 +1,1200 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the key interactiveshell module.
3 3
4 4 Historically the main classes in interactiveshell have been under-tested. This
5 5 module should grow as many single-method tests as possible to trap many of the
6 6 recurring bugs we seem to encounter with high-level interaction.
7 7 """
8 8
9 9 # Copyright (c) IPython Development Team.
10 10 # Distributed under the terms of the Modified BSD License.
11 11
12 12 import asyncio
13 13 import ast
14 14 import os
15 15 import signal
16 16 import shutil
17 17 import sys
18 18 import tempfile
19 19 import unittest
20 20 import pytest
21 21 from unittest import mock
22 22
23 23 from os.path import join
24 24
25 25 from IPython.core.error import InputRejected
26 26 from IPython.core.inputtransformer import InputTransformer
27 27 from IPython.core import interactiveshell
28 from IPython.core.oinspect import OInfo
28 29 from IPython.testing.decorators import (
29 30 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
30 31 )
31 32 from IPython.testing import tools as tt
32 33 from IPython.utils.process import find_cmd
33 34
34 35 #-----------------------------------------------------------------------------
35 36 # Globals
36 37 #-----------------------------------------------------------------------------
37 38 # This is used by every single test, no point repeating it ad nauseam
38 39
39 40 #-----------------------------------------------------------------------------
40 41 # Tests
41 42 #-----------------------------------------------------------------------------
42 43
43 44 class DerivedInterrupt(KeyboardInterrupt):
44 45 pass
45 46
46 47 class InteractiveShellTestCase(unittest.TestCase):
47 48 def test_naked_string_cells(self):
48 49 """Test that cells with only naked strings are fully executed"""
49 50 # First, single-line inputs
50 51 ip.run_cell('"a"\n')
51 52 self.assertEqual(ip.user_ns['_'], 'a')
52 53 # And also multi-line cells
53 54 ip.run_cell('"""a\nb"""\n')
54 55 self.assertEqual(ip.user_ns['_'], 'a\nb')
55 56
56 57 def test_run_empty_cell(self):
57 58 """Just make sure we don't get a horrible error with a blank
58 59 cell of input. Yes, I did overlook that."""
59 60 old_xc = ip.execution_count
60 61 res = ip.run_cell('')
61 62 self.assertEqual(ip.execution_count, old_xc)
62 63 self.assertEqual(res.execution_count, None)
63 64
64 65 def test_run_cell_multiline(self):
65 66 """Multi-block, multi-line cells must execute correctly.
66 67 """
67 68 src = '\n'.join(["x=1",
68 69 "y=2",
69 70 "if 1:",
70 71 " x += 1",
71 72 " y += 1",])
72 73 res = ip.run_cell(src)
73 74 self.assertEqual(ip.user_ns['x'], 2)
74 75 self.assertEqual(ip.user_ns['y'], 3)
75 76 self.assertEqual(res.success, True)
76 77 self.assertEqual(res.result, None)
77 78
78 79 def test_multiline_string_cells(self):
79 80 "Code sprinkled with multiline strings should execute (GH-306)"
80 81 ip.run_cell('tmp=0')
81 82 self.assertEqual(ip.user_ns['tmp'], 0)
82 83 res = ip.run_cell('tmp=1;"""a\nb"""\n')
83 84 self.assertEqual(ip.user_ns['tmp'], 1)
84 85 self.assertEqual(res.success, True)
85 86 self.assertEqual(res.result, "a\nb")
86 87
87 88 def test_dont_cache_with_semicolon(self):
88 89 "Ending a line with semicolon should not cache the returned object (GH-307)"
89 90 oldlen = len(ip.user_ns['Out'])
90 91 for cell in ['1;', '1;1;']:
91 92 res = ip.run_cell(cell, store_history=True)
92 93 newlen = len(ip.user_ns['Out'])
93 94 self.assertEqual(oldlen, newlen)
94 95 self.assertIsNone(res.result)
95 96 i = 0
96 97 #also test the default caching behavior
97 98 for cell in ['1', '1;1']:
98 99 ip.run_cell(cell, store_history=True)
99 100 newlen = len(ip.user_ns['Out'])
100 101 i += 1
101 102 self.assertEqual(oldlen+i, newlen)
102 103
103 104 def test_syntax_error(self):
104 105 res = ip.run_cell("raise = 3")
105 106 self.assertIsInstance(res.error_before_exec, SyntaxError)
106 107
107 108 def test_open_standard_input_stream(self):
108 109 res = ip.run_cell("open(0)")
109 110 self.assertIsInstance(res.error_in_exec, ValueError)
110 111
111 112 def test_open_standard_output_stream(self):
112 113 res = ip.run_cell("open(1)")
113 114 self.assertIsInstance(res.error_in_exec, ValueError)
114 115
115 116 def test_open_standard_error_stream(self):
116 117 res = ip.run_cell("open(2)")
117 118 self.assertIsInstance(res.error_in_exec, ValueError)
118 119
119 120 def test_In_variable(self):
120 121 "Verify that In variable grows with user input (GH-284)"
121 122 oldlen = len(ip.user_ns['In'])
122 123 ip.run_cell('1;', store_history=True)
123 124 newlen = len(ip.user_ns['In'])
124 125 self.assertEqual(oldlen+1, newlen)
125 126 self.assertEqual(ip.user_ns['In'][-1],'1;')
126 127
127 128 def test_magic_names_in_string(self):
128 129 ip.run_cell('a = """\n%exit\n"""')
129 130 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
130 131
131 132 def test_trailing_newline(self):
132 133 """test that running !(command) does not raise a SyntaxError"""
133 134 ip.run_cell('!(true)\n', False)
134 135 ip.run_cell('!(true)\n\n\n', False)
135 136
136 137 def test_gh_597(self):
137 138 """Pretty-printing lists of objects with non-ascii reprs may cause
138 139 problems."""
139 140 class Spam(object):
140 141 def __repr__(self):
141 142 return "\xe9"*50
142 143 import IPython.core.formatters
143 144 f = IPython.core.formatters.PlainTextFormatter()
144 145 f([Spam(),Spam()])
145 146
146 147
147 148 def test_future_flags(self):
148 149 """Check that future flags are used for parsing code (gh-777)"""
149 150 ip.run_cell('from __future__ import barry_as_FLUFL')
150 151 try:
151 152 ip.run_cell('prfunc_return_val = 1 <> 2')
152 153 assert 'prfunc_return_val' in ip.user_ns
153 154 finally:
154 155 # Reset compiler flags so we don't mess up other tests.
155 156 ip.compile.reset_compiler_flags()
156 157
157 158 def test_can_pickle(self):
158 159 "Can we pickle objects defined interactively (GH-29)"
159 160 ip = get_ipython()
160 161 ip.reset()
161 162 ip.run_cell(("class Mylist(list):\n"
162 163 " def __init__(self,x=[]):\n"
163 164 " list.__init__(self,x)"))
164 165 ip.run_cell("w=Mylist([1,2,3])")
165 166
166 167 from pickle import dumps
167 168
168 169 # We need to swap in our main module - this is only necessary
169 170 # inside the test framework, because IPython puts the interactive module
170 171 # in place (but the test framework undoes this).
171 172 _main = sys.modules['__main__']
172 173 sys.modules['__main__'] = ip.user_module
173 174 try:
174 175 res = dumps(ip.user_ns["w"])
175 176 finally:
176 177 sys.modules['__main__'] = _main
177 178 self.assertTrue(isinstance(res, bytes))
178 179
179 180 def test_global_ns(self):
180 181 "Code in functions must be able to access variables outside them."
181 182 ip = get_ipython()
182 183 ip.run_cell("a = 10")
183 184 ip.run_cell(("def f(x):\n"
184 185 " return x + a"))
185 186 ip.run_cell("b = f(12)")
186 187 self.assertEqual(ip.user_ns["b"], 22)
187 188
188 189 def test_bad_custom_tb(self):
189 190 """Check that InteractiveShell is protected from bad custom exception handlers"""
190 191 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
191 192 self.assertEqual(ip.custom_exceptions, (IOError,))
192 193 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
193 194 ip.run_cell(u'raise IOError("foo")')
194 195 self.assertEqual(ip.custom_exceptions, ())
195 196
196 197 def test_bad_custom_tb_return(self):
197 198 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
198 199 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
199 200 self.assertEqual(ip.custom_exceptions, (NameError,))
200 201 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
201 202 ip.run_cell(u'a=abracadabra')
202 203 self.assertEqual(ip.custom_exceptions, ())
203 204
204 205 def test_drop_by_id(self):
205 206 myvars = {"a":object(), "b":object(), "c": object()}
206 207 ip.push(myvars, interactive=False)
207 208 for name in myvars:
208 209 assert name in ip.user_ns, name
209 210 assert name in ip.user_ns_hidden, name
210 211 ip.user_ns['b'] = 12
211 212 ip.drop_by_id(myvars)
212 213 for name in ["a", "c"]:
213 214 assert name not in ip.user_ns, name
214 215 assert name not in ip.user_ns_hidden, name
215 216 assert ip.user_ns['b'] == 12
216 217 ip.reset()
217 218
218 219 def test_var_expand(self):
219 220 ip.user_ns['f'] = u'Ca\xf1o'
220 221 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
221 222 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
222 223 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
223 224 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
224 225
225 226 self.assertEqual(ip.var_expand(u"grep x | awk '{print $1}'"), u"grep x | awk '{print $1}'")
226 227
227 228 ip.user_ns['f'] = b'Ca\xc3\xb1o'
228 229 # This should not raise any exception:
229 230 ip.var_expand(u'echo $f')
230 231
231 232 def test_var_expand_local(self):
232 233 """Test local variable expansion in !system and %magic calls"""
233 234 # !system
234 235 ip.run_cell(
235 236 "def test():\n"
236 237 ' lvar = "ttt"\n'
237 238 " ret = !echo {lvar}\n"
238 239 " return ret[0]\n"
239 240 )
240 241 res = ip.user_ns["test"]()
241 242 self.assertIn("ttt", res)
242 243
243 244 # %magic
244 245 ip.run_cell(
245 246 "def makemacro():\n"
246 247 ' macroname = "macro_var_expand_locals"\n'
247 248 " %macro {macroname} codestr\n"
248 249 )
249 250 ip.user_ns["codestr"] = "str(12)"
250 251 ip.run_cell("makemacro()")
251 252 self.assertIn("macro_var_expand_locals", ip.user_ns)
252 253
253 254 def test_var_expand_self(self):
254 255 """Test variable expansion with the name 'self', which was failing.
255 256
256 257 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
257 258 """
258 259 ip.run_cell(
259 260 "class cTest:\n"
260 261 ' classvar="see me"\n'
261 262 " def test(self):\n"
262 263 " res = !echo Variable: {self.classvar}\n"
263 264 " return res[0]\n"
264 265 )
265 266 self.assertIn("see me", ip.user_ns["cTest"]().test())
266 267
267 268 def test_bad_var_expand(self):
268 269 """var_expand on invalid formats shouldn't raise"""
269 270 # SyntaxError
270 271 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
271 272 # NameError
272 273 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
273 274 # ZeroDivisionError
274 275 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
275 276
276 277 def test_silent_postexec(self):
277 278 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
278 279 pre_explicit = mock.Mock()
279 280 pre_always = mock.Mock()
280 281 post_explicit = mock.Mock()
281 282 post_always = mock.Mock()
282 283 all_mocks = [pre_explicit, pre_always, post_explicit, post_always]
283 284
284 285 ip.events.register('pre_run_cell', pre_explicit)
285 286 ip.events.register('pre_execute', pre_always)
286 287 ip.events.register('post_run_cell', post_explicit)
287 288 ip.events.register('post_execute', post_always)
288 289
289 290 try:
290 291 ip.run_cell("1", silent=True)
291 292 assert pre_always.called
292 293 assert not pre_explicit.called
293 294 assert post_always.called
294 295 assert not post_explicit.called
295 296 # double-check that non-silent exec did what we expected
296 297 # silent to avoid
297 298 ip.run_cell("1")
298 299 assert pre_explicit.called
299 300 assert post_explicit.called
300 301 info, = pre_explicit.call_args[0]
301 302 result, = post_explicit.call_args[0]
302 303 self.assertEqual(info, result.info)
303 304 # check that post hooks are always called
304 305 [m.reset_mock() for m in all_mocks]
305 306 ip.run_cell("syntax error")
306 307 assert pre_always.called
307 308 assert pre_explicit.called
308 309 assert post_always.called
309 310 assert post_explicit.called
310 311 info, = pre_explicit.call_args[0]
311 312 result, = post_explicit.call_args[0]
312 313 self.assertEqual(info, result.info)
313 314 finally:
314 315 # remove post-exec
315 316 ip.events.unregister('pre_run_cell', pre_explicit)
316 317 ip.events.unregister('pre_execute', pre_always)
317 318 ip.events.unregister('post_run_cell', post_explicit)
318 319 ip.events.unregister('post_execute', post_always)
319 320
320 321 def test_silent_noadvance(self):
321 322 """run_cell(silent=True) doesn't advance execution_count"""
322 323 ec = ip.execution_count
323 324 # silent should force store_history=False
324 325 ip.run_cell("1", store_history=True, silent=True)
325 326
326 327 self.assertEqual(ec, ip.execution_count)
327 328 # double-check that non-silent exec did what we expected
328 329 # silent to avoid
329 330 ip.run_cell("1", store_history=True)
330 331 self.assertEqual(ec+1, ip.execution_count)
331 332
332 333 def test_silent_nodisplayhook(self):
333 334 """run_cell(silent=True) doesn't trigger displayhook"""
334 335 d = dict(called=False)
335 336
336 337 trap = ip.display_trap
337 338 save_hook = trap.hook
338 339
339 340 def failing_hook(*args, **kwargs):
340 341 d['called'] = True
341 342
342 343 try:
343 344 trap.hook = failing_hook
344 345 res = ip.run_cell("1", silent=True)
345 346 self.assertFalse(d['called'])
346 347 self.assertIsNone(res.result)
347 348 # double-check that non-silent exec did what we expected
348 349 # silent to avoid
349 350 ip.run_cell("1")
350 351 self.assertTrue(d['called'])
351 352 finally:
352 353 trap.hook = save_hook
353 354
354 355 def test_ofind_line_magic(self):
355 356 from IPython.core.magic import register_line_magic
356 357
357 358 @register_line_magic
358 359 def lmagic(line):
359 360 "A line magic"
360 361
361 362 # Get info on line magic
362 363 lfind = ip._ofind("lmagic")
363 info = dict(
364 info = OInfo(
364 365 found=True,
365 366 isalias=False,
366 367 ismagic=True,
367 368 namespace="IPython internal",
368 369 obj=lmagic,
369 370 parent=None,
370 371 )
371 372 self.assertEqual(lfind, info)
372 373
373 374 def test_ofind_cell_magic(self):
374 375 from IPython.core.magic import register_cell_magic
375 376
376 377 @register_cell_magic
377 378 def cmagic(line, cell):
378 379 "A cell magic"
379 380
380 381 # Get info on cell magic
381 382 find = ip._ofind("cmagic")
382 info = dict(
383 info = OInfo(
383 384 found=True,
384 385 isalias=False,
385 386 ismagic=True,
386 387 namespace="IPython internal",
387 388 obj=cmagic,
388 389 parent=None,
389 390 )
390 391 self.assertEqual(find, info)
391 392
392 393 def test_ofind_property_with_error(self):
393 394 class A(object):
394 395 @property
395 396 def foo(self):
396 397 raise NotImplementedError() # pragma: no cover
397 398
398 399 a = A()
399 400
400 found = ip._ofind('a.foo', [('locals', locals())])
401 info = dict(found=True, isalias=False, ismagic=False,
402 namespace='locals', obj=A.foo, parent=a)
401 found = ip._ofind("a.foo", [("locals", locals())])
402 info = OInfo(
403 found=True,
404 isalias=False,
405 ismagic=False,
406 namespace="locals",
407 obj=A.foo,
408 parent=a,
409 )
403 410 self.assertEqual(found, info)
404 411
405 412 def test_ofind_multiple_attribute_lookups(self):
406 413 class A(object):
407 414 @property
408 415 def foo(self):
409 416 raise NotImplementedError() # pragma: no cover
410 417
411 418 a = A()
412 419 a.a = A()
413 420 a.a.a = A()
414 421
415 found = ip._ofind('a.a.a.foo', [('locals', locals())])
416 info = dict(found=True, isalias=False, ismagic=False,
417 namespace='locals', obj=A.foo, parent=a.a.a)
422 found = ip._ofind("a.a.a.foo", [("locals", locals())])
423 info = OInfo(
424 found=True,
425 isalias=False,
426 ismagic=False,
427 namespace="locals",
428 obj=A.foo,
429 parent=a.a.a,
430 )
418 431 self.assertEqual(found, info)
419 432
420 433 def test_ofind_slotted_attributes(self):
421 434 class A(object):
422 435 __slots__ = ['foo']
423 436 def __init__(self):
424 437 self.foo = 'bar'
425 438
426 439 a = A()
427 found = ip._ofind('a.foo', [('locals', locals())])
428 info = dict(found=True, isalias=False, ismagic=False,
429 namespace='locals', obj=a.foo, parent=a)
440 found = ip._ofind("a.foo", [("locals", locals())])
441 info = OInfo(
442 found=True,
443 isalias=False,
444 ismagic=False,
445 namespace="locals",
446 obj=a.foo,
447 parent=a,
448 )
430 449 self.assertEqual(found, info)
431 450
432 found = ip._ofind('a.bar', [('locals', locals())])
433 info = dict(found=False, isalias=False, ismagic=False,
434 namespace=None, obj=None, parent=a)
451 found = ip._ofind("a.bar", [("locals", locals())])
452 info = OInfo(
453 found=False,
454 isalias=False,
455 ismagic=False,
456 namespace=None,
457 obj=None,
458 parent=a,
459 )
435 460 self.assertEqual(found, info)
436 461
437 462 def test_ofind_prefers_property_to_instance_level_attribute(self):
438 463 class A(object):
439 464 @property
440 465 def foo(self):
441 466 return 'bar'
442 467 a = A()
443 468 a.__dict__["foo"] = "baz"
444 469 self.assertEqual(a.foo, "bar")
445 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 473 def test_custom_syntaxerror_exception(self):
449 474 called = []
450 475 def my_handler(shell, etype, value, tb, tb_offset=None):
451 476 called.append(etype)
452 477 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
453 478
454 479 ip.set_custom_exc((SyntaxError,), my_handler)
455 480 try:
456 481 ip.run_cell("1f")
457 482 # Check that this was called, and only once.
458 483 self.assertEqual(called, [SyntaxError])
459 484 finally:
460 485 # Reset the custom exception hook
461 486 ip.set_custom_exc((), None)
462 487
463 488 def test_custom_exception(self):
464 489 called = []
465 490 def my_handler(shell, etype, value, tb, tb_offset=None):
466 491 called.append(etype)
467 492 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
468 493
469 494 ip.set_custom_exc((ValueError,), my_handler)
470 495 try:
471 496 res = ip.run_cell("raise ValueError('test')")
472 497 # Check that this was called, and only once.
473 498 self.assertEqual(called, [ValueError])
474 499 # Check that the error is on the result object
475 500 self.assertIsInstance(res.error_in_exec, ValueError)
476 501 finally:
477 502 # Reset the custom exception hook
478 503 ip.set_custom_exc((), None)
479 504
480 505 @mock.patch("builtins.print")
481 506 def test_showtraceback_with_surrogates(self, mocked_print):
482 507 values = []
483 508
484 509 def mock_print_func(value, sep=" ", end="\n", file=sys.stdout, flush=False):
485 510 values.append(value)
486 511 if value == chr(0xD8FF):
487 512 raise UnicodeEncodeError("utf-8", chr(0xD8FF), 0, 1, "")
488 513
489 514 # mock builtins.print
490 515 mocked_print.side_effect = mock_print_func
491 516
492 517 # ip._showtraceback() is replaced in globalipapp.py.
493 518 # Call original method to test.
494 519 interactiveshell.InteractiveShell._showtraceback(ip, None, None, chr(0xD8FF))
495 520
496 521 self.assertEqual(mocked_print.call_count, 2)
497 522 self.assertEqual(values, [chr(0xD8FF), "\\ud8ff"])
498 523
499 524 def test_mktempfile(self):
500 525 filename = ip.mktempfile()
501 526 # Check that we can open the file again on Windows
502 527 with open(filename, "w", encoding="utf-8") as f:
503 528 f.write("abc")
504 529
505 530 filename = ip.mktempfile(data="blah")
506 531 with open(filename, "r", encoding="utf-8") as f:
507 532 self.assertEqual(f.read(), "blah")
508 533
509 534 def test_new_main_mod(self):
510 535 # Smoketest to check that this accepts a unicode module name
511 536 name = u'jiefmw'
512 537 mod = ip.new_main_mod(u'%s.py' % name, name)
513 538 self.assertEqual(mod.__name__, name)
514 539
515 540 def test_get_exception_only(self):
516 541 try:
517 542 raise KeyboardInterrupt
518 543 except KeyboardInterrupt:
519 544 msg = ip.get_exception_only()
520 545 self.assertEqual(msg, 'KeyboardInterrupt\n')
521 546
522 547 try:
523 548 raise DerivedInterrupt("foo")
524 549 except KeyboardInterrupt:
525 550 msg = ip.get_exception_only()
526 551 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
527 552
528 553 def test_inspect_text(self):
529 554 ip.run_cell('a = 5')
530 555 text = ip.object_inspect_text('a')
531 556 self.assertIsInstance(text, str)
532 557
533 558 def test_last_execution_result(self):
534 559 """ Check that last execution result gets set correctly (GH-10702) """
535 560 result = ip.run_cell('a = 5; a')
536 561 self.assertTrue(ip.last_execution_succeeded)
537 562 self.assertEqual(ip.last_execution_result.result, 5)
538 563
539 564 result = ip.run_cell('a = x_invalid_id_x')
540 565 self.assertFalse(ip.last_execution_succeeded)
541 566 self.assertFalse(ip.last_execution_result.success)
542 567 self.assertIsInstance(ip.last_execution_result.error_in_exec, NameError)
543 568
544 569 def test_reset_aliasing(self):
545 570 """ Check that standard posix aliases work after %reset. """
546 571 if os.name != 'posix':
547 572 return
548 573
549 574 ip.reset()
550 575 for cmd in ('clear', 'more', 'less', 'man'):
551 576 res = ip.run_cell('%' + cmd)
552 577 self.assertEqual(res.success, True)
553 578
554 579
555 580 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
556 581
557 582 @onlyif_unicode_paths
558 583 def setUp(self):
559 584 self.BASETESTDIR = tempfile.mkdtemp()
560 585 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
561 586 os.mkdir(self.TESTDIR)
562 587 with open(
563 588 join(self.TESTDIR, "åäötestscript.py"), "w", encoding="utf-8"
564 589 ) as sfile:
565 590 sfile.write("pass\n")
566 591 self.oldpath = os.getcwd()
567 592 os.chdir(self.TESTDIR)
568 593 self.fname = u"åäötestscript.py"
569 594
570 595 def tearDown(self):
571 596 os.chdir(self.oldpath)
572 597 shutil.rmtree(self.BASETESTDIR)
573 598
574 599 @onlyif_unicode_paths
575 600 def test_1(self):
576 601 """Test safe_execfile with non-ascii path
577 602 """
578 603 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
579 604
580 605 class ExitCodeChecks(tt.TempFileMixin):
581 606
582 607 def setUp(self):
583 608 self.system = ip.system_raw
584 609
585 610 def test_exit_code_ok(self):
586 611 self.system('exit 0')
587 612 self.assertEqual(ip.user_ns['_exit_code'], 0)
588 613
589 614 def test_exit_code_error(self):
590 615 self.system('exit 1')
591 616 self.assertEqual(ip.user_ns['_exit_code'], 1)
592 617
593 618 @skipif(not hasattr(signal, 'SIGALRM'))
594 619 def test_exit_code_signal(self):
595 620 self.mktmp("import signal, time\n"
596 621 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
597 622 "time.sleep(1)\n")
598 623 self.system("%s %s" % (sys.executable, self.fname))
599 624 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
600 625
601 626 @onlyif_cmds_exist("csh")
602 627 def test_exit_code_signal_csh(self): # pragma: no cover
603 628 SHELL = os.environ.get("SHELL", None)
604 629 os.environ["SHELL"] = find_cmd("csh")
605 630 try:
606 631 self.test_exit_code_signal()
607 632 finally:
608 633 if SHELL is not None:
609 634 os.environ['SHELL'] = SHELL
610 635 else:
611 636 del os.environ['SHELL']
612 637
613 638
614 639 class TestSystemRaw(ExitCodeChecks):
615 640
616 641 def setUp(self):
617 642 super().setUp()
618 643 self.system = ip.system_raw
619 644
620 645 @onlyif_unicode_paths
621 646 def test_1(self):
622 647 """Test system_raw with non-ascii cmd
623 648 """
624 649 cmd = u'''python -c "'åäö'" '''
625 650 ip.system_raw(cmd)
626 651
627 652 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
628 653 @mock.patch('os.system', side_effect=KeyboardInterrupt)
629 654 def test_control_c(self, *mocks):
630 655 try:
631 656 self.system("sleep 1 # wont happen")
632 657 except KeyboardInterrupt: # pragma: no cove
633 658 self.fail(
634 659 "system call should intercept "
635 660 "keyboard interrupt from subprocess.call"
636 661 )
637 662 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
638 663
639 664
640 665 @pytest.mark.parametrize("magic_cmd", ["pip", "conda", "cd"])
641 666 def test_magic_warnings(magic_cmd):
642 667 if sys.platform == "win32":
643 668 to_mock = "os.system"
644 669 expected_arg, expected_kwargs = magic_cmd, dict()
645 670 else:
646 671 to_mock = "subprocess.call"
647 672 expected_arg, expected_kwargs = magic_cmd, dict(
648 673 shell=True, executable=os.environ.get("SHELL", None)
649 674 )
650 675
651 676 with mock.patch(to_mock, return_value=0) as mock_sub:
652 677 with pytest.warns(Warning, match=r"You executed the system command"):
653 678 ip.system_raw(magic_cmd)
654 679 mock_sub.assert_called_once_with(expected_arg, **expected_kwargs)
655 680
656 681
657 682 # TODO: Exit codes are currently ignored on Windows.
658 683 class TestSystemPipedExitCode(ExitCodeChecks):
659 684
660 685 def setUp(self):
661 686 super().setUp()
662 687 self.system = ip.system_piped
663 688
664 689 @skip_win32
665 690 def test_exit_code_ok(self):
666 691 ExitCodeChecks.test_exit_code_ok(self)
667 692
668 693 @skip_win32
669 694 def test_exit_code_error(self):
670 695 ExitCodeChecks.test_exit_code_error(self)
671 696
672 697 @skip_win32
673 698 def test_exit_code_signal(self):
674 699 ExitCodeChecks.test_exit_code_signal(self)
675 700
676 701 class TestModules(tt.TempFileMixin):
677 702 def test_extraneous_loads(self):
678 703 """Test we're not loading modules on startup that we shouldn't.
679 704 """
680 705 self.mktmp("import sys\n"
681 706 "print('numpy' in sys.modules)\n"
682 707 "print('ipyparallel' in sys.modules)\n"
683 708 "print('ipykernel' in sys.modules)\n"
684 709 )
685 710 out = "False\nFalse\nFalse\n"
686 711 tt.ipexec_validate(self.fname, out)
687 712
688 713 class Negator(ast.NodeTransformer):
689 714 """Negates all number literals in an AST."""
690 715
691 716 # for python 3.7 and earlier
692 717 def visit_Num(self, node):
693 718 node.n = -node.n
694 719 return node
695 720
696 721 # for python 3.8+
697 722 def visit_Constant(self, node):
698 723 if isinstance(node.value, int):
699 724 return self.visit_Num(node)
700 725 return node
701 726
702 727 class TestAstTransform(unittest.TestCase):
703 728 def setUp(self):
704 729 self.negator = Negator()
705 730 ip.ast_transformers.append(self.negator)
706 731
707 732 def tearDown(self):
708 733 ip.ast_transformers.remove(self.negator)
709 734
710 735 def test_non_int_const(self):
711 736 with tt.AssertPrints("hello"):
712 737 ip.run_cell('print("hello")')
713 738
714 739 def test_run_cell(self):
715 740 with tt.AssertPrints("-34"):
716 741 ip.run_cell("print(12 + 22)")
717 742
718 743 # A named reference to a number shouldn't be transformed.
719 744 ip.user_ns["n"] = 55
720 745 with tt.AssertNotPrints("-55"):
721 746 ip.run_cell("print(n)")
722 747
723 748 def test_timeit(self):
724 749 called = set()
725 750 def f(x):
726 751 called.add(x)
727 752 ip.push({'f':f})
728 753
729 754 with tt.AssertPrints("std. dev. of"):
730 755 ip.run_line_magic("timeit", "-n1 f(1)")
731 756 self.assertEqual(called, {-1})
732 757 called.clear()
733 758
734 759 with tt.AssertPrints("std. dev. of"):
735 760 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
736 761 self.assertEqual(called, {-2, -3})
737 762
738 763 def test_time(self):
739 764 called = []
740 765 def f(x):
741 766 called.append(x)
742 767 ip.push({'f':f})
743 768
744 769 # Test with an expression
745 770 with tt.AssertPrints("Wall time: "):
746 771 ip.run_line_magic("time", "f(5+9)")
747 772 self.assertEqual(called, [-14])
748 773 called[:] = []
749 774
750 775 # Test with a statement (different code path)
751 776 with tt.AssertPrints("Wall time: "):
752 777 ip.run_line_magic("time", "a = f(-3 + -2)")
753 778 self.assertEqual(called, [5])
754 779
755 780 def test_macro(self):
756 781 ip.push({'a':10})
757 782 # The AST transformation makes this do a+=-1
758 783 ip.define_macro("amacro", "a+=1\nprint(a)")
759 784
760 785 with tt.AssertPrints("9"):
761 786 ip.run_cell("amacro")
762 787 with tt.AssertPrints("8"):
763 788 ip.run_cell("amacro")
764 789
765 790 class TestMiscTransform(unittest.TestCase):
766 791
767 792
768 793 def test_transform_only_once(self):
769 794 cleanup = 0
770 795 line_t = 0
771 796 def count_cleanup(lines):
772 797 nonlocal cleanup
773 798 cleanup += 1
774 799 return lines
775 800
776 801 def count_line_t(lines):
777 802 nonlocal line_t
778 803 line_t += 1
779 804 return lines
780 805
781 806 ip.input_transformer_manager.cleanup_transforms.append(count_cleanup)
782 807 ip.input_transformer_manager.line_transforms.append(count_line_t)
783 808
784 809 ip.run_cell('1')
785 810
786 811 assert cleanup == 1
787 812 assert line_t == 1
788 813
789 814 class IntegerWrapper(ast.NodeTransformer):
790 815 """Wraps all integers in a call to Integer()"""
791 816
792 817 # for Python 3.7 and earlier
793 818
794 819 # for Python 3.7 and earlier
795 820 def visit_Num(self, node):
796 821 if isinstance(node.n, int):
797 822 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
798 823 args=[node], keywords=[])
799 824 return node
800 825
801 826 # For Python 3.8+
802 827 def visit_Constant(self, node):
803 828 if isinstance(node.value, int):
804 829 return self.visit_Num(node)
805 830 return node
806 831
807 832
808 833 class TestAstTransform2(unittest.TestCase):
809 834 def setUp(self):
810 835 self.intwrapper = IntegerWrapper()
811 836 ip.ast_transformers.append(self.intwrapper)
812 837
813 838 self.calls = []
814 839 def Integer(*args):
815 840 self.calls.append(args)
816 841 return args
817 842 ip.push({"Integer": Integer})
818 843
819 844 def tearDown(self):
820 845 ip.ast_transformers.remove(self.intwrapper)
821 846 del ip.user_ns['Integer']
822 847
823 848 def test_run_cell(self):
824 849 ip.run_cell("n = 2")
825 850 self.assertEqual(self.calls, [(2,)])
826 851
827 852 # This shouldn't throw an error
828 853 ip.run_cell("o = 2.0")
829 854 self.assertEqual(ip.user_ns['o'], 2.0)
830 855
831 856 def test_run_cell_non_int(self):
832 857 ip.run_cell("n = 'a'")
833 858 assert self.calls == []
834 859
835 860 def test_timeit(self):
836 861 called = set()
837 862 def f(x):
838 863 called.add(x)
839 864 ip.push({'f':f})
840 865
841 866 with tt.AssertPrints("std. dev. of"):
842 867 ip.run_line_magic("timeit", "-n1 f(1)")
843 868 self.assertEqual(called, {(1,)})
844 869 called.clear()
845 870
846 871 with tt.AssertPrints("std. dev. of"):
847 872 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
848 873 self.assertEqual(called, {(2,), (3,)})
849 874
850 875 class ErrorTransformer(ast.NodeTransformer):
851 876 """Throws an error when it sees a number."""
852 877
853 878 def visit_Constant(self, node):
854 879 if isinstance(node.value, int):
855 880 raise ValueError("test")
856 881 return node
857 882
858 883
859 884 class TestAstTransformError(unittest.TestCase):
860 885 def test_unregistering(self):
861 886 err_transformer = ErrorTransformer()
862 887 ip.ast_transformers.append(err_transformer)
863 888
864 889 with self.assertWarnsRegex(UserWarning, "It will be unregistered"):
865 890 ip.run_cell("1 + 2")
866 891
867 892 # This should have been removed.
868 893 self.assertNotIn(err_transformer, ip.ast_transformers)
869 894
870 895
871 896 class StringRejector(ast.NodeTransformer):
872 897 """Throws an InputRejected when it sees a string literal.
873 898
874 899 Used to verify that NodeTransformers can signal that a piece of code should
875 900 not be executed by throwing an InputRejected.
876 901 """
877 902
878 903 # 3.8 only
879 904 def visit_Constant(self, node):
880 905 if isinstance(node.value, str):
881 906 raise InputRejected("test")
882 907 return node
883 908
884 909
885 910 class TestAstTransformInputRejection(unittest.TestCase):
886 911
887 912 def setUp(self):
888 913 self.transformer = StringRejector()
889 914 ip.ast_transformers.append(self.transformer)
890 915
891 916 def tearDown(self):
892 917 ip.ast_transformers.remove(self.transformer)
893 918
894 919 def test_input_rejection(self):
895 920 """Check that NodeTransformers can reject input."""
896 921
897 922 expect_exception_tb = tt.AssertPrints("InputRejected: test")
898 923 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
899 924
900 925 # Run the same check twice to verify that the transformer is not
901 926 # disabled after raising.
902 927 with expect_exception_tb, expect_no_cell_output:
903 928 ip.run_cell("'unsafe'")
904 929
905 930 with expect_exception_tb, expect_no_cell_output:
906 931 res = ip.run_cell("'unsafe'")
907 932
908 933 self.assertIsInstance(res.error_before_exec, InputRejected)
909 934
910 935 def test__IPYTHON__():
911 936 # This shouldn't raise a NameError, that's all
912 937 __IPYTHON__
913 938
914 939
915 940 class DummyRepr(object):
916 941 def __repr__(self):
917 942 return "DummyRepr"
918 943
919 944 def _repr_html_(self):
920 945 return "<b>dummy</b>"
921 946
922 947 def _repr_javascript_(self):
923 948 return "console.log('hi');", {'key': 'value'}
924 949
925 950
926 951 def test_user_variables():
927 952 # enable all formatters
928 953 ip.display_formatter.active_types = ip.display_formatter.format_types
929 954
930 955 ip.user_ns['dummy'] = d = DummyRepr()
931 956 keys = {'dummy', 'doesnotexist'}
932 957 r = ip.user_expressions({ key:key for key in keys})
933 958
934 959 assert keys == set(r.keys())
935 960 dummy = r["dummy"]
936 961 assert {"status", "data", "metadata"} == set(dummy.keys())
937 962 assert dummy["status"] == "ok"
938 963 data = dummy["data"]
939 964 metadata = dummy["metadata"]
940 965 assert data.get("text/html") == d._repr_html_()
941 966 js, jsmd = d._repr_javascript_()
942 967 assert data.get("application/javascript") == js
943 968 assert metadata.get("application/javascript") == jsmd
944 969
945 970 dne = r["doesnotexist"]
946 971 assert dne["status"] == "error"
947 972 assert dne["ename"] == "NameError"
948 973
949 974 # back to text only
950 975 ip.display_formatter.active_types = ['text/plain']
951 976
952 977 def test_user_expression():
953 978 # enable all formatters
954 979 ip.display_formatter.active_types = ip.display_formatter.format_types
955 980 query = {
956 981 'a' : '1 + 2',
957 982 'b' : '1/0',
958 983 }
959 984 r = ip.user_expressions(query)
960 985 import pprint
961 986 pprint.pprint(r)
962 987 assert set(r.keys()) == set(query.keys())
963 988 a = r["a"]
964 989 assert {"status", "data", "metadata"} == set(a.keys())
965 990 assert a["status"] == "ok"
966 991 data = a["data"]
967 992 metadata = a["metadata"]
968 993 assert data.get("text/plain") == "3"
969 994
970 995 b = r["b"]
971 996 assert b["status"] == "error"
972 997 assert b["ename"] == "ZeroDivisionError"
973 998
974 999 # back to text only
975 1000 ip.display_formatter.active_types = ['text/plain']
976 1001
977 1002
978 1003 class TestSyntaxErrorTransformer(unittest.TestCase):
979 1004 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
980 1005
981 1006 @staticmethod
982 1007 def transformer(lines):
983 1008 for line in lines:
984 1009 pos = line.find('syntaxerror')
985 1010 if pos >= 0:
986 1011 e = SyntaxError('input contains "syntaxerror"')
987 1012 e.text = line
988 1013 e.offset = pos + 1
989 1014 raise e
990 1015 return lines
991 1016
992 1017 def setUp(self):
993 1018 ip.input_transformers_post.append(self.transformer)
994 1019
995 1020 def tearDown(self):
996 1021 ip.input_transformers_post.remove(self.transformer)
997 1022
998 1023 def test_syntaxerror_input_transformer(self):
999 1024 with tt.AssertPrints('1234'):
1000 1025 ip.run_cell('1234')
1001 1026 with tt.AssertPrints('SyntaxError: invalid syntax'):
1002 1027 ip.run_cell('1 2 3') # plain python syntax error
1003 1028 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
1004 1029 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
1005 1030 with tt.AssertPrints('3456'):
1006 1031 ip.run_cell('3456')
1007 1032
1008 1033
1009 1034 class TestWarningSuppression(unittest.TestCase):
1010 1035 def test_warning_suppression(self):
1011 1036 ip.run_cell("import warnings")
1012 1037 try:
1013 1038 with self.assertWarnsRegex(UserWarning, "asdf"):
1014 1039 ip.run_cell("warnings.warn('asdf')")
1015 1040 # Here's the real test -- if we run that again, we should get the
1016 1041 # warning again. Traditionally, each warning was only issued once per
1017 1042 # IPython session (approximately), even if the user typed in new and
1018 1043 # different code that should have also triggered the warning, leading
1019 1044 # to much confusion.
1020 1045 with self.assertWarnsRegex(UserWarning, "asdf"):
1021 1046 ip.run_cell("warnings.warn('asdf')")
1022 1047 finally:
1023 1048 ip.run_cell("del warnings")
1024 1049
1025 1050
1026 1051 def test_deprecation_warning(self):
1027 1052 ip.run_cell("""
1028 1053 import warnings
1029 1054 def wrn():
1030 1055 warnings.warn(
1031 1056 "I AM A WARNING",
1032 1057 DeprecationWarning
1033 1058 )
1034 1059 """)
1035 1060 try:
1036 1061 with self.assertWarnsRegex(DeprecationWarning, "I AM A WARNING"):
1037 1062 ip.run_cell("wrn()")
1038 1063 finally:
1039 1064 ip.run_cell("del warnings")
1040 1065 ip.run_cell("del wrn")
1041 1066
1042 1067
1043 1068 class TestImportNoDeprecate(tt.TempFileMixin):
1044 1069
1045 1070 def setUp(self):
1046 1071 """Make a valid python temp file."""
1047 1072 self.mktmp("""
1048 1073 import warnings
1049 1074 def wrn():
1050 1075 warnings.warn(
1051 1076 "I AM A WARNING",
1052 1077 DeprecationWarning
1053 1078 )
1054 1079 """)
1055 1080 super().setUp()
1056 1081
1057 1082 def test_no_dep(self):
1058 1083 """
1059 1084 No deprecation warning should be raised from imported functions
1060 1085 """
1061 1086 ip.run_cell("from {} import wrn".format(self.fname))
1062 1087
1063 1088 with tt.AssertNotPrints("I AM A WARNING"):
1064 1089 ip.run_cell("wrn()")
1065 1090 ip.run_cell("del wrn")
1066 1091
1067 1092
1068 1093 def test_custom_exc_count():
1069 1094 hook = mock.Mock(return_value=None)
1070 1095 ip.set_custom_exc((SyntaxError,), hook)
1071 1096 before = ip.execution_count
1072 1097 ip.run_cell("def foo()", store_history=True)
1073 1098 # restore default excepthook
1074 1099 ip.set_custom_exc((), None)
1075 1100 assert hook.call_count == 1
1076 1101 assert ip.execution_count == before + 1
1077 1102
1078 1103
1079 1104 def test_run_cell_async():
1080 1105 ip.run_cell("import asyncio")
1081 1106 coro = ip.run_cell_async("await asyncio.sleep(0.01)\n5")
1082 1107 assert asyncio.iscoroutine(coro)
1083 1108 loop = asyncio.new_event_loop()
1084 1109 result = loop.run_until_complete(coro)
1085 1110 assert isinstance(result, interactiveshell.ExecutionResult)
1086 1111 assert result.result == 5
1087 1112
1088 1113
1089 1114 def test_run_cell_await():
1090 1115 ip.run_cell("import asyncio")
1091 1116 result = ip.run_cell("await asyncio.sleep(0.01); 10")
1092 1117 assert ip.user_ns["_"] == 10
1093 1118
1094 1119
1095 1120 def test_run_cell_asyncio_run():
1096 1121 ip.run_cell("import asyncio")
1097 1122 result = ip.run_cell("await asyncio.sleep(0.01); 1")
1098 1123 assert ip.user_ns["_"] == 1
1099 1124 result = ip.run_cell("asyncio.run(asyncio.sleep(0.01)); 2")
1100 1125 assert ip.user_ns["_"] == 2
1101 1126 result = ip.run_cell("await asyncio.sleep(0.01); 3")
1102 1127 assert ip.user_ns["_"] == 3
1103 1128
1104 1129
1105 1130 def test_should_run_async():
1106 1131 assert not ip.should_run_async("a = 5", transformed_cell="a = 5")
1107 1132 assert ip.should_run_async("await x", transformed_cell="await x")
1108 1133 assert ip.should_run_async(
1109 1134 "import asyncio; await asyncio.sleep(1)",
1110 1135 transformed_cell="import asyncio; await asyncio.sleep(1)",
1111 1136 )
1112 1137
1113 1138
1114 1139 def test_set_custom_completer():
1115 1140 num_completers = len(ip.Completer.matchers)
1116 1141
1117 1142 def foo(*args, **kwargs):
1118 1143 return "I'm a completer!"
1119 1144
1120 1145 ip.set_custom_completer(foo, 0)
1121 1146
1122 1147 # check that we've really added a new completer
1123 1148 assert len(ip.Completer.matchers) == num_completers + 1
1124 1149
1125 1150 # check that the first completer is the function we defined
1126 1151 assert ip.Completer.matchers[0]() == "I'm a completer!"
1127 1152
1128 1153 # clean up
1129 1154 ip.Completer.custom_matchers.pop()
1130 1155
1131 1156
1132 1157 class TestShowTracebackAttack(unittest.TestCase):
1133 1158 """Test that the interactive shell is resilient against the client attack of
1134 1159 manipulating the showtracebacks method. These attacks shouldn't result in an
1135 1160 unhandled exception in the kernel."""
1136 1161
1137 1162 def setUp(self):
1138 1163 self.orig_showtraceback = interactiveshell.InteractiveShell.showtraceback
1139 1164
1140 1165 def tearDown(self):
1141 1166 interactiveshell.InteractiveShell.showtraceback = self.orig_showtraceback
1142 1167
1143 1168 def test_set_show_tracebacks_none(self):
1144 1169 """Test the case of the client setting showtracebacks to None"""
1145 1170
1146 1171 result = ip.run_cell(
1147 1172 """
1148 1173 import IPython.core.interactiveshell
1149 1174 IPython.core.interactiveshell.InteractiveShell.showtraceback = None
1150 1175
1151 1176 assert False, "This should not raise an exception"
1152 1177 """
1153 1178 )
1154 1179 print(result)
1155 1180
1156 1181 assert result.result is None
1157 1182 assert isinstance(result.error_in_exec, TypeError)
1158 1183 assert str(result.error_in_exec) == "'NoneType' object is not callable"
1159 1184
1160 1185 def test_set_show_tracebacks_noop(self):
1161 1186 """Test the case of the client setting showtracebacks to a no op lambda"""
1162 1187
1163 1188 result = ip.run_cell(
1164 1189 """
1165 1190 import IPython.core.interactiveshell
1166 1191 IPython.core.interactiveshell.InteractiveShell.showtraceback = lambda *args, **kwargs: None
1167 1192
1168 1193 assert False, "This should not raise an exception"
1169 1194 """
1170 1195 )
1171 1196 print(result)
1172 1197
1173 1198 assert result.result is None
1174 1199 assert isinstance(result.error_in_exec, AssertionError)
1175 1200 assert str(result.error_in_exec) == "This should not raise an exception"
@@ -1,1531 +1,1548 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for various magic functions."""
3 3
4 4 import gc
5 5 import io
6 6 import os
7 7 import re
8 8 import shlex
9 9 import sys
10 10 import warnings
11 11 from importlib import invalidate_caches
12 12 from io import StringIO
13 13 from pathlib import Path
14 14 from textwrap import dedent
15 15 from unittest import TestCase, mock
16 16
17 17 import pytest
18 18
19 19 from IPython import get_ipython
20 20 from IPython.core import magic
21 21 from IPython.core.error import UsageError
22 22 from IPython.core.magic import (
23 23 Magics,
24 24 cell_magic,
25 25 line_magic,
26 26 magics_class,
27 27 register_cell_magic,
28 28 register_line_magic,
29 29 )
30 30 from IPython.core.magics import code, execution, logging, osm, script
31 31 from IPython.testing import decorators as dec
32 32 from IPython.testing import tools as tt
33 33 from IPython.utils.io import capture_output
34 34 from IPython.utils.process import find_cmd
35 35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
36 36 from IPython.utils.syspathcontext import prepended_to_syspath
37 37
38 38 from .test_debugger import PdbTestInput
39 39
40 40 from tempfile import NamedTemporaryFile
41 41
42 42 @magic.magics_class
43 43 class DummyMagics(magic.Magics): pass
44 44
45 45 def test_extract_code_ranges():
46 46 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
47 47 expected = [
48 48 (0, 1),
49 49 (2, 3),
50 50 (4, 6),
51 51 (6, 9),
52 52 (9, 14),
53 53 (16, None),
54 54 (None, 9),
55 55 (9, None),
56 56 (None, 13),
57 57 (None, None),
58 58 ]
59 59 actual = list(code.extract_code_ranges(instr))
60 60 assert actual == expected
61 61
62 62 def test_extract_symbols():
63 63 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
64 64 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
65 65 expected = [([], ['a']),
66 66 (["def b():\n return 42\n"], []),
67 67 (["class A: pass\n"], []),
68 68 (["class A: pass\n", "def b():\n return 42\n"], []),
69 69 (["class A: pass\n"], ['a']),
70 70 ([], ['z'])]
71 71 for symbols, exp in zip(symbols_args, expected):
72 72 assert code.extract_symbols(source, symbols) == exp
73 73
74 74
75 75 def test_extract_symbols_raises_exception_with_non_python_code():
76 76 source = ("=begin A Ruby program :)=end\n"
77 77 "def hello\n"
78 78 "puts 'Hello world'\n"
79 79 "end")
80 80 with pytest.raises(SyntaxError):
81 81 code.extract_symbols(source, "hello")
82 82
83 83
84 84 def test_magic_not_found():
85 85 # magic not found raises UsageError
86 86 with pytest.raises(UsageError):
87 87 _ip.run_line_magic("doesntexist", "")
88 88
89 89 # ensure result isn't success when a magic isn't found
90 90 result = _ip.run_cell('%doesntexist')
91 91 assert isinstance(result.error_in_exec, UsageError)
92 92
93 93
94 94 def test_cell_magic_not_found():
95 95 # magic not found raises UsageError
96 96 with pytest.raises(UsageError):
97 97 _ip.run_cell_magic('doesntexist', 'line', 'cell')
98 98
99 99 # ensure result isn't success when a magic isn't found
100 100 result = _ip.run_cell('%%doesntexist')
101 101 assert isinstance(result.error_in_exec, UsageError)
102 102
103 103
104 104 def test_magic_error_status():
105 105 def fail(shell):
106 106 1/0
107 107 _ip.register_magic_function(fail)
108 108 result = _ip.run_cell('%fail')
109 109 assert isinstance(result.error_in_exec, ZeroDivisionError)
110 110
111 111
112 112 def test_config():
113 113 """ test that config magic does not raise
114 114 can happen if Configurable init is moved too early into
115 115 Magics.__init__ as then a Config object will be registered as a
116 116 magic.
117 117 """
118 118 ## should not raise.
119 119 _ip.run_line_magic("config", "")
120 120
121 121
122 122 def test_config_available_configs():
123 123 """ test that config magic prints available configs in unique and
124 124 sorted order. """
125 125 with capture_output() as captured:
126 126 _ip.run_line_magic("config", "")
127 127
128 128 stdout = captured.stdout
129 129 config_classes = stdout.strip().split('\n')[1:]
130 130 assert config_classes == sorted(set(config_classes))
131 131
132 132 def test_config_print_class():
133 133 """ test that config with a classname prints the class's options. """
134 134 with capture_output() as captured:
135 135 _ip.run_line_magic("config", "TerminalInteractiveShell")
136 136
137 137 stdout = captured.stdout
138 138 assert re.match(
139 139 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
140 140 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
141 141
142 142
143 143 def test_rehashx():
144 144 # clear up everything
145 145 _ip.alias_manager.clear_aliases()
146 146 del _ip.db['syscmdlist']
147 147
148 148 _ip.run_line_magic("rehashx", "")
149 149 # Practically ALL ipython development systems will have more than 10 aliases
150 150
151 151 assert len(_ip.alias_manager.aliases) > 10
152 152 for name, cmd in _ip.alias_manager.aliases:
153 153 # we must strip dots from alias names
154 154 assert "." not in name
155 155
156 156 # rehashx must fill up syscmdlist
157 157 scoms = _ip.db['syscmdlist']
158 158 assert len(scoms) > 10
159 159
160 160
161 161 def test_magic_parse_options():
162 162 """Test that we don't mangle paths when parsing magic options."""
163 163 ip = get_ipython()
164 164 path = 'c:\\x'
165 165 m = DummyMagics(ip)
166 166 opts = m.parse_options('-f %s' % path,'f:')[0]
167 167 # argv splitting is os-dependent
168 168 if os.name == 'posix':
169 169 expected = 'c:x'
170 170 else:
171 171 expected = path
172 172 assert opts["f"] == expected
173 173
174 174
175 175 def test_magic_parse_long_options():
176 176 """Magic.parse_options can handle --foo=bar long options"""
177 177 ip = get_ipython()
178 178 m = DummyMagics(ip)
179 179 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
180 180 assert "foo" in opts
181 181 assert "bar" in opts
182 182 assert opts["bar"] == "bubble"
183 183
184 184
185 185 def doctest_hist_f():
186 186 """Test %hist -f with temporary filename.
187 187
188 188 In [9]: import tempfile
189 189
190 190 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
191 191
192 192 In [11]: %hist -nl -f $tfile 3
193 193
194 194 In [13]: import os; os.unlink(tfile)
195 195 """
196 196
197 197
198 198 def doctest_hist_op():
199 199 """Test %hist -op
200 200
201 201 In [1]: class b(float):
202 202 ...: pass
203 203 ...:
204 204
205 205 In [2]: class s(object):
206 206 ...: def __str__(self):
207 207 ...: return 's'
208 208 ...:
209 209
210 210 In [3]:
211 211
212 212 In [4]: class r(b):
213 213 ...: def __repr__(self):
214 214 ...: return 'r'
215 215 ...:
216 216
217 217 In [5]: class sr(s,r): pass
218 218 ...:
219 219
220 220 In [6]:
221 221
222 222 In [7]: bb=b()
223 223
224 224 In [8]: ss=s()
225 225
226 226 In [9]: rr=r()
227 227
228 228 In [10]: ssrr=sr()
229 229
230 230 In [11]: 4.5
231 231 Out[11]: 4.5
232 232
233 233 In [12]: str(ss)
234 234 Out[12]: 's'
235 235
236 236 In [13]:
237 237
238 238 In [14]: %hist -op
239 239 >>> class b:
240 240 ... pass
241 241 ...
242 242 >>> class s(b):
243 243 ... def __str__(self):
244 244 ... return 's'
245 245 ...
246 246 >>>
247 247 >>> class r(b):
248 248 ... def __repr__(self):
249 249 ... return 'r'
250 250 ...
251 251 >>> class sr(s,r): pass
252 252 >>>
253 253 >>> bb=b()
254 254 >>> ss=s()
255 255 >>> rr=r()
256 256 >>> ssrr=sr()
257 257 >>> 4.5
258 258 4.5
259 259 >>> str(ss)
260 260 's'
261 261 >>>
262 262 """
263 263
264 264 def test_hist_pof():
265 265 ip = get_ipython()
266 266 ip.run_cell("1+2", store_history=True)
267 267 #raise Exception(ip.history_manager.session_number)
268 268 #raise Exception(list(ip.history_manager._get_range_session()))
269 269 with TemporaryDirectory() as td:
270 270 tf = os.path.join(td, 'hist.py')
271 271 ip.run_line_magic('history', '-pof %s' % tf)
272 272 assert os.path.isfile(tf)
273 273
274 274
275 275 def test_macro():
276 276 ip = get_ipython()
277 277 ip.history_manager.reset() # Clear any existing history.
278 278 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
279 279 for i, cmd in enumerate(cmds, start=1):
280 280 ip.history_manager.store_inputs(i, cmd)
281 281 ip.run_line_magic("macro", "test 1-3")
282 282 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
283 283
284 284 # List macros
285 285 assert "test" in ip.run_line_magic("macro", "")
286 286
287 287
288 288 def test_macro_run():
289 289 """Test that we can run a multi-line macro successfully."""
290 290 ip = get_ipython()
291 291 ip.history_manager.reset()
292 292 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
293 293 for cmd in cmds:
294 294 ip.run_cell(cmd, store_history=True)
295 295 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
296 296 with tt.AssertPrints("12"):
297 297 ip.run_cell("test")
298 298 with tt.AssertPrints("13"):
299 299 ip.run_cell("test")
300 300
301 301
302 302 def test_magic_magic():
303 303 """Test %magic"""
304 304 ip = get_ipython()
305 305 with capture_output() as captured:
306 306 ip.run_line_magic("magic", "")
307 307
308 308 stdout = captured.stdout
309 309 assert "%magic" in stdout
310 310 assert "IPython" in stdout
311 311 assert "Available" in stdout
312 312
313 313
314 314 @dec.skipif_not_numpy
315 315 def test_numpy_reset_array_undec():
316 316 "Test '%reset array' functionality"
317 317 _ip.ex("import numpy as np")
318 318 _ip.ex("a = np.empty(2)")
319 319 assert "a" in _ip.user_ns
320 320 _ip.run_line_magic("reset", "-f array")
321 321 assert "a" not in _ip.user_ns
322 322
323 323
324 324 def test_reset_out():
325 325 "Test '%reset out' magic"
326 326 _ip.run_cell("parrot = 'dead'", store_history=True)
327 327 # test '%reset -f out', make an Out prompt
328 328 _ip.run_cell("parrot", store_history=True)
329 329 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
330 330 _ip.run_line_magic("reset", "-f out")
331 331 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
332 332 assert len(_ip.user_ns["Out"]) == 0
333 333
334 334
335 335 def test_reset_in():
336 336 "Test '%reset in' magic"
337 337 # test '%reset -f in'
338 338 _ip.run_cell("parrot", store_history=True)
339 339 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
340 340 _ip.run_line_magic("reset", "-f in")
341 341 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
342 342 assert len(set(_ip.user_ns["In"])) == 1
343 343
344 344
345 345 def test_reset_dhist():
346 346 "Test '%reset dhist' magic"
347 347 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
348 348 _ip.run_line_magic("cd", os.path.dirname(pytest.__file__))
349 349 _ip.run_line_magic("cd", "-")
350 350 assert len(_ip.user_ns["_dh"]) > 0
351 351 _ip.run_line_magic("reset", "-f dhist")
352 352 assert len(_ip.user_ns["_dh"]) == 0
353 353 _ip.run_cell("_dh = [d for d in tmp]") # restore
354 354
355 355
356 356 def test_reset_in_length():
357 357 "Test that '%reset in' preserves In[] length"
358 358 _ip.run_cell("print 'foo'")
359 359 _ip.run_cell("reset -f in")
360 360 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
361 361
362 362
363 363 class TestResetErrors(TestCase):
364 364
365 365 def test_reset_redefine(self):
366 366
367 367 @magics_class
368 368 class KernelMagics(Magics):
369 369 @line_magic
370 370 def less(self, shell): pass
371 371
372 372 _ip.register_magics(KernelMagics)
373 373
374 374 with self.assertLogs() as cm:
375 375 # hack, we want to just capture logs, but assertLogs fails if not
376 376 # logs get produce.
377 377 # so log one things we ignore.
378 378 import logging as log_mod
379 379 log = log_mod.getLogger()
380 380 log.info('Nothing')
381 381 # end hack.
382 382 _ip.run_cell("reset -f")
383 383
384 384 assert len(cm.output) == 1
385 385 for out in cm.output:
386 386 assert "Invalid alias" not in out
387 387
388 388 def test_tb_syntaxerror():
389 389 """test %tb after a SyntaxError"""
390 390 ip = get_ipython()
391 391 ip.run_cell("for")
392 392
393 393 # trap and validate stdout
394 394 save_stdout = sys.stdout
395 395 try:
396 396 sys.stdout = StringIO()
397 397 ip.run_cell("%tb")
398 398 out = sys.stdout.getvalue()
399 399 finally:
400 400 sys.stdout = save_stdout
401 401 # trim output, and only check the last line
402 402 last_line = out.rstrip().splitlines()[-1].strip()
403 403 assert last_line == "SyntaxError: invalid syntax"
404 404
405 405
406 406 def test_time():
407 407 ip = get_ipython()
408 408
409 409 with tt.AssertPrints("Wall time: "):
410 410 ip.run_cell("%time None")
411 411
412 412 ip.run_cell("def f(kmjy):\n"
413 413 " %time print (2*kmjy)")
414 414
415 415 with tt.AssertPrints("Wall time: "):
416 416 with tt.AssertPrints("hihi", suppress=False):
417 417 ip.run_cell("f('hi')")
418 418
419 419
420 420 # ';' at the end of %time prevents instruction value to be printed.
421 421 # This tests fix for #13837.
422 422 def test_time_no_output_with_semicolon():
423 423 ip = get_ipython()
424 424
425 425 # Test %time cases
426 426 with tt.AssertPrints(" 123456"):
427 427 with tt.AssertPrints("Wall time: ", suppress=False):
428 428 with tt.AssertPrints("CPU times: ", suppress=False):
429 429 ip.run_cell("%time 123000+456")
430 430
431 431 with tt.AssertNotPrints(" 123456"):
432 432 with tt.AssertPrints("Wall time: ", suppress=False):
433 433 with tt.AssertPrints("CPU times: ", suppress=False):
434 434 ip.run_cell("%time 123000+456;")
435 435
436 436 with tt.AssertPrints(" 123456"):
437 437 with tt.AssertPrints("Wall time: ", suppress=False):
438 438 with tt.AssertPrints("CPU times: ", suppress=False):
439 439 ip.run_cell("%time 123000+456 # Comment")
440 440
441 441 with tt.AssertNotPrints(" 123456"):
442 442 with tt.AssertPrints("Wall time: ", suppress=False):
443 443 with tt.AssertPrints("CPU times: ", suppress=False):
444 444 ip.run_cell("%time 123000+456; # Comment")
445 445
446 446 with tt.AssertPrints(" 123456"):
447 447 with tt.AssertPrints("Wall time: ", suppress=False):
448 448 with tt.AssertPrints("CPU times: ", suppress=False):
449 449 ip.run_cell("%time 123000+456 # ;Comment")
450 450
451 451 # Test %%time cases
452 452 with tt.AssertPrints("123456"):
453 453 with tt.AssertPrints("Wall time: ", suppress=False):
454 454 with tt.AssertPrints("CPU times: ", suppress=False):
455 455 ip.run_cell("%%time\n123000+456\n\n\n")
456 456
457 457 with tt.AssertNotPrints("123456"):
458 458 with tt.AssertPrints("Wall time: ", suppress=False):
459 459 with tt.AssertPrints("CPU times: ", suppress=False):
460 460 ip.run_cell("%%time\n123000+456;\n\n\n")
461 461
462 462 with tt.AssertPrints("123456"):
463 463 with tt.AssertPrints("Wall time: ", suppress=False):
464 464 with tt.AssertPrints("CPU times: ", suppress=False):
465 465 ip.run_cell("%%time\n123000+456 # Comment\n\n\n")
466 466
467 467 with tt.AssertNotPrints("123456"):
468 468 with tt.AssertPrints("Wall time: ", suppress=False):
469 469 with tt.AssertPrints("CPU times: ", suppress=False):
470 470 ip.run_cell("%%time\n123000+456; # Comment\n\n\n")
471 471
472 472 with tt.AssertPrints("123456"):
473 473 with tt.AssertPrints("Wall time: ", suppress=False):
474 474 with tt.AssertPrints("CPU times: ", suppress=False):
475 475 ip.run_cell("%%time\n123000+456 # ;Comment\n\n\n")
476 476
477 477
478 478 def test_time_last_not_expression():
479 479 ip.run_cell("%%time\n"
480 480 "var_1 = 1\n"
481 481 "var_2 = 2\n")
482 482 assert ip.user_ns['var_1'] == 1
483 483 del ip.user_ns['var_1']
484 484 assert ip.user_ns['var_2'] == 2
485 485 del ip.user_ns['var_2']
486 486
487 487
488 488 @dec.skip_win32
489 489 def test_time2():
490 490 ip = get_ipython()
491 491
492 492 with tt.AssertPrints("CPU times: user "):
493 493 ip.run_cell("%time None")
494 494
495 495 def test_time3():
496 496 """Erroneous magic function calls, issue gh-3334"""
497 497 ip = get_ipython()
498 498 ip.user_ns.pop('run', None)
499 499
500 500 with tt.AssertNotPrints("not found", channel='stderr'):
501 501 ip.run_cell("%%time\n"
502 502 "run = 0\n"
503 503 "run += 1")
504 504
505 505 def test_multiline_time():
506 506 """Make sure last statement from time return a value."""
507 507 ip = get_ipython()
508 508 ip.user_ns.pop('run', None)
509 509
510 510 ip.run_cell(
511 511 dedent(
512 512 """\
513 513 %%time
514 514 a = "ho"
515 515 b = "hey"
516 516 a+b
517 517 """
518 518 )
519 519 )
520 520 assert ip.user_ns_hidden["_"] == "hohey"
521 521
522 522
523 523 def test_time_local_ns():
524 524 """
525 525 Test that local_ns is actually global_ns when running a cell magic
526 526 """
527 527 ip = get_ipython()
528 528 ip.run_cell("%%time\n" "myvar = 1")
529 529 assert ip.user_ns["myvar"] == 1
530 530 del ip.user_ns["myvar"]
531 531
532 532
533 533 # Test %%capture magic. Added to test issue #13926
534 534 def test_capture():
535 535 ip = get_ipython()
536 536
537 537 # Test %%capture nominal case
538 538 ip.run_cell("%%capture abc\n1+2")
539 539 with tt.AssertPrints("True", suppress=False):
540 540 ip.run_cell("'abc' in locals()")
541 541 with tt.AssertPrints("True", suppress=False):
542 542 ip.run_cell("'outputs' in dir(abc)")
543 543 with tt.AssertPrints("3", suppress=False):
544 544 ip.run_cell("abc.outputs[0]")
545 545
546 546 # Test %%capture with ';' at end of expression
547 547 ip.run_cell("%%capture abc\n7+8;")
548 548 with tt.AssertPrints("False", suppress=False):
549 549 ip.run_cell("'abc' in locals()")
550 550
551 551
552 552 def test_doctest_mode():
553 553 "Toggle doctest_mode twice, it should be a no-op and run without error"
554 554 _ip.run_line_magic("doctest_mode", "")
555 555 _ip.run_line_magic("doctest_mode", "")
556 556
557 557
558 558 def test_parse_options():
559 559 """Tests for basic options parsing in magics."""
560 560 # These are only the most minimal of tests, more should be added later. At
561 561 # the very least we check that basic text/unicode calls work OK.
562 562 m = DummyMagics(_ip)
563 563 assert m.parse_options("foo", "")[1] == "foo"
564 564 assert m.parse_options("foo", "")[1] == "foo"
565 565
566 566
567 567 def test_parse_options_preserve_non_option_string():
568 568 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
569 569 m = DummyMagics(_ip)
570 570 opts, stmt = m.parse_options(
571 571 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
572 572 )
573 573 assert opts == {"n": "1", "r": "13"}
574 574 assert stmt == "_ = 314 + foo"
575 575
576 576
577 577 def test_run_magic_preserve_code_block():
578 578 """Test to assert preservation of non-option part of magic-block, while running magic."""
579 579 _ip.user_ns["spaces"] = []
580 580 _ip.run_line_magic(
581 581 "timeit", "-n1 -r1 spaces.append([s.count(' ') for s in ['document']])"
582 582 )
583 583 assert _ip.user_ns["spaces"] == [[0]]
584 584
585 585
586 586 def test_dirops():
587 587 """Test various directory handling operations."""
588 588 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
589 589 curpath = os.getcwd
590 590 startdir = os.getcwd()
591 591 ipdir = os.path.realpath(_ip.ipython_dir)
592 592 try:
593 593 _ip.run_line_magic("cd", '"%s"' % ipdir)
594 594 assert curpath() == ipdir
595 595 _ip.run_line_magic("cd", "-")
596 596 assert curpath() == startdir
597 597 _ip.run_line_magic("pushd", '"%s"' % ipdir)
598 598 assert curpath() == ipdir
599 599 _ip.run_line_magic("popd", "")
600 600 assert curpath() == startdir
601 601 finally:
602 602 os.chdir(startdir)
603 603
604 604
605 605 def test_cd_force_quiet():
606 606 """Test OSMagics.cd_force_quiet option"""
607 607 _ip.config.OSMagics.cd_force_quiet = True
608 608 osmagics = osm.OSMagics(shell=_ip)
609 609
610 610 startdir = os.getcwd()
611 611 ipdir = os.path.realpath(_ip.ipython_dir)
612 612
613 613 try:
614 614 with tt.AssertNotPrints(ipdir):
615 615 osmagics.cd('"%s"' % ipdir)
616 616 with tt.AssertNotPrints(startdir):
617 617 osmagics.cd('-')
618 618 finally:
619 619 os.chdir(startdir)
620 620
621 621
622 622 def test_xmode():
623 623 # Calling xmode three times should be a no-op
624 624 xmode = _ip.InteractiveTB.mode
625 625 for i in range(4):
626 626 _ip.run_line_magic("xmode", "")
627 627 assert _ip.InteractiveTB.mode == xmode
628 628
629 629 def test_reset_hard():
630 630 monitor = []
631 631 class A(object):
632 632 def __del__(self):
633 633 monitor.append(1)
634 634 def __repr__(self):
635 635 return "<A instance>"
636 636
637 637 _ip.user_ns["a"] = A()
638 638 _ip.run_cell("a")
639 639
640 640 assert monitor == []
641 641 _ip.run_line_magic("reset", "-f")
642 642 assert monitor == [1]
643 643
644 644 class TestXdel(tt.TempFileMixin):
645 645 def test_xdel(self):
646 646 """Test that references from %run are cleared by xdel."""
647 647 src = ("class A(object):\n"
648 648 " monitor = []\n"
649 649 " def __del__(self):\n"
650 650 " self.monitor.append(1)\n"
651 651 "a = A()\n")
652 652 self.mktmp(src)
653 653 # %run creates some hidden references...
654 654 _ip.run_line_magic("run", "%s" % self.fname)
655 655 # ... as does the displayhook.
656 656 _ip.run_cell("a")
657 657
658 658 monitor = _ip.user_ns["A"].monitor
659 659 assert monitor == []
660 660
661 661 _ip.run_line_magic("xdel", "a")
662 662
663 663 # Check that a's __del__ method has been called.
664 664 gc.collect(0)
665 665 assert monitor == [1]
666 666
667 667 def doctest_who():
668 668 """doctest for %who
669 669
670 670 In [1]: %reset -sf
671 671
672 672 In [2]: alpha = 123
673 673
674 674 In [3]: beta = 'beta'
675 675
676 676 In [4]: %who int
677 677 alpha
678 678
679 679 In [5]: %who str
680 680 beta
681 681
682 682 In [6]: %whos
683 683 Variable Type Data/Info
684 684 ----------------------------
685 685 alpha int 123
686 686 beta str beta
687 687
688 688 In [7]: %who_ls
689 689 Out[7]: ['alpha', 'beta']
690 690 """
691 691
692 692 def test_whos():
693 693 """Check that whos is protected against objects where repr() fails."""
694 694 class A(object):
695 695 def __repr__(self):
696 696 raise Exception()
697 697 _ip.user_ns['a'] = A()
698 698 _ip.run_line_magic("whos", "")
699 699
700 700 def doctest_precision():
701 701 """doctest for %precision
702 702
703 703 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
704 704
705 705 In [2]: %precision 5
706 706 Out[2]: '%.5f'
707 707
708 708 In [3]: f.float_format
709 709 Out[3]: '%.5f'
710 710
711 711 In [4]: %precision %e
712 712 Out[4]: '%e'
713 713
714 714 In [5]: f(3.1415927)
715 715 Out[5]: '3.141593e+00'
716 716 """
717 717
718
718 719 def test_debug_magic():
719 720 """Test debugging a small code with %debug
720 721
721 722 In [1]: with PdbTestInput(['c']):
722 723 ...: %debug print("a b") #doctest: +ELLIPSIS
723 724 ...:
724 725 ...
725 726 ipdb> c
726 727 a b
727 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 747 def test_psearch():
731 748 with tt.AssertPrints("dict.fromkeys"):
732 749 _ip.run_cell("dict.fr*?")
733 750 with tt.AssertPrints("π.is_integer"):
734 751 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
735 752
736 753 def test_timeit_shlex():
737 754 """test shlex issues with timeit (#1109)"""
738 755 _ip.ex("def f(*a,**kw): pass")
739 756 _ip.run_line_magic("timeit", '-n1 "this is a bug".count(" ")')
740 757 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1)')
741 758 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1, " ", 2, " ")')
742 759 _ip.run_line_magic("timeit", '-r1 -n1 ("a " + "b")')
743 760 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b")')
744 761 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b ")')
745 762
746 763
747 764 def test_timeit_special_syntax():
748 765 "Test %%timeit with IPython special syntax"
749 766 @register_line_magic
750 767 def lmagic(line):
751 768 ip = get_ipython()
752 769 ip.user_ns['lmagic_out'] = line
753 770
754 771 # line mode test
755 772 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
756 773 assert _ip.user_ns["lmagic_out"] == "my line"
757 774 # cell mode test
758 775 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
759 776 assert _ip.user_ns["lmagic_out"] == "my line2"
760 777
761 778
762 779 def test_timeit_return():
763 780 """
764 781 test whether timeit -o return object
765 782 """
766 783
767 784 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
768 785 assert(res is not None)
769 786
770 787 def test_timeit_quiet():
771 788 """
772 789 test quiet option of timeit magic
773 790 """
774 791 with tt.AssertNotPrints("loops"):
775 792 _ip.run_cell("%timeit -n1 -r1 -q 1")
776 793
777 794 def test_timeit_return_quiet():
778 795 with tt.AssertNotPrints("loops"):
779 796 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
780 797 assert (res is not None)
781 798
782 799 def test_timeit_invalid_return():
783 800 with pytest.raises(SyntaxError):
784 801 _ip.run_line_magic('timeit', 'return')
785 802
786 803 @dec.skipif(execution.profile is None)
787 804 def test_prun_special_syntax():
788 805 "Test %%prun with IPython special syntax"
789 806 @register_line_magic
790 807 def lmagic(line):
791 808 ip = get_ipython()
792 809 ip.user_ns['lmagic_out'] = line
793 810
794 811 # line mode test
795 812 _ip.run_line_magic("prun", "-q %lmagic my line")
796 813 assert _ip.user_ns["lmagic_out"] == "my line"
797 814 # cell mode test
798 815 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
799 816 assert _ip.user_ns["lmagic_out"] == "my line2"
800 817
801 818
802 819 @dec.skipif(execution.profile is None)
803 820 def test_prun_quotes():
804 821 "Test that prun does not clobber string escapes (GH #1302)"
805 822 _ip.magic(r"prun -q x = '\t'")
806 823 assert _ip.user_ns["x"] == "\t"
807 824
808 825
809 826 def test_extension():
810 827 # Debugging information for failures of this test
811 828 print('sys.path:')
812 829 for p in sys.path:
813 830 print(' ', p)
814 831 print('CWD', os.getcwd())
815 832
816 833 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
817 834 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
818 835 sys.path.insert(0, daft_path)
819 836 try:
820 837 _ip.user_ns.pop('arq', None)
821 838 invalidate_caches() # Clear import caches
822 839 _ip.run_line_magic("load_ext", "daft_extension")
823 840 assert _ip.user_ns["arq"] == 185
824 841 _ip.run_line_magic("unload_ext", "daft_extension")
825 842 assert 'arq' not in _ip.user_ns
826 843 finally:
827 844 sys.path.remove(daft_path)
828 845
829 846
830 847 def test_notebook_export_json():
831 848 pytest.importorskip("nbformat")
832 849 _ip = get_ipython()
833 850 _ip.history_manager.reset() # Clear any existing history.
834 851 cmds = ["a=1", "def b():\n return a**2", "print('noël, été', b())"]
835 852 for i, cmd in enumerate(cmds, start=1):
836 853 _ip.history_manager.store_inputs(i, cmd)
837 854 with TemporaryDirectory() as td:
838 855 outfile = os.path.join(td, "nb.ipynb")
839 856 _ip.run_line_magic("notebook", "%s" % outfile)
840 857
841 858
842 859 class TestEnv(TestCase):
843 860
844 861 def test_env(self):
845 862 env = _ip.run_line_magic("env", "")
846 863 self.assertTrue(isinstance(env, dict))
847 864
848 865 def test_env_secret(self):
849 866 env = _ip.run_line_magic("env", "")
850 867 hidden = "<hidden>"
851 868 with mock.patch.dict(
852 869 os.environ,
853 870 {
854 871 "API_KEY": "abc123",
855 872 "SECRET_THING": "ssshhh",
856 873 "JUPYTER_TOKEN": "",
857 874 "VAR": "abc"
858 875 }
859 876 ):
860 877 env = _ip.run_line_magic("env", "")
861 878 assert env["API_KEY"] == hidden
862 879 assert env["SECRET_THING"] == hidden
863 880 assert env["JUPYTER_TOKEN"] == hidden
864 881 assert env["VAR"] == "abc"
865 882
866 883 def test_env_get_set_simple(self):
867 884 env = _ip.run_line_magic("env", "var val1")
868 885 self.assertEqual(env, None)
869 886 self.assertEqual(os.environ["var"], "val1")
870 887 self.assertEqual(_ip.run_line_magic("env", "var"), "val1")
871 888 env = _ip.run_line_magic("env", "var=val2")
872 889 self.assertEqual(env, None)
873 890 self.assertEqual(os.environ['var'], 'val2')
874 891
875 892 def test_env_get_set_complex(self):
876 893 env = _ip.run_line_magic("env", "var 'val1 '' 'val2")
877 894 self.assertEqual(env, None)
878 895 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
879 896 self.assertEqual(_ip.run_line_magic("env", "var"), "'val1 '' 'val2")
880 897 env = _ip.run_line_magic("env", 'var=val2 val3="val4')
881 898 self.assertEqual(env, None)
882 899 self.assertEqual(os.environ['var'], 'val2 val3="val4')
883 900
884 901 def test_env_set_bad_input(self):
885 902 self.assertRaises(UsageError, lambda: _ip.run_line_magic("set_env", "var"))
886 903
887 904 def test_env_set_whitespace(self):
888 905 self.assertRaises(UsageError, lambda: _ip.run_line_magic("env", "var A=B"))
889 906
890 907
891 908 class CellMagicTestCase(TestCase):
892 909
893 910 def check_ident(self, magic):
894 911 # Manually called, we get the result
895 912 out = _ip.run_cell_magic(magic, "a", "b")
896 913 assert out == ("a", "b")
897 914 # Via run_cell, it goes into the user's namespace via displayhook
898 915 _ip.run_cell("%%" + magic + " c\nd\n")
899 916 assert _ip.user_ns["_"] == ("c", "d\n")
900 917
901 918 def test_cell_magic_func_deco(self):
902 919 "Cell magic using simple decorator"
903 920 @register_cell_magic
904 921 def cellm(line, cell):
905 922 return line, cell
906 923
907 924 self.check_ident('cellm')
908 925
909 926 def test_cell_magic_reg(self):
910 927 "Cell magic manually registered"
911 928 def cellm(line, cell):
912 929 return line, cell
913 930
914 931 _ip.register_magic_function(cellm, 'cell', 'cellm2')
915 932 self.check_ident('cellm2')
916 933
917 934 def test_cell_magic_class(self):
918 935 "Cell magics declared via a class"
919 936 @magics_class
920 937 class MyMagics(Magics):
921 938
922 939 @cell_magic
923 940 def cellm3(self, line, cell):
924 941 return line, cell
925 942
926 943 _ip.register_magics(MyMagics)
927 944 self.check_ident('cellm3')
928 945
929 946 def test_cell_magic_class2(self):
930 947 "Cell magics declared via a class, #2"
931 948 @magics_class
932 949 class MyMagics2(Magics):
933 950
934 951 @cell_magic('cellm4')
935 952 def cellm33(self, line, cell):
936 953 return line, cell
937 954
938 955 _ip.register_magics(MyMagics2)
939 956 self.check_ident('cellm4')
940 957 # Check that nothing is registered as 'cellm33'
941 958 c33 = _ip.find_cell_magic('cellm33')
942 959 assert c33 == None
943 960
944 961 def test_file():
945 962 """Basic %%writefile"""
946 963 ip = get_ipython()
947 964 with TemporaryDirectory() as td:
948 965 fname = os.path.join(td, "file1")
949 966 ip.run_cell_magic(
950 967 "writefile",
951 968 fname,
952 969 "\n".join(
953 970 [
954 971 "line1",
955 972 "line2",
956 973 ]
957 974 ),
958 975 )
959 976 s = Path(fname).read_text(encoding="utf-8")
960 977 assert "line1\n" in s
961 978 assert "line2" in s
962 979
963 980
964 981 @dec.skip_win32
965 982 def test_file_single_quote():
966 983 """Basic %%writefile with embedded single quotes"""
967 984 ip = get_ipython()
968 985 with TemporaryDirectory() as td:
969 986 fname = os.path.join(td, "'file1'")
970 987 ip.run_cell_magic(
971 988 "writefile",
972 989 fname,
973 990 "\n".join(
974 991 [
975 992 "line1",
976 993 "line2",
977 994 ]
978 995 ),
979 996 )
980 997 s = Path(fname).read_text(encoding="utf-8")
981 998 assert "line1\n" in s
982 999 assert "line2" in s
983 1000
984 1001
985 1002 @dec.skip_win32
986 1003 def test_file_double_quote():
987 1004 """Basic %%writefile with embedded double quotes"""
988 1005 ip = get_ipython()
989 1006 with TemporaryDirectory() as td:
990 1007 fname = os.path.join(td, '"file1"')
991 1008 ip.run_cell_magic(
992 1009 "writefile",
993 1010 fname,
994 1011 "\n".join(
995 1012 [
996 1013 "line1",
997 1014 "line2",
998 1015 ]
999 1016 ),
1000 1017 )
1001 1018 s = Path(fname).read_text(encoding="utf-8")
1002 1019 assert "line1\n" in s
1003 1020 assert "line2" in s
1004 1021
1005 1022
1006 1023 def test_file_var_expand():
1007 1024 """%%writefile $filename"""
1008 1025 ip = get_ipython()
1009 1026 with TemporaryDirectory() as td:
1010 1027 fname = os.path.join(td, "file1")
1011 1028 ip.user_ns["filename"] = fname
1012 1029 ip.run_cell_magic(
1013 1030 "writefile",
1014 1031 "$filename",
1015 1032 "\n".join(
1016 1033 [
1017 1034 "line1",
1018 1035 "line2",
1019 1036 ]
1020 1037 ),
1021 1038 )
1022 1039 s = Path(fname).read_text(encoding="utf-8")
1023 1040 assert "line1\n" in s
1024 1041 assert "line2" in s
1025 1042
1026 1043
1027 1044 def test_file_unicode():
1028 1045 """%%writefile with unicode cell"""
1029 1046 ip = get_ipython()
1030 1047 with TemporaryDirectory() as td:
1031 1048 fname = os.path.join(td, 'file1')
1032 1049 ip.run_cell_magic("writefile", fname, u'\n'.join([
1033 1050 u'liné1',
1034 1051 u'liné2',
1035 1052 ]))
1036 1053 with io.open(fname, encoding='utf-8') as f:
1037 1054 s = f.read()
1038 1055 assert "liné1\n" in s
1039 1056 assert "liné2" in s
1040 1057
1041 1058
1042 1059 def test_file_amend():
1043 1060 """%%writefile -a amends files"""
1044 1061 ip = get_ipython()
1045 1062 with TemporaryDirectory() as td:
1046 1063 fname = os.path.join(td, "file2")
1047 1064 ip.run_cell_magic(
1048 1065 "writefile",
1049 1066 fname,
1050 1067 "\n".join(
1051 1068 [
1052 1069 "line1",
1053 1070 "line2",
1054 1071 ]
1055 1072 ),
1056 1073 )
1057 1074 ip.run_cell_magic(
1058 1075 "writefile",
1059 1076 "-a %s" % fname,
1060 1077 "\n".join(
1061 1078 [
1062 1079 "line3",
1063 1080 "line4",
1064 1081 ]
1065 1082 ),
1066 1083 )
1067 1084 s = Path(fname).read_text(encoding="utf-8")
1068 1085 assert "line1\n" in s
1069 1086 assert "line3\n" in s
1070 1087
1071 1088
1072 1089 def test_file_spaces():
1073 1090 """%%file with spaces in filename"""
1074 1091 ip = get_ipython()
1075 1092 with TemporaryWorkingDirectory() as td:
1076 1093 fname = "file name"
1077 1094 ip.run_cell_magic(
1078 1095 "file",
1079 1096 '"%s"' % fname,
1080 1097 "\n".join(
1081 1098 [
1082 1099 "line1",
1083 1100 "line2",
1084 1101 ]
1085 1102 ),
1086 1103 )
1087 1104 s = Path(fname).read_text(encoding="utf-8")
1088 1105 assert "line1\n" in s
1089 1106 assert "line2" in s
1090 1107
1091 1108
1092 1109 def test_script_config():
1093 1110 ip = get_ipython()
1094 1111 ip.config.ScriptMagics.script_magics = ['whoda']
1095 1112 sm = script.ScriptMagics(shell=ip)
1096 1113 assert "whoda" in sm.magics["cell"]
1097 1114
1098 1115
1099 1116 def test_script_out():
1100 1117 ip = get_ipython()
1101 1118 ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
1102 1119 assert ip.user_ns["output"].strip() == "hi"
1103 1120
1104 1121
1105 1122 def test_script_err():
1106 1123 ip = get_ipython()
1107 1124 ip.run_cell_magic(
1108 1125 "script",
1109 1126 f"--err error {sys.executable}",
1110 1127 "import sys; print('hello', file=sys.stderr)",
1111 1128 )
1112 1129 assert ip.user_ns["error"].strip() == "hello"
1113 1130
1114 1131
1115 1132 def test_script_out_err():
1116 1133 ip = get_ipython()
1117 1134 ip.run_cell_magic(
1118 1135 "script",
1119 1136 f"--out output --err error {sys.executable}",
1120 1137 "\n".join(
1121 1138 [
1122 1139 "import sys",
1123 1140 "print('hi')",
1124 1141 "print('hello', file=sys.stderr)",
1125 1142 ]
1126 1143 ),
1127 1144 )
1128 1145 assert ip.user_ns["output"].strip() == "hi"
1129 1146 assert ip.user_ns["error"].strip() == "hello"
1130 1147
1131 1148
1132 1149 async def test_script_bg_out():
1133 1150 ip = get_ipython()
1134 1151 ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1135 1152 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1136 1153 assert ip.user_ns["output"].at_eof()
1137 1154
1138 1155
1139 1156 async def test_script_bg_err():
1140 1157 ip = get_ipython()
1141 1158 ip.run_cell_magic(
1142 1159 "script",
1143 1160 f"--bg --err error {sys.executable}",
1144 1161 "import sys; print('hello', file=sys.stderr)",
1145 1162 )
1146 1163 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1147 1164 assert ip.user_ns["error"].at_eof()
1148 1165
1149 1166
1150 1167 async def test_script_bg_out_err():
1151 1168 ip = get_ipython()
1152 1169 ip.run_cell_magic(
1153 1170 "script",
1154 1171 f"--bg --out output --err error {sys.executable}",
1155 1172 "\n".join(
1156 1173 [
1157 1174 "import sys",
1158 1175 "print('hi')",
1159 1176 "print('hello', file=sys.stderr)",
1160 1177 ]
1161 1178 ),
1162 1179 )
1163 1180 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1164 1181 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1165 1182 assert ip.user_ns["output"].at_eof()
1166 1183 assert ip.user_ns["error"].at_eof()
1167 1184
1168 1185
1169 1186 async def test_script_bg_proc():
1170 1187 ip = get_ipython()
1171 1188 ip.run_cell_magic(
1172 1189 "script",
1173 1190 f"--bg --out output --proc p {sys.executable}",
1174 1191 "\n".join(
1175 1192 [
1176 1193 "import sys",
1177 1194 "print('hi')",
1178 1195 "print('hello', file=sys.stderr)",
1179 1196 ]
1180 1197 ),
1181 1198 )
1182 1199 p = ip.user_ns["p"]
1183 1200 await p.wait()
1184 1201 assert p.returncode == 0
1185 1202 assert (await p.stdout.read()).strip() == b"hi"
1186 1203 # not captured, so empty
1187 1204 assert (await p.stderr.read()) == b""
1188 1205 assert p.stdout.at_eof()
1189 1206 assert p.stderr.at_eof()
1190 1207
1191 1208
1192 1209 def test_script_defaults():
1193 1210 ip = get_ipython()
1194 1211 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1195 1212 try:
1196 1213 find_cmd(cmd)
1197 1214 except Exception:
1198 1215 pass
1199 1216 else:
1200 1217 assert cmd in ip.magics_manager.magics["cell"]
1201 1218
1202 1219
1203 1220 @magics_class
1204 1221 class FooFoo(Magics):
1205 1222 """class with both %foo and %%foo magics"""
1206 1223 @line_magic('foo')
1207 1224 def line_foo(self, line):
1208 1225 "I am line foo"
1209 1226 pass
1210 1227
1211 1228 @cell_magic("foo")
1212 1229 def cell_foo(self, line, cell):
1213 1230 "I am cell foo, not line foo"
1214 1231 pass
1215 1232
1216 1233 def test_line_cell_info():
1217 1234 """%%foo and %foo magics are distinguishable to inspect"""
1218 1235 ip = get_ipython()
1219 1236 ip.magics_manager.register(FooFoo)
1220 1237 oinfo = ip.object_inspect("foo")
1221 1238 assert oinfo["found"] is True
1222 1239 assert oinfo["ismagic"] is True
1223 1240
1224 1241 oinfo = ip.object_inspect("%%foo")
1225 1242 assert oinfo["found"] is True
1226 1243 assert oinfo["ismagic"] is True
1227 1244 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1228 1245
1229 1246 oinfo = ip.object_inspect("%foo")
1230 1247 assert oinfo["found"] is True
1231 1248 assert oinfo["ismagic"] is True
1232 1249 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1233 1250
1234 1251
1235 1252 def test_multiple_magics():
1236 1253 ip = get_ipython()
1237 1254 foo1 = FooFoo(ip)
1238 1255 foo2 = FooFoo(ip)
1239 1256 mm = ip.magics_manager
1240 1257 mm.register(foo1)
1241 1258 assert mm.magics["line"]["foo"].__self__ is foo1
1242 1259 mm.register(foo2)
1243 1260 assert mm.magics["line"]["foo"].__self__ is foo2
1244 1261
1245 1262
1246 1263 def test_alias_magic():
1247 1264 """Test %alias_magic."""
1248 1265 ip = get_ipython()
1249 1266 mm = ip.magics_manager
1250 1267
1251 1268 # Basic operation: both cell and line magics are created, if possible.
1252 1269 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1253 1270 assert "timeit_alias" in mm.magics["line"]
1254 1271 assert "timeit_alias" in mm.magics["cell"]
1255 1272
1256 1273 # --cell is specified, line magic not created.
1257 1274 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1258 1275 assert "timeit_cell_alias" not in mm.magics["line"]
1259 1276 assert "timeit_cell_alias" in mm.magics["cell"]
1260 1277
1261 1278 # Test that line alias is created successfully.
1262 1279 ip.run_line_magic("alias_magic", "--line env_alias env")
1263 1280 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1264 1281
1265 1282 # Test that line alias with parameters passed in is created successfully.
1266 1283 ip.run_line_magic(
1267 1284 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1268 1285 )
1269 1286 assert "history_alias" in mm.magics["line"]
1270 1287
1271 1288
1272 1289 def test_save():
1273 1290 """Test %save."""
1274 1291 ip = get_ipython()
1275 1292 ip.history_manager.reset() # Clear any existing history.
1276 1293 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1277 1294 for i, cmd in enumerate(cmds, start=1):
1278 1295 ip.history_manager.store_inputs(i, cmd)
1279 1296 with TemporaryDirectory() as tmpdir:
1280 1297 file = os.path.join(tmpdir, "testsave.py")
1281 1298 ip.run_line_magic("save", "%s 1-10" % file)
1282 1299 content = Path(file).read_text(encoding="utf-8")
1283 1300 assert content.count(cmds[0]) == 1
1284 1301 assert "coding: utf-8" in content
1285 1302 ip.run_line_magic("save", "-a %s 1-10" % file)
1286 1303 content = Path(file).read_text(encoding="utf-8")
1287 1304 assert content.count(cmds[0]) == 2
1288 1305 assert "coding: utf-8" in content
1289 1306
1290 1307
1291 1308 def test_save_with_no_args():
1292 1309 ip = get_ipython()
1293 1310 ip.history_manager.reset() # Clear any existing history.
1294 1311 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1295 1312 for i, cmd in enumerate(cmds, start=1):
1296 1313 ip.history_manager.store_inputs(i, cmd)
1297 1314
1298 1315 with TemporaryDirectory() as tmpdir:
1299 1316 path = os.path.join(tmpdir, "testsave.py")
1300 1317 ip.run_line_magic("save", path)
1301 1318 content = Path(path).read_text(encoding="utf-8")
1302 1319 expected_content = dedent(
1303 1320 """\
1304 1321 # coding: utf-8
1305 1322 a=1
1306 1323 def b():
1307 1324 return a**2
1308 1325 print(a, b())
1309 1326 """
1310 1327 )
1311 1328 assert content == expected_content
1312 1329
1313 1330
1314 1331 def test_store():
1315 1332 """Test %store."""
1316 1333 ip = get_ipython()
1317 1334 ip.run_line_magic('load_ext', 'storemagic')
1318 1335
1319 1336 # make sure the storage is empty
1320 1337 ip.run_line_magic("store", "-z")
1321 1338 ip.user_ns["var"] = 42
1322 1339 ip.run_line_magic("store", "var")
1323 1340 ip.user_ns["var"] = 39
1324 1341 ip.run_line_magic("store", "-r")
1325 1342 assert ip.user_ns["var"] == 42
1326 1343
1327 1344 ip.run_line_magic("store", "-d var")
1328 1345 ip.user_ns["var"] = 39
1329 1346 ip.run_line_magic("store", "-r")
1330 1347 assert ip.user_ns["var"] == 39
1331 1348
1332 1349
1333 1350 def _run_edit_test(arg_s, exp_filename=None,
1334 1351 exp_lineno=-1,
1335 1352 exp_contents=None,
1336 1353 exp_is_temp=None):
1337 1354 ip = get_ipython()
1338 1355 M = code.CodeMagics(ip)
1339 1356 last_call = ['','']
1340 1357 opts,args = M.parse_options(arg_s,'prxn:')
1341 1358 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1342 1359
1343 1360 if exp_filename is not None:
1344 1361 assert exp_filename == filename
1345 1362 if exp_contents is not None:
1346 1363 with io.open(filename, 'r', encoding='utf-8') as f:
1347 1364 contents = f.read()
1348 1365 assert exp_contents == contents
1349 1366 if exp_lineno != -1:
1350 1367 assert exp_lineno == lineno
1351 1368 if exp_is_temp is not None:
1352 1369 assert exp_is_temp == is_temp
1353 1370
1354 1371
1355 1372 def test_edit_interactive():
1356 1373 """%edit on interactively defined objects"""
1357 1374 ip = get_ipython()
1358 1375 n = ip.execution_count
1359 1376 ip.run_cell("def foo(): return 1", store_history=True)
1360 1377
1361 1378 with pytest.raises(code.InteractivelyDefined) as e:
1362 1379 _run_edit_test("foo")
1363 1380 assert e.value.index == n
1364 1381
1365 1382
1366 1383 def test_edit_cell():
1367 1384 """%edit [cell id]"""
1368 1385 ip = get_ipython()
1369 1386
1370 1387 ip.run_cell("def foo(): return 1", store_history=True)
1371 1388
1372 1389 # test
1373 1390 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1374 1391
1375 1392 def test_edit_fname():
1376 1393 """%edit file"""
1377 1394 # test
1378 1395 _run_edit_test("test file.py", exp_filename="test file.py")
1379 1396
1380 1397 def test_bookmark():
1381 1398 ip = get_ipython()
1382 1399 ip.run_line_magic('bookmark', 'bmname')
1383 1400 with tt.AssertPrints('bmname'):
1384 1401 ip.run_line_magic('bookmark', '-l')
1385 1402 ip.run_line_magic('bookmark', '-d bmname')
1386 1403
1387 1404 def test_ls_magic():
1388 1405 ip = get_ipython()
1389 1406 json_formatter = ip.display_formatter.formatters['application/json']
1390 1407 json_formatter.enabled = True
1391 1408 lsmagic = ip.run_line_magic("lsmagic", "")
1392 1409 with warnings.catch_warnings(record=True) as w:
1393 1410 j = json_formatter(lsmagic)
1394 1411 assert sorted(j) == ["cell", "line"]
1395 1412 assert w == [] # no warnings
1396 1413
1397 1414
1398 1415 def test_strip_initial_indent():
1399 1416 def sii(s):
1400 1417 lines = s.splitlines()
1401 1418 return '\n'.join(code.strip_initial_indent(lines))
1402 1419
1403 1420 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1404 1421 assert sii(" a\n b\nc") == "a\n b\nc"
1405 1422 assert sii("a\n b") == "a\n b"
1406 1423
1407 1424 def test_logging_magic_quiet_from_arg():
1408 1425 _ip.config.LoggingMagics.quiet = False
1409 1426 lm = logging.LoggingMagics(shell=_ip)
1410 1427 with TemporaryDirectory() as td:
1411 1428 try:
1412 1429 with tt.AssertNotPrints(re.compile("Activating.*")):
1413 1430 lm.logstart('-q {}'.format(
1414 1431 os.path.join(td, "quiet_from_arg.log")))
1415 1432 finally:
1416 1433 _ip.logger.logstop()
1417 1434
1418 1435 def test_logging_magic_quiet_from_config():
1419 1436 _ip.config.LoggingMagics.quiet = True
1420 1437 lm = logging.LoggingMagics(shell=_ip)
1421 1438 with TemporaryDirectory() as td:
1422 1439 try:
1423 1440 with tt.AssertNotPrints(re.compile("Activating.*")):
1424 1441 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1425 1442 finally:
1426 1443 _ip.logger.logstop()
1427 1444
1428 1445
1429 1446 def test_logging_magic_not_quiet():
1430 1447 _ip.config.LoggingMagics.quiet = False
1431 1448 lm = logging.LoggingMagics(shell=_ip)
1432 1449 with TemporaryDirectory() as td:
1433 1450 try:
1434 1451 with tt.AssertPrints(re.compile("Activating.*")):
1435 1452 lm.logstart(os.path.join(td, "not_quiet.log"))
1436 1453 finally:
1437 1454 _ip.logger.logstop()
1438 1455
1439 1456
1440 1457 def test_time_no_var_expand():
1441 1458 _ip.user_ns["a"] = 5
1442 1459 _ip.user_ns["b"] = []
1443 1460 _ip.run_line_magic("time", 'b.append("{a}")')
1444 1461 assert _ip.user_ns["b"] == ["{a}"]
1445 1462
1446 1463
1447 1464 # this is slow, put at the end for local testing.
1448 1465 def test_timeit_arguments():
1449 1466 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1450 1467 _ip.run_line_magic("timeit", "-n1 -r1 a=('#')")
1451 1468
1452 1469
1453 1470 MINIMAL_LAZY_MAGIC = """
1454 1471 from IPython.core.magic import (
1455 1472 Magics,
1456 1473 magics_class,
1457 1474 line_magic,
1458 1475 cell_magic,
1459 1476 )
1460 1477
1461 1478
1462 1479 @magics_class
1463 1480 class LazyMagics(Magics):
1464 1481 @line_magic
1465 1482 def lazy_line(self, line):
1466 1483 print("Lazy Line")
1467 1484
1468 1485 @cell_magic
1469 1486 def lazy_cell(self, line, cell):
1470 1487 print("Lazy Cell")
1471 1488
1472 1489
1473 1490 def load_ipython_extension(ipython):
1474 1491 ipython.register_magics(LazyMagics)
1475 1492 """
1476 1493
1477 1494
1478 1495 def test_lazy_magics():
1479 1496 with pytest.raises(UsageError):
1480 1497 ip.run_line_magic("lazy_line", "")
1481 1498
1482 1499 startdir = os.getcwd()
1483 1500
1484 1501 with TemporaryDirectory() as tmpdir:
1485 1502 with prepended_to_syspath(tmpdir):
1486 1503 ptempdir = Path(tmpdir)
1487 1504 tf = ptempdir / "lazy_magic_module.py"
1488 1505 tf.write_text(MINIMAL_LAZY_MAGIC)
1489 1506 ip.magics_manager.register_lazy("lazy_line", Path(tf.name).name[:-3])
1490 1507 with tt.AssertPrints("Lazy Line"):
1491 1508 ip.run_line_magic("lazy_line", "")
1492 1509
1493 1510
1494 1511 TEST_MODULE = """
1495 1512 print('Loaded my_tmp')
1496 1513 if __name__ == "__main__":
1497 1514 print('I just ran a script')
1498 1515 """
1499 1516
1500 1517 def test_run_module_from_import_hook():
1501 1518 "Test that a module can be loaded via an import hook"
1502 1519 with TemporaryDirectory() as tmpdir:
1503 1520 fullpath = os.path.join(tmpdir, "my_tmp.py")
1504 1521 Path(fullpath).write_text(TEST_MODULE, encoding="utf-8")
1505 1522
1506 1523 import importlib.abc
1507 1524 import importlib.util
1508 1525
1509 1526 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1510 1527 def find_spec(self, fullname, path, target=None):
1511 1528 if fullname == "my_tmp":
1512 1529 return importlib.util.spec_from_loader(fullname, self)
1513 1530
1514 1531 def get_filename(self, fullname):
1515 1532 assert fullname == "my_tmp"
1516 1533 return fullpath
1517 1534
1518 1535 def get_data(self, path):
1519 1536 assert Path(path).samefile(fullpath)
1520 1537 return Path(fullpath).read_text(encoding="utf-8")
1521 1538
1522 1539 sys.meta_path.insert(0, MyTempImporter())
1523 1540
1524 1541 with capture_output() as captured:
1525 1542 _ip.run_line_magic("run", "-m my_tmp")
1526 1543 _ip.run_cell("import my_tmp")
1527 1544
1528 1545 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1529 1546 assert output == captured.stdout
1530 1547
1531 1548 sys.meta_path.pop(0)
@@ -1,1381 +1,1381 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Verbose and colourful traceback formatting.
4 4
5 5 **ColorTB**
6 6
7 7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 8 ColorTB class is a solution to that problem. It colors the different parts of a
9 9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 10 text editor.
11 11
12 12 Installation instructions for ColorTB::
13 13
14 14 import sys,ultratb
15 15 sys.excepthook = ultratb.ColorTB()
16 16
17 17 **VerboseTB**
18 18
19 19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 21 and intended it for CGI programmers, but why should they have all the fun? I
22 22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 23 but kind of neat, and maybe useful for long-running programs that you believe
24 24 are bug-free. If a crash *does* occur in that type of program you want details.
25 25 Give it a shot--you'll love it or you'll hate it.
26 26
27 27 .. note::
28 28
29 29 The Verbose mode prints the variables currently visible where the exception
30 30 happened (shortening their strings if too long). This can potentially be
31 31 very slow, if you happen to have a huge data structure whose string
32 32 representation is complex to compute. Your computer may appear to freeze for
33 33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 34 with Ctrl-C (maybe hitting it more than once).
35 35
36 36 If you encounter this kind of situation often, you may want to use the
37 37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 38 variables (but otherwise includes the information and context given by
39 39 Verbose).
40 40
41 41 .. note::
42 42
43 43 The verbose mode print all variables in the stack, which means it can
44 44 potentially leak sensitive information like access keys, or unencrypted
45 45 password.
46 46
47 47 Installation instructions for VerboseTB::
48 48
49 49 import sys,ultratb
50 50 sys.excepthook = ultratb.VerboseTB()
51 51
52 52 Note: Much of the code in this module was lifted verbatim from the standard
53 53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54 54
55 55 Color schemes
56 56 -------------
57 57
58 58 The colors are defined in the class TBTools through the use of the
59 59 ColorSchemeTable class. Currently the following exist:
60 60
61 61 - NoColor: allows all of this module to be used in any terminal (the color
62 62 escapes are just dummy blank strings).
63 63
64 64 - Linux: is meant to look good in a terminal like the Linux console (black
65 65 or very dark background).
66 66
67 67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 68 in light background terminals.
69 69
70 70 - Neutral: a neutral color scheme that should be readable on both light and
71 71 dark background
72 72
73 73 You can implement other color schemes easily, the syntax is fairly
74 74 self-explanatory. Please send back new schemes you develop to the author for
75 75 possible inclusion in future releases.
76 76
77 77 Inheritance diagram:
78 78
79 79 .. inheritance-diagram:: IPython.core.ultratb
80 80 :parts: 3
81 81 """
82 82
83 83 #*****************************************************************************
84 84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
85 85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
86 86 #
87 87 # Distributed under the terms of the BSD License. The full license is in
88 88 # the file COPYING, distributed as part of this software.
89 89 #*****************************************************************************
90 90
91 91
92 92 import inspect
93 93 import linecache
94 94 import pydoc
95 95 import sys
96 96 import time
97 97 import traceback
98 98 from types import TracebackType
99 99 from typing import Tuple, List, Any, Optional
100 100
101 101 import stack_data
102 102 from stack_data import FrameInfo as SDFrameInfo
103 103 from pygments.formatters.terminal256 import Terminal256Formatter
104 104 from pygments.styles import get_style_by_name
105 105
106 106 # IPython's own modules
107 107 from IPython import get_ipython
108 108 from IPython.core import debugger
109 109 from IPython.core.display_trap import DisplayTrap
110 110 from IPython.core.excolors import exception_colors
111 111 from IPython.utils import PyColorize
112 112 from IPython.utils import path as util_path
113 113 from IPython.utils import py3compat
114 114 from IPython.utils.terminal import get_terminal_size
115 115
116 116 import IPython.utils.colorable as colorable
117 117
118 118 # Globals
119 119 # amount of space to put line numbers before verbose tracebacks
120 120 INDENT_SIZE = 8
121 121
122 122 # Default color scheme. This is used, for example, by the traceback
123 123 # formatter. When running in an actual IPython instance, the user's rc.colors
124 124 # value is used, but having a module global makes this functionality available
125 125 # to users of ultratb who are NOT running inside ipython.
126 126 DEFAULT_SCHEME = 'NoColor'
127 127 FAST_THRESHOLD = 10_000
128 128
129 129 # ---------------------------------------------------------------------------
130 130 # Code begins
131 131
132 132 # Helper function -- largely belongs to VerboseTB, but we need the same
133 133 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
134 134 # can be recognized properly by ipython.el's py-traceback-line-re
135 135 # (SyntaxErrors have to be treated specially because they have no traceback)
136 136
137 137
138 138 def _format_traceback_lines(lines, Colors, has_colors: bool, lvals):
139 139 """
140 140 Format tracebacks lines with pointing arrow, leading numbers...
141 141
142 142 Parameters
143 143 ----------
144 144 lines : list[Line]
145 145 Colors
146 146 ColorScheme used.
147 147 lvals : str
148 148 Values of local variables, already colored, to inject just after the error line.
149 149 """
150 150 numbers_width = INDENT_SIZE - 1
151 151 res = []
152 152
153 153 for stack_line in lines:
154 154 if stack_line is stack_data.LINE_GAP:
155 155 res.append('%s (...)%s\n' % (Colors.linenoEm, Colors.Normal))
156 156 continue
157 157
158 158 line = stack_line.render(pygmented=has_colors).rstrip('\n') + '\n'
159 159 lineno = stack_line.lineno
160 160 if stack_line.is_current:
161 161 # This is the line with the error
162 162 pad = numbers_width - len(str(lineno))
163 163 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
164 164 start_color = Colors.linenoEm
165 165 else:
166 166 num = '%*s' % (numbers_width, lineno)
167 167 start_color = Colors.lineno
168 168
169 169 line = '%s%s%s %s' % (start_color, num, Colors.Normal, line)
170 170
171 171 res.append(line)
172 172 if lvals and stack_line.is_current:
173 173 res.append(lvals + '\n')
174 174 return res
175 175
176 176 def _simple_format_traceback_lines(lnum, index, lines, Colors, lvals, _line_format):
177 177 """
178 178 Format tracebacks lines with pointing arrow, leading numbers...
179 179
180 180 Parameters
181 181 ==========
182 182
183 183 lnum: int
184 184 number of the target line of code.
185 185 index: int
186 186 which line in the list should be highlighted.
187 187 lines: list[string]
188 188 Colors:
189 189 ColorScheme used.
190 190 lvals: bytes
191 191 Values of local variables, already colored, to inject just after the error line.
192 192 _line_format: f (str) -> (str, bool)
193 193 return (colorized version of str, failure to do so)
194 194 """
195 195 numbers_width = INDENT_SIZE - 1
196 196 res = []
197 197
198 198 for i, line in enumerate(lines, lnum - index):
199 199 line = py3compat.cast_unicode(line)
200 200
201 201 new_line, err = _line_format(line, "str")
202 202 if not err:
203 203 line = new_line
204 204
205 205 if i == lnum:
206 206 # This is the line with the error
207 207 pad = numbers_width - len(str(i))
208 208 num = "%s%s" % (debugger.make_arrow(pad), str(lnum))
209 209 line = "%s%s%s %s%s" % (
210 210 Colors.linenoEm,
211 211 num,
212 212 Colors.line,
213 213 line,
214 214 Colors.Normal,
215 215 )
216 216 else:
217 217 num = "%*s" % (numbers_width, i)
218 218 line = "%s%s%s %s" % (Colors.lineno, num, Colors.Normal, line)
219 219
220 220 res.append(line)
221 221 if lvals and i == lnum:
222 222 res.append(lvals + "\n")
223 223 return res
224 224
225 225
226 226 def _format_filename(file, ColorFilename, ColorNormal, *, lineno=None):
227 227 """
228 228 Format filename lines with custom formatting from caching compiler or `File *.py` by default
229 229
230 230 Parameters
231 231 ----------
232 232 file : str
233 233 ColorFilename
234 234 ColorScheme's filename coloring to be used.
235 235 ColorNormal
236 236 ColorScheme's normal coloring to be used.
237 237 """
238 238 ipinst = get_ipython()
239 239 if (
240 240 ipinst is not None
241 241 and (data := ipinst.compile.format_code_name(file)) is not None
242 242 ):
243 243 label, name = data
244 244 if lineno is None:
245 245 tpl_link = f"{{label}} {ColorFilename}{{name}}{ColorNormal}"
246 246 else:
247 247 tpl_link = (
248 248 f"{{label}} {ColorFilename}{{name}}, line {{lineno}}{ColorNormal}"
249 249 )
250 250 else:
251 251 label = "File"
252 252 name = util_path.compress_user(
253 253 py3compat.cast_unicode(file, util_path.fs_encoding)
254 254 )
255 255 if lineno is None:
256 256 tpl_link = f"{{label}} {ColorFilename}{{name}}{ColorNormal}"
257 257 else:
258 258 # can we make this the more friendly ", line {{lineno}}", or do we need to preserve the formatting with the colon?
259 259 tpl_link = f"{{label}} {ColorFilename}{{name}}:{{lineno}}{ColorNormal}"
260 260
261 261 return tpl_link.format(label=label, name=name, lineno=lineno)
262 262
263 263 #---------------------------------------------------------------------------
264 264 # Module classes
265 265 class TBTools(colorable.Colorable):
266 266 """Basic tools used by all traceback printer classes."""
267 267
268 268 # Number of frames to skip when reporting tracebacks
269 269 tb_offset = 0
270 270
271 271 def __init__(
272 272 self,
273 273 color_scheme="NoColor",
274 274 call_pdb=False,
275 275 ostream=None,
276 276 parent=None,
277 277 config=None,
278 278 *,
279 279 debugger_cls=None,
280 280 ):
281 281 # Whether to call the interactive pdb debugger after printing
282 282 # tracebacks or not
283 283 super(TBTools, self).__init__(parent=parent, config=config)
284 284 self.call_pdb = call_pdb
285 285
286 286 # Output stream to write to. Note that we store the original value in
287 287 # a private attribute and then make the public ostream a property, so
288 288 # that we can delay accessing sys.stdout until runtime. The way
289 289 # things are written now, the sys.stdout object is dynamically managed
290 290 # so a reference to it should NEVER be stored statically. This
291 291 # property approach confines this detail to a single location, and all
292 292 # subclasses can simply access self.ostream for writing.
293 293 self._ostream = ostream
294 294
295 295 # Create color table
296 296 self.color_scheme_table = exception_colors()
297 297
298 298 self.set_colors(color_scheme)
299 299 self.old_scheme = color_scheme # save initial value for toggles
300 300 self.debugger_cls = debugger_cls or debugger.Pdb
301 301
302 302 if call_pdb:
303 303 self.pdb = self.debugger_cls()
304 304 else:
305 305 self.pdb = None
306 306
307 307 def _get_ostream(self):
308 308 """Output stream that exceptions are written to.
309 309
310 310 Valid values are:
311 311
312 312 - None: the default, which means that IPython will dynamically resolve
313 313 to sys.stdout. This ensures compatibility with most tools, including
314 314 Windows (where plain stdout doesn't recognize ANSI escapes).
315 315
316 316 - Any object with 'write' and 'flush' attributes.
317 317 """
318 318 return sys.stdout if self._ostream is None else self._ostream
319 319
320 320 def _set_ostream(self, val):
321 321 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
322 322 self._ostream = val
323 323
324 324 ostream = property(_get_ostream, _set_ostream)
325 325
326 326 @staticmethod
327 327 def _get_chained_exception(exception_value):
328 328 cause = getattr(exception_value, "__cause__", None)
329 329 if cause:
330 330 return cause
331 331 if getattr(exception_value, "__suppress_context__", False):
332 332 return None
333 333 return getattr(exception_value, "__context__", None)
334 334
335 335 def get_parts_of_chained_exception(
336 336 self, evalue
337 337 ) -> Optional[Tuple[type, BaseException, TracebackType]]:
338 338 chained_evalue = self._get_chained_exception(evalue)
339 339
340 340 if chained_evalue:
341 341 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
342 342 return None
343 343
344 344 def prepare_chained_exception_message(self, cause) -> List[Any]:
345 345 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
346 346 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
347 347
348 348 if cause:
349 349 message = [[direct_cause]]
350 350 else:
351 351 message = [[exception_during_handling]]
352 352 return message
353 353
354 354 @property
355 355 def has_colors(self) -> bool:
356 356 return self.color_scheme_table.active_scheme_name.lower() != "nocolor"
357 357
358 358 def set_colors(self, *args, **kw):
359 359 """Shorthand access to the color table scheme selector method."""
360 360
361 361 # Set own color table
362 362 self.color_scheme_table.set_active_scheme(*args, **kw)
363 363 # for convenience, set Colors to the active scheme
364 364 self.Colors = self.color_scheme_table.active_colors
365 365 # Also set colors of debugger
366 366 if hasattr(self, 'pdb') and self.pdb is not None:
367 367 self.pdb.set_colors(*args, **kw)
368 368
369 369 def color_toggle(self):
370 370 """Toggle between the currently active color scheme and NoColor."""
371 371
372 372 if self.color_scheme_table.active_scheme_name == 'NoColor':
373 373 self.color_scheme_table.set_active_scheme(self.old_scheme)
374 374 self.Colors = self.color_scheme_table.active_colors
375 375 else:
376 376 self.old_scheme = self.color_scheme_table.active_scheme_name
377 377 self.color_scheme_table.set_active_scheme('NoColor')
378 378 self.Colors = self.color_scheme_table.active_colors
379 379
380 380 def stb2text(self, stb):
381 381 """Convert a structured traceback (a list) to a string."""
382 382 return '\n'.join(stb)
383 383
384 384 def text(self, etype, value, tb, tb_offset: Optional[int] = None, context=5):
385 385 """Return formatted traceback.
386 386
387 387 Subclasses may override this if they add extra arguments.
388 388 """
389 389 tb_list = self.structured_traceback(etype, value, tb,
390 390 tb_offset, context)
391 391 return self.stb2text(tb_list)
392 392
393 393 def structured_traceback(
394 394 self, etype, evalue, tb, tb_offset: Optional[int] = None, context=5, mode=None
395 395 ):
396 396 """Return a list of traceback frames.
397 397
398 398 Must be implemented by each class.
399 399 """
400 400 raise NotImplementedError()
401 401
402 402
403 403 #---------------------------------------------------------------------------
404 404 class ListTB(TBTools):
405 405 """Print traceback information from a traceback list, with optional color.
406 406
407 407 Calling requires 3 arguments: (etype, evalue, elist)
408 408 as would be obtained by::
409 409
410 410 etype, evalue, tb = sys.exc_info()
411 411 if tb:
412 412 elist = traceback.extract_tb(tb)
413 413 else:
414 414 elist = None
415 415
416 416 It can thus be used by programs which need to process the traceback before
417 417 printing (such as console replacements based on the code module from the
418 418 standard library).
419 419
420 420 Because they are meant to be called without a full traceback (only a
421 421 list), instances of this class can't call the interactive pdb debugger."""
422 422
423 423
424 424 def __call__(self, etype, value, elist):
425 425 self.ostream.flush()
426 426 self.ostream.write(self.text(etype, value, elist))
427 427 self.ostream.write('\n')
428 428
429 429 def _extract_tb(self, tb):
430 430 if tb:
431 431 return traceback.extract_tb(tb)
432 432 else:
433 433 return None
434 434
435 435 def structured_traceback(
436 436 self,
437 437 etype: type,
438 438 evalue: BaseException,
439 439 etb: Optional[TracebackType] = None,
440 440 tb_offset: Optional[int] = None,
441 441 context=5,
442 442 ):
443 443 """Return a color formatted string with the traceback info.
444 444
445 445 Parameters
446 446 ----------
447 447 etype : exception type
448 448 Type of the exception raised.
449 449 evalue : object
450 450 Data stored in the exception
451 451 etb : list | TracebackType | None
452 452 If list: List of frames, see class docstring for details.
453 453 If Traceback: Traceback of the exception.
454 454 tb_offset : int, optional
455 455 Number of frames in the traceback to skip. If not given, the
456 456 instance evalue is used (set in constructor).
457 457 context : int, optional
458 458 Number of lines of context information to print.
459 459
460 460 Returns
461 461 -------
462 462 String with formatted exception.
463 463 """
464 464 # This is a workaround to get chained_exc_ids in recursive calls
465 465 # etb should not be a tuple if structured_traceback is not recursive
466 466 if isinstance(etb, tuple):
467 467 etb, chained_exc_ids = etb
468 468 else:
469 469 chained_exc_ids = set()
470 470
471 471 if isinstance(etb, list):
472 472 elist = etb
473 473 elif etb is not None:
474 474 elist = self._extract_tb(etb)
475 475 else:
476 476 elist = []
477 477 tb_offset = self.tb_offset if tb_offset is None else tb_offset
478 478 assert isinstance(tb_offset, int)
479 479 Colors = self.Colors
480 480 out_list = []
481 481 if elist:
482 482
483 483 if tb_offset and len(elist) > tb_offset:
484 484 elist = elist[tb_offset:]
485 485
486 486 out_list.append('Traceback %s(most recent call last)%s:' %
487 487 (Colors.normalEm, Colors.Normal) + '\n')
488 488 out_list.extend(self._format_list(elist))
489 489 # The exception info should be a single entry in the list.
490 490 lines = ''.join(self._format_exception_only(etype, evalue))
491 491 out_list.append(lines)
492 492
493 493 exception = self.get_parts_of_chained_exception(evalue)
494 494
495 495 if exception and not id(exception[1]) in chained_exc_ids:
496 496 chained_exception_message = self.prepare_chained_exception_message(
497 497 evalue.__cause__)[0]
498 498 etype, evalue, etb = exception
499 499 # Trace exception to avoid infinite 'cause' loop
500 500 chained_exc_ids.add(id(exception[1]))
501 501 chained_exceptions_tb_offset = 0
502 502 out_list = (
503 503 self.structured_traceback(
504 504 etype, evalue, (etb, chained_exc_ids),
505 505 chained_exceptions_tb_offset, context)
506 506 + chained_exception_message
507 507 + out_list)
508 508
509 509 return out_list
510 510
511 511 def _format_list(self, extracted_list):
512 512 """Format a list of traceback entry tuples for printing.
513 513
514 514 Given a list of tuples as returned by extract_tb() or
515 515 extract_stack(), return a list of strings ready for printing.
516 516 Each string in the resulting list corresponds to the item with the
517 517 same index in the argument list. Each string ends in a newline;
518 518 the strings may contain internal newlines as well, for those items
519 519 whose source text line is not None.
520 520
521 521 Lifted almost verbatim from traceback.py
522 522 """
523 523
524 524 Colors = self.Colors
525 525 list = []
526 526 for ind, (filename, lineno, name, line) in enumerate(extracted_list):
527 527 normalCol, nameCol, fileCol, lineCol = (
528 528 # Emphasize the last entry
529 529 (Colors.normalEm, Colors.nameEm, Colors.filenameEm, Colors.line)
530 530 if ind == len(extracted_list) - 1
531 531 else (Colors.Normal, Colors.name, Colors.filename, "")
532 532 )
533 533
534 534 fns = _format_filename(filename, fileCol, normalCol, lineno=lineno)
535 535 item = f"{normalCol} {fns}"
536 536
537 537 if name != "<module>":
538 538 item += f" in {nameCol}{name}{normalCol}\n"
539 539 else:
540 540 item += "\n"
541 541 if line:
542 542 item += f"{lineCol} {line.strip()}{normalCol}\n"
543 543 list.append(item)
544 544
545 545 return list
546 546
547 547 def _format_exception_only(self, etype, value):
548 548 """Format the exception part of a traceback.
549 549
550 550 The arguments are the exception type and value such as given by
551 551 sys.exc_info()[:2]. The return value is a list of strings, each ending
552 552 in a newline. Normally, the list contains a single string; however,
553 553 for SyntaxError exceptions, it contains several lines that (when
554 554 printed) display detailed information about where the syntax error
555 555 occurred. The message indicating which exception occurred is the
556 556 always last string in the list.
557 557
558 558 Also lifted nearly verbatim from traceback.py
559 559 """
560 560 have_filedata = False
561 561 Colors = self.Colors
562 562 list = []
563 563 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
564 564 if value is None:
565 565 # Not sure if this can still happen in Python 2.6 and above
566 566 list.append(stype + '\n')
567 567 else:
568 568 if issubclass(etype, SyntaxError):
569 569 have_filedata = True
570 570 if not value.filename: value.filename = "<string>"
571 571 if value.lineno:
572 572 lineno = value.lineno
573 573 textline = linecache.getline(value.filename, value.lineno)
574 574 else:
575 575 lineno = "unknown"
576 576 textline = ""
577 577 list.append(
578 578 "%s %s%s\n"
579 579 % (
580 580 Colors.normalEm,
581 581 _format_filename(
582 582 value.filename,
583 583 Colors.filenameEm,
584 584 Colors.normalEm,
585 585 lineno=(None if lineno == "unknown" else lineno),
586 586 ),
587 587 Colors.Normal,
588 588 )
589 589 )
590 590 if textline == "":
591 591 textline = py3compat.cast_unicode(value.text, "utf-8")
592 592
593 593 if textline is not None:
594 594 i = 0
595 595 while i < len(textline) and textline[i].isspace():
596 596 i += 1
597 597 list.append('%s %s%s\n' % (Colors.line,
598 598 textline.strip(),
599 599 Colors.Normal))
600 600 if value.offset is not None:
601 601 s = ' '
602 602 for c in textline[i:value.offset - 1]:
603 603 if c.isspace():
604 604 s += c
605 605 else:
606 606 s += ' '
607 607 list.append('%s%s^%s\n' % (Colors.caret, s,
608 608 Colors.Normal))
609 609
610 610 try:
611 611 s = value.msg
612 612 except Exception:
613 613 s = self._some_str(value)
614 614 if s:
615 615 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
616 616 Colors.Normal, s))
617 617 else:
618 618 list.append('%s\n' % stype)
619 619
620 620 # sync with user hooks
621 621 if have_filedata:
622 622 ipinst = get_ipython()
623 623 if ipinst is not None:
624 624 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
625 625
626 626 return list
627 627
628 628 def get_exception_only(self, etype, value):
629 629 """Only print the exception type and message, without a traceback.
630 630
631 631 Parameters
632 632 ----------
633 633 etype : exception type
634 634 value : exception value
635 635 """
636 636 return ListTB.structured_traceback(self, etype, value)
637 637
638 638 def show_exception_only(self, etype, evalue):
639 639 """Only print the exception type and message, without a traceback.
640 640
641 641 Parameters
642 642 ----------
643 643 etype : exception type
644 644 evalue : exception value
645 645 """
646 646 # This method needs to use __call__ from *this* class, not the one from
647 647 # a subclass whose signature or behavior may be different
648 648 ostream = self.ostream
649 649 ostream.flush()
650 650 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
651 651 ostream.flush()
652 652
653 653 def _some_str(self, value):
654 654 # Lifted from traceback.py
655 655 try:
656 656 return py3compat.cast_unicode(str(value))
657 657 except:
658 658 return u'<unprintable %s object>' % type(value).__name__
659 659
660 660
661 661 class FrameInfo:
662 662 """
663 663 Mirror of stack data's FrameInfo, but so that we can bypass highlighting on
664 664 really long frames.
665 665 """
666 666
667 667 description: Optional[str]
668 668 filename: str
669 669 lineno: int
670 670
671 671 @classmethod
672 672 def _from_stack_data_FrameInfo(cls, frame_info):
673 673 return cls(
674 674 getattr(frame_info, "description", None),
675 675 getattr(frame_info, "filename", None),
676 676 getattr(frame_info, "lineno", None),
677 677 getattr(frame_info, "frame", None),
678 678 getattr(frame_info, "code", None),
679 679 sd=frame_info,
680 680 )
681 681
682 682 def __init__(self, description, filename, lineno, frame, code, sd=None):
683 683 self.description = description
684 684 self.filename = filename
685 685 self.lineno = lineno
686 686 self.frame = frame
687 687 self.code = code
688 688 self._sd = sd
689 689
690 690 # self.lines = []
691 691 if sd is None:
692 692 ix = inspect.getsourcelines(frame)
693 693 self.raw_lines = ix[0]
694 694
695 695 @property
696 696 def variables_in_executing_piece(self):
697 697 if self._sd:
698 698 return self._sd.variables_in_executing_piece
699 699 else:
700 700 return []
701 701
702 702 @property
703 703 def lines(self):
704 704 return self._sd.lines
705 705
706 706 @property
707 707 def executing(self):
708 708 if self._sd:
709 709 return self._sd.executing
710 710 else:
711 711 return None
712 712
713 713
714 714 # ----------------------------------------------------------------------------
715 715 class VerboseTB(TBTools):
716 716 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
717 717 of HTML. Requires inspect and pydoc. Crazy, man.
718 718
719 719 Modified version which optionally strips the topmost entries from the
720 720 traceback, to be used with alternate interpreters (because their own code
721 721 would appear in the traceback)."""
722 722
723 723 _tb_highlight = "bg:ansiyellow"
724 724
725 725 def __init__(
726 726 self,
727 727 color_scheme: str = "Linux",
728 728 call_pdb: bool = False,
729 729 ostream=None,
730 730 tb_offset: int = 0,
731 731 long_header: bool = False,
732 732 include_vars: bool = True,
733 733 check_cache=None,
734 734 debugger_cls=None,
735 735 parent=None,
736 736 config=None,
737 737 ):
738 738 """Specify traceback offset, headers and color scheme.
739 739
740 740 Define how many frames to drop from the tracebacks. Calling it with
741 741 tb_offset=1 allows use of this handler in interpreters which will have
742 742 their own code at the top of the traceback (VerboseTB will first
743 743 remove that frame before printing the traceback info)."""
744 744 TBTools.__init__(
745 745 self,
746 746 color_scheme=color_scheme,
747 747 call_pdb=call_pdb,
748 748 ostream=ostream,
749 749 parent=parent,
750 750 config=config,
751 751 debugger_cls=debugger_cls,
752 752 )
753 753 self.tb_offset = tb_offset
754 754 self.long_header = long_header
755 755 self.include_vars = include_vars
756 756 # By default we use linecache.checkcache, but the user can provide a
757 757 # different check_cache implementation. This was formerly used by the
758 758 # IPython kernel for interactive code, but is no longer necessary.
759 759 if check_cache is None:
760 760 check_cache = linecache.checkcache
761 761 self.check_cache = check_cache
762 762
763 763 self.skip_hidden = True
764 764
765 765 def format_record(self, frame_info: FrameInfo):
766 766 """Format a single stack frame"""
767 767 assert isinstance(frame_info, FrameInfo)
768 768 Colors = self.Colors # just a shorthand + quicker name lookup
769 769 ColorsNormal = Colors.Normal # used a lot
770 770
771 771 if isinstance(frame_info._sd, stack_data.RepeatedFrames):
772 772 return ' %s[... skipping similar frames: %s]%s\n' % (
773 773 Colors.excName, frame_info.description, ColorsNormal)
774 774
775 775 indent = " " * INDENT_SIZE
776 776 em_normal = "%s\n%s%s" % (Colors.valEm, indent, ColorsNormal)
777 777 tpl_call = f"in {Colors.vName}{{file}}{Colors.valEm}{{scope}}{ColorsNormal}"
778 778 tpl_call_fail = "in %s%%s%s(***failed resolving arguments***)%s" % (
779 779 Colors.vName,
780 780 Colors.valEm,
781 781 ColorsNormal,
782 782 )
783 783 tpl_name_val = "%%s %s= %%s%s" % (Colors.valEm, ColorsNormal)
784 784
785 785 link = _format_filename(
786 786 frame_info.filename,
787 787 Colors.filenameEm,
788 788 ColorsNormal,
789 789 lineno=frame_info.lineno,
790 790 )
791 791 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
792 792 if frame_info.executing is not None:
793 793 func = frame_info.executing.code_qualname()
794 794 else:
795 795 func = "?"
796 796 if func == "<module>":
797 797 call = ""
798 798 else:
799 799 # Decide whether to include variable details or not
800 800 var_repr = eqrepr if self.include_vars else nullrepr
801 801 try:
802 802 scope = inspect.formatargvalues(
803 803 args, varargs, varkw, locals_, formatvalue=var_repr
804 804 )
805 805 call = tpl_call.format(file=func, scope=scope)
806 806 except KeyError:
807 807 # This happens in situations like errors inside generator
808 808 # expressions, where local variables are listed in the
809 809 # line, but can't be extracted from the frame. I'm not
810 810 # 100% sure this isn't actually a bug in inspect itself,
811 811 # but since there's no info for us to compute with, the
812 812 # best we can do is report the failure and move on. Here
813 813 # we must *not* call any traceback construction again,
814 814 # because that would mess up use of %debug later on. So we
815 815 # simply report the failure and move on. The only
816 816 # limitation will be that this frame won't have locals
817 817 # listed in the call signature. Quite subtle problem...
818 818 # I can't think of a good way to validate this in a unit
819 819 # test, but running a script consisting of:
820 820 # dict( (k,v.strip()) for (k,v) in range(10) )
821 821 # will illustrate the error, if this exception catch is
822 822 # disabled.
823 823 call = tpl_call_fail % func
824 824
825 825 lvals = ''
826 826 lvals_list = []
827 827 if self.include_vars:
828 828 try:
829 829 # we likely want to fix stackdata at some point, but
830 830 # still need a workaround.
831 831 fibp = frame_info.variables_in_executing_piece
832 832 for var in fibp:
833 833 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
834 834 except Exception:
835 835 lvals_list.append(
836 836 "Exception trying to inspect frame. No more locals available."
837 837 )
838 838 if lvals_list:
839 839 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
840 840
841 841 result = f'{link}{", " if call else ""}{call}\n'
842 842 if frame_info._sd is None:
843 843 assert False
844 844 # fast fallback if file is too long
845 845 tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
846 846 link = tpl_link % util_path.compress_user(frame_info.filename)
847 847 level = "%s %s\n" % (link, call)
848 848 _line_format = PyColorize.Parser(
849 849 style=self.color_scheme_table.active_scheme_name, parent=self
850 850 ).format2
851 851 first_line = frame_info.code.co_firstlineno
852 852 current_line = frame_info.lineno[0]
853 853 return "%s%s" % (
854 854 level,
855 855 "".join(
856 856 _simple_format_traceback_lines(
857 857 current_line,
858 858 current_line - first_line,
859 859 frame_info.raw_lines,
860 860 Colors,
861 861 lvals,
862 862 _line_format,
863 863 )
864 864 ),
865 865 )
866 866 # result += "\n".join(frame_info.raw_lines)
867 867 else:
868 868 result += "".join(
869 869 _format_traceback_lines(
870 870 frame_info.lines, Colors, self.has_colors, lvals
871 871 )
872 872 )
873 873 return result
874 874
875 875 def prepare_header(self, etype, long_version=False):
876 876 colors = self.Colors # just a shorthand + quicker name lookup
877 877 colorsnormal = colors.Normal # used a lot
878 878 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
879 879 width = min(75, get_terminal_size()[0])
880 880 if long_version:
881 881 # Header with the exception type, python version, and date
882 882 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
883 883 date = time.ctime(time.time())
884 884
885 885 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
886 886 exc, ' ' * (width - len(str(etype)) - len(pyver)),
887 887 pyver, date.rjust(width) )
888 888 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
889 889 "\ncalls leading up to the error, with the most recent (innermost) call last."
890 890 else:
891 891 # Simplified header
892 892 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
893 893 rjust(width - len(str(etype))) )
894 894
895 895 return head
896 896
897 897 def format_exception(self, etype, evalue):
898 898 colors = self.Colors # just a shorthand + quicker name lookup
899 899 colorsnormal = colors.Normal # used a lot
900 900 # Get (safely) a string form of the exception info
901 901 try:
902 902 etype_str, evalue_str = map(str, (etype, evalue))
903 903 except:
904 904 # User exception is improperly defined.
905 905 etype, evalue = str, sys.exc_info()[:2]
906 906 etype_str, evalue_str = map(str, (etype, evalue))
907 907 # ... and format it
908 908 return ['%s%s%s: %s' % (colors.excName, etype_str,
909 909 colorsnormal, py3compat.cast_unicode(evalue_str))]
910 910
911 911 def format_exception_as_a_whole(
912 912 self,
913 913 etype: type,
914 914 evalue: BaseException,
915 915 etb: Optional[TracebackType],
916 916 number_of_lines_of_context,
917 917 tb_offset: Optional[int],
918 918 ):
919 919 """Formats the header, traceback and exception message for a single exception.
920 920
921 921 This may be called multiple times by Python 3 exception chaining
922 922 (PEP 3134).
923 923 """
924 924 # some locals
925 925 orig_etype = etype
926 926 try:
927 927 etype = etype.__name__
928 928 except AttributeError:
929 929 pass
930 930
931 931 tb_offset = self.tb_offset if tb_offset is None else tb_offset
932 932 assert isinstance(tb_offset, int)
933 933 head = self.prepare_header(etype, self.long_header)
934 934 records = (
935 935 self.get_records(etb, number_of_lines_of_context, tb_offset) if etb else []
936 936 )
937 937
938 938 frames = []
939 939 skipped = 0
940 940 lastrecord = len(records) - 1
941 941 for i, record in enumerate(records):
942 942 if (
943 943 not isinstance(record._sd, stack_data.RepeatedFrames)
944 944 and self.skip_hidden
945 945 ):
946 946 if (
947 947 record.frame.f_locals.get("__tracebackhide__", 0)
948 948 and i != lastrecord
949 949 ):
950 950 skipped += 1
951 951 continue
952 952 if skipped:
953 953 Colors = self.Colors # just a shorthand + quicker name lookup
954 954 ColorsNormal = Colors.Normal # used a lot
955 955 frames.append(
956 956 " %s[... skipping hidden %s frame]%s\n"
957 957 % (Colors.excName, skipped, ColorsNormal)
958 958 )
959 959 skipped = 0
960 960 frames.append(self.format_record(record))
961 961 if skipped:
962 962 Colors = self.Colors # just a shorthand + quicker name lookup
963 963 ColorsNormal = Colors.Normal # used a lot
964 964 frames.append(
965 965 " %s[... skipping hidden %s frame]%s\n"
966 966 % (Colors.excName, skipped, ColorsNormal)
967 967 )
968 968
969 969 formatted_exception = self.format_exception(etype, evalue)
970 970 if records:
971 971 frame_info = records[-1]
972 972 ipinst = get_ipython()
973 973 if ipinst is not None:
974 974 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
975 975
976 976 return [[head] + frames + [''.join(formatted_exception[0])]]
977 977
978 978 def get_records(
979 979 self, etb: TracebackType, number_of_lines_of_context: int, tb_offset: int
980 980 ):
981 981 assert etb is not None
982 982 context = number_of_lines_of_context - 1
983 983 after = context // 2
984 984 before = context - after
985 985 if self.has_colors:
986 986 style = get_style_by_name("default")
987 987 style = stack_data.style_with_executing_node(style, self._tb_highlight)
988 988 formatter = Terminal256Formatter(style=style)
989 989 else:
990 990 formatter = None
991 991 options = stack_data.Options(
992 992 before=before,
993 993 after=after,
994 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 998 cf = etb
999 999 max_len = 0
1000 1000 tbs = []
1001 1001 while cf is not None:
1002 1002 try:
1003 1003 source_file = inspect.getsourcefile(etb.tb_frame)
1004 1004 lines, first = inspect.getsourcelines(etb.tb_frame)
1005 1005 except OSError:
1006 1006 max_len = float("-inf")
1007 1007 break
1008 1008 max_len = max(max_len, first + len(lines))
1009 1009 tbs.append(cf)
1010 1010 cf = cf.tb_next
1011 1011
1012 1012 if max_len > FAST_THRESHOLD:
1013 1013 FIs = []
1014 1014 for tb in tbs:
1015 1015 frame = tb.tb_frame
1016 1016 lineno = (frame.f_lineno,)
1017 1017 code = frame.f_code
1018 1018 filename = code.co_filename
1019 1019 FIs.append(FrameInfo("Raw frame", filename, lineno, frame, code))
1020 1020 return FIs
1021 1021 res = list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
1022 1022 res = [FrameInfo._from_stack_data_FrameInfo(r) for r in res]
1023 1023 return res
1024 1024
1025 1025 def structured_traceback(
1026 1026 self,
1027 1027 etype: type,
1028 1028 evalue: Optional[BaseException],
1029 1029 etb: Optional[TracebackType],
1030 1030 tb_offset: Optional[int] = None,
1031 1031 number_of_lines_of_context: int = 5,
1032 1032 ):
1033 1033 """Return a nice text document describing the traceback."""
1034 1034 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1035 1035 tb_offset)
1036 1036
1037 1037 colors = self.Colors # just a shorthand + quicker name lookup
1038 1038 colorsnormal = colors.Normal # used a lot
1039 1039 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1040 1040 structured_traceback_parts = [head]
1041 1041 chained_exceptions_tb_offset = 0
1042 1042 lines_of_context = 3
1043 1043 formatted_exceptions = formatted_exception
1044 1044 exception = self.get_parts_of_chained_exception(evalue)
1045 1045 if exception:
1046 1046 assert evalue is not None
1047 1047 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1048 1048 etype, evalue, etb = exception
1049 1049 else:
1050 1050 evalue = None
1051 1051 chained_exc_ids = set()
1052 1052 while evalue:
1053 1053 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1054 1054 chained_exceptions_tb_offset)
1055 1055 exception = self.get_parts_of_chained_exception(evalue)
1056 1056
1057 1057 if exception and not id(exception[1]) in chained_exc_ids:
1058 1058 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1059 1059 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1060 1060 etype, evalue, etb = exception
1061 1061 else:
1062 1062 evalue = None
1063 1063
1064 1064 # we want to see exceptions in a reversed order:
1065 1065 # the first exception should be on top
1066 1066 for formatted_exception in reversed(formatted_exceptions):
1067 1067 structured_traceback_parts += formatted_exception
1068 1068
1069 1069 return structured_traceback_parts
1070 1070
1071 1071 def debugger(self, force: bool = False):
1072 1072 """Call up the pdb debugger if desired, always clean up the tb
1073 1073 reference.
1074 1074
1075 1075 Keywords:
1076 1076
1077 1077 - force(False): by default, this routine checks the instance call_pdb
1078 1078 flag and does not actually invoke the debugger if the flag is false.
1079 1079 The 'force' option forces the debugger to activate even if the flag
1080 1080 is false.
1081 1081
1082 1082 If the call_pdb flag is set, the pdb interactive debugger is
1083 1083 invoked. In all cases, the self.tb reference to the current traceback
1084 1084 is deleted to prevent lingering references which hamper memory
1085 1085 management.
1086 1086
1087 1087 Note that each call to pdb() does an 'import readline', so if your app
1088 1088 requires a special setup for the readline completers, you'll have to
1089 1089 fix that by hand after invoking the exception handler."""
1090 1090
1091 1091 if force or self.call_pdb:
1092 1092 if self.pdb is None:
1093 1093 self.pdb = self.debugger_cls()
1094 1094 # the system displayhook may have changed, restore the original
1095 1095 # for pdb
1096 1096 display_trap = DisplayTrap(hook=sys.__displayhook__)
1097 1097 with display_trap:
1098 1098 self.pdb.reset()
1099 1099 # Find the right frame so we don't pop up inside ipython itself
1100 1100 if hasattr(self, 'tb') and self.tb is not None:
1101 1101 etb = self.tb
1102 1102 else:
1103 1103 etb = self.tb = sys.last_traceback
1104 1104 while self.tb is not None and self.tb.tb_next is not None:
1105 1105 assert self.tb.tb_next is not None
1106 1106 self.tb = self.tb.tb_next
1107 1107 if etb and etb.tb_next:
1108 1108 etb = etb.tb_next
1109 1109 self.pdb.botframe = etb.tb_frame
1110 1110 self.pdb.interaction(None, etb)
1111 1111
1112 1112 if hasattr(self, 'tb'):
1113 1113 del self.tb
1114 1114
1115 1115 def handler(self, info=None):
1116 1116 (etype, evalue, etb) = info or sys.exc_info()
1117 1117 self.tb = etb
1118 1118 ostream = self.ostream
1119 1119 ostream.flush()
1120 1120 ostream.write(self.text(etype, evalue, etb))
1121 1121 ostream.write('\n')
1122 1122 ostream.flush()
1123 1123
1124 1124 # Changed so an instance can just be called as VerboseTB_inst() and print
1125 1125 # out the right info on its own.
1126 1126 def __call__(self, etype=None, evalue=None, etb=None):
1127 1127 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1128 1128 if etb is None:
1129 1129 self.handler()
1130 1130 else:
1131 1131 self.handler((etype, evalue, etb))
1132 1132 try:
1133 1133 self.debugger()
1134 1134 except KeyboardInterrupt:
1135 1135 print("\nKeyboardInterrupt")
1136 1136
1137 1137
1138 1138 #----------------------------------------------------------------------------
1139 1139 class FormattedTB(VerboseTB, ListTB):
1140 1140 """Subclass ListTB but allow calling with a traceback.
1141 1141
1142 1142 It can thus be used as a sys.excepthook for Python > 2.1.
1143 1143
1144 1144 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1145 1145
1146 1146 Allows a tb_offset to be specified. This is useful for situations where
1147 1147 one needs to remove a number of topmost frames from the traceback (such as
1148 1148 occurs with python programs that themselves execute other python code,
1149 1149 like Python shells). """
1150 1150
1151 1151 mode: str
1152 1152
1153 1153 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1154 1154 ostream=None,
1155 1155 tb_offset=0, long_header=False, include_vars=False,
1156 1156 check_cache=None, debugger_cls=None,
1157 1157 parent=None, config=None):
1158 1158
1159 1159 # NEVER change the order of this list. Put new modes at the end:
1160 1160 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
1161 1161 self.verbose_modes = self.valid_modes[1:3]
1162 1162
1163 1163 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1164 1164 ostream=ostream, tb_offset=tb_offset,
1165 1165 long_header=long_header, include_vars=include_vars,
1166 1166 check_cache=check_cache, debugger_cls=debugger_cls,
1167 1167 parent=parent, config=config)
1168 1168
1169 1169 # Different types of tracebacks are joined with different separators to
1170 1170 # form a single string. They are taken from this dict
1171 1171 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
1172 1172 Minimal='')
1173 1173 # set_mode also sets the tb_join_char attribute
1174 1174 self.set_mode(mode)
1175 1175
1176 1176 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1177 1177 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1178 1178 mode = self.mode
1179 1179 if mode in self.verbose_modes:
1180 1180 # Verbose modes need a full traceback
1181 1181 return VerboseTB.structured_traceback(
1182 1182 self, etype, value, tb, tb_offset, number_of_lines_of_context
1183 1183 )
1184 1184 elif mode == 'Minimal':
1185 1185 return ListTB.get_exception_only(self, etype, value)
1186 1186 else:
1187 1187 # We must check the source cache because otherwise we can print
1188 1188 # out-of-date source code.
1189 1189 self.check_cache()
1190 1190 # Now we can extract and format the exception
1191 1191 return ListTB.structured_traceback(
1192 1192 self, etype, value, tb, tb_offset, number_of_lines_of_context
1193 1193 )
1194 1194
1195 1195 def stb2text(self, stb):
1196 1196 """Convert a structured traceback (a list) to a string."""
1197 1197 return self.tb_join_char.join(stb)
1198 1198
1199 1199 def set_mode(self, mode: Optional[str] = None):
1200 1200 """Switch to the desired mode.
1201 1201
1202 1202 If mode is not specified, cycles through the available modes."""
1203 1203
1204 1204 if not mode:
1205 1205 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1206 1206 len(self.valid_modes)
1207 1207 self.mode = self.valid_modes[new_idx]
1208 1208 elif mode not in self.valid_modes:
1209 1209 raise ValueError(
1210 1210 "Unrecognized mode in FormattedTB: <" + mode + ">\n"
1211 1211 "Valid modes: " + str(self.valid_modes)
1212 1212 )
1213 1213 else:
1214 1214 assert isinstance(mode, str)
1215 1215 self.mode = mode
1216 1216 # include variable details only in 'Verbose' mode
1217 1217 self.include_vars = (self.mode == self.valid_modes[2])
1218 1218 # Set the join character for generating text tracebacks
1219 1219 self.tb_join_char = self._join_chars[self.mode]
1220 1220
1221 1221 # some convenient shortcuts
1222 1222 def plain(self):
1223 1223 self.set_mode(self.valid_modes[0])
1224 1224
1225 1225 def context(self):
1226 1226 self.set_mode(self.valid_modes[1])
1227 1227
1228 1228 def verbose(self):
1229 1229 self.set_mode(self.valid_modes[2])
1230 1230
1231 1231 def minimal(self):
1232 1232 self.set_mode(self.valid_modes[3])
1233 1233
1234 1234
1235 1235 #----------------------------------------------------------------------------
1236 1236 class AutoFormattedTB(FormattedTB):
1237 1237 """A traceback printer which can be called on the fly.
1238 1238
1239 1239 It will find out about exceptions by itself.
1240 1240
1241 1241 A brief example::
1242 1242
1243 1243 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1244 1244 try:
1245 1245 ...
1246 1246 except:
1247 1247 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1248 1248 """
1249 1249
1250 1250 def __call__(self, etype=None, evalue=None, etb=None,
1251 1251 out=None, tb_offset=None):
1252 1252 """Print out a formatted exception traceback.
1253 1253
1254 1254 Optional arguments:
1255 1255 - out: an open file-like object to direct output to.
1256 1256
1257 1257 - tb_offset: the number of frames to skip over in the stack, on a
1258 1258 per-call basis (this overrides temporarily the instance's tb_offset
1259 1259 given at initialization time."""
1260 1260
1261 1261 if out is None:
1262 1262 out = self.ostream
1263 1263 out.flush()
1264 1264 out.write(self.text(etype, evalue, etb, tb_offset))
1265 1265 out.write('\n')
1266 1266 out.flush()
1267 1267 # FIXME: we should remove the auto pdb behavior from here and leave
1268 1268 # that to the clients.
1269 1269 try:
1270 1270 self.debugger()
1271 1271 except KeyboardInterrupt:
1272 1272 print("\nKeyboardInterrupt")
1273 1273
1274 1274 def structured_traceback(
1275 1275 self,
1276 1276 etype=None,
1277 1277 value=None,
1278 1278 tb=None,
1279 1279 tb_offset=None,
1280 1280 number_of_lines_of_context=5,
1281 1281 ):
1282 1282 etype: type
1283 1283 value: BaseException
1284 1284 # tb: TracebackType or tupleof tb types ?
1285 1285 if etype is None:
1286 1286 etype, value, tb = sys.exc_info()
1287 1287 if isinstance(tb, tuple):
1288 1288 # tb is a tuple if this is a chained exception.
1289 1289 self.tb = tb[0]
1290 1290 else:
1291 1291 self.tb = tb
1292 1292 return FormattedTB.structured_traceback(
1293 1293 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1294 1294
1295 1295
1296 1296 #---------------------------------------------------------------------------
1297 1297
1298 1298 # A simple class to preserve Nathan's original functionality.
1299 1299 class ColorTB(FormattedTB):
1300 1300 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1301 1301
1302 1302 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1303 1303 FormattedTB.__init__(self, color_scheme=color_scheme,
1304 1304 call_pdb=call_pdb, **kwargs)
1305 1305
1306 1306
1307 1307 class SyntaxTB(ListTB):
1308 1308 """Extension which holds some state: the last exception value"""
1309 1309
1310 1310 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1311 1311 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1312 1312 self.last_syntax_error = None
1313 1313
1314 1314 def __call__(self, etype, value, elist):
1315 1315 self.last_syntax_error = value
1316 1316
1317 1317 ListTB.__call__(self, etype, value, elist)
1318 1318
1319 1319 def structured_traceback(self, etype, value, elist, tb_offset=None,
1320 1320 context=5):
1321 1321 # If the source file has been edited, the line in the syntax error can
1322 1322 # be wrong (retrieved from an outdated cache). This replaces it with
1323 1323 # the current value.
1324 1324 if isinstance(value, SyntaxError) \
1325 1325 and isinstance(value.filename, str) \
1326 1326 and isinstance(value.lineno, int):
1327 1327 linecache.checkcache(value.filename)
1328 1328 newtext = linecache.getline(value.filename, value.lineno)
1329 1329 if newtext:
1330 1330 value.text = newtext
1331 1331 self.last_syntax_error = value
1332 1332 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1333 1333 tb_offset=tb_offset, context=context)
1334 1334
1335 1335 def clear_err_state(self):
1336 1336 """Return the current error state and clear it"""
1337 1337 e = self.last_syntax_error
1338 1338 self.last_syntax_error = None
1339 1339 return e
1340 1340
1341 1341 def stb2text(self, stb):
1342 1342 """Convert a structured traceback (a list) to a string."""
1343 1343 return ''.join(stb)
1344 1344
1345 1345
1346 1346 # some internal-use functions
1347 1347 def text_repr(value):
1348 1348 """Hopefully pretty robust repr equivalent."""
1349 1349 # this is pretty horrible but should always return *something*
1350 1350 try:
1351 1351 return pydoc.text.repr(value)
1352 1352 except KeyboardInterrupt:
1353 1353 raise
1354 1354 except:
1355 1355 try:
1356 1356 return repr(value)
1357 1357 except KeyboardInterrupt:
1358 1358 raise
1359 1359 except:
1360 1360 try:
1361 1361 # all still in an except block so we catch
1362 1362 # getattr raising
1363 1363 name = getattr(value, '__name__', None)
1364 1364 if name:
1365 1365 # ick, recursion
1366 1366 return text_repr(name)
1367 1367 klass = getattr(value, '__class__', None)
1368 1368 if klass:
1369 1369 return '%s instance' % text_repr(klass)
1370 1370 except KeyboardInterrupt:
1371 1371 raise
1372 1372 except:
1373 1373 return 'UNRECOVERABLE REPR FAILURE'
1374 1374
1375 1375
1376 1376 def eqrepr(value, repr=text_repr):
1377 1377 return '=%s' % repr(value)
1378 1378
1379 1379
1380 1380 def nullrepr(value, repr=text_repr):
1381 1381 return ''
@@ -1,405 +1,410 b''
1 1 """
2 2 This module contains factory functions that attempt
3 3 to return Qt submodules from the various python Qt bindings.
4 4
5 5 It also protects against double-importing Qt with different
6 6 bindings, which is unstable and likely to crash
7 7
8 8 This is used primarily by qt and qt_for_kernel, and shouldn't
9 9 be accessed directly from the outside
10 10 """
11 11 import importlib.abc
12 12 import sys
13 import os
13 14 import types
14 15 from functools import partial, lru_cache
15 16 import operator
16 17
17 18 # ### Available APIs.
18 19 # Qt6
19 20 QT_API_PYQT6 = "pyqt6"
20 21 QT_API_PYSIDE6 = "pyside6"
21 22
22 23 # Qt5
23 24 QT_API_PYQT5 = 'pyqt5'
24 25 QT_API_PYSIDE2 = 'pyside2'
25 26
26 27 # Qt4
27 28 # NOTE: Here for legacy matplotlib compatibility, but not really supported on the IPython side.
28 29 QT_API_PYQT = "pyqt" # Force version 2
29 30 QT_API_PYQTv1 = "pyqtv1" # Force version 2
30 31 QT_API_PYSIDE = "pyside"
31 32
32 33 QT_API_PYQT_DEFAULT = "pyqtdefault" # use system default for version 1 vs. 2
33 34
34 35 api_to_module = {
35 36 # Qt6
36 37 QT_API_PYQT6: "PyQt6",
37 38 QT_API_PYSIDE6: "PySide6",
38 39 # Qt5
39 40 QT_API_PYQT5: "PyQt5",
40 41 QT_API_PYSIDE2: "PySide2",
41 42 # Qt4
42 43 QT_API_PYSIDE: "PySide",
43 44 QT_API_PYQT: "PyQt4",
44 45 QT_API_PYQTv1: "PyQt4",
45 46 # default
46 47 QT_API_PYQT_DEFAULT: "PyQt6",
47 48 }
48 49
49 50
50 51 class ImportDenier(importlib.abc.MetaPathFinder):
51 52 """Import Hook that will guard against bad Qt imports
52 53 once IPython commits to a specific binding
53 54 """
54 55
55 56 def __init__(self):
56 57 self.__forbidden = set()
57 58
58 59 def forbid(self, module_name):
59 60 sys.modules.pop(module_name, None)
60 61 self.__forbidden.add(module_name)
61 62
62 63 def find_spec(self, fullname, path, target=None):
63 64 if path:
64 65 return
65 66 if fullname in self.__forbidden:
66 67 raise ImportError(
67 68 """
68 69 Importing %s disabled by IPython, which has
69 70 already imported an Incompatible QT Binding: %s
70 71 """
71 72 % (fullname, loaded_api())
72 73 )
73 74
74 75
75 76 ID = ImportDenier()
76 77 sys.meta_path.insert(0, ID)
77 78
78 79
79 80 def commit_api(api):
80 81 """Commit to a particular API, and trigger ImportErrors on subsequent
81 82 dangerous imports"""
82 83 modules = set(api_to_module.values())
83 84
84 85 modules.remove(api_to_module[api])
85 86 for mod in modules:
86 87 ID.forbid(mod)
87 88
88 89
89 90 def loaded_api():
90 91 """Return which API is loaded, if any
91 92
92 93 If this returns anything besides None,
93 94 importing any other Qt binding is unsafe.
94 95
95 96 Returns
96 97 -------
97 98 None, 'pyside6', 'pyqt6', 'pyside2', 'pyside', 'pyqt', 'pyqt5', 'pyqtv1'
98 99 """
99 100 if sys.modules.get("PyQt6.QtCore"):
100 101 return QT_API_PYQT6
101 102 elif sys.modules.get("PySide6.QtCore"):
102 103 return QT_API_PYSIDE6
103 104 elif sys.modules.get("PyQt5.QtCore"):
104 105 return QT_API_PYQT5
105 106 elif sys.modules.get("PySide2.QtCore"):
106 107 return QT_API_PYSIDE2
107 108 elif sys.modules.get("PyQt4.QtCore"):
108 109 if qtapi_version() == 2:
109 110 return QT_API_PYQT
110 111 else:
111 112 return QT_API_PYQTv1
112 113 elif sys.modules.get("PySide.QtCore"):
113 114 return QT_API_PYSIDE
114 115
115 116 return None
116 117
117 118
118 119 def has_binding(api):
119 120 """Safely check for PyQt4/5, PySide or PySide2, without importing submodules
120 121
121 122 Parameters
122 123 ----------
123 124 api : str [ 'pyqtv1' | 'pyqt' | 'pyqt5' | 'pyside' | 'pyside2' | 'pyqtdefault']
124 125 Which module to check for
125 126
126 127 Returns
127 128 -------
128 129 True if the relevant module appears to be importable
129 130 """
130 131 module_name = api_to_module[api]
131 132 from importlib.util import find_spec
132 133
133 134 required = ['QtCore', 'QtGui', 'QtSvg']
134 135 if api in (QT_API_PYQT5, QT_API_PYSIDE2, QT_API_PYQT6, QT_API_PYSIDE6):
135 136 # QT5 requires QtWidgets too
136 137 required.append('QtWidgets')
137 138
138 139 for submod in required:
139 140 try:
140 141 spec = find_spec('%s.%s' % (module_name, submod))
141 142 except ImportError:
142 143 # Package (e.g. PyQt5) not found
143 144 return False
144 145 else:
145 146 if spec is None:
146 147 # Submodule (e.g. PyQt5.QtCore) not found
147 148 return False
148 149
149 150 if api == QT_API_PYSIDE:
150 151 # We can also safely check PySide version
151 152 import PySide
152 153
153 154 return PySide.__version_info__ >= (1, 0, 3)
154 155
155 156 return True
156 157
157 158
158 159 def qtapi_version():
159 160 """Return which QString API has been set, if any
160 161
161 162 Returns
162 163 -------
163 164 The QString API version (1 or 2), or None if not set
164 165 """
165 166 try:
166 167 import sip
167 168 except ImportError:
168 169 # as of PyQt5 5.11, sip is no longer available as a top-level
169 170 # module and needs to be imported from the PyQt5 namespace
170 171 try:
171 172 from PyQt5 import sip
172 173 except ImportError:
173 174 return
174 175 try:
175 176 return sip.getapi('QString')
176 177 except ValueError:
177 178 return
178 179
179 180
180 181 def can_import(api):
181 182 """Safely query whether an API is importable, without importing it"""
182 183 if not has_binding(api):
183 184 return False
184 185
185 186 current = loaded_api()
186 187 if api == QT_API_PYQT_DEFAULT:
187 188 return current in [QT_API_PYQT6, None]
188 189 else:
189 190 return current in [api, None]
190 191
191 192
192 193 def import_pyqt4(version=2):
193 194 """
194 195 Import PyQt4
195 196
196 197 Parameters
197 198 ----------
198 199 version : 1, 2, or None
199 200 Which QString/QVariant API to use. Set to None to use the system
200 201 default
201 202 ImportErrors raised within this function are non-recoverable
202 203 """
203 204 # The new-style string API (version=2) automatically
204 205 # converts QStrings to Unicode Python strings. Also, automatically unpacks
205 206 # QVariants to their underlying objects.
206 207 import sip
207 208
208 209 if version is not None:
209 210 sip.setapi('QString', version)
210 211 sip.setapi('QVariant', version)
211 212
212 213 from PyQt4 import QtGui, QtCore, QtSvg
213 214
214 215 if QtCore.PYQT_VERSION < 0x040700:
215 216 raise ImportError("IPython requires PyQt4 >= 4.7, found %s" %
216 217 QtCore.PYQT_VERSION_STR)
217 218
218 219 # Alias PyQt-specific functions for PySide compatibility.
219 220 QtCore.Signal = QtCore.pyqtSignal
220 221 QtCore.Slot = QtCore.pyqtSlot
221 222
222 223 # query for the API version (in case version == None)
223 224 version = sip.getapi('QString')
224 225 api = QT_API_PYQTv1 if version == 1 else QT_API_PYQT
225 226 return QtCore, QtGui, QtSvg, api
226 227
227 228
228 229 def import_pyqt5():
229 230 """
230 231 Import PyQt5
231 232
232 233 ImportErrors raised within this function are non-recoverable
233 234 """
234 235
235 236 from PyQt5 import QtCore, QtSvg, QtWidgets, QtGui
236 237
237 238 # Alias PyQt-specific functions for PySide compatibility.
238 239 QtCore.Signal = QtCore.pyqtSignal
239 240 QtCore.Slot = QtCore.pyqtSlot
240 241
241 242 # Join QtGui and QtWidgets for Qt4 compatibility.
242 243 QtGuiCompat = types.ModuleType('QtGuiCompat')
243 244 QtGuiCompat.__dict__.update(QtGui.__dict__)
244 245 QtGuiCompat.__dict__.update(QtWidgets.__dict__)
245 246
246 247 api = QT_API_PYQT5
247 248 return QtCore, QtGuiCompat, QtSvg, api
248 249
249 250
250 251 def import_pyqt6():
251 252 """
252 253 Import PyQt6
253 254
254 255 ImportErrors raised within this function are non-recoverable
255 256 """
256 257
257 258 from PyQt6 import QtCore, QtSvg, QtWidgets, QtGui
258 259
259 260 # Alias PyQt-specific functions for PySide compatibility.
260 261 QtCore.Signal = QtCore.pyqtSignal
261 262 QtCore.Slot = QtCore.pyqtSlot
262 263
263 264 # Join QtGui and QtWidgets for Qt4 compatibility.
264 265 QtGuiCompat = types.ModuleType("QtGuiCompat")
265 266 QtGuiCompat.__dict__.update(QtGui.__dict__)
266 267 QtGuiCompat.__dict__.update(QtWidgets.__dict__)
267 268
268 269 api = QT_API_PYQT6
269 270 return QtCore, QtGuiCompat, QtSvg, api
270 271
271 272
272 273 def import_pyside():
273 274 """
274 275 Import PySide
275 276
276 277 ImportErrors raised within this function are non-recoverable
277 278 """
278 279 from PySide import QtGui, QtCore, QtSvg
279 280 return QtCore, QtGui, QtSvg, QT_API_PYSIDE
280 281
281 282 def import_pyside2():
282 283 """
283 284 Import PySide2
284 285
285 286 ImportErrors raised within this function are non-recoverable
286 287 """
287 288 from PySide2 import QtGui, QtCore, QtSvg, QtWidgets, QtPrintSupport
288 289
289 290 # Join QtGui and QtWidgets for Qt4 compatibility.
290 291 QtGuiCompat = types.ModuleType('QtGuiCompat')
291 292 QtGuiCompat.__dict__.update(QtGui.__dict__)
292 293 QtGuiCompat.__dict__.update(QtWidgets.__dict__)
293 294 QtGuiCompat.__dict__.update(QtPrintSupport.__dict__)
294 295
295 296 return QtCore, QtGuiCompat, QtSvg, QT_API_PYSIDE2
296 297
297 298
298 299 def import_pyside6():
299 300 """
300 301 Import PySide6
301 302
302 303 ImportErrors raised within this function are non-recoverable
303 304 """
304 305 from PySide6 import QtGui, QtCore, QtSvg, QtWidgets, QtPrintSupport
305 306
306 307 # Join QtGui and QtWidgets for Qt4 compatibility.
307 308 QtGuiCompat = types.ModuleType("QtGuiCompat")
308 309 QtGuiCompat.__dict__.update(QtGui.__dict__)
309 310 QtGuiCompat.__dict__.update(QtWidgets.__dict__)
310 311 QtGuiCompat.__dict__.update(QtPrintSupport.__dict__)
311 312
312 313 return QtCore, QtGuiCompat, QtSvg, QT_API_PYSIDE6
313 314
314 315
315 316 def load_qt(api_options):
316 317 """
317 318 Attempt to import Qt, given a preference list
318 319 of permissible bindings
319 320
320 321 It is safe to call this function multiple times.
321 322
322 323 Parameters
323 324 ----------
324 325 api_options : List of strings
325 326 The order of APIs to try. Valid items are 'pyside', 'pyside2',
326 327 'pyqt', 'pyqt5', 'pyqtv1' and 'pyqtdefault'
327 328
328 329 Returns
329 330 -------
330 331 A tuple of QtCore, QtGui, QtSvg, QT_API
331 332 The first three are the Qt modules. The last is the
332 333 string indicating which module was loaded.
333 334
334 335 Raises
335 336 ------
336 337 ImportError, if it isn't possible to import any requested
337 338 bindings (either because they aren't installed, or because
338 339 an incompatible library has already been installed)
339 340 """
340 341 loaders = {
341 342 # Qt6
342 343 QT_API_PYQT6: import_pyqt6,
343 344 QT_API_PYSIDE6: import_pyside6,
344 345 # Qt5
345 346 QT_API_PYQT5: import_pyqt5,
346 347 QT_API_PYSIDE2: import_pyside2,
347 348 # Qt4
348 349 QT_API_PYSIDE: import_pyside,
349 350 QT_API_PYQT: import_pyqt4,
350 351 QT_API_PYQTv1: partial(import_pyqt4, version=1),
351 352 # default
352 353 QT_API_PYQT_DEFAULT: import_pyqt6,
353 354 }
354 355
355 356 for api in api_options:
356 357
357 358 if api not in loaders:
358 359 raise RuntimeError(
359 360 "Invalid Qt API %r, valid values are: %s" %
360 361 (api, ", ".join(["%r" % k for k in loaders.keys()])))
361 362
362 363 if not can_import(api):
363 364 continue
364 365
365 366 #cannot safely recover from an ImportError during this
366 367 result = loaders[api]()
367 368 api = result[-1] # changed if api = QT_API_PYQT_DEFAULT
368 369 commit_api(api)
369 370 return result
370 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 376 raise ImportError(
372 377 """
373 378 Could not load requested Qt binding. Please ensure that
374 379 PyQt4 >= 4.7, PyQt5, PyQt6, PySide >= 1.0.3, PySide2, or
375 380 PySide6 is available, and only one is imported per session.
376 381
377 382 Currently-imported Qt library: %r
378 383 PyQt5 available (requires QtCore, QtGui, QtSvg, QtWidgets): %s
379 384 PyQt6 available (requires QtCore, QtGui, QtSvg, QtWidgets): %s
380 385 PySide2 installed: %s
381 386 PySide6 installed: %s
382 387 Tried to load: %r
383 388 """
384 389 % (
385 390 loaded_api(),
386 391 has_binding(QT_API_PYQT5),
387 392 has_binding(QT_API_PYQT6),
388 393 has_binding(QT_API_PYSIDE2),
389 394 has_binding(QT_API_PYSIDE6),
390 395 api_options,
391 396 )
392 397 )
393 398
394 399
395 400 def enum_factory(QT_API, QtCore):
396 401 """Construct an enum helper to account for PyQt5 <-> PyQt6 changes."""
397 402
398 403 @lru_cache(None)
399 404 def _enum(name):
400 405 # foo.bar.Enum.Entry (PyQt6) <=> foo.bar.Entry (non-PyQt6).
401 406 return operator.attrgetter(
402 407 name if QT_API == QT_API_PYQT6 else name.rpartition(".")[0]
403 408 )(sys.modules[QtCore.__package__])
404 409
405 410 return _enum
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now