mirror of
https://github.com/aykhans/AzSuicideDataVisualization.git
synced 2025-07-02 14:27:31 +00:00
first commit
This commit is contained in:
42
.venv/Lib/site-packages/IPython/core/magics/__init__.py
Normal file
42
.venv/Lib/site-packages/IPython/core/magics/__init__.py
Normal file
@ -0,0 +1,42 @@
|
||||
"""Implementation of all the magic functions built into IPython.
|
||||
"""
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (c) 2012 The IPython Development Team.
|
||||
#
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
#
|
||||
# The full license is in the file COPYING.txt, distributed with this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
from ..magic import Magics, magics_class
|
||||
from .auto import AutoMagics
|
||||
from .basic import BasicMagics, AsyncMagics
|
||||
from .code import CodeMagics, MacroToEdit
|
||||
from .config import ConfigMagics
|
||||
from .display import DisplayMagics
|
||||
from .execution import ExecutionMagics
|
||||
from .extension import ExtensionMagics
|
||||
from .history import HistoryMagics
|
||||
from .logging import LoggingMagics
|
||||
from .namespace import NamespaceMagics
|
||||
from .osm import OSMagics
|
||||
from .packaging import PackagingMagics
|
||||
from .pylab import PylabMagics
|
||||
from .script import ScriptMagics
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Magic implementation classes
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@magics_class
|
||||
class UserMagics(Magics):
|
||||
"""Placeholder for user-defined magics to be added at runtime.
|
||||
|
||||
All magics are eventually merged into a single namespace at runtime, but we
|
||||
use this class to isolate the magics defined dynamically by the user into
|
||||
their own class.
|
||||
"""
|
144
.venv/Lib/site-packages/IPython/core/magics/auto.py
Normal file
144
.venv/Lib/site-packages/IPython/core/magics/auto.py
Normal file
@ -0,0 +1,144 @@
|
||||
"""Implementation of magic functions that control various automatic behaviors.
|
||||
"""
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (c) 2012 The IPython Development Team.
|
||||
#
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
#
|
||||
# The full license is in the file COPYING.txt, distributed with this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Our own packages
|
||||
from IPython.core.magic import Bunch, Magics, magics_class, line_magic
|
||||
from IPython.testing.skipdoctest import skip_doctest
|
||||
from logging import error
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Magic implementation classes
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@magics_class
|
||||
class AutoMagics(Magics):
|
||||
"""Magics that control various autoX behaviors."""
|
||||
|
||||
def __init__(self, shell):
|
||||
super(AutoMagics, self).__init__(shell)
|
||||
# namespace for holding state we may need
|
||||
self._magic_state = Bunch()
|
||||
|
||||
@line_magic
|
||||
def automagic(self, parameter_s=''):
|
||||
"""Make magic functions callable without having to type the initial %.
|
||||
|
||||
Without arguments toggles on/off (when off, you must call it as
|
||||
%automagic, of course). With arguments it sets the value, and you can
|
||||
use any of (case insensitive):
|
||||
|
||||
- on, 1, True: to activate
|
||||
|
||||
- off, 0, False: to deactivate.
|
||||
|
||||
Note that magic functions have lowest priority, so if there's a
|
||||
variable whose name collides with that of a magic fn, automagic won't
|
||||
work for that function (you get the variable instead). However, if you
|
||||
delete the variable (del var), the previously shadowed magic function
|
||||
becomes visible to automagic again."""
|
||||
|
||||
arg = parameter_s.lower()
|
||||
mman = self.shell.magics_manager
|
||||
if arg in ('on', '1', 'true'):
|
||||
val = True
|
||||
elif arg in ('off', '0', 'false'):
|
||||
val = False
|
||||
else:
|
||||
val = not mman.auto_magic
|
||||
mman.auto_magic = val
|
||||
print('\n' + self.shell.magics_manager.auto_status())
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
def autocall(self, parameter_s=''):
|
||||
"""Make functions callable without having to type parentheses.
|
||||
|
||||
Usage:
|
||||
|
||||
%autocall [mode]
|
||||
|
||||
The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the
|
||||
value is toggled on and off (remembering the previous state).
|
||||
|
||||
In more detail, these values mean:
|
||||
|
||||
0 -> fully disabled
|
||||
|
||||
1 -> active, but do not apply if there are no arguments on the line.
|
||||
|
||||
In this mode, you get::
|
||||
|
||||
In [1]: callable
|
||||
Out[1]: <built-in function callable>
|
||||
|
||||
In [2]: callable 'hello'
|
||||
------> callable('hello')
|
||||
Out[2]: False
|
||||
|
||||
2 -> Active always. Even if no arguments are present, the callable
|
||||
object is called::
|
||||
|
||||
In [2]: float
|
||||
------> float()
|
||||
Out[2]: 0.0
|
||||
|
||||
Note that even with autocall off, you can still use '/' at the start of
|
||||
a line to treat the first argument on the command line as a function
|
||||
and add parentheses to it::
|
||||
|
||||
In [8]: /str 43
|
||||
------> str(43)
|
||||
Out[8]: '43'
|
||||
|
||||
# all-random (note for auto-testing)
|
||||
"""
|
||||
|
||||
valid_modes = {
|
||||
0: "Off",
|
||||
1: "Smart",
|
||||
2: "Full",
|
||||
}
|
||||
|
||||
def errorMessage() -> str:
|
||||
error = "Valid modes: "
|
||||
for k, v in valid_modes.items():
|
||||
error += str(k) + "->" + v + ", "
|
||||
error = error[:-2] # remove tailing `, ` after last element
|
||||
return error
|
||||
|
||||
if parameter_s:
|
||||
if not parameter_s in map(str, valid_modes.keys()):
|
||||
error(errorMessage())
|
||||
return
|
||||
arg = int(parameter_s)
|
||||
else:
|
||||
arg = 'toggle'
|
||||
|
||||
if not arg in (*list(valid_modes.keys()), "toggle"):
|
||||
error(errorMessage())
|
||||
return
|
||||
|
||||
if arg in (valid_modes.keys()):
|
||||
self.shell.autocall = arg
|
||||
else: # toggle
|
||||
if self.shell.autocall:
|
||||
self._magic_state.autocall_save = self.shell.autocall
|
||||
self.shell.autocall = 0
|
||||
else:
|
||||
try:
|
||||
self.shell.autocall = self._magic_state.autocall_save
|
||||
except AttributeError:
|
||||
self.shell.autocall = self._magic_state.autocall_save = 1
|
||||
|
||||
print("Automatic calling is:", list(valid_modes.values())[self.shell.autocall])
|
659
.venv/Lib/site-packages/IPython/core/magics/basic.py
Normal file
659
.venv/Lib/site-packages/IPython/core/magics/basic.py
Normal file
@ -0,0 +1,659 @@
|
||||
"""Implementation of basic magic functions."""
|
||||
|
||||
|
||||
import argparse
|
||||
from logging import error
|
||||
import io
|
||||
import os
|
||||
from pprint import pformat
|
||||
import sys
|
||||
from warnings import warn
|
||||
|
||||
from traitlets.utils.importstring import import_item
|
||||
from IPython.core import magic_arguments, page
|
||||
from IPython.core.error import UsageError
|
||||
from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes
|
||||
from IPython.utils.text import format_screen, dedent, indent
|
||||
from IPython.testing.skipdoctest import skip_doctest
|
||||
from IPython.utils.ipstruct import Struct
|
||||
|
||||
|
||||
class MagicsDisplay(object):
|
||||
def __init__(self, magics_manager, ignore=None):
|
||||
self.ignore = ignore if ignore else []
|
||||
self.magics_manager = magics_manager
|
||||
|
||||
def _lsmagic(self):
|
||||
"""The main implementation of the %lsmagic"""
|
||||
mesc = magic_escapes['line']
|
||||
cesc = magic_escapes['cell']
|
||||
mman = self.magics_manager
|
||||
magics = mman.lsmagic()
|
||||
out = ['Available line magics:',
|
||||
mesc + (' '+mesc).join(sorted([m for m,v in magics['line'].items() if (v not in self.ignore)])),
|
||||
'',
|
||||
'Available cell magics:',
|
||||
cesc + (' '+cesc).join(sorted([m for m,v in magics['cell'].items() if (v not in self.ignore)])),
|
||||
'',
|
||||
mman.auto_status()]
|
||||
return '\n'.join(out)
|
||||
|
||||
def _repr_pretty_(self, p, cycle):
|
||||
p.text(self._lsmagic())
|
||||
|
||||
def __str__(self):
|
||||
return self._lsmagic()
|
||||
|
||||
def _jsonable(self):
|
||||
"""turn magics dict into jsonable dict of the same structure
|
||||
|
||||
replaces object instances with their class names as strings
|
||||
"""
|
||||
magic_dict = {}
|
||||
mman = self.magics_manager
|
||||
magics = mman.lsmagic()
|
||||
for key, subdict in magics.items():
|
||||
d = {}
|
||||
magic_dict[key] = d
|
||||
for name, obj in subdict.items():
|
||||
try:
|
||||
classname = obj.__self__.__class__.__name__
|
||||
except AttributeError:
|
||||
classname = 'Other'
|
||||
|
||||
d[name] = classname
|
||||
return magic_dict
|
||||
|
||||
def _repr_json_(self):
|
||||
return self._jsonable()
|
||||
|
||||
|
||||
@magics_class
|
||||
class BasicMagics(Magics):
|
||||
"""Magics that provide central IPython functionality.
|
||||
|
||||
These are various magics that don't fit into specific categories but that
|
||||
are all part of the base 'IPython experience'."""
|
||||
|
||||
@skip_doctest
|
||||
@magic_arguments.magic_arguments()
|
||||
@magic_arguments.argument(
|
||||
'-l', '--line', action='store_true',
|
||||
help="""Create a line magic alias."""
|
||||
)
|
||||
@magic_arguments.argument(
|
||||
'-c', '--cell', action='store_true',
|
||||
help="""Create a cell magic alias."""
|
||||
)
|
||||
@magic_arguments.argument(
|
||||
'name',
|
||||
help="""Name of the magic to be created."""
|
||||
)
|
||||
@magic_arguments.argument(
|
||||
'target',
|
||||
help="""Name of the existing line or cell magic."""
|
||||
)
|
||||
@magic_arguments.argument(
|
||||
'-p', '--params', default=None,
|
||||
help="""Parameters passed to the magic function."""
|
||||
)
|
||||
@line_magic
|
||||
def alias_magic(self, line=''):
|
||||
"""Create an alias for an existing line or cell magic.
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
|
||||
In [1]: %alias_magic t timeit
|
||||
Created `%t` as an alias for `%timeit`.
|
||||
Created `%%t` as an alias for `%%timeit`.
|
||||
|
||||
In [2]: %t -n1 pass
|
||||
1 loops, best of 3: 954 ns per loop
|
||||
|
||||
In [3]: %%t -n1
|
||||
...: pass
|
||||
...:
|
||||
1 loops, best of 3: 954 ns per loop
|
||||
|
||||
In [4]: %alias_magic --cell whereami pwd
|
||||
UsageError: Cell magic function `%%pwd` not found.
|
||||
In [5]: %alias_magic --line whereami pwd
|
||||
Created `%whereami` as an alias for `%pwd`.
|
||||
|
||||
In [6]: %whereami
|
||||
Out[6]: u'/home/testuser'
|
||||
|
||||
In [7]: %alias_magic h history "-p -l 30" --line
|
||||
Created `%h` as an alias for `%history -l 30`.
|
||||
"""
|
||||
|
||||
args = magic_arguments.parse_argstring(self.alias_magic, line)
|
||||
shell = self.shell
|
||||
mman = self.shell.magics_manager
|
||||
escs = ''.join(magic_escapes.values())
|
||||
|
||||
target = args.target.lstrip(escs)
|
||||
name = args.name.lstrip(escs)
|
||||
|
||||
params = args.params
|
||||
if (params and
|
||||
((params.startswith('"') and params.endswith('"'))
|
||||
or (params.startswith("'") and params.endswith("'")))):
|
||||
params = params[1:-1]
|
||||
|
||||
# Find the requested magics.
|
||||
m_line = shell.find_magic(target, 'line')
|
||||
m_cell = shell.find_magic(target, 'cell')
|
||||
if args.line and m_line is None:
|
||||
raise UsageError('Line magic function `%s%s` not found.' %
|
||||
(magic_escapes['line'], target))
|
||||
if args.cell and m_cell is None:
|
||||
raise UsageError('Cell magic function `%s%s` not found.' %
|
||||
(magic_escapes['cell'], target))
|
||||
|
||||
# If --line and --cell are not specified, default to the ones
|
||||
# that are available.
|
||||
if not args.line and not args.cell:
|
||||
if not m_line and not m_cell:
|
||||
raise UsageError(
|
||||
'No line or cell magic with name `%s` found.' % target
|
||||
)
|
||||
args.line = bool(m_line)
|
||||
args.cell = bool(m_cell)
|
||||
|
||||
params_str = "" if params is None else " " + params
|
||||
|
||||
if args.line:
|
||||
mman.register_alias(name, target, 'line', params)
|
||||
print('Created `%s%s` as an alias for `%s%s%s`.' % (
|
||||
magic_escapes['line'], name,
|
||||
magic_escapes['line'], target, params_str))
|
||||
|
||||
if args.cell:
|
||||
mman.register_alias(name, target, 'cell', params)
|
||||
print('Created `%s%s` as an alias for `%s%s%s`.' % (
|
||||
magic_escapes['cell'], name,
|
||||
magic_escapes['cell'], target, params_str))
|
||||
|
||||
@line_magic
|
||||
def lsmagic(self, parameter_s=''):
|
||||
"""List currently available magic functions."""
|
||||
return MagicsDisplay(self.shell.magics_manager, ignore=[])
|
||||
|
||||
def _magic_docs(self, brief=False, rest=False):
|
||||
"""Return docstrings from magic functions."""
|
||||
mman = self.shell.magics_manager
|
||||
docs = mman.lsmagic_docs(brief, missing='No documentation')
|
||||
|
||||
if rest:
|
||||
format_string = '**%s%s**::\n\n%s\n\n'
|
||||
else:
|
||||
format_string = '%s%s:\n%s\n'
|
||||
|
||||
return ''.join(
|
||||
[format_string % (magic_escapes['line'], fname,
|
||||
indent(dedent(fndoc)))
|
||||
for fname, fndoc in sorted(docs['line'].items())]
|
||||
+
|
||||
[format_string % (magic_escapes['cell'], fname,
|
||||
indent(dedent(fndoc)))
|
||||
for fname, fndoc in sorted(docs['cell'].items())]
|
||||
)
|
||||
|
||||
@line_magic
|
||||
def magic(self, parameter_s=''):
|
||||
"""Print information about the magic function system.
|
||||
|
||||
Supported formats: -latex, -brief, -rest
|
||||
"""
|
||||
|
||||
mode = ''
|
||||
try:
|
||||
mode = parameter_s.split()[0][1:]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
brief = (mode == 'brief')
|
||||
rest = (mode == 'rest')
|
||||
magic_docs = self._magic_docs(brief, rest)
|
||||
|
||||
if mode == 'latex':
|
||||
print(self.format_latex(magic_docs))
|
||||
return
|
||||
else:
|
||||
magic_docs = format_screen(magic_docs)
|
||||
|
||||
out = ["""
|
||||
IPython's 'magic' functions
|
||||
===========================
|
||||
|
||||
The magic function system provides a series of functions which allow you to
|
||||
control the behavior of IPython itself, plus a lot of system-type
|
||||
features. There are two kinds of magics, line-oriented and cell-oriented.
|
||||
|
||||
Line magics are prefixed with the % character and work much like OS
|
||||
command-line calls: they get as an argument the rest of the line, where
|
||||
arguments are passed without parentheses or quotes. For example, this will
|
||||
time the given statement::
|
||||
|
||||
%timeit range(1000)
|
||||
|
||||
Cell magics are prefixed with a double %%, and they are functions that get as
|
||||
an argument not only the rest of the line, but also the lines below it in a
|
||||
separate argument. These magics are called with two arguments: the rest of the
|
||||
call line and the body of the cell, consisting of the lines below the first.
|
||||
For example::
|
||||
|
||||
%%timeit x = numpy.random.randn((100, 100))
|
||||
numpy.linalg.svd(x)
|
||||
|
||||
will time the execution of the numpy svd routine, running the assignment of x
|
||||
as part of the setup phase, which is not timed.
|
||||
|
||||
In a line-oriented client (the terminal or Qt console IPython), starting a new
|
||||
input with %% will automatically enter cell mode, and IPython will continue
|
||||
reading input until a blank line is given. In the notebook, simply type the
|
||||
whole cell as one entity, but keep in mind that the %% escape can only be at
|
||||
the very start of the cell.
|
||||
|
||||
NOTE: If you have 'automagic' enabled (via the command line option or with the
|
||||
%automagic function), you don't need to type in the % explicitly for line
|
||||
magics; cell magics always require an explicit '%%' escape. By default,
|
||||
IPython ships with automagic on, so you should only rarely need the % escape.
|
||||
|
||||
Example: typing '%cd mydir' (without the quotes) changes your working directory
|
||||
to 'mydir', if it exists.
|
||||
|
||||
For a list of the available magic functions, use %lsmagic. For a description
|
||||
of any of them, type %magic_name?, e.g. '%cd?'.
|
||||
|
||||
Currently the magic system has the following functions:""",
|
||||
magic_docs,
|
||||
"Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
|
||||
str(self.lsmagic()),
|
||||
]
|
||||
page.page('\n'.join(out))
|
||||
|
||||
|
||||
@line_magic
|
||||
def page(self, parameter_s=''):
|
||||
"""Pretty print the object and display it through a pager.
|
||||
|
||||
%page [options] OBJECT
|
||||
|
||||
If no object is given, use _ (last output).
|
||||
|
||||
Options:
|
||||
|
||||
-r: page str(object), don't pretty-print it."""
|
||||
|
||||
# After a function contributed by Olivier Aubert, slightly modified.
|
||||
|
||||
# Process options/args
|
||||
opts, args = self.parse_options(parameter_s, 'r')
|
||||
raw = 'r' in opts
|
||||
|
||||
oname = args and args or '_'
|
||||
info = self.shell._ofind(oname)
|
||||
if info['found']:
|
||||
txt = (raw and str or pformat)( info['obj'] )
|
||||
page.page(txt)
|
||||
else:
|
||||
print('Object `%s` not found' % oname)
|
||||
|
||||
@line_magic
|
||||
def pprint(self, parameter_s=''):
|
||||
"""Toggle pretty printing on/off."""
|
||||
ptformatter = self.shell.display_formatter.formatters['text/plain']
|
||||
ptformatter.pprint = bool(1 - ptformatter.pprint)
|
||||
print('Pretty printing has been turned',
|
||||
['OFF','ON'][ptformatter.pprint])
|
||||
|
||||
@line_magic
|
||||
def colors(self, parameter_s=''):
|
||||
"""Switch color scheme for prompts, info system and exception handlers.
|
||||
|
||||
Currently implemented schemes: NoColor, Linux, LightBG.
|
||||
|
||||
Color scheme names are not case-sensitive.
|
||||
|
||||
Examples
|
||||
--------
|
||||
To get a plain black and white terminal::
|
||||
|
||||
%colors nocolor
|
||||
"""
|
||||
def color_switch_err(name):
|
||||
warn('Error changing %s color schemes.\n%s' %
|
||||
(name, sys.exc_info()[1]), stacklevel=2)
|
||||
|
||||
|
||||
new_scheme = parameter_s.strip()
|
||||
if not new_scheme:
|
||||
raise UsageError(
|
||||
"%colors: you must specify a color scheme. See '%colors?'")
|
||||
# local shortcut
|
||||
shell = self.shell
|
||||
|
||||
# Set shell colour scheme
|
||||
try:
|
||||
shell.colors = new_scheme
|
||||
shell.refresh_style()
|
||||
except:
|
||||
color_switch_err('shell')
|
||||
|
||||
# Set exception colors
|
||||
try:
|
||||
shell.InteractiveTB.set_colors(scheme = new_scheme)
|
||||
shell.SyntaxTB.set_colors(scheme = new_scheme)
|
||||
except:
|
||||
color_switch_err('exception')
|
||||
|
||||
# Set info (for 'object?') colors
|
||||
if shell.color_info:
|
||||
try:
|
||||
shell.inspector.set_active_scheme(new_scheme)
|
||||
except:
|
||||
color_switch_err('object inspector')
|
||||
else:
|
||||
shell.inspector.set_active_scheme('NoColor')
|
||||
|
||||
@line_magic
|
||||
def xmode(self, parameter_s=''):
|
||||
"""Switch modes for the exception handlers.
|
||||
|
||||
Valid modes: Plain, Context, Verbose, and Minimal.
|
||||
|
||||
If called without arguments, acts as a toggle.
|
||||
|
||||
When in verbose mode the value --show (and --hide)
|
||||
will respectively show (or hide) frames with ``__tracebackhide__ =
|
||||
True`` value set.
|
||||
"""
|
||||
|
||||
def xmode_switch_err(name):
|
||||
warn('Error changing %s exception modes.\n%s' %
|
||||
(name,sys.exc_info()[1]))
|
||||
|
||||
shell = self.shell
|
||||
if parameter_s.strip() == "--show":
|
||||
shell.InteractiveTB.skip_hidden = False
|
||||
return
|
||||
if parameter_s.strip() == "--hide":
|
||||
shell.InteractiveTB.skip_hidden = True
|
||||
return
|
||||
|
||||
new_mode = parameter_s.strip().capitalize()
|
||||
try:
|
||||
shell.InteractiveTB.set_mode(mode=new_mode)
|
||||
print('Exception reporting mode:',shell.InteractiveTB.mode)
|
||||
except:
|
||||
xmode_switch_err('user')
|
||||
|
||||
@line_magic
|
||||
def quickref(self, arg):
|
||||
""" Show a quick reference sheet """
|
||||
from IPython.core.usage import quick_reference
|
||||
qr = quick_reference + self._magic_docs(brief=True)
|
||||
page.page(qr)
|
||||
|
||||
@line_magic
|
||||
def doctest_mode(self, parameter_s=''):
|
||||
"""Toggle doctest mode on and off.
|
||||
|
||||
This mode is intended to make IPython behave as much as possible like a
|
||||
plain Python shell, from the perspective of how its prompts, exceptions
|
||||
and output look. This makes it easy to copy and paste parts of a
|
||||
session into doctests. It does so by:
|
||||
|
||||
- Changing the prompts to the classic ``>>>`` ones.
|
||||
- Changing the exception reporting mode to 'Plain'.
|
||||
- Disabling pretty-printing of output.
|
||||
|
||||
Note that IPython also supports the pasting of code snippets that have
|
||||
leading '>>>' and '...' prompts in them. This means that you can paste
|
||||
doctests from files or docstrings (even if they have leading
|
||||
whitespace), and the code will execute correctly. You can then use
|
||||
'%history -t' to see the translated history; this will give you the
|
||||
input after removal of all the leading prompts and whitespace, which
|
||||
can be pasted back into an editor.
|
||||
|
||||
With these features, you can switch into this mode easily whenever you
|
||||
need to do testing and changes to doctests, without having to leave
|
||||
your existing IPython session.
|
||||
"""
|
||||
|
||||
# Shorthands
|
||||
shell = self.shell
|
||||
meta = shell.meta
|
||||
disp_formatter = self.shell.display_formatter
|
||||
ptformatter = disp_formatter.formatters['text/plain']
|
||||
# dstore is a data store kept in the instance metadata bag to track any
|
||||
# changes we make, so we can undo them later.
|
||||
dstore = meta.setdefault('doctest_mode',Struct())
|
||||
save_dstore = dstore.setdefault
|
||||
|
||||
# save a few values we'll need to recover later
|
||||
mode = save_dstore('mode',False)
|
||||
save_dstore('rc_pprint',ptformatter.pprint)
|
||||
save_dstore('xmode',shell.InteractiveTB.mode)
|
||||
save_dstore('rc_separate_out',shell.separate_out)
|
||||
save_dstore('rc_separate_out2',shell.separate_out2)
|
||||
save_dstore('rc_separate_in',shell.separate_in)
|
||||
save_dstore('rc_active_types',disp_formatter.active_types)
|
||||
|
||||
if not mode:
|
||||
# turn on
|
||||
|
||||
# Prompt separators like plain python
|
||||
shell.separate_in = ''
|
||||
shell.separate_out = ''
|
||||
shell.separate_out2 = ''
|
||||
|
||||
|
||||
ptformatter.pprint = False
|
||||
disp_formatter.active_types = ['text/plain']
|
||||
|
||||
shell.magic('xmode Plain')
|
||||
else:
|
||||
# turn off
|
||||
shell.separate_in = dstore.rc_separate_in
|
||||
|
||||
shell.separate_out = dstore.rc_separate_out
|
||||
shell.separate_out2 = dstore.rc_separate_out2
|
||||
|
||||
ptformatter.pprint = dstore.rc_pprint
|
||||
disp_formatter.active_types = dstore.rc_active_types
|
||||
|
||||
shell.magic('xmode ' + dstore.xmode)
|
||||
|
||||
# mode here is the state before we switch; switch_doctest_mode takes
|
||||
# the mode we're switching to.
|
||||
shell.switch_doctest_mode(not mode)
|
||||
|
||||
# Store new mode and inform
|
||||
dstore.mode = bool(not mode)
|
||||
mode_label = ['OFF','ON'][dstore.mode]
|
||||
print('Doctest mode is:', mode_label)
|
||||
|
||||
@line_magic
|
||||
def gui(self, parameter_s=''):
|
||||
"""Enable or disable IPython GUI event loop integration.
|
||||
|
||||
%gui [GUINAME]
|
||||
|
||||
This magic replaces IPython's threaded shells that were activated
|
||||
using the (pylab/wthread/etc.) command line flags. GUI toolkits
|
||||
can now be enabled at runtime and keyboard
|
||||
interrupts should work without any problems. The following toolkits
|
||||
are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
|
||||
|
||||
%gui wx # enable wxPython event loop integration
|
||||
%gui qt4|qt # enable PyQt4 event loop integration
|
||||
%gui qt5 # enable PyQt5 event loop integration
|
||||
%gui gtk # enable PyGTK event loop integration
|
||||
%gui gtk3 # enable Gtk3 event loop integration
|
||||
%gui gtk4 # enable Gtk4 event loop integration
|
||||
%gui tk # enable Tk event loop integration
|
||||
%gui osx # enable Cocoa event loop integration
|
||||
# (requires %matplotlib 1.1)
|
||||
%gui # disable all event loop integration
|
||||
|
||||
WARNING: after any of these has been called you can simply create
|
||||
an application object, but DO NOT start the event loop yourself, as
|
||||
we have already handled that.
|
||||
"""
|
||||
opts, arg = self.parse_options(parameter_s, '')
|
||||
if arg=='': arg = None
|
||||
try:
|
||||
return self.shell.enable_gui(arg)
|
||||
except Exception as e:
|
||||
# print simple error message, rather than traceback if we can't
|
||||
# hook up the GUI
|
||||
error(str(e))
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
def precision(self, s=''):
|
||||
"""Set floating point precision for pretty printing.
|
||||
|
||||
Can set either integer precision or a format string.
|
||||
|
||||
If numpy has been imported and precision is an int,
|
||||
numpy display precision will also be set, via ``numpy.set_printoptions``.
|
||||
|
||||
If no argument is given, defaults will be restored.
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
|
||||
In [1]: from math import pi
|
||||
|
||||
In [2]: %precision 3
|
||||
Out[2]: u'%.3f'
|
||||
|
||||
In [3]: pi
|
||||
Out[3]: 3.142
|
||||
|
||||
In [4]: %precision %i
|
||||
Out[4]: u'%i'
|
||||
|
||||
In [5]: pi
|
||||
Out[5]: 3
|
||||
|
||||
In [6]: %precision %e
|
||||
Out[6]: u'%e'
|
||||
|
||||
In [7]: pi**10
|
||||
Out[7]: 9.364805e+04
|
||||
|
||||
In [8]: %precision
|
||||
Out[8]: u'%r'
|
||||
|
||||
In [9]: pi**10
|
||||
Out[9]: 93648.047476082982
|
||||
"""
|
||||
ptformatter = self.shell.display_formatter.formatters['text/plain']
|
||||
ptformatter.float_precision = s
|
||||
return ptformatter.float_format
|
||||
|
||||
@magic_arguments.magic_arguments()
|
||||
@magic_arguments.argument(
|
||||
'filename', type=str,
|
||||
help='Notebook name or filename'
|
||||
)
|
||||
@line_magic
|
||||
def notebook(self, s):
|
||||
"""Export and convert IPython notebooks.
|
||||
|
||||
This function can export the current IPython history to a notebook file.
|
||||
For example, to export the history to "foo.ipynb" do "%notebook foo.ipynb".
|
||||
"""
|
||||
args = magic_arguments.parse_argstring(self.notebook, s)
|
||||
outfname = os.path.expanduser(args.filename)
|
||||
|
||||
from nbformat import write, v4
|
||||
|
||||
cells = []
|
||||
hist = list(self.shell.history_manager.get_range())
|
||||
if(len(hist)<=1):
|
||||
raise ValueError('History is empty, cannot export')
|
||||
for session, execution_count, source in hist[:-1]:
|
||||
cells.append(v4.new_code_cell(
|
||||
execution_count=execution_count,
|
||||
source=source
|
||||
))
|
||||
nb = v4.new_notebook(cells=cells)
|
||||
with io.open(outfname, "w", encoding="utf-8") as f:
|
||||
write(nb, f, version=4)
|
||||
|
||||
@magics_class
|
||||
class AsyncMagics(BasicMagics):
|
||||
|
||||
@line_magic
|
||||
def autoawait(self, parameter_s):
|
||||
"""
|
||||
Allow to change the status of the autoawait option.
|
||||
|
||||
This allow you to set a specific asynchronous code runner.
|
||||
|
||||
If no value is passed, print the currently used asynchronous integration
|
||||
and whether it is activated.
|
||||
|
||||
It can take a number of value evaluated in the following order:
|
||||
|
||||
- False/false/off deactivate autoawait integration
|
||||
- True/true/on activate autoawait integration using configured default
|
||||
loop
|
||||
- asyncio/curio/trio activate autoawait integration and use integration
|
||||
with said library.
|
||||
|
||||
- `sync` turn on the pseudo-sync integration (mostly used for
|
||||
`IPython.embed()` which does not run IPython with a real eventloop and
|
||||
deactivate running asynchronous code. Turning on Asynchronous code with
|
||||
the pseudo sync loop is undefined behavior and may lead IPython to crash.
|
||||
|
||||
If the passed parameter does not match any of the above and is a python
|
||||
identifier, get said object from user namespace and set it as the
|
||||
runner, and activate autoawait.
|
||||
|
||||
If the object is a fully qualified object name, attempt to import it and
|
||||
set it as the runner, and activate autoawait.
|
||||
|
||||
The exact behavior of autoawait is experimental and subject to change
|
||||
across version of IPython and Python.
|
||||
"""
|
||||
|
||||
param = parameter_s.strip()
|
||||
d = {True: "on", False: "off"}
|
||||
|
||||
if not param:
|
||||
print("IPython autoawait is `{}`, and set to use `{}`".format(
|
||||
d[self.shell.autoawait],
|
||||
self.shell.loop_runner
|
||||
))
|
||||
return None
|
||||
|
||||
if param.lower() in ('false', 'off'):
|
||||
self.shell.autoawait = False
|
||||
return None
|
||||
if param.lower() in ('true', 'on'):
|
||||
self.shell.autoawait = True
|
||||
return None
|
||||
|
||||
if param in self.shell.loop_runner_map:
|
||||
self.shell.loop_runner, self.shell.autoawait = self.shell.loop_runner_map[param]
|
||||
return None
|
||||
|
||||
if param in self.shell.user_ns :
|
||||
self.shell.loop_runner = self.shell.user_ns[param]
|
||||
self.shell.autoawait = True
|
||||
return None
|
||||
|
||||
runner = import_item(param)
|
||||
|
||||
self.shell.loop_runner = runner
|
||||
self.shell.autoawait = True
|
755
.venv/Lib/site-packages/IPython/core/magics/code.py
Normal file
755
.venv/Lib/site-packages/IPython/core/magics/code.py
Normal file
@ -0,0 +1,755 @@
|
||||
"""Implementation of code management magic functions.
|
||||
"""
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (c) 2012 The IPython Development Team.
|
||||
#
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
#
|
||||
# The full license is in the file COPYING.txt, distributed with this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Stdlib
|
||||
import inspect
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import ast
|
||||
from itertools import chain
|
||||
from urllib.request import Request, urlopen
|
||||
from urllib.parse import urlencode
|
||||
from pathlib import Path
|
||||
|
||||
# Our own packages
|
||||
from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
|
||||
from IPython.core.macro import Macro
|
||||
from IPython.core.magic import Magics, magics_class, line_magic
|
||||
from IPython.core.oinspect import find_file, find_source_lines
|
||||
from IPython.core.release import version
|
||||
from IPython.testing.skipdoctest import skip_doctest
|
||||
from IPython.utils.contexts import preserve_keys
|
||||
from IPython.utils.path import get_py_filename
|
||||
from warnings import warn
|
||||
from logging import error
|
||||
from IPython.utils.text import get_text_list
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Magic implementation classes
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Used for exception handling in magic_edit
|
||||
class MacroToEdit(ValueError): pass
|
||||
|
||||
ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
|
||||
|
||||
# To match, e.g. 8-10 1:5 :10 3-
|
||||
range_re = re.compile(r"""
|
||||
(?P<start>\d+)?
|
||||
((?P<sep>[\-:])
|
||||
(?P<end>\d+)?)?
|
||||
$""", re.VERBOSE)
|
||||
|
||||
|
||||
def extract_code_ranges(ranges_str):
|
||||
"""Turn a string of range for %%load into 2-tuples of (start, stop)
|
||||
ready to use as a slice of the content split by lines.
|
||||
|
||||
Examples
|
||||
--------
|
||||
list(extract_input_ranges("5-10 2"))
|
||||
[(4, 10), (1, 2)]
|
||||
"""
|
||||
for range_str in ranges_str.split():
|
||||
rmatch = range_re.match(range_str)
|
||||
if not rmatch:
|
||||
continue
|
||||
sep = rmatch.group("sep")
|
||||
start = rmatch.group("start")
|
||||
end = rmatch.group("end")
|
||||
|
||||
if sep == '-':
|
||||
start = int(start) - 1 if start else None
|
||||
end = int(end) if end else None
|
||||
elif sep == ':':
|
||||
start = int(start) - 1 if start else None
|
||||
end = int(end) - 1 if end else None
|
||||
else:
|
||||
end = int(start)
|
||||
start = int(start) - 1
|
||||
yield (start, end)
|
||||
|
||||
|
||||
def extract_symbols(code, symbols):
|
||||
"""
|
||||
Return a tuple (blocks, not_found)
|
||||
where ``blocks`` is a list of code fragments
|
||||
for each symbol parsed from code, and ``not_found`` are
|
||||
symbols not found in the code.
|
||||
|
||||
For example::
|
||||
|
||||
In [1]: code = '''a = 10
|
||||
...: def b(): return 42
|
||||
...: class A: pass'''
|
||||
|
||||
In [2]: extract_symbols(code, 'A,b,z')
|
||||
Out[2]: (['class A: pass\\n', 'def b(): return 42\\n'], ['z'])
|
||||
"""
|
||||
symbols = symbols.split(',')
|
||||
|
||||
# this will raise SyntaxError if code isn't valid Python
|
||||
py_code = ast.parse(code)
|
||||
|
||||
marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
|
||||
code = code.split('\n')
|
||||
|
||||
symbols_lines = {}
|
||||
|
||||
# we already know the start_lineno of each symbol (marks).
|
||||
# To find each end_lineno, we traverse in reverse order until each
|
||||
# non-blank line
|
||||
end = len(code)
|
||||
for name, start in reversed(marks):
|
||||
while not code[end - 1].strip():
|
||||
end -= 1
|
||||
if name:
|
||||
symbols_lines[name] = (start - 1, end)
|
||||
end = start - 1
|
||||
|
||||
# Now symbols_lines is a map
|
||||
# {'symbol_name': (start_lineno, end_lineno), ...}
|
||||
|
||||
# fill a list with chunks of codes for each requested symbol
|
||||
blocks = []
|
||||
not_found = []
|
||||
for symbol in symbols:
|
||||
if symbol in symbols_lines:
|
||||
start, end = symbols_lines[symbol]
|
||||
blocks.append('\n'.join(code[start:end]) + '\n')
|
||||
else:
|
||||
not_found.append(symbol)
|
||||
|
||||
return blocks, not_found
|
||||
|
||||
def strip_initial_indent(lines):
|
||||
"""For %load, strip indent from lines until finding an unindented line.
|
||||
|
||||
https://github.com/ipython/ipython/issues/9775
|
||||
"""
|
||||
indent_re = re.compile(r'\s+')
|
||||
|
||||
it = iter(lines)
|
||||
first_line = next(it)
|
||||
indent_match = indent_re.match(first_line)
|
||||
|
||||
if indent_match:
|
||||
# First line was indented
|
||||
indent = indent_match.group()
|
||||
yield first_line[len(indent):]
|
||||
|
||||
for line in it:
|
||||
if line.startswith(indent):
|
||||
yield line[len(indent):]
|
||||
else:
|
||||
# Less indented than the first line - stop dedenting
|
||||
yield line
|
||||
break
|
||||
else:
|
||||
yield first_line
|
||||
|
||||
# Pass the remaining lines through without dedenting
|
||||
for line in it:
|
||||
yield line
|
||||
|
||||
|
||||
class InteractivelyDefined(Exception):
|
||||
"""Exception for interactively defined variable in magic_edit"""
|
||||
def __init__(self, index):
|
||||
self.index = index
|
||||
|
||||
|
||||
@magics_class
|
||||
class CodeMagics(Magics):
|
||||
"""Magics related to code management (loading, saving, editing, ...)."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._knowntemps = set()
|
||||
super(CodeMagics, self).__init__(*args, **kwargs)
|
||||
|
||||
@line_magic
|
||||
def save(self, parameter_s=''):
|
||||
"""Save a set of lines or a macro to a given filename.
|
||||
|
||||
Usage:\\
|
||||
%save [options] filename [history]
|
||||
|
||||
Options:
|
||||
|
||||
-r: use 'raw' input. By default, the 'processed' history is used,
|
||||
so that magics are loaded in their transformed version to valid
|
||||
Python. If this option is given, the raw input as typed as the
|
||||
command line is used instead.
|
||||
|
||||
-f: force overwrite. If file exists, %save will prompt for overwrite
|
||||
unless -f is given.
|
||||
|
||||
-a: append to the file instead of overwriting it.
|
||||
|
||||
The history argument uses the same syntax as %history for input ranges,
|
||||
then saves the lines to the filename you specify.
|
||||
|
||||
If no ranges are specified, saves history of the current session up to
|
||||
this point.
|
||||
|
||||
It adds a '.py' extension to the file if you don't do so yourself, and
|
||||
it asks for confirmation before overwriting existing files.
|
||||
|
||||
If `-r` option is used, the default extension is `.ipy`.
|
||||
"""
|
||||
|
||||
opts,args = self.parse_options(parameter_s,'fra',mode='list')
|
||||
if not args:
|
||||
raise UsageError('Missing filename.')
|
||||
raw = 'r' in opts
|
||||
force = 'f' in opts
|
||||
append = 'a' in opts
|
||||
mode = 'a' if append else 'w'
|
||||
ext = '.ipy' if raw else '.py'
|
||||
fname, codefrom = args[0], " ".join(args[1:])
|
||||
if not fname.endswith(('.py','.ipy')):
|
||||
fname += ext
|
||||
fname = os.path.expanduser(fname)
|
||||
file_exists = os.path.isfile(fname)
|
||||
if file_exists and not force and not append:
|
||||
try:
|
||||
overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
|
||||
except StdinNotImplementedError:
|
||||
print("File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s))
|
||||
return
|
||||
if not overwrite :
|
||||
print('Operation cancelled.')
|
||||
return
|
||||
try:
|
||||
cmds = self.shell.find_user_code(codefrom,raw)
|
||||
except (TypeError, ValueError) as e:
|
||||
print(e.args[0])
|
||||
return
|
||||
with io.open(fname, mode, encoding="utf-8") as f:
|
||||
if not file_exists or not append:
|
||||
f.write("# coding: utf-8\n")
|
||||
f.write(cmds)
|
||||
# make sure we end on a newline
|
||||
if not cmds.endswith('\n'):
|
||||
f.write('\n')
|
||||
print('The following commands were written to file `%s`:' % fname)
|
||||
print(cmds)
|
||||
|
||||
@line_magic
|
||||
def pastebin(self, parameter_s=''):
|
||||
"""Upload code to dpaste.com, returning the URL.
|
||||
|
||||
Usage:\\
|
||||
%pastebin [-d "Custom description"][-e 24] 1-7
|
||||
|
||||
The argument can be an input history range, a filename, or the name of a
|
||||
string or macro.
|
||||
|
||||
If no arguments are given, uploads the history of this session up to
|
||||
this point.
|
||||
|
||||
Options:
|
||||
|
||||
-d: Pass a custom description. The default will say
|
||||
"Pasted from IPython".
|
||||
-e: Pass number of days for the link to be expired.
|
||||
The default will be 7 days.
|
||||
"""
|
||||
opts, args = self.parse_options(parameter_s, "d:e:")
|
||||
|
||||
try:
|
||||
code = self.shell.find_user_code(args)
|
||||
except (ValueError, TypeError) as e:
|
||||
print(e.args[0])
|
||||
return
|
||||
|
||||
expiry_days = 7
|
||||
try:
|
||||
expiry_days = int(opts.get("e", 7))
|
||||
except ValueError as e:
|
||||
print(e.args[0].capitalize())
|
||||
return
|
||||
if expiry_days < 1 or expiry_days > 365:
|
||||
print("Expiry days should be in range of 1 to 365")
|
||||
return
|
||||
|
||||
post_data = urlencode(
|
||||
{
|
||||
"title": opts.get("d", "Pasted from IPython"),
|
||||
"syntax": "python",
|
||||
"content": code,
|
||||
"expiry_days": expiry_days,
|
||||
}
|
||||
).encode("utf-8")
|
||||
|
||||
request = Request(
|
||||
"https://dpaste.com/api/v2/",
|
||||
headers={"User-Agent": "IPython v{}".format(version)},
|
||||
)
|
||||
response = urlopen(request, post_data)
|
||||
return response.headers.get('Location')
|
||||
|
||||
@line_magic
|
||||
def loadpy(self, arg_s):
|
||||
"""Alias of `%load`
|
||||
|
||||
`%loadpy` has gained some flexibility and dropped the requirement of a `.py`
|
||||
extension. So it has been renamed simply into %load. You can look at
|
||||
`%load`'s docstring for more info.
|
||||
"""
|
||||
self.load(arg_s)
|
||||
|
||||
@line_magic
|
||||
def load(self, arg_s):
|
||||
"""Load code into the current frontend.
|
||||
|
||||
Usage:\\
|
||||
%load [options] source
|
||||
|
||||
where source can be a filename, URL, input history range, macro, or
|
||||
element in the user namespace
|
||||
|
||||
If no arguments are given, loads the history of this session up to this
|
||||
point.
|
||||
|
||||
Options:
|
||||
|
||||
-r <lines>: Specify lines or ranges of lines to load from the source.
|
||||
Ranges could be specified as x-y (x..y) or in python-style x:y
|
||||
(x..(y-1)). Both limits x and y can be left blank (meaning the
|
||||
beginning and end of the file, respectively).
|
||||
|
||||
-s <symbols>: Specify function or classes to load from python source.
|
||||
|
||||
-y : Don't ask confirmation for loading source above 200 000 characters.
|
||||
|
||||
-n : Include the user's namespace when searching for source code.
|
||||
|
||||
This magic command can either take a local filename, a URL, an history
|
||||
range (see %history) or a macro as argument, it will prompt for
|
||||
confirmation before loading source with more than 200 000 characters, unless
|
||||
-y flag is passed or if the frontend does not support raw_input::
|
||||
|
||||
%load
|
||||
%load myscript.py
|
||||
%load 7-27
|
||||
%load myMacro
|
||||
%load http://www.example.com/myscript.py
|
||||
%load -r 5-10 myscript.py
|
||||
%load -r 10-20,30,40: foo.py
|
||||
%load -s MyClass,wonder_function myscript.py
|
||||
%load -n MyClass
|
||||
%load -n my_module.wonder_function
|
||||
"""
|
||||
opts,args = self.parse_options(arg_s,'yns:r:')
|
||||
search_ns = 'n' in opts
|
||||
contents = self.shell.find_user_code(args, search_ns=search_ns)
|
||||
|
||||
if 's' in opts:
|
||||
try:
|
||||
blocks, not_found = extract_symbols(contents, opts['s'])
|
||||
except SyntaxError:
|
||||
# non python code
|
||||
error("Unable to parse the input as valid Python code")
|
||||
return
|
||||
|
||||
if len(not_found) == 1:
|
||||
warn('The symbol `%s` was not found' % not_found[0])
|
||||
elif len(not_found) > 1:
|
||||
warn('The symbols %s were not found' % get_text_list(not_found,
|
||||
wrap_item_with='`')
|
||||
)
|
||||
|
||||
contents = '\n'.join(blocks)
|
||||
|
||||
if 'r' in opts:
|
||||
ranges = opts['r'].replace(',', ' ')
|
||||
lines = contents.split('\n')
|
||||
slices = extract_code_ranges(ranges)
|
||||
contents = [lines[slice(*slc)] for slc in slices]
|
||||
contents = '\n'.join(strip_initial_indent(chain.from_iterable(contents)))
|
||||
|
||||
l = len(contents)
|
||||
|
||||
# 200 000 is ~ 2500 full 80 character lines
|
||||
# so in average, more than 5000 lines
|
||||
if l > 200000 and 'y' not in opts:
|
||||
try:
|
||||
ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
|
||||
" (%d characters). Continue (y/[N]) ?" % l), default='n' )
|
||||
except StdinNotImplementedError:
|
||||
#assume yes if raw input not implemented
|
||||
ans = True
|
||||
|
||||
if ans is False :
|
||||
print('Operation cancelled.')
|
||||
return
|
||||
|
||||
contents = "# %load {}\n".format(arg_s) + contents
|
||||
|
||||
self.shell.set_next_input(contents, replace=True)
|
||||
|
||||
@staticmethod
|
||||
def _find_edit_target(shell, args, opts, last_call):
|
||||
"""Utility method used by magic_edit to find what to edit."""
|
||||
|
||||
def make_filename(arg):
|
||||
"Make a filename from the given args"
|
||||
try:
|
||||
filename = get_py_filename(arg)
|
||||
except IOError:
|
||||
# If it ends with .py but doesn't already exist, assume we want
|
||||
# a new file.
|
||||
if arg.endswith('.py'):
|
||||
filename = arg
|
||||
else:
|
||||
filename = None
|
||||
return filename
|
||||
|
||||
# Set a few locals from the options for convenience:
|
||||
opts_prev = 'p' in opts
|
||||
opts_raw = 'r' in opts
|
||||
|
||||
# custom exceptions
|
||||
class DataIsObject(Exception): pass
|
||||
|
||||
# Default line number value
|
||||
lineno = opts.get('n',None)
|
||||
|
||||
if opts_prev:
|
||||
args = '_%s' % last_call[0]
|
||||
if args not in shell.user_ns:
|
||||
args = last_call[1]
|
||||
|
||||
# by default this is done with temp files, except when the given
|
||||
# arg is a filename
|
||||
use_temp = True
|
||||
|
||||
data = ''
|
||||
|
||||
# First, see if the arguments should be a filename.
|
||||
filename = make_filename(args)
|
||||
if filename:
|
||||
use_temp = False
|
||||
elif args:
|
||||
# Mode where user specifies ranges of lines, like in %macro.
|
||||
data = shell.extract_input_lines(args, opts_raw)
|
||||
if not data:
|
||||
try:
|
||||
# Load the parameter given as a variable. If not a string,
|
||||
# process it as an object instead (below)
|
||||
|
||||
#print '*** args',args,'type',type(args) # dbg
|
||||
data = eval(args, shell.user_ns)
|
||||
if not isinstance(data, str):
|
||||
raise DataIsObject
|
||||
|
||||
except (NameError,SyntaxError):
|
||||
# given argument is not a variable, try as a filename
|
||||
filename = make_filename(args)
|
||||
if filename is None:
|
||||
warn("Argument given (%s) can't be found as a variable "
|
||||
"or as a filename." % args)
|
||||
return (None, None, None)
|
||||
use_temp = False
|
||||
|
||||
except DataIsObject as e:
|
||||
# macros have a special edit function
|
||||
if isinstance(data, Macro):
|
||||
raise MacroToEdit(data) from e
|
||||
|
||||
# For objects, try to edit the file where they are defined
|
||||
filename = find_file(data)
|
||||
if filename:
|
||||
if 'fakemodule' in filename.lower() and \
|
||||
inspect.isclass(data):
|
||||
# class created by %edit? Try to find source
|
||||
# by looking for method definitions instead, the
|
||||
# __module__ in those classes is FakeModule.
|
||||
attrs = [getattr(data, aname) for aname in dir(data)]
|
||||
for attr in attrs:
|
||||
if not inspect.ismethod(attr):
|
||||
continue
|
||||
filename = find_file(attr)
|
||||
if filename and \
|
||||
'fakemodule' not in filename.lower():
|
||||
# change the attribute to be the edit
|
||||
# target instead
|
||||
data = attr
|
||||
break
|
||||
|
||||
m = ipython_input_pat.match(os.path.basename(filename))
|
||||
if m:
|
||||
raise InteractivelyDefined(int(m.groups()[0])) from e
|
||||
|
||||
datafile = 1
|
||||
if filename is None:
|
||||
filename = make_filename(args)
|
||||
datafile = 1
|
||||
if filename is not None:
|
||||
# only warn about this if we get a real name
|
||||
warn('Could not find file where `%s` is defined.\n'
|
||||
'Opening a file named `%s`' % (args, filename))
|
||||
# Now, make sure we can actually read the source (if it was
|
||||
# in a temp file it's gone by now).
|
||||
if datafile:
|
||||
if lineno is None:
|
||||
lineno = find_source_lines(data)
|
||||
if lineno is None:
|
||||
filename = make_filename(args)
|
||||
if filename is None:
|
||||
warn('The file where `%s` was defined '
|
||||
'cannot be read or found.' % data)
|
||||
return (None, None, None)
|
||||
use_temp = False
|
||||
|
||||
if use_temp:
|
||||
filename = shell.mktempfile(data)
|
||||
print('IPython will make a temporary file named:',filename)
|
||||
|
||||
# use last_call to remember the state of the previous call, but don't
|
||||
# let it be clobbered by successive '-p' calls.
|
||||
try:
|
||||
last_call[0] = shell.displayhook.prompt_count
|
||||
if not opts_prev:
|
||||
last_call[1] = args
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
return filename, lineno, use_temp
|
||||
|
||||
def _edit_macro(self,mname,macro):
|
||||
"""open an editor with the macro data in a file"""
|
||||
filename = self.shell.mktempfile(macro.value)
|
||||
self.shell.hooks.editor(filename)
|
||||
|
||||
# and make a new macro object, to replace the old one
|
||||
mvalue = Path(filename).read_text(encoding="utf-8")
|
||||
self.shell.user_ns[mname] = Macro(mvalue)
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
def edit(self, parameter_s='',last_call=['','']):
|
||||
"""Bring up an editor and execute the resulting code.
|
||||
|
||||
Usage:
|
||||
%edit [options] [args]
|
||||
|
||||
%edit runs IPython's editor hook. The default version of this hook is
|
||||
set to call the editor specified by your $EDITOR environment variable.
|
||||
If this isn't found, it will default to vi under Linux/Unix and to
|
||||
notepad under Windows. See the end of this docstring for how to change
|
||||
the editor hook.
|
||||
|
||||
You can also set the value of this editor via the
|
||||
``TerminalInteractiveShell.editor`` option in your configuration file.
|
||||
This is useful if you wish to use a different editor from your typical
|
||||
default with IPython (and for Windows users who typically don't set
|
||||
environment variables).
|
||||
|
||||
This command allows you to conveniently edit multi-line code right in
|
||||
your IPython session.
|
||||
|
||||
If called without arguments, %edit opens up an empty editor with a
|
||||
temporary file and will execute the contents of this file when you
|
||||
close it (don't forget to save it!).
|
||||
|
||||
|
||||
Options:
|
||||
|
||||
-n <number>: open the editor at a specified line number. By default,
|
||||
the IPython editor hook uses the unix syntax 'editor +N filename', but
|
||||
you can configure this by providing your own modified hook if your
|
||||
favorite editor supports line-number specifications with a different
|
||||
syntax.
|
||||
|
||||
-p: this will call the editor with the same data as the previous time
|
||||
it was used, regardless of how long ago (in your current session) it
|
||||
was.
|
||||
|
||||
-r: use 'raw' input. This option only applies to input taken from the
|
||||
user's history. By default, the 'processed' history is used, so that
|
||||
magics are loaded in their transformed version to valid Python. If
|
||||
this option is given, the raw input as typed as the command line is
|
||||
used instead. When you exit the editor, it will be executed by
|
||||
IPython's own processor.
|
||||
|
||||
-x: do not execute the edited code immediately upon exit. This is
|
||||
mainly useful if you are editing programs which need to be called with
|
||||
command line arguments, which you can then do using %run.
|
||||
|
||||
|
||||
Arguments:
|
||||
|
||||
If arguments are given, the following possibilities exist:
|
||||
|
||||
- If the argument is a filename, IPython will load that into the
|
||||
editor. It will execute its contents with execfile() when you exit,
|
||||
loading any code in the file into your interactive namespace.
|
||||
|
||||
- The arguments are ranges of input history, e.g. "7 ~1/4-6".
|
||||
The syntax is the same as in the %history magic.
|
||||
|
||||
- If the argument is a string variable, its contents are loaded
|
||||
into the editor. You can thus edit any string which contains
|
||||
python code (including the result of previous edits).
|
||||
|
||||
- If the argument is the name of an object (other than a string),
|
||||
IPython will try to locate the file where it was defined and open the
|
||||
editor at the point where it is defined. You can use `%edit function`
|
||||
to load an editor exactly at the point where 'function' is defined,
|
||||
edit it and have the file be executed automatically.
|
||||
|
||||
- If the object is a macro (see %macro for details), this opens up your
|
||||
specified editor with a temporary file containing the macro's data.
|
||||
Upon exit, the macro is reloaded with the contents of the file.
|
||||
|
||||
Note: opening at an exact line is only supported under Unix, and some
|
||||
editors (like kedit and gedit up to Gnome 2.8) do not understand the
|
||||
'+NUMBER' parameter necessary for this feature. Good editors like
|
||||
(X)Emacs, vi, jed, pico and joe all do.
|
||||
|
||||
After executing your code, %edit will return as output the code you
|
||||
typed in the editor (except when it was an existing file). This way
|
||||
you can reload the code in further invocations of %edit as a variable,
|
||||
via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
|
||||
the output.
|
||||
|
||||
Note that %edit is also available through the alias %ed.
|
||||
|
||||
This is an example of creating a simple function inside the editor and
|
||||
then modifying it. First, start up the editor::
|
||||
|
||||
In [1]: edit
|
||||
Editing... done. Executing edited code...
|
||||
Out[1]: 'def foo():\\n print "foo() was defined in an editing
|
||||
session"\\n'
|
||||
|
||||
We can then call the function foo()::
|
||||
|
||||
In [2]: foo()
|
||||
foo() was defined in an editing session
|
||||
|
||||
Now we edit foo. IPython automatically loads the editor with the
|
||||
(temporary) file where foo() was previously defined::
|
||||
|
||||
In [3]: edit foo
|
||||
Editing... done. Executing edited code...
|
||||
|
||||
And if we call foo() again we get the modified version::
|
||||
|
||||
In [4]: foo()
|
||||
foo() has now been changed!
|
||||
|
||||
Here is an example of how to edit a code snippet successive
|
||||
times. First we call the editor::
|
||||
|
||||
In [5]: edit
|
||||
Editing... done. Executing edited code...
|
||||
hello
|
||||
Out[5]: "print 'hello'\\n"
|
||||
|
||||
Now we call it again with the previous output (stored in _)::
|
||||
|
||||
In [6]: edit _
|
||||
Editing... done. Executing edited code...
|
||||
hello world
|
||||
Out[6]: "print 'hello world'\\n"
|
||||
|
||||
Now we call it with the output #8 (stored in _8, also as Out[8])::
|
||||
|
||||
In [7]: edit _8
|
||||
Editing... done. Executing edited code...
|
||||
hello again
|
||||
Out[7]: "print 'hello again'\\n"
|
||||
|
||||
|
||||
Changing the default editor hook:
|
||||
|
||||
If you wish to write your own editor hook, you can put it in a
|
||||
configuration file which you load at startup time. The default hook
|
||||
is defined in the IPython.core.hooks module, and you can use that as a
|
||||
starting example for further modifications. That file also has
|
||||
general instructions on how to set a new hook for use once you've
|
||||
defined it."""
|
||||
opts,args = self.parse_options(parameter_s,'prxn:')
|
||||
|
||||
try:
|
||||
filename, lineno, is_temp = self._find_edit_target(self.shell,
|
||||
args, opts, last_call)
|
||||
except MacroToEdit as e:
|
||||
self._edit_macro(args, e.args[0])
|
||||
return
|
||||
except InteractivelyDefined as e:
|
||||
print("Editing In[%i]" % e.index)
|
||||
args = str(e.index)
|
||||
filename, lineno, is_temp = self._find_edit_target(self.shell,
|
||||
args, opts, last_call)
|
||||
if filename is None:
|
||||
# nothing was found, warnings have already been issued,
|
||||
# just give up.
|
||||
return
|
||||
|
||||
if is_temp:
|
||||
self._knowntemps.add(filename)
|
||||
elif (filename in self._knowntemps):
|
||||
is_temp = True
|
||||
|
||||
|
||||
# do actual editing here
|
||||
print('Editing...', end=' ')
|
||||
sys.stdout.flush()
|
||||
filepath = Path(filename)
|
||||
try:
|
||||
# Quote filenames that may have spaces in them when opening
|
||||
# the editor
|
||||
quoted = filename = str(filepath.absolute())
|
||||
if " " in quoted:
|
||||
quoted = "'%s'" % quoted
|
||||
self.shell.hooks.editor(quoted, lineno)
|
||||
except TryNext:
|
||||
warn('Could not open editor')
|
||||
return
|
||||
|
||||
# XXX TODO: should this be generalized for all string vars?
|
||||
# For now, this is special-cased to blocks created by cpaste
|
||||
if args.strip() == "pasted_block":
|
||||
self.shell.user_ns["pasted_block"] = filepath.read_text(encoding="utf-8")
|
||||
|
||||
if 'x' in opts: # -x prevents actual execution
|
||||
print()
|
||||
else:
|
||||
print('done. Executing edited code...')
|
||||
with preserve_keys(self.shell.user_ns, '__file__'):
|
||||
if not is_temp:
|
||||
self.shell.user_ns["__file__"] = filename
|
||||
if "r" in opts: # Untranslated IPython code
|
||||
source = filepath.read_text(encoding="utf-8")
|
||||
self.shell.run_cell(source, store_history=False)
|
||||
else:
|
||||
self.shell.safe_execfile(filename, self.shell.user_ns,
|
||||
self.shell.user_ns)
|
||||
|
||||
if is_temp:
|
||||
try:
|
||||
return filepath.read_text(encoding="utf-8")
|
||||
except IOError as msg:
|
||||
if Path(msg.filename) == filepath:
|
||||
warn('File not found. Did you forget to save?')
|
||||
return
|
||||
else:
|
||||
self.shell.showtraceback()
|
187
.venv/Lib/site-packages/IPython/core/magics/config.py
Normal file
187
.venv/Lib/site-packages/IPython/core/magics/config.py
Normal file
@ -0,0 +1,187 @@
|
||||
"""Implementation of configuration-related magic functions.
|
||||
"""
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (c) 2012 The IPython Development Team.
|
||||
#
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
#
|
||||
# The full license is in the file COPYING.txt, distributed with this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Stdlib
|
||||
import re
|
||||
|
||||
# Our own packages
|
||||
from IPython.core.error import UsageError
|
||||
from IPython.core.magic import Magics, magics_class, line_magic
|
||||
from logging import error
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Magic implementation classes
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
reg = re.compile(r'^\w+\.\w+$')
|
||||
@magics_class
|
||||
class ConfigMagics(Magics):
|
||||
|
||||
def __init__(self, shell):
|
||||
super(ConfigMagics, self).__init__(shell)
|
||||
self.configurables = []
|
||||
|
||||
@line_magic
|
||||
def config(self, s):
|
||||
"""configure IPython
|
||||
|
||||
%config Class[.trait=value]
|
||||
|
||||
This magic exposes most of the IPython config system. Any
|
||||
Configurable class should be able to be configured with the simple
|
||||
line::
|
||||
|
||||
%config Class.trait=value
|
||||
|
||||
Where `value` will be resolved in the user's namespace, if it is an
|
||||
expression or variable name.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
To see what classes are available for config, pass no arguments::
|
||||
|
||||
In [1]: %config
|
||||
Available objects for config:
|
||||
AliasManager
|
||||
DisplayFormatter
|
||||
HistoryManager
|
||||
IPCompleter
|
||||
LoggingMagics
|
||||
MagicsManager
|
||||
OSMagics
|
||||
PrefilterManager
|
||||
ScriptMagics
|
||||
TerminalInteractiveShell
|
||||
|
||||
To view what is configurable on a given class, just pass the class
|
||||
name::
|
||||
|
||||
In [2]: %config IPCompleter
|
||||
IPCompleter(Completer) options
|
||||
----------------------------
|
||||
IPCompleter.backslash_combining_completions=<Bool>
|
||||
Enable unicode completions, e.g. \\alpha<tab> . Includes completion of latex
|
||||
commands, unicode names, and expanding unicode characters back to latex
|
||||
commands.
|
||||
Current: True
|
||||
IPCompleter.debug=<Bool>
|
||||
Enable debug for the Completer. Mostly print extra information for
|
||||
experimental jedi integration.
|
||||
Current: False
|
||||
IPCompleter.greedy=<Bool>
|
||||
Activate greedy completion
|
||||
PENDING DEPRECATION. this is now mostly taken care of with Jedi.
|
||||
This will enable completion on elements of lists, results of function calls, etc.,
|
||||
but can be unsafe because the code is actually evaluated on TAB.
|
||||
Current: False
|
||||
IPCompleter.jedi_compute_type_timeout=<Int>
|
||||
Experimental: restrict time (in milliseconds) during which Jedi can compute types.
|
||||
Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt
|
||||
performance by preventing jedi to build its cache.
|
||||
Current: 400
|
||||
IPCompleter.limit_to__all__=<Bool>
|
||||
DEPRECATED as of version 5.0.
|
||||
Instruct the completer to use __all__ for the completion
|
||||
Specifically, when completing on ``object.<tab>``.
|
||||
When True: only those names in obj.__all__ will be included.
|
||||
When False [default]: the __all__ attribute is ignored
|
||||
Current: False
|
||||
IPCompleter.merge_completions=<Bool>
|
||||
Whether to merge completion results into a single list
|
||||
If False, only the completion results from the first non-empty
|
||||
completer will be returned.
|
||||
Current: True
|
||||
IPCompleter.omit__names=<Enum>
|
||||
Instruct the completer to omit private method names
|
||||
Specifically, when completing on ``object.<tab>``.
|
||||
When 2 [default]: all names that start with '_' will be excluded.
|
||||
When 1: all 'magic' names (``__foo__``) will be excluded.
|
||||
When 0: nothing will be excluded.
|
||||
Choices: any of [0, 1, 2]
|
||||
Current: 2
|
||||
IPCompleter.profile_completions=<Bool>
|
||||
If True, emit profiling data for completion subsystem using cProfile.
|
||||
Current: False
|
||||
IPCompleter.profiler_output_dir=<Unicode>
|
||||
Template for path at which to output profile data for completions.
|
||||
Current: '.completion_profiles'
|
||||
IPCompleter.use_jedi=<Bool>
|
||||
Experimental: Use Jedi to generate autocompletions. Default to True if jedi
|
||||
is installed.
|
||||
Current: True
|
||||
|
||||
but the real use is in setting values::
|
||||
|
||||
In [3]: %config IPCompleter.greedy = True
|
||||
|
||||
and these values are read from the user_ns if they are variables::
|
||||
|
||||
In [4]: feeling_greedy=False
|
||||
|
||||
In [5]: %config IPCompleter.greedy = feeling_greedy
|
||||
|
||||
"""
|
||||
from traitlets.config.loader import Config
|
||||
# some IPython objects are Configurable, but do not yet have
|
||||
# any configurable traits. Exclude them from the effects of
|
||||
# this magic, as their presence is just noise:
|
||||
configurables = sorted(set([ c for c in self.shell.configurables
|
||||
if c.__class__.class_traits(config=True)
|
||||
]), key=lambda x: x.__class__.__name__)
|
||||
classnames = [ c.__class__.__name__ for c in configurables ]
|
||||
|
||||
line = s.strip()
|
||||
if not line:
|
||||
# print available configurable names
|
||||
print("Available objects for config:")
|
||||
for name in classnames:
|
||||
print(" ", name)
|
||||
return
|
||||
elif line in classnames:
|
||||
# `%config TerminalInteractiveShell` will print trait info for
|
||||
# TerminalInteractiveShell
|
||||
c = configurables[classnames.index(line)]
|
||||
cls = c.__class__
|
||||
help = cls.class_get_help(c)
|
||||
# strip leading '--' from cl-args:
|
||||
help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
|
||||
print(help)
|
||||
return
|
||||
elif reg.match(line):
|
||||
cls, attr = line.split('.')
|
||||
return getattr(configurables[classnames.index(cls)],attr)
|
||||
elif '=' not in line:
|
||||
msg = "Invalid config statement: %r, "\
|
||||
"should be `Class.trait = value`."
|
||||
|
||||
ll = line.lower()
|
||||
for classname in classnames:
|
||||
if ll == classname.lower():
|
||||
msg = msg + '\nDid you mean %s (note the case)?' % classname
|
||||
break
|
||||
|
||||
raise UsageError( msg % line)
|
||||
|
||||
# otherwise, assume we are setting configurables.
|
||||
# leave quotes on args when splitting, because we want
|
||||
# unquoted args to eval in user_ns
|
||||
cfg = Config()
|
||||
exec("cfg."+line, self.shell.user_ns, locals())
|
||||
|
||||
for configurable in configurables:
|
||||
try:
|
||||
configurable.update_config(cfg)
|
||||
except Exception as e:
|
||||
error(e)
|
93
.venv/Lib/site-packages/IPython/core/magics/display.py
Normal file
93
.venv/Lib/site-packages/IPython/core/magics/display.py
Normal file
@ -0,0 +1,93 @@
|
||||
"""Simple magics for display formats"""
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (c) 2012 The IPython Development Team.
|
||||
#
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
#
|
||||
# The full license is in the file COPYING.txt, distributed with this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Our own packages
|
||||
from IPython.display import display, Javascript, Latex, SVG, HTML, Markdown
|
||||
from IPython.core.magic import (
|
||||
Magics, magics_class, cell_magic
|
||||
)
|
||||
from IPython.core import magic_arguments
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Magic implementation classes
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
@magics_class
|
||||
class DisplayMagics(Magics):
|
||||
"""Magics for displaying various output types with literals
|
||||
|
||||
Defines javascript/latex/svg/html cell magics for writing
|
||||
blocks in those languages, to be rendered in the frontend.
|
||||
"""
|
||||
|
||||
@cell_magic
|
||||
def js(self, line, cell):
|
||||
"""Run the cell block of Javascript code
|
||||
|
||||
Alias of `%%javascript`
|
||||
|
||||
Starting with IPython 8.0 %%javascript is pending deprecation to be replaced
|
||||
by a more flexible system
|
||||
|
||||
Please See https://github.com/ipython/ipython/issues/13376
|
||||
"""
|
||||
self.javascript(line, cell)
|
||||
|
||||
@cell_magic
|
||||
def javascript(self, line, cell):
|
||||
"""Run the cell block of Javascript code
|
||||
|
||||
Starting with IPython 8.0 %%javascript is pending deprecation to be replaced
|
||||
by a more flexible system
|
||||
|
||||
Please See https://github.com/ipython/ipython/issues/13376
|
||||
"""
|
||||
display(Javascript(cell))
|
||||
|
||||
|
||||
@cell_magic
|
||||
def latex(self, line, cell):
|
||||
"""Render the cell as a block of LaTeX
|
||||
|
||||
The subset of LaTeX which is supported depends on the implementation in
|
||||
the client. In the Jupyter Notebook, this magic only renders the subset
|
||||
of LaTeX defined by MathJax
|
||||
[here](https://docs.mathjax.org/en/v2.5-latest/tex.html)."""
|
||||
display(Latex(cell))
|
||||
|
||||
@cell_magic
|
||||
def svg(self, line, cell):
|
||||
"""Render the cell as an SVG literal"""
|
||||
display(SVG(cell))
|
||||
|
||||
@magic_arguments.magic_arguments()
|
||||
@magic_arguments.argument(
|
||||
'--isolated', action='store_true', default=False,
|
||||
help="""Annotate the cell as 'isolated'.
|
||||
Isolated cells are rendered inside their own <iframe> tag"""
|
||||
)
|
||||
@cell_magic
|
||||
def html(self, line, cell):
|
||||
"""Render the cell as a block of HTML"""
|
||||
args = magic_arguments.parse_argstring(self.html, line)
|
||||
html = HTML(cell)
|
||||
if args.isolated:
|
||||
display(html, metadata={'text/html':{'isolated':True}})
|
||||
else:
|
||||
display(html)
|
||||
|
||||
@cell_magic
|
||||
def markdown(self, line, cell):
|
||||
"""Render the cell as Markdown text block"""
|
||||
display(Markdown(cell))
|
1510
.venv/Lib/site-packages/IPython/core/magics/execution.py
Normal file
1510
.venv/Lib/site-packages/IPython/core/magics/execution.py
Normal file
File diff suppressed because it is too large
Load Diff
63
.venv/Lib/site-packages/IPython/core/magics/extension.py
Normal file
63
.venv/Lib/site-packages/IPython/core/magics/extension.py
Normal file
@ -0,0 +1,63 @@
|
||||
"""Implementation of magic functions for the extension machinery.
|
||||
"""
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (c) 2012 The IPython Development Team.
|
||||
#
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
#
|
||||
# The full license is in the file COPYING.txt, distributed with this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Our own packages
|
||||
from IPython.core.error import UsageError
|
||||
from IPython.core.magic import Magics, magics_class, line_magic
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Magic implementation classes
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@magics_class
|
||||
class ExtensionMagics(Magics):
|
||||
"""Magics to manage the IPython extensions system."""
|
||||
|
||||
@line_magic
|
||||
def load_ext(self, module_str):
|
||||
"""Load an IPython extension by its module name."""
|
||||
if not module_str:
|
||||
raise UsageError('Missing module name.')
|
||||
res = self.shell.extension_manager.load_extension(module_str)
|
||||
|
||||
if res == 'already loaded':
|
||||
print("The %s extension is already loaded. To reload it, use:" % module_str)
|
||||
print(" %reload_ext", module_str)
|
||||
elif res == 'no load function':
|
||||
print("The %s module is not an IPython extension." % module_str)
|
||||
|
||||
@line_magic
|
||||
def unload_ext(self, module_str):
|
||||
"""Unload an IPython extension by its module name.
|
||||
|
||||
Not all extensions can be unloaded, only those which define an
|
||||
``unload_ipython_extension`` function.
|
||||
"""
|
||||
if not module_str:
|
||||
raise UsageError('Missing module name.')
|
||||
|
||||
res = self.shell.extension_manager.unload_extension(module_str)
|
||||
|
||||
if res == 'no unload function':
|
||||
print("The %s extension doesn't define how to unload it." % module_str)
|
||||
elif res == "not loaded":
|
||||
print("The %s extension is not loaded." % module_str)
|
||||
|
||||
@line_magic
|
||||
def reload_ext(self, module_str):
|
||||
"""Reload an IPython extension by its module name."""
|
||||
if not module_str:
|
||||
raise UsageError('Missing module name.')
|
||||
self.shell.extension_manager.reload_extension(module_str)
|
338
.venv/Lib/site-packages/IPython/core/magics/history.py
Normal file
338
.venv/Lib/site-packages/IPython/core/magics/history.py
Normal file
@ -0,0 +1,338 @@
|
||||
"""Implementation of magic functions related to History.
|
||||
"""
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (c) 2012, IPython Development Team.
|
||||
#
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
#
|
||||
# The full license is in the file COPYING.txt, distributed with this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Stdlib
|
||||
import os
|
||||
import sys
|
||||
from io import open as io_open
|
||||
import fnmatch
|
||||
|
||||
# Our own packages
|
||||
from IPython.core.error import StdinNotImplementedError
|
||||
from IPython.core.magic import Magics, magics_class, line_magic
|
||||
from IPython.core.magic_arguments import (argument, magic_arguments,
|
||||
parse_argstring)
|
||||
from IPython.testing.skipdoctest import skip_doctest
|
||||
from IPython.utils import io
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Magics class implementation
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
_unspecified = object()
|
||||
|
||||
|
||||
@magics_class
|
||||
class HistoryMagics(Magics):
|
||||
|
||||
@magic_arguments()
|
||||
@argument(
|
||||
'-n', dest='print_nums', action='store_true', default=False,
|
||||
help="""
|
||||
print line numbers for each input.
|
||||
This feature is only available if numbered prompts are in use.
|
||||
""")
|
||||
@argument(
|
||||
'-o', dest='get_output', action='store_true', default=False,
|
||||
help="also print outputs for each input.")
|
||||
@argument(
|
||||
'-p', dest='pyprompts', action='store_true', default=False,
|
||||
help="""
|
||||
print classic '>>>' python prompts before each input.
|
||||
This is useful for making documentation, and in conjunction
|
||||
with -o, for producing doctest-ready output.
|
||||
""")
|
||||
@argument(
|
||||
'-t', dest='raw', action='store_false', default=True,
|
||||
help="""
|
||||
print the 'translated' history, as IPython understands it.
|
||||
IPython filters your input and converts it all into valid Python
|
||||
source before executing it (things like magics or aliases are turned
|
||||
into function calls, for example). With this option, you'll see the
|
||||
native history instead of the user-entered version: '%%cd /' will be
|
||||
seen as 'get_ipython().run_line_magic("cd", "/")' instead of '%%cd /'.
|
||||
""")
|
||||
@argument(
|
||||
'-f', dest='filename',
|
||||
help="""
|
||||
FILENAME: instead of printing the output to the screen, redirect
|
||||
it to the given file. The file is always overwritten, though *when
|
||||
it can*, IPython asks for confirmation first. In particular, running
|
||||
the command 'history -f FILENAME' from the IPython Notebook
|
||||
interface will replace FILENAME even if it already exists *without*
|
||||
confirmation.
|
||||
""")
|
||||
@argument(
|
||||
'-g', dest='pattern', nargs='*', default=None,
|
||||
help="""
|
||||
treat the arg as a glob pattern to search for in (full) history.
|
||||
This includes the saved history (almost all commands ever written).
|
||||
The pattern may contain '?' to match one unknown character and '*'
|
||||
to match any number of unknown characters. Use '%%hist -g' to show
|
||||
full saved history (may be very long).
|
||||
""")
|
||||
@argument(
|
||||
'-l', dest='limit', type=int, nargs='?', default=_unspecified,
|
||||
help="""
|
||||
get the last n lines from all sessions. Specify n as a single
|
||||
arg, or the default is the last 10 lines.
|
||||
""")
|
||||
@argument(
|
||||
'-u', dest='unique', action='store_true',
|
||||
help="""
|
||||
when searching history using `-g`, show only unique history.
|
||||
""")
|
||||
@argument('range', nargs='*')
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
def history(self, parameter_s = ''):
|
||||
"""Print input history (_i<n> variables), with most recent last.
|
||||
|
||||
By default, input history is printed without line numbers so it can be
|
||||
directly pasted into an editor. Use -n to show them.
|
||||
|
||||
By default, all input history from the current session is displayed.
|
||||
Ranges of history can be indicated using the syntax:
|
||||
|
||||
``4``
|
||||
Line 4, current session
|
||||
``4-6``
|
||||
Lines 4-6, current session
|
||||
``243/1-5``
|
||||
Lines 1-5, session 243
|
||||
``~2/7``
|
||||
Line 7, session 2 before current
|
||||
``~8/1-~6/5``
|
||||
From the first line of 8 sessions ago, to the fifth line of 6
|
||||
sessions ago.
|
||||
|
||||
Multiple ranges can be entered, separated by spaces
|
||||
|
||||
The same syntax is used by %macro, %save, %edit, %rerun
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
|
||||
In [6]: %history -n 4-6
|
||||
4:a = 12
|
||||
5:print a**2
|
||||
6:%history -n 4-6
|
||||
|
||||
"""
|
||||
|
||||
args = parse_argstring(self.history, parameter_s)
|
||||
|
||||
# For brevity
|
||||
history_manager = self.shell.history_manager
|
||||
|
||||
def _format_lineno(session, line):
|
||||
"""Helper function to format line numbers properly."""
|
||||
if session in (0, history_manager.session_number):
|
||||
return str(line)
|
||||
return "%s/%s" % (session, line)
|
||||
|
||||
# Check if output to specific file was requested.
|
||||
outfname = args.filename
|
||||
if not outfname:
|
||||
outfile = sys.stdout # default
|
||||
# We don't want to close stdout at the end!
|
||||
close_at_end = False
|
||||
else:
|
||||
outfname = os.path.expanduser(outfname)
|
||||
if os.path.exists(outfname):
|
||||
try:
|
||||
ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
|
||||
except StdinNotImplementedError:
|
||||
ans = True
|
||||
if not ans:
|
||||
print('Aborting.')
|
||||
return
|
||||
print("Overwriting file.")
|
||||
outfile = io_open(outfname, 'w', encoding='utf-8')
|
||||
close_at_end = True
|
||||
|
||||
print_nums = args.print_nums
|
||||
get_output = args.get_output
|
||||
pyprompts = args.pyprompts
|
||||
raw = args.raw
|
||||
|
||||
pattern = None
|
||||
limit = None if args.limit is _unspecified else args.limit
|
||||
|
||||
range_pattern = False
|
||||
if args.pattern is not None and not args.range:
|
||||
if args.pattern:
|
||||
pattern = "*" + " ".join(args.pattern) + "*"
|
||||
else:
|
||||
pattern = "*"
|
||||
hist = history_manager.search(pattern, raw=raw, output=get_output,
|
||||
n=limit, unique=args.unique)
|
||||
print_nums = True
|
||||
elif args.limit is not _unspecified:
|
||||
n = 10 if limit is None else limit
|
||||
hist = history_manager.get_tail(n, raw=raw, output=get_output)
|
||||
else:
|
||||
if args.pattern:
|
||||
range_pattern = "*" + " ".join(args.pattern) + "*"
|
||||
print_nums = True
|
||||
hist = history_manager.get_range_by_str(
|
||||
" ".join(args.range), raw, get_output
|
||||
)
|
||||
|
||||
# We could be displaying the entire history, so let's not try to pull
|
||||
# it into a list in memory. Anything that needs more space will just
|
||||
# misalign.
|
||||
width = 4
|
||||
|
||||
for session, lineno, inline in hist:
|
||||
# Print user history with tabs expanded to 4 spaces. The GUI
|
||||
# clients use hard tabs for easier usability in auto-indented code,
|
||||
# but we want to produce PEP-8 compliant history for safe pasting
|
||||
# into an editor.
|
||||
if get_output:
|
||||
inline, output = inline
|
||||
if range_pattern:
|
||||
if not fnmatch.fnmatch(inline, range_pattern):
|
||||
continue
|
||||
inline = inline.expandtabs(4).rstrip()
|
||||
|
||||
multiline = "\n" in inline
|
||||
line_sep = '\n' if multiline else ' '
|
||||
if print_nums:
|
||||
print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
|
||||
line_sep), file=outfile, end=u'')
|
||||
if pyprompts:
|
||||
print(u">>> ", end=u"", file=outfile)
|
||||
if multiline:
|
||||
inline = "\n... ".join(inline.splitlines()) + "\n..."
|
||||
print(inline, file=outfile)
|
||||
if get_output and output:
|
||||
print(output, file=outfile)
|
||||
|
||||
if close_at_end:
|
||||
outfile.close()
|
||||
|
||||
@line_magic
|
||||
def recall(self, arg):
|
||||
r"""Repeat a command, or get command to input line for editing.
|
||||
|
||||
%recall and %rep are equivalent.
|
||||
|
||||
- %recall (no arguments):
|
||||
|
||||
Place a string version of last computation result (stored in the
|
||||
special '_' variable) to the next input prompt. Allows you to create
|
||||
elaborate command lines without using copy-paste::
|
||||
|
||||
In[1]: l = ["hei", "vaan"]
|
||||
In[2]: "".join(l)
|
||||
Out[2]: heivaan
|
||||
In[3]: %recall
|
||||
In[4]: heivaan_ <== cursor blinking
|
||||
|
||||
%recall 45
|
||||
|
||||
Place history line 45 on the next input prompt. Use %hist to find
|
||||
out the number.
|
||||
|
||||
%recall 1-4
|
||||
|
||||
Combine the specified lines into one cell, and place it on the next
|
||||
input prompt. See %history for the slice syntax.
|
||||
|
||||
%recall foo+bar
|
||||
|
||||
If foo+bar can be evaluated in the user namespace, the result is
|
||||
placed at the next input prompt. Otherwise, the history is searched
|
||||
for lines which contain that substring, and the most recent one is
|
||||
placed at the next input prompt.
|
||||
"""
|
||||
if not arg: # Last output
|
||||
self.shell.set_next_input(str(self.shell.user_ns["_"]))
|
||||
return
|
||||
# Get history range
|
||||
histlines = self.shell.history_manager.get_range_by_str(arg)
|
||||
cmd = "\n".join(x[2] for x in histlines)
|
||||
if cmd:
|
||||
self.shell.set_next_input(cmd.rstrip())
|
||||
return
|
||||
|
||||
try: # Variable in user namespace
|
||||
cmd = str(eval(arg, self.shell.user_ns))
|
||||
except Exception: # Search for term in history
|
||||
histlines = self.shell.history_manager.search("*"+arg+"*")
|
||||
for h in reversed([x[2] for x in histlines]):
|
||||
if 'recall' in h or 'rep' in h:
|
||||
continue
|
||||
self.shell.set_next_input(h.rstrip())
|
||||
return
|
||||
else:
|
||||
self.shell.set_next_input(cmd.rstrip())
|
||||
return
|
||||
print("Couldn't evaluate or find in history:", arg)
|
||||
|
||||
@line_magic
|
||||
def rerun(self, parameter_s=''):
|
||||
"""Re-run previous input
|
||||
|
||||
By default, you can specify ranges of input history to be repeated
|
||||
(as with %history). With no arguments, it will repeat the last line.
|
||||
|
||||
Options:
|
||||
|
||||
-l <n> : Repeat the last n lines of input, not including the
|
||||
current command.
|
||||
|
||||
-g foo : Repeat the most recent line which contains foo
|
||||
"""
|
||||
opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
|
||||
if "l" in opts: # Last n lines
|
||||
try:
|
||||
n = int(opts["l"])
|
||||
except ValueError:
|
||||
print("Number of lines must be an integer")
|
||||
return
|
||||
|
||||
if n == 0:
|
||||
print("Requested 0 last lines - nothing to run")
|
||||
return
|
||||
elif n < 0:
|
||||
print("Number of lines to rerun cannot be negative")
|
||||
return
|
||||
|
||||
hist = self.shell.history_manager.get_tail(n)
|
||||
elif "g" in opts: # Search
|
||||
p = "*"+opts['g']+"*"
|
||||
hist = list(self.shell.history_manager.search(p))
|
||||
for l in reversed(hist):
|
||||
if "rerun" not in l[2]:
|
||||
hist = [l] # The last match which isn't a %rerun
|
||||
break
|
||||
else:
|
||||
hist = [] # No matches except %rerun
|
||||
elif args: # Specify history ranges
|
||||
hist = self.shell.history_manager.get_range_by_str(args)
|
||||
else: # Last line
|
||||
hist = self.shell.history_manager.get_tail(1)
|
||||
hist = [x[2] for x in hist]
|
||||
if not hist:
|
||||
print("No lines in history match specification")
|
||||
return
|
||||
histlines = "\n".join(hist)
|
||||
print("=== Executing: ===")
|
||||
print(histlines)
|
||||
print("=== Output: ===")
|
||||
self.shell.run_cell("\n".join(hist), store_history=False)
|
195
.venv/Lib/site-packages/IPython/core/magics/logging.py
Normal file
195
.venv/Lib/site-packages/IPython/core/magics/logging.py
Normal file
@ -0,0 +1,195 @@
|
||||
"""Implementation of magic functions for IPython's own logging.
|
||||
"""
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (c) 2012 The IPython Development Team.
|
||||
#
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
#
|
||||
# The full license is in the file COPYING.txt, distributed with this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Stdlib
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Our own packages
|
||||
from IPython.core.magic import Magics, magics_class, line_magic
|
||||
from warnings import warn
|
||||
from traitlets import Bool
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Magic implementation classes
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@magics_class
|
||||
class LoggingMagics(Magics):
|
||||
"""Magics related to all logging machinery."""
|
||||
|
||||
quiet = Bool(False, help=
|
||||
"""
|
||||
Suppress output of log state when logging is enabled
|
||||
"""
|
||||
).tag(config=True)
|
||||
|
||||
@line_magic
|
||||
def logstart(self, parameter_s=''):
|
||||
"""Start logging anywhere in a session.
|
||||
|
||||
%logstart [-o|-r|-t|-q] [log_name [log_mode]]
|
||||
|
||||
If no name is given, it defaults to a file named 'ipython_log.py' in your
|
||||
current directory, in 'rotate' mode (see below).
|
||||
|
||||
'%logstart name' saves to file 'name' in 'backup' mode. It saves your
|
||||
history up to that point and then continues logging.
|
||||
|
||||
%logstart takes a second optional parameter: logging mode. This can be one
|
||||
of (note that the modes are given unquoted):
|
||||
|
||||
append
|
||||
Keep logging at the end of any existing file.
|
||||
|
||||
backup
|
||||
Rename any existing file to name~ and start name.
|
||||
|
||||
global
|
||||
Append to a single logfile in your home directory.
|
||||
|
||||
over
|
||||
Overwrite any existing log.
|
||||
|
||||
rotate
|
||||
Create rotating logs: name.1~, name.2~, etc.
|
||||
|
||||
Options:
|
||||
|
||||
-o
|
||||
log also IPython's output. In this mode, all commands which
|
||||
generate an Out[NN] prompt are recorded to the logfile, right after
|
||||
their corresponding input line. The output lines are always
|
||||
prepended with a '#[Out]# ' marker, so that the log remains valid
|
||||
Python code.
|
||||
|
||||
Since this marker is always the same, filtering only the output from
|
||||
a log is very easy, using for example a simple awk call::
|
||||
|
||||
awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py
|
||||
|
||||
-r
|
||||
log 'raw' input. Normally, IPython's logs contain the processed
|
||||
input, so that user lines are logged in their final form, converted
|
||||
into valid Python. For example, %Exit is logged as
|
||||
_ip.magic("Exit"). If the -r flag is given, all input is logged
|
||||
exactly as typed, with no transformations applied.
|
||||
|
||||
-t
|
||||
put timestamps before each input line logged (these are put in
|
||||
comments).
|
||||
|
||||
-q
|
||||
suppress output of logstate message when logging is invoked
|
||||
"""
|
||||
|
||||
opts,par = self.parse_options(parameter_s,'ortq')
|
||||
log_output = 'o' in opts
|
||||
log_raw_input = 'r' in opts
|
||||
timestamp = 't' in opts
|
||||
quiet = 'q' in opts
|
||||
|
||||
logger = self.shell.logger
|
||||
|
||||
# if no args are given, the defaults set in the logger constructor by
|
||||
# ipython remain valid
|
||||
if par:
|
||||
try:
|
||||
logfname,logmode = par.split()
|
||||
except:
|
||||
logfname = par
|
||||
logmode = 'backup'
|
||||
else:
|
||||
logfname = logger.logfname
|
||||
logmode = logger.logmode
|
||||
# put logfname into rc struct as if it had been called on the command
|
||||
# line, so it ends up saved in the log header Save it in case we need
|
||||
# to restore it...
|
||||
old_logfile = self.shell.logfile
|
||||
if logfname:
|
||||
logfname = os.path.expanduser(logfname)
|
||||
self.shell.logfile = logfname
|
||||
|
||||
loghead = u'# IPython log file\n\n'
|
||||
try:
|
||||
logger.logstart(logfname, loghead, logmode, log_output, timestamp,
|
||||
log_raw_input)
|
||||
except:
|
||||
self.shell.logfile = old_logfile
|
||||
warn("Couldn't start log: %s" % sys.exc_info()[1])
|
||||
else:
|
||||
# log input history up to this point, optionally interleaving
|
||||
# output if requested
|
||||
|
||||
if timestamp:
|
||||
# disable timestamping for the previous history, since we've
|
||||
# lost those already (no time machine here).
|
||||
logger.timestamp = False
|
||||
|
||||
if log_raw_input:
|
||||
input_hist = self.shell.history_manager.input_hist_raw
|
||||
else:
|
||||
input_hist = self.shell.history_manager.input_hist_parsed
|
||||
|
||||
if log_output:
|
||||
log_write = logger.log_write
|
||||
output_hist = self.shell.history_manager.output_hist
|
||||
for n in range(1,len(input_hist)-1):
|
||||
log_write(input_hist[n].rstrip() + u'\n')
|
||||
if n in output_hist:
|
||||
log_write(repr(output_hist[n]),'output')
|
||||
else:
|
||||
logger.log_write(u'\n'.join(input_hist[1:]))
|
||||
logger.log_write(u'\n')
|
||||
if timestamp:
|
||||
# re-enable timestamping
|
||||
logger.timestamp = True
|
||||
|
||||
if not (self.quiet or quiet):
|
||||
print ('Activating auto-logging. '
|
||||
'Current session state plus future input saved.')
|
||||
logger.logstate()
|
||||
|
||||
@line_magic
|
||||
def logstop(self, parameter_s=''):
|
||||
"""Fully stop logging and close log file.
|
||||
|
||||
In order to start logging again, a new %logstart call needs to be made,
|
||||
possibly (though not necessarily) with a new filename, mode and other
|
||||
options."""
|
||||
self.shell.logger.logstop()
|
||||
|
||||
@line_magic
|
||||
def logoff(self, parameter_s=''):
|
||||
"""Temporarily stop logging.
|
||||
|
||||
You must have previously started logging."""
|
||||
self.shell.logger.switch_log(0)
|
||||
|
||||
@line_magic
|
||||
def logon(self, parameter_s=''):
|
||||
"""Restart logging.
|
||||
|
||||
This function is for restarting logging which you've temporarily
|
||||
stopped with %logoff. For starting logging for the first time, you
|
||||
must use the %logstart function, which allows you to specify an
|
||||
optional log filename."""
|
||||
|
||||
self.shell.logger.switch_log(1)
|
||||
|
||||
@line_magic
|
||||
def logstate(self, parameter_s=''):
|
||||
"""Print the status of the logging system."""
|
||||
|
||||
self.shell.logger.logstate()
|
711
.venv/Lib/site-packages/IPython/core/magics/namespace.py
Normal file
711
.venv/Lib/site-packages/IPython/core/magics/namespace.py
Normal file
@ -0,0 +1,711 @@
|
||||
"""Implementation of namespace-related magic functions.
|
||||
"""
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (c) 2012 The IPython Development Team.
|
||||
#
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
#
|
||||
# The full license is in the file COPYING.txt, distributed with this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Stdlib
|
||||
import gc
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Our own packages
|
||||
from IPython.core import page
|
||||
from IPython.core.error import StdinNotImplementedError, UsageError
|
||||
from IPython.core.magic import Magics, magics_class, line_magic
|
||||
from IPython.testing.skipdoctest import skip_doctest
|
||||
from IPython.utils.encoding import DEFAULT_ENCODING
|
||||
from IPython.utils.openpy import read_py_file
|
||||
from IPython.utils.path import get_py_filename
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Magic implementation classes
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@magics_class
|
||||
class NamespaceMagics(Magics):
|
||||
"""Magics to manage various aspects of the user's namespace.
|
||||
|
||||
These include listing variables, introspecting into them, etc.
|
||||
"""
|
||||
|
||||
@line_magic
|
||||
def pinfo(self, parameter_s='', namespaces=None):
|
||||
"""Provide detailed information about an object.
|
||||
|
||||
'%pinfo object' is just a synonym for object? or ?object."""
|
||||
|
||||
#print 'pinfo par: <%s>' % parameter_s # dbg
|
||||
# detail_level: 0 -> obj? , 1 -> obj??
|
||||
detail_level = 0
|
||||
# We need to detect if we got called as 'pinfo pinfo foo', which can
|
||||
# happen if the user types 'pinfo foo?' at the cmd line.
|
||||
pinfo,qmark1,oname,qmark2 = \
|
||||
re.match(r'(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups()
|
||||
if pinfo or qmark1 or qmark2:
|
||||
detail_level = 1
|
||||
if "*" in oname:
|
||||
self.psearch(oname)
|
||||
else:
|
||||
self.shell._inspect('pinfo', oname, detail_level=detail_level,
|
||||
namespaces=namespaces)
|
||||
|
||||
@line_magic
|
||||
def pinfo2(self, parameter_s='', namespaces=None):
|
||||
"""Provide extra detailed information about an object.
|
||||
|
||||
'%pinfo2 object' is just a synonym for object?? or ??object."""
|
||||
self.shell._inspect('pinfo', parameter_s, detail_level=1,
|
||||
namespaces=namespaces)
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
def pdef(self, parameter_s='', namespaces=None):
|
||||
"""Print the call signature for any callable object.
|
||||
|
||||
If the object is a class, print the constructor information.
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
|
||||
In [3]: %pdef urllib.urlopen
|
||||
urllib.urlopen(url, data=None, proxies=None)
|
||||
"""
|
||||
self.shell._inspect('pdef',parameter_s, namespaces)
|
||||
|
||||
@line_magic
|
||||
def pdoc(self, parameter_s='', namespaces=None):
|
||||
"""Print the docstring for an object.
|
||||
|
||||
If the given object is a class, it will print both the class and the
|
||||
constructor docstrings."""
|
||||
self.shell._inspect('pdoc',parameter_s, namespaces)
|
||||
|
||||
@line_magic
|
||||
def psource(self, parameter_s='', namespaces=None):
|
||||
"""Print (or run through pager) the source code for an object."""
|
||||
if not parameter_s:
|
||||
raise UsageError('Missing object name.')
|
||||
self.shell._inspect('psource',parameter_s, namespaces)
|
||||
|
||||
@line_magic
|
||||
def pfile(self, parameter_s='', namespaces=None):
|
||||
"""Print (or run through pager) the file where an object is defined.
|
||||
|
||||
The file opens at the line where the object definition begins. IPython
|
||||
will honor the environment variable PAGER if set, and otherwise will
|
||||
do its best to print the file in a convenient form.
|
||||
|
||||
If the given argument is not an object currently defined, IPython will
|
||||
try to interpret it as a filename (automatically adding a .py extension
|
||||
if needed). You can thus use %pfile as a syntax highlighting code
|
||||
viewer."""
|
||||
|
||||
# first interpret argument as an object name
|
||||
out = self.shell._inspect('pfile',parameter_s, namespaces)
|
||||
# if not, try the input as a filename
|
||||
if out == 'not found':
|
||||
try:
|
||||
filename = get_py_filename(parameter_s)
|
||||
except IOError as msg:
|
||||
print(msg)
|
||||
return
|
||||
page.page(self.shell.pycolorize(read_py_file(filename, skip_encoding_cookie=False)))
|
||||
|
||||
@line_magic
|
||||
def psearch(self, parameter_s=''):
|
||||
"""Search for object in namespaces by wildcard.
|
||||
|
||||
%psearch [options] PATTERN [OBJECT TYPE]
|
||||
|
||||
Note: ? can be used as a synonym for %psearch, at the beginning or at
|
||||
the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the
|
||||
rest of the command line must be unchanged (options come first), so
|
||||
for example the following forms are equivalent
|
||||
|
||||
%psearch -i a* function
|
||||
-i a* function?
|
||||
?-i a* function
|
||||
|
||||
Arguments:
|
||||
|
||||
PATTERN
|
||||
|
||||
where PATTERN is a string containing * as a wildcard similar to its
|
||||
use in a shell. The pattern is matched in all namespaces on the
|
||||
search path. By default objects starting with a single _ are not
|
||||
matched, many IPython generated objects have a single
|
||||
underscore. The default is case insensitive matching. Matching is
|
||||
also done on the attributes of objects and not only on the objects
|
||||
in a module.
|
||||
|
||||
[OBJECT TYPE]
|
||||
|
||||
Is the name of a python type from the types module. The name is
|
||||
given in lowercase without the ending type, ex. StringType is
|
||||
written string. By adding a type here only objects matching the
|
||||
given type are matched. Using all here makes the pattern match all
|
||||
types (this is the default).
|
||||
|
||||
Options:
|
||||
|
||||
-a: makes the pattern match even objects whose names start with a
|
||||
single underscore. These names are normally omitted from the
|
||||
search.
|
||||
|
||||
-i/-c: make the pattern case insensitive/sensitive. If neither of
|
||||
these options are given, the default is read from your configuration
|
||||
file, with the option ``InteractiveShell.wildcards_case_sensitive``.
|
||||
If this option is not specified in your configuration file, IPython's
|
||||
internal default is to do a case sensitive search.
|
||||
|
||||
-e/-s NAMESPACE: exclude/search a given namespace. The pattern you
|
||||
specify can be searched in any of the following namespaces:
|
||||
'builtin', 'user', 'user_global','internal', 'alias', where
|
||||
'builtin' and 'user' are the search defaults. Note that you should
|
||||
not use quotes when specifying namespaces.
|
||||
|
||||
-l: List all available object types for object matching. This function
|
||||
can be used without arguments.
|
||||
|
||||
'Builtin' contains the python module builtin, 'user' contains all
|
||||
user data, 'alias' only contain the shell aliases and no python
|
||||
objects, 'internal' contains objects used by IPython. The
|
||||
'user_global' namespace is only used by embedded IPython instances,
|
||||
and it contains module-level globals. You can add namespaces to the
|
||||
search with -s or exclude them with -e (these options can be given
|
||||
more than once).
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
|
||||
%psearch a* -> objects beginning with an a
|
||||
%psearch -e builtin a* -> objects NOT in the builtin space starting in a
|
||||
%psearch a* function -> all functions beginning with an a
|
||||
%psearch re.e* -> objects beginning with an e in module re
|
||||
%psearch r*.e* -> objects that start with e in modules starting in r
|
||||
%psearch r*.* string -> all strings in modules beginning with r
|
||||
|
||||
Case sensitive search::
|
||||
|
||||
%psearch -c a* list all object beginning with lower case a
|
||||
|
||||
Show objects beginning with a single _::
|
||||
|
||||
%psearch -a _* list objects beginning with a single underscore
|
||||
|
||||
List available objects::
|
||||
|
||||
%psearch -l list all available object types
|
||||
"""
|
||||
# default namespaces to be searched
|
||||
def_search = ['user_local', 'user_global', 'builtin']
|
||||
|
||||
# Process options/args
|
||||
opts,args = self.parse_options(parameter_s,'cias:e:l',list_all=True)
|
||||
opt = opts.get
|
||||
shell = self.shell
|
||||
psearch = shell.inspector.psearch
|
||||
|
||||
# select list object types
|
||||
list_types = False
|
||||
if 'l' in opts:
|
||||
list_types = True
|
||||
|
||||
# select case options
|
||||
if 'i' in opts:
|
||||
ignore_case = True
|
||||
elif 'c' in opts:
|
||||
ignore_case = False
|
||||
else:
|
||||
ignore_case = not shell.wildcards_case_sensitive
|
||||
|
||||
# Build list of namespaces to search from user options
|
||||
def_search.extend(opt('s',[]))
|
||||
ns_exclude = ns_exclude=opt('e',[])
|
||||
ns_search = [nm for nm in def_search if nm not in ns_exclude]
|
||||
|
||||
# Call the actual search
|
||||
try:
|
||||
psearch(args,shell.ns_table,ns_search,
|
||||
show_all=opt('a'),ignore_case=ignore_case, list_types=list_types)
|
||||
except:
|
||||
shell.showtraceback()
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
def who_ls(self, parameter_s=''):
|
||||
"""Return a sorted list of all interactive variables.
|
||||
|
||||
If arguments are given, only variables of types matching these
|
||||
arguments are returned.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Define two variables and list them with who_ls::
|
||||
|
||||
In [1]: alpha = 123
|
||||
|
||||
In [2]: beta = 'test'
|
||||
|
||||
In [3]: %who_ls
|
||||
Out[3]: ['alpha', 'beta']
|
||||
|
||||
In [4]: %who_ls int
|
||||
Out[4]: ['alpha']
|
||||
|
||||
In [5]: %who_ls str
|
||||
Out[5]: ['beta']
|
||||
"""
|
||||
|
||||
user_ns = self.shell.user_ns
|
||||
user_ns_hidden = self.shell.user_ns_hidden
|
||||
nonmatching = object() # This can never be in user_ns
|
||||
out = [ i for i in user_ns
|
||||
if not i.startswith('_') \
|
||||
and (user_ns[i] is not user_ns_hidden.get(i, nonmatching)) ]
|
||||
|
||||
typelist = parameter_s.split()
|
||||
if typelist:
|
||||
typeset = set(typelist)
|
||||
out = [i for i in out if type(user_ns[i]).__name__ in typeset]
|
||||
|
||||
out.sort()
|
||||
return out
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
def who(self, parameter_s=''):
|
||||
"""Print all interactive variables, with some minimal formatting.
|
||||
|
||||
If any arguments are given, only variables whose type matches one of
|
||||
these are printed. For example::
|
||||
|
||||
%who function str
|
||||
|
||||
will only list functions and strings, excluding all other types of
|
||||
variables. To find the proper type names, simply use type(var) at a
|
||||
command line to see how python prints type names. For example:
|
||||
|
||||
::
|
||||
|
||||
In [1]: type('hello')\\
|
||||
Out[1]: <type 'str'>
|
||||
|
||||
indicates that the type name for strings is 'str'.
|
||||
|
||||
``%who`` always excludes executed names loaded through your configuration
|
||||
file and things which are internal to IPython.
|
||||
|
||||
This is deliberate, as typically you may load many modules and the
|
||||
purpose of %who is to show you only what you've manually defined.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Define two variables and list them with who::
|
||||
|
||||
In [1]: alpha = 123
|
||||
|
||||
In [2]: beta = 'test'
|
||||
|
||||
In [3]: %who
|
||||
alpha beta
|
||||
|
||||
In [4]: %who int
|
||||
alpha
|
||||
|
||||
In [5]: %who str
|
||||
beta
|
||||
"""
|
||||
|
||||
varlist = self.who_ls(parameter_s)
|
||||
if not varlist:
|
||||
if parameter_s:
|
||||
print('No variables match your requested type.')
|
||||
else:
|
||||
print('Interactive namespace is empty.')
|
||||
return
|
||||
|
||||
# if we have variables, move on...
|
||||
count = 0
|
||||
for i in varlist:
|
||||
print(i+'\t', end=' ')
|
||||
count += 1
|
||||
if count > 8:
|
||||
count = 0
|
||||
print()
|
||||
print()
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
def whos(self, parameter_s=''):
|
||||
"""Like %who, but gives some extra information about each variable.
|
||||
|
||||
The same type filtering of %who can be applied here.
|
||||
|
||||
For all variables, the type is printed. Additionally it prints:
|
||||
|
||||
- For {},[],(): their length.
|
||||
|
||||
- For numpy arrays, a summary with shape, number of
|
||||
elements, typecode and size in memory.
|
||||
|
||||
- Everything else: a string representation, snipping their middle if
|
||||
too long.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Define two variables and list them with whos::
|
||||
|
||||
In [1]: alpha = 123
|
||||
|
||||
In [2]: beta = 'test'
|
||||
|
||||
In [3]: %whos
|
||||
Variable Type Data/Info
|
||||
--------------------------------
|
||||
alpha int 123
|
||||
beta str test
|
||||
"""
|
||||
|
||||
varnames = self.who_ls(parameter_s)
|
||||
if not varnames:
|
||||
if parameter_s:
|
||||
print('No variables match your requested type.')
|
||||
else:
|
||||
print('Interactive namespace is empty.')
|
||||
return
|
||||
|
||||
# if we have variables, move on...
|
||||
|
||||
# for these types, show len() instead of data:
|
||||
seq_types = ['dict', 'list', 'tuple']
|
||||
|
||||
# for numpy arrays, display summary info
|
||||
ndarray_type = None
|
||||
if 'numpy' in sys.modules:
|
||||
try:
|
||||
from numpy import ndarray
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
ndarray_type = ndarray.__name__
|
||||
|
||||
# Find all variable names and types so we can figure out column sizes
|
||||
|
||||
# some types are well known and can be shorter
|
||||
abbrevs = {'IPython.core.macro.Macro' : 'Macro'}
|
||||
def type_name(v):
|
||||
tn = type(v).__name__
|
||||
return abbrevs.get(tn,tn)
|
||||
|
||||
varlist = [self.shell.user_ns[n] for n in varnames]
|
||||
|
||||
typelist = []
|
||||
for vv in varlist:
|
||||
tt = type_name(vv)
|
||||
|
||||
if tt=='instance':
|
||||
typelist.append( abbrevs.get(str(vv.__class__),
|
||||
str(vv.__class__)))
|
||||
else:
|
||||
typelist.append(tt)
|
||||
|
||||
# column labels and # of spaces as separator
|
||||
varlabel = 'Variable'
|
||||
typelabel = 'Type'
|
||||
datalabel = 'Data/Info'
|
||||
colsep = 3
|
||||
# variable format strings
|
||||
vformat = "{0:<{varwidth}}{1:<{typewidth}}"
|
||||
aformat = "%s: %s elems, type `%s`, %s bytes"
|
||||
# find the size of the columns to format the output nicely
|
||||
varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep
|
||||
typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep
|
||||
# table header
|
||||
print(varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \
|
||||
' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1))
|
||||
# and the table itself
|
||||
kb = 1024
|
||||
Mb = 1048576 # kb**2
|
||||
for vname,var,vtype in zip(varnames,varlist,typelist):
|
||||
print(vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth), end=' ')
|
||||
if vtype in seq_types:
|
||||
print("n="+str(len(var)))
|
||||
elif vtype == ndarray_type:
|
||||
vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1]
|
||||
if vtype==ndarray_type:
|
||||
# numpy
|
||||
vsize = var.size
|
||||
vbytes = vsize*var.itemsize
|
||||
vdtype = var.dtype
|
||||
|
||||
if vbytes < 100000:
|
||||
print(aformat % (vshape, vsize, vdtype, vbytes))
|
||||
else:
|
||||
print(aformat % (vshape, vsize, vdtype, vbytes), end=' ')
|
||||
if vbytes < Mb:
|
||||
print('(%s kb)' % (vbytes/kb,))
|
||||
else:
|
||||
print('(%s Mb)' % (vbytes/Mb,))
|
||||
else:
|
||||
try:
|
||||
vstr = str(var)
|
||||
except UnicodeEncodeError:
|
||||
vstr = var.encode(DEFAULT_ENCODING,
|
||||
'backslashreplace')
|
||||
except:
|
||||
vstr = "<object with id %d (str() failed)>" % id(var)
|
||||
vstr = vstr.replace('\n', '\\n')
|
||||
if len(vstr) < 50:
|
||||
print(vstr)
|
||||
else:
|
||||
print(vstr[:25] + "<...>" + vstr[-25:])
|
||||
|
||||
@line_magic
|
||||
def reset(self, parameter_s=''):
|
||||
"""Resets the namespace by removing all names defined by the user, if
|
||||
called without arguments, or by removing some types of objects, such
|
||||
as everything currently in IPython's In[] and Out[] containers (see
|
||||
the parameters for details).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
-f
|
||||
force reset without asking for confirmation.
|
||||
-s
|
||||
'Soft' reset: Only clears your namespace, leaving history intact.
|
||||
References to objects may be kept. By default (without this option),
|
||||
we do a 'hard' reset, giving you a new session and removing all
|
||||
references to objects from the current session.
|
||||
--aggressive
|
||||
Try to aggressively remove modules from sys.modules ; this
|
||||
may allow you to reimport Python modules that have been updated and
|
||||
pick up changes, but can have unattended consequences.
|
||||
|
||||
in
|
||||
reset input history
|
||||
out
|
||||
reset output history
|
||||
dhist
|
||||
reset directory history
|
||||
array
|
||||
reset only variables that are NumPy arrays
|
||||
|
||||
See Also
|
||||
--------
|
||||
reset_selective : invoked as ``%reset_selective``
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
|
||||
In [6]: a = 1
|
||||
|
||||
In [7]: a
|
||||
Out[7]: 1
|
||||
|
||||
In [8]: 'a' in get_ipython().user_ns
|
||||
Out[8]: True
|
||||
|
||||
In [9]: %reset -f
|
||||
|
||||
In [1]: 'a' in get_ipython().user_ns
|
||||
Out[1]: False
|
||||
|
||||
In [2]: %reset -f in
|
||||
Flushing input history
|
||||
|
||||
In [3]: %reset -f dhist in
|
||||
Flushing directory history
|
||||
Flushing input history
|
||||
|
||||
Notes
|
||||
-----
|
||||
Calling this magic from clients that do not implement standard input,
|
||||
such as the ipython notebook interface, will reset the namespace
|
||||
without confirmation.
|
||||
"""
|
||||
opts, args = self.parse_options(parameter_s, "sf", "aggressive", mode="list")
|
||||
if "f" in opts:
|
||||
ans = True
|
||||
else:
|
||||
try:
|
||||
ans = self.shell.ask_yes_no(
|
||||
"Once deleted, variables cannot be recovered. Proceed (y/[n])?",
|
||||
default='n')
|
||||
except StdinNotImplementedError:
|
||||
ans = True
|
||||
if not ans:
|
||||
print('Nothing done.')
|
||||
return
|
||||
|
||||
if 's' in opts: # Soft reset
|
||||
user_ns = self.shell.user_ns
|
||||
for i in self.who_ls():
|
||||
del(user_ns[i])
|
||||
elif len(args) == 0: # Hard reset
|
||||
self.shell.reset(new_session=False, aggressive=("aggressive" in opts))
|
||||
|
||||
# reset in/out/dhist/array: previously extensinions/clearcmd.py
|
||||
ip = self.shell
|
||||
user_ns = self.shell.user_ns # local lookup, heavily used
|
||||
|
||||
for target in args:
|
||||
target = target.lower() # make matches case insensitive
|
||||
if target == 'out':
|
||||
print("Flushing output cache (%d entries)" % len(user_ns['_oh']))
|
||||
self.shell.displayhook.flush()
|
||||
|
||||
elif target == 'in':
|
||||
print("Flushing input history")
|
||||
pc = self.shell.displayhook.prompt_count + 1
|
||||
for n in range(1, pc):
|
||||
key = '_i'+repr(n)
|
||||
user_ns.pop(key,None)
|
||||
user_ns.update(dict(_i=u'',_ii=u'',_iii=u''))
|
||||
hm = ip.history_manager
|
||||
# don't delete these, as %save and %macro depending on the
|
||||
# length of these lists to be preserved
|
||||
hm.input_hist_parsed[:] = [''] * pc
|
||||
hm.input_hist_raw[:] = [''] * pc
|
||||
# hm has internal machinery for _i,_ii,_iii, clear it out
|
||||
hm._i = hm._ii = hm._iii = hm._i00 = u''
|
||||
|
||||
elif target == 'array':
|
||||
# Support cleaning up numpy arrays
|
||||
try:
|
||||
from numpy import ndarray
|
||||
# This must be done with items and not iteritems because
|
||||
# we're going to modify the dict in-place.
|
||||
for x,val in list(user_ns.items()):
|
||||
if isinstance(val,ndarray):
|
||||
del user_ns[x]
|
||||
except ImportError:
|
||||
print("reset array only works if Numpy is available.")
|
||||
|
||||
elif target == 'dhist':
|
||||
print("Flushing directory history")
|
||||
del user_ns['_dh'][:]
|
||||
|
||||
else:
|
||||
print("Don't know how to reset ", end=' ')
|
||||
print(target + ", please run `%reset?` for details")
|
||||
|
||||
gc.collect()
|
||||
|
||||
@line_magic
|
||||
def reset_selective(self, parameter_s=''):
|
||||
"""Resets the namespace by removing names defined by the user.
|
||||
|
||||
Input/Output history are left around in case you need them.
|
||||
|
||||
%reset_selective [-f] regex
|
||||
|
||||
No action is taken if regex is not included
|
||||
|
||||
Options
|
||||
-f : force reset without asking for confirmation.
|
||||
|
||||
See Also
|
||||
--------
|
||||
reset : invoked as ``%reset``
|
||||
|
||||
Examples
|
||||
--------
|
||||
We first fully reset the namespace so your output looks identical to
|
||||
this example for pedagogical reasons; in practice you do not need a
|
||||
full reset::
|
||||
|
||||
In [1]: %reset -f
|
||||
|
||||
Now, with a clean namespace we can make a few variables and use
|
||||
``%reset_selective`` to only delete names that match our regexp::
|
||||
|
||||
In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8
|
||||
|
||||
In [3]: who_ls
|
||||
Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c']
|
||||
|
||||
In [4]: %reset_selective -f b[2-3]m
|
||||
|
||||
In [5]: who_ls
|
||||
Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
|
||||
|
||||
In [6]: %reset_selective -f d
|
||||
|
||||
In [7]: who_ls
|
||||
Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
|
||||
|
||||
In [8]: %reset_selective -f c
|
||||
|
||||
In [9]: who_ls
|
||||
Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m']
|
||||
|
||||
In [10]: %reset_selective -f b
|
||||
|
||||
In [11]: who_ls
|
||||
Out[11]: ['a']
|
||||
|
||||
Notes
|
||||
-----
|
||||
Calling this magic from clients that do not implement standard input,
|
||||
such as the ipython notebook interface, will reset the namespace
|
||||
without confirmation.
|
||||
"""
|
||||
|
||||
opts, regex = self.parse_options(parameter_s,'f')
|
||||
|
||||
if 'f' in opts:
|
||||
ans = True
|
||||
else:
|
||||
try:
|
||||
ans = self.shell.ask_yes_no(
|
||||
"Once deleted, variables cannot be recovered. Proceed (y/[n])? ",
|
||||
default='n')
|
||||
except StdinNotImplementedError:
|
||||
ans = True
|
||||
if not ans:
|
||||
print('Nothing done.')
|
||||
return
|
||||
user_ns = self.shell.user_ns
|
||||
if not regex:
|
||||
print('No regex pattern specified. Nothing done.')
|
||||
return
|
||||
else:
|
||||
try:
|
||||
m = re.compile(regex)
|
||||
except TypeError as e:
|
||||
raise TypeError('regex must be a string or compiled pattern') from e
|
||||
for i in self.who_ls():
|
||||
if m.search(i):
|
||||
del(user_ns[i])
|
||||
|
||||
@line_magic
|
||||
def xdel(self, parameter_s=''):
|
||||
"""Delete a variable, trying to clear it from anywhere that
|
||||
IPython's machinery has references to it. By default, this uses
|
||||
the identity of the named object in the user namespace to remove
|
||||
references held under other names. The object is also removed
|
||||
from the output history.
|
||||
|
||||
Options
|
||||
-n : Delete the specified name from all namespaces, without
|
||||
checking their identity.
|
||||
"""
|
||||
opts, varname = self.parse_options(parameter_s,'n')
|
||||
try:
|
||||
self.shell.del_var(varname, ('n' in opts))
|
||||
except (NameError, ValueError) as e:
|
||||
print(type(e).__name__ +": "+ str(e))
|
854
.venv/Lib/site-packages/IPython/core/magics/osm.py
Normal file
854
.venv/Lib/site-packages/IPython/core/magics/osm.py
Normal file
@ -0,0 +1,854 @@
|
||||
"""Implementation of magic functions for interaction with the OS.
|
||||
|
||||
Note: this module is named 'osm' instead of 'os' to avoid a collision with the
|
||||
builtin.
|
||||
"""
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pprint import pformat
|
||||
|
||||
from IPython.core import magic_arguments
|
||||
from IPython.core import oinspect
|
||||
from IPython.core import page
|
||||
from IPython.core.alias import AliasError, Alias
|
||||
from IPython.core.error import UsageError
|
||||
from IPython.core.magic import (
|
||||
Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
|
||||
)
|
||||
from IPython.testing.skipdoctest import skip_doctest
|
||||
from IPython.utils.openpy import source_to_unicode
|
||||
from IPython.utils.process import abbrev_cwd
|
||||
from IPython.utils.terminal import set_term_title
|
||||
from traitlets import Bool
|
||||
from warnings import warn
|
||||
|
||||
|
||||
@magics_class
|
||||
class OSMagics(Magics):
|
||||
"""Magics to interact with the underlying OS (shell-type functionality).
|
||||
"""
|
||||
|
||||
cd_force_quiet = Bool(False,
|
||||
help="Force %cd magic to be quiet even if -q is not passed."
|
||||
).tag(config=True)
|
||||
|
||||
def __init__(self, shell=None, **kwargs):
|
||||
|
||||
# Now define isexec in a cross platform manner.
|
||||
self.is_posix = False
|
||||
self.execre = None
|
||||
if os.name == 'posix':
|
||||
self.is_posix = True
|
||||
else:
|
||||
try:
|
||||
winext = os.environ['pathext'].replace(';','|').replace('.','')
|
||||
except KeyError:
|
||||
winext = 'exe|com|bat|py'
|
||||
try:
|
||||
self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
|
||||
except re.error:
|
||||
warn("Seems like your pathext environmental "
|
||||
"variable is malformed. Please check it to "
|
||||
"enable a proper handle of file extensions "
|
||||
"managed for your system")
|
||||
winext = 'exe|com|bat|py'
|
||||
self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
|
||||
|
||||
# call up the chain
|
||||
super().__init__(shell=shell, **kwargs)
|
||||
|
||||
|
||||
def _isexec_POSIX(self, file):
|
||||
"""
|
||||
Test for executable on a POSIX system
|
||||
"""
|
||||
if os.access(file.path, os.X_OK):
|
||||
# will fail on maxOS if access is not X_OK
|
||||
return file.is_file()
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def _isexec_WIN(self, file):
|
||||
"""
|
||||
Test for executable file on non POSIX system
|
||||
"""
|
||||
return file.is_file() and self.execre.match(file.name) is not None
|
||||
|
||||
def isexec(self, file):
|
||||
"""
|
||||
Test for executable file on non POSIX system
|
||||
"""
|
||||
if self.is_posix:
|
||||
return self._isexec_POSIX(file)
|
||||
else:
|
||||
return self._isexec_WIN(file)
|
||||
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
def alias(self, parameter_s=''):
|
||||
"""Define an alias for a system command.
|
||||
|
||||
'%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
|
||||
|
||||
Then, typing 'alias_name params' will execute the system command 'cmd
|
||||
params' (from your underlying operating system).
|
||||
|
||||
Aliases have lower precedence than magic functions and Python normal
|
||||
variables, so if 'foo' is both a Python variable and an alias, the
|
||||
alias can not be executed until 'del foo' removes the Python variable.
|
||||
|
||||
You can use the %l specifier in an alias definition to represent the
|
||||
whole line when the alias is called. For example::
|
||||
|
||||
In [2]: alias bracket echo "Input in brackets: <%l>"
|
||||
In [3]: bracket hello world
|
||||
Input in brackets: <hello world>
|
||||
|
||||
You can also define aliases with parameters using %s specifiers (one
|
||||
per parameter)::
|
||||
|
||||
In [1]: alias parts echo first %s second %s
|
||||
In [2]: %parts A B
|
||||
first A second B
|
||||
In [3]: %parts A
|
||||
Incorrect number of arguments: 2 expected.
|
||||
parts is an alias to: 'echo first %s second %s'
|
||||
|
||||
Note that %l and %s are mutually exclusive. You can only use one or
|
||||
the other in your aliases.
|
||||
|
||||
Aliases expand Python variables just like system calls using ! or !!
|
||||
do: all expressions prefixed with '$' get expanded. For details of
|
||||
the semantic rules, see PEP-215:
|
||||
https://peps.python.org/pep-0215/. This is the library used by
|
||||
IPython for variable expansion. If you want to access a true shell
|
||||
variable, an extra $ is necessary to prevent its expansion by
|
||||
IPython::
|
||||
|
||||
In [6]: alias show echo
|
||||
In [7]: PATH='A Python string'
|
||||
In [8]: show $PATH
|
||||
A Python string
|
||||
In [9]: show $$PATH
|
||||
/usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
|
||||
|
||||
You can use the alias facility to access all of $PATH. See the %rehashx
|
||||
function, which automatically creates aliases for the contents of your
|
||||
$PATH.
|
||||
|
||||
If called with no parameters, %alias prints the current alias table
|
||||
for your system. For posix systems, the default aliases are 'cat',
|
||||
'cp', 'mv', 'rm', 'rmdir', and 'mkdir', and other platform-specific
|
||||
aliases are added. For windows-based systems, the default aliases are
|
||||
'copy', 'ddir', 'echo', 'ls', 'ldir', 'mkdir', 'ren', and 'rmdir'.
|
||||
|
||||
You can see the definition of alias by adding a question mark in the
|
||||
end::
|
||||
|
||||
In [1]: cat?
|
||||
Repr: <alias cat for 'cat'>"""
|
||||
|
||||
par = parameter_s.strip()
|
||||
if not par:
|
||||
aliases = sorted(self.shell.alias_manager.aliases)
|
||||
# stored = self.shell.db.get('stored_aliases', {} )
|
||||
# for k, v in stored:
|
||||
# atab.append(k, v[0])
|
||||
|
||||
print("Total number of aliases:", len(aliases))
|
||||
sys.stdout.flush()
|
||||
return aliases
|
||||
|
||||
# Now try to define a new one
|
||||
try:
|
||||
alias,cmd = par.split(None, 1)
|
||||
except TypeError:
|
||||
print(oinspect.getdoc(self.alias))
|
||||
return
|
||||
|
||||
try:
|
||||
self.shell.alias_manager.define_alias(alias, cmd)
|
||||
except AliasError as e:
|
||||
print(e)
|
||||
# end magic_alias
|
||||
|
||||
@line_magic
|
||||
def unalias(self, parameter_s=''):
|
||||
"""Remove an alias"""
|
||||
|
||||
aname = parameter_s.strip()
|
||||
try:
|
||||
self.shell.alias_manager.undefine_alias(aname)
|
||||
except ValueError as e:
|
||||
print(e)
|
||||
return
|
||||
|
||||
stored = self.shell.db.get('stored_aliases', {} )
|
||||
if aname in stored:
|
||||
print("Removing %stored alias",aname)
|
||||
del stored[aname]
|
||||
self.shell.db['stored_aliases'] = stored
|
||||
|
||||
@line_magic
|
||||
def rehashx(self, parameter_s=''):
|
||||
"""Update the alias table with all executable files in $PATH.
|
||||
|
||||
rehashx explicitly checks that every entry in $PATH is a file
|
||||
with execute access (os.X_OK).
|
||||
|
||||
Under Windows, it checks executability as a match against a
|
||||
'|'-separated string of extensions, stored in the IPython config
|
||||
variable win_exec_ext. This defaults to 'exe|com|bat'.
|
||||
|
||||
This function also resets the root module cache of module completer,
|
||||
used on slow filesystems.
|
||||
"""
|
||||
from IPython.core.alias import InvalidAliasError
|
||||
|
||||
# for the benefit of module completer in ipy_completers.py
|
||||
del self.shell.db['rootmodules_cache']
|
||||
|
||||
path = [os.path.abspath(os.path.expanduser(p)) for p in
|
||||
os.environ.get('PATH','').split(os.pathsep)]
|
||||
|
||||
syscmdlist = []
|
||||
savedir = os.getcwd()
|
||||
|
||||
# Now walk the paths looking for executables to alias.
|
||||
try:
|
||||
# write the whole loop for posix/Windows so we don't have an if in
|
||||
# the innermost part
|
||||
if self.is_posix:
|
||||
for pdir in path:
|
||||
try:
|
||||
os.chdir(pdir)
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
# for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
|
||||
dirlist = os.scandir(path=pdir)
|
||||
for ff in dirlist:
|
||||
if self.isexec(ff):
|
||||
fname = ff.name
|
||||
try:
|
||||
# Removes dots from the name since ipython
|
||||
# will assume names with dots to be python.
|
||||
if not self.shell.alias_manager.is_alias(fname):
|
||||
self.shell.alias_manager.define_alias(
|
||||
fname.replace('.',''), fname)
|
||||
except InvalidAliasError:
|
||||
pass
|
||||
else:
|
||||
syscmdlist.append(fname)
|
||||
else:
|
||||
no_alias = Alias.blacklist
|
||||
for pdir in path:
|
||||
try:
|
||||
os.chdir(pdir)
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
# for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
|
||||
dirlist = os.scandir(pdir)
|
||||
for ff in dirlist:
|
||||
fname = ff.name
|
||||
base, ext = os.path.splitext(fname)
|
||||
if self.isexec(ff) and base.lower() not in no_alias:
|
||||
if ext.lower() == '.exe':
|
||||
fname = base
|
||||
try:
|
||||
# Removes dots from the name since ipython
|
||||
# will assume names with dots to be python.
|
||||
self.shell.alias_manager.define_alias(
|
||||
base.lower().replace('.',''), fname)
|
||||
except InvalidAliasError:
|
||||
pass
|
||||
syscmdlist.append(fname)
|
||||
|
||||
self.shell.db['syscmdlist'] = syscmdlist
|
||||
finally:
|
||||
os.chdir(savedir)
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
def pwd(self, parameter_s=''):
|
||||
"""Return the current working directory path.
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
|
||||
In [9]: pwd
|
||||
Out[9]: '/home/tsuser/sprint/ipython'
|
||||
"""
|
||||
try:
|
||||
return os.getcwd()
|
||||
except FileNotFoundError as e:
|
||||
raise UsageError("CWD no longer exists - please use %cd to change directory.") from e
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
def cd(self, parameter_s=''):
|
||||
"""Change the current working directory.
|
||||
|
||||
This command automatically maintains an internal list of directories
|
||||
you visit during your IPython session, in the variable ``_dh``. The
|
||||
command :magic:`%dhist` shows this history nicely formatted. You can
|
||||
also do ``cd -<tab>`` to see directory history conveniently.
|
||||
Usage:
|
||||
|
||||
- ``cd 'dir'``: changes to directory 'dir'.
|
||||
- ``cd -``: changes to the last visited directory.
|
||||
- ``cd -<n>``: changes to the n-th directory in the directory history.
|
||||
- ``cd --foo``: change to directory that matches 'foo' in history
|
||||
- ``cd -b <bookmark_name>``: jump to a bookmark set by %bookmark
|
||||
- Hitting a tab key after ``cd -b`` allows you to tab-complete
|
||||
bookmark names.
|
||||
|
||||
.. note::
|
||||
``cd <bookmark_name>`` is enough if there is no directory
|
||||
``<bookmark_name>``, but a bookmark with the name exists.
|
||||
|
||||
Options:
|
||||
|
||||
-q Be quiet. Do not print the working directory after the
|
||||
cd command is executed. By default IPython's cd
|
||||
command does print this directory, since the default
|
||||
prompts do not display path information.
|
||||
|
||||
.. note::
|
||||
Note that ``!cd`` doesn't work for this purpose because the shell
|
||||
where ``!command`` runs is immediately discarded after executing
|
||||
'command'.
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
|
||||
In [10]: cd parent/child
|
||||
/home/tsuser/parent/child
|
||||
"""
|
||||
|
||||
try:
|
||||
oldcwd = os.getcwd()
|
||||
except FileNotFoundError:
|
||||
# Happens if the CWD has been deleted.
|
||||
oldcwd = None
|
||||
|
||||
numcd = re.match(r'(-)(\d+)$',parameter_s)
|
||||
# jump in directory history by number
|
||||
if numcd:
|
||||
nn = int(numcd.group(2))
|
||||
try:
|
||||
ps = self.shell.user_ns['_dh'][nn]
|
||||
except IndexError:
|
||||
print('The requested directory does not exist in history.')
|
||||
return
|
||||
else:
|
||||
opts = {}
|
||||
elif parameter_s.startswith('--'):
|
||||
ps = None
|
||||
fallback = None
|
||||
pat = parameter_s[2:]
|
||||
dh = self.shell.user_ns['_dh']
|
||||
# first search only by basename (last component)
|
||||
for ent in reversed(dh):
|
||||
if pat in os.path.basename(ent) and os.path.isdir(ent):
|
||||
ps = ent
|
||||
break
|
||||
|
||||
if fallback is None and pat in ent and os.path.isdir(ent):
|
||||
fallback = ent
|
||||
|
||||
# if we have no last part match, pick the first full path match
|
||||
if ps is None:
|
||||
ps = fallback
|
||||
|
||||
if ps is None:
|
||||
print("No matching entry in directory history")
|
||||
return
|
||||
else:
|
||||
opts = {}
|
||||
|
||||
|
||||
else:
|
||||
opts, ps = self.parse_options(parameter_s, 'qb', mode='string')
|
||||
# jump to previous
|
||||
if ps == '-':
|
||||
try:
|
||||
ps = self.shell.user_ns['_dh'][-2]
|
||||
except IndexError as e:
|
||||
raise UsageError('%cd -: No previous directory to change to.') from e
|
||||
# jump to bookmark if needed
|
||||
else:
|
||||
if not os.path.isdir(ps) or 'b' in opts:
|
||||
bkms = self.shell.db.get('bookmarks', {})
|
||||
|
||||
if ps in bkms:
|
||||
target = bkms[ps]
|
||||
print('(bookmark:%s) -> %s' % (ps, target))
|
||||
ps = target
|
||||
else:
|
||||
if 'b' in opts:
|
||||
raise UsageError("Bookmark '%s' not found. "
|
||||
"Use '%%bookmark -l' to see your bookmarks." % ps)
|
||||
|
||||
# at this point ps should point to the target dir
|
||||
if ps:
|
||||
try:
|
||||
os.chdir(os.path.expanduser(ps))
|
||||
if hasattr(self.shell, 'term_title') and self.shell.term_title:
|
||||
set_term_title(self.shell.term_title_format.format(cwd=abbrev_cwd()))
|
||||
except OSError:
|
||||
print(sys.exc_info()[1])
|
||||
else:
|
||||
cwd = os.getcwd()
|
||||
dhist = self.shell.user_ns['_dh']
|
||||
if oldcwd != cwd:
|
||||
dhist.append(cwd)
|
||||
self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
|
||||
|
||||
else:
|
||||
os.chdir(self.shell.home_dir)
|
||||
if hasattr(self.shell, 'term_title') and self.shell.term_title:
|
||||
set_term_title(self.shell.term_title_format.format(cwd="~"))
|
||||
cwd = os.getcwd()
|
||||
dhist = self.shell.user_ns['_dh']
|
||||
|
||||
if oldcwd != cwd:
|
||||
dhist.append(cwd)
|
||||
self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
|
||||
if not 'q' in opts and not self.cd_force_quiet and self.shell.user_ns['_dh']:
|
||||
print(self.shell.user_ns['_dh'][-1])
|
||||
|
||||
@line_magic
|
||||
def env(self, parameter_s=''):
|
||||
"""Get, set, or list environment variables.
|
||||
|
||||
Usage:\\
|
||||
|
||||
:``%env``: lists all environment variables/values
|
||||
:``%env var``: get value for var
|
||||
:``%env var val``: set value for var
|
||||
:``%env var=val``: set value for var
|
||||
:``%env var=$val``: set value for var, using python expansion if possible
|
||||
"""
|
||||
if parameter_s.strip():
|
||||
split = '=' if '=' in parameter_s else ' '
|
||||
bits = parameter_s.split(split)
|
||||
if len(bits) == 1:
|
||||
key = parameter_s.strip()
|
||||
if key in os.environ:
|
||||
return os.environ[key]
|
||||
else:
|
||||
err = "Environment does not have key: {0}".format(key)
|
||||
raise UsageError(err)
|
||||
if len(bits) > 1:
|
||||
return self.set_env(parameter_s)
|
||||
env = dict(os.environ)
|
||||
# hide likely secrets when printing the whole environment
|
||||
for key in list(env):
|
||||
if any(s in key.lower() for s in ('key', 'token', 'secret')):
|
||||
env[key] = '<hidden>'
|
||||
|
||||
return env
|
||||
|
||||
@line_magic
|
||||
def set_env(self, parameter_s):
|
||||
"""Set environment variables. Assumptions are that either "val" is a
|
||||
name in the user namespace, or val is something that evaluates to a
|
||||
string.
|
||||
|
||||
Usage:\\
|
||||
%set_env var val: set value for var
|
||||
%set_env var=val: set value for var
|
||||
%set_env var=$val: set value for var, using python expansion if possible
|
||||
"""
|
||||
split = '=' if '=' in parameter_s else ' '
|
||||
bits = parameter_s.split(split, 1)
|
||||
if not parameter_s.strip() or len(bits)<2:
|
||||
raise UsageError("usage is 'set_env var=val'")
|
||||
var = bits[0].strip()
|
||||
val = bits[1].strip()
|
||||
if re.match(r'.*\s.*', var):
|
||||
# an environment variable with whitespace is almost certainly
|
||||
# not what the user intended. what's more likely is the wrong
|
||||
# split was chosen, ie for "set_env cmd_args A=B", we chose
|
||||
# '=' for the split and should have chosen ' '. to get around
|
||||
# this, users should just assign directly to os.environ or use
|
||||
# standard magic {var} expansion.
|
||||
err = "refusing to set env var with whitespace: '{0}'"
|
||||
err = err.format(val)
|
||||
raise UsageError(err)
|
||||
os.environ[var] = val
|
||||
print('env: {0}={1}'.format(var,val))
|
||||
|
||||
@line_magic
|
||||
def pushd(self, parameter_s=''):
|
||||
"""Place the current dir on stack and change directory.
|
||||
|
||||
Usage:\\
|
||||
%pushd ['dirname']
|
||||
"""
|
||||
|
||||
dir_s = self.shell.dir_stack
|
||||
tgt = os.path.expanduser(parameter_s)
|
||||
cwd = os.getcwd().replace(self.shell.home_dir,'~')
|
||||
if tgt:
|
||||
self.cd(parameter_s)
|
||||
dir_s.insert(0,cwd)
|
||||
return self.shell.run_line_magic('dirs', '')
|
||||
|
||||
@line_magic
|
||||
def popd(self, parameter_s=''):
|
||||
"""Change to directory popped off the top of the stack.
|
||||
"""
|
||||
if not self.shell.dir_stack:
|
||||
raise UsageError("%popd on empty stack")
|
||||
top = self.shell.dir_stack.pop(0)
|
||||
self.cd(top)
|
||||
print("popd ->",top)
|
||||
|
||||
@line_magic
|
||||
def dirs(self, parameter_s=''):
|
||||
"""Return the current directory stack."""
|
||||
|
||||
return self.shell.dir_stack
|
||||
|
||||
@line_magic
|
||||
def dhist(self, parameter_s=''):
|
||||
"""Print your history of visited directories.
|
||||
|
||||
%dhist -> print full history\\
|
||||
%dhist n -> print last n entries only\\
|
||||
%dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
|
||||
|
||||
This history is automatically maintained by the %cd command, and
|
||||
always available as the global list variable _dh. You can use %cd -<n>
|
||||
to go to directory number <n>.
|
||||
|
||||
Note that most of time, you should view directory history by entering
|
||||
cd -<TAB>.
|
||||
|
||||
"""
|
||||
|
||||
dh = self.shell.user_ns['_dh']
|
||||
if parameter_s:
|
||||
try:
|
||||
args = map(int,parameter_s.split())
|
||||
except:
|
||||
self.arg_err(self.dhist)
|
||||
return
|
||||
if len(args) == 1:
|
||||
ini,fin = max(len(dh)-(args[0]),0),len(dh)
|
||||
elif len(args) == 2:
|
||||
ini,fin = args
|
||||
fin = min(fin, len(dh))
|
||||
else:
|
||||
self.arg_err(self.dhist)
|
||||
return
|
||||
else:
|
||||
ini,fin = 0,len(dh)
|
||||
print('Directory history (kept in _dh)')
|
||||
for i in range(ini, fin):
|
||||
print("%d: %s" % (i, dh[i]))
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
def sc(self, parameter_s=''):
|
||||
"""Shell capture - run shell command and capture output (DEPRECATED use !).
|
||||
|
||||
DEPRECATED. Suboptimal, retained for backwards compatibility.
|
||||
|
||||
You should use the form 'var = !command' instead. Example:
|
||||
|
||||
"%sc -l myfiles = ls ~" should now be written as
|
||||
|
||||
"myfiles = !ls ~"
|
||||
|
||||
myfiles.s, myfiles.l and myfiles.n still apply as documented
|
||||
below.
|
||||
|
||||
--
|
||||
%sc [options] varname=command
|
||||
|
||||
IPython will run the given command using commands.getoutput(), and
|
||||
will then update the user's interactive namespace with a variable
|
||||
called varname, containing the value of the call. Your command can
|
||||
contain shell wildcards, pipes, etc.
|
||||
|
||||
The '=' sign in the syntax is mandatory, and the variable name you
|
||||
supply must follow Python's standard conventions for valid names.
|
||||
|
||||
(A special format without variable name exists for internal use)
|
||||
|
||||
Options:
|
||||
|
||||
-l: list output. Split the output on newlines into a list before
|
||||
assigning it to the given variable. By default the output is stored
|
||||
as a single string.
|
||||
|
||||
-v: verbose. Print the contents of the variable.
|
||||
|
||||
In most cases you should not need to split as a list, because the
|
||||
returned value is a special type of string which can automatically
|
||||
provide its contents either as a list (split on newlines) or as a
|
||||
space-separated string. These are convenient, respectively, either
|
||||
for sequential processing or to be passed to a shell command.
|
||||
|
||||
For example::
|
||||
|
||||
# Capture into variable a
|
||||
In [1]: sc a=ls *py
|
||||
|
||||
# a is a string with embedded newlines
|
||||
In [2]: a
|
||||
Out[2]: 'setup.py\\nwin32_manual_post_install.py'
|
||||
|
||||
# which can be seen as a list:
|
||||
In [3]: a.l
|
||||
Out[3]: ['setup.py', 'win32_manual_post_install.py']
|
||||
|
||||
# or as a whitespace-separated string:
|
||||
In [4]: a.s
|
||||
Out[4]: 'setup.py win32_manual_post_install.py'
|
||||
|
||||
# a.s is useful to pass as a single command line:
|
||||
In [5]: !wc -l $a.s
|
||||
146 setup.py
|
||||
130 win32_manual_post_install.py
|
||||
276 total
|
||||
|
||||
# while the list form is useful to loop over:
|
||||
In [6]: for f in a.l:
|
||||
...: !wc -l $f
|
||||
...:
|
||||
146 setup.py
|
||||
130 win32_manual_post_install.py
|
||||
|
||||
Similarly, the lists returned by the -l option are also special, in
|
||||
the sense that you can equally invoke the .s attribute on them to
|
||||
automatically get a whitespace-separated string from their contents::
|
||||
|
||||
In [7]: sc -l b=ls *py
|
||||
|
||||
In [8]: b
|
||||
Out[8]: ['setup.py', 'win32_manual_post_install.py']
|
||||
|
||||
In [9]: b.s
|
||||
Out[9]: 'setup.py win32_manual_post_install.py'
|
||||
|
||||
In summary, both the lists and strings used for output capture have
|
||||
the following special attributes::
|
||||
|
||||
.l (or .list) : value as list.
|
||||
.n (or .nlstr): value as newline-separated string.
|
||||
.s (or .spstr): value as space-separated string.
|
||||
"""
|
||||
|
||||
opts,args = self.parse_options(parameter_s, 'lv')
|
||||
# Try to get a variable name and command to run
|
||||
try:
|
||||
# the variable name must be obtained from the parse_options
|
||||
# output, which uses shlex.split to strip options out.
|
||||
var,_ = args.split('=', 1)
|
||||
var = var.strip()
|
||||
# But the command has to be extracted from the original input
|
||||
# parameter_s, not on what parse_options returns, to avoid the
|
||||
# quote stripping which shlex.split performs on it.
|
||||
_,cmd = parameter_s.split('=', 1)
|
||||
except ValueError:
|
||||
var,cmd = '',''
|
||||
# If all looks ok, proceed
|
||||
split = 'l' in opts
|
||||
out = self.shell.getoutput(cmd, split=split)
|
||||
if 'v' in opts:
|
||||
print('%s ==\n%s' % (var, pformat(out)))
|
||||
if var:
|
||||
self.shell.user_ns.update({var:out})
|
||||
else:
|
||||
return out
|
||||
|
||||
@line_cell_magic
|
||||
def sx(self, line='', cell=None):
|
||||
"""Shell execute - run shell command and capture output (!! is short-hand).
|
||||
|
||||
%sx command
|
||||
|
||||
IPython will run the given command using commands.getoutput(), and
|
||||
return the result formatted as a list (split on '\\n'). Since the
|
||||
output is _returned_, it will be stored in ipython's regular output
|
||||
cache Out[N] and in the '_N' automatic variables.
|
||||
|
||||
Notes:
|
||||
|
||||
1) If an input line begins with '!!', then %sx is automatically
|
||||
invoked. That is, while::
|
||||
|
||||
!ls
|
||||
|
||||
causes ipython to simply issue system('ls'), typing::
|
||||
|
||||
!!ls
|
||||
|
||||
is a shorthand equivalent to::
|
||||
|
||||
%sx ls
|
||||
|
||||
2) %sx differs from %sc in that %sx automatically splits into a list,
|
||||
like '%sc -l'. The reason for this is to make it as easy as possible
|
||||
to process line-oriented shell output via further python commands.
|
||||
%sc is meant to provide much finer control, but requires more
|
||||
typing.
|
||||
|
||||
3) Just like %sc -l, this is a list with special attributes:
|
||||
::
|
||||
|
||||
.l (or .list) : value as list.
|
||||
.n (or .nlstr): value as newline-separated string.
|
||||
.s (or .spstr): value as whitespace-separated string.
|
||||
|
||||
This is very useful when trying to use such lists as arguments to
|
||||
system commands."""
|
||||
|
||||
if cell is None:
|
||||
# line magic
|
||||
return self.shell.getoutput(line)
|
||||
else:
|
||||
opts,args = self.parse_options(line, '', 'out=')
|
||||
output = self.shell.getoutput(cell)
|
||||
out_name = opts.get('out', opts.get('o'))
|
||||
if out_name:
|
||||
self.shell.user_ns[out_name] = output
|
||||
else:
|
||||
return output
|
||||
|
||||
system = line_cell_magic('system')(sx)
|
||||
bang = cell_magic('!')(sx)
|
||||
|
||||
@line_magic
|
||||
def bookmark(self, parameter_s=''):
|
||||
"""Manage IPython's bookmark system.
|
||||
|
||||
%bookmark <name> - set bookmark to current dir
|
||||
%bookmark <name> <dir> - set bookmark to <dir>
|
||||
%bookmark -l - list all bookmarks
|
||||
%bookmark -d <name> - remove bookmark
|
||||
%bookmark -r - remove all bookmarks
|
||||
|
||||
You can later on access a bookmarked folder with::
|
||||
|
||||
%cd -b <name>
|
||||
|
||||
or simply '%cd <name>' if there is no directory called <name> AND
|
||||
there is such a bookmark defined.
|
||||
|
||||
Your bookmarks persist through IPython sessions, but they are
|
||||
associated with each profile."""
|
||||
|
||||
opts,args = self.parse_options(parameter_s,'drl',mode='list')
|
||||
if len(args) > 2:
|
||||
raise UsageError("%bookmark: too many arguments")
|
||||
|
||||
bkms = self.shell.db.get('bookmarks',{})
|
||||
|
||||
if 'd' in opts:
|
||||
try:
|
||||
todel = args[0]
|
||||
except IndexError as e:
|
||||
raise UsageError(
|
||||
"%bookmark -d: must provide a bookmark to delete") from e
|
||||
else:
|
||||
try:
|
||||
del bkms[todel]
|
||||
except KeyError as e:
|
||||
raise UsageError(
|
||||
"%%bookmark -d: Can't delete bookmark '%s'" % todel) from e
|
||||
|
||||
elif 'r' in opts:
|
||||
bkms = {}
|
||||
elif 'l' in opts:
|
||||
bks = sorted(bkms)
|
||||
if bks:
|
||||
size = max(map(len, bks))
|
||||
else:
|
||||
size = 0
|
||||
fmt = '%-'+str(size)+'s -> %s'
|
||||
print('Current bookmarks:')
|
||||
for bk in bks:
|
||||
print(fmt % (bk, bkms[bk]))
|
||||
else:
|
||||
if not args:
|
||||
raise UsageError("%bookmark: You must specify the bookmark name")
|
||||
elif len(args)==1:
|
||||
bkms[args[0]] = os.getcwd()
|
||||
elif len(args)==2:
|
||||
bkms[args[0]] = args[1]
|
||||
self.shell.db['bookmarks'] = bkms
|
||||
|
||||
@line_magic
|
||||
def pycat(self, parameter_s=''):
|
||||
"""Show a syntax-highlighted file through a pager.
|
||||
|
||||
This magic is similar to the cat utility, but it will assume the file
|
||||
to be Python source and will show it with syntax highlighting.
|
||||
|
||||
This magic command can either take a local filename, an url,
|
||||
an history range (see %history) or a macro as argument.
|
||||
|
||||
If no parameter is given, prints out history of current session up to
|
||||
this point. ::
|
||||
|
||||
%pycat myscript.py
|
||||
%pycat 7-27
|
||||
%pycat myMacro
|
||||
%pycat http://www.example.com/myscript.py
|
||||
"""
|
||||
try:
|
||||
cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
|
||||
except (ValueError, IOError):
|
||||
print("Error: no such file, variable, URL, history range or macro")
|
||||
return
|
||||
|
||||
page.page(self.shell.pycolorize(source_to_unicode(cont)))
|
||||
|
||||
@magic_arguments.magic_arguments()
|
||||
@magic_arguments.argument(
|
||||
'-a', '--append', action='store_true', default=False,
|
||||
help='Append contents of the cell to an existing file. '
|
||||
'The file will be created if it does not exist.'
|
||||
)
|
||||
@magic_arguments.argument(
|
||||
'filename', type=str,
|
||||
help='file to write'
|
||||
)
|
||||
@cell_magic
|
||||
def writefile(self, line, cell):
|
||||
"""Write the contents of the cell to a file.
|
||||
|
||||
The file will be overwritten unless the -a (--append) flag is specified.
|
||||
"""
|
||||
args = magic_arguments.parse_argstring(self.writefile, line)
|
||||
if re.match(r'^(\'.*\')|(".*")$', args.filename):
|
||||
filename = os.path.expanduser(args.filename[1:-1])
|
||||
else:
|
||||
filename = os.path.expanduser(args.filename)
|
||||
|
||||
if os.path.exists(filename):
|
||||
if args.append:
|
||||
print("Appending to %s" % filename)
|
||||
else:
|
||||
print("Overwriting %s" % filename)
|
||||
else:
|
||||
print("Writing %s" % filename)
|
||||
|
||||
mode = 'a' if args.append else 'w'
|
||||
with io.open(filename, mode, encoding='utf-8') as f:
|
||||
f.write(cell)
|
112
.venv/Lib/site-packages/IPython/core/magics/packaging.py
Normal file
112
.venv/Lib/site-packages/IPython/core/magics/packaging.py
Normal file
@ -0,0 +1,112 @@
|
||||
"""Implementation of packaging-related magic functions.
|
||||
"""
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (c) 2018 The IPython Development Team.
|
||||
#
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
#
|
||||
# The full license is in the file COPYING.txt, distributed with this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
import re
|
||||
import shlex
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from IPython.core.magic import Magics, magics_class, line_magic
|
||||
|
||||
|
||||
def _is_conda_environment():
|
||||
"""Return True if the current Python executable is in a conda env"""
|
||||
# TODO: does this need to change on windows?
|
||||
return Path(sys.prefix, "conda-meta", "history").exists()
|
||||
|
||||
|
||||
def _get_conda_executable():
|
||||
"""Find the path to the conda executable"""
|
||||
# Check if there is a conda executable in the same directory as the Python executable.
|
||||
# This is the case within conda's root environment.
|
||||
conda = Path(sys.executable).parent / "conda"
|
||||
if conda.is_file():
|
||||
return str(conda)
|
||||
|
||||
# Otherwise, attempt to extract the executable from conda history.
|
||||
# This applies in any conda environment.
|
||||
history = Path(sys.prefix, "conda-meta", "history").read_text(encoding="utf-8")
|
||||
match = re.search(
|
||||
r"^#\s*cmd:\s*(?P<command>.*conda)\s[create|install]",
|
||||
history,
|
||||
flags=re.MULTILINE,
|
||||
)
|
||||
if match:
|
||||
return match.groupdict()["command"]
|
||||
|
||||
# Fallback: assume conda is available on the system path.
|
||||
return "conda"
|
||||
|
||||
|
||||
CONDA_COMMANDS_REQUIRING_PREFIX = {
|
||||
'install', 'list', 'remove', 'uninstall', 'update', 'upgrade',
|
||||
}
|
||||
CONDA_COMMANDS_REQUIRING_YES = {
|
||||
'install', 'remove', 'uninstall', 'update', 'upgrade',
|
||||
}
|
||||
CONDA_ENV_FLAGS = {'-p', '--prefix', '-n', '--name'}
|
||||
CONDA_YES_FLAGS = {'-y', '--y'}
|
||||
|
||||
|
||||
@magics_class
|
||||
class PackagingMagics(Magics):
|
||||
"""Magics related to packaging & installation"""
|
||||
|
||||
@line_magic
|
||||
def pip(self, line):
|
||||
"""Run the pip package manager within the current kernel.
|
||||
|
||||
Usage:
|
||||
%pip install [pkgs]
|
||||
"""
|
||||
python = sys.executable
|
||||
if sys.platform == "win32":
|
||||
python = '"' + python + '"'
|
||||
else:
|
||||
python = shlex.quote(python)
|
||||
|
||||
self.shell.system(" ".join([python, "-m", "pip", line]))
|
||||
|
||||
print("Note: you may need to restart the kernel to use updated packages.")
|
||||
|
||||
@line_magic
|
||||
def conda(self, line):
|
||||
"""Run the conda package manager within the current kernel.
|
||||
|
||||
Usage:
|
||||
%conda install [pkgs]
|
||||
"""
|
||||
if not _is_conda_environment():
|
||||
raise ValueError("The python kernel does not appear to be a conda environment. "
|
||||
"Please use ``%pip install`` instead.")
|
||||
|
||||
conda = _get_conda_executable()
|
||||
args = shlex.split(line)
|
||||
command = args[0] if len(args) > 0 else ""
|
||||
args = args[1:] if len(args) > 1 else [""]
|
||||
|
||||
extra_args = []
|
||||
|
||||
# When the subprocess does not allow us to respond "yes" during the installation,
|
||||
# we need to insert --yes in the argument list for some commands
|
||||
stdin_disabled = getattr(self.shell, 'kernel', None) is not None
|
||||
needs_yes = command in CONDA_COMMANDS_REQUIRING_YES
|
||||
has_yes = set(args).intersection(CONDA_YES_FLAGS)
|
||||
if stdin_disabled and needs_yes and not has_yes:
|
||||
extra_args.append("--yes")
|
||||
|
||||
# Add --prefix to point conda installation to the current environment
|
||||
needs_prefix = command in CONDA_COMMANDS_REQUIRING_PREFIX
|
||||
has_prefix = set(args).intersection(CONDA_ENV_FLAGS)
|
||||
if needs_prefix and not has_prefix:
|
||||
extra_args.extend(["--prefix", sys.prefix])
|
||||
|
||||
self.shell.system(' '.join([conda, command] + extra_args + args))
|
||||
print("\nNote: you may need to restart the kernel to use updated packages.")
|
169
.venv/Lib/site-packages/IPython/core/magics/pylab.py
Normal file
169
.venv/Lib/site-packages/IPython/core/magics/pylab.py
Normal file
@ -0,0 +1,169 @@
|
||||
"""Implementation of magic functions for matplotlib/pylab support.
|
||||
"""
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (c) 2012 The IPython Development Team.
|
||||
#
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
#
|
||||
# The full license is in the file COPYING.txt, distributed with this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Our own packages
|
||||
from traitlets.config.application import Application
|
||||
from IPython.core import magic_arguments
|
||||
from IPython.core.magic import Magics, magics_class, line_magic
|
||||
from IPython.testing.skipdoctest import skip_doctest
|
||||
from warnings import warn
|
||||
from IPython.core.pylabtools import backends
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Magic implementation classes
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
magic_gui_arg = magic_arguments.argument(
|
||||
'gui', nargs='?',
|
||||
help="""Name of the matplotlib backend to use %s.
|
||||
If given, the corresponding matplotlib backend is used,
|
||||
otherwise it will be matplotlib's default
|
||||
(which you can set in your matplotlib config file).
|
||||
""" % str(tuple(sorted(backends.keys())))
|
||||
)
|
||||
|
||||
|
||||
@magics_class
|
||||
class PylabMagics(Magics):
|
||||
"""Magics related to matplotlib's pylab support"""
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
@magic_arguments.magic_arguments()
|
||||
@magic_arguments.argument('-l', '--list', action='store_true',
|
||||
help='Show available matplotlib backends')
|
||||
@magic_gui_arg
|
||||
def matplotlib(self, line=''):
|
||||
"""Set up matplotlib to work interactively.
|
||||
|
||||
This function lets you activate matplotlib interactive support
|
||||
at any point during an IPython session. It does not import anything
|
||||
into the interactive namespace.
|
||||
|
||||
If you are using the inline matplotlib backend in the IPython Notebook
|
||||
you can set which figure formats are enabled using the following::
|
||||
|
||||
In [1]: from IPython.display import set_matplotlib_formats
|
||||
|
||||
In [2]: set_matplotlib_formats('pdf', 'svg')
|
||||
|
||||
The default for inline figures sets `bbox_inches` to 'tight'. This can
|
||||
cause discrepancies between the displayed image and the identical
|
||||
image created using `savefig`. This behavior can be disabled using the
|
||||
`%config` magic::
|
||||
|
||||
In [3]: %config InlineBackend.print_figure_kwargs = {'bbox_inches':None}
|
||||
|
||||
In addition, see the docstring of
|
||||
`IPython.display.set_matplotlib_formats` and
|
||||
`IPython.display.set_matplotlib_close` for more information on
|
||||
changing additional behaviors of the inline backend.
|
||||
|
||||
Examples
|
||||
--------
|
||||
To enable the inline backend for usage with the IPython Notebook::
|
||||
|
||||
In [1]: %matplotlib inline
|
||||
|
||||
In this case, where the matplotlib default is TkAgg::
|
||||
|
||||
In [2]: %matplotlib
|
||||
Using matplotlib backend: TkAgg
|
||||
|
||||
But you can explicitly request a different GUI backend::
|
||||
|
||||
In [3]: %matplotlib qt
|
||||
|
||||
You can list the available backends using the -l/--list option::
|
||||
|
||||
In [4]: %matplotlib --list
|
||||
Available matplotlib backends: ['osx', 'qt4', 'qt5', 'gtk3', 'gtk4', 'notebook', 'wx', 'qt', 'nbagg',
|
||||
'gtk', 'tk', 'inline']
|
||||
"""
|
||||
args = magic_arguments.parse_argstring(self.matplotlib, line)
|
||||
if args.list:
|
||||
backends_list = list(backends.keys())
|
||||
print("Available matplotlib backends: %s" % backends_list)
|
||||
else:
|
||||
gui, backend = self.shell.enable_matplotlib(args.gui.lower() if isinstance(args.gui, str) else args.gui)
|
||||
self._show_matplotlib_backend(args.gui, backend)
|
||||
|
||||
@skip_doctest
|
||||
@line_magic
|
||||
@magic_arguments.magic_arguments()
|
||||
@magic_arguments.argument(
|
||||
'--no-import-all', action='store_true', default=None,
|
||||
help="""Prevent IPython from performing ``import *`` into the interactive namespace.
|
||||
|
||||
You can govern the default behavior of this flag with the
|
||||
InteractiveShellApp.pylab_import_all configurable.
|
||||
"""
|
||||
)
|
||||
@magic_gui_arg
|
||||
def pylab(self, line=''):
|
||||
"""Load numpy and matplotlib to work interactively.
|
||||
|
||||
This function lets you activate pylab (matplotlib, numpy and
|
||||
interactive support) at any point during an IPython session.
|
||||
|
||||
%pylab makes the following imports::
|
||||
|
||||
import numpy
|
||||
import matplotlib
|
||||
from matplotlib import pylab, mlab, pyplot
|
||||
np = numpy
|
||||
plt = pyplot
|
||||
|
||||
from IPython.display import display
|
||||
from IPython.core.pylabtools import figsize, getfigs
|
||||
|
||||
from pylab import *
|
||||
from numpy import *
|
||||
|
||||
If you pass `--no-import-all`, the last two `*` imports will be excluded.
|
||||
|
||||
See the %matplotlib magic for more details about activating matplotlib
|
||||
without affecting the interactive namespace.
|
||||
"""
|
||||
args = magic_arguments.parse_argstring(self.pylab, line)
|
||||
if args.no_import_all is None:
|
||||
# get default from Application
|
||||
if Application.initialized():
|
||||
app = Application.instance()
|
||||
try:
|
||||
import_all = app.pylab_import_all
|
||||
except AttributeError:
|
||||
import_all = True
|
||||
else:
|
||||
# nothing specified, no app - default True
|
||||
import_all = True
|
||||
else:
|
||||
# invert no-import flag
|
||||
import_all = not args.no_import_all
|
||||
|
||||
gui, backend, clobbered = self.shell.enable_pylab(args.gui, import_all=import_all)
|
||||
self._show_matplotlib_backend(args.gui, backend)
|
||||
print(
|
||||
"%pylab is deprecated, use %matplotlib inline and import the required libraries."
|
||||
)
|
||||
print("Populating the interactive namespace from numpy and matplotlib")
|
||||
if clobbered:
|
||||
warn("pylab import has clobbered these variables: %s" % clobbered +
|
||||
"\n`%matplotlib` prevents importing * from pylab and numpy"
|
||||
)
|
||||
|
||||
def _show_matplotlib_backend(self, gui, backend):
|
||||
"""show matplotlib message backend message"""
|
||||
if not gui or gui == 'auto':
|
||||
print("Using matplotlib backend: %s" % backend)
|
362
.venv/Lib/site-packages/IPython/core/magics/script.py
Normal file
362
.venv/Lib/site-packages/IPython/core/magics/script.py
Normal file
@ -0,0 +1,362 @@
|
||||
"""Magic functions for running cells in various scripts."""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import asyncio
|
||||
import atexit
|
||||
import errno
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
from subprocess import CalledProcessError
|
||||
from threading import Thread
|
||||
|
||||
from traitlets import Any, Dict, List, default
|
||||
|
||||
from IPython.core import magic_arguments
|
||||
from IPython.core.async_helpers import _AsyncIOProxy
|
||||
from IPython.core.magic import Magics, cell_magic, line_magic, magics_class
|
||||
from IPython.utils.process import arg_split
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Magic implementation classes
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def script_args(f):
|
||||
"""single decorator for adding script args"""
|
||||
args = [
|
||||
magic_arguments.argument(
|
||||
'--out', type=str,
|
||||
help="""The variable in which to store stdout from the script.
|
||||
If the script is backgrounded, this will be the stdout *pipe*,
|
||||
instead of the stderr text itself and will not be auto closed.
|
||||
"""
|
||||
),
|
||||
magic_arguments.argument(
|
||||
'--err', type=str,
|
||||
help="""The variable in which to store stderr from the script.
|
||||
If the script is backgrounded, this will be the stderr *pipe*,
|
||||
instead of the stderr text itself and will not be autoclosed.
|
||||
"""
|
||||
),
|
||||
magic_arguments.argument(
|
||||
'--bg', action="store_true",
|
||||
help="""Whether to run the script in the background.
|
||||
If given, the only way to see the output of the command is
|
||||
with --out/err.
|
||||
"""
|
||||
),
|
||||
magic_arguments.argument(
|
||||
'--proc', type=str,
|
||||
help="""The variable in which to store Popen instance.
|
||||
This is used only when --bg option is given.
|
||||
"""
|
||||
),
|
||||
magic_arguments.argument(
|
||||
'--no-raise-error', action="store_false", dest='raise_error',
|
||||
help="""Whether you should raise an error message in addition to
|
||||
a stream on stderr if you get a nonzero exit code.
|
||||
""",
|
||||
),
|
||||
]
|
||||
for arg in args:
|
||||
f = arg(f)
|
||||
return f
|
||||
|
||||
|
||||
@magics_class
|
||||
class ScriptMagics(Magics):
|
||||
"""Magics for talking to scripts
|
||||
|
||||
This defines a base `%%script` cell magic for running a cell
|
||||
with a program in a subprocess, and registers a few top-level
|
||||
magics that call %%script with common interpreters.
|
||||
"""
|
||||
|
||||
event_loop = Any(
|
||||
help="""
|
||||
The event loop on which to run subprocesses
|
||||
|
||||
Not the main event loop,
|
||||
because we want to be able to make blocking calls
|
||||
and have certain requirements we don't want to impose on the main loop.
|
||||
"""
|
||||
)
|
||||
|
||||
script_magics = List(
|
||||
help="""Extra script cell magics to define
|
||||
|
||||
This generates simple wrappers of `%%script foo` as `%%foo`.
|
||||
|
||||
If you want to add script magics that aren't on your path,
|
||||
specify them in script_paths
|
||||
""",
|
||||
).tag(config=True)
|
||||
@default('script_magics')
|
||||
def _script_magics_default(self):
|
||||
"""default to a common list of programs"""
|
||||
|
||||
defaults = [
|
||||
'sh',
|
||||
'bash',
|
||||
'perl',
|
||||
'ruby',
|
||||
'python',
|
||||
'python2',
|
||||
'python3',
|
||||
'pypy',
|
||||
]
|
||||
if os.name == 'nt':
|
||||
defaults.extend([
|
||||
'cmd',
|
||||
])
|
||||
|
||||
return defaults
|
||||
|
||||
script_paths = Dict(
|
||||
help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby'
|
||||
|
||||
Only necessary for items in script_magics where the default path will not
|
||||
find the right interpreter.
|
||||
"""
|
||||
).tag(config=True)
|
||||
|
||||
def __init__(self, shell=None):
|
||||
super(ScriptMagics, self).__init__(shell=shell)
|
||||
self._generate_script_magics()
|
||||
self.bg_processes = []
|
||||
atexit.register(self.kill_bg_processes)
|
||||
|
||||
def __del__(self):
|
||||
self.kill_bg_processes()
|
||||
|
||||
def _generate_script_magics(self):
|
||||
cell_magics = self.magics['cell']
|
||||
for name in self.script_magics:
|
||||
cell_magics[name] = self._make_script_magic(name)
|
||||
|
||||
def _make_script_magic(self, name):
|
||||
"""make a named magic, that calls %%script with a particular program"""
|
||||
# expand to explicit path if necessary:
|
||||
script = self.script_paths.get(name, name)
|
||||
|
||||
@magic_arguments.magic_arguments()
|
||||
@script_args
|
||||
def named_script_magic(line, cell):
|
||||
# if line, add it as cl-flags
|
||||
if line:
|
||||
line = "%s %s" % (script, line)
|
||||
else:
|
||||
line = script
|
||||
return self.shebang(line, cell)
|
||||
|
||||
# write a basic docstring:
|
||||
named_script_magic.__doc__ = \
|
||||
"""%%{name} script magic
|
||||
|
||||
Run cells with {script} in a subprocess.
|
||||
|
||||
This is a shortcut for `%%script {script}`
|
||||
""".format(**locals())
|
||||
|
||||
return named_script_magic
|
||||
|
||||
@magic_arguments.magic_arguments()
|
||||
@script_args
|
||||
@cell_magic("script")
|
||||
def shebang(self, line, cell):
|
||||
"""Run a cell via a shell command
|
||||
|
||||
The `%%script` line is like the #! line of script,
|
||||
specifying a program (bash, perl, ruby, etc.) with which to run.
|
||||
|
||||
The rest of the cell is run by that program.
|
||||
|
||||
Examples
|
||||
--------
|
||||
::
|
||||
|
||||
In [1]: %%script bash
|
||||
...: for i in 1 2 3; do
|
||||
...: echo $i
|
||||
...: done
|
||||
1
|
||||
2
|
||||
3
|
||||
"""
|
||||
|
||||
# Create the event loop in which to run script magics
|
||||
# this operates on a background thread
|
||||
if self.event_loop is None:
|
||||
if sys.platform == "win32":
|
||||
# don't override the current policy,
|
||||
# just create an event loop
|
||||
event_loop = asyncio.WindowsProactorEventLoopPolicy().new_event_loop()
|
||||
else:
|
||||
event_loop = asyncio.new_event_loop()
|
||||
self.event_loop = event_loop
|
||||
|
||||
# start the loop in a background thread
|
||||
asyncio_thread = Thread(target=event_loop.run_forever, daemon=True)
|
||||
asyncio_thread.start()
|
||||
else:
|
||||
event_loop = self.event_loop
|
||||
|
||||
def in_thread(coro):
|
||||
"""Call a coroutine on the asyncio thread"""
|
||||
return asyncio.run_coroutine_threadsafe(coro, event_loop).result()
|
||||
|
||||
async def _handle_stream(stream, stream_arg, file_object):
|
||||
while True:
|
||||
line = (await stream.readline()).decode("utf8")
|
||||
if not line:
|
||||
break
|
||||
if stream_arg:
|
||||
self.shell.user_ns[stream_arg] = line
|
||||
else:
|
||||
file_object.write(line)
|
||||
file_object.flush()
|
||||
|
||||
async def _stream_communicate(process, cell):
|
||||
process.stdin.write(cell)
|
||||
process.stdin.close()
|
||||
stdout_task = asyncio.create_task(
|
||||
_handle_stream(process.stdout, args.out, sys.stdout)
|
||||
)
|
||||
stderr_task = asyncio.create_task(
|
||||
_handle_stream(process.stderr, args.err, sys.stderr)
|
||||
)
|
||||
await asyncio.wait([stdout_task, stderr_task])
|
||||
await process.wait()
|
||||
|
||||
argv = arg_split(line, posix=not sys.platform.startswith("win"))
|
||||
args, cmd = self.shebang.parser.parse_known_args(argv)
|
||||
|
||||
try:
|
||||
p = in_thread(
|
||||
asyncio.create_subprocess_exec(
|
||||
*cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
stdin=asyncio.subprocess.PIPE,
|
||||
)
|
||||
)
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
print("Couldn't find program: %r" % cmd[0])
|
||||
return
|
||||
else:
|
||||
raise
|
||||
|
||||
if not cell.endswith('\n'):
|
||||
cell += '\n'
|
||||
cell = cell.encode('utf8', 'replace')
|
||||
if args.bg:
|
||||
self.bg_processes.append(p)
|
||||
self._gc_bg_processes()
|
||||
to_close = []
|
||||
if args.out:
|
||||
self.shell.user_ns[args.out] = _AsyncIOProxy(p.stdout, event_loop)
|
||||
else:
|
||||
to_close.append(p.stdout)
|
||||
if args.err:
|
||||
self.shell.user_ns[args.err] = _AsyncIOProxy(p.stderr, event_loop)
|
||||
else:
|
||||
to_close.append(p.stderr)
|
||||
event_loop.call_soon_threadsafe(
|
||||
lambda: asyncio.Task(self._run_script(p, cell, to_close))
|
||||
)
|
||||
if args.proc:
|
||||
proc_proxy = _AsyncIOProxy(p, event_loop)
|
||||
proc_proxy.stdout = _AsyncIOProxy(p.stdout, event_loop)
|
||||
proc_proxy.stderr = _AsyncIOProxy(p.stderr, event_loop)
|
||||
self.shell.user_ns[args.proc] = proc_proxy
|
||||
return
|
||||
|
||||
try:
|
||||
in_thread(_stream_communicate(p, cell))
|
||||
except KeyboardInterrupt:
|
||||
try:
|
||||
p.send_signal(signal.SIGINT)
|
||||
in_thread(asyncio.wait_for(p.wait(), timeout=0.1))
|
||||
if p.returncode is not None:
|
||||
print("Process is interrupted.")
|
||||
return
|
||||
p.terminate()
|
||||
in_thread(asyncio.wait_for(p.wait(), timeout=0.1))
|
||||
if p.returncode is not None:
|
||||
print("Process is terminated.")
|
||||
return
|
||||
p.kill()
|
||||
print("Process is killed.")
|
||||
except OSError:
|
||||
pass
|
||||
except Exception as e:
|
||||
print("Error while terminating subprocess (pid=%i): %s" % (p.pid, e))
|
||||
return
|
||||
|
||||
if args.raise_error and p.returncode != 0:
|
||||
# If we get here and p.returncode is still None, we must have
|
||||
# killed it but not yet seen its return code. We don't wait for it,
|
||||
# in case it's stuck in uninterruptible sleep. -9 = SIGKILL
|
||||
rc = p.returncode or -9
|
||||
raise CalledProcessError(rc, cell)
|
||||
|
||||
shebang.__skip_doctest__ = os.name != "posix"
|
||||
|
||||
async def _run_script(self, p, cell, to_close):
|
||||
"""callback for running the script in the background"""
|
||||
|
||||
p.stdin.write(cell)
|
||||
await p.stdin.drain()
|
||||
p.stdin.close()
|
||||
await p.stdin.wait_closed()
|
||||
await p.wait()
|
||||
# asyncio read pipes have no close
|
||||
# but we should drain the data anyway
|
||||
for s in to_close:
|
||||
await s.read()
|
||||
self._gc_bg_processes()
|
||||
|
||||
@line_magic("killbgscripts")
|
||||
def killbgscripts(self, _nouse_=''):
|
||||
"""Kill all BG processes started by %%script and its family."""
|
||||
self.kill_bg_processes()
|
||||
print("All background processes were killed.")
|
||||
|
||||
def kill_bg_processes(self):
|
||||
"""Kill all BG processes which are still running."""
|
||||
if not self.bg_processes:
|
||||
return
|
||||
for p in self.bg_processes:
|
||||
if p.returncode is None:
|
||||
try:
|
||||
p.send_signal(signal.SIGINT)
|
||||
except:
|
||||
pass
|
||||
time.sleep(0.1)
|
||||
self._gc_bg_processes()
|
||||
if not self.bg_processes:
|
||||
return
|
||||
for p in self.bg_processes:
|
||||
if p.returncode is None:
|
||||
try:
|
||||
p.terminate()
|
||||
except:
|
||||
pass
|
||||
time.sleep(0.1)
|
||||
self._gc_bg_processes()
|
||||
if not self.bg_processes:
|
||||
return
|
||||
for p in self.bg_processes:
|
||||
if p.returncode is None:
|
||||
try:
|
||||
p.kill()
|
||||
except:
|
||||
pass
|
||||
self._gc_bg_processes()
|
||||
|
||||
def _gc_bg_processes(self):
|
||||
self.bg_processes = [p for p in self.bg_processes if p.returncode is None]
|
Reference in New Issue
Block a user