##// END OF EJS Templates
Revert "Fix DeprecationWarning: There is no current event loop"
Min RK -
r27191:83991b98 revert-13269-patch-1
parent child Browse files
Show More
@@ -1,695 +1,695 b''
1 1 """IPython terminal interface using prompt_toolkit"""
2 2
3 3 import asyncio
4 4 import os
5 5 import sys
6 6 import warnings
7 7 from warnings import warn
8 8
9 9 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
10 10 from IPython.utils import io
11 11 from IPython.utils.py3compat import input
12 12 from IPython.utils.terminal import toggle_set_term_title, set_term_title, restore_term_title
13 13 from IPython.utils.process import abbrev_cwd
14 14 from traitlets import (
15 15 Bool,
16 16 Unicode,
17 17 Dict,
18 18 Integer,
19 19 observe,
20 20 Instance,
21 21 Type,
22 22 default,
23 23 Enum,
24 24 Union,
25 25 Any,
26 26 validate,
27 27 Float,
28 28 )
29 29
30 30 from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
31 31 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
32 32 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
33 33 from prompt_toolkit.formatted_text import PygmentsTokens
34 34 from prompt_toolkit.history import InMemoryHistory
35 35 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
36 36 from prompt_toolkit.output import ColorDepth
37 37 from prompt_toolkit.patch_stdout import patch_stdout
38 38 from prompt_toolkit.shortcuts import PromptSession, CompleteStyle, print_formatted_text
39 39 from prompt_toolkit.styles import DynamicStyle, merge_styles
40 40 from prompt_toolkit.styles.pygments import style_from_pygments_cls, style_from_pygments_dict
41 41 from prompt_toolkit import __version__ as ptk_version
42 42
43 43 from pygments.styles import get_style_by_name
44 44 from pygments.style import Style
45 45 from pygments.token import Token
46 46
47 47 from .debugger import TerminalPdb, Pdb
48 48 from .magics import TerminalMagics
49 49 from .pt_inputhooks import get_inputhook_name_and_func
50 50 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
51 51 from .ptutils import IPythonPTCompleter, IPythonPTLexer
52 52 from .shortcuts import create_ipython_shortcuts
53 53
54 54 DISPLAY_BANNER_DEPRECATED = object()
55 55 PTK3 = ptk_version.startswith('3.')
56 56
57 57
58 58 class _NoStyle(Style): pass
59 59
60 60
61 61
62 62 _style_overrides_light_bg = {
63 63 Token.Prompt: '#ansibrightblue',
64 64 Token.PromptNum: '#ansiblue bold',
65 65 Token.OutPrompt: '#ansibrightred',
66 66 Token.OutPromptNum: '#ansired bold',
67 67 }
68 68
69 69 _style_overrides_linux = {
70 70 Token.Prompt: '#ansibrightgreen',
71 71 Token.PromptNum: '#ansigreen bold',
72 72 Token.OutPrompt: '#ansibrightred',
73 73 Token.OutPromptNum: '#ansired bold',
74 74 }
75 75
76 76 def get_default_editor():
77 77 try:
78 78 return os.environ['EDITOR']
79 79 except KeyError:
80 80 pass
81 81 except UnicodeError:
82 82 warn("$EDITOR environment variable is not pure ASCII. Using platform "
83 83 "default editor.")
84 84
85 85 if os.name == 'posix':
86 86 return 'vi' # the only one guaranteed to be there!
87 87 else:
88 88 return 'notepad' # same in Windows!
89 89
90 90 # conservatively check for tty
91 91 # overridden streams can result in things like:
92 92 # - sys.stdin = None
93 93 # - no isatty method
94 94 for _name in ('stdin', 'stdout', 'stderr'):
95 95 _stream = getattr(sys, _name)
96 96 if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty():
97 97 _is_tty = False
98 98 break
99 99 else:
100 100 _is_tty = True
101 101
102 102
103 103 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
104 104
105 105 def black_reformat_handler(text_before_cursor):
106 106 import black
107 107 formatted_text = black.format_str(text_before_cursor, mode=black.FileMode())
108 108 if not text_before_cursor.endswith('\n') and formatted_text.endswith('\n'):
109 109 formatted_text = formatted_text[:-1]
110 110 return formatted_text
111 111
112 112
113 113 class TerminalInteractiveShell(InteractiveShell):
114 114 mime_renderers = Dict().tag(config=True)
115 115
116 116 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
117 117 'to reserve for the tab completion menu, '
118 118 'search history, ...etc, the height of '
119 119 'these menus will at most this value. '
120 120 'Increase it is you prefer long and skinny '
121 121 'menus, decrease for short and wide.'
122 122 ).tag(config=True)
123 123
124 124 pt_app = None
125 125 debugger_history = None
126 126
127 127 debugger_history_file = Unicode(
128 128 "~/.pdbhistory", help="File in which to store and read history"
129 129 ).tag(config=True)
130 130
131 131 simple_prompt = Bool(_use_simple_prompt,
132 132 help="""Use `raw_input` for the REPL, without completion and prompt colors.
133 133
134 134 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
135 135 IPython own testing machinery, and emacs inferior-shell integration through elpy.
136 136
137 137 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
138 138 environment variable is set, or the current terminal is not a tty."""
139 139 ).tag(config=True)
140 140
141 141 @property
142 142 def debugger_cls(self):
143 143 return Pdb if self.simple_prompt else TerminalPdb
144 144
145 145 confirm_exit = Bool(True,
146 146 help="""
147 147 Set to confirm when you try to exit IPython with an EOF (Control-D
148 148 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
149 149 you can force a direct exit without any confirmation.""",
150 150 ).tag(config=True)
151 151
152 152 editing_mode = Unicode('emacs',
153 153 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
154 154 ).tag(config=True)
155 155
156 156 emacs_bindings_in_vi_insert_mode = Bool(
157 157 True,
158 158 help="Add shortcuts from 'emacs' insert mode to 'vi' insert mode.",
159 159 ).tag(config=True)
160 160
161 161 modal_cursor = Bool(
162 162 True,
163 163 help="""
164 164 Cursor shape changes depending on vi mode: beam in vi insert mode,
165 165 block in nav mode, underscore in replace mode.""",
166 166 ).tag(config=True)
167 167
168 168 ttimeoutlen = Float(
169 169 0.01,
170 170 help="""The time in milliseconds that is waited for a key code
171 171 to complete.""",
172 172 ).tag(config=True)
173 173
174 174 timeoutlen = Float(
175 175 0.5,
176 176 help="""The time in milliseconds that is waited for a mapped key
177 177 sequence to complete.""",
178 178 ).tag(config=True)
179 179
180 180 autoformatter = Unicode(None,
181 181 help="Autoformatter to reformat Terminal code. Can be `'black'` or `None`",
182 182 allow_none=True
183 183 ).tag(config=True)
184 184
185 185 mouse_support = Bool(False,
186 186 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
187 187 ).tag(config=True)
188 188
189 189 # We don't load the list of styles for the help string, because loading
190 190 # Pygments plugins takes time and can cause unexpected errors.
191 191 highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
192 192 help="""The name or class of a Pygments style to use for syntax
193 193 highlighting. To see available styles, run `pygmentize -L styles`."""
194 194 ).tag(config=True)
195 195
196 196 @validate('editing_mode')
197 197 def _validate_editing_mode(self, proposal):
198 198 if proposal['value'].lower() == 'vim':
199 199 proposal['value']= 'vi'
200 200 elif proposal['value'].lower() == 'default':
201 201 proposal['value']= 'emacs'
202 202
203 203 if hasattr(EditingMode, proposal['value'].upper()):
204 204 return proposal['value'].lower()
205 205
206 206 return self.editing_mode
207 207
208 208
209 209 @observe('editing_mode')
210 210 def _editing_mode(self, change):
211 211 if self.pt_app:
212 212 self.pt_app.editing_mode = getattr(EditingMode, change.new.upper())
213 213
214 214 @observe('autoformatter')
215 215 def _autoformatter_changed(self, change):
216 216 formatter = change.new
217 217 if formatter is None:
218 218 self.reformat_handler = lambda x:x
219 219 elif formatter == 'black':
220 220 self.reformat_handler = black_reformat_handler
221 221 else:
222 222 raise ValueError
223 223
224 224 @observe('highlighting_style')
225 225 @observe('colors')
226 226 def _highlighting_style_changed(self, change):
227 227 self.refresh_style()
228 228
229 229 def refresh_style(self):
230 230 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
231 231
232 232
233 233 highlighting_style_overrides = Dict(
234 234 help="Override highlighting format for specific tokens"
235 235 ).tag(config=True)
236 236
237 237 true_color = Bool(False,
238 238 help="""Use 24bit colors instead of 256 colors in prompt highlighting.
239 239 If your terminal supports true color, the following command should
240 240 print ``TRUECOLOR`` in orange::
241 241
242 242 printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"
243 243 """,
244 244 ).tag(config=True)
245 245
246 246 editor = Unicode(get_default_editor(),
247 247 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
248 248 ).tag(config=True)
249 249
250 250 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
251 251
252 252 prompts = Instance(Prompts)
253 253
254 254 @default('prompts')
255 255 def _prompts_default(self):
256 256 return self.prompts_class(self)
257 257
258 258 # @observe('prompts')
259 259 # def _(self, change):
260 260 # self._update_layout()
261 261
262 262 @default('displayhook_class')
263 263 def _displayhook_class_default(self):
264 264 return RichPromptDisplayHook
265 265
266 266 term_title = Bool(True,
267 267 help="Automatically set the terminal title"
268 268 ).tag(config=True)
269 269
270 270 term_title_format = Unicode("IPython: {cwd}",
271 271 help="Customize the terminal title format. This is a python format string. " +
272 272 "Available substitutions are: {cwd}."
273 273 ).tag(config=True)
274 274
275 275 display_completions = Enum(('column', 'multicolumn','readlinelike'),
276 276 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
277 277 "'readlinelike'. These options are for `prompt_toolkit`, see "
278 278 "`prompt_toolkit` documentation for more information."
279 279 ),
280 280 default_value='multicolumn').tag(config=True)
281 281
282 282 highlight_matching_brackets = Bool(True,
283 283 help="Highlight matching brackets.",
284 284 ).tag(config=True)
285 285
286 286 extra_open_editor_shortcuts = Bool(False,
287 287 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
288 288 "This is in addition to the F2 binding, which is always enabled."
289 289 ).tag(config=True)
290 290
291 291 handle_return = Any(None,
292 292 help="Provide an alternative handler to be called when the user presses "
293 293 "Return. This is an advanced option intended for debugging, which "
294 294 "may be changed or removed in later releases."
295 295 ).tag(config=True)
296 296
297 297 enable_history_search = Bool(True,
298 298 help="Allows to enable/disable the prompt toolkit history search"
299 299 ).tag(config=True)
300 300
301 301 prompt_includes_vi_mode = Bool(True,
302 302 help="Display the current vi mode (when using vi editing mode)."
303 303 ).tag(config=True)
304 304
305 305 @observe('term_title')
306 306 def init_term_title(self, change=None):
307 307 # Enable or disable the terminal title.
308 308 if self.term_title:
309 309 toggle_set_term_title(True)
310 310 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
311 311 else:
312 312 toggle_set_term_title(False)
313 313
314 314 def restore_term_title(self):
315 315 if self.term_title:
316 316 restore_term_title()
317 317
318 318 def init_display_formatter(self):
319 319 super(TerminalInteractiveShell, self).init_display_formatter()
320 320 # terminal only supports plain text
321 321 self.display_formatter.active_types = ['text/plain']
322 322 # disable `_ipython_display_`
323 323 self.display_formatter.ipython_display_formatter.enabled = False
324 324
325 325 def init_prompt_toolkit_cli(self):
326 326 if self.simple_prompt:
327 327 # Fall back to plain non-interactive output for tests.
328 328 # This is very limited.
329 329 def prompt():
330 330 prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
331 331 lines = [input(prompt_text)]
332 332 prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
333 333 while self.check_complete('\n'.join(lines))[0] == 'incomplete':
334 334 lines.append( input(prompt_continuation) )
335 335 return '\n'.join(lines)
336 336 self.prompt_for_code = prompt
337 337 return
338 338
339 339 # Set up keyboard shortcuts
340 340 key_bindings = create_ipython_shortcuts(self)
341 341
342 342 # Pre-populate history from IPython's history database
343 343 history = InMemoryHistory()
344 344 last_cell = u""
345 345 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
346 346 include_latest=True):
347 347 # Ignore blank lines and consecutive duplicates
348 348 cell = cell.rstrip()
349 349 if cell and (cell != last_cell):
350 350 history.append_string(cell)
351 351 last_cell = cell
352 352
353 353 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
354 354 self.style = DynamicStyle(lambda: self._style)
355 355
356 356 editing_mode = getattr(EditingMode, self.editing_mode.upper())
357 357
358 358 self.pt_loop = asyncio.new_event_loop()
359 359 self.pt_app = PromptSession(
360 360 auto_suggest=AutoSuggestFromHistory(),
361 361 editing_mode=editing_mode,
362 362 key_bindings=key_bindings,
363 363 history=history,
364 364 completer=IPythonPTCompleter(shell=self),
365 365 enable_history_search=self.enable_history_search,
366 366 style=self.style,
367 367 include_default_pygments_style=False,
368 368 mouse_support=self.mouse_support,
369 369 enable_open_in_editor=self.extra_open_editor_shortcuts,
370 370 color_depth=self.color_depth,
371 371 tempfile_suffix=".py",
372 372 **self._extra_prompt_options()
373 373 )
374 374
375 375 def _make_style_from_name_or_cls(self, name_or_cls):
376 376 """
377 377 Small wrapper that make an IPython compatible style from a style name
378 378
379 379 We need that to add style for prompt ... etc.
380 380 """
381 381 style_overrides = {}
382 382 if name_or_cls == 'legacy':
383 383 legacy = self.colors.lower()
384 384 if legacy == 'linux':
385 385 style_cls = get_style_by_name('monokai')
386 386 style_overrides = _style_overrides_linux
387 387 elif legacy == 'lightbg':
388 388 style_overrides = _style_overrides_light_bg
389 389 style_cls = get_style_by_name('pastie')
390 390 elif legacy == 'neutral':
391 391 # The default theme needs to be visible on both a dark background
392 392 # and a light background, because we can't tell what the terminal
393 393 # looks like. These tweaks to the default theme help with that.
394 394 style_cls = get_style_by_name('default')
395 395 style_overrides.update({
396 396 Token.Number: '#ansigreen',
397 397 Token.Operator: 'noinherit',
398 398 Token.String: '#ansiyellow',
399 399 Token.Name.Function: '#ansiblue',
400 400 Token.Name.Class: 'bold #ansiblue',
401 401 Token.Name.Namespace: 'bold #ansiblue',
402 402 Token.Name.Variable.Magic: '#ansiblue',
403 403 Token.Prompt: '#ansigreen',
404 404 Token.PromptNum: '#ansibrightgreen bold',
405 405 Token.OutPrompt: '#ansired',
406 406 Token.OutPromptNum: '#ansibrightred bold',
407 407 })
408 408
409 409 # Hack: Due to limited color support on the Windows console
410 410 # the prompt colors will be wrong without this
411 411 if os.name == 'nt':
412 412 style_overrides.update({
413 413 Token.Prompt: '#ansidarkgreen',
414 414 Token.PromptNum: '#ansigreen bold',
415 415 Token.OutPrompt: '#ansidarkred',
416 416 Token.OutPromptNum: '#ansired bold',
417 417 })
418 418 elif legacy =='nocolor':
419 419 style_cls=_NoStyle
420 420 style_overrides = {}
421 421 else :
422 422 raise ValueError('Got unknown colors: ', legacy)
423 423 else :
424 424 if isinstance(name_or_cls, str):
425 425 style_cls = get_style_by_name(name_or_cls)
426 426 else:
427 427 style_cls = name_or_cls
428 428 style_overrides = {
429 429 Token.Prompt: '#ansigreen',
430 430 Token.PromptNum: '#ansibrightgreen bold',
431 431 Token.OutPrompt: '#ansired',
432 432 Token.OutPromptNum: '#ansibrightred bold',
433 433 }
434 434 style_overrides.update(self.highlighting_style_overrides)
435 435 style = merge_styles([
436 436 style_from_pygments_cls(style_cls),
437 437 style_from_pygments_dict(style_overrides),
438 438 ])
439 439
440 440 return style
441 441
442 442 @property
443 443 def pt_complete_style(self):
444 444 return {
445 445 'multicolumn': CompleteStyle.MULTI_COLUMN,
446 446 'column': CompleteStyle.COLUMN,
447 447 'readlinelike': CompleteStyle.READLINE_LIKE,
448 448 }[self.display_completions]
449 449
450 450 @property
451 451 def color_depth(self):
452 452 return (ColorDepth.TRUE_COLOR if self.true_color else None)
453 453
454 454 def _extra_prompt_options(self):
455 455 """
456 456 Return the current layout option for the current Terminal InteractiveShell
457 457 """
458 458 def get_message():
459 459 return PygmentsTokens(self.prompts.in_prompt_tokens())
460 460
461 461 if self.editing_mode == 'emacs':
462 462 # with emacs mode the prompt is (usually) static, so we call only
463 463 # the function once. With VI mode it can toggle between [ins] and
464 464 # [nor] so we can't precompute.
465 465 # here I'm going to favor the default keybinding which almost
466 466 # everybody uses to decrease CPU usage.
467 467 # if we have issues with users with custom Prompts we can see how to
468 468 # work around this.
469 469 get_message = get_message()
470 470
471 471 options = {
472 472 'complete_in_thread': False,
473 473 'lexer':IPythonPTLexer(),
474 474 'reserve_space_for_menu':self.space_for_menu,
475 475 'message': get_message,
476 476 'prompt_continuation': (
477 477 lambda width, lineno, is_soft_wrap:
478 478 PygmentsTokens(self.prompts.continuation_prompt_tokens(width))),
479 479 'multiline': True,
480 480 'complete_style': self.pt_complete_style,
481 481
482 482 # Highlight matching brackets, but only when this setting is
483 483 # enabled, and only when the DEFAULT_BUFFER has the focus.
484 484 'input_processors': [ConditionalProcessor(
485 485 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
486 486 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
487 487 Condition(lambda: self.highlight_matching_brackets))],
488 488 }
489 489 if not PTK3:
490 490 options['inputhook'] = self.inputhook
491 491
492 492 return options
493 493
494 494 def prompt_for_code(self):
495 495 if self.rl_next_input:
496 496 default = self.rl_next_input
497 497 self.rl_next_input = None
498 498 else:
499 499 default = ''
500 500
501 501 # In order to make sure that asyncio code written in the
502 502 # interactive shell doesn't interfere with the prompt, we run the
503 503 # prompt in a different event loop.
504 504 # If we don't do this, people could spawn coroutine with a
505 505 # while/true inside which will freeze the prompt.
506 506
507 507 try:
508 old_loop = asyncio.get_running_loop()
508 old_loop = asyncio.get_event_loop()
509 509 except RuntimeError:
510 510 # This happens when the user used `asyncio.run()`.
511 511 old_loop = None
512 512
513 513 asyncio.set_event_loop(self.pt_loop)
514 514 try:
515 515 with patch_stdout(raw=True):
516 516 text = self.pt_app.prompt(
517 517 default=default,
518 518 **self._extra_prompt_options())
519 519 finally:
520 520 # Restore the original event loop.
521 521 asyncio.set_event_loop(old_loop)
522 522
523 523 return text
524 524
525 525 def enable_win_unicode_console(self):
526 526 # Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
527 527 # console by default, so WUC shouldn't be needed.
528 528 from warnings import warn
529 529 warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
530 530 DeprecationWarning,
531 531 stacklevel=2)
532 532
533 533 def init_io(self):
534 534 if sys.platform not in {'win32', 'cli'}:
535 535 return
536 536
537 537 import colorama
538 538 colorama.init()
539 539
540 540 # For some reason we make these wrappers around stdout/stderr.
541 541 # For now, we need to reset them so all output gets coloured.
542 542 # https://github.com/ipython/ipython/issues/8669
543 543 # io.std* are deprecated, but don't show our own deprecation warnings
544 544 # during initialization of the deprecated API.
545 545 with warnings.catch_warnings():
546 546 warnings.simplefilter('ignore', DeprecationWarning)
547 547 io.stdout = io.IOStream(sys.stdout)
548 548 io.stderr = io.IOStream(sys.stderr)
549 549
550 550 def init_magics(self):
551 551 super(TerminalInteractiveShell, self).init_magics()
552 552 self.register_magics(TerminalMagics)
553 553
554 554 def init_alias(self):
555 555 # The parent class defines aliases that can be safely used with any
556 556 # frontend.
557 557 super(TerminalInteractiveShell, self).init_alias()
558 558
559 559 # Now define aliases that only make sense on the terminal, because they
560 560 # need direct access to the console in a way that we can't emulate in
561 561 # GUI or web frontend
562 562 if os.name == 'posix':
563 563 for cmd in ('clear', 'more', 'less', 'man'):
564 564 self.alias_manager.soft_define_alias(cmd, cmd)
565 565
566 566
567 567 def __init__(self, *args, **kwargs):
568 568 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
569 569 self.init_prompt_toolkit_cli()
570 570 self.init_term_title()
571 571 self.keep_running = True
572 572
573 573
574 574 def ask_exit(self):
575 575 self.keep_running = False
576 576
577 577 rl_next_input = None
578 578
579 579 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
580 580
581 581 if display_banner is not DISPLAY_BANNER_DEPRECATED:
582 582 warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
583 583
584 584 self.keep_running = True
585 585 while self.keep_running:
586 586 print(self.separate_in, end='')
587 587
588 588 try:
589 589 code = self.prompt_for_code()
590 590 except EOFError:
591 591 if (not self.confirm_exit) \
592 592 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
593 593 self.ask_exit()
594 594
595 595 else:
596 596 if code:
597 597 self.run_cell(code, store_history=True)
598 598
599 599 def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
600 600 # An extra layer of protection in case someone mashing Ctrl-C breaks
601 601 # out of our internal code.
602 602 if display_banner is not DISPLAY_BANNER_DEPRECATED:
603 603 warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
604 604 while True:
605 605 try:
606 606 self.interact()
607 607 break
608 608 except KeyboardInterrupt as e:
609 609 print("\n%s escaped interact()\n" % type(e).__name__)
610 610 finally:
611 611 # An interrupt during the eventloop will mess up the
612 612 # internal state of the prompt_toolkit library.
613 613 # Stopping the eventloop fixes this, see
614 614 # https://github.com/ipython/ipython/pull/9867
615 615 if hasattr(self, '_eventloop'):
616 616 self._eventloop.stop()
617 617
618 618 self.restore_term_title()
619 619
620 620 # try to call some at-exit operation optimistically as some things can't
621 621 # be done during interpreter shutdown. this is technically inaccurate as
622 622 # this make mainlool not re-callable, but that should be a rare if not
623 623 # in existent use case.
624 624
625 625 self._atexit_once()
626 626
627 627
628 628 _inputhook = None
629 629 def inputhook(self, context):
630 630 if self._inputhook is not None:
631 631 self._inputhook(context)
632 632
633 633 active_eventloop = None
634 634 def enable_gui(self, gui=None):
635 635 if gui and (gui != 'inline') :
636 636 self.active_eventloop, self._inputhook =\
637 637 get_inputhook_name_and_func(gui)
638 638 else:
639 639 self.active_eventloop = self._inputhook = None
640 640
641 641 # For prompt_toolkit 3.0. We have to create an asyncio event loop with
642 642 # this inputhook.
643 643 if PTK3:
644 644 import asyncio
645 645 from prompt_toolkit.eventloop import new_eventloop_with_inputhook
646 646
647 647 if gui == 'asyncio':
648 648 # When we integrate the asyncio event loop, run the UI in the
649 649 # same event loop as the rest of the code. don't use an actual
650 650 # input hook. (Asyncio is not made for nesting event loops.)
651 651 self.pt_loop = asyncio.get_event_loop_policy().get_event_loop()
652 652
653 653 elif self._inputhook:
654 654 # If an inputhook was set, create a new asyncio event loop with
655 655 # this inputhook for the prompt.
656 656 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
657 657 else:
658 658 # When there's no inputhook, run the prompt in a separate
659 659 # asyncio event loop.
660 660 self.pt_loop = asyncio.new_event_loop()
661 661
662 662 # Run !system commands directly, not through pipes, so terminal programs
663 663 # work correctly.
664 664 system = InteractiveShell.system_raw
665 665
666 666 def auto_rewrite_input(self, cmd):
667 667 """Overridden from the parent class to use fancy rewriting prompt"""
668 668 if not self.show_rewritten_input:
669 669 return
670 670
671 671 tokens = self.prompts.rewrite_prompt_tokens()
672 672 if self.pt_app:
673 673 print_formatted_text(PygmentsTokens(tokens), end='',
674 674 style=self.pt_app.app.style)
675 675 print(cmd)
676 676 else:
677 677 prompt = ''.join(s for t, s in tokens)
678 678 print(prompt, cmd, sep='')
679 679
680 680 _prompts_before = None
681 681 def switch_doctest_mode(self, mode):
682 682 """Switch prompts to classic for %doctest_mode"""
683 683 if mode:
684 684 self._prompts_before = self.prompts
685 685 self.prompts = ClassicPrompts(self)
686 686 elif self._prompts_before:
687 687 self.prompts = self._prompts_before
688 688 self._prompts_before = None
689 689 # self._update_layout()
690 690
691 691
692 692 InteractiveShellABC.register(TerminalInteractiveShell)
693 693
694 694 if __name__ == '__main__':
695 695 TerminalInteractiveShell.instance().interact()
General Comments 0
You need to be logged in to leave comments. Login now