Uploaded Test files
This commit is contained in:
parent
f584ad9d97
commit
2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions
0
venv/Lib/site-packages/IPython/terminal/__init__.py
Normal file
0
venv/Lib/site-packages/IPython/terminal/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
19
venv/Lib/site-packages/IPython/terminal/console.py
Normal file
19
venv/Lib/site-packages/IPython/terminal/console.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
"""
|
||||
Shim to maintain backwards compatibility with old IPython.terminal.console imports.
|
||||
"""
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import sys
|
||||
from warnings import warn
|
||||
|
||||
from IPython.utils.shimmodule import ShimModule, ShimWarning
|
||||
|
||||
warn("The `IPython.terminal.console` package has been deprecated since IPython 4.0. "
|
||||
"You should import from jupyter_console instead.", ShimWarning)
|
||||
|
||||
# Unconditionally insert the shim into sys.modules so that further import calls
|
||||
# trigger the custom attribute access above
|
||||
|
||||
sys.modules['IPython.terminal.console'] = ShimModule(
|
||||
src='IPython.terminal.console', mirror='jupyter_console')
|
151
venv/Lib/site-packages/IPython/terminal/debugger.py
Normal file
151
venv/Lib/site-packages/IPython/terminal/debugger.py
Normal file
|
@ -0,0 +1,151 @@
|
|||
import asyncio
|
||||
import signal
|
||||
import sys
|
||||
import threading
|
||||
|
||||
from IPython.core.debugger import Pdb
|
||||
|
||||
from IPython.core.completer import IPCompleter
|
||||
from .ptutils import IPythonPTCompleter
|
||||
from .shortcuts import create_ipython_shortcuts, suspend_to_bg, cursor_in_leading_ws
|
||||
|
||||
from prompt_toolkit.enums import DEFAULT_BUFFER
|
||||
from prompt_toolkit.filters import (Condition, has_focus, has_selection,
|
||||
vi_insert_mode, emacs_insert_mode)
|
||||
from prompt_toolkit.key_binding import KeyBindings
|
||||
from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
|
||||
from pygments.token import Token
|
||||
from prompt_toolkit.shortcuts.prompt import PromptSession
|
||||
from prompt_toolkit.enums import EditingMode
|
||||
from prompt_toolkit.formatted_text import PygmentsTokens
|
||||
|
||||
from prompt_toolkit import __version__ as ptk_version
|
||||
PTK3 = ptk_version.startswith('3.')
|
||||
|
||||
|
||||
class TerminalPdb(Pdb):
|
||||
"""Standalone IPython debugger."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
Pdb.__init__(self, *args, **kwargs)
|
||||
self._ptcomp = None
|
||||
self.pt_init()
|
||||
|
||||
def pt_init(self):
|
||||
def get_prompt_tokens():
|
||||
return [(Token.Prompt, self.prompt)]
|
||||
|
||||
if self._ptcomp is None:
|
||||
compl = IPCompleter(shell=self.shell,
|
||||
namespace={},
|
||||
global_namespace={},
|
||||
parent=self.shell,
|
||||
)
|
||||
# add a completer for all the do_ methods
|
||||
methods_names = [m[3:] for m in dir(self) if m.startswith("do_")]
|
||||
|
||||
def gen_comp(self, text):
|
||||
return [m for m in methods_names if m.startswith(text)]
|
||||
import types
|
||||
newcomp = types.MethodType(gen_comp, compl)
|
||||
compl.custom_matchers.insert(0, newcomp)
|
||||
# end add completer.
|
||||
|
||||
self._ptcomp = IPythonPTCompleter(compl)
|
||||
|
||||
options = dict(
|
||||
message=(lambda: PygmentsTokens(get_prompt_tokens())),
|
||||
editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
|
||||
key_bindings=create_ipython_shortcuts(self.shell),
|
||||
history=self.shell.debugger_history,
|
||||
completer=self._ptcomp,
|
||||
enable_history_search=True,
|
||||
mouse_support=self.shell.mouse_support,
|
||||
complete_style=self.shell.pt_complete_style,
|
||||
style=self.shell.style,
|
||||
color_depth=self.shell.color_depth,
|
||||
)
|
||||
|
||||
if not PTK3:
|
||||
options['inputhook'] = self.shell.inputhook
|
||||
self.pt_loop = asyncio.new_event_loop()
|
||||
self.pt_app = PromptSession(**options)
|
||||
|
||||
def cmdloop(self, intro=None):
|
||||
"""Repeatedly issue a prompt, accept input, parse an initial prefix
|
||||
off the received input, and dispatch to action methods, passing them
|
||||
the remainder of the line as argument.
|
||||
|
||||
override the same methods from cmd.Cmd to provide prompt toolkit replacement.
|
||||
"""
|
||||
if not self.use_rawinput:
|
||||
raise ValueError('Sorry ipdb does not support use_rawinput=False')
|
||||
|
||||
# In order to make sure that prompt, which uses asyncio doesn't
|
||||
# interfere with applications in which it's used, we always run the
|
||||
# prompt itself in a different thread (we can't start an event loop
|
||||
# within an event loop). This new thread won't have any event loop
|
||||
# running, and here we run our prompt-loop.
|
||||
|
||||
self.preloop()
|
||||
|
||||
try:
|
||||
if intro is not None:
|
||||
self.intro = intro
|
||||
if self.intro:
|
||||
self.stdout.write(str(self.intro)+"\n")
|
||||
stop = None
|
||||
while not stop:
|
||||
if self.cmdqueue:
|
||||
line = self.cmdqueue.pop(0)
|
||||
else:
|
||||
self._ptcomp.ipy_completer.namespace = self.curframe_locals
|
||||
self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
|
||||
|
||||
# Run the prompt in a different thread.
|
||||
line = ''
|
||||
keyboard_interrupt = False
|
||||
|
||||
def in_thread():
|
||||
nonlocal line, keyboard_interrupt
|
||||
try:
|
||||
line = self.pt_app.prompt()
|
||||
except EOFError:
|
||||
line = 'EOF'
|
||||
except KeyboardInterrupt:
|
||||
keyboard_interrupt = True
|
||||
|
||||
th = threading.Thread(target=in_thread)
|
||||
th.start()
|
||||
th.join()
|
||||
|
||||
if keyboard_interrupt:
|
||||
raise KeyboardInterrupt
|
||||
|
||||
line = self.precmd(line)
|
||||
stop = self.onecmd(line)
|
||||
stop = self.postcmd(stop, line)
|
||||
self.postloop()
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
|
||||
def set_trace(frame=None):
|
||||
"""
|
||||
Start debugging from `frame`.
|
||||
|
||||
If frame is not specified, debugging starts from caller's frame.
|
||||
"""
|
||||
TerminalPdb().set_trace(frame or sys._getframe().f_back)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import pdb
|
||||
# IPython.core.debugger.Pdb.trace_dispatch shall not catch
|
||||
# bdb.BdbQuit. When started through __main__ and an exception
|
||||
# happened after hitting "c", this is needed in order to
|
||||
# be able to quit the debugging session (see #9950).
|
||||
old_trace_dispatch = pdb.Pdb.trace_dispatch
|
||||
pdb.Pdb = TerminalPdb
|
||||
pdb.Pdb.trace_dispatch = old_trace_dispatch
|
||||
pdb.main()
|
399
venv/Lib/site-packages/IPython/terminal/embed.py
Normal file
399
venv/Lib/site-packages/IPython/terminal/embed.py
Normal file
|
@ -0,0 +1,399 @@
|
|||
# encoding: utf-8
|
||||
"""
|
||||
An embedded IPython shell.
|
||||
"""
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
from IPython.core import ultratb, compilerop
|
||||
from IPython.core import magic_arguments
|
||||
from IPython.core.magic import Magics, magics_class, line_magic
|
||||
from IPython.core.interactiveshell import DummyMod, InteractiveShell
|
||||
from IPython.terminal.interactiveshell import TerminalInteractiveShell
|
||||
from IPython.terminal.ipapp import load_default_config
|
||||
|
||||
from traitlets import Bool, CBool, Unicode
|
||||
from IPython.utils.io import ask_yes_no
|
||||
|
||||
class KillEmbedded(Exception):pass
|
||||
|
||||
# kept for backward compatibility as IPython 6 was released with
|
||||
# the typo. See https://github.com/ipython/ipython/pull/10706
|
||||
KillEmbeded = KillEmbedded
|
||||
|
||||
# This is an additional magic that is exposed in embedded shells.
|
||||
@magics_class
|
||||
class EmbeddedMagics(Magics):
|
||||
|
||||
@line_magic
|
||||
@magic_arguments.magic_arguments()
|
||||
@magic_arguments.argument('-i', '--instance', action='store_true',
|
||||
help='Kill instance instead of call location')
|
||||
@magic_arguments.argument('-x', '--exit', action='store_true',
|
||||
help='Also exit the current session')
|
||||
@magic_arguments.argument('-y', '--yes', action='store_true',
|
||||
help='Do not ask confirmation')
|
||||
def kill_embedded(self, parameter_s=''):
|
||||
"""%kill_embedded : deactivate for good the current embedded IPython
|
||||
|
||||
This function (after asking for confirmation) sets an internal flag so
|
||||
that an embedded IPython will never activate again for the given call
|
||||
location. This is useful to permanently disable a shell that is being
|
||||
called inside a loop: once you've figured out what you needed from it,
|
||||
you may then kill it and the program will then continue to run without
|
||||
the interactive shell interfering again.
|
||||
|
||||
|
||||
Kill Instance Option:
|
||||
|
||||
If for some reasons you need to kill the location where the instance
|
||||
is created and not called, for example if you create a single
|
||||
instance in one place and debug in many locations, you can use the
|
||||
``--instance`` option to kill this specific instance. Like for the
|
||||
``call location`` killing an "instance" should work even if it is
|
||||
recreated within a loop.
|
||||
|
||||
.. note::
|
||||
|
||||
This was the default behavior before IPython 5.2
|
||||
|
||||
"""
|
||||
|
||||
args = magic_arguments.parse_argstring(self.kill_embedded, parameter_s)
|
||||
print(args)
|
||||
if args.instance:
|
||||
# let no ask
|
||||
if not args.yes:
|
||||
kill = ask_yes_no(
|
||||
"Are you sure you want to kill this embedded instance? [y/N] ", 'n')
|
||||
else:
|
||||
kill = True
|
||||
if kill:
|
||||
self.shell._disable_init_location()
|
||||
print("This embedded IPython instance will not reactivate anymore "
|
||||
"once you exit.")
|
||||
else:
|
||||
if not args.yes:
|
||||
kill = ask_yes_no(
|
||||
"Are you sure you want to kill this embedded call_location? [y/N] ", 'n')
|
||||
else:
|
||||
kill = True
|
||||
if kill:
|
||||
self.shell.embedded_active = False
|
||||
print("This embedded IPython call location will not reactivate anymore "
|
||||
"once you exit.")
|
||||
|
||||
if args.exit:
|
||||
# Ask-exit does not really ask, it just set internals flags to exit
|
||||
# on next loop.
|
||||
self.shell.ask_exit()
|
||||
|
||||
|
||||
@line_magic
|
||||
def exit_raise(self, parameter_s=''):
|
||||
"""%exit_raise Make the current embedded kernel exit and raise and exception.
|
||||
|
||||
This function sets an internal flag so that an embedded IPython will
|
||||
raise a `IPython.terminal.embed.KillEmbedded` Exception on exit, and then exit the current I. This is
|
||||
useful to permanently exit a loop that create IPython embed instance.
|
||||
"""
|
||||
|
||||
self.shell.should_raise = True
|
||||
self.shell.ask_exit()
|
||||
|
||||
|
||||
|
||||
class InteractiveShellEmbed(TerminalInteractiveShell):
|
||||
|
||||
dummy_mode = Bool(False)
|
||||
exit_msg = Unicode('')
|
||||
embedded = CBool(True)
|
||||
should_raise = CBool(False)
|
||||
# Like the base class display_banner is not configurable, but here it
|
||||
# is True by default.
|
||||
display_banner = CBool(True)
|
||||
exit_msg = Unicode()
|
||||
|
||||
# When embedding, by default we don't change the terminal title
|
||||
term_title = Bool(False,
|
||||
help="Automatically set the terminal title"
|
||||
).tag(config=True)
|
||||
|
||||
_inactive_locations = set()
|
||||
|
||||
@property
|
||||
def embedded_active(self):
|
||||
return (self._call_location_id not in InteractiveShellEmbed._inactive_locations)\
|
||||
and (self._init_location_id not in InteractiveShellEmbed._inactive_locations)
|
||||
|
||||
def _disable_init_location(self):
|
||||
"""Disable the current Instance creation location"""
|
||||
InteractiveShellEmbed._inactive_locations.add(self._init_location_id)
|
||||
|
||||
@embedded_active.setter
|
||||
def embedded_active(self, value):
|
||||
if value:
|
||||
InteractiveShellEmbed._inactive_locations.discard(
|
||||
self._call_location_id)
|
||||
InteractiveShellEmbed._inactive_locations.discard(
|
||||
self._init_location_id)
|
||||
else:
|
||||
InteractiveShellEmbed._inactive_locations.add(
|
||||
self._call_location_id)
|
||||
|
||||
def __init__(self, **kw):
|
||||
if kw.get('user_global_ns', None) is not None:
|
||||
raise DeprecationWarning(
|
||||
"Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0.")
|
||||
|
||||
clid = kw.pop('_init_location_id', None)
|
||||
if not clid:
|
||||
frame = sys._getframe(1)
|
||||
clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno)
|
||||
self._init_location_id = clid
|
||||
|
||||
super(InteractiveShellEmbed,self).__init__(**kw)
|
||||
|
||||
# don't use the ipython crash handler so that user exceptions aren't
|
||||
# trapped
|
||||
sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors,
|
||||
mode=self.xmode,
|
||||
call_pdb=self.pdb)
|
||||
|
||||
def init_sys_modules(self):
|
||||
"""
|
||||
Explicitly overwrite :mod:`IPython.core.interactiveshell` to do nothing.
|
||||
"""
|
||||
pass
|
||||
|
||||
def init_magics(self):
|
||||
super(InteractiveShellEmbed, self).init_magics()
|
||||
self.register_magics(EmbeddedMagics)
|
||||
|
||||
def __call__(self, header='', local_ns=None, module=None, dummy=None,
|
||||
stack_depth=1, global_ns=None, compile_flags=None, **kw):
|
||||
"""Activate the interactive interpreter.
|
||||
|
||||
__call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
|
||||
the interpreter shell with the given local and global namespaces, and
|
||||
optionally print a header string at startup.
|
||||
|
||||
The shell can be globally activated/deactivated using the
|
||||
dummy_mode attribute. This allows you to turn off a shell used
|
||||
for debugging globally.
|
||||
|
||||
However, *each* time you call the shell you can override the current
|
||||
state of dummy_mode with the optional keyword parameter 'dummy'. For
|
||||
example, if you set dummy mode on with IPShell.dummy_mode = True, you
|
||||
can still have a specific call work by making it as IPShell(dummy=False).
|
||||
"""
|
||||
|
||||
# we are called, set the underlying interactiveshell not to exit.
|
||||
self.keep_running = True
|
||||
|
||||
# If the user has turned it off, go away
|
||||
clid = kw.pop('_call_location_id', None)
|
||||
if not clid:
|
||||
frame = sys._getframe(1)
|
||||
clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno)
|
||||
self._call_location_id = clid
|
||||
|
||||
if not self.embedded_active:
|
||||
return
|
||||
|
||||
# Normal exits from interactive mode set this flag, so the shell can't
|
||||
# re-enter (it checks this variable at the start of interactive mode).
|
||||
self.exit_now = False
|
||||
|
||||
# Allow the dummy parameter to override the global __dummy_mode
|
||||
if dummy or (dummy != 0 and self.dummy_mode):
|
||||
return
|
||||
|
||||
# self.banner is auto computed
|
||||
if header:
|
||||
self.old_banner2 = self.banner2
|
||||
self.banner2 = self.banner2 + '\n' + header + '\n'
|
||||
else:
|
||||
self.old_banner2 = ''
|
||||
|
||||
if self.display_banner:
|
||||
self.show_banner()
|
||||
|
||||
# Call the embedding code with a stack depth of 1 so it can skip over
|
||||
# our call and get the original caller's namespaces.
|
||||
self.mainloop(local_ns, module, stack_depth=stack_depth,
|
||||
global_ns=global_ns, compile_flags=compile_flags)
|
||||
|
||||
self.banner2 = self.old_banner2
|
||||
|
||||
if self.exit_msg is not None:
|
||||
print(self.exit_msg)
|
||||
|
||||
if self.should_raise:
|
||||
raise KillEmbedded('Embedded IPython raising error, as user requested.')
|
||||
|
||||
|
||||
def mainloop(self, local_ns=None, module=None, stack_depth=0,
|
||||
display_banner=None, global_ns=None, compile_flags=None):
|
||||
"""Embeds IPython into a running python program.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
local_ns, module
|
||||
Working local namespace (a dict) and module (a module or similar
|
||||
object). If given as None, they are automatically taken from the scope
|
||||
where the shell was called, so that program variables become visible.
|
||||
|
||||
stack_depth : int
|
||||
How many levels in the stack to go to looking for namespaces (when
|
||||
local_ns or module is None). This allows an intermediate caller to
|
||||
make sure that this function gets the namespace from the intended
|
||||
level in the stack. By default (0) it will get its locals and globals
|
||||
from the immediate caller.
|
||||
|
||||
compile_flags
|
||||
A bit field identifying the __future__ features
|
||||
that are enabled, as passed to the builtin :func:`compile` function.
|
||||
If given as None, they are automatically taken from the scope where
|
||||
the shell was called.
|
||||
|
||||
"""
|
||||
|
||||
if (global_ns is not None) and (module is None):
|
||||
raise DeprecationWarning("'global_ns' keyword argument is deprecated, and has been removed in IPython 5.0 use `module` keyword argument instead.")
|
||||
|
||||
if (display_banner is not None):
|
||||
warnings.warn("The display_banner parameter is deprecated since IPython 4.0", DeprecationWarning)
|
||||
|
||||
# Get locals and globals from caller
|
||||
if ((local_ns is None or module is None or compile_flags is None)
|
||||
and self.default_user_namespaces):
|
||||
call_frame = sys._getframe(stack_depth).f_back
|
||||
|
||||
if local_ns is None:
|
||||
local_ns = call_frame.f_locals
|
||||
if module is None:
|
||||
global_ns = call_frame.f_globals
|
||||
try:
|
||||
module = sys.modules[global_ns['__name__']]
|
||||
except KeyError:
|
||||
warnings.warn("Failed to get module %s" % \
|
||||
global_ns.get('__name__', 'unknown module')
|
||||
)
|
||||
module = DummyMod()
|
||||
module.__dict__ = global_ns
|
||||
if compile_flags is None:
|
||||
compile_flags = (call_frame.f_code.co_flags &
|
||||
compilerop.PyCF_MASK)
|
||||
|
||||
# Save original namespace and module so we can restore them after
|
||||
# embedding; otherwise the shell doesn't shut down correctly.
|
||||
orig_user_module = self.user_module
|
||||
orig_user_ns = self.user_ns
|
||||
orig_compile_flags = self.compile.flags
|
||||
|
||||
# Update namespaces and fire up interpreter
|
||||
|
||||
# The global one is easy, we can just throw it in
|
||||
if module is not None:
|
||||
self.user_module = module
|
||||
|
||||
# But the user/local one is tricky: ipython needs it to store internal
|
||||
# data, but we also need the locals. We'll throw our hidden variables
|
||||
# like _ih and get_ipython() into the local namespace, but delete them
|
||||
# later.
|
||||
if local_ns is not None:
|
||||
reentrant_local_ns = {k: v for (k, v) in local_ns.items() if k not in self.user_ns_hidden.keys()}
|
||||
self.user_ns = reentrant_local_ns
|
||||
self.init_user_ns()
|
||||
|
||||
# Compiler flags
|
||||
if compile_flags is not None:
|
||||
self.compile.flags = compile_flags
|
||||
|
||||
# make sure the tab-completer has the correct frame information, so it
|
||||
# actually completes using the frame's locals/globals
|
||||
self.set_completer_frame()
|
||||
|
||||
with self.builtin_trap, self.display_trap:
|
||||
self.interact()
|
||||
|
||||
# now, purge out the local namespace of IPython's hidden variables.
|
||||
if local_ns is not None:
|
||||
local_ns.update({k: v for (k, v) in self.user_ns.items() if k not in self.user_ns_hidden.keys()})
|
||||
|
||||
|
||||
# Restore original namespace so shell can shut down when we exit.
|
||||
self.user_module = orig_user_module
|
||||
self.user_ns = orig_user_ns
|
||||
self.compile.flags = orig_compile_flags
|
||||
|
||||
|
||||
def embed(**kwargs):
|
||||
"""Call this to embed IPython at the current point in your program.
|
||||
|
||||
The first invocation of this will create an :class:`InteractiveShellEmbed`
|
||||
instance and then call it. Consecutive calls just call the already
|
||||
created instance.
|
||||
|
||||
If you don't want the kernel to initialize the namespace
|
||||
from the scope of the surrounding function,
|
||||
and/or you want to load full IPython configuration,
|
||||
you probably want `IPython.start_ipython()` instead.
|
||||
|
||||
Here is a simple example::
|
||||
|
||||
from IPython import embed
|
||||
a = 10
|
||||
b = 20
|
||||
embed(header='First time')
|
||||
c = 30
|
||||
d = 40
|
||||
embed()
|
||||
|
||||
Full customization can be done by passing a :class:`Config` in as the
|
||||
config argument.
|
||||
"""
|
||||
config = kwargs.get('config')
|
||||
header = kwargs.pop('header', u'')
|
||||
compile_flags = kwargs.pop('compile_flags', None)
|
||||
if config is None:
|
||||
config = load_default_config()
|
||||
config.InteractiveShellEmbed = config.TerminalInteractiveShell
|
||||
kwargs['config'] = config
|
||||
using = kwargs.get('using', 'sync')
|
||||
if using :
|
||||
kwargs['config'].update({'TerminalInteractiveShell':{'loop_runner':using, 'colors':'NoColor', 'autoawait': using!='sync'}})
|
||||
#save ps1/ps2 if defined
|
||||
ps1 = None
|
||||
ps2 = None
|
||||
try:
|
||||
ps1 = sys.ps1
|
||||
ps2 = sys.ps2
|
||||
except AttributeError:
|
||||
pass
|
||||
#save previous instance
|
||||
saved_shell_instance = InteractiveShell._instance
|
||||
if saved_shell_instance is not None:
|
||||
cls = type(saved_shell_instance)
|
||||
cls.clear_instance()
|
||||
frame = sys._getframe(1)
|
||||
shell = InteractiveShellEmbed.instance(_init_location_id='%s:%s' % (
|
||||
frame.f_code.co_filename, frame.f_lineno), **kwargs)
|
||||
shell(header=header, stack_depth=2, compile_flags=compile_flags,
|
||||
_call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno))
|
||||
InteractiveShellEmbed.clear_instance()
|
||||
#restore previous instance
|
||||
if saved_shell_instance is not None:
|
||||
cls = type(saved_shell_instance)
|
||||
cls.clear_instance()
|
||||
for subclass in cls._walk_mro():
|
||||
subclass._instance = saved_shell_instance
|
||||
if ps1 is not None:
|
||||
sys.ps1 = ps1
|
||||
sys.ps2 = ps2
|
645
venv/Lib/site-packages/IPython/terminal/interactiveshell.py
Normal file
645
venv/Lib/site-packages/IPython/terminal/interactiveshell.py
Normal file
|
@ -0,0 +1,645 @@
|
|||
"""IPython terminal interface using prompt_toolkit"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
from warnings import warn
|
||||
|
||||
from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
|
||||
from IPython.utils import io
|
||||
from IPython.utils.py3compat import input
|
||||
from IPython.utils.terminal import toggle_set_term_title, set_term_title, restore_term_title
|
||||
from IPython.utils.process import abbrev_cwd
|
||||
from traitlets import (
|
||||
Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union,
|
||||
Any, validate
|
||||
)
|
||||
|
||||
from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
|
||||
from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
|
||||
from prompt_toolkit.formatted_text import PygmentsTokens
|
||||
from prompt_toolkit.history import InMemoryHistory
|
||||
from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
|
||||
from prompt_toolkit.output import ColorDepth
|
||||
from prompt_toolkit.patch_stdout import patch_stdout
|
||||
from prompt_toolkit.shortcuts import PromptSession, CompleteStyle, print_formatted_text
|
||||
from prompt_toolkit.styles import DynamicStyle, merge_styles
|
||||
from prompt_toolkit.styles.pygments import style_from_pygments_cls, style_from_pygments_dict
|
||||
from prompt_toolkit import __version__ as ptk_version
|
||||
|
||||
from pygments.styles import get_style_by_name
|
||||
from pygments.style import Style
|
||||
from pygments.token import Token
|
||||
|
||||
from .debugger import TerminalPdb, Pdb
|
||||
from .magics import TerminalMagics
|
||||
from .pt_inputhooks import get_inputhook_name_and_func
|
||||
from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
|
||||
from .ptutils import IPythonPTCompleter, IPythonPTLexer
|
||||
from .shortcuts import create_ipython_shortcuts
|
||||
|
||||
DISPLAY_BANNER_DEPRECATED = object()
|
||||
PTK3 = ptk_version.startswith('3.')
|
||||
|
||||
|
||||
class _NoStyle(Style): pass
|
||||
|
||||
|
||||
|
||||
_style_overrides_light_bg = {
|
||||
Token.Prompt: '#0000ff',
|
||||
Token.PromptNum: '#0000ee bold',
|
||||
Token.OutPrompt: '#cc0000',
|
||||
Token.OutPromptNum: '#bb0000 bold',
|
||||
}
|
||||
|
||||
_style_overrides_linux = {
|
||||
Token.Prompt: '#00cc00',
|
||||
Token.PromptNum: '#00bb00 bold',
|
||||
Token.OutPrompt: '#cc0000',
|
||||
Token.OutPromptNum: '#bb0000 bold',
|
||||
}
|
||||
|
||||
def get_default_editor():
|
||||
try:
|
||||
return os.environ['EDITOR']
|
||||
except KeyError:
|
||||
pass
|
||||
except UnicodeError:
|
||||
warn("$EDITOR environment variable is not pure ASCII. Using platform "
|
||||
"default editor.")
|
||||
|
||||
if os.name == 'posix':
|
||||
return 'vi' # the only one guaranteed to be there!
|
||||
else:
|
||||
return 'notepad' # same in Windows!
|
||||
|
||||
# conservatively check for tty
|
||||
# overridden streams can result in things like:
|
||||
# - sys.stdin = None
|
||||
# - no isatty method
|
||||
for _name in ('stdin', 'stdout', 'stderr'):
|
||||
_stream = getattr(sys, _name)
|
||||
if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty():
|
||||
_is_tty = False
|
||||
break
|
||||
else:
|
||||
_is_tty = True
|
||||
|
||||
|
||||
_use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
|
||||
|
||||
def black_reformat_handler(text_before_cursor):
|
||||
import black
|
||||
formatted_text = black.format_str(text_before_cursor, mode=black.FileMode())
|
||||
if not text_before_cursor.endswith('\n') and formatted_text.endswith('\n'):
|
||||
formatted_text = formatted_text[:-1]
|
||||
return formatted_text
|
||||
|
||||
|
||||
class TerminalInteractiveShell(InteractiveShell):
|
||||
mime_renderers = Dict().tag(config=True)
|
||||
|
||||
space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
|
||||
'to reserve for the tab completion menu, '
|
||||
'search history, ...etc, the height of '
|
||||
'these menus will at most this value. '
|
||||
'Increase it is you prefer long and skinny '
|
||||
'menus, decrease for short and wide.'
|
||||
).tag(config=True)
|
||||
|
||||
pt_app = None
|
||||
debugger_history = None
|
||||
|
||||
simple_prompt = Bool(_use_simple_prompt,
|
||||
help="""Use `raw_input` for the REPL, without completion and prompt colors.
|
||||
|
||||
Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
|
||||
IPython own testing machinery, and emacs inferior-shell integration through elpy.
|
||||
|
||||
This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
|
||||
environment variable is set, or the current terminal is not a tty."""
|
||||
).tag(config=True)
|
||||
|
||||
@property
|
||||
def debugger_cls(self):
|
||||
return Pdb if self.simple_prompt else TerminalPdb
|
||||
|
||||
confirm_exit = Bool(True,
|
||||
help="""
|
||||
Set to confirm when you try to exit IPython with an EOF (Control-D
|
||||
in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
|
||||
you can force a direct exit without any confirmation.""",
|
||||
).tag(config=True)
|
||||
|
||||
editing_mode = Unicode('emacs',
|
||||
help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
|
||||
).tag(config=True)
|
||||
|
||||
autoformatter = Unicode(None,
|
||||
help="Autoformatter to reformat Terminal code. Can be `'black'` or `None`",
|
||||
allow_none=True
|
||||
).tag(config=True)
|
||||
|
||||
mouse_support = Bool(False,
|
||||
help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
|
||||
).tag(config=True)
|
||||
|
||||
# We don't load the list of styles for the help string, because loading
|
||||
# Pygments plugins takes time and can cause unexpected errors.
|
||||
highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
|
||||
help="""The name or class of a Pygments style to use for syntax
|
||||
highlighting. To see available styles, run `pygmentize -L styles`."""
|
||||
).tag(config=True)
|
||||
|
||||
@validate('editing_mode')
|
||||
def _validate_editing_mode(self, proposal):
|
||||
if proposal['value'].lower() == 'vim':
|
||||
proposal['value']= 'vi'
|
||||
elif proposal['value'].lower() == 'default':
|
||||
proposal['value']= 'emacs'
|
||||
|
||||
if hasattr(EditingMode, proposal['value'].upper()):
|
||||
return proposal['value'].lower()
|
||||
|
||||
return self.editing_mode
|
||||
|
||||
|
||||
@observe('editing_mode')
|
||||
def _editing_mode(self, change):
|
||||
u_mode = change.new.upper()
|
||||
if self.pt_app:
|
||||
self.pt_app.editing_mode = u_mode
|
||||
|
||||
@observe('autoformatter')
|
||||
def _autoformatter_changed(self, change):
|
||||
formatter = change.new
|
||||
if formatter is None:
|
||||
self.reformat_handler = lambda x:x
|
||||
elif formatter == 'black':
|
||||
self.reformat_handler = black_reformat_handler
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
@observe('highlighting_style')
|
||||
@observe('colors')
|
||||
def _highlighting_style_changed(self, change):
|
||||
self.refresh_style()
|
||||
|
||||
def refresh_style(self):
|
||||
self._style = self._make_style_from_name_or_cls(self.highlighting_style)
|
||||
|
||||
|
||||
highlighting_style_overrides = Dict(
|
||||
help="Override highlighting format for specific tokens"
|
||||
).tag(config=True)
|
||||
|
||||
true_color = Bool(False,
|
||||
help=("Use 24bit colors instead of 256 colors in prompt highlighting. "
|
||||
"If your terminal supports true color, the following command "
|
||||
"should print 'TRUECOLOR' in orange: "
|
||||
"printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"")
|
||||
).tag(config=True)
|
||||
|
||||
editor = Unicode(get_default_editor(),
|
||||
help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
|
||||
).tag(config=True)
|
||||
|
||||
prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
|
||||
|
||||
prompts = Instance(Prompts)
|
||||
|
||||
@default('prompts')
|
||||
def _prompts_default(self):
|
||||
return self.prompts_class(self)
|
||||
|
||||
# @observe('prompts')
|
||||
# def _(self, change):
|
||||
# self._update_layout()
|
||||
|
||||
@default('displayhook_class')
|
||||
def _displayhook_class_default(self):
|
||||
return RichPromptDisplayHook
|
||||
|
||||
term_title = Bool(True,
|
||||
help="Automatically set the terminal title"
|
||||
).tag(config=True)
|
||||
|
||||
term_title_format = Unicode("IPython: {cwd}",
|
||||
help="Customize the terminal title format. This is a python format string. " +
|
||||
"Available substitutions are: {cwd}."
|
||||
).tag(config=True)
|
||||
|
||||
display_completions = Enum(('column', 'multicolumn','readlinelike'),
|
||||
help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
|
||||
"'readlinelike'. These options are for `prompt_toolkit`, see "
|
||||
"`prompt_toolkit` documentation for more information."
|
||||
),
|
||||
default_value='multicolumn').tag(config=True)
|
||||
|
||||
highlight_matching_brackets = Bool(True,
|
||||
help="Highlight matching brackets.",
|
||||
).tag(config=True)
|
||||
|
||||
extra_open_editor_shortcuts = Bool(False,
|
||||
help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
|
||||
"This is in addition to the F2 binding, which is always enabled."
|
||||
).tag(config=True)
|
||||
|
||||
handle_return = Any(None,
|
||||
help="Provide an alternative handler to be called when the user presses "
|
||||
"Return. This is an advanced option intended for debugging, which "
|
||||
"may be changed or removed in later releases."
|
||||
).tag(config=True)
|
||||
|
||||
enable_history_search = Bool(True,
|
||||
help="Allows to enable/disable the prompt toolkit history search"
|
||||
).tag(config=True)
|
||||
|
||||
prompt_includes_vi_mode = Bool(True,
|
||||
help="Display the current vi mode (when using vi editing mode)."
|
||||
).tag(config=True)
|
||||
|
||||
@observe('term_title')
|
||||
def init_term_title(self, change=None):
|
||||
# Enable or disable the terminal title.
|
||||
if self.term_title:
|
||||
toggle_set_term_title(True)
|
||||
set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
|
||||
else:
|
||||
toggle_set_term_title(False)
|
||||
|
||||
def restore_term_title(self):
|
||||
if self.term_title:
|
||||
restore_term_title()
|
||||
|
||||
def init_display_formatter(self):
|
||||
super(TerminalInteractiveShell, self).init_display_formatter()
|
||||
# terminal only supports plain text
|
||||
self.display_formatter.active_types = ['text/plain']
|
||||
# disable `_ipython_display_`
|
||||
self.display_formatter.ipython_display_formatter.enabled = False
|
||||
|
||||
def init_prompt_toolkit_cli(self):
|
||||
if self.simple_prompt:
|
||||
# Fall back to plain non-interactive output for tests.
|
||||
# This is very limited.
|
||||
def prompt():
|
||||
prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
|
||||
lines = [input(prompt_text)]
|
||||
prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
|
||||
while self.check_complete('\n'.join(lines))[0] == 'incomplete':
|
||||
lines.append( input(prompt_continuation) )
|
||||
return '\n'.join(lines)
|
||||
self.prompt_for_code = prompt
|
||||
return
|
||||
|
||||
# Set up keyboard shortcuts
|
||||
key_bindings = create_ipython_shortcuts(self)
|
||||
|
||||
# Pre-populate history from IPython's history database
|
||||
history = InMemoryHistory()
|
||||
last_cell = u""
|
||||
for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
|
||||
include_latest=True):
|
||||
# Ignore blank lines and consecutive duplicates
|
||||
cell = cell.rstrip()
|
||||
if cell and (cell != last_cell):
|
||||
history.append_string(cell)
|
||||
last_cell = cell
|
||||
|
||||
self._style = self._make_style_from_name_or_cls(self.highlighting_style)
|
||||
self.style = DynamicStyle(lambda: self._style)
|
||||
|
||||
editing_mode = getattr(EditingMode, self.editing_mode.upper())
|
||||
|
||||
self.pt_loop = asyncio.new_event_loop()
|
||||
self.pt_app = PromptSession(
|
||||
editing_mode=editing_mode,
|
||||
key_bindings=key_bindings,
|
||||
history=history,
|
||||
completer=IPythonPTCompleter(shell=self),
|
||||
enable_history_search = self.enable_history_search,
|
||||
style=self.style,
|
||||
include_default_pygments_style=False,
|
||||
mouse_support=self.mouse_support,
|
||||
enable_open_in_editor=self.extra_open_editor_shortcuts,
|
||||
color_depth=self.color_depth,
|
||||
tempfile_suffix=".py",
|
||||
**self._extra_prompt_options())
|
||||
|
||||
def _make_style_from_name_or_cls(self, name_or_cls):
|
||||
"""
|
||||
Small wrapper that make an IPython compatible style from a style name
|
||||
|
||||
We need that to add style for prompt ... etc.
|
||||
"""
|
||||
style_overrides = {}
|
||||
if name_or_cls == 'legacy':
|
||||
legacy = self.colors.lower()
|
||||
if legacy == 'linux':
|
||||
style_cls = get_style_by_name('monokai')
|
||||
style_overrides = _style_overrides_linux
|
||||
elif legacy == 'lightbg':
|
||||
style_overrides = _style_overrides_light_bg
|
||||
style_cls = get_style_by_name('pastie')
|
||||
elif legacy == 'neutral':
|
||||
# The default theme needs to be visible on both a dark background
|
||||
# and a light background, because we can't tell what the terminal
|
||||
# looks like. These tweaks to the default theme help with that.
|
||||
style_cls = get_style_by_name('default')
|
||||
style_overrides.update({
|
||||
Token.Number: '#007700',
|
||||
Token.Operator: 'noinherit',
|
||||
Token.String: '#BB6622',
|
||||
Token.Name.Function: '#2080D0',
|
||||
Token.Name.Class: 'bold #2080D0',
|
||||
Token.Name.Namespace: 'bold #2080D0',
|
||||
Token.Prompt: '#009900',
|
||||
Token.PromptNum: '#ansibrightgreen bold',
|
||||
Token.OutPrompt: '#990000',
|
||||
Token.OutPromptNum: '#ansibrightred bold',
|
||||
})
|
||||
|
||||
# Hack: Due to limited color support on the Windows console
|
||||
# the prompt colors will be wrong without this
|
||||
if os.name == 'nt':
|
||||
style_overrides.update({
|
||||
Token.Prompt: '#ansidarkgreen',
|
||||
Token.PromptNum: '#ansigreen bold',
|
||||
Token.OutPrompt: '#ansidarkred',
|
||||
Token.OutPromptNum: '#ansired bold',
|
||||
})
|
||||
elif legacy =='nocolor':
|
||||
style_cls=_NoStyle
|
||||
style_overrides = {}
|
||||
else :
|
||||
raise ValueError('Got unknown colors: ', legacy)
|
||||
else :
|
||||
if isinstance(name_or_cls, str):
|
||||
style_cls = get_style_by_name(name_or_cls)
|
||||
else:
|
||||
style_cls = name_or_cls
|
||||
style_overrides = {
|
||||
Token.Prompt: '#009900',
|
||||
Token.PromptNum: '#ansibrightgreen bold',
|
||||
Token.OutPrompt: '#990000',
|
||||
Token.OutPromptNum: '#ansibrightred bold',
|
||||
}
|
||||
style_overrides.update(self.highlighting_style_overrides)
|
||||
style = merge_styles([
|
||||
style_from_pygments_cls(style_cls),
|
||||
style_from_pygments_dict(style_overrides),
|
||||
])
|
||||
|
||||
return style
|
||||
|
||||
@property
|
||||
def pt_complete_style(self):
|
||||
return {
|
||||
'multicolumn': CompleteStyle.MULTI_COLUMN,
|
||||
'column': CompleteStyle.COLUMN,
|
||||
'readlinelike': CompleteStyle.READLINE_LIKE,
|
||||
}[self.display_completions]
|
||||
|
||||
@property
|
||||
def color_depth(self):
|
||||
return (ColorDepth.TRUE_COLOR if self.true_color else None)
|
||||
|
||||
def _extra_prompt_options(self):
|
||||
"""
|
||||
Return the current layout option for the current Terminal InteractiveShell
|
||||
"""
|
||||
def get_message():
|
||||
return PygmentsTokens(self.prompts.in_prompt_tokens())
|
||||
|
||||
if self.editing_mode == 'emacs':
|
||||
# with emacs mode the prompt is (usually) static, so we call only
|
||||
# the function once. With VI mode it can toggle between [ins] and
|
||||
# [nor] so we can't precompute.
|
||||
# here I'm going to favor the default keybinding which almost
|
||||
# everybody uses to decrease CPU usage.
|
||||
# if we have issues with users with custom Prompts we can see how to
|
||||
# work around this.
|
||||
get_message = get_message()
|
||||
|
||||
options = {
|
||||
'complete_in_thread': False,
|
||||
'lexer':IPythonPTLexer(),
|
||||
'reserve_space_for_menu':self.space_for_menu,
|
||||
'message': get_message,
|
||||
'prompt_continuation': (
|
||||
lambda width, lineno, is_soft_wrap:
|
||||
PygmentsTokens(self.prompts.continuation_prompt_tokens(width))),
|
||||
'multiline': True,
|
||||
'complete_style': self.pt_complete_style,
|
||||
|
||||
# Highlight matching brackets, but only when this setting is
|
||||
# enabled, and only when the DEFAULT_BUFFER has the focus.
|
||||
'input_processors': [ConditionalProcessor(
|
||||
processor=HighlightMatchingBracketProcessor(chars='[](){}'),
|
||||
filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
|
||||
Condition(lambda: self.highlight_matching_brackets))],
|
||||
}
|
||||
if not PTK3:
|
||||
options['inputhook'] = self.inputhook
|
||||
|
||||
return options
|
||||
|
||||
def prompt_for_code(self):
|
||||
if self.rl_next_input:
|
||||
default = self.rl_next_input
|
||||
self.rl_next_input = None
|
||||
else:
|
||||
default = ''
|
||||
|
||||
# In order to make sure that asyncio code written in the
|
||||
# interactive shell doesn't interfere with the prompt, we run the
|
||||
# prompt in a different event loop.
|
||||
# If we don't do this, people could spawn coroutine with a
|
||||
# while/true inside which will freeze the prompt.
|
||||
|
||||
try:
|
||||
old_loop = asyncio.get_event_loop()
|
||||
except RuntimeError:
|
||||
# This happens when the user used `asyncio.run()`.
|
||||
old_loop = None
|
||||
|
||||
asyncio.set_event_loop(self.pt_loop)
|
||||
try:
|
||||
with patch_stdout(raw=True):
|
||||
text = self.pt_app.prompt(
|
||||
default=default,
|
||||
**self._extra_prompt_options())
|
||||
finally:
|
||||
# Restore the original event loop.
|
||||
asyncio.set_event_loop(old_loop)
|
||||
|
||||
return text
|
||||
|
||||
def enable_win_unicode_console(self):
|
||||
# Since IPython 7.10 doesn't support python < 3.6 and PEP 528, Python uses the unicode APIs for the Windows
|
||||
# console by default, so WUC shouldn't be needed.
|
||||
from warnings import warn
|
||||
warn("`enable_win_unicode_console` is deprecated since IPython 7.10, does not do anything and will be removed in the future",
|
||||
DeprecationWarning,
|
||||
stacklevel=2)
|
||||
|
||||
def init_io(self):
|
||||
if sys.platform not in {'win32', 'cli'}:
|
||||
return
|
||||
|
||||
import colorama
|
||||
colorama.init()
|
||||
|
||||
# For some reason we make these wrappers around stdout/stderr.
|
||||
# For now, we need to reset them so all output gets coloured.
|
||||
# https://github.com/ipython/ipython/issues/8669
|
||||
# io.std* are deprecated, but don't show our own deprecation warnings
|
||||
# during initialization of the deprecated API.
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('ignore', DeprecationWarning)
|
||||
io.stdout = io.IOStream(sys.stdout)
|
||||
io.stderr = io.IOStream(sys.stderr)
|
||||
|
||||
def init_magics(self):
|
||||
super(TerminalInteractiveShell, self).init_magics()
|
||||
self.register_magics(TerminalMagics)
|
||||
|
||||
def init_alias(self):
|
||||
# The parent class defines aliases that can be safely used with any
|
||||
# frontend.
|
||||
super(TerminalInteractiveShell, self).init_alias()
|
||||
|
||||
# Now define aliases that only make sense on the terminal, because they
|
||||
# need direct access to the console in a way that we can't emulate in
|
||||
# GUI or web frontend
|
||||
if os.name == 'posix':
|
||||
for cmd in ('clear', 'more', 'less', 'man'):
|
||||
self.alias_manager.soft_define_alias(cmd, cmd)
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
|
||||
self.init_prompt_toolkit_cli()
|
||||
self.init_term_title()
|
||||
self.keep_running = True
|
||||
|
||||
self.debugger_history = InMemoryHistory()
|
||||
|
||||
def ask_exit(self):
|
||||
self.keep_running = False
|
||||
|
||||
rl_next_input = None
|
||||
|
||||
def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
|
||||
|
||||
if display_banner is not DISPLAY_BANNER_DEPRECATED:
|
||||
warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
|
||||
|
||||
self.keep_running = True
|
||||
while self.keep_running:
|
||||
print(self.separate_in, end='')
|
||||
|
||||
try:
|
||||
code = self.prompt_for_code()
|
||||
except EOFError:
|
||||
if (not self.confirm_exit) \
|
||||
or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
|
||||
self.ask_exit()
|
||||
|
||||
else:
|
||||
if code:
|
||||
self.run_cell(code, store_history=True)
|
||||
|
||||
def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
|
||||
# An extra layer of protection in case someone mashing Ctrl-C breaks
|
||||
# out of our internal code.
|
||||
if display_banner is not DISPLAY_BANNER_DEPRECATED:
|
||||
warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
|
||||
while True:
|
||||
try:
|
||||
self.interact()
|
||||
break
|
||||
except KeyboardInterrupt as e:
|
||||
print("\n%s escaped interact()\n" % type(e).__name__)
|
||||
finally:
|
||||
# An interrupt during the eventloop will mess up the
|
||||
# internal state of the prompt_toolkit library.
|
||||
# Stopping the eventloop fixes this, see
|
||||
# https://github.com/ipython/ipython/pull/9867
|
||||
if hasattr(self, '_eventloop'):
|
||||
self._eventloop.stop()
|
||||
|
||||
self.restore_term_title()
|
||||
|
||||
|
||||
_inputhook = None
|
||||
def inputhook(self, context):
|
||||
if self._inputhook is not None:
|
||||
self._inputhook(context)
|
||||
|
||||
active_eventloop = None
|
||||
def enable_gui(self, gui=None):
|
||||
if gui and (gui != 'inline') :
|
||||
self.active_eventloop, self._inputhook =\
|
||||
get_inputhook_name_and_func(gui)
|
||||
else:
|
||||
self.active_eventloop = self._inputhook = None
|
||||
|
||||
# For prompt_toolkit 3.0. We have to create an asyncio event loop with
|
||||
# this inputhook.
|
||||
if PTK3:
|
||||
import asyncio
|
||||
from prompt_toolkit.eventloop import new_eventloop_with_inputhook
|
||||
|
||||
if gui == 'asyncio':
|
||||
# When we integrate the asyncio event loop, run the UI in the
|
||||
# same event loop as the rest of the code. don't use an actual
|
||||
# input hook. (Asyncio is not made for nesting event loops.)
|
||||
self.pt_loop = asyncio.get_event_loop()
|
||||
|
||||
elif self._inputhook:
|
||||
# If an inputhook was set, create a new asyncio event loop with
|
||||
# this inputhook for the prompt.
|
||||
self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
|
||||
else:
|
||||
# When there's no inputhook, run the prompt in a separate
|
||||
# asyncio event loop.
|
||||
self.pt_loop = asyncio.new_event_loop()
|
||||
|
||||
# Run !system commands directly, not through pipes, so terminal programs
|
||||
# work correctly.
|
||||
system = InteractiveShell.system_raw
|
||||
|
||||
def auto_rewrite_input(self, cmd):
|
||||
"""Overridden from the parent class to use fancy rewriting prompt"""
|
||||
if not self.show_rewritten_input:
|
||||
return
|
||||
|
||||
tokens = self.prompts.rewrite_prompt_tokens()
|
||||
if self.pt_app:
|
||||
print_formatted_text(PygmentsTokens(tokens), end='',
|
||||
style=self.pt_app.app.style)
|
||||
print(cmd)
|
||||
else:
|
||||
prompt = ''.join(s for t, s in tokens)
|
||||
print(prompt, cmd, sep='')
|
||||
|
||||
_prompts_before = None
|
||||
def switch_doctest_mode(self, mode):
|
||||
"""Switch prompts to classic for %doctest_mode"""
|
||||
if mode:
|
||||
self._prompts_before = self.prompts
|
||||
self.prompts = ClassicPrompts(self)
|
||||
elif self._prompts_before:
|
||||
self.prompts = self._prompts_before
|
||||
self._prompts_before = None
|
||||
# self._update_layout()
|
||||
|
||||
|
||||
InteractiveShellABC.register(TerminalInteractiveShell)
|
||||
|
||||
if __name__ == '__main__':
|
||||
TerminalInteractiveShell.instance().interact()
|
380
venv/Lib/site-packages/IPython/terminal/ipapp.py
Normal file
380
venv/Lib/site-packages/IPython/terminal/ipapp.py
Normal file
|
@ -0,0 +1,380 @@
|
|||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
"""
|
||||
The :class:`~IPython.core.application.Application` object for the command
|
||||
line :command:`ipython` program.
|
||||
"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
from traitlets.config.loader import Config
|
||||
from traitlets.config.application import boolean_flag, catch_config_error
|
||||
from IPython.core import release
|
||||
from IPython.core import usage
|
||||
from IPython.core.completer import IPCompleter
|
||||
from IPython.core.crashhandler import CrashHandler
|
||||
from IPython.core.formatters import PlainTextFormatter
|
||||
from IPython.core.history import HistoryManager
|
||||
from IPython.core.application import (
|
||||
ProfileDir, BaseIPythonApplication, base_flags, base_aliases
|
||||
)
|
||||
from IPython.core.magics import (
|
||||
ScriptMagics, LoggingMagics
|
||||
)
|
||||
from IPython.core.shellapp import (
|
||||
InteractiveShellApp, shell_flags, shell_aliases
|
||||
)
|
||||
from IPython.extensions.storemagic import StoreMagics
|
||||
from .interactiveshell import TerminalInteractiveShell
|
||||
from IPython.paths import get_ipython_dir
|
||||
from traitlets import (
|
||||
Bool, List, default, observe, Type
|
||||
)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Globals, utilities and helpers
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
_examples = """
|
||||
ipython --matplotlib # enable matplotlib integration
|
||||
ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
|
||||
|
||||
ipython --log-level=DEBUG # set logging to DEBUG
|
||||
ipython --profile=foo # start with profile foo
|
||||
|
||||
ipython profile create foo # create profile foo w/ default config files
|
||||
ipython help profile # show the help for the profile subcmd
|
||||
|
||||
ipython locate # print the path to the IPython directory
|
||||
ipython locate profile foo # print the path to the directory for profile `foo`
|
||||
"""
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Crash handler for this application
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
class IPAppCrashHandler(CrashHandler):
|
||||
"""sys.excepthook for IPython itself, leaves a detailed report on disk."""
|
||||
|
||||
def __init__(self, app):
|
||||
contact_name = release.author
|
||||
contact_email = release.author_email
|
||||
bug_tracker = 'https://github.com/ipython/ipython/issues'
|
||||
super(IPAppCrashHandler,self).__init__(
|
||||
app, contact_name, contact_email, bug_tracker
|
||||
)
|
||||
|
||||
def make_report(self,traceback):
|
||||
"""Return a string containing a crash report."""
|
||||
|
||||
sec_sep = self.section_sep
|
||||
# Start with parent report
|
||||
report = [super(IPAppCrashHandler, self).make_report(traceback)]
|
||||
# Add interactive-specific info we may have
|
||||
rpt_add = report.append
|
||||
try:
|
||||
rpt_add(sec_sep+"History of session input:")
|
||||
for line in self.app.shell.user_ns['_ih']:
|
||||
rpt_add(line)
|
||||
rpt_add('\n*** Last line of input (may not be in above history):\n')
|
||||
rpt_add(self.app.shell._last_input_line+'\n')
|
||||
except:
|
||||
pass
|
||||
|
||||
return ''.join(report)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Aliases and Flags
|
||||
#-----------------------------------------------------------------------------
|
||||
flags = dict(base_flags)
|
||||
flags.update(shell_flags)
|
||||
frontend_flags = {}
|
||||
addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
|
||||
addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
|
||||
'Turn on auto editing of files with syntax errors.',
|
||||
'Turn off auto editing of files with syntax errors.'
|
||||
)
|
||||
addflag('simple-prompt', 'TerminalInteractiveShell.simple_prompt',
|
||||
"Force simple minimal prompt using `raw_input`",
|
||||
"Use a rich interactive prompt with prompt_toolkit",
|
||||
)
|
||||
|
||||
addflag('banner', 'TerminalIPythonApp.display_banner',
|
||||
"Display a banner upon starting IPython.",
|
||||
"Don't display a banner upon starting IPython."
|
||||
)
|
||||
addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
|
||||
"""Set to confirm when you try to exit IPython with an EOF (Control-D
|
||||
in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
|
||||
you can force a direct exit without any confirmation.""",
|
||||
"Don't prompt the user when exiting."
|
||||
)
|
||||
addflag('term-title', 'TerminalInteractiveShell.term_title',
|
||||
"Enable auto setting the terminal title.",
|
||||
"Disable auto setting the terminal title."
|
||||
)
|
||||
classic_config = Config()
|
||||
classic_config.InteractiveShell.cache_size = 0
|
||||
classic_config.PlainTextFormatter.pprint = False
|
||||
classic_config.TerminalInteractiveShell.prompts_class='IPython.terminal.prompts.ClassicPrompts'
|
||||
classic_config.InteractiveShell.separate_in = ''
|
||||
classic_config.InteractiveShell.separate_out = ''
|
||||
classic_config.InteractiveShell.separate_out2 = ''
|
||||
classic_config.InteractiveShell.colors = 'NoColor'
|
||||
classic_config.InteractiveShell.xmode = 'Plain'
|
||||
|
||||
frontend_flags['classic']=(
|
||||
classic_config,
|
||||
"Gives IPython a similar feel to the classic Python prompt."
|
||||
)
|
||||
# # log doesn't make so much sense this way anymore
|
||||
# paa('--log','-l',
|
||||
# action='store_true', dest='InteractiveShell.logstart',
|
||||
# help="Start logging to the default log file (./ipython_log.py).")
|
||||
#
|
||||
# # quick is harder to implement
|
||||
frontend_flags['quick']=(
|
||||
{'TerminalIPythonApp' : {'quick' : True}},
|
||||
"Enable quick startup with no config files."
|
||||
)
|
||||
|
||||
frontend_flags['i'] = (
|
||||
{'TerminalIPythonApp' : {'force_interact' : True}},
|
||||
"""If running code from the command line, become interactive afterwards.
|
||||
It is often useful to follow this with `--` to treat remaining flags as
|
||||
script arguments.
|
||||
"""
|
||||
)
|
||||
flags.update(frontend_flags)
|
||||
|
||||
aliases = dict(base_aliases)
|
||||
aliases.update(shell_aliases)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Main classes and functions
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
class LocateIPythonApp(BaseIPythonApplication):
|
||||
description = """print the path to the IPython dir"""
|
||||
subcommands = dict(
|
||||
profile=('IPython.core.profileapp.ProfileLocate',
|
||||
"print the path to an IPython profile directory",
|
||||
),
|
||||
)
|
||||
def start(self):
|
||||
if self.subapp is not None:
|
||||
return self.subapp.start()
|
||||
else:
|
||||
print(self.ipython_dir)
|
||||
|
||||
|
||||
class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
|
||||
name = u'ipython'
|
||||
description = usage.cl_usage
|
||||
crash_handler_class = IPAppCrashHandler
|
||||
examples = _examples
|
||||
|
||||
flags = flags
|
||||
aliases = aliases
|
||||
classes = List()
|
||||
|
||||
interactive_shell_class = Type(
|
||||
klass=object, # use default_value otherwise which only allow subclasses.
|
||||
default_value=TerminalInteractiveShell,
|
||||
help="Class to use to instantiate the TerminalInteractiveShell object. Useful for custom Frontends"
|
||||
).tag(config=True)
|
||||
|
||||
@default('classes')
|
||||
def _classes_default(self):
|
||||
"""This has to be in a method, for TerminalIPythonApp to be available."""
|
||||
return [
|
||||
InteractiveShellApp, # ShellApp comes before TerminalApp, because
|
||||
self.__class__, # it will also affect subclasses (e.g. QtConsole)
|
||||
TerminalInteractiveShell,
|
||||
HistoryManager,
|
||||
ProfileDir,
|
||||
PlainTextFormatter,
|
||||
IPCompleter,
|
||||
ScriptMagics,
|
||||
LoggingMagics,
|
||||
StoreMagics,
|
||||
]
|
||||
|
||||
deprecated_subcommands = dict(
|
||||
qtconsole=('qtconsole.qtconsoleapp.JupyterQtConsoleApp',
|
||||
"""DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter Qt Console."""
|
||||
),
|
||||
notebook=('notebook.notebookapp.NotebookApp',
|
||||
"""DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter HTML Notebook Server."""
|
||||
),
|
||||
console=('jupyter_console.app.ZMQTerminalIPythonApp',
|
||||
"""DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter terminal-based Console."""
|
||||
),
|
||||
nbconvert=('nbconvert.nbconvertapp.NbConvertApp',
|
||||
"DEPRECATED, Will be removed in IPython 6.0 : Convert notebooks to/from other formats."
|
||||
),
|
||||
trust=('nbformat.sign.TrustNotebookApp',
|
||||
"DEPRECATED, Will be removed in IPython 6.0 : Sign notebooks to trust their potentially unsafe contents at load."
|
||||
),
|
||||
kernelspec=('jupyter_client.kernelspecapp.KernelSpecApp',
|
||||
"DEPRECATED, Will be removed in IPython 6.0 : Manage Jupyter kernel specifications."
|
||||
),
|
||||
)
|
||||
subcommands = dict(
|
||||
profile = ("IPython.core.profileapp.ProfileApp",
|
||||
"Create and manage IPython profiles."
|
||||
),
|
||||
kernel = ("ipykernel.kernelapp.IPKernelApp",
|
||||
"Start a kernel without an attached frontend."
|
||||
),
|
||||
locate=('IPython.terminal.ipapp.LocateIPythonApp',
|
||||
LocateIPythonApp.description
|
||||
),
|
||||
history=('IPython.core.historyapp.HistoryApp',
|
||||
"Manage the IPython history database."
|
||||
),
|
||||
)
|
||||
deprecated_subcommands['install-nbextension'] = (
|
||||
"notebook.nbextensions.InstallNBExtensionApp",
|
||||
"DEPRECATED, Will be removed in IPython 6.0 : Install Jupyter notebook extension files"
|
||||
)
|
||||
subcommands.update(deprecated_subcommands)
|
||||
|
||||
# *do* autocreate requested profile, but don't create the config file.
|
||||
auto_create=Bool(True)
|
||||
# configurables
|
||||
quick = Bool(False,
|
||||
help="""Start IPython quickly by skipping the loading of config files."""
|
||||
).tag(config=True)
|
||||
@observe('quick')
|
||||
def _quick_changed(self, change):
|
||||
if change['new']:
|
||||
self.load_config_file = lambda *a, **kw: None
|
||||
|
||||
display_banner = Bool(True,
|
||||
help="Whether to display a banner upon starting IPython."
|
||||
).tag(config=True)
|
||||
|
||||
# if there is code of files to run from the cmd line, don't interact
|
||||
# unless the --i flag (App.force_interact) is true.
|
||||
force_interact = Bool(False,
|
||||
help="""If a command or file is given via the command-line,
|
||||
e.g. 'ipython foo.py', start an interactive shell after executing the
|
||||
file or command."""
|
||||
).tag(config=True)
|
||||
@observe('force_interact')
|
||||
def _force_interact_changed(self, change):
|
||||
if change['new']:
|
||||
self.interact = True
|
||||
|
||||
@observe('file_to_run', 'code_to_run', 'module_to_run')
|
||||
def _file_to_run_changed(self, change):
|
||||
new = change['new']
|
||||
if new:
|
||||
self.something_to_run = True
|
||||
if new and not self.force_interact:
|
||||
self.interact = False
|
||||
|
||||
# internal, not-configurable
|
||||
something_to_run=Bool(False)
|
||||
|
||||
def parse_command_line(self, argv=None):
|
||||
"""override to allow old '-pylab' flag with deprecation warning"""
|
||||
|
||||
argv = sys.argv[1:] if argv is None else argv
|
||||
|
||||
if '-pylab' in argv:
|
||||
# deprecated `-pylab` given,
|
||||
# warn and transform into current syntax
|
||||
argv = argv[:] # copy, don't clobber
|
||||
idx = argv.index('-pylab')
|
||||
warnings.warn("`-pylab` flag has been deprecated.\n"
|
||||
" Use `--matplotlib <backend>` and import pylab manually.")
|
||||
argv[idx] = '--pylab'
|
||||
|
||||
return super(TerminalIPythonApp, self).parse_command_line(argv)
|
||||
|
||||
@catch_config_error
|
||||
def initialize(self, argv=None):
|
||||
"""Do actions after construct, but before starting the app."""
|
||||
super(TerminalIPythonApp, self).initialize(argv)
|
||||
if self.subapp is not None:
|
||||
# don't bother initializing further, starting subapp
|
||||
return
|
||||
# print self.extra_args
|
||||
if self.extra_args and not self.something_to_run:
|
||||
self.file_to_run = self.extra_args[0]
|
||||
self.init_path()
|
||||
# create the shell
|
||||
self.init_shell()
|
||||
# and draw the banner
|
||||
self.init_banner()
|
||||
# Now a variety of things that happen after the banner is printed.
|
||||
self.init_gui_pylab()
|
||||
self.init_extensions()
|
||||
self.init_code()
|
||||
|
||||
def init_shell(self):
|
||||
"""initialize the InteractiveShell instance"""
|
||||
# Create an InteractiveShell instance.
|
||||
# shell.display_banner should always be False for the terminal
|
||||
# based app, because we call shell.show_banner() by hand below
|
||||
# so the banner shows *before* all extension loading stuff.
|
||||
self.shell = self.interactive_shell_class.instance(parent=self,
|
||||
profile_dir=self.profile_dir,
|
||||
ipython_dir=self.ipython_dir, user_ns=self.user_ns)
|
||||
self.shell.configurables.append(self)
|
||||
|
||||
def init_banner(self):
|
||||
"""optionally display the banner"""
|
||||
if self.display_banner and self.interact:
|
||||
self.shell.show_banner()
|
||||
# Make sure there is a space below the banner.
|
||||
if self.log_level <= logging.INFO: print()
|
||||
|
||||
def _pylab_changed(self, name, old, new):
|
||||
"""Replace --pylab='inline' with --pylab='auto'"""
|
||||
if new == 'inline':
|
||||
warnings.warn("'inline' not available as pylab backend, "
|
||||
"using 'auto' instead.")
|
||||
self.pylab = 'auto'
|
||||
|
||||
def start(self):
|
||||
if self.subapp is not None:
|
||||
return self.subapp.start()
|
||||
# perform any prexec steps:
|
||||
if self.interact:
|
||||
self.log.debug("Starting IPython's mainloop...")
|
||||
self.shell.mainloop()
|
||||
else:
|
||||
self.log.debug("IPython not interactive...")
|
||||
if not self.shell.last_execution_succeeded:
|
||||
sys.exit(1)
|
||||
|
||||
def load_default_config(ipython_dir=None):
|
||||
"""Load the default config file from the default ipython_dir.
|
||||
|
||||
This is useful for embedded shells.
|
||||
"""
|
||||
if ipython_dir is None:
|
||||
ipython_dir = get_ipython_dir()
|
||||
|
||||
profile_dir = os.path.join(ipython_dir, 'profile_default')
|
||||
app = TerminalIPythonApp()
|
||||
app.config_file_paths.append(profile_dir)
|
||||
app.load_config_file()
|
||||
return app.config
|
||||
|
||||
launch_new_instance = TerminalIPythonApp.launch_instance
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
launch_new_instance()
|
203
venv/Lib/site-packages/IPython/terminal/magics.py
Normal file
203
venv/Lib/site-packages/IPython/terminal/magics.py
Normal file
|
@ -0,0 +1,203 @@
|
|||
"""Extra magics for terminal use."""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
|
||||
from logging import error
|
||||
import os
|
||||
import sys
|
||||
|
||||
from IPython.core.error import TryNext, UsageError
|
||||
from IPython.core.magic import Magics, magics_class, line_magic
|
||||
from IPython.lib.clipboard import ClipboardEmpty
|
||||
from IPython.utils.text import SList, strip_email_quotes
|
||||
from IPython.utils import py3compat
|
||||
|
||||
def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False):
|
||||
""" Yield pasted lines until the user enters the given sentinel value.
|
||||
"""
|
||||
if not quiet:
|
||||
print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
|
||||
% sentinel)
|
||||
prompt = ":"
|
||||
else:
|
||||
prompt = ""
|
||||
while True:
|
||||
try:
|
||||
l = l_input(prompt)
|
||||
if l == sentinel:
|
||||
return
|
||||
else:
|
||||
yield l
|
||||
except EOFError:
|
||||
print('<EOF>')
|
||||
return
|
||||
|
||||
|
||||
@magics_class
|
||||
class TerminalMagics(Magics):
|
||||
def __init__(self, shell):
|
||||
super(TerminalMagics, self).__init__(shell)
|
||||
|
||||
def store_or_execute(self, block, name):
|
||||
""" Execute a block, or store it in a variable, per the user's request.
|
||||
"""
|
||||
if name:
|
||||
# If storing it for further editing
|
||||
self.shell.user_ns[name] = SList(block.splitlines())
|
||||
print("Block assigned to '%s'" % name)
|
||||
else:
|
||||
b = self.preclean_input(block)
|
||||
self.shell.user_ns['pasted_block'] = b
|
||||
self.shell.using_paste_magics = True
|
||||
try:
|
||||
self.shell.run_cell(b)
|
||||
finally:
|
||||
self.shell.using_paste_magics = False
|
||||
|
||||
def preclean_input(self, block):
|
||||
lines = block.splitlines()
|
||||
while lines and not lines[0].strip():
|
||||
lines = lines[1:]
|
||||
return strip_email_quotes('\n'.join(lines))
|
||||
|
||||
def rerun_pasted(self, name='pasted_block'):
|
||||
""" Rerun a previously pasted command.
|
||||
"""
|
||||
b = self.shell.user_ns.get(name)
|
||||
|
||||
# Sanity checks
|
||||
if b is None:
|
||||
raise UsageError('No previous pasted block available')
|
||||
if not isinstance(b, str):
|
||||
raise UsageError(
|
||||
"Variable 'pasted_block' is not a string, can't execute")
|
||||
|
||||
print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
|
||||
self.shell.run_cell(b)
|
||||
|
||||
@line_magic
|
||||
def autoindent(self, parameter_s = ''):
|
||||
"""Toggle autoindent on/off (deprecated)"""
|
||||
self.shell.set_autoindent()
|
||||
print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
|
||||
|
||||
@line_magic
|
||||
def cpaste(self, parameter_s=''):
|
||||
"""Paste & execute a pre-formatted code block from clipboard.
|
||||
|
||||
You must terminate the block with '--' (two minus-signs) or Ctrl-D
|
||||
alone on the line. You can also provide your own sentinel with '%paste
|
||||
-s %%' ('%%' is the new sentinel for this operation).
|
||||
|
||||
The block is dedented prior to execution to enable execution of method
|
||||
definitions. '>' and '+' characters at the beginning of a line are
|
||||
ignored, to allow pasting directly from e-mails, diff files and
|
||||
doctests (the '...' continuation prompt is also stripped). The
|
||||
executed block is also assigned to variable named 'pasted_block' for
|
||||
later editing with '%edit pasted_block'.
|
||||
|
||||
You can also pass a variable name as an argument, e.g. '%cpaste foo'.
|
||||
This assigns the pasted block to variable 'foo' as string, without
|
||||
dedenting or executing it (preceding >>> and + is still stripped)
|
||||
|
||||
'%cpaste -r' re-executes the block previously entered by cpaste.
|
||||
'%cpaste -q' suppresses any additional output messages.
|
||||
|
||||
Do not be alarmed by garbled output on Windows (it's a readline bug).
|
||||
Just press enter and type -- (and press enter again) and the block
|
||||
will be what was just pasted.
|
||||
|
||||
IPython statements (magics, shell escapes) are not supported (yet).
|
||||
|
||||
See also
|
||||
--------
|
||||
paste: automatically pull code from clipboard.
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
|
||||
In [8]: %cpaste
|
||||
Pasting code; enter '--' alone on the line to stop.
|
||||
:>>> a = ["world!", "Hello"]
|
||||
:>>> print " ".join(sorted(a))
|
||||
:--
|
||||
Hello world!
|
||||
"""
|
||||
opts, name = self.parse_options(parameter_s, 'rqs:', mode='string')
|
||||
if 'r' in opts:
|
||||
self.rerun_pasted()
|
||||
return
|
||||
|
||||
quiet = ('q' in opts)
|
||||
|
||||
sentinel = opts.get('s', u'--')
|
||||
block = '\n'.join(get_pasted_lines(sentinel, quiet=quiet))
|
||||
self.store_or_execute(block, name)
|
||||
|
||||
@line_magic
|
||||
def paste(self, parameter_s=''):
|
||||
"""Paste & execute a pre-formatted code block from clipboard.
|
||||
|
||||
The text is pulled directly from the clipboard without user
|
||||
intervention and printed back on the screen before execution (unless
|
||||
the -q flag is given to force quiet mode).
|
||||
|
||||
The block is dedented prior to execution to enable execution of method
|
||||
definitions. '>' and '+' characters at the beginning of a line are
|
||||
ignored, to allow pasting directly from e-mails, diff files and
|
||||
doctests (the '...' continuation prompt is also stripped). The
|
||||
executed block is also assigned to variable named 'pasted_block' for
|
||||
later editing with '%edit pasted_block'.
|
||||
|
||||
You can also pass a variable name as an argument, e.g. '%paste foo'.
|
||||
This assigns the pasted block to variable 'foo' as string, without
|
||||
executing it (preceding >>> and + is still stripped).
|
||||
|
||||
Options:
|
||||
|
||||
-r: re-executes the block previously entered by cpaste.
|
||||
|
||||
-q: quiet mode: do not echo the pasted text back to the terminal.
|
||||
|
||||
IPython statements (magics, shell escapes) are not supported (yet).
|
||||
|
||||
See also
|
||||
--------
|
||||
cpaste: manually paste code into terminal until you mark its end.
|
||||
"""
|
||||
opts, name = self.parse_options(parameter_s, 'rq', mode='string')
|
||||
if 'r' in opts:
|
||||
self.rerun_pasted()
|
||||
return
|
||||
try:
|
||||
block = self.shell.hooks.clipboard_get()
|
||||
except TryNext as clipboard_exc:
|
||||
message = getattr(clipboard_exc, 'args')
|
||||
if message:
|
||||
error(message[0])
|
||||
else:
|
||||
error('Could not get text from the clipboard.')
|
||||
return
|
||||
except ClipboardEmpty:
|
||||
raise UsageError("The clipboard appears to be empty")
|
||||
|
||||
# By default, echo back to terminal unless quiet mode is requested
|
||||
if 'q' not in opts:
|
||||
write = self.shell.write
|
||||
write(self.shell.pycolorize(block))
|
||||
if not block.endswith('\n'):
|
||||
write('\n')
|
||||
write("## -- End pasted text --\n")
|
||||
|
||||
self.store_or_execute(block, name)
|
||||
|
||||
# Class-level: add a '%cls' magic only on Windows
|
||||
if sys.platform == 'win32':
|
||||
@line_magic
|
||||
def cls(self, s):
|
||||
"""Clear screen.
|
||||
"""
|
||||
os.system("cls")
|
108
venv/Lib/site-packages/IPython/terminal/prompts.py
Normal file
108
venv/Lib/site-packages/IPython/terminal/prompts.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
"""Terminal input and output prompts."""
|
||||
|
||||
from pygments.token import Token
|
||||
import sys
|
||||
|
||||
from IPython.core.displayhook import DisplayHook
|
||||
|
||||
from prompt_toolkit.formatted_text import fragment_list_width, PygmentsTokens
|
||||
from prompt_toolkit.shortcuts import print_formatted_text
|
||||
from prompt_toolkit.enums import EditingMode
|
||||
|
||||
|
||||
class Prompts(object):
|
||||
def __init__(self, shell):
|
||||
self.shell = shell
|
||||
|
||||
def vi_mode(self):
|
||||
if (getattr(self.shell.pt_app, 'editing_mode', None) == EditingMode.VI
|
||||
and self.shell.prompt_includes_vi_mode):
|
||||
mode = str(self.shell.pt_app.app.vi_state.input_mode)
|
||||
if mode.startswith('InputMode.'):
|
||||
mode = mode[10:13].lower()
|
||||
elif mode.startswith('vi-'):
|
||||
mode = mode[3:6]
|
||||
return '['+mode+'] '
|
||||
return ''
|
||||
|
||||
|
||||
def in_prompt_tokens(self):
|
||||
return [
|
||||
(Token.Prompt, self.vi_mode() ),
|
||||
(Token.Prompt, 'In ['),
|
||||
(Token.PromptNum, str(self.shell.execution_count)),
|
||||
(Token.Prompt, ']: '),
|
||||
]
|
||||
|
||||
def _width(self):
|
||||
return fragment_list_width(self.in_prompt_tokens())
|
||||
|
||||
def continuation_prompt_tokens(self, width=None):
|
||||
if width is None:
|
||||
width = self._width()
|
||||
return [
|
||||
(Token.Prompt, (' ' * (width - 5)) + '...: '),
|
||||
]
|
||||
|
||||
def rewrite_prompt_tokens(self):
|
||||
width = self._width()
|
||||
return [
|
||||
(Token.Prompt, ('-' * (width - 2)) + '> '),
|
||||
]
|
||||
|
||||
def out_prompt_tokens(self):
|
||||
return [
|
||||
(Token.OutPrompt, 'Out['),
|
||||
(Token.OutPromptNum, str(self.shell.execution_count)),
|
||||
(Token.OutPrompt, ']: '),
|
||||
]
|
||||
|
||||
class ClassicPrompts(Prompts):
|
||||
def in_prompt_tokens(self):
|
||||
return [
|
||||
(Token.Prompt, '>>> '),
|
||||
]
|
||||
|
||||
def continuation_prompt_tokens(self, width=None):
|
||||
return [
|
||||
(Token.Prompt, '... ')
|
||||
]
|
||||
|
||||
def rewrite_prompt_tokens(self):
|
||||
return []
|
||||
|
||||
def out_prompt_tokens(self):
|
||||
return []
|
||||
|
||||
class RichPromptDisplayHook(DisplayHook):
|
||||
"""Subclass of base display hook using coloured prompt"""
|
||||
def write_output_prompt(self):
|
||||
sys.stdout.write(self.shell.separate_out)
|
||||
# If we're not displaying a prompt, it effectively ends with a newline,
|
||||
# because the output will be left-aligned.
|
||||
self.prompt_end_newline = True
|
||||
|
||||
if self.do_full_cache:
|
||||
tokens = self.shell.prompts.out_prompt_tokens()
|
||||
prompt_txt = ''.join(s for t, s in tokens)
|
||||
if prompt_txt and not prompt_txt.endswith('\n'):
|
||||
# Ask for a newline before multiline output
|
||||
self.prompt_end_newline = False
|
||||
|
||||
if self.shell.pt_app:
|
||||
print_formatted_text(PygmentsTokens(tokens),
|
||||
style=self.shell.pt_app.app.style, end='',
|
||||
)
|
||||
else:
|
||||
sys.stdout.write(prompt_txt)
|
||||
|
||||
def write_format_data(self, format_dict, md_dict=None) -> None:
|
||||
if self.shell.mime_renderers:
|
||||
|
||||
for mime, handler in self.shell.mime_renderers.items():
|
||||
if mime in format_dict:
|
||||
handler(format_dict[mime], None)
|
||||
return
|
||||
|
||||
super().write_format_data(format_dict, md_dict)
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import importlib
|
||||
import os
|
||||
|
||||
aliases = {
|
||||
'qt4': 'qt',
|
||||
'gtk2': 'gtk',
|
||||
}
|
||||
|
||||
backends = [
|
||||
'qt', 'qt4', 'qt5',
|
||||
'gtk', 'gtk2', 'gtk3',
|
||||
'tk',
|
||||
'wx',
|
||||
'pyglet', 'glut',
|
||||
'osx',
|
||||
'asyncio'
|
||||
]
|
||||
|
||||
registered = {}
|
||||
|
||||
def register(name, inputhook):
|
||||
"""Register the function *inputhook* as an event loop integration."""
|
||||
registered[name] = inputhook
|
||||
|
||||
class UnknownBackend(KeyError):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __str__(self):
|
||||
return ("No event loop integration for {!r}. "
|
||||
"Supported event loops are: {}").format(self.name,
|
||||
', '.join(backends + sorted(registered)))
|
||||
|
||||
def get_inputhook_name_and_func(gui):
|
||||
if gui in registered:
|
||||
return gui, registered[gui]
|
||||
|
||||
if gui not in backends:
|
||||
raise UnknownBackend(gui)
|
||||
|
||||
if gui in aliases:
|
||||
return get_inputhook_name_and_func(aliases[gui])
|
||||
|
||||
gui_mod = gui
|
||||
if gui == 'qt5':
|
||||
os.environ['QT_API'] = 'pyqt5'
|
||||
gui_mod = 'qt'
|
||||
|
||||
mod = importlib.import_module('IPython.terminal.pt_inputhooks.'+gui_mod)
|
||||
return gui, mod.inputhook
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,64 @@
|
|||
"""
|
||||
Inputhook for running the original asyncio event loop while we're waiting for
|
||||
input.
|
||||
|
||||
By default, in IPython, we run the prompt with a different asyncio event loop,
|
||||
because otherwise we risk that people are freezing the prompt by scheduling bad
|
||||
coroutines. E.g., a coroutine that does a while/true and never yield back
|
||||
control to the loop. We can't cancel that.
|
||||
|
||||
However, sometimes we want the asyncio loop to keep running while waiting for
|
||||
a prompt.
|
||||
|
||||
The following example will print the numbers from 1 to 10 above the prompt,
|
||||
while we are waiting for input. (This works also because we use
|
||||
prompt_toolkit`s `patch_stdout`)::
|
||||
|
||||
In [1]: import asyncio
|
||||
|
||||
In [2]: %gui asyncio
|
||||
|
||||
In [3]: async def f():
|
||||
...: for i in range(10):
|
||||
...: await asyncio.sleep(1)
|
||||
...: print(i)
|
||||
|
||||
|
||||
In [4]: asyncio.ensure_future(f())
|
||||
|
||||
"""
|
||||
import asyncio
|
||||
from prompt_toolkit import __version__ as ptk_version
|
||||
|
||||
PTK3 = ptk_version.startswith('3.')
|
||||
|
||||
|
||||
# Keep reference to the original asyncio loop, because getting the event loop
|
||||
# within the input hook would return the other loop.
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
|
||||
def inputhook(context):
|
||||
"""
|
||||
Inputhook for asyncio event loop integration.
|
||||
"""
|
||||
# For prompt_toolkit 3.0, this input hook literally doesn't do anything.
|
||||
# The event loop integration here is implemented in `interactiveshell.py`
|
||||
# by running the prompt itself in the current asyncio loop. The main reason
|
||||
# for this is that nesting asyncio event loops is unreliable.
|
||||
if PTK3:
|
||||
return
|
||||
|
||||
# For prompt_toolkit 2.0, we can run the current asyncio event loop,
|
||||
# because prompt_toolkit 2.0 uses a different event loop internally.
|
||||
|
||||
def stop():
|
||||
loop.stop()
|
||||
|
||||
fileno = context.fileno()
|
||||
loop.add_reader(fileno, stop)
|
||||
try:
|
||||
loop.run_forever()
|
||||
finally:
|
||||
loop.remove_reader(fileno)
|
||||
|
140
venv/Lib/site-packages/IPython/terminal/pt_inputhooks/glut.py
Normal file
140
venv/Lib/site-packages/IPython/terminal/pt_inputhooks/glut.py
Normal file
|
@ -0,0 +1,140 @@
|
|||
"""GLUT Input hook for interactive use with prompt_toolkit
|
||||
"""
|
||||
|
||||
|
||||
# GLUT is quite an old library and it is difficult to ensure proper
|
||||
# integration within IPython since original GLUT does not allow to handle
|
||||
# events one by one. Instead, it requires for the mainloop to be entered
|
||||
# and never returned (there is not even a function to exit he
|
||||
# mainloop). Fortunately, there are alternatives such as freeglut
|
||||
# (available for linux and windows) and the OSX implementation gives
|
||||
# access to a glutCheckLoop() function that blocks itself until a new
|
||||
# event is received. This means we have to setup the idle callback to
|
||||
# ensure we got at least one event that will unblock the function.
|
||||
#
|
||||
# Furthermore, it is not possible to install these handlers without a window
|
||||
# being first created. We choose to make this window invisible. This means that
|
||||
# display mode options are set at this level and user won't be able to change
|
||||
# them later without modifying the code. This should probably be made available
|
||||
# via IPython options system.
|
||||
|
||||
import sys
|
||||
import time
|
||||
import signal
|
||||
import OpenGL.GLUT as glut
|
||||
import OpenGL.platform as platform
|
||||
from timeit import default_timer as clock
|
||||
|
||||
# Frame per second : 60
|
||||
# Should probably be an IPython option
|
||||
glut_fps = 60
|
||||
|
||||
# Display mode : double buffeed + rgba + depth
|
||||
# Should probably be an IPython option
|
||||
glut_display_mode = (glut.GLUT_DOUBLE |
|
||||
glut.GLUT_RGBA |
|
||||
glut.GLUT_DEPTH)
|
||||
|
||||
glutMainLoopEvent = None
|
||||
if sys.platform == 'darwin':
|
||||
try:
|
||||
glutCheckLoop = platform.createBaseFunction(
|
||||
'glutCheckLoop', dll=platform.GLUT, resultType=None,
|
||||
argTypes=[],
|
||||
doc='glutCheckLoop( ) -> None',
|
||||
argNames=(),
|
||||
)
|
||||
except AttributeError:
|
||||
raise RuntimeError(
|
||||
'''Your glut implementation does not allow interactive sessions'''
|
||||
'''Consider installing freeglut.''')
|
||||
glutMainLoopEvent = glutCheckLoop
|
||||
elif glut.HAVE_FREEGLUT:
|
||||
glutMainLoopEvent = glut.glutMainLoopEvent
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'''Your glut implementation does not allow interactive sessions. '''
|
||||
'''Consider installing freeglut.''')
|
||||
|
||||
|
||||
def glut_display():
|
||||
# Dummy display function
|
||||
pass
|
||||
|
||||
def glut_idle():
|
||||
# Dummy idle function
|
||||
pass
|
||||
|
||||
def glut_close():
|
||||
# Close function only hides the current window
|
||||
glut.glutHideWindow()
|
||||
glutMainLoopEvent()
|
||||
|
||||
def glut_int_handler(signum, frame):
|
||||
# Catch sigint and print the defaultipyt message
|
||||
signal.signal(signal.SIGINT, signal.default_int_handler)
|
||||
print('\nKeyboardInterrupt')
|
||||
# Need to reprint the prompt at this stage
|
||||
|
||||
# Initialisation code
|
||||
glut.glutInit( sys.argv )
|
||||
glut.glutInitDisplayMode( glut_display_mode )
|
||||
# This is specific to freeglut
|
||||
if bool(glut.glutSetOption):
|
||||
glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
|
||||
glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
|
||||
glut.glutCreateWindow( b'ipython' )
|
||||
glut.glutReshapeWindow( 1, 1 )
|
||||
glut.glutHideWindow( )
|
||||
glut.glutWMCloseFunc( glut_close )
|
||||
glut.glutDisplayFunc( glut_display )
|
||||
glut.glutIdleFunc( glut_idle )
|
||||
|
||||
|
||||
def inputhook(context):
|
||||
"""Run the pyglet event loop by processing pending events only.
|
||||
|
||||
This keeps processing pending events until stdin is ready. After
|
||||
processing all pending events, a call to time.sleep is inserted. This is
|
||||
needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
|
||||
though for best performance.
|
||||
"""
|
||||
# We need to protect against a user pressing Control-C when IPython is
|
||||
# idle and this is running. We trap KeyboardInterrupt and pass.
|
||||
|
||||
signal.signal(signal.SIGINT, glut_int_handler)
|
||||
|
||||
try:
|
||||
t = clock()
|
||||
|
||||
# Make sure the default window is set after a window has been closed
|
||||
if glut.glutGetWindow() == 0:
|
||||
glut.glutSetWindow( 1 )
|
||||
glutMainLoopEvent()
|
||||
return 0
|
||||
|
||||
while not context.input_is_ready():
|
||||
glutMainLoopEvent()
|
||||
# We need to sleep at this point to keep the idle CPU load
|
||||
# low. However, if sleep to long, GUI response is poor. As
|
||||
# a compromise, we watch how often GUI events are being processed
|
||||
# and switch between a short and long sleep time. Here are some
|
||||
# stats useful in helping to tune this.
|
||||
# time CPU load
|
||||
# 0.001 13%
|
||||
# 0.005 3%
|
||||
# 0.01 1.5%
|
||||
# 0.05 0.5%
|
||||
used_time = clock() - t
|
||||
if used_time > 10.0:
|
||||
# print 'Sleep for 1 s' # dbg
|
||||
time.sleep(1.0)
|
||||
elif used_time > 0.1:
|
||||
# Few GUI events coming in, so we can sleep longer
|
||||
# print 'Sleep for 0.05 s' # dbg
|
||||
time.sleep(0.05)
|
||||
else:
|
||||
# Many GUI events coming in, so sleep only very little
|
||||
time.sleep(0.001)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
58
venv/Lib/site-packages/IPython/terminal/pt_inputhooks/gtk.py
Normal file
58
venv/Lib/site-packages/IPython/terminal/pt_inputhooks/gtk.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Code borrowed from python-prompt-toolkit examples
|
||||
# https://github.com/jonathanslenders/python-prompt-toolkit/blob/77cdcfbc7f4b4c34a9d2f9a34d422d7152f16209/examples/inputhook.py
|
||||
|
||||
# Copyright (c) 2014, Jonathan Slenders
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
# list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
# * Neither the name of the {organization} nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
PyGTK input hook for prompt_toolkit.
|
||||
|
||||
Listens on the pipe prompt_toolkit sets up for a notification that it should
|
||||
return control to the terminal event loop.
|
||||
"""
|
||||
|
||||
import gtk, gobject
|
||||
|
||||
# Enable threading in GTK. (Otherwise, GTK will keep the GIL.)
|
||||
gtk.gdk.threads_init()
|
||||
|
||||
def inputhook(context):
|
||||
"""
|
||||
When the eventloop of prompt-toolkit is idle, call this inputhook.
|
||||
|
||||
This will run the GTK main loop until the file descriptor
|
||||
`context.fileno()` becomes ready.
|
||||
|
||||
:param context: An `InputHookContext` instance.
|
||||
"""
|
||||
def _main_quit(*a, **kw):
|
||||
gtk.main_quit()
|
||||
return False
|
||||
|
||||
gobject.io_add_watch(context.fileno(), gobject.IO_IN, _main_quit)
|
||||
gtk.main()
|
|
@ -0,0 +1,12 @@
|
|||
"""prompt_toolkit input hook for GTK 3
|
||||
"""
|
||||
|
||||
from gi.repository import Gtk, GLib
|
||||
|
||||
def _main_quit(*args, **kwargs):
|
||||
Gtk.main_quit()
|
||||
return False
|
||||
|
||||
def inputhook(context):
|
||||
GLib.io_add_watch(context.fileno(), GLib.PRIORITY_DEFAULT, GLib.IO_IN, _main_quit)
|
||||
Gtk.main()
|
137
venv/Lib/site-packages/IPython/terminal/pt_inputhooks/osx.py
Normal file
137
venv/Lib/site-packages/IPython/terminal/pt_inputhooks/osx.py
Normal file
|
@ -0,0 +1,137 @@
|
|||
"""Inputhook for OS X
|
||||
|
||||
Calls NSApp / CoreFoundation APIs via ctypes.
|
||||
"""
|
||||
|
||||
# obj-c boilerplate from appnope, used under BSD 2-clause
|
||||
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
from threading import Event
|
||||
|
||||
objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc'))
|
||||
|
||||
void_p = ctypes.c_void_p
|
||||
|
||||
objc.objc_getClass.restype = void_p
|
||||
objc.sel_registerName.restype = void_p
|
||||
objc.objc_msgSend.restype = void_p
|
||||
objc.objc_msgSend.argtypes = [void_p, void_p]
|
||||
|
||||
msg = objc.objc_msgSend
|
||||
|
||||
def _utf8(s):
|
||||
"""ensure utf8 bytes"""
|
||||
if not isinstance(s, bytes):
|
||||
s = s.encode('utf8')
|
||||
return s
|
||||
|
||||
def n(name):
|
||||
"""create a selector name (for ObjC methods)"""
|
||||
return objc.sel_registerName(_utf8(name))
|
||||
|
||||
def C(classname):
|
||||
"""get an ObjC Class by name"""
|
||||
return objc.objc_getClass(_utf8(classname))
|
||||
|
||||
# end obj-c boilerplate from appnope
|
||||
|
||||
# CoreFoundation C-API calls we will use:
|
||||
CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation'))
|
||||
|
||||
CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate
|
||||
CFFileDescriptorCreate.restype = void_p
|
||||
CFFileDescriptorCreate.argtypes = [void_p, ctypes.c_int, ctypes.c_bool, void_p]
|
||||
|
||||
CFFileDescriptorGetNativeDescriptor = CoreFoundation.CFFileDescriptorGetNativeDescriptor
|
||||
CFFileDescriptorGetNativeDescriptor.restype = ctypes.c_int
|
||||
CFFileDescriptorGetNativeDescriptor.argtypes = [void_p]
|
||||
|
||||
CFFileDescriptorEnableCallBacks = CoreFoundation.CFFileDescriptorEnableCallBacks
|
||||
CFFileDescriptorEnableCallBacks.restype = None
|
||||
CFFileDescriptorEnableCallBacks.argtypes = [void_p, ctypes.c_ulong]
|
||||
|
||||
CFFileDescriptorCreateRunLoopSource = CoreFoundation.CFFileDescriptorCreateRunLoopSource
|
||||
CFFileDescriptorCreateRunLoopSource.restype = void_p
|
||||
CFFileDescriptorCreateRunLoopSource.argtypes = [void_p, void_p, void_p]
|
||||
|
||||
CFRunLoopGetCurrent = CoreFoundation.CFRunLoopGetCurrent
|
||||
CFRunLoopGetCurrent.restype = void_p
|
||||
|
||||
CFRunLoopAddSource = CoreFoundation.CFRunLoopAddSource
|
||||
CFRunLoopAddSource.restype = None
|
||||
CFRunLoopAddSource.argtypes = [void_p, void_p, void_p]
|
||||
|
||||
CFRelease = CoreFoundation.CFRelease
|
||||
CFRelease.restype = None
|
||||
CFRelease.argtypes = [void_p]
|
||||
|
||||
CFFileDescriptorInvalidate = CoreFoundation.CFFileDescriptorInvalidate
|
||||
CFFileDescriptorInvalidate.restype = None
|
||||
CFFileDescriptorInvalidate.argtypes = [void_p]
|
||||
|
||||
# From CFFileDescriptor.h
|
||||
kCFFileDescriptorReadCallBack = 1
|
||||
kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, 'kCFRunLoopCommonModes')
|
||||
|
||||
|
||||
def _NSApp():
|
||||
"""Return the global NSApplication instance (NSApp)"""
|
||||
return msg(C('NSApplication'), n('sharedApplication'))
|
||||
|
||||
|
||||
def _wake(NSApp):
|
||||
"""Wake the Application"""
|
||||
event = msg(C('NSEvent'),
|
||||
n('otherEventWithType:location:modifierFlags:'
|
||||
'timestamp:windowNumber:context:subtype:data1:data2:'),
|
||||
15, # Type
|
||||
0, # location
|
||||
0, # flags
|
||||
0, # timestamp
|
||||
0, # window
|
||||
None, # context
|
||||
0, # subtype
|
||||
0, # data1
|
||||
0, # data2
|
||||
)
|
||||
msg(NSApp, n('postEvent:atStart:'), void_p(event), True)
|
||||
|
||||
|
||||
_triggered = Event()
|
||||
|
||||
def _input_callback(fdref, flags, info):
|
||||
"""Callback to fire when there's input to be read"""
|
||||
_triggered.set()
|
||||
CFFileDescriptorInvalidate(fdref)
|
||||
CFRelease(fdref)
|
||||
NSApp = _NSApp()
|
||||
msg(NSApp, n('stop:'), NSApp)
|
||||
_wake(NSApp)
|
||||
|
||||
_c_callback_func_type = ctypes.CFUNCTYPE(None, void_p, void_p, void_p)
|
||||
_c_input_callback = _c_callback_func_type(_input_callback)
|
||||
|
||||
|
||||
def _stop_on_read(fd):
|
||||
"""Register callback to stop eventloop when there's data on fd"""
|
||||
_triggered.clear()
|
||||
fdref = CFFileDescriptorCreate(None, fd, False, _c_input_callback, None)
|
||||
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack)
|
||||
source = CFFileDescriptorCreateRunLoopSource(None, fdref, 0)
|
||||
loop = CFRunLoopGetCurrent()
|
||||
CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes)
|
||||
CFRelease(source)
|
||||
|
||||
|
||||
def inputhook(context):
|
||||
"""Inputhook for Cocoa (NSApp)"""
|
||||
NSApp = _NSApp()
|
||||
_stop_on_read(context.fileno())
|
||||
msg(NSApp, n('run'))
|
||||
if not _triggered.is_set():
|
||||
# app closed without firing callback,
|
||||
# probably due to last window being closed.
|
||||
# Run the loop manually in this case,
|
||||
# since there may be events still to process (#9734)
|
||||
CoreFoundation.CFRunLoopRun()
|
|
@ -0,0 +1,66 @@
|
|||
"""Enable pyglet to be used interactively with prompt_toolkit
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
from timeit import default_timer as clock
|
||||
import pyglet
|
||||
|
||||
# On linux only, window.flip() has a bug that causes an AttributeError on
|
||||
# window close. For details, see:
|
||||
# http://groups.google.com/group/pyglet-users/browse_thread/thread/47c1aab9aa4a3d23/c22f9e819826799e?#c22f9e819826799e
|
||||
|
||||
if sys.platform.startswith('linux'):
|
||||
def flip(window):
|
||||
try:
|
||||
window.flip()
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
def flip(window):
|
||||
window.flip()
|
||||
|
||||
|
||||
def inputhook(context):
|
||||
"""Run the pyglet event loop by processing pending events only.
|
||||
|
||||
This keeps processing pending events until stdin is ready. After
|
||||
processing all pending events, a call to time.sleep is inserted. This is
|
||||
needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
|
||||
though for best performance.
|
||||
"""
|
||||
# We need to protect against a user pressing Control-C when IPython is
|
||||
# idle and this is running. We trap KeyboardInterrupt and pass.
|
||||
try:
|
||||
t = clock()
|
||||
while not context.input_is_ready():
|
||||
pyglet.clock.tick()
|
||||
for window in pyglet.app.windows:
|
||||
window.switch_to()
|
||||
window.dispatch_events()
|
||||
window.dispatch_event('on_draw')
|
||||
flip(window)
|
||||
|
||||
# We need to sleep at this point to keep the idle CPU load
|
||||
# low. However, if sleep to long, GUI response is poor. As
|
||||
# a compromise, we watch how often GUI events are being processed
|
||||
# and switch between a short and long sleep time. Here are some
|
||||
# stats useful in helping to tune this.
|
||||
# time CPU load
|
||||
# 0.001 13%
|
||||
# 0.005 3%
|
||||
# 0.01 1.5%
|
||||
# 0.05 0.5%
|
||||
used_time = clock() - t
|
||||
if used_time > 10.0:
|
||||
# print 'Sleep for 1 s' # dbg
|
||||
time.sleep(1.0)
|
||||
elif used_time > 0.1:
|
||||
# Few GUI events coming in, so we can sleep longer
|
||||
# print 'Sleep for 0.05 s' # dbg
|
||||
time.sleep(0.05)
|
||||
else:
|
||||
# Many GUI events coming in, so sleep only very little
|
||||
time.sleep(0.001)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
54
venv/Lib/site-packages/IPython/terminal/pt_inputhooks/qt.py
Normal file
54
venv/Lib/site-packages/IPython/terminal/pt_inputhooks/qt.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
import sys
|
||||
import os
|
||||
from IPython.external.qt_for_kernel import QtCore, QtGui
|
||||
|
||||
# If we create a QApplication, keep a reference to it so that it doesn't get
|
||||
# garbage collected.
|
||||
_appref = None
|
||||
_already_warned = False
|
||||
|
||||
|
||||
def inputhook(context):
|
||||
global _appref
|
||||
app = QtCore.QCoreApplication.instance()
|
||||
if not app:
|
||||
if sys.platform == 'linux':
|
||||
if not os.environ.get('DISPLAY') \
|
||||
and not os.environ.get('WAYLAND_DISPLAY'):
|
||||
import warnings
|
||||
global _already_warned
|
||||
if not _already_warned:
|
||||
_already_warned = True
|
||||
warnings.warn(
|
||||
'The DISPLAY or WAYLAND_DISPLAY environment variable is '
|
||||
'not set or empty and Qt5 requires this environment '
|
||||
'variable. Deactivate Qt5 code.'
|
||||
)
|
||||
return
|
||||
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
|
||||
_appref = app = QtGui.QApplication([" "])
|
||||
event_loop = QtCore.QEventLoop(app)
|
||||
|
||||
if sys.platform == 'win32':
|
||||
# The QSocketNotifier method doesn't appear to work on Windows.
|
||||
# Use polling instead.
|
||||
timer = QtCore.QTimer()
|
||||
timer.timeout.connect(event_loop.quit)
|
||||
while not context.input_is_ready():
|
||||
timer.start(50) # 50 ms
|
||||
event_loop.exec_()
|
||||
timer.stop()
|
||||
else:
|
||||
# On POSIX platforms, we can use a file descriptor to quit the event
|
||||
# loop when there is input ready to read.
|
||||
notifier = QtCore.QSocketNotifier(context.fileno(),
|
||||
QtCore.QSocketNotifier.Read)
|
||||
try:
|
||||
# connect the callback we care about before we turn it on
|
||||
notifier.activated.connect(lambda: event_loop.exit())
|
||||
notifier.setEnabled(True)
|
||||
# only start the event loop we are not already flipped
|
||||
if not context.input_is_ready():
|
||||
event_loop.exec_()
|
||||
finally:
|
||||
notifier.setEnabled(False)
|
90
venv/Lib/site-packages/IPython/terminal/pt_inputhooks/tk.py
Normal file
90
venv/Lib/site-packages/IPython/terminal/pt_inputhooks/tk.py
Normal file
|
@ -0,0 +1,90 @@
|
|||
# Code borrowed from ptpython
|
||||
# https://github.com/jonathanslenders/ptpython/blob/86b71a89626114b18898a0af463978bdb32eeb70/ptpython/eventloop.py
|
||||
|
||||
# Copyright (c) 2015, Jonathan Slenders
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
# list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
# * Neither the name of the {organization} nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
Wrapper around the eventloop that gives some time to the Tkinter GUI to process
|
||||
events when it's loaded and while we are waiting for input at the REPL. This
|
||||
way we don't block the UI of for instance ``turtle`` and other Tk libraries.
|
||||
|
||||
(Normally Tkinter registers it's callbacks in ``PyOS_InputHook`` to integrate
|
||||
in readline. ``prompt-toolkit`` doesn't understand that input hook, but this
|
||||
will fix it for Tk.)
|
||||
"""
|
||||
import time
|
||||
|
||||
import _tkinter
|
||||
import tkinter
|
||||
|
||||
def inputhook(inputhook_context):
|
||||
"""
|
||||
Inputhook for Tk.
|
||||
Run the Tk eventloop until prompt-toolkit needs to process the next input.
|
||||
"""
|
||||
# Get the current TK application.
|
||||
root = tkinter._default_root
|
||||
|
||||
def wait_using_filehandler():
|
||||
"""
|
||||
Run the TK eventloop until the file handler that we got from the
|
||||
inputhook becomes readable.
|
||||
"""
|
||||
# Add a handler that sets the stop flag when `prompt-toolkit` has input
|
||||
# to process.
|
||||
stop = [False]
|
||||
def done(*a):
|
||||
stop[0] = True
|
||||
|
||||
root.createfilehandler(inputhook_context.fileno(), _tkinter.READABLE, done)
|
||||
|
||||
# Run the TK event loop as long as we don't receive input.
|
||||
while root.dooneevent(_tkinter.ALL_EVENTS):
|
||||
if stop[0]:
|
||||
break
|
||||
|
||||
root.deletefilehandler(inputhook_context.fileno())
|
||||
|
||||
def wait_using_polling():
|
||||
"""
|
||||
Windows TK doesn't support 'createfilehandler'.
|
||||
So, run the TK eventloop and poll until input is ready.
|
||||
"""
|
||||
while not inputhook_context.input_is_ready():
|
||||
while root.dooneevent(_tkinter.ALL_EVENTS | _tkinter.DONT_WAIT):
|
||||
pass
|
||||
# Sleep to make the CPU idle, but not too long, so that the UI
|
||||
# stays responsive.
|
||||
time.sleep(.01)
|
||||
|
||||
if root is not None:
|
||||
if hasattr(root, 'createfilehandler'):
|
||||
wait_using_filehandler()
|
||||
else:
|
||||
wait_using_polling()
|
219
venv/Lib/site-packages/IPython/terminal/pt_inputhooks/wx.py
Normal file
219
venv/Lib/site-packages/IPython/terminal/pt_inputhooks/wx.py
Normal file
|
@ -0,0 +1,219 @@
|
|||
"""Enable wxPython to be used interactively in prompt_toolkit
|
||||
"""
|
||||
|
||||
import sys
|
||||
import signal
|
||||
import time
|
||||
from timeit import default_timer as clock
|
||||
import wx
|
||||
|
||||
|
||||
def ignore_keyboardinterrupts(func):
|
||||
"""Decorator which causes KeyboardInterrupt exceptions to be ignored during
|
||||
execution of the decorated function.
|
||||
|
||||
This is used by the inputhook functions to handle the event where the user
|
||||
presses CTRL+C while IPython is idle, and the inputhook loop is running. In
|
||||
this case, we want to ignore interrupts.
|
||||
"""
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
return wrapper
|
||||
|
||||
|
||||
@ignore_keyboardinterrupts
|
||||
def inputhook_wx1(context):
|
||||
"""Run the wx event loop by processing pending events only.
|
||||
|
||||
This approach seems to work, but its performance is not great as it
|
||||
relies on having PyOS_InputHook called regularly.
|
||||
"""
|
||||
app = wx.GetApp()
|
||||
if app is not None:
|
||||
assert wx.Thread_IsMain()
|
||||
|
||||
# Make a temporary event loop and process system events until
|
||||
# there are no more waiting, then allow idle events (which
|
||||
# will also deal with pending or posted wx events.)
|
||||
evtloop = wx.EventLoop()
|
||||
ea = wx.EventLoopActivator(evtloop)
|
||||
while evtloop.Pending():
|
||||
evtloop.Dispatch()
|
||||
app.ProcessIdle()
|
||||
del ea
|
||||
return 0
|
||||
|
||||
|
||||
class EventLoopTimer(wx.Timer):
|
||||
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
wx.Timer.__init__(self)
|
||||
|
||||
def Notify(self):
|
||||
self.func()
|
||||
|
||||
|
||||
class EventLoopRunner(object):
|
||||
|
||||
def Run(self, time, input_is_ready):
|
||||
self.input_is_ready = input_is_ready
|
||||
self.evtloop = wx.EventLoop()
|
||||
self.timer = EventLoopTimer(self.check_stdin)
|
||||
self.timer.Start(time)
|
||||
self.evtloop.Run()
|
||||
|
||||
def check_stdin(self):
|
||||
if self.input_is_ready():
|
||||
self.timer.Stop()
|
||||
self.evtloop.Exit()
|
||||
|
||||
|
||||
@ignore_keyboardinterrupts
|
||||
def inputhook_wx2(context):
|
||||
"""Run the wx event loop, polling for stdin.
|
||||
|
||||
This version runs the wx eventloop for an undetermined amount of time,
|
||||
during which it periodically checks to see if anything is ready on
|
||||
stdin. If anything is ready on stdin, the event loop exits.
|
||||
|
||||
The argument to elr.Run controls how often the event loop looks at stdin.
|
||||
This determines the responsiveness at the keyboard. A setting of 1000
|
||||
enables a user to type at most 1 char per second. I have found that a
|
||||
setting of 10 gives good keyboard response. We can shorten it further,
|
||||
but eventually performance would suffer from calling select/kbhit too
|
||||
often.
|
||||
"""
|
||||
app = wx.GetApp()
|
||||
if app is not None:
|
||||
assert wx.Thread_IsMain()
|
||||
elr = EventLoopRunner()
|
||||
# As this time is made shorter, keyboard response improves, but idle
|
||||
# CPU load goes up. 10 ms seems like a good compromise.
|
||||
elr.Run(time=10, # CHANGE time here to control polling interval
|
||||
input_is_ready=context.input_is_ready)
|
||||
return 0
|
||||
|
||||
|
||||
@ignore_keyboardinterrupts
|
||||
def inputhook_wx3(context):
|
||||
"""Run the wx event loop by processing pending events only.
|
||||
|
||||
This is like inputhook_wx1, but it keeps processing pending events
|
||||
until stdin is ready. After processing all pending events, a call to
|
||||
time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
|
||||
This sleep time should be tuned though for best performance.
|
||||
"""
|
||||
app = wx.GetApp()
|
||||
if app is not None:
|
||||
assert wx.Thread_IsMain()
|
||||
|
||||
# The import of wx on Linux sets the handler for signal.SIGINT
|
||||
# to 0. This is a bug in wx or gtk. We fix by just setting it
|
||||
# back to the Python default.
|
||||
if not callable(signal.getsignal(signal.SIGINT)):
|
||||
signal.signal(signal.SIGINT, signal.default_int_handler)
|
||||
|
||||
evtloop = wx.EventLoop()
|
||||
ea = wx.EventLoopActivator(evtloop)
|
||||
t = clock()
|
||||
while not context.input_is_ready():
|
||||
while evtloop.Pending():
|
||||
t = clock()
|
||||
evtloop.Dispatch()
|
||||
app.ProcessIdle()
|
||||
# We need to sleep at this point to keep the idle CPU load
|
||||
# low. However, if sleep to long, GUI response is poor. As
|
||||
# a compromise, we watch how often GUI events are being processed
|
||||
# and switch between a short and long sleep time. Here are some
|
||||
# stats useful in helping to tune this.
|
||||
# time CPU load
|
||||
# 0.001 13%
|
||||
# 0.005 3%
|
||||
# 0.01 1.5%
|
||||
# 0.05 0.5%
|
||||
used_time = clock() - t
|
||||
if used_time > 10.0:
|
||||
# print 'Sleep for 1 s' # dbg
|
||||
time.sleep(1.0)
|
||||
elif used_time > 0.1:
|
||||
# Few GUI events coming in, so we can sleep longer
|
||||
# print 'Sleep for 0.05 s' # dbg
|
||||
time.sleep(0.05)
|
||||
else:
|
||||
# Many GUI events coming in, so sleep only very little
|
||||
time.sleep(0.001)
|
||||
del ea
|
||||
return 0
|
||||
|
||||
|
||||
@ignore_keyboardinterrupts
|
||||
def inputhook_wxphoenix(context):
|
||||
"""Run the wx event loop until the user provides more input.
|
||||
|
||||
This input hook is suitable for use with wxPython >= 4 (a.k.a. Phoenix).
|
||||
|
||||
It uses the same approach to that used in
|
||||
ipykernel.eventloops.loop_wx. The wx.MainLoop is executed, and a wx.Timer
|
||||
is used to periodically poll the context for input. As soon as input is
|
||||
ready, the wx.MainLoop is stopped.
|
||||
"""
|
||||
|
||||
app = wx.GetApp()
|
||||
|
||||
if app is None:
|
||||
return
|
||||
|
||||
if context.input_is_ready():
|
||||
return
|
||||
|
||||
assert wx.IsMainThread()
|
||||
|
||||
# Wx uses milliseconds
|
||||
poll_interval = 100
|
||||
|
||||
# Use a wx.Timer to periodically check whether input is ready - as soon as
|
||||
# it is, we exit the main loop
|
||||
timer = wx.Timer()
|
||||
|
||||
def poll(ev):
|
||||
if context.input_is_ready():
|
||||
timer.Stop()
|
||||
app.ExitMainLoop()
|
||||
|
||||
timer.Start(poll_interval)
|
||||
timer.Bind(wx.EVT_TIMER, poll)
|
||||
|
||||
# The import of wx on Linux sets the handler for signal.SIGINT to 0. This
|
||||
# is a bug in wx or gtk. We fix by just setting it back to the Python
|
||||
# default.
|
||||
if not callable(signal.getsignal(signal.SIGINT)):
|
||||
signal.signal(signal.SIGINT, signal.default_int_handler)
|
||||
|
||||
# The SetExitOnFrameDelete call allows us to run the wx mainloop without
|
||||
# having a frame open.
|
||||
app.SetExitOnFrameDelete(False)
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
# Get the major wx version number to figure out what input hook we should use.
|
||||
major_version = 3
|
||||
|
||||
try:
|
||||
major_version = int(wx.__version__[0])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Use the phoenix hook on all platforms for wxpython >= 4
|
||||
if major_version >= 4:
|
||||
inputhook = inputhook_wxphoenix
|
||||
# On OSX, evtloop.Pending() always returns True, regardless of there being
|
||||
# any events pending. As such we can't use implementations 1 or 3 of the
|
||||
# inputhook as those depend on a pending/dispatch loop.
|
||||
elif sys.platform == 'darwin':
|
||||
inputhook = inputhook_wx2
|
||||
else:
|
||||
inputhook = inputhook_wx3
|
8
venv/Lib/site-packages/IPython/terminal/ptshell.py
Normal file
8
venv/Lib/site-packages/IPython/terminal/ptshell.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
raise DeprecationWarning("""DEPRECATED:
|
||||
|
||||
After Popular request and decision from the BDFL:
|
||||
`IPython.terminal.ptshell` has been moved back to `IPython.terminal.interactiveshell`
|
||||
during the beta cycle (after IPython 5.0.beta3) Sorry about that.
|
||||
|
||||
This file will be removed in 5.0 rc or final.
|
||||
""")
|
192
venv/Lib/site-packages/IPython/terminal/ptutils.py
Normal file
192
venv/Lib/site-packages/IPython/terminal/ptutils.py
Normal file
|
@ -0,0 +1,192 @@
|
|||
"""prompt-toolkit utilities
|
||||
|
||||
Everything in this module is a private API,
|
||||
not to be used outside IPython.
|
||||
"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import unicodedata
|
||||
from wcwidth import wcwidth
|
||||
|
||||
from IPython.core.completer import (
|
||||
provisionalcompleter, cursor_to_position,
|
||||
_deduplicate_completions)
|
||||
from prompt_toolkit.completion import Completer, Completion
|
||||
from prompt_toolkit.lexers import Lexer
|
||||
from prompt_toolkit.lexers import PygmentsLexer
|
||||
from prompt_toolkit.patch_stdout import patch_stdout
|
||||
|
||||
import pygments.lexers as pygments_lexers
|
||||
import os
|
||||
|
||||
_completion_sentinel = object()
|
||||
|
||||
def _elide_point(string:str, *, min_elide=30)->str:
|
||||
"""
|
||||
If a string is long enough, and has at least 3 dots,
|
||||
replace the middle part with ellipses.
|
||||
|
||||
If a string naming a file is long enough, and has at least 3 slashes,
|
||||
replace the middle part with ellipses.
|
||||
|
||||
If three consecutive dots, or two consecutive dots are encountered these are
|
||||
replaced by the equivalents HORIZONTAL ELLIPSIS or TWO DOT LEADER unicode
|
||||
equivalents
|
||||
"""
|
||||
string = string.replace('...','\N{HORIZONTAL ELLIPSIS}')
|
||||
string = string.replace('..','\N{TWO DOT LEADER}')
|
||||
if len(string) < min_elide:
|
||||
return string
|
||||
|
||||
object_parts = string.split('.')
|
||||
file_parts = string.split(os.sep)
|
||||
if file_parts[-1] == '':
|
||||
file_parts.pop()
|
||||
|
||||
if len(object_parts) > 3:
|
||||
return '{}.{}\N{HORIZONTAL ELLIPSIS}{}.{}'.format(object_parts[0], object_parts[1][0], object_parts[-2][-1], object_parts[-1])
|
||||
|
||||
elif len(file_parts) > 3:
|
||||
return ('{}' + os.sep + '{}\N{HORIZONTAL ELLIPSIS}{}' + os.sep + '{}').format(file_parts[0], file_parts[1][0], file_parts[-2][-1], file_parts[-1])
|
||||
|
||||
return string
|
||||
|
||||
def _elide_typed(string:str, typed:str, *, min_elide:int=30)->str:
|
||||
"""
|
||||
Elide the middle of a long string if the beginning has already been typed.
|
||||
"""
|
||||
|
||||
if len(string) < min_elide:
|
||||
return string
|
||||
cut_how_much = len(typed)-3
|
||||
if cut_how_much < 7:
|
||||
return string
|
||||
if string.startswith(typed) and len(string)> len(typed):
|
||||
return f"{string[:3]}\N{HORIZONTAL ELLIPSIS}{string[cut_how_much:]}"
|
||||
return string
|
||||
|
||||
def _elide(string:str, typed:str, min_elide=30)->str:
|
||||
return _elide_typed(
|
||||
_elide_point(string, min_elide=min_elide),
|
||||
typed, min_elide=min_elide)
|
||||
|
||||
|
||||
|
||||
def _adjust_completion_text_based_on_context(text, body, offset):
|
||||
if text.endswith('=') and len(body) > offset and body[offset] == '=':
|
||||
return text[:-1]
|
||||
else:
|
||||
return text
|
||||
|
||||
|
||||
class IPythonPTCompleter(Completer):
|
||||
"""Adaptor to provide IPython completions to prompt_toolkit"""
|
||||
def __init__(self, ipy_completer=None, shell=None):
|
||||
if shell is None and ipy_completer is None:
|
||||
raise TypeError("Please pass shell=an InteractiveShell instance.")
|
||||
self._ipy_completer = ipy_completer
|
||||
self.shell = shell
|
||||
|
||||
@property
|
||||
def ipy_completer(self):
|
||||
if self._ipy_completer:
|
||||
return self._ipy_completer
|
||||
else:
|
||||
return self.shell.Completer
|
||||
|
||||
def get_completions(self, document, complete_event):
|
||||
if not document.current_line.strip():
|
||||
return
|
||||
# Some bits of our completion system may print stuff (e.g. if a module
|
||||
# is imported). This context manager ensures that doesn't interfere with
|
||||
# the prompt.
|
||||
|
||||
with patch_stdout(), provisionalcompleter():
|
||||
body = document.text
|
||||
cursor_row = document.cursor_position_row
|
||||
cursor_col = document.cursor_position_col
|
||||
cursor_position = document.cursor_position
|
||||
offset = cursor_to_position(body, cursor_row, cursor_col)
|
||||
try:
|
||||
yield from self._get_completions(body, offset, cursor_position, self.ipy_completer)
|
||||
except Exception as e:
|
||||
from traceback import print_tb
|
||||
print_tb(e)
|
||||
|
||||
@staticmethod
|
||||
def _get_completions(body, offset, cursor_position, ipyc):
|
||||
"""
|
||||
Private equivalent of get_completions() use only for unit_testing.
|
||||
"""
|
||||
debug = getattr(ipyc, 'debug', False)
|
||||
completions = _deduplicate_completions(
|
||||
body, ipyc.completions(body, offset))
|
||||
for c in completions:
|
||||
if not c.text:
|
||||
# Guard against completion machinery giving us an empty string.
|
||||
continue
|
||||
text = unicodedata.normalize('NFC', c.text)
|
||||
# When the first character of the completion has a zero length,
|
||||
# then it's probably a decomposed unicode character. E.g. caused by
|
||||
# the "\dot" completion. Try to compose again with the previous
|
||||
# character.
|
||||
if wcwidth(text[0]) == 0:
|
||||
if cursor_position + c.start > 0:
|
||||
char_before = body[c.start - 1]
|
||||
fixed_text = unicodedata.normalize(
|
||||
'NFC', char_before + text)
|
||||
|
||||
# Yield the modified completion instead, if this worked.
|
||||
if wcwidth(text[0:1]) == 1:
|
||||
yield Completion(fixed_text, start_position=c.start - offset - 1)
|
||||
continue
|
||||
|
||||
# TODO: Use Jedi to determine meta_text
|
||||
# (Jedi currently has a bug that results in incorrect information.)
|
||||
# meta_text = ''
|
||||
# yield Completion(m, start_position=start_pos,
|
||||
# display_meta=meta_text)
|
||||
display_text = c.text
|
||||
|
||||
adjusted_text = _adjust_completion_text_based_on_context(c.text, body, offset)
|
||||
if c.type == 'function':
|
||||
yield Completion(adjusted_text, start_position=c.start - offset, display=_elide(display_text+'()', body[c.start:c.end]), display_meta=c.type+c.signature)
|
||||
else:
|
||||
yield Completion(adjusted_text, start_position=c.start - offset, display=_elide(display_text, body[c.start:c.end]), display_meta=c.type)
|
||||
|
||||
class IPythonPTLexer(Lexer):
|
||||
"""
|
||||
Wrapper around PythonLexer and BashLexer.
|
||||
"""
|
||||
def __init__(self):
|
||||
l = pygments_lexers
|
||||
self.python_lexer = PygmentsLexer(l.Python3Lexer)
|
||||
self.shell_lexer = PygmentsLexer(l.BashLexer)
|
||||
|
||||
self.magic_lexers = {
|
||||
'HTML': PygmentsLexer(l.HtmlLexer),
|
||||
'html': PygmentsLexer(l.HtmlLexer),
|
||||
'javascript': PygmentsLexer(l.JavascriptLexer),
|
||||
'js': PygmentsLexer(l.JavascriptLexer),
|
||||
'perl': PygmentsLexer(l.PerlLexer),
|
||||
'ruby': PygmentsLexer(l.RubyLexer),
|
||||
'latex': PygmentsLexer(l.TexLexer),
|
||||
}
|
||||
|
||||
def lex_document(self, document):
|
||||
text = document.text.lstrip()
|
||||
|
||||
lexer = self.python_lexer
|
||||
|
||||
if text.startswith('!') or text.startswith('%%bash'):
|
||||
lexer = self.shell_lexer
|
||||
|
||||
elif text.startswith('%%'):
|
||||
for magic, l in self.magic_lexers.items():
|
||||
if text.startswith('%%' + magic):
|
||||
lexer = l
|
||||
break
|
||||
|
||||
return lexer.lex_document(document)
|
276
venv/Lib/site-packages/IPython/terminal/shortcuts.py
Normal file
276
venv/Lib/site-packages/IPython/terminal/shortcuts.py
Normal file
|
@ -0,0 +1,276 @@
|
|||
"""
|
||||
Module to define and register Terminal IPython shortcuts with
|
||||
:mod:`prompt_toolkit`
|
||||
"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import warnings
|
||||
import signal
|
||||
import sys
|
||||
from typing import Callable
|
||||
|
||||
|
||||
from prompt_toolkit.application.current import get_app
|
||||
from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
|
||||
from prompt_toolkit.filters import (has_focus, has_selection, Condition,
|
||||
vi_insert_mode, emacs_insert_mode, has_completions, vi_mode)
|
||||
from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
|
||||
from prompt_toolkit.key_binding import KeyBindings
|
||||
|
||||
from IPython.utils.decorators import undoc
|
||||
|
||||
@undoc
|
||||
@Condition
|
||||
def cursor_in_leading_ws():
|
||||
before = get_app().current_buffer.document.current_line_before_cursor
|
||||
return (not before) or before.isspace()
|
||||
|
||||
|
||||
def create_ipython_shortcuts(shell):
|
||||
"""Set up the prompt_toolkit keyboard shortcuts for IPython"""
|
||||
|
||||
kb = KeyBindings()
|
||||
insert_mode = vi_insert_mode | emacs_insert_mode
|
||||
|
||||
if getattr(shell, 'handle_return', None):
|
||||
return_handler = shell.handle_return(shell)
|
||||
else:
|
||||
return_handler = newline_or_execute_outer(shell)
|
||||
|
||||
kb.add('enter', filter=(has_focus(DEFAULT_BUFFER)
|
||||
& ~has_selection
|
||||
& insert_mode
|
||||
))(return_handler)
|
||||
|
||||
def reformat_and_execute(event):
|
||||
reformat_text_before_cursor(event.current_buffer, event.current_buffer.document, shell)
|
||||
event.current_buffer.validate_and_handle()
|
||||
|
||||
kb.add('escape', 'enter', filter=(has_focus(DEFAULT_BUFFER)
|
||||
& ~has_selection
|
||||
& insert_mode
|
||||
))(reformat_and_execute)
|
||||
|
||||
kb.add('c-\\')(force_exit)
|
||||
|
||||
kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
|
||||
)(previous_history_or_previous_completion)
|
||||
|
||||
kb.add('c-n', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
|
||||
)(next_history_or_next_completion)
|
||||
|
||||
kb.add('c-g', filter=(has_focus(DEFAULT_BUFFER) & has_completions)
|
||||
)(dismiss_completion)
|
||||
|
||||
kb.add('c-c', filter=has_focus(DEFAULT_BUFFER))(reset_buffer)
|
||||
|
||||
kb.add('c-c', filter=has_focus(SEARCH_BUFFER))(reset_search_buffer)
|
||||
|
||||
supports_suspend = Condition(lambda: hasattr(signal, 'SIGTSTP'))
|
||||
kb.add('c-z', filter=supports_suspend)(suspend_to_bg)
|
||||
|
||||
# Ctrl+I == Tab
|
||||
kb.add('tab', filter=(has_focus(DEFAULT_BUFFER)
|
||||
& ~has_selection
|
||||
& insert_mode
|
||||
& cursor_in_leading_ws
|
||||
))(indent_buffer)
|
||||
kb.add('c-o', filter=(has_focus(DEFAULT_BUFFER) & emacs_insert_mode)
|
||||
)(newline_autoindent_outer(shell.input_transformer_manager))
|
||||
|
||||
kb.add('f2', filter=has_focus(DEFAULT_BUFFER))(open_input_in_editor)
|
||||
|
||||
if shell.display_completions == 'readlinelike':
|
||||
kb.add('c-i', filter=(has_focus(DEFAULT_BUFFER)
|
||||
& ~has_selection
|
||||
& insert_mode
|
||||
& ~cursor_in_leading_ws
|
||||
))(display_completions_like_readline)
|
||||
|
||||
if sys.platform == 'win32':
|
||||
kb.add('c-v', filter=(has_focus(DEFAULT_BUFFER) & ~vi_mode))(win_paste)
|
||||
|
||||
return kb
|
||||
|
||||
|
||||
def reformat_text_before_cursor(buffer, document, shell):
|
||||
text = buffer.delete_before_cursor(len(document.text[:document.cursor_position]))
|
||||
try:
|
||||
formatted_text = shell.reformat_handler(text)
|
||||
buffer.insert_text(formatted_text)
|
||||
except Exception as e:
|
||||
buffer.insert_text(text)
|
||||
|
||||
|
||||
def newline_or_execute_outer(shell):
|
||||
|
||||
def newline_or_execute(event):
|
||||
"""When the user presses return, insert a newline or execute the code."""
|
||||
b = event.current_buffer
|
||||
d = b.document
|
||||
|
||||
if b.complete_state:
|
||||
cc = b.complete_state.current_completion
|
||||
if cc:
|
||||
b.apply_completion(cc)
|
||||
else:
|
||||
b.cancel_completion()
|
||||
return
|
||||
|
||||
# If there's only one line, treat it as if the cursor is at the end.
|
||||
# See https://github.com/ipython/ipython/issues/10425
|
||||
if d.line_count == 1:
|
||||
check_text = d.text
|
||||
else:
|
||||
check_text = d.text[:d.cursor_position]
|
||||
status, indent = shell.check_complete(check_text)
|
||||
|
||||
# if all we have after the cursor is whitespace: reformat current text
|
||||
# before cursor
|
||||
after_cursor = d.text[d.cursor_position:]
|
||||
reformatted = False
|
||||
if not after_cursor.strip():
|
||||
reformat_text_before_cursor(b, d, shell)
|
||||
reformatted = True
|
||||
if not (d.on_last_line or
|
||||
d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
|
||||
):
|
||||
if shell.autoindent:
|
||||
b.insert_text('\n' + indent)
|
||||
else:
|
||||
b.insert_text('\n')
|
||||
return
|
||||
|
||||
if (status != 'incomplete') and b.accept_handler:
|
||||
if not reformatted:
|
||||
reformat_text_before_cursor(b, d, shell)
|
||||
b.validate_and_handle()
|
||||
else:
|
||||
if shell.autoindent:
|
||||
b.insert_text('\n' + indent)
|
||||
else:
|
||||
b.insert_text('\n')
|
||||
return newline_or_execute
|
||||
|
||||
|
||||
def previous_history_or_previous_completion(event):
|
||||
"""
|
||||
Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
|
||||
|
||||
If completer is open this still select previous completion.
|
||||
"""
|
||||
event.current_buffer.auto_up()
|
||||
|
||||
|
||||
def next_history_or_next_completion(event):
|
||||
"""
|
||||
Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
|
||||
|
||||
If completer is open this still select next completion.
|
||||
"""
|
||||
event.current_buffer.auto_down()
|
||||
|
||||
|
||||
def dismiss_completion(event):
|
||||
b = event.current_buffer
|
||||
if b.complete_state:
|
||||
b.cancel_completion()
|
||||
|
||||
|
||||
def reset_buffer(event):
|
||||
b = event.current_buffer
|
||||
if b.complete_state:
|
||||
b.cancel_completion()
|
||||
else:
|
||||
b.reset()
|
||||
|
||||
|
||||
def reset_search_buffer(event):
|
||||
if event.current_buffer.document.text:
|
||||
event.current_buffer.reset()
|
||||
else:
|
||||
event.app.layout.focus(DEFAULT_BUFFER)
|
||||
|
||||
def suspend_to_bg(event):
|
||||
event.app.suspend_to_background()
|
||||
|
||||
def force_exit(event):
|
||||
"""
|
||||
Force exit (with a non-zero return value)
|
||||
"""
|
||||
sys.exit("Quit")
|
||||
|
||||
def indent_buffer(event):
|
||||
event.current_buffer.insert_text(' ' * 4)
|
||||
|
||||
@undoc
|
||||
def newline_with_copy_margin(event):
|
||||
"""
|
||||
DEPRECATED since IPython 6.0
|
||||
|
||||
See :any:`newline_autoindent_outer` for a replacement.
|
||||
|
||||
Preserve margin and cursor position when using
|
||||
Control-O to insert a newline in EMACS mode
|
||||
"""
|
||||
warnings.warn("`newline_with_copy_margin(event)` is deprecated since IPython 6.0. "
|
||||
"see `newline_autoindent_outer(shell)(event)` for a replacement.",
|
||||
DeprecationWarning, stacklevel=2)
|
||||
|
||||
b = event.current_buffer
|
||||
cursor_start_pos = b.document.cursor_position_col
|
||||
b.newline(copy_margin=True)
|
||||
b.cursor_up(count=1)
|
||||
cursor_end_pos = b.document.cursor_position_col
|
||||
if cursor_start_pos != cursor_end_pos:
|
||||
pos_diff = cursor_start_pos - cursor_end_pos
|
||||
b.cursor_right(count=pos_diff)
|
||||
|
||||
def newline_autoindent_outer(inputsplitter) -> Callable[..., None]:
|
||||
"""
|
||||
Return a function suitable for inserting a indented newline after the cursor.
|
||||
|
||||
Fancier version of deprecated ``newline_with_copy_margin`` which should
|
||||
compute the correct indentation of the inserted line. That is to say, indent
|
||||
by 4 extra space after a function definition, class definition, context
|
||||
manager... And dedent by 4 space after ``pass``, ``return``, ``raise ...``.
|
||||
"""
|
||||
|
||||
def newline_autoindent(event):
|
||||
"""insert a newline after the cursor indented appropriately."""
|
||||
b = event.current_buffer
|
||||
d = b.document
|
||||
|
||||
if b.complete_state:
|
||||
b.cancel_completion()
|
||||
text = d.text[:d.cursor_position] + '\n'
|
||||
_, indent = inputsplitter.check_complete(text)
|
||||
b.insert_text('\n' + (' ' * (indent or 0)), move_cursor=False)
|
||||
|
||||
return newline_autoindent
|
||||
|
||||
|
||||
def open_input_in_editor(event):
|
||||
event.app.current_buffer.open_in_editor()
|
||||
|
||||
|
||||
if sys.platform == 'win32':
|
||||
from IPython.core.error import TryNext
|
||||
from IPython.lib.clipboard import (ClipboardEmpty,
|
||||
win32_clipboard_get,
|
||||
tkinter_clipboard_get)
|
||||
|
||||
@undoc
|
||||
def win_paste(event):
|
||||
try:
|
||||
text = win32_clipboard_get()
|
||||
except TryNext:
|
||||
try:
|
||||
text = tkinter_clipboard_get()
|
||||
except (TryNext, ClipboardEmpty):
|
||||
return
|
||||
except ClipboardEmpty:
|
||||
return
|
||||
event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,78 @@
|
|||
"""Test embedding of IPython"""
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (C) 2013 The IPython Development Team
|
||||
#
|
||||
# Distributed under the terms of the BSD License. The full license is in
|
||||
# the file COPYING, distributed as part of this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import sys
|
||||
from IPython.testing.decorators import skip_win32
|
||||
from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Tests
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@skip_win32
|
||||
def test_debug_magic_passes_through_generators():
|
||||
"""
|
||||
This test that we can correctly pass through frames of a generator post-mortem.
|
||||
"""
|
||||
import pexpect
|
||||
import re
|
||||
in_prompt = re.compile(br'In ?\[\d+\]:')
|
||||
ipdb_prompt = 'ipdb>'
|
||||
env = os.environ.copy()
|
||||
child = pexpect.spawn(sys.executable, ['-m', 'IPython', '--colors=nocolor', '--simple-prompt'],
|
||||
env=env)
|
||||
child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
|
||||
|
||||
child.expect(in_prompt)
|
||||
|
||||
child.timeout = 2 * IPYTHON_TESTING_TIMEOUT_SCALE
|
||||
|
||||
child.sendline("def f(x):")
|
||||
child.sendline(" raise Exception")
|
||||
child.sendline("")
|
||||
|
||||
child.expect(in_prompt)
|
||||
child.sendline("gen = (f(x) for x in [0])")
|
||||
child.sendline("")
|
||||
|
||||
child.expect(in_prompt)
|
||||
child.sendline("for x in gen:")
|
||||
child.sendline(" pass")
|
||||
child.sendline("")
|
||||
|
||||
child.expect('Exception:')
|
||||
|
||||
child.expect(in_prompt)
|
||||
child.sendline(r'%debug')
|
||||
child.expect('----> 2 raise Exception')
|
||||
|
||||
child.expect(ipdb_prompt)
|
||||
child.sendline('u')
|
||||
child.expect_exact(r'----> 1 gen = (f(x) for x in [0])')
|
||||
|
||||
child.expect(ipdb_prompt)
|
||||
child.sendline('u')
|
||||
child.expect_exact('----> 1 for x in gen:')
|
||||
|
||||
child.expect(ipdb_prompt)
|
||||
child.sendline('u')
|
||||
child.expect_exact('*** Oldest frame')
|
||||
|
||||
child.expect(ipdb_prompt)
|
||||
child.sendline('exit')
|
||||
|
||||
child.expect(in_prompt)
|
||||
child.sendline('exit')
|
||||
|
||||
child.close()
|
136
venv/Lib/site-packages/IPython/terminal/tests/test_embed.py
Normal file
136
venv/Lib/site-packages/IPython/terminal/tests/test_embed.py
Normal file
|
@ -0,0 +1,136 @@
|
|||
"""Test embedding of IPython"""
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (C) 2013 The IPython Development Team
|
||||
#
|
||||
# Distributed under the terms of the BSD License. The full license is in
|
||||
# the file COPYING, distributed as part of this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import nose.tools as nt
|
||||
from IPython.utils.tempdir import NamedFileInTemporaryDirectory
|
||||
from IPython.testing.decorators import skip_win32
|
||||
from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Tests
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
_sample_embed = b"""
|
||||
import IPython
|
||||
|
||||
a = 3
|
||||
b = 14
|
||||
print(a, '.', b)
|
||||
|
||||
IPython.embed()
|
||||
|
||||
print('bye!')
|
||||
"""
|
||||
|
||||
_exit = b"exit\r"
|
||||
|
||||
def test_ipython_embed():
|
||||
"""test that `IPython.embed()` works"""
|
||||
with NamedFileInTemporaryDirectory('file_with_embed.py') as f:
|
||||
f.write(_sample_embed)
|
||||
f.flush()
|
||||
f.close() # otherwise msft won't be able to read the file
|
||||
|
||||
# run `python file_with_embed.py`
|
||||
cmd = [sys.executable, f.name]
|
||||
env = os.environ.copy()
|
||||
env['IPY_TEST_SIMPLE_PROMPT'] = '1'
|
||||
|
||||
p = subprocess.Popen(cmd, env=env, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
out, err = p.communicate(_exit)
|
||||
std = out.decode('UTF-8')
|
||||
|
||||
nt.assert_equal(p.returncode, 0)
|
||||
nt.assert_in('3 . 14', std)
|
||||
if os.name != 'nt':
|
||||
# TODO: Fix up our different stdout references, see issue gh-14
|
||||
nt.assert_in('IPython', std)
|
||||
nt.assert_in('bye!', std)
|
||||
|
||||
@skip_win32
|
||||
def test_nest_embed():
|
||||
"""test that `IPython.embed()` is nestable"""
|
||||
import pexpect
|
||||
ipy_prompt = r']:' #ansi color codes give problems matching beyond this
|
||||
env = os.environ.copy()
|
||||
env['IPY_TEST_SIMPLE_PROMPT'] = '1'
|
||||
|
||||
|
||||
child = pexpect.spawn(sys.executable, ['-m', 'IPython', '--colors=nocolor'],
|
||||
env=env)
|
||||
child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline("import IPython")
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline("ip0 = get_ipython()")
|
||||
#enter first nested embed
|
||||
child.sendline("IPython.embed()")
|
||||
#skip the banner until we get to a prompt
|
||||
try:
|
||||
prompted = -1
|
||||
while prompted != 0:
|
||||
prompted = child.expect([ipy_prompt, '\r\n'])
|
||||
except pexpect.TIMEOUT as e:
|
||||
print(e)
|
||||
#child.interact()
|
||||
child.sendline("embed1 = get_ipython()")
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline("print('true' if embed1 is not ip0 else 'false')")
|
||||
assert(child.expect(['true\r\n', 'false\r\n']) == 0)
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline("print('true' if IPython.get_ipython() is embed1 else 'false')")
|
||||
assert(child.expect(['true\r\n', 'false\r\n']) == 0)
|
||||
child.expect(ipy_prompt)
|
||||
#enter second nested embed
|
||||
child.sendline("IPython.embed()")
|
||||
#skip the banner until we get to a prompt
|
||||
try:
|
||||
prompted = -1
|
||||
while prompted != 0:
|
||||
prompted = child.expect([ipy_prompt, '\r\n'])
|
||||
except pexpect.TIMEOUT as e:
|
||||
print(e)
|
||||
#child.interact()
|
||||
child.sendline("embed2 = get_ipython()")
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline("print('true' if embed2 is not embed1 else 'false')")
|
||||
assert(child.expect(['true\r\n', 'false\r\n']) == 0)
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline("print('true' if embed2 is IPython.get_ipython() else 'false')")
|
||||
assert(child.expect(['true\r\n', 'false\r\n']) == 0)
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline('exit')
|
||||
#back at first embed
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline("print('true' if get_ipython() is embed1 else 'false')")
|
||||
assert(child.expect(['true\r\n', 'false\r\n']) == 0)
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline("print('true' if IPython.get_ipython() is embed1 else 'false')")
|
||||
assert(child.expect(['true\r\n', 'false\r\n']) == 0)
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline('exit')
|
||||
#back at launching scope
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline("print('true' if get_ipython() is ip0 else 'false')")
|
||||
assert(child.expect(['true\r\n', 'false\r\n']) == 0)
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline("print('true' if IPython.get_ipython() is ip0 else 'false')")
|
||||
assert(child.expect(['true\r\n', 'false\r\n']) == 0)
|
||||
child.expect(ipy_prompt)
|
||||
child.sendline('exit')
|
||||
child.close()
|
28
venv/Lib/site-packages/IPython/terminal/tests/test_help.py
Normal file
28
venv/Lib/site-packages/IPython/terminal/tests/test_help.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
"""Test help output of various IPython entry points"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import IPython.testing.tools as tt
|
||||
|
||||
|
||||
def test_ipython_help():
|
||||
tt.help_all_output_test()
|
||||
|
||||
def test_profile_help():
|
||||
tt.help_all_output_test("profile")
|
||||
|
||||
def test_profile_list_help():
|
||||
tt.help_all_output_test("profile list")
|
||||
|
||||
def test_profile_create_help():
|
||||
tt.help_all_output_test("profile create")
|
||||
|
||||
def test_locate_help():
|
||||
tt.help_all_output_test("locate")
|
||||
|
||||
def test_locate_profile_help():
|
||||
tt.help_all_output_test("locate profile")
|
||||
|
||||
def test_trust_help():
|
||||
tt.help_all_output_test("trust")
|
|
@ -0,0 +1,193 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Tests for the TerminalInteractiveShell and related pieces."""
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
import os
|
||||
|
||||
from IPython.core.inputtransformer import InputTransformer
|
||||
from IPython.testing import tools as tt
|
||||
from IPython.utils.capture import capture_output
|
||||
|
||||
from IPython.terminal.ptutils import _elide, _adjust_completion_text_based_on_context
|
||||
import nose.tools as nt
|
||||
|
||||
class TestElide(unittest.TestCase):
|
||||
|
||||
def test_elide(self):
|
||||
_elide('concatenate((a1, a2, ...), axis', '') # do not raise
|
||||
_elide('concatenate((a1, a2, ..), . axis', '') # do not raise
|
||||
nt.assert_equal(_elide('aaaa.bbbb.ccccc.dddddd.eeeee.fffff.gggggg.hhhhhh',''), 'aaaa.b…g.hhhhhh')
|
||||
|
||||
test_string = os.sep.join(['', 10*'a', 10*'b', 10*'c', ''])
|
||||
expect_stirng = os.sep + 'a' + '\N{HORIZONTAL ELLIPSIS}' + 'b' + os.sep + 10*'c'
|
||||
nt.assert_equal(_elide(test_string, ''), expect_stirng)
|
||||
|
||||
def test_elide_typed_normal(self):
|
||||
nt.assert_equal(_elide('the quick brown fox jumped over the lazy dog', 'the quick brown fox', min_elide=10), 'the…fox jumped over the lazy dog')
|
||||
|
||||
|
||||
def test_elide_typed_short_match(self):
|
||||
"""
|
||||
if the match is too short we don't elide.
|
||||
avoid the "the...the"
|
||||
"""
|
||||
nt.assert_equal(_elide('the quick brown fox jumped over the lazy dog', 'the', min_elide=10), 'the quick brown fox jumped over the lazy dog')
|
||||
|
||||
def test_elide_typed_no_match(self):
|
||||
"""
|
||||
if the match is too short we don't elide.
|
||||
avoid the "the...the"
|
||||
"""
|
||||
# here we typed red instead of brown
|
||||
nt.assert_equal(_elide('the quick brown fox jumped over the lazy dog', 'the quick red fox', min_elide=10), 'the quick brown fox jumped over the lazy dog')
|
||||
|
||||
class TestContextAwareCompletion(unittest.TestCase):
|
||||
|
||||
def test_adjust_completion_text_based_on_context(self):
|
||||
# Adjusted case
|
||||
nt.assert_equal(_adjust_completion_text_based_on_context('arg1=', 'func1(a=)', 7), 'arg1')
|
||||
|
||||
# Untouched cases
|
||||
nt.assert_equal(_adjust_completion_text_based_on_context('arg1=', 'func1(a)', 7), 'arg1=')
|
||||
nt.assert_equal(_adjust_completion_text_based_on_context('arg1=', 'func1(a', 7), 'arg1=')
|
||||
nt.assert_equal(_adjust_completion_text_based_on_context('%magic', 'func1(a=)', 7), '%magic')
|
||||
nt.assert_equal(_adjust_completion_text_based_on_context('func2', 'func1(a=)', 7), 'func2')
|
||||
|
||||
# Decorator for interaction loop tests -----------------------------------------
|
||||
|
||||
class mock_input_helper(object):
|
||||
"""Machinery for tests of the main interact loop.
|
||||
|
||||
Used by the mock_input decorator.
|
||||
"""
|
||||
def __init__(self, testgen):
|
||||
self.testgen = testgen
|
||||
self.exception = None
|
||||
self.ip = get_ipython()
|
||||
|
||||
def __enter__(self):
|
||||
self.orig_prompt_for_code = self.ip.prompt_for_code
|
||||
self.ip.prompt_for_code = self.fake_input
|
||||
return self
|
||||
|
||||
def __exit__(self, etype, value, tb):
|
||||
self.ip.prompt_for_code = self.orig_prompt_for_code
|
||||
|
||||
def fake_input(self):
|
||||
try:
|
||||
return next(self.testgen)
|
||||
except StopIteration:
|
||||
self.ip.keep_running = False
|
||||
return u''
|
||||
except:
|
||||
self.exception = sys.exc_info()
|
||||
self.ip.keep_running = False
|
||||
return u''
|
||||
|
||||
def mock_input(testfunc):
|
||||
"""Decorator for tests of the main interact loop.
|
||||
|
||||
Write the test as a generator, yield-ing the input strings, which IPython
|
||||
will see as if they were typed in at the prompt.
|
||||
"""
|
||||
def test_method(self):
|
||||
testgen = testfunc(self)
|
||||
with mock_input_helper(testgen) as mih:
|
||||
mih.ip.interact()
|
||||
|
||||
if mih.exception is not None:
|
||||
# Re-raise captured exception
|
||||
etype, value, tb = mih.exception
|
||||
import traceback
|
||||
traceback.print_tb(tb, file=sys.stdout)
|
||||
del tb # Avoid reference loop
|
||||
raise value
|
||||
|
||||
return test_method
|
||||
|
||||
# Test classes -----------------------------------------------------------------
|
||||
|
||||
class InteractiveShellTestCase(unittest.TestCase):
|
||||
def rl_hist_entries(self, rl, n):
|
||||
"""Get last n readline history entries as a list"""
|
||||
return [rl.get_history_item(rl.get_current_history_length() - x)
|
||||
for x in range(n - 1, -1, -1)]
|
||||
|
||||
@mock_input
|
||||
def test_inputtransformer_syntaxerror(self):
|
||||
ip = get_ipython()
|
||||
ip.input_transformers_post.append(syntax_error_transformer)
|
||||
|
||||
try:
|
||||
#raise Exception
|
||||
with tt.AssertPrints('4', suppress=False):
|
||||
yield u'print(2*2)'
|
||||
|
||||
with tt.AssertPrints('SyntaxError: input contains', suppress=False):
|
||||
yield u'print(2345) # syntaxerror'
|
||||
|
||||
with tt.AssertPrints('16', suppress=False):
|
||||
yield u'print(4*4)'
|
||||
|
||||
finally:
|
||||
ip.input_transformers_post.remove(syntax_error_transformer)
|
||||
|
||||
def test_plain_text_only(self):
|
||||
ip = get_ipython()
|
||||
formatter = ip.display_formatter
|
||||
assert formatter.active_types == ['text/plain']
|
||||
assert not formatter.ipython_display_formatter.enabled
|
||||
|
||||
class Test(object):
|
||||
def __repr__(self):
|
||||
return "<Test %i>" % id(self)
|
||||
|
||||
def _repr_html_(self):
|
||||
return '<html>'
|
||||
|
||||
# verify that HTML repr isn't computed
|
||||
obj = Test()
|
||||
data, _ = formatter.format(obj)
|
||||
self.assertEqual(data, {'text/plain': repr(obj)})
|
||||
|
||||
class Test2(Test):
|
||||
def _ipython_display_(self):
|
||||
from IPython.display import display
|
||||
display('<custom>')
|
||||
|
||||
# verify that _ipython_display_ shortcut isn't called
|
||||
obj = Test2()
|
||||
with capture_output() as captured:
|
||||
data, _ = formatter.format(obj)
|
||||
|
||||
self.assertEqual(data, {'text/plain': repr(obj)})
|
||||
assert captured.stdout == ''
|
||||
|
||||
def syntax_error_transformer(lines):
|
||||
"""Transformer that throws SyntaxError if 'syntaxerror' is in the code."""
|
||||
for line in lines:
|
||||
pos = line.find('syntaxerror')
|
||||
if pos >= 0:
|
||||
e = SyntaxError('input contains "syntaxerror"')
|
||||
e.text = line
|
||||
e.offset = pos + 1
|
||||
raise e
|
||||
return lines
|
||||
|
||||
|
||||
class TerminalMagicsTestCase(unittest.TestCase):
|
||||
def test_paste_magics_blankline(self):
|
||||
"""Test that code with a blank line doesn't get split (gh-3246)."""
|
||||
ip = get_ipython()
|
||||
s = ('def pasted_func(a):\n'
|
||||
' b = a+1\n'
|
||||
'\n'
|
||||
' return b')
|
||||
|
||||
tm = ip.magics_manager.registry['TerminalMagics']
|
||||
tm.store_or_execute(s, name=None)
|
||||
|
||||
self.assertEqual(ip.user_ns['pasted_func'](54), 55)
|
Loading…
Add table
Add a link
Reference in a new issue