##// END OF EJS Templates
Merge pull request #13520 from Carreau/main-tempfile-import...
Matthias Bussonnier -
r27548:6d40fd89 merge
parent child Browse files
Show More
@@ -1,3722 +1,3737 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Main IPython class."""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13
14 14 import abc
15 15 import ast
16 16 import atexit
17 17 import builtins as builtin_mod
18 18 import dis
19 19 import functools
20 20 import inspect
21 21 import os
22 22 import re
23 23 import runpy
24 import subprocess
24 25 import sys
25 26 import tempfile
26 27 import traceback
27 28 import types
28 import subprocess
29 29 import warnings
30 from ast import stmt
30 31 from io import open as io_open
31
32 from logging import error
32 33 from pathlib import Path
33 from pickleshare import PickleShareDB
34 from typing import Callable
35 from typing import List as ListType
36 from typing import Optional, Tuple
37 from warnings import warn
34 38
39 from pickleshare import PickleShareDB
40 from tempfile import TemporaryDirectory
41 from traitlets import (
42 Any,
43 Bool,
44 CaselessStrEnum,
45 Dict,
46 Enum,
47 Instance,
48 Integer,
49 List,
50 Type,
51 Unicode,
52 default,
53 observe,
54 validate,
55 )
35 56 from traitlets.config.configurable import SingletonConfigurable
36 57 from traitlets.utils.importstring import import_item
37 from IPython.core import oinspect
38 from IPython.core import magic
39 from IPython.core import page
40 from IPython.core import prefilter
41 from IPython.core import ultratb
58
59 import IPython.core.hooks
60 from IPython.core import magic, oinspect, page, prefilter, ultratb
42 61 from IPython.core.alias import Alias, AliasManager
43 62 from IPython.core.autocall import ExitAutocall
44 63 from IPython.core.builtin_trap import BuiltinTrap
45 from IPython.core.events import EventManager, available_events
46 64 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
47 65 from IPython.core.debugger import InterruptiblePdb
48 66 from IPython.core.display_trap import DisplayTrap
49 67 from IPython.core.displayhook import DisplayHook
50 68 from IPython.core.displaypub import DisplayPublisher
51 69 from IPython.core.error import InputRejected, UsageError
70 from IPython.core.events import EventManager, available_events
52 71 from IPython.core.extensions import ExtensionManager
53 72 from IPython.core.formatters import DisplayFormatter
54 73 from IPython.core.history import HistoryManager
55 74 from IPython.core.inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
56 75 from IPython.core.logger import Logger
57 76 from IPython.core.macro import Macro
58 77 from IPython.core.payload import PayloadManager
59 78 from IPython.core.prefilter import PrefilterManager
60 79 from IPython.core.profiledir import ProfileDir
61 80 from IPython.core.usage import default_banner
62 81 from IPython.display import display
82 from IPython.paths import get_ipython_dir
63 83 from IPython.testing.skipdoctest import skip_doctest
64 from IPython.utils import PyColorize
65 from IPython.utils import io
66 from IPython.utils import py3compat
67 from IPython.utils import openpy
84 from IPython.utils import PyColorize, io, openpy, py3compat
68 85 from IPython.utils.decorators import undoc
69 86 from IPython.utils.io import ask_yes_no
70 87 from IPython.utils.ipstruct import Struct
71 from IPython.paths import get_ipython_dir
72 from IPython.utils.path import get_home_dir, get_py_filename, ensure_dir_exists
73 from IPython.utils.process import system, getoutput
88 from IPython.utils.path import ensure_dir_exists, get_home_dir, get_py_filename
89 from IPython.utils.process import getoutput, system
74 90 from IPython.utils.strdispatch import StrDispatch
75 91 from IPython.utils.syspathcontext import prepended_to_syspath
76 from IPython.utils.text import format_screen, LSString, SList, DollarFormatter
77 from IPython.utils.tempdir import TemporaryDirectory
78 from traitlets import (
79 Integer, Bool, CaselessStrEnum, Enum, List, Dict, Unicode, Instance, Type,
80 observe, default, validate, Any
81 )
82 from warnings import warn
83 from logging import error
84 import IPython.core.hooks
85
86 from typing import List as ListType, Tuple, Optional, Callable
87 from ast import stmt
92 from IPython.utils.text import DollarFormatter, LSString, SList, format_screen
88 93
89 94 sphinxify: Optional[Callable]
90 95
91 96 try:
92 97 import docrepr.sphinxify as sphx
93 98
94 99 def sphinxify(oinfo):
95 100 wrapped_docstring = sphx.wrap_main_docstring(oinfo)
96 101
97 102 def sphinxify_docstring(docstring):
98 103 with TemporaryDirectory() as dirname:
99 104 return {
100 105 "text/html": sphx.sphinxify(wrapped_docstring, dirname),
101 106 "text/plain": docstring,
102 107 }
103 108
104 109 return sphinxify_docstring
105 110 except ImportError:
106 111 sphinxify = None
107 112
108 113
109 114 class ProvisionalWarning(DeprecationWarning):
110 115 """
111 116 Warning class for unstable features
112 117 """
113 118 pass
114 119
115 120 from ast import Module
116 121
117 122 _assign_nodes = (ast.AugAssign, ast.AnnAssign, ast.Assign)
118 123 _single_targets_nodes = (ast.AugAssign, ast.AnnAssign)
119 124
120 125 #-----------------------------------------------------------------------------
121 126 # Await Helpers
122 127 #-----------------------------------------------------------------------------
123 128
124 129 # we still need to run things using the asyncio eventloop, but there is no
125 130 # async integration
126 from .async_helpers import _asyncio_runner, _pseudo_sync_runner
127 from .async_helpers import _curio_runner, _trio_runner, _should_be_async
131 from .async_helpers import (
132 _asyncio_runner,
133 _curio_runner,
134 _pseudo_sync_runner,
135 _should_be_async,
136 _trio_runner,
137 )
128 138
129 139 #-----------------------------------------------------------------------------
130 140 # Globals
131 141 #-----------------------------------------------------------------------------
132 142
133 143 # compiled regexps for autoindent management
134 144 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
135 145
136 146 #-----------------------------------------------------------------------------
137 147 # Utilities
138 148 #-----------------------------------------------------------------------------
139 149
140 150 @undoc
141 151 def softspace(file, newvalue):
142 152 """Copied from code.py, to remove the dependency"""
143 153
144 154 oldvalue = 0
145 155 try:
146 156 oldvalue = file.softspace
147 157 except AttributeError:
148 158 pass
149 159 try:
150 160 file.softspace = newvalue
151 161 except (AttributeError, TypeError):
152 162 # "attribute-less object" or "read-only attributes"
153 163 pass
154 164 return oldvalue
155 165
156 166 @undoc
157 167 def no_op(*a, **kw):
158 168 pass
159 169
160 170
161 171 class SpaceInInput(Exception): pass
162 172
163 173
164 174 class SeparateUnicode(Unicode):
165 175 r"""A Unicode subclass to validate separate_in, separate_out, etc.
166 176
167 177 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
168 178 """
169 179
170 180 def validate(self, obj, value):
171 181 if value == '0': value = ''
172 182 value = value.replace('\\n','\n')
173 183 return super(SeparateUnicode, self).validate(obj, value)
174 184
175 185
176 186 @undoc
177 187 class DummyMod(object):
178 188 """A dummy module used for IPython's interactive module when
179 189 a namespace must be assigned to the module's __dict__."""
180 190 __spec__ = None
181 191
182 192
183 193 class ExecutionInfo(object):
184 194 """The arguments used for a call to :meth:`InteractiveShell.run_cell`
185 195
186 196 Stores information about what is going to happen.
187 197 """
188 198 raw_cell = None
189 199 store_history = False
190 200 silent = False
191 201 shell_futures = True
192 202
193 203 def __init__(self, raw_cell, store_history, silent, shell_futures):
194 204 self.raw_cell = raw_cell
195 205 self.store_history = store_history
196 206 self.silent = silent
197 207 self.shell_futures = shell_futures
198 208
199 209 def __repr__(self):
200 210 name = self.__class__.__qualname__
201 211 raw_cell = ((self.raw_cell[:50] + '..')
202 212 if len(self.raw_cell) > 50 else self.raw_cell)
203 213 return '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s>' %\
204 214 (name, id(self), raw_cell, self.store_history, self.silent, self.shell_futures)
205 215
206 216
207 217 class ExecutionResult(object):
208 218 """The result of a call to :meth:`InteractiveShell.run_cell`
209 219
210 220 Stores information about what took place.
211 221 """
212 222 execution_count = None
213 223 error_before_exec = None
214 224 error_in_exec: Optional[BaseException] = None
215 225 info = None
216 226 result = None
217 227
218 228 def __init__(self, info):
219 229 self.info = info
220 230
221 231 @property
222 232 def success(self):
223 233 return (self.error_before_exec is None) and (self.error_in_exec is None)
224 234
225 235 def raise_error(self):
226 236 """Reraises error if `success` is `False`, otherwise does nothing"""
227 237 if self.error_before_exec is not None:
228 238 raise self.error_before_exec
229 239 if self.error_in_exec is not None:
230 240 raise self.error_in_exec
231 241
232 242 def __repr__(self):
233 243 name = self.__class__.__qualname__
234 244 return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s info=%s result=%s>' %\
235 245 (name, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.info), repr(self.result))
236 246
237 247
238 248 class InteractiveShell(SingletonConfigurable):
239 249 """An enhanced, interactive shell for Python."""
240 250
241 251 _instance = None
242 252
243 253 ast_transformers = List([], help=
244 254 """
245 255 A list of ast.NodeTransformer subclass instances, which will be applied
246 256 to user input before code is run.
247 257 """
248 258 ).tag(config=True)
249 259
250 260 autocall = Enum((0,1,2), default_value=0, help=
251 261 """
252 262 Make IPython automatically call any callable object even if you didn't
253 263 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
254 264 automatically. The value can be '0' to disable the feature, '1' for
255 265 'smart' autocall, where it is not applied if there are no more
256 266 arguments on the line, and '2' for 'full' autocall, where all callable
257 267 objects are automatically called (even if no arguments are present).
258 268 """
259 269 ).tag(config=True)
260 270
261 271 autoindent = Bool(True, help=
262 272 """
263 273 Autoindent IPython code entered interactively.
264 274 """
265 275 ).tag(config=True)
266 276
267 277 autoawait = Bool(True, help=
268 278 """
269 279 Automatically run await statement in the top level repl.
270 280 """
271 281 ).tag(config=True)
272 282
273 283 loop_runner_map ={
274 284 'asyncio':(_asyncio_runner, True),
275 285 'curio':(_curio_runner, True),
276 286 'trio':(_trio_runner, True),
277 287 'sync': (_pseudo_sync_runner, False)
278 288 }
279 289
280 290 loop_runner = Any(default_value="IPython.core.interactiveshell._asyncio_runner",
281 291 allow_none=True,
282 292 help="""Select the loop runner that will be used to execute top-level asynchronous code"""
283 293 ).tag(config=True)
284 294
285 295 @default('loop_runner')
286 296 def _default_loop_runner(self):
287 297 return import_item("IPython.core.interactiveshell._asyncio_runner")
288 298
289 299 @validate('loop_runner')
290 300 def _import_runner(self, proposal):
291 301 if isinstance(proposal.value, str):
292 302 if proposal.value in self.loop_runner_map:
293 303 runner, autoawait = self.loop_runner_map[proposal.value]
294 304 self.autoawait = autoawait
295 305 return runner
296 306 runner = import_item(proposal.value)
297 307 if not callable(runner):
298 308 raise ValueError('loop_runner must be callable')
299 309 return runner
300 310 if not callable(proposal.value):
301 311 raise ValueError('loop_runner must be callable')
302 312 return proposal.value
303 313
304 314 automagic = Bool(True, help=
305 315 """
306 316 Enable magic commands to be called without the leading %.
307 317 """
308 318 ).tag(config=True)
309 319
310 320 banner1 = Unicode(default_banner,
311 321 help="""The part of the banner to be printed before the profile"""
312 322 ).tag(config=True)
313 323 banner2 = Unicode('',
314 324 help="""The part of the banner to be printed after the profile"""
315 325 ).tag(config=True)
316 326
317 327 cache_size = Integer(1000, help=
318 328 """
319 329 Set the size of the output cache. The default is 1000, you can
320 330 change it permanently in your config file. Setting it to 0 completely
321 331 disables the caching system, and the minimum value accepted is 3 (if
322 332 you provide a value less than 3, it is reset to 0 and a warning is
323 333 issued). This limit is defined because otherwise you'll spend more
324 334 time re-flushing a too small cache than working
325 335 """
326 336 ).tag(config=True)
327 337 color_info = Bool(True, help=
328 338 """
329 339 Use colors for displaying information about objects. Because this
330 340 information is passed through a pager (like 'less'), and some pagers
331 341 get confused with color codes, this capability can be turned off.
332 342 """
333 343 ).tag(config=True)
334 344 colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'),
335 345 default_value='Neutral',
336 346 help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)."
337 347 ).tag(config=True)
338 348 debug = Bool(False).tag(config=True)
339 349 disable_failing_post_execute = Bool(False,
340 350 help="Don't call post-execute functions that have failed in the past."
341 351 ).tag(config=True)
342 352 display_formatter = Instance(DisplayFormatter, allow_none=True)
343 353 displayhook_class = Type(DisplayHook)
344 354 display_pub_class = Type(DisplayPublisher)
345 355 compiler_class = Type(CachingCompiler)
346 356
347 357 sphinxify_docstring = Bool(False, help=
348 358 """
349 359 Enables rich html representation of docstrings. (This requires the
350 360 docrepr module).
351 361 """).tag(config=True)
352 362
353 363 @observe("sphinxify_docstring")
354 364 def _sphinxify_docstring_changed(self, change):
355 365 if change['new']:
356 366 warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning)
357 367
358 368 enable_html_pager = Bool(False, help=
359 369 """
360 370 (Provisional API) enables html representation in mime bundles sent
361 371 to pagers.
362 372 """).tag(config=True)
363 373
364 374 @observe("enable_html_pager")
365 375 def _enable_html_pager_changed(self, change):
366 376 if change['new']:
367 377 warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning)
368 378
369 379 data_pub_class = None
370 380
371 381 exit_now = Bool(False)
372 382 exiter = Instance(ExitAutocall)
373 383 @default('exiter')
374 384 def _exiter_default(self):
375 385 return ExitAutocall(self)
376 386 # Monotonically increasing execution counter
377 387 execution_count = Integer(1)
378 388 filename = Unicode("<ipython console>")
379 389 ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__
380 390
381 391 # Used to transform cells before running them, and check whether code is complete
382 392 input_transformer_manager = Instance('IPython.core.inputtransformer2.TransformerManager',
383 393 ())
384 394
385 395 @property
386 396 def input_transformers_cleanup(self):
387 397 return self.input_transformer_manager.cleanup_transforms
388 398
389 399 input_transformers_post = List([],
390 400 help="A list of string input transformers, to be applied after IPython's "
391 401 "own input transformations."
392 402 )
393 403
394 404 @property
395 405 def input_splitter(self):
396 406 """Make this available for backward compatibility (pre-7.0 release) with existing code.
397 407
398 408 For example, ipykernel ipykernel currently uses
399 409 `shell.input_splitter.check_complete`
400 410 """
401 411 from warnings import warn
402 412 warn("`input_splitter` is deprecated since IPython 7.0, prefer `input_transformer_manager`.",
403 413 DeprecationWarning, stacklevel=2
404 414 )
405 415 return self.input_transformer_manager
406 416
407 417 logstart = Bool(False, help=
408 418 """
409 419 Start logging to the default log file in overwrite mode.
410 420 Use `logappend` to specify a log file to **append** logs to.
411 421 """
412 422 ).tag(config=True)
413 423 logfile = Unicode('', help=
414 424 """
415 425 The name of the logfile to use.
416 426 """
417 427 ).tag(config=True)
418 428 logappend = Unicode('', help=
419 429 """
420 430 Start logging to the given file in append mode.
421 431 Use `logfile` to specify a log file to **overwrite** logs to.
422 432 """
423 433 ).tag(config=True)
424 434 object_info_string_level = Enum((0,1,2), default_value=0,
425 435 ).tag(config=True)
426 436 pdb = Bool(False, help=
427 437 """
428 438 Automatically call the pdb debugger after every exception.
429 439 """
430 440 ).tag(config=True)
431 441 display_page = Bool(False,
432 442 help="""If True, anything that would be passed to the pager
433 443 will be displayed as regular output instead."""
434 444 ).tag(config=True)
435 445
436 446
437 447 show_rewritten_input = Bool(True,
438 448 help="Show rewritten input, e.g. for autocall."
439 449 ).tag(config=True)
440 450
441 451 quiet = Bool(False).tag(config=True)
442 452
443 453 history_length = Integer(10000,
444 454 help='Total length of command history'
445 455 ).tag(config=True)
446 456
447 457 history_load_length = Integer(1000, help=
448 458 """
449 459 The number of saved history entries to be loaded
450 460 into the history buffer at startup.
451 461 """
452 462 ).tag(config=True)
453 463
454 464 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'],
455 465 default_value='last_expr',
456 466 help="""
457 467 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying
458 468 which nodes should be run interactively (displaying output from expressions).
459 469 """
460 470 ).tag(config=True)
461 471
462 472 # TODO: this part of prompt management should be moved to the frontends.
463 473 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
464 474 separate_in = SeparateUnicode('\n').tag(config=True)
465 475 separate_out = SeparateUnicode('').tag(config=True)
466 476 separate_out2 = SeparateUnicode('').tag(config=True)
467 477 wildcards_case_sensitive = Bool(True).tag(config=True)
468 478 xmode = CaselessStrEnum(('Context', 'Plain', 'Verbose', 'Minimal'),
469 479 default_value='Context',
470 480 help="Switch modes for the IPython exception handlers."
471 481 ).tag(config=True)
472 482
473 483 # Subcomponents of InteractiveShell
474 484 alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True)
475 485 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
476 486 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap', allow_none=True)
477 487 display_trap = Instance('IPython.core.display_trap.DisplayTrap', allow_none=True)
478 488 extension_manager = Instance('IPython.core.extensions.ExtensionManager', allow_none=True)
479 489 payload_manager = Instance('IPython.core.payload.PayloadManager', allow_none=True)
480 490 history_manager = Instance('IPython.core.history.HistoryAccessorBase', allow_none=True)
481 491 magics_manager = Instance('IPython.core.magic.MagicsManager', allow_none=True)
482 492
483 493 profile_dir = Instance('IPython.core.application.ProfileDir', allow_none=True)
484 494 @property
485 495 def profile(self):
486 496 if self.profile_dir is not None:
487 497 name = os.path.basename(self.profile_dir.location)
488 498 return name.replace('profile_','')
489 499
490 500
491 501 # Private interface
492 502 _post_execute = Dict()
493 503
494 504 # Tracks any GUI loop loaded for pylab
495 505 pylab_gui_select = None
496 506
497 507 last_execution_succeeded = Bool(True, help='Did last executed command succeeded')
498 508
499 509 last_execution_result = Instance('IPython.core.interactiveshell.ExecutionResult', help='Result of executing the last command', allow_none=True)
500 510
501 511 def __init__(self, ipython_dir=None, profile_dir=None,
502 512 user_module=None, user_ns=None,
503 513 custom_exceptions=((), None), **kwargs):
504 514 # This is where traits with a config_key argument are updated
505 515 # from the values on config.
506 516 super(InteractiveShell, self).__init__(**kwargs)
507 517 if 'PromptManager' in self.config:
508 518 warn('As of IPython 5.0 `PromptManager` config will have no effect'
509 519 ' and has been replaced by TerminalInteractiveShell.prompts_class')
510 520 self.configurables = [self]
511 521
512 522 # These are relatively independent and stateless
513 523 self.init_ipython_dir(ipython_dir)
514 524 self.init_profile_dir(profile_dir)
515 525 self.init_instance_attrs()
516 526 self.init_environment()
517 527
518 528 # Check if we're in a virtualenv, and set up sys.path.
519 529 self.init_virtualenv()
520 530
521 531 # Create namespaces (user_ns, user_global_ns, etc.)
522 532 self.init_create_namespaces(user_module, user_ns)
523 533 # This has to be done after init_create_namespaces because it uses
524 534 # something in self.user_ns, but before init_sys_modules, which
525 535 # is the first thing to modify sys.
526 536 # TODO: When we override sys.stdout and sys.stderr before this class
527 537 # is created, we are saving the overridden ones here. Not sure if this
528 538 # is what we want to do.
529 539 self.save_sys_module_state()
530 540 self.init_sys_modules()
531 541
532 542 # While we're trying to have each part of the code directly access what
533 543 # it needs without keeping redundant references to objects, we have too
534 544 # much legacy code that expects ip.db to exist.
535 545 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
536 546
537 547 self.init_history()
538 548 self.init_encoding()
539 549 self.init_prefilter()
540 550
541 551 self.init_syntax_highlighting()
542 552 self.init_hooks()
543 553 self.init_events()
544 554 self.init_pushd_popd_magic()
545 555 self.init_user_ns()
546 556 self.init_logger()
547 557 self.init_builtins()
548 558
549 559 # The following was in post_config_initialization
550 560 self.init_inspector()
551 561 self.raw_input_original = input
552 562 self.init_completer()
553 563 # TODO: init_io() needs to happen before init_traceback handlers
554 564 # because the traceback handlers hardcode the stdout/stderr streams.
555 565 # This logic in in debugger.Pdb and should eventually be changed.
556 566 self.init_io()
557 567 self.init_traceback_handlers(custom_exceptions)
558 568 self.init_prompts()
559 569 self.init_display_formatter()
560 570 self.init_display_pub()
561 571 self.init_data_pub()
562 572 self.init_displayhook()
563 573 self.init_magics()
564 574 self.init_alias()
565 575 self.init_logstart()
566 576 self.init_pdb()
567 577 self.init_extension_manager()
568 578 self.init_payload()
569 579 self.events.trigger('shell_initialized', self)
570 580 atexit.register(self.atexit_operations)
571 581
572 582 # The trio runner is used for running Trio in the foreground thread. It
573 583 # is different from `_trio_runner(async_fn)` in `async_helpers.py`
574 584 # which calls `trio.run()` for every cell. This runner runs all cells
575 585 # inside a single Trio event loop. If used, it is set from
576 586 # `ipykernel.kernelapp`.
577 587 self.trio_runner = None
578 588
579 589 def get_ipython(self):
580 590 """Return the currently running IPython instance."""
581 591 return self
582 592
583 593 #-------------------------------------------------------------------------
584 594 # Trait changed handlers
585 595 #-------------------------------------------------------------------------
586 596 @observe('ipython_dir')
587 597 def _ipython_dir_changed(self, change):
588 598 ensure_dir_exists(change['new'])
589 599
590 600 def set_autoindent(self,value=None):
591 601 """Set the autoindent flag.
592 602
593 603 If called with no arguments, it acts as a toggle."""
594 604 if value is None:
595 605 self.autoindent = not self.autoindent
596 606 else:
597 607 self.autoindent = value
598 608
599 609 def set_trio_runner(self, tr):
600 610 self.trio_runner = tr
601 611
602 612 #-------------------------------------------------------------------------
603 613 # init_* methods called by __init__
604 614 #-------------------------------------------------------------------------
605 615
606 616 def init_ipython_dir(self, ipython_dir):
607 617 if ipython_dir is not None:
608 618 self.ipython_dir = ipython_dir
609 619 return
610 620
611 621 self.ipython_dir = get_ipython_dir()
612 622
613 623 def init_profile_dir(self, profile_dir):
614 624 if profile_dir is not None:
615 625 self.profile_dir = profile_dir
616 626 return
617 627 self.profile_dir = ProfileDir.create_profile_dir_by_name(
618 628 self.ipython_dir, "default"
619 629 )
620 630
621 631 def init_instance_attrs(self):
622 632 self.more = False
623 633
624 634 # command compiler
625 635 self.compile = self.compiler_class()
626 636
627 637 # Make an empty namespace, which extension writers can rely on both
628 638 # existing and NEVER being used by ipython itself. This gives them a
629 639 # convenient location for storing additional information and state
630 640 # their extensions may require, without fear of collisions with other
631 641 # ipython names that may develop later.
632 642 self.meta = Struct()
633 643
634 644 # Temporary files used for various purposes. Deleted at exit.
635 645 # The files here are stored with Path from Pathlib
636 646 self.tempfiles = []
637 647 self.tempdirs = []
638 648
639 649 # keep track of where we started running (mainly for crash post-mortem)
640 650 # This is not being used anywhere currently.
641 651 self.starting_dir = os.getcwd()
642 652
643 653 # Indentation management
644 654 self.indent_current_nsp = 0
645 655
646 656 # Dict to track post-execution functions that have been registered
647 657 self._post_execute = {}
648 658
649 659 def init_environment(self):
650 660 """Any changes we need to make to the user's environment."""
651 661 pass
652 662
653 663 def init_encoding(self):
654 664 # Get system encoding at startup time. Certain terminals (like Emacs
655 665 # under Win32 have it set to None, and we need to have a known valid
656 666 # encoding to use in the raw_input() method
657 667 try:
658 668 self.stdin_encoding = sys.stdin.encoding or 'ascii'
659 669 except AttributeError:
660 670 self.stdin_encoding = 'ascii'
661 671
662 672
663 673 @observe('colors')
664 674 def init_syntax_highlighting(self, changes=None):
665 675 # Python source parser/formatter for syntax highlighting
666 676 pyformat = PyColorize.Parser(style=self.colors, parent=self).format
667 677 self.pycolorize = lambda src: pyformat(src,'str')
668 678
669 679 def refresh_style(self):
670 680 # No-op here, used in subclass
671 681 pass
672 682
673 683 def init_pushd_popd_magic(self):
674 684 # for pushd/popd management
675 685 self.home_dir = get_home_dir()
676 686
677 687 self.dir_stack = []
678 688
679 689 def init_logger(self):
680 690 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
681 691 logmode='rotate')
682 692
683 693 def init_logstart(self):
684 694 """Initialize logging in case it was requested at the command line.
685 695 """
686 696 if self.logappend:
687 697 self.magic('logstart %s append' % self.logappend)
688 698 elif self.logfile:
689 699 self.magic('logstart %s' % self.logfile)
690 700 elif self.logstart:
691 701 self.magic('logstart')
692 702
693 703
694 704 def init_builtins(self):
695 705 # A single, static flag that we set to True. Its presence indicates
696 706 # that an IPython shell has been created, and we make no attempts at
697 707 # removing on exit or representing the existence of more than one
698 708 # IPython at a time.
699 709 builtin_mod.__dict__['__IPYTHON__'] = True
700 710 builtin_mod.__dict__['display'] = display
701 711
702 712 self.builtin_trap = BuiltinTrap(shell=self)
703 713
704 714 @observe('colors')
705 715 def init_inspector(self, changes=None):
706 716 # Object inspector
707 717 self.inspector = oinspect.Inspector(oinspect.InspectColors,
708 718 PyColorize.ANSICodeColors,
709 719 self.colors,
710 720 self.object_info_string_level)
711 721
712 722 def init_io(self):
713 723 # implemented in subclasses, TerminalInteractiveShell does call
714 724 # colorama.init().
715 725 pass
716 726
717 727 def init_prompts(self):
718 728 # Set system prompts, so that scripts can decide if they are running
719 729 # interactively.
720 730 sys.ps1 = 'In : '
721 731 sys.ps2 = '...: '
722 732 sys.ps3 = 'Out: '
723 733
724 734 def init_display_formatter(self):
725 735 self.display_formatter = DisplayFormatter(parent=self)
726 736 self.configurables.append(self.display_formatter)
727 737
728 738 def init_display_pub(self):
729 739 self.display_pub = self.display_pub_class(parent=self, shell=self)
730 740 self.configurables.append(self.display_pub)
731 741
732 742 def init_data_pub(self):
733 743 if not self.data_pub_class:
734 744 self.data_pub = None
735 745 return
736 746 self.data_pub = self.data_pub_class(parent=self)
737 747 self.configurables.append(self.data_pub)
738 748
739 749 def init_displayhook(self):
740 750 # Initialize displayhook, set in/out prompts and printing system
741 751 self.displayhook = self.displayhook_class(
742 752 parent=self,
743 753 shell=self,
744 754 cache_size=self.cache_size,
745 755 )
746 756 self.configurables.append(self.displayhook)
747 757 # This is a context manager that installs/revmoes the displayhook at
748 758 # the appropriate time.
749 759 self.display_trap = DisplayTrap(hook=self.displayhook)
750 760
751 761 def init_virtualenv(self):
752 762 """Add the current virtualenv to sys.path so the user can import modules from it.
753 763 This isn't perfect: it doesn't use the Python interpreter with which the
754 764 virtualenv was built, and it ignores the --no-site-packages option. A
755 765 warning will appear suggesting the user installs IPython in the
756 766 virtualenv, but for many cases, it probably works well enough.
757 767
758 768 Adapted from code snippets online.
759 769
760 770 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
761 771 """
762 772 if 'VIRTUAL_ENV' not in os.environ:
763 773 # Not in a virtualenv
764 774 return
765 775 elif os.environ["VIRTUAL_ENV"] == "":
766 776 warn("Virtual env path set to '', please check if this is intended.")
767 777 return
768 778
769 779 p = Path(sys.executable)
770 780 p_venv = Path(os.environ["VIRTUAL_ENV"])
771 781
772 782 # fallback venv detection:
773 783 # stdlib venv may symlink sys.executable, so we can't use realpath.
774 784 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
775 785 # So we just check every item in the symlink tree (generally <= 3)
776 786 paths = [p]
777 787 while p.is_symlink():
778 788 new_path = p.readlink()
779 789 if not new_path.is_absolute():
780 790 new_path = p.parent / new_path
781 791 p = new_path
782 792 paths.append(p)
783 793
784 794 # In Cygwin paths like "c:\..." and '\cygdrive\c\...' are possible
785 795 if p_venv.parts[1] == "cygdrive":
786 796 drive_name = p_venv.parts[2]
787 797 p_venv = (drive_name + ":/") / Path(*p_venv.parts[3:])
788 798
789 799 if any(p_venv == p.parents[1] for p in paths):
790 800 # Our exe is inside or has access to the virtualenv, don't need to do anything.
791 801 return
792 802
793 803 if sys.platform == "win32":
794 804 virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages"))
795 805 else:
796 806 virtual_env_path = Path(
797 807 os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages"
798 808 )
799 809 p_ver = sys.version_info[:2]
800 810
801 811 # Predict version from py[thon]-x.x in the $VIRTUAL_ENV
802 812 re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"])
803 813 if re_m:
804 814 predicted_path = Path(str(virtual_env_path).format(*re_m.groups()))
805 815 if predicted_path.exists():
806 816 p_ver = re_m.groups()
807 817
808 818 virtual_env = str(virtual_env_path).format(*p_ver)
809 819
810 820 warn(
811 821 "Attempting to work in a virtualenv. If you encounter problems, "
812 822 "please install IPython inside the virtualenv."
813 823 )
814 824 import site
815 825 sys.path.insert(0, virtual_env)
816 826 site.addsitedir(virtual_env)
817 827
818 828 #-------------------------------------------------------------------------
819 829 # Things related to injections into the sys module
820 830 #-------------------------------------------------------------------------
821 831
822 832 def save_sys_module_state(self):
823 833 """Save the state of hooks in the sys module.
824 834
825 835 This has to be called after self.user_module is created.
826 836 """
827 837 self._orig_sys_module_state = {'stdin': sys.stdin,
828 838 'stdout': sys.stdout,
829 839 'stderr': sys.stderr,
830 840 'excepthook': sys.excepthook}
831 841 self._orig_sys_modules_main_name = self.user_module.__name__
832 842 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
833 843
834 844 def restore_sys_module_state(self):
835 845 """Restore the state of the sys module."""
836 846 try:
837 847 for k, v in self._orig_sys_module_state.items():
838 848 setattr(sys, k, v)
839 849 except AttributeError:
840 850 pass
841 851 # Reset what what done in self.init_sys_modules
842 852 if self._orig_sys_modules_main_mod is not None:
843 853 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
844 854
845 855 #-------------------------------------------------------------------------
846 856 # Things related to the banner
847 857 #-------------------------------------------------------------------------
848 858
849 859 @property
850 860 def banner(self):
851 861 banner = self.banner1
852 862 if self.profile and self.profile != 'default':
853 863 banner += '\nIPython profile: %s\n' % self.profile
854 864 if self.banner2:
855 865 banner += '\n' + self.banner2
856 866 return banner
857 867
858 868 def show_banner(self, banner=None):
859 869 if banner is None:
860 870 banner = self.banner
861 871 sys.stdout.write(banner)
862 872
863 873 #-------------------------------------------------------------------------
864 874 # Things related to hooks
865 875 #-------------------------------------------------------------------------
866 876
867 877 def init_hooks(self):
868 878 # hooks holds pointers used for user-side customizations
869 879 self.hooks = Struct()
870 880
871 881 self.strdispatchers = {}
872 882
873 883 # Set all default hooks, defined in the IPython.hooks module.
874 884 hooks = IPython.core.hooks
875 885 for hook_name in hooks.__all__:
876 886 # default hooks have priority 100, i.e. low; user hooks should have
877 887 # 0-100 priority
878 888 self.set_hook(hook_name, getattr(hooks, hook_name), 100)
879 889
880 890 if self.display_page:
881 891 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
882 892
883 893 def set_hook(self, name, hook, priority=50, str_key=None, re_key=None):
884 894 """set_hook(name,hook) -> sets an internal IPython hook.
885 895
886 896 IPython exposes some of its internal API as user-modifiable hooks. By
887 897 adding your function to one of these hooks, you can modify IPython's
888 898 behavior to call at runtime your own routines."""
889 899
890 900 # At some point in the future, this should validate the hook before it
891 901 # accepts it. Probably at least check that the hook takes the number
892 902 # of args it's supposed to.
893 903
894 904 f = types.MethodType(hook,self)
895 905
896 906 # check if the hook is for strdispatcher first
897 907 if str_key is not None:
898 908 sdp = self.strdispatchers.get(name, StrDispatch())
899 909 sdp.add_s(str_key, f, priority )
900 910 self.strdispatchers[name] = sdp
901 911 return
902 912 if re_key is not None:
903 913 sdp = self.strdispatchers.get(name, StrDispatch())
904 914 sdp.add_re(re.compile(re_key), f, priority )
905 915 self.strdispatchers[name] = sdp
906 916 return
907 917
908 918 dp = getattr(self.hooks, name, None)
909 919 if name not in IPython.core.hooks.__all__:
910 920 print("Warning! Hook '%s' is not one of %s" % \
911 921 (name, IPython.core.hooks.__all__ ))
912 922
913 923 if name in IPython.core.hooks.deprecated:
914 924 alternative = IPython.core.hooks.deprecated[name]
915 925 raise ValueError(
916 926 "Hook {} has been deprecated since IPython 5.0. Use {} instead.".format(
917 927 name, alternative
918 928 )
919 929 )
920 930
921 931 if not dp:
922 932 dp = IPython.core.hooks.CommandChainDispatcher()
923 933
924 934 try:
925 935 dp.add(f,priority)
926 936 except AttributeError:
927 937 # it was not commandchain, plain old func - replace
928 938 dp = f
929 939
930 940 setattr(self.hooks,name, dp)
931 941
932 942 #-------------------------------------------------------------------------
933 943 # Things related to events
934 944 #-------------------------------------------------------------------------
935 945
936 946 def init_events(self):
937 947 self.events = EventManager(self, available_events)
938 948
939 949 self.events.register("pre_execute", self._clear_warning_registry)
940 950
941 951 def register_post_execute(self, func):
942 952 """DEPRECATED: Use ip.events.register('post_run_cell', func)
943 953
944 954 Register a function for calling after code execution.
945 955 """
946 956 raise ValueError(
947 957 "ip.register_post_execute is deprecated since IPython 1.0, use "
948 958 "ip.events.register('post_run_cell', func) instead."
949 959 )
950 960
951 961 def _clear_warning_registry(self):
952 962 # clear the warning registry, so that different code blocks with
953 963 # overlapping line number ranges don't cause spurious suppression of
954 964 # warnings (see gh-6611 for details)
955 965 if "__warningregistry__" in self.user_global_ns:
956 966 del self.user_global_ns["__warningregistry__"]
957 967
958 968 #-------------------------------------------------------------------------
959 969 # Things related to the "main" module
960 970 #-------------------------------------------------------------------------
961 971
962 972 def new_main_mod(self, filename, modname):
963 973 """Return a new 'main' module object for user code execution.
964 974
965 975 ``filename`` should be the path of the script which will be run in the
966 976 module. Requests with the same filename will get the same module, with
967 977 its namespace cleared.
968 978
969 979 ``modname`` should be the module name - normally either '__main__' or
970 980 the basename of the file without the extension.
971 981
972 982 When scripts are executed via %run, we must keep a reference to their
973 983 __main__ module around so that Python doesn't
974 984 clear it, rendering references to module globals useless.
975 985
976 986 This method keeps said reference in a private dict, keyed by the
977 987 absolute path of the script. This way, for multiple executions of the
978 988 same script we only keep one copy of the namespace (the last one),
979 989 thus preventing memory leaks from old references while allowing the
980 990 objects from the last execution to be accessible.
981 991 """
982 992 filename = os.path.abspath(filename)
983 993 try:
984 994 main_mod = self._main_mod_cache[filename]
985 995 except KeyError:
986 996 main_mod = self._main_mod_cache[filename] = types.ModuleType(
987 997 modname,
988 998 doc="Module created for script run in IPython")
989 999 else:
990 1000 main_mod.__dict__.clear()
991 1001 main_mod.__name__ = modname
992 1002
993 1003 main_mod.__file__ = filename
994 1004 # It seems pydoc (and perhaps others) needs any module instance to
995 1005 # implement a __nonzero__ method
996 1006 main_mod.__nonzero__ = lambda : True
997 1007
998 1008 return main_mod
999 1009
1000 1010 def clear_main_mod_cache(self):
1001 1011 """Clear the cache of main modules.
1002 1012
1003 1013 Mainly for use by utilities like %reset.
1004 1014
1005 1015 Examples
1006 1016 --------
1007 1017 In [15]: import IPython
1008 1018
1009 1019 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
1010 1020
1011 1021 In [17]: len(_ip._main_mod_cache) > 0
1012 1022 Out[17]: True
1013 1023
1014 1024 In [18]: _ip.clear_main_mod_cache()
1015 1025
1016 1026 In [19]: len(_ip._main_mod_cache) == 0
1017 1027 Out[19]: True
1018 1028 """
1019 1029 self._main_mod_cache.clear()
1020 1030
1021 1031 #-------------------------------------------------------------------------
1022 1032 # Things related to debugging
1023 1033 #-------------------------------------------------------------------------
1024 1034
1025 1035 def init_pdb(self):
1026 1036 # Set calling of pdb on exceptions
1027 1037 # self.call_pdb is a property
1028 1038 self.call_pdb = self.pdb
1029 1039
1030 1040 def _get_call_pdb(self):
1031 1041 return self._call_pdb
1032 1042
1033 1043 def _set_call_pdb(self,val):
1034 1044
1035 1045 if val not in (0,1,False,True):
1036 1046 raise ValueError('new call_pdb value must be boolean')
1037 1047
1038 1048 # store value in instance
1039 1049 self._call_pdb = val
1040 1050
1041 1051 # notify the actual exception handlers
1042 1052 self.InteractiveTB.call_pdb = val
1043 1053
1044 1054 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
1045 1055 'Control auto-activation of pdb at exceptions')
1046 1056
1047 1057 def debugger(self,force=False):
1048 1058 """Call the pdb debugger.
1049 1059
1050 1060 Keywords:
1051 1061
1052 1062 - force(False): by default, this routine checks the instance call_pdb
1053 1063 flag and does not actually invoke the debugger if the flag is false.
1054 1064 The 'force' option forces the debugger to activate even if the flag
1055 1065 is false.
1056 1066 """
1057 1067
1058 1068 if not (force or self.call_pdb):
1059 1069 return
1060 1070
1061 1071 if not hasattr(sys,'last_traceback'):
1062 1072 error('No traceback has been produced, nothing to debug.')
1063 1073 return
1064 1074
1065 1075 self.InteractiveTB.debugger(force=True)
1066 1076
1067 1077 #-------------------------------------------------------------------------
1068 1078 # Things related to IPython's various namespaces
1069 1079 #-------------------------------------------------------------------------
1070 1080 default_user_namespaces = True
1071 1081
1072 1082 def init_create_namespaces(self, user_module=None, user_ns=None):
1073 1083 # Create the namespace where the user will operate. user_ns is
1074 1084 # normally the only one used, and it is passed to the exec calls as
1075 1085 # the locals argument. But we do carry a user_global_ns namespace
1076 1086 # given as the exec 'globals' argument, This is useful in embedding
1077 1087 # situations where the ipython shell opens in a context where the
1078 1088 # distinction between locals and globals is meaningful. For
1079 1089 # non-embedded contexts, it is just the same object as the user_ns dict.
1080 1090
1081 1091 # FIXME. For some strange reason, __builtins__ is showing up at user
1082 1092 # level as a dict instead of a module. This is a manual fix, but I
1083 1093 # should really track down where the problem is coming from. Alex
1084 1094 # Schmolck reported this problem first.
1085 1095
1086 1096 # A useful post by Alex Martelli on this topic:
1087 1097 # Re: inconsistent value from __builtins__
1088 1098 # Von: Alex Martelli <aleaxit@yahoo.com>
1089 1099 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1090 1100 # Gruppen: comp.lang.python
1091 1101
1092 1102 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1093 1103 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1094 1104 # > <type 'dict'>
1095 1105 # > >>> print type(__builtins__)
1096 1106 # > <type 'module'>
1097 1107 # > Is this difference in return value intentional?
1098 1108
1099 1109 # Well, it's documented that '__builtins__' can be either a dictionary
1100 1110 # or a module, and it's been that way for a long time. Whether it's
1101 1111 # intentional (or sensible), I don't know. In any case, the idea is
1102 1112 # that if you need to access the built-in namespace directly, you
1103 1113 # should start with "import __builtin__" (note, no 's') which will
1104 1114 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1105 1115
1106 1116 # These routines return a properly built module and dict as needed by
1107 1117 # the rest of the code, and can also be used by extension writers to
1108 1118 # generate properly initialized namespaces.
1109 1119 if (user_ns is not None) or (user_module is not None):
1110 1120 self.default_user_namespaces = False
1111 1121 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1112 1122
1113 1123 # A record of hidden variables we have added to the user namespace, so
1114 1124 # we can list later only variables defined in actual interactive use.
1115 1125 self.user_ns_hidden = {}
1116 1126
1117 1127 # Now that FakeModule produces a real module, we've run into a nasty
1118 1128 # problem: after script execution (via %run), the module where the user
1119 1129 # code ran is deleted. Now that this object is a true module (needed
1120 1130 # so doctest and other tools work correctly), the Python module
1121 1131 # teardown mechanism runs over it, and sets to None every variable
1122 1132 # present in that module. Top-level references to objects from the
1123 1133 # script survive, because the user_ns is updated with them. However,
1124 1134 # calling functions defined in the script that use other things from
1125 1135 # the script will fail, because the function's closure had references
1126 1136 # to the original objects, which are now all None. So we must protect
1127 1137 # these modules from deletion by keeping a cache.
1128 1138 #
1129 1139 # To avoid keeping stale modules around (we only need the one from the
1130 1140 # last run), we use a dict keyed with the full path to the script, so
1131 1141 # only the last version of the module is held in the cache. Note,
1132 1142 # however, that we must cache the module *namespace contents* (their
1133 1143 # __dict__). Because if we try to cache the actual modules, old ones
1134 1144 # (uncached) could be destroyed while still holding references (such as
1135 1145 # those held by GUI objects that tend to be long-lived)>
1136 1146 #
1137 1147 # The %reset command will flush this cache. See the cache_main_mod()
1138 1148 # and clear_main_mod_cache() methods for details on use.
1139 1149
1140 1150 # This is the cache used for 'main' namespaces
1141 1151 self._main_mod_cache = {}
1142 1152
1143 1153 # A table holding all the namespaces IPython deals with, so that
1144 1154 # introspection facilities can search easily.
1145 1155 self.ns_table = {'user_global':self.user_module.__dict__,
1146 1156 'user_local':self.user_ns,
1147 1157 'builtin':builtin_mod.__dict__
1148 1158 }
1149 1159
1150 1160 @property
1151 1161 def user_global_ns(self):
1152 1162 return self.user_module.__dict__
1153 1163
1154 1164 def prepare_user_module(self, user_module=None, user_ns=None):
1155 1165 """Prepare the module and namespace in which user code will be run.
1156 1166
1157 1167 When IPython is started normally, both parameters are None: a new module
1158 1168 is created automatically, and its __dict__ used as the namespace.
1159 1169
1160 1170 If only user_module is provided, its __dict__ is used as the namespace.
1161 1171 If only user_ns is provided, a dummy module is created, and user_ns
1162 1172 becomes the global namespace. If both are provided (as they may be
1163 1173 when embedding), user_ns is the local namespace, and user_module
1164 1174 provides the global namespace.
1165 1175
1166 1176 Parameters
1167 1177 ----------
1168 1178 user_module : module, optional
1169 1179 The current user module in which IPython is being run. If None,
1170 1180 a clean module will be created.
1171 1181 user_ns : dict, optional
1172 1182 A namespace in which to run interactive commands.
1173 1183
1174 1184 Returns
1175 1185 -------
1176 1186 A tuple of user_module and user_ns, each properly initialised.
1177 1187 """
1178 1188 if user_module is None and user_ns is not None:
1179 1189 user_ns.setdefault("__name__", "__main__")
1180 1190 user_module = DummyMod()
1181 1191 user_module.__dict__ = user_ns
1182 1192
1183 1193 if user_module is None:
1184 1194 user_module = types.ModuleType("__main__",
1185 1195 doc="Automatically created module for IPython interactive environment")
1186 1196
1187 1197 # We must ensure that __builtin__ (without the final 's') is always
1188 1198 # available and pointing to the __builtin__ *module*. For more details:
1189 1199 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1190 1200 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1191 1201 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1192 1202
1193 1203 if user_ns is None:
1194 1204 user_ns = user_module.__dict__
1195 1205
1196 1206 return user_module, user_ns
1197 1207
1198 1208 def init_sys_modules(self):
1199 1209 # We need to insert into sys.modules something that looks like a
1200 1210 # module but which accesses the IPython namespace, for shelve and
1201 1211 # pickle to work interactively. Normally they rely on getting
1202 1212 # everything out of __main__, but for embedding purposes each IPython
1203 1213 # instance has its own private namespace, so we can't go shoving
1204 1214 # everything into __main__.
1205 1215
1206 1216 # note, however, that we should only do this for non-embedded
1207 1217 # ipythons, which really mimic the __main__.__dict__ with their own
1208 1218 # namespace. Embedded instances, on the other hand, should not do
1209 1219 # this because they need to manage the user local/global namespaces
1210 1220 # only, but they live within a 'normal' __main__ (meaning, they
1211 1221 # shouldn't overtake the execution environment of the script they're
1212 1222 # embedded in).
1213 1223
1214 1224 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1215 1225 main_name = self.user_module.__name__
1216 1226 sys.modules[main_name] = self.user_module
1217 1227
1218 1228 def init_user_ns(self):
1219 1229 """Initialize all user-visible namespaces to their minimum defaults.
1220 1230
1221 1231 Certain history lists are also initialized here, as they effectively
1222 1232 act as user namespaces.
1223 1233
1224 1234 Notes
1225 1235 -----
1226 1236 All data structures here are only filled in, they are NOT reset by this
1227 1237 method. If they were not empty before, data will simply be added to
1228 1238 them.
1229 1239 """
1230 1240 # This function works in two parts: first we put a few things in
1231 1241 # user_ns, and we sync that contents into user_ns_hidden so that these
1232 1242 # initial variables aren't shown by %who. After the sync, we add the
1233 1243 # rest of what we *do* want the user to see with %who even on a new
1234 1244 # session (probably nothing, so they really only see their own stuff)
1235 1245
1236 1246 # The user dict must *always* have a __builtin__ reference to the
1237 1247 # Python standard __builtin__ namespace, which must be imported.
1238 1248 # This is so that certain operations in prompt evaluation can be
1239 1249 # reliably executed with builtins. Note that we can NOT use
1240 1250 # __builtins__ (note the 's'), because that can either be a dict or a
1241 1251 # module, and can even mutate at runtime, depending on the context
1242 1252 # (Python makes no guarantees on it). In contrast, __builtin__ is
1243 1253 # always a module object, though it must be explicitly imported.
1244 1254
1245 1255 # For more details:
1246 1256 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1247 1257 ns = {}
1248 1258
1249 1259 # make global variables for user access to the histories
1250 1260 ns['_ih'] = self.history_manager.input_hist_parsed
1251 1261 ns['_oh'] = self.history_manager.output_hist
1252 1262 ns['_dh'] = self.history_manager.dir_hist
1253 1263
1254 1264 # user aliases to input and output histories. These shouldn't show up
1255 1265 # in %who, as they can have very large reprs.
1256 1266 ns['In'] = self.history_manager.input_hist_parsed
1257 1267 ns['Out'] = self.history_manager.output_hist
1258 1268
1259 1269 # Store myself as the public api!!!
1260 1270 ns['get_ipython'] = self.get_ipython
1261 1271
1262 1272 ns['exit'] = self.exiter
1263 1273 ns['quit'] = self.exiter
1264 1274
1265 1275 # Sync what we've added so far to user_ns_hidden so these aren't seen
1266 1276 # by %who
1267 1277 self.user_ns_hidden.update(ns)
1268 1278
1269 1279 # Anything put into ns now would show up in %who. Think twice before
1270 1280 # putting anything here, as we really want %who to show the user their
1271 1281 # stuff, not our variables.
1272 1282
1273 1283 # Finally, update the real user's namespace
1274 1284 self.user_ns.update(ns)
1275 1285
1276 1286 @property
1277 1287 def all_ns_refs(self):
1278 1288 """Get a list of references to all the namespace dictionaries in which
1279 1289 IPython might store a user-created object.
1280 1290
1281 1291 Note that this does not include the displayhook, which also caches
1282 1292 objects from the output."""
1283 1293 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1284 1294 [m.__dict__ for m in self._main_mod_cache.values()]
1285 1295
1286 1296 def reset(self, new_session=True, aggressive=False):
1287 1297 """Clear all internal namespaces, and attempt to release references to
1288 1298 user objects.
1289 1299
1290 1300 If new_session is True, a new history session will be opened.
1291 1301 """
1292 1302 # Clear histories
1293 1303 self.history_manager.reset(new_session)
1294 1304 # Reset counter used to index all histories
1295 1305 if new_session:
1296 1306 self.execution_count = 1
1297 1307
1298 1308 # Reset last execution result
1299 1309 self.last_execution_succeeded = True
1300 1310 self.last_execution_result = None
1301 1311
1302 1312 # Flush cached output items
1303 1313 if self.displayhook.do_full_cache:
1304 1314 self.displayhook.flush()
1305 1315
1306 1316 # The main execution namespaces must be cleared very carefully,
1307 1317 # skipping the deletion of the builtin-related keys, because doing so
1308 1318 # would cause errors in many object's __del__ methods.
1309 1319 if self.user_ns is not self.user_global_ns:
1310 1320 self.user_ns.clear()
1311 1321 ns = self.user_global_ns
1312 1322 drop_keys = set(ns.keys())
1313 1323 drop_keys.discard('__builtin__')
1314 1324 drop_keys.discard('__builtins__')
1315 1325 drop_keys.discard('__name__')
1316 1326 for k in drop_keys:
1317 1327 del ns[k]
1318 1328
1319 1329 self.user_ns_hidden.clear()
1320 1330
1321 1331 # Restore the user namespaces to minimal usability
1322 1332 self.init_user_ns()
1323 1333 if aggressive and not hasattr(self, "_sys_modules_keys"):
1324 1334 print("Cannot restore sys.module, no snapshot")
1325 1335 elif aggressive:
1326 1336 print("culling sys module...")
1327 1337 current_keys = set(sys.modules.keys())
1328 1338 for k in current_keys - self._sys_modules_keys:
1329 1339 if k.startswith("multiprocessing"):
1330 1340 continue
1331 1341 del sys.modules[k]
1332 1342
1333 1343 # Restore the default and user aliases
1334 1344 self.alias_manager.clear_aliases()
1335 1345 self.alias_manager.init_aliases()
1336 1346
1337 1347 # Now define aliases that only make sense on the terminal, because they
1338 1348 # need direct access to the console in a way that we can't emulate in
1339 1349 # GUI or web frontend
1340 1350 if os.name == 'posix':
1341 1351 for cmd in ('clear', 'more', 'less', 'man'):
1342 1352 if cmd not in self.magics_manager.magics['line']:
1343 1353 self.alias_manager.soft_define_alias(cmd, cmd)
1344 1354
1345 1355 # Flush the private list of module references kept for script
1346 1356 # execution protection
1347 1357 self.clear_main_mod_cache()
1348 1358
1349 1359 def del_var(self, varname, by_name=False):
1350 1360 """Delete a variable from the various namespaces, so that, as
1351 1361 far as possible, we're not keeping any hidden references to it.
1352 1362
1353 1363 Parameters
1354 1364 ----------
1355 1365 varname : str
1356 1366 The name of the variable to delete.
1357 1367 by_name : bool
1358 1368 If True, delete variables with the given name in each
1359 1369 namespace. If False (default), find the variable in the user
1360 1370 namespace, and delete references to it.
1361 1371 """
1362 1372 if varname in ('__builtin__', '__builtins__'):
1363 1373 raise ValueError("Refusing to delete %s" % varname)
1364 1374
1365 1375 ns_refs = self.all_ns_refs
1366 1376
1367 1377 if by_name: # Delete by name
1368 1378 for ns in ns_refs:
1369 1379 try:
1370 1380 del ns[varname]
1371 1381 except KeyError:
1372 1382 pass
1373 1383 else: # Delete by object
1374 1384 try:
1375 1385 obj = self.user_ns[varname]
1376 1386 except KeyError as e:
1377 1387 raise NameError("name '%s' is not defined" % varname) from e
1378 1388 # Also check in output history
1379 1389 ns_refs.append(self.history_manager.output_hist)
1380 1390 for ns in ns_refs:
1381 1391 to_delete = [n for n, o in ns.items() if o is obj]
1382 1392 for name in to_delete:
1383 1393 del ns[name]
1384 1394
1385 1395 # Ensure it is removed from the last execution result
1386 1396 if self.last_execution_result.result is obj:
1387 1397 self.last_execution_result = None
1388 1398
1389 1399 # displayhook keeps extra references, but not in a dictionary
1390 1400 for name in ('_', '__', '___'):
1391 1401 if getattr(self.displayhook, name) is obj:
1392 1402 setattr(self.displayhook, name, None)
1393 1403
1394 1404 def reset_selective(self, regex=None):
1395 1405 """Clear selective variables from internal namespaces based on a
1396 1406 specified regular expression.
1397 1407
1398 1408 Parameters
1399 1409 ----------
1400 1410 regex : string or compiled pattern, optional
1401 1411 A regular expression pattern that will be used in searching
1402 1412 variable names in the users namespaces.
1403 1413 """
1404 1414 if regex is not None:
1405 1415 try:
1406 1416 m = re.compile(regex)
1407 1417 except TypeError as e:
1408 1418 raise TypeError('regex must be a string or compiled pattern') from e
1409 1419 # Search for keys in each namespace that match the given regex
1410 1420 # If a match is found, delete the key/value pair.
1411 1421 for ns in self.all_ns_refs:
1412 1422 for var in ns:
1413 1423 if m.search(var):
1414 1424 del ns[var]
1415 1425
1416 1426 def push(self, variables, interactive=True):
1417 1427 """Inject a group of variables into the IPython user namespace.
1418 1428
1419 1429 Parameters
1420 1430 ----------
1421 1431 variables : dict, str or list/tuple of str
1422 1432 The variables to inject into the user's namespace. If a dict, a
1423 1433 simple update is done. If a str, the string is assumed to have
1424 1434 variable names separated by spaces. A list/tuple of str can also
1425 1435 be used to give the variable names. If just the variable names are
1426 1436 give (list/tuple/str) then the variable values looked up in the
1427 1437 callers frame.
1428 1438 interactive : bool
1429 1439 If True (default), the variables will be listed with the ``who``
1430 1440 magic.
1431 1441 """
1432 1442 vdict = None
1433 1443
1434 1444 # We need a dict of name/value pairs to do namespace updates.
1435 1445 if isinstance(variables, dict):
1436 1446 vdict = variables
1437 1447 elif isinstance(variables, (str, list, tuple)):
1438 1448 if isinstance(variables, str):
1439 1449 vlist = variables.split()
1440 1450 else:
1441 1451 vlist = variables
1442 1452 vdict = {}
1443 1453 cf = sys._getframe(1)
1444 1454 for name in vlist:
1445 1455 try:
1446 1456 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1447 1457 except:
1448 1458 print('Could not get variable %s from %s' %
1449 1459 (name,cf.f_code.co_name))
1450 1460 else:
1451 1461 raise ValueError('variables must be a dict/str/list/tuple')
1452 1462
1453 1463 # Propagate variables to user namespace
1454 1464 self.user_ns.update(vdict)
1455 1465
1456 1466 # And configure interactive visibility
1457 1467 user_ns_hidden = self.user_ns_hidden
1458 1468 if interactive:
1459 1469 for name in vdict:
1460 1470 user_ns_hidden.pop(name, None)
1461 1471 else:
1462 1472 user_ns_hidden.update(vdict)
1463 1473
1464 1474 def drop_by_id(self, variables):
1465 1475 """Remove a dict of variables from the user namespace, if they are the
1466 1476 same as the values in the dictionary.
1467 1477
1468 1478 This is intended for use by extensions: variables that they've added can
1469 1479 be taken back out if they are unloaded, without removing any that the
1470 1480 user has overwritten.
1471 1481
1472 1482 Parameters
1473 1483 ----------
1474 1484 variables : dict
1475 1485 A dictionary mapping object names (as strings) to the objects.
1476 1486 """
1477 1487 for name, obj in variables.items():
1478 1488 if name in self.user_ns and self.user_ns[name] is obj:
1479 1489 del self.user_ns[name]
1480 1490 self.user_ns_hidden.pop(name, None)
1481 1491
1482 1492 #-------------------------------------------------------------------------
1483 1493 # Things related to object introspection
1484 1494 #-------------------------------------------------------------------------
1485 1495
1486 1496 def _ofind(self, oname, namespaces=None):
1487 1497 """Find an object in the available namespaces.
1488 1498
1489 1499 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1490 1500
1491 1501 Has special code to detect magic functions.
1492 1502 """
1493 1503 oname = oname.strip()
1494 1504 if not oname.startswith(ESC_MAGIC) and \
1495 1505 not oname.startswith(ESC_MAGIC2) and \
1496 1506 not all(a.isidentifier() for a in oname.split(".")):
1497 1507 return {'found': False}
1498 1508
1499 1509 if namespaces is None:
1500 1510 # Namespaces to search in:
1501 1511 # Put them in a list. The order is important so that we
1502 1512 # find things in the same order that Python finds them.
1503 1513 namespaces = [ ('Interactive', self.user_ns),
1504 1514 ('Interactive (global)', self.user_global_ns),
1505 1515 ('Python builtin', builtin_mod.__dict__),
1506 1516 ]
1507 1517
1508 1518 ismagic = False
1509 1519 isalias = False
1510 1520 found = False
1511 1521 ospace = None
1512 1522 parent = None
1513 1523 obj = None
1514 1524
1515 1525
1516 1526 # Look for the given name by splitting it in parts. If the head is
1517 1527 # found, then we look for all the remaining parts as members, and only
1518 1528 # declare success if we can find them all.
1519 1529 oname_parts = oname.split('.')
1520 1530 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1521 1531 for nsname,ns in namespaces:
1522 1532 try:
1523 1533 obj = ns[oname_head]
1524 1534 except KeyError:
1525 1535 continue
1526 1536 else:
1527 1537 for idx, part in enumerate(oname_rest):
1528 1538 try:
1529 1539 parent = obj
1530 1540 # The last part is looked up in a special way to avoid
1531 1541 # descriptor invocation as it may raise or have side
1532 1542 # effects.
1533 1543 if idx == len(oname_rest) - 1:
1534 1544 obj = self._getattr_property(obj, part)
1535 1545 else:
1536 1546 obj = getattr(obj, part)
1537 1547 except:
1538 1548 # Blanket except b/c some badly implemented objects
1539 1549 # allow __getattr__ to raise exceptions other than
1540 1550 # AttributeError, which then crashes IPython.
1541 1551 break
1542 1552 else:
1543 1553 # If we finish the for loop (no break), we got all members
1544 1554 found = True
1545 1555 ospace = nsname
1546 1556 break # namespace loop
1547 1557
1548 1558 # Try to see if it's magic
1549 1559 if not found:
1550 1560 obj = None
1551 1561 if oname.startswith(ESC_MAGIC2):
1552 1562 oname = oname.lstrip(ESC_MAGIC2)
1553 1563 obj = self.find_cell_magic(oname)
1554 1564 elif oname.startswith(ESC_MAGIC):
1555 1565 oname = oname.lstrip(ESC_MAGIC)
1556 1566 obj = self.find_line_magic(oname)
1557 1567 else:
1558 1568 # search without prefix, so run? will find %run?
1559 1569 obj = self.find_line_magic(oname)
1560 1570 if obj is None:
1561 1571 obj = self.find_cell_magic(oname)
1562 1572 if obj is not None:
1563 1573 found = True
1564 1574 ospace = 'IPython internal'
1565 1575 ismagic = True
1566 1576 isalias = isinstance(obj, Alias)
1567 1577
1568 1578 # Last try: special-case some literals like '', [], {}, etc:
1569 1579 if not found and oname_head in ["''",'""','[]','{}','()']:
1570 1580 obj = eval(oname_head)
1571 1581 found = True
1572 1582 ospace = 'Interactive'
1573 1583
1574 1584 return {
1575 1585 'obj':obj,
1576 1586 'found':found,
1577 1587 'parent':parent,
1578 1588 'ismagic':ismagic,
1579 1589 'isalias':isalias,
1580 1590 'namespace':ospace
1581 1591 }
1582 1592
1583 1593 @staticmethod
1584 1594 def _getattr_property(obj, attrname):
1585 1595 """Property-aware getattr to use in object finding.
1586 1596
1587 1597 If attrname represents a property, return it unevaluated (in case it has
1588 1598 side effects or raises an error.
1589 1599
1590 1600 """
1591 1601 if not isinstance(obj, type):
1592 1602 try:
1593 1603 # `getattr(type(obj), attrname)` is not guaranteed to return
1594 1604 # `obj`, but does so for property:
1595 1605 #
1596 1606 # property.__get__(self, None, cls) -> self
1597 1607 #
1598 1608 # The universal alternative is to traverse the mro manually
1599 1609 # searching for attrname in class dicts.
1600 1610 attr = getattr(type(obj), attrname)
1601 1611 except AttributeError:
1602 1612 pass
1603 1613 else:
1604 1614 # This relies on the fact that data descriptors (with both
1605 1615 # __get__ & __set__ magic methods) take precedence over
1606 1616 # instance-level attributes:
1607 1617 #
1608 1618 # class A(object):
1609 1619 # @property
1610 1620 # def foobar(self): return 123
1611 1621 # a = A()
1612 1622 # a.__dict__['foobar'] = 345
1613 1623 # a.foobar # == 123
1614 1624 #
1615 1625 # So, a property may be returned right away.
1616 1626 if isinstance(attr, property):
1617 1627 return attr
1618 1628
1619 1629 # Nothing helped, fall back.
1620 1630 return getattr(obj, attrname)
1621 1631
1622 1632 def _object_find(self, oname, namespaces=None):
1623 1633 """Find an object and return a struct with info about it."""
1624 1634 return Struct(self._ofind(oname, namespaces))
1625 1635
1626 1636 def _inspect(self, meth, oname, namespaces=None, **kw):
1627 1637 """Generic interface to the inspector system.
1628 1638
1629 1639 This function is meant to be called by pdef, pdoc & friends.
1630 1640 """
1631 1641 info = self._object_find(oname, namespaces)
1632 1642 docformat = (
1633 1643 sphinxify(self.object_inspect(oname)) if self.sphinxify_docstring else None
1634 1644 )
1635 1645 if info.found:
1636 1646 pmethod = getattr(self.inspector, meth)
1637 1647 # TODO: only apply format_screen to the plain/text repr of the mime
1638 1648 # bundle.
1639 1649 formatter = format_screen if info.ismagic else docformat
1640 1650 if meth == 'pdoc':
1641 1651 pmethod(info.obj, oname, formatter)
1642 1652 elif meth == 'pinfo':
1643 1653 pmethod(
1644 1654 info.obj,
1645 1655 oname,
1646 1656 formatter,
1647 1657 info,
1648 1658 enable_html_pager=self.enable_html_pager,
1649 1659 **kw,
1650 1660 )
1651 1661 else:
1652 1662 pmethod(info.obj, oname)
1653 1663 else:
1654 1664 print('Object `%s` not found.' % oname)
1655 1665 return 'not found' # so callers can take other action
1656 1666
1657 1667 def object_inspect(self, oname, detail_level=0):
1658 1668 """Get object info about oname"""
1659 1669 with self.builtin_trap:
1660 1670 info = self._object_find(oname)
1661 1671 if info.found:
1662 1672 return self.inspector.info(info.obj, oname, info=info,
1663 1673 detail_level=detail_level
1664 1674 )
1665 1675 else:
1666 1676 return oinspect.object_info(name=oname, found=False)
1667 1677
1668 1678 def object_inspect_text(self, oname, detail_level=0):
1669 1679 """Get object info as formatted text"""
1670 1680 return self.object_inspect_mime(oname, detail_level)['text/plain']
1671 1681
1672 1682 def object_inspect_mime(self, oname, detail_level=0, omit_sections=()):
1673 1683 """Get object info as a mimebundle of formatted representations.
1674 1684
1675 1685 A mimebundle is a dictionary, keyed by mime-type.
1676 1686 It must always have the key `'text/plain'`.
1677 1687 """
1678 1688 with self.builtin_trap:
1679 1689 info = self._object_find(oname)
1680 1690 if info.found:
1681 1691 docformat = (
1682 1692 sphinxify(self.object_inspect(oname))
1683 1693 if self.sphinxify_docstring
1684 1694 else None
1685 1695 )
1686 1696 return self.inspector._get_info(
1687 1697 info.obj,
1688 1698 oname,
1689 1699 info=info,
1690 1700 detail_level=detail_level,
1691 1701 formatter=docformat,
1692 1702 omit_sections=omit_sections,
1693 1703 )
1694 1704 else:
1695 1705 raise KeyError(oname)
1696 1706
1697 1707 #-------------------------------------------------------------------------
1698 1708 # Things related to history management
1699 1709 #-------------------------------------------------------------------------
1700 1710
1701 1711 def init_history(self):
1702 1712 """Sets up the command history, and starts regular autosaves."""
1703 1713 self.history_manager = HistoryManager(shell=self, parent=self)
1704 1714 self.configurables.append(self.history_manager)
1705 1715
1706 1716 #-------------------------------------------------------------------------
1707 1717 # Things related to exception handling and tracebacks (not debugging)
1708 1718 #-------------------------------------------------------------------------
1709 1719
1710 1720 debugger_cls = InterruptiblePdb
1711 1721
1712 1722 def init_traceback_handlers(self, custom_exceptions):
1713 1723 # Syntax error handler.
1714 1724 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor', parent=self)
1715 1725
1716 1726 # The interactive one is initialized with an offset, meaning we always
1717 1727 # want to remove the topmost item in the traceback, which is our own
1718 1728 # internal code. Valid modes: ['Plain','Context','Verbose','Minimal']
1719 1729 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1720 1730 color_scheme='NoColor',
1721 1731 tb_offset = 1,
1722 1732 check_cache=check_linecache_ipython,
1723 1733 debugger_cls=self.debugger_cls, parent=self)
1724 1734
1725 1735 # The instance will store a pointer to the system-wide exception hook,
1726 1736 # so that runtime code (such as magics) can access it. This is because
1727 1737 # during the read-eval loop, it may get temporarily overwritten.
1728 1738 self.sys_excepthook = sys.excepthook
1729 1739
1730 1740 # and add any custom exception handlers the user may have specified
1731 1741 self.set_custom_exc(*custom_exceptions)
1732 1742
1733 1743 # Set the exception mode
1734 1744 self.InteractiveTB.set_mode(mode=self.xmode)
1735 1745
1736 1746 def set_custom_exc(self, exc_tuple, handler):
1737 1747 """set_custom_exc(exc_tuple, handler)
1738 1748
1739 1749 Set a custom exception handler, which will be called if any of the
1740 1750 exceptions in exc_tuple occur in the mainloop (specifically, in the
1741 1751 run_code() method).
1742 1752
1743 1753 Parameters
1744 1754 ----------
1745 1755 exc_tuple : tuple of exception classes
1746 1756 A *tuple* of exception classes, for which to call the defined
1747 1757 handler. It is very important that you use a tuple, and NOT A
1748 1758 LIST here, because of the way Python's except statement works. If
1749 1759 you only want to trap a single exception, use a singleton tuple::
1750 1760
1751 1761 exc_tuple == (MyCustomException,)
1752 1762
1753 1763 handler : callable
1754 1764 handler must have the following signature::
1755 1765
1756 1766 def my_handler(self, etype, value, tb, tb_offset=None):
1757 1767 ...
1758 1768 return structured_traceback
1759 1769
1760 1770 Your handler must return a structured traceback (a list of strings),
1761 1771 or None.
1762 1772
1763 1773 This will be made into an instance method (via types.MethodType)
1764 1774 of IPython itself, and it will be called if any of the exceptions
1765 1775 listed in the exc_tuple are caught. If the handler is None, an
1766 1776 internal basic one is used, which just prints basic info.
1767 1777
1768 1778 To protect IPython from crashes, if your handler ever raises an
1769 1779 exception or returns an invalid result, it will be immediately
1770 1780 disabled.
1771 1781
1772 1782 Notes
1773 1783 -----
1774 1784 WARNING: by putting in your own exception handler into IPython's main
1775 1785 execution loop, you run a very good chance of nasty crashes. This
1776 1786 facility should only be used if you really know what you are doing.
1777 1787 """
1778 1788
1779 1789 if not isinstance(exc_tuple, tuple):
1780 1790 raise TypeError("The custom exceptions must be given as a tuple.")
1781 1791
1782 1792 def dummy_handler(self, etype, value, tb, tb_offset=None):
1783 1793 print('*** Simple custom exception handler ***')
1784 1794 print('Exception type :', etype)
1785 1795 print('Exception value:', value)
1786 1796 print('Traceback :', tb)
1787 1797
1788 1798 def validate_stb(stb):
1789 1799 """validate structured traceback return type
1790 1800
1791 1801 return type of CustomTB *should* be a list of strings, but allow
1792 1802 single strings or None, which are harmless.
1793 1803
1794 1804 This function will *always* return a list of strings,
1795 1805 and will raise a TypeError if stb is inappropriate.
1796 1806 """
1797 1807 msg = "CustomTB must return list of strings, not %r" % stb
1798 1808 if stb is None:
1799 1809 return []
1800 1810 elif isinstance(stb, str):
1801 1811 return [stb]
1802 1812 elif not isinstance(stb, list):
1803 1813 raise TypeError(msg)
1804 1814 # it's a list
1805 1815 for line in stb:
1806 1816 # check every element
1807 1817 if not isinstance(line, str):
1808 1818 raise TypeError(msg)
1809 1819 return stb
1810 1820
1811 1821 if handler is None:
1812 1822 wrapped = dummy_handler
1813 1823 else:
1814 1824 def wrapped(self,etype,value,tb,tb_offset=None):
1815 1825 """wrap CustomTB handler, to protect IPython from user code
1816 1826
1817 1827 This makes it harder (but not impossible) for custom exception
1818 1828 handlers to crash IPython.
1819 1829 """
1820 1830 try:
1821 1831 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1822 1832 return validate_stb(stb)
1823 1833 except:
1824 1834 # clear custom handler immediately
1825 1835 self.set_custom_exc((), None)
1826 1836 print("Custom TB Handler failed, unregistering", file=sys.stderr)
1827 1837 # show the exception in handler first
1828 1838 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1829 1839 print(self.InteractiveTB.stb2text(stb))
1830 1840 print("The original exception:")
1831 1841 stb = self.InteractiveTB.structured_traceback(
1832 1842 (etype,value,tb), tb_offset=tb_offset
1833 1843 )
1834 1844 return stb
1835 1845
1836 1846 self.CustomTB = types.MethodType(wrapped,self)
1837 1847 self.custom_exceptions = exc_tuple
1838 1848
1839 1849 def excepthook(self, etype, value, tb):
1840 1850 """One more defense for GUI apps that call sys.excepthook.
1841 1851
1842 1852 GUI frameworks like wxPython trap exceptions and call
1843 1853 sys.excepthook themselves. I guess this is a feature that
1844 1854 enables them to keep running after exceptions that would
1845 1855 otherwise kill their mainloop. This is a bother for IPython
1846 1856 which expects to catch all of the program exceptions with a try:
1847 1857 except: statement.
1848 1858
1849 1859 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1850 1860 any app directly invokes sys.excepthook, it will look to the user like
1851 1861 IPython crashed. In order to work around this, we can disable the
1852 1862 CrashHandler and replace it with this excepthook instead, which prints a
1853 1863 regular traceback using our InteractiveTB. In this fashion, apps which
1854 1864 call sys.excepthook will generate a regular-looking exception from
1855 1865 IPython, and the CrashHandler will only be triggered by real IPython
1856 1866 crashes.
1857 1867
1858 1868 This hook should be used sparingly, only in places which are not likely
1859 1869 to be true IPython errors.
1860 1870 """
1861 1871 self.showtraceback((etype, value, tb), tb_offset=0)
1862 1872
1863 1873 def _get_exc_info(self, exc_tuple=None):
1864 1874 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1865 1875
1866 1876 Ensures sys.last_type,value,traceback hold the exc_info we found,
1867 1877 from whichever source.
1868 1878
1869 1879 raises ValueError if none of these contain any information
1870 1880 """
1871 1881 if exc_tuple is None:
1872 1882 etype, value, tb = sys.exc_info()
1873 1883 else:
1874 1884 etype, value, tb = exc_tuple
1875 1885
1876 1886 if etype is None:
1877 1887 if hasattr(sys, 'last_type'):
1878 1888 etype, value, tb = sys.last_type, sys.last_value, \
1879 1889 sys.last_traceback
1880 1890
1881 1891 if etype is None:
1882 1892 raise ValueError("No exception to find")
1883 1893
1884 1894 # Now store the exception info in sys.last_type etc.
1885 1895 # WARNING: these variables are somewhat deprecated and not
1886 1896 # necessarily safe to use in a threaded environment, but tools
1887 1897 # like pdb depend on their existence, so let's set them. If we
1888 1898 # find problems in the field, we'll need to revisit their use.
1889 1899 sys.last_type = etype
1890 1900 sys.last_value = value
1891 1901 sys.last_traceback = tb
1892 1902
1893 1903 return etype, value, tb
1894 1904
1895 1905 def show_usage_error(self, exc):
1896 1906 """Show a short message for UsageErrors
1897 1907
1898 1908 These are special exceptions that shouldn't show a traceback.
1899 1909 """
1900 1910 print("UsageError: %s" % exc, file=sys.stderr)
1901 1911
1902 1912 def get_exception_only(self, exc_tuple=None):
1903 1913 """
1904 1914 Return as a string (ending with a newline) the exception that
1905 1915 just occurred, without any traceback.
1906 1916 """
1907 1917 etype, value, tb = self._get_exc_info(exc_tuple)
1908 1918 msg = traceback.format_exception_only(etype, value)
1909 1919 return ''.join(msg)
1910 1920
1911 1921 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
1912 1922 exception_only=False, running_compiled_code=False):
1913 1923 """Display the exception that just occurred.
1914 1924
1915 1925 If nothing is known about the exception, this is the method which
1916 1926 should be used throughout the code for presenting user tracebacks,
1917 1927 rather than directly invoking the InteractiveTB object.
1918 1928
1919 1929 A specific showsyntaxerror() also exists, but this method can take
1920 1930 care of calling it if needed, so unless you are explicitly catching a
1921 1931 SyntaxError exception, don't try to analyze the stack manually and
1922 1932 simply call this method."""
1923 1933
1924 1934 try:
1925 1935 try:
1926 1936 etype, value, tb = self._get_exc_info(exc_tuple)
1927 1937 except ValueError:
1928 1938 print('No traceback available to show.', file=sys.stderr)
1929 1939 return
1930 1940
1931 1941 if issubclass(etype, SyntaxError):
1932 1942 # Though this won't be called by syntax errors in the input
1933 1943 # line, there may be SyntaxError cases with imported code.
1934 1944 self.showsyntaxerror(filename, running_compiled_code)
1935 1945 elif etype is UsageError:
1936 1946 self.show_usage_error(value)
1937 1947 else:
1938 1948 if exception_only:
1939 1949 stb = ['An exception has occurred, use %tb to see '
1940 1950 'the full traceback.\n']
1941 1951 stb.extend(self.InteractiveTB.get_exception_only(etype,
1942 1952 value))
1943 1953 else:
1944 1954 try:
1945 1955 # Exception classes can customise their traceback - we
1946 1956 # use this in IPython.parallel for exceptions occurring
1947 1957 # in the engines. This should return a list of strings.
1948 1958 stb = value._render_traceback_()
1949 1959 except Exception:
1950 1960 stb = self.InteractiveTB.structured_traceback(etype,
1951 1961 value, tb, tb_offset=tb_offset)
1952 1962
1953 1963 self._showtraceback(etype, value, stb)
1954 1964 if self.call_pdb:
1955 1965 # drop into debugger
1956 1966 self.debugger(force=True)
1957 1967 return
1958 1968
1959 1969 # Actually show the traceback
1960 1970 self._showtraceback(etype, value, stb)
1961 1971
1962 1972 except KeyboardInterrupt:
1963 1973 print('\n' + self.get_exception_only(), file=sys.stderr)
1964 1974
1965 1975 def _showtraceback(self, etype, evalue, stb: str):
1966 1976 """Actually show a traceback.
1967 1977
1968 1978 Subclasses may override this method to put the traceback on a different
1969 1979 place, like a side channel.
1970 1980 """
1971 1981 val = self.InteractiveTB.stb2text(stb)
1972 1982 try:
1973 1983 print(val)
1974 1984 except UnicodeEncodeError:
1975 1985 print(val.encode("utf-8", "backslashreplace").decode())
1976 1986
1977 1987 def showsyntaxerror(self, filename=None, running_compiled_code=False):
1978 1988 """Display the syntax error that just occurred.
1979 1989
1980 1990 This doesn't display a stack trace because there isn't one.
1981 1991
1982 1992 If a filename is given, it is stuffed in the exception instead
1983 1993 of what was there before (because Python's parser always uses
1984 1994 "<string>" when reading from a string).
1985 1995
1986 1996 If the syntax error occurred when running a compiled code (i.e. running_compile_code=True),
1987 1997 longer stack trace will be displayed.
1988 1998 """
1989 1999 etype, value, last_traceback = self._get_exc_info()
1990 2000
1991 2001 if filename and issubclass(etype, SyntaxError):
1992 2002 try:
1993 2003 value.filename = filename
1994 2004 except:
1995 2005 # Not the format we expect; leave it alone
1996 2006 pass
1997 2007
1998 2008 # If the error occurred when executing compiled code, we should provide full stacktrace.
1999 2009 elist = traceback.extract_tb(last_traceback) if running_compiled_code else []
2000 2010 stb = self.SyntaxTB.structured_traceback(etype, value, elist)
2001 2011 self._showtraceback(etype, value, stb)
2002 2012
2003 2013 # This is overridden in TerminalInteractiveShell to show a message about
2004 2014 # the %paste magic.
2005 2015 def showindentationerror(self):
2006 2016 """Called by _run_cell when there's an IndentationError in code entered
2007 2017 at the prompt.
2008 2018
2009 2019 This is overridden in TerminalInteractiveShell to show a message about
2010 2020 the %paste magic."""
2011 2021 self.showsyntaxerror()
2012 2022
2013 2023 @skip_doctest
2014 2024 def set_next_input(self, s, replace=False):
2015 2025 """ Sets the 'default' input string for the next command line.
2016 2026
2017 2027 Example::
2018 2028
2019 2029 In [1]: _ip.set_next_input("Hello Word")
2020 2030 In [2]: Hello Word_ # cursor is here
2021 2031 """
2022 2032 self.rl_next_input = s
2023 2033
2024 2034 def _indent_current_str(self):
2025 2035 """return the current level of indentation as a string"""
2026 2036 return self.input_splitter.get_indent_spaces() * ' '
2027 2037
2028 2038 #-------------------------------------------------------------------------
2029 2039 # Things related to text completion
2030 2040 #-------------------------------------------------------------------------
2031 2041
2032 2042 def init_completer(self):
2033 2043 """Initialize the completion machinery.
2034 2044
2035 2045 This creates completion machinery that can be used by client code,
2036 2046 either interactively in-process (typically triggered by the readline
2037 2047 library), programmatically (such as in test suites) or out-of-process
2038 2048 (typically over the network by remote frontends).
2039 2049 """
2040 2050 from IPython.core.completer import IPCompleter
2041 from IPython.core.completerlib import (module_completer,
2042 magic_run_completer, cd_completer, reset_completer)
2051 from IPython.core.completerlib import (
2052 cd_completer,
2053 magic_run_completer,
2054 module_completer,
2055 reset_completer,
2056 )
2043 2057
2044 2058 self.Completer = IPCompleter(shell=self,
2045 2059 namespace=self.user_ns,
2046 2060 global_namespace=self.user_global_ns,
2047 2061 parent=self,
2048 2062 )
2049 2063 self.configurables.append(self.Completer)
2050 2064
2051 2065 # Add custom completers to the basic ones built into IPCompleter
2052 2066 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2053 2067 self.strdispatchers['complete_command'] = sdisp
2054 2068 self.Completer.custom_completers = sdisp
2055 2069
2056 2070 self.set_hook('complete_command', module_completer, str_key = 'import')
2057 2071 self.set_hook('complete_command', module_completer, str_key = 'from')
2058 2072 self.set_hook('complete_command', module_completer, str_key = '%aimport')
2059 2073 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2060 2074 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2061 2075 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2062 2076
2063 2077 @skip_doctest
2064 2078 def complete(self, text, line=None, cursor_pos=None):
2065 2079 """Return the completed text and a list of completions.
2066 2080
2067 2081 Parameters
2068 2082 ----------
2069 2083 text : string
2070 2084 A string of text to be completed on. It can be given as empty and
2071 2085 instead a line/position pair are given. In this case, the
2072 2086 completer itself will split the line like readline does.
2073 2087 line : string, optional
2074 2088 The complete line that text is part of.
2075 2089 cursor_pos : int, optional
2076 2090 The position of the cursor on the input line.
2077 2091
2078 2092 Returns
2079 2093 -------
2080 2094 text : string
2081 2095 The actual text that was completed.
2082 2096 matches : list
2083 2097 A sorted list with all possible completions.
2084 2098
2085 2099 Notes
2086 2100 -----
2087 2101 The optional arguments allow the completion to take more context into
2088 2102 account, and are part of the low-level completion API.
2089 2103
2090 2104 This is a wrapper around the completion mechanism, similar to what
2091 2105 readline does at the command line when the TAB key is hit. By
2092 2106 exposing it as a method, it can be used by other non-readline
2093 2107 environments (such as GUIs) for text completion.
2094 2108
2095 2109 Examples
2096 2110 --------
2097 2111 In [1]: x = 'hello'
2098 2112
2099 2113 In [2]: _ip.complete('x.l')
2100 2114 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2101 2115 """
2102 2116
2103 2117 # Inject names into __builtin__ so we can complete on the added names.
2104 2118 with self.builtin_trap:
2105 2119 return self.Completer.complete(text, line, cursor_pos)
2106 2120
2107 2121 def set_custom_completer(self, completer, pos=0) -> None:
2108 2122 """Adds a new custom completer function.
2109 2123
2110 2124 The position argument (defaults to 0) is the index in the completers
2111 2125 list where you want the completer to be inserted.
2112 2126
2113 2127 `completer` should have the following signature::
2114 2128
2115 2129 def completion(self: Completer, text: string) -> List[str]:
2116 2130 raise NotImplementedError
2117 2131
2118 2132 It will be bound to the current Completer instance and pass some text
2119 2133 and return a list with current completions to suggest to the user.
2120 2134 """
2121 2135
2122 2136 newcomp = types.MethodType(completer, self.Completer)
2123 2137 self.Completer.custom_matchers.insert(pos,newcomp)
2124 2138
2125 2139 def set_completer_frame(self, frame=None):
2126 2140 """Set the frame of the completer."""
2127 2141 if frame:
2128 2142 self.Completer.namespace = frame.f_locals
2129 2143 self.Completer.global_namespace = frame.f_globals
2130 2144 else:
2131 2145 self.Completer.namespace = self.user_ns
2132 2146 self.Completer.global_namespace = self.user_global_ns
2133 2147
2134 2148 #-------------------------------------------------------------------------
2135 2149 # Things related to magics
2136 2150 #-------------------------------------------------------------------------
2137 2151
2138 2152 def init_magics(self):
2139 2153 from IPython.core import magics as m
2140 2154 self.magics_manager = magic.MagicsManager(shell=self,
2141 2155 parent=self,
2142 2156 user_magics=m.UserMagics(self))
2143 2157 self.configurables.append(self.magics_manager)
2144 2158
2145 2159 # Expose as public API from the magics manager
2146 2160 self.register_magics = self.magics_manager.register
2147 2161
2148 2162 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2149 2163 m.ConfigMagics, m.DisplayMagics, m.ExecutionMagics,
2150 2164 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2151 2165 m.NamespaceMagics, m.OSMagics, m.PackagingMagics,
2152 2166 m.PylabMagics, m.ScriptMagics,
2153 2167 )
2154 2168 self.register_magics(m.AsyncMagics)
2155 2169
2156 2170 # Register Magic Aliases
2157 2171 mman = self.magics_manager
2158 2172 # FIXME: magic aliases should be defined by the Magics classes
2159 2173 # or in MagicsManager, not here
2160 2174 mman.register_alias('ed', 'edit')
2161 2175 mman.register_alias('hist', 'history')
2162 2176 mman.register_alias('rep', 'recall')
2163 2177 mman.register_alias('SVG', 'svg', 'cell')
2164 2178 mman.register_alias('HTML', 'html', 'cell')
2165 2179 mman.register_alias('file', 'writefile', 'cell')
2166 2180
2167 2181 # FIXME: Move the color initialization to the DisplayHook, which
2168 2182 # should be split into a prompt manager and displayhook. We probably
2169 2183 # even need a centralize colors management object.
2170 2184 self.run_line_magic('colors', self.colors)
2171 2185
2172 2186 # Defined here so that it's included in the documentation
2173 2187 @functools.wraps(magic.MagicsManager.register_function)
2174 2188 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2175 2189 self.magics_manager.register_function(
2176 2190 func, magic_kind=magic_kind, magic_name=magic_name
2177 2191 )
2178 2192
2179 2193 def _find_with_lazy_load(self, /, type_, magic_name: str):
2180 2194 """
2181 2195 Try to find a magic potentially lazy-loading it.
2182 2196
2183 2197 Parameters
2184 2198 ----------
2185 2199
2186 2200 type_: "line"|"cell"
2187 2201 the type of magics we are trying to find/lazy load.
2188 2202 magic_name: str
2189 2203 The name of the magic we are trying to find/lazy load
2190 2204
2191 2205
2192 2206 Note that this may have any side effects
2193 2207 """
2194 2208 finder = {"line": self.find_line_magic, "cell": self.find_cell_magic}[type_]
2195 2209 fn = finder(magic_name)
2196 2210 if fn is not None:
2197 2211 return fn
2198 2212 lazy = self.magics_manager.lazy_magics.get(magic_name)
2199 2213 if lazy is None:
2200 2214 return None
2201 2215
2202 2216 self.run_line_magic("load_ext", lazy)
2203 2217 res = finder(magic_name)
2204 2218 return res
2205 2219
2206 2220 def run_line_magic(self, magic_name: str, line, _stack_depth=1):
2207 2221 """Execute the given line magic.
2208 2222
2209 2223 Parameters
2210 2224 ----------
2211 2225 magic_name : str
2212 2226 Name of the desired magic function, without '%' prefix.
2213 2227 line : str
2214 2228 The rest of the input line as a single string.
2215 2229 _stack_depth : int
2216 2230 If run_line_magic() is called from magic() then _stack_depth=2.
2217 2231 This is added to ensure backward compatibility for use of 'get_ipython().magic()'
2218 2232 """
2219 2233 fn = self._find_with_lazy_load("line", magic_name)
2220 2234 if fn is None:
2221 2235 lazy = self.magics_manager.lazy_magics.get(magic_name)
2222 2236 if lazy:
2223 2237 self.run_line_magic("load_ext", lazy)
2224 2238 fn = self.find_line_magic(magic_name)
2225 2239 if fn is None:
2226 2240 cm = self.find_cell_magic(magic_name)
2227 2241 etpl = "Line magic function `%%%s` not found%s."
2228 2242 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2229 2243 'did you mean that instead?)' % magic_name )
2230 2244 raise UsageError(etpl % (magic_name, extra))
2231 2245 else:
2232 2246 # Note: this is the distance in the stack to the user's frame.
2233 2247 # This will need to be updated if the internal calling logic gets
2234 2248 # refactored, or else we'll be expanding the wrong variables.
2235 2249
2236 2250 # Determine stack_depth depending on where run_line_magic() has been called
2237 2251 stack_depth = _stack_depth
2238 2252 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2239 2253 # magic has opted out of var_expand
2240 2254 magic_arg_s = line
2241 2255 else:
2242 2256 magic_arg_s = self.var_expand(line, stack_depth)
2243 2257 # Put magic args in a list so we can call with f(*a) syntax
2244 2258 args = [magic_arg_s]
2245 2259 kwargs = {}
2246 2260 # Grab local namespace if we need it:
2247 2261 if getattr(fn, "needs_local_scope", False):
2248 2262 kwargs['local_ns'] = self.get_local_scope(stack_depth)
2249 2263 with self.builtin_trap:
2250 2264 result = fn(*args, **kwargs)
2251 2265 return result
2252 2266
2253 2267 def get_local_scope(self, stack_depth):
2254 2268 """Get local scope at given stack depth.
2255 2269
2256 2270 Parameters
2257 2271 ----------
2258 2272 stack_depth : int
2259 2273 Depth relative to calling frame
2260 2274 """
2261 2275 return sys._getframe(stack_depth + 1).f_locals
2262 2276
2263 2277 def run_cell_magic(self, magic_name, line, cell):
2264 2278 """Execute the given cell magic.
2265 2279
2266 2280 Parameters
2267 2281 ----------
2268 2282 magic_name : str
2269 2283 Name of the desired magic function, without '%' prefix.
2270 2284 line : str
2271 2285 The rest of the first input line as a single string.
2272 2286 cell : str
2273 2287 The body of the cell as a (possibly multiline) string.
2274 2288 """
2275 2289 fn = self._find_with_lazy_load("cell", magic_name)
2276 2290 if fn is None:
2277 2291 lm = self.find_line_magic(magic_name)
2278 2292 etpl = "Cell magic `%%{0}` not found{1}."
2279 2293 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2280 2294 'did you mean that instead?)'.format(magic_name))
2281 2295 raise UsageError(etpl.format(magic_name, extra))
2282 2296 elif cell == '':
2283 2297 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2284 2298 if self.find_line_magic(magic_name) is not None:
2285 2299 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2286 2300 raise UsageError(message)
2287 2301 else:
2288 2302 # Note: this is the distance in the stack to the user's frame.
2289 2303 # This will need to be updated if the internal calling logic gets
2290 2304 # refactored, or else we'll be expanding the wrong variables.
2291 2305 stack_depth = 2
2292 2306 if getattr(fn, magic.MAGIC_NO_VAR_EXPAND_ATTR, False):
2293 2307 # magic has opted out of var_expand
2294 2308 magic_arg_s = line
2295 2309 else:
2296 2310 magic_arg_s = self.var_expand(line, stack_depth)
2297 2311 kwargs = {}
2298 2312 if getattr(fn, "needs_local_scope", False):
2299 2313 kwargs['local_ns'] = self.user_ns
2300 2314
2301 2315 with self.builtin_trap:
2302 2316 args = (magic_arg_s, cell)
2303 2317 result = fn(*args, **kwargs)
2304 2318 return result
2305 2319
2306 2320 def find_line_magic(self, magic_name):
2307 2321 """Find and return a line magic by name.
2308 2322
2309 2323 Returns None if the magic isn't found."""
2310 2324 return self.magics_manager.magics['line'].get(magic_name)
2311 2325
2312 2326 def find_cell_magic(self, magic_name):
2313 2327 """Find and return a cell magic by name.
2314 2328
2315 2329 Returns None if the magic isn't found."""
2316 2330 return self.magics_manager.magics['cell'].get(magic_name)
2317 2331
2318 2332 def find_magic(self, magic_name, magic_kind='line'):
2319 2333 """Find and return a magic of the given type by name.
2320 2334
2321 2335 Returns None if the magic isn't found."""
2322 2336 return self.magics_manager.magics[magic_kind].get(magic_name)
2323 2337
2324 2338 def magic(self, arg_s):
2325 2339 """
2326 2340 DEPRECATED
2327 2341
2328 2342 Deprecated since IPython 0.13 (warning added in
2329 2343 8.1), use run_line_magic(magic_name, parameter_s).
2330 2344
2331 2345 Call a magic function by name.
2332 2346
2333 2347 Input: a string containing the name of the magic function to call and
2334 2348 any additional arguments to be passed to the magic.
2335 2349
2336 2350 magic('name -opt foo bar') is equivalent to typing at the ipython
2337 2351 prompt:
2338 2352
2339 2353 In[1]: %name -opt foo bar
2340 2354
2341 2355 To call a magic without arguments, simply use magic('name').
2342 2356
2343 2357 This provides a proper Python function to call IPython's magics in any
2344 2358 valid Python code you can type at the interpreter, including loops and
2345 2359 compound statements.
2346 2360 """
2347 2361 warnings.warn(
2348 2362 "`magic(...)` is deprecated since IPython 0.13 (warning added in "
2349 2363 "8.1), use run_line_magic(magic_name, parameter_s).",
2350 2364 DeprecationWarning,
2351 2365 stacklevel=2,
2352 2366 )
2353 2367 # TODO: should we issue a loud deprecation warning here?
2354 2368 magic_name, _, magic_arg_s = arg_s.partition(' ')
2355 2369 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2356 2370 return self.run_line_magic(magic_name, magic_arg_s, _stack_depth=2)
2357 2371
2358 2372 #-------------------------------------------------------------------------
2359 2373 # Things related to macros
2360 2374 #-------------------------------------------------------------------------
2361 2375
2362 2376 def define_macro(self, name, themacro):
2363 2377 """Define a new macro
2364 2378
2365 2379 Parameters
2366 2380 ----------
2367 2381 name : str
2368 2382 The name of the macro.
2369 2383 themacro : str or Macro
2370 2384 The action to do upon invoking the macro. If a string, a new
2371 2385 Macro object is created by passing the string to it.
2372 2386 """
2373 2387
2374 2388 from IPython.core import macro
2375 2389
2376 2390 if isinstance(themacro, str):
2377 2391 themacro = macro.Macro(themacro)
2378 2392 if not isinstance(themacro, macro.Macro):
2379 2393 raise ValueError('A macro must be a string or a Macro instance.')
2380 2394 self.user_ns[name] = themacro
2381 2395
2382 2396 #-------------------------------------------------------------------------
2383 2397 # Things related to the running of system commands
2384 2398 #-------------------------------------------------------------------------
2385 2399
2386 2400 def system_piped(self, cmd):
2387 2401 """Call the given cmd in a subprocess, piping stdout/err
2388 2402
2389 2403 Parameters
2390 2404 ----------
2391 2405 cmd : str
2392 2406 Command to execute (can not end in '&', as background processes are
2393 2407 not supported. Should not be a command that expects input
2394 2408 other than simple text.
2395 2409 """
2396 2410 if cmd.rstrip().endswith('&'):
2397 2411 # this is *far* from a rigorous test
2398 2412 # We do not support backgrounding processes because we either use
2399 2413 # pexpect or pipes to read from. Users can always just call
2400 2414 # os.system() or use ip.system=ip.system_raw
2401 2415 # if they really want a background process.
2402 2416 raise OSError("Background processes not supported.")
2403 2417
2404 2418 # we explicitly do NOT return the subprocess status code, because
2405 2419 # a non-None value would trigger :func:`sys.displayhook` calls.
2406 2420 # Instead, we store the exit_code in user_ns.
2407 2421 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2408 2422
2409 2423 def system_raw(self, cmd):
2410 2424 """Call the given cmd in a subprocess using os.system on Windows or
2411 2425 subprocess.call using the system shell on other platforms.
2412 2426
2413 2427 Parameters
2414 2428 ----------
2415 2429 cmd : str
2416 2430 Command to execute.
2417 2431 """
2418 2432 cmd = self.var_expand(cmd, depth=1)
2419 2433 # warn if there is an IPython magic alternative.
2420 2434 main_cmd = cmd.split()[0]
2421 2435 has_magic_alternatives = ("pip", "conda", "cd")
2422 2436
2423 2437 if main_cmd in has_magic_alternatives:
2424 2438 warnings.warn(
2425 2439 (
2426 2440 "You executed the system command !{0} which may not work "
2427 2441 "as expected. Try the IPython magic %{0} instead."
2428 2442 ).format(main_cmd)
2429 2443 )
2430 2444
2431 2445 # protect os.system from UNC paths on Windows, which it can't handle:
2432 2446 if sys.platform == 'win32':
2433 2447 from IPython.utils._process_win32 import AvoidUNCPath
2434 2448 with AvoidUNCPath() as path:
2435 2449 if path is not None:
2436 2450 cmd = '"pushd %s &&"%s' % (path, cmd)
2437 2451 try:
2438 2452 ec = os.system(cmd)
2439 2453 except KeyboardInterrupt:
2440 2454 print('\n' + self.get_exception_only(), file=sys.stderr)
2441 2455 ec = -2
2442 2456 else:
2443 2457 # For posix the result of the subprocess.call() below is an exit
2444 2458 # code, which by convention is zero for success, positive for
2445 2459 # program failure. Exit codes above 128 are reserved for signals,
2446 2460 # and the formula for converting a signal to an exit code is usually
2447 2461 # signal_number+128. To more easily differentiate between exit
2448 2462 # codes and signals, ipython uses negative numbers. For instance
2449 2463 # since control-c is signal 2 but exit code 130, ipython's
2450 2464 # _exit_code variable will read -2. Note that some shells like
2451 2465 # csh and fish don't follow sh/bash conventions for exit codes.
2452 2466 executable = os.environ.get('SHELL', None)
2453 2467 try:
2454 2468 # Use env shell instead of default /bin/sh
2455 2469 ec = subprocess.call(cmd, shell=True, executable=executable)
2456 2470 except KeyboardInterrupt:
2457 2471 # intercept control-C; a long traceback is not useful here
2458 2472 print('\n' + self.get_exception_only(), file=sys.stderr)
2459 2473 ec = 130
2460 2474 if ec > 128:
2461 2475 ec = -(ec - 128)
2462 2476
2463 2477 # We explicitly do NOT return the subprocess status code, because
2464 2478 # a non-None value would trigger :func:`sys.displayhook` calls.
2465 2479 # Instead, we store the exit_code in user_ns. Note the semantics
2466 2480 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2467 2481 # but raising SystemExit(_exit_code) will give status 254!
2468 2482 self.user_ns['_exit_code'] = ec
2469 2483
2470 2484 # use piped system by default, because it is better behaved
2471 2485 system = system_piped
2472 2486
2473 2487 def getoutput(self, cmd, split=True, depth=0):
2474 2488 """Get output (possibly including stderr) from a subprocess.
2475 2489
2476 2490 Parameters
2477 2491 ----------
2478 2492 cmd : str
2479 2493 Command to execute (can not end in '&', as background processes are
2480 2494 not supported.
2481 2495 split : bool, optional
2482 2496 If True, split the output into an IPython SList. Otherwise, an
2483 2497 IPython LSString is returned. These are objects similar to normal
2484 2498 lists and strings, with a few convenience attributes for easier
2485 2499 manipulation of line-based output. You can use '?' on them for
2486 2500 details.
2487 2501 depth : int, optional
2488 2502 How many frames above the caller are the local variables which should
2489 2503 be expanded in the command string? The default (0) assumes that the
2490 2504 expansion variables are in the stack frame calling this function.
2491 2505 """
2492 2506 if cmd.rstrip().endswith('&'):
2493 2507 # this is *far* from a rigorous test
2494 2508 raise OSError("Background processes not supported.")
2495 2509 out = getoutput(self.var_expand(cmd, depth=depth+1))
2496 2510 if split:
2497 2511 out = SList(out.splitlines())
2498 2512 else:
2499 2513 out = LSString(out)
2500 2514 return out
2501 2515
2502 2516 #-------------------------------------------------------------------------
2503 2517 # Things related to aliases
2504 2518 #-------------------------------------------------------------------------
2505 2519
2506 2520 def init_alias(self):
2507 2521 self.alias_manager = AliasManager(shell=self, parent=self)
2508 2522 self.configurables.append(self.alias_manager)
2509 2523
2510 2524 #-------------------------------------------------------------------------
2511 2525 # Things related to extensions
2512 2526 #-------------------------------------------------------------------------
2513 2527
2514 2528 def init_extension_manager(self):
2515 2529 self.extension_manager = ExtensionManager(shell=self, parent=self)
2516 2530 self.configurables.append(self.extension_manager)
2517 2531
2518 2532 #-------------------------------------------------------------------------
2519 2533 # Things related to payloads
2520 2534 #-------------------------------------------------------------------------
2521 2535
2522 2536 def init_payload(self):
2523 2537 self.payload_manager = PayloadManager(parent=self)
2524 2538 self.configurables.append(self.payload_manager)
2525 2539
2526 2540 #-------------------------------------------------------------------------
2527 2541 # Things related to the prefilter
2528 2542 #-------------------------------------------------------------------------
2529 2543
2530 2544 def init_prefilter(self):
2531 2545 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2532 2546 self.configurables.append(self.prefilter_manager)
2533 2547 # Ultimately this will be refactored in the new interpreter code, but
2534 2548 # for now, we should expose the main prefilter method (there's legacy
2535 2549 # code out there that may rely on this).
2536 2550 self.prefilter = self.prefilter_manager.prefilter_lines
2537 2551
2538 2552 def auto_rewrite_input(self, cmd):
2539 2553 """Print to the screen the rewritten form of the user's command.
2540 2554
2541 2555 This shows visual feedback by rewriting input lines that cause
2542 2556 automatic calling to kick in, like::
2543 2557
2544 2558 /f x
2545 2559
2546 2560 into::
2547 2561
2548 2562 ------> f(x)
2549 2563
2550 2564 after the user's input prompt. This helps the user understand that the
2551 2565 input line was transformed automatically by IPython.
2552 2566 """
2553 2567 if not self.show_rewritten_input:
2554 2568 return
2555 2569
2556 2570 # This is overridden in TerminalInteractiveShell to use fancy prompts
2557 2571 print("------> " + cmd)
2558 2572
2559 2573 #-------------------------------------------------------------------------
2560 2574 # Things related to extracting values/expressions from kernel and user_ns
2561 2575 #-------------------------------------------------------------------------
2562 2576
2563 2577 def _user_obj_error(self):
2564 2578 """return simple exception dict
2565 2579
2566 2580 for use in user_expressions
2567 2581 """
2568 2582
2569 2583 etype, evalue, tb = self._get_exc_info()
2570 2584 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2571 2585
2572 2586 exc_info = {
2573 2587 "status": "error",
2574 2588 "traceback": stb,
2575 2589 "ename": etype.__name__,
2576 2590 "evalue": py3compat.safe_unicode(evalue),
2577 2591 }
2578 2592
2579 2593 return exc_info
2580 2594
2581 2595 def _format_user_obj(self, obj):
2582 2596 """format a user object to display dict
2583 2597
2584 2598 for use in user_expressions
2585 2599 """
2586 2600
2587 2601 data, md = self.display_formatter.format(obj)
2588 2602 value = {
2589 2603 'status' : 'ok',
2590 2604 'data' : data,
2591 2605 'metadata' : md,
2592 2606 }
2593 2607 return value
2594 2608
2595 2609 def user_expressions(self, expressions):
2596 2610 """Evaluate a dict of expressions in the user's namespace.
2597 2611
2598 2612 Parameters
2599 2613 ----------
2600 2614 expressions : dict
2601 2615 A dict with string keys and string values. The expression values
2602 2616 should be valid Python expressions, each of which will be evaluated
2603 2617 in the user namespace.
2604 2618
2605 2619 Returns
2606 2620 -------
2607 2621 A dict, keyed like the input expressions dict, with the rich mime-typed
2608 2622 display_data of each value.
2609 2623 """
2610 2624 out = {}
2611 2625 user_ns = self.user_ns
2612 2626 global_ns = self.user_global_ns
2613 2627
2614 2628 for key, expr in expressions.items():
2615 2629 try:
2616 2630 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2617 2631 except:
2618 2632 value = self._user_obj_error()
2619 2633 out[key] = value
2620 2634 return out
2621 2635
2622 2636 #-------------------------------------------------------------------------
2623 2637 # Things related to the running of code
2624 2638 #-------------------------------------------------------------------------
2625 2639
2626 2640 def ex(self, cmd):
2627 2641 """Execute a normal python statement in user namespace."""
2628 2642 with self.builtin_trap:
2629 2643 exec(cmd, self.user_global_ns, self.user_ns)
2630 2644
2631 2645 def ev(self, expr):
2632 2646 """Evaluate python expression expr in user namespace.
2633 2647
2634 2648 Returns the result of evaluation
2635 2649 """
2636 2650 with self.builtin_trap:
2637 2651 return eval(expr, self.user_global_ns, self.user_ns)
2638 2652
2639 2653 def safe_execfile(self, fname, *where, exit_ignore=False, raise_exceptions=False, shell_futures=False):
2640 2654 """A safe version of the builtin execfile().
2641 2655
2642 2656 This version will never throw an exception, but instead print
2643 2657 helpful error messages to the screen. This only works on pure
2644 2658 Python files with the .py extension.
2645 2659
2646 2660 Parameters
2647 2661 ----------
2648 2662 fname : string
2649 2663 The name of the file to be executed.
2650 2664 *where : tuple
2651 2665 One or two namespaces, passed to execfile() as (globals,locals).
2652 2666 If only one is given, it is passed as both.
2653 2667 exit_ignore : bool (False)
2654 2668 If True, then silence SystemExit for non-zero status (it is always
2655 2669 silenced for zero status, as it is so common).
2656 2670 raise_exceptions : bool (False)
2657 2671 If True raise exceptions everywhere. Meant for testing.
2658 2672 shell_futures : bool (False)
2659 2673 If True, the code will share future statements with the interactive
2660 2674 shell. It will both be affected by previous __future__ imports, and
2661 2675 any __future__ imports in the code will affect the shell. If False,
2662 2676 __future__ imports are not shared in either direction.
2663 2677
2664 2678 """
2665 2679 fname = Path(fname).expanduser().resolve()
2666 2680
2667 2681 # Make sure we can open the file
2668 2682 try:
2669 2683 with fname.open("rb"):
2670 2684 pass
2671 2685 except:
2672 2686 warn('Could not open file <%s> for safe execution.' % fname)
2673 2687 return
2674 2688
2675 2689 # Find things also in current directory. This is needed to mimic the
2676 2690 # behavior of running a script from the system command line, where
2677 2691 # Python inserts the script's directory into sys.path
2678 2692 dname = str(fname.parent)
2679 2693
2680 2694 with prepended_to_syspath(dname), self.builtin_trap:
2681 2695 try:
2682 2696 glob, loc = (where + (None, ))[:2]
2683 2697 py3compat.execfile(
2684 2698 fname, glob, loc,
2685 2699 self.compile if shell_futures else None)
2686 2700 except SystemExit as status:
2687 2701 # If the call was made with 0 or None exit status (sys.exit(0)
2688 2702 # or sys.exit() ), don't bother showing a traceback, as both of
2689 2703 # these are considered normal by the OS:
2690 2704 # > python -c'import sys;sys.exit(0)'; echo $?
2691 2705 # 0
2692 2706 # > python -c'import sys;sys.exit()'; echo $?
2693 2707 # 0
2694 2708 # For other exit status, we show the exception unless
2695 2709 # explicitly silenced, but only in short form.
2696 2710 if status.code:
2697 2711 if raise_exceptions:
2698 2712 raise
2699 2713 if not exit_ignore:
2700 2714 self.showtraceback(exception_only=True)
2701 2715 except:
2702 2716 if raise_exceptions:
2703 2717 raise
2704 2718 # tb offset is 2 because we wrap execfile
2705 2719 self.showtraceback(tb_offset=2)
2706 2720
2707 2721 def safe_execfile_ipy(self, fname, shell_futures=False, raise_exceptions=False):
2708 2722 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2709 2723
2710 2724 Parameters
2711 2725 ----------
2712 2726 fname : str
2713 2727 The name of the file to execute. The filename must have a
2714 2728 .ipy or .ipynb extension.
2715 2729 shell_futures : bool (False)
2716 2730 If True, the code will share future statements with the interactive
2717 2731 shell. It will both be affected by previous __future__ imports, and
2718 2732 any __future__ imports in the code will affect the shell. If False,
2719 2733 __future__ imports are not shared in either direction.
2720 2734 raise_exceptions : bool (False)
2721 2735 If True raise exceptions everywhere. Meant for testing.
2722 2736 """
2723 2737 fname = Path(fname).expanduser().resolve()
2724 2738
2725 2739 # Make sure we can open the file
2726 2740 try:
2727 2741 with fname.open("rb"):
2728 2742 pass
2729 2743 except:
2730 2744 warn('Could not open file <%s> for safe execution.' % fname)
2731 2745 return
2732 2746
2733 2747 # Find things also in current directory. This is needed to mimic the
2734 2748 # behavior of running a script from the system command line, where
2735 2749 # Python inserts the script's directory into sys.path
2736 2750 dname = str(fname.parent)
2737 2751
2738 2752 def get_cells():
2739 2753 """generator for sequence of code blocks to run"""
2740 2754 if fname.suffix == ".ipynb":
2741 2755 from nbformat import read
2742 2756 nb = read(fname, as_version=4)
2743 2757 if not nb.cells:
2744 2758 return
2745 2759 for cell in nb.cells:
2746 2760 if cell.cell_type == 'code':
2747 2761 yield cell.source
2748 2762 else:
2749 2763 yield fname.read_text(encoding="utf-8")
2750 2764
2751 2765 with prepended_to_syspath(dname):
2752 2766 try:
2753 2767 for cell in get_cells():
2754 2768 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2755 2769 if raise_exceptions:
2756 2770 result.raise_error()
2757 2771 elif not result.success:
2758 2772 break
2759 2773 except:
2760 2774 if raise_exceptions:
2761 2775 raise
2762 2776 self.showtraceback()
2763 2777 warn('Unknown failure executing file: <%s>' % fname)
2764 2778
2765 2779 def safe_run_module(self, mod_name, where):
2766 2780 """A safe version of runpy.run_module().
2767 2781
2768 2782 This version will never throw an exception, but instead print
2769 2783 helpful error messages to the screen.
2770 2784
2771 2785 `SystemExit` exceptions with status code 0 or None are ignored.
2772 2786
2773 2787 Parameters
2774 2788 ----------
2775 2789 mod_name : string
2776 2790 The name of the module to be executed.
2777 2791 where : dict
2778 2792 The globals namespace.
2779 2793 """
2780 2794 try:
2781 2795 try:
2782 2796 where.update(
2783 2797 runpy.run_module(str(mod_name), run_name="__main__",
2784 2798 alter_sys=True)
2785 2799 )
2786 2800 except SystemExit as status:
2787 2801 if status.code:
2788 2802 raise
2789 2803 except:
2790 2804 self.showtraceback()
2791 2805 warn('Unknown failure executing module: <%s>' % mod_name)
2792 2806
2793 2807 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2794 2808 """Run a complete IPython cell.
2795 2809
2796 2810 Parameters
2797 2811 ----------
2798 2812 raw_cell : str
2799 2813 The code (including IPython code such as %magic functions) to run.
2800 2814 store_history : bool
2801 2815 If True, the raw and translated cell will be stored in IPython's
2802 2816 history. For user code calling back into IPython's machinery, this
2803 2817 should be set to False.
2804 2818 silent : bool
2805 2819 If True, avoid side-effects, such as implicit displayhooks and
2806 2820 and logging. silent=True forces store_history=False.
2807 2821 shell_futures : bool
2808 2822 If True, the code will share future statements with the interactive
2809 2823 shell. It will both be affected by previous __future__ imports, and
2810 2824 any __future__ imports in the code will affect the shell. If False,
2811 2825 __future__ imports are not shared in either direction.
2812 2826
2813 2827 Returns
2814 2828 -------
2815 2829 result : :class:`ExecutionResult`
2816 2830 """
2817 2831 result = None
2818 2832 try:
2819 2833 result = self._run_cell(
2820 2834 raw_cell, store_history, silent, shell_futures)
2821 2835 finally:
2822 2836 self.events.trigger('post_execute')
2823 2837 if not silent:
2824 2838 self.events.trigger('post_run_cell', result)
2825 2839 return result
2826 2840
2827 2841 def _run_cell(self, raw_cell:str, store_history:bool, silent:bool, shell_futures:bool) -> ExecutionResult:
2828 2842 """Internal method to run a complete IPython cell."""
2829 2843
2830 2844 # we need to avoid calling self.transform_cell multiple time on the same thing
2831 2845 # so we need to store some results:
2832 2846 preprocessing_exc_tuple = None
2833 2847 try:
2834 2848 transformed_cell = self.transform_cell(raw_cell)
2835 2849 except Exception:
2836 2850 transformed_cell = raw_cell
2837 2851 preprocessing_exc_tuple = sys.exc_info()
2838 2852
2839 2853 assert transformed_cell is not None
2840 2854 coro = self.run_cell_async(
2841 2855 raw_cell,
2842 2856 store_history=store_history,
2843 2857 silent=silent,
2844 2858 shell_futures=shell_futures,
2845 2859 transformed_cell=transformed_cell,
2846 2860 preprocessing_exc_tuple=preprocessing_exc_tuple,
2847 2861 )
2848 2862
2849 2863 # run_cell_async is async, but may not actually need an eventloop.
2850 2864 # when this is the case, we want to run it using the pseudo_sync_runner
2851 2865 # so that code can invoke eventloops (for example via the %run , and
2852 2866 # `%paste` magic.
2853 2867 if self.trio_runner:
2854 2868 runner = self.trio_runner
2855 2869 elif self.should_run_async(
2856 2870 raw_cell,
2857 2871 transformed_cell=transformed_cell,
2858 2872 preprocessing_exc_tuple=preprocessing_exc_tuple,
2859 2873 ):
2860 2874 runner = self.loop_runner
2861 2875 else:
2862 2876 runner = _pseudo_sync_runner
2863 2877
2864 2878 try:
2865 2879 return runner(coro)
2866 2880 except BaseException as e:
2867 2881 info = ExecutionInfo(raw_cell, store_history, silent, shell_futures)
2868 2882 result = ExecutionResult(info)
2869 2883 result.error_in_exec = e
2870 2884 self.showtraceback(running_compiled_code=True)
2871 2885 return result
2872 2886
2873 2887 def should_run_async(
2874 2888 self, raw_cell: str, *, transformed_cell=None, preprocessing_exc_tuple=None
2875 2889 ) -> bool:
2876 2890 """Return whether a cell should be run asynchronously via a coroutine runner
2877 2891
2878 2892 Parameters
2879 2893 ----------
2880 2894 raw_cell : str
2881 2895 The code to be executed
2882 2896
2883 2897 Returns
2884 2898 -------
2885 2899 result: bool
2886 2900 Whether the code needs to be run with a coroutine runner or not
2887 2901 .. versionadded:: 7.0
2888 2902 """
2889 2903 if not self.autoawait:
2890 2904 return False
2891 2905 if preprocessing_exc_tuple is not None:
2892 2906 return False
2893 2907 assert preprocessing_exc_tuple is None
2894 2908 if transformed_cell is None:
2895 2909 warnings.warn(
2896 2910 "`should_run_async` will not call `transform_cell`"
2897 2911 " automatically in the future. Please pass the result to"
2898 2912 " `transformed_cell` argument and any exception that happen"
2899 2913 " during the"
2900 2914 "transform in `preprocessing_exc_tuple` in"
2901 2915 " IPython 7.17 and above.",
2902 2916 DeprecationWarning,
2903 2917 stacklevel=2,
2904 2918 )
2905 2919 try:
2906 2920 cell = self.transform_cell(raw_cell)
2907 2921 except Exception:
2908 2922 # any exception during transform will be raised
2909 2923 # prior to execution
2910 2924 return False
2911 2925 else:
2912 2926 cell = transformed_cell
2913 2927 return _should_be_async(cell)
2914 2928
2915 2929 async def run_cell_async(
2916 2930 self,
2917 2931 raw_cell: str,
2918 2932 store_history=False,
2919 2933 silent=False,
2920 2934 shell_futures=True,
2921 2935 *,
2922 2936 transformed_cell: Optional[str] = None,
2923 2937 preprocessing_exc_tuple: Optional[Any] = None
2924 2938 ) -> ExecutionResult:
2925 2939 """Run a complete IPython cell asynchronously.
2926 2940
2927 2941 Parameters
2928 2942 ----------
2929 2943 raw_cell : str
2930 2944 The code (including IPython code such as %magic functions) to run.
2931 2945 store_history : bool
2932 2946 If True, the raw and translated cell will be stored in IPython's
2933 2947 history. For user code calling back into IPython's machinery, this
2934 2948 should be set to False.
2935 2949 silent : bool
2936 2950 If True, avoid side-effects, such as implicit displayhooks and
2937 2951 and logging. silent=True forces store_history=False.
2938 2952 shell_futures : bool
2939 2953 If True, the code will share future statements with the interactive
2940 2954 shell. It will both be affected by previous __future__ imports, and
2941 2955 any __future__ imports in the code will affect the shell. If False,
2942 2956 __future__ imports are not shared in either direction.
2943 2957 transformed_cell: str
2944 2958 cell that was passed through transformers
2945 2959 preprocessing_exc_tuple:
2946 2960 trace if the transformation failed.
2947 2961
2948 2962 Returns
2949 2963 -------
2950 2964 result : :class:`ExecutionResult`
2951 2965
2952 2966 .. versionadded:: 7.0
2953 2967 """
2954 2968 info = ExecutionInfo(
2955 2969 raw_cell, store_history, silent, shell_futures)
2956 2970 result = ExecutionResult(info)
2957 2971
2958 2972 if (not raw_cell) or raw_cell.isspace():
2959 2973 self.last_execution_succeeded = True
2960 2974 self.last_execution_result = result
2961 2975 return result
2962 2976
2963 2977 if silent:
2964 2978 store_history = False
2965 2979
2966 2980 if store_history:
2967 2981 result.execution_count = self.execution_count
2968 2982
2969 2983 def error_before_exec(value):
2970 2984 if store_history:
2971 2985 self.execution_count += 1
2972 2986 result.error_before_exec = value
2973 2987 self.last_execution_succeeded = False
2974 2988 self.last_execution_result = result
2975 2989 return result
2976 2990
2977 2991 self.events.trigger('pre_execute')
2978 2992 if not silent:
2979 2993 self.events.trigger('pre_run_cell', info)
2980 2994
2981 2995 if transformed_cell is None:
2982 2996 warnings.warn(
2983 2997 "`run_cell_async` will not call `transform_cell`"
2984 2998 " automatically in the future. Please pass the result to"
2985 2999 " `transformed_cell` argument and any exception that happen"
2986 3000 " during the"
2987 3001 "transform in `preprocessing_exc_tuple` in"
2988 3002 " IPython 7.17 and above.",
2989 3003 DeprecationWarning,
2990 3004 stacklevel=2,
2991 3005 )
2992 3006 # If any of our input transformation (input_transformer_manager or
2993 3007 # prefilter_manager) raises an exception, we store it in this variable
2994 3008 # so that we can display the error after logging the input and storing
2995 3009 # it in the history.
2996 3010 try:
2997 3011 cell = self.transform_cell(raw_cell)
2998 3012 except Exception:
2999 3013 preprocessing_exc_tuple = sys.exc_info()
3000 3014 cell = raw_cell # cell has to exist so it can be stored/logged
3001 3015 else:
3002 3016 preprocessing_exc_tuple = None
3003 3017 else:
3004 3018 if preprocessing_exc_tuple is None:
3005 3019 cell = transformed_cell
3006 3020 else:
3007 3021 cell = raw_cell
3008 3022
3009 3023 # Store raw and processed history
3010 3024 if store_history:
3011 3025 self.history_manager.store_inputs(self.execution_count,
3012 3026 cell, raw_cell)
3013 3027 if not silent:
3014 3028 self.logger.log(cell, raw_cell)
3015 3029
3016 3030 # Display the exception if input processing failed.
3017 3031 if preprocessing_exc_tuple is not None:
3018 3032 self.showtraceback(preprocessing_exc_tuple)
3019 3033 if store_history:
3020 3034 self.execution_count += 1
3021 3035 return error_before_exec(preprocessing_exc_tuple[1])
3022 3036
3023 3037 # Our own compiler remembers the __future__ environment. If we want to
3024 3038 # run code with a separate __future__ environment, use the default
3025 3039 # compiler
3026 3040 compiler = self.compile if shell_futures else self.compiler_class()
3027 3041
3028 3042 _run_async = False
3029 3043
3030 3044 with self.builtin_trap:
3031 3045 cell_name = compiler.cache(cell, self.execution_count, raw_code=raw_cell)
3032 3046
3033 3047 with self.display_trap:
3034 3048 # Compile to bytecode
3035 3049 try:
3036 3050 code_ast = compiler.ast_parse(cell, filename=cell_name)
3037 3051 except self.custom_exceptions as e:
3038 3052 etype, value, tb = sys.exc_info()
3039 3053 self.CustomTB(etype, value, tb)
3040 3054 return error_before_exec(e)
3041 3055 except IndentationError as e:
3042 3056 self.showindentationerror()
3043 3057 return error_before_exec(e)
3044 3058 except (OverflowError, SyntaxError, ValueError, TypeError,
3045 3059 MemoryError) as e:
3046 3060 self.showsyntaxerror()
3047 3061 return error_before_exec(e)
3048 3062
3049 3063 # Apply AST transformations
3050 3064 try:
3051 3065 code_ast = self.transform_ast(code_ast)
3052 3066 except InputRejected as e:
3053 3067 self.showtraceback()
3054 3068 return error_before_exec(e)
3055 3069
3056 3070 # Give the displayhook a reference to our ExecutionResult so it
3057 3071 # can fill in the output value.
3058 3072 self.displayhook.exec_result = result
3059 3073
3060 3074 # Execute the user code
3061 3075 interactivity = "none" if silent else self.ast_node_interactivity
3062 3076
3063 3077 has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
3064 3078 interactivity=interactivity, compiler=compiler, result=result)
3065 3079
3066 3080 self.last_execution_succeeded = not has_raised
3067 3081 self.last_execution_result = result
3068 3082
3069 3083 # Reset this so later displayed values do not modify the
3070 3084 # ExecutionResult
3071 3085 self.displayhook.exec_result = None
3072 3086
3073 3087 if store_history:
3074 3088 # Write output to the database. Does nothing unless
3075 3089 # history output logging is enabled.
3076 3090 self.history_manager.store_output(self.execution_count)
3077 3091 # Each cell is a *single* input, regardless of how many lines it has
3078 3092 self.execution_count += 1
3079 3093
3080 3094 return result
3081 3095
3082 3096 def transform_cell(self, raw_cell):
3083 3097 """Transform an input cell before parsing it.
3084 3098
3085 3099 Static transformations, implemented in IPython.core.inputtransformer2,
3086 3100 deal with things like ``%magic`` and ``!system`` commands.
3087 3101 These run on all input.
3088 3102 Dynamic transformations, for things like unescaped magics and the exit
3089 3103 autocall, depend on the state of the interpreter.
3090 3104 These only apply to single line inputs.
3091 3105
3092 3106 These string-based transformations are followed by AST transformations;
3093 3107 see :meth:`transform_ast`.
3094 3108 """
3095 3109 # Static input transformations
3096 3110 cell = self.input_transformer_manager.transform_cell(raw_cell)
3097 3111
3098 3112 if len(cell.splitlines()) == 1:
3099 3113 # Dynamic transformations - only applied for single line commands
3100 3114 with self.builtin_trap:
3101 3115 # use prefilter_lines to handle trailing newlines
3102 3116 # restore trailing newline for ast.parse
3103 3117 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
3104 3118
3105 3119 lines = cell.splitlines(keepends=True)
3106 3120 for transform in self.input_transformers_post:
3107 3121 lines = transform(lines)
3108 3122 cell = ''.join(lines)
3109 3123
3110 3124 return cell
3111 3125
3112 3126 def transform_ast(self, node):
3113 3127 """Apply the AST transformations from self.ast_transformers
3114 3128
3115 3129 Parameters
3116 3130 ----------
3117 3131 node : ast.Node
3118 3132 The root node to be transformed. Typically called with the ast.Module
3119 3133 produced by parsing user input.
3120 3134
3121 3135 Returns
3122 3136 -------
3123 3137 An ast.Node corresponding to the node it was called with. Note that it
3124 3138 may also modify the passed object, so don't rely on references to the
3125 3139 original AST.
3126 3140 """
3127 3141 for transformer in self.ast_transformers:
3128 3142 try:
3129 3143 node = transformer.visit(node)
3130 3144 except InputRejected:
3131 3145 # User-supplied AST transformers can reject an input by raising
3132 3146 # an InputRejected. Short-circuit in this case so that we
3133 3147 # don't unregister the transform.
3134 3148 raise
3135 3149 except Exception:
3136 3150 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
3137 3151 self.ast_transformers.remove(transformer)
3138 3152
3139 3153 if self.ast_transformers:
3140 3154 ast.fix_missing_locations(node)
3141 3155 return node
3142 3156
3143 3157 def _update_code_co_name(self, code):
3144 3158 """Python 3.10 changed the behaviour so that whenever a code object
3145 3159 is assembled in the compile(ast) the co_firstlineno would be == 1.
3146 3160
3147 3161 This makes pydevd/debugpy think that all cells invoked are the same
3148 3162 since it caches information based on (co_firstlineno, co_name, co_filename).
3149 3163
3150 3164 Given that, this function changes the code 'co_name' to be unique
3151 3165 based on the first real lineno of the code (which also has a nice
3152 3166 side effect of customizing the name so that it's not always <module>).
3153 3167
3154 3168 See: https://github.com/ipython/ipykernel/issues/841
3155 3169 """
3156 3170 if not hasattr(code, "replace"):
3157 3171 # It may not be available on older versions of Python (only
3158 3172 # available for 3.8 onwards).
3159 3173 return code
3160 3174 try:
3161 3175 first_real_line = next(dis.findlinestarts(code))[1]
3162 3176 except StopIteration:
3163 3177 return code
3164 3178 return code.replace(co_name="<cell line: %s>" % (first_real_line,))
3165 3179
3166 3180 async def run_ast_nodes(
3167 3181 self,
3168 3182 nodelist: ListType[stmt],
3169 3183 cell_name: str,
3170 3184 interactivity="last_expr",
3171 3185 compiler=compile,
3172 3186 result=None,
3173 3187 ):
3174 3188 """Run a sequence of AST nodes. The execution mode depends on the
3175 3189 interactivity parameter.
3176 3190
3177 3191 Parameters
3178 3192 ----------
3179 3193 nodelist : list
3180 3194 A sequence of AST nodes to run.
3181 3195 cell_name : str
3182 3196 Will be passed to the compiler as the filename of the cell. Typically
3183 3197 the value returned by ip.compile.cache(cell).
3184 3198 interactivity : str
3185 3199 'all', 'last', 'last_expr' , 'last_expr_or_assign' or 'none',
3186 3200 specifying which nodes should be run interactively (displaying output
3187 3201 from expressions). 'last_expr' will run the last node interactively
3188 3202 only if it is an expression (i.e. expressions in loops or other blocks
3189 3203 are not displayed) 'last_expr_or_assign' will run the last expression
3190 3204 or the last assignment. Other values for this parameter will raise a
3191 3205 ValueError.
3192 3206
3193 3207 compiler : callable
3194 3208 A function with the same interface as the built-in compile(), to turn
3195 3209 the AST nodes into code objects. Default is the built-in compile().
3196 3210 result : ExecutionResult, optional
3197 3211 An object to store exceptions that occur during execution.
3198 3212
3199 3213 Returns
3200 3214 -------
3201 3215 True if an exception occurred while running code, False if it finished
3202 3216 running.
3203 3217 """
3204 3218 if not nodelist:
3205 3219 return
3206 3220
3207 3221
3208 3222 if interactivity == 'last_expr_or_assign':
3209 3223 if isinstance(nodelist[-1], _assign_nodes):
3210 3224 asg = nodelist[-1]
3211 3225 if isinstance(asg, ast.Assign) and len(asg.targets) == 1:
3212 3226 target = asg.targets[0]
3213 3227 elif isinstance(asg, _single_targets_nodes):
3214 3228 target = asg.target
3215 3229 else:
3216 3230 target = None
3217 3231 if isinstance(target, ast.Name):
3218 3232 nnode = ast.Expr(ast.Name(target.id, ast.Load()))
3219 3233 ast.fix_missing_locations(nnode)
3220 3234 nodelist.append(nnode)
3221 3235 interactivity = 'last_expr'
3222 3236
3223 3237 _async = False
3224 3238 if interactivity == 'last_expr':
3225 3239 if isinstance(nodelist[-1], ast.Expr):
3226 3240 interactivity = "last"
3227 3241 else:
3228 3242 interactivity = "none"
3229 3243
3230 3244 if interactivity == 'none':
3231 3245 to_run_exec, to_run_interactive = nodelist, []
3232 3246 elif interactivity == 'last':
3233 3247 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
3234 3248 elif interactivity == 'all':
3235 3249 to_run_exec, to_run_interactive = [], nodelist
3236 3250 else:
3237 3251 raise ValueError("Interactivity was %r" % interactivity)
3238 3252
3239 3253 try:
3240 3254
3241 3255 def compare(code):
3242 3256 is_async = inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE
3243 3257 return is_async
3244 3258
3245 3259 # refactor that to just change the mod constructor.
3246 3260 to_run = []
3247 3261 for node in to_run_exec:
3248 3262 to_run.append((node, "exec"))
3249 3263
3250 3264 for node in to_run_interactive:
3251 3265 to_run.append((node, "single"))
3252 3266
3253 3267 for node, mode in to_run:
3254 3268 if mode == "exec":
3255 3269 mod = Module([node], [])
3256 3270 elif mode == "single":
3257 3271 mod = ast.Interactive([node])
3258 3272 with compiler.extra_flags(
3259 3273 getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
3260 3274 if self.autoawait
3261 3275 else 0x0
3262 3276 ):
3263 3277 code = compiler(mod, cell_name, mode)
3264 3278 code = self._update_code_co_name(code)
3265 3279 asy = compare(code)
3266 3280 if await self.run_code(code, result, async_=asy):
3267 3281 return True
3268 3282
3269 3283 # Flush softspace
3270 3284 if softspace(sys.stdout, 0):
3271 3285 print()
3272 3286
3273 3287 except:
3274 3288 # It's possible to have exceptions raised here, typically by
3275 3289 # compilation of odd code (such as a naked 'return' outside a
3276 3290 # function) that did parse but isn't valid. Typically the exception
3277 3291 # is a SyntaxError, but it's safest just to catch anything and show
3278 3292 # the user a traceback.
3279 3293
3280 3294 # We do only one try/except outside the loop to minimize the impact
3281 3295 # on runtime, and also because if any node in the node list is
3282 3296 # broken, we should stop execution completely.
3283 3297 if result:
3284 3298 result.error_before_exec = sys.exc_info()[1]
3285 3299 self.showtraceback()
3286 3300 return True
3287 3301
3288 3302 return False
3289 3303
3290 3304 async def run_code(self, code_obj, result=None, *, async_=False):
3291 3305 """Execute a code object.
3292 3306
3293 3307 When an exception occurs, self.showtraceback() is called to display a
3294 3308 traceback.
3295 3309
3296 3310 Parameters
3297 3311 ----------
3298 3312 code_obj : code object
3299 3313 A compiled code object, to be executed
3300 3314 result : ExecutionResult, optional
3301 3315 An object to store exceptions that occur during execution.
3302 3316 async_ : Bool (Experimental)
3303 3317 Attempt to run top-level asynchronous code in a default loop.
3304 3318
3305 3319 Returns
3306 3320 -------
3307 3321 False : successful execution.
3308 3322 True : an error occurred.
3309 3323 """
3310 3324 # special value to say that anything above is IPython and should be
3311 3325 # hidden.
3312 3326 __tracebackhide__ = "__ipython_bottom__"
3313 3327 # Set our own excepthook in case the user code tries to call it
3314 3328 # directly, so that the IPython crash handler doesn't get triggered
3315 3329 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3316 3330
3317 3331 # we save the original sys.excepthook in the instance, in case config
3318 3332 # code (such as magics) needs access to it.
3319 3333 self.sys_excepthook = old_excepthook
3320 3334 outflag = True # happens in more places, so it's easier as default
3321 3335 try:
3322 3336 try:
3323 3337 if async_:
3324 3338 await eval(code_obj, self.user_global_ns, self.user_ns)
3325 3339 else:
3326 3340 exec(code_obj, self.user_global_ns, self.user_ns)
3327 3341 finally:
3328 3342 # Reset our crash handler in place
3329 3343 sys.excepthook = old_excepthook
3330 3344 except SystemExit as e:
3331 3345 if result is not None:
3332 3346 result.error_in_exec = e
3333 3347 self.showtraceback(exception_only=True)
3334 3348 warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
3335 3349 except self.custom_exceptions:
3336 3350 etype, value, tb = sys.exc_info()
3337 3351 if result is not None:
3338 3352 result.error_in_exec = value
3339 3353 self.CustomTB(etype, value, tb)
3340 3354 except:
3341 3355 if result is not None:
3342 3356 result.error_in_exec = sys.exc_info()[1]
3343 3357 self.showtraceback(running_compiled_code=True)
3344 3358 else:
3345 3359 outflag = False
3346 3360 return outflag
3347 3361
3348 3362 # For backwards compatibility
3349 3363 runcode = run_code
3350 3364
3351 3365 def check_complete(self, code: str) -> Tuple[str, str]:
3352 3366 """Return whether a block of code is ready to execute, or should be continued
3353 3367
3354 3368 Parameters
3355 3369 ----------
3356 3370 code : string
3357 3371 Python input code, which can be multiline.
3358 3372
3359 3373 Returns
3360 3374 -------
3361 3375 status : str
3362 3376 One of 'complete', 'incomplete', or 'invalid' if source is not a
3363 3377 prefix of valid code.
3364 3378 indent : str
3365 3379 When status is 'incomplete', this is some whitespace to insert on
3366 3380 the next line of the prompt.
3367 3381 """
3368 3382 status, nspaces = self.input_transformer_manager.check_complete(code)
3369 3383 return status, ' ' * (nspaces or 0)
3370 3384
3371 3385 #-------------------------------------------------------------------------
3372 3386 # Things related to GUI support and pylab
3373 3387 #-------------------------------------------------------------------------
3374 3388
3375 3389 active_eventloop = None
3376 3390
3377 3391 def enable_gui(self, gui=None):
3378 3392 raise NotImplementedError('Implement enable_gui in a subclass')
3379 3393
3380 3394 def enable_matplotlib(self, gui=None):
3381 3395 """Enable interactive matplotlib and inline figure support.
3382 3396
3383 3397 This takes the following steps:
3384 3398
3385 3399 1. select the appropriate eventloop and matplotlib backend
3386 3400 2. set up matplotlib for interactive use with that backend
3387 3401 3. configure formatters for inline figure display
3388 3402 4. enable the selected gui eventloop
3389 3403
3390 3404 Parameters
3391 3405 ----------
3392 3406 gui : optional, string
3393 3407 If given, dictates the choice of matplotlib GUI backend to use
3394 3408 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3395 3409 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3396 3410 matplotlib (as dictated by the matplotlib build-time options plus the
3397 3411 user's matplotlibrc configuration file). Note that not all backends
3398 3412 make sense in all contexts, for example a terminal ipython can't
3399 3413 display figures inline.
3400 3414 """
3401 from IPython.core import pylabtools as pt
3402 3415 from matplotlib_inline.backend_inline import configure_inline_support
3416
3417 from IPython.core import pylabtools as pt
3403 3418 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3404 3419
3405 3420 if gui != 'inline':
3406 3421 # If we have our first gui selection, store it
3407 3422 if self.pylab_gui_select is None:
3408 3423 self.pylab_gui_select = gui
3409 3424 # Otherwise if they are different
3410 3425 elif gui != self.pylab_gui_select:
3411 3426 print('Warning: Cannot change to a different GUI toolkit: %s.'
3412 3427 ' Using %s instead.' % (gui, self.pylab_gui_select))
3413 3428 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3414 3429
3415 3430 pt.activate_matplotlib(backend)
3416 3431 configure_inline_support(self, backend)
3417 3432
3418 3433 # Now we must activate the gui pylab wants to use, and fix %run to take
3419 3434 # plot updates into account
3420 3435 self.enable_gui(gui)
3421 3436 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3422 3437 pt.mpl_runner(self.safe_execfile)
3423 3438
3424 3439 return gui, backend
3425 3440
3426 3441 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3427 3442 """Activate pylab support at runtime.
3428 3443
3429 3444 This turns on support for matplotlib, preloads into the interactive
3430 3445 namespace all of numpy and pylab, and configures IPython to correctly
3431 3446 interact with the GUI event loop. The GUI backend to be used can be
3432 3447 optionally selected with the optional ``gui`` argument.
3433 3448
3434 3449 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3435 3450
3436 3451 Parameters
3437 3452 ----------
3438 3453 gui : optional, string
3439 3454 If given, dictates the choice of matplotlib GUI backend to use
3440 3455 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3441 3456 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3442 3457 matplotlib (as dictated by the matplotlib build-time options plus the
3443 3458 user's matplotlibrc configuration file). Note that not all backends
3444 3459 make sense in all contexts, for example a terminal ipython can't
3445 3460 display figures inline.
3446 3461 import_all : optional, bool, default: True
3447 3462 Whether to do `from numpy import *` and `from pylab import *`
3448 3463 in addition to module imports.
3449 3464 welcome_message : deprecated
3450 3465 This argument is ignored, no welcome message will be displayed.
3451 3466 """
3452 3467 from IPython.core.pylabtools import import_pylab
3453 3468
3454 3469 gui, backend = self.enable_matplotlib(gui)
3455 3470
3456 3471 # We want to prevent the loading of pylab to pollute the user's
3457 3472 # namespace as shown by the %who* magics, so we execute the activation
3458 3473 # code in an empty namespace, and we update *both* user_ns and
3459 3474 # user_ns_hidden with this information.
3460 3475 ns = {}
3461 3476 import_pylab(ns, import_all)
3462 3477 # warn about clobbered names
3463 3478 ignored = {"__builtins__"}
3464 3479 both = set(ns).intersection(self.user_ns).difference(ignored)
3465 3480 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3466 3481 self.user_ns.update(ns)
3467 3482 self.user_ns_hidden.update(ns)
3468 3483 return gui, backend, clobbered
3469 3484
3470 3485 #-------------------------------------------------------------------------
3471 3486 # Utilities
3472 3487 #-------------------------------------------------------------------------
3473 3488
3474 3489 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3475 3490 """Expand python variables in a string.
3476 3491
3477 3492 The depth argument indicates how many frames above the caller should
3478 3493 be walked to look for the local namespace where to expand variables.
3479 3494
3480 3495 The global namespace for expansion is always the user's interactive
3481 3496 namespace.
3482 3497 """
3483 3498 ns = self.user_ns.copy()
3484 3499 try:
3485 3500 frame = sys._getframe(depth+1)
3486 3501 except ValueError:
3487 3502 # This is thrown if there aren't that many frames on the stack,
3488 3503 # e.g. if a script called run_line_magic() directly.
3489 3504 pass
3490 3505 else:
3491 3506 ns.update(frame.f_locals)
3492 3507
3493 3508 try:
3494 3509 # We have to use .vformat() here, because 'self' is a valid and common
3495 3510 # name, and expanding **ns for .format() would make it collide with
3496 3511 # the 'self' argument of the method.
3497 3512 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3498 3513 except Exception:
3499 3514 # if formatter couldn't format, just let it go untransformed
3500 3515 pass
3501 3516 return cmd
3502 3517
3503 3518 def mktempfile(self, data=None, prefix='ipython_edit_'):
3504 3519 """Make a new tempfile and return its filename.
3505 3520
3506 3521 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3507 3522 but it registers the created filename internally so ipython cleans it up
3508 3523 at exit time.
3509 3524
3510 3525 Optional inputs:
3511 3526
3512 3527 - data(None): if data is given, it gets written out to the temp file
3513 3528 immediately, and the file is closed again."""
3514 3529
3515 3530 dir_path = Path(tempfile.mkdtemp(prefix=prefix))
3516 3531 self.tempdirs.append(dir_path)
3517 3532
3518 3533 handle, filename = tempfile.mkstemp(".py", prefix, dir=str(dir_path))
3519 3534 os.close(handle) # On Windows, there can only be one open handle on a file
3520 3535
3521 3536 file_path = Path(filename)
3522 3537 self.tempfiles.append(file_path)
3523 3538
3524 3539 if data:
3525 3540 file_path.write_text(data, encoding="utf-8")
3526 3541 return filename
3527 3542
3528 3543 def ask_yes_no(self, prompt, default=None, interrupt=None):
3529 3544 if self.quiet:
3530 3545 return True
3531 3546 return ask_yes_no(prompt,default,interrupt)
3532 3547
3533 3548 def show_usage(self):
3534 3549 """Show a usage message"""
3535 3550 page.page(IPython.core.usage.interactive_usage)
3536 3551
3537 3552 def extract_input_lines(self, range_str, raw=False):
3538 3553 """Return as a string a set of input history slices.
3539 3554
3540 3555 Parameters
3541 3556 ----------
3542 3557 range_str : str
3543 3558 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3544 3559 since this function is for use by magic functions which get their
3545 3560 arguments as strings. The number before the / is the session
3546 3561 number: ~n goes n back from the current session.
3547 3562
3548 3563 If empty string is given, returns history of current session
3549 3564 without the last input.
3550 3565
3551 3566 raw : bool, optional
3552 3567 By default, the processed input is used. If this is true, the raw
3553 3568 input history is used instead.
3554 3569
3555 3570 Notes
3556 3571 -----
3557 3572 Slices can be described with two notations:
3558 3573
3559 3574 * ``N:M`` -> standard python form, means including items N...(M-1).
3560 3575 * ``N-M`` -> include items N..M (closed endpoint).
3561 3576 """
3562 3577 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3563 3578 text = "\n".join(x for _, _, x in lines)
3564 3579
3565 3580 # Skip the last line, as it's probably the magic that called this
3566 3581 if not range_str:
3567 3582 if "\n" not in text:
3568 3583 text = ""
3569 3584 else:
3570 3585 text = text[: text.rfind("\n")]
3571 3586
3572 3587 return text
3573 3588
3574 3589 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3575 3590 """Get a code string from history, file, url, or a string or macro.
3576 3591
3577 3592 This is mainly used by magic functions.
3578 3593
3579 3594 Parameters
3580 3595 ----------
3581 3596 target : str
3582 3597 A string specifying code to retrieve. This will be tried respectively
3583 3598 as: ranges of input history (see %history for syntax), url,
3584 3599 corresponding .py file, filename, or an expression evaluating to a
3585 3600 string or Macro in the user namespace.
3586 3601
3587 3602 If empty string is given, returns complete history of current
3588 3603 session, without the last line.
3589 3604
3590 3605 raw : bool
3591 3606 If true (default), retrieve raw history. Has no effect on the other
3592 3607 retrieval mechanisms.
3593 3608
3594 3609 py_only : bool (default False)
3595 3610 Only try to fetch python code, do not try alternative methods to decode file
3596 3611 if unicode fails.
3597 3612
3598 3613 Returns
3599 3614 -------
3600 3615 A string of code.
3601 3616 ValueError is raised if nothing is found, and TypeError if it evaluates
3602 3617 to an object of another type. In each case, .args[0] is a printable
3603 3618 message.
3604 3619 """
3605 3620 code = self.extract_input_lines(target, raw=raw) # Grab history
3606 3621 if code:
3607 3622 return code
3608 3623 try:
3609 3624 if target.startswith(('http://', 'https://')):
3610 3625 return openpy.read_py_url(target, skip_encoding_cookie=skip_encoding_cookie)
3611 3626 except UnicodeDecodeError as e:
3612 3627 if not py_only :
3613 3628 # Deferred import
3614 3629 from urllib.request import urlopen
3615 3630 response = urlopen(target)
3616 3631 return response.read().decode('latin1')
3617 3632 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3618 3633
3619 3634 potential_target = [target]
3620 3635 try :
3621 3636 potential_target.insert(0,get_py_filename(target))
3622 3637 except IOError:
3623 3638 pass
3624 3639
3625 3640 for tgt in potential_target :
3626 3641 if os.path.isfile(tgt): # Read file
3627 3642 try :
3628 3643 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3629 3644 except UnicodeDecodeError as e:
3630 3645 if not py_only :
3631 3646 with io_open(tgt,'r', encoding='latin1') as f :
3632 3647 return f.read()
3633 3648 raise ValueError(("'%s' seem to be unreadable.") % target) from e
3634 3649 elif os.path.isdir(os.path.expanduser(tgt)):
3635 3650 raise ValueError("'%s' is a directory, not a regular file." % target)
3636 3651
3637 3652 if search_ns:
3638 3653 # Inspect namespace to load object source
3639 3654 object_info = self.object_inspect(target, detail_level=1)
3640 3655 if object_info['found'] and object_info['source']:
3641 3656 return object_info['source']
3642 3657
3643 3658 try: # User namespace
3644 3659 codeobj = eval(target, self.user_ns)
3645 3660 except Exception as e:
3646 3661 raise ValueError(("'%s' was not found in history, as a file, url, "
3647 3662 "nor in the user namespace.") % target) from e
3648 3663
3649 3664 if isinstance(codeobj, str):
3650 3665 return codeobj
3651 3666 elif isinstance(codeobj, Macro):
3652 3667 return codeobj.value
3653 3668
3654 3669 raise TypeError("%s is neither a string nor a macro." % target,
3655 3670 codeobj)
3656 3671
3657 3672 def _atexit_once(self):
3658 3673 """
3659 3674 At exist operation that need to be called at most once.
3660 3675 Second call to this function per instance will do nothing.
3661 3676 """
3662 3677
3663 3678 if not getattr(self, "_atexit_once_called", False):
3664 3679 self._atexit_once_called = True
3665 3680 # Clear all user namespaces to release all references cleanly.
3666 3681 self.reset(new_session=False)
3667 3682 # Close the history session (this stores the end time and line count)
3668 3683 # this must be *before* the tempfile cleanup, in case of temporary
3669 3684 # history db
3670 3685 self.history_manager.end_session()
3671 3686 self.history_manager = None
3672 3687
3673 3688 #-------------------------------------------------------------------------
3674 3689 # Things related to IPython exiting
3675 3690 #-------------------------------------------------------------------------
3676 3691 def atexit_operations(self):
3677 3692 """This will be executed at the time of exit.
3678 3693
3679 3694 Cleanup operations and saving of persistent data that is done
3680 3695 unconditionally by IPython should be performed here.
3681 3696
3682 3697 For things that may depend on startup flags or platform specifics (such
3683 3698 as having readline or not), register a separate atexit function in the
3684 3699 code that has the appropriate information, rather than trying to
3685 3700 clutter
3686 3701 """
3687 3702 self._atexit_once()
3688 3703
3689 3704 # Cleanup all tempfiles and folders left around
3690 3705 for tfile in self.tempfiles:
3691 3706 try:
3692 3707 tfile.unlink()
3693 3708 self.tempfiles.remove(tfile)
3694 3709 except FileNotFoundError:
3695 3710 pass
3696 3711 del self.tempfiles
3697 3712 for tdir in self.tempdirs:
3698 3713 try:
3699 3714 tdir.rmdir()
3700 3715 self.tempdirs.remove(tdir)
3701 3716 except FileNotFoundError:
3702 3717 pass
3703 3718 del self.tempdirs
3704 3719
3705 3720 # Restore user's cursor
3706 3721 if hasattr(self, "editing_mode") and self.editing_mode == "vi":
3707 3722 sys.stdout.write("\x1b[0 q")
3708 3723 sys.stdout.flush()
3709 3724
3710 3725 def cleanup(self):
3711 3726 self.restore_sys_module_state()
3712 3727
3713 3728
3714 3729 # Overridden in terminal subclass to change prompts
3715 3730 def switch_doctest_mode(self, mode):
3716 3731 pass
3717 3732
3718 3733
3719 3734 class InteractiveShellABC(metaclass=abc.ABCMeta):
3720 3735 """An abstract base class for InteractiveShell."""
3721 3736
3722 3737 InteractiveShellABC.register(InteractiveShell)
@@ -1,70 +1,70 b''
1 1 # coding: utf-8
2 2 """Tests for IPython.core.application"""
3 3
4 4 import os
5 5 import tempfile
6 6
7 from tempfile import TemporaryDirectory
7 8 from traitlets import Unicode
8 9
9 10 from IPython.core.application import BaseIPythonApplication
10 11 from IPython.testing import decorators as dec
11 from IPython.utils.tempdir import TemporaryDirectory
12 12
13 13
14 14 @dec.onlyif_unicode_paths
15 15 def test_unicode_cwd():
16 16 """Check that IPython starts with non-ascii characters in the path."""
17 17 wd = tempfile.mkdtemp(suffix=u"€")
18 18
19 19 old_wd = os.getcwd()
20 20 os.chdir(wd)
21 21 #raise Exception(repr(os.getcwd()))
22 22 try:
23 23 app = BaseIPythonApplication()
24 24 # The lines below are copied from Application.initialize()
25 25 app.init_profile_dir()
26 26 app.init_config_files()
27 27 app.load_config_file(suppress_errors=False)
28 28 finally:
29 29 os.chdir(old_wd)
30 30
31 31 @dec.onlyif_unicode_paths
32 32 def test_unicode_ipdir():
33 33 """Check that IPython starts with non-ascii characters in the IP dir."""
34 34 ipdir = tempfile.mkdtemp(suffix=u"€")
35 35
36 36 # Create the config file, so it tries to load it.
37 37 with open(os.path.join(ipdir, "ipython_config.py"), "w", encoding="utf-8") as f:
38 38 pass
39 39
40 40 old_ipdir1 = os.environ.pop("IPYTHONDIR", None)
41 41 old_ipdir2 = os.environ.pop("IPYTHON_DIR", None)
42 42 os.environ["IPYTHONDIR"] = ipdir
43 43 try:
44 44 app = BaseIPythonApplication()
45 45 # The lines below are copied from Application.initialize()
46 46 app.init_profile_dir()
47 47 app.init_config_files()
48 48 app.load_config_file(suppress_errors=False)
49 49 finally:
50 50 if old_ipdir1:
51 51 os.environ["IPYTHONDIR"] = old_ipdir1
52 52 if old_ipdir2:
53 53 os.environ["IPYTHONDIR"] = old_ipdir2
54 54
55 55 def test_cli_priority():
56 56 with TemporaryDirectory() as td:
57 57
58 58 class TestApp(BaseIPythonApplication):
59 59 test = Unicode().tag(config=True)
60 60
61 61 # Create the config file, so it tries to load it.
62 62 with open(os.path.join(td, "ipython_config.py"), "w", encoding="utf-8") as f:
63 63 f.write("c.TestApp.test = 'config file'")
64 64
65 65 app = TestApp()
66 66 app.initialize(["--profile-dir", td])
67 67 assert app.test == "config file"
68 68 app = TestApp()
69 69 app.initialize(["--profile-dir", td, "--TestApp.test=cli"])
70 70 assert app.test == "cli"
@@ -1,192 +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 from tempfile import TemporaryDirectory
18
17 19 from IPython.core.completerlib import magic_run_completer, module_completion, try_import
18 from IPython.utils.tempdir import TemporaryDirectory
19 20 from IPython.testing.decorators import onlyif_unicode_paths
20 21
21 22
22 23 class MockEvent(object):
23 24 def __init__(self, line):
24 25 self.line = line
25 26
26 27 #-----------------------------------------------------------------------------
27 28 # Test functions begin
28 29 #-----------------------------------------------------------------------------
29 30 class Test_magic_run_completer(unittest.TestCase):
30 31 files = [u"aao.py", u"a.py", u"b.py", u"aao.txt"]
31 32 dirs = [u"adir/", "bdir/"]
32 33
33 34 def setUp(self):
34 35 self.BASETESTDIR = tempfile.mkdtemp()
35 36 for fil in self.files:
36 37 with open(join(self.BASETESTDIR, fil), "w", encoding="utf-8") as sfile:
37 38 sfile.write("pass\n")
38 39 for d in self.dirs:
39 40 os.mkdir(join(self.BASETESTDIR, d))
40 41
41 42 self.oldpath = os.getcwd()
42 43 os.chdir(self.BASETESTDIR)
43 44
44 45 def tearDown(self):
45 46 os.chdir(self.oldpath)
46 47 shutil.rmtree(self.BASETESTDIR)
47 48
48 49 def test_1(self):
49 50 """Test magic_run_completer, should match two alternatives
50 51 """
51 52 event = MockEvent(u"%run a")
52 53 mockself = None
53 54 match = set(magic_run_completer(mockself, event))
54 55 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
55 56
56 57 def test_2(self):
57 58 """Test magic_run_completer, should match one alternative
58 59 """
59 60 event = MockEvent(u"%run aa")
60 61 mockself = None
61 62 match = set(magic_run_completer(mockself, event))
62 63 self.assertEqual(match, {u"aao.py"})
63 64
64 65 def test_3(self):
65 66 """Test magic_run_completer with unterminated " """
66 67 event = MockEvent(u'%run "a')
67 68 mockself = None
68 69 match = set(magic_run_completer(mockself, event))
69 70 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
70 71
71 72 def test_completion_more_args(self):
72 73 event = MockEvent(u'%run a.py ')
73 74 match = set(magic_run_completer(None, event))
74 75 self.assertEqual(match, set(self.files + self.dirs))
75 76
76 77 def test_completion_in_dir(self):
77 78 # Github issue #3459
78 79 event = MockEvent(u'%run a.py {}'.format(join(self.BASETESTDIR, 'a')))
79 80 print(repr(event.line))
80 81 match = set(magic_run_completer(None, event))
81 82 # We specifically use replace here rather than normpath, because
82 83 # at one point there were duplicates 'adir' and 'adir/', and normpath
83 84 # would hide the failure for that.
84 85 self.assertEqual(match, {join(self.BASETESTDIR, f).replace('\\','/')
85 86 for f in (u'a.py', u'aao.py', u'aao.txt', u'adir/')})
86 87
87 88 class Test_magic_run_completer_nonascii(unittest.TestCase):
88 89 @onlyif_unicode_paths
89 90 def setUp(self):
90 91 self.BASETESTDIR = tempfile.mkdtemp()
91 92 for fil in [u"aaΓΈ.py", u"a.py", u"b.py"]:
92 93 with open(join(self.BASETESTDIR, fil), "w", encoding="utf-8") as sfile:
93 94 sfile.write("pass\n")
94 95 self.oldpath = os.getcwd()
95 96 os.chdir(self.BASETESTDIR)
96 97
97 98 def tearDown(self):
98 99 os.chdir(self.oldpath)
99 100 shutil.rmtree(self.BASETESTDIR)
100 101
101 102 @onlyif_unicode_paths
102 103 def test_1(self):
103 104 """Test magic_run_completer, should match two alternatives
104 105 """
105 106 event = MockEvent(u"%run a")
106 107 mockself = None
107 108 match = set(magic_run_completer(mockself, event))
108 109 self.assertEqual(match, {u"a.py", u"aaΓΈ.py"})
109 110
110 111 @onlyif_unicode_paths
111 112 def test_2(self):
112 113 """Test magic_run_completer, should match one alternative
113 114 """
114 115 event = MockEvent(u"%run aa")
115 116 mockself = None
116 117 match = set(magic_run_completer(mockself, event))
117 118 self.assertEqual(match, {u"aaΓΈ.py"})
118 119
119 120 @onlyif_unicode_paths
120 121 def test_3(self):
121 122 """Test magic_run_completer with unterminated " """
122 123 event = MockEvent(u'%run "a')
123 124 mockself = None
124 125 match = set(magic_run_completer(mockself, event))
125 126 self.assertEqual(match, {u"a.py", u"aaΓΈ.py"})
126 127
127 128 # module_completer:
128 129
129 130 def test_import_invalid_module():
130 131 """Testing of issue https://github.com/ipython/ipython/issues/1107"""
131 132 invalid_module_names = {'foo-bar', 'foo:bar', '10foo'}
132 133 valid_module_names = {'foobar'}
133 134 with TemporaryDirectory() as tmpdir:
134 135 sys.path.insert( 0, tmpdir )
135 136 for name in invalid_module_names | valid_module_names:
136 137 filename = os.path.join(tmpdir, name + ".py")
137 138 open(filename, "w", encoding="utf-8").close()
138 139
139 140 s = set( module_completion('import foo') )
140 141 intersection = s.intersection(invalid_module_names)
141 142 assert intersection == set()
142 143
143 144 assert valid_module_names.issubset(s), valid_module_names.intersection(s)
144 145
145 146
146 147 def test_bad_module_all():
147 148 """Test module with invalid __all__
148 149
149 150 https://github.com/ipython/ipython/issues/9678
150 151 """
151 152 testsdir = os.path.dirname(__file__)
152 153 sys.path.insert(0, testsdir)
153 154 try:
154 155 results = module_completion("from bad_all import ")
155 156 assert "puppies" in results
156 157 for r in results:
157 158 assert isinstance(r, str)
158 159
159 160 # bad_all doesn't contain submodules, but this completion
160 161 # should finish without raising an exception:
161 162 results = module_completion("import bad_all.")
162 163 assert results == []
163 164 finally:
164 165 sys.path.remove(testsdir)
165 166
166 167
167 168 def test_module_without_init():
168 169 """
169 170 Test module without __init__.py.
170 171
171 172 https://github.com/ipython/ipython/issues/11226
172 173 """
173 174 fake_module_name = "foo"
174 175 with TemporaryDirectory() as tmpdir:
175 176 sys.path.insert(0, tmpdir)
176 177 try:
177 178 os.makedirs(os.path.join(tmpdir, fake_module_name))
178 179 s = try_import(mod=fake_module_name)
179 180 assert s == []
180 181 finally:
181 182 sys.path.remove(tmpdir)
182 183
183 184
184 185 def test_valid_exported_submodules():
185 186 """
186 187 Test checking exported (__all__) objects are submodules
187 188 """
188 189 results = module_completion("import os.pa")
189 190 # ensure we get a valid submodule:
190 191 assert "os.path" in results
191 192 # ensure we don't get objects that aren't submodules:
192 193 assert "os.pathconf" not in results
@@ -1,94 +1,95 b''
1 1 import os.path
2 2
3 from tempfile import TemporaryDirectory
4
3 5 import IPython.testing.tools as tt
4 6 from IPython.utils.syspathcontext import prepended_to_syspath
5 from IPython.utils.tempdir import TemporaryDirectory
6 7
7 8 ext1_content = """
8 9 def load_ipython_extension(ip):
9 10 print("Running ext1 load")
10 11
11 12 def unload_ipython_extension(ip):
12 13 print("Running ext1 unload")
13 14 """
14 15
15 16 ext2_content = """
16 17 def load_ipython_extension(ip):
17 18 print("Running ext2 load")
18 19 """
19 20
20 21 ext3_content = """
21 22 def load_ipython_extension(ip):
22 23 ip2 = get_ipython()
23 24 print(ip is ip2)
24 25 """
25 26
26 27 def test_extension_loading():
27 28 em = get_ipython().extension_manager
28 29 with TemporaryDirectory() as td:
29 30 ext1 = os.path.join(td, "ext1.py")
30 31 with open(ext1, "w", encoding="utf-8") as f:
31 32 f.write(ext1_content)
32 33
33 34 ext2 = os.path.join(td, "ext2.py")
34 35 with open(ext2, "w", encoding="utf-8") as f:
35 36 f.write(ext2_content)
36 37
37 38 with prepended_to_syspath(td):
38 39 assert 'ext1' not in em.loaded
39 40 assert 'ext2' not in em.loaded
40 41
41 42 # Load extension
42 43 with tt.AssertPrints("Running ext1 load"):
43 44 assert em.load_extension('ext1') is None
44 45 assert 'ext1' in em.loaded
45 46
46 47 # Should refuse to load it again
47 48 with tt.AssertNotPrints("Running ext1 load"):
48 49 assert em.load_extension('ext1') == 'already loaded'
49 50
50 51 # Reload
51 52 with tt.AssertPrints("Running ext1 unload"):
52 53 with tt.AssertPrints("Running ext1 load", suppress=False):
53 54 em.reload_extension('ext1')
54 55
55 56 # Unload
56 57 with tt.AssertPrints("Running ext1 unload"):
57 58 assert em.unload_extension('ext1') is None
58 59
59 60 # Can't unload again
60 61 with tt.AssertNotPrints("Running ext1 unload"):
61 62 assert em.unload_extension('ext1') == 'not loaded'
62 63 assert em.unload_extension('ext2') == 'not loaded'
63 64
64 65 # Load extension 2
65 66 with tt.AssertPrints("Running ext2 load"):
66 67 assert em.load_extension('ext2') is None
67 68
68 69 # Can't unload this
69 70 assert em.unload_extension('ext2') == 'no unload function'
70 71
71 72 # But can reload it
72 73 with tt.AssertPrints("Running ext2 load"):
73 74 em.reload_extension('ext2')
74 75
75 76
76 77 def test_extension_builtins():
77 78 em = get_ipython().extension_manager
78 79 with TemporaryDirectory() as td:
79 80 ext3 = os.path.join(td, "ext3.py")
80 81 with open(ext3, "w", encoding="utf-8") as f:
81 82 f.write(ext3_content)
82 83
83 84 assert 'ext3' not in em.loaded
84 85
85 86 with prepended_to_syspath(td):
86 87 # Load extension
87 88 with tt.AssertPrints("True"):
88 89 assert em.load_extension('ext3') is None
89 90 assert 'ext3' in em.loaded
90 91
91 92
92 93 def test_non_extension():
93 94 em = get_ipython().extension_manager
94 95 assert em.load_extension("sys") == "no load function"
@@ -1,227 +1,229 b''
1 1 # coding: utf-8
2 2 """Tests for the IPython tab-completion machinery.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Module imports
6 6 #-----------------------------------------------------------------------------
7 7
8 8 # stdlib
9 9 import io
10 from pathlib import Path
10 import sqlite3
11 11 import sys
12 12 import tempfile
13 13 from datetime import datetime
14 import sqlite3
14 from pathlib import Path
15 15
16 from tempfile import TemporaryDirectory
16 17 # our own packages
17 18 from traitlets.config.loader import Config
18 from IPython.utils.tempdir import TemporaryDirectory
19
19 20 from IPython.core.history import HistoryManager, extract_hist_ranges
20 21
22
21 23 def test_proper_default_encoding():
22 24 assert sys.getdefaultencoding() == "utf-8"
23 25
24 26 def test_history():
25 27 ip = get_ipython()
26 28 with TemporaryDirectory() as tmpdir:
27 29 tmp_path = Path(tmpdir)
28 30 hist_manager_ori = ip.history_manager
29 31 hist_file = tmp_path / "history.sqlite"
30 32 try:
31 33 ip.history_manager = HistoryManager(shell=ip, hist_file=hist_file)
32 34 hist = ["a=1", "def f():\n test = 1\n return test", "b='β‚¬Γ†ΒΎΓ·ΓŸ'"]
33 35 for i, h in enumerate(hist, start=1):
34 36 ip.history_manager.store_inputs(i, h)
35 37
36 38 ip.history_manager.db_log_output = True
37 39 # Doesn't match the input, but we'll just check it's stored.
38 40 ip.history_manager.output_hist_reprs[3] = "spam"
39 41 ip.history_manager.store_output(3)
40 42
41 43 assert ip.history_manager.input_hist_raw == [""] + hist
42 44
43 45 # Detailed tests for _get_range_session
44 46 grs = ip.history_manager._get_range_session
45 47 assert list(grs(start=2, stop=-1)) == list(zip([0], [2], hist[1:-1]))
46 48 assert list(grs(start=-2)) == list(zip([0, 0], [2, 3], hist[-2:]))
47 49 assert list(grs(output=True)) == list(
48 50 zip([0, 0, 0], [1, 2, 3], zip(hist, [None, None, "spam"]))
49 51 )
50 52
51 53 # Check whether specifying a range beyond the end of the current
52 54 # session results in an error (gh-804)
53 55 ip.magic('%hist 2-500')
54 56
55 57 # Check that we can write non-ascii characters to a file
56 58 ip.magic("%%hist -f %s" % (tmp_path / "test1"))
57 59 ip.magic("%%hist -pf %s" % (tmp_path / "test2"))
58 60 ip.magic("%%hist -nf %s" % (tmp_path / "test3"))
59 61 ip.magic("%%save %s 1-10" % (tmp_path / "test4"))
60 62
61 63 # New session
62 64 ip.history_manager.reset()
63 65 newcmds = ["z=5", "class X(object):\n pass", "k='p'", "z=5"]
64 66 for i, cmd in enumerate(newcmds, start=1):
65 67 ip.history_manager.store_inputs(i, cmd)
66 68 gothist = ip.history_manager.get_range(start=1, stop=4)
67 69 assert list(gothist) == list(zip([0, 0, 0], [1, 2, 3], newcmds))
68 70 # Previous session:
69 71 gothist = ip.history_manager.get_range(-1, 1, 4)
70 72 assert list(gothist) == list(zip([1, 1, 1], [1, 2, 3], hist))
71 73
72 74 newhist = [(2, i, c) for (i, c) in enumerate(newcmds, 1)]
73 75
74 76 # Check get_hist_tail
75 77 gothist = ip.history_manager.get_tail(5, output=True,
76 78 include_latest=True)
77 79 expected = [(1, 3, (hist[-1], "spam"))] \
78 80 + [(s, n, (c, None)) for (s, n, c) in newhist]
79 81 assert list(gothist) == expected
80 82
81 83 gothist = ip.history_manager.get_tail(2)
82 84 expected = newhist[-3:-1]
83 85 assert list(gothist) == expected
84 86
85 87 # Check get_hist_search
86 88
87 89 gothist = ip.history_manager.search("*test*")
88 90 assert list(gothist) == [(1, 2, hist[1])]
89 91
90 92 gothist = ip.history_manager.search("*=*")
91 93 assert list(gothist) == [
92 94 (1, 1, hist[0]),
93 95 (1, 2, hist[1]),
94 96 (1, 3, hist[2]),
95 97 newhist[0],
96 98 newhist[2],
97 99 newhist[3],
98 100 ]
99 101
100 102 gothist = ip.history_manager.search("*=*", n=4)
101 103 assert list(gothist) == [
102 104 (1, 3, hist[2]),
103 105 newhist[0],
104 106 newhist[2],
105 107 newhist[3],
106 108 ]
107 109
108 110 gothist = ip.history_manager.search("*=*", unique=True)
109 111 assert list(gothist) == [
110 112 (1, 1, hist[0]),
111 113 (1, 2, hist[1]),
112 114 (1, 3, hist[2]),
113 115 newhist[2],
114 116 newhist[3],
115 117 ]
116 118
117 119 gothist = ip.history_manager.search("*=*", unique=True, n=3)
118 120 assert list(gothist) == [(1, 3, hist[2]), newhist[2], newhist[3]]
119 121
120 122 gothist = ip.history_manager.search("b*", output=True)
121 123 assert list(gothist) == [(1, 3, (hist[2], "spam"))]
122 124
123 125 # Cross testing: check that magic %save can get previous session.
124 126 testfilename = (tmp_path / "test.py").resolve()
125 127 ip.magic("save " + str(testfilename) + " ~1/1-3")
126 128 with io.open(testfilename, encoding="utf-8") as testfile:
127 129 assert testfile.read() == "# coding: utf-8\n" + "\n".join(hist) + "\n"
128 130
129 131 # Duplicate line numbers - check that it doesn't crash, and
130 132 # gets a new session
131 133 ip.history_manager.store_inputs(1, "rogue")
132 134 ip.history_manager.writeout_cache()
133 135 assert ip.history_manager.session_number == 3
134 136
135 137 # Check that session and line values are not just max values
136 138 sessid, lineno, entry = newhist[-1]
137 139 assert lineno > 1
138 140 ip.history_manager.reset()
139 141 lineno = 1
140 142 ip.history_manager.store_inputs(lineno, entry)
141 143 gothist = ip.history_manager.search("*=*", unique=True)
142 144 hist = list(gothist)[-1]
143 145 assert sessid < hist[0]
144 146 assert hist[1:] == (lineno, entry)
145 147 finally:
146 148 # Ensure saving thread is shut down before we try to clean up the files
147 149 ip.history_manager.save_thread.stop()
148 150 # Forcibly close database rather than relying on garbage collection
149 151 ip.history_manager.db.close()
150 152 # Restore history manager
151 153 ip.history_manager = hist_manager_ori
152 154
153 155
154 156 def test_extract_hist_ranges():
155 157 instr = "1 2/3 ~4/5-6 ~4/7-~4/9 ~9/2-~7/5 ~10/"
156 158 expected = [(0, 1, 2), # 0 == current session
157 159 (2, 3, 4),
158 160 (-4, 5, 7),
159 161 (-4, 7, 10),
160 162 (-9, 2, None), # None == to end
161 163 (-8, 1, None),
162 164 (-7, 1, 6),
163 165 (-10, 1, None)]
164 166 actual = list(extract_hist_ranges(instr))
165 167 assert actual == expected
166 168
167 169
168 170 def test_extract_hist_ranges_empty_str():
169 171 instr = ""
170 172 expected = [(0, 1, None)] # 0 == current session, None == to end
171 173 actual = list(extract_hist_ranges(instr))
172 174 assert actual == expected
173 175
174 176
175 177 def test_magic_rerun():
176 178 """Simple test for %rerun (no args -> rerun last line)"""
177 179 ip = get_ipython()
178 180 ip.run_cell("a = 10", store_history=True)
179 181 ip.run_cell("a += 1", store_history=True)
180 182 assert ip.user_ns["a"] == 11
181 183 ip.run_cell("%rerun", store_history=True)
182 184 assert ip.user_ns["a"] == 12
183 185
184 186 def test_timestamp_type():
185 187 ip = get_ipython()
186 188 info = ip.history_manager.get_session_info()
187 189 assert isinstance(info[1], datetime)
188 190
189 191 def test_hist_file_config():
190 192 cfg = Config()
191 193 tfile = tempfile.NamedTemporaryFile(delete=False)
192 194 cfg.HistoryManager.hist_file = Path(tfile.name)
193 195 try:
194 196 hm = HistoryManager(shell=get_ipython(), config=cfg)
195 197 assert hm.hist_file == cfg.HistoryManager.hist_file
196 198 finally:
197 199 try:
198 200 Path(tfile.name).unlink()
199 201 except OSError:
200 202 # same catch as in testing.tools.TempFileMixin
201 203 # On Windows, even though we close the file, we still can't
202 204 # delete it. I have no clue why
203 205 pass
204 206
205 207 def test_histmanager_disabled():
206 208 """Ensure that disabling the history manager doesn't create a database."""
207 209 cfg = Config()
208 210 cfg.HistoryAccessor.enabled = False
209 211
210 212 ip = get_ipython()
211 213 with TemporaryDirectory() as tmpdir:
212 214 hist_manager_ori = ip.history_manager
213 215 hist_file = Path(tmpdir) / "history.sqlite"
214 216 cfg.HistoryManager.hist_file = hist_file
215 217 try:
216 218 ip.history_manager = HistoryManager(shell=ip, config=cfg)
217 219 hist = ["a=1", "def f():\n test = 1\n return test", "b='β‚¬Γ†ΒΎΓ·ΓŸ'"]
218 220 for i, h in enumerate(hist, start=1):
219 221 ip.history_manager.store_inputs(i, h)
220 222 assert ip.history_manager.input_hist_raw == [""] + hist
221 223 ip.history_manager.reset()
222 224 ip.history_manager.end_session()
223 225 finally:
224 226 ip.history_manager = hist_manager_ori
225 227
226 228 # hist_file should not be created
227 229 assert hist_file.exists() is False
@@ -1,26 +1,27 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Test IPython.core.logger"""
3 3
4 4 import os.path
5
5 6 import pytest
7 from tempfile import TemporaryDirectory
6 8
7 from IPython.utils.tempdir import TemporaryDirectory
8 9
9 10 def test_logstart_inaccessible_file():
10 11 with pytest.raises(IOError):
11 12 _ip.logger.logstart(logfname="/") # Opening that filename will fail.
12 13
13 14 try:
14 15 _ip.run_cell("a=1") # Check it doesn't try to log this
15 16 finally:
16 17 _ip.logger.log_active = False # If this fails, don't let later tests fail
17 18
18 19 def test_logstart_unicode():
19 20 with TemporaryDirectory() as tdir:
20 21 logfname = os.path.join(tdir, "test_unicode.log")
21 22 _ip.run_cell("'abc€'")
22 23 try:
23 24 _ip.magic("logstart -to %s" % logfname)
24 25 _ip.run_cell("'abc€'")
25 26 finally:
26 27 _ip.logger.logstop()
@@ -1,201 +1,201 b''
1 1 import errno
2 2 import os
3 3 import shutil
4 4 import sys
5 5 import tempfile
6 6 import warnings
7 7 from unittest.mock import patch
8 8
9 from testpath import modified_env, assert_isdir, assert_isfile
9 from tempfile import TemporaryDirectory
10 from testpath import assert_isdir, assert_isfile, modified_env
10 11
11 12 from IPython import paths
12 13 from IPython.testing.decorators import skip_win32
13 from IPython.utils.tempdir import TemporaryDirectory
14 14
15 15 TMP_TEST_DIR = os.path.realpath(tempfile.mkdtemp())
16 16 HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
17 17 XDG_TEST_DIR = os.path.join(HOME_TEST_DIR, "xdg_test_dir")
18 18 XDG_CACHE_DIR = os.path.join(HOME_TEST_DIR, "xdg_cache_dir")
19 19 IP_TEST_DIR = os.path.join(HOME_TEST_DIR,'.ipython')
20 20
21 21 def setup_module():
22 22 """Setup testenvironment for the module:
23 23
24 24 - Adds dummy home dir tree
25 25 """
26 26 # Do not mask exceptions here. In particular, catching WindowsError is a
27 27 # problem because that exception is only defined on Windows...
28 28 os.makedirs(IP_TEST_DIR)
29 29 os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
30 30 os.makedirs(os.path.join(XDG_CACHE_DIR, 'ipython'))
31 31
32 32
33 33 def teardown_module():
34 34 """Teardown testenvironment for the module:
35 35
36 36 - Remove dummy home dir tree
37 37 """
38 38 # Note: we remove the parent test dir, which is the root of all test
39 39 # subdirs we may have created. Use shutil instead of os.removedirs, so
40 40 # that non-empty directories are all recursively removed.
41 41 shutil.rmtree(TMP_TEST_DIR)
42 42
43 43 def patch_get_home_dir(dirpath):
44 44 return patch.object(paths, 'get_home_dir', return_value=dirpath)
45 45
46 46
47 47 def test_get_ipython_dir_1():
48 48 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
49 49 env_ipdir = os.path.join("someplace", ".ipython")
50 50 with patch.object(paths, '_writable_dir', return_value=True), \
51 51 modified_env({'IPYTHONDIR': env_ipdir}):
52 52 ipdir = paths.get_ipython_dir()
53 53
54 54 assert ipdir == env_ipdir
55 55
56 56 def test_get_ipython_dir_2():
57 57 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
58 58 with patch_get_home_dir('someplace'), \
59 59 patch.object(paths, 'get_xdg_dir', return_value=None), \
60 60 patch.object(paths, '_writable_dir', return_value=True), \
61 61 patch('os.name', "posix"), \
62 62 modified_env({'IPYTHON_DIR': None,
63 63 'IPYTHONDIR': None,
64 64 'XDG_CONFIG_HOME': None
65 65 }):
66 66 ipdir = paths.get_ipython_dir()
67 67
68 68 assert ipdir == os.path.join("someplace", ".ipython")
69 69
70 70 def test_get_ipython_dir_3():
71 71 """test_get_ipython_dir_3, use XDG if defined and exists, and .ipython doesn't exist."""
72 72 tmphome = TemporaryDirectory()
73 73 try:
74 74 with patch_get_home_dir(tmphome.name), \
75 75 patch('os.name', 'posix'), \
76 76 modified_env({
77 77 'IPYTHON_DIR': None,
78 78 'IPYTHONDIR': None,
79 79 'XDG_CONFIG_HOME': XDG_TEST_DIR,
80 80 }), warnings.catch_warnings(record=True) as w:
81 81 ipdir = paths.get_ipython_dir()
82 82
83 83 assert ipdir == os.path.join(tmphome.name, XDG_TEST_DIR, "ipython")
84 84 assert len(w) == 0
85 85 finally:
86 86 tmphome.cleanup()
87 87
88 88 def test_get_ipython_dir_4():
89 89 """test_get_ipython_dir_4, warn if XDG and home both exist."""
90 90 with patch_get_home_dir(HOME_TEST_DIR), \
91 91 patch('os.name', 'posix'):
92 92 try:
93 93 os.mkdir(os.path.join(XDG_TEST_DIR, 'ipython'))
94 94 except OSError as e:
95 95 if e.errno != errno.EEXIST:
96 96 raise
97 97
98 98
99 99 with modified_env({
100 100 'IPYTHON_DIR': None,
101 101 'IPYTHONDIR': None,
102 102 'XDG_CONFIG_HOME': XDG_TEST_DIR,
103 103 }), warnings.catch_warnings(record=True) as w:
104 104 ipdir = paths.get_ipython_dir()
105 105
106 106 assert len(w) == 1
107 107 assert "Ignoring" in str(w[0])
108 108
109 109
110 110 def test_get_ipython_dir_5():
111 111 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
112 112 with patch_get_home_dir(HOME_TEST_DIR), \
113 113 patch('os.name', 'posix'):
114 114 try:
115 115 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
116 116 except OSError as e:
117 117 if e.errno != errno.ENOENT:
118 118 raise
119 119
120 120 with modified_env({
121 121 'IPYTHON_DIR': None,
122 122 'IPYTHONDIR': None,
123 123 'XDG_CONFIG_HOME': XDG_TEST_DIR,
124 124 }):
125 125 ipdir = paths.get_ipython_dir()
126 126
127 127 assert ipdir == IP_TEST_DIR
128 128
129 129 def test_get_ipython_dir_6():
130 130 """test_get_ipython_dir_6, use home over XDG if defined and neither exist."""
131 131 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
132 132 os.mkdir(xdg)
133 133 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
134 134 print(paths._writable_dir)
135 135 with patch_get_home_dir(HOME_TEST_DIR), \
136 136 patch.object(paths, 'get_xdg_dir', return_value=xdg), \
137 137 patch('os.name', 'posix'), \
138 138 modified_env({
139 139 'IPYTHON_DIR': None,
140 140 'IPYTHONDIR': None,
141 141 'XDG_CONFIG_HOME': None,
142 142 }), warnings.catch_warnings(record=True) as w:
143 143 ipdir = paths.get_ipython_dir()
144 144
145 145 assert ipdir == os.path.join(HOME_TEST_DIR, ".ipython")
146 146 assert len(w) == 0
147 147
148 148 def test_get_ipython_dir_7():
149 149 """test_get_ipython_dir_7, test home directory expansion on IPYTHONDIR"""
150 150 home_dir = os.path.normpath(os.path.expanduser('~'))
151 151 with modified_env({'IPYTHONDIR': os.path.join('~', 'somewhere')}), \
152 152 patch.object(paths, '_writable_dir', return_value=True):
153 153 ipdir = paths.get_ipython_dir()
154 154 assert ipdir == os.path.join(home_dir, "somewhere")
155 155
156 156
157 157 @skip_win32
158 158 def test_get_ipython_dir_8():
159 159 """test_get_ipython_dir_8, test / home directory"""
160 160 if not os.access("/", os.W_OK):
161 161 # test only when HOME directory actually writable
162 162 return
163 163
164 164 with patch.object(paths, "_writable_dir", lambda path: bool(path)), patch.object(
165 165 paths, "get_xdg_dir", return_value=None
166 166 ), modified_env(
167 167 {
168 168 "IPYTHON_DIR": None,
169 169 "IPYTHONDIR": None,
170 170 "HOME": "/",
171 171 }
172 172 ):
173 173 assert paths.get_ipython_dir() == "/.ipython"
174 174
175 175
176 176 def test_get_ipython_cache_dir():
177 177 with modified_env({'HOME': HOME_TEST_DIR}):
178 178 if os.name == "posix":
179 179 # test default
180 180 os.makedirs(os.path.join(HOME_TEST_DIR, ".cache"))
181 181 with modified_env({'XDG_CACHE_HOME': None}):
182 182 ipdir = paths.get_ipython_cache_dir()
183 183 assert os.path.join(HOME_TEST_DIR, ".cache", "ipython") == ipdir
184 184 assert_isdir(ipdir)
185 185
186 186 # test env override
187 187 with modified_env({"XDG_CACHE_HOME": XDG_CACHE_DIR}):
188 188 ipdir = paths.get_ipython_cache_dir()
189 189 assert_isdir(ipdir)
190 190 assert ipdir == os.path.join(XDG_CACHE_DIR, "ipython")
191 191 else:
192 192 assert paths.get_ipython_cache_dir() == paths.get_ipython_dir()
193 193
194 194 def test_get_ipython_package_dir():
195 195 ipdir = paths.get_ipython_package_dir()
196 196 assert_isdir(ipdir)
197 197
198 198
199 199 def test_get_ipython_module_path():
200 200 ipapp_path = paths.get_ipython_module_path('IPython.terminal.ipapp')
201 201 assert_isfile(ipapp_path)
@@ -1,156 +1,155 b''
1 1 # coding: utf-8
2 2 """Tests for profile-related functions.
3 3
4 4 Currently only the startup-dir functionality is tested, but more tests should
5 5 be added for:
6 6
7 7 * ipython profile create
8 8 * ipython profile list
9 9 * ipython profile create --parallel
10 10 * security dir permissions
11 11
12 12 Authors
13 13 -------
14 14
15 15 * MinRK
16 16
17 17 """
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import shutil
24 24 import sys
25 25 import tempfile
26
27 26 from pathlib import Path
28 27 from unittest import TestCase
29 28
30 from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
31 from IPython.core.profiledir import ProfileDir
29 from tempfile import TemporaryDirectory
32 30
31 from IPython.core.profileapp import list_bundled_profiles, list_profiles_in
32 from IPython.core.profiledir import ProfileDir
33 33 from IPython.testing import decorators as dec
34 34 from IPython.testing import tools as tt
35 35 from IPython.utils.process import getoutput
36 from IPython.utils.tempdir import TemporaryDirectory
37 36
38 37 #-----------------------------------------------------------------------------
39 38 # Globals
40 39 #-----------------------------------------------------------------------------
41 40 TMP_TEST_DIR = Path(tempfile.mkdtemp())
42 41 HOME_TEST_DIR = TMP_TEST_DIR / "home_test_dir"
43 42 IP_TEST_DIR = HOME_TEST_DIR / ".ipython"
44 43
45 44 #
46 45 # Setup/teardown functions/decorators
47 46 #
48 47
49 48 def setup_module():
50 49 """Setup test environment for the module:
51 50
52 51 - Adds dummy home dir tree
53 52 """
54 53 # Do not mask exceptions here. In particular, catching WindowsError is a
55 54 # problem because that exception is only defined on Windows...
56 55 (Path.cwd() / IP_TEST_DIR).mkdir(parents=True)
57 56
58 57
59 58 def teardown_module():
60 59 """Teardown test environment for the module:
61 60
62 61 - Remove dummy home dir tree
63 62 """
64 63 # Note: we remove the parent test dir, which is the root of all test
65 64 # subdirs we may have created. Use shutil instead of os.removedirs, so
66 65 # that non-empty directories are all recursively removed.
67 66 shutil.rmtree(TMP_TEST_DIR)
68 67
69 68
70 69 #-----------------------------------------------------------------------------
71 70 # Test functions
72 71 #-----------------------------------------------------------------------------
73 72 class ProfileStartupTest(TestCase):
74 73 def setUp(self):
75 74 # create profile dir
76 75 self.pd = ProfileDir.create_profile_dir_by_name(IP_TEST_DIR, "test")
77 76 self.options = ["--ipython-dir", IP_TEST_DIR, "--profile", "test"]
78 77 self.fname = TMP_TEST_DIR / "test.py"
79 78
80 79 def tearDown(self):
81 80 # We must remove this profile right away so its presence doesn't
82 81 # confuse other tests.
83 82 shutil.rmtree(self.pd.location)
84 83
85 84 def init(self, startup_file, startup, test):
86 85 # write startup python file
87 86 with open(Path(self.pd.startup_dir) / startup_file, "w", encoding="utf-8") as f:
88 87 f.write(startup)
89 88 # write simple test file, to check that the startup file was run
90 89 with open(self.fname, "w", encoding="utf-8") as f:
91 90 f.write(test)
92 91
93 92 def validate(self, output):
94 93 tt.ipexec_validate(self.fname, output, "", options=self.options)
95 94
96 95 def test_startup_py(self):
97 96 self.init('00-start.py', 'zzz=123\n', 'print(zzz)\n')
98 97 self.validate('123')
99 98
100 99 def test_startup_ipy(self):
101 100 self.init('00-start.ipy', '%xmode plain\n', '')
102 101 self.validate('Exception reporting mode: Plain')
103 102
104 103
105 104 def test_list_profiles_in():
106 105 # No need to remove these directories and files, as they will get nuked in
107 106 # the module-level teardown.
108 107 td = Path(tempfile.mkdtemp(dir=TMP_TEST_DIR))
109 108 for name in ("profile_foo", "profile_hello", "not_a_profile"):
110 109 Path(td / name).mkdir(parents=True)
111 110 if dec.unicode_paths:
112 111 Path(td / u"profile_ΓΌnicode").mkdir(parents=True)
113 112
114 113 with open(td / "profile_file", "w", encoding="utf-8") as f:
115 114 f.write("I am not a profile directory")
116 115 profiles = list_profiles_in(td)
117 116
118 117 # unicode normalization can turn u'ΓΌnicode' into u'u\0308nicode',
119 118 # so only check for *nicode, and that creating a ProfileDir from the
120 119 # name remains valid
121 120 found_unicode = False
122 121 for p in list(profiles):
123 122 if p.endswith('nicode'):
124 123 pd = ProfileDir.find_profile_dir_by_name(td, p)
125 124 profiles.remove(p)
126 125 found_unicode = True
127 126 break
128 127 if dec.unicode_paths:
129 128 assert found_unicode is True
130 129 assert set(profiles) == {"foo", "hello"}
131 130
132 131
133 132 def test_list_bundled_profiles():
134 133 # This variable will need to be updated when a new profile gets bundled
135 134 bundled = sorted(list_bundled_profiles())
136 135 assert bundled == []
137 136
138 137
139 138 def test_profile_create_ipython_dir():
140 139 """ipython profile create respects --ipython-dir"""
141 140 with TemporaryDirectory() as td:
142 141 getoutput(
143 142 [
144 143 sys.executable,
145 144 "-m",
146 145 "IPython",
147 146 "profile",
148 147 "create",
149 148 "foo",
150 149 "--ipython-dir=%s" % td,
151 150 ]
152 151 )
153 152 profile_dir = Path(td) / "profile_foo"
154 153 assert Path(profile_dir).exists()
155 154 ipython_config = profile_dir / "ipython_config.py"
156 155 assert Path(ipython_config).exists()
@@ -1,620 +1,622 b''
1 1 # encoding: utf-8
2 2 """Tests for code execution (%run and related), which is particularly tricky.
3 3
4 4 Because of how %run manages namespaces, and the fact that we are trying here to
5 5 verify subtle object deletion and reference counting issues, the %run tests
6 6 will be kept in this separate file. This makes it easier to aggregate in one
7 7 place the tricks needed to handle it; most other magics are much easier to test
8 8 and we do so in a common test_magic file.
9 9
10 10 Note that any test using `run -i` should make sure to do a `reset` afterwards,
11 11 as otherwise it may influence later tests.
12 12 """
13 13
14 14 # Copyright (c) IPython Development Team.
15 15 # Distributed under the terms of the Modified BSD License.
16 16
17 17
18 18
19 19 import functools
20 20 import os
21 21 import platform
22 from os.path import join as pjoin
23 22 import random
24 23 import string
25 24 import sys
26 25 import textwrap
27 26 import unittest
27 from os.path import join as pjoin
28 28 from unittest.mock import patch
29 29
30 30 import pytest
31 from tempfile import TemporaryDirectory
31 32
33 from IPython.core import debugger
32 34 from IPython.testing import decorators as dec
33 35 from IPython.testing import tools as tt
34 36 from IPython.utils.io import capture_output
35 from IPython.utils.tempdir import TemporaryDirectory
36 from IPython.core import debugger
37
37 38
38 39 def doctest_refbug():
39 40 """Very nasty problem with references held by multiple runs of a script.
40 41 See: https://github.com/ipython/ipython/issues/141
41 42
42 43 In [1]: _ip.clear_main_mod_cache()
43 44 # random
44 45
45 46 In [2]: %run refbug
46 47
47 48 In [3]: call_f()
48 49 lowercased: hello
49 50
50 51 In [4]: %run refbug
51 52
52 53 In [5]: call_f()
53 54 lowercased: hello
54 55 lowercased: hello
55 56 """
56 57
57 58
58 59 def doctest_run_builtins():
59 60 r"""Check that %run doesn't damage __builtins__.
60 61
61 62 In [1]: import tempfile
62 63
63 64 In [2]: bid1 = id(__builtins__)
64 65
65 66 In [3]: fname = tempfile.mkstemp('.py')[1]
66 67
67 68 In [3]: f = open(fname, 'w', encoding='utf-8')
68 69
69 70 In [4]: dummy= f.write('pass\n')
70 71
71 72 In [5]: f.flush()
72 73
73 74 In [6]: t1 = type(__builtins__)
74 75
75 76 In [7]: %run $fname
76 77
77 78 In [7]: f.close()
78 79
79 80 In [8]: bid2 = id(__builtins__)
80 81
81 82 In [9]: t2 = type(__builtins__)
82 83
83 84 In [10]: t1 == t2
84 85 Out[10]: True
85 86
86 87 In [10]: bid1 == bid2
87 88 Out[10]: True
88 89
89 90 In [12]: try:
90 91 ....: os.unlink(fname)
91 92 ....: except:
92 93 ....: pass
93 94 ....:
94 95 """
95 96
96 97
97 98 def doctest_run_option_parser():
98 99 r"""Test option parser in %run.
99 100
100 101 In [1]: %run print_argv.py
101 102 []
102 103
103 104 In [2]: %run print_argv.py print*.py
104 105 ['print_argv.py']
105 106
106 107 In [3]: %run -G print_argv.py print*.py
107 108 ['print*.py']
108 109
109 110 """
110 111
111 112
112 113 @dec.skip_win32
113 114 def doctest_run_option_parser_for_posix():
114 115 r"""Test option parser in %run (Linux/OSX specific).
115 116
116 117 You need double quote to escape glob in POSIX systems:
117 118
118 119 In [1]: %run print_argv.py print\\*.py
119 120 ['print*.py']
120 121
121 122 You can't use quote to escape glob in POSIX systems:
122 123
123 124 In [2]: %run print_argv.py 'print*.py'
124 125 ['print_argv.py']
125 126
126 127 """
127 128
128 129
129 130 doctest_run_option_parser_for_posix.__skip_doctest__ = sys.platform == "win32"
130 131
131 132
132 133 @dec.skip_if_not_win32
133 134 def doctest_run_option_parser_for_windows():
134 135 r"""Test option parser in %run (Windows specific).
135 136
136 137 In Windows, you can't escape ``*` `by backslash:
137 138
138 139 In [1]: %run print_argv.py print\\*.py
139 140 ['print\\\\*.py']
140 141
141 142 You can use quote to escape glob:
142 143
143 144 In [2]: %run print_argv.py 'print*.py'
144 145 ["'print*.py'"]
145 146
146 147 """
147 148
148 149
149 150 doctest_run_option_parser_for_windows.__skip_doctest__ = sys.platform != "win32"
150 151
151 152
152 153 def doctest_reset_del():
153 154 """Test that resetting doesn't cause errors in __del__ methods.
154 155
155 156 In [2]: class A(object):
156 157 ...: def __del__(self):
157 158 ...: print(str("Hi"))
158 159 ...:
159 160
160 161 In [3]: a = A()
161 162
162 163 In [4]: get_ipython().reset(); import gc; x = gc.collect(0)
163 164 Hi
164 165
165 166 In [5]: 1+1
166 167 Out[5]: 2
167 168 """
168 169
169 170 # For some tests, it will be handy to organize them in a class with a common
170 171 # setup that makes a temp file
171 172
172 173 class TestMagicRunPass(tt.TempFileMixin):
173 174
174 175 def setUp(self):
175 176 content = "a = [1,2,3]\nb = 1"
176 177 self.mktmp(content)
177 178
178 179 def run_tmpfile(self):
179 180 _ip = get_ipython()
180 181 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
181 182 # See below and ticket https://bugs.launchpad.net/bugs/366353
182 183 _ip.magic('run %s' % self.fname)
183 184
184 185 def run_tmpfile_p(self):
185 186 _ip = get_ipython()
186 187 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
187 188 # See below and ticket https://bugs.launchpad.net/bugs/366353
188 189 _ip.magic('run -p %s' % self.fname)
189 190
190 191 def test_builtins_id(self):
191 192 """Check that %run doesn't damage __builtins__ """
192 193 _ip = get_ipython()
193 194 # Test that the id of __builtins__ is not modified by %run
194 195 bid1 = id(_ip.user_ns['__builtins__'])
195 196 self.run_tmpfile()
196 197 bid2 = id(_ip.user_ns['__builtins__'])
197 198 assert bid1 == bid2
198 199
199 200 def test_builtins_type(self):
200 201 """Check that the type of __builtins__ doesn't change with %run.
201 202
202 203 However, the above could pass if __builtins__ was already modified to
203 204 be a dict (it should be a module) by a previous use of %run. So we
204 205 also check explicitly that it really is a module:
205 206 """
206 207 _ip = get_ipython()
207 208 self.run_tmpfile()
208 209 assert type(_ip.user_ns["__builtins__"]) == type(sys)
209 210
210 211 def test_run_profile(self):
211 212 """Test that the option -p, which invokes the profiler, do not
212 213 crash by invoking execfile"""
213 214 self.run_tmpfile_p()
214 215
215 216 def test_run_debug_twice(self):
216 217 # https://github.com/ipython/ipython/issues/10028
217 218 _ip = get_ipython()
218 219 with tt.fake_input(['c']):
219 220 _ip.magic('run -d %s' % self.fname)
220 221 with tt.fake_input(['c']):
221 222 _ip.magic('run -d %s' % self.fname)
222 223
223 224 def test_run_debug_twice_with_breakpoint(self):
224 225 """Make a valid python temp file."""
225 226 _ip = get_ipython()
226 227 with tt.fake_input(['b 2', 'c', 'c']):
227 228 _ip.magic('run -d %s' % self.fname)
228 229
229 230 with tt.fake_input(['c']):
230 231 with tt.AssertNotPrints('KeyError'):
231 232 _ip.magic('run -d %s' % self.fname)
232 233
233 234
234 235 class TestMagicRunSimple(tt.TempFileMixin):
235 236
236 237 def test_simpledef(self):
237 238 """Test that simple class definitions work."""
238 239 src = ("class foo: pass\n"
239 240 "def f(): return foo()")
240 241 self.mktmp(src)
241 242 _ip.magic("run %s" % self.fname)
242 243 _ip.run_cell("t = isinstance(f(), foo)")
243 244 assert _ip.user_ns["t"] is True
244 245
245 246 @pytest.mark.xfail(
246 247 platform.python_implementation() == "PyPy",
247 248 reason="expecting __del__ call on exit is unreliable and doesn't happen on PyPy",
248 249 )
249 250 def test_obj_del(self):
250 251 """Test that object's __del__ methods are called on exit."""
251 252 src = ("class A(object):\n"
252 253 " def __del__(self):\n"
253 254 " print('object A deleted')\n"
254 255 "a = A()\n")
255 256 self.mktmp(src)
256 257 err = None
257 258 tt.ipexec_validate(self.fname, 'object A deleted', err)
258 259
259 260 def test_aggressive_namespace_cleanup(self):
260 261 """Test that namespace cleanup is not too aggressive GH-238
261 262
262 263 Returning from another run magic deletes the namespace"""
263 264 # see ticket https://github.com/ipython/ipython/issues/238
264 265
265 266 with tt.TempFileMixin() as empty:
266 267 empty.mktmp("")
267 268 # On Windows, the filename will have \users in it, so we need to use the
268 269 # repr so that the \u becomes \\u.
269 270 src = (
270 271 "ip = get_ipython()\n"
271 272 "for i in range(5):\n"
272 273 " try:\n"
273 274 " ip.magic(%r)\n"
274 275 " except NameError as e:\n"
275 276 " print(i)\n"
276 277 " break\n" % ("run " + empty.fname)
277 278 )
278 279 self.mktmp(src)
279 280 _ip.magic("run %s" % self.fname)
280 281 _ip.run_cell("ip == get_ipython()")
281 282 assert _ip.user_ns["i"] == 4
282 283
283 284 def test_run_second(self):
284 285 """Test that running a second file doesn't clobber the first, gh-3547"""
285 286 self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n")
286 287
287 288 with tt.TempFileMixin() as empty:
288 289 empty.mktmp("")
289 290
290 291 _ip.magic("run %s" % self.fname)
291 292 _ip.magic("run %s" % empty.fname)
292 293 assert _ip.user_ns["afunc"]() == 1
293 294
294 295 def test_tclass(self):
295 296 mydir = os.path.dirname(__file__)
296 297 tc = os.path.join(mydir, "tclass")
297 298 src = f"""\
298 299 import gc
299 300 %run "{tc}" C-first
300 301 gc.collect(0)
301 302 %run "{tc}" C-second
302 303 gc.collect(0)
303 304 %run "{tc}" C-third
304 305 gc.collect(0)
305 306 %reset -f
306 307 """
307 308 self.mktmp(src, ".ipy")
308 309 out = """\
309 310 ARGV 1-: ['C-first']
310 311 ARGV 1-: ['C-second']
311 312 tclass.py: deleting object: C-first
312 313 ARGV 1-: ['C-third']
313 314 tclass.py: deleting object: C-second
314 315 tclass.py: deleting object: C-third
315 316 """
316 317 err = None
317 318 tt.ipexec_validate(self.fname, out, err)
318 319
319 320 def test_run_i_after_reset(self):
320 321 """Check that %run -i still works after %reset (gh-693)"""
321 322 src = "yy = zz\n"
322 323 self.mktmp(src)
323 324 _ip.run_cell("zz = 23")
324 325 try:
325 326 _ip.magic("run -i %s" % self.fname)
326 327 assert _ip.user_ns["yy"] == 23
327 328 finally:
328 329 _ip.magic('reset -f')
329 330
330 331 _ip.run_cell("zz = 23")
331 332 try:
332 333 _ip.magic("run -i %s" % self.fname)
333 334 assert _ip.user_ns["yy"] == 23
334 335 finally:
335 336 _ip.magic('reset -f')
336 337
337 338 def test_unicode(self):
338 339 """Check that files in odd encodings are accepted."""
339 340 mydir = os.path.dirname(__file__)
340 341 na = os.path.join(mydir, 'nonascii.py')
341 342 _ip.magic('run "%s"' % na)
342 343 assert _ip.user_ns["u"] == "ΠŽΡ‚β„–Π€"
343 344
344 345 def test_run_py_file_attribute(self):
345 346 """Test handling of `__file__` attribute in `%run <file>.py`."""
346 347 src = "t = __file__\n"
347 348 self.mktmp(src)
348 349 _missing = object()
349 350 file1 = _ip.user_ns.get('__file__', _missing)
350 351 _ip.magic('run %s' % self.fname)
351 352 file2 = _ip.user_ns.get('__file__', _missing)
352 353
353 354 # Check that __file__ was equal to the filename in the script's
354 355 # namespace.
355 356 assert _ip.user_ns["t"] == self.fname
356 357
357 358 # Check that __file__ was not leaked back into user_ns.
358 359 assert file1 == file2
359 360
360 361 def test_run_ipy_file_attribute(self):
361 362 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
362 363 src = "t = __file__\n"
363 364 self.mktmp(src, ext='.ipy')
364 365 _missing = object()
365 366 file1 = _ip.user_ns.get('__file__', _missing)
366 367 _ip.magic('run %s' % self.fname)
367 368 file2 = _ip.user_ns.get('__file__', _missing)
368 369
369 370 # Check that __file__ was equal to the filename in the script's
370 371 # namespace.
371 372 assert _ip.user_ns["t"] == self.fname
372 373
373 374 # Check that __file__ was not leaked back into user_ns.
374 375 assert file1 == file2
375 376
376 377 def test_run_formatting(self):
377 378 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
378 379 src = "pass"
379 380 self.mktmp(src)
380 381 _ip.magic('run -t -N 1 %s' % self.fname)
381 382 _ip.magic('run -t -N 10 %s' % self.fname)
382 383
383 384 def test_ignore_sys_exit(self):
384 385 """Test the -e option to ignore sys.exit()"""
385 386 src = "import sys; sys.exit(1)"
386 387 self.mktmp(src)
387 388 with tt.AssertPrints('SystemExit'):
388 389 _ip.magic('run %s' % self.fname)
389 390
390 391 with tt.AssertNotPrints('SystemExit'):
391 392 _ip.magic('run -e %s' % self.fname)
392 393
393 394 def test_run_nb(self):
394 395 """Test %run notebook.ipynb"""
395 396 pytest.importorskip("nbformat")
396 397 from nbformat import v4, writes
397 398 nb = v4.new_notebook(
398 399 cells=[
399 400 v4.new_markdown_cell("The Ultimate Question of Everything"),
400 401 v4.new_code_cell("answer=42")
401 402 ]
402 403 )
403 404 src = writes(nb, version=4)
404 405 self.mktmp(src, ext='.ipynb')
405 406
406 407 _ip.magic("run %s" % self.fname)
407 408
408 409 assert _ip.user_ns["answer"] == 42
409 410
410 411 def test_run_nb_error(self):
411 412 """Test %run notebook.ipynb error"""
412 413 pytest.importorskip("nbformat")
413 414 from nbformat import v4, writes
415
414 416 # %run when a file name isn't provided
415 417 pytest.raises(Exception, _ip.magic, "run")
416 418
417 419 # %run when a file doesn't exist
418 420 pytest.raises(Exception, _ip.magic, "run foobar.ipynb")
419 421
420 422 # %run on a notebook with an error
421 423 nb = v4.new_notebook(
422 424 cells=[
423 425 v4.new_code_cell("0/0")
424 426 ]
425 427 )
426 428 src = writes(nb, version=4)
427 429 self.mktmp(src, ext='.ipynb')
428 430 pytest.raises(Exception, _ip.magic, "run %s" % self.fname)
429 431
430 432 def test_file_options(self):
431 433 src = ('import sys\n'
432 434 'a = " ".join(sys.argv[1:])\n')
433 435 self.mktmp(src)
434 436 test_opts = "-x 3 --verbose"
435 437 _ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts))
436 438 assert _ip.user_ns["a"] == test_opts
437 439
438 440
439 441 class TestMagicRunWithPackage(unittest.TestCase):
440 442
441 443 def writefile(self, name, content):
442 444 path = os.path.join(self.tempdir.name, name)
443 445 d = os.path.dirname(path)
444 446 if not os.path.isdir(d):
445 447 os.makedirs(d)
446 448 with open(path, "w", encoding="utf-8") as f:
447 449 f.write(textwrap.dedent(content))
448 450
449 451 def setUp(self):
450 452 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
451 453 """Temporary (probably) valid python package name."""
452 454
453 455 self.value = int(random.random() * 10000)
454 456
455 457 self.tempdir = TemporaryDirectory()
456 458 self.__orig_cwd = os.getcwd()
457 459 sys.path.insert(0, self.tempdir.name)
458 460
459 461 self.writefile(os.path.join(package, '__init__.py'), '')
460 462 self.writefile(os.path.join(package, 'sub.py'), """
461 463 x = {0!r}
462 464 """.format(self.value))
463 465 self.writefile(os.path.join(package, 'relative.py'), """
464 466 from .sub import x
465 467 """)
466 468 self.writefile(os.path.join(package, 'absolute.py'), """
467 469 from {0}.sub import x
468 470 """.format(package))
469 471 self.writefile(os.path.join(package, 'args.py'), """
470 472 import sys
471 473 a = " ".join(sys.argv[1:])
472 474 """.format(package))
473 475
474 476 def tearDown(self):
475 477 os.chdir(self.__orig_cwd)
476 478 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
477 479 self.tempdir.cleanup()
478 480
479 481 def check_run_submodule(self, submodule, opts=''):
480 482 _ip.user_ns.pop('x', None)
481 483 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
482 484 self.assertEqual(_ip.user_ns['x'], self.value,
483 485 'Variable `x` is not loaded from module `{0}`.'
484 486 .format(submodule))
485 487
486 488 def test_run_submodule_with_absolute_import(self):
487 489 self.check_run_submodule('absolute')
488 490
489 491 def test_run_submodule_with_relative_import(self):
490 492 """Run submodule that has a relative import statement (#2727)."""
491 493 self.check_run_submodule('relative')
492 494
493 495 def test_prun_submodule_with_absolute_import(self):
494 496 self.check_run_submodule('absolute', '-p')
495 497
496 498 def test_prun_submodule_with_relative_import(self):
497 499 self.check_run_submodule('relative', '-p')
498 500
499 501 def with_fake_debugger(func):
500 502 @functools.wraps(func)
501 503 def wrapper(*args, **kwds):
502 504 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
503 505 return func(*args, **kwds)
504 506 return wrapper
505 507
506 508 @with_fake_debugger
507 509 def test_debug_run_submodule_with_absolute_import(self):
508 510 self.check_run_submodule('absolute', '-d')
509 511
510 512 @with_fake_debugger
511 513 def test_debug_run_submodule_with_relative_import(self):
512 514 self.check_run_submodule('relative', '-d')
513 515
514 516 def test_module_options(self):
515 517 _ip.user_ns.pop("a", None)
516 518 test_opts = "-x abc -m test"
517 519 _ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts))
518 520 assert _ip.user_ns["a"] == test_opts
519 521
520 522 def test_module_options_with_separator(self):
521 523 _ip.user_ns.pop("a", None)
522 524 test_opts = "-x abc -m test"
523 525 _ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts))
524 526 assert _ip.user_ns["a"] == test_opts
525 527
526 528
527 529 def test_run__name__():
528 530 with TemporaryDirectory() as td:
529 531 path = pjoin(td, "foo.py")
530 532 with open(path, "w", encoding="utf-8") as f:
531 533 f.write("q = __name__")
532 534
533 535 _ip.user_ns.pop("q", None)
534 536 _ip.magic("run {}".format(path))
535 537 assert _ip.user_ns.pop("q") == "__main__"
536 538
537 539 _ip.magic("run -n {}".format(path))
538 540 assert _ip.user_ns.pop("q") == "foo"
539 541
540 542 try:
541 543 _ip.magic("run -i -n {}".format(path))
542 544 assert _ip.user_ns.pop("q") == "foo"
543 545 finally:
544 546 _ip.magic('reset -f')
545 547
546 548
547 549 def test_run_tb():
548 550 """Test traceback offset in %run"""
549 551 with TemporaryDirectory() as td:
550 552 path = pjoin(td, "foo.py")
551 553 with open(path, "w", encoding="utf-8") as f:
552 554 f.write(
553 555 "\n".join(
554 556 [
555 557 "def foo():",
556 558 " return bar()",
557 559 "def bar():",
558 560 " raise RuntimeError('hello!')",
559 561 "foo()",
560 562 ]
561 563 )
562 564 )
563 565 with capture_output() as io:
564 566 _ip.magic('run {}'.format(path))
565 567 out = io.stdout
566 568 assert "execfile" not in out
567 569 assert "RuntimeError" in out
568 570 assert out.count("---->") == 3
569 571 del ip.user_ns['bar']
570 572 del ip.user_ns['foo']
571 573
572 574
573 575 def test_multiprocessing_run():
574 576 """Set we can run mutiprocesgin without messing up up main namespace
575 577
576 578 Note that import `nose.tools as nt` mdify the value s
577 579 sys.module['__mp_main__'] so we need to temporarily set it to None to test
578 580 the issue.
579 581 """
580 582 with TemporaryDirectory() as td:
581 583 mpm = sys.modules.get('__mp_main__')
582 584 sys.modules['__mp_main__'] = None
583 585 try:
584 586 path = pjoin(td, "test.py")
585 587 with open(path, "w", encoding="utf-8") as f:
586 588 f.write("import multiprocessing\nprint('hoy')")
587 589 with capture_output() as io:
588 590 _ip.run_line_magic('run', path)
589 591 _ip.run_cell("i_m_undefined")
590 592 out = io.stdout
591 593 assert "hoy" in out
592 594 assert "AttributeError" not in out
593 595 assert "NameError" in out
594 596 assert out.count("---->") == 1
595 597 except:
596 598 raise
597 599 finally:
598 600 sys.modules['__mp_main__'] = mpm
599 601
600 602
601 603 def test_script_tb():
602 604 """Test traceback offset in `ipython script.py`"""
603 605 with TemporaryDirectory() as td:
604 606 path = pjoin(td, "foo.py")
605 607 with open(path, "w", encoding="utf-8") as f:
606 608 f.write(
607 609 "\n".join(
608 610 [
609 611 "def foo():",
610 612 " return bar()",
611 613 "def bar():",
612 614 " raise RuntimeError('hello!')",
613 615 "foo()",
614 616 ]
615 617 )
616 618 )
617 619 out, err = tt.ipexec(path)
618 620 assert "execfile" not in out
619 621 assert "RuntimeError" in out
620 622 assert out.count("---->") == 3
@@ -1,410 +1,409 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.core.ultratb
3 3 """
4 4 import io
5 5 import logging
6 import os.path
6 7 import platform
7 8 import re
8 9 import sys
9 import os.path
10 from textwrap import dedent
11 10 import traceback
12 11 import unittest
12 from textwrap import dedent
13 13
14 from IPython.core.ultratb import ColorTB, VerboseTB
15
14 from tempfile import TemporaryDirectory
16 15
16 from IPython.core.ultratb import ColorTB, VerboseTB
17 17 from IPython.testing import tools as tt
18 18 from IPython.testing.decorators import onlyif_unicode_paths
19 19 from IPython.utils.syspathcontext import prepended_to_syspath
20 from IPython.utils.tempdir import TemporaryDirectory
21 20
22 21 file_1 = """1
23 22 2
24 23 3
25 24 def f():
26 25 1/0
27 26 """
28 27
29 28 file_2 = """def f():
30 29 1/0
31 30 """
32 31
33 32
34 33 def recursionlimit(frames):
35 34 """
36 35 decorator to set the recursion limit temporarily
37 36 """
38 37
39 38 def inner(test_function):
40 39 def wrapper(*args, **kwargs):
41 40 rl = sys.getrecursionlimit()
42 41 sys.setrecursionlimit(frames)
43 42 try:
44 43 return test_function(*args, **kwargs)
45 44 finally:
46 45 sys.setrecursionlimit(rl)
47 46
48 47 return wrapper
49 48
50 49 return inner
51 50
52 51
53 52 class ChangedPyFileTest(unittest.TestCase):
54 53 def test_changing_py_file(self):
55 54 """Traceback produced if the line where the error occurred is missing?
56 55
57 56 https://github.com/ipython/ipython/issues/1456
58 57 """
59 58 with TemporaryDirectory() as td:
60 59 fname = os.path.join(td, "foo.py")
61 60 with open(fname, "w", encoding="utf-8") as f:
62 61 f.write(file_1)
63 62
64 63 with prepended_to_syspath(td):
65 64 ip.run_cell("import foo")
66 65
67 66 with tt.AssertPrints("ZeroDivisionError"):
68 67 ip.run_cell("foo.f()")
69 68
70 69 # Make the file shorter, so the line of the error is missing.
71 70 with open(fname, "w", encoding="utf-8") as f:
72 71 f.write(file_2)
73 72
74 73 # For some reason, this was failing on the *second* call after
75 74 # changing the file, so we call f() twice.
76 75 with tt.AssertNotPrints("Internal Python error", channel='stderr'):
77 76 with tt.AssertPrints("ZeroDivisionError"):
78 77 ip.run_cell("foo.f()")
79 78 with tt.AssertPrints("ZeroDivisionError"):
80 79 ip.run_cell("foo.f()")
81 80
82 81 iso_8859_5_file = u'''# coding: iso-8859-5
83 82
84 83 def fail():
85 84 """Π΄Π±Π˜Π–"""
86 85 1/0 # Π΄Π±Π˜Π–
87 86 '''
88 87
89 88 class NonAsciiTest(unittest.TestCase):
90 89 @onlyif_unicode_paths
91 90 def test_nonascii_path(self):
92 91 # Non-ascii directory name as well.
93 92 with TemporaryDirectory(suffix=u'Γ©') as td:
94 93 fname = os.path.join(td, u"fooΓ©.py")
95 94 with open(fname, "w", encoding="utf-8") as f:
96 95 f.write(file_1)
97 96
98 97 with prepended_to_syspath(td):
99 98 ip.run_cell("import foo")
100 99
101 100 with tt.AssertPrints("ZeroDivisionError"):
102 101 ip.run_cell("foo.f()")
103 102
104 103 def test_iso8859_5(self):
105 104 with TemporaryDirectory() as td:
106 105 fname = os.path.join(td, 'dfghjkl.py')
107 106
108 107 with io.open(fname, 'w', encoding='iso-8859-5') as f:
109 108 f.write(iso_8859_5_file)
110 109
111 110 with prepended_to_syspath(td):
112 111 ip.run_cell("from dfghjkl import fail")
113 112
114 113 with tt.AssertPrints("ZeroDivisionError"):
115 114 with tt.AssertPrints(u'Π΄Π±Π˜Π–', suppress=False):
116 115 ip.run_cell('fail()')
117 116
118 117 def test_nonascii_msg(self):
119 118 cell = u"raise Exception('Γ©')"
120 119 expected = u"Exception('Γ©')"
121 120 ip.run_cell("%xmode plain")
122 121 with tt.AssertPrints(expected):
123 122 ip.run_cell(cell)
124 123
125 124 ip.run_cell("%xmode verbose")
126 125 with tt.AssertPrints(expected):
127 126 ip.run_cell(cell)
128 127
129 128 ip.run_cell("%xmode context")
130 129 with tt.AssertPrints(expected):
131 130 ip.run_cell(cell)
132 131
133 132 ip.run_cell("%xmode minimal")
134 133 with tt.AssertPrints(u"Exception: Γ©"):
135 134 ip.run_cell(cell)
136 135
137 136 # Put this back into Context mode for later tests.
138 137 ip.run_cell("%xmode context")
139 138
140 139 class NestedGenExprTestCase(unittest.TestCase):
141 140 """
142 141 Regression test for the following issues:
143 142 https://github.com/ipython/ipython/issues/8293
144 143 https://github.com/ipython/ipython/issues/8205
145 144 """
146 145 def test_nested_genexpr(self):
147 146 code = dedent(
148 147 """\
149 148 class SpecificException(Exception):
150 149 pass
151 150
152 151 def foo(x):
153 152 raise SpecificException("Success!")
154 153
155 154 sum(sum(foo(x) for _ in [0]) for x in [0])
156 155 """
157 156 )
158 157 with tt.AssertPrints('SpecificException: Success!', suppress=False):
159 158 ip.run_cell(code)
160 159
161 160
162 161 indentationerror_file = """if True:
163 162 zoon()
164 163 """
165 164
166 165 class IndentationErrorTest(unittest.TestCase):
167 166 def test_indentationerror_shows_line(self):
168 167 # See issue gh-2398
169 168 with tt.AssertPrints("IndentationError"):
170 169 with tt.AssertPrints("zoon()", suppress=False):
171 170 ip.run_cell(indentationerror_file)
172 171
173 172 with TemporaryDirectory() as td:
174 173 fname = os.path.join(td, "foo.py")
175 174 with open(fname, "w", encoding="utf-8") as f:
176 175 f.write(indentationerror_file)
177 176
178 177 with tt.AssertPrints("IndentationError"):
179 178 with tt.AssertPrints("zoon()", suppress=False):
180 179 ip.magic('run %s' % fname)
181 180
182 181 se_file_1 = """1
183 182 2
184 183 7/
185 184 """
186 185
187 186 se_file_2 = """7/
188 187 """
189 188
190 189 class SyntaxErrorTest(unittest.TestCase):
191 190
192 191 def test_syntaxerror_no_stacktrace_at_compile_time(self):
193 192 syntax_error_at_compile_time = """
194 193 def foo():
195 194 ..
196 195 """
197 196 with tt.AssertPrints("SyntaxError"):
198 197 ip.run_cell(syntax_error_at_compile_time)
199 198
200 199 with tt.AssertNotPrints("foo()"):
201 200 ip.run_cell(syntax_error_at_compile_time)
202 201
203 202 def test_syntaxerror_stacktrace_when_running_compiled_code(self):
204 203 syntax_error_at_runtime = """
205 204 def foo():
206 205 eval("..")
207 206
208 207 def bar():
209 208 foo()
210 209
211 210 bar()
212 211 """
213 212 with tt.AssertPrints("SyntaxError"):
214 213 ip.run_cell(syntax_error_at_runtime)
215 214 # Assert syntax error during runtime generate stacktrace
216 215 with tt.AssertPrints(["foo()", "bar()"]):
217 216 ip.run_cell(syntax_error_at_runtime)
218 217 del ip.user_ns['bar']
219 218 del ip.user_ns['foo']
220 219
221 220 def test_changing_py_file(self):
222 221 with TemporaryDirectory() as td:
223 222 fname = os.path.join(td, "foo.py")
224 223 with open(fname, "w", encoding="utf-8") as f:
225 224 f.write(se_file_1)
226 225
227 226 with tt.AssertPrints(["7/", "SyntaxError"]):
228 227 ip.magic("run " + fname)
229 228
230 229 # Modify the file
231 230 with open(fname, "w", encoding="utf-8") as f:
232 231 f.write(se_file_2)
233 232
234 233 # The SyntaxError should point to the correct line
235 234 with tt.AssertPrints(["7/", "SyntaxError"]):
236 235 ip.magic("run " + fname)
237 236
238 237 def test_non_syntaxerror(self):
239 238 # SyntaxTB may be called with an error other than a SyntaxError
240 239 # See e.g. gh-4361
241 240 try:
242 241 raise ValueError('QWERTY')
243 242 except ValueError:
244 243 with tt.AssertPrints('QWERTY'):
245 244 ip.showsyntaxerror()
246 245
247 246 import sys
248 247
249 248 if sys.version_info < (3, 9) and platform.python_implementation() != "PyPy":
250 249 """
251 250 New 3.9 Pgen Parser does not raise Memory error, except on failed malloc.
252 251 """
253 252 class MemoryErrorTest(unittest.TestCase):
254 253 def test_memoryerror(self):
255 254 memoryerror_code = "(" * 200 + ")" * 200
256 255 with tt.AssertPrints("MemoryError"):
257 256 ip.run_cell(memoryerror_code)
258 257
259 258
260 259 class Python3ChainedExceptionsTest(unittest.TestCase):
261 260 DIRECT_CAUSE_ERROR_CODE = """
262 261 try:
263 262 x = 1 + 2
264 263 print(not_defined_here)
265 264 except Exception as e:
266 265 x += 55
267 266 x - 1
268 267 y = {}
269 268 raise KeyError('uh') from e
270 269 """
271 270
272 271 EXCEPTION_DURING_HANDLING_CODE = """
273 272 try:
274 273 x = 1 + 2
275 274 print(not_defined_here)
276 275 except Exception as e:
277 276 x += 55
278 277 x - 1
279 278 y = {}
280 279 raise KeyError('uh')
281 280 """
282 281
283 282 SUPPRESS_CHAINING_CODE = """
284 283 try:
285 284 1/0
286 285 except Exception:
287 286 raise ValueError("Yikes") from None
288 287 """
289 288
290 289 def test_direct_cause_error(self):
291 290 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
292 291 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
293 292
294 293 def test_exception_during_handling_error(self):
295 294 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
296 295 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
297 296
298 297 def test_suppress_exception_chaining(self):
299 298 with tt.AssertNotPrints("ZeroDivisionError"), \
300 299 tt.AssertPrints("ValueError", suppress=False):
301 300 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
302 301
303 302 def test_plain_direct_cause_error(self):
304 303 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
305 304 ip.run_cell("%xmode Plain")
306 305 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
307 306 ip.run_cell("%xmode Verbose")
308 307
309 308 def test_plain_exception_during_handling_error(self):
310 309 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
311 310 ip.run_cell("%xmode Plain")
312 311 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
313 312 ip.run_cell("%xmode Verbose")
314 313
315 314 def test_plain_suppress_exception_chaining(self):
316 315 with tt.AssertNotPrints("ZeroDivisionError"), \
317 316 tt.AssertPrints("ValueError", suppress=False):
318 317 ip.run_cell("%xmode Plain")
319 318 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
320 319 ip.run_cell("%xmode Verbose")
321 320
322 321
323 322 class RecursionTest(unittest.TestCase):
324 323 DEFINITIONS = """
325 324 def non_recurs():
326 325 1/0
327 326
328 327 def r1():
329 328 r1()
330 329
331 330 def r3a():
332 331 r3b()
333 332
334 333 def r3b():
335 334 r3c()
336 335
337 336 def r3c():
338 337 r3a()
339 338
340 339 def r3o1():
341 340 r3a()
342 341
343 342 def r3o2():
344 343 r3o1()
345 344 """
346 345 def setUp(self):
347 346 ip.run_cell(self.DEFINITIONS)
348 347
349 348 def test_no_recursion(self):
350 349 with tt.AssertNotPrints("skipping similar frames"):
351 350 ip.run_cell("non_recurs()")
352 351
353 352 @recursionlimit(200)
354 353 def test_recursion_one_frame(self):
355 354 with tt.AssertPrints(re.compile(
356 355 r"\[\.\.\. skipping similar frames: r1 at line 5 \(\d{2,3} times\)\]")
357 356 ):
358 357 ip.run_cell("r1()")
359 358
360 359 @recursionlimit(160)
361 360 def test_recursion_three_frames(self):
362 361 with tt.AssertPrints("[... skipping similar frames: "), \
363 362 tt.AssertPrints(re.compile(r"r3a at line 8 \(\d{2} times\)"), suppress=False), \
364 363 tt.AssertPrints(re.compile(r"r3b at line 11 \(\d{2} times\)"), suppress=False), \
365 364 tt.AssertPrints(re.compile(r"r3c at line 14 \(\d{2} times\)"), suppress=False):
366 365 ip.run_cell("r3o2()")
367 366
368 367
369 368 #----------------------------------------------------------------------------
370 369
371 370 # module testing (minimal)
372 371 def test_handlers():
373 372 def spam(c, d_e):
374 373 (d, e) = d_e
375 374 x = c + d
376 375 y = c * d
377 376 foo(x, y)
378 377
379 378 def foo(a, b, bar=1):
380 379 eggs(a, b + bar)
381 380
382 381 def eggs(f, g, z=globals()):
383 382 h = f + g
384 383 i = f - g
385 384 return h / i
386 385
387 386 buff = io.StringIO()
388 387
389 388 buff.write('')
390 389 buff.write('*** Before ***')
391 390 try:
392 391 buff.write(spam(1, (2, 3)))
393 392 except:
394 393 traceback.print_exc(file=buff)
395 394
396 395 handler = ColorTB(ostream=buff)
397 396 buff.write('*** ColorTB ***')
398 397 try:
399 398 buff.write(spam(1, (2, 3)))
400 399 except:
401 400 handler(*sys.exc_info())
402 401 buff.write('')
403 402
404 403 handler = VerboseTB(ostream=buff)
405 404 buff.write('*** VerboseTB ***')
406 405 try:
407 406 buff.write(spam(1, (2, 3)))
408 407 except:
409 408 handler(*sys.exc_info())
410 409 buff.write('')
@@ -1,56 +1,57 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Test suite for the deepreload module."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 import pytest
8 7 import types
9
10 8 from pathlib import Path
11 9
10 import pytest
11 from tempfile import TemporaryDirectory
12
13 from IPython.lib.deepreload import modules_reloading
14 from IPython.lib.deepreload import reload as dreload
12 15 from IPython.utils.syspathcontext import prepended_to_syspath
13 from IPython.utils.tempdir import TemporaryDirectory
14 from IPython.lib.deepreload import reload as dreload, modules_reloading
15 16
16 17
17 18 def test_deepreload():
18 19 "Test that dreload does deep reloads and skips excluded modules."
19 20 with TemporaryDirectory() as tmpdir:
20 21 with prepended_to_syspath(tmpdir):
21 22 tmpdirpath = Path(tmpdir)
22 23 with open(tmpdirpath / "A.py", "w", encoding="utf-8") as f:
23 24 f.write("class Object:\n pass\nok = True\n")
24 25 with open(tmpdirpath / "B.py", "w", encoding="utf-8") as f:
25 26 f.write("import A\nassert A.ok, 'we are fine'\n")
26 27 import A
27 28 import B
28 29
29 30 # Test that A is not reloaded.
30 31 obj = A.Object()
31 32 dreload(B, exclude=["A"])
32 33 assert isinstance(obj, A.Object) is True
33 34
34 35 # Test that an import failure will not blow-up us.
35 36 A.ok = False
36 37 with pytest.raises(AssertionError, match="we are fine"):
37 38 dreload(B, exclude=["A"])
38 39 assert len(modules_reloading) == 0
39 40 assert not A.ok
40 41
41 42 # Test that A is reloaded.
42 43 obj = A.Object()
43 44 A.ok = False
44 45 dreload(B)
45 46 assert A.ok
46 47 assert isinstance(obj, A.Object) is False
47 48
48 49
49 50 def test_not_module():
50 51 pytest.raises(TypeError, dreload, "modulename")
51 52
52 53
53 54 def test_not_in_sys_modules():
54 55 fake_module = types.ModuleType("fake_module")
55 56 with pytest.raises(ImportError, match="not in sys.modules"):
56 57 dreload(fake_module)
@@ -1,59 +1,58 b''
1 1 """ This module contains classes - NamedFileInTemporaryDirectory, TemporaryWorkingDirectory.
2 2
3 3 These classes add extra features such as creating a named file in temporary directory and
4 4 creating a context manager for the working directory which is also temporary.
5 5 """
6 6
7 7 import os as _os
8 8 from pathlib import Path
9 9 from tempfile import TemporaryDirectory
10 10
11 11
12 12 class NamedFileInTemporaryDirectory(object):
13
14 def __init__(self, filename, mode='w+b', bufsize=-1, **kwds):
13 def __init__(self, filename, mode="w+b", bufsize=-1, add_to_syspath=False, **kwds):
15 14 """
16 15 Open a file named `filename` in a temporary directory.
17 16
18 17 This context manager is preferred over `NamedTemporaryFile` in
19 18 stdlib `tempfile` when one needs to reopen the file.
20 19
21 20 Arguments `mode` and `bufsize` are passed to `open`.
22 21 Rest of the arguments are passed to `TemporaryDirectory`.
23 22
24 23 """
25 24 self._tmpdir = TemporaryDirectory(**kwds)
26 25 path = Path(self._tmpdir.name) / filename
27 26 encoding = None if "b" in mode else "utf-8"
28 27 self.file = open(path, mode, bufsize, encoding=encoding)
29 28
30 29 def cleanup(self):
31 30 self.file.close()
32 31 self._tmpdir.cleanup()
33 32
34 33 __del__ = cleanup
35 34
36 35 def __enter__(self):
37 36 return self.file
38 37
39 38 def __exit__(self, type, value, traceback):
40 39 self.cleanup()
41 40
42 41
43 42 class TemporaryWorkingDirectory(TemporaryDirectory):
44 43 """
45 44 Creates a temporary directory and sets the cwd to that directory.
46 45 Automatically reverts to previous cwd upon cleanup.
47 46 Usage example:
48 47
49 48 with TemporaryWorkingDirectory() as tmpdir:
50 49 ...
51 50 """
52 51 def __enter__(self):
53 52 self.old_wd = Path.cwd()
54 53 _os.chdir(self.name)
55 54 return super(TemporaryWorkingDirectory, self).__enter__()
56 55
57 56 def __exit__(self, exc, value, tb):
58 57 _os.chdir(self.old_wd)
59 58 return super(TemporaryWorkingDirectory, self).__exit__(exc, value, tb)
@@ -1,509 +1,509 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.utils.path.py"""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 import os
8 8 import shutil
9 9 import sys
10 10 import tempfile
11 11 import unittest
12 12 from contextlib import contextmanager
13 from unittest.mock import patch
14 from os.path import join, abspath
15 13 from importlib import reload
14 from os.path import abspath, join
15 from unittest.mock import patch
16 16
17 17 import pytest
18 from tempfile import TemporaryDirectory
18 19
19 20 import IPython
20 21 from IPython import paths
21 22 from IPython.testing import decorators as dec
22 23 from IPython.testing.decorators import (
24 onlyif_unicode_paths,
23 25 skip_if_not_win32,
24 26 skip_win32,
25 onlyif_unicode_paths,
26 27 )
27 28 from IPython.testing.tools import make_tempfile
28 29 from IPython.utils import path
29 from IPython.utils.tempdir import TemporaryDirectory
30
31 30
32 31 # Platform-dependent imports
33 32 try:
34 33 import winreg as wreg
35 34 except ImportError:
36 35 #Fake _winreg module on non-windows platforms
37 36 import types
38 37 wr_name = "winreg"
39 38 sys.modules[wr_name] = types.ModuleType(wr_name)
40 39 try:
41 40 import winreg as wreg
42 41 except ImportError:
43 42 import _winreg as wreg
43
44 44 #Add entries that needs to be stubbed by the testing code
45 45 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
46 46
47 47 #-----------------------------------------------------------------------------
48 48 # Globals
49 49 #-----------------------------------------------------------------------------
50 50 env = os.environ
51 51 TMP_TEST_DIR = tempfile.mkdtemp()
52 52 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
53 53 #
54 54 # Setup/teardown functions/decorators
55 55 #
56 56
57 57 def setup_module():
58 58 """Setup testenvironment for the module:
59 59
60 60 - Adds dummy home dir tree
61 61 """
62 62 # Do not mask exceptions here. In particular, catching WindowsError is a
63 63 # problem because that exception is only defined on Windows...
64 64 os.makedirs(os.path.join(HOME_TEST_DIR, 'ipython'))
65 65
66 66
67 67 def teardown_module():
68 68 """Teardown testenvironment for the module:
69 69
70 70 - Remove dummy home dir tree
71 71 """
72 72 # Note: we remove the parent test dir, which is the root of all test
73 73 # subdirs we may have created. Use shutil instead of os.removedirs, so
74 74 # that non-empty directories are all recursively removed.
75 75 shutil.rmtree(TMP_TEST_DIR)
76 76
77 77
78 78 def setup_environment():
79 79 """Setup testenvironment for some functions that are tested
80 80 in this module. In particular this functions stores attributes
81 81 and other things that we need to stub in some test functions.
82 82 This needs to be done on a function level and not module level because
83 83 each testfunction needs a pristine environment.
84 84 """
85 85 global oldstuff, platformstuff
86 86 oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd())
87 87
88 88 def teardown_environment():
89 89 """Restore things that were remembered by the setup_environment function
90 90 """
91 91 (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
92 92 os.chdir(old_wd)
93 93 reload(path)
94 94
95 95 for key in list(env):
96 96 if key not in oldenv:
97 97 del env[key]
98 98 env.update(oldenv)
99 99 if hasattr(sys, 'frozen'):
100 100 del sys.frozen
101 101
102 102
103 103 # Build decorator that uses the setup_environment/setup_environment
104 104 @pytest.fixture
105 105 def environment():
106 106 setup_environment()
107 107 yield
108 108 teardown_environment()
109 109
110 110
111 111 with_environment = pytest.mark.usefixtures("environment")
112 112
113 113
114 114 @skip_if_not_win32
115 115 @with_environment
116 116 def test_get_home_dir_1():
117 117 """Testcase for py2exe logic, un-compressed lib
118 118 """
119 119 unfrozen = path.get_home_dir()
120 120 sys.frozen = True
121 121
122 122 #fake filename for IPython.__init__
123 123 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
124 124
125 125 home_dir = path.get_home_dir()
126 126 assert home_dir == unfrozen
127 127
128 128
129 129 @skip_if_not_win32
130 130 @with_environment
131 131 def test_get_home_dir_2():
132 132 """Testcase for py2exe logic, compressed lib
133 133 """
134 134 unfrozen = path.get_home_dir()
135 135 sys.frozen = True
136 136 #fake filename for IPython.__init__
137 137 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
138 138
139 139 home_dir = path.get_home_dir(True)
140 140 assert home_dir == unfrozen
141 141
142 142
143 143 @skip_win32
144 144 @with_environment
145 145 def test_get_home_dir_3():
146 146 """get_home_dir() uses $HOME if set"""
147 147 env["HOME"] = HOME_TEST_DIR
148 148 home_dir = path.get_home_dir(True)
149 149 # get_home_dir expands symlinks
150 150 assert home_dir == os.path.realpath(env["HOME"])
151 151
152 152
153 153 @with_environment
154 154 def test_get_home_dir_4():
155 155 """get_home_dir() still works if $HOME is not set"""
156 156
157 157 if 'HOME' in env: del env['HOME']
158 158 # this should still succeed, but we don't care what the answer is
159 159 home = path.get_home_dir(False)
160 160
161 161 @skip_win32
162 162 @with_environment
163 163 def test_get_home_dir_5():
164 164 """raise HomeDirError if $HOME is specified, but not a writable dir"""
165 165 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
166 166 # set os.name = posix, to prevent My Documents fallback on Windows
167 167 os.name = 'posix'
168 168 pytest.raises(path.HomeDirError, path.get_home_dir, True)
169 169
170 170 # Should we stub wreg fully so we can run the test on all platforms?
171 171 @skip_if_not_win32
172 172 @with_environment
173 173 def test_get_home_dir_8():
174 174 """Using registry hack for 'My Documents', os=='nt'
175 175
176 176 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
177 177 """
178 178 os.name = 'nt'
179 179 # Remove from stub environment all keys that may be set
180 180 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
181 181 env.pop(key, None)
182 182
183 183 class key:
184 184 def __enter__(self):
185 185 pass
186 186 def Close(self):
187 187 pass
188 188 def __exit__(*args, **kwargs):
189 189 pass
190 190
191 191 with patch.object(wreg, 'OpenKey', return_value=key()), \
192 192 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
193 193 home_dir = path.get_home_dir()
194 194 assert home_dir == abspath(HOME_TEST_DIR)
195 195
196 196 @with_environment
197 197 def test_get_xdg_dir_0():
198 198 """test_get_xdg_dir_0, check xdg_dir"""
199 199 reload(path)
200 200 path._writable_dir = lambda path: True
201 201 path.get_home_dir = lambda : 'somewhere'
202 202 os.name = "posix"
203 203 sys.platform = "linux2"
204 204 env.pop('IPYTHON_DIR', None)
205 205 env.pop('IPYTHONDIR', None)
206 206 env.pop('XDG_CONFIG_HOME', None)
207 207
208 208 assert path.get_xdg_dir() == os.path.join("somewhere", ".config")
209 209
210 210
211 211 @with_environment
212 212 def test_get_xdg_dir_1():
213 213 """test_get_xdg_dir_1, check nonexistent xdg_dir"""
214 214 reload(path)
215 215 path.get_home_dir = lambda : HOME_TEST_DIR
216 216 os.name = "posix"
217 217 sys.platform = "linux2"
218 218 env.pop('IPYTHON_DIR', None)
219 219 env.pop('IPYTHONDIR', None)
220 220 env.pop('XDG_CONFIG_HOME', None)
221 221 assert path.get_xdg_dir() is None
222 222
223 223 @with_environment
224 224 def test_get_xdg_dir_2():
225 225 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
226 226 reload(path)
227 227 path.get_home_dir = lambda : HOME_TEST_DIR
228 228 os.name = "posix"
229 229 sys.platform = "linux2"
230 230 env.pop('IPYTHON_DIR', None)
231 231 env.pop('IPYTHONDIR', None)
232 232 env.pop('XDG_CONFIG_HOME', None)
233 233 cfgdir=os.path.join(path.get_home_dir(), '.config')
234 234 if not os.path.exists(cfgdir):
235 235 os.makedirs(cfgdir)
236 236
237 237 assert path.get_xdg_dir() == cfgdir
238 238
239 239 @with_environment
240 240 def test_get_xdg_dir_3():
241 241 """test_get_xdg_dir_3, check xdg_dir not used on non-posix systems"""
242 242 reload(path)
243 243 path.get_home_dir = lambda : HOME_TEST_DIR
244 244 os.name = "nt"
245 245 sys.platform = "win32"
246 246 env.pop('IPYTHON_DIR', None)
247 247 env.pop('IPYTHONDIR', None)
248 248 env.pop('XDG_CONFIG_HOME', None)
249 249 cfgdir=os.path.join(path.get_home_dir(), '.config')
250 250 os.makedirs(cfgdir, exist_ok=True)
251 251
252 252 assert path.get_xdg_dir() is None
253 253
254 254 def test_filefind():
255 255 """Various tests for filefind"""
256 256 f = tempfile.NamedTemporaryFile()
257 257 # print 'fname:',f.name
258 258 alt_dirs = paths.get_ipython_dir()
259 259 t = path.filefind(f.name, alt_dirs)
260 260 # print 'found:',t
261 261
262 262
263 263 @dec.skip_if_not_win32
264 264 def test_get_long_path_name_win32():
265 265 with TemporaryDirectory() as tmpdir:
266 266
267 267 # Make a long path. Expands the path of tmpdir prematurely as it may already have a long
268 268 # path component, so ensure we include the long form of it
269 269 long_path = os.path.join(path.get_long_path_name(tmpdir), 'this is my long path name')
270 270 os.makedirs(long_path)
271 271
272 272 # Test to see if the short path evaluates correctly.
273 273 short_path = os.path.join(tmpdir, 'THISIS~1')
274 274 evaluated_path = path.get_long_path_name(short_path)
275 275 assert evaluated_path.lower() == long_path.lower()
276 276
277 277
278 278 @dec.skip_win32
279 279 def test_get_long_path_name():
280 280 p = path.get_long_path_name("/usr/local")
281 281 assert p == "/usr/local"
282 282
283 283
284 284 class TestRaiseDeprecation(unittest.TestCase):
285 285
286 286 @dec.skip_win32 # can't create not-user-writable dir on win
287 287 @with_environment
288 288 def test_not_writable_ipdir(self):
289 289 tmpdir = tempfile.mkdtemp()
290 290 os.name = "posix"
291 291 env.pop('IPYTHON_DIR', None)
292 292 env.pop('IPYTHONDIR', None)
293 293 env.pop('XDG_CONFIG_HOME', None)
294 294 env['HOME'] = tmpdir
295 295 ipdir = os.path.join(tmpdir, '.ipython')
296 296 os.mkdir(ipdir, 0o555)
297 297 try:
298 298 open(os.path.join(ipdir, "_foo_"), "w", encoding="utf-8").close()
299 299 except IOError:
300 300 pass
301 301 else:
302 302 # I can still write to an unwritable dir,
303 303 # assume I'm root and skip the test
304 304 pytest.skip("I can't create directories that I can't write to")
305 305
306 306 with self.assertWarnsRegex(UserWarning, 'is not a writable location'):
307 307 ipdir = paths.get_ipython_dir()
308 308 env.pop('IPYTHON_DIR', None)
309 309
310 310 @with_environment
311 311 def test_get_py_filename():
312 312 os.chdir(TMP_TEST_DIR)
313 313 with make_tempfile("foo.py"):
314 314 assert path.get_py_filename("foo.py") == "foo.py"
315 315 assert path.get_py_filename("foo") == "foo.py"
316 316 with make_tempfile("foo"):
317 317 assert path.get_py_filename("foo") == "foo"
318 318 pytest.raises(IOError, path.get_py_filename, "foo.py")
319 319 pytest.raises(IOError, path.get_py_filename, "foo")
320 320 pytest.raises(IOError, path.get_py_filename, "foo.py")
321 321 true_fn = "foo with spaces.py"
322 322 with make_tempfile(true_fn):
323 323 assert path.get_py_filename("foo with spaces") == true_fn
324 324 assert path.get_py_filename("foo with spaces.py") == true_fn
325 325 pytest.raises(IOError, path.get_py_filename, '"foo with spaces.py"')
326 326 pytest.raises(IOError, path.get_py_filename, "'foo with spaces.py'")
327 327
328 328 @onlyif_unicode_paths
329 329 def test_unicode_in_filename():
330 330 """When a file doesn't exist, the exception raised should be safe to call
331 331 str() on - i.e. in Python 2 it must only have ASCII characters.
332 332
333 333 https://github.com/ipython/ipython/issues/875
334 334 """
335 335 try:
336 336 # these calls should not throw unicode encode exceptions
337 337 path.get_py_filename('fooéè.py')
338 338 except IOError as ex:
339 339 str(ex)
340 340
341 341
342 342 class TestShellGlob(unittest.TestCase):
343 343
344 344 @classmethod
345 345 def setUpClass(cls):
346 346 cls.filenames_start_with_a = ['a0', 'a1', 'a2']
347 347 cls.filenames_end_with_b = ['0b', '1b', '2b']
348 348 cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b
349 349 cls.tempdir = TemporaryDirectory()
350 350 td = cls.tempdir.name
351 351
352 352 with cls.in_tempdir():
353 353 # Create empty files
354 354 for fname in cls.filenames:
355 355 open(os.path.join(td, fname), "w", encoding="utf-8").close()
356 356
357 357 @classmethod
358 358 def tearDownClass(cls):
359 359 cls.tempdir.cleanup()
360 360
361 361 @classmethod
362 362 @contextmanager
363 363 def in_tempdir(cls):
364 364 save = os.getcwd()
365 365 try:
366 366 os.chdir(cls.tempdir.name)
367 367 yield
368 368 finally:
369 369 os.chdir(save)
370 370
371 371 def check_match(self, patterns, matches):
372 372 with self.in_tempdir():
373 373 # glob returns unordered list. that's why sorted is required.
374 374 assert sorted(path.shellglob(patterns)) == sorted(matches)
375 375
376 376 def common_cases(self):
377 377 return [
378 378 (['*'], self.filenames),
379 379 (['a*'], self.filenames_start_with_a),
380 380 (['*c'], ['*c']),
381 381 (['*', 'a*', '*b', '*c'], self.filenames
382 382 + self.filenames_start_with_a
383 383 + self.filenames_end_with_b
384 384 + ['*c']),
385 385 (['a[012]'], self.filenames_start_with_a),
386 386 ]
387 387
388 388 @skip_win32
389 389 def test_match_posix(self):
390 390 for (patterns, matches) in self.common_cases() + [
391 391 ([r'\*'], ['*']),
392 392 ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a),
393 393 ([r'a\[012]'], ['a[012]']),
394 394 ]:
395 395 self.check_match(patterns, matches)
396 396
397 397 @skip_if_not_win32
398 398 def test_match_windows(self):
399 399 for (patterns, matches) in self.common_cases() + [
400 400 # In windows, backslash is interpreted as path
401 401 # separator. Therefore, you can't escape glob
402 402 # using it.
403 403 ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a),
404 404 ([r'a\[012]'], [r'a\[012]']),
405 405 ]:
406 406 self.check_match(patterns, matches)
407 407
408 408
409 409 @pytest.mark.parametrize(
410 410 "globstr, unescaped_globstr",
411 411 [
412 412 (r"\*\[\!\]\?", "*[!]?"),
413 413 (r"\\*", r"\*"),
414 414 (r"\\\*", r"\*"),
415 415 (r"\\a", r"\a"),
416 416 (r"\a", r"\a"),
417 417 ],
418 418 )
419 419 def test_unescape_glob(globstr, unescaped_globstr):
420 420 assert path.unescape_glob(globstr) == unescaped_globstr
421 421
422 422
423 423 @onlyif_unicode_paths
424 424 def test_ensure_dir_exists():
425 425 with TemporaryDirectory() as td:
426 426 d = os.path.join(td, 'βˆ‚ir')
427 427 path.ensure_dir_exists(d) # create it
428 428 assert os.path.isdir(d)
429 429 path.ensure_dir_exists(d) # no-op
430 430 f = os.path.join(td, "Ζ’ile")
431 431 open(f, "w", encoding="utf-8").close() # touch
432 432 with pytest.raises(IOError):
433 433 path.ensure_dir_exists(f)
434 434
435 435 class TestLinkOrCopy(unittest.TestCase):
436 436 def setUp(self):
437 437 self.tempdir = TemporaryDirectory()
438 438 self.src = self.dst("src")
439 439 with open(self.src, "w", encoding="utf-8") as f:
440 440 f.write("Hello, world!")
441 441
442 442 def tearDown(self):
443 443 self.tempdir.cleanup()
444 444
445 445 def dst(self, *args):
446 446 return os.path.join(self.tempdir.name, *args)
447 447
448 448 def assert_inode_not_equal(self, a, b):
449 449 assert (
450 450 os.stat(a).st_ino != os.stat(b).st_ino
451 451 ), "%r and %r do reference the same indoes" % (a, b)
452 452
453 453 def assert_inode_equal(self, a, b):
454 454 assert (
455 455 os.stat(a).st_ino == os.stat(b).st_ino
456 456 ), "%r and %r do not reference the same indoes" % (a, b)
457 457
458 458 def assert_content_equal(self, a, b):
459 459 with open(a, "rb") as a_f:
460 460 with open(b, "rb") as b_f:
461 461 assert a_f.read() == b_f.read()
462 462
463 463 @skip_win32
464 464 def test_link_successful(self):
465 465 dst = self.dst("target")
466 466 path.link_or_copy(self.src, dst)
467 467 self.assert_inode_equal(self.src, dst)
468 468
469 469 @skip_win32
470 470 def test_link_into_dir(self):
471 471 dst = self.dst("some_dir")
472 472 os.mkdir(dst)
473 473 path.link_or_copy(self.src, dst)
474 474 expected_dst = self.dst("some_dir", os.path.basename(self.src))
475 475 self.assert_inode_equal(self.src, expected_dst)
476 476
477 477 @skip_win32
478 478 def test_target_exists(self):
479 479 dst = self.dst("target")
480 480 open(dst, "w", encoding="utf-8").close()
481 481 path.link_or_copy(self.src, dst)
482 482 self.assert_inode_equal(self.src, dst)
483 483
484 484 @skip_win32
485 485 def test_no_link(self):
486 486 real_link = os.link
487 487 try:
488 488 del os.link
489 489 dst = self.dst("target")
490 490 path.link_or_copy(self.src, dst)
491 491 self.assert_content_equal(self.src, dst)
492 492 self.assert_inode_not_equal(self.src, dst)
493 493 finally:
494 494 os.link = real_link
495 495
496 496 @skip_if_not_win32
497 497 def test_windows(self):
498 498 dst = self.dst("target")
499 499 path.link_or_copy(self.src, dst)
500 500 self.assert_content_equal(self.src, dst)
501 501
502 502 def test_link_twice(self):
503 503 # Linking the same file twice shouldn't leave duplicates around.
504 504 # See https://github.com/ipython/ipython/issues/6450
505 505 dst = self.dst('target')
506 506 path.link_or_copy(self.src, dst)
507 507 path.link_or_copy(self.src, dst)
508 508 self.assert_inode_equal(self.src, dst)
509 509 assert sorted(os.listdir(self.tempdir.name)) == ["src", "target"]
General Comments 0
You need to be logged in to leave comments. Login now