Spaces:
Running
on
Zero
Running
on
Zero
Fixed font issues.
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- openalex_env_map/lib/python3.10/site-packages/IPython/__init__.py +0 -163
- openalex_env_map/lib/python3.10/site-packages/IPython/__main__.py +0 -15
- openalex_env_map/lib/python3.10/site-packages/IPython/conftest.py +0 -87
- openalex_env_map/lib/python3.10/site-packages/IPython/consoleapp.py +0 -12
- openalex_env_map/lib/python3.10/site-packages/IPython/core/__init__.py +0 -0
- openalex_env_map/lib/python3.10/site-packages/IPython/core/alias.py +0 -267
- openalex_env_map/lib/python3.10/site-packages/IPython/core/application.py +0 -492
- openalex_env_map/lib/python3.10/site-packages/IPython/core/async_helpers.py +0 -155
- openalex_env_map/lib/python3.10/site-packages/IPython/core/autocall.py +0 -70
- openalex_env_map/lib/python3.10/site-packages/IPython/core/builtin_trap.py +0 -86
- openalex_env_map/lib/python3.10/site-packages/IPython/core/compilerop.py +0 -214
- openalex_env_map/lib/python3.10/site-packages/IPython/core/completer.py +0 -0
- openalex_env_map/lib/python3.10/site-packages/IPython/core/completerlib.py +0 -382
- openalex_env_map/lib/python3.10/site-packages/IPython/core/crashhandler.py +0 -248
- openalex_env_map/lib/python3.10/site-packages/IPython/core/debugger.py +0 -1136
- openalex_env_map/lib/python3.10/site-packages/IPython/core/display.py +0 -1373
- openalex_env_map/lib/python3.10/site-packages/IPython/core/display_functions.py +0 -391
- openalex_env_map/lib/python3.10/site-packages/IPython/core/display_trap.py +0 -70
- openalex_env_map/lib/python3.10/site-packages/IPython/core/displayhook.py +0 -336
- openalex_env_map/lib/python3.10/site-packages/IPython/core/displaypub.py +0 -149
- openalex_env_map/lib/python3.10/site-packages/IPython/core/error.py +0 -60
- openalex_env_map/lib/python3.10/site-packages/IPython/core/events.py +0 -158
- openalex_env_map/lib/python3.10/site-packages/IPython/core/excolors.py +0 -192
- openalex_env_map/lib/python3.10/site-packages/IPython/core/extensions.py +0 -135
- openalex_env_map/lib/python3.10/site-packages/IPython/core/formatters.py +0 -1090
- openalex_env_map/lib/python3.10/site-packages/IPython/core/getipython.py +0 -24
- openalex_env_map/lib/python3.10/site-packages/IPython/core/guarded_eval.py +0 -895
- openalex_env_map/lib/python3.10/site-packages/IPython/core/history.py +0 -989
- openalex_env_map/lib/python3.10/site-packages/IPython/core/historyapp.py +0 -158
- openalex_env_map/lib/python3.10/site-packages/IPython/core/hooks.py +0 -173
- openalex_env_map/lib/python3.10/site-packages/IPython/core/inputsplitter.py +0 -799
- openalex_env_map/lib/python3.10/site-packages/IPython/core/inputtransformer.py +0 -577
- openalex_env_map/lib/python3.10/site-packages/IPython/core/inputtransformer2.py +0 -830
- openalex_env_map/lib/python3.10/site-packages/IPython/core/interactiveshell.py +0 -0
- openalex_env_map/lib/python3.10/site-packages/IPython/core/latex_symbols.py +0 -1301
- openalex_env_map/lib/python3.10/site-packages/IPython/core/logger.py +0 -231
- openalex_env_map/lib/python3.10/site-packages/IPython/core/macro.py +0 -53
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magic.py +0 -759
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magic_arguments.py +0 -310
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/__init__.py +0 -42
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/ast_mod.py +0 -330
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/auto.py +0 -144
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/basic.py +0 -666
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/code.py +0 -757
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/config.py +0 -140
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/display.py +0 -93
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/execution.py +0 -1624
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/extension.py +0 -63
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/history.py +0 -338
- openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/logging.py +0 -195
openalex_env_map/lib/python3.10/site-packages/IPython/__init__.py
DELETED
@@ -1,163 +0,0 @@
|
|
1 |
-
# PYTHON_ARGCOMPLETE_OK
|
2 |
-
"""
|
3 |
-
IPython: tools for interactive and parallel computing in Python.
|
4 |
-
|
5 |
-
https://ipython.org
|
6 |
-
"""
|
7 |
-
#-----------------------------------------------------------------------------
|
8 |
-
# Copyright (c) 2008-2011, IPython Development Team.
|
9 |
-
# Copyright (c) 2001-2007, Fernando Perez <[email protected]>
|
10 |
-
# Copyright (c) 2001, Janko Hauser <[email protected]>
|
11 |
-
# Copyright (c) 2001, Nathaniel Gray <[email protected]>
|
12 |
-
#
|
13 |
-
# Distributed under the terms of the Modified BSD License.
|
14 |
-
#
|
15 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
16 |
-
#-----------------------------------------------------------------------------
|
17 |
-
|
18 |
-
#-----------------------------------------------------------------------------
|
19 |
-
# Imports
|
20 |
-
#-----------------------------------------------------------------------------
|
21 |
-
|
22 |
-
import sys
|
23 |
-
|
24 |
-
#-----------------------------------------------------------------------------
|
25 |
-
# Setup everything
|
26 |
-
#-----------------------------------------------------------------------------
|
27 |
-
|
28 |
-
# Don't forget to also update setup.py when this changes!
|
29 |
-
if sys.version_info < (3, 10):
|
30 |
-
raise ImportError(
|
31 |
-
"""
|
32 |
-
IPython 8.19+ supports Python 3.10 and above, following SPEC0.
|
33 |
-
IPython 8.13+ supports Python 3.9 and above, following NEP 29.
|
34 |
-
IPython 8.0-8.12 supports Python 3.8 and above, following NEP 29.
|
35 |
-
When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
|
36 |
-
Python 3.3 and 3.4 were supported up to IPython 6.x.
|
37 |
-
Python 3.5 was supported with IPython 7.0 to 7.9.
|
38 |
-
Python 3.6 was supported with IPython up to 7.16.
|
39 |
-
Python 3.7 was still supported with the 7.x branch.
|
40 |
-
|
41 |
-
See IPython `README.rst` file for more information:
|
42 |
-
|
43 |
-
https://github.com/ipython/ipython/blob/main/README.rst
|
44 |
-
|
45 |
-
"""
|
46 |
-
)
|
47 |
-
|
48 |
-
#-----------------------------------------------------------------------------
|
49 |
-
# Setup the top level names
|
50 |
-
#-----------------------------------------------------------------------------
|
51 |
-
|
52 |
-
from .core.getipython import get_ipython
|
53 |
-
from .core import release
|
54 |
-
from .core.application import Application
|
55 |
-
from .terminal.embed import embed
|
56 |
-
|
57 |
-
from .core.interactiveshell import InteractiveShell
|
58 |
-
from .utils.sysinfo import sys_info
|
59 |
-
from .utils.frame import extract_module_locals
|
60 |
-
|
61 |
-
__all__ = ["start_ipython", "embed", "start_kernel", "embed_kernel"]
|
62 |
-
|
63 |
-
# Release data
|
64 |
-
__author__ = '%s <%s>' % (release.author, release.author_email)
|
65 |
-
__license__ = release.license
|
66 |
-
__version__ = release.version
|
67 |
-
version_info = release.version_info
|
68 |
-
# list of CVEs that should have been patched in this release.
|
69 |
-
# this is informational and should not be relied upon.
|
70 |
-
__patched_cves__ = {"CVE-2022-21699", "CVE-2023-24816"}
|
71 |
-
|
72 |
-
|
73 |
-
def embed_kernel(module=None, local_ns=None, **kwargs):
|
74 |
-
"""Embed and start an IPython kernel in a given scope.
|
75 |
-
|
76 |
-
If you don't want the kernel to initialize the namespace
|
77 |
-
from the scope of the surrounding function,
|
78 |
-
and/or you want to load full IPython configuration,
|
79 |
-
you probably want `IPython.start_kernel()` instead.
|
80 |
-
|
81 |
-
Parameters
|
82 |
-
----------
|
83 |
-
module : types.ModuleType, optional
|
84 |
-
The module to load into IPython globals (default: caller)
|
85 |
-
local_ns : dict, optional
|
86 |
-
The namespace to load into IPython user namespace (default: caller)
|
87 |
-
**kwargs : various, optional
|
88 |
-
Further keyword args are relayed to the IPKernelApp constructor,
|
89 |
-
such as `config`, a traitlets :class:`Config` object (see :ref:`configure_start_ipython`),
|
90 |
-
allowing configuration of the kernel (see :ref:`kernel_options`). Will only have an effect
|
91 |
-
on the first embed_kernel call for a given process.
|
92 |
-
"""
|
93 |
-
|
94 |
-
(caller_module, caller_locals) = extract_module_locals(1)
|
95 |
-
if module is None:
|
96 |
-
module = caller_module
|
97 |
-
if local_ns is None:
|
98 |
-
local_ns = caller_locals
|
99 |
-
|
100 |
-
# Only import .zmq when we really need it
|
101 |
-
from ipykernel.embed import embed_kernel as real_embed_kernel
|
102 |
-
real_embed_kernel(module=module, local_ns=local_ns, **kwargs)
|
103 |
-
|
104 |
-
def start_ipython(argv=None, **kwargs):
|
105 |
-
"""Launch a normal IPython instance (as opposed to embedded)
|
106 |
-
|
107 |
-
`IPython.embed()` puts a shell in a particular calling scope,
|
108 |
-
such as a function or method for debugging purposes,
|
109 |
-
which is often not desirable.
|
110 |
-
|
111 |
-
`start_ipython()` does full, regular IPython initialization,
|
112 |
-
including loading startup files, configuration, etc.
|
113 |
-
much of which is skipped by `embed()`.
|
114 |
-
|
115 |
-
This is a public API method, and will survive implementation changes.
|
116 |
-
|
117 |
-
Parameters
|
118 |
-
----------
|
119 |
-
argv : list or None, optional
|
120 |
-
If unspecified or None, IPython will parse command-line options from sys.argv.
|
121 |
-
To prevent any command-line parsing, pass an empty list: `argv=[]`.
|
122 |
-
user_ns : dict, optional
|
123 |
-
specify this dictionary to initialize the IPython user namespace with particular values.
|
124 |
-
**kwargs : various, optional
|
125 |
-
Any other kwargs will be passed to the Application constructor,
|
126 |
-
such as `config`, a traitlets :class:`Config` object (see :ref:`configure_start_ipython`),
|
127 |
-
allowing configuration of the instance (see :ref:`terminal_options`).
|
128 |
-
"""
|
129 |
-
from IPython.terminal.ipapp import launch_new_instance
|
130 |
-
return launch_new_instance(argv=argv, **kwargs)
|
131 |
-
|
132 |
-
def start_kernel(argv=None, **kwargs):
|
133 |
-
"""Launch a normal IPython kernel instance (as opposed to embedded)
|
134 |
-
|
135 |
-
`IPython.embed_kernel()` puts a shell in a particular calling scope,
|
136 |
-
such as a function or method for debugging purposes,
|
137 |
-
which is often not desirable.
|
138 |
-
|
139 |
-
`start_kernel()` does full, regular IPython initialization,
|
140 |
-
including loading startup files, configuration, etc.
|
141 |
-
much of which is skipped by `embed_kernel()`.
|
142 |
-
|
143 |
-
Parameters
|
144 |
-
----------
|
145 |
-
argv : list or None, optional
|
146 |
-
If unspecified or None, IPython will parse command-line options from sys.argv.
|
147 |
-
To prevent any command-line parsing, pass an empty list: `argv=[]`.
|
148 |
-
user_ns : dict, optional
|
149 |
-
specify this dictionary to initialize the IPython user namespace with particular values.
|
150 |
-
**kwargs : various, optional
|
151 |
-
Any other kwargs will be passed to the Application constructor,
|
152 |
-
such as `config`, a traitlets :class:`Config` object (see :ref:`configure_start_ipython`),
|
153 |
-
allowing configuration of the kernel (see :ref:`kernel_options`).
|
154 |
-
"""
|
155 |
-
import warnings
|
156 |
-
|
157 |
-
warnings.warn(
|
158 |
-
"start_kernel is deprecated since IPython 8.0, use from `ipykernel.kernelapp.launch_new_instance`",
|
159 |
-
DeprecationWarning,
|
160 |
-
stacklevel=2,
|
161 |
-
)
|
162 |
-
from ipykernel.kernelapp import launch_new_instance
|
163 |
-
return launch_new_instance(argv=argv, **kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/__main__.py
DELETED
@@ -1,15 +0,0 @@
|
|
1 |
-
# PYTHON_ARGCOMPLETE_OK
|
2 |
-
# encoding: utf-8
|
3 |
-
"""Terminal-based IPython entry point.
|
4 |
-
"""
|
5 |
-
# -----------------------------------------------------------------------------
|
6 |
-
# Copyright (c) 2012, IPython Development Team.
|
7 |
-
#
|
8 |
-
# Distributed under the terms of the Modified BSD License.
|
9 |
-
#
|
10 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
11 |
-
# -----------------------------------------------------------------------------
|
12 |
-
|
13 |
-
from IPython import start_ipython
|
14 |
-
|
15 |
-
start_ipython()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/conftest.py
DELETED
@@ -1,87 +0,0 @@
|
|
1 |
-
import builtins
|
2 |
-
import inspect
|
3 |
-
import os
|
4 |
-
import pathlib
|
5 |
-
import shutil
|
6 |
-
import sys
|
7 |
-
import types
|
8 |
-
|
9 |
-
import pytest
|
10 |
-
|
11 |
-
# Must register before it gets imported
|
12 |
-
pytest.register_assert_rewrite("IPython.testing.tools")
|
13 |
-
|
14 |
-
from .testing import tools
|
15 |
-
|
16 |
-
|
17 |
-
def pytest_collection_modifyitems(items):
|
18 |
-
"""This function is automatically run by pytest passing all collected test
|
19 |
-
functions.
|
20 |
-
|
21 |
-
We use it to add asyncio marker to all async tests and assert we don't use
|
22 |
-
test functions that are async generators which wouldn't make sense.
|
23 |
-
"""
|
24 |
-
for item in items:
|
25 |
-
if inspect.iscoroutinefunction(item.obj):
|
26 |
-
item.add_marker("asyncio")
|
27 |
-
assert not inspect.isasyncgenfunction(item.obj)
|
28 |
-
|
29 |
-
|
30 |
-
def get_ipython():
|
31 |
-
from .terminal.interactiveshell import TerminalInteractiveShell
|
32 |
-
if TerminalInteractiveShell._instance:
|
33 |
-
return TerminalInteractiveShell.instance()
|
34 |
-
|
35 |
-
config = tools.default_config()
|
36 |
-
config.TerminalInteractiveShell.simple_prompt = True
|
37 |
-
|
38 |
-
# Create and initialize our test-friendly IPython instance.
|
39 |
-
shell = TerminalInteractiveShell.instance(config=config)
|
40 |
-
return shell
|
41 |
-
|
42 |
-
|
43 |
-
@pytest.fixture(scope='session', autouse=True)
|
44 |
-
def work_path():
|
45 |
-
path = pathlib.Path("./tmp-ipython-pytest-profiledir")
|
46 |
-
os.environ["IPYTHONDIR"] = str(path.absolute())
|
47 |
-
if path.exists():
|
48 |
-
raise ValueError('IPython dir temporary path already exists ! Did previous test run exit successfully ?')
|
49 |
-
path.mkdir()
|
50 |
-
yield
|
51 |
-
shutil.rmtree(str(path.resolve()))
|
52 |
-
|
53 |
-
|
54 |
-
def nopage(strng, start=0, screen_lines=0, pager_cmd=None):
|
55 |
-
if isinstance(strng, dict):
|
56 |
-
strng = strng.get("text/plain", "")
|
57 |
-
print(strng)
|
58 |
-
|
59 |
-
|
60 |
-
def xsys(self, cmd):
|
61 |
-
"""Replace the default system call with a capturing one for doctest.
|
62 |
-
"""
|
63 |
-
# We use getoutput, but we need to strip it because pexpect captures
|
64 |
-
# the trailing newline differently from commands.getoutput
|
65 |
-
print(self.getoutput(cmd, split=False, depth=1).rstrip(), end="", file=sys.stdout)
|
66 |
-
sys.stdout.flush()
|
67 |
-
|
68 |
-
|
69 |
-
# for things to work correctly we would need this as a session fixture;
|
70 |
-
# unfortunately this will fail on some test that get executed as _collection_
|
71 |
-
# time (before the fixture run), in particular parametrized test that contain
|
72 |
-
# yields. so for now execute at import time.
|
73 |
-
#@pytest.fixture(autouse=True, scope='session')
|
74 |
-
def inject():
|
75 |
-
|
76 |
-
builtins.get_ipython = get_ipython
|
77 |
-
builtins._ip = get_ipython()
|
78 |
-
builtins.ip = get_ipython()
|
79 |
-
builtins.ip.system = types.MethodType(xsys, ip)
|
80 |
-
builtins.ip.builtin_trap.activate()
|
81 |
-
from .core import page
|
82 |
-
|
83 |
-
page.pager_page = nopage
|
84 |
-
# yield
|
85 |
-
|
86 |
-
|
87 |
-
inject()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/consoleapp.py
DELETED
@@ -1,12 +0,0 @@
|
|
1 |
-
"""
|
2 |
-
Shim to maintain backwards compatibility with old IPython.consoleapp imports.
|
3 |
-
"""
|
4 |
-
# Copyright (c) IPython Development Team.
|
5 |
-
# Distributed under the terms of the Modified BSD License.
|
6 |
-
|
7 |
-
from warnings import warn
|
8 |
-
|
9 |
-
warn("The `IPython.consoleapp` package has been deprecated since IPython 4.0."
|
10 |
-
"You should import from jupyter_client.consoleapp instead.", stacklevel=2)
|
11 |
-
|
12 |
-
from jupyter_client.consoleapp import *
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/__init__.py
DELETED
File without changes
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/alias.py
DELETED
@@ -1,267 +0,0 @@
|
|
1 |
-
# encoding: utf-8
|
2 |
-
"""
|
3 |
-
System command aliases.
|
4 |
-
|
5 |
-
Authors:
|
6 |
-
|
7 |
-
* Fernando Perez
|
8 |
-
* Brian Granger
|
9 |
-
"""
|
10 |
-
|
11 |
-
#-----------------------------------------------------------------------------
|
12 |
-
# Copyright (C) 2008-2011 The IPython Development Team
|
13 |
-
#
|
14 |
-
# Distributed under the terms of the BSD License.
|
15 |
-
#
|
16 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
17 |
-
#-----------------------------------------------------------------------------
|
18 |
-
|
19 |
-
#-----------------------------------------------------------------------------
|
20 |
-
# Imports
|
21 |
-
#-----------------------------------------------------------------------------
|
22 |
-
|
23 |
-
import os
|
24 |
-
import re
|
25 |
-
import sys
|
26 |
-
|
27 |
-
from traitlets.config.configurable import Configurable
|
28 |
-
from .error import UsageError
|
29 |
-
|
30 |
-
from traitlets import List, Instance
|
31 |
-
from logging import error
|
32 |
-
|
33 |
-
import typing as t
|
34 |
-
|
35 |
-
|
36 |
-
#-----------------------------------------------------------------------------
|
37 |
-
# Utilities
|
38 |
-
#-----------------------------------------------------------------------------
|
39 |
-
|
40 |
-
# This is used as the pattern for calls to split_user_input.
|
41 |
-
shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
|
42 |
-
|
43 |
-
def default_aliases() -> t.List[t.Tuple[str, str]]:
|
44 |
-
"""Return list of shell aliases to auto-define.
|
45 |
-
"""
|
46 |
-
# Note: the aliases defined here should be safe to use on a kernel
|
47 |
-
# regardless of what frontend it is attached to. Frontends that use a
|
48 |
-
# kernel in-process can define additional aliases that will only work in
|
49 |
-
# their case. For example, things like 'less' or 'clear' that manipulate
|
50 |
-
# the terminal should NOT be declared here, as they will only work if the
|
51 |
-
# kernel is running inside a true terminal, and not over the network.
|
52 |
-
|
53 |
-
if os.name == 'posix':
|
54 |
-
default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
|
55 |
-
('mv', 'mv'), ('rm', 'rm'), ('cp', 'cp'),
|
56 |
-
('cat', 'cat'),
|
57 |
-
]
|
58 |
-
# Useful set of ls aliases. The GNU and BSD options are a little
|
59 |
-
# different, so we make aliases that provide as similar as possible
|
60 |
-
# behavior in ipython, by passing the right flags for each platform
|
61 |
-
if sys.platform.startswith('linux'):
|
62 |
-
ls_aliases = [('ls', 'ls -F --color'),
|
63 |
-
# long ls
|
64 |
-
('ll', 'ls -F -o --color'),
|
65 |
-
# ls normal files only
|
66 |
-
('lf', 'ls -F -o --color %l | grep ^-'),
|
67 |
-
# ls symbolic links
|
68 |
-
('lk', 'ls -F -o --color %l | grep ^l'),
|
69 |
-
# directories or links to directories,
|
70 |
-
('ldir', 'ls -F -o --color %l | grep /$'),
|
71 |
-
# things which are executable
|
72 |
-
('lx', 'ls -F -o --color %l | grep ^-..x'),
|
73 |
-
]
|
74 |
-
elif sys.platform.startswith('openbsd') or sys.platform.startswith('netbsd'):
|
75 |
-
# OpenBSD, NetBSD. The ls implementation on these platforms do not support
|
76 |
-
# the -G switch and lack the ability to use colorized output.
|
77 |
-
ls_aliases = [('ls', 'ls -F'),
|
78 |
-
# long ls
|
79 |
-
('ll', 'ls -F -l'),
|
80 |
-
# ls normal files only
|
81 |
-
('lf', 'ls -F -l %l | grep ^-'),
|
82 |
-
# ls symbolic links
|
83 |
-
('lk', 'ls -F -l %l | grep ^l'),
|
84 |
-
# directories or links to directories,
|
85 |
-
('ldir', 'ls -F -l %l | grep /$'),
|
86 |
-
# things which are executable
|
87 |
-
('lx', 'ls -F -l %l | grep ^-..x'),
|
88 |
-
]
|
89 |
-
else:
|
90 |
-
# BSD, OSX, etc.
|
91 |
-
ls_aliases = [('ls', 'ls -F -G'),
|
92 |
-
# long ls
|
93 |
-
('ll', 'ls -F -l -G'),
|
94 |
-
# ls normal files only
|
95 |
-
('lf', 'ls -F -l -G %l | grep ^-'),
|
96 |
-
# ls symbolic links
|
97 |
-
('lk', 'ls -F -l -G %l | grep ^l'),
|
98 |
-
# directories or links to directories,
|
99 |
-
('ldir', 'ls -F -G -l %l | grep /$'),
|
100 |
-
# things which are executable
|
101 |
-
('lx', 'ls -F -l -G %l | grep ^-..x'),
|
102 |
-
]
|
103 |
-
default_aliases = default_aliases + ls_aliases
|
104 |
-
elif os.name in ['nt', 'dos']:
|
105 |
-
default_aliases = [('ls', 'dir /on'),
|
106 |
-
('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
|
107 |
-
('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
|
108 |
-
('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
|
109 |
-
]
|
110 |
-
else:
|
111 |
-
default_aliases = []
|
112 |
-
|
113 |
-
return default_aliases
|
114 |
-
|
115 |
-
|
116 |
-
class AliasError(Exception):
|
117 |
-
pass
|
118 |
-
|
119 |
-
|
120 |
-
class InvalidAliasError(AliasError):
|
121 |
-
pass
|
122 |
-
|
123 |
-
class Alias(object):
|
124 |
-
"""Callable object storing the details of one alias.
|
125 |
-
|
126 |
-
Instances are registered as magic functions to allow use of aliases.
|
127 |
-
"""
|
128 |
-
|
129 |
-
# Prepare blacklist
|
130 |
-
blacklist = {'cd','popd','pushd','dhist','alias','unalias'}
|
131 |
-
|
132 |
-
def __init__(self, shell, name, cmd):
|
133 |
-
self.shell = shell
|
134 |
-
self.name = name
|
135 |
-
self.cmd = cmd
|
136 |
-
self.__doc__ = "Alias for `!{}`".format(cmd)
|
137 |
-
self.nargs = self.validate()
|
138 |
-
|
139 |
-
def validate(self):
|
140 |
-
"""Validate the alias, and return the number of arguments."""
|
141 |
-
if self.name in self.blacklist:
|
142 |
-
raise InvalidAliasError("The name %s can't be aliased "
|
143 |
-
"because it is a keyword or builtin." % self.name)
|
144 |
-
try:
|
145 |
-
caller = self.shell.magics_manager.magics['line'][self.name]
|
146 |
-
except KeyError:
|
147 |
-
pass
|
148 |
-
else:
|
149 |
-
if not isinstance(caller, Alias):
|
150 |
-
raise InvalidAliasError("The name %s can't be aliased "
|
151 |
-
"because it is another magic command." % self.name)
|
152 |
-
|
153 |
-
if not (isinstance(self.cmd, str)):
|
154 |
-
raise InvalidAliasError("An alias command must be a string, "
|
155 |
-
"got: %r" % self.cmd)
|
156 |
-
|
157 |
-
nargs = self.cmd.count('%s') - self.cmd.count('%%s')
|
158 |
-
|
159 |
-
if (nargs > 0) and (self.cmd.find('%l') >= 0):
|
160 |
-
raise InvalidAliasError('The %s and %l specifiers are mutually '
|
161 |
-
'exclusive in alias definitions.')
|
162 |
-
|
163 |
-
return nargs
|
164 |
-
|
165 |
-
def __repr__(self):
|
166 |
-
return "<alias {} for {!r}>".format(self.name, self.cmd)
|
167 |
-
|
168 |
-
def __call__(self, rest=''):
|
169 |
-
cmd = self.cmd
|
170 |
-
nargs = self.nargs
|
171 |
-
# Expand the %l special to be the user's input line
|
172 |
-
if cmd.find('%l') >= 0:
|
173 |
-
cmd = cmd.replace('%l', rest)
|
174 |
-
rest = ''
|
175 |
-
|
176 |
-
if nargs==0:
|
177 |
-
if cmd.find('%%s') >= 1:
|
178 |
-
cmd = cmd.replace('%%s', '%s')
|
179 |
-
# Simple, argument-less aliases
|
180 |
-
cmd = '%s %s' % (cmd, rest)
|
181 |
-
else:
|
182 |
-
# Handle aliases with positional arguments
|
183 |
-
args = rest.split(None, nargs)
|
184 |
-
if len(args) < nargs:
|
185 |
-
raise UsageError('Alias <%s> requires %s arguments, %s given.' %
|
186 |
-
(self.name, nargs, len(args)))
|
187 |
-
cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
|
188 |
-
|
189 |
-
self.shell.system(cmd)
|
190 |
-
|
191 |
-
#-----------------------------------------------------------------------------
|
192 |
-
# Main AliasManager class
|
193 |
-
#-----------------------------------------------------------------------------
|
194 |
-
|
195 |
-
class AliasManager(Configurable):
|
196 |
-
default_aliases: List = List(default_aliases()).tag(config=True)
|
197 |
-
user_aliases: List = List(default_value=[]).tag(config=True)
|
198 |
-
shell = Instance(
|
199 |
-
"IPython.core.interactiveshell.InteractiveShellABC", allow_none=True
|
200 |
-
)
|
201 |
-
|
202 |
-
def __init__(self, shell=None, **kwargs):
|
203 |
-
super(AliasManager, self).__init__(shell=shell, **kwargs)
|
204 |
-
# For convenient access
|
205 |
-
if self.shell is not None:
|
206 |
-
self.linemagics = self.shell.magics_manager.magics["line"]
|
207 |
-
self.init_aliases()
|
208 |
-
|
209 |
-
def init_aliases(self):
|
210 |
-
# Load default & user aliases
|
211 |
-
for name, cmd in self.default_aliases + self.user_aliases:
|
212 |
-
if (
|
213 |
-
cmd.startswith("ls ")
|
214 |
-
and self.shell is not None
|
215 |
-
and self.shell.colors == "NoColor"
|
216 |
-
):
|
217 |
-
cmd = cmd.replace(" --color", "")
|
218 |
-
self.soft_define_alias(name, cmd)
|
219 |
-
|
220 |
-
@property
|
221 |
-
def aliases(self):
|
222 |
-
return [(n, func.cmd) for (n, func) in self.linemagics.items()
|
223 |
-
if isinstance(func, Alias)]
|
224 |
-
|
225 |
-
def soft_define_alias(self, name, cmd):
|
226 |
-
"""Define an alias, but don't raise on an AliasError."""
|
227 |
-
try:
|
228 |
-
self.define_alias(name, cmd)
|
229 |
-
except AliasError as e:
|
230 |
-
error("Invalid alias: %s" % e)
|
231 |
-
|
232 |
-
def define_alias(self, name, cmd):
|
233 |
-
"""Define a new alias after validating it.
|
234 |
-
|
235 |
-
This will raise an :exc:`AliasError` if there are validation
|
236 |
-
problems.
|
237 |
-
"""
|
238 |
-
caller = Alias(shell=self.shell, name=name, cmd=cmd)
|
239 |
-
self.shell.magics_manager.register_function(caller, magic_kind='line',
|
240 |
-
magic_name=name)
|
241 |
-
|
242 |
-
def get_alias(self, name):
|
243 |
-
"""Return an alias, or None if no alias by that name exists."""
|
244 |
-
aname = self.linemagics.get(name, None)
|
245 |
-
return aname if isinstance(aname, Alias) else None
|
246 |
-
|
247 |
-
def is_alias(self, name):
|
248 |
-
"""Return whether or not a given name has been defined as an alias"""
|
249 |
-
return self.get_alias(name) is not None
|
250 |
-
|
251 |
-
def undefine_alias(self, name):
|
252 |
-
if self.is_alias(name):
|
253 |
-
del self.linemagics[name]
|
254 |
-
else:
|
255 |
-
raise ValueError('%s is not an alias' % name)
|
256 |
-
|
257 |
-
def clear_aliases(self):
|
258 |
-
for name, _ in self.aliases:
|
259 |
-
self.undefine_alias(name)
|
260 |
-
|
261 |
-
def retrieve_alias(self, name):
|
262 |
-
"""Retrieve the command to which an alias expands."""
|
263 |
-
caller = self.get_alias(name)
|
264 |
-
if caller:
|
265 |
-
return caller.cmd
|
266 |
-
else:
|
267 |
-
raise ValueError('%s is not an alias' % name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/application.py
DELETED
@@ -1,492 +0,0 @@
|
|
1 |
-
# encoding: utf-8
|
2 |
-
"""
|
3 |
-
An application for IPython.
|
4 |
-
|
5 |
-
All top-level applications should use the classes in this module for
|
6 |
-
handling configuration and creating configurables.
|
7 |
-
|
8 |
-
The job of an :class:`Application` is to create the master configuration
|
9 |
-
object and then create the configurable objects, passing the config to them.
|
10 |
-
"""
|
11 |
-
|
12 |
-
# Copyright (c) IPython Development Team.
|
13 |
-
# Distributed under the terms of the Modified BSD License.
|
14 |
-
|
15 |
-
import atexit
|
16 |
-
from copy import deepcopy
|
17 |
-
import logging
|
18 |
-
import os
|
19 |
-
import shutil
|
20 |
-
import sys
|
21 |
-
|
22 |
-
from pathlib import Path
|
23 |
-
|
24 |
-
from traitlets.config.application import Application, catch_config_error
|
25 |
-
from traitlets.config.loader import ConfigFileNotFound, PyFileConfigLoader
|
26 |
-
from IPython.core import release, crashhandler
|
27 |
-
from IPython.core.profiledir import ProfileDir, ProfileDirError
|
28 |
-
from IPython.paths import get_ipython_dir, get_ipython_package_dir
|
29 |
-
from IPython.utils.path import ensure_dir_exists
|
30 |
-
from traitlets import (
|
31 |
-
List, Unicode, Type, Bool, Set, Instance, Undefined,
|
32 |
-
default, observe,
|
33 |
-
)
|
34 |
-
|
35 |
-
if os.name == "nt":
|
36 |
-
programdata = os.environ.get("PROGRAMDATA", None)
|
37 |
-
if programdata is not None:
|
38 |
-
SYSTEM_CONFIG_DIRS = [str(Path(programdata) / "ipython")]
|
39 |
-
else: # PROGRAMDATA is not defined by default on XP.
|
40 |
-
SYSTEM_CONFIG_DIRS = []
|
41 |
-
else:
|
42 |
-
SYSTEM_CONFIG_DIRS = [
|
43 |
-
"/usr/local/etc/ipython",
|
44 |
-
"/etc/ipython",
|
45 |
-
]
|
46 |
-
|
47 |
-
|
48 |
-
ENV_CONFIG_DIRS = []
|
49 |
-
_env_config_dir = os.path.join(sys.prefix, 'etc', 'ipython')
|
50 |
-
if _env_config_dir not in SYSTEM_CONFIG_DIRS:
|
51 |
-
# only add ENV_CONFIG if sys.prefix is not already included
|
52 |
-
ENV_CONFIG_DIRS.append(_env_config_dir)
|
53 |
-
|
54 |
-
|
55 |
-
_envvar = os.environ.get('IPYTHON_SUPPRESS_CONFIG_ERRORS')
|
56 |
-
if _envvar in {None, ''}:
|
57 |
-
IPYTHON_SUPPRESS_CONFIG_ERRORS = None
|
58 |
-
else:
|
59 |
-
if _envvar.lower() in {'1','true'}:
|
60 |
-
IPYTHON_SUPPRESS_CONFIG_ERRORS = True
|
61 |
-
elif _envvar.lower() in {'0','false'} :
|
62 |
-
IPYTHON_SUPPRESS_CONFIG_ERRORS = False
|
63 |
-
else:
|
64 |
-
sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_CONFIG_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar )
|
65 |
-
|
66 |
-
# aliases and flags
|
67 |
-
|
68 |
-
base_aliases = {}
|
69 |
-
if isinstance(Application.aliases, dict):
|
70 |
-
# traitlets 5
|
71 |
-
base_aliases.update(Application.aliases)
|
72 |
-
base_aliases.update(
|
73 |
-
{
|
74 |
-
"profile-dir": "ProfileDir.location",
|
75 |
-
"profile": "BaseIPythonApplication.profile",
|
76 |
-
"ipython-dir": "BaseIPythonApplication.ipython_dir",
|
77 |
-
"log-level": "Application.log_level",
|
78 |
-
"config": "BaseIPythonApplication.extra_config_file",
|
79 |
-
}
|
80 |
-
)
|
81 |
-
|
82 |
-
base_flags = dict()
|
83 |
-
if isinstance(Application.flags, dict):
|
84 |
-
# traitlets 5
|
85 |
-
base_flags.update(Application.flags)
|
86 |
-
base_flags.update(
|
87 |
-
dict(
|
88 |
-
debug=(
|
89 |
-
{"Application": {"log_level": logging.DEBUG}},
|
90 |
-
"set log level to logging.DEBUG (maximize logging output)",
|
91 |
-
),
|
92 |
-
quiet=(
|
93 |
-
{"Application": {"log_level": logging.CRITICAL}},
|
94 |
-
"set log level to logging.CRITICAL (minimize logging output)",
|
95 |
-
),
|
96 |
-
init=(
|
97 |
-
{
|
98 |
-
"BaseIPythonApplication": {
|
99 |
-
"copy_config_files": True,
|
100 |
-
"auto_create": True,
|
101 |
-
}
|
102 |
-
},
|
103 |
-
"""Initialize profile with default config files. This is equivalent
|
104 |
-
to running `ipython profile create <profile>` prior to startup.
|
105 |
-
""",
|
106 |
-
),
|
107 |
-
)
|
108 |
-
)
|
109 |
-
|
110 |
-
|
111 |
-
class ProfileAwareConfigLoader(PyFileConfigLoader):
|
112 |
-
"""A Python file config loader that is aware of IPython profiles."""
|
113 |
-
def load_subconfig(self, fname, path=None, profile=None):
|
114 |
-
if profile is not None:
|
115 |
-
try:
|
116 |
-
profile_dir = ProfileDir.find_profile_dir_by_name(
|
117 |
-
get_ipython_dir(),
|
118 |
-
profile,
|
119 |
-
)
|
120 |
-
except ProfileDirError:
|
121 |
-
return
|
122 |
-
path = profile_dir.location
|
123 |
-
return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
|
124 |
-
|
125 |
-
class BaseIPythonApplication(Application):
|
126 |
-
name = "ipython"
|
127 |
-
description = "IPython: an enhanced interactive Python shell."
|
128 |
-
version = Unicode(release.version)
|
129 |
-
|
130 |
-
aliases = base_aliases
|
131 |
-
flags = base_flags
|
132 |
-
classes = List([ProfileDir])
|
133 |
-
|
134 |
-
# enable `load_subconfig('cfg.py', profile='name')`
|
135 |
-
python_config_loader_class = ProfileAwareConfigLoader
|
136 |
-
|
137 |
-
# Track whether the config_file has changed,
|
138 |
-
# because some logic happens only if we aren't using the default.
|
139 |
-
config_file_specified = Set()
|
140 |
-
|
141 |
-
config_file_name = Unicode()
|
142 |
-
@default('config_file_name')
|
143 |
-
def _config_file_name_default(self):
|
144 |
-
return self.name.replace('-','_') + u'_config.py'
|
145 |
-
@observe('config_file_name')
|
146 |
-
def _config_file_name_changed(self, change):
|
147 |
-
if change['new'] != change['old']:
|
148 |
-
self.config_file_specified.add(change['new'])
|
149 |
-
|
150 |
-
# The directory that contains IPython's builtin profiles.
|
151 |
-
builtin_profile_dir = Unicode(
|
152 |
-
os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
|
153 |
-
)
|
154 |
-
|
155 |
-
config_file_paths = List(Unicode())
|
156 |
-
@default('config_file_paths')
|
157 |
-
def _config_file_paths_default(self):
|
158 |
-
return []
|
159 |
-
|
160 |
-
extra_config_file = Unicode(
|
161 |
-
help="""Path to an extra config file to load.
|
162 |
-
|
163 |
-
If specified, load this config file in addition to any other IPython config.
|
164 |
-
""").tag(config=True)
|
165 |
-
@observe('extra_config_file')
|
166 |
-
def _extra_config_file_changed(self, change):
|
167 |
-
old = change['old']
|
168 |
-
new = change['new']
|
169 |
-
try:
|
170 |
-
self.config_files.remove(old)
|
171 |
-
except ValueError:
|
172 |
-
pass
|
173 |
-
self.config_file_specified.add(new)
|
174 |
-
self.config_files.append(new)
|
175 |
-
|
176 |
-
profile = Unicode(u'default',
|
177 |
-
help="""The IPython profile to use."""
|
178 |
-
).tag(config=True)
|
179 |
-
|
180 |
-
@observe('profile')
|
181 |
-
def _profile_changed(self, change):
|
182 |
-
self.builtin_profile_dir = os.path.join(
|
183 |
-
get_ipython_package_dir(), u'config', u'profile', change['new']
|
184 |
-
)
|
185 |
-
|
186 |
-
add_ipython_dir_to_sys_path = Bool(
|
187 |
-
False,
|
188 |
-
"""Should the IPython profile directory be added to sys path ?
|
189 |
-
|
190 |
-
This option was non-existing before IPython 8.0, and ipython_dir was added to
|
191 |
-
sys path to allow import of extensions present there. This was historical
|
192 |
-
baggage from when pip did not exist. This now default to false,
|
193 |
-
but can be set to true for legacy reasons.
|
194 |
-
""",
|
195 |
-
).tag(config=True)
|
196 |
-
|
197 |
-
ipython_dir = Unicode(
|
198 |
-
help="""
|
199 |
-
The name of the IPython directory. This directory is used for logging
|
200 |
-
configuration (through profiles), history storage, etc. The default
|
201 |
-
is usually $HOME/.ipython. This option can also be specified through
|
202 |
-
the environment variable IPYTHONDIR.
|
203 |
-
"""
|
204 |
-
).tag(config=True)
|
205 |
-
@default('ipython_dir')
|
206 |
-
def _ipython_dir_default(self):
|
207 |
-
d = get_ipython_dir()
|
208 |
-
self._ipython_dir_changed({
|
209 |
-
'name': 'ipython_dir',
|
210 |
-
'old': d,
|
211 |
-
'new': d,
|
212 |
-
})
|
213 |
-
return d
|
214 |
-
|
215 |
-
_in_init_profile_dir = False
|
216 |
-
|
217 |
-
profile_dir = Instance(ProfileDir, allow_none=True)
|
218 |
-
|
219 |
-
@default('profile_dir')
|
220 |
-
def _profile_dir_default(self):
|
221 |
-
# avoid recursion
|
222 |
-
if self._in_init_profile_dir:
|
223 |
-
return
|
224 |
-
# profile_dir requested early, force initialization
|
225 |
-
self.init_profile_dir()
|
226 |
-
return self.profile_dir
|
227 |
-
|
228 |
-
overwrite = Bool(False,
|
229 |
-
help="""Whether to overwrite existing config files when copying"""
|
230 |
-
).tag(config=True)
|
231 |
-
|
232 |
-
auto_create = Bool(False,
|
233 |
-
help="""Whether to create profile dir if it doesn't exist"""
|
234 |
-
).tag(config=True)
|
235 |
-
|
236 |
-
config_files = List(Unicode())
|
237 |
-
|
238 |
-
@default('config_files')
|
239 |
-
def _config_files_default(self):
|
240 |
-
return [self.config_file_name]
|
241 |
-
|
242 |
-
copy_config_files = Bool(False,
|
243 |
-
help="""Whether to install the default config files into the profile dir.
|
244 |
-
If a new profile is being created, and IPython contains config files for that
|
245 |
-
profile, then they will be staged into the new directory. Otherwise,
|
246 |
-
default config files will be automatically generated.
|
247 |
-
""").tag(config=True)
|
248 |
-
|
249 |
-
verbose_crash = Bool(False,
|
250 |
-
help="""Create a massive crash report when IPython encounters what may be an
|
251 |
-
internal error. The default is to append a short message to the
|
252 |
-
usual traceback""").tag(config=True)
|
253 |
-
|
254 |
-
# The class to use as the crash handler.
|
255 |
-
crash_handler_class = Type(crashhandler.CrashHandler)
|
256 |
-
|
257 |
-
@catch_config_error
|
258 |
-
def __init__(self, **kwargs):
|
259 |
-
super(BaseIPythonApplication, self).__init__(**kwargs)
|
260 |
-
# ensure current working directory exists
|
261 |
-
try:
|
262 |
-
os.getcwd()
|
263 |
-
except:
|
264 |
-
# exit if cwd doesn't exist
|
265 |
-
self.log.error("Current working directory doesn't exist.")
|
266 |
-
self.exit(1)
|
267 |
-
|
268 |
-
#-------------------------------------------------------------------------
|
269 |
-
# Various stages of Application creation
|
270 |
-
#-------------------------------------------------------------------------
|
271 |
-
|
272 |
-
def init_crash_handler(self):
|
273 |
-
"""Create a crash handler, typically setting sys.excepthook to it."""
|
274 |
-
self.crash_handler = self.crash_handler_class(self)
|
275 |
-
sys.excepthook = self.excepthook
|
276 |
-
def unset_crashhandler():
|
277 |
-
sys.excepthook = sys.__excepthook__
|
278 |
-
atexit.register(unset_crashhandler)
|
279 |
-
|
280 |
-
def excepthook(self, etype, evalue, tb):
|
281 |
-
"""this is sys.excepthook after init_crashhandler
|
282 |
-
|
283 |
-
set self.verbose_crash=True to use our full crashhandler, instead of
|
284 |
-
a regular traceback with a short message (crash_handler_lite)
|
285 |
-
"""
|
286 |
-
|
287 |
-
if self.verbose_crash:
|
288 |
-
return self.crash_handler(etype, evalue, tb)
|
289 |
-
else:
|
290 |
-
return crashhandler.crash_handler_lite(etype, evalue, tb)
|
291 |
-
|
292 |
-
@observe('ipython_dir')
|
293 |
-
def _ipython_dir_changed(self, change):
|
294 |
-
old = change['old']
|
295 |
-
new = change['new']
|
296 |
-
if old is not Undefined:
|
297 |
-
str_old = os.path.abspath(old)
|
298 |
-
if str_old in sys.path:
|
299 |
-
sys.path.remove(str_old)
|
300 |
-
if self.add_ipython_dir_to_sys_path:
|
301 |
-
str_path = os.path.abspath(new)
|
302 |
-
sys.path.append(str_path)
|
303 |
-
ensure_dir_exists(new)
|
304 |
-
readme = os.path.join(new, "README")
|
305 |
-
readme_src = os.path.join(
|
306 |
-
get_ipython_package_dir(), "config", "profile", "README"
|
307 |
-
)
|
308 |
-
if not os.path.exists(readme) and os.path.exists(readme_src):
|
309 |
-
shutil.copy(readme_src, readme)
|
310 |
-
for d in ("extensions", "nbextensions"):
|
311 |
-
path = os.path.join(new, d)
|
312 |
-
try:
|
313 |
-
ensure_dir_exists(path)
|
314 |
-
except OSError as e:
|
315 |
-
# this will not be EEXIST
|
316 |
-
self.log.error("couldn't create path %s: %s", path, e)
|
317 |
-
self.log.debug("IPYTHONDIR set to: %s", new)
|
318 |
-
|
319 |
-
def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_CONFIG_ERRORS):
|
320 |
-
"""Load the config file.
|
321 |
-
|
322 |
-
By default, errors in loading config are handled, and a warning
|
323 |
-
printed on screen. For testing, the suppress_errors option is set
|
324 |
-
to False, so errors will make tests fail.
|
325 |
-
|
326 |
-
`suppress_errors` default value is to be `None` in which case the
|
327 |
-
behavior default to the one of `traitlets.Application`.
|
328 |
-
|
329 |
-
The default value can be set :
|
330 |
-
- to `False` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '0', or 'false' (case insensitive).
|
331 |
-
- to `True` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '1' or 'true' (case insensitive).
|
332 |
-
- to `None` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '' (empty string) or leaving it unset.
|
333 |
-
|
334 |
-
Any other value are invalid, and will make IPython exit with a non-zero return code.
|
335 |
-
"""
|
336 |
-
|
337 |
-
|
338 |
-
self.log.debug("Searching path %s for config files", self.config_file_paths)
|
339 |
-
base_config = 'ipython_config.py'
|
340 |
-
self.log.debug("Attempting to load config file: %s" %
|
341 |
-
base_config)
|
342 |
-
try:
|
343 |
-
if suppress_errors is not None:
|
344 |
-
old_value = Application.raise_config_file_errors
|
345 |
-
Application.raise_config_file_errors = not suppress_errors;
|
346 |
-
Application.load_config_file(
|
347 |
-
self,
|
348 |
-
base_config,
|
349 |
-
path=self.config_file_paths
|
350 |
-
)
|
351 |
-
except ConfigFileNotFound:
|
352 |
-
# ignore errors loading parent
|
353 |
-
self.log.debug("Config file %s not found", base_config)
|
354 |
-
pass
|
355 |
-
if suppress_errors is not None:
|
356 |
-
Application.raise_config_file_errors = old_value
|
357 |
-
|
358 |
-
for config_file_name in self.config_files:
|
359 |
-
if not config_file_name or config_file_name == base_config:
|
360 |
-
continue
|
361 |
-
self.log.debug("Attempting to load config file: %s" %
|
362 |
-
self.config_file_name)
|
363 |
-
try:
|
364 |
-
Application.load_config_file(
|
365 |
-
self,
|
366 |
-
config_file_name,
|
367 |
-
path=self.config_file_paths
|
368 |
-
)
|
369 |
-
except ConfigFileNotFound:
|
370 |
-
# Only warn if the default config file was NOT being used.
|
371 |
-
if config_file_name in self.config_file_specified:
|
372 |
-
msg = self.log.warning
|
373 |
-
else:
|
374 |
-
msg = self.log.debug
|
375 |
-
msg("Config file not found, skipping: %s", config_file_name)
|
376 |
-
except Exception:
|
377 |
-
# For testing purposes.
|
378 |
-
if not suppress_errors:
|
379 |
-
raise
|
380 |
-
self.log.warning("Error loading config file: %s" %
|
381 |
-
self.config_file_name, exc_info=True)
|
382 |
-
|
383 |
-
def init_profile_dir(self):
|
384 |
-
"""initialize the profile dir"""
|
385 |
-
self._in_init_profile_dir = True
|
386 |
-
if self.profile_dir is not None:
|
387 |
-
# already ran
|
388 |
-
return
|
389 |
-
if 'ProfileDir.location' not in self.config:
|
390 |
-
# location not specified, find by profile name
|
391 |
-
try:
|
392 |
-
p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
|
393 |
-
except ProfileDirError:
|
394 |
-
# not found, maybe create it (always create default profile)
|
395 |
-
if self.auto_create or self.profile == 'default':
|
396 |
-
try:
|
397 |
-
p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
|
398 |
-
except ProfileDirError:
|
399 |
-
self.log.fatal("Could not create profile: %r"%self.profile)
|
400 |
-
self.exit(1)
|
401 |
-
else:
|
402 |
-
self.log.info("Created profile dir: %r"%p.location)
|
403 |
-
else:
|
404 |
-
self.log.fatal("Profile %r not found."%self.profile)
|
405 |
-
self.exit(1)
|
406 |
-
else:
|
407 |
-
self.log.debug("Using existing profile dir: %r", p.location)
|
408 |
-
else:
|
409 |
-
location = self.config.ProfileDir.location
|
410 |
-
# location is fully specified
|
411 |
-
try:
|
412 |
-
p = ProfileDir.find_profile_dir(location, self.config)
|
413 |
-
except ProfileDirError:
|
414 |
-
# not found, maybe create it
|
415 |
-
if self.auto_create:
|
416 |
-
try:
|
417 |
-
p = ProfileDir.create_profile_dir(location, self.config)
|
418 |
-
except ProfileDirError:
|
419 |
-
self.log.fatal("Could not create profile directory: %r"%location)
|
420 |
-
self.exit(1)
|
421 |
-
else:
|
422 |
-
self.log.debug("Creating new profile dir: %r"%location)
|
423 |
-
else:
|
424 |
-
self.log.fatal("Profile directory %r not found."%location)
|
425 |
-
self.exit(1)
|
426 |
-
else:
|
427 |
-
self.log.debug("Using existing profile dir: %r", p.location)
|
428 |
-
# if profile_dir is specified explicitly, set profile name
|
429 |
-
dir_name = os.path.basename(p.location)
|
430 |
-
if dir_name.startswith('profile_'):
|
431 |
-
self.profile = dir_name[8:]
|
432 |
-
|
433 |
-
self.profile_dir = p
|
434 |
-
self.config_file_paths.append(p.location)
|
435 |
-
self._in_init_profile_dir = False
|
436 |
-
|
437 |
-
def init_config_files(self):
|
438 |
-
"""[optionally] copy default config files into profile dir."""
|
439 |
-
self.config_file_paths.extend(ENV_CONFIG_DIRS)
|
440 |
-
self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
|
441 |
-
# copy config files
|
442 |
-
path = Path(self.builtin_profile_dir)
|
443 |
-
if self.copy_config_files:
|
444 |
-
src = self.profile
|
445 |
-
|
446 |
-
cfg = self.config_file_name
|
447 |
-
if path and (path / cfg).exists():
|
448 |
-
self.log.warning(
|
449 |
-
"Staging %r from %s into %r [overwrite=%s]"
|
450 |
-
% (cfg, src, self.profile_dir.location, self.overwrite)
|
451 |
-
)
|
452 |
-
self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
|
453 |
-
else:
|
454 |
-
self.stage_default_config_file()
|
455 |
-
else:
|
456 |
-
# Still stage *bundled* config files, but not generated ones
|
457 |
-
# This is necessary for `ipython profile=sympy` to load the profile
|
458 |
-
# on the first go
|
459 |
-
files = path.glob("*.py")
|
460 |
-
for fullpath in files:
|
461 |
-
cfg = fullpath.name
|
462 |
-
if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
|
463 |
-
# file was copied
|
464 |
-
self.log.warning("Staging bundled %s from %s into %r"%(
|
465 |
-
cfg, self.profile, self.profile_dir.location)
|
466 |
-
)
|
467 |
-
|
468 |
-
|
469 |
-
def stage_default_config_file(self):
|
470 |
-
"""auto generate default config file, and stage it into the profile."""
|
471 |
-
s = self.generate_config_file()
|
472 |
-
config_file = Path(self.profile_dir.location) / self.config_file_name
|
473 |
-
if self.overwrite or not config_file.exists():
|
474 |
-
self.log.warning("Generating default config file: %r", (config_file))
|
475 |
-
config_file.write_text(s, encoding="utf-8")
|
476 |
-
|
477 |
-
@catch_config_error
|
478 |
-
def initialize(self, argv=None):
|
479 |
-
# don't hook up crash handler before parsing command-line
|
480 |
-
self.parse_command_line(argv)
|
481 |
-
self.init_crash_handler()
|
482 |
-
if self.subapp is not None:
|
483 |
-
# stop here if subapp is taking over
|
484 |
-
return
|
485 |
-
# save a copy of CLI config to re-load after config files
|
486 |
-
# so that it has highest priority
|
487 |
-
cl_config = deepcopy(self.config)
|
488 |
-
self.init_profile_dir()
|
489 |
-
self.init_config_files()
|
490 |
-
self.load_config_file()
|
491 |
-
# enforce cl-opts override configfile opts:
|
492 |
-
self.update_config(cl_config)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/async_helpers.py
DELETED
@@ -1,155 +0,0 @@
|
|
1 |
-
"""
|
2 |
-
Async helper function that are invalid syntax on Python 3.5 and below.
|
3 |
-
|
4 |
-
This code is best effort, and may have edge cases not behaving as expected. In
|
5 |
-
particular it contain a number of heuristics to detect whether code is
|
6 |
-
effectively async and need to run in an event loop or not.
|
7 |
-
|
8 |
-
Some constructs (like top-level `return`, or `yield`) are taken care of
|
9 |
-
explicitly to actually raise a SyntaxError and stay as close as possible to
|
10 |
-
Python semantics.
|
11 |
-
"""
|
12 |
-
|
13 |
-
import ast
|
14 |
-
import asyncio
|
15 |
-
import inspect
|
16 |
-
from functools import wraps
|
17 |
-
|
18 |
-
_asyncio_event_loop = None
|
19 |
-
|
20 |
-
|
21 |
-
def get_asyncio_loop():
|
22 |
-
"""asyncio has deprecated get_event_loop
|
23 |
-
|
24 |
-
Replicate it here, with our desired semantics:
|
25 |
-
|
26 |
-
- always returns a valid, not-closed loop
|
27 |
-
- not thread-local like asyncio's,
|
28 |
-
because we only want one loop for IPython
|
29 |
-
- if called from inside a coroutine (e.g. in ipykernel),
|
30 |
-
return the running loop
|
31 |
-
|
32 |
-
.. versionadded:: 8.0
|
33 |
-
"""
|
34 |
-
try:
|
35 |
-
return asyncio.get_running_loop()
|
36 |
-
except RuntimeError:
|
37 |
-
# not inside a coroutine,
|
38 |
-
# track our own global
|
39 |
-
pass
|
40 |
-
|
41 |
-
# not thread-local like asyncio's,
|
42 |
-
# because we only track one event loop to run for IPython itself,
|
43 |
-
# always in the main thread.
|
44 |
-
global _asyncio_event_loop
|
45 |
-
if _asyncio_event_loop is None or _asyncio_event_loop.is_closed():
|
46 |
-
_asyncio_event_loop = asyncio.new_event_loop()
|
47 |
-
return _asyncio_event_loop
|
48 |
-
|
49 |
-
|
50 |
-
class _AsyncIORunner:
|
51 |
-
def __call__(self, coro):
|
52 |
-
"""
|
53 |
-
Handler for asyncio autoawait
|
54 |
-
"""
|
55 |
-
return get_asyncio_loop().run_until_complete(coro)
|
56 |
-
|
57 |
-
def __str__(self):
|
58 |
-
return "asyncio"
|
59 |
-
|
60 |
-
|
61 |
-
_asyncio_runner = _AsyncIORunner()
|
62 |
-
|
63 |
-
|
64 |
-
class _AsyncIOProxy:
|
65 |
-
"""Proxy-object for an asyncio
|
66 |
-
|
67 |
-
Any coroutine methods will be wrapped in event_loop.run_
|
68 |
-
"""
|
69 |
-
|
70 |
-
def __init__(self, obj, event_loop):
|
71 |
-
self._obj = obj
|
72 |
-
self._event_loop = event_loop
|
73 |
-
|
74 |
-
def __repr__(self):
|
75 |
-
return f"<_AsyncIOProxy({self._obj!r})>"
|
76 |
-
|
77 |
-
def __getattr__(self, key):
|
78 |
-
attr = getattr(self._obj, key)
|
79 |
-
if inspect.iscoroutinefunction(attr):
|
80 |
-
# if it's a coroutine method,
|
81 |
-
# return a threadsafe wrapper onto the _current_ asyncio loop
|
82 |
-
@wraps(attr)
|
83 |
-
def _wrapped(*args, **kwargs):
|
84 |
-
concurrent_future = asyncio.run_coroutine_threadsafe(
|
85 |
-
attr(*args, **kwargs), self._event_loop
|
86 |
-
)
|
87 |
-
return asyncio.wrap_future(concurrent_future)
|
88 |
-
|
89 |
-
return _wrapped
|
90 |
-
else:
|
91 |
-
return attr
|
92 |
-
|
93 |
-
def __dir__(self):
|
94 |
-
return dir(self._obj)
|
95 |
-
|
96 |
-
|
97 |
-
def _curio_runner(coroutine):
|
98 |
-
"""
|
99 |
-
handler for curio autoawait
|
100 |
-
"""
|
101 |
-
import curio
|
102 |
-
|
103 |
-
return curio.run(coroutine)
|
104 |
-
|
105 |
-
|
106 |
-
def _trio_runner(async_fn):
|
107 |
-
import trio
|
108 |
-
|
109 |
-
async def loc(coro):
|
110 |
-
"""
|
111 |
-
We need the dummy no-op async def to protect from
|
112 |
-
trio's internal. See https://github.com/python-trio/trio/issues/89
|
113 |
-
"""
|
114 |
-
return await coro
|
115 |
-
|
116 |
-
return trio.run(loc, async_fn)
|
117 |
-
|
118 |
-
|
119 |
-
def _pseudo_sync_runner(coro):
|
120 |
-
"""
|
121 |
-
A runner that does not really allow async execution, and just advance the coroutine.
|
122 |
-
|
123 |
-
See discussion in https://github.com/python-trio/trio/issues/608,
|
124 |
-
|
125 |
-
Credit to Nathaniel Smith
|
126 |
-
"""
|
127 |
-
try:
|
128 |
-
coro.send(None)
|
129 |
-
except StopIteration as exc:
|
130 |
-
return exc.value
|
131 |
-
else:
|
132 |
-
# TODO: do not raise but return an execution result with the right info.
|
133 |
-
raise RuntimeError(
|
134 |
-
"{coro_name!r} needs a real async loop".format(coro_name=coro.__name__)
|
135 |
-
)
|
136 |
-
|
137 |
-
|
138 |
-
def _should_be_async(cell: str) -> bool:
|
139 |
-
"""Detect if a block of code need to be wrapped in an `async def`
|
140 |
-
|
141 |
-
Attempt to parse the block of code, it it compile we're fine.
|
142 |
-
Otherwise we wrap if and try to compile.
|
143 |
-
|
144 |
-
If it works, assume it should be async. Otherwise Return False.
|
145 |
-
|
146 |
-
Not handled yet: If the block of code has a return statement as the top
|
147 |
-
level, it will be seen as async. This is a know limitation.
|
148 |
-
"""
|
149 |
-
try:
|
150 |
-
code = compile(
|
151 |
-
cell, "<>", "exec", flags=getattr(ast, "PyCF_ALLOW_TOP_LEVEL_AWAIT", 0x0)
|
152 |
-
)
|
153 |
-
return inspect.CO_COROUTINE & code.co_flags == inspect.CO_COROUTINE
|
154 |
-
except (SyntaxError, MemoryError):
|
155 |
-
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/autocall.py
DELETED
@@ -1,70 +0,0 @@
|
|
1 |
-
# encoding: utf-8
|
2 |
-
"""
|
3 |
-
Autocall capabilities for IPython.core.
|
4 |
-
|
5 |
-
Authors:
|
6 |
-
|
7 |
-
* Brian Granger
|
8 |
-
* Fernando Perez
|
9 |
-
* Thomas Kluyver
|
10 |
-
|
11 |
-
Notes
|
12 |
-
-----
|
13 |
-
"""
|
14 |
-
|
15 |
-
#-----------------------------------------------------------------------------
|
16 |
-
# Copyright (C) 2008-2011 The IPython Development Team
|
17 |
-
#
|
18 |
-
# Distributed under the terms of the BSD License. The full license is in
|
19 |
-
# the file COPYING, distributed as part of this software.
|
20 |
-
#-----------------------------------------------------------------------------
|
21 |
-
|
22 |
-
#-----------------------------------------------------------------------------
|
23 |
-
# Imports
|
24 |
-
#-----------------------------------------------------------------------------
|
25 |
-
|
26 |
-
|
27 |
-
#-----------------------------------------------------------------------------
|
28 |
-
# Code
|
29 |
-
#-----------------------------------------------------------------------------
|
30 |
-
|
31 |
-
class IPyAutocall(object):
|
32 |
-
""" Instances of this class are always autocalled
|
33 |
-
|
34 |
-
This happens regardless of 'autocall' variable state. Use this to
|
35 |
-
develop macro-like mechanisms.
|
36 |
-
"""
|
37 |
-
_ip = None
|
38 |
-
rewrite = True
|
39 |
-
def __init__(self, ip=None):
|
40 |
-
self._ip = ip
|
41 |
-
|
42 |
-
def set_ip(self, ip):
|
43 |
-
"""Will be used to set _ip point to current ipython instance b/f call
|
44 |
-
|
45 |
-
Override this method if you don't want this to happen.
|
46 |
-
|
47 |
-
"""
|
48 |
-
self._ip = ip
|
49 |
-
|
50 |
-
|
51 |
-
class ExitAutocall(IPyAutocall):
|
52 |
-
"""An autocallable object which will be added to the user namespace so that
|
53 |
-
exit, exit(), quit or quit() are all valid ways to close the shell."""
|
54 |
-
rewrite = False
|
55 |
-
|
56 |
-
def __call__(self):
|
57 |
-
self._ip.ask_exit()
|
58 |
-
|
59 |
-
class ZMQExitAutocall(ExitAutocall):
|
60 |
-
"""Exit IPython. Autocallable, so it needn't be explicitly called.
|
61 |
-
|
62 |
-
Parameters
|
63 |
-
----------
|
64 |
-
keep_kernel : bool
|
65 |
-
If True, leave the kernel alive. Otherwise, tell the kernel to exit too
|
66 |
-
(default).
|
67 |
-
"""
|
68 |
-
def __call__(self, keep_kernel=False):
|
69 |
-
self._ip.keepkernel_on_exit = keep_kernel
|
70 |
-
self._ip.ask_exit()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/builtin_trap.py
DELETED
@@ -1,86 +0,0 @@
|
|
1 |
-
"""
|
2 |
-
A context manager for managing things injected into :mod:`builtins`.
|
3 |
-
"""
|
4 |
-
# Copyright (c) IPython Development Team.
|
5 |
-
# Distributed under the terms of the Modified BSD License.
|
6 |
-
import builtins as builtin_mod
|
7 |
-
|
8 |
-
from traitlets.config.configurable import Configurable
|
9 |
-
|
10 |
-
from traitlets import Instance
|
11 |
-
|
12 |
-
|
13 |
-
class __BuiltinUndefined(object): pass
|
14 |
-
BuiltinUndefined = __BuiltinUndefined()
|
15 |
-
|
16 |
-
class __HideBuiltin(object): pass
|
17 |
-
HideBuiltin = __HideBuiltin()
|
18 |
-
|
19 |
-
|
20 |
-
class BuiltinTrap(Configurable):
|
21 |
-
|
22 |
-
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
|
23 |
-
allow_none=True)
|
24 |
-
|
25 |
-
def __init__(self, shell=None):
|
26 |
-
super(BuiltinTrap, self).__init__(shell=shell, config=None)
|
27 |
-
self._orig_builtins = {}
|
28 |
-
# We define this to track if a single BuiltinTrap is nested.
|
29 |
-
# Only turn off the trap when the outermost call to __exit__ is made.
|
30 |
-
self._nested_level = 0
|
31 |
-
self.shell = shell
|
32 |
-
# builtins we always add - if set to HideBuiltin, they will just
|
33 |
-
# be removed instead of being replaced by something else
|
34 |
-
self.auto_builtins = {'exit': HideBuiltin,
|
35 |
-
'quit': HideBuiltin,
|
36 |
-
'get_ipython': self.shell.get_ipython,
|
37 |
-
}
|
38 |
-
|
39 |
-
def __enter__(self):
|
40 |
-
if self._nested_level == 0:
|
41 |
-
self.activate()
|
42 |
-
self._nested_level += 1
|
43 |
-
# I return self, so callers can use add_builtin in a with clause.
|
44 |
-
return self
|
45 |
-
|
46 |
-
def __exit__(self, type, value, traceback):
|
47 |
-
if self._nested_level == 1:
|
48 |
-
self.deactivate()
|
49 |
-
self._nested_level -= 1
|
50 |
-
# Returning False will cause exceptions to propagate
|
51 |
-
return False
|
52 |
-
|
53 |
-
def add_builtin(self, key, value):
|
54 |
-
"""Add a builtin and save the original."""
|
55 |
-
bdict = builtin_mod.__dict__
|
56 |
-
orig = bdict.get(key, BuiltinUndefined)
|
57 |
-
if value is HideBuiltin:
|
58 |
-
if orig is not BuiltinUndefined: #same as 'key in bdict'
|
59 |
-
self._orig_builtins[key] = orig
|
60 |
-
del bdict[key]
|
61 |
-
else:
|
62 |
-
self._orig_builtins[key] = orig
|
63 |
-
bdict[key] = value
|
64 |
-
|
65 |
-
def remove_builtin(self, key, orig):
|
66 |
-
"""Remove an added builtin and re-set the original."""
|
67 |
-
if orig is BuiltinUndefined:
|
68 |
-
del builtin_mod.__dict__[key]
|
69 |
-
else:
|
70 |
-
builtin_mod.__dict__[key] = orig
|
71 |
-
|
72 |
-
def activate(self):
|
73 |
-
"""Store ipython references in the __builtin__ namespace."""
|
74 |
-
|
75 |
-
add_builtin = self.add_builtin
|
76 |
-
for name, func in self.auto_builtins.items():
|
77 |
-
add_builtin(name, func)
|
78 |
-
|
79 |
-
def deactivate(self):
|
80 |
-
"""Remove any builtins which might have been added by add_builtins, or
|
81 |
-
restore overwritten ones to their previous values."""
|
82 |
-
remove_builtin = self.remove_builtin
|
83 |
-
for key, val in self._orig_builtins.items():
|
84 |
-
remove_builtin(key, val)
|
85 |
-
self._orig_builtins.clear()
|
86 |
-
self._builtins_added = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/compilerop.py
DELETED
@@ -1,214 +0,0 @@
|
|
1 |
-
"""Compiler tools with improved interactive support.
|
2 |
-
|
3 |
-
Provides compilation machinery similar to codeop, but with caching support so
|
4 |
-
we can provide interactive tracebacks.
|
5 |
-
|
6 |
-
Authors
|
7 |
-
-------
|
8 |
-
* Robert Kern
|
9 |
-
* Fernando Perez
|
10 |
-
* Thomas Kluyver
|
11 |
-
"""
|
12 |
-
|
13 |
-
# Note: though it might be more natural to name this module 'compiler', that
|
14 |
-
# name is in the stdlib and name collisions with the stdlib tend to produce
|
15 |
-
# weird problems (often with third-party tools).
|
16 |
-
|
17 |
-
#-----------------------------------------------------------------------------
|
18 |
-
# Copyright (C) 2010-2011 The IPython Development Team.
|
19 |
-
#
|
20 |
-
# Distributed under the terms of the BSD License.
|
21 |
-
#
|
22 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
23 |
-
#-----------------------------------------------------------------------------
|
24 |
-
|
25 |
-
#-----------------------------------------------------------------------------
|
26 |
-
# Imports
|
27 |
-
#-----------------------------------------------------------------------------
|
28 |
-
|
29 |
-
# Stdlib imports
|
30 |
-
import __future__
|
31 |
-
from ast import PyCF_ONLY_AST
|
32 |
-
import codeop
|
33 |
-
import functools
|
34 |
-
import hashlib
|
35 |
-
import linecache
|
36 |
-
import operator
|
37 |
-
import time
|
38 |
-
from contextlib import contextmanager
|
39 |
-
|
40 |
-
#-----------------------------------------------------------------------------
|
41 |
-
# Constants
|
42 |
-
#-----------------------------------------------------------------------------
|
43 |
-
|
44 |
-
# Roughly equal to PyCF_MASK | PyCF_MASK_OBSOLETE as defined in pythonrun.h,
|
45 |
-
# this is used as a bitmask to extract future-related code flags.
|
46 |
-
PyCF_MASK = functools.reduce(operator.or_,
|
47 |
-
(getattr(__future__, fname).compiler_flag
|
48 |
-
for fname in __future__.all_feature_names))
|
49 |
-
|
50 |
-
#-----------------------------------------------------------------------------
|
51 |
-
# Local utilities
|
52 |
-
#-----------------------------------------------------------------------------
|
53 |
-
|
54 |
-
def code_name(code, number=0):
|
55 |
-
""" Compute a (probably) unique name for code for caching.
|
56 |
-
|
57 |
-
This now expects code to be unicode.
|
58 |
-
"""
|
59 |
-
hash_digest = hashlib.sha1(code.encode("utf-8")).hexdigest()
|
60 |
-
# Include the number and 12 characters of the hash in the name. It's
|
61 |
-
# pretty much impossible that in a single session we'll have collisions
|
62 |
-
# even with truncated hashes, and the full one makes tracebacks too long
|
63 |
-
return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
|
64 |
-
|
65 |
-
#-----------------------------------------------------------------------------
|
66 |
-
# Classes and functions
|
67 |
-
#-----------------------------------------------------------------------------
|
68 |
-
|
69 |
-
class CachingCompiler(codeop.Compile):
|
70 |
-
"""A compiler that caches code compiled from interactive statements.
|
71 |
-
"""
|
72 |
-
|
73 |
-
def __init__(self):
|
74 |
-
codeop.Compile.__init__(self)
|
75 |
-
|
76 |
-
# Caching a dictionary { filename: execution_count } for nicely
|
77 |
-
# rendered tracebacks. The filename corresponds to the filename
|
78 |
-
# argument used for the builtins.compile function.
|
79 |
-
self._filename_map = {}
|
80 |
-
|
81 |
-
def ast_parse(self, source, filename='<unknown>', symbol='exec'):
|
82 |
-
"""Parse code to an AST with the current compiler flags active.
|
83 |
-
|
84 |
-
Arguments are exactly the same as ast.parse (in the standard library),
|
85 |
-
and are passed to the built-in compile function."""
|
86 |
-
return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
|
87 |
-
|
88 |
-
def reset_compiler_flags(self):
|
89 |
-
"""Reset compiler flags to default state."""
|
90 |
-
# This value is copied from codeop.Compile.__init__, so if that ever
|
91 |
-
# changes, it will need to be updated.
|
92 |
-
self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
|
93 |
-
|
94 |
-
@property
|
95 |
-
def compiler_flags(self):
|
96 |
-
"""Flags currently active in the compilation process.
|
97 |
-
"""
|
98 |
-
return self.flags
|
99 |
-
|
100 |
-
def get_code_name(self, raw_code, transformed_code, number):
|
101 |
-
"""Compute filename given the code, and the cell number.
|
102 |
-
|
103 |
-
Parameters
|
104 |
-
----------
|
105 |
-
raw_code : str
|
106 |
-
The raw cell code.
|
107 |
-
transformed_code : str
|
108 |
-
The executable Python source code to cache and compile.
|
109 |
-
number : int
|
110 |
-
A number which forms part of the code's name. Used for the execution
|
111 |
-
counter.
|
112 |
-
|
113 |
-
Returns
|
114 |
-
-------
|
115 |
-
The computed filename.
|
116 |
-
"""
|
117 |
-
return code_name(transformed_code, number)
|
118 |
-
|
119 |
-
def format_code_name(self, name):
|
120 |
-
"""Return a user-friendly label and name for a code block.
|
121 |
-
|
122 |
-
Parameters
|
123 |
-
----------
|
124 |
-
name : str
|
125 |
-
The name for the code block returned from get_code_name
|
126 |
-
|
127 |
-
Returns
|
128 |
-
-------
|
129 |
-
A (label, name) pair that can be used in tracebacks, or None if the default formatting should be used.
|
130 |
-
"""
|
131 |
-
if name in self._filename_map:
|
132 |
-
return "Cell", "In[%s]" % self._filename_map[name]
|
133 |
-
|
134 |
-
def cache(self, transformed_code, number=0, raw_code=None):
|
135 |
-
"""Make a name for a block of code, and cache the code.
|
136 |
-
|
137 |
-
Parameters
|
138 |
-
----------
|
139 |
-
transformed_code : str
|
140 |
-
The executable Python source code to cache and compile.
|
141 |
-
number : int
|
142 |
-
A number which forms part of the code's name. Used for the execution
|
143 |
-
counter.
|
144 |
-
raw_code : str
|
145 |
-
The raw code before transformation, if None, set to `transformed_code`.
|
146 |
-
|
147 |
-
Returns
|
148 |
-
-------
|
149 |
-
The name of the cached code (as a string). Pass this as the filename
|
150 |
-
argument to compilation, so that tracebacks are correctly hooked up.
|
151 |
-
"""
|
152 |
-
if raw_code is None:
|
153 |
-
raw_code = transformed_code
|
154 |
-
|
155 |
-
name = self.get_code_name(raw_code, transformed_code, number)
|
156 |
-
|
157 |
-
# Save the execution count
|
158 |
-
self._filename_map[name] = number
|
159 |
-
|
160 |
-
# Since Python 2.5, setting mtime to `None` means the lines will
|
161 |
-
# never be removed by `linecache.checkcache`. This means all the
|
162 |
-
# monkeypatching has *never* been necessary, since this code was
|
163 |
-
# only added in 2010, at which point IPython had already stopped
|
164 |
-
# supporting Python 2.4.
|
165 |
-
#
|
166 |
-
# Note that `linecache.clearcache` and `linecache.updatecache` may
|
167 |
-
# still remove our code from the cache, but those show explicit
|
168 |
-
# intent, and we should not try to interfere. Normally the former
|
169 |
-
# is never called except when out of memory, and the latter is only
|
170 |
-
# called for lines *not* in the cache.
|
171 |
-
entry = (
|
172 |
-
len(transformed_code),
|
173 |
-
None,
|
174 |
-
[line + "\n" for line in transformed_code.splitlines()],
|
175 |
-
name,
|
176 |
-
)
|
177 |
-
linecache.cache[name] = entry
|
178 |
-
return name
|
179 |
-
|
180 |
-
@contextmanager
|
181 |
-
def extra_flags(self, flags):
|
182 |
-
## bits that we'll set to 1
|
183 |
-
turn_on_bits = ~self.flags & flags
|
184 |
-
|
185 |
-
|
186 |
-
self.flags = self.flags | flags
|
187 |
-
try:
|
188 |
-
yield
|
189 |
-
finally:
|
190 |
-
# turn off only the bits we turned on so that something like
|
191 |
-
# __future__ that set flags stays.
|
192 |
-
self.flags &= ~turn_on_bits
|
193 |
-
|
194 |
-
|
195 |
-
def check_linecache_ipython(*args):
|
196 |
-
"""Deprecated since IPython 8.6. Call linecache.checkcache() directly.
|
197 |
-
|
198 |
-
It was already not necessary to call this function directly. If no
|
199 |
-
CachingCompiler had been created, this function would fail badly. If
|
200 |
-
an instance had been created, this function would've been monkeypatched
|
201 |
-
into place.
|
202 |
-
|
203 |
-
As of IPython 8.6, the monkeypatching has gone away entirely. But there
|
204 |
-
were still internal callers of this function, so maybe external callers
|
205 |
-
also existed?
|
206 |
-
"""
|
207 |
-
import warnings
|
208 |
-
|
209 |
-
warnings.warn(
|
210 |
-
"Deprecated Since IPython 8.6, Just call linecache.checkcache() directly.",
|
211 |
-
DeprecationWarning,
|
212 |
-
stacklevel=2,
|
213 |
-
)
|
214 |
-
linecache.checkcache()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/completer.py
DELETED
The diff for this file is too large to render.
See raw diff
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/completerlib.py
DELETED
@@ -1,382 +0,0 @@
|
|
1 |
-
# encoding: utf-8
|
2 |
-
"""Implementations for various useful completers.
|
3 |
-
|
4 |
-
These are all loaded by default by IPython.
|
5 |
-
"""
|
6 |
-
#-----------------------------------------------------------------------------
|
7 |
-
# Copyright (C) 2010-2011 The IPython Development Team.
|
8 |
-
#
|
9 |
-
# Distributed under the terms of the BSD License.
|
10 |
-
#
|
11 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
12 |
-
#-----------------------------------------------------------------------------
|
13 |
-
|
14 |
-
#-----------------------------------------------------------------------------
|
15 |
-
# Imports
|
16 |
-
#-----------------------------------------------------------------------------
|
17 |
-
|
18 |
-
# Stdlib imports
|
19 |
-
import glob
|
20 |
-
import inspect
|
21 |
-
import os
|
22 |
-
import re
|
23 |
-
import sys
|
24 |
-
from importlib import import_module
|
25 |
-
from importlib.machinery import all_suffixes
|
26 |
-
|
27 |
-
|
28 |
-
# Third-party imports
|
29 |
-
from time import time
|
30 |
-
from zipimport import zipimporter
|
31 |
-
|
32 |
-
# Our own imports
|
33 |
-
from .completer import expand_user, compress_user
|
34 |
-
from .error import TryNext
|
35 |
-
from ..utils._process_common import arg_split
|
36 |
-
|
37 |
-
# FIXME: this should be pulled in with the right call via the component system
|
38 |
-
from IPython import get_ipython
|
39 |
-
|
40 |
-
from typing import List
|
41 |
-
|
42 |
-
#-----------------------------------------------------------------------------
|
43 |
-
# Globals and constants
|
44 |
-
#-----------------------------------------------------------------------------
|
45 |
-
_suffixes = all_suffixes()
|
46 |
-
|
47 |
-
# Time in seconds after which the rootmodules will be stored permanently in the
|
48 |
-
# ipython ip.db database (kept in the user's .ipython dir).
|
49 |
-
TIMEOUT_STORAGE = 2
|
50 |
-
|
51 |
-
# Time in seconds after which we give up
|
52 |
-
TIMEOUT_GIVEUP = 20
|
53 |
-
|
54 |
-
# Regular expression for the python import statement
|
55 |
-
import_re = re.compile(r'(?P<name>[^\W\d]\w*?)'
|
56 |
-
r'(?P<package>[/\\]__init__)?'
|
57 |
-
r'(?P<suffix>%s)$' %
|
58 |
-
r'|'.join(re.escape(s) for s in _suffixes))
|
59 |
-
|
60 |
-
# RE for the ipython %run command (python + ipython scripts)
|
61 |
-
magic_run_re = re.compile(r'.*(\.ipy|\.ipynb|\.py[w]?)$')
|
62 |
-
|
63 |
-
#-----------------------------------------------------------------------------
|
64 |
-
# Local utilities
|
65 |
-
#-----------------------------------------------------------------------------
|
66 |
-
|
67 |
-
|
68 |
-
def module_list(path: str) -> List[str]:
|
69 |
-
"""
|
70 |
-
Return the list containing the names of the modules available in the given
|
71 |
-
folder.
|
72 |
-
"""
|
73 |
-
# sys.path has the cwd as an empty string, but isdir/listdir need it as '.'
|
74 |
-
if path == '':
|
75 |
-
path = '.'
|
76 |
-
|
77 |
-
# A few local constants to be used in loops below
|
78 |
-
pjoin = os.path.join
|
79 |
-
|
80 |
-
if os.path.isdir(path):
|
81 |
-
# Build a list of all files in the directory and all files
|
82 |
-
# in its subdirectories. For performance reasons, do not
|
83 |
-
# recurse more than one level into subdirectories.
|
84 |
-
files: List[str] = []
|
85 |
-
for root, dirs, nondirs in os.walk(path, followlinks=True):
|
86 |
-
subdir = root[len(path)+1:]
|
87 |
-
if subdir:
|
88 |
-
files.extend(pjoin(subdir, f) for f in nondirs)
|
89 |
-
dirs[:] = [] # Do not recurse into additional subdirectories.
|
90 |
-
else:
|
91 |
-
files.extend(nondirs)
|
92 |
-
|
93 |
-
else:
|
94 |
-
try:
|
95 |
-
files = list(zipimporter(path)._files.keys()) # type: ignore
|
96 |
-
except Exception:
|
97 |
-
files = []
|
98 |
-
|
99 |
-
# Build a list of modules which match the import_re regex.
|
100 |
-
modules = []
|
101 |
-
for f in files:
|
102 |
-
m = import_re.match(f)
|
103 |
-
if m:
|
104 |
-
modules.append(m.group('name'))
|
105 |
-
return list(set(modules))
|
106 |
-
|
107 |
-
|
108 |
-
def get_root_modules():
|
109 |
-
"""
|
110 |
-
Returns a list containing the names of all the modules available in the
|
111 |
-
folders of the pythonpath.
|
112 |
-
|
113 |
-
ip.db['rootmodules_cache'] maps sys.path entries to list of modules.
|
114 |
-
"""
|
115 |
-
ip = get_ipython()
|
116 |
-
if ip is None:
|
117 |
-
# No global shell instance to store cached list of modules.
|
118 |
-
# Don't try to scan for modules every time.
|
119 |
-
return list(sys.builtin_module_names)
|
120 |
-
|
121 |
-
if getattr(ip.db, "_mock", False):
|
122 |
-
rootmodules_cache = {}
|
123 |
-
else:
|
124 |
-
rootmodules_cache = ip.db.get("rootmodules_cache", {})
|
125 |
-
rootmodules = list(sys.builtin_module_names)
|
126 |
-
start_time = time()
|
127 |
-
store = False
|
128 |
-
for path in sys.path:
|
129 |
-
try:
|
130 |
-
modules = rootmodules_cache[path]
|
131 |
-
except KeyError:
|
132 |
-
modules = module_list(path)
|
133 |
-
try:
|
134 |
-
modules.remove('__init__')
|
135 |
-
except ValueError:
|
136 |
-
pass
|
137 |
-
if path not in ('', '.'): # cwd modules should not be cached
|
138 |
-
rootmodules_cache[path] = modules
|
139 |
-
if time() - start_time > TIMEOUT_STORAGE and not store:
|
140 |
-
store = True
|
141 |
-
print("\nCaching the list of root modules, please wait!")
|
142 |
-
print("(This will only be done once - type '%rehashx' to "
|
143 |
-
"reset cache!)\n")
|
144 |
-
sys.stdout.flush()
|
145 |
-
if time() - start_time > TIMEOUT_GIVEUP:
|
146 |
-
print("This is taking too long, we give up.\n")
|
147 |
-
return []
|
148 |
-
rootmodules.extend(modules)
|
149 |
-
if store:
|
150 |
-
ip.db['rootmodules_cache'] = rootmodules_cache
|
151 |
-
rootmodules = list(set(rootmodules))
|
152 |
-
return rootmodules
|
153 |
-
|
154 |
-
|
155 |
-
def is_importable(module, attr: str, only_modules) -> bool:
|
156 |
-
if only_modules:
|
157 |
-
try:
|
158 |
-
mod = getattr(module, attr)
|
159 |
-
except ModuleNotFoundError:
|
160 |
-
# See gh-14434
|
161 |
-
return False
|
162 |
-
return inspect.ismodule(mod)
|
163 |
-
else:
|
164 |
-
return not(attr[:2] == '__' and attr[-2:] == '__')
|
165 |
-
|
166 |
-
def is_possible_submodule(module, attr):
|
167 |
-
try:
|
168 |
-
obj = getattr(module, attr)
|
169 |
-
except AttributeError:
|
170 |
-
# Is possibly an unimported submodule
|
171 |
-
return True
|
172 |
-
except TypeError:
|
173 |
-
# https://github.com/ipython/ipython/issues/9678
|
174 |
-
return False
|
175 |
-
return inspect.ismodule(obj)
|
176 |
-
|
177 |
-
|
178 |
-
def try_import(mod: str, only_modules=False) -> List[str]:
|
179 |
-
"""
|
180 |
-
Try to import given module and return list of potential completions.
|
181 |
-
"""
|
182 |
-
mod = mod.rstrip('.')
|
183 |
-
try:
|
184 |
-
m = import_module(mod)
|
185 |
-
except:
|
186 |
-
return []
|
187 |
-
|
188 |
-
m_is_init = '__init__' in (getattr(m, '__file__', '') or '')
|
189 |
-
|
190 |
-
completions = []
|
191 |
-
if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
|
192 |
-
completions.extend( [attr for attr in dir(m) if
|
193 |
-
is_importable(m, attr, only_modules)])
|
194 |
-
|
195 |
-
m_all = getattr(m, "__all__", [])
|
196 |
-
if only_modules:
|
197 |
-
completions.extend(attr for attr in m_all if is_possible_submodule(m, attr))
|
198 |
-
else:
|
199 |
-
completions.extend(m_all)
|
200 |
-
|
201 |
-
if m_is_init:
|
202 |
-
file_ = m.__file__
|
203 |
-
file_path = os.path.dirname(file_) # type: ignore
|
204 |
-
if file_path is not None:
|
205 |
-
completions.extend(module_list(file_path))
|
206 |
-
completions_set = {c for c in completions if isinstance(c, str)}
|
207 |
-
completions_set.discard('__init__')
|
208 |
-
return list(completions_set)
|
209 |
-
|
210 |
-
|
211 |
-
#-----------------------------------------------------------------------------
|
212 |
-
# Completion-related functions.
|
213 |
-
#-----------------------------------------------------------------------------
|
214 |
-
|
215 |
-
def quick_completer(cmd, completions):
|
216 |
-
r""" Easily create a trivial completer for a command.
|
217 |
-
|
218 |
-
Takes either a list of completions, or all completions in string (that will
|
219 |
-
be split on whitespace).
|
220 |
-
|
221 |
-
Example::
|
222 |
-
|
223 |
-
[d:\ipython]|1> import ipy_completers
|
224 |
-
[d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
|
225 |
-
[d:\ipython]|3> foo b<TAB>
|
226 |
-
bar baz
|
227 |
-
[d:\ipython]|3> foo ba
|
228 |
-
"""
|
229 |
-
|
230 |
-
if isinstance(completions, str):
|
231 |
-
completions = completions.split()
|
232 |
-
|
233 |
-
def do_complete(self, event):
|
234 |
-
return completions
|
235 |
-
|
236 |
-
get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
|
237 |
-
|
238 |
-
def module_completion(line):
|
239 |
-
"""
|
240 |
-
Returns a list containing the completion possibilities for an import line.
|
241 |
-
|
242 |
-
The line looks like this :
|
243 |
-
'import xml.d'
|
244 |
-
'from xml.dom import'
|
245 |
-
"""
|
246 |
-
|
247 |
-
words = line.split(' ')
|
248 |
-
nwords = len(words)
|
249 |
-
|
250 |
-
# from whatever <tab> -> 'import '
|
251 |
-
if nwords == 3 and words[0] == 'from':
|
252 |
-
return ['import ']
|
253 |
-
|
254 |
-
# 'from xy<tab>' or 'import xy<tab>'
|
255 |
-
if nwords < 3 and (words[0] in {'%aimport', 'import', 'from'}) :
|
256 |
-
if nwords == 1:
|
257 |
-
return get_root_modules()
|
258 |
-
mod = words[1].split('.')
|
259 |
-
if len(mod) < 2:
|
260 |
-
return get_root_modules()
|
261 |
-
completion_list = try_import('.'.join(mod[:-1]), True)
|
262 |
-
return ['.'.join(mod[:-1] + [el]) for el in completion_list]
|
263 |
-
|
264 |
-
# 'from xyz import abc<tab>'
|
265 |
-
if nwords >= 3 and words[0] == 'from':
|
266 |
-
mod = words[1]
|
267 |
-
return try_import(mod)
|
268 |
-
|
269 |
-
#-----------------------------------------------------------------------------
|
270 |
-
# Completers
|
271 |
-
#-----------------------------------------------------------------------------
|
272 |
-
# These all have the func(self, event) signature to be used as custom
|
273 |
-
# completers
|
274 |
-
|
275 |
-
def module_completer(self,event):
|
276 |
-
"""Give completions after user has typed 'import ...' or 'from ...'"""
|
277 |
-
|
278 |
-
# This works in all versions of python. While 2.5 has
|
279 |
-
# pkgutil.walk_packages(), that particular routine is fairly dangerous,
|
280 |
-
# since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
|
281 |
-
# of possibly problematic side effects.
|
282 |
-
# This search the folders in the sys.path for available modules.
|
283 |
-
|
284 |
-
return module_completion(event.line)
|
285 |
-
|
286 |
-
# FIXME: there's a lot of logic common to the run, cd and builtin file
|
287 |
-
# completers, that is currently reimplemented in each.
|
288 |
-
|
289 |
-
def magic_run_completer(self, event):
|
290 |
-
"""Complete files that end in .py or .ipy or .ipynb for the %run command.
|
291 |
-
"""
|
292 |
-
comps = arg_split(event.line, strict=False)
|
293 |
-
# relpath should be the current token that we need to complete.
|
294 |
-
if (len(comps) > 1) and (not event.line.endswith(' ')):
|
295 |
-
relpath = comps[-1].strip("'\"")
|
296 |
-
else:
|
297 |
-
relpath = ''
|
298 |
-
|
299 |
-
#print("\nev=", event) # dbg
|
300 |
-
#print("rp=", relpath) # dbg
|
301 |
-
#print('comps=', comps) # dbg
|
302 |
-
|
303 |
-
lglob = glob.glob
|
304 |
-
isdir = os.path.isdir
|
305 |
-
relpath, tilde_expand, tilde_val = expand_user(relpath)
|
306 |
-
|
307 |
-
# Find if the user has already typed the first filename, after which we
|
308 |
-
# should complete on all files, since after the first one other files may
|
309 |
-
# be arguments to the input script.
|
310 |
-
|
311 |
-
if any(magic_run_re.match(c) for c in comps):
|
312 |
-
matches = [f.replace('\\','/') + ('/' if isdir(f) else '')
|
313 |
-
for f in lglob(relpath+'*')]
|
314 |
-
else:
|
315 |
-
dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
|
316 |
-
pys = [f.replace('\\','/')
|
317 |
-
for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
|
318 |
-
lglob(relpath+'*.ipynb') + lglob(relpath + '*.pyw')]
|
319 |
-
|
320 |
-
matches = dirs + pys
|
321 |
-
|
322 |
-
#print('run comp:', dirs+pys) # dbg
|
323 |
-
return [compress_user(p, tilde_expand, tilde_val) for p in matches]
|
324 |
-
|
325 |
-
|
326 |
-
def cd_completer(self, event):
|
327 |
-
"""Completer function for cd, which only returns directories."""
|
328 |
-
ip = get_ipython()
|
329 |
-
relpath = event.symbol
|
330 |
-
|
331 |
-
#print(event) # dbg
|
332 |
-
if event.line.endswith('-b') or ' -b ' in event.line:
|
333 |
-
# return only bookmark completions
|
334 |
-
bkms = self.db.get('bookmarks', None)
|
335 |
-
if bkms:
|
336 |
-
return bkms.keys()
|
337 |
-
else:
|
338 |
-
return []
|
339 |
-
|
340 |
-
if event.symbol == '-':
|
341 |
-
width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
|
342 |
-
# jump in directory history by number
|
343 |
-
fmt = '-%0' + width_dh +'d [%s]'
|
344 |
-
ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
|
345 |
-
if len(ents) > 1:
|
346 |
-
return ents
|
347 |
-
return []
|
348 |
-
|
349 |
-
if event.symbol.startswith('--'):
|
350 |
-
return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
|
351 |
-
|
352 |
-
# Expand ~ in path and normalize directory separators.
|
353 |
-
relpath, tilde_expand, tilde_val = expand_user(relpath)
|
354 |
-
relpath = relpath.replace('\\','/')
|
355 |
-
|
356 |
-
found = []
|
357 |
-
for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
|
358 |
-
if os.path.isdir(f)]:
|
359 |
-
if ' ' in d:
|
360 |
-
# we don't want to deal with any of that, complex code
|
361 |
-
# for this is elsewhere
|
362 |
-
raise TryNext
|
363 |
-
|
364 |
-
found.append(d)
|
365 |
-
|
366 |
-
if not found:
|
367 |
-
if os.path.isdir(relpath):
|
368 |
-
return [compress_user(relpath, tilde_expand, tilde_val)]
|
369 |
-
|
370 |
-
# if no completions so far, try bookmarks
|
371 |
-
bks = self.db.get('bookmarks',{})
|
372 |
-
bkmatches = [s for s in bks if s.startswith(event.symbol)]
|
373 |
-
if bkmatches:
|
374 |
-
return bkmatches
|
375 |
-
|
376 |
-
raise TryNext
|
377 |
-
|
378 |
-
return [compress_user(p, tilde_expand, tilde_val) for p in found]
|
379 |
-
|
380 |
-
def reset_completer(self, event):
|
381 |
-
"A completer for %reset magic"
|
382 |
-
return '-f -s in out array dhist'.split()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/crashhandler.py
DELETED
@@ -1,248 +0,0 @@
|
|
1 |
-
# encoding: utf-8
|
2 |
-
"""sys.excepthook for IPython itself, leaves a detailed report on disk.
|
3 |
-
|
4 |
-
Authors:
|
5 |
-
|
6 |
-
* Fernando Perez
|
7 |
-
* Brian E. Granger
|
8 |
-
"""
|
9 |
-
|
10 |
-
#-----------------------------------------------------------------------------
|
11 |
-
# Copyright (C) 2001-2007 Fernando Perez. <[email protected]>
|
12 |
-
# Copyright (C) 2008-2011 The IPython Development Team
|
13 |
-
#
|
14 |
-
# Distributed under the terms of the BSD License. The full license is in
|
15 |
-
# the file COPYING, distributed as part of this software.
|
16 |
-
#-----------------------------------------------------------------------------
|
17 |
-
|
18 |
-
#-----------------------------------------------------------------------------
|
19 |
-
# Imports
|
20 |
-
#-----------------------------------------------------------------------------
|
21 |
-
|
22 |
-
import sys
|
23 |
-
import traceback
|
24 |
-
from pprint import pformat
|
25 |
-
from pathlib import Path
|
26 |
-
|
27 |
-
import builtins as builtin_mod
|
28 |
-
|
29 |
-
from IPython.core import ultratb
|
30 |
-
from IPython.core.application import Application
|
31 |
-
from IPython.core.release import author_email
|
32 |
-
from IPython.utils.sysinfo import sys_info
|
33 |
-
|
34 |
-
from IPython.core.release import __version__ as version
|
35 |
-
|
36 |
-
from typing import Optional, Dict
|
37 |
-
import types
|
38 |
-
|
39 |
-
#-----------------------------------------------------------------------------
|
40 |
-
# Code
|
41 |
-
#-----------------------------------------------------------------------------
|
42 |
-
|
43 |
-
# Template for the user message.
|
44 |
-
_default_message_template = """\
|
45 |
-
Oops, {app_name} crashed. We do our best to make it stable, but...
|
46 |
-
|
47 |
-
A crash report was automatically generated with the following information:
|
48 |
-
- A verbatim copy of the crash traceback.
|
49 |
-
- A copy of your input history during this session.
|
50 |
-
- Data on your current {app_name} configuration.
|
51 |
-
|
52 |
-
It was left in the file named:
|
53 |
-
\t'{crash_report_fname}'
|
54 |
-
If you can email this file to the developers, the information in it will help
|
55 |
-
them in understanding and correcting the problem.
|
56 |
-
|
57 |
-
You can mail it to: {contact_name} at {contact_email}
|
58 |
-
with the subject '{app_name} Crash Report'.
|
59 |
-
|
60 |
-
If you want to do it now, the following command will work (under Unix):
|
61 |
-
mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
|
62 |
-
|
63 |
-
In your email, please also include information about:
|
64 |
-
- The operating system under which the crash happened: Linux, macOS, Windows,
|
65 |
-
other, and which exact version (for example: Ubuntu 16.04.3, macOS 10.13.2,
|
66 |
-
Windows 10 Pro), and whether it is 32-bit or 64-bit;
|
67 |
-
- How {app_name} was installed: using pip or conda, from GitHub, as part of
|
68 |
-
a Docker container, or other, providing more detail if possible;
|
69 |
-
- How to reproduce the crash: what exact sequence of instructions can one
|
70 |
-
input to get the same crash? Ideally, find a minimal yet complete sequence
|
71 |
-
of instructions that yields the crash.
|
72 |
-
|
73 |
-
To ensure accurate tracking of this issue, please file a report about it at:
|
74 |
-
{bug_tracker}
|
75 |
-
"""
|
76 |
-
|
77 |
-
_lite_message_template = """
|
78 |
-
If you suspect this is an IPython {version} bug, please report it at:
|
79 |
-
https://github.com/ipython/ipython/issues
|
80 |
-
or send an email to the mailing list at {email}
|
81 |
-
|
82 |
-
You can print a more detailed traceback right now with "%tb", or use "%debug"
|
83 |
-
to interactively debug it.
|
84 |
-
|
85 |
-
Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
|
86 |
-
{config}Application.verbose_crash=True
|
87 |
-
"""
|
88 |
-
|
89 |
-
|
90 |
-
class CrashHandler:
|
91 |
-
"""Customizable crash handlers for IPython applications.
|
92 |
-
|
93 |
-
Instances of this class provide a :meth:`__call__` method which can be
|
94 |
-
used as a ``sys.excepthook``. The :meth:`__call__` signature is::
|
95 |
-
|
96 |
-
def __call__(self, etype, evalue, etb)
|
97 |
-
"""
|
98 |
-
|
99 |
-
message_template = _default_message_template
|
100 |
-
section_sep = '\n\n'+'*'*75+'\n\n'
|
101 |
-
info: Dict[str, Optional[str]]
|
102 |
-
|
103 |
-
def __init__(
|
104 |
-
self,
|
105 |
-
app: Application,
|
106 |
-
contact_name: Optional[str] = None,
|
107 |
-
contact_email: Optional[str] = None,
|
108 |
-
bug_tracker: Optional[str] = None,
|
109 |
-
show_crash_traceback: bool = True,
|
110 |
-
call_pdb: bool = False,
|
111 |
-
):
|
112 |
-
"""Create a new crash handler
|
113 |
-
|
114 |
-
Parameters
|
115 |
-
----------
|
116 |
-
app : Application
|
117 |
-
A running :class:`Application` instance, which will be queried at
|
118 |
-
crash time for internal information.
|
119 |
-
contact_name : str
|
120 |
-
A string with the name of the person to contact.
|
121 |
-
contact_email : str
|
122 |
-
A string with the email address of the contact.
|
123 |
-
bug_tracker : str
|
124 |
-
A string with the URL for your project's bug tracker.
|
125 |
-
show_crash_traceback : bool
|
126 |
-
If false, don't print the crash traceback on stderr, only generate
|
127 |
-
the on-disk report
|
128 |
-
call_pdb
|
129 |
-
Whether to call pdb on crash
|
130 |
-
|
131 |
-
Attributes
|
132 |
-
----------
|
133 |
-
These instances contain some non-argument attributes which allow for
|
134 |
-
further customization of the crash handler's behavior. Please see the
|
135 |
-
source for further details.
|
136 |
-
|
137 |
-
"""
|
138 |
-
self.crash_report_fname = "Crash_report_%s.txt" % app.name
|
139 |
-
self.app = app
|
140 |
-
self.call_pdb = call_pdb
|
141 |
-
#self.call_pdb = True # dbg
|
142 |
-
self.show_crash_traceback = show_crash_traceback
|
143 |
-
self.info = dict(app_name = app.name,
|
144 |
-
contact_name = contact_name,
|
145 |
-
contact_email = contact_email,
|
146 |
-
bug_tracker = bug_tracker,
|
147 |
-
crash_report_fname = self.crash_report_fname)
|
148 |
-
|
149 |
-
def __call__(
|
150 |
-
self,
|
151 |
-
etype: type[BaseException],
|
152 |
-
evalue: BaseException,
|
153 |
-
etb: types.TracebackType,
|
154 |
-
) -> None:
|
155 |
-
"""Handle an exception, call for compatible with sys.excepthook"""
|
156 |
-
|
157 |
-
# do not allow the crash handler to be called twice without reinstalling it
|
158 |
-
# this prevents unlikely errors in the crash handling from entering an
|
159 |
-
# infinite loop.
|
160 |
-
sys.excepthook = sys.__excepthook__
|
161 |
-
|
162 |
-
# Report tracebacks shouldn't use color in general (safer for users)
|
163 |
-
color_scheme = 'NoColor'
|
164 |
-
|
165 |
-
# Use this ONLY for developer debugging (keep commented out for release)
|
166 |
-
# color_scheme = 'Linux' # dbg
|
167 |
-
ipython_dir = getattr(self.app, "ipython_dir", None)
|
168 |
-
if ipython_dir is not None:
|
169 |
-
assert isinstance(ipython_dir, str)
|
170 |
-
rptdir = Path(ipython_dir)
|
171 |
-
else:
|
172 |
-
rptdir = Path.cwd()
|
173 |
-
if not rptdir.is_dir():
|
174 |
-
rptdir = Path.cwd()
|
175 |
-
report_name = rptdir / self.crash_report_fname
|
176 |
-
# write the report filename into the instance dict so it can get
|
177 |
-
# properly expanded out in the user message template
|
178 |
-
self.crash_report_fname = str(report_name)
|
179 |
-
self.info["crash_report_fname"] = str(report_name)
|
180 |
-
TBhandler = ultratb.VerboseTB(
|
181 |
-
color_scheme=color_scheme,
|
182 |
-
long_header=True,
|
183 |
-
call_pdb=self.call_pdb,
|
184 |
-
)
|
185 |
-
if self.call_pdb:
|
186 |
-
TBhandler(etype,evalue,etb)
|
187 |
-
return
|
188 |
-
else:
|
189 |
-
traceback = TBhandler.text(etype,evalue,etb,context=31)
|
190 |
-
|
191 |
-
# print traceback to screen
|
192 |
-
if self.show_crash_traceback:
|
193 |
-
print(traceback, file=sys.stderr)
|
194 |
-
|
195 |
-
# and generate a complete report on disk
|
196 |
-
try:
|
197 |
-
report = open(report_name, "w", encoding="utf-8")
|
198 |
-
except:
|
199 |
-
print('Could not create crash report on disk.', file=sys.stderr)
|
200 |
-
return
|
201 |
-
|
202 |
-
with report:
|
203 |
-
# Inform user on stderr of what happened
|
204 |
-
print('\n'+'*'*70+'\n', file=sys.stderr)
|
205 |
-
print(self.message_template.format(**self.info), file=sys.stderr)
|
206 |
-
|
207 |
-
# Construct report on disk
|
208 |
-
report.write(self.make_report(str(traceback)))
|
209 |
-
|
210 |
-
builtin_mod.input("Hit <Enter> to quit (your terminal may close):")
|
211 |
-
|
212 |
-
def make_report(self, traceback: str) -> str:
|
213 |
-
"""Return a string containing a crash report."""
|
214 |
-
|
215 |
-
sec_sep = self.section_sep
|
216 |
-
|
217 |
-
report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
|
218 |
-
rpt_add = report.append
|
219 |
-
rpt_add(sys_info())
|
220 |
-
|
221 |
-
try:
|
222 |
-
config = pformat(self.app.config)
|
223 |
-
rpt_add(sec_sep)
|
224 |
-
rpt_add("Application name: %s\n\n" % self.app.name)
|
225 |
-
rpt_add("Current user configuration structure:\n\n")
|
226 |
-
rpt_add(config)
|
227 |
-
except:
|
228 |
-
pass
|
229 |
-
rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
|
230 |
-
|
231 |
-
return ''.join(report)
|
232 |
-
|
233 |
-
|
234 |
-
def crash_handler_lite(
|
235 |
-
etype: type[BaseException], evalue: BaseException, tb: types.TracebackType
|
236 |
-
) -> None:
|
237 |
-
"""a light excepthook, adding a small message to the usual traceback"""
|
238 |
-
traceback.print_exception(etype, evalue, tb)
|
239 |
-
|
240 |
-
from IPython.core.interactiveshell import InteractiveShell
|
241 |
-
if InteractiveShell.initialized():
|
242 |
-
# we are in a Shell environment, give %magic example
|
243 |
-
config = "%config "
|
244 |
-
else:
|
245 |
-
# we are not in a shell, show generic config
|
246 |
-
config = "c."
|
247 |
-
print(_lite_message_template.format(email=author_email, config=config, version=version), file=sys.stderr)
|
248 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/debugger.py
DELETED
@@ -1,1136 +0,0 @@
|
|
1 |
-
"""
|
2 |
-
Pdb debugger class.
|
3 |
-
|
4 |
-
|
5 |
-
This is an extension to PDB which adds a number of new features.
|
6 |
-
Note that there is also the `IPython.terminal.debugger` class which provides UI
|
7 |
-
improvements.
|
8 |
-
|
9 |
-
We also strongly recommend to use this via the `ipdb` package, which provides
|
10 |
-
extra configuration options.
|
11 |
-
|
12 |
-
Among other things, this subclass of PDB:
|
13 |
-
- supports many IPython magics like pdef/psource
|
14 |
-
- hide frames in tracebacks based on `__tracebackhide__`
|
15 |
-
- allows to skip frames based on `__debuggerskip__`
|
16 |
-
|
17 |
-
|
18 |
-
Global Configuration
|
19 |
-
--------------------
|
20 |
-
|
21 |
-
The IPython debugger will by read the global ``~/.pdbrc`` file.
|
22 |
-
That is to say you can list all commands supported by ipdb in your `~/.pdbrc`
|
23 |
-
configuration file, to globally configure pdb.
|
24 |
-
|
25 |
-
Example::
|
26 |
-
|
27 |
-
# ~/.pdbrc
|
28 |
-
skip_predicates debuggerskip false
|
29 |
-
skip_hidden false
|
30 |
-
context 25
|
31 |
-
|
32 |
-
Features
|
33 |
-
--------
|
34 |
-
|
35 |
-
The IPython debugger can hide and skip frames when printing or moving through
|
36 |
-
the stack. This can have a performance impact, so can be configures.
|
37 |
-
|
38 |
-
The skipping and hiding frames are configurable via the `skip_predicates`
|
39 |
-
command.
|
40 |
-
|
41 |
-
By default, frames from readonly files will be hidden, frames containing
|
42 |
-
``__tracebackhide__ = True`` will be hidden.
|
43 |
-
|
44 |
-
Frames containing ``__debuggerskip__`` will be stepped over, frames whose parent
|
45 |
-
frames value of ``__debuggerskip__`` is ``True`` will also be skipped.
|
46 |
-
|
47 |
-
>>> def helpers_helper():
|
48 |
-
... pass
|
49 |
-
...
|
50 |
-
... def helper_1():
|
51 |
-
... print("don't step in me")
|
52 |
-
... helpers_helpers() # will be stepped over unless breakpoint set.
|
53 |
-
...
|
54 |
-
...
|
55 |
-
... def helper_2():
|
56 |
-
... print("in me neither")
|
57 |
-
...
|
58 |
-
|
59 |
-
One can define a decorator that wraps a function between the two helpers:
|
60 |
-
|
61 |
-
>>> def pdb_skipped_decorator(function):
|
62 |
-
...
|
63 |
-
...
|
64 |
-
... def wrapped_fn(*args, **kwargs):
|
65 |
-
... __debuggerskip__ = True
|
66 |
-
... helper_1()
|
67 |
-
... __debuggerskip__ = False
|
68 |
-
... result = function(*args, **kwargs)
|
69 |
-
... __debuggerskip__ = True
|
70 |
-
... helper_2()
|
71 |
-
... # setting __debuggerskip__ to False again is not necessary
|
72 |
-
... return result
|
73 |
-
...
|
74 |
-
... return wrapped_fn
|
75 |
-
|
76 |
-
When decorating a function, ipdb will directly step into ``bar()`` by
|
77 |
-
default:
|
78 |
-
|
79 |
-
>>> @foo_decorator
|
80 |
-
... def bar(x, y):
|
81 |
-
... return x * y
|
82 |
-
|
83 |
-
|
84 |
-
You can toggle the behavior with
|
85 |
-
|
86 |
-
ipdb> skip_predicates debuggerskip false
|
87 |
-
|
88 |
-
or configure it in your ``.pdbrc``
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
License
|
93 |
-
-------
|
94 |
-
|
95 |
-
Modified from the standard pdb.Pdb class to avoid including readline, so that
|
96 |
-
the command line completion of other programs which include this isn't
|
97 |
-
damaged.
|
98 |
-
|
99 |
-
In the future, this class will be expanded with improvements over the standard
|
100 |
-
pdb.
|
101 |
-
|
102 |
-
The original code in this file is mainly lifted out of cmd.py in Python 2.2,
|
103 |
-
with minor changes. Licensing should therefore be under the standard Python
|
104 |
-
terms. For details on the PSF (Python Software Foundation) standard license,
|
105 |
-
see:
|
106 |
-
|
107 |
-
https://docs.python.org/2/license.html
|
108 |
-
|
109 |
-
|
110 |
-
All the changes since then are under the same license as IPython.
|
111 |
-
|
112 |
-
"""
|
113 |
-
|
114 |
-
#*****************************************************************************
|
115 |
-
#
|
116 |
-
# This file is licensed under the PSF license.
|
117 |
-
#
|
118 |
-
# Copyright (C) 2001 Python Software Foundation, www.python.org
|
119 |
-
# Copyright (C) 2005-2006 Fernando Perez. <[email protected]>
|
120 |
-
#
|
121 |
-
#
|
122 |
-
#*****************************************************************************
|
123 |
-
|
124 |
-
from __future__ import annotations
|
125 |
-
|
126 |
-
import inspect
|
127 |
-
import linecache
|
128 |
-
import os
|
129 |
-
import re
|
130 |
-
import sys
|
131 |
-
from contextlib import contextmanager
|
132 |
-
from functools import lru_cache
|
133 |
-
|
134 |
-
from IPython import get_ipython
|
135 |
-
from IPython.core.excolors import exception_colors
|
136 |
-
from IPython.utils import PyColorize, coloransi, py3compat
|
137 |
-
|
138 |
-
from typing import TYPE_CHECKING
|
139 |
-
|
140 |
-
if TYPE_CHECKING:
|
141 |
-
# otherwise circular import
|
142 |
-
from IPython.core.interactiveshell import InteractiveShell
|
143 |
-
|
144 |
-
# skip module docstests
|
145 |
-
__skip_doctest__ = True
|
146 |
-
|
147 |
-
prompt = 'ipdb> '
|
148 |
-
|
149 |
-
# We have to check this directly from sys.argv, config struct not yet available
|
150 |
-
from pdb import Pdb as OldPdb
|
151 |
-
|
152 |
-
# Allow the set_trace code to operate outside of an ipython instance, even if
|
153 |
-
# it does so with some limitations. The rest of this support is implemented in
|
154 |
-
# the Tracer constructor.
|
155 |
-
|
156 |
-
DEBUGGERSKIP = "__debuggerskip__"
|
157 |
-
|
158 |
-
|
159 |
-
# this has been implemented in Pdb in Python 3.13 (https://github.com/python/cpython/pull/106676
|
160 |
-
# on lower python versions, we backported the feature.
|
161 |
-
CHAIN_EXCEPTIONS = sys.version_info < (3, 13)
|
162 |
-
|
163 |
-
|
164 |
-
def make_arrow(pad):
|
165 |
-
"""generate the leading arrow in front of traceback or debugger"""
|
166 |
-
if pad >= 2:
|
167 |
-
return '-'*(pad-2) + '> '
|
168 |
-
elif pad == 1:
|
169 |
-
return '>'
|
170 |
-
return ''
|
171 |
-
|
172 |
-
|
173 |
-
def BdbQuit_excepthook(et, ev, tb, excepthook=None):
|
174 |
-
"""Exception hook which handles `BdbQuit` exceptions.
|
175 |
-
|
176 |
-
All other exceptions are processed using the `excepthook`
|
177 |
-
parameter.
|
178 |
-
"""
|
179 |
-
raise ValueError(
|
180 |
-
"`BdbQuit_excepthook` is deprecated since version 5.1. It is still around only because it is still imported by ipdb.",
|
181 |
-
)
|
182 |
-
|
183 |
-
|
184 |
-
RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+')
|
185 |
-
|
186 |
-
|
187 |
-
def strip_indentation(multiline_string):
|
188 |
-
return RGX_EXTRA_INDENT.sub('', multiline_string)
|
189 |
-
|
190 |
-
|
191 |
-
def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
|
192 |
-
"""Make new_fn have old_fn's doc string. This is particularly useful
|
193 |
-
for the ``do_...`` commands that hook into the help system.
|
194 |
-
Adapted from from a comp.lang.python posting
|
195 |
-
by Duncan Booth."""
|
196 |
-
def wrapper(*args, **kw):
|
197 |
-
return new_fn(*args, **kw)
|
198 |
-
if old_fn.__doc__:
|
199 |
-
wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text
|
200 |
-
return wrapper
|
201 |
-
|
202 |
-
|
203 |
-
class Pdb(OldPdb):
|
204 |
-
"""Modified Pdb class, does not load readline.
|
205 |
-
|
206 |
-
for a standalone version that uses prompt_toolkit, see
|
207 |
-
`IPython.terminal.debugger.TerminalPdb` and
|
208 |
-
`IPython.terminal.debugger.set_trace()`
|
209 |
-
|
210 |
-
|
211 |
-
This debugger can hide and skip frames that are tagged according to some predicates.
|
212 |
-
See the `skip_predicates` commands.
|
213 |
-
|
214 |
-
"""
|
215 |
-
|
216 |
-
shell: InteractiveShell
|
217 |
-
|
218 |
-
if CHAIN_EXCEPTIONS:
|
219 |
-
MAX_CHAINED_EXCEPTION_DEPTH = 999
|
220 |
-
|
221 |
-
default_predicates = {
|
222 |
-
"tbhide": True,
|
223 |
-
"readonly": False,
|
224 |
-
"ipython_internal": True,
|
225 |
-
"debuggerskip": True,
|
226 |
-
}
|
227 |
-
|
228 |
-
def __init__(self, completekey=None, stdin=None, stdout=None, context=5, **kwargs):
|
229 |
-
"""Create a new IPython debugger.
|
230 |
-
|
231 |
-
Parameters
|
232 |
-
----------
|
233 |
-
completekey : default None
|
234 |
-
Passed to pdb.Pdb.
|
235 |
-
stdin : default None
|
236 |
-
Passed to pdb.Pdb.
|
237 |
-
stdout : default None
|
238 |
-
Passed to pdb.Pdb.
|
239 |
-
context : int
|
240 |
-
Number of lines of source code context to show when
|
241 |
-
displaying stacktrace information.
|
242 |
-
**kwargs
|
243 |
-
Passed to pdb.Pdb.
|
244 |
-
|
245 |
-
Notes
|
246 |
-
-----
|
247 |
-
The possibilities are python version dependent, see the python
|
248 |
-
docs for more info.
|
249 |
-
"""
|
250 |
-
|
251 |
-
# Parent constructor:
|
252 |
-
try:
|
253 |
-
self.context = int(context)
|
254 |
-
if self.context <= 0:
|
255 |
-
raise ValueError("Context must be a positive integer")
|
256 |
-
except (TypeError, ValueError) as e:
|
257 |
-
raise ValueError("Context must be a positive integer") from e
|
258 |
-
|
259 |
-
# `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
|
260 |
-
OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
|
261 |
-
|
262 |
-
# IPython changes...
|
263 |
-
self.shell = get_ipython()
|
264 |
-
|
265 |
-
if self.shell is None:
|
266 |
-
save_main = sys.modules['__main__']
|
267 |
-
# No IPython instance running, we must create one
|
268 |
-
from IPython.terminal.interactiveshell import \
|
269 |
-
TerminalInteractiveShell
|
270 |
-
self.shell = TerminalInteractiveShell.instance()
|
271 |
-
# needed by any code which calls __import__("__main__") after
|
272 |
-
# the debugger was entered. See also #9941.
|
273 |
-
sys.modules["__main__"] = save_main
|
274 |
-
|
275 |
-
|
276 |
-
color_scheme = self.shell.colors
|
277 |
-
|
278 |
-
self.aliases = {}
|
279 |
-
|
280 |
-
# Create color table: we copy the default one from the traceback
|
281 |
-
# module and add a few attributes needed for debugging
|
282 |
-
self.color_scheme_table = exception_colors()
|
283 |
-
|
284 |
-
# shorthands
|
285 |
-
C = coloransi.TermColors
|
286 |
-
cst = self.color_scheme_table
|
287 |
-
|
288 |
-
|
289 |
-
# Add a python parser so we can syntax highlight source while
|
290 |
-
# debugging.
|
291 |
-
self.parser = PyColorize.Parser(style=color_scheme)
|
292 |
-
self.set_colors(color_scheme)
|
293 |
-
|
294 |
-
# Set the prompt - the default prompt is '(Pdb)'
|
295 |
-
self.prompt = prompt
|
296 |
-
self.skip_hidden = True
|
297 |
-
self.report_skipped = True
|
298 |
-
|
299 |
-
# list of predicates we use to skip frames
|
300 |
-
self._predicates = self.default_predicates
|
301 |
-
|
302 |
-
if CHAIN_EXCEPTIONS:
|
303 |
-
self._chained_exceptions = tuple()
|
304 |
-
self._chained_exception_index = 0
|
305 |
-
|
306 |
-
#
|
307 |
-
def set_colors(self, scheme):
|
308 |
-
"""Shorthand access to the color table scheme selector method."""
|
309 |
-
self.color_scheme_table.set_active_scheme(scheme)
|
310 |
-
self.parser.style = scheme
|
311 |
-
|
312 |
-
def set_trace(self, frame=None):
|
313 |
-
if frame is None:
|
314 |
-
frame = sys._getframe().f_back
|
315 |
-
self.initial_frame = frame
|
316 |
-
return super().set_trace(frame)
|
317 |
-
|
318 |
-
def _hidden_predicate(self, frame):
|
319 |
-
"""
|
320 |
-
Given a frame return whether it it should be hidden or not by IPython.
|
321 |
-
"""
|
322 |
-
|
323 |
-
if self._predicates["readonly"]:
|
324 |
-
fname = frame.f_code.co_filename
|
325 |
-
# we need to check for file existence and interactively define
|
326 |
-
# function would otherwise appear as RO.
|
327 |
-
if os.path.isfile(fname) and not os.access(fname, os.W_OK):
|
328 |
-
return True
|
329 |
-
|
330 |
-
if self._predicates["tbhide"]:
|
331 |
-
if frame in (self.curframe, getattr(self, "initial_frame", None)):
|
332 |
-
return False
|
333 |
-
frame_locals = self._get_frame_locals(frame)
|
334 |
-
if "__tracebackhide__" not in frame_locals:
|
335 |
-
return False
|
336 |
-
return frame_locals["__tracebackhide__"]
|
337 |
-
return False
|
338 |
-
|
339 |
-
def hidden_frames(self, stack):
|
340 |
-
"""
|
341 |
-
Given an index in the stack return whether it should be skipped.
|
342 |
-
|
343 |
-
This is used in up/down and where to skip frames.
|
344 |
-
"""
|
345 |
-
# The f_locals dictionary is updated from the actual frame
|
346 |
-
# locals whenever the .f_locals accessor is called, so we
|
347 |
-
# avoid calling it here to preserve self.curframe_locals.
|
348 |
-
# Furthermore, there is no good reason to hide the current frame.
|
349 |
-
ip_hide = [self._hidden_predicate(s[0]) for s in stack]
|
350 |
-
ip_start = [i for i, s in enumerate(ip_hide) if s == "__ipython_bottom__"]
|
351 |
-
if ip_start and self._predicates["ipython_internal"]:
|
352 |
-
ip_hide = [h if i > ip_start[0] else True for (i, h) in enumerate(ip_hide)]
|
353 |
-
return ip_hide
|
354 |
-
|
355 |
-
if CHAIN_EXCEPTIONS:
|
356 |
-
|
357 |
-
def _get_tb_and_exceptions(self, tb_or_exc):
|
358 |
-
"""
|
359 |
-
Given a tracecack or an exception, return a tuple of chained exceptions
|
360 |
-
and current traceback to inspect.
|
361 |
-
This will deal with selecting the right ``__cause__`` or ``__context__``
|
362 |
-
as well as handling cycles, and return a flattened list of exceptions we
|
363 |
-
can jump to with do_exceptions.
|
364 |
-
"""
|
365 |
-
_exceptions = []
|
366 |
-
if isinstance(tb_or_exc, BaseException):
|
367 |
-
traceback, current = tb_or_exc.__traceback__, tb_or_exc
|
368 |
-
|
369 |
-
while current is not None:
|
370 |
-
if current in _exceptions:
|
371 |
-
break
|
372 |
-
_exceptions.append(current)
|
373 |
-
if current.__cause__ is not None:
|
374 |
-
current = current.__cause__
|
375 |
-
elif (
|
376 |
-
current.__context__ is not None
|
377 |
-
and not current.__suppress_context__
|
378 |
-
):
|
379 |
-
current = current.__context__
|
380 |
-
|
381 |
-
if len(_exceptions) >= self.MAX_CHAINED_EXCEPTION_DEPTH:
|
382 |
-
self.message(
|
383 |
-
f"More than {self.MAX_CHAINED_EXCEPTION_DEPTH}"
|
384 |
-
" chained exceptions found, not all exceptions"
|
385 |
-
"will be browsable with `exceptions`."
|
386 |
-
)
|
387 |
-
break
|
388 |
-
else:
|
389 |
-
traceback = tb_or_exc
|
390 |
-
return tuple(reversed(_exceptions)), traceback
|
391 |
-
|
392 |
-
@contextmanager
|
393 |
-
def _hold_exceptions(self, exceptions):
|
394 |
-
"""
|
395 |
-
Context manager to ensure proper cleaning of exceptions references
|
396 |
-
When given a chained exception instead of a traceback,
|
397 |
-
pdb may hold references to many objects which may leak memory.
|
398 |
-
We use this context manager to make sure everything is properly cleaned
|
399 |
-
"""
|
400 |
-
try:
|
401 |
-
self._chained_exceptions = exceptions
|
402 |
-
self._chained_exception_index = len(exceptions) - 1
|
403 |
-
yield
|
404 |
-
finally:
|
405 |
-
# we can't put those in forget as otherwise they would
|
406 |
-
# be cleared on exception change
|
407 |
-
self._chained_exceptions = tuple()
|
408 |
-
self._chained_exception_index = 0
|
409 |
-
|
410 |
-
def do_exceptions(self, arg):
|
411 |
-
"""exceptions [number]
|
412 |
-
List or change current exception in an exception chain.
|
413 |
-
Without arguments, list all the current exception in the exception
|
414 |
-
chain. Exceptions will be numbered, with the current exception indicated
|
415 |
-
with an arrow.
|
416 |
-
If given an integer as argument, switch to the exception at that index.
|
417 |
-
"""
|
418 |
-
if not self._chained_exceptions:
|
419 |
-
self.message(
|
420 |
-
"Did not find chained exceptions. To move between"
|
421 |
-
" exceptions, pdb/post_mortem must be given an exception"
|
422 |
-
" object rather than a traceback."
|
423 |
-
)
|
424 |
-
return
|
425 |
-
if not arg:
|
426 |
-
for ix, exc in enumerate(self._chained_exceptions):
|
427 |
-
prompt = ">" if ix == self._chained_exception_index else " "
|
428 |
-
rep = repr(exc)
|
429 |
-
if len(rep) > 80:
|
430 |
-
rep = rep[:77] + "..."
|
431 |
-
indicator = (
|
432 |
-
" -"
|
433 |
-
if self._chained_exceptions[ix].__traceback__ is None
|
434 |
-
else f"{ix:>3}"
|
435 |
-
)
|
436 |
-
self.message(f"{prompt} {indicator} {rep}")
|
437 |
-
else:
|
438 |
-
try:
|
439 |
-
number = int(arg)
|
440 |
-
except ValueError:
|
441 |
-
self.error("Argument must be an integer")
|
442 |
-
return
|
443 |
-
if 0 <= number < len(self._chained_exceptions):
|
444 |
-
if self._chained_exceptions[number].__traceback__ is None:
|
445 |
-
self.error(
|
446 |
-
"This exception does not have a traceback, cannot jump to it"
|
447 |
-
)
|
448 |
-
return
|
449 |
-
|
450 |
-
self._chained_exception_index = number
|
451 |
-
self.setup(None, self._chained_exceptions[number].__traceback__)
|
452 |
-
self.print_stack_entry(self.stack[self.curindex])
|
453 |
-
else:
|
454 |
-
self.error("No exception with that number")
|
455 |
-
|
456 |
-
def interaction(self, frame, tb_or_exc):
|
457 |
-
try:
|
458 |
-
if CHAIN_EXCEPTIONS:
|
459 |
-
# this context manager is part of interaction in 3.13
|
460 |
-
_chained_exceptions, tb = self._get_tb_and_exceptions(tb_or_exc)
|
461 |
-
if isinstance(tb_or_exc, BaseException):
|
462 |
-
assert tb is not None, "main exception must have a traceback"
|
463 |
-
with self._hold_exceptions(_chained_exceptions):
|
464 |
-
OldPdb.interaction(self, frame, tb)
|
465 |
-
else:
|
466 |
-
OldPdb.interaction(self, frame, tb_or_exc)
|
467 |
-
|
468 |
-
except KeyboardInterrupt:
|
469 |
-
self.stdout.write("\n" + self.shell.get_exception_only())
|
470 |
-
|
471 |
-
def precmd(self, line):
|
472 |
-
"""Perform useful escapes on the command before it is executed."""
|
473 |
-
|
474 |
-
if line.endswith("??"):
|
475 |
-
line = "pinfo2 " + line[:-2]
|
476 |
-
elif line.endswith("?"):
|
477 |
-
line = "pinfo " + line[:-1]
|
478 |
-
|
479 |
-
line = super().precmd(line)
|
480 |
-
|
481 |
-
return line
|
482 |
-
|
483 |
-
def new_do_quit(self, arg):
|
484 |
-
return OldPdb.do_quit(self, arg)
|
485 |
-
|
486 |
-
do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
|
487 |
-
|
488 |
-
def print_stack_trace(self, context=None):
|
489 |
-
Colors = self.color_scheme_table.active_colors
|
490 |
-
ColorsNormal = Colors.Normal
|
491 |
-
if context is None:
|
492 |
-
context = self.context
|
493 |
-
try:
|
494 |
-
context = int(context)
|
495 |
-
if context <= 0:
|
496 |
-
raise ValueError("Context must be a positive integer")
|
497 |
-
except (TypeError, ValueError) as e:
|
498 |
-
raise ValueError("Context must be a positive integer") from e
|
499 |
-
try:
|
500 |
-
skipped = 0
|
501 |
-
for hidden, frame_lineno in zip(self.hidden_frames(self.stack), self.stack):
|
502 |
-
if hidden and self.skip_hidden:
|
503 |
-
skipped += 1
|
504 |
-
continue
|
505 |
-
if skipped:
|
506 |
-
print(
|
507 |
-
f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
|
508 |
-
)
|
509 |
-
skipped = 0
|
510 |
-
self.print_stack_entry(frame_lineno, context=context)
|
511 |
-
if skipped:
|
512 |
-
print(
|
513 |
-
f"{Colors.excName} [... skipping {skipped} hidden frame(s)]{ColorsNormal}\n"
|
514 |
-
)
|
515 |
-
except KeyboardInterrupt:
|
516 |
-
pass
|
517 |
-
|
518 |
-
def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
|
519 |
-
context=None):
|
520 |
-
if context is None:
|
521 |
-
context = self.context
|
522 |
-
try:
|
523 |
-
context = int(context)
|
524 |
-
if context <= 0:
|
525 |
-
raise ValueError("Context must be a positive integer")
|
526 |
-
except (TypeError, ValueError) as e:
|
527 |
-
raise ValueError("Context must be a positive integer") from e
|
528 |
-
print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
|
529 |
-
|
530 |
-
# vds: >>
|
531 |
-
frame, lineno = frame_lineno
|
532 |
-
filename = frame.f_code.co_filename
|
533 |
-
self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
|
534 |
-
# vds: <<
|
535 |
-
|
536 |
-
def _get_frame_locals(self, frame):
|
537 |
-
""" "
|
538 |
-
Accessing f_local of current frame reset the namespace, so we want to avoid
|
539 |
-
that or the following can happen
|
540 |
-
|
541 |
-
ipdb> foo
|
542 |
-
"old"
|
543 |
-
ipdb> foo = "new"
|
544 |
-
ipdb> foo
|
545 |
-
"new"
|
546 |
-
ipdb> where
|
547 |
-
ipdb> foo
|
548 |
-
"old"
|
549 |
-
|
550 |
-
So if frame is self.current_frame we instead return self.curframe_locals
|
551 |
-
|
552 |
-
"""
|
553 |
-
if frame is getattr(self, "curframe", None):
|
554 |
-
return self.curframe_locals
|
555 |
-
else:
|
556 |
-
return frame.f_locals
|
557 |
-
|
558 |
-
def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
|
559 |
-
if context is None:
|
560 |
-
context = self.context
|
561 |
-
try:
|
562 |
-
context = int(context)
|
563 |
-
if context <= 0:
|
564 |
-
print("Context must be a positive integer", file=self.stdout)
|
565 |
-
except (TypeError, ValueError):
|
566 |
-
print("Context must be a positive integer", file=self.stdout)
|
567 |
-
|
568 |
-
import reprlib
|
569 |
-
|
570 |
-
ret = []
|
571 |
-
|
572 |
-
Colors = self.color_scheme_table.active_colors
|
573 |
-
ColorsNormal = Colors.Normal
|
574 |
-
tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal)
|
575 |
-
tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal)
|
576 |
-
tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal)
|
577 |
-
tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal)
|
578 |
-
|
579 |
-
frame, lineno = frame_lineno
|
580 |
-
|
581 |
-
return_value = ''
|
582 |
-
loc_frame = self._get_frame_locals(frame)
|
583 |
-
if "__return__" in loc_frame:
|
584 |
-
rv = loc_frame["__return__"]
|
585 |
-
# return_value += '->'
|
586 |
-
return_value += reprlib.repr(rv) + "\n"
|
587 |
-
ret.append(return_value)
|
588 |
-
|
589 |
-
#s = filename + '(' + `lineno` + ')'
|
590 |
-
filename = self.canonic(frame.f_code.co_filename)
|
591 |
-
link = tpl_link % py3compat.cast_unicode(filename)
|
592 |
-
|
593 |
-
if frame.f_code.co_name:
|
594 |
-
func = frame.f_code.co_name
|
595 |
-
else:
|
596 |
-
func = "<lambda>"
|
597 |
-
|
598 |
-
call = ""
|
599 |
-
if func != "?":
|
600 |
-
if "__args__" in loc_frame:
|
601 |
-
args = reprlib.repr(loc_frame["__args__"])
|
602 |
-
else:
|
603 |
-
args = '()'
|
604 |
-
call = tpl_call % (func, args)
|
605 |
-
|
606 |
-
# The level info should be generated in the same format pdb uses, to
|
607 |
-
# avoid breaking the pdbtrack functionality of python-mode in *emacs.
|
608 |
-
if frame is self.curframe:
|
609 |
-
ret.append('> ')
|
610 |
-
else:
|
611 |
-
ret.append(" ")
|
612 |
-
ret.append("%s(%s)%s\n" % (link, lineno, call))
|
613 |
-
|
614 |
-
start = lineno - 1 - context//2
|
615 |
-
lines = linecache.getlines(filename)
|
616 |
-
start = min(start, len(lines) - context)
|
617 |
-
start = max(start, 0)
|
618 |
-
lines = lines[start : start + context]
|
619 |
-
|
620 |
-
for i, line in enumerate(lines):
|
621 |
-
show_arrow = start + 1 + i == lineno
|
622 |
-
linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line
|
623 |
-
ret.append(
|
624 |
-
self.__format_line(
|
625 |
-
linetpl, filename, start + 1 + i, line, arrow=show_arrow
|
626 |
-
)
|
627 |
-
)
|
628 |
-
return "".join(ret)
|
629 |
-
|
630 |
-
def __format_line(self, tpl_line, filename, lineno, line, arrow=False):
|
631 |
-
bp_mark = ""
|
632 |
-
bp_mark_color = ""
|
633 |
-
|
634 |
-
new_line, err = self.parser.format2(line, 'str')
|
635 |
-
if not err:
|
636 |
-
line = new_line
|
637 |
-
|
638 |
-
bp = None
|
639 |
-
if lineno in self.get_file_breaks(filename):
|
640 |
-
bps = self.get_breaks(filename, lineno)
|
641 |
-
bp = bps[-1]
|
642 |
-
|
643 |
-
if bp:
|
644 |
-
Colors = self.color_scheme_table.active_colors
|
645 |
-
bp_mark = str(bp.number)
|
646 |
-
bp_mark_color = Colors.breakpoint_enabled
|
647 |
-
if not bp.enabled:
|
648 |
-
bp_mark_color = Colors.breakpoint_disabled
|
649 |
-
|
650 |
-
numbers_width = 7
|
651 |
-
if arrow:
|
652 |
-
# This is the line with the error
|
653 |
-
pad = numbers_width - len(str(lineno)) - len(bp_mark)
|
654 |
-
num = '%s%s' % (make_arrow(pad), str(lineno))
|
655 |
-
else:
|
656 |
-
num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
|
657 |
-
|
658 |
-
return tpl_line % (bp_mark_color + bp_mark, num, line)
|
659 |
-
|
660 |
-
def print_list_lines(self, filename, first, last):
|
661 |
-
"""The printing (as opposed to the parsing part of a 'list'
|
662 |
-
command."""
|
663 |
-
try:
|
664 |
-
Colors = self.color_scheme_table.active_colors
|
665 |
-
ColorsNormal = Colors.Normal
|
666 |
-
tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
|
667 |
-
tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
|
668 |
-
src = []
|
669 |
-
if filename == "<string>" and hasattr(self, "_exec_filename"):
|
670 |
-
filename = self._exec_filename
|
671 |
-
|
672 |
-
for lineno in range(first, last+1):
|
673 |
-
line = linecache.getline(filename, lineno)
|
674 |
-
if not line:
|
675 |
-
break
|
676 |
-
|
677 |
-
if lineno == self.curframe.f_lineno:
|
678 |
-
line = self.__format_line(
|
679 |
-
tpl_line_em, filename, lineno, line, arrow=True
|
680 |
-
)
|
681 |
-
else:
|
682 |
-
line = self.__format_line(
|
683 |
-
tpl_line, filename, lineno, line, arrow=False
|
684 |
-
)
|
685 |
-
|
686 |
-
src.append(line)
|
687 |
-
self.lineno = lineno
|
688 |
-
|
689 |
-
print(''.join(src), file=self.stdout)
|
690 |
-
|
691 |
-
except KeyboardInterrupt:
|
692 |
-
pass
|
693 |
-
|
694 |
-
def do_skip_predicates(self, args):
|
695 |
-
"""
|
696 |
-
Turn on/off individual predicates as to whether a frame should be hidden/skip.
|
697 |
-
|
698 |
-
The global option to skip (or not) hidden frames is set with skip_hidden
|
699 |
-
|
700 |
-
To change the value of a predicate
|
701 |
-
|
702 |
-
skip_predicates key [true|false]
|
703 |
-
|
704 |
-
Call without arguments to see the current values.
|
705 |
-
|
706 |
-
To permanently change the value of an option add the corresponding
|
707 |
-
command to your ``~/.pdbrc`` file. If you are programmatically using the
|
708 |
-
Pdb instance you can also change the ``default_predicates`` class
|
709 |
-
attribute.
|
710 |
-
"""
|
711 |
-
if not args.strip():
|
712 |
-
print("current predicates:")
|
713 |
-
for p, v in self._predicates.items():
|
714 |
-
print(" ", p, ":", v)
|
715 |
-
return
|
716 |
-
type_value = args.strip().split(" ")
|
717 |
-
if len(type_value) != 2:
|
718 |
-
print(
|
719 |
-
f"Usage: skip_predicates <type> <value>, with <type> one of {set(self._predicates.keys())}"
|
720 |
-
)
|
721 |
-
return
|
722 |
-
|
723 |
-
type_, value = type_value
|
724 |
-
if type_ not in self._predicates:
|
725 |
-
print(f"{type_!r} not in {set(self._predicates.keys())}")
|
726 |
-
return
|
727 |
-
if value.lower() not in ("true", "yes", "1", "no", "false", "0"):
|
728 |
-
print(
|
729 |
-
f"{value!r} is invalid - use one of ('true', 'yes', '1', 'no', 'false', '0')"
|
730 |
-
)
|
731 |
-
return
|
732 |
-
|
733 |
-
self._predicates[type_] = value.lower() in ("true", "yes", "1")
|
734 |
-
if not any(self._predicates.values()):
|
735 |
-
print(
|
736 |
-
"Warning, all predicates set to False, skip_hidden may not have any effects."
|
737 |
-
)
|
738 |
-
|
739 |
-
def do_skip_hidden(self, arg):
|
740 |
-
"""
|
741 |
-
Change whether or not we should skip frames with the
|
742 |
-
__tracebackhide__ attribute.
|
743 |
-
"""
|
744 |
-
if not arg.strip():
|
745 |
-
print(
|
746 |
-
f"skip_hidden = {self.skip_hidden}, use 'yes','no', 'true', or 'false' to change."
|
747 |
-
)
|
748 |
-
elif arg.strip().lower() in ("true", "yes"):
|
749 |
-
self.skip_hidden = True
|
750 |
-
elif arg.strip().lower() in ("false", "no"):
|
751 |
-
self.skip_hidden = False
|
752 |
-
if not any(self._predicates.values()):
|
753 |
-
print(
|
754 |
-
"Warning, all predicates set to False, skip_hidden may not have any effects."
|
755 |
-
)
|
756 |
-
|
757 |
-
def do_list(self, arg):
|
758 |
-
"""Print lines of code from the current stack frame
|
759 |
-
"""
|
760 |
-
self.lastcmd = 'list'
|
761 |
-
last = None
|
762 |
-
if arg and arg != ".":
|
763 |
-
try:
|
764 |
-
x = eval(arg, {}, {})
|
765 |
-
if type(x) == type(()):
|
766 |
-
first, last = x
|
767 |
-
first = int(first)
|
768 |
-
last = int(last)
|
769 |
-
if last < first:
|
770 |
-
# Assume it's a count
|
771 |
-
last = first + last
|
772 |
-
else:
|
773 |
-
first = max(1, int(x) - 5)
|
774 |
-
except:
|
775 |
-
print('*** Error in argument:', repr(arg), file=self.stdout)
|
776 |
-
return
|
777 |
-
elif self.lineno is None or arg == ".":
|
778 |
-
first = max(1, self.curframe.f_lineno - 5)
|
779 |
-
else:
|
780 |
-
first = self.lineno + 1
|
781 |
-
if last is None:
|
782 |
-
last = first + 10
|
783 |
-
self.print_list_lines(self.curframe.f_code.co_filename, first, last)
|
784 |
-
|
785 |
-
# vds: >>
|
786 |
-
lineno = first
|
787 |
-
filename = self.curframe.f_code.co_filename
|
788 |
-
self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
|
789 |
-
# vds: <<
|
790 |
-
|
791 |
-
do_l = do_list
|
792 |
-
|
793 |
-
def getsourcelines(self, obj):
|
794 |
-
lines, lineno = inspect.findsource(obj)
|
795 |
-
if inspect.isframe(obj) and obj.f_globals is self._get_frame_locals(obj):
|
796 |
-
# must be a module frame: do not try to cut a block out of it
|
797 |
-
return lines, 1
|
798 |
-
elif inspect.ismodule(obj):
|
799 |
-
return lines, 1
|
800 |
-
return inspect.getblock(lines[lineno:]), lineno+1
|
801 |
-
|
802 |
-
def do_longlist(self, arg):
|
803 |
-
"""Print lines of code from the current stack frame.
|
804 |
-
|
805 |
-
Shows more lines than 'list' does.
|
806 |
-
"""
|
807 |
-
self.lastcmd = 'longlist'
|
808 |
-
try:
|
809 |
-
lines, lineno = self.getsourcelines(self.curframe)
|
810 |
-
except OSError as err:
|
811 |
-
self.error(err)
|
812 |
-
return
|
813 |
-
last = lineno + len(lines)
|
814 |
-
self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
|
815 |
-
do_ll = do_longlist
|
816 |
-
|
817 |
-
def do_debug(self, arg):
|
818 |
-
"""debug code
|
819 |
-
Enter a recursive debugger that steps through the code
|
820 |
-
argument (which is an arbitrary expression or statement to be
|
821 |
-
executed in the current environment).
|
822 |
-
"""
|
823 |
-
trace_function = sys.gettrace()
|
824 |
-
sys.settrace(None)
|
825 |
-
globals = self.curframe.f_globals
|
826 |
-
locals = self.curframe_locals
|
827 |
-
p = self.__class__(completekey=self.completekey,
|
828 |
-
stdin=self.stdin, stdout=self.stdout)
|
829 |
-
p.use_rawinput = self.use_rawinput
|
830 |
-
p.prompt = "(%s) " % self.prompt.strip()
|
831 |
-
self.message("ENTERING RECURSIVE DEBUGGER")
|
832 |
-
sys.call_tracing(p.run, (arg, globals, locals))
|
833 |
-
self.message("LEAVING RECURSIVE DEBUGGER")
|
834 |
-
sys.settrace(trace_function)
|
835 |
-
self.lastcmd = p.lastcmd
|
836 |
-
|
837 |
-
def do_pdef(self, arg):
|
838 |
-
"""Print the call signature for any callable object.
|
839 |
-
|
840 |
-
The debugger interface to %pdef"""
|
841 |
-
namespaces = [
|
842 |
-
("Locals", self.curframe_locals),
|
843 |
-
("Globals", self.curframe.f_globals),
|
844 |
-
]
|
845 |
-
self.shell.find_line_magic("pdef")(arg, namespaces=namespaces)
|
846 |
-
|
847 |
-
def do_pdoc(self, arg):
|
848 |
-
"""Print the docstring for an object.
|
849 |
-
|
850 |
-
The debugger interface to %pdoc."""
|
851 |
-
namespaces = [
|
852 |
-
("Locals", self.curframe_locals),
|
853 |
-
("Globals", self.curframe.f_globals),
|
854 |
-
]
|
855 |
-
self.shell.find_line_magic("pdoc")(arg, namespaces=namespaces)
|
856 |
-
|
857 |
-
def do_pfile(self, arg):
|
858 |
-
"""Print (or run through pager) the file where an object is defined.
|
859 |
-
|
860 |
-
The debugger interface to %pfile.
|
861 |
-
"""
|
862 |
-
namespaces = [
|
863 |
-
("Locals", self.curframe_locals),
|
864 |
-
("Globals", self.curframe.f_globals),
|
865 |
-
]
|
866 |
-
self.shell.find_line_magic("pfile")(arg, namespaces=namespaces)
|
867 |
-
|
868 |
-
def do_pinfo(self, arg):
|
869 |
-
"""Provide detailed information about an object.
|
870 |
-
|
871 |
-
The debugger interface to %pinfo, i.e., obj?."""
|
872 |
-
namespaces = [
|
873 |
-
("Locals", self.curframe_locals),
|
874 |
-
("Globals", self.curframe.f_globals),
|
875 |
-
]
|
876 |
-
self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
|
877 |
-
|
878 |
-
def do_pinfo2(self, arg):
|
879 |
-
"""Provide extra detailed information about an object.
|
880 |
-
|
881 |
-
The debugger interface to %pinfo2, i.e., obj??."""
|
882 |
-
namespaces = [
|
883 |
-
("Locals", self.curframe_locals),
|
884 |
-
("Globals", self.curframe.f_globals),
|
885 |
-
]
|
886 |
-
self.shell.find_line_magic("pinfo2")(arg, namespaces=namespaces)
|
887 |
-
|
888 |
-
def do_psource(self, arg):
|
889 |
-
"""Print (or run through pager) the source code for an object."""
|
890 |
-
namespaces = [
|
891 |
-
("Locals", self.curframe_locals),
|
892 |
-
("Globals", self.curframe.f_globals),
|
893 |
-
]
|
894 |
-
self.shell.find_line_magic("psource")(arg, namespaces=namespaces)
|
895 |
-
|
896 |
-
def do_where(self, arg):
|
897 |
-
"""w(here)
|
898 |
-
Print a stack trace, with the most recent frame at the bottom.
|
899 |
-
An arrow indicates the "current frame", which determines the
|
900 |
-
context of most commands. 'bt' is an alias for this command.
|
901 |
-
|
902 |
-
Take a number as argument as an (optional) number of context line to
|
903 |
-
print"""
|
904 |
-
if arg:
|
905 |
-
try:
|
906 |
-
context = int(arg)
|
907 |
-
except ValueError as err:
|
908 |
-
self.error(err)
|
909 |
-
return
|
910 |
-
self.print_stack_trace(context)
|
911 |
-
else:
|
912 |
-
self.print_stack_trace()
|
913 |
-
|
914 |
-
do_w = do_where
|
915 |
-
|
916 |
-
def break_anywhere(self, frame):
|
917 |
-
"""
|
918 |
-
_stop_in_decorator_internals is overly restrictive, as we may still want
|
919 |
-
to trace function calls, so we need to also update break_anywhere so
|
920 |
-
that is we don't `stop_here`, because of debugger skip, we may still
|
921 |
-
stop at any point inside the function
|
922 |
-
|
923 |
-
"""
|
924 |
-
|
925 |
-
sup = super().break_anywhere(frame)
|
926 |
-
if sup:
|
927 |
-
return sup
|
928 |
-
if self._predicates["debuggerskip"]:
|
929 |
-
if DEBUGGERSKIP in frame.f_code.co_varnames:
|
930 |
-
return True
|
931 |
-
if frame.f_back and self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
|
932 |
-
return True
|
933 |
-
return False
|
934 |
-
|
935 |
-
def _is_in_decorator_internal_and_should_skip(self, frame):
|
936 |
-
"""
|
937 |
-
Utility to tell us whether we are in a decorator internal and should stop.
|
938 |
-
|
939 |
-
"""
|
940 |
-
# if we are disabled don't skip
|
941 |
-
if not self._predicates["debuggerskip"]:
|
942 |
-
return False
|
943 |
-
|
944 |
-
return self._cachable_skip(frame)
|
945 |
-
|
946 |
-
@lru_cache(1024)
|
947 |
-
def _cached_one_parent_frame_debuggerskip(self, frame):
|
948 |
-
"""
|
949 |
-
Cache looking up for DEBUGGERSKIP on parent frame.
|
950 |
-
|
951 |
-
This should speedup walking through deep frame when one of the highest
|
952 |
-
one does have a debugger skip.
|
953 |
-
|
954 |
-
This is likely to introduce fake positive though.
|
955 |
-
"""
|
956 |
-
while getattr(frame, "f_back", None):
|
957 |
-
frame = frame.f_back
|
958 |
-
if self._get_frame_locals(frame).get(DEBUGGERSKIP):
|
959 |
-
return True
|
960 |
-
return None
|
961 |
-
|
962 |
-
@lru_cache(1024)
|
963 |
-
def _cachable_skip(self, frame):
|
964 |
-
# if frame is tagged, skip by default.
|
965 |
-
if DEBUGGERSKIP in frame.f_code.co_varnames:
|
966 |
-
return True
|
967 |
-
|
968 |
-
# if one of the parent frame value set to True skip as well.
|
969 |
-
if self._cached_one_parent_frame_debuggerskip(frame):
|
970 |
-
return True
|
971 |
-
|
972 |
-
return False
|
973 |
-
|
974 |
-
def stop_here(self, frame):
|
975 |
-
if self._is_in_decorator_internal_and_should_skip(frame) is True:
|
976 |
-
return False
|
977 |
-
|
978 |
-
hidden = False
|
979 |
-
if self.skip_hidden:
|
980 |
-
hidden = self._hidden_predicate(frame)
|
981 |
-
if hidden:
|
982 |
-
if self.report_skipped:
|
983 |
-
Colors = self.color_scheme_table.active_colors
|
984 |
-
ColorsNormal = Colors.Normal
|
985 |
-
print(
|
986 |
-
f"{Colors.excName} [... skipped 1 hidden frame]{ColorsNormal}\n"
|
987 |
-
)
|
988 |
-
return super().stop_here(frame)
|
989 |
-
|
990 |
-
def do_up(self, arg):
|
991 |
-
"""u(p) [count]
|
992 |
-
Move the current frame count (default one) levels up in the
|
993 |
-
stack trace (to an older frame).
|
994 |
-
|
995 |
-
Will skip hidden frames.
|
996 |
-
"""
|
997 |
-
# modified version of upstream that skips
|
998 |
-
# frames with __tracebackhide__
|
999 |
-
if self.curindex == 0:
|
1000 |
-
self.error("Oldest frame")
|
1001 |
-
return
|
1002 |
-
try:
|
1003 |
-
count = int(arg or 1)
|
1004 |
-
except ValueError:
|
1005 |
-
self.error("Invalid frame count (%s)" % arg)
|
1006 |
-
return
|
1007 |
-
skipped = 0
|
1008 |
-
if count < 0:
|
1009 |
-
_newframe = 0
|
1010 |
-
else:
|
1011 |
-
counter = 0
|
1012 |
-
hidden_frames = self.hidden_frames(self.stack)
|
1013 |
-
for i in range(self.curindex - 1, -1, -1):
|
1014 |
-
if hidden_frames[i] and self.skip_hidden:
|
1015 |
-
skipped += 1
|
1016 |
-
continue
|
1017 |
-
counter += 1
|
1018 |
-
if counter >= count:
|
1019 |
-
break
|
1020 |
-
else:
|
1021 |
-
# if no break occurred.
|
1022 |
-
self.error(
|
1023 |
-
"all frames above hidden, use `skip_hidden False` to get get into those."
|
1024 |
-
)
|
1025 |
-
return
|
1026 |
-
|
1027 |
-
Colors = self.color_scheme_table.active_colors
|
1028 |
-
ColorsNormal = Colors.Normal
|
1029 |
-
_newframe = i
|
1030 |
-
self._select_frame(_newframe)
|
1031 |
-
if skipped:
|
1032 |
-
print(
|
1033 |
-
f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
|
1034 |
-
)
|
1035 |
-
|
1036 |
-
def do_down(self, arg):
|
1037 |
-
"""d(own) [count]
|
1038 |
-
Move the current frame count (default one) levels down in the
|
1039 |
-
stack trace (to a newer frame).
|
1040 |
-
|
1041 |
-
Will skip hidden frames.
|
1042 |
-
"""
|
1043 |
-
if self.curindex + 1 == len(self.stack):
|
1044 |
-
self.error("Newest frame")
|
1045 |
-
return
|
1046 |
-
try:
|
1047 |
-
count = int(arg or 1)
|
1048 |
-
except ValueError:
|
1049 |
-
self.error("Invalid frame count (%s)" % arg)
|
1050 |
-
return
|
1051 |
-
if count < 0:
|
1052 |
-
_newframe = len(self.stack) - 1
|
1053 |
-
else:
|
1054 |
-
counter = 0
|
1055 |
-
skipped = 0
|
1056 |
-
hidden_frames = self.hidden_frames(self.stack)
|
1057 |
-
for i in range(self.curindex + 1, len(self.stack)):
|
1058 |
-
if hidden_frames[i] and self.skip_hidden:
|
1059 |
-
skipped += 1
|
1060 |
-
continue
|
1061 |
-
counter += 1
|
1062 |
-
if counter >= count:
|
1063 |
-
break
|
1064 |
-
else:
|
1065 |
-
self.error(
|
1066 |
-
"all frames below hidden, use `skip_hidden False` to get get into those."
|
1067 |
-
)
|
1068 |
-
return
|
1069 |
-
|
1070 |
-
Colors = self.color_scheme_table.active_colors
|
1071 |
-
ColorsNormal = Colors.Normal
|
1072 |
-
if skipped:
|
1073 |
-
print(
|
1074 |
-
f"{Colors.excName} [... skipped {skipped} hidden frame(s)]{ColorsNormal}\n"
|
1075 |
-
)
|
1076 |
-
_newframe = i
|
1077 |
-
|
1078 |
-
self._select_frame(_newframe)
|
1079 |
-
|
1080 |
-
do_d = do_down
|
1081 |
-
do_u = do_up
|
1082 |
-
|
1083 |
-
def do_context(self, context):
|
1084 |
-
"""context number_of_lines
|
1085 |
-
Set the number of lines of source code to show when displaying
|
1086 |
-
stacktrace information.
|
1087 |
-
"""
|
1088 |
-
try:
|
1089 |
-
new_context = int(context)
|
1090 |
-
if new_context <= 0:
|
1091 |
-
raise ValueError()
|
1092 |
-
self.context = new_context
|
1093 |
-
except ValueError:
|
1094 |
-
self.error(
|
1095 |
-
f"The 'context' command requires a positive integer argument (current value {self.context})."
|
1096 |
-
)
|
1097 |
-
|
1098 |
-
|
1099 |
-
class InterruptiblePdb(Pdb):
|
1100 |
-
"""Version of debugger where KeyboardInterrupt exits the debugger altogether."""
|
1101 |
-
|
1102 |
-
def cmdloop(self, intro=None):
|
1103 |
-
"""Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
|
1104 |
-
try:
|
1105 |
-
return OldPdb.cmdloop(self, intro=intro)
|
1106 |
-
except KeyboardInterrupt:
|
1107 |
-
self.stop_here = lambda frame: False
|
1108 |
-
self.do_quit("")
|
1109 |
-
sys.settrace(None)
|
1110 |
-
self.quitting = False
|
1111 |
-
raise
|
1112 |
-
|
1113 |
-
def _cmdloop(self):
|
1114 |
-
while True:
|
1115 |
-
try:
|
1116 |
-
# keyboard interrupts allow for an easy way to cancel
|
1117 |
-
# the current command, so allow them during interactive input
|
1118 |
-
self.allow_kbdint = True
|
1119 |
-
self.cmdloop()
|
1120 |
-
self.allow_kbdint = False
|
1121 |
-
break
|
1122 |
-
except KeyboardInterrupt:
|
1123 |
-
self.message('--KeyboardInterrupt--')
|
1124 |
-
raise
|
1125 |
-
|
1126 |
-
|
1127 |
-
def set_trace(frame=None, header=None):
|
1128 |
-
"""
|
1129 |
-
Start debugging from `frame`.
|
1130 |
-
|
1131 |
-
If frame is not specified, debugging starts from caller's frame.
|
1132 |
-
"""
|
1133 |
-
pdb = Pdb()
|
1134 |
-
if header is not None:
|
1135 |
-
pdb.message(header)
|
1136 |
-
pdb.set_trace(frame or sys._getframe().f_back)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/display.py
DELETED
@@ -1,1373 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
"""Top-level display functions for displaying object in different formats."""
|
3 |
-
|
4 |
-
# Copyright (c) IPython Development Team.
|
5 |
-
# Distributed under the terms of the Modified BSD License.
|
6 |
-
|
7 |
-
|
8 |
-
from binascii import b2a_base64, hexlify
|
9 |
-
import html
|
10 |
-
import json
|
11 |
-
import mimetypes
|
12 |
-
import os
|
13 |
-
import struct
|
14 |
-
import warnings
|
15 |
-
from copy import deepcopy
|
16 |
-
from os.path import splitext
|
17 |
-
from pathlib import Path, PurePath
|
18 |
-
|
19 |
-
from typing import Optional
|
20 |
-
|
21 |
-
from IPython.testing.skipdoctest import skip_doctest
|
22 |
-
from . import display_functions
|
23 |
-
|
24 |
-
|
25 |
-
__all__ = [
|
26 |
-
"display_pretty",
|
27 |
-
"display_html",
|
28 |
-
"display_markdown",
|
29 |
-
"display_svg",
|
30 |
-
"display_png",
|
31 |
-
"display_jpeg",
|
32 |
-
"display_webp",
|
33 |
-
"display_latex",
|
34 |
-
"display_json",
|
35 |
-
"display_javascript",
|
36 |
-
"display_pdf",
|
37 |
-
"DisplayObject",
|
38 |
-
"TextDisplayObject",
|
39 |
-
"Pretty",
|
40 |
-
"HTML",
|
41 |
-
"Markdown",
|
42 |
-
"Math",
|
43 |
-
"Latex",
|
44 |
-
"SVG",
|
45 |
-
"ProgressBar",
|
46 |
-
"JSON",
|
47 |
-
"GeoJSON",
|
48 |
-
"Javascript",
|
49 |
-
"Image",
|
50 |
-
"set_matplotlib_formats",
|
51 |
-
"set_matplotlib_close",
|
52 |
-
"Video",
|
53 |
-
]
|
54 |
-
|
55 |
-
_deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
|
56 |
-
|
57 |
-
__all__ = __all__ + _deprecated_names
|
58 |
-
|
59 |
-
|
60 |
-
# ----- warn to import from IPython.display -----
|
61 |
-
|
62 |
-
from warnings import warn
|
63 |
-
|
64 |
-
|
65 |
-
def __getattr__(name):
|
66 |
-
if name in _deprecated_names:
|
67 |
-
warn(
|
68 |
-
f"Importing {name} from IPython.core.display is deprecated since IPython 7.14, please import from IPython.display",
|
69 |
-
DeprecationWarning,
|
70 |
-
stacklevel=2,
|
71 |
-
)
|
72 |
-
return getattr(display_functions, name)
|
73 |
-
|
74 |
-
if name in globals().keys():
|
75 |
-
return globals()[name]
|
76 |
-
else:
|
77 |
-
raise AttributeError(f"module {__name__} has no attribute {name}")
|
78 |
-
|
79 |
-
|
80 |
-
#-----------------------------------------------------------------------------
|
81 |
-
# utility functions
|
82 |
-
#-----------------------------------------------------------------------------
|
83 |
-
|
84 |
-
def _safe_exists(path):
|
85 |
-
"""Check path, but don't let exceptions raise"""
|
86 |
-
try:
|
87 |
-
return os.path.exists(path)
|
88 |
-
except Exception:
|
89 |
-
return False
|
90 |
-
|
91 |
-
|
92 |
-
def _display_mimetype(mimetype, objs, raw=False, metadata=None):
|
93 |
-
"""internal implementation of all display_foo methods
|
94 |
-
|
95 |
-
Parameters
|
96 |
-
----------
|
97 |
-
mimetype : str
|
98 |
-
The mimetype to be published (e.g. 'image/png')
|
99 |
-
*objs : object
|
100 |
-
The Python objects to display, or if raw=True raw text data to
|
101 |
-
display.
|
102 |
-
raw : bool
|
103 |
-
Are the data objects raw data or Python objects that need to be
|
104 |
-
formatted before display? [default: False]
|
105 |
-
metadata : dict (optional)
|
106 |
-
Metadata to be associated with the specific mimetype output.
|
107 |
-
"""
|
108 |
-
if metadata:
|
109 |
-
metadata = {mimetype: metadata}
|
110 |
-
if raw:
|
111 |
-
# turn list of pngdata into list of { 'image/png': pngdata }
|
112 |
-
objs = [ {mimetype: obj} for obj in objs ]
|
113 |
-
display_functions.display(*objs, raw=raw, metadata=metadata, include=[mimetype])
|
114 |
-
|
115 |
-
#-----------------------------------------------------------------------------
|
116 |
-
# Main functions
|
117 |
-
#-----------------------------------------------------------------------------
|
118 |
-
|
119 |
-
|
120 |
-
def display_pretty(*objs, **kwargs):
|
121 |
-
"""Display the pretty (default) representation of an object.
|
122 |
-
|
123 |
-
Parameters
|
124 |
-
----------
|
125 |
-
*objs : object
|
126 |
-
The Python objects to display, or if raw=True raw text data to
|
127 |
-
display.
|
128 |
-
raw : bool
|
129 |
-
Are the data objects raw data or Python objects that need to be
|
130 |
-
formatted before display? [default: False]
|
131 |
-
metadata : dict (optional)
|
132 |
-
Metadata to be associated with the specific mimetype output.
|
133 |
-
"""
|
134 |
-
_display_mimetype('text/plain', objs, **kwargs)
|
135 |
-
|
136 |
-
|
137 |
-
def display_html(*objs, **kwargs):
|
138 |
-
"""Display the HTML representation of an object.
|
139 |
-
|
140 |
-
Note: If raw=False and the object does not have a HTML
|
141 |
-
representation, no HTML will be shown.
|
142 |
-
|
143 |
-
Parameters
|
144 |
-
----------
|
145 |
-
*objs : object
|
146 |
-
The Python objects to display, or if raw=True raw HTML data to
|
147 |
-
display.
|
148 |
-
raw : bool
|
149 |
-
Are the data objects raw data or Python objects that need to be
|
150 |
-
formatted before display? [default: False]
|
151 |
-
metadata : dict (optional)
|
152 |
-
Metadata to be associated with the specific mimetype output.
|
153 |
-
"""
|
154 |
-
_display_mimetype('text/html', objs, **kwargs)
|
155 |
-
|
156 |
-
|
157 |
-
def display_markdown(*objs, **kwargs):
|
158 |
-
"""Displays the Markdown representation of an object.
|
159 |
-
|
160 |
-
Parameters
|
161 |
-
----------
|
162 |
-
*objs : object
|
163 |
-
The Python objects to display, or if raw=True raw markdown data to
|
164 |
-
display.
|
165 |
-
raw : bool
|
166 |
-
Are the data objects raw data or Python objects that need to be
|
167 |
-
formatted before display? [default: False]
|
168 |
-
metadata : dict (optional)
|
169 |
-
Metadata to be associated with the specific mimetype output.
|
170 |
-
"""
|
171 |
-
|
172 |
-
_display_mimetype('text/markdown', objs, **kwargs)
|
173 |
-
|
174 |
-
|
175 |
-
def display_svg(*objs, **kwargs):
|
176 |
-
"""Display the SVG representation of an object.
|
177 |
-
|
178 |
-
Parameters
|
179 |
-
----------
|
180 |
-
*objs : object
|
181 |
-
The Python objects to display, or if raw=True raw svg data to
|
182 |
-
display.
|
183 |
-
raw : bool
|
184 |
-
Are the data objects raw data or Python objects that need to be
|
185 |
-
formatted before display? [default: False]
|
186 |
-
metadata : dict (optional)
|
187 |
-
Metadata to be associated with the specific mimetype output.
|
188 |
-
"""
|
189 |
-
_display_mimetype('image/svg+xml', objs, **kwargs)
|
190 |
-
|
191 |
-
|
192 |
-
def display_png(*objs, **kwargs):
|
193 |
-
"""Display the PNG representation of an object.
|
194 |
-
|
195 |
-
Parameters
|
196 |
-
----------
|
197 |
-
*objs : object
|
198 |
-
The Python objects to display, or if raw=True raw png data to
|
199 |
-
display.
|
200 |
-
raw : bool
|
201 |
-
Are the data objects raw data or Python objects that need to be
|
202 |
-
formatted before display? [default: False]
|
203 |
-
metadata : dict (optional)
|
204 |
-
Metadata to be associated with the specific mimetype output.
|
205 |
-
"""
|
206 |
-
_display_mimetype('image/png', objs, **kwargs)
|
207 |
-
|
208 |
-
|
209 |
-
def display_jpeg(*objs, **kwargs):
|
210 |
-
"""Display the JPEG representation of an object.
|
211 |
-
|
212 |
-
Parameters
|
213 |
-
----------
|
214 |
-
*objs : object
|
215 |
-
The Python objects to display, or if raw=True raw JPEG data to
|
216 |
-
display.
|
217 |
-
raw : bool
|
218 |
-
Are the data objects raw data or Python objects that need to be
|
219 |
-
formatted before display? [default: False]
|
220 |
-
metadata : dict (optional)
|
221 |
-
Metadata to be associated with the specific mimetype output.
|
222 |
-
"""
|
223 |
-
_display_mimetype('image/jpeg', objs, **kwargs)
|
224 |
-
|
225 |
-
|
226 |
-
def display_webp(*objs, **kwargs):
|
227 |
-
"""Display the WEBP representation of an object.
|
228 |
-
|
229 |
-
Parameters
|
230 |
-
----------
|
231 |
-
*objs : object
|
232 |
-
The Python objects to display, or if raw=True raw JPEG data to
|
233 |
-
display.
|
234 |
-
raw : bool
|
235 |
-
Are the data objects raw data or Python objects that need to be
|
236 |
-
formatted before display? [default: False]
|
237 |
-
metadata : dict (optional)
|
238 |
-
Metadata to be associated with the specific mimetype output.
|
239 |
-
"""
|
240 |
-
_display_mimetype("image/webp", objs, **kwargs)
|
241 |
-
|
242 |
-
|
243 |
-
def display_latex(*objs, **kwargs):
|
244 |
-
"""Display the LaTeX representation of an object.
|
245 |
-
|
246 |
-
Parameters
|
247 |
-
----------
|
248 |
-
*objs : object
|
249 |
-
The Python objects to display, or if raw=True raw latex data to
|
250 |
-
display.
|
251 |
-
raw : bool
|
252 |
-
Are the data objects raw data or Python objects that need to be
|
253 |
-
formatted before display? [default: False]
|
254 |
-
metadata : dict (optional)
|
255 |
-
Metadata to be associated with the specific mimetype output.
|
256 |
-
"""
|
257 |
-
_display_mimetype('text/latex', objs, **kwargs)
|
258 |
-
|
259 |
-
|
260 |
-
def display_json(*objs, **kwargs):
|
261 |
-
"""Display the JSON representation of an object.
|
262 |
-
|
263 |
-
Note that not many frontends support displaying JSON.
|
264 |
-
|
265 |
-
Parameters
|
266 |
-
----------
|
267 |
-
*objs : object
|
268 |
-
The Python objects to display, or if raw=True raw json data to
|
269 |
-
display.
|
270 |
-
raw : bool
|
271 |
-
Are the data objects raw data or Python objects that need to be
|
272 |
-
formatted before display? [default: False]
|
273 |
-
metadata : dict (optional)
|
274 |
-
Metadata to be associated with the specific mimetype output.
|
275 |
-
"""
|
276 |
-
_display_mimetype('application/json', objs, **kwargs)
|
277 |
-
|
278 |
-
|
279 |
-
def display_javascript(*objs, **kwargs):
|
280 |
-
"""Display the Javascript representation of an object.
|
281 |
-
|
282 |
-
Parameters
|
283 |
-
----------
|
284 |
-
*objs : object
|
285 |
-
The Python objects to display, or if raw=True raw javascript data to
|
286 |
-
display.
|
287 |
-
raw : bool
|
288 |
-
Are the data objects raw data or Python objects that need to be
|
289 |
-
formatted before display? [default: False]
|
290 |
-
metadata : dict (optional)
|
291 |
-
Metadata to be associated with the specific mimetype output.
|
292 |
-
"""
|
293 |
-
_display_mimetype('application/javascript', objs, **kwargs)
|
294 |
-
|
295 |
-
|
296 |
-
def display_pdf(*objs, **kwargs):
|
297 |
-
"""Display the PDF representation of an object.
|
298 |
-
|
299 |
-
Parameters
|
300 |
-
----------
|
301 |
-
*objs : object
|
302 |
-
The Python objects to display, or if raw=True raw javascript data to
|
303 |
-
display.
|
304 |
-
raw : bool
|
305 |
-
Are the data objects raw data or Python objects that need to be
|
306 |
-
formatted before display? [default: False]
|
307 |
-
metadata : dict (optional)
|
308 |
-
Metadata to be associated with the specific mimetype output.
|
309 |
-
"""
|
310 |
-
_display_mimetype('application/pdf', objs, **kwargs)
|
311 |
-
|
312 |
-
|
313 |
-
#-----------------------------------------------------------------------------
|
314 |
-
# Smart classes
|
315 |
-
#-----------------------------------------------------------------------------
|
316 |
-
|
317 |
-
|
318 |
-
class DisplayObject(object):
|
319 |
-
"""An object that wraps data to be displayed."""
|
320 |
-
|
321 |
-
_read_flags = 'r'
|
322 |
-
_show_mem_addr = False
|
323 |
-
metadata = None
|
324 |
-
|
325 |
-
def __init__(self, data=None, url=None, filename=None, metadata=None):
|
326 |
-
"""Create a display object given raw data.
|
327 |
-
|
328 |
-
When this object is returned by an expression or passed to the
|
329 |
-
display function, it will result in the data being displayed
|
330 |
-
in the frontend. The MIME type of the data should match the
|
331 |
-
subclasses used, so the Png subclass should be used for 'image/png'
|
332 |
-
data. If the data is a URL, the data will first be downloaded
|
333 |
-
and then displayed.
|
334 |
-
|
335 |
-
Parameters
|
336 |
-
----------
|
337 |
-
data : unicode, str or bytes
|
338 |
-
The raw data or a URL or file to load the data from
|
339 |
-
url : unicode
|
340 |
-
A URL to download the data from.
|
341 |
-
filename : unicode
|
342 |
-
Path to a local file to load the data from.
|
343 |
-
metadata : dict
|
344 |
-
Dict of metadata associated to be the object when displayed
|
345 |
-
"""
|
346 |
-
if isinstance(data, (Path, PurePath)):
|
347 |
-
data = str(data)
|
348 |
-
|
349 |
-
if data is not None and isinstance(data, str):
|
350 |
-
if data.startswith('http') and url is None:
|
351 |
-
url = data
|
352 |
-
filename = None
|
353 |
-
data = None
|
354 |
-
elif _safe_exists(data) and filename is None:
|
355 |
-
url = None
|
356 |
-
filename = data
|
357 |
-
data = None
|
358 |
-
|
359 |
-
self.url = url
|
360 |
-
self.filename = filename
|
361 |
-
# because of @data.setter methods in
|
362 |
-
# subclasses ensure url and filename are set
|
363 |
-
# before assigning to self.data
|
364 |
-
self.data = data
|
365 |
-
|
366 |
-
if metadata is not None:
|
367 |
-
self.metadata = metadata
|
368 |
-
elif self.metadata is None:
|
369 |
-
self.metadata = {}
|
370 |
-
|
371 |
-
self.reload()
|
372 |
-
self._check_data()
|
373 |
-
|
374 |
-
def __repr__(self):
|
375 |
-
if not self._show_mem_addr:
|
376 |
-
cls = self.__class__
|
377 |
-
r = "<%s.%s object>" % (cls.__module__, cls.__name__)
|
378 |
-
else:
|
379 |
-
r = super(DisplayObject, self).__repr__()
|
380 |
-
return r
|
381 |
-
|
382 |
-
def _check_data(self):
|
383 |
-
"""Override in subclasses if there's something to check."""
|
384 |
-
pass
|
385 |
-
|
386 |
-
def _data_and_metadata(self):
|
387 |
-
"""shortcut for returning metadata with shape information, if defined"""
|
388 |
-
if self.metadata:
|
389 |
-
return self.data, deepcopy(self.metadata)
|
390 |
-
else:
|
391 |
-
return self.data
|
392 |
-
|
393 |
-
def reload(self):
|
394 |
-
"""Reload the raw data from file or URL."""
|
395 |
-
if self.filename is not None:
|
396 |
-
encoding = None if "b" in self._read_flags else "utf-8"
|
397 |
-
with open(self.filename, self._read_flags, encoding=encoding) as f:
|
398 |
-
self.data = f.read()
|
399 |
-
elif self.url is not None:
|
400 |
-
# Deferred import
|
401 |
-
from urllib.request import urlopen
|
402 |
-
response = urlopen(self.url)
|
403 |
-
data = response.read()
|
404 |
-
# extract encoding from header, if there is one:
|
405 |
-
encoding = None
|
406 |
-
if 'content-type' in response.headers:
|
407 |
-
for sub in response.headers['content-type'].split(';'):
|
408 |
-
sub = sub.strip()
|
409 |
-
if sub.startswith('charset'):
|
410 |
-
encoding = sub.split('=')[-1].strip()
|
411 |
-
break
|
412 |
-
if 'content-encoding' in response.headers:
|
413 |
-
# TODO: do deflate?
|
414 |
-
if 'gzip' in response.headers['content-encoding']:
|
415 |
-
import gzip
|
416 |
-
from io import BytesIO
|
417 |
-
|
418 |
-
# assume utf-8 if encoding is not specified
|
419 |
-
with gzip.open(
|
420 |
-
BytesIO(data), "rt", encoding=encoding or "utf-8"
|
421 |
-
) as fp:
|
422 |
-
encoding = None
|
423 |
-
data = fp.read()
|
424 |
-
|
425 |
-
# decode data, if an encoding was specified
|
426 |
-
# We only touch self.data once since
|
427 |
-
# subclasses such as SVG have @data.setter methods
|
428 |
-
# that transform self.data into ... well svg.
|
429 |
-
if encoding:
|
430 |
-
self.data = data.decode(encoding, 'replace')
|
431 |
-
else:
|
432 |
-
self.data = data
|
433 |
-
|
434 |
-
|
435 |
-
class TextDisplayObject(DisplayObject):
|
436 |
-
"""Create a text display object given raw data.
|
437 |
-
|
438 |
-
Parameters
|
439 |
-
----------
|
440 |
-
data : str or unicode
|
441 |
-
The raw data or a URL or file to load the data from.
|
442 |
-
url : unicode
|
443 |
-
A URL to download the data from.
|
444 |
-
filename : unicode
|
445 |
-
Path to a local file to load the data from.
|
446 |
-
metadata : dict
|
447 |
-
Dict of metadata associated to be the object when displayed
|
448 |
-
"""
|
449 |
-
def _check_data(self):
|
450 |
-
if self.data is not None and not isinstance(self.data, str):
|
451 |
-
raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
|
452 |
-
|
453 |
-
class Pretty(TextDisplayObject):
|
454 |
-
|
455 |
-
def _repr_pretty_(self, pp, cycle):
|
456 |
-
return pp.text(self.data)
|
457 |
-
|
458 |
-
|
459 |
-
class HTML(TextDisplayObject):
|
460 |
-
|
461 |
-
def __init__(self, data=None, url=None, filename=None, metadata=None):
|
462 |
-
def warn():
|
463 |
-
if not data:
|
464 |
-
return False
|
465 |
-
|
466 |
-
#
|
467 |
-
# Avoid calling lower() on the entire data, because it could be a
|
468 |
-
# long string and we're only interested in its beginning and end.
|
469 |
-
#
|
470 |
-
prefix = data[:10].lower()
|
471 |
-
suffix = data[-10:].lower()
|
472 |
-
return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
|
473 |
-
|
474 |
-
if warn():
|
475 |
-
warnings.warn("Consider using IPython.display.IFrame instead")
|
476 |
-
super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
|
477 |
-
|
478 |
-
def _repr_html_(self):
|
479 |
-
return self._data_and_metadata()
|
480 |
-
|
481 |
-
def __html__(self):
|
482 |
-
"""
|
483 |
-
This method exists to inform other HTML-using modules (e.g. Markupsafe,
|
484 |
-
htmltag, etc) that this object is HTML and does not need things like
|
485 |
-
special characters (<>&) escaped.
|
486 |
-
"""
|
487 |
-
return self._repr_html_()
|
488 |
-
|
489 |
-
|
490 |
-
class Markdown(TextDisplayObject):
|
491 |
-
|
492 |
-
def _repr_markdown_(self):
|
493 |
-
return self._data_and_metadata()
|
494 |
-
|
495 |
-
|
496 |
-
class Math(TextDisplayObject):
|
497 |
-
|
498 |
-
def _repr_latex_(self):
|
499 |
-
s = r"$\displaystyle %s$" % self.data.strip('$')
|
500 |
-
if self.metadata:
|
501 |
-
return s, deepcopy(self.metadata)
|
502 |
-
else:
|
503 |
-
return s
|
504 |
-
|
505 |
-
|
506 |
-
class Latex(TextDisplayObject):
|
507 |
-
|
508 |
-
def _repr_latex_(self):
|
509 |
-
return self._data_and_metadata()
|
510 |
-
|
511 |
-
|
512 |
-
class SVG(DisplayObject):
|
513 |
-
"""Embed an SVG into the display.
|
514 |
-
|
515 |
-
Note if you just want to view a svg image via a URL use `:class:Image` with
|
516 |
-
a url=URL keyword argument.
|
517 |
-
"""
|
518 |
-
|
519 |
-
_read_flags = 'rb'
|
520 |
-
# wrap data in a property, which extracts the <svg> tag, discarding
|
521 |
-
# document headers
|
522 |
-
_data: Optional[str] = None
|
523 |
-
|
524 |
-
@property
|
525 |
-
def data(self):
|
526 |
-
return self._data
|
527 |
-
|
528 |
-
@data.setter
|
529 |
-
def data(self, svg):
|
530 |
-
if svg is None:
|
531 |
-
self._data = None
|
532 |
-
return
|
533 |
-
# parse into dom object
|
534 |
-
from xml.dom import minidom
|
535 |
-
x = minidom.parseString(svg)
|
536 |
-
# get svg tag (should be 1)
|
537 |
-
found_svg = x.getElementsByTagName('svg')
|
538 |
-
if found_svg:
|
539 |
-
svg = found_svg[0].toxml()
|
540 |
-
else:
|
541 |
-
# fallback on the input, trust the user
|
542 |
-
# but this is probably an error.
|
543 |
-
pass
|
544 |
-
if isinstance(svg, bytes):
|
545 |
-
self._data = svg.decode(errors="replace")
|
546 |
-
else:
|
547 |
-
self._data = svg
|
548 |
-
|
549 |
-
def _repr_svg_(self):
|
550 |
-
return self._data_and_metadata()
|
551 |
-
|
552 |
-
class ProgressBar(DisplayObject):
|
553 |
-
"""Progressbar supports displaying a progressbar like element
|
554 |
-
"""
|
555 |
-
def __init__(self, total):
|
556 |
-
"""Creates a new progressbar
|
557 |
-
|
558 |
-
Parameters
|
559 |
-
----------
|
560 |
-
total : int
|
561 |
-
maximum size of the progressbar
|
562 |
-
"""
|
563 |
-
self.total = total
|
564 |
-
self._progress = 0
|
565 |
-
self.html_width = '60ex'
|
566 |
-
self.text_width = 60
|
567 |
-
self._display_id = hexlify(os.urandom(8)).decode('ascii')
|
568 |
-
|
569 |
-
def __repr__(self):
|
570 |
-
fraction = self.progress / self.total
|
571 |
-
filled = '=' * int(fraction * self.text_width)
|
572 |
-
rest = ' ' * (self.text_width - len(filled))
|
573 |
-
return '[{}{}] {}/{}'.format(
|
574 |
-
filled, rest,
|
575 |
-
self.progress, self.total,
|
576 |
-
)
|
577 |
-
|
578 |
-
def _repr_html_(self):
|
579 |
-
return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
|
580 |
-
self.html_width, self.total, self.progress)
|
581 |
-
|
582 |
-
def display(self):
|
583 |
-
display_functions.display(self, display_id=self._display_id)
|
584 |
-
|
585 |
-
def update(self):
|
586 |
-
display_functions.display(self, display_id=self._display_id, update=True)
|
587 |
-
|
588 |
-
@property
|
589 |
-
def progress(self):
|
590 |
-
return self._progress
|
591 |
-
|
592 |
-
@progress.setter
|
593 |
-
def progress(self, value):
|
594 |
-
self._progress = value
|
595 |
-
self.update()
|
596 |
-
|
597 |
-
def __iter__(self):
|
598 |
-
self.display()
|
599 |
-
self._progress = -1 # First iteration is 0
|
600 |
-
return self
|
601 |
-
|
602 |
-
def __next__(self):
|
603 |
-
"""Returns current value and increments display by one."""
|
604 |
-
self.progress += 1
|
605 |
-
if self.progress < self.total:
|
606 |
-
return self.progress
|
607 |
-
else:
|
608 |
-
raise StopIteration()
|
609 |
-
|
610 |
-
class JSON(DisplayObject):
|
611 |
-
"""JSON expects a JSON-able dict or list
|
612 |
-
|
613 |
-
not an already-serialized JSON string.
|
614 |
-
|
615 |
-
Scalar types (None, number, string) are not allowed, only dict or list containers.
|
616 |
-
"""
|
617 |
-
# wrap data in a property, which warns about passing already-serialized JSON
|
618 |
-
_data = None
|
619 |
-
def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
|
620 |
-
"""Create a JSON display object given raw data.
|
621 |
-
|
622 |
-
Parameters
|
623 |
-
----------
|
624 |
-
data : dict or list
|
625 |
-
JSON data to display. Not an already-serialized JSON string.
|
626 |
-
Scalar types (None, number, string) are not allowed, only dict
|
627 |
-
or list containers.
|
628 |
-
url : unicode
|
629 |
-
A URL to download the data from.
|
630 |
-
filename : unicode
|
631 |
-
Path to a local file to load the data from.
|
632 |
-
expanded : boolean
|
633 |
-
Metadata to control whether a JSON display component is expanded.
|
634 |
-
metadata : dict
|
635 |
-
Specify extra metadata to attach to the json display object.
|
636 |
-
root : str
|
637 |
-
The name of the root element of the JSON tree
|
638 |
-
"""
|
639 |
-
self.metadata = {
|
640 |
-
'expanded': expanded,
|
641 |
-
'root': root,
|
642 |
-
}
|
643 |
-
if metadata:
|
644 |
-
self.metadata.update(metadata)
|
645 |
-
if kwargs:
|
646 |
-
self.metadata.update(kwargs)
|
647 |
-
super(JSON, self).__init__(data=data, url=url, filename=filename)
|
648 |
-
|
649 |
-
def _check_data(self):
|
650 |
-
if self.data is not None and not isinstance(self.data, (dict, list)):
|
651 |
-
raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
|
652 |
-
|
653 |
-
@property
|
654 |
-
def data(self):
|
655 |
-
return self._data
|
656 |
-
|
657 |
-
@data.setter
|
658 |
-
def data(self, data):
|
659 |
-
if isinstance(data, (Path, PurePath)):
|
660 |
-
data = str(data)
|
661 |
-
|
662 |
-
if isinstance(data, str):
|
663 |
-
if self.filename is None and self.url is None:
|
664 |
-
warnings.warn("JSON expects JSONable dict or list, not JSON strings")
|
665 |
-
data = json.loads(data)
|
666 |
-
self._data = data
|
667 |
-
|
668 |
-
def _data_and_metadata(self):
|
669 |
-
return self.data, self.metadata
|
670 |
-
|
671 |
-
def _repr_json_(self):
|
672 |
-
return self._data_and_metadata()
|
673 |
-
|
674 |
-
|
675 |
-
_css_t = """var link = document.createElement("link");
|
676 |
-
link.rel = "stylesheet";
|
677 |
-
link.type = "text/css";
|
678 |
-
link.href = "%s";
|
679 |
-
document.head.appendChild(link);
|
680 |
-
"""
|
681 |
-
|
682 |
-
_lib_t1 = """new Promise(function(resolve, reject) {
|
683 |
-
var script = document.createElement("script");
|
684 |
-
script.onload = resolve;
|
685 |
-
script.onerror = reject;
|
686 |
-
script.src = "%s";
|
687 |
-
document.head.appendChild(script);
|
688 |
-
}).then(() => {
|
689 |
-
"""
|
690 |
-
|
691 |
-
_lib_t2 = """
|
692 |
-
});"""
|
693 |
-
|
694 |
-
class GeoJSON(JSON):
|
695 |
-
"""GeoJSON expects JSON-able dict
|
696 |
-
|
697 |
-
not an already-serialized JSON string.
|
698 |
-
|
699 |
-
Scalar types (None, number, string) are not allowed, only dict containers.
|
700 |
-
"""
|
701 |
-
|
702 |
-
def __init__(self, *args, **kwargs):
|
703 |
-
"""Create a GeoJSON display object given raw data.
|
704 |
-
|
705 |
-
Parameters
|
706 |
-
----------
|
707 |
-
data : dict or list
|
708 |
-
VegaLite data. Not an already-serialized JSON string.
|
709 |
-
Scalar types (None, number, string) are not allowed, only dict
|
710 |
-
or list containers.
|
711 |
-
url_template : string
|
712 |
-
Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
|
713 |
-
layer_options : dict
|
714 |
-
Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
|
715 |
-
url : unicode
|
716 |
-
A URL to download the data from.
|
717 |
-
filename : unicode
|
718 |
-
Path to a local file to load the data from.
|
719 |
-
metadata : dict
|
720 |
-
Specify extra metadata to attach to the json display object.
|
721 |
-
|
722 |
-
Examples
|
723 |
-
--------
|
724 |
-
The following will display an interactive map of Mars with a point of
|
725 |
-
interest on frontend that do support GeoJSON display.
|
726 |
-
|
727 |
-
>>> from IPython.display import GeoJSON
|
728 |
-
|
729 |
-
>>> GeoJSON(data={
|
730 |
-
... "type": "Feature",
|
731 |
-
... "geometry": {
|
732 |
-
... "type": "Point",
|
733 |
-
... "coordinates": [-81.327, 296.038]
|
734 |
-
... }
|
735 |
-
... },
|
736 |
-
... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
|
737 |
-
... layer_options={
|
738 |
-
... "basemap_id": "celestia_mars-shaded-16k_global",
|
739 |
-
... "attribution" : "Celestia/praesepe",
|
740 |
-
... "minZoom" : 0,
|
741 |
-
... "maxZoom" : 18,
|
742 |
-
... })
|
743 |
-
<IPython.core.display.GeoJSON object>
|
744 |
-
|
745 |
-
In the terminal IPython, you will only see the text representation of
|
746 |
-
the GeoJSON object.
|
747 |
-
|
748 |
-
"""
|
749 |
-
|
750 |
-
super(GeoJSON, self).__init__(*args, **kwargs)
|
751 |
-
|
752 |
-
|
753 |
-
def _ipython_display_(self):
|
754 |
-
bundle = {
|
755 |
-
'application/geo+json': self.data,
|
756 |
-
'text/plain': '<IPython.display.GeoJSON object>'
|
757 |
-
}
|
758 |
-
metadata = {
|
759 |
-
'application/geo+json': self.metadata
|
760 |
-
}
|
761 |
-
display_functions.display(bundle, metadata=metadata, raw=True)
|
762 |
-
|
763 |
-
class Javascript(TextDisplayObject):
|
764 |
-
|
765 |
-
def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
|
766 |
-
"""Create a Javascript display object given raw data.
|
767 |
-
|
768 |
-
When this object is returned by an expression or passed to the
|
769 |
-
display function, it will result in the data being displayed
|
770 |
-
in the frontend. If the data is a URL, the data will first be
|
771 |
-
downloaded and then displayed.
|
772 |
-
|
773 |
-
In the Notebook, the containing element will be available as `element`,
|
774 |
-
and jQuery will be available. Content appended to `element` will be
|
775 |
-
visible in the output area.
|
776 |
-
|
777 |
-
Parameters
|
778 |
-
----------
|
779 |
-
data : unicode, str or bytes
|
780 |
-
The Javascript source code or a URL to download it from.
|
781 |
-
url : unicode
|
782 |
-
A URL to download the data from.
|
783 |
-
filename : unicode
|
784 |
-
Path to a local file to load the data from.
|
785 |
-
lib : list or str
|
786 |
-
A sequence of Javascript library URLs to load asynchronously before
|
787 |
-
running the source code. The full URLs of the libraries should
|
788 |
-
be given. A single Javascript library URL can also be given as a
|
789 |
-
string.
|
790 |
-
css : list or str
|
791 |
-
A sequence of css files to load before running the source code.
|
792 |
-
The full URLs of the css files should be given. A single css URL
|
793 |
-
can also be given as a string.
|
794 |
-
"""
|
795 |
-
if isinstance(lib, str):
|
796 |
-
lib = [lib]
|
797 |
-
elif lib is None:
|
798 |
-
lib = []
|
799 |
-
if isinstance(css, str):
|
800 |
-
css = [css]
|
801 |
-
elif css is None:
|
802 |
-
css = []
|
803 |
-
if not isinstance(lib, (list,tuple)):
|
804 |
-
raise TypeError('expected sequence, got: %r' % lib)
|
805 |
-
if not isinstance(css, (list,tuple)):
|
806 |
-
raise TypeError('expected sequence, got: %r' % css)
|
807 |
-
self.lib = lib
|
808 |
-
self.css = css
|
809 |
-
super(Javascript, self).__init__(data=data, url=url, filename=filename)
|
810 |
-
|
811 |
-
def _repr_javascript_(self):
|
812 |
-
r = ''
|
813 |
-
for c in self.css:
|
814 |
-
r += _css_t % c
|
815 |
-
for l in self.lib:
|
816 |
-
r += _lib_t1 % l
|
817 |
-
r += self.data
|
818 |
-
r += _lib_t2*len(self.lib)
|
819 |
-
return r
|
820 |
-
|
821 |
-
|
822 |
-
# constants for identifying png/jpeg/gif/webp data
|
823 |
-
_PNG = b"\x89PNG\r\n\x1a\n"
|
824 |
-
_JPEG = b"\xff\xd8"
|
825 |
-
_GIF1 = b"GIF87a"
|
826 |
-
_GIF2 = b"GIF89a"
|
827 |
-
_WEBP = b"WEBP"
|
828 |
-
|
829 |
-
|
830 |
-
def _pngxy(data):
|
831 |
-
"""read the (width, height) from a PNG header"""
|
832 |
-
ihdr = data.index(b'IHDR')
|
833 |
-
# next 8 bytes are width/height
|
834 |
-
return struct.unpack('>ii', data[ihdr+4:ihdr+12])
|
835 |
-
|
836 |
-
|
837 |
-
def _jpegxy(data):
|
838 |
-
"""read the (width, height) from a JPEG header"""
|
839 |
-
# adapted from http://www.64lines.com/jpeg-width-height
|
840 |
-
|
841 |
-
idx = 4
|
842 |
-
while True:
|
843 |
-
block_size = struct.unpack('>H', data[idx:idx+2])[0]
|
844 |
-
idx = idx + block_size
|
845 |
-
if data[idx:idx+2] == b'\xFF\xC0':
|
846 |
-
# found Start of Frame
|
847 |
-
iSOF = idx
|
848 |
-
break
|
849 |
-
else:
|
850 |
-
# read another block
|
851 |
-
idx += 2
|
852 |
-
|
853 |
-
h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
|
854 |
-
return w, h
|
855 |
-
|
856 |
-
|
857 |
-
def _gifxy(data):
|
858 |
-
"""read the (width, height) from a GIF header"""
|
859 |
-
return struct.unpack('<HH', data[6:10])
|
860 |
-
|
861 |
-
|
862 |
-
def _webpxy(data):
|
863 |
-
"""read the (width, height) from a WEBP header"""
|
864 |
-
if data[12:16] == b"VP8 ":
|
865 |
-
width, height = struct.unpack("<HH", data[24:30])
|
866 |
-
width = width & 0x3FFF
|
867 |
-
height = height & 0x3FFF
|
868 |
-
return (width, height)
|
869 |
-
elif data[12:16] == b"VP8L":
|
870 |
-
size_info = struct.unpack("<I", data[21:25])[0]
|
871 |
-
width = 1 + ((size_info & 0x3F) << 8) | (size_info >> 24)
|
872 |
-
height = 1 + (
|
873 |
-
(((size_info >> 8) & 0xF) << 10)
|
874 |
-
| (((size_info >> 14) & 0x3FC) << 2)
|
875 |
-
| ((size_info >> 22) & 0x3)
|
876 |
-
)
|
877 |
-
return (width, height)
|
878 |
-
else:
|
879 |
-
raise ValueError("Not a valid WEBP header")
|
880 |
-
|
881 |
-
|
882 |
-
class Image(DisplayObject):
|
883 |
-
|
884 |
-
_read_flags = "rb"
|
885 |
-
_FMT_JPEG = "jpeg"
|
886 |
-
_FMT_PNG = "png"
|
887 |
-
_FMT_GIF = "gif"
|
888 |
-
_FMT_WEBP = "webp"
|
889 |
-
_ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF, _FMT_WEBP]
|
890 |
-
_MIMETYPES = {
|
891 |
-
_FMT_PNG: "image/png",
|
892 |
-
_FMT_JPEG: "image/jpeg",
|
893 |
-
_FMT_GIF: "image/gif",
|
894 |
-
_FMT_WEBP: "image/webp",
|
895 |
-
}
|
896 |
-
|
897 |
-
def __init__(
|
898 |
-
self,
|
899 |
-
data=None,
|
900 |
-
url=None,
|
901 |
-
filename=None,
|
902 |
-
format=None,
|
903 |
-
embed=None,
|
904 |
-
width=None,
|
905 |
-
height=None,
|
906 |
-
retina=False,
|
907 |
-
unconfined=False,
|
908 |
-
metadata=None,
|
909 |
-
alt=None,
|
910 |
-
):
|
911 |
-
"""Create a PNG/JPEG/GIF/WEBP image object given raw data.
|
912 |
-
|
913 |
-
When this object is returned by an input cell or passed to the
|
914 |
-
display function, it will result in the image being displayed
|
915 |
-
in the frontend.
|
916 |
-
|
917 |
-
Parameters
|
918 |
-
----------
|
919 |
-
data : unicode, str or bytes
|
920 |
-
The raw image data or a URL or filename to load the data from.
|
921 |
-
This always results in embedded image data.
|
922 |
-
|
923 |
-
url : unicode
|
924 |
-
A URL to download the data from. If you specify `url=`,
|
925 |
-
the image data will not be embedded unless you also specify `embed=True`.
|
926 |
-
|
927 |
-
filename : unicode
|
928 |
-
Path to a local file to load the data from.
|
929 |
-
Images from a file are always embedded.
|
930 |
-
|
931 |
-
format : unicode
|
932 |
-
The format of the image data (png/jpeg/jpg/gif/webp). If a filename or URL is given
|
933 |
-
for format will be inferred from the filename extension.
|
934 |
-
|
935 |
-
embed : bool
|
936 |
-
Should the image data be embedded using a data URI (True) or be
|
937 |
-
loaded using an <img> tag. Set this to True if you want the image
|
938 |
-
to be viewable later with no internet connection in the notebook.
|
939 |
-
|
940 |
-
Default is `True`, unless the keyword argument `url` is set, then
|
941 |
-
default value is `False`.
|
942 |
-
|
943 |
-
Note that QtConsole is not able to display images if `embed` is set to `False`
|
944 |
-
|
945 |
-
width : int
|
946 |
-
Width in pixels to which to constrain the image in html
|
947 |
-
|
948 |
-
height : int
|
949 |
-
Height in pixels to which to constrain the image in html
|
950 |
-
|
951 |
-
retina : bool
|
952 |
-
Automatically set the width and height to half of the measured
|
953 |
-
width and height.
|
954 |
-
This only works for embedded images because it reads the width/height
|
955 |
-
from image data.
|
956 |
-
For non-embedded images, you can just set the desired display width
|
957 |
-
and height directly.
|
958 |
-
|
959 |
-
unconfined : bool
|
960 |
-
Set unconfined=True to disable max-width confinement of the image.
|
961 |
-
|
962 |
-
metadata : dict
|
963 |
-
Specify extra metadata to attach to the image.
|
964 |
-
|
965 |
-
alt : unicode
|
966 |
-
Alternative text for the image, for use by screen readers.
|
967 |
-
|
968 |
-
Examples
|
969 |
-
--------
|
970 |
-
embedded image data, works in qtconsole and notebook
|
971 |
-
when passed positionally, the first arg can be any of raw image data,
|
972 |
-
a URL, or a filename from which to load image data.
|
973 |
-
The result is always embedding image data for inline images.
|
974 |
-
|
975 |
-
>>> Image('https://www.google.fr/images/srpr/logo3w.png') # doctest: +SKIP
|
976 |
-
<IPython.core.display.Image object>
|
977 |
-
|
978 |
-
>>> Image('/path/to/image.jpg')
|
979 |
-
<IPython.core.display.Image object>
|
980 |
-
|
981 |
-
>>> Image(b'RAW_PNG_DATA...')
|
982 |
-
<IPython.core.display.Image object>
|
983 |
-
|
984 |
-
Specifying Image(url=...) does not embed the image data,
|
985 |
-
it only generates ``<img>`` tag with a link to the source.
|
986 |
-
This will not work in the qtconsole or offline.
|
987 |
-
|
988 |
-
>>> Image(url='https://www.google.fr/images/srpr/logo3w.png')
|
989 |
-
<IPython.core.display.Image object>
|
990 |
-
|
991 |
-
"""
|
992 |
-
if isinstance(data, (Path, PurePath)):
|
993 |
-
data = str(data)
|
994 |
-
|
995 |
-
if filename is not None:
|
996 |
-
ext = self._find_ext(filename)
|
997 |
-
elif url is not None:
|
998 |
-
ext = self._find_ext(url)
|
999 |
-
elif data is None:
|
1000 |
-
raise ValueError("No image data found. Expecting filename, url, or data.")
|
1001 |
-
elif isinstance(data, str) and (
|
1002 |
-
data.startswith('http') or _safe_exists(data)
|
1003 |
-
):
|
1004 |
-
ext = self._find_ext(data)
|
1005 |
-
else:
|
1006 |
-
ext = None
|
1007 |
-
|
1008 |
-
if format is None:
|
1009 |
-
if ext is not None:
|
1010 |
-
if ext == u'jpg' or ext == u'jpeg':
|
1011 |
-
format = self._FMT_JPEG
|
1012 |
-
elif ext == u'png':
|
1013 |
-
format = self._FMT_PNG
|
1014 |
-
elif ext == u'gif':
|
1015 |
-
format = self._FMT_GIF
|
1016 |
-
elif ext == "webp":
|
1017 |
-
format = self._FMT_WEBP
|
1018 |
-
else:
|
1019 |
-
format = ext.lower()
|
1020 |
-
elif isinstance(data, bytes):
|
1021 |
-
# infer image type from image data header,
|
1022 |
-
# only if format has not been specified.
|
1023 |
-
if data[:2] == _JPEG:
|
1024 |
-
format = self._FMT_JPEG
|
1025 |
-
elif data[:8] == _PNG:
|
1026 |
-
format = self._FMT_PNG
|
1027 |
-
elif data[8:12] == _WEBP:
|
1028 |
-
format = self._FMT_WEBP
|
1029 |
-
elif data[:6] == _GIF1 or data[:6] == _GIF2:
|
1030 |
-
format = self._FMT_GIF
|
1031 |
-
|
1032 |
-
# failed to detect format, default png
|
1033 |
-
if format is None:
|
1034 |
-
format = self._FMT_PNG
|
1035 |
-
|
1036 |
-
if format.lower() == 'jpg':
|
1037 |
-
# jpg->jpeg
|
1038 |
-
format = self._FMT_JPEG
|
1039 |
-
|
1040 |
-
self.format = format.lower()
|
1041 |
-
self.embed = embed if embed is not None else (url is None)
|
1042 |
-
|
1043 |
-
if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
|
1044 |
-
raise ValueError("Cannot embed the '%s' image format" % (self.format))
|
1045 |
-
if self.embed:
|
1046 |
-
self._mimetype = self._MIMETYPES.get(self.format)
|
1047 |
-
|
1048 |
-
self.width = width
|
1049 |
-
self.height = height
|
1050 |
-
self.retina = retina
|
1051 |
-
self.unconfined = unconfined
|
1052 |
-
self.alt = alt
|
1053 |
-
super(Image, self).__init__(data=data, url=url, filename=filename,
|
1054 |
-
metadata=metadata)
|
1055 |
-
|
1056 |
-
if self.width is None and self.metadata.get('width', {}):
|
1057 |
-
self.width = metadata['width']
|
1058 |
-
|
1059 |
-
if self.height is None and self.metadata.get('height', {}):
|
1060 |
-
self.height = metadata['height']
|
1061 |
-
|
1062 |
-
if self.alt is None and self.metadata.get("alt", {}):
|
1063 |
-
self.alt = metadata["alt"]
|
1064 |
-
|
1065 |
-
if retina:
|
1066 |
-
self._retina_shape()
|
1067 |
-
|
1068 |
-
|
1069 |
-
def _retina_shape(self):
|
1070 |
-
"""load pixel-doubled width and height from image data"""
|
1071 |
-
if not self.embed:
|
1072 |
-
return
|
1073 |
-
if self.format == self._FMT_PNG:
|
1074 |
-
w, h = _pngxy(self.data)
|
1075 |
-
elif self.format == self._FMT_JPEG:
|
1076 |
-
w, h = _jpegxy(self.data)
|
1077 |
-
elif self.format == self._FMT_GIF:
|
1078 |
-
w, h = _gifxy(self.data)
|
1079 |
-
else:
|
1080 |
-
# retina only supports png
|
1081 |
-
return
|
1082 |
-
self.width = w // 2
|
1083 |
-
self.height = h // 2
|
1084 |
-
|
1085 |
-
def reload(self):
|
1086 |
-
"""Reload the raw data from file or URL."""
|
1087 |
-
if self.embed:
|
1088 |
-
super(Image,self).reload()
|
1089 |
-
if self.retina:
|
1090 |
-
self._retina_shape()
|
1091 |
-
|
1092 |
-
def _repr_html_(self):
|
1093 |
-
if not self.embed:
|
1094 |
-
width = height = klass = alt = ""
|
1095 |
-
if self.width:
|
1096 |
-
width = ' width="%d"' % self.width
|
1097 |
-
if self.height:
|
1098 |
-
height = ' height="%d"' % self.height
|
1099 |
-
if self.unconfined:
|
1100 |
-
klass = ' class="unconfined"'
|
1101 |
-
if self.alt:
|
1102 |
-
alt = ' alt="%s"' % html.escape(self.alt)
|
1103 |
-
return '<img src="{url}"{width}{height}{klass}{alt}/>'.format(
|
1104 |
-
url=self.url,
|
1105 |
-
width=width,
|
1106 |
-
height=height,
|
1107 |
-
klass=klass,
|
1108 |
-
alt=alt,
|
1109 |
-
)
|
1110 |
-
|
1111 |
-
def _repr_mimebundle_(self, include=None, exclude=None):
|
1112 |
-
"""Return the image as a mimebundle
|
1113 |
-
|
1114 |
-
Any new mimetype support should be implemented here.
|
1115 |
-
"""
|
1116 |
-
if self.embed:
|
1117 |
-
mimetype = self._mimetype
|
1118 |
-
data, metadata = self._data_and_metadata(always_both=True)
|
1119 |
-
if metadata:
|
1120 |
-
metadata = {mimetype: metadata}
|
1121 |
-
return {mimetype: data}, metadata
|
1122 |
-
else:
|
1123 |
-
return {'text/html': self._repr_html_()}
|
1124 |
-
|
1125 |
-
def _data_and_metadata(self, always_both=False):
|
1126 |
-
"""shortcut for returning metadata with shape information, if defined"""
|
1127 |
-
try:
|
1128 |
-
b64_data = b2a_base64(self.data, newline=False).decode("ascii")
|
1129 |
-
except TypeError as e:
|
1130 |
-
raise FileNotFoundError(
|
1131 |
-
"No such file or directory: '%s'" % (self.data)) from e
|
1132 |
-
md = {}
|
1133 |
-
if self.metadata:
|
1134 |
-
md.update(self.metadata)
|
1135 |
-
if self.width:
|
1136 |
-
md['width'] = self.width
|
1137 |
-
if self.height:
|
1138 |
-
md['height'] = self.height
|
1139 |
-
if self.unconfined:
|
1140 |
-
md['unconfined'] = self.unconfined
|
1141 |
-
if self.alt:
|
1142 |
-
md["alt"] = self.alt
|
1143 |
-
if md or always_both:
|
1144 |
-
return b64_data, md
|
1145 |
-
else:
|
1146 |
-
return b64_data
|
1147 |
-
|
1148 |
-
def _repr_png_(self):
|
1149 |
-
if self.embed and self.format == self._FMT_PNG:
|
1150 |
-
return self._data_and_metadata()
|
1151 |
-
|
1152 |
-
def _repr_jpeg_(self):
|
1153 |
-
if self.embed and self.format == self._FMT_JPEG:
|
1154 |
-
return self._data_and_metadata()
|
1155 |
-
|
1156 |
-
def _find_ext(self, s):
|
1157 |
-
base, ext = splitext(s)
|
1158 |
-
|
1159 |
-
if not ext:
|
1160 |
-
return base
|
1161 |
-
|
1162 |
-
# `splitext` includes leading period, so we skip it
|
1163 |
-
return ext[1:].lower()
|
1164 |
-
|
1165 |
-
|
1166 |
-
class Video(DisplayObject):
|
1167 |
-
|
1168 |
-
def __init__(self, data=None, url=None, filename=None, embed=False,
|
1169 |
-
mimetype=None, width=None, height=None, html_attributes="controls"):
|
1170 |
-
"""Create a video object given raw data or an URL.
|
1171 |
-
|
1172 |
-
When this object is returned by an input cell or passed to the
|
1173 |
-
display function, it will result in the video being displayed
|
1174 |
-
in the frontend.
|
1175 |
-
|
1176 |
-
Parameters
|
1177 |
-
----------
|
1178 |
-
data : unicode, str or bytes
|
1179 |
-
The raw video data or a URL or filename to load the data from.
|
1180 |
-
Raw data will require passing ``embed=True``.
|
1181 |
-
|
1182 |
-
url : unicode
|
1183 |
-
A URL for the video. If you specify ``url=``,
|
1184 |
-
the image data will not be embedded.
|
1185 |
-
|
1186 |
-
filename : unicode
|
1187 |
-
Path to a local file containing the video.
|
1188 |
-
Will be interpreted as a local URL unless ``embed=True``.
|
1189 |
-
|
1190 |
-
embed : bool
|
1191 |
-
Should the video be embedded using a data URI (True) or be
|
1192 |
-
loaded using a <video> tag (False).
|
1193 |
-
|
1194 |
-
Since videos are large, embedding them should be avoided, if possible.
|
1195 |
-
You must confirm embedding as your intention by passing ``embed=True``.
|
1196 |
-
|
1197 |
-
Local files can be displayed with URLs without embedding the content, via::
|
1198 |
-
|
1199 |
-
Video('./video.mp4')
|
1200 |
-
|
1201 |
-
mimetype : unicode
|
1202 |
-
Specify the mimetype for embedded videos.
|
1203 |
-
Default will be guessed from file extension, if available.
|
1204 |
-
|
1205 |
-
width : int
|
1206 |
-
Width in pixels to which to constrain the video in HTML.
|
1207 |
-
If not supplied, defaults to the width of the video.
|
1208 |
-
|
1209 |
-
height : int
|
1210 |
-
Height in pixels to which to constrain the video in html.
|
1211 |
-
If not supplied, defaults to the height of the video.
|
1212 |
-
|
1213 |
-
html_attributes : str
|
1214 |
-
Attributes for the HTML ``<video>`` block.
|
1215 |
-
Default: ``"controls"`` to get video controls.
|
1216 |
-
Other examples: ``"controls muted"`` for muted video with controls,
|
1217 |
-
``"loop autoplay"`` for looping autoplaying video without controls.
|
1218 |
-
|
1219 |
-
Examples
|
1220 |
-
--------
|
1221 |
-
::
|
1222 |
-
|
1223 |
-
Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
|
1224 |
-
Video('path/to/video.mp4')
|
1225 |
-
Video('path/to/video.mp4', embed=True)
|
1226 |
-
Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
|
1227 |
-
Video(b'raw-videodata', embed=True)
|
1228 |
-
"""
|
1229 |
-
if isinstance(data, (Path, PurePath)):
|
1230 |
-
data = str(data)
|
1231 |
-
|
1232 |
-
if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
|
1233 |
-
url = data
|
1234 |
-
data = None
|
1235 |
-
elif data is not None and os.path.exists(data):
|
1236 |
-
filename = data
|
1237 |
-
data = None
|
1238 |
-
|
1239 |
-
if data and not embed:
|
1240 |
-
msg = ''.join([
|
1241 |
-
"To embed videos, you must pass embed=True ",
|
1242 |
-
"(this may make your notebook files huge)\n",
|
1243 |
-
"Consider passing Video(url='...')",
|
1244 |
-
])
|
1245 |
-
raise ValueError(msg)
|
1246 |
-
|
1247 |
-
self.mimetype = mimetype
|
1248 |
-
self.embed = embed
|
1249 |
-
self.width = width
|
1250 |
-
self.height = height
|
1251 |
-
self.html_attributes = html_attributes
|
1252 |
-
super(Video, self).__init__(data=data, url=url, filename=filename)
|
1253 |
-
|
1254 |
-
def _repr_html_(self):
|
1255 |
-
width = height = ''
|
1256 |
-
if self.width:
|
1257 |
-
width = ' width="%d"' % self.width
|
1258 |
-
if self.height:
|
1259 |
-
height = ' height="%d"' % self.height
|
1260 |
-
|
1261 |
-
# External URLs and potentially local files are not embedded into the
|
1262 |
-
# notebook output.
|
1263 |
-
if not self.embed:
|
1264 |
-
url = self.url if self.url is not None else self.filename
|
1265 |
-
output = """<video src="{0}" {1} {2} {3}>
|
1266 |
-
Your browser does not support the <code>video</code> element.
|
1267 |
-
</video>""".format(url, self.html_attributes, width, height)
|
1268 |
-
return output
|
1269 |
-
|
1270 |
-
# Embedded videos are base64-encoded.
|
1271 |
-
mimetype = self.mimetype
|
1272 |
-
if self.filename is not None:
|
1273 |
-
if not mimetype:
|
1274 |
-
mimetype, _ = mimetypes.guess_type(self.filename)
|
1275 |
-
|
1276 |
-
with open(self.filename, 'rb') as f:
|
1277 |
-
video = f.read()
|
1278 |
-
else:
|
1279 |
-
video = self.data
|
1280 |
-
if isinstance(video, str):
|
1281 |
-
# unicode input is already b64-encoded
|
1282 |
-
b64_video = video
|
1283 |
-
else:
|
1284 |
-
b64_video = b2a_base64(video, newline=False).decode("ascii").rstrip()
|
1285 |
-
|
1286 |
-
output = """<video {0} {1} {2}>
|
1287 |
-
<source src="data:{3};base64,{4}" type="{3}">
|
1288 |
-
Your browser does not support the video tag.
|
1289 |
-
</video>""".format(self.html_attributes, width, height, mimetype, b64_video)
|
1290 |
-
return output
|
1291 |
-
|
1292 |
-
def reload(self):
|
1293 |
-
# TODO
|
1294 |
-
pass
|
1295 |
-
|
1296 |
-
|
1297 |
-
@skip_doctest
|
1298 |
-
def set_matplotlib_formats(*formats, **kwargs):
|
1299 |
-
"""
|
1300 |
-
.. deprecated:: 7.23
|
1301 |
-
|
1302 |
-
use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
|
1303 |
-
|
1304 |
-
Select figure formats for the inline backend. Optionally pass quality for JPEG.
|
1305 |
-
|
1306 |
-
For example, this enables PNG and JPEG output with a JPEG quality of 90%::
|
1307 |
-
|
1308 |
-
In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
|
1309 |
-
|
1310 |
-
To set this in your config files use the following::
|
1311 |
-
|
1312 |
-
c.InlineBackend.figure_formats = {'png', 'jpeg'}
|
1313 |
-
c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
|
1314 |
-
|
1315 |
-
Parameters
|
1316 |
-
----------
|
1317 |
-
*formats : strs
|
1318 |
-
One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
|
1319 |
-
**kwargs
|
1320 |
-
Keyword args will be relayed to ``figure.canvas.print_figure``.
|
1321 |
-
"""
|
1322 |
-
warnings.warn(
|
1323 |
-
"`set_matplotlib_formats` is deprecated since IPython 7.23, directly "
|
1324 |
-
"use `matplotlib_inline.backend_inline.set_matplotlib_formats()`",
|
1325 |
-
DeprecationWarning,
|
1326 |
-
stacklevel=2,
|
1327 |
-
)
|
1328 |
-
|
1329 |
-
from matplotlib_inline.backend_inline import (
|
1330 |
-
set_matplotlib_formats as set_matplotlib_formats_orig,
|
1331 |
-
)
|
1332 |
-
|
1333 |
-
set_matplotlib_formats_orig(*formats, **kwargs)
|
1334 |
-
|
1335 |
-
@skip_doctest
|
1336 |
-
def set_matplotlib_close(close=True):
|
1337 |
-
"""
|
1338 |
-
.. deprecated:: 7.23
|
1339 |
-
|
1340 |
-
use `matplotlib_inline.backend_inline.set_matplotlib_close()`
|
1341 |
-
|
1342 |
-
Set whether the inline backend closes all figures automatically or not.
|
1343 |
-
|
1344 |
-
By default, the inline backend used in the IPython Notebook will close all
|
1345 |
-
matplotlib figures automatically after each cell is run. This means that
|
1346 |
-
plots in different cells won't interfere. Sometimes, you may want to make
|
1347 |
-
a plot in one cell and then refine it in later cells. This can be accomplished
|
1348 |
-
by::
|
1349 |
-
|
1350 |
-
In [1]: set_matplotlib_close(False)
|
1351 |
-
|
1352 |
-
To set this in your config files use the following::
|
1353 |
-
|
1354 |
-
c.InlineBackend.close_figures = False
|
1355 |
-
|
1356 |
-
Parameters
|
1357 |
-
----------
|
1358 |
-
close : bool
|
1359 |
-
Should all matplotlib figures be automatically closed after each cell is
|
1360 |
-
run?
|
1361 |
-
"""
|
1362 |
-
warnings.warn(
|
1363 |
-
"`set_matplotlib_close` is deprecated since IPython 7.23, directly "
|
1364 |
-
"use `matplotlib_inline.backend_inline.set_matplotlib_close()`",
|
1365 |
-
DeprecationWarning,
|
1366 |
-
stacklevel=2,
|
1367 |
-
)
|
1368 |
-
|
1369 |
-
from matplotlib_inline.backend_inline import (
|
1370 |
-
set_matplotlib_close as set_matplotlib_close_orig,
|
1371 |
-
)
|
1372 |
-
|
1373 |
-
set_matplotlib_close_orig(close)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/display_functions.py
DELETED
@@ -1,391 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
"""Top-level display functions for displaying object in different formats."""
|
3 |
-
|
4 |
-
# Copyright (c) IPython Development Team.
|
5 |
-
# Distributed under the terms of the Modified BSD License.
|
6 |
-
|
7 |
-
|
8 |
-
from binascii import b2a_hex
|
9 |
-
import os
|
10 |
-
import sys
|
11 |
-
import warnings
|
12 |
-
|
13 |
-
__all__ = ['display', 'clear_output', 'publish_display_data', 'update_display', 'DisplayHandle']
|
14 |
-
|
15 |
-
#-----------------------------------------------------------------------------
|
16 |
-
# utility functions
|
17 |
-
#-----------------------------------------------------------------------------
|
18 |
-
|
19 |
-
|
20 |
-
def _merge(d1, d2):
|
21 |
-
"""Like update, but merges sub-dicts instead of clobbering at the top level.
|
22 |
-
|
23 |
-
Updates d1 in-place
|
24 |
-
"""
|
25 |
-
|
26 |
-
if not isinstance(d2, dict) or not isinstance(d1, dict):
|
27 |
-
return d2
|
28 |
-
for key, value in d2.items():
|
29 |
-
d1[key] = _merge(d1.get(key), value)
|
30 |
-
return d1
|
31 |
-
|
32 |
-
|
33 |
-
#-----------------------------------------------------------------------------
|
34 |
-
# Main functions
|
35 |
-
#-----------------------------------------------------------------------------
|
36 |
-
|
37 |
-
class _Sentinel:
|
38 |
-
def __repr__(self):
|
39 |
-
return "<deprecated>"
|
40 |
-
|
41 |
-
|
42 |
-
_sentinel = _Sentinel()
|
43 |
-
|
44 |
-
# use * to indicate transient is keyword-only
|
45 |
-
def publish_display_data(
|
46 |
-
data, metadata=None, source=_sentinel, *, transient=None, **kwargs
|
47 |
-
):
|
48 |
-
"""Publish data and metadata to all frontends.
|
49 |
-
|
50 |
-
See the ``display_data`` message in the messaging documentation for
|
51 |
-
more details about this message type.
|
52 |
-
|
53 |
-
Keys of data and metadata can be any mime-type.
|
54 |
-
|
55 |
-
Parameters
|
56 |
-
----------
|
57 |
-
data : dict
|
58 |
-
A dictionary having keys that are valid MIME types (like
|
59 |
-
'text/plain' or 'image/svg+xml') and values that are the data for
|
60 |
-
that MIME type. The data itself must be a JSON'able data
|
61 |
-
structure. Minimally all data should have the 'text/plain' data,
|
62 |
-
which can be displayed by all frontends. If more than the plain
|
63 |
-
text is given, it is up to the frontend to decide which
|
64 |
-
representation to use.
|
65 |
-
metadata : dict
|
66 |
-
A dictionary for metadata related to the data. This can contain
|
67 |
-
arbitrary key, value pairs that frontends can use to interpret
|
68 |
-
the data. mime-type keys matching those in data can be used
|
69 |
-
to specify metadata about particular representations.
|
70 |
-
source : str, deprecated
|
71 |
-
Unused.
|
72 |
-
transient : dict, keyword-only
|
73 |
-
A dictionary of transient data, such as display_id.
|
74 |
-
"""
|
75 |
-
from IPython.core.interactiveshell import InteractiveShell
|
76 |
-
|
77 |
-
if source is not _sentinel:
|
78 |
-
warnings.warn(
|
79 |
-
"The `source` parameter emit a deprecation warning since"
|
80 |
-
" IPython 8.0, it had no effects for a long time and will "
|
81 |
-
" be removed in future versions.",
|
82 |
-
DeprecationWarning,
|
83 |
-
stacklevel=2,
|
84 |
-
)
|
85 |
-
display_pub = InteractiveShell.instance().display_pub
|
86 |
-
|
87 |
-
# only pass transient if supplied,
|
88 |
-
# to avoid errors with older ipykernel.
|
89 |
-
# TODO: We could check for ipykernel version and provide a detailed upgrade message.
|
90 |
-
if transient:
|
91 |
-
kwargs['transient'] = transient
|
92 |
-
|
93 |
-
display_pub.publish(
|
94 |
-
data=data,
|
95 |
-
metadata=metadata,
|
96 |
-
**kwargs
|
97 |
-
)
|
98 |
-
|
99 |
-
|
100 |
-
def _new_id():
|
101 |
-
"""Generate a new random text id with urandom"""
|
102 |
-
return b2a_hex(os.urandom(16)).decode('ascii')
|
103 |
-
|
104 |
-
|
105 |
-
def display(
|
106 |
-
*objs,
|
107 |
-
include=None,
|
108 |
-
exclude=None,
|
109 |
-
metadata=None,
|
110 |
-
transient=None,
|
111 |
-
display_id=None,
|
112 |
-
raw=False,
|
113 |
-
clear=False,
|
114 |
-
**kwargs,
|
115 |
-
):
|
116 |
-
"""Display a Python object in all frontends.
|
117 |
-
|
118 |
-
By default all representations will be computed and sent to the frontends.
|
119 |
-
Frontends can decide which representation is used and how.
|
120 |
-
|
121 |
-
In terminal IPython this will be similar to using :func:`print`, for use in richer
|
122 |
-
frontends see Jupyter notebook examples with rich display logic.
|
123 |
-
|
124 |
-
Parameters
|
125 |
-
----------
|
126 |
-
*objs : object
|
127 |
-
The Python objects to display.
|
128 |
-
raw : bool, optional
|
129 |
-
Are the objects to be displayed already mimetype-keyed dicts of raw display data,
|
130 |
-
or Python objects that need to be formatted before display? [default: False]
|
131 |
-
include : list, tuple or set, optional
|
132 |
-
A list of format type strings (MIME types) to include in the
|
133 |
-
format data dict. If this is set *only* the format types included
|
134 |
-
in this list will be computed.
|
135 |
-
exclude : list, tuple or set, optional
|
136 |
-
A list of format type strings (MIME types) to exclude in the format
|
137 |
-
data dict. If this is set all format types will be computed,
|
138 |
-
except for those included in this argument.
|
139 |
-
metadata : dict, optional
|
140 |
-
A dictionary of metadata to associate with the output.
|
141 |
-
mime-type keys in this dictionary will be associated with the individual
|
142 |
-
representation formats, if they exist.
|
143 |
-
transient : dict, optional
|
144 |
-
A dictionary of transient data to associate with the output.
|
145 |
-
Data in this dict should not be persisted to files (e.g. notebooks).
|
146 |
-
display_id : str, bool optional
|
147 |
-
Set an id for the display.
|
148 |
-
This id can be used for updating this display area later via update_display.
|
149 |
-
If given as `True`, generate a new `display_id`
|
150 |
-
clear : bool, optional
|
151 |
-
Should the output area be cleared before displaying anything? If True,
|
152 |
-
this will wait for additional output before clearing. [default: False]
|
153 |
-
**kwargs : additional keyword-args, optional
|
154 |
-
Additional keyword-arguments are passed through to the display publisher.
|
155 |
-
|
156 |
-
Returns
|
157 |
-
-------
|
158 |
-
handle: DisplayHandle
|
159 |
-
Returns a handle on updatable displays for use with :func:`update_display`,
|
160 |
-
if `display_id` is given. Returns :any:`None` if no `display_id` is given
|
161 |
-
(default).
|
162 |
-
|
163 |
-
Examples
|
164 |
-
--------
|
165 |
-
>>> class Json(object):
|
166 |
-
... def __init__(self, json):
|
167 |
-
... self.json = json
|
168 |
-
... def _repr_pretty_(self, pp, cycle):
|
169 |
-
... import json
|
170 |
-
... pp.text(json.dumps(self.json, indent=2))
|
171 |
-
... def __repr__(self):
|
172 |
-
... return str(self.json)
|
173 |
-
...
|
174 |
-
|
175 |
-
>>> d = Json({1:2, 3: {4:5}})
|
176 |
-
|
177 |
-
>>> print(d)
|
178 |
-
{1: 2, 3: {4: 5}}
|
179 |
-
|
180 |
-
>>> display(d)
|
181 |
-
{
|
182 |
-
"1": 2,
|
183 |
-
"3": {
|
184 |
-
"4": 5
|
185 |
-
}
|
186 |
-
}
|
187 |
-
|
188 |
-
>>> def int_formatter(integer, pp, cycle):
|
189 |
-
... pp.text('I'*integer)
|
190 |
-
|
191 |
-
>>> plain = get_ipython().display_formatter.formatters['text/plain']
|
192 |
-
>>> plain.for_type(int, int_formatter)
|
193 |
-
<function _repr_pprint at 0x...>
|
194 |
-
>>> display(7-5)
|
195 |
-
II
|
196 |
-
|
197 |
-
>>> del plain.type_printers[int]
|
198 |
-
>>> display(7-5)
|
199 |
-
2
|
200 |
-
|
201 |
-
See Also
|
202 |
-
--------
|
203 |
-
:func:`update_display`
|
204 |
-
|
205 |
-
Notes
|
206 |
-
-----
|
207 |
-
In Python, objects can declare their textual representation using the
|
208 |
-
`__repr__` method. IPython expands on this idea and allows objects to declare
|
209 |
-
other, rich representations including:
|
210 |
-
|
211 |
-
- HTML
|
212 |
-
- JSON
|
213 |
-
- PNG
|
214 |
-
- JPEG
|
215 |
-
- SVG
|
216 |
-
- LaTeX
|
217 |
-
|
218 |
-
A single object can declare some or all of these representations; all are
|
219 |
-
handled by IPython's display system.
|
220 |
-
|
221 |
-
The main idea of the first approach is that you have to implement special
|
222 |
-
display methods when you define your class, one for each representation you
|
223 |
-
want to use. Here is a list of the names of the special methods and the
|
224 |
-
values they must return:
|
225 |
-
|
226 |
-
- `_repr_html_`: return raw HTML as a string, or a tuple (see below).
|
227 |
-
- `_repr_json_`: return a JSONable dict, or a tuple (see below).
|
228 |
-
- `_repr_jpeg_`: return raw JPEG data, or a tuple (see below).
|
229 |
-
- `_repr_png_`: return raw PNG data, or a tuple (see below).
|
230 |
-
- `_repr_svg_`: return raw SVG data as a string, or a tuple (see below).
|
231 |
-
- `_repr_latex_`: return LaTeX commands in a string surrounded by "$",
|
232 |
-
or a tuple (see below).
|
233 |
-
- `_repr_mimebundle_`: return a full mimebundle containing the mapping
|
234 |
-
from all mimetypes to data.
|
235 |
-
Use this for any mime-type not listed above.
|
236 |
-
|
237 |
-
The above functions may also return the object's metadata alonside the
|
238 |
-
data. If the metadata is available, the functions will return a tuple
|
239 |
-
containing the data and metadata, in that order. If there is no metadata
|
240 |
-
available, then the functions will return the data only.
|
241 |
-
|
242 |
-
When you are directly writing your own classes, you can adapt them for
|
243 |
-
display in IPython by following the above approach. But in practice, you
|
244 |
-
often need to work with existing classes that you can't easily modify.
|
245 |
-
|
246 |
-
You can refer to the documentation on integrating with the display system in
|
247 |
-
order to register custom formatters for already existing types
|
248 |
-
(:ref:`integrating_rich_display`).
|
249 |
-
|
250 |
-
.. versionadded:: 5.4 display available without import
|
251 |
-
.. versionadded:: 6.1 display available without import
|
252 |
-
|
253 |
-
Since IPython 5.4 and 6.1 :func:`display` is automatically made available to
|
254 |
-
the user without import. If you are using display in a document that might
|
255 |
-
be used in a pure python context or with older version of IPython, use the
|
256 |
-
following import at the top of your file::
|
257 |
-
|
258 |
-
from IPython.display import display
|
259 |
-
|
260 |
-
"""
|
261 |
-
from IPython.core.interactiveshell import InteractiveShell
|
262 |
-
|
263 |
-
if not InteractiveShell.initialized():
|
264 |
-
# Directly print objects.
|
265 |
-
print(*objs)
|
266 |
-
return
|
267 |
-
|
268 |
-
if transient is None:
|
269 |
-
transient = {}
|
270 |
-
if metadata is None:
|
271 |
-
metadata={}
|
272 |
-
if display_id:
|
273 |
-
if display_id is True:
|
274 |
-
display_id = _new_id()
|
275 |
-
transient['display_id'] = display_id
|
276 |
-
if kwargs.get('update') and 'display_id' not in transient:
|
277 |
-
raise TypeError('display_id required for update_display')
|
278 |
-
if transient:
|
279 |
-
kwargs['transient'] = transient
|
280 |
-
|
281 |
-
if not objs and display_id:
|
282 |
-
# if given no objects, but still a request for a display_id,
|
283 |
-
# we assume the user wants to insert an empty output that
|
284 |
-
# can be updated later
|
285 |
-
objs = [{}]
|
286 |
-
raw = True
|
287 |
-
|
288 |
-
if not raw:
|
289 |
-
format = InteractiveShell.instance().display_formatter.format
|
290 |
-
|
291 |
-
if clear:
|
292 |
-
clear_output(wait=True)
|
293 |
-
|
294 |
-
for obj in objs:
|
295 |
-
if raw:
|
296 |
-
publish_display_data(data=obj, metadata=metadata, **kwargs)
|
297 |
-
else:
|
298 |
-
format_dict, md_dict = format(obj, include=include, exclude=exclude)
|
299 |
-
if not format_dict:
|
300 |
-
# nothing to display (e.g. _ipython_display_ took over)
|
301 |
-
continue
|
302 |
-
if metadata:
|
303 |
-
# kwarg-specified metadata gets precedence
|
304 |
-
_merge(md_dict, metadata)
|
305 |
-
publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
|
306 |
-
if display_id:
|
307 |
-
return DisplayHandle(display_id)
|
308 |
-
|
309 |
-
|
310 |
-
# use * for keyword-only display_id arg
|
311 |
-
def update_display(obj, *, display_id, **kwargs):
|
312 |
-
"""Update an existing display by id
|
313 |
-
|
314 |
-
Parameters
|
315 |
-
----------
|
316 |
-
obj
|
317 |
-
The object with which to update the display
|
318 |
-
display_id : keyword-only
|
319 |
-
The id of the display to update
|
320 |
-
|
321 |
-
See Also
|
322 |
-
--------
|
323 |
-
:func:`display`
|
324 |
-
"""
|
325 |
-
kwargs['update'] = True
|
326 |
-
display(obj, display_id=display_id, **kwargs)
|
327 |
-
|
328 |
-
|
329 |
-
class DisplayHandle(object):
|
330 |
-
"""A handle on an updatable display
|
331 |
-
|
332 |
-
Call `.update(obj)` to display a new object.
|
333 |
-
|
334 |
-
Call `.display(obj`) to add a new instance of this display,
|
335 |
-
and update existing instances.
|
336 |
-
|
337 |
-
See Also
|
338 |
-
--------
|
339 |
-
|
340 |
-
:func:`display`, :func:`update_display`
|
341 |
-
|
342 |
-
"""
|
343 |
-
|
344 |
-
def __init__(self, display_id=None):
|
345 |
-
if display_id is None:
|
346 |
-
display_id = _new_id()
|
347 |
-
self.display_id = display_id
|
348 |
-
|
349 |
-
def __repr__(self):
|
350 |
-
return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
|
351 |
-
|
352 |
-
def display(self, obj, **kwargs):
|
353 |
-
"""Make a new display with my id, updating existing instances.
|
354 |
-
|
355 |
-
Parameters
|
356 |
-
----------
|
357 |
-
obj
|
358 |
-
object to display
|
359 |
-
**kwargs
|
360 |
-
additional keyword arguments passed to display
|
361 |
-
"""
|
362 |
-
display(obj, display_id=self.display_id, **kwargs)
|
363 |
-
|
364 |
-
def update(self, obj, **kwargs):
|
365 |
-
"""Update existing displays with my id
|
366 |
-
|
367 |
-
Parameters
|
368 |
-
----------
|
369 |
-
obj
|
370 |
-
object to display
|
371 |
-
**kwargs
|
372 |
-
additional keyword arguments passed to update_display
|
373 |
-
"""
|
374 |
-
update_display(obj, display_id=self.display_id, **kwargs)
|
375 |
-
|
376 |
-
|
377 |
-
def clear_output(wait=False):
|
378 |
-
"""Clear the output of the current cell receiving output.
|
379 |
-
|
380 |
-
Parameters
|
381 |
-
----------
|
382 |
-
wait : bool [default: false]
|
383 |
-
Wait to clear the output until new output is available to replace it."""
|
384 |
-
from IPython.core.interactiveshell import InteractiveShell
|
385 |
-
if InteractiveShell.initialized():
|
386 |
-
InteractiveShell.instance().display_pub.clear_output(wait)
|
387 |
-
else:
|
388 |
-
print('\033[2K\r', end='')
|
389 |
-
sys.stdout.flush()
|
390 |
-
print('\033[2K\r', end='')
|
391 |
-
sys.stderr.flush()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/display_trap.py
DELETED
@@ -1,70 +0,0 @@
|
|
1 |
-
# encoding: utf-8
|
2 |
-
"""
|
3 |
-
A context manager for handling sys.displayhook.
|
4 |
-
|
5 |
-
Authors:
|
6 |
-
|
7 |
-
* Robert Kern
|
8 |
-
* Brian Granger
|
9 |
-
"""
|
10 |
-
|
11 |
-
#-----------------------------------------------------------------------------
|
12 |
-
# Copyright (C) 2008-2011 The IPython Development Team
|
13 |
-
#
|
14 |
-
# Distributed under the terms of the BSD License. The full license is in
|
15 |
-
# the file COPYING, distributed as part of this software.
|
16 |
-
#-----------------------------------------------------------------------------
|
17 |
-
|
18 |
-
#-----------------------------------------------------------------------------
|
19 |
-
# Imports
|
20 |
-
#-----------------------------------------------------------------------------
|
21 |
-
|
22 |
-
import sys
|
23 |
-
|
24 |
-
from traitlets.config.configurable import Configurable
|
25 |
-
from traitlets import Any
|
26 |
-
|
27 |
-
#-----------------------------------------------------------------------------
|
28 |
-
# Classes and functions
|
29 |
-
#-----------------------------------------------------------------------------
|
30 |
-
|
31 |
-
|
32 |
-
class DisplayTrap(Configurable):
|
33 |
-
"""Object to manage sys.displayhook.
|
34 |
-
|
35 |
-
This came from IPython.core.kernel.display_hook, but is simplified
|
36 |
-
(no callbacks or formatters) until more of the core is refactored.
|
37 |
-
"""
|
38 |
-
|
39 |
-
hook = Any()
|
40 |
-
|
41 |
-
def __init__(self, hook=None):
|
42 |
-
super(DisplayTrap, self).__init__(hook=hook, config=None)
|
43 |
-
self.old_hook = None
|
44 |
-
# We define this to track if a single BuiltinTrap is nested.
|
45 |
-
# Only turn off the trap when the outermost call to __exit__ is made.
|
46 |
-
self._nested_level = 0
|
47 |
-
|
48 |
-
def __enter__(self):
|
49 |
-
if self._nested_level == 0:
|
50 |
-
self.set()
|
51 |
-
self._nested_level += 1
|
52 |
-
return self
|
53 |
-
|
54 |
-
def __exit__(self, type, value, traceback):
|
55 |
-
if self._nested_level == 1:
|
56 |
-
self.unset()
|
57 |
-
self._nested_level -= 1
|
58 |
-
# Returning False will cause exceptions to propagate
|
59 |
-
return False
|
60 |
-
|
61 |
-
def set(self):
|
62 |
-
"""Set the hook."""
|
63 |
-
if sys.displayhook is not self.hook:
|
64 |
-
self.old_hook = sys.displayhook
|
65 |
-
sys.displayhook = self.hook
|
66 |
-
|
67 |
-
def unset(self):
|
68 |
-
"""Unset the hook."""
|
69 |
-
sys.displayhook = self.old_hook
|
70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/displayhook.py
DELETED
@@ -1,336 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
"""Displayhook for IPython.
|
3 |
-
|
4 |
-
This defines a callable class that IPython uses for `sys.displayhook`.
|
5 |
-
"""
|
6 |
-
|
7 |
-
# Copyright (c) IPython Development Team.
|
8 |
-
# Distributed under the terms of the Modified BSD License.
|
9 |
-
|
10 |
-
import builtins as builtin_mod
|
11 |
-
import sys
|
12 |
-
import io as _io
|
13 |
-
import tokenize
|
14 |
-
|
15 |
-
from traitlets.config.configurable import Configurable
|
16 |
-
from traitlets import Instance, Float
|
17 |
-
from warnings import warn
|
18 |
-
|
19 |
-
# TODO: Move the various attributes (cache_size, [others now moved]). Some
|
20 |
-
# of these are also attributes of InteractiveShell. They should be on ONE object
|
21 |
-
# only and the other objects should ask that one object for their values.
|
22 |
-
|
23 |
-
class DisplayHook(Configurable):
|
24 |
-
"""The custom IPython displayhook to replace sys.displayhook.
|
25 |
-
|
26 |
-
This class does many things, but the basic idea is that it is a callable
|
27 |
-
that gets called anytime user code returns a value.
|
28 |
-
"""
|
29 |
-
|
30 |
-
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
|
31 |
-
allow_none=True)
|
32 |
-
exec_result = Instance('IPython.core.interactiveshell.ExecutionResult',
|
33 |
-
allow_none=True)
|
34 |
-
cull_fraction = Float(0.2)
|
35 |
-
|
36 |
-
def __init__(self, shell=None, cache_size=1000, **kwargs):
|
37 |
-
super(DisplayHook, self).__init__(shell=shell, **kwargs)
|
38 |
-
cache_size_min = 3
|
39 |
-
if cache_size <= 0:
|
40 |
-
self.do_full_cache = 0
|
41 |
-
cache_size = 0
|
42 |
-
elif cache_size < cache_size_min:
|
43 |
-
self.do_full_cache = 0
|
44 |
-
cache_size = 0
|
45 |
-
warn('caching was disabled (min value for cache size is %s).' %
|
46 |
-
cache_size_min,stacklevel=3)
|
47 |
-
else:
|
48 |
-
self.do_full_cache = 1
|
49 |
-
|
50 |
-
self.cache_size = cache_size
|
51 |
-
|
52 |
-
# we need a reference to the user-level namespace
|
53 |
-
self.shell = shell
|
54 |
-
|
55 |
-
self._,self.__,self.___ = '','',''
|
56 |
-
|
57 |
-
# these are deliberately global:
|
58 |
-
to_user_ns = {'_':self._,'__':self.__,'___':self.___}
|
59 |
-
self.shell.user_ns.update(to_user_ns)
|
60 |
-
|
61 |
-
@property
|
62 |
-
def prompt_count(self):
|
63 |
-
return self.shell.execution_count
|
64 |
-
|
65 |
-
#-------------------------------------------------------------------------
|
66 |
-
# Methods used in __call__. Override these methods to modify the behavior
|
67 |
-
# of the displayhook.
|
68 |
-
#-------------------------------------------------------------------------
|
69 |
-
|
70 |
-
def check_for_underscore(self):
|
71 |
-
"""Check if the user has set the '_' variable by hand."""
|
72 |
-
# If something injected a '_' variable in __builtin__, delete
|
73 |
-
# ipython's automatic one so we don't clobber that. gettext() in
|
74 |
-
# particular uses _, so we need to stay away from it.
|
75 |
-
if '_' in builtin_mod.__dict__:
|
76 |
-
try:
|
77 |
-
user_value = self.shell.user_ns['_']
|
78 |
-
if user_value is not self._:
|
79 |
-
return
|
80 |
-
del self.shell.user_ns['_']
|
81 |
-
except KeyError:
|
82 |
-
pass
|
83 |
-
|
84 |
-
def quiet(self):
|
85 |
-
"""Should we silence the display hook because of ';'?"""
|
86 |
-
# do not print output if input ends in ';'
|
87 |
-
|
88 |
-
try:
|
89 |
-
cell = self.shell.history_manager.input_hist_parsed[-1]
|
90 |
-
except IndexError:
|
91 |
-
# some uses of ipshellembed may fail here
|
92 |
-
return False
|
93 |
-
|
94 |
-
return self.semicolon_at_end_of_expression(cell)
|
95 |
-
|
96 |
-
@staticmethod
|
97 |
-
def semicolon_at_end_of_expression(expression):
|
98 |
-
"""Parse Python expression and detects whether last token is ';'"""
|
99 |
-
|
100 |
-
sio = _io.StringIO(expression)
|
101 |
-
tokens = list(tokenize.generate_tokens(sio.readline))
|
102 |
-
|
103 |
-
for token in reversed(tokens):
|
104 |
-
if token[0] in (tokenize.ENDMARKER, tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT):
|
105 |
-
continue
|
106 |
-
if (token[0] == tokenize.OP) and (token[1] == ';'):
|
107 |
-
return True
|
108 |
-
else:
|
109 |
-
return False
|
110 |
-
|
111 |
-
def start_displayhook(self):
|
112 |
-
"""Start the displayhook, initializing resources."""
|
113 |
-
pass
|
114 |
-
|
115 |
-
def write_output_prompt(self):
|
116 |
-
"""Write the output prompt.
|
117 |
-
|
118 |
-
The default implementation simply writes the prompt to
|
119 |
-
``sys.stdout``.
|
120 |
-
"""
|
121 |
-
# Use write, not print which adds an extra space.
|
122 |
-
sys.stdout.write(self.shell.separate_out)
|
123 |
-
outprompt = 'Out[{}]: '.format(self.shell.execution_count)
|
124 |
-
if self.do_full_cache:
|
125 |
-
sys.stdout.write(outprompt)
|
126 |
-
|
127 |
-
def compute_format_data(self, result):
|
128 |
-
"""Compute format data of the object to be displayed.
|
129 |
-
|
130 |
-
The format data is a generalization of the :func:`repr` of an object.
|
131 |
-
In the default implementation the format data is a :class:`dict` of
|
132 |
-
key value pair where the keys are valid MIME types and the values
|
133 |
-
are JSON'able data structure containing the raw data for that MIME
|
134 |
-
type. It is up to frontends to determine pick a MIME to to use and
|
135 |
-
display that data in an appropriate manner.
|
136 |
-
|
137 |
-
This method only computes the format data for the object and should
|
138 |
-
NOT actually print or write that to a stream.
|
139 |
-
|
140 |
-
Parameters
|
141 |
-
----------
|
142 |
-
result : object
|
143 |
-
The Python object passed to the display hook, whose format will be
|
144 |
-
computed.
|
145 |
-
|
146 |
-
Returns
|
147 |
-
-------
|
148 |
-
(format_dict, md_dict) : dict
|
149 |
-
format_dict is a :class:`dict` whose keys are valid MIME types and values are
|
150 |
-
JSON'able raw data for that MIME type. It is recommended that
|
151 |
-
all return values of this should always include the "text/plain"
|
152 |
-
MIME type representation of the object.
|
153 |
-
md_dict is a :class:`dict` with the same MIME type keys
|
154 |
-
of metadata associated with each output.
|
155 |
-
|
156 |
-
"""
|
157 |
-
return self.shell.display_formatter.format(result)
|
158 |
-
|
159 |
-
# This can be set to True by the write_output_prompt method in a subclass
|
160 |
-
prompt_end_newline = False
|
161 |
-
|
162 |
-
def write_format_data(self, format_dict, md_dict=None) -> None:
|
163 |
-
"""Write the format data dict to the frontend.
|
164 |
-
|
165 |
-
This default version of this method simply writes the plain text
|
166 |
-
representation of the object to ``sys.stdout``. Subclasses should
|
167 |
-
override this method to send the entire `format_dict` to the
|
168 |
-
frontends.
|
169 |
-
|
170 |
-
Parameters
|
171 |
-
----------
|
172 |
-
format_dict : dict
|
173 |
-
The format dict for the object passed to `sys.displayhook`.
|
174 |
-
md_dict : dict (optional)
|
175 |
-
The metadata dict to be associated with the display data.
|
176 |
-
"""
|
177 |
-
if 'text/plain' not in format_dict:
|
178 |
-
# nothing to do
|
179 |
-
return
|
180 |
-
# We want to print because we want to always make sure we have a
|
181 |
-
# newline, even if all the prompt separators are ''. This is the
|
182 |
-
# standard IPython behavior.
|
183 |
-
result_repr = format_dict['text/plain']
|
184 |
-
if '\n' in result_repr:
|
185 |
-
# So that multi-line strings line up with the left column of
|
186 |
-
# the screen, instead of having the output prompt mess up
|
187 |
-
# their first line.
|
188 |
-
# We use the prompt template instead of the expanded prompt
|
189 |
-
# because the expansion may add ANSI escapes that will interfere
|
190 |
-
# with our ability to determine whether or not we should add
|
191 |
-
# a newline.
|
192 |
-
if not self.prompt_end_newline:
|
193 |
-
# But avoid extraneous empty lines.
|
194 |
-
result_repr = '\n' + result_repr
|
195 |
-
|
196 |
-
try:
|
197 |
-
print(result_repr)
|
198 |
-
except UnicodeEncodeError:
|
199 |
-
# If a character is not supported by the terminal encoding replace
|
200 |
-
# it with its \u or \x representation
|
201 |
-
print(result_repr.encode(sys.stdout.encoding,'backslashreplace').decode(sys.stdout.encoding))
|
202 |
-
|
203 |
-
def update_user_ns(self, result):
|
204 |
-
"""Update user_ns with various things like _, __, _1, etc."""
|
205 |
-
|
206 |
-
# Avoid recursive reference when displaying _oh/Out
|
207 |
-
if self.cache_size and result is not self.shell.user_ns['_oh']:
|
208 |
-
if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
|
209 |
-
self.cull_cache()
|
210 |
-
|
211 |
-
# Don't overwrite '_' and friends if '_' is in __builtin__
|
212 |
-
# (otherwise we cause buggy behavior for things like gettext). and
|
213 |
-
# do not overwrite _, __ or ___ if one of these has been assigned
|
214 |
-
# by the user.
|
215 |
-
update_unders = True
|
216 |
-
for unders in ['_'*i for i in range(1,4)]:
|
217 |
-
if not unders in self.shell.user_ns:
|
218 |
-
continue
|
219 |
-
if getattr(self, unders) is not self.shell.user_ns.get(unders):
|
220 |
-
update_unders = False
|
221 |
-
|
222 |
-
self.___ = self.__
|
223 |
-
self.__ = self._
|
224 |
-
self._ = result
|
225 |
-
|
226 |
-
if ('_' not in builtin_mod.__dict__) and (update_unders):
|
227 |
-
self.shell.push({'_':self._,
|
228 |
-
'__':self.__,
|
229 |
-
'___':self.___}, interactive=False)
|
230 |
-
|
231 |
-
# hackish access to top-level namespace to create _1,_2... dynamically
|
232 |
-
to_main = {}
|
233 |
-
if self.do_full_cache:
|
234 |
-
new_result = '_%s' % self.prompt_count
|
235 |
-
to_main[new_result] = result
|
236 |
-
self.shell.push(to_main, interactive=False)
|
237 |
-
self.shell.user_ns['_oh'][self.prompt_count] = result
|
238 |
-
|
239 |
-
def fill_exec_result(self, result):
|
240 |
-
if self.exec_result is not None:
|
241 |
-
self.exec_result.result = result
|
242 |
-
|
243 |
-
def log_output(self, format_dict):
|
244 |
-
"""Log the output."""
|
245 |
-
if 'text/plain' not in format_dict:
|
246 |
-
# nothing to do
|
247 |
-
return
|
248 |
-
if self.shell.logger.log_output:
|
249 |
-
self.shell.logger.log_write(format_dict['text/plain'], 'output')
|
250 |
-
self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
|
251 |
-
format_dict['text/plain']
|
252 |
-
|
253 |
-
def finish_displayhook(self):
|
254 |
-
"""Finish up all displayhook activities."""
|
255 |
-
sys.stdout.write(self.shell.separate_out2)
|
256 |
-
sys.stdout.flush()
|
257 |
-
|
258 |
-
def __call__(self, result=None):
|
259 |
-
"""Printing with history cache management.
|
260 |
-
|
261 |
-
This is invoked every time the interpreter needs to print, and is
|
262 |
-
activated by setting the variable sys.displayhook to it.
|
263 |
-
"""
|
264 |
-
self.check_for_underscore()
|
265 |
-
if result is not None and not self.quiet():
|
266 |
-
self.start_displayhook()
|
267 |
-
self.write_output_prompt()
|
268 |
-
format_dict, md_dict = self.compute_format_data(result)
|
269 |
-
self.update_user_ns(result)
|
270 |
-
self.fill_exec_result(result)
|
271 |
-
if format_dict:
|
272 |
-
self.write_format_data(format_dict, md_dict)
|
273 |
-
self.log_output(format_dict)
|
274 |
-
self.finish_displayhook()
|
275 |
-
|
276 |
-
def cull_cache(self):
|
277 |
-
"""Output cache is full, cull the oldest entries"""
|
278 |
-
oh = self.shell.user_ns.get('_oh', {})
|
279 |
-
sz = len(oh)
|
280 |
-
cull_count = max(int(sz * self.cull_fraction), 2)
|
281 |
-
warn('Output cache limit (currently {sz} entries) hit.\n'
|
282 |
-
'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
|
283 |
-
|
284 |
-
for i, n in enumerate(sorted(oh)):
|
285 |
-
if i >= cull_count:
|
286 |
-
break
|
287 |
-
self.shell.user_ns.pop('_%i' % n, None)
|
288 |
-
oh.pop(n, None)
|
289 |
-
|
290 |
-
|
291 |
-
def flush(self):
|
292 |
-
if not self.do_full_cache:
|
293 |
-
raise ValueError("You shouldn't have reached the cache flush "
|
294 |
-
"if full caching is not enabled!")
|
295 |
-
# delete auto-generated vars from global namespace
|
296 |
-
|
297 |
-
for n in range(1,self.prompt_count + 1):
|
298 |
-
key = '_'+repr(n)
|
299 |
-
try:
|
300 |
-
del self.shell.user_ns_hidden[key]
|
301 |
-
except KeyError:
|
302 |
-
pass
|
303 |
-
try:
|
304 |
-
del self.shell.user_ns[key]
|
305 |
-
except KeyError:
|
306 |
-
pass
|
307 |
-
# In some embedded circumstances, the user_ns doesn't have the
|
308 |
-
# '_oh' key set up.
|
309 |
-
oh = self.shell.user_ns.get('_oh', None)
|
310 |
-
if oh is not None:
|
311 |
-
oh.clear()
|
312 |
-
|
313 |
-
# Release our own references to objects:
|
314 |
-
self._, self.__, self.___ = '', '', ''
|
315 |
-
|
316 |
-
if '_' not in builtin_mod.__dict__:
|
317 |
-
self.shell.user_ns.update({'_':self._,'__':self.__,'___':self.___})
|
318 |
-
import gc
|
319 |
-
# TODO: Is this really needed?
|
320 |
-
# IronPython blocks here forever
|
321 |
-
if sys.platform != "cli":
|
322 |
-
gc.collect()
|
323 |
-
|
324 |
-
|
325 |
-
class CapturingDisplayHook(object):
|
326 |
-
def __init__(self, shell, outputs=None):
|
327 |
-
self.shell = shell
|
328 |
-
if outputs is None:
|
329 |
-
outputs = []
|
330 |
-
self.outputs = outputs
|
331 |
-
|
332 |
-
def __call__(self, result=None):
|
333 |
-
if result is None:
|
334 |
-
return
|
335 |
-
format_dict, md_dict = self.shell.display_formatter.format(result)
|
336 |
-
self.outputs.append({ 'data': format_dict, 'metadata': md_dict })
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/displaypub.py
DELETED
@@ -1,149 +0,0 @@
|
|
1 |
-
"""An interface for publishing rich data to frontends.
|
2 |
-
|
3 |
-
There are two components of the display system:
|
4 |
-
|
5 |
-
* Display formatters, which take a Python object and compute the
|
6 |
-
representation of the object in various formats (text, HTML, SVG, etc.).
|
7 |
-
* The display publisher that is used to send the representation data to the
|
8 |
-
various frontends.
|
9 |
-
|
10 |
-
This module defines the logic display publishing. The display publisher uses
|
11 |
-
the ``display_data`` message type that is defined in the IPython messaging
|
12 |
-
spec.
|
13 |
-
"""
|
14 |
-
|
15 |
-
# Copyright (c) IPython Development Team.
|
16 |
-
# Distributed under the terms of the Modified BSD License.
|
17 |
-
|
18 |
-
|
19 |
-
import sys
|
20 |
-
|
21 |
-
from traitlets.config.configurable import Configurable
|
22 |
-
from traitlets import List
|
23 |
-
|
24 |
-
# This used to be defined here - it is imported for backwards compatibility
|
25 |
-
from .display_functions import publish_display_data
|
26 |
-
|
27 |
-
import typing as t
|
28 |
-
|
29 |
-
# -----------------------------------------------------------------------------
|
30 |
-
# Main payload class
|
31 |
-
#-----------------------------------------------------------------------------
|
32 |
-
|
33 |
-
|
34 |
-
class DisplayPublisher(Configurable):
|
35 |
-
"""A traited class that publishes display data to frontends.
|
36 |
-
|
37 |
-
Instances of this class are created by the main IPython object and should
|
38 |
-
be accessed there.
|
39 |
-
"""
|
40 |
-
|
41 |
-
def __init__(self, shell=None, *args, **kwargs):
|
42 |
-
self.shell = shell
|
43 |
-
super().__init__(*args, **kwargs)
|
44 |
-
|
45 |
-
def _validate_data(self, data, metadata=None):
|
46 |
-
"""Validate the display data.
|
47 |
-
|
48 |
-
Parameters
|
49 |
-
----------
|
50 |
-
data : dict
|
51 |
-
The formata data dictionary.
|
52 |
-
metadata : dict
|
53 |
-
Any metadata for the data.
|
54 |
-
"""
|
55 |
-
|
56 |
-
if not isinstance(data, dict):
|
57 |
-
raise TypeError('data must be a dict, got: %r' % data)
|
58 |
-
if metadata is not None:
|
59 |
-
if not isinstance(metadata, dict):
|
60 |
-
raise TypeError('metadata must be a dict, got: %r' % data)
|
61 |
-
|
62 |
-
# use * to indicate transient, update are keyword-only
|
63 |
-
def publish(self, data, metadata=None, source=None, *, transient=None, update=False, **kwargs) -> None:
|
64 |
-
"""Publish data and metadata to all frontends.
|
65 |
-
|
66 |
-
See the ``display_data`` message in the messaging documentation for
|
67 |
-
more details about this message type.
|
68 |
-
|
69 |
-
The following MIME types are currently implemented:
|
70 |
-
|
71 |
-
* text/plain
|
72 |
-
* text/html
|
73 |
-
* text/markdown
|
74 |
-
* text/latex
|
75 |
-
* application/json
|
76 |
-
* application/javascript
|
77 |
-
* image/png
|
78 |
-
* image/jpeg
|
79 |
-
* image/svg+xml
|
80 |
-
|
81 |
-
Parameters
|
82 |
-
----------
|
83 |
-
data : dict
|
84 |
-
A dictionary having keys that are valid MIME types (like
|
85 |
-
'text/plain' or 'image/svg+xml') and values that are the data for
|
86 |
-
that MIME type. The data itself must be a JSON'able data
|
87 |
-
structure. Minimally all data should have the 'text/plain' data,
|
88 |
-
which can be displayed by all frontends. If more than the plain
|
89 |
-
text is given, it is up to the frontend to decide which
|
90 |
-
representation to use.
|
91 |
-
metadata : dict
|
92 |
-
A dictionary for metadata related to the data. This can contain
|
93 |
-
arbitrary key, value pairs that frontends can use to interpret
|
94 |
-
the data. Metadata specific to each mime-type can be specified
|
95 |
-
in the metadata dict with the same mime-type keys as
|
96 |
-
the data itself.
|
97 |
-
source : str, deprecated
|
98 |
-
Unused.
|
99 |
-
transient : dict, keyword-only
|
100 |
-
A dictionary for transient data.
|
101 |
-
Data in this dictionary should not be persisted as part of saving this output.
|
102 |
-
Examples include 'display_id'.
|
103 |
-
update : bool, keyword-only, default: False
|
104 |
-
If True, only update existing outputs with the same display_id,
|
105 |
-
rather than creating a new output.
|
106 |
-
"""
|
107 |
-
|
108 |
-
handlers: t.Dict = {}
|
109 |
-
if self.shell is not None:
|
110 |
-
handlers = getattr(self.shell, "mime_renderers", {})
|
111 |
-
|
112 |
-
for mime, handler in handlers.items():
|
113 |
-
if mime in data:
|
114 |
-
handler(data[mime], metadata.get(mime, None))
|
115 |
-
return
|
116 |
-
|
117 |
-
if 'text/plain' in data:
|
118 |
-
print(data['text/plain'])
|
119 |
-
|
120 |
-
def clear_output(self, wait=False):
|
121 |
-
"""Clear the output of the cell receiving output."""
|
122 |
-
print('\033[2K\r', end='')
|
123 |
-
sys.stdout.flush()
|
124 |
-
print('\033[2K\r', end='')
|
125 |
-
sys.stderr.flush()
|
126 |
-
|
127 |
-
|
128 |
-
class CapturingDisplayPublisher(DisplayPublisher):
|
129 |
-
"""A DisplayPublisher that stores"""
|
130 |
-
|
131 |
-
outputs: List = List()
|
132 |
-
|
133 |
-
def publish(
|
134 |
-
self, data, metadata=None, source=None, *, transient=None, update=False
|
135 |
-
):
|
136 |
-
self.outputs.append(
|
137 |
-
{
|
138 |
-
"data": data,
|
139 |
-
"metadata": metadata,
|
140 |
-
"transient": transient,
|
141 |
-
"update": update,
|
142 |
-
}
|
143 |
-
)
|
144 |
-
|
145 |
-
def clear_output(self, wait=False):
|
146 |
-
super(CapturingDisplayPublisher, self).clear_output(wait)
|
147 |
-
|
148 |
-
# empty the list, *do not* reassign a new list
|
149 |
-
self.outputs.clear()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/error.py
DELETED
@@ -1,60 +0,0 @@
|
|
1 |
-
# encoding: utf-8
|
2 |
-
"""
|
3 |
-
Global exception classes for IPython.core.
|
4 |
-
|
5 |
-
Authors:
|
6 |
-
|
7 |
-
* Brian Granger
|
8 |
-
* Fernando Perez
|
9 |
-
* Min Ragan-Kelley
|
10 |
-
|
11 |
-
Notes
|
12 |
-
-----
|
13 |
-
"""
|
14 |
-
|
15 |
-
#-----------------------------------------------------------------------------
|
16 |
-
# Copyright (C) 2008 The IPython Development Team
|
17 |
-
#
|
18 |
-
# Distributed under the terms of the BSD License. The full license is in
|
19 |
-
# the file COPYING, distributed as part of this software.
|
20 |
-
#-----------------------------------------------------------------------------
|
21 |
-
|
22 |
-
#-----------------------------------------------------------------------------
|
23 |
-
# Imports
|
24 |
-
#-----------------------------------------------------------------------------
|
25 |
-
|
26 |
-
#-----------------------------------------------------------------------------
|
27 |
-
# Exception classes
|
28 |
-
#-----------------------------------------------------------------------------
|
29 |
-
|
30 |
-
class IPythonCoreError(Exception):
|
31 |
-
pass
|
32 |
-
|
33 |
-
|
34 |
-
class TryNext(IPythonCoreError):
|
35 |
-
"""Try next hook exception.
|
36 |
-
|
37 |
-
Raise this in your hook function to indicate that the next hook handler
|
38 |
-
should be used to handle the operation.
|
39 |
-
"""
|
40 |
-
|
41 |
-
class UsageError(IPythonCoreError):
|
42 |
-
"""Error in magic function arguments, etc.
|
43 |
-
|
44 |
-
Something that probably won't warrant a full traceback, but should
|
45 |
-
nevertheless interrupt a macro / batch file.
|
46 |
-
"""
|
47 |
-
|
48 |
-
class StdinNotImplementedError(IPythonCoreError, NotImplementedError):
|
49 |
-
"""raw_input was requested in a context where it is not supported
|
50 |
-
|
51 |
-
For use in IPython kernels, where only some frontends may support
|
52 |
-
stdin requests.
|
53 |
-
"""
|
54 |
-
|
55 |
-
class InputRejected(Exception):
|
56 |
-
"""Input rejected by ast transformer.
|
57 |
-
|
58 |
-
Raise this in your NodeTransformer to indicate that InteractiveShell should
|
59 |
-
not execute the supplied input.
|
60 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/events.py
DELETED
@@ -1,158 +0,0 @@
|
|
1 |
-
"""Infrastructure for registering and firing callbacks on application events.
|
2 |
-
|
3 |
-
Unlike :mod:`IPython.core.hooks`, which lets end users set single functions to
|
4 |
-
be called at specific times, or a collection of alternative methods to try,
|
5 |
-
callbacks are designed to be used by extension authors. A number of callbacks
|
6 |
-
can be registered for the same event without needing to be aware of one another.
|
7 |
-
|
8 |
-
The functions defined in this module are no-ops indicating the names of available
|
9 |
-
events and the arguments which will be passed to them.
|
10 |
-
|
11 |
-
.. note::
|
12 |
-
|
13 |
-
This API is experimental in IPython 2.0, and may be revised in future versions.
|
14 |
-
"""
|
15 |
-
|
16 |
-
|
17 |
-
class EventManager(object):
|
18 |
-
"""Manage a collection of events and a sequence of callbacks for each.
|
19 |
-
|
20 |
-
This is attached to :class:`~IPython.core.interactiveshell.InteractiveShell`
|
21 |
-
instances as an ``events`` attribute.
|
22 |
-
|
23 |
-
.. note::
|
24 |
-
|
25 |
-
This API is experimental in IPython 2.0, and may be revised in future versions.
|
26 |
-
"""
|
27 |
-
|
28 |
-
def __init__(self, shell, available_events, print_on_error=True):
|
29 |
-
"""Initialise the :class:`CallbackManager`.
|
30 |
-
|
31 |
-
Parameters
|
32 |
-
----------
|
33 |
-
shell
|
34 |
-
The :class:`~IPython.core.interactiveshell.InteractiveShell` instance
|
35 |
-
available_events
|
36 |
-
An iterable of names for callback events.
|
37 |
-
print_on_error:
|
38 |
-
A boolean flag to set whether the EventManager will print a warning which a event errors.
|
39 |
-
"""
|
40 |
-
self.shell = shell
|
41 |
-
self.callbacks = {n:[] for n in available_events}
|
42 |
-
self.print_on_error = print_on_error
|
43 |
-
|
44 |
-
def register(self, event, function):
|
45 |
-
"""Register a new event callback.
|
46 |
-
|
47 |
-
Parameters
|
48 |
-
----------
|
49 |
-
event : str
|
50 |
-
The event for which to register this callback.
|
51 |
-
function : callable
|
52 |
-
A function to be called on the given event. It should take the same
|
53 |
-
parameters as the appropriate callback prototype.
|
54 |
-
|
55 |
-
Raises
|
56 |
-
------
|
57 |
-
TypeError
|
58 |
-
If ``function`` is not callable.
|
59 |
-
KeyError
|
60 |
-
If ``event`` is not one of the known events.
|
61 |
-
"""
|
62 |
-
if not callable(function):
|
63 |
-
raise TypeError('Need a callable, got %r' % function)
|
64 |
-
if function not in self.callbacks[event]:
|
65 |
-
self.callbacks[event].append(function)
|
66 |
-
|
67 |
-
def unregister(self, event, function):
|
68 |
-
"""Remove a callback from the given event."""
|
69 |
-
if function in self.callbacks[event]:
|
70 |
-
return self.callbacks[event].remove(function)
|
71 |
-
|
72 |
-
raise ValueError('Function {!r} is not registered as a {} callback'.format(function, event))
|
73 |
-
|
74 |
-
def trigger(self, event, *args, **kwargs):
|
75 |
-
"""Call callbacks for ``event``.
|
76 |
-
|
77 |
-
Any additional arguments are passed to all callbacks registered for this
|
78 |
-
event. Exceptions raised by callbacks are caught, and a message printed.
|
79 |
-
"""
|
80 |
-
for func in self.callbacks[event][:]:
|
81 |
-
try:
|
82 |
-
func(*args, **kwargs)
|
83 |
-
except (Exception, KeyboardInterrupt):
|
84 |
-
if self.print_on_error:
|
85 |
-
print(
|
86 |
-
"Error in callback {} (for {}), with arguments args {},kwargs {}:".format(
|
87 |
-
func, event, args, kwargs
|
88 |
-
)
|
89 |
-
)
|
90 |
-
self.shell.showtraceback()
|
91 |
-
|
92 |
-
# event_name -> prototype mapping
|
93 |
-
available_events = {}
|
94 |
-
|
95 |
-
def _define_event(callback_function):
|
96 |
-
available_events[callback_function.__name__] = callback_function
|
97 |
-
return callback_function
|
98 |
-
|
99 |
-
# ------------------------------------------------------------------------------
|
100 |
-
# Callback prototypes
|
101 |
-
#
|
102 |
-
# No-op functions which describe the names of available events and the
|
103 |
-
# signatures of callbacks for those events.
|
104 |
-
# ------------------------------------------------------------------------------
|
105 |
-
|
106 |
-
@_define_event
|
107 |
-
def pre_execute():
|
108 |
-
"""Fires before code is executed in response to user/frontend action.
|
109 |
-
|
110 |
-
This includes comm and widget messages and silent execution, as well as user
|
111 |
-
code cells.
|
112 |
-
"""
|
113 |
-
pass
|
114 |
-
|
115 |
-
@_define_event
|
116 |
-
def pre_run_cell(info):
|
117 |
-
"""Fires before user-entered code runs.
|
118 |
-
|
119 |
-
Parameters
|
120 |
-
----------
|
121 |
-
info : :class:`~IPython.core.interactiveshell.ExecutionInfo`
|
122 |
-
An object containing information used for the code execution.
|
123 |
-
"""
|
124 |
-
pass
|
125 |
-
|
126 |
-
@_define_event
|
127 |
-
def post_execute():
|
128 |
-
"""Fires after code is executed in response to user/frontend action.
|
129 |
-
|
130 |
-
This includes comm and widget messages and silent execution, as well as user
|
131 |
-
code cells.
|
132 |
-
"""
|
133 |
-
pass
|
134 |
-
|
135 |
-
@_define_event
|
136 |
-
def post_run_cell(result):
|
137 |
-
"""Fires after user-entered code runs.
|
138 |
-
|
139 |
-
Parameters
|
140 |
-
----------
|
141 |
-
result : :class:`~IPython.core.interactiveshell.ExecutionResult`
|
142 |
-
The object which will be returned as the execution result.
|
143 |
-
"""
|
144 |
-
pass
|
145 |
-
|
146 |
-
@_define_event
|
147 |
-
def shell_initialized(ip):
|
148 |
-
"""Fires after initialisation of :class:`~IPython.core.interactiveshell.InteractiveShell`.
|
149 |
-
|
150 |
-
This is before extensions and startup scripts are loaded, so it can only be
|
151 |
-
set by subclassing.
|
152 |
-
|
153 |
-
Parameters
|
154 |
-
----------
|
155 |
-
ip : :class:`~IPython.core.interactiveshell.InteractiveShell`
|
156 |
-
The newly initialised shell.
|
157 |
-
"""
|
158 |
-
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/excolors.py
DELETED
@@ -1,192 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
"""
|
3 |
-
Color schemes for exception handling code in IPython.
|
4 |
-
"""
|
5 |
-
|
6 |
-
import os
|
7 |
-
|
8 |
-
#*****************************************************************************
|
9 |
-
# Copyright (C) 2005-2006 Fernando Perez <[email protected]>
|
10 |
-
#
|
11 |
-
# Distributed under the terms of the BSD License. The full license is in
|
12 |
-
# the file COPYING, distributed as part of this software.
|
13 |
-
#*****************************************************************************
|
14 |
-
|
15 |
-
from IPython.utils.coloransi import ColorSchemeTable, TermColors, ColorScheme
|
16 |
-
|
17 |
-
def exception_colors():
|
18 |
-
"""Return a color table with fields for exception reporting.
|
19 |
-
|
20 |
-
The table is an instance of ColorSchemeTable with schemes added for
|
21 |
-
'Neutral', 'Linux', 'LightBG' and 'NoColor' and fields for exception handling filled
|
22 |
-
in.
|
23 |
-
|
24 |
-
Examples:
|
25 |
-
|
26 |
-
>>> ec = exception_colors()
|
27 |
-
>>> ec.active_scheme_name
|
28 |
-
''
|
29 |
-
>>> print(ec.active_colors)
|
30 |
-
None
|
31 |
-
|
32 |
-
Now we activate a color scheme:
|
33 |
-
>>> ec.set_active_scheme('NoColor')
|
34 |
-
>>> ec.active_scheme_name
|
35 |
-
'NoColor'
|
36 |
-
>>> sorted(ec.active_colors.keys())
|
37 |
-
['Normal', 'breakpoint_disabled', 'breakpoint_enabled', 'caret', 'em',
|
38 |
-
'excName', 'filename', 'filenameEm', 'line', 'lineno', 'linenoEm', 'name',
|
39 |
-
'nameEm', 'normalEm', 'prompt', 'topline', 'vName', 'val', 'valEm']
|
40 |
-
|
41 |
-
"""
|
42 |
-
|
43 |
-
ex_colors = ColorSchemeTable()
|
44 |
-
|
45 |
-
# Populate it with color schemes
|
46 |
-
C = TermColors # shorthand and local lookup
|
47 |
-
ex_colors.add_scheme(
|
48 |
-
ColorScheme(
|
49 |
-
"NoColor",
|
50 |
-
{
|
51 |
-
# The color to be used for the top line
|
52 |
-
"topline": C.NoColor,
|
53 |
-
|
54 |
-
# The colors to be used in the traceback
|
55 |
-
"filename": C.NoColor,
|
56 |
-
"lineno": C.NoColor,
|
57 |
-
"name": C.NoColor,
|
58 |
-
"vName": C.NoColor,
|
59 |
-
"val": C.NoColor,
|
60 |
-
"em": C.NoColor,
|
61 |
-
|
62 |
-
# Emphasized colors for the last frame of the traceback
|
63 |
-
"normalEm": C.NoColor,
|
64 |
-
"filenameEm": C.NoColor,
|
65 |
-
"linenoEm": C.NoColor,
|
66 |
-
"nameEm": C.NoColor,
|
67 |
-
"valEm": C.NoColor,
|
68 |
-
|
69 |
-
# Colors for printing the exception
|
70 |
-
"excName": C.NoColor,
|
71 |
-
"line": C.NoColor,
|
72 |
-
"caret": C.NoColor,
|
73 |
-
"Normal": C.NoColor,
|
74 |
-
# debugger
|
75 |
-
"prompt": C.NoColor,
|
76 |
-
"breakpoint_enabled": C.NoColor,
|
77 |
-
"breakpoint_disabled": C.NoColor,
|
78 |
-
},
|
79 |
-
)
|
80 |
-
)
|
81 |
-
|
82 |
-
# make some schemes as instances so we can copy them for modification easily
|
83 |
-
ex_colors.add_scheme(
|
84 |
-
ColorScheme(
|
85 |
-
"Linux",
|
86 |
-
{
|
87 |
-
# The color to be used for the top line
|
88 |
-
"topline": C.LightRed,
|
89 |
-
# The colors to be used in the traceback
|
90 |
-
"filename": C.Green,
|
91 |
-
"lineno": C.Green,
|
92 |
-
"name": C.Purple,
|
93 |
-
"vName": C.Cyan,
|
94 |
-
"val": C.Green,
|
95 |
-
"em": C.LightCyan,
|
96 |
-
# Emphasized colors for the last frame of the traceback
|
97 |
-
"normalEm": C.LightCyan,
|
98 |
-
"filenameEm": C.LightGreen,
|
99 |
-
"linenoEm": C.LightGreen,
|
100 |
-
"nameEm": C.LightPurple,
|
101 |
-
"valEm": C.LightBlue,
|
102 |
-
# Colors for printing the exception
|
103 |
-
"excName": C.LightRed,
|
104 |
-
"line": C.Yellow,
|
105 |
-
"caret": C.White,
|
106 |
-
"Normal": C.Normal,
|
107 |
-
# debugger
|
108 |
-
"prompt": C.Green,
|
109 |
-
"breakpoint_enabled": C.LightRed,
|
110 |
-
"breakpoint_disabled": C.Red,
|
111 |
-
},
|
112 |
-
)
|
113 |
-
)
|
114 |
-
|
115 |
-
# For light backgrounds, swap dark/light colors
|
116 |
-
ex_colors.add_scheme(
|
117 |
-
ColorScheme(
|
118 |
-
"LightBG",
|
119 |
-
{
|
120 |
-
# The color to be used for the top line
|
121 |
-
"topline": C.Red,
|
122 |
-
|
123 |
-
# The colors to be used in the traceback
|
124 |
-
"filename": C.LightGreen,
|
125 |
-
"lineno": C.LightGreen,
|
126 |
-
"name": C.LightPurple,
|
127 |
-
"vName": C.Cyan,
|
128 |
-
"val": C.LightGreen,
|
129 |
-
"em": C.Cyan,
|
130 |
-
|
131 |
-
# Emphasized colors for the last frame of the traceback
|
132 |
-
"normalEm": C.Cyan,
|
133 |
-
"filenameEm": C.Green,
|
134 |
-
"linenoEm": C.Green,
|
135 |
-
"nameEm": C.Purple,
|
136 |
-
"valEm": C.Blue,
|
137 |
-
|
138 |
-
# Colors for printing the exception
|
139 |
-
"excName": C.Red,
|
140 |
-
# "line": C.Brown, # brown often is displayed as yellow
|
141 |
-
"line": C.Red,
|
142 |
-
"caret": C.Normal,
|
143 |
-
"Normal": C.Normal,
|
144 |
-
# debugger
|
145 |
-
"prompt": C.Blue,
|
146 |
-
"breakpoint_enabled": C.LightRed,
|
147 |
-
"breakpoint_disabled": C.Red,
|
148 |
-
},
|
149 |
-
)
|
150 |
-
)
|
151 |
-
|
152 |
-
ex_colors.add_scheme(
|
153 |
-
ColorScheme(
|
154 |
-
"Neutral",
|
155 |
-
{
|
156 |
-
# The color to be used for the top line
|
157 |
-
"topline": C.Red,
|
158 |
-
# The colors to be used in the traceback
|
159 |
-
"filename": C.LightGreen,
|
160 |
-
"lineno": C.LightGreen,
|
161 |
-
"name": C.LightPurple,
|
162 |
-
"vName": C.Cyan,
|
163 |
-
"val": C.LightGreen,
|
164 |
-
"em": C.Cyan,
|
165 |
-
# Emphasized colors for the last frame of the traceback
|
166 |
-
"normalEm": C.Cyan,
|
167 |
-
"filenameEm": C.Green,
|
168 |
-
"linenoEm": C.Green,
|
169 |
-
"nameEm": C.Purple,
|
170 |
-
"valEm": C.Blue,
|
171 |
-
# Colors for printing the exception
|
172 |
-
"excName": C.Red,
|
173 |
-
# line = C.Brown, # brown often is displayed as yellow
|
174 |
-
"line": C.Red,
|
175 |
-
"caret": C.Normal,
|
176 |
-
"Normal": C.Normal,
|
177 |
-
# debugger
|
178 |
-
"prompt": C.Blue,
|
179 |
-
"breakpoint_enabled": C.LightRed,
|
180 |
-
"breakpoint_disabled": C.Red,
|
181 |
-
},
|
182 |
-
)
|
183 |
-
)
|
184 |
-
|
185 |
-
# Hack: the 'neutral' colours are not very visible on a dark background on
|
186 |
-
# Windows. Since Windows command prompts have a dark background by default, and
|
187 |
-
# relatively few users are likely to alter that, we will use the 'Linux' colours,
|
188 |
-
# designed for a dark background, as the default on Windows.
|
189 |
-
if os.name == "nt":
|
190 |
-
ex_colors.add_scheme(ex_colors['Linux'].copy('Neutral'))
|
191 |
-
|
192 |
-
return ex_colors
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/extensions.py
DELETED
@@ -1,135 +0,0 @@
|
|
1 |
-
# encoding: utf-8
|
2 |
-
"""A class for managing IPython extensions."""
|
3 |
-
|
4 |
-
# Copyright (c) IPython Development Team.
|
5 |
-
# Distributed under the terms of the Modified BSD License.
|
6 |
-
|
7 |
-
import os
|
8 |
-
import os.path
|
9 |
-
import sys
|
10 |
-
from importlib import import_module, reload
|
11 |
-
|
12 |
-
from traitlets.config.configurable import Configurable
|
13 |
-
from IPython.utils.path import ensure_dir_exists
|
14 |
-
from traitlets import Instance
|
15 |
-
|
16 |
-
|
17 |
-
#-----------------------------------------------------------------------------
|
18 |
-
# Main class
|
19 |
-
#-----------------------------------------------------------------------------
|
20 |
-
|
21 |
-
BUILTINS_EXTS = {"storemagic": False, "autoreload": False}
|
22 |
-
|
23 |
-
|
24 |
-
class ExtensionManager(Configurable):
|
25 |
-
"""A class to manage IPython extensions.
|
26 |
-
|
27 |
-
An IPython extension is an importable Python module that has
|
28 |
-
a function with the signature::
|
29 |
-
|
30 |
-
def load_ipython_extension(ipython):
|
31 |
-
# Do things with ipython
|
32 |
-
|
33 |
-
This function is called after your extension is imported and the
|
34 |
-
currently active :class:`InteractiveShell` instance is passed as
|
35 |
-
the only argument. You can do anything you want with IPython at
|
36 |
-
that point, including defining new magic and aliases, adding new
|
37 |
-
components, etc.
|
38 |
-
|
39 |
-
You can also optionally define an :func:`unload_ipython_extension(ipython)`
|
40 |
-
function, which will be called if the user unloads or reloads the extension.
|
41 |
-
The extension manager will only call :func:`load_ipython_extension` again
|
42 |
-
if the extension is reloaded.
|
43 |
-
|
44 |
-
You can put your extension modules anywhere you want, as long as
|
45 |
-
they can be imported by Python's standard import mechanism.
|
46 |
-
"""
|
47 |
-
|
48 |
-
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
|
49 |
-
|
50 |
-
def __init__(self, shell=None, **kwargs):
|
51 |
-
super(ExtensionManager, self).__init__(shell=shell, **kwargs)
|
52 |
-
self.loaded = set()
|
53 |
-
|
54 |
-
def load_extension(self, module_str: str):
|
55 |
-
"""Load an IPython extension by its module name.
|
56 |
-
|
57 |
-
Returns the string "already loaded" if the extension is already loaded,
|
58 |
-
"no load function" if the module doesn't have a load_ipython_extension
|
59 |
-
function, or None if it succeeded.
|
60 |
-
"""
|
61 |
-
try:
|
62 |
-
return self._load_extension(module_str)
|
63 |
-
except ModuleNotFoundError:
|
64 |
-
if module_str in BUILTINS_EXTS:
|
65 |
-
BUILTINS_EXTS[module_str] = True
|
66 |
-
return self._load_extension("IPython.extensions." + module_str)
|
67 |
-
raise
|
68 |
-
|
69 |
-
def _load_extension(self, module_str: str):
|
70 |
-
if module_str in self.loaded:
|
71 |
-
return "already loaded"
|
72 |
-
|
73 |
-
assert self.shell is not None
|
74 |
-
|
75 |
-
with self.shell.builtin_trap:
|
76 |
-
if module_str not in sys.modules:
|
77 |
-
mod = import_module(module_str)
|
78 |
-
mod = sys.modules[module_str]
|
79 |
-
if self._call_load_ipython_extension(mod):
|
80 |
-
self.loaded.add(module_str)
|
81 |
-
else:
|
82 |
-
return "no load function"
|
83 |
-
|
84 |
-
def unload_extension(self, module_str: str):
|
85 |
-
"""Unload an IPython extension by its module name.
|
86 |
-
|
87 |
-
This function looks up the extension's name in ``sys.modules`` and
|
88 |
-
simply calls ``mod.unload_ipython_extension(self)``.
|
89 |
-
|
90 |
-
Returns the string "no unload function" if the extension doesn't define
|
91 |
-
a function to unload itself, "not loaded" if the extension isn't loaded,
|
92 |
-
otherwise None.
|
93 |
-
"""
|
94 |
-
if BUILTINS_EXTS.get(module_str, False) is True:
|
95 |
-
module_str = "IPython.extensions." + module_str
|
96 |
-
if module_str not in self.loaded:
|
97 |
-
return "not loaded"
|
98 |
-
|
99 |
-
if module_str in sys.modules:
|
100 |
-
mod = sys.modules[module_str]
|
101 |
-
if self._call_unload_ipython_extension(mod):
|
102 |
-
self.loaded.discard(module_str)
|
103 |
-
else:
|
104 |
-
return "no unload function"
|
105 |
-
|
106 |
-
def reload_extension(self, module_str: str):
|
107 |
-
"""Reload an IPython extension by calling reload.
|
108 |
-
|
109 |
-
If the module has not been loaded before,
|
110 |
-
:meth:`InteractiveShell.load_extension` is called. Otherwise
|
111 |
-
:func:`reload` is called and then the :func:`load_ipython_extension`
|
112 |
-
function of the module, if it exists is called.
|
113 |
-
"""
|
114 |
-
|
115 |
-
if BUILTINS_EXTS.get(module_str, False) is True:
|
116 |
-
module_str = "IPython.extensions." + module_str
|
117 |
-
|
118 |
-
if (module_str in self.loaded) and (module_str in sys.modules):
|
119 |
-
self.unload_extension(module_str)
|
120 |
-
mod = sys.modules[module_str]
|
121 |
-
reload(mod)
|
122 |
-
if self._call_load_ipython_extension(mod):
|
123 |
-
self.loaded.add(module_str)
|
124 |
-
else:
|
125 |
-
self.load_extension(module_str)
|
126 |
-
|
127 |
-
def _call_load_ipython_extension(self, mod):
|
128 |
-
if hasattr(mod, 'load_ipython_extension'):
|
129 |
-
mod.load_ipython_extension(self.shell)
|
130 |
-
return True
|
131 |
-
|
132 |
-
def _call_unload_ipython_extension(self, mod):
|
133 |
-
if hasattr(mod, 'unload_ipython_extension'):
|
134 |
-
mod.unload_ipython_extension(self.shell)
|
135 |
-
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/formatters.py
DELETED
@@ -1,1090 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
"""Display formatters.
|
3 |
-
|
4 |
-
This module defines the base instances in order to implement custom
|
5 |
-
formatters/mimetypes
|
6 |
-
got objects:
|
7 |
-
|
8 |
-
As we want to see internal IPython working we are going to use the following
|
9 |
-
function to diaply objects instead of the normal print or display method:
|
10 |
-
|
11 |
-
>>> ip = get_ipython()
|
12 |
-
>>> ip.display_formatter.format(...)
|
13 |
-
({'text/plain': 'Ellipsis'}, {})
|
14 |
-
|
15 |
-
This return a tuple with the mimebumdle for the current object, and the
|
16 |
-
associated metadata.
|
17 |
-
|
18 |
-
|
19 |
-
We can now define our own formatter and register it:
|
20 |
-
|
21 |
-
|
22 |
-
>>> from IPython.core.formatters import BaseFormatter, FormatterABC
|
23 |
-
|
24 |
-
|
25 |
-
>>> class LLMFormatter(BaseFormatter):
|
26 |
-
...
|
27 |
-
... format_type = 'x-vendor/llm'
|
28 |
-
... print_method = '_repr_llm_'
|
29 |
-
... _return_type = (dict, str)
|
30 |
-
|
31 |
-
>>> llm_formatter = LLMFormatter(parent=ip.display_formatter)
|
32 |
-
|
33 |
-
>>> ip.display_formatter.formatters[LLMFormatter.format_type] = llm_formatter
|
34 |
-
|
35 |
-
Now any class that define `_repr_llm_` will return a x-vendor/llm as part of
|
36 |
-
it's display data:
|
37 |
-
|
38 |
-
>>> class A:
|
39 |
-
...
|
40 |
-
... def _repr_llm_(self, *kwargs):
|
41 |
-
... return 'This a A'
|
42 |
-
...
|
43 |
-
|
44 |
-
>>> ip.display_formatter.format(A())
|
45 |
-
({'text/plain': '<IPython.core.formatters.A at ...>', 'x-vendor/llm': 'This a A'}, {})
|
46 |
-
|
47 |
-
As usual, you can register methods for third party types (see
|
48 |
-
:ref:`third_party_formatting`)
|
49 |
-
|
50 |
-
>>> def llm_int(obj):
|
51 |
-
... return 'This is the integer %s, in between %s and %s'%(obj, obj-1, obj+1)
|
52 |
-
|
53 |
-
>>> llm_formatter.for_type(int, llm_int)
|
54 |
-
|
55 |
-
>>> ip.display_formatter.format(42)
|
56 |
-
({'text/plain': '42', 'x-vendor/llm': 'This is the integer 42, in between 41 and 43'}, {})
|
57 |
-
|
58 |
-
|
59 |
-
Inheritance diagram:
|
60 |
-
|
61 |
-
.. inheritance-diagram:: IPython.core.formatters
|
62 |
-
:parts: 3
|
63 |
-
"""
|
64 |
-
|
65 |
-
# Copyright (c) IPython Development Team.
|
66 |
-
# Distributed under the terms of the Modified BSD License.
|
67 |
-
|
68 |
-
import abc
|
69 |
-
import sys
|
70 |
-
import traceback
|
71 |
-
import warnings
|
72 |
-
from io import StringIO
|
73 |
-
|
74 |
-
from decorator import decorator
|
75 |
-
|
76 |
-
from traitlets.config.configurable import Configurable
|
77 |
-
from .getipython import get_ipython
|
78 |
-
from ..utils.sentinel import Sentinel
|
79 |
-
from ..utils.dir2 import get_real_method
|
80 |
-
from ..lib import pretty
|
81 |
-
from traitlets import (
|
82 |
-
Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
|
83 |
-
ForwardDeclaredInstance,
|
84 |
-
default, observe,
|
85 |
-
)
|
86 |
-
|
87 |
-
from typing import Any
|
88 |
-
|
89 |
-
|
90 |
-
class DisplayFormatter(Configurable):
|
91 |
-
|
92 |
-
active_types = List(Unicode(),
|
93 |
-
help="""List of currently active mime-types to display.
|
94 |
-
You can use this to set a white-list for formats to display.
|
95 |
-
|
96 |
-
Most users will not need to change this value.
|
97 |
-
""",
|
98 |
-
).tag(config=True)
|
99 |
-
|
100 |
-
@default('active_types')
|
101 |
-
def _active_types_default(self):
|
102 |
-
return self.format_types
|
103 |
-
|
104 |
-
@observe('active_types')
|
105 |
-
def _active_types_changed(self, change):
|
106 |
-
for key, formatter in self.formatters.items():
|
107 |
-
if key in change['new']:
|
108 |
-
formatter.enabled = True
|
109 |
-
else:
|
110 |
-
formatter.enabled = False
|
111 |
-
|
112 |
-
ipython_display_formatter = ForwardDeclaredInstance("FormatterABC") # type: ignore
|
113 |
-
|
114 |
-
@default("ipython_display_formatter")
|
115 |
-
def _default_formatter(self):
|
116 |
-
return IPythonDisplayFormatter(parent=self)
|
117 |
-
|
118 |
-
mimebundle_formatter = ForwardDeclaredInstance("FormatterABC") # type: ignore
|
119 |
-
|
120 |
-
@default("mimebundle_formatter")
|
121 |
-
def _default_mime_formatter(self):
|
122 |
-
return MimeBundleFormatter(parent=self)
|
123 |
-
|
124 |
-
# A dict of formatter whose keys are format types (MIME types) and whose
|
125 |
-
# values are subclasses of BaseFormatter.
|
126 |
-
formatters = Dict()
|
127 |
-
|
128 |
-
@default("formatters")
|
129 |
-
def _formatters_default(self):
|
130 |
-
"""Activate the default formatters."""
|
131 |
-
formatter_classes = [
|
132 |
-
PlainTextFormatter,
|
133 |
-
HTMLFormatter,
|
134 |
-
MarkdownFormatter,
|
135 |
-
SVGFormatter,
|
136 |
-
PNGFormatter,
|
137 |
-
PDFFormatter,
|
138 |
-
JPEGFormatter,
|
139 |
-
LatexFormatter,
|
140 |
-
JSONFormatter,
|
141 |
-
JavascriptFormatter
|
142 |
-
]
|
143 |
-
d = {}
|
144 |
-
for cls in formatter_classes:
|
145 |
-
f = cls(parent=self)
|
146 |
-
d[f.format_type] = f
|
147 |
-
return d
|
148 |
-
|
149 |
-
def format(self, obj, include=None, exclude=None):
|
150 |
-
"""Return a format data dict for an object.
|
151 |
-
|
152 |
-
By default all format types will be computed.
|
153 |
-
|
154 |
-
The following MIME types are usually implemented:
|
155 |
-
|
156 |
-
* text/plain
|
157 |
-
* text/html
|
158 |
-
* text/markdown
|
159 |
-
* text/latex
|
160 |
-
* application/json
|
161 |
-
* application/javascript
|
162 |
-
* application/pdf
|
163 |
-
* image/png
|
164 |
-
* image/jpeg
|
165 |
-
* image/svg+xml
|
166 |
-
|
167 |
-
Parameters
|
168 |
-
----------
|
169 |
-
obj : object
|
170 |
-
The Python object whose format data will be computed.
|
171 |
-
include : list, tuple or set; optional
|
172 |
-
A list of format type strings (MIME types) to include in the
|
173 |
-
format data dict. If this is set *only* the format types included
|
174 |
-
in this list will be computed.
|
175 |
-
exclude : list, tuple or set; optional
|
176 |
-
A list of format type string (MIME types) to exclude in the format
|
177 |
-
data dict. If this is set all format types will be computed,
|
178 |
-
except for those included in this argument.
|
179 |
-
Mimetypes present in exclude will take precedence over the ones in include
|
180 |
-
|
181 |
-
Returns
|
182 |
-
-------
|
183 |
-
(format_dict, metadata_dict) : tuple of two dicts
|
184 |
-
format_dict is a dictionary of key/value pairs, one of each format that was
|
185 |
-
generated for the object. The keys are the format types, which
|
186 |
-
will usually be MIME type strings and the values and JSON'able
|
187 |
-
data structure containing the raw data for the representation in
|
188 |
-
that format.
|
189 |
-
|
190 |
-
metadata_dict is a dictionary of metadata about each mime-type output.
|
191 |
-
Its keys will be a strict subset of the keys in format_dict.
|
192 |
-
|
193 |
-
Notes
|
194 |
-
-----
|
195 |
-
If an object implement `_repr_mimebundle_` as well as various
|
196 |
-
`_repr_*_`, the data returned by `_repr_mimebundle_` will take
|
197 |
-
precedence and the corresponding `_repr_*_` for this mimetype will
|
198 |
-
not be called.
|
199 |
-
|
200 |
-
"""
|
201 |
-
format_dict = {}
|
202 |
-
md_dict = {}
|
203 |
-
|
204 |
-
if self.ipython_display_formatter(obj):
|
205 |
-
# object handled itself, don't proceed
|
206 |
-
return {}, {}
|
207 |
-
|
208 |
-
format_dict, md_dict = self.mimebundle_formatter(obj, include=include, exclude=exclude)
|
209 |
-
|
210 |
-
if format_dict or md_dict:
|
211 |
-
if include:
|
212 |
-
format_dict = {k:v for k,v in format_dict.items() if k in include}
|
213 |
-
md_dict = {k:v for k,v in md_dict.items() if k in include}
|
214 |
-
if exclude:
|
215 |
-
format_dict = {k:v for k,v in format_dict.items() if k not in exclude}
|
216 |
-
md_dict = {k:v for k,v in md_dict.items() if k not in exclude}
|
217 |
-
|
218 |
-
for format_type, formatter in self.formatters.items():
|
219 |
-
if format_type in format_dict:
|
220 |
-
# already got it from mimebundle, maybe don't render again.
|
221 |
-
# exception: manually registered per-mime renderer
|
222 |
-
# check priority:
|
223 |
-
# 1. user-registered per-mime formatter
|
224 |
-
# 2. mime-bundle (user-registered or repr method)
|
225 |
-
# 3. default per-mime formatter (e.g. repr method)
|
226 |
-
try:
|
227 |
-
formatter.lookup(obj)
|
228 |
-
except KeyError:
|
229 |
-
# no special formatter, use mime-bundle-provided value
|
230 |
-
continue
|
231 |
-
if include and format_type not in include:
|
232 |
-
continue
|
233 |
-
if exclude and format_type in exclude:
|
234 |
-
continue
|
235 |
-
|
236 |
-
md = None
|
237 |
-
try:
|
238 |
-
data = formatter(obj)
|
239 |
-
except:
|
240 |
-
# FIXME: log the exception
|
241 |
-
raise
|
242 |
-
|
243 |
-
# formatters can return raw data or (data, metadata)
|
244 |
-
if isinstance(data, tuple) and len(data) == 2:
|
245 |
-
data, md = data
|
246 |
-
|
247 |
-
if data is not None:
|
248 |
-
format_dict[format_type] = data
|
249 |
-
if md is not None:
|
250 |
-
md_dict[format_type] = md
|
251 |
-
return format_dict, md_dict
|
252 |
-
|
253 |
-
@property
|
254 |
-
def format_types(self):
|
255 |
-
"""Return the format types (MIME types) of the active formatters."""
|
256 |
-
return list(self.formatters.keys())
|
257 |
-
|
258 |
-
|
259 |
-
#-----------------------------------------------------------------------------
|
260 |
-
# Formatters for specific format types (text, html, svg, etc.)
|
261 |
-
#-----------------------------------------------------------------------------
|
262 |
-
|
263 |
-
|
264 |
-
def _safe_repr(obj):
|
265 |
-
"""Try to return a repr of an object
|
266 |
-
|
267 |
-
always returns a string, at least.
|
268 |
-
"""
|
269 |
-
try:
|
270 |
-
return repr(obj)
|
271 |
-
except Exception as e:
|
272 |
-
return "un-repr-able object (%r)" % e
|
273 |
-
|
274 |
-
|
275 |
-
class FormatterWarning(UserWarning):
|
276 |
-
"""Warning class for errors in formatters"""
|
277 |
-
|
278 |
-
@decorator
|
279 |
-
def catch_format_error(method, self, *args, **kwargs):
|
280 |
-
"""show traceback on failed format call"""
|
281 |
-
try:
|
282 |
-
r = method(self, *args, **kwargs)
|
283 |
-
except NotImplementedError:
|
284 |
-
# don't warn on NotImplementedErrors
|
285 |
-
return self._check_return(None, args[0])
|
286 |
-
except Exception:
|
287 |
-
exc_info = sys.exc_info()
|
288 |
-
ip = get_ipython()
|
289 |
-
if ip is not None:
|
290 |
-
ip.showtraceback(exc_info)
|
291 |
-
else:
|
292 |
-
traceback.print_exception(*exc_info)
|
293 |
-
return self._check_return(None, args[0])
|
294 |
-
return self._check_return(r, args[0])
|
295 |
-
|
296 |
-
|
297 |
-
class FormatterABC(metaclass=abc.ABCMeta):
|
298 |
-
""" Abstract base class for Formatters.
|
299 |
-
|
300 |
-
A formatter is a callable class that is responsible for computing the
|
301 |
-
raw format data for a particular format type (MIME type). For example,
|
302 |
-
an HTML formatter would have a format type of `text/html` and would return
|
303 |
-
the HTML representation of the object when called.
|
304 |
-
"""
|
305 |
-
|
306 |
-
# The format type of the data returned, usually a MIME type.
|
307 |
-
format_type = 'text/plain'
|
308 |
-
|
309 |
-
# Is the formatter enabled...
|
310 |
-
enabled = True
|
311 |
-
|
312 |
-
@abc.abstractmethod
|
313 |
-
def __call__(self, obj):
|
314 |
-
"""Return a JSON'able representation of the object.
|
315 |
-
|
316 |
-
If the object cannot be formatted by this formatter,
|
317 |
-
warn and return None.
|
318 |
-
"""
|
319 |
-
return repr(obj)
|
320 |
-
|
321 |
-
|
322 |
-
def _mod_name_key(typ):
|
323 |
-
"""Return a (__module__, __name__) tuple for a type.
|
324 |
-
|
325 |
-
Used as key in Formatter.deferred_printers.
|
326 |
-
"""
|
327 |
-
module = getattr(typ, '__module__', None)
|
328 |
-
name = getattr(typ, '__name__', None)
|
329 |
-
return (module, name)
|
330 |
-
|
331 |
-
|
332 |
-
def _get_type(obj):
|
333 |
-
"""Return the type of an instance (old and new-style)"""
|
334 |
-
return getattr(obj, '__class__', None) or type(obj)
|
335 |
-
|
336 |
-
|
337 |
-
_raise_key_error = Sentinel(
|
338 |
-
"_raise_key_error",
|
339 |
-
__name__,
|
340 |
-
"""
|
341 |
-
Special value to raise a KeyError
|
342 |
-
|
343 |
-
Raise KeyError in `BaseFormatter.pop` if passed as the default value to `pop`
|
344 |
-
""",
|
345 |
-
)
|
346 |
-
|
347 |
-
|
348 |
-
class BaseFormatter(Configurable):
|
349 |
-
"""A base formatter class that is configurable.
|
350 |
-
|
351 |
-
This formatter should usually be used as the base class of all formatters.
|
352 |
-
It is a traited :class:`Configurable` class and includes an extensible
|
353 |
-
API for users to determine how their objects are formatted. The following
|
354 |
-
logic is used to find a function to format an given object.
|
355 |
-
|
356 |
-
1. The object is introspected to see if it has a method with the name
|
357 |
-
:attr:`print_method`. If is does, that object is passed to that method
|
358 |
-
for formatting.
|
359 |
-
2. If no print method is found, three internal dictionaries are consulted
|
360 |
-
to find print method: :attr:`singleton_printers`, :attr:`type_printers`
|
361 |
-
and :attr:`deferred_printers`.
|
362 |
-
|
363 |
-
Users should use these dictionaries to register functions that will be
|
364 |
-
used to compute the format data for their objects (if those objects don't
|
365 |
-
have the special print methods). The easiest way of using these
|
366 |
-
dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
|
367 |
-
methods.
|
368 |
-
|
369 |
-
If no function/callable is found to compute the format data, ``None`` is
|
370 |
-
returned and this format type is not used.
|
371 |
-
"""
|
372 |
-
|
373 |
-
format_type = Unicode("text/plain")
|
374 |
-
_return_type: Any = str
|
375 |
-
|
376 |
-
enabled = Bool(True).tag(config=True)
|
377 |
-
|
378 |
-
print_method = ObjectName('__repr__')
|
379 |
-
|
380 |
-
# The singleton printers.
|
381 |
-
# Maps the IDs of the builtin singleton objects to the format functions.
|
382 |
-
singleton_printers = Dict().tag(config=True)
|
383 |
-
|
384 |
-
# The type-specific printers.
|
385 |
-
# Map type objects to the format functions.
|
386 |
-
type_printers = Dict().tag(config=True)
|
387 |
-
|
388 |
-
# The deferred-import type-specific printers.
|
389 |
-
# Map (modulename, classname) pairs to the format functions.
|
390 |
-
deferred_printers = Dict().tag(config=True)
|
391 |
-
|
392 |
-
@catch_format_error
|
393 |
-
def __call__(self, obj):
|
394 |
-
"""Compute the format for an object."""
|
395 |
-
if self.enabled:
|
396 |
-
# lookup registered printer
|
397 |
-
try:
|
398 |
-
printer = self.lookup(obj)
|
399 |
-
except KeyError:
|
400 |
-
pass
|
401 |
-
else:
|
402 |
-
return printer(obj)
|
403 |
-
# Finally look for special method names
|
404 |
-
method = get_real_method(obj, self.print_method)
|
405 |
-
if method is not None:
|
406 |
-
return method()
|
407 |
-
return None
|
408 |
-
else:
|
409 |
-
return None
|
410 |
-
|
411 |
-
def __contains__(self, typ):
|
412 |
-
"""map in to lookup_by_type"""
|
413 |
-
try:
|
414 |
-
self.lookup_by_type(typ)
|
415 |
-
except KeyError:
|
416 |
-
return False
|
417 |
-
else:
|
418 |
-
return True
|
419 |
-
|
420 |
-
def _check_return(self, r, obj):
|
421 |
-
"""Check that a return value is appropriate
|
422 |
-
|
423 |
-
Return the value if so, None otherwise, warning if invalid.
|
424 |
-
"""
|
425 |
-
if r is None or isinstance(r, self._return_type) or \
|
426 |
-
(isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
|
427 |
-
return r
|
428 |
-
else:
|
429 |
-
warnings.warn(
|
430 |
-
"%s formatter returned invalid type %s (expected %s) for object: %s" % \
|
431 |
-
(self.format_type, type(r), self._return_type, _safe_repr(obj)),
|
432 |
-
FormatterWarning
|
433 |
-
)
|
434 |
-
|
435 |
-
def lookup(self, obj):
|
436 |
-
"""Look up the formatter for a given instance.
|
437 |
-
|
438 |
-
Parameters
|
439 |
-
----------
|
440 |
-
obj : object instance
|
441 |
-
|
442 |
-
Returns
|
443 |
-
-------
|
444 |
-
f : callable
|
445 |
-
The registered formatting callable for the type.
|
446 |
-
|
447 |
-
Raises
|
448 |
-
------
|
449 |
-
KeyError if the type has not been registered.
|
450 |
-
"""
|
451 |
-
# look for singleton first
|
452 |
-
obj_id = id(obj)
|
453 |
-
if obj_id in self.singleton_printers:
|
454 |
-
return self.singleton_printers[obj_id]
|
455 |
-
# then lookup by type
|
456 |
-
return self.lookup_by_type(_get_type(obj))
|
457 |
-
|
458 |
-
def lookup_by_type(self, typ):
|
459 |
-
"""Look up the registered formatter for a type.
|
460 |
-
|
461 |
-
Parameters
|
462 |
-
----------
|
463 |
-
typ : type or '__module__.__name__' string for a type
|
464 |
-
|
465 |
-
Returns
|
466 |
-
-------
|
467 |
-
f : callable
|
468 |
-
The registered formatting callable for the type.
|
469 |
-
|
470 |
-
Raises
|
471 |
-
------
|
472 |
-
KeyError if the type has not been registered.
|
473 |
-
"""
|
474 |
-
if isinstance(typ, str):
|
475 |
-
typ_key = tuple(typ.rsplit('.',1))
|
476 |
-
if typ_key not in self.deferred_printers:
|
477 |
-
# We may have it cached in the type map. We will have to
|
478 |
-
# iterate over all of the types to check.
|
479 |
-
for cls in self.type_printers:
|
480 |
-
if _mod_name_key(cls) == typ_key:
|
481 |
-
return self.type_printers[cls]
|
482 |
-
else:
|
483 |
-
return self.deferred_printers[typ_key]
|
484 |
-
else:
|
485 |
-
for cls in pretty._get_mro(typ):
|
486 |
-
if cls in self.type_printers or self._in_deferred_types(cls):
|
487 |
-
return self.type_printers[cls]
|
488 |
-
|
489 |
-
# If we have reached here, the lookup failed.
|
490 |
-
raise KeyError("No registered printer for {0!r}".format(typ))
|
491 |
-
|
492 |
-
def for_type(self, typ, func=None):
|
493 |
-
"""Add a format function for a given type.
|
494 |
-
|
495 |
-
Parameters
|
496 |
-
----------
|
497 |
-
typ : type or '__module__.__name__' string for a type
|
498 |
-
The class of the object that will be formatted using `func`.
|
499 |
-
|
500 |
-
func : callable
|
501 |
-
A callable for computing the format data.
|
502 |
-
`func` will be called with the object to be formatted,
|
503 |
-
and will return the raw data in this formatter's format.
|
504 |
-
Subclasses may use a different call signature for the
|
505 |
-
`func` argument.
|
506 |
-
|
507 |
-
If `func` is None or not specified, there will be no change,
|
508 |
-
only returning the current value.
|
509 |
-
|
510 |
-
Returns
|
511 |
-
-------
|
512 |
-
oldfunc : callable
|
513 |
-
The currently registered callable.
|
514 |
-
If you are registering a new formatter,
|
515 |
-
this will be the previous value (to enable restoring later).
|
516 |
-
"""
|
517 |
-
# if string given, interpret as 'pkg.module.class_name'
|
518 |
-
if isinstance(typ, str):
|
519 |
-
type_module, type_name = typ.rsplit('.', 1)
|
520 |
-
return self.for_type_by_name(type_module, type_name, func)
|
521 |
-
|
522 |
-
try:
|
523 |
-
oldfunc = self.lookup_by_type(typ)
|
524 |
-
except KeyError:
|
525 |
-
oldfunc = None
|
526 |
-
|
527 |
-
if func is not None:
|
528 |
-
self.type_printers[typ] = func
|
529 |
-
|
530 |
-
return oldfunc
|
531 |
-
|
532 |
-
def for_type_by_name(self, type_module, type_name, func=None):
|
533 |
-
"""Add a format function for a type specified by the full dotted
|
534 |
-
module and name of the type, rather than the type of the object.
|
535 |
-
|
536 |
-
Parameters
|
537 |
-
----------
|
538 |
-
type_module : str
|
539 |
-
The full dotted name of the module the type is defined in, like
|
540 |
-
``numpy``.
|
541 |
-
|
542 |
-
type_name : str
|
543 |
-
The name of the type (the class name), like ``dtype``
|
544 |
-
|
545 |
-
func : callable
|
546 |
-
A callable for computing the format data.
|
547 |
-
`func` will be called with the object to be formatted,
|
548 |
-
and will return the raw data in this formatter's format.
|
549 |
-
Subclasses may use a different call signature for the
|
550 |
-
`func` argument.
|
551 |
-
|
552 |
-
If `func` is None or unspecified, there will be no change,
|
553 |
-
only returning the current value.
|
554 |
-
|
555 |
-
Returns
|
556 |
-
-------
|
557 |
-
oldfunc : callable
|
558 |
-
The currently registered callable.
|
559 |
-
If you are registering a new formatter,
|
560 |
-
this will be the previous value (to enable restoring later).
|
561 |
-
"""
|
562 |
-
key = (type_module, type_name)
|
563 |
-
|
564 |
-
try:
|
565 |
-
oldfunc = self.lookup_by_type("%s.%s" % key)
|
566 |
-
except KeyError:
|
567 |
-
oldfunc = None
|
568 |
-
|
569 |
-
if func is not None:
|
570 |
-
self.deferred_printers[key] = func
|
571 |
-
return oldfunc
|
572 |
-
|
573 |
-
def pop(self, typ, default=_raise_key_error):
|
574 |
-
"""Pop a formatter for the given type.
|
575 |
-
|
576 |
-
Parameters
|
577 |
-
----------
|
578 |
-
typ : type or '__module__.__name__' string for a type
|
579 |
-
default : object
|
580 |
-
value to be returned if no formatter is registered for typ.
|
581 |
-
|
582 |
-
Returns
|
583 |
-
-------
|
584 |
-
obj : object
|
585 |
-
The last registered object for the type.
|
586 |
-
|
587 |
-
Raises
|
588 |
-
------
|
589 |
-
KeyError if the type is not registered and default is not specified.
|
590 |
-
"""
|
591 |
-
|
592 |
-
if isinstance(typ, str):
|
593 |
-
typ_key = tuple(typ.rsplit('.',1))
|
594 |
-
if typ_key not in self.deferred_printers:
|
595 |
-
# We may have it cached in the type map. We will have to
|
596 |
-
# iterate over all of the types to check.
|
597 |
-
for cls in self.type_printers:
|
598 |
-
if _mod_name_key(cls) == typ_key:
|
599 |
-
old = self.type_printers.pop(cls)
|
600 |
-
break
|
601 |
-
else:
|
602 |
-
old = default
|
603 |
-
else:
|
604 |
-
old = self.deferred_printers.pop(typ_key)
|
605 |
-
else:
|
606 |
-
if typ in self.type_printers:
|
607 |
-
old = self.type_printers.pop(typ)
|
608 |
-
else:
|
609 |
-
old = self.deferred_printers.pop(_mod_name_key(typ), default)
|
610 |
-
if old is _raise_key_error:
|
611 |
-
raise KeyError("No registered value for {0!r}".format(typ))
|
612 |
-
return old
|
613 |
-
|
614 |
-
def _in_deferred_types(self, cls):
|
615 |
-
"""
|
616 |
-
Check if the given class is specified in the deferred type registry.
|
617 |
-
|
618 |
-
Successful matches will be moved to the regular type registry for future use.
|
619 |
-
"""
|
620 |
-
mod = getattr(cls, '__module__', None)
|
621 |
-
name = getattr(cls, '__name__', None)
|
622 |
-
key = (mod, name)
|
623 |
-
if key in self.deferred_printers:
|
624 |
-
# Move the printer over to the regular registry.
|
625 |
-
printer = self.deferred_printers.pop(key)
|
626 |
-
self.type_printers[cls] = printer
|
627 |
-
return True
|
628 |
-
return False
|
629 |
-
|
630 |
-
|
631 |
-
class PlainTextFormatter(BaseFormatter):
|
632 |
-
"""The default pretty-printer.
|
633 |
-
|
634 |
-
This uses :mod:`IPython.lib.pretty` to compute the format data of
|
635 |
-
the object. If the object cannot be pretty printed, :func:`repr` is used.
|
636 |
-
See the documentation of :mod:`IPython.lib.pretty` for details on
|
637 |
-
how to write pretty printers. Here is a simple example::
|
638 |
-
|
639 |
-
def dtype_pprinter(obj, p, cycle):
|
640 |
-
if cycle:
|
641 |
-
return p.text('dtype(...)')
|
642 |
-
if hasattr(obj, 'fields'):
|
643 |
-
if obj.fields is None:
|
644 |
-
p.text(repr(obj))
|
645 |
-
else:
|
646 |
-
p.begin_group(7, 'dtype([')
|
647 |
-
for i, field in enumerate(obj.descr):
|
648 |
-
if i > 0:
|
649 |
-
p.text(',')
|
650 |
-
p.breakable()
|
651 |
-
p.pretty(field)
|
652 |
-
p.end_group(7, '])')
|
653 |
-
"""
|
654 |
-
|
655 |
-
# The format type of data returned.
|
656 |
-
format_type = Unicode('text/plain')
|
657 |
-
|
658 |
-
# This subclass ignores this attribute as it always need to return
|
659 |
-
# something.
|
660 |
-
enabled = Bool(True).tag(config=False)
|
661 |
-
|
662 |
-
max_seq_length = Integer(pretty.MAX_SEQ_LENGTH,
|
663 |
-
help="""Truncate large collections (lists, dicts, tuples, sets) to this size.
|
664 |
-
|
665 |
-
Set to 0 to disable truncation.
|
666 |
-
""",
|
667 |
-
).tag(config=True)
|
668 |
-
|
669 |
-
# Look for a _repr_pretty_ methods to use for pretty printing.
|
670 |
-
print_method = ObjectName('_repr_pretty_')
|
671 |
-
|
672 |
-
# Whether to pretty-print or not.
|
673 |
-
pprint = Bool(True).tag(config=True)
|
674 |
-
|
675 |
-
# Whether to be verbose or not.
|
676 |
-
verbose = Bool(False).tag(config=True)
|
677 |
-
|
678 |
-
# The maximum width.
|
679 |
-
max_width = Integer(79).tag(config=True)
|
680 |
-
|
681 |
-
# The newline character.
|
682 |
-
newline = Unicode('\n').tag(config=True)
|
683 |
-
|
684 |
-
# format-string for pprinting floats
|
685 |
-
float_format = Unicode('%r')
|
686 |
-
# setter for float precision, either int or direct format-string
|
687 |
-
float_precision = CUnicode('').tag(config=True)
|
688 |
-
|
689 |
-
@observe('float_precision')
|
690 |
-
def _float_precision_changed(self, change):
|
691 |
-
"""float_precision changed, set float_format accordingly.
|
692 |
-
|
693 |
-
float_precision can be set by int or str.
|
694 |
-
This will set float_format, after interpreting input.
|
695 |
-
If numpy has been imported, numpy print precision will also be set.
|
696 |
-
|
697 |
-
integer `n` sets format to '%.nf', otherwise, format set directly.
|
698 |
-
|
699 |
-
An empty string returns to defaults (repr for float, 8 for numpy).
|
700 |
-
|
701 |
-
This parameter can be set via the '%precision' magic.
|
702 |
-
"""
|
703 |
-
new = change['new']
|
704 |
-
if '%' in new:
|
705 |
-
# got explicit format string
|
706 |
-
fmt = new
|
707 |
-
try:
|
708 |
-
fmt%3.14159
|
709 |
-
except Exception as e:
|
710 |
-
raise ValueError("Precision must be int or format string, not %r"%new) from e
|
711 |
-
elif new:
|
712 |
-
# otherwise, should be an int
|
713 |
-
try:
|
714 |
-
i = int(new)
|
715 |
-
assert i >= 0
|
716 |
-
except ValueError as e:
|
717 |
-
raise ValueError("Precision must be int or format string, not %r"%new) from e
|
718 |
-
except AssertionError as e:
|
719 |
-
raise ValueError("int precision must be non-negative, not %r"%i) from e
|
720 |
-
|
721 |
-
fmt = '%%.%if'%i
|
722 |
-
if 'numpy' in sys.modules:
|
723 |
-
# set numpy precision if it has been imported
|
724 |
-
import numpy
|
725 |
-
numpy.set_printoptions(precision=i)
|
726 |
-
else:
|
727 |
-
# default back to repr
|
728 |
-
fmt = '%r'
|
729 |
-
if 'numpy' in sys.modules:
|
730 |
-
import numpy
|
731 |
-
# numpy default is 8
|
732 |
-
numpy.set_printoptions(precision=8)
|
733 |
-
self.float_format = fmt
|
734 |
-
|
735 |
-
# Use the default pretty printers from IPython.lib.pretty.
|
736 |
-
@default('singleton_printers')
|
737 |
-
def _singleton_printers_default(self):
|
738 |
-
return pretty._singleton_pprinters.copy()
|
739 |
-
|
740 |
-
@default('type_printers')
|
741 |
-
def _type_printers_default(self):
|
742 |
-
d = pretty._type_pprinters.copy()
|
743 |
-
d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
|
744 |
-
# if NumPy is used, set precision for its float64 type
|
745 |
-
if "numpy" in sys.modules:
|
746 |
-
import numpy
|
747 |
-
|
748 |
-
d[numpy.float64] = lambda obj, p, cycle: p.text(self.float_format % obj)
|
749 |
-
return d
|
750 |
-
|
751 |
-
@default('deferred_printers')
|
752 |
-
def _deferred_printers_default(self):
|
753 |
-
return pretty._deferred_type_pprinters.copy()
|
754 |
-
|
755 |
-
#### FormatterABC interface ####
|
756 |
-
|
757 |
-
@catch_format_error
|
758 |
-
def __call__(self, obj):
|
759 |
-
"""Compute the pretty representation of the object."""
|
760 |
-
if not self.pprint:
|
761 |
-
return repr(obj)
|
762 |
-
else:
|
763 |
-
stream = StringIO()
|
764 |
-
printer = pretty.RepresentationPrinter(stream, self.verbose,
|
765 |
-
self.max_width, self.newline,
|
766 |
-
max_seq_length=self.max_seq_length,
|
767 |
-
singleton_pprinters=self.singleton_printers,
|
768 |
-
type_pprinters=self.type_printers,
|
769 |
-
deferred_pprinters=self.deferred_printers)
|
770 |
-
printer.pretty(obj)
|
771 |
-
printer.flush()
|
772 |
-
return stream.getvalue()
|
773 |
-
|
774 |
-
|
775 |
-
class HTMLFormatter(BaseFormatter):
|
776 |
-
"""An HTML formatter.
|
777 |
-
|
778 |
-
To define the callables that compute the HTML representation of your
|
779 |
-
objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
|
780 |
-
or :meth:`for_type_by_name` methods to register functions that handle
|
781 |
-
this.
|
782 |
-
|
783 |
-
The return value of this formatter should be a valid HTML snippet that
|
784 |
-
could be injected into an existing DOM. It should *not* include the
|
785 |
-
```<html>`` or ```<body>`` tags.
|
786 |
-
"""
|
787 |
-
format_type = Unicode('text/html')
|
788 |
-
|
789 |
-
print_method = ObjectName('_repr_html_')
|
790 |
-
|
791 |
-
|
792 |
-
class MarkdownFormatter(BaseFormatter):
|
793 |
-
"""A Markdown formatter.
|
794 |
-
|
795 |
-
To define the callables that compute the Markdown representation of your
|
796 |
-
objects, define a :meth:`_repr_markdown_` method or use the :meth:`for_type`
|
797 |
-
or :meth:`for_type_by_name` methods to register functions that handle
|
798 |
-
this.
|
799 |
-
|
800 |
-
The return value of this formatter should be a valid Markdown.
|
801 |
-
"""
|
802 |
-
format_type = Unicode('text/markdown')
|
803 |
-
|
804 |
-
print_method = ObjectName('_repr_markdown_')
|
805 |
-
|
806 |
-
class SVGFormatter(BaseFormatter):
|
807 |
-
"""An SVG formatter.
|
808 |
-
|
809 |
-
To define the callables that compute the SVG representation of your
|
810 |
-
objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
|
811 |
-
or :meth:`for_type_by_name` methods to register functions that handle
|
812 |
-
this.
|
813 |
-
|
814 |
-
The return value of this formatter should be valid SVG enclosed in
|
815 |
-
```<svg>``` tags, that could be injected into an existing DOM. It should
|
816 |
-
*not* include the ```<html>`` or ```<body>`` tags.
|
817 |
-
"""
|
818 |
-
format_type = Unicode('image/svg+xml')
|
819 |
-
|
820 |
-
print_method = ObjectName('_repr_svg_')
|
821 |
-
|
822 |
-
|
823 |
-
class PNGFormatter(BaseFormatter):
|
824 |
-
"""A PNG formatter.
|
825 |
-
|
826 |
-
To define the callables that compute the PNG representation of your
|
827 |
-
objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
|
828 |
-
or :meth:`for_type_by_name` methods to register functions that handle
|
829 |
-
this.
|
830 |
-
|
831 |
-
The return value of this formatter should be raw PNG data, *not*
|
832 |
-
base64 encoded.
|
833 |
-
"""
|
834 |
-
format_type = Unicode('image/png')
|
835 |
-
|
836 |
-
print_method = ObjectName('_repr_png_')
|
837 |
-
|
838 |
-
_return_type = (bytes, str)
|
839 |
-
|
840 |
-
|
841 |
-
class JPEGFormatter(BaseFormatter):
|
842 |
-
"""A JPEG formatter.
|
843 |
-
|
844 |
-
To define the callables that compute the JPEG representation of your
|
845 |
-
objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
|
846 |
-
or :meth:`for_type_by_name` methods to register functions that handle
|
847 |
-
this.
|
848 |
-
|
849 |
-
The return value of this formatter should be raw JPEG data, *not*
|
850 |
-
base64 encoded.
|
851 |
-
"""
|
852 |
-
format_type = Unicode('image/jpeg')
|
853 |
-
|
854 |
-
print_method = ObjectName('_repr_jpeg_')
|
855 |
-
|
856 |
-
_return_type = (bytes, str)
|
857 |
-
|
858 |
-
|
859 |
-
class LatexFormatter(BaseFormatter):
|
860 |
-
"""A LaTeX formatter.
|
861 |
-
|
862 |
-
To define the callables that compute the LaTeX representation of your
|
863 |
-
objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
|
864 |
-
or :meth:`for_type_by_name` methods to register functions that handle
|
865 |
-
this.
|
866 |
-
|
867 |
-
The return value of this formatter should be a valid LaTeX equation,
|
868 |
-
enclosed in either ```$```, ```$$``` or another LaTeX equation
|
869 |
-
environment.
|
870 |
-
"""
|
871 |
-
format_type = Unicode('text/latex')
|
872 |
-
|
873 |
-
print_method = ObjectName('_repr_latex_')
|
874 |
-
|
875 |
-
|
876 |
-
class JSONFormatter(BaseFormatter):
|
877 |
-
"""A JSON string formatter.
|
878 |
-
|
879 |
-
To define the callables that compute the JSONable representation of
|
880 |
-
your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
|
881 |
-
or :meth:`for_type_by_name` methods to register functions that handle
|
882 |
-
this.
|
883 |
-
|
884 |
-
The return value of this formatter should be a JSONable list or dict.
|
885 |
-
JSON scalars (None, number, string) are not allowed, only dict or list containers.
|
886 |
-
"""
|
887 |
-
format_type = Unicode('application/json')
|
888 |
-
_return_type = (list, dict)
|
889 |
-
|
890 |
-
print_method = ObjectName('_repr_json_')
|
891 |
-
|
892 |
-
def _check_return(self, r, obj):
|
893 |
-
"""Check that a return value is appropriate
|
894 |
-
|
895 |
-
Return the value if so, None otherwise, warning if invalid.
|
896 |
-
"""
|
897 |
-
if r is None:
|
898 |
-
return
|
899 |
-
md = None
|
900 |
-
if isinstance(r, tuple):
|
901 |
-
# unpack data, metadata tuple for type checking on first element
|
902 |
-
r, md = r
|
903 |
-
|
904 |
-
assert not isinstance(
|
905 |
-
r, str
|
906 |
-
), "JSON-as-string has been deprecated since IPython < 3"
|
907 |
-
|
908 |
-
if md is not None:
|
909 |
-
# put the tuple back together
|
910 |
-
r = (r, md)
|
911 |
-
return super(JSONFormatter, self)._check_return(r, obj)
|
912 |
-
|
913 |
-
|
914 |
-
class JavascriptFormatter(BaseFormatter):
|
915 |
-
"""A Javascript formatter.
|
916 |
-
|
917 |
-
To define the callables that compute the Javascript representation of
|
918 |
-
your objects, define a :meth:`_repr_javascript_` method or use the
|
919 |
-
:meth:`for_type` or :meth:`for_type_by_name` methods to register functions
|
920 |
-
that handle this.
|
921 |
-
|
922 |
-
The return value of this formatter should be valid Javascript code and
|
923 |
-
should *not* be enclosed in ```<script>``` tags.
|
924 |
-
"""
|
925 |
-
format_type = Unicode('application/javascript')
|
926 |
-
|
927 |
-
print_method = ObjectName('_repr_javascript_')
|
928 |
-
|
929 |
-
|
930 |
-
class PDFFormatter(BaseFormatter):
|
931 |
-
"""A PDF formatter.
|
932 |
-
|
933 |
-
To define the callables that compute the PDF representation of your
|
934 |
-
objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type`
|
935 |
-
or :meth:`for_type_by_name` methods to register functions that handle
|
936 |
-
this.
|
937 |
-
|
938 |
-
The return value of this formatter should be raw PDF data, *not*
|
939 |
-
base64 encoded.
|
940 |
-
"""
|
941 |
-
format_type = Unicode('application/pdf')
|
942 |
-
|
943 |
-
print_method = ObjectName('_repr_pdf_')
|
944 |
-
|
945 |
-
_return_type = (bytes, str)
|
946 |
-
|
947 |
-
class IPythonDisplayFormatter(BaseFormatter):
|
948 |
-
"""An escape-hatch Formatter for objects that know how to display themselves.
|
949 |
-
|
950 |
-
To define the callables that compute the representation of your
|
951 |
-
objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type`
|
952 |
-
or :meth:`for_type_by_name` methods to register functions that handle
|
953 |
-
this. Unlike mime-type displays, this method should not return anything,
|
954 |
-
instead calling any appropriate display methods itself.
|
955 |
-
|
956 |
-
This display formatter has highest priority.
|
957 |
-
If it fires, no other display formatter will be called.
|
958 |
-
|
959 |
-
Prior to IPython 6.1, `_ipython_display_` was the only way to display custom mime-types
|
960 |
-
without registering a new Formatter.
|
961 |
-
|
962 |
-
IPython 6.1 introduces `_repr_mimebundle_` for displaying custom mime-types,
|
963 |
-
so `_ipython_display_` should only be used for objects that require unusual
|
964 |
-
display patterns, such as multiple display calls.
|
965 |
-
"""
|
966 |
-
print_method = ObjectName('_ipython_display_')
|
967 |
-
_return_type = (type(None), bool)
|
968 |
-
|
969 |
-
@catch_format_error
|
970 |
-
def __call__(self, obj):
|
971 |
-
"""Compute the format for an object."""
|
972 |
-
if self.enabled:
|
973 |
-
# lookup registered printer
|
974 |
-
try:
|
975 |
-
printer = self.lookup(obj)
|
976 |
-
except KeyError:
|
977 |
-
pass
|
978 |
-
else:
|
979 |
-
printer(obj)
|
980 |
-
return True
|
981 |
-
# Finally look for special method names
|
982 |
-
method = get_real_method(obj, self.print_method)
|
983 |
-
if method is not None:
|
984 |
-
method()
|
985 |
-
return True
|
986 |
-
|
987 |
-
|
988 |
-
class MimeBundleFormatter(BaseFormatter):
|
989 |
-
"""A Formatter for arbitrary mime-types.
|
990 |
-
|
991 |
-
Unlike other `_repr_<mimetype>_` methods,
|
992 |
-
`_repr_mimebundle_` should return mime-bundle data,
|
993 |
-
either the mime-keyed `data` dictionary or the tuple `(data, metadata)`.
|
994 |
-
Any mime-type is valid.
|
995 |
-
|
996 |
-
To define the callables that compute the mime-bundle representation of your
|
997 |
-
objects, define a :meth:`_repr_mimebundle_` method or use the :meth:`for_type`
|
998 |
-
or :meth:`for_type_by_name` methods to register functions that handle
|
999 |
-
this.
|
1000 |
-
|
1001 |
-
.. versionadded:: 6.1
|
1002 |
-
"""
|
1003 |
-
print_method = ObjectName('_repr_mimebundle_')
|
1004 |
-
_return_type = dict
|
1005 |
-
|
1006 |
-
def _check_return(self, r, obj):
|
1007 |
-
r = super(MimeBundleFormatter, self)._check_return(r, obj)
|
1008 |
-
# always return (data, metadata):
|
1009 |
-
if r is None:
|
1010 |
-
return {}, {}
|
1011 |
-
if not isinstance(r, tuple):
|
1012 |
-
return r, {}
|
1013 |
-
return r
|
1014 |
-
|
1015 |
-
@catch_format_error
|
1016 |
-
def __call__(self, obj, include=None, exclude=None):
|
1017 |
-
"""Compute the format for an object.
|
1018 |
-
|
1019 |
-
Identical to parent's method but we pass extra parameters to the method.
|
1020 |
-
|
1021 |
-
Unlike other _repr_*_ `_repr_mimebundle_` should allow extra kwargs, in
|
1022 |
-
particular `include` and `exclude`.
|
1023 |
-
"""
|
1024 |
-
if self.enabled:
|
1025 |
-
# lookup registered printer
|
1026 |
-
try:
|
1027 |
-
printer = self.lookup(obj)
|
1028 |
-
except KeyError:
|
1029 |
-
pass
|
1030 |
-
else:
|
1031 |
-
return printer(obj)
|
1032 |
-
# Finally look for special method names
|
1033 |
-
method = get_real_method(obj, self.print_method)
|
1034 |
-
|
1035 |
-
if method is not None:
|
1036 |
-
return method(include=include, exclude=exclude)
|
1037 |
-
return None
|
1038 |
-
else:
|
1039 |
-
return None
|
1040 |
-
|
1041 |
-
|
1042 |
-
FormatterABC.register(BaseFormatter)
|
1043 |
-
FormatterABC.register(PlainTextFormatter)
|
1044 |
-
FormatterABC.register(HTMLFormatter)
|
1045 |
-
FormatterABC.register(MarkdownFormatter)
|
1046 |
-
FormatterABC.register(SVGFormatter)
|
1047 |
-
FormatterABC.register(PNGFormatter)
|
1048 |
-
FormatterABC.register(PDFFormatter)
|
1049 |
-
FormatterABC.register(JPEGFormatter)
|
1050 |
-
FormatterABC.register(LatexFormatter)
|
1051 |
-
FormatterABC.register(JSONFormatter)
|
1052 |
-
FormatterABC.register(JavascriptFormatter)
|
1053 |
-
FormatterABC.register(IPythonDisplayFormatter)
|
1054 |
-
FormatterABC.register(MimeBundleFormatter)
|
1055 |
-
|
1056 |
-
|
1057 |
-
def format_display_data(obj, include=None, exclude=None):
|
1058 |
-
"""Return a format data dict for an object.
|
1059 |
-
|
1060 |
-
By default all format types will be computed.
|
1061 |
-
|
1062 |
-
Parameters
|
1063 |
-
----------
|
1064 |
-
obj : object
|
1065 |
-
The Python object whose format data will be computed.
|
1066 |
-
|
1067 |
-
Returns
|
1068 |
-
-------
|
1069 |
-
format_dict : dict
|
1070 |
-
A dictionary of key/value pairs, one or each format that was
|
1071 |
-
generated for the object. The keys are the format types, which
|
1072 |
-
will usually be MIME type strings and the values and JSON'able
|
1073 |
-
data structure containing the raw data for the representation in
|
1074 |
-
that format.
|
1075 |
-
include : list or tuple, optional
|
1076 |
-
A list of format type strings (MIME types) to include in the
|
1077 |
-
format data dict. If this is set *only* the format types included
|
1078 |
-
in this list will be computed.
|
1079 |
-
exclude : list or tuple, optional
|
1080 |
-
A list of format type string (MIME types) to exclude in the format
|
1081 |
-
data dict. If this is set all format types will be computed,
|
1082 |
-
except for those included in this argument.
|
1083 |
-
"""
|
1084 |
-
from .interactiveshell import InteractiveShell
|
1085 |
-
|
1086 |
-
return InteractiveShell.instance().display_formatter.format(
|
1087 |
-
obj,
|
1088 |
-
include,
|
1089 |
-
exclude
|
1090 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/getipython.py
DELETED
@@ -1,24 +0,0 @@
|
|
1 |
-
# encoding: utf-8
|
2 |
-
"""Simple function to call to get the current InteractiveShell instance
|
3 |
-
"""
|
4 |
-
|
5 |
-
#-----------------------------------------------------------------------------
|
6 |
-
# Copyright (C) 2013 The IPython Development Team
|
7 |
-
#
|
8 |
-
# Distributed under the terms of the BSD License. The full license is in
|
9 |
-
# the file COPYING, distributed as part of this software.
|
10 |
-
#-----------------------------------------------------------------------------
|
11 |
-
|
12 |
-
#-----------------------------------------------------------------------------
|
13 |
-
# Classes and functions
|
14 |
-
#-----------------------------------------------------------------------------
|
15 |
-
|
16 |
-
|
17 |
-
def get_ipython():
|
18 |
-
"""Get the global InteractiveShell instance.
|
19 |
-
|
20 |
-
Returns None if no InteractiveShell instance is registered.
|
21 |
-
"""
|
22 |
-
from IPython.core.interactiveshell import InteractiveShell
|
23 |
-
if InteractiveShell.initialized():
|
24 |
-
return InteractiveShell.instance()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/guarded_eval.py
DELETED
@@ -1,895 +0,0 @@
|
|
1 |
-
from inspect import isclass, signature, Signature
|
2 |
-
from typing import (
|
3 |
-
Annotated,
|
4 |
-
AnyStr,
|
5 |
-
Callable,
|
6 |
-
Dict,
|
7 |
-
Literal,
|
8 |
-
NamedTuple,
|
9 |
-
NewType,
|
10 |
-
Optional,
|
11 |
-
Protocol,
|
12 |
-
Set,
|
13 |
-
Sequence,
|
14 |
-
Tuple,
|
15 |
-
Type,
|
16 |
-
TypeGuard,
|
17 |
-
Union,
|
18 |
-
get_args,
|
19 |
-
get_origin,
|
20 |
-
is_typeddict,
|
21 |
-
)
|
22 |
-
import ast
|
23 |
-
import builtins
|
24 |
-
import collections
|
25 |
-
import operator
|
26 |
-
import sys
|
27 |
-
from functools import cached_property
|
28 |
-
from dataclasses import dataclass, field
|
29 |
-
from types import MethodDescriptorType, ModuleType
|
30 |
-
|
31 |
-
from IPython.utils.decorators import undoc
|
32 |
-
|
33 |
-
|
34 |
-
if sys.version_info < (3, 11):
|
35 |
-
from typing_extensions import Self, LiteralString
|
36 |
-
else:
|
37 |
-
from typing import Self, LiteralString
|
38 |
-
|
39 |
-
if sys.version_info < (3, 12):
|
40 |
-
from typing_extensions import TypeAliasType
|
41 |
-
else:
|
42 |
-
from typing import TypeAliasType
|
43 |
-
|
44 |
-
|
45 |
-
@undoc
|
46 |
-
class HasGetItem(Protocol):
|
47 |
-
def __getitem__(self, key) -> None: ...
|
48 |
-
|
49 |
-
|
50 |
-
@undoc
|
51 |
-
class InstancesHaveGetItem(Protocol):
|
52 |
-
def __call__(self, *args, **kwargs) -> HasGetItem: ...
|
53 |
-
|
54 |
-
|
55 |
-
@undoc
|
56 |
-
class HasGetAttr(Protocol):
|
57 |
-
def __getattr__(self, key) -> None: ...
|
58 |
-
|
59 |
-
|
60 |
-
@undoc
|
61 |
-
class DoesNotHaveGetAttr(Protocol):
|
62 |
-
pass
|
63 |
-
|
64 |
-
|
65 |
-
# By default `__getattr__` is not explicitly implemented on most objects
|
66 |
-
MayHaveGetattr = Union[HasGetAttr, DoesNotHaveGetAttr]
|
67 |
-
|
68 |
-
|
69 |
-
def _unbind_method(func: Callable) -> Union[Callable, None]:
|
70 |
-
"""Get unbound method for given bound method.
|
71 |
-
|
72 |
-
Returns None if cannot get unbound method, or method is already unbound.
|
73 |
-
"""
|
74 |
-
owner = getattr(func, "__self__", None)
|
75 |
-
owner_class = type(owner)
|
76 |
-
name = getattr(func, "__name__", None)
|
77 |
-
instance_dict_overrides = getattr(owner, "__dict__", None)
|
78 |
-
if (
|
79 |
-
owner is not None
|
80 |
-
and name
|
81 |
-
and (
|
82 |
-
not instance_dict_overrides
|
83 |
-
or (instance_dict_overrides and name not in instance_dict_overrides)
|
84 |
-
)
|
85 |
-
):
|
86 |
-
return getattr(owner_class, name)
|
87 |
-
return None
|
88 |
-
|
89 |
-
|
90 |
-
@undoc
|
91 |
-
@dataclass
|
92 |
-
class EvaluationPolicy:
|
93 |
-
"""Definition of evaluation policy."""
|
94 |
-
|
95 |
-
allow_locals_access: bool = False
|
96 |
-
allow_globals_access: bool = False
|
97 |
-
allow_item_access: bool = False
|
98 |
-
allow_attr_access: bool = False
|
99 |
-
allow_builtins_access: bool = False
|
100 |
-
allow_all_operations: bool = False
|
101 |
-
allow_any_calls: bool = False
|
102 |
-
allowed_calls: Set[Callable] = field(default_factory=set)
|
103 |
-
|
104 |
-
def can_get_item(self, value, item):
|
105 |
-
return self.allow_item_access
|
106 |
-
|
107 |
-
def can_get_attr(self, value, attr):
|
108 |
-
return self.allow_attr_access
|
109 |
-
|
110 |
-
def can_operate(self, dunders: Tuple[str, ...], a, b=None):
|
111 |
-
if self.allow_all_operations:
|
112 |
-
return True
|
113 |
-
|
114 |
-
def can_call(self, func):
|
115 |
-
if self.allow_any_calls:
|
116 |
-
return True
|
117 |
-
|
118 |
-
if func in self.allowed_calls:
|
119 |
-
return True
|
120 |
-
|
121 |
-
owner_method = _unbind_method(func)
|
122 |
-
|
123 |
-
if owner_method and owner_method in self.allowed_calls:
|
124 |
-
return True
|
125 |
-
|
126 |
-
|
127 |
-
def _get_external(module_name: str, access_path: Sequence[str]):
|
128 |
-
"""Get value from external module given a dotted access path.
|
129 |
-
|
130 |
-
Raises:
|
131 |
-
* `KeyError` if module is removed not found, and
|
132 |
-
* `AttributeError` if access path does not match an exported object
|
133 |
-
"""
|
134 |
-
member_type = sys.modules[module_name]
|
135 |
-
for attr in access_path:
|
136 |
-
member_type = getattr(member_type, attr)
|
137 |
-
return member_type
|
138 |
-
|
139 |
-
|
140 |
-
def _has_original_dunder_external(
|
141 |
-
value,
|
142 |
-
module_name: str,
|
143 |
-
access_path: Sequence[str],
|
144 |
-
method_name: str,
|
145 |
-
):
|
146 |
-
if module_name not in sys.modules:
|
147 |
-
# LBYLB as it is faster
|
148 |
-
return False
|
149 |
-
try:
|
150 |
-
member_type = _get_external(module_name, access_path)
|
151 |
-
value_type = type(value)
|
152 |
-
if type(value) == member_type:
|
153 |
-
return True
|
154 |
-
if method_name == "__getattribute__":
|
155 |
-
# we have to short-circuit here due to an unresolved issue in
|
156 |
-
# `isinstance` implementation: https://bugs.python.org/issue32683
|
157 |
-
return False
|
158 |
-
if isinstance(value, member_type):
|
159 |
-
method = getattr(value_type, method_name, None)
|
160 |
-
member_method = getattr(member_type, method_name, None)
|
161 |
-
if member_method == method:
|
162 |
-
return True
|
163 |
-
except (AttributeError, KeyError):
|
164 |
-
return False
|
165 |
-
|
166 |
-
|
167 |
-
def _has_original_dunder(
|
168 |
-
value, allowed_types, allowed_methods, allowed_external, method_name
|
169 |
-
):
|
170 |
-
# note: Python ignores `__getattr__`/`__getitem__` on instances,
|
171 |
-
# we only need to check at class level
|
172 |
-
value_type = type(value)
|
173 |
-
|
174 |
-
# strict type check passes → no need to check method
|
175 |
-
if value_type in allowed_types:
|
176 |
-
return True
|
177 |
-
|
178 |
-
method = getattr(value_type, method_name, None)
|
179 |
-
|
180 |
-
if method is None:
|
181 |
-
return None
|
182 |
-
|
183 |
-
if method in allowed_methods:
|
184 |
-
return True
|
185 |
-
|
186 |
-
for module_name, *access_path in allowed_external:
|
187 |
-
if _has_original_dunder_external(value, module_name, access_path, method_name):
|
188 |
-
return True
|
189 |
-
|
190 |
-
return False
|
191 |
-
|
192 |
-
|
193 |
-
@undoc
|
194 |
-
@dataclass
|
195 |
-
class SelectivePolicy(EvaluationPolicy):
|
196 |
-
allowed_getitem: Set[InstancesHaveGetItem] = field(default_factory=set)
|
197 |
-
allowed_getitem_external: Set[Tuple[str, ...]] = field(default_factory=set)
|
198 |
-
|
199 |
-
allowed_getattr: Set[MayHaveGetattr] = field(default_factory=set)
|
200 |
-
allowed_getattr_external: Set[Tuple[str, ...]] = field(default_factory=set)
|
201 |
-
|
202 |
-
allowed_operations: Set = field(default_factory=set)
|
203 |
-
allowed_operations_external: Set[Tuple[str, ...]] = field(default_factory=set)
|
204 |
-
|
205 |
-
_operation_methods_cache: Dict[str, Set[Callable]] = field(
|
206 |
-
default_factory=dict, init=False
|
207 |
-
)
|
208 |
-
|
209 |
-
def can_get_attr(self, value, attr):
|
210 |
-
has_original_attribute = _has_original_dunder(
|
211 |
-
value,
|
212 |
-
allowed_types=self.allowed_getattr,
|
213 |
-
allowed_methods=self._getattribute_methods,
|
214 |
-
allowed_external=self.allowed_getattr_external,
|
215 |
-
method_name="__getattribute__",
|
216 |
-
)
|
217 |
-
has_original_attr = _has_original_dunder(
|
218 |
-
value,
|
219 |
-
allowed_types=self.allowed_getattr,
|
220 |
-
allowed_methods=self._getattr_methods,
|
221 |
-
allowed_external=self.allowed_getattr_external,
|
222 |
-
method_name="__getattr__",
|
223 |
-
)
|
224 |
-
|
225 |
-
accept = False
|
226 |
-
|
227 |
-
# Many objects do not have `__getattr__`, this is fine.
|
228 |
-
if has_original_attr is None and has_original_attribute:
|
229 |
-
accept = True
|
230 |
-
else:
|
231 |
-
# Accept objects without modifications to `__getattr__` and `__getattribute__`
|
232 |
-
accept = has_original_attr and has_original_attribute
|
233 |
-
|
234 |
-
if accept:
|
235 |
-
# We still need to check for overridden properties.
|
236 |
-
|
237 |
-
value_class = type(value)
|
238 |
-
if not hasattr(value_class, attr):
|
239 |
-
return True
|
240 |
-
|
241 |
-
class_attr_val = getattr(value_class, attr)
|
242 |
-
is_property = isinstance(class_attr_val, property)
|
243 |
-
|
244 |
-
if not is_property:
|
245 |
-
return True
|
246 |
-
|
247 |
-
# Properties in allowed types are ok (although we do not include any
|
248 |
-
# properties in our default allow list currently).
|
249 |
-
if type(value) in self.allowed_getattr:
|
250 |
-
return True # pragma: no cover
|
251 |
-
|
252 |
-
# Properties in subclasses of allowed types may be ok if not changed
|
253 |
-
for module_name, *access_path in self.allowed_getattr_external:
|
254 |
-
try:
|
255 |
-
external_class = _get_external(module_name, access_path)
|
256 |
-
external_class_attr_val = getattr(external_class, attr)
|
257 |
-
except (KeyError, AttributeError):
|
258 |
-
return False # pragma: no cover
|
259 |
-
return class_attr_val == external_class_attr_val
|
260 |
-
|
261 |
-
return False
|
262 |
-
|
263 |
-
def can_get_item(self, value, item):
|
264 |
-
"""Allow accessing `__getiitem__` of allow-listed instances unless it was not modified."""
|
265 |
-
return _has_original_dunder(
|
266 |
-
value,
|
267 |
-
allowed_types=self.allowed_getitem,
|
268 |
-
allowed_methods=self._getitem_methods,
|
269 |
-
allowed_external=self.allowed_getitem_external,
|
270 |
-
method_name="__getitem__",
|
271 |
-
)
|
272 |
-
|
273 |
-
def can_operate(self, dunders: Tuple[str, ...], a, b=None):
|
274 |
-
objects = [a]
|
275 |
-
if b is not None:
|
276 |
-
objects.append(b)
|
277 |
-
return all(
|
278 |
-
[
|
279 |
-
_has_original_dunder(
|
280 |
-
obj,
|
281 |
-
allowed_types=self.allowed_operations,
|
282 |
-
allowed_methods=self._operator_dunder_methods(dunder),
|
283 |
-
allowed_external=self.allowed_operations_external,
|
284 |
-
method_name=dunder,
|
285 |
-
)
|
286 |
-
for dunder in dunders
|
287 |
-
for obj in objects
|
288 |
-
]
|
289 |
-
)
|
290 |
-
|
291 |
-
def _operator_dunder_methods(self, dunder: str) -> Set[Callable]:
|
292 |
-
if dunder not in self._operation_methods_cache:
|
293 |
-
self._operation_methods_cache[dunder] = self._safe_get_methods(
|
294 |
-
self.allowed_operations, dunder
|
295 |
-
)
|
296 |
-
return self._operation_methods_cache[dunder]
|
297 |
-
|
298 |
-
@cached_property
|
299 |
-
def _getitem_methods(self) -> Set[Callable]:
|
300 |
-
return self._safe_get_methods(self.allowed_getitem, "__getitem__")
|
301 |
-
|
302 |
-
@cached_property
|
303 |
-
def _getattr_methods(self) -> Set[Callable]:
|
304 |
-
return self._safe_get_methods(self.allowed_getattr, "__getattr__")
|
305 |
-
|
306 |
-
@cached_property
|
307 |
-
def _getattribute_methods(self) -> Set[Callable]:
|
308 |
-
return self._safe_get_methods(self.allowed_getattr, "__getattribute__")
|
309 |
-
|
310 |
-
def _safe_get_methods(self, classes, name) -> Set[Callable]:
|
311 |
-
return {
|
312 |
-
method
|
313 |
-
for class_ in classes
|
314 |
-
for method in [getattr(class_, name, None)]
|
315 |
-
if method
|
316 |
-
}
|
317 |
-
|
318 |
-
|
319 |
-
class _DummyNamedTuple(NamedTuple):
|
320 |
-
"""Used internally to retrieve methods of named tuple instance."""
|
321 |
-
|
322 |
-
|
323 |
-
class EvaluationContext(NamedTuple):
|
324 |
-
#: Local namespace
|
325 |
-
locals: dict
|
326 |
-
#: Global namespace
|
327 |
-
globals: dict
|
328 |
-
#: Evaluation policy identifier
|
329 |
-
evaluation: Literal["forbidden", "minimal", "limited", "unsafe", "dangerous"] = (
|
330 |
-
"forbidden"
|
331 |
-
)
|
332 |
-
#: Whether the evaluation of code takes place inside of a subscript.
|
333 |
-
#: Useful for evaluating ``:-1, 'col'`` in ``df[:-1, 'col']``.
|
334 |
-
in_subscript: bool = False
|
335 |
-
|
336 |
-
|
337 |
-
class _IdentitySubscript:
|
338 |
-
"""Returns the key itself when item is requested via subscript."""
|
339 |
-
|
340 |
-
def __getitem__(self, key):
|
341 |
-
return key
|
342 |
-
|
343 |
-
|
344 |
-
IDENTITY_SUBSCRIPT = _IdentitySubscript()
|
345 |
-
SUBSCRIPT_MARKER = "__SUBSCRIPT_SENTINEL__"
|
346 |
-
UNKNOWN_SIGNATURE = Signature()
|
347 |
-
NOT_EVALUATED = object()
|
348 |
-
|
349 |
-
|
350 |
-
class GuardRejection(Exception):
|
351 |
-
"""Exception raised when guard rejects evaluation attempt."""
|
352 |
-
|
353 |
-
pass
|
354 |
-
|
355 |
-
|
356 |
-
def guarded_eval(code: str, context: EvaluationContext):
|
357 |
-
"""Evaluate provided code in the evaluation context.
|
358 |
-
|
359 |
-
If evaluation policy given by context is set to ``forbidden``
|
360 |
-
no evaluation will be performed; if it is set to ``dangerous``
|
361 |
-
standard :func:`eval` will be used; finally, for any other,
|
362 |
-
policy :func:`eval_node` will be called on parsed AST.
|
363 |
-
"""
|
364 |
-
locals_ = context.locals
|
365 |
-
|
366 |
-
if context.evaluation == "forbidden":
|
367 |
-
raise GuardRejection("Forbidden mode")
|
368 |
-
|
369 |
-
# note: not using `ast.literal_eval` as it does not implement
|
370 |
-
# getitem at all, for example it fails on simple `[0][1]`
|
371 |
-
|
372 |
-
if context.in_subscript:
|
373 |
-
# syntactic sugar for ellipsis (:) is only available in subscripts
|
374 |
-
# so we need to trick the ast parser into thinking that we have
|
375 |
-
# a subscript, but we need to be able to later recognise that we did
|
376 |
-
# it so we can ignore the actual __getitem__ operation
|
377 |
-
if not code:
|
378 |
-
return tuple()
|
379 |
-
locals_ = locals_.copy()
|
380 |
-
locals_[SUBSCRIPT_MARKER] = IDENTITY_SUBSCRIPT
|
381 |
-
code = SUBSCRIPT_MARKER + "[" + code + "]"
|
382 |
-
context = EvaluationContext(**{**context._asdict(), **{"locals": locals_}})
|
383 |
-
|
384 |
-
if context.evaluation == "dangerous":
|
385 |
-
return eval(code, context.globals, context.locals)
|
386 |
-
|
387 |
-
expression = ast.parse(code, mode="eval")
|
388 |
-
|
389 |
-
return eval_node(expression, context)
|
390 |
-
|
391 |
-
|
392 |
-
BINARY_OP_DUNDERS: Dict[Type[ast.operator], Tuple[str]] = {
|
393 |
-
ast.Add: ("__add__",),
|
394 |
-
ast.Sub: ("__sub__",),
|
395 |
-
ast.Mult: ("__mul__",),
|
396 |
-
ast.Div: ("__truediv__",),
|
397 |
-
ast.FloorDiv: ("__floordiv__",),
|
398 |
-
ast.Mod: ("__mod__",),
|
399 |
-
ast.Pow: ("__pow__",),
|
400 |
-
ast.LShift: ("__lshift__",),
|
401 |
-
ast.RShift: ("__rshift__",),
|
402 |
-
ast.BitOr: ("__or__",),
|
403 |
-
ast.BitXor: ("__xor__",),
|
404 |
-
ast.BitAnd: ("__and__",),
|
405 |
-
ast.MatMult: ("__matmul__",),
|
406 |
-
}
|
407 |
-
|
408 |
-
COMP_OP_DUNDERS: Dict[Type[ast.cmpop], Tuple[str, ...]] = {
|
409 |
-
ast.Eq: ("__eq__",),
|
410 |
-
ast.NotEq: ("__ne__", "__eq__"),
|
411 |
-
ast.Lt: ("__lt__", "__gt__"),
|
412 |
-
ast.LtE: ("__le__", "__ge__"),
|
413 |
-
ast.Gt: ("__gt__", "__lt__"),
|
414 |
-
ast.GtE: ("__ge__", "__le__"),
|
415 |
-
ast.In: ("__contains__",),
|
416 |
-
# Note: ast.Is, ast.IsNot, ast.NotIn are handled specially
|
417 |
-
}
|
418 |
-
|
419 |
-
UNARY_OP_DUNDERS: Dict[Type[ast.unaryop], Tuple[str, ...]] = {
|
420 |
-
ast.USub: ("__neg__",),
|
421 |
-
ast.UAdd: ("__pos__",),
|
422 |
-
# we have to check both __inv__ and __invert__!
|
423 |
-
ast.Invert: ("__invert__", "__inv__"),
|
424 |
-
ast.Not: ("__not__",),
|
425 |
-
}
|
426 |
-
|
427 |
-
|
428 |
-
class ImpersonatingDuck:
|
429 |
-
"""A dummy class used to create objects of other classes without calling their ``__init__``"""
|
430 |
-
|
431 |
-
# no-op: override __class__ to impersonate
|
432 |
-
|
433 |
-
|
434 |
-
class _Duck:
|
435 |
-
"""A dummy class used to create objects pretending to have given attributes"""
|
436 |
-
|
437 |
-
def __init__(self, attributes: Optional[dict] = None, items: Optional[dict] = None):
|
438 |
-
self.attributes = attributes or {}
|
439 |
-
self.items = items or {}
|
440 |
-
|
441 |
-
def __getattr__(self, attr: str):
|
442 |
-
return self.attributes[attr]
|
443 |
-
|
444 |
-
def __hasattr__(self, attr: str):
|
445 |
-
return attr in self.attributes
|
446 |
-
|
447 |
-
def __dir__(self):
|
448 |
-
return [*dir(super), *self.attributes]
|
449 |
-
|
450 |
-
def __getitem__(self, key: str):
|
451 |
-
return self.items[key]
|
452 |
-
|
453 |
-
def __hasitem__(self, key: str):
|
454 |
-
return self.items[key]
|
455 |
-
|
456 |
-
def _ipython_key_completions_(self):
|
457 |
-
return self.items.keys()
|
458 |
-
|
459 |
-
|
460 |
-
def _find_dunder(node_op, dunders) -> Union[Tuple[str, ...], None]:
|
461 |
-
dunder = None
|
462 |
-
for op, candidate_dunder in dunders.items():
|
463 |
-
if isinstance(node_op, op):
|
464 |
-
dunder = candidate_dunder
|
465 |
-
return dunder
|
466 |
-
|
467 |
-
|
468 |
-
def eval_node(node: Union[ast.AST, None], context: EvaluationContext):
|
469 |
-
"""Evaluate AST node in provided context.
|
470 |
-
|
471 |
-
Applies evaluation restrictions defined in the context. Currently does not support evaluation of functions with keyword arguments.
|
472 |
-
|
473 |
-
Does not evaluate actions that always have side effects:
|
474 |
-
|
475 |
-
- class definitions (``class sth: ...``)
|
476 |
-
- function definitions (``def sth: ...``)
|
477 |
-
- variable assignments (``x = 1``)
|
478 |
-
- augmented assignments (``x += 1``)
|
479 |
-
- deletions (``del x``)
|
480 |
-
|
481 |
-
Does not evaluate operations which do not return values:
|
482 |
-
|
483 |
-
- assertions (``assert x``)
|
484 |
-
- pass (``pass``)
|
485 |
-
- imports (``import x``)
|
486 |
-
- control flow:
|
487 |
-
|
488 |
-
- conditionals (``if x:``) except for ternary IfExp (``a if x else b``)
|
489 |
-
- loops (``for`` and ``while``)
|
490 |
-
- exception handling
|
491 |
-
|
492 |
-
The purpose of this function is to guard against unwanted side-effects;
|
493 |
-
it does not give guarantees on protection from malicious code execution.
|
494 |
-
"""
|
495 |
-
policy = EVALUATION_POLICIES[context.evaluation]
|
496 |
-
if node is None:
|
497 |
-
return None
|
498 |
-
if isinstance(node, ast.Expression):
|
499 |
-
return eval_node(node.body, context)
|
500 |
-
if isinstance(node, ast.BinOp):
|
501 |
-
left = eval_node(node.left, context)
|
502 |
-
right = eval_node(node.right, context)
|
503 |
-
dunders = _find_dunder(node.op, BINARY_OP_DUNDERS)
|
504 |
-
if dunders:
|
505 |
-
if policy.can_operate(dunders, left, right):
|
506 |
-
return getattr(left, dunders[0])(right)
|
507 |
-
else:
|
508 |
-
raise GuardRejection(
|
509 |
-
f"Operation (`{dunders}`) for",
|
510 |
-
type(left),
|
511 |
-
f"not allowed in {context.evaluation} mode",
|
512 |
-
)
|
513 |
-
if isinstance(node, ast.Compare):
|
514 |
-
left = eval_node(node.left, context)
|
515 |
-
all_true = True
|
516 |
-
negate = False
|
517 |
-
for op, right in zip(node.ops, node.comparators):
|
518 |
-
right = eval_node(right, context)
|
519 |
-
dunder = None
|
520 |
-
dunders = _find_dunder(op, COMP_OP_DUNDERS)
|
521 |
-
if not dunders:
|
522 |
-
if isinstance(op, ast.NotIn):
|
523 |
-
dunders = COMP_OP_DUNDERS[ast.In]
|
524 |
-
negate = True
|
525 |
-
if isinstance(op, ast.Is):
|
526 |
-
dunder = "is_"
|
527 |
-
if isinstance(op, ast.IsNot):
|
528 |
-
dunder = "is_"
|
529 |
-
negate = True
|
530 |
-
if not dunder and dunders:
|
531 |
-
dunder = dunders[0]
|
532 |
-
if dunder:
|
533 |
-
a, b = (right, left) if dunder == "__contains__" else (left, right)
|
534 |
-
if dunder == "is_" or dunders and policy.can_operate(dunders, a, b):
|
535 |
-
result = getattr(operator, dunder)(a, b)
|
536 |
-
if negate:
|
537 |
-
result = not result
|
538 |
-
if not result:
|
539 |
-
all_true = False
|
540 |
-
left = right
|
541 |
-
else:
|
542 |
-
raise GuardRejection(
|
543 |
-
f"Comparison (`{dunder}`) for",
|
544 |
-
type(left),
|
545 |
-
f"not allowed in {context.evaluation} mode",
|
546 |
-
)
|
547 |
-
else:
|
548 |
-
raise ValueError(
|
549 |
-
f"Comparison `{dunder}` not supported"
|
550 |
-
) # pragma: no cover
|
551 |
-
return all_true
|
552 |
-
if isinstance(node, ast.Constant):
|
553 |
-
return node.value
|
554 |
-
if isinstance(node, ast.Tuple):
|
555 |
-
return tuple(eval_node(e, context) for e in node.elts)
|
556 |
-
if isinstance(node, ast.List):
|
557 |
-
return [eval_node(e, context) for e in node.elts]
|
558 |
-
if isinstance(node, ast.Set):
|
559 |
-
return {eval_node(e, context) for e in node.elts}
|
560 |
-
if isinstance(node, ast.Dict):
|
561 |
-
return dict(
|
562 |
-
zip(
|
563 |
-
[eval_node(k, context) for k in node.keys],
|
564 |
-
[eval_node(v, context) for v in node.values],
|
565 |
-
)
|
566 |
-
)
|
567 |
-
if isinstance(node, ast.Slice):
|
568 |
-
return slice(
|
569 |
-
eval_node(node.lower, context),
|
570 |
-
eval_node(node.upper, context),
|
571 |
-
eval_node(node.step, context),
|
572 |
-
)
|
573 |
-
if isinstance(node, ast.UnaryOp):
|
574 |
-
value = eval_node(node.operand, context)
|
575 |
-
dunders = _find_dunder(node.op, UNARY_OP_DUNDERS)
|
576 |
-
if dunders:
|
577 |
-
if policy.can_operate(dunders, value):
|
578 |
-
return getattr(value, dunders[0])()
|
579 |
-
else:
|
580 |
-
raise GuardRejection(
|
581 |
-
f"Operation (`{dunders}`) for",
|
582 |
-
type(value),
|
583 |
-
f"not allowed in {context.evaluation} mode",
|
584 |
-
)
|
585 |
-
if isinstance(node, ast.Subscript):
|
586 |
-
value = eval_node(node.value, context)
|
587 |
-
slice_ = eval_node(node.slice, context)
|
588 |
-
if policy.can_get_item(value, slice_):
|
589 |
-
return value[slice_]
|
590 |
-
raise GuardRejection(
|
591 |
-
"Subscript access (`__getitem__`) for",
|
592 |
-
type(value), # not joined to avoid calling `repr`
|
593 |
-
f" not allowed in {context.evaluation} mode",
|
594 |
-
)
|
595 |
-
if isinstance(node, ast.Name):
|
596 |
-
return _eval_node_name(node.id, context)
|
597 |
-
if isinstance(node, ast.Attribute):
|
598 |
-
value = eval_node(node.value, context)
|
599 |
-
if policy.can_get_attr(value, node.attr):
|
600 |
-
return getattr(value, node.attr)
|
601 |
-
raise GuardRejection(
|
602 |
-
"Attribute access (`__getattr__`) for",
|
603 |
-
type(value), # not joined to avoid calling `repr`
|
604 |
-
f"not allowed in {context.evaluation} mode",
|
605 |
-
)
|
606 |
-
if isinstance(node, ast.IfExp):
|
607 |
-
test = eval_node(node.test, context)
|
608 |
-
if test:
|
609 |
-
return eval_node(node.body, context)
|
610 |
-
else:
|
611 |
-
return eval_node(node.orelse, context)
|
612 |
-
if isinstance(node, ast.Call):
|
613 |
-
func = eval_node(node.func, context)
|
614 |
-
if policy.can_call(func) and not node.keywords:
|
615 |
-
args = [eval_node(arg, context) for arg in node.args]
|
616 |
-
return func(*args)
|
617 |
-
if isclass(func):
|
618 |
-
# this code path gets entered when calling class e.g. `MyClass()`
|
619 |
-
# or `my_instance.__class__()` - in both cases `func` is `MyClass`.
|
620 |
-
# Should return `MyClass` if `__new__` is not overridden,
|
621 |
-
# otherwise whatever `__new__` return type is.
|
622 |
-
overridden_return_type = _eval_return_type(func.__new__, node, context)
|
623 |
-
if overridden_return_type is not NOT_EVALUATED:
|
624 |
-
return overridden_return_type
|
625 |
-
return _create_duck_for_heap_type(func)
|
626 |
-
else:
|
627 |
-
return_type = _eval_return_type(func, node, context)
|
628 |
-
if return_type is not NOT_EVALUATED:
|
629 |
-
return return_type
|
630 |
-
raise GuardRejection(
|
631 |
-
"Call for",
|
632 |
-
func, # not joined to avoid calling `repr`
|
633 |
-
f"not allowed in {context.evaluation} mode",
|
634 |
-
)
|
635 |
-
raise ValueError("Unhandled node", ast.dump(node))
|
636 |
-
|
637 |
-
|
638 |
-
def _eval_return_type(func: Callable, node: ast.Call, context: EvaluationContext):
|
639 |
-
"""Evaluate return type of a given callable function.
|
640 |
-
|
641 |
-
Returns the built-in type, a duck or NOT_EVALUATED sentinel.
|
642 |
-
"""
|
643 |
-
try:
|
644 |
-
sig = signature(func)
|
645 |
-
except ValueError:
|
646 |
-
sig = UNKNOWN_SIGNATURE
|
647 |
-
# if annotation was not stringized, or it was stringized
|
648 |
-
# but resolved by signature call we know the return type
|
649 |
-
not_empty = sig.return_annotation is not Signature.empty
|
650 |
-
if not_empty:
|
651 |
-
return _resolve_annotation(sig.return_annotation, sig, func, node, context)
|
652 |
-
return NOT_EVALUATED
|
653 |
-
|
654 |
-
|
655 |
-
def _resolve_annotation(
|
656 |
-
annotation,
|
657 |
-
sig: Signature,
|
658 |
-
func: Callable,
|
659 |
-
node: ast.Call,
|
660 |
-
context: EvaluationContext,
|
661 |
-
):
|
662 |
-
"""Resolve annotation created by user with `typing` module and custom objects."""
|
663 |
-
annotation = (
|
664 |
-
_eval_node_name(annotation, context)
|
665 |
-
if isinstance(annotation, str)
|
666 |
-
else annotation
|
667 |
-
)
|
668 |
-
origin = get_origin(annotation)
|
669 |
-
if annotation is Self and hasattr(func, "__self__"):
|
670 |
-
return func.__self__
|
671 |
-
elif origin is Literal:
|
672 |
-
type_args = get_args(annotation)
|
673 |
-
if len(type_args) == 1:
|
674 |
-
return type_args[0]
|
675 |
-
elif annotation is LiteralString:
|
676 |
-
return ""
|
677 |
-
elif annotation is AnyStr:
|
678 |
-
index = None
|
679 |
-
for i, (key, value) in enumerate(sig.parameters.items()):
|
680 |
-
if value.annotation is AnyStr:
|
681 |
-
index = i
|
682 |
-
break
|
683 |
-
if index is not None and index < len(node.args):
|
684 |
-
return eval_node(node.args[index], context)
|
685 |
-
elif origin is TypeGuard:
|
686 |
-
return bool()
|
687 |
-
elif origin is Union:
|
688 |
-
attributes = [
|
689 |
-
attr
|
690 |
-
for type_arg in get_args(annotation)
|
691 |
-
for attr in dir(_resolve_annotation(type_arg, sig, func, node, context))
|
692 |
-
]
|
693 |
-
return _Duck(attributes=dict.fromkeys(attributes))
|
694 |
-
elif is_typeddict(annotation):
|
695 |
-
return _Duck(
|
696 |
-
attributes=dict.fromkeys(dir(dict())),
|
697 |
-
items={
|
698 |
-
k: _resolve_annotation(v, sig, func, node, context)
|
699 |
-
for k, v in annotation.__annotations__.items()
|
700 |
-
},
|
701 |
-
)
|
702 |
-
elif hasattr(annotation, "_is_protocol"):
|
703 |
-
return _Duck(attributes=dict.fromkeys(dir(annotation)))
|
704 |
-
elif origin is Annotated:
|
705 |
-
type_arg = get_args(annotation)[0]
|
706 |
-
return _resolve_annotation(type_arg, sig, func, node, context)
|
707 |
-
elif isinstance(annotation, NewType):
|
708 |
-
return _eval_or_create_duck(annotation.__supertype__, node, context)
|
709 |
-
elif isinstance(annotation, TypeAliasType):
|
710 |
-
return _eval_or_create_duck(annotation.__value__, node, context)
|
711 |
-
else:
|
712 |
-
return _eval_or_create_duck(annotation, node, context)
|
713 |
-
|
714 |
-
|
715 |
-
def _eval_node_name(node_id: str, context: EvaluationContext):
|
716 |
-
policy = EVALUATION_POLICIES[context.evaluation]
|
717 |
-
if policy.allow_locals_access and node_id in context.locals:
|
718 |
-
return context.locals[node_id]
|
719 |
-
if policy.allow_globals_access and node_id in context.globals:
|
720 |
-
return context.globals[node_id]
|
721 |
-
if policy.allow_builtins_access and hasattr(builtins, node_id):
|
722 |
-
# note: do not use __builtins__, it is implementation detail of cPython
|
723 |
-
return getattr(builtins, node_id)
|
724 |
-
if not policy.allow_globals_access and not policy.allow_locals_access:
|
725 |
-
raise GuardRejection(
|
726 |
-
f"Namespace access not allowed in {context.evaluation} mode"
|
727 |
-
)
|
728 |
-
else:
|
729 |
-
raise NameError(f"{node_id} not found in locals, globals, nor builtins")
|
730 |
-
|
731 |
-
|
732 |
-
def _eval_or_create_duck(duck_type, node: ast.Call, context: EvaluationContext):
|
733 |
-
policy = EVALUATION_POLICIES[context.evaluation]
|
734 |
-
# if allow-listed builtin is on type annotation, instantiate it
|
735 |
-
if policy.can_call(duck_type) and not node.keywords:
|
736 |
-
args = [eval_node(arg, context) for arg in node.args]
|
737 |
-
return duck_type(*args)
|
738 |
-
# if custom class is in type annotation, mock it
|
739 |
-
return _create_duck_for_heap_type(duck_type)
|
740 |
-
|
741 |
-
|
742 |
-
def _create_duck_for_heap_type(duck_type):
|
743 |
-
"""Create an imitation of an object of a given type (a duck).
|
744 |
-
|
745 |
-
Returns the duck or NOT_EVALUATED sentinel if duck could not be created.
|
746 |
-
"""
|
747 |
-
duck = ImpersonatingDuck()
|
748 |
-
try:
|
749 |
-
# this only works for heap types, not builtins
|
750 |
-
duck.__class__ = duck_type
|
751 |
-
return duck
|
752 |
-
except TypeError:
|
753 |
-
pass
|
754 |
-
return NOT_EVALUATED
|
755 |
-
|
756 |
-
|
757 |
-
SUPPORTED_EXTERNAL_GETITEM = {
|
758 |
-
("pandas", "core", "indexing", "_iLocIndexer"),
|
759 |
-
("pandas", "core", "indexing", "_LocIndexer"),
|
760 |
-
("pandas", "DataFrame"),
|
761 |
-
("pandas", "Series"),
|
762 |
-
("numpy", "ndarray"),
|
763 |
-
("numpy", "void"),
|
764 |
-
}
|
765 |
-
|
766 |
-
|
767 |
-
BUILTIN_GETITEM: Set[InstancesHaveGetItem] = {
|
768 |
-
dict,
|
769 |
-
str, # type: ignore[arg-type]
|
770 |
-
bytes, # type: ignore[arg-type]
|
771 |
-
list,
|
772 |
-
tuple,
|
773 |
-
collections.defaultdict,
|
774 |
-
collections.deque,
|
775 |
-
collections.OrderedDict,
|
776 |
-
collections.ChainMap,
|
777 |
-
collections.UserDict,
|
778 |
-
collections.UserList,
|
779 |
-
collections.UserString, # type: ignore[arg-type]
|
780 |
-
_DummyNamedTuple,
|
781 |
-
_IdentitySubscript,
|
782 |
-
}
|
783 |
-
|
784 |
-
|
785 |
-
def _list_methods(cls, source=None):
|
786 |
-
"""For use on immutable objects or with methods returning a copy"""
|
787 |
-
return [getattr(cls, k) for k in (source if source else dir(cls))]
|
788 |
-
|
789 |
-
|
790 |
-
dict_non_mutating_methods = ("copy", "keys", "values", "items")
|
791 |
-
list_non_mutating_methods = ("copy", "index", "count")
|
792 |
-
set_non_mutating_methods = set(dir(set)) & set(dir(frozenset))
|
793 |
-
|
794 |
-
|
795 |
-
dict_keys: Type[collections.abc.KeysView] = type({}.keys())
|
796 |
-
|
797 |
-
NUMERICS = {int, float, complex}
|
798 |
-
|
799 |
-
ALLOWED_CALLS = {
|
800 |
-
bytes,
|
801 |
-
*_list_methods(bytes),
|
802 |
-
dict,
|
803 |
-
*_list_methods(dict, dict_non_mutating_methods),
|
804 |
-
dict_keys.isdisjoint,
|
805 |
-
list,
|
806 |
-
*_list_methods(list, list_non_mutating_methods),
|
807 |
-
set,
|
808 |
-
*_list_methods(set, set_non_mutating_methods),
|
809 |
-
frozenset,
|
810 |
-
*_list_methods(frozenset),
|
811 |
-
range,
|
812 |
-
str,
|
813 |
-
*_list_methods(str),
|
814 |
-
tuple,
|
815 |
-
*_list_methods(tuple),
|
816 |
-
*NUMERICS,
|
817 |
-
*[method for numeric_cls in NUMERICS for method in _list_methods(numeric_cls)],
|
818 |
-
collections.deque,
|
819 |
-
*_list_methods(collections.deque, list_non_mutating_methods),
|
820 |
-
collections.defaultdict,
|
821 |
-
*_list_methods(collections.defaultdict, dict_non_mutating_methods),
|
822 |
-
collections.OrderedDict,
|
823 |
-
*_list_methods(collections.OrderedDict, dict_non_mutating_methods),
|
824 |
-
collections.UserDict,
|
825 |
-
*_list_methods(collections.UserDict, dict_non_mutating_methods),
|
826 |
-
collections.UserList,
|
827 |
-
*_list_methods(collections.UserList, list_non_mutating_methods),
|
828 |
-
collections.UserString,
|
829 |
-
*_list_methods(collections.UserString, dir(str)),
|
830 |
-
collections.Counter,
|
831 |
-
*_list_methods(collections.Counter, dict_non_mutating_methods),
|
832 |
-
collections.Counter.elements,
|
833 |
-
collections.Counter.most_common,
|
834 |
-
}
|
835 |
-
|
836 |
-
BUILTIN_GETATTR: Set[MayHaveGetattr] = {
|
837 |
-
*BUILTIN_GETITEM,
|
838 |
-
set,
|
839 |
-
frozenset,
|
840 |
-
object,
|
841 |
-
type, # `type` handles a lot of generic cases, e.g. numbers as in `int.real`.
|
842 |
-
*NUMERICS,
|
843 |
-
dict_keys,
|
844 |
-
MethodDescriptorType,
|
845 |
-
ModuleType,
|
846 |
-
}
|
847 |
-
|
848 |
-
|
849 |
-
BUILTIN_OPERATIONS = {*BUILTIN_GETATTR}
|
850 |
-
|
851 |
-
EVALUATION_POLICIES = {
|
852 |
-
"minimal": EvaluationPolicy(
|
853 |
-
allow_builtins_access=True,
|
854 |
-
allow_locals_access=False,
|
855 |
-
allow_globals_access=False,
|
856 |
-
allow_item_access=False,
|
857 |
-
allow_attr_access=False,
|
858 |
-
allowed_calls=set(),
|
859 |
-
allow_any_calls=False,
|
860 |
-
allow_all_operations=False,
|
861 |
-
),
|
862 |
-
"limited": SelectivePolicy(
|
863 |
-
allowed_getitem=BUILTIN_GETITEM,
|
864 |
-
allowed_getitem_external=SUPPORTED_EXTERNAL_GETITEM,
|
865 |
-
allowed_getattr=BUILTIN_GETATTR,
|
866 |
-
allowed_getattr_external={
|
867 |
-
# pandas Series/Frame implements custom `__getattr__`
|
868 |
-
("pandas", "DataFrame"),
|
869 |
-
("pandas", "Series"),
|
870 |
-
},
|
871 |
-
allowed_operations=BUILTIN_OPERATIONS,
|
872 |
-
allow_builtins_access=True,
|
873 |
-
allow_locals_access=True,
|
874 |
-
allow_globals_access=True,
|
875 |
-
allowed_calls=ALLOWED_CALLS,
|
876 |
-
),
|
877 |
-
"unsafe": EvaluationPolicy(
|
878 |
-
allow_builtins_access=True,
|
879 |
-
allow_locals_access=True,
|
880 |
-
allow_globals_access=True,
|
881 |
-
allow_attr_access=True,
|
882 |
-
allow_item_access=True,
|
883 |
-
allow_any_calls=True,
|
884 |
-
allow_all_operations=True,
|
885 |
-
),
|
886 |
-
}
|
887 |
-
|
888 |
-
|
889 |
-
__all__ = [
|
890 |
-
"guarded_eval",
|
891 |
-
"eval_node",
|
892 |
-
"GuardRejection",
|
893 |
-
"EvaluationContext",
|
894 |
-
"_unbind_method",
|
895 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/history.py
DELETED
@@ -1,989 +0,0 @@
|
|
1 |
-
""" History related magics and functionality """
|
2 |
-
|
3 |
-
# Copyright (c) IPython Development Team.
|
4 |
-
# Distributed under the terms of the Modified BSD License.
|
5 |
-
|
6 |
-
|
7 |
-
import atexit
|
8 |
-
import datetime
|
9 |
-
import re
|
10 |
-
import sqlite3
|
11 |
-
import threading
|
12 |
-
from pathlib import Path
|
13 |
-
|
14 |
-
from decorator import decorator
|
15 |
-
from traitlets import (
|
16 |
-
Any,
|
17 |
-
Bool,
|
18 |
-
Dict,
|
19 |
-
Instance,
|
20 |
-
Integer,
|
21 |
-
List,
|
22 |
-
TraitError,
|
23 |
-
Unicode,
|
24 |
-
Union,
|
25 |
-
default,
|
26 |
-
observe,
|
27 |
-
)
|
28 |
-
from traitlets.config.configurable import LoggingConfigurable
|
29 |
-
|
30 |
-
from IPython.paths import locate_profile
|
31 |
-
from IPython.utils.decorators import undoc
|
32 |
-
|
33 |
-
#-----------------------------------------------------------------------------
|
34 |
-
# Classes and functions
|
35 |
-
#-----------------------------------------------------------------------------
|
36 |
-
|
37 |
-
@undoc
|
38 |
-
class DummyDB(object):
|
39 |
-
"""Dummy DB that will act as a black hole for history.
|
40 |
-
|
41 |
-
Only used in the absence of sqlite"""
|
42 |
-
def execute(*args, **kwargs):
|
43 |
-
return []
|
44 |
-
|
45 |
-
def commit(self, *args, **kwargs):
|
46 |
-
pass
|
47 |
-
|
48 |
-
def __enter__(self, *args, **kwargs):
|
49 |
-
pass
|
50 |
-
|
51 |
-
def __exit__(self, *args, **kwargs):
|
52 |
-
pass
|
53 |
-
|
54 |
-
|
55 |
-
@decorator
|
56 |
-
def only_when_enabled(f, self, *a, **kw):
|
57 |
-
"""Decorator: return an empty list in the absence of sqlite."""
|
58 |
-
if not self.enabled:
|
59 |
-
return []
|
60 |
-
else:
|
61 |
-
return f(self, *a, **kw)
|
62 |
-
|
63 |
-
|
64 |
-
# use 16kB as threshold for whether a corrupt history db should be saved
|
65 |
-
# that should be at least 100 entries or so
|
66 |
-
_SAVE_DB_SIZE = 16384
|
67 |
-
|
68 |
-
@decorator
|
69 |
-
def catch_corrupt_db(f, self, *a, **kw):
|
70 |
-
"""A decorator which wraps HistoryAccessor method calls to catch errors from
|
71 |
-
a corrupt SQLite database, move the old database out of the way, and create
|
72 |
-
a new one.
|
73 |
-
|
74 |
-
We avoid clobbering larger databases because this may be triggered due to filesystem issues,
|
75 |
-
not just a corrupt file.
|
76 |
-
"""
|
77 |
-
try:
|
78 |
-
return f(self, *a, **kw)
|
79 |
-
except (sqlite3.DatabaseError, sqlite3.OperationalError) as e:
|
80 |
-
self._corrupt_db_counter += 1
|
81 |
-
self.log.error("Failed to open SQLite history %s (%s).", self.hist_file, e)
|
82 |
-
if self.hist_file != ':memory:':
|
83 |
-
if self._corrupt_db_counter > self._corrupt_db_limit:
|
84 |
-
self.hist_file = ':memory:'
|
85 |
-
self.log.error("Failed to load history too many times, history will not be saved.")
|
86 |
-
elif self.hist_file.is_file():
|
87 |
-
# move the file out of the way
|
88 |
-
base = str(self.hist_file.parent / self.hist_file.stem)
|
89 |
-
ext = self.hist_file.suffix
|
90 |
-
size = self.hist_file.stat().st_size
|
91 |
-
if size >= _SAVE_DB_SIZE:
|
92 |
-
# if there's significant content, avoid clobbering
|
93 |
-
now = datetime.datetime.now().isoformat().replace(':', '.')
|
94 |
-
newpath = base + '-corrupt-' + now + ext
|
95 |
-
# don't clobber previous corrupt backups
|
96 |
-
for i in range(100):
|
97 |
-
if not Path(newpath).exists():
|
98 |
-
break
|
99 |
-
else:
|
100 |
-
newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext
|
101 |
-
else:
|
102 |
-
# not much content, possibly empty; don't worry about clobbering
|
103 |
-
# maybe we should just delete it?
|
104 |
-
newpath = base + '-corrupt' + ext
|
105 |
-
self.hist_file.rename(newpath)
|
106 |
-
self.log.error("History file was moved to %s and a new file created.", newpath)
|
107 |
-
self.init_db()
|
108 |
-
return []
|
109 |
-
else:
|
110 |
-
# Failed with :memory:, something serious is wrong
|
111 |
-
raise
|
112 |
-
|
113 |
-
|
114 |
-
class HistoryAccessorBase(LoggingConfigurable):
|
115 |
-
"""An abstract class for History Accessors """
|
116 |
-
|
117 |
-
def get_tail(self, n=10, raw=True, output=False, include_latest=False):
|
118 |
-
raise NotImplementedError
|
119 |
-
|
120 |
-
def search(self, pattern="*", raw=True, search_raw=True,
|
121 |
-
output=False, n=None, unique=False):
|
122 |
-
raise NotImplementedError
|
123 |
-
|
124 |
-
def get_range(self, session, start=1, stop=None, raw=True,output=False):
|
125 |
-
raise NotImplementedError
|
126 |
-
|
127 |
-
def get_range_by_str(self, rangestr, raw=True, output=False):
|
128 |
-
raise NotImplementedError
|
129 |
-
|
130 |
-
|
131 |
-
class HistoryAccessor(HistoryAccessorBase):
|
132 |
-
"""Access the history database without adding to it.
|
133 |
-
|
134 |
-
This is intended for use by standalone history tools. IPython shells use
|
135 |
-
HistoryManager, below, which is a subclass of this."""
|
136 |
-
|
137 |
-
# counter for init_db retries, so we don't keep trying over and over
|
138 |
-
_corrupt_db_counter = 0
|
139 |
-
# after two failures, fallback on :memory:
|
140 |
-
_corrupt_db_limit = 2
|
141 |
-
|
142 |
-
# String holding the path to the history file
|
143 |
-
hist_file = Union(
|
144 |
-
[Instance(Path), Unicode()],
|
145 |
-
help="""Path to file to use for SQLite history database.
|
146 |
-
|
147 |
-
By default, IPython will put the history database in the IPython
|
148 |
-
profile directory. If you would rather share one history among
|
149 |
-
profiles, you can set this value in each, so that they are consistent.
|
150 |
-
|
151 |
-
Due to an issue with fcntl, SQLite is known to misbehave on some NFS
|
152 |
-
mounts. If you see IPython hanging, try setting this to something on a
|
153 |
-
local disk, e.g::
|
154 |
-
|
155 |
-
ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
|
156 |
-
|
157 |
-
you can also use the specific value `:memory:` (including the colon
|
158 |
-
at both end but not the back ticks), to avoid creating an history file.
|
159 |
-
|
160 |
-
""",
|
161 |
-
).tag(config=True)
|
162 |
-
|
163 |
-
enabled = Bool(True,
|
164 |
-
help="""enable the SQLite history
|
165 |
-
|
166 |
-
set enabled=False to disable the SQLite history,
|
167 |
-
in which case there will be no stored history, no SQLite connection,
|
168 |
-
and no background saving thread. This may be necessary in some
|
169 |
-
threaded environments where IPython is embedded.
|
170 |
-
""",
|
171 |
-
).tag(config=True)
|
172 |
-
|
173 |
-
connection_options = Dict(
|
174 |
-
help="""Options for configuring the SQLite connection
|
175 |
-
|
176 |
-
These options are passed as keyword args to sqlite3.connect
|
177 |
-
when establishing database connections.
|
178 |
-
"""
|
179 |
-
).tag(config=True)
|
180 |
-
|
181 |
-
@default("connection_options")
|
182 |
-
def _default_connection_options(self):
|
183 |
-
return dict(check_same_thread=False)
|
184 |
-
|
185 |
-
# The SQLite database
|
186 |
-
db = Any()
|
187 |
-
@observe('db')
|
188 |
-
def _db_changed(self, change):
|
189 |
-
"""validate the db, since it can be an Instance of two different types"""
|
190 |
-
new = change['new']
|
191 |
-
connection_types = (DummyDB, sqlite3.Connection)
|
192 |
-
if not isinstance(new, connection_types):
|
193 |
-
msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
|
194 |
-
(self.__class__.__name__, new)
|
195 |
-
raise TraitError(msg)
|
196 |
-
|
197 |
-
def __init__(self, profile="default", hist_file="", **traits):
|
198 |
-
"""Create a new history accessor.
|
199 |
-
|
200 |
-
Parameters
|
201 |
-
----------
|
202 |
-
profile : str
|
203 |
-
The name of the profile from which to open history.
|
204 |
-
hist_file : str
|
205 |
-
Path to an SQLite history database stored by IPython. If specified,
|
206 |
-
hist_file overrides profile.
|
207 |
-
config : :class:`~traitlets.config.loader.Config`
|
208 |
-
Config object. hist_file can also be set through this.
|
209 |
-
"""
|
210 |
-
super(HistoryAccessor, self).__init__(**traits)
|
211 |
-
# defer setting hist_file from kwarg until after init,
|
212 |
-
# otherwise the default kwarg value would clobber any value
|
213 |
-
# set by config
|
214 |
-
if hist_file:
|
215 |
-
self.hist_file = hist_file
|
216 |
-
|
217 |
-
try:
|
218 |
-
self.hist_file
|
219 |
-
except TraitError:
|
220 |
-
# No one has set the hist_file, yet.
|
221 |
-
self.hist_file = self._get_hist_file_name(profile)
|
222 |
-
|
223 |
-
self.init_db()
|
224 |
-
|
225 |
-
def _get_hist_file_name(self, profile='default'):
|
226 |
-
"""Find the history file for the given profile name.
|
227 |
-
|
228 |
-
This is overridden by the HistoryManager subclass, to use the shell's
|
229 |
-
active profile.
|
230 |
-
|
231 |
-
Parameters
|
232 |
-
----------
|
233 |
-
profile : str
|
234 |
-
The name of a profile which has a history file.
|
235 |
-
"""
|
236 |
-
return Path(locate_profile(profile)) / "history.sqlite"
|
237 |
-
|
238 |
-
@catch_corrupt_db
|
239 |
-
def init_db(self):
|
240 |
-
"""Connect to the database, and create tables if necessary."""
|
241 |
-
if not self.enabled:
|
242 |
-
self.db = DummyDB()
|
243 |
-
return
|
244 |
-
|
245 |
-
# use detect_types so that timestamps return datetime objects
|
246 |
-
kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
|
247 |
-
kwargs.update(self.connection_options)
|
248 |
-
self.db = sqlite3.connect(str(self.hist_file), **kwargs)
|
249 |
-
with self.db:
|
250 |
-
self.db.execute(
|
251 |
-
"""CREATE TABLE IF NOT EXISTS sessions (session integer
|
252 |
-
primary key autoincrement, start timestamp,
|
253 |
-
end timestamp, num_cmds integer, remark text)"""
|
254 |
-
)
|
255 |
-
self.db.execute(
|
256 |
-
"""CREATE TABLE IF NOT EXISTS history
|
257 |
-
(session integer, line integer, source text, source_raw text,
|
258 |
-
PRIMARY KEY (session, line))"""
|
259 |
-
)
|
260 |
-
# Output history is optional, but ensure the table's there so it can be
|
261 |
-
# enabled later.
|
262 |
-
self.db.execute(
|
263 |
-
"""CREATE TABLE IF NOT EXISTS output_history
|
264 |
-
(session integer, line integer, output text,
|
265 |
-
PRIMARY KEY (session, line))"""
|
266 |
-
)
|
267 |
-
# success! reset corrupt db count
|
268 |
-
self._corrupt_db_counter = 0
|
269 |
-
|
270 |
-
def writeout_cache(self):
|
271 |
-
"""Overridden by HistoryManager to dump the cache before certain
|
272 |
-
database lookups."""
|
273 |
-
pass
|
274 |
-
|
275 |
-
## -------------------------------
|
276 |
-
## Methods for retrieving history:
|
277 |
-
## -------------------------------
|
278 |
-
def _run_sql(self, sql, params, raw=True, output=False, latest=False):
|
279 |
-
"""Prepares and runs an SQL query for the history database.
|
280 |
-
|
281 |
-
Parameters
|
282 |
-
----------
|
283 |
-
sql : str
|
284 |
-
Any filtering expressions to go after SELECT ... FROM ...
|
285 |
-
params : tuple
|
286 |
-
Parameters passed to the SQL query (to replace "?")
|
287 |
-
raw, output : bool
|
288 |
-
See :meth:`get_range`
|
289 |
-
latest : bool
|
290 |
-
Select rows with max (session, line)
|
291 |
-
|
292 |
-
Returns
|
293 |
-
-------
|
294 |
-
Tuples as :meth:`get_range`
|
295 |
-
"""
|
296 |
-
toget = 'source_raw' if raw else 'source'
|
297 |
-
sqlfrom = "history"
|
298 |
-
if output:
|
299 |
-
sqlfrom = "history LEFT JOIN output_history USING (session, line)"
|
300 |
-
toget = "history.%s, output_history.output" % toget
|
301 |
-
if latest:
|
302 |
-
toget += ", MAX(session * 128 * 1024 + line)"
|
303 |
-
this_querry = "SELECT session, line, %s FROM %s " % (toget, sqlfrom) + sql
|
304 |
-
cur = self.db.execute(this_querry, params)
|
305 |
-
if latest:
|
306 |
-
cur = (row[:-1] for row in cur)
|
307 |
-
if output: # Regroup into 3-tuples, and parse JSON
|
308 |
-
return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
|
309 |
-
return cur
|
310 |
-
|
311 |
-
@only_when_enabled
|
312 |
-
@catch_corrupt_db
|
313 |
-
def get_session_info(self, session):
|
314 |
-
"""Get info about a session.
|
315 |
-
|
316 |
-
Parameters
|
317 |
-
----------
|
318 |
-
session : int
|
319 |
-
Session number to retrieve.
|
320 |
-
|
321 |
-
Returns
|
322 |
-
-------
|
323 |
-
session_id : int
|
324 |
-
Session ID number
|
325 |
-
start : datetime
|
326 |
-
Timestamp for the start of the session.
|
327 |
-
end : datetime
|
328 |
-
Timestamp for the end of the session, or None if IPython crashed.
|
329 |
-
num_cmds : int
|
330 |
-
Number of commands run, or None if IPython crashed.
|
331 |
-
remark : unicode
|
332 |
-
A manually set description.
|
333 |
-
"""
|
334 |
-
query = "SELECT * from sessions where session == ?"
|
335 |
-
return self.db.execute(query, (session,)).fetchone()
|
336 |
-
|
337 |
-
@catch_corrupt_db
|
338 |
-
def get_last_session_id(self):
|
339 |
-
"""Get the last session ID currently in the database.
|
340 |
-
|
341 |
-
Within IPython, this should be the same as the value stored in
|
342 |
-
:attr:`HistoryManager.session_number`.
|
343 |
-
"""
|
344 |
-
for record in self.get_tail(n=1, include_latest=True):
|
345 |
-
return record[0]
|
346 |
-
|
347 |
-
@catch_corrupt_db
|
348 |
-
def get_tail(self, n=10, raw=True, output=False, include_latest=False):
|
349 |
-
"""Get the last n lines from the history database.
|
350 |
-
|
351 |
-
Parameters
|
352 |
-
----------
|
353 |
-
n : int
|
354 |
-
The number of lines to get
|
355 |
-
raw, output : bool
|
356 |
-
See :meth:`get_range`
|
357 |
-
include_latest : bool
|
358 |
-
If False (default), n+1 lines are fetched, and the latest one
|
359 |
-
is discarded. This is intended to be used where the function
|
360 |
-
is called by a user command, which it should not return.
|
361 |
-
|
362 |
-
Returns
|
363 |
-
-------
|
364 |
-
Tuples as :meth:`get_range`
|
365 |
-
"""
|
366 |
-
self.writeout_cache()
|
367 |
-
if not include_latest:
|
368 |
-
n += 1
|
369 |
-
cur = self._run_sql(
|
370 |
-
"ORDER BY session DESC, line DESC LIMIT ?", (n,), raw=raw, output=output
|
371 |
-
)
|
372 |
-
if not include_latest:
|
373 |
-
return reversed(list(cur)[1:])
|
374 |
-
return reversed(list(cur))
|
375 |
-
|
376 |
-
@catch_corrupt_db
|
377 |
-
def search(self, pattern="*", raw=True, search_raw=True,
|
378 |
-
output=False, n=None, unique=False):
|
379 |
-
"""Search the database using unix glob-style matching (wildcards
|
380 |
-
* and ?).
|
381 |
-
|
382 |
-
Parameters
|
383 |
-
----------
|
384 |
-
pattern : str
|
385 |
-
The wildcarded pattern to match when searching
|
386 |
-
search_raw : bool
|
387 |
-
If True, search the raw input, otherwise, the parsed input
|
388 |
-
raw, output : bool
|
389 |
-
See :meth:`get_range`
|
390 |
-
n : None or int
|
391 |
-
If an integer is given, it defines the limit of
|
392 |
-
returned entries.
|
393 |
-
unique : bool
|
394 |
-
When it is true, return only unique entries.
|
395 |
-
|
396 |
-
Returns
|
397 |
-
-------
|
398 |
-
Tuples as :meth:`get_range`
|
399 |
-
"""
|
400 |
-
tosearch = "source_raw" if search_raw else "source"
|
401 |
-
if output:
|
402 |
-
tosearch = "history." + tosearch
|
403 |
-
self.writeout_cache()
|
404 |
-
sqlform = "WHERE %s GLOB ?" % tosearch
|
405 |
-
params = (pattern,)
|
406 |
-
if unique:
|
407 |
-
sqlform += ' GROUP BY {0}'.format(tosearch)
|
408 |
-
if n is not None:
|
409 |
-
sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
|
410 |
-
params += (n,)
|
411 |
-
elif unique:
|
412 |
-
sqlform += " ORDER BY session, line"
|
413 |
-
cur = self._run_sql(sqlform, params, raw=raw, output=output, latest=unique)
|
414 |
-
if n is not None:
|
415 |
-
return reversed(list(cur))
|
416 |
-
return cur
|
417 |
-
|
418 |
-
@catch_corrupt_db
|
419 |
-
def get_range(self, session, start=1, stop=None, raw=True,output=False):
|
420 |
-
"""Retrieve input by session.
|
421 |
-
|
422 |
-
Parameters
|
423 |
-
----------
|
424 |
-
session : int
|
425 |
-
Session number to retrieve.
|
426 |
-
start : int
|
427 |
-
First line to retrieve.
|
428 |
-
stop : int
|
429 |
-
End of line range (excluded from output itself). If None, retrieve
|
430 |
-
to the end of the session.
|
431 |
-
raw : bool
|
432 |
-
If True, return untranslated input
|
433 |
-
output : bool
|
434 |
-
If True, attempt to include output. This will be 'real' Python
|
435 |
-
objects for the current session, or text reprs from previous
|
436 |
-
sessions if db_log_output was enabled at the time. Where no output
|
437 |
-
is found, None is used.
|
438 |
-
|
439 |
-
Returns
|
440 |
-
-------
|
441 |
-
entries
|
442 |
-
An iterator over the desired lines. Each line is a 3-tuple, either
|
443 |
-
(session, line, input) if output is False, or
|
444 |
-
(session, line, (input, output)) if output is True.
|
445 |
-
"""
|
446 |
-
if stop:
|
447 |
-
lineclause = "line >= ? AND line < ?"
|
448 |
-
params = (session, start, stop)
|
449 |
-
else:
|
450 |
-
lineclause = "line>=?"
|
451 |
-
params = (session, start)
|
452 |
-
|
453 |
-
return self._run_sql("WHERE session==? AND %s" % lineclause,
|
454 |
-
params, raw=raw, output=output)
|
455 |
-
|
456 |
-
def get_range_by_str(self, rangestr, raw=True, output=False):
|
457 |
-
"""Get lines of history from a string of ranges, as used by magic
|
458 |
-
commands %hist, %save, %macro, etc.
|
459 |
-
|
460 |
-
Parameters
|
461 |
-
----------
|
462 |
-
rangestr : str
|
463 |
-
A string specifying ranges, e.g. "5 ~2/1-4". If empty string is used,
|
464 |
-
this will return everything from current session's history.
|
465 |
-
|
466 |
-
See the documentation of :func:`%history` for the full details.
|
467 |
-
|
468 |
-
raw, output : bool
|
469 |
-
As :meth:`get_range`
|
470 |
-
|
471 |
-
Returns
|
472 |
-
-------
|
473 |
-
Tuples as :meth:`get_range`
|
474 |
-
"""
|
475 |
-
for sess, s, e in extract_hist_ranges(rangestr):
|
476 |
-
for line in self.get_range(sess, s, e, raw=raw, output=output):
|
477 |
-
yield line
|
478 |
-
|
479 |
-
|
480 |
-
class HistoryManager(HistoryAccessor):
|
481 |
-
"""A class to organize all history-related functionality in one place.
|
482 |
-
"""
|
483 |
-
# Public interface
|
484 |
-
|
485 |
-
# An instance of the IPython shell we are attached to
|
486 |
-
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
|
487 |
-
allow_none=True)
|
488 |
-
# Lists to hold processed and raw history. These start with a blank entry
|
489 |
-
# so that we can index them starting from 1
|
490 |
-
input_hist_parsed = List([""])
|
491 |
-
input_hist_raw = List([""])
|
492 |
-
# A list of directories visited during session
|
493 |
-
dir_hist: List = List()
|
494 |
-
|
495 |
-
@default("dir_hist")
|
496 |
-
def _dir_hist_default(self):
|
497 |
-
try:
|
498 |
-
return [Path.cwd()]
|
499 |
-
except OSError:
|
500 |
-
return []
|
501 |
-
|
502 |
-
# A dict of output history, keyed with ints from the shell's
|
503 |
-
# execution count.
|
504 |
-
output_hist = Dict()
|
505 |
-
# The text/plain repr of outputs.
|
506 |
-
output_hist_reprs = Dict()
|
507 |
-
|
508 |
-
# The number of the current session in the history database
|
509 |
-
session_number = Integer()
|
510 |
-
|
511 |
-
db_log_output = Bool(False,
|
512 |
-
help="Should the history database include output? (default: no)"
|
513 |
-
).tag(config=True)
|
514 |
-
db_cache_size = Integer(0,
|
515 |
-
help="Write to database every x commands (higher values save disk access & power).\n"
|
516 |
-
"Values of 1 or less effectively disable caching."
|
517 |
-
).tag(config=True)
|
518 |
-
# The input and output caches
|
519 |
-
db_input_cache: List = List()
|
520 |
-
db_output_cache: List = List()
|
521 |
-
|
522 |
-
# History saving in separate thread
|
523 |
-
save_thread = Instance('IPython.core.history.HistorySavingThread',
|
524 |
-
allow_none=True)
|
525 |
-
save_flag = Instance(threading.Event, allow_none=True)
|
526 |
-
|
527 |
-
# Private interface
|
528 |
-
# Variables used to store the three last inputs from the user. On each new
|
529 |
-
# history update, we populate the user's namespace with these, shifted as
|
530 |
-
# necessary.
|
531 |
-
_i00 = Unicode("")
|
532 |
-
_i = Unicode("")
|
533 |
-
_ii = Unicode("")
|
534 |
-
_iii = Unicode("")
|
535 |
-
|
536 |
-
# A regex matching all forms of the exit command, so that we don't store
|
537 |
-
# them in the history (it's annoying to rewind the first entry and land on
|
538 |
-
# an exit call).
|
539 |
-
_exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
|
540 |
-
|
541 |
-
def __init__(self, shell=None, config=None, **traits):
|
542 |
-
"""Create a new history manager associated with a shell instance.
|
543 |
-
"""
|
544 |
-
super(HistoryManager, self).__init__(shell=shell, config=config,
|
545 |
-
**traits)
|
546 |
-
self.save_flag = threading.Event()
|
547 |
-
self.db_input_cache_lock = threading.Lock()
|
548 |
-
self.db_output_cache_lock = threading.Lock()
|
549 |
-
|
550 |
-
try:
|
551 |
-
self.new_session()
|
552 |
-
except sqlite3.OperationalError:
|
553 |
-
self.log.error("Failed to create history session in %s. History will not be saved.",
|
554 |
-
self.hist_file, exc_info=True)
|
555 |
-
self.hist_file = ':memory:'
|
556 |
-
|
557 |
-
if self.enabled and self.hist_file != ':memory:':
|
558 |
-
self.save_thread = HistorySavingThread(self)
|
559 |
-
try:
|
560 |
-
self.save_thread.start()
|
561 |
-
except RuntimeError:
|
562 |
-
self.log.error(
|
563 |
-
"Failed to start history saving thread. History will not be saved.",
|
564 |
-
exc_info=True,
|
565 |
-
)
|
566 |
-
self.hist_file = ":memory:"
|
567 |
-
|
568 |
-
def _get_hist_file_name(self, profile=None):
|
569 |
-
"""Get default history file name based on the Shell's profile.
|
570 |
-
|
571 |
-
The profile parameter is ignored, but must exist for compatibility with
|
572 |
-
the parent class."""
|
573 |
-
profile_dir = self.shell.profile_dir.location
|
574 |
-
return Path(profile_dir) / "history.sqlite"
|
575 |
-
|
576 |
-
@only_when_enabled
|
577 |
-
def new_session(self, conn=None):
|
578 |
-
"""Get a new session number."""
|
579 |
-
if conn is None:
|
580 |
-
conn = self.db
|
581 |
-
|
582 |
-
with conn:
|
583 |
-
cur = conn.execute(
|
584 |
-
"""INSERT INTO sessions VALUES (NULL, ?, NULL,
|
585 |
-
NULL, '') """,
|
586 |
-
(datetime.datetime.now().isoformat(" "),),
|
587 |
-
)
|
588 |
-
self.session_number = cur.lastrowid
|
589 |
-
|
590 |
-
def end_session(self):
|
591 |
-
"""Close the database session, filling in the end time and line count."""
|
592 |
-
self.writeout_cache()
|
593 |
-
with self.db:
|
594 |
-
self.db.execute(
|
595 |
-
"""UPDATE sessions SET end=?, num_cmds=? WHERE
|
596 |
-
session==?""",
|
597 |
-
(
|
598 |
-
datetime.datetime.now().isoformat(" "),
|
599 |
-
len(self.input_hist_parsed) - 1,
|
600 |
-
self.session_number,
|
601 |
-
),
|
602 |
-
)
|
603 |
-
self.session_number = 0
|
604 |
-
|
605 |
-
def name_session(self, name):
|
606 |
-
"""Give the current session a name in the history database."""
|
607 |
-
with self.db:
|
608 |
-
self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
|
609 |
-
(name, self.session_number))
|
610 |
-
|
611 |
-
def reset(self, new_session=True):
|
612 |
-
"""Clear the session history, releasing all object references, and
|
613 |
-
optionally open a new session."""
|
614 |
-
self.output_hist.clear()
|
615 |
-
# The directory history can't be completely empty
|
616 |
-
self.dir_hist[:] = [Path.cwd()]
|
617 |
-
|
618 |
-
if new_session:
|
619 |
-
if self.session_number:
|
620 |
-
self.end_session()
|
621 |
-
self.input_hist_parsed[:] = [""]
|
622 |
-
self.input_hist_raw[:] = [""]
|
623 |
-
self.new_session()
|
624 |
-
|
625 |
-
# ------------------------------
|
626 |
-
# Methods for retrieving history
|
627 |
-
# ------------------------------
|
628 |
-
def get_session_info(self, session=0):
|
629 |
-
"""Get info about a session.
|
630 |
-
|
631 |
-
Parameters
|
632 |
-
----------
|
633 |
-
session : int
|
634 |
-
Session number to retrieve. The current session is 0, and negative
|
635 |
-
numbers count back from current session, so -1 is the previous session.
|
636 |
-
|
637 |
-
Returns
|
638 |
-
-------
|
639 |
-
session_id : int
|
640 |
-
Session ID number
|
641 |
-
start : datetime
|
642 |
-
Timestamp for the start of the session.
|
643 |
-
end : datetime
|
644 |
-
Timestamp for the end of the session, or None if IPython crashed.
|
645 |
-
num_cmds : int
|
646 |
-
Number of commands run, or None if IPython crashed.
|
647 |
-
remark : unicode
|
648 |
-
A manually set description.
|
649 |
-
"""
|
650 |
-
if session <= 0:
|
651 |
-
session += self.session_number
|
652 |
-
|
653 |
-
return super(HistoryManager, self).get_session_info(session=session)
|
654 |
-
|
655 |
-
@catch_corrupt_db
|
656 |
-
def get_tail(self, n=10, raw=True, output=False, include_latest=False):
|
657 |
-
"""Get the last n lines from the history database.
|
658 |
-
|
659 |
-
Most recent entry last.
|
660 |
-
|
661 |
-
Completion will be reordered so that that the last ones are when
|
662 |
-
possible from current session.
|
663 |
-
|
664 |
-
Parameters
|
665 |
-
----------
|
666 |
-
n : int
|
667 |
-
The number of lines to get
|
668 |
-
raw, output : bool
|
669 |
-
See :meth:`get_range`
|
670 |
-
include_latest : bool
|
671 |
-
If False (default), n+1 lines are fetched, and the latest one
|
672 |
-
is discarded. This is intended to be used where the function
|
673 |
-
is called by a user command, which it should not return.
|
674 |
-
|
675 |
-
Returns
|
676 |
-
-------
|
677 |
-
Tuples as :meth:`get_range`
|
678 |
-
"""
|
679 |
-
self.writeout_cache()
|
680 |
-
if not include_latest:
|
681 |
-
n += 1
|
682 |
-
# cursor/line/entry
|
683 |
-
this_cur = list(
|
684 |
-
self._run_sql(
|
685 |
-
"WHERE session == ? ORDER BY line DESC LIMIT ? ",
|
686 |
-
(self.session_number, n),
|
687 |
-
raw=raw,
|
688 |
-
output=output,
|
689 |
-
)
|
690 |
-
)
|
691 |
-
other_cur = list(
|
692 |
-
self._run_sql(
|
693 |
-
"WHERE session != ? ORDER BY session DESC, line DESC LIMIT ?",
|
694 |
-
(self.session_number, n),
|
695 |
-
raw=raw,
|
696 |
-
output=output,
|
697 |
-
)
|
698 |
-
)
|
699 |
-
|
700 |
-
everything = this_cur + other_cur
|
701 |
-
|
702 |
-
everything = everything[:n]
|
703 |
-
|
704 |
-
if not include_latest:
|
705 |
-
return list(everything)[:0:-1]
|
706 |
-
return list(everything)[::-1]
|
707 |
-
|
708 |
-
def _get_range_session(self, start=1, stop=None, raw=True, output=False):
|
709 |
-
"""Get input and output history from the current session. Called by
|
710 |
-
get_range, and takes similar parameters."""
|
711 |
-
input_hist = self.input_hist_raw if raw else self.input_hist_parsed
|
712 |
-
|
713 |
-
n = len(input_hist)
|
714 |
-
if start < 0:
|
715 |
-
start += n
|
716 |
-
if not stop or (stop > n):
|
717 |
-
stop = n
|
718 |
-
elif stop < 0:
|
719 |
-
stop += n
|
720 |
-
|
721 |
-
for i in range(start, stop):
|
722 |
-
if output:
|
723 |
-
line = (input_hist[i], self.output_hist_reprs.get(i))
|
724 |
-
else:
|
725 |
-
line = input_hist[i]
|
726 |
-
yield (0, i, line)
|
727 |
-
|
728 |
-
def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
|
729 |
-
"""Retrieve input by session.
|
730 |
-
|
731 |
-
Parameters
|
732 |
-
----------
|
733 |
-
session : int
|
734 |
-
Session number to retrieve. The current session is 0, and negative
|
735 |
-
numbers count back from current session, so -1 is previous session.
|
736 |
-
start : int
|
737 |
-
First line to retrieve.
|
738 |
-
stop : int
|
739 |
-
End of line range (excluded from output itself). If None, retrieve
|
740 |
-
to the end of the session.
|
741 |
-
raw : bool
|
742 |
-
If True, return untranslated input
|
743 |
-
output : bool
|
744 |
-
If True, attempt to include output. This will be 'real' Python
|
745 |
-
objects for the current session, or text reprs from previous
|
746 |
-
sessions if db_log_output was enabled at the time. Where no output
|
747 |
-
is found, None is used.
|
748 |
-
|
749 |
-
Returns
|
750 |
-
-------
|
751 |
-
entries
|
752 |
-
An iterator over the desired lines. Each line is a 3-tuple, either
|
753 |
-
(session, line, input) if output is False, or
|
754 |
-
(session, line, (input, output)) if output is True.
|
755 |
-
"""
|
756 |
-
if session <= 0:
|
757 |
-
session += self.session_number
|
758 |
-
if session==self.session_number: # Current session
|
759 |
-
return self._get_range_session(start, stop, raw, output)
|
760 |
-
return super(HistoryManager, self).get_range(session, start, stop, raw,
|
761 |
-
output)
|
762 |
-
|
763 |
-
## ----------------------------
|
764 |
-
## Methods for storing history:
|
765 |
-
## ----------------------------
|
766 |
-
def store_inputs(self, line_num, source, source_raw=None):
|
767 |
-
"""Store source and raw input in history and create input cache
|
768 |
-
variables ``_i*``.
|
769 |
-
|
770 |
-
Parameters
|
771 |
-
----------
|
772 |
-
line_num : int
|
773 |
-
The prompt number of this input.
|
774 |
-
source : str
|
775 |
-
Python input.
|
776 |
-
source_raw : str, optional
|
777 |
-
If given, this is the raw input without any IPython transformations
|
778 |
-
applied to it. If not given, ``source`` is used.
|
779 |
-
"""
|
780 |
-
if source_raw is None:
|
781 |
-
source_raw = source
|
782 |
-
source = source.rstrip('\n')
|
783 |
-
source_raw = source_raw.rstrip('\n')
|
784 |
-
|
785 |
-
# do not store exit/quit commands
|
786 |
-
if self._exit_re.match(source_raw.strip()):
|
787 |
-
return
|
788 |
-
|
789 |
-
self.input_hist_parsed.append(source)
|
790 |
-
self.input_hist_raw.append(source_raw)
|
791 |
-
|
792 |
-
with self.db_input_cache_lock:
|
793 |
-
self.db_input_cache.append((line_num, source, source_raw))
|
794 |
-
# Trigger to flush cache and write to DB.
|
795 |
-
if len(self.db_input_cache) >= self.db_cache_size:
|
796 |
-
self.save_flag.set()
|
797 |
-
|
798 |
-
# update the auto _i variables
|
799 |
-
self._iii = self._ii
|
800 |
-
self._ii = self._i
|
801 |
-
self._i = self._i00
|
802 |
-
self._i00 = source_raw
|
803 |
-
|
804 |
-
# hackish access to user namespace to create _i1,_i2... dynamically
|
805 |
-
new_i = '_i%s' % line_num
|
806 |
-
to_main = {'_i': self._i,
|
807 |
-
'_ii': self._ii,
|
808 |
-
'_iii': self._iii,
|
809 |
-
new_i : self._i00 }
|
810 |
-
|
811 |
-
if self.shell is not None:
|
812 |
-
self.shell.push(to_main, interactive=False)
|
813 |
-
|
814 |
-
def store_output(self, line_num):
|
815 |
-
"""If database output logging is enabled, this saves all the
|
816 |
-
outputs from the indicated prompt number to the database. It's
|
817 |
-
called by run_cell after code has been executed.
|
818 |
-
|
819 |
-
Parameters
|
820 |
-
----------
|
821 |
-
line_num : int
|
822 |
-
The line number from which to save outputs
|
823 |
-
"""
|
824 |
-
if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
|
825 |
-
return
|
826 |
-
output = self.output_hist_reprs[line_num]
|
827 |
-
|
828 |
-
with self.db_output_cache_lock:
|
829 |
-
self.db_output_cache.append((line_num, output))
|
830 |
-
if self.db_cache_size <= 1:
|
831 |
-
self.save_flag.set()
|
832 |
-
|
833 |
-
def _writeout_input_cache(self, conn):
|
834 |
-
with conn:
|
835 |
-
for line in self.db_input_cache:
|
836 |
-
conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
|
837 |
-
(self.session_number,)+line)
|
838 |
-
|
839 |
-
def _writeout_output_cache(self, conn):
|
840 |
-
with conn:
|
841 |
-
for line in self.db_output_cache:
|
842 |
-
conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
|
843 |
-
(self.session_number,)+line)
|
844 |
-
|
845 |
-
@only_when_enabled
|
846 |
-
def writeout_cache(self, conn=None):
|
847 |
-
"""Write any entries in the cache to the database."""
|
848 |
-
if conn is None:
|
849 |
-
conn = self.db
|
850 |
-
|
851 |
-
with self.db_input_cache_lock:
|
852 |
-
try:
|
853 |
-
self._writeout_input_cache(conn)
|
854 |
-
except sqlite3.IntegrityError:
|
855 |
-
self.new_session(conn)
|
856 |
-
print("ERROR! Session/line number was not unique in",
|
857 |
-
"database. History logging moved to new session",
|
858 |
-
self.session_number)
|
859 |
-
try:
|
860 |
-
# Try writing to the new session. If this fails, don't
|
861 |
-
# recurse
|
862 |
-
self._writeout_input_cache(conn)
|
863 |
-
except sqlite3.IntegrityError:
|
864 |
-
pass
|
865 |
-
finally:
|
866 |
-
self.db_input_cache = []
|
867 |
-
|
868 |
-
with self.db_output_cache_lock:
|
869 |
-
try:
|
870 |
-
self._writeout_output_cache(conn)
|
871 |
-
except sqlite3.IntegrityError:
|
872 |
-
print("!! Session/line number for output was not unique",
|
873 |
-
"in database. Output will not be stored.")
|
874 |
-
finally:
|
875 |
-
self.db_output_cache = []
|
876 |
-
|
877 |
-
|
878 |
-
class HistorySavingThread(threading.Thread):
|
879 |
-
"""This thread takes care of writing history to the database, so that
|
880 |
-
the UI isn't held up while that happens.
|
881 |
-
|
882 |
-
It waits for the HistoryManager's save_flag to be set, then writes out
|
883 |
-
the history cache. The main thread is responsible for setting the flag when
|
884 |
-
the cache size reaches a defined threshold."""
|
885 |
-
daemon = True
|
886 |
-
stop_now = False
|
887 |
-
enabled = True
|
888 |
-
def __init__(self, history_manager):
|
889 |
-
super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
|
890 |
-
self.history_manager = history_manager
|
891 |
-
self.enabled = history_manager.enabled
|
892 |
-
|
893 |
-
@only_when_enabled
|
894 |
-
def run(self):
|
895 |
-
atexit.register(self.stop)
|
896 |
-
# We need a separate db connection per thread:
|
897 |
-
try:
|
898 |
-
self.db = sqlite3.connect(
|
899 |
-
str(self.history_manager.hist_file),
|
900 |
-
**self.history_manager.connection_options,
|
901 |
-
)
|
902 |
-
while True:
|
903 |
-
self.history_manager.save_flag.wait()
|
904 |
-
if self.stop_now:
|
905 |
-
self.db.close()
|
906 |
-
return
|
907 |
-
self.history_manager.save_flag.clear()
|
908 |
-
self.history_manager.writeout_cache(self.db)
|
909 |
-
except Exception as e:
|
910 |
-
print(("The history saving thread hit an unexpected error (%s)."
|
911 |
-
"History will not be written to the database.") % repr(e))
|
912 |
-
finally:
|
913 |
-
atexit.unregister(self.stop)
|
914 |
-
|
915 |
-
def stop(self):
|
916 |
-
"""This can be called from the main thread to safely stop this thread.
|
917 |
-
|
918 |
-
Note that it does not attempt to write out remaining history before
|
919 |
-
exiting. That should be done by calling the HistoryManager's
|
920 |
-
end_session method."""
|
921 |
-
self.stop_now = True
|
922 |
-
self.history_manager.save_flag.set()
|
923 |
-
self.join()
|
924 |
-
|
925 |
-
|
926 |
-
# To match, e.g. ~5/8-~2/3
|
927 |
-
range_re = re.compile(r"""
|
928 |
-
((?P<startsess>~?\d+)/)?
|
929 |
-
(?P<start>\d+)?
|
930 |
-
((?P<sep>[\-:])
|
931 |
-
((?P<endsess>~?\d+)/)?
|
932 |
-
(?P<end>\d+))?
|
933 |
-
$""", re.VERBOSE)
|
934 |
-
|
935 |
-
|
936 |
-
def extract_hist_ranges(ranges_str):
|
937 |
-
"""Turn a string of history ranges into 3-tuples of (session, start, stop).
|
938 |
-
|
939 |
-
Empty string results in a `[(0, 1, None)]`, i.e. "everything from current
|
940 |
-
session".
|
941 |
-
|
942 |
-
Examples
|
943 |
-
--------
|
944 |
-
>>> list(extract_hist_ranges("~8/5-~7/4 2"))
|
945 |
-
[(-8, 5, None), (-7, 1, 5), (0, 2, 3)]
|
946 |
-
"""
|
947 |
-
if ranges_str == "":
|
948 |
-
yield (0, 1, None) # Everything from current session
|
949 |
-
return
|
950 |
-
|
951 |
-
for range_str in ranges_str.split():
|
952 |
-
rmatch = range_re.match(range_str)
|
953 |
-
if not rmatch:
|
954 |
-
continue
|
955 |
-
start = rmatch.group("start")
|
956 |
-
if start:
|
957 |
-
start = int(start)
|
958 |
-
end = rmatch.group("end")
|
959 |
-
# If no end specified, get (a, a + 1)
|
960 |
-
end = int(end) if end else start + 1
|
961 |
-
else: # start not specified
|
962 |
-
if not rmatch.group('startsess'): # no startsess
|
963 |
-
continue
|
964 |
-
start = 1
|
965 |
-
end = None # provide the entire session hist
|
966 |
-
|
967 |
-
if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
|
968 |
-
end += 1
|
969 |
-
startsess = rmatch.group("startsess") or "0"
|
970 |
-
endsess = rmatch.group("endsess") or startsess
|
971 |
-
startsess = int(startsess.replace("~","-"))
|
972 |
-
endsess = int(endsess.replace("~","-"))
|
973 |
-
assert endsess >= startsess, "start session must be earlier than end session"
|
974 |
-
|
975 |
-
if endsess == startsess:
|
976 |
-
yield (startsess, start, end)
|
977 |
-
continue
|
978 |
-
# Multiple sessions in one range:
|
979 |
-
yield (startsess, start, None)
|
980 |
-
for sess in range(startsess+1, endsess):
|
981 |
-
yield (sess, 1, None)
|
982 |
-
yield (endsess, 1, end)
|
983 |
-
|
984 |
-
|
985 |
-
def _format_lineno(session, line):
|
986 |
-
"""Helper function to format line numbers properly."""
|
987 |
-
if session == 0:
|
988 |
-
return str(line)
|
989 |
-
return "%s#%s" % (session, line)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/historyapp.py
DELETED
@@ -1,158 +0,0 @@
|
|
1 |
-
# encoding: utf-8
|
2 |
-
"""
|
3 |
-
An application for managing IPython history.
|
4 |
-
|
5 |
-
To be invoked as the `ipython history` subcommand.
|
6 |
-
"""
|
7 |
-
|
8 |
-
import sqlite3
|
9 |
-
from pathlib import Path
|
10 |
-
|
11 |
-
from traitlets.config.application import Application
|
12 |
-
from .application import BaseIPythonApplication
|
13 |
-
from traitlets import Bool, Int, Dict
|
14 |
-
from ..utils.io import ask_yes_no
|
15 |
-
|
16 |
-
trim_hist_help = """Trim the IPython history database to the last 1000 entries.
|
17 |
-
|
18 |
-
This actually copies the last 1000 entries to a new database, and then replaces
|
19 |
-
the old file with the new. Use the `--keep=` argument to specify a number
|
20 |
-
other than 1000.
|
21 |
-
"""
|
22 |
-
|
23 |
-
clear_hist_help = """Clear the IPython history database, deleting all entries.
|
24 |
-
|
25 |
-
Because this is a destructive operation, IPython will prompt the user if they
|
26 |
-
really want to do this. Passing a `-f` flag will force clearing without a
|
27 |
-
prompt.
|
28 |
-
|
29 |
-
This is an handy alias to `ipython history trim --keep=0`
|
30 |
-
"""
|
31 |
-
|
32 |
-
|
33 |
-
class HistoryTrim(BaseIPythonApplication):
|
34 |
-
description = trim_hist_help
|
35 |
-
|
36 |
-
backup = Bool(False, help="Keep the old history file as history.sqlite.<N>").tag(
|
37 |
-
config=True
|
38 |
-
)
|
39 |
-
|
40 |
-
keep = Int(1000, help="Number of recent lines to keep in the database.").tag(
|
41 |
-
config=True
|
42 |
-
)
|
43 |
-
|
44 |
-
flags = Dict( # type: ignore
|
45 |
-
dict(backup=({"HistoryTrim": {"backup": True}}, backup.help))
|
46 |
-
)
|
47 |
-
|
48 |
-
aliases = Dict(dict(keep="HistoryTrim.keep")) # type: ignore
|
49 |
-
|
50 |
-
def start(self):
|
51 |
-
profile_dir = Path(self.profile_dir.location)
|
52 |
-
hist_file = profile_dir / "history.sqlite"
|
53 |
-
con = sqlite3.connect(hist_file)
|
54 |
-
|
55 |
-
# Grab the recent history from the current database.
|
56 |
-
inputs = list(con.execute('SELECT session, line, source, source_raw FROM '
|
57 |
-
'history ORDER BY session DESC, line DESC LIMIT ?', (self.keep+1,)))
|
58 |
-
if len(inputs) <= self.keep:
|
59 |
-
print("There are already at most %d entries in the history database." % self.keep)
|
60 |
-
print("Not doing anything. Use --keep= argument to keep fewer entries")
|
61 |
-
return
|
62 |
-
|
63 |
-
print("Trimming history to the most recent %d entries." % self.keep)
|
64 |
-
|
65 |
-
inputs.pop() # Remove the extra element we got to check the length.
|
66 |
-
inputs.reverse()
|
67 |
-
if inputs:
|
68 |
-
first_session = inputs[0][0]
|
69 |
-
outputs = list(con.execute('SELECT session, line, output FROM '
|
70 |
-
'output_history WHERE session >= ?', (first_session,)))
|
71 |
-
sessions = list(con.execute('SELECT session, start, end, num_cmds, remark FROM '
|
72 |
-
'sessions WHERE session >= ?', (first_session,)))
|
73 |
-
con.close()
|
74 |
-
|
75 |
-
# Create the new history database.
|
76 |
-
new_hist_file = profile_dir / "history.sqlite.new"
|
77 |
-
i = 0
|
78 |
-
while new_hist_file.exists():
|
79 |
-
# Make sure we don't interfere with an existing file.
|
80 |
-
i += 1
|
81 |
-
new_hist_file = profile_dir / ("history.sqlite.new" + str(i))
|
82 |
-
new_db = sqlite3.connect(new_hist_file)
|
83 |
-
new_db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
|
84 |
-
primary key autoincrement, start timestamp,
|
85 |
-
end timestamp, num_cmds integer, remark text)""")
|
86 |
-
new_db.execute("""CREATE TABLE IF NOT EXISTS history
|
87 |
-
(session integer, line integer, source text, source_raw text,
|
88 |
-
PRIMARY KEY (session, line))""")
|
89 |
-
new_db.execute("""CREATE TABLE IF NOT EXISTS output_history
|
90 |
-
(session integer, line integer, output text,
|
91 |
-
PRIMARY KEY (session, line))""")
|
92 |
-
new_db.commit()
|
93 |
-
|
94 |
-
|
95 |
-
if inputs:
|
96 |
-
with new_db:
|
97 |
-
# Add the recent history into the new database.
|
98 |
-
new_db.executemany('insert into sessions values (?,?,?,?,?)', sessions)
|
99 |
-
new_db.executemany('insert into history values (?,?,?,?)', inputs)
|
100 |
-
new_db.executemany('insert into output_history values (?,?,?)', outputs)
|
101 |
-
new_db.close()
|
102 |
-
|
103 |
-
if self.backup:
|
104 |
-
i = 1
|
105 |
-
backup_hist_file = profile_dir / ("history.sqlite.old.%d" % i)
|
106 |
-
while backup_hist_file.exists():
|
107 |
-
i += 1
|
108 |
-
backup_hist_file = profile_dir / ("history.sqlite.old.%d" % i)
|
109 |
-
hist_file.rename(backup_hist_file)
|
110 |
-
print("Backed up longer history file to", backup_hist_file)
|
111 |
-
else:
|
112 |
-
hist_file.unlink()
|
113 |
-
|
114 |
-
new_hist_file.rename(hist_file)
|
115 |
-
|
116 |
-
|
117 |
-
class HistoryClear(HistoryTrim):
|
118 |
-
description = clear_hist_help
|
119 |
-
keep = Int(0, help="Number of recent lines to keep in the database.")
|
120 |
-
|
121 |
-
force = Bool(False, help="Don't prompt user for confirmation").tag(config=True)
|
122 |
-
|
123 |
-
flags = Dict( # type: ignore
|
124 |
-
dict(
|
125 |
-
force=({"HistoryClear": {"force": True}}, force.help),
|
126 |
-
f=({"HistoryTrim": {"force": True}}, force.help),
|
127 |
-
)
|
128 |
-
)
|
129 |
-
aliases = Dict() # type: ignore
|
130 |
-
|
131 |
-
def start(self):
|
132 |
-
if self.force or ask_yes_no(
|
133 |
-
"Really delete all ipython history? ", default="no", interrupt="no"
|
134 |
-
):
|
135 |
-
HistoryTrim.start(self)
|
136 |
-
|
137 |
-
|
138 |
-
class HistoryApp(Application):
|
139 |
-
name = "ipython-history"
|
140 |
-
description = "Manage the IPython history database."
|
141 |
-
|
142 |
-
subcommands = Dict(dict(
|
143 |
-
trim = (HistoryTrim, HistoryTrim.description.splitlines()[0]),
|
144 |
-
clear = (HistoryClear, HistoryClear.description.splitlines()[0]),
|
145 |
-
))
|
146 |
-
|
147 |
-
def start(self):
|
148 |
-
if self.subapp is None:
|
149 |
-
print(
|
150 |
-
"No subcommand specified. Must specify one of: "
|
151 |
-
+ ", ".join(map(repr, self.subcommands))
|
152 |
-
+ ".\n"
|
153 |
-
)
|
154 |
-
self.print_description()
|
155 |
-
self.print_subcommands()
|
156 |
-
self.exit(1)
|
157 |
-
else:
|
158 |
-
return self.subapp.start()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/hooks.py
DELETED
@@ -1,173 +0,0 @@
|
|
1 |
-
"""Hooks for IPython.
|
2 |
-
|
3 |
-
In Python, it is possible to overwrite any method of any object if you really
|
4 |
-
want to. But IPython exposes a few 'hooks', methods which are *designed* to
|
5 |
-
be overwritten by users for customization purposes. This module defines the
|
6 |
-
default versions of all such hooks, which get used by IPython if not
|
7 |
-
overridden by the user.
|
8 |
-
|
9 |
-
Hooks are simple functions, but they should be declared with ``self`` as their
|
10 |
-
first argument, because when activated they are registered into IPython as
|
11 |
-
instance methods. The self argument will be the IPython running instance
|
12 |
-
itself, so hooks have full access to the entire IPython object.
|
13 |
-
|
14 |
-
If you wish to define a new hook and activate it, you can make an :doc:`extension
|
15 |
-
</config/extensions/index>` or a :ref:`startup script <startup_files>`. For
|
16 |
-
example, you could use a startup file like this::
|
17 |
-
|
18 |
-
import os
|
19 |
-
|
20 |
-
def calljed(self,filename, linenum):
|
21 |
-
"My editor hook calls the jed editor directly."
|
22 |
-
print("Calling my own editor, jed ...")
|
23 |
-
if os.system('jed +%d %s' % (linenum,filename)) != 0:
|
24 |
-
raise TryNext()
|
25 |
-
|
26 |
-
def load_ipython_extension(ip):
|
27 |
-
ip.set_hook('editor', calljed)
|
28 |
-
|
29 |
-
"""
|
30 |
-
|
31 |
-
#*****************************************************************************
|
32 |
-
# Copyright (C) 2005 Fernando Perez. <[email protected]>
|
33 |
-
#
|
34 |
-
# Distributed under the terms of the BSD License. The full license is in
|
35 |
-
# the file COPYING, distributed as part of this software.
|
36 |
-
#*****************************************************************************
|
37 |
-
|
38 |
-
import os
|
39 |
-
import subprocess
|
40 |
-
import sys
|
41 |
-
|
42 |
-
from .error import TryNext
|
43 |
-
|
44 |
-
# List here all the default hooks. For now it's just the editor functions
|
45 |
-
# but over time we'll move here all the public API for user-accessible things.
|
46 |
-
|
47 |
-
__all__ = [
|
48 |
-
"editor",
|
49 |
-
"synchronize_with_editor",
|
50 |
-
"show_in_pager",
|
51 |
-
"pre_prompt_hook",
|
52 |
-
"clipboard_get",
|
53 |
-
]
|
54 |
-
|
55 |
-
deprecated = {'pre_run_code_hook': "a callback for the 'pre_execute' or 'pre_run_cell' event",
|
56 |
-
'late_startup_hook': "a callback for the 'shell_initialized' event",
|
57 |
-
'shutdown_hook': "the atexit module",
|
58 |
-
}
|
59 |
-
|
60 |
-
def editor(self, filename, linenum=None, wait=True):
|
61 |
-
"""Open the default editor at the given filename and linenumber.
|
62 |
-
|
63 |
-
This is IPython's default editor hook, you can use it as an example to
|
64 |
-
write your own modified one. To set your own editor function as the
|
65 |
-
new editor hook, call ip.set_hook('editor',yourfunc)."""
|
66 |
-
|
67 |
-
# IPython configures a default editor at startup by reading $EDITOR from
|
68 |
-
# the environment, and falling back on vi (unix) or notepad (win32).
|
69 |
-
editor = self.editor
|
70 |
-
|
71 |
-
# marker for at which line to open the file (for existing objects)
|
72 |
-
if linenum is None or editor=='notepad':
|
73 |
-
linemark = ''
|
74 |
-
else:
|
75 |
-
linemark = '+%d' % int(linenum)
|
76 |
-
|
77 |
-
# Enclose in quotes if necessary and legal
|
78 |
-
if ' ' in editor and os.path.isfile(editor) and editor[0] != '"':
|
79 |
-
editor = '"%s"' % editor
|
80 |
-
|
81 |
-
# Call the actual editor
|
82 |
-
proc = subprocess.Popen('%s %s %s' % (editor, linemark, filename),
|
83 |
-
shell=True)
|
84 |
-
if wait and proc.wait() != 0:
|
85 |
-
raise TryNext()
|
86 |
-
|
87 |
-
|
88 |
-
def synchronize_with_editor(self, filename, linenum, column):
|
89 |
-
pass
|
90 |
-
|
91 |
-
|
92 |
-
class CommandChainDispatcher:
|
93 |
-
""" Dispatch calls to a chain of commands until some func can handle it
|
94 |
-
|
95 |
-
Usage: instantiate, execute "add" to add commands (with optional
|
96 |
-
priority), execute normally via f() calling mechanism.
|
97 |
-
|
98 |
-
"""
|
99 |
-
def __init__(self,commands=None):
|
100 |
-
if commands is None:
|
101 |
-
self.chain = []
|
102 |
-
else:
|
103 |
-
self.chain = commands
|
104 |
-
|
105 |
-
|
106 |
-
def __call__(self,*args, **kw):
|
107 |
-
""" Command chain is called just like normal func.
|
108 |
-
|
109 |
-
This will call all funcs in chain with the same args as were given to
|
110 |
-
this function, and return the result of first func that didn't raise
|
111 |
-
TryNext"""
|
112 |
-
last_exc = TryNext()
|
113 |
-
for prio,cmd in self.chain:
|
114 |
-
# print("prio",prio,"cmd",cmd) # dbg
|
115 |
-
try:
|
116 |
-
return cmd(*args, **kw)
|
117 |
-
except TryNext as exc:
|
118 |
-
last_exc = exc
|
119 |
-
# if no function will accept it, raise TryNext up to the caller
|
120 |
-
raise last_exc
|
121 |
-
|
122 |
-
def __str__(self):
|
123 |
-
return str(self.chain)
|
124 |
-
|
125 |
-
def add(self, func, priority=0):
|
126 |
-
""" Add a func to the cmd chain with given priority """
|
127 |
-
self.chain.append((priority, func))
|
128 |
-
self.chain.sort(key=lambda x: x[0])
|
129 |
-
|
130 |
-
def __iter__(self):
|
131 |
-
""" Return all objects in chain.
|
132 |
-
|
133 |
-
Handy if the objects are not callable.
|
134 |
-
"""
|
135 |
-
return iter(self.chain)
|
136 |
-
|
137 |
-
|
138 |
-
def show_in_pager(self, data, start, screen_lines):
|
139 |
-
""" Run a string through pager """
|
140 |
-
# raising TryNext here will use the default paging functionality
|
141 |
-
raise TryNext
|
142 |
-
|
143 |
-
|
144 |
-
def pre_prompt_hook(self):
|
145 |
-
""" Run before displaying the next prompt
|
146 |
-
|
147 |
-
Use this e.g. to display output from asynchronous operations (in order
|
148 |
-
to not mess up text entry)
|
149 |
-
"""
|
150 |
-
|
151 |
-
return None
|
152 |
-
|
153 |
-
|
154 |
-
def clipboard_get(self):
|
155 |
-
""" Get text from the clipboard.
|
156 |
-
"""
|
157 |
-
from ..lib.clipboard import (
|
158 |
-
osx_clipboard_get,
|
159 |
-
tkinter_clipboard_get,
|
160 |
-
win32_clipboard_get,
|
161 |
-
wayland_clipboard_get,
|
162 |
-
)
|
163 |
-
if sys.platform == 'win32':
|
164 |
-
chain = [win32_clipboard_get, tkinter_clipboard_get]
|
165 |
-
elif sys.platform == 'darwin':
|
166 |
-
chain = [osx_clipboard_get, tkinter_clipboard_get]
|
167 |
-
else:
|
168 |
-
chain = [wayland_clipboard_get, tkinter_clipboard_get]
|
169 |
-
dispatcher = CommandChainDispatcher()
|
170 |
-
for func in chain:
|
171 |
-
dispatcher.add(func)
|
172 |
-
text = dispatcher()
|
173 |
-
return text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/inputsplitter.py
DELETED
@@ -1,799 +0,0 @@
|
|
1 |
-
"""DEPRECATED: Input handling and transformation machinery.
|
2 |
-
|
3 |
-
This module was deprecated in IPython 7.0, in favour of inputtransformer2.
|
4 |
-
|
5 |
-
The first class in this module, :class:`InputSplitter`, is designed to tell when
|
6 |
-
input from a line-oriented frontend is complete and should be executed, and when
|
7 |
-
the user should be prompted for another line of code instead. The name 'input
|
8 |
-
splitter' is largely for historical reasons.
|
9 |
-
|
10 |
-
A companion, :class:`IPythonInputSplitter`, provides the same functionality but
|
11 |
-
with full support for the extended IPython syntax (magics, system calls, etc).
|
12 |
-
The code to actually do these transformations is in :mod:`IPython.core.inputtransformer`.
|
13 |
-
:class:`IPythonInputSplitter` feeds the raw code to the transformers in order
|
14 |
-
and stores the results.
|
15 |
-
|
16 |
-
For more details, see the class docstrings below.
|
17 |
-
"""
|
18 |
-
|
19 |
-
from __future__ import annotations
|
20 |
-
|
21 |
-
from warnings import warn
|
22 |
-
|
23 |
-
warn('IPython.core.inputsplitter is deprecated since IPython 7 in favor of `IPython.core.inputtransformer2`',
|
24 |
-
DeprecationWarning)
|
25 |
-
|
26 |
-
# Copyright (c) IPython Development Team.
|
27 |
-
# Distributed under the terms of the Modified BSD License.
|
28 |
-
import ast
|
29 |
-
import codeop
|
30 |
-
import io
|
31 |
-
import re
|
32 |
-
import sys
|
33 |
-
import tokenize
|
34 |
-
import warnings
|
35 |
-
|
36 |
-
from typing import List, Tuple, Union, Optional, TYPE_CHECKING
|
37 |
-
from types import CodeType
|
38 |
-
|
39 |
-
from IPython.core.inputtransformer import (leading_indent,
|
40 |
-
classic_prompt,
|
41 |
-
ipy_prompt,
|
42 |
-
cellmagic,
|
43 |
-
assemble_logical_lines,
|
44 |
-
help_end,
|
45 |
-
escaped_commands,
|
46 |
-
assign_from_magic,
|
47 |
-
assign_from_system,
|
48 |
-
assemble_python_lines,
|
49 |
-
)
|
50 |
-
from IPython.utils import tokenutil
|
51 |
-
|
52 |
-
# These are available in this module for backwards compatibility.
|
53 |
-
from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
|
54 |
-
ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
|
55 |
-
ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
|
56 |
-
|
57 |
-
if TYPE_CHECKING:
|
58 |
-
from typing_extensions import Self
|
59 |
-
#-----------------------------------------------------------------------------
|
60 |
-
# Utilities
|
61 |
-
#-----------------------------------------------------------------------------
|
62 |
-
|
63 |
-
# FIXME: These are general-purpose utilities that later can be moved to the
|
64 |
-
# general ward. Kept here for now because we're being very strict about test
|
65 |
-
# coverage with this code, and this lets us ensure that we keep 100% coverage
|
66 |
-
# while developing.
|
67 |
-
|
68 |
-
# compiled regexps for autoindent management
|
69 |
-
dedent_re = re.compile('|'.join([
|
70 |
-
r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
|
71 |
-
r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
|
72 |
-
r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
|
73 |
-
r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
|
74 |
-
r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
|
75 |
-
r'^\s+break\s*$', # break (optionally followed by trailing spaces)
|
76 |
-
r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
|
77 |
-
]))
|
78 |
-
ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
|
79 |
-
|
80 |
-
# regexp to match pure comment lines so we don't accidentally insert 'if 1:'
|
81 |
-
# before pure comments
|
82 |
-
comment_line_re = re.compile(r'^\s*\#')
|
83 |
-
|
84 |
-
|
85 |
-
def num_ini_spaces(s):
|
86 |
-
"""Return the number of initial spaces in a string.
|
87 |
-
|
88 |
-
Note that tabs are counted as a single space. For now, we do *not* support
|
89 |
-
mixing of tabs and spaces in the user's input.
|
90 |
-
|
91 |
-
Parameters
|
92 |
-
----------
|
93 |
-
s : string
|
94 |
-
|
95 |
-
Returns
|
96 |
-
-------
|
97 |
-
n : int
|
98 |
-
"""
|
99 |
-
warnings.warn(
|
100 |
-
"`num_ini_spaces` is Pending Deprecation since IPython 8.17."
|
101 |
-
"It is considered for removal in in future version. "
|
102 |
-
"Please open an issue if you believe it should be kept.",
|
103 |
-
stacklevel=2,
|
104 |
-
category=PendingDeprecationWarning,
|
105 |
-
)
|
106 |
-
ini_spaces = ini_spaces_re.match(s)
|
107 |
-
if ini_spaces:
|
108 |
-
return ini_spaces.end()
|
109 |
-
else:
|
110 |
-
return 0
|
111 |
-
|
112 |
-
# Fake token types for partial_tokenize:
|
113 |
-
INCOMPLETE_STRING = tokenize.N_TOKENS
|
114 |
-
IN_MULTILINE_STATEMENT = tokenize.N_TOKENS + 1
|
115 |
-
|
116 |
-
# The 2 classes below have the same API as TokenInfo, but don't try to look up
|
117 |
-
# a token type name that they won't find.
|
118 |
-
class IncompleteString:
|
119 |
-
type = exact_type = INCOMPLETE_STRING
|
120 |
-
def __init__(self, s, start, end, line):
|
121 |
-
self.s = s
|
122 |
-
self.start = start
|
123 |
-
self.end = end
|
124 |
-
self.line = line
|
125 |
-
|
126 |
-
class InMultilineStatement:
|
127 |
-
type = exact_type = IN_MULTILINE_STATEMENT
|
128 |
-
def __init__(self, pos, line):
|
129 |
-
self.s = ''
|
130 |
-
self.start = self.end = pos
|
131 |
-
self.line = line
|
132 |
-
|
133 |
-
def partial_tokens(s):
|
134 |
-
"""Iterate over tokens from a possibly-incomplete string of code.
|
135 |
-
|
136 |
-
This adds two special token types: INCOMPLETE_STRING and
|
137 |
-
IN_MULTILINE_STATEMENT. These can only occur as the last token yielded, and
|
138 |
-
represent the two main ways for code to be incomplete.
|
139 |
-
"""
|
140 |
-
readline = io.StringIO(s).readline
|
141 |
-
token = tokenize.TokenInfo(tokenize.NEWLINE, '', (1, 0), (1, 0), '')
|
142 |
-
try:
|
143 |
-
for token in tokenutil.generate_tokens_catch_errors(readline):
|
144 |
-
yield token
|
145 |
-
except tokenize.TokenError as e:
|
146 |
-
# catch EOF error
|
147 |
-
lines = s.splitlines(keepends=True)
|
148 |
-
end = len(lines), len(lines[-1])
|
149 |
-
if 'multi-line string' in e.args[0]:
|
150 |
-
l, c = start = token.end
|
151 |
-
s = lines[l-1][c:] + ''.join(lines[l:])
|
152 |
-
yield IncompleteString(s, start, end, lines[-1])
|
153 |
-
elif 'multi-line statement' in e.args[0]:
|
154 |
-
yield InMultilineStatement(end, lines[-1])
|
155 |
-
else:
|
156 |
-
raise
|
157 |
-
|
158 |
-
def find_next_indent(code) -> int:
|
159 |
-
"""Find the number of spaces for the next line of indentation"""
|
160 |
-
tokens = list(partial_tokens(code))
|
161 |
-
if tokens[-1].type == tokenize.ENDMARKER:
|
162 |
-
tokens.pop()
|
163 |
-
if not tokens:
|
164 |
-
return 0
|
165 |
-
|
166 |
-
while tokens[-1].type in {
|
167 |
-
tokenize.DEDENT,
|
168 |
-
tokenize.NEWLINE,
|
169 |
-
tokenize.COMMENT,
|
170 |
-
tokenize.ERRORTOKEN,
|
171 |
-
}:
|
172 |
-
tokens.pop()
|
173 |
-
|
174 |
-
# Starting in Python 3.12, the tokenize module adds implicit newlines at the end
|
175 |
-
# of input. We need to remove those if we're in a multiline statement
|
176 |
-
if tokens[-1].type == IN_MULTILINE_STATEMENT:
|
177 |
-
while tokens[-2].type in {tokenize.NL}:
|
178 |
-
tokens.pop(-2)
|
179 |
-
|
180 |
-
|
181 |
-
if tokens[-1].type == INCOMPLETE_STRING:
|
182 |
-
# Inside a multiline string
|
183 |
-
return 0
|
184 |
-
|
185 |
-
# Find the indents used before
|
186 |
-
prev_indents = [0]
|
187 |
-
def _add_indent(n):
|
188 |
-
if n != prev_indents[-1]:
|
189 |
-
prev_indents.append(n)
|
190 |
-
|
191 |
-
tokiter = iter(tokens)
|
192 |
-
for tok in tokiter:
|
193 |
-
if tok.type in {tokenize.INDENT, tokenize.DEDENT}:
|
194 |
-
_add_indent(tok.end[1])
|
195 |
-
elif (tok.type == tokenize.NL):
|
196 |
-
try:
|
197 |
-
_add_indent(next(tokiter).start[1])
|
198 |
-
except StopIteration:
|
199 |
-
break
|
200 |
-
|
201 |
-
last_indent = prev_indents.pop()
|
202 |
-
|
203 |
-
# If we've just opened a multiline statement (e.g. 'a = ['), indent more
|
204 |
-
if tokens[-1].type == IN_MULTILINE_STATEMENT:
|
205 |
-
if tokens[-2].exact_type in {tokenize.LPAR, tokenize.LSQB, tokenize.LBRACE}:
|
206 |
-
return last_indent + 4
|
207 |
-
return last_indent
|
208 |
-
|
209 |
-
if tokens[-1].exact_type == tokenize.COLON:
|
210 |
-
# Line ends with colon - indent
|
211 |
-
return last_indent + 4
|
212 |
-
|
213 |
-
if last_indent:
|
214 |
-
# Examine the last line for dedent cues - statements like return or
|
215 |
-
# raise which normally end a block of code.
|
216 |
-
last_line_starts = 0
|
217 |
-
for i, tok in enumerate(tokens):
|
218 |
-
if tok.type == tokenize.NEWLINE:
|
219 |
-
last_line_starts = i + 1
|
220 |
-
|
221 |
-
last_line_tokens = tokens[last_line_starts:]
|
222 |
-
names = [t.string for t in last_line_tokens if t.type == tokenize.NAME]
|
223 |
-
if names and names[0] in {'raise', 'return', 'pass', 'break', 'continue'}:
|
224 |
-
# Find the most recent indentation less than the current level
|
225 |
-
for indent in reversed(prev_indents):
|
226 |
-
if indent < last_indent:
|
227 |
-
return indent
|
228 |
-
|
229 |
-
return last_indent
|
230 |
-
|
231 |
-
|
232 |
-
def last_blank(src):
|
233 |
-
"""Determine if the input source ends in a blank.
|
234 |
-
|
235 |
-
A blank is either a newline or a line consisting of whitespace.
|
236 |
-
|
237 |
-
Parameters
|
238 |
-
----------
|
239 |
-
src : string
|
240 |
-
A single or multiline string.
|
241 |
-
"""
|
242 |
-
if not src: return False
|
243 |
-
ll = src.splitlines()[-1]
|
244 |
-
return (ll == '') or ll.isspace()
|
245 |
-
|
246 |
-
|
247 |
-
last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
|
248 |
-
last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
|
249 |
-
|
250 |
-
def last_two_blanks(src):
|
251 |
-
"""Determine if the input source ends in two blanks.
|
252 |
-
|
253 |
-
A blank is either a newline or a line consisting of whitespace.
|
254 |
-
|
255 |
-
Parameters
|
256 |
-
----------
|
257 |
-
src : string
|
258 |
-
A single or multiline string.
|
259 |
-
"""
|
260 |
-
if not src: return False
|
261 |
-
# The logic here is tricky: I couldn't get a regexp to work and pass all
|
262 |
-
# the tests, so I took a different approach: split the source by lines,
|
263 |
-
# grab the last two and prepend '###\n' as a stand-in for whatever was in
|
264 |
-
# the body before the last two lines. Then, with that structure, it's
|
265 |
-
# possible to analyze with two regexps. Not the most elegant solution, but
|
266 |
-
# it works. If anyone tries to change this logic, make sure to validate
|
267 |
-
# the whole test suite first!
|
268 |
-
new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
|
269 |
-
return (bool(last_two_blanks_re.match(new_src)) or
|
270 |
-
bool(last_two_blanks_re2.match(new_src)) )
|
271 |
-
|
272 |
-
|
273 |
-
def remove_comments(src):
|
274 |
-
"""Remove all comments from input source.
|
275 |
-
|
276 |
-
Note: comments are NOT recognized inside of strings!
|
277 |
-
|
278 |
-
Parameters
|
279 |
-
----------
|
280 |
-
src : string
|
281 |
-
A single or multiline input string.
|
282 |
-
|
283 |
-
Returns
|
284 |
-
-------
|
285 |
-
String with all Python comments removed.
|
286 |
-
"""
|
287 |
-
|
288 |
-
return re.sub('#.*', '', src)
|
289 |
-
|
290 |
-
|
291 |
-
def get_input_encoding():
|
292 |
-
"""Return the default standard input encoding.
|
293 |
-
|
294 |
-
If sys.stdin has no encoding, 'ascii' is returned."""
|
295 |
-
# There are strange environments for which sys.stdin.encoding is None. We
|
296 |
-
# ensure that a valid encoding is returned.
|
297 |
-
encoding = getattr(sys.stdin, 'encoding', None)
|
298 |
-
if encoding is None:
|
299 |
-
encoding = 'ascii'
|
300 |
-
return encoding
|
301 |
-
|
302 |
-
#-----------------------------------------------------------------------------
|
303 |
-
# Classes and functions for normal Python syntax handling
|
304 |
-
#-----------------------------------------------------------------------------
|
305 |
-
|
306 |
-
class InputSplitter(object):
|
307 |
-
r"""An object that can accumulate lines of Python source before execution.
|
308 |
-
|
309 |
-
This object is designed to be fed python source line-by-line, using
|
310 |
-
:meth:`push`. It will return on each push whether the currently pushed
|
311 |
-
code could be executed already. In addition, it provides a method called
|
312 |
-
:meth:`push_accepts_more` that can be used to query whether more input
|
313 |
-
can be pushed into a single interactive block.
|
314 |
-
|
315 |
-
This is a simple example of how an interactive terminal-based client can use
|
316 |
-
this tool::
|
317 |
-
|
318 |
-
isp = InputSplitter()
|
319 |
-
while isp.push_accepts_more():
|
320 |
-
indent = ' '*isp.indent_spaces
|
321 |
-
prompt = '>>> ' + indent
|
322 |
-
line = indent + raw_input(prompt)
|
323 |
-
isp.push(line)
|
324 |
-
print('Input source was:\n', isp.source_reset())
|
325 |
-
"""
|
326 |
-
# A cache for storing the current indentation
|
327 |
-
# The first value stores the most recently processed source input
|
328 |
-
# The second value is the number of spaces for the current indentation
|
329 |
-
# If self.source matches the first value, the second value is a valid
|
330 |
-
# current indentation. Otherwise, the cache is invalid and the indentation
|
331 |
-
# must be recalculated.
|
332 |
-
_indent_spaces_cache: Union[Tuple[None, None], Tuple[str, int]] = None, None
|
333 |
-
# String, indicating the default input encoding. It is computed by default
|
334 |
-
# at initialization time via get_input_encoding(), but it can be reset by a
|
335 |
-
# client with specific knowledge of the encoding.
|
336 |
-
encoding = ''
|
337 |
-
# String where the current full source input is stored, properly encoded.
|
338 |
-
# Reading this attribute is the normal way of querying the currently pushed
|
339 |
-
# source code, that has been properly encoded.
|
340 |
-
source: str = ""
|
341 |
-
# Code object corresponding to the current source. It is automatically
|
342 |
-
# synced to the source, so it can be queried at any time to obtain the code
|
343 |
-
# object; it will be None if the source doesn't compile to valid Python.
|
344 |
-
code: Optional[CodeType] = None
|
345 |
-
|
346 |
-
# Private attributes
|
347 |
-
|
348 |
-
# List with lines of input accumulated so far
|
349 |
-
_buffer: List[str]
|
350 |
-
# Command compiler
|
351 |
-
_compile: codeop.CommandCompiler
|
352 |
-
# Boolean indicating whether the current block is complete
|
353 |
-
_is_complete: Optional[bool] = None
|
354 |
-
# Boolean indicating whether the current block has an unrecoverable syntax error
|
355 |
-
_is_invalid: bool = False
|
356 |
-
|
357 |
-
def __init__(self) -> None:
|
358 |
-
"""Create a new InputSplitter instance."""
|
359 |
-
self._buffer = []
|
360 |
-
self._compile = codeop.CommandCompiler()
|
361 |
-
self.encoding = get_input_encoding()
|
362 |
-
|
363 |
-
def reset(self):
|
364 |
-
"""Reset the input buffer and associated state."""
|
365 |
-
self._buffer[:] = []
|
366 |
-
self.source = ''
|
367 |
-
self.code = None
|
368 |
-
self._is_complete = False
|
369 |
-
self._is_invalid = False
|
370 |
-
|
371 |
-
def source_reset(self):
|
372 |
-
"""Return the input source and perform a full reset.
|
373 |
-
"""
|
374 |
-
out = self.source
|
375 |
-
self.reset()
|
376 |
-
return out
|
377 |
-
|
378 |
-
def check_complete(self, source):
|
379 |
-
"""Return whether a block of code is ready to execute, or should be continued
|
380 |
-
|
381 |
-
This is a non-stateful API, and will reset the state of this InputSplitter.
|
382 |
-
|
383 |
-
Parameters
|
384 |
-
----------
|
385 |
-
source : string
|
386 |
-
Python input code, which can be multiline.
|
387 |
-
|
388 |
-
Returns
|
389 |
-
-------
|
390 |
-
status : str
|
391 |
-
One of 'complete', 'incomplete', or 'invalid' if source is not a
|
392 |
-
prefix of valid code.
|
393 |
-
indent_spaces : int or None
|
394 |
-
The number of spaces by which to indent the next line of code. If
|
395 |
-
status is not 'incomplete', this is None.
|
396 |
-
"""
|
397 |
-
self.reset()
|
398 |
-
try:
|
399 |
-
self.push(source)
|
400 |
-
except SyntaxError:
|
401 |
-
# Transformers in IPythonInputSplitter can raise SyntaxError,
|
402 |
-
# which push() will not catch.
|
403 |
-
return 'invalid', None
|
404 |
-
else:
|
405 |
-
if self._is_invalid:
|
406 |
-
return 'invalid', None
|
407 |
-
elif self.push_accepts_more():
|
408 |
-
return 'incomplete', self.get_indent_spaces()
|
409 |
-
else:
|
410 |
-
return 'complete', None
|
411 |
-
finally:
|
412 |
-
self.reset()
|
413 |
-
|
414 |
-
def push(self, lines:str) -> bool:
|
415 |
-
"""Push one or more lines of input.
|
416 |
-
|
417 |
-
This stores the given lines and returns a status code indicating
|
418 |
-
whether the code forms a complete Python block or not.
|
419 |
-
|
420 |
-
Any exceptions generated in compilation are swallowed, but if an
|
421 |
-
exception was produced, the method returns True.
|
422 |
-
|
423 |
-
Parameters
|
424 |
-
----------
|
425 |
-
lines : string
|
426 |
-
One or more lines of Python input.
|
427 |
-
|
428 |
-
Returns
|
429 |
-
-------
|
430 |
-
is_complete : boolean
|
431 |
-
True if the current input source (the result of the current input
|
432 |
-
plus prior inputs) forms a complete Python execution block. Note that
|
433 |
-
this value is also stored as a private attribute (``_is_complete``), so it
|
434 |
-
can be queried at any time.
|
435 |
-
"""
|
436 |
-
assert isinstance(lines, str)
|
437 |
-
self._store(lines)
|
438 |
-
source = self.source
|
439 |
-
|
440 |
-
# Before calling _compile(), reset the code object to None so that if an
|
441 |
-
# exception is raised in compilation, we don't mislead by having
|
442 |
-
# inconsistent code/source attributes.
|
443 |
-
self.code, self._is_complete = None, None
|
444 |
-
self._is_invalid = False
|
445 |
-
|
446 |
-
# Honor termination lines properly
|
447 |
-
if source.endswith('\\\n'):
|
448 |
-
return False
|
449 |
-
|
450 |
-
try:
|
451 |
-
with warnings.catch_warnings():
|
452 |
-
warnings.simplefilter('error', SyntaxWarning)
|
453 |
-
self.code = self._compile(source, symbol="exec")
|
454 |
-
# Invalid syntax can produce any of a number of different errors from
|
455 |
-
# inside the compiler, so we have to catch them all. Syntax errors
|
456 |
-
# immediately produce a 'ready' block, so the invalid Python can be
|
457 |
-
# sent to the kernel for evaluation with possible ipython
|
458 |
-
# special-syntax conversion.
|
459 |
-
except (SyntaxError, OverflowError, ValueError, TypeError,
|
460 |
-
MemoryError, SyntaxWarning):
|
461 |
-
self._is_complete = True
|
462 |
-
self._is_invalid = True
|
463 |
-
else:
|
464 |
-
# Compilation didn't produce any exceptions (though it may not have
|
465 |
-
# given a complete code object)
|
466 |
-
self._is_complete = self.code is not None
|
467 |
-
|
468 |
-
return self._is_complete
|
469 |
-
|
470 |
-
def push_accepts_more(self):
|
471 |
-
"""Return whether a block of interactive input can accept more input.
|
472 |
-
|
473 |
-
This method is meant to be used by line-oriented frontends, who need to
|
474 |
-
guess whether a block is complete or not based solely on prior and
|
475 |
-
current input lines. The InputSplitter considers it has a complete
|
476 |
-
interactive block and will not accept more input when either:
|
477 |
-
|
478 |
-
* A SyntaxError is raised
|
479 |
-
|
480 |
-
* The code is complete and consists of a single line or a single
|
481 |
-
non-compound statement
|
482 |
-
|
483 |
-
* The code is complete and has a blank line at the end
|
484 |
-
|
485 |
-
If the current input produces a syntax error, this method immediately
|
486 |
-
returns False but does *not* raise the syntax error exception, as
|
487 |
-
typically clients will want to send invalid syntax to an execution
|
488 |
-
backend which might convert the invalid syntax into valid Python via
|
489 |
-
one of the dynamic IPython mechanisms.
|
490 |
-
"""
|
491 |
-
|
492 |
-
# With incomplete input, unconditionally accept more
|
493 |
-
# A syntax error also sets _is_complete to True - see push()
|
494 |
-
if not self._is_complete:
|
495 |
-
#print("Not complete") # debug
|
496 |
-
return True
|
497 |
-
|
498 |
-
# The user can make any (complete) input execute by leaving a blank line
|
499 |
-
last_line = self.source.splitlines()[-1]
|
500 |
-
if (not last_line) or last_line.isspace():
|
501 |
-
#print("Blank line") # debug
|
502 |
-
return False
|
503 |
-
|
504 |
-
# If there's just a single line or AST node, and we're flush left, as is
|
505 |
-
# the case after a simple statement such as 'a=1', we want to execute it
|
506 |
-
# straight away.
|
507 |
-
if self.get_indent_spaces() == 0:
|
508 |
-
if len(self.source.splitlines()) <= 1:
|
509 |
-
return False
|
510 |
-
|
511 |
-
try:
|
512 |
-
code_ast = ast.parse("".join(self._buffer))
|
513 |
-
except Exception:
|
514 |
-
#print("Can't parse AST") # debug
|
515 |
-
return False
|
516 |
-
else:
|
517 |
-
if len(code_ast.body) == 1 and \
|
518 |
-
not hasattr(code_ast.body[0], 'body'):
|
519 |
-
#print("Simple statement") # debug
|
520 |
-
return False
|
521 |
-
|
522 |
-
# General fallback - accept more code
|
523 |
-
return True
|
524 |
-
|
525 |
-
def get_indent_spaces(self) -> int:
|
526 |
-
sourcefor, n = self._indent_spaces_cache
|
527 |
-
if sourcefor == self.source:
|
528 |
-
assert n is not None
|
529 |
-
return n
|
530 |
-
|
531 |
-
# self.source always has a trailing newline
|
532 |
-
n = find_next_indent(self.source[:-1])
|
533 |
-
self._indent_spaces_cache = (self.source, n)
|
534 |
-
return n
|
535 |
-
|
536 |
-
# Backwards compatibility. I think all code that used .indent_spaces was
|
537 |
-
# inside IPython, but we can leave this here until IPython 7 in case any
|
538 |
-
# other modules are using it. -TK, November 2017
|
539 |
-
indent_spaces = property(get_indent_spaces)
|
540 |
-
|
541 |
-
def _store(self, lines, buffer=None, store='source'):
|
542 |
-
"""Store one or more lines of input.
|
543 |
-
|
544 |
-
If input lines are not newline-terminated, a newline is automatically
|
545 |
-
appended."""
|
546 |
-
|
547 |
-
if buffer is None:
|
548 |
-
buffer = self._buffer
|
549 |
-
|
550 |
-
if lines.endswith('\n'):
|
551 |
-
buffer.append(lines)
|
552 |
-
else:
|
553 |
-
buffer.append(lines+'\n')
|
554 |
-
setattr(self, store, self._set_source(buffer))
|
555 |
-
|
556 |
-
def _set_source(self, buffer):
|
557 |
-
return u''.join(buffer)
|
558 |
-
|
559 |
-
|
560 |
-
class IPythonInputSplitter(InputSplitter):
|
561 |
-
"""An input splitter that recognizes all of IPython's special syntax."""
|
562 |
-
|
563 |
-
# String with raw, untransformed input.
|
564 |
-
source_raw = ''
|
565 |
-
|
566 |
-
# Flag to track when a transformer has stored input that it hasn't given
|
567 |
-
# back yet.
|
568 |
-
transformer_accumulating = False
|
569 |
-
|
570 |
-
# Flag to track when assemble_python_lines has stored input that it hasn't
|
571 |
-
# given back yet.
|
572 |
-
within_python_line = False
|
573 |
-
|
574 |
-
# Private attributes
|
575 |
-
|
576 |
-
# List with lines of raw input accumulated so far.
|
577 |
-
_buffer_raw: List[str]
|
578 |
-
|
579 |
-
def __init__(self, line_input_checker=True, physical_line_transforms=None,
|
580 |
-
logical_line_transforms=None, python_line_transforms=None):
|
581 |
-
super(IPythonInputSplitter, self).__init__()
|
582 |
-
self._buffer_raw = []
|
583 |
-
self._validate = True
|
584 |
-
|
585 |
-
if physical_line_transforms is not None:
|
586 |
-
self.physical_line_transforms = physical_line_transforms
|
587 |
-
else:
|
588 |
-
self.physical_line_transforms = [
|
589 |
-
leading_indent(),
|
590 |
-
classic_prompt(),
|
591 |
-
ipy_prompt(),
|
592 |
-
cellmagic(end_on_blank_line=line_input_checker),
|
593 |
-
]
|
594 |
-
|
595 |
-
self.assemble_logical_lines = assemble_logical_lines()
|
596 |
-
if logical_line_transforms is not None:
|
597 |
-
self.logical_line_transforms = logical_line_transforms
|
598 |
-
else:
|
599 |
-
self.logical_line_transforms = [
|
600 |
-
help_end(),
|
601 |
-
escaped_commands(),
|
602 |
-
assign_from_magic(),
|
603 |
-
assign_from_system(),
|
604 |
-
]
|
605 |
-
|
606 |
-
self.assemble_python_lines = assemble_python_lines()
|
607 |
-
if python_line_transforms is not None:
|
608 |
-
self.python_line_transforms = python_line_transforms
|
609 |
-
else:
|
610 |
-
# We don't use any of these at present
|
611 |
-
self.python_line_transforms = []
|
612 |
-
|
613 |
-
@property
|
614 |
-
def transforms(self):
|
615 |
-
"Quick access to all transformers."
|
616 |
-
return self.physical_line_transforms + \
|
617 |
-
[self.assemble_logical_lines] + self.logical_line_transforms + \
|
618 |
-
[self.assemble_python_lines] + self.python_line_transforms
|
619 |
-
|
620 |
-
@property
|
621 |
-
def transforms_in_use(self):
|
622 |
-
"""Transformers, excluding logical line transformers if we're in a
|
623 |
-
Python line."""
|
624 |
-
t = self.physical_line_transforms[:]
|
625 |
-
if not self.within_python_line:
|
626 |
-
t += [self.assemble_logical_lines] + self.logical_line_transforms
|
627 |
-
return t + [self.assemble_python_lines] + self.python_line_transforms
|
628 |
-
|
629 |
-
def reset(self):
|
630 |
-
"""Reset the input buffer and associated state."""
|
631 |
-
super(IPythonInputSplitter, self).reset()
|
632 |
-
self._buffer_raw[:] = []
|
633 |
-
self.source_raw = ''
|
634 |
-
self.transformer_accumulating = False
|
635 |
-
self.within_python_line = False
|
636 |
-
|
637 |
-
for t in self.transforms:
|
638 |
-
try:
|
639 |
-
t.reset()
|
640 |
-
except SyntaxError:
|
641 |
-
# Nothing that calls reset() expects to handle transformer
|
642 |
-
# errors
|
643 |
-
pass
|
644 |
-
|
645 |
-
def flush_transformers(self: Self):
|
646 |
-
def _flush(transform, outs: List[str]):
|
647 |
-
"""yield transformed lines
|
648 |
-
|
649 |
-
always strings, never None
|
650 |
-
|
651 |
-
transform: the current transform
|
652 |
-
outs: an iterable of previously transformed inputs.
|
653 |
-
Each may be multiline, which will be passed
|
654 |
-
one line at a time to transform.
|
655 |
-
"""
|
656 |
-
for out in outs:
|
657 |
-
for line in out.splitlines():
|
658 |
-
# push one line at a time
|
659 |
-
tmp = transform.push(line)
|
660 |
-
if tmp is not None:
|
661 |
-
yield tmp
|
662 |
-
|
663 |
-
# reset the transform
|
664 |
-
tmp = transform.reset()
|
665 |
-
if tmp is not None:
|
666 |
-
yield tmp
|
667 |
-
|
668 |
-
out: List[str] = []
|
669 |
-
for t in self.transforms_in_use:
|
670 |
-
out = _flush(t, out)
|
671 |
-
|
672 |
-
out = list(out)
|
673 |
-
if out:
|
674 |
-
self._store('\n'.join(out))
|
675 |
-
|
676 |
-
def raw_reset(self):
|
677 |
-
"""Return raw input only and perform a full reset.
|
678 |
-
"""
|
679 |
-
out = self.source_raw
|
680 |
-
self.reset()
|
681 |
-
return out
|
682 |
-
|
683 |
-
def source_reset(self):
|
684 |
-
try:
|
685 |
-
self.flush_transformers()
|
686 |
-
return self.source
|
687 |
-
finally:
|
688 |
-
self.reset()
|
689 |
-
|
690 |
-
def push_accepts_more(self):
|
691 |
-
if self.transformer_accumulating:
|
692 |
-
return True
|
693 |
-
else:
|
694 |
-
return super(IPythonInputSplitter, self).push_accepts_more()
|
695 |
-
|
696 |
-
def transform_cell(self, cell):
|
697 |
-
"""Process and translate a cell of input.
|
698 |
-
"""
|
699 |
-
self.reset()
|
700 |
-
try:
|
701 |
-
self.push(cell)
|
702 |
-
self.flush_transformers()
|
703 |
-
return self.source
|
704 |
-
finally:
|
705 |
-
self.reset()
|
706 |
-
|
707 |
-
def push(self, lines:str) -> bool:
|
708 |
-
"""Push one or more lines of IPython input.
|
709 |
-
|
710 |
-
This stores the given lines and returns a status code indicating
|
711 |
-
whether the code forms a complete Python block or not, after processing
|
712 |
-
all input lines for special IPython syntax.
|
713 |
-
|
714 |
-
Any exceptions generated in compilation are swallowed, but if an
|
715 |
-
exception was produced, the method returns True.
|
716 |
-
|
717 |
-
Parameters
|
718 |
-
----------
|
719 |
-
lines : string
|
720 |
-
One or more lines of Python input.
|
721 |
-
|
722 |
-
Returns
|
723 |
-
-------
|
724 |
-
is_complete : boolean
|
725 |
-
True if the current input source (the result of the current input
|
726 |
-
plus prior inputs) forms a complete Python execution block. Note that
|
727 |
-
this value is also stored as a private attribute (_is_complete), so it
|
728 |
-
can be queried at any time.
|
729 |
-
"""
|
730 |
-
assert isinstance(lines, str)
|
731 |
-
# We must ensure all input is pure unicode
|
732 |
-
# ''.splitlines() --> [], but we need to push the empty line to transformers
|
733 |
-
lines_list = lines.splitlines()
|
734 |
-
if not lines_list:
|
735 |
-
lines_list = ['']
|
736 |
-
|
737 |
-
# Store raw source before applying any transformations to it. Note
|
738 |
-
# that this must be done *after* the reset() call that would otherwise
|
739 |
-
# flush the buffer.
|
740 |
-
self._store(lines, self._buffer_raw, 'source_raw')
|
741 |
-
|
742 |
-
transformed_lines_list = []
|
743 |
-
for line in lines_list:
|
744 |
-
transformed = self._transform_line(line)
|
745 |
-
if transformed is not None:
|
746 |
-
transformed_lines_list.append(transformed)
|
747 |
-
|
748 |
-
if transformed_lines_list:
|
749 |
-
transformed_lines = '\n'.join(transformed_lines_list)
|
750 |
-
return super(IPythonInputSplitter, self).push(transformed_lines)
|
751 |
-
else:
|
752 |
-
# Got nothing back from transformers - they must be waiting for
|
753 |
-
# more input.
|
754 |
-
return False
|
755 |
-
|
756 |
-
def _transform_line(self, line):
|
757 |
-
"""Push a line of input code through the various transformers.
|
758 |
-
|
759 |
-
Returns any output from the transformers, or None if a transformer
|
760 |
-
is accumulating lines.
|
761 |
-
|
762 |
-
Sets self.transformer_accumulating as a side effect.
|
763 |
-
"""
|
764 |
-
def _accumulating(dbg):
|
765 |
-
#print(dbg)
|
766 |
-
self.transformer_accumulating = True
|
767 |
-
return None
|
768 |
-
|
769 |
-
for transformer in self.physical_line_transforms:
|
770 |
-
line = transformer.push(line)
|
771 |
-
if line is None:
|
772 |
-
return _accumulating(transformer)
|
773 |
-
|
774 |
-
if not self.within_python_line:
|
775 |
-
line = self.assemble_logical_lines.push(line)
|
776 |
-
if line is None:
|
777 |
-
return _accumulating('acc logical line')
|
778 |
-
|
779 |
-
for transformer in self.logical_line_transforms:
|
780 |
-
line = transformer.push(line)
|
781 |
-
if line is None:
|
782 |
-
return _accumulating(transformer)
|
783 |
-
|
784 |
-
line = self.assemble_python_lines.push(line)
|
785 |
-
if line is None:
|
786 |
-
self.within_python_line = True
|
787 |
-
return _accumulating('acc python line')
|
788 |
-
else:
|
789 |
-
self.within_python_line = False
|
790 |
-
|
791 |
-
for transformer in self.python_line_transforms:
|
792 |
-
line = transformer.push(line)
|
793 |
-
if line is None:
|
794 |
-
return _accumulating(transformer)
|
795 |
-
|
796 |
-
#print("transformers clear") #debug
|
797 |
-
self.transformer_accumulating = False
|
798 |
-
return line
|
799 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/inputtransformer.py
DELETED
@@ -1,577 +0,0 @@
|
|
1 |
-
"""DEPRECATED: Input transformer classes to support IPython special syntax.
|
2 |
-
|
3 |
-
This module was deprecated in IPython 7.0, in favour of inputtransformer2.
|
4 |
-
|
5 |
-
This includes the machinery to recognise and transform ``%magic`` commands,
|
6 |
-
``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
|
7 |
-
"""
|
8 |
-
import abc
|
9 |
-
import functools
|
10 |
-
import re
|
11 |
-
import tokenize
|
12 |
-
import warnings
|
13 |
-
from tokenize import untokenize, TokenError
|
14 |
-
from io import StringIO
|
15 |
-
|
16 |
-
from IPython.core.splitinput import LineInfo
|
17 |
-
from IPython.utils import tokenutil
|
18 |
-
|
19 |
-
#-----------------------------------------------------------------------------
|
20 |
-
# Globals
|
21 |
-
#-----------------------------------------------------------------------------
|
22 |
-
|
23 |
-
# The escape sequences that define the syntax transformations IPython will
|
24 |
-
# apply to user input. These can NOT be just changed here: many regular
|
25 |
-
# expressions and other parts of the code may use their hardcoded values, and
|
26 |
-
# for all intents and purposes they constitute the 'IPython syntax', so they
|
27 |
-
# should be considered fixed.
|
28 |
-
|
29 |
-
ESC_SHELL = '!' # Send line to underlying system shell
|
30 |
-
ESC_SH_CAP = '!!' # Send line to system shell and capture output
|
31 |
-
ESC_HELP = '?' # Find information about object
|
32 |
-
ESC_HELP2 = '??' # Find extra-detailed information about object
|
33 |
-
ESC_MAGIC = '%' # Call magic function
|
34 |
-
ESC_MAGIC2 = '%%' # Call cell-magic function
|
35 |
-
ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
|
36 |
-
ESC_QUOTE2 = ';' # Quote all args as a single string, call
|
37 |
-
ESC_PAREN = '/' # Call first argument with rest of line as arguments
|
38 |
-
|
39 |
-
ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
|
40 |
-
ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
|
41 |
-
ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
|
42 |
-
|
43 |
-
|
44 |
-
class InputTransformer(metaclass=abc.ABCMeta):
|
45 |
-
"""Abstract base class for line-based input transformers."""
|
46 |
-
|
47 |
-
def __init__(self):
|
48 |
-
warnings.warn(
|
49 |
-
"`InputTransformer` has been deprecated since IPython 7.0"
|
50 |
-
" and emit a warnig since IPython 8.31, it"
|
51 |
-
" will be removed in the future",
|
52 |
-
DeprecationWarning,
|
53 |
-
stacklevel=2,
|
54 |
-
)
|
55 |
-
|
56 |
-
@abc.abstractmethod
|
57 |
-
def push(self, line):
|
58 |
-
"""Send a line of input to the transformer, returning the transformed
|
59 |
-
input or None if the transformer is waiting for more input.
|
60 |
-
|
61 |
-
Must be overridden by subclasses.
|
62 |
-
|
63 |
-
Implementations may raise ``SyntaxError`` if the input is invalid. No
|
64 |
-
other exceptions may be raised.
|
65 |
-
"""
|
66 |
-
pass
|
67 |
-
|
68 |
-
@abc.abstractmethod
|
69 |
-
def reset(self):
|
70 |
-
"""Return, transformed any lines that the transformer has accumulated,
|
71 |
-
and reset its internal state.
|
72 |
-
|
73 |
-
Must be overridden by subclasses.
|
74 |
-
"""
|
75 |
-
pass
|
76 |
-
|
77 |
-
@classmethod
|
78 |
-
def wrap(cls, func):
|
79 |
-
"""Can be used by subclasses as a decorator, to return a factory that
|
80 |
-
will allow instantiation with the decorated object.
|
81 |
-
"""
|
82 |
-
@functools.wraps(func)
|
83 |
-
def transformer_factory(**kwargs):
|
84 |
-
return cls(func, **kwargs) # type: ignore [call-arg]
|
85 |
-
|
86 |
-
return transformer_factory
|
87 |
-
|
88 |
-
class StatelessInputTransformer(InputTransformer):
|
89 |
-
"""Wrapper for a stateless input transformer implemented as a function."""
|
90 |
-
def __init__(self, func):
|
91 |
-
super().__init__()
|
92 |
-
warnings.warn(
|
93 |
-
"`StatelessInputTransformer` has been deprecated since IPython 7.0"
|
94 |
-
" and emit a warnig since IPython 8.31, it"
|
95 |
-
" will be removed in the future",
|
96 |
-
DeprecationWarning,
|
97 |
-
stacklevel=2,
|
98 |
-
)
|
99 |
-
self.func = func
|
100 |
-
|
101 |
-
def __repr__(self):
|
102 |
-
return "StatelessInputTransformer(func={0!r})".format(self.func)
|
103 |
-
|
104 |
-
def push(self, line):
|
105 |
-
"""Send a line of input to the transformer, returning the
|
106 |
-
transformed input."""
|
107 |
-
return self.func(line)
|
108 |
-
|
109 |
-
def reset(self):
|
110 |
-
"""No-op - exists for compatibility."""
|
111 |
-
pass
|
112 |
-
|
113 |
-
class CoroutineInputTransformer(InputTransformer):
|
114 |
-
"""Wrapper for an input transformer implemented as a coroutine."""
|
115 |
-
def __init__(self, coro, **kwargs):
|
116 |
-
# Prime it
|
117 |
-
super().__init__()
|
118 |
-
warnings.warn(
|
119 |
-
"`CoroutineInputTransformer` has been deprecated since IPython 7.0"
|
120 |
-
" and emit a warnig since IPython 8.31, it"
|
121 |
-
" will be removed in the future",
|
122 |
-
DeprecationWarning,
|
123 |
-
stacklevel=2,
|
124 |
-
)
|
125 |
-
self.coro = coro(**kwargs)
|
126 |
-
next(self.coro)
|
127 |
-
|
128 |
-
def __repr__(self):
|
129 |
-
return "CoroutineInputTransformer(coro={0!r})".format(self.coro)
|
130 |
-
|
131 |
-
def push(self, line):
|
132 |
-
"""Send a line of input to the transformer, returning the
|
133 |
-
transformed input or None if the transformer is waiting for more
|
134 |
-
input.
|
135 |
-
"""
|
136 |
-
return self.coro.send(line)
|
137 |
-
|
138 |
-
def reset(self):
|
139 |
-
"""Return, transformed any lines that the transformer has
|
140 |
-
accumulated, and reset its internal state.
|
141 |
-
"""
|
142 |
-
return self.coro.send(None)
|
143 |
-
|
144 |
-
class TokenInputTransformer(InputTransformer):
|
145 |
-
"""Wrapper for a token-based input transformer.
|
146 |
-
|
147 |
-
func should accept a list of tokens (5-tuples, see tokenize docs), and
|
148 |
-
return an iterable which can be passed to tokenize.untokenize().
|
149 |
-
"""
|
150 |
-
def __init__(self, func):
|
151 |
-
warnings.warn(
|
152 |
-
"`CoroutineInputTransformer` has been deprecated since IPython 7.0"
|
153 |
-
" and emit a warnig since IPython 8.31, it"
|
154 |
-
" will be removed in the future",
|
155 |
-
DeprecationWarning,
|
156 |
-
stacklevel=2,
|
157 |
-
)
|
158 |
-
self.func = func
|
159 |
-
self.buf = []
|
160 |
-
self.reset_tokenizer()
|
161 |
-
|
162 |
-
def reset_tokenizer(self):
|
163 |
-
it = iter(self.buf)
|
164 |
-
self.tokenizer = tokenutil.generate_tokens_catch_errors(it.__next__)
|
165 |
-
|
166 |
-
def push(self, line):
|
167 |
-
self.buf.append(line + '\n')
|
168 |
-
if all(l.isspace() for l in self.buf):
|
169 |
-
return self.reset()
|
170 |
-
|
171 |
-
tokens = []
|
172 |
-
stop_at_NL = False
|
173 |
-
try:
|
174 |
-
for intok in self.tokenizer:
|
175 |
-
tokens.append(intok)
|
176 |
-
t = intok[0]
|
177 |
-
if t == tokenize.NEWLINE or (stop_at_NL and t == tokenize.NL):
|
178 |
-
# Stop before we try to pull a line we don't have yet
|
179 |
-
break
|
180 |
-
elif t == tokenize.ERRORTOKEN:
|
181 |
-
stop_at_NL = True
|
182 |
-
except TokenError:
|
183 |
-
# Multi-line statement - stop and try again with the next line
|
184 |
-
self.reset_tokenizer()
|
185 |
-
return None
|
186 |
-
|
187 |
-
return self.output(tokens)
|
188 |
-
|
189 |
-
def output(self, tokens):
|
190 |
-
self.buf.clear()
|
191 |
-
self.reset_tokenizer()
|
192 |
-
return untokenize(self.func(tokens)).rstrip('\n')
|
193 |
-
|
194 |
-
def reset(self):
|
195 |
-
l = ''.join(self.buf)
|
196 |
-
self.buf.clear()
|
197 |
-
self.reset_tokenizer()
|
198 |
-
if l:
|
199 |
-
return l.rstrip('\n')
|
200 |
-
|
201 |
-
class assemble_python_lines(TokenInputTransformer):
|
202 |
-
def __init__(self):
|
203 |
-
super().__init__(None)
|
204 |
-
|
205 |
-
def output(self, tokens):
|
206 |
-
return self.reset()
|
207 |
-
|
208 |
-
@CoroutineInputTransformer.wrap
|
209 |
-
def assemble_logical_lines():
|
210 |
-
r"""Join lines following explicit line continuations (\)"""
|
211 |
-
line = ''
|
212 |
-
while True:
|
213 |
-
line = (yield line)
|
214 |
-
if not line or line.isspace():
|
215 |
-
continue
|
216 |
-
|
217 |
-
parts = []
|
218 |
-
while line is not None:
|
219 |
-
if line.endswith('\\') and (not has_comment(line)):
|
220 |
-
parts.append(line[:-1])
|
221 |
-
line = (yield None) # Get another line
|
222 |
-
else:
|
223 |
-
parts.append(line)
|
224 |
-
break
|
225 |
-
|
226 |
-
# Output
|
227 |
-
line = ''.join(parts)
|
228 |
-
|
229 |
-
# Utilities
|
230 |
-
def _make_help_call(target: str, esc: str, lspace: str) -> str:
|
231 |
-
"""Prepares a pinfo(2)/psearch call from a target name and the escape
|
232 |
-
(i.e. ? or ??)"""
|
233 |
-
method = 'pinfo2' if esc == '??' \
|
234 |
-
else 'psearch' if '*' in target \
|
235 |
-
else 'pinfo'
|
236 |
-
arg = " ".join([method, target])
|
237 |
-
#Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
|
238 |
-
t_magic_name, _, t_magic_arg_s = arg.partition(' ')
|
239 |
-
t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
|
240 |
-
return "%sget_ipython().run_line_magic(%r, %r)" % (
|
241 |
-
lspace,
|
242 |
-
t_magic_name,
|
243 |
-
t_magic_arg_s,
|
244 |
-
)
|
245 |
-
|
246 |
-
|
247 |
-
# These define the transformations for the different escape characters.
|
248 |
-
def _tr_system(line_info: LineInfo):
|
249 |
-
"Translate lines escaped with: !"
|
250 |
-
cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
|
251 |
-
return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
|
252 |
-
|
253 |
-
|
254 |
-
def _tr_system2(line_info: LineInfo):
|
255 |
-
"Translate lines escaped with: !!"
|
256 |
-
cmd = line_info.line.lstrip()[2:]
|
257 |
-
return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
|
258 |
-
|
259 |
-
|
260 |
-
def _tr_help(line_info: LineInfo):
|
261 |
-
"Translate lines escaped with: ?/??"
|
262 |
-
# A naked help line should just fire the intro help screen
|
263 |
-
if not line_info.line[1:]:
|
264 |
-
return 'get_ipython().show_usage()'
|
265 |
-
|
266 |
-
return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
|
267 |
-
|
268 |
-
|
269 |
-
def _tr_magic(line_info: LineInfo):
|
270 |
-
"Translate lines escaped with: %"
|
271 |
-
tpl = '%sget_ipython().run_line_magic(%r, %r)'
|
272 |
-
if line_info.line.startswith(ESC_MAGIC2):
|
273 |
-
return line_info.line
|
274 |
-
cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
|
275 |
-
#Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
|
276 |
-
t_magic_name, _, t_magic_arg_s = cmd.partition(' ')
|
277 |
-
t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
|
278 |
-
return tpl % (line_info.pre, t_magic_name, t_magic_arg_s)
|
279 |
-
|
280 |
-
|
281 |
-
def _tr_quote(line_info: LineInfo):
|
282 |
-
"Translate lines escaped with: ,"
|
283 |
-
return '%s%s("%s")' % (line_info.pre, line_info.ifun,
|
284 |
-
'", "'.join(line_info.the_rest.split()) )
|
285 |
-
|
286 |
-
|
287 |
-
def _tr_quote2(line_info: LineInfo):
|
288 |
-
"Translate lines escaped with: ;"
|
289 |
-
return '%s%s("%s")' % (line_info.pre, line_info.ifun,
|
290 |
-
line_info.the_rest)
|
291 |
-
|
292 |
-
|
293 |
-
def _tr_paren(line_info: LineInfo):
|
294 |
-
"Translate lines escaped with: /"
|
295 |
-
return '%s%s(%s)' % (line_info.pre, line_info.ifun,
|
296 |
-
", ".join(line_info.the_rest.split()))
|
297 |
-
|
298 |
-
tr = { ESC_SHELL : _tr_system,
|
299 |
-
ESC_SH_CAP : _tr_system2,
|
300 |
-
ESC_HELP : _tr_help,
|
301 |
-
ESC_HELP2 : _tr_help,
|
302 |
-
ESC_MAGIC : _tr_magic,
|
303 |
-
ESC_QUOTE : _tr_quote,
|
304 |
-
ESC_QUOTE2 : _tr_quote2,
|
305 |
-
ESC_PAREN : _tr_paren }
|
306 |
-
|
307 |
-
@StatelessInputTransformer.wrap
|
308 |
-
def escaped_commands(line: str):
|
309 |
-
"""Transform escaped commands - %magic, !system, ?help + various autocalls."""
|
310 |
-
if not line or line.isspace():
|
311 |
-
return line
|
312 |
-
lineinf = LineInfo(line)
|
313 |
-
if lineinf.esc not in tr:
|
314 |
-
return line
|
315 |
-
|
316 |
-
return tr[lineinf.esc](lineinf)
|
317 |
-
|
318 |
-
_initial_space_re = re.compile(r'\s*')
|
319 |
-
|
320 |
-
_help_end_re = re.compile(r"""(%{0,2}
|
321 |
-
(?!\d)[\w*]+ # Variable name
|
322 |
-
(\.(?!\d)[\w*]+)* # .etc.etc
|
323 |
-
)
|
324 |
-
(\?\??)$ # ? or ??
|
325 |
-
""",
|
326 |
-
re.VERBOSE)
|
327 |
-
|
328 |
-
# Extra pseudotokens for multiline strings and data structures
|
329 |
-
_MULTILINE_STRING = object()
|
330 |
-
_MULTILINE_STRUCTURE = object()
|
331 |
-
|
332 |
-
def _line_tokens(line):
|
333 |
-
"""Helper for has_comment and ends_in_comment_or_string."""
|
334 |
-
readline = StringIO(line).readline
|
335 |
-
toktypes = set()
|
336 |
-
try:
|
337 |
-
for t in tokenutil.generate_tokens_catch_errors(readline):
|
338 |
-
toktypes.add(t[0])
|
339 |
-
except TokenError as e:
|
340 |
-
# There are only two cases where a TokenError is raised.
|
341 |
-
if 'multi-line string' in e.args[0]:
|
342 |
-
toktypes.add(_MULTILINE_STRING)
|
343 |
-
else:
|
344 |
-
toktypes.add(_MULTILINE_STRUCTURE)
|
345 |
-
return toktypes
|
346 |
-
|
347 |
-
def has_comment(src):
|
348 |
-
"""Indicate whether an input line has (i.e. ends in, or is) a comment.
|
349 |
-
|
350 |
-
This uses tokenize, so it can distinguish comments from # inside strings.
|
351 |
-
|
352 |
-
Parameters
|
353 |
-
----------
|
354 |
-
src : string
|
355 |
-
A single line input string.
|
356 |
-
|
357 |
-
Returns
|
358 |
-
-------
|
359 |
-
comment : bool
|
360 |
-
True if source has a comment.
|
361 |
-
"""
|
362 |
-
return (tokenize.COMMENT in _line_tokens(src))
|
363 |
-
|
364 |
-
def ends_in_comment_or_string(src):
|
365 |
-
"""Indicates whether or not an input line ends in a comment or within
|
366 |
-
a multiline string.
|
367 |
-
|
368 |
-
Parameters
|
369 |
-
----------
|
370 |
-
src : string
|
371 |
-
A single line input string.
|
372 |
-
|
373 |
-
Returns
|
374 |
-
-------
|
375 |
-
comment : bool
|
376 |
-
True if source ends in a comment or multiline string.
|
377 |
-
"""
|
378 |
-
toktypes = _line_tokens(src)
|
379 |
-
return (tokenize.COMMENT in toktypes) or (_MULTILINE_STRING in toktypes)
|
380 |
-
|
381 |
-
|
382 |
-
@StatelessInputTransformer.wrap
|
383 |
-
def help_end(line: str):
|
384 |
-
"""Translate lines with ?/?? at the end"""
|
385 |
-
m = _help_end_re.search(line)
|
386 |
-
if m is None or ends_in_comment_or_string(line):
|
387 |
-
return line
|
388 |
-
target = m.group(1)
|
389 |
-
esc = m.group(3)
|
390 |
-
match = _initial_space_re.match(line)
|
391 |
-
assert match is not None
|
392 |
-
lspace = match.group(0)
|
393 |
-
|
394 |
-
return _make_help_call(target, esc, lspace)
|
395 |
-
|
396 |
-
|
397 |
-
@CoroutineInputTransformer.wrap
|
398 |
-
def cellmagic(end_on_blank_line: bool = False):
|
399 |
-
"""Captures & transforms cell magics.
|
400 |
-
|
401 |
-
After a cell magic is started, this stores up any lines it gets until it is
|
402 |
-
reset (sent None).
|
403 |
-
"""
|
404 |
-
tpl = 'get_ipython().run_cell_magic(%r, %r, %r)'
|
405 |
-
cellmagic_help_re = re.compile(r'%%\w+\?')
|
406 |
-
line = ''
|
407 |
-
while True:
|
408 |
-
line = (yield line)
|
409 |
-
# consume leading empty lines
|
410 |
-
while not line:
|
411 |
-
line = (yield line)
|
412 |
-
|
413 |
-
if not line.startswith(ESC_MAGIC2):
|
414 |
-
# This isn't a cell magic, idle waiting for reset then start over
|
415 |
-
while line is not None:
|
416 |
-
line = (yield line)
|
417 |
-
continue
|
418 |
-
|
419 |
-
if cellmagic_help_re.match(line):
|
420 |
-
# This case will be handled by help_end
|
421 |
-
continue
|
422 |
-
|
423 |
-
first = line
|
424 |
-
body = []
|
425 |
-
line = (yield None)
|
426 |
-
while (line is not None) and \
|
427 |
-
((line.strip() != '') or not end_on_blank_line):
|
428 |
-
body.append(line)
|
429 |
-
line = (yield None)
|
430 |
-
|
431 |
-
# Output
|
432 |
-
magic_name, _, first = first.partition(' ')
|
433 |
-
magic_name = magic_name.lstrip(ESC_MAGIC2)
|
434 |
-
line = tpl % (magic_name, first, u'\n'.join(body))
|
435 |
-
|
436 |
-
|
437 |
-
def _strip_prompts(prompt_re, initial_re=None, turnoff_re=None):
|
438 |
-
"""Remove matching input prompts from a block of input.
|
439 |
-
|
440 |
-
Parameters
|
441 |
-
----------
|
442 |
-
prompt_re : regular expression
|
443 |
-
A regular expression matching any input prompt (including continuation)
|
444 |
-
initial_re : regular expression, optional
|
445 |
-
A regular expression matching only the initial prompt, but not continuation.
|
446 |
-
If no initial expression is given, prompt_re will be used everywhere.
|
447 |
-
Used mainly for plain Python prompts, where the continuation prompt
|
448 |
-
``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
|
449 |
-
|
450 |
-
Notes
|
451 |
-
-----
|
452 |
-
If `initial_re` and `prompt_re differ`,
|
453 |
-
only `initial_re` will be tested against the first line.
|
454 |
-
If any prompt is found on the first two lines,
|
455 |
-
prompts will be stripped from the rest of the block.
|
456 |
-
"""
|
457 |
-
if initial_re is None:
|
458 |
-
initial_re = prompt_re
|
459 |
-
line = ''
|
460 |
-
while True:
|
461 |
-
line = (yield line)
|
462 |
-
|
463 |
-
# First line of cell
|
464 |
-
if line is None:
|
465 |
-
continue
|
466 |
-
out, n1 = initial_re.subn('', line, count=1)
|
467 |
-
if turnoff_re and not n1:
|
468 |
-
if turnoff_re.match(line):
|
469 |
-
# We're in e.g. a cell magic; disable this transformer for
|
470 |
-
# the rest of the cell.
|
471 |
-
while line is not None:
|
472 |
-
line = (yield line)
|
473 |
-
continue
|
474 |
-
|
475 |
-
line = (yield out)
|
476 |
-
|
477 |
-
if line is None:
|
478 |
-
continue
|
479 |
-
# check for any prompt on the second line of the cell,
|
480 |
-
# because people often copy from just after the first prompt,
|
481 |
-
# so we might not see it in the first line.
|
482 |
-
out, n2 = prompt_re.subn('', line, count=1)
|
483 |
-
line = (yield out)
|
484 |
-
|
485 |
-
if n1 or n2:
|
486 |
-
# Found a prompt in the first two lines - check for it in
|
487 |
-
# the rest of the cell as well.
|
488 |
-
while line is not None:
|
489 |
-
line = (yield prompt_re.sub('', line, count=1))
|
490 |
-
|
491 |
-
else:
|
492 |
-
# Prompts not in input - wait for reset
|
493 |
-
while line is not None:
|
494 |
-
line = (yield line)
|
495 |
-
|
496 |
-
@CoroutineInputTransformer.wrap
|
497 |
-
def classic_prompt():
|
498 |
-
"""Strip the >>>/... prompts of the Python interactive shell."""
|
499 |
-
# FIXME: non-capturing version (?:...) usable?
|
500 |
-
prompt_re = re.compile(r'^(>>>|\.\.\.)( |$)')
|
501 |
-
initial_re = re.compile(r'^>>>( |$)')
|
502 |
-
# Any %magic/!system is IPython syntax, so we needn't look for >>> prompts
|
503 |
-
turnoff_re = re.compile(r'^[%!]')
|
504 |
-
return _strip_prompts(prompt_re, initial_re, turnoff_re)
|
505 |
-
|
506 |
-
@CoroutineInputTransformer.wrap
|
507 |
-
def ipy_prompt():
|
508 |
-
"""Strip IPython's In [1]:/...: prompts."""
|
509 |
-
# FIXME: non-capturing version (?:...) usable?
|
510 |
-
prompt_re = re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)')
|
511 |
-
# Disable prompt stripping inside cell magics
|
512 |
-
turnoff_re = re.compile(r'^%%')
|
513 |
-
return _strip_prompts(prompt_re, turnoff_re=turnoff_re)
|
514 |
-
|
515 |
-
|
516 |
-
@CoroutineInputTransformer.wrap
|
517 |
-
def leading_indent():
|
518 |
-
"""Remove leading indentation.
|
519 |
-
|
520 |
-
If the first line starts with a spaces or tabs, the same whitespace will be
|
521 |
-
removed from each following line until it is reset.
|
522 |
-
"""
|
523 |
-
space_re = re.compile(r'^[ \t]+')
|
524 |
-
line = ''
|
525 |
-
while True:
|
526 |
-
line = (yield line)
|
527 |
-
|
528 |
-
if line is None:
|
529 |
-
continue
|
530 |
-
|
531 |
-
m = space_re.match(line)
|
532 |
-
if m:
|
533 |
-
space = m.group(0)
|
534 |
-
while line is not None:
|
535 |
-
if line.startswith(space):
|
536 |
-
line = line[len(space):]
|
537 |
-
line = (yield line)
|
538 |
-
else:
|
539 |
-
# No leading spaces - wait for reset
|
540 |
-
while line is not None:
|
541 |
-
line = (yield line)
|
542 |
-
|
543 |
-
|
544 |
-
_assign_pat = \
|
545 |
-
r'''(?P<lhs>(\s*)
|
546 |
-
([\w\.]+) # Initial identifier
|
547 |
-
(\s*,\s*
|
548 |
-
\*?[\w\.]+)* # Further identifiers for unpacking
|
549 |
-
\s*?,? # Trailing comma
|
550 |
-
)
|
551 |
-
\s*=\s*
|
552 |
-
'''
|
553 |
-
|
554 |
-
assign_system_re = re.compile(r'{}!\s*(?P<cmd>.*)'.format(_assign_pat), re.VERBOSE)
|
555 |
-
assign_system_template = '%s = get_ipython().getoutput(%r)'
|
556 |
-
@StatelessInputTransformer.wrap
|
557 |
-
def assign_from_system(line):
|
558 |
-
"""Transform assignment from system commands (e.g. files = !ls)"""
|
559 |
-
m = assign_system_re.match(line)
|
560 |
-
if m is None:
|
561 |
-
return line
|
562 |
-
|
563 |
-
return assign_system_template % m.group('lhs', 'cmd')
|
564 |
-
|
565 |
-
assign_magic_re = re.compile(r'{}%\s*(?P<cmd>.*)'.format(_assign_pat), re.VERBOSE)
|
566 |
-
assign_magic_template = '%s = get_ipython().run_line_magic(%r, %r)'
|
567 |
-
@StatelessInputTransformer.wrap
|
568 |
-
def assign_from_magic(line):
|
569 |
-
"""Transform assignment from magic commands (e.g. a = %who_ls)"""
|
570 |
-
m = assign_magic_re.match(line)
|
571 |
-
if m is None:
|
572 |
-
return line
|
573 |
-
#Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
|
574 |
-
m_lhs, m_cmd = m.group('lhs', 'cmd')
|
575 |
-
t_magic_name, _, t_magic_arg_s = m_cmd.partition(' ')
|
576 |
-
t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
|
577 |
-
return assign_magic_template % (m_lhs, t_magic_name, t_magic_arg_s)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/inputtransformer2.py
DELETED
@@ -1,830 +0,0 @@
|
|
1 |
-
"""Input transformer machinery to support IPython special syntax.
|
2 |
-
|
3 |
-
This includes the machinery to recognise and transform ``%magic`` commands,
|
4 |
-
``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
|
5 |
-
|
6 |
-
Added: IPython 7.0. Replaces inputsplitter and inputtransformer which were
|
7 |
-
deprecated in 7.0.
|
8 |
-
"""
|
9 |
-
|
10 |
-
# Copyright (c) IPython Development Team.
|
11 |
-
# Distributed under the terms of the Modified BSD License.
|
12 |
-
|
13 |
-
import ast
|
14 |
-
from codeop import CommandCompiler, Compile
|
15 |
-
import re
|
16 |
-
import sys
|
17 |
-
import tokenize
|
18 |
-
from typing import List, Tuple, Optional, Any
|
19 |
-
import warnings
|
20 |
-
|
21 |
-
from IPython.utils import tokenutil
|
22 |
-
|
23 |
-
_indent_re = re.compile(r'^[ \t]+')
|
24 |
-
|
25 |
-
def leading_empty_lines(lines):
|
26 |
-
"""Remove leading empty lines
|
27 |
-
|
28 |
-
If the leading lines are empty or contain only whitespace, they will be
|
29 |
-
removed.
|
30 |
-
"""
|
31 |
-
if not lines:
|
32 |
-
return lines
|
33 |
-
for i, line in enumerate(lines):
|
34 |
-
if line and not line.isspace():
|
35 |
-
return lines[i:]
|
36 |
-
return lines
|
37 |
-
|
38 |
-
def leading_indent(lines):
|
39 |
-
"""Remove leading indentation.
|
40 |
-
|
41 |
-
If the first line starts with a spaces or tabs, the same whitespace will be
|
42 |
-
removed from each following line in the cell.
|
43 |
-
"""
|
44 |
-
if not lines:
|
45 |
-
return lines
|
46 |
-
m = _indent_re.match(lines[0])
|
47 |
-
if not m:
|
48 |
-
return lines
|
49 |
-
space = m.group(0)
|
50 |
-
n = len(space)
|
51 |
-
return [l[n:] if l.startswith(space) else l
|
52 |
-
for l in lines]
|
53 |
-
|
54 |
-
class PromptStripper:
|
55 |
-
"""Remove matching input prompts from a block of input.
|
56 |
-
|
57 |
-
Parameters
|
58 |
-
----------
|
59 |
-
prompt_re : regular expression
|
60 |
-
A regular expression matching any input prompt (including continuation,
|
61 |
-
e.g. ``...``)
|
62 |
-
initial_re : regular expression, optional
|
63 |
-
A regular expression matching only the initial prompt, but not continuation.
|
64 |
-
If no initial expression is given, prompt_re will be used everywhere.
|
65 |
-
Used mainly for plain Python prompts (``>>>``), where the continuation prompt
|
66 |
-
``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
|
67 |
-
|
68 |
-
Notes
|
69 |
-
-----
|
70 |
-
|
71 |
-
If initial_re and prompt_re differ,
|
72 |
-
only initial_re will be tested against the first line.
|
73 |
-
If any prompt is found on the first two lines,
|
74 |
-
prompts will be stripped from the rest of the block.
|
75 |
-
"""
|
76 |
-
def __init__(self, prompt_re, initial_re=None):
|
77 |
-
self.prompt_re = prompt_re
|
78 |
-
self.initial_re = initial_re or prompt_re
|
79 |
-
|
80 |
-
def _strip(self, lines):
|
81 |
-
return [self.prompt_re.sub('', l, count=1) for l in lines]
|
82 |
-
|
83 |
-
def __call__(self, lines):
|
84 |
-
if not lines:
|
85 |
-
return lines
|
86 |
-
if self.initial_re.match(lines[0]) or \
|
87 |
-
(len(lines) > 1 and self.prompt_re.match(lines[1])):
|
88 |
-
return self._strip(lines)
|
89 |
-
return lines
|
90 |
-
|
91 |
-
classic_prompt = PromptStripper(
|
92 |
-
prompt_re=re.compile(r'^(>>>|\.\.\.)( |$)'),
|
93 |
-
initial_re=re.compile(r'^>>>( |$)')
|
94 |
-
)
|
95 |
-
|
96 |
-
ipython_prompt = PromptStripper(
|
97 |
-
re.compile(
|
98 |
-
r"""
|
99 |
-
^( # Match from the beginning of a line, either:
|
100 |
-
|
101 |
-
# 1. First-line prompt:
|
102 |
-
((\[nav\]|\[ins\])?\ )? # Vi editing mode prompt, if it's there
|
103 |
-
In\ # The 'In' of the prompt, with a space
|
104 |
-
\[\d+\]: # Command index, as displayed in the prompt
|
105 |
-
\ # With a mandatory trailing space
|
106 |
-
|
107 |
-
| # ... or ...
|
108 |
-
|
109 |
-
# 2. The three dots of the multiline prompt
|
110 |
-
\s* # All leading whitespace characters
|
111 |
-
\.{3,}: # The three (or more) dots
|
112 |
-
\ ? # With an optional trailing space
|
113 |
-
|
114 |
-
)
|
115 |
-
""",
|
116 |
-
re.VERBOSE,
|
117 |
-
)
|
118 |
-
)
|
119 |
-
|
120 |
-
|
121 |
-
def cell_magic(lines):
|
122 |
-
if not lines or not lines[0].startswith('%%'):
|
123 |
-
return lines
|
124 |
-
if re.match(r'%%\w+\?', lines[0]):
|
125 |
-
# This case will be handled by help_end
|
126 |
-
return lines
|
127 |
-
magic_name, _, first_line = lines[0][2:].rstrip().partition(' ')
|
128 |
-
body = ''.join(lines[1:])
|
129 |
-
return ['get_ipython().run_cell_magic(%r, %r, %r)\n'
|
130 |
-
% (magic_name, first_line, body)]
|
131 |
-
|
132 |
-
|
133 |
-
def _find_assign_op(token_line) -> Optional[int]:
|
134 |
-
"""Get the index of the first assignment in the line ('=' not inside brackets)
|
135 |
-
|
136 |
-
Note: We don't try to support multiple special assignment (a = b = %foo)
|
137 |
-
"""
|
138 |
-
paren_level = 0
|
139 |
-
for i, ti in enumerate(token_line):
|
140 |
-
s = ti.string
|
141 |
-
if s == '=' and paren_level == 0:
|
142 |
-
return i
|
143 |
-
if s in {'(','[','{'}:
|
144 |
-
paren_level += 1
|
145 |
-
elif s in {')', ']', '}'}:
|
146 |
-
if paren_level > 0:
|
147 |
-
paren_level -= 1
|
148 |
-
return None
|
149 |
-
|
150 |
-
def find_end_of_continued_line(lines, start_line: int):
|
151 |
-
"""Find the last line of a line explicitly extended using backslashes.
|
152 |
-
|
153 |
-
Uses 0-indexed line numbers.
|
154 |
-
"""
|
155 |
-
end_line = start_line
|
156 |
-
while lines[end_line].endswith('\\\n'):
|
157 |
-
end_line += 1
|
158 |
-
if end_line >= len(lines):
|
159 |
-
break
|
160 |
-
return end_line
|
161 |
-
|
162 |
-
def assemble_continued_line(lines, start: Tuple[int, int], end_line: int):
|
163 |
-
r"""Assemble a single line from multiple continued line pieces
|
164 |
-
|
165 |
-
Continued lines are lines ending in ``\``, and the line following the last
|
166 |
-
``\`` in the block.
|
167 |
-
|
168 |
-
For example, this code continues over multiple lines::
|
169 |
-
|
170 |
-
if (assign_ix is not None) \
|
171 |
-
and (len(line) >= assign_ix + 2) \
|
172 |
-
and (line[assign_ix+1].string == '%') \
|
173 |
-
and (line[assign_ix+2].type == tokenize.NAME):
|
174 |
-
|
175 |
-
This statement contains four continued line pieces.
|
176 |
-
Assembling these pieces into a single line would give::
|
177 |
-
|
178 |
-
if (assign_ix is not None) and (len(line) >= assign_ix + 2) and (line[...
|
179 |
-
|
180 |
-
This uses 0-indexed line numbers. *start* is (lineno, colno).
|
181 |
-
|
182 |
-
Used to allow ``%magic`` and ``!system`` commands to be continued over
|
183 |
-
multiple lines.
|
184 |
-
"""
|
185 |
-
parts = [lines[start[0]][start[1]:]] + lines[start[0]+1:end_line+1]
|
186 |
-
return ' '.join([p.rstrip()[:-1] for p in parts[:-1]] # Strip backslash+newline
|
187 |
-
+ [parts[-1].rstrip()]) # Strip newline from last line
|
188 |
-
|
189 |
-
class TokenTransformBase:
|
190 |
-
"""Base class for transformations which examine tokens.
|
191 |
-
|
192 |
-
Special syntax should not be transformed when it occurs inside strings or
|
193 |
-
comments. This is hard to reliably avoid with regexes. The solution is to
|
194 |
-
tokenise the code as Python, and recognise the special syntax in the tokens.
|
195 |
-
|
196 |
-
IPython's special syntax is not valid Python syntax, so tokenising may go
|
197 |
-
wrong after the special syntax starts. These classes therefore find and
|
198 |
-
transform *one* instance of special syntax at a time into regular Python
|
199 |
-
syntax. After each transformation, tokens are regenerated to find the next
|
200 |
-
piece of special syntax.
|
201 |
-
|
202 |
-
Subclasses need to implement one class method (find)
|
203 |
-
and one regular method (transform).
|
204 |
-
|
205 |
-
The priority attribute can select which transformation to apply if multiple
|
206 |
-
transformers match in the same place. Lower numbers have higher priority.
|
207 |
-
This allows "%magic?" to be turned into a help call rather than a magic call.
|
208 |
-
"""
|
209 |
-
# Lower numbers -> higher priority (for matches in the same location)
|
210 |
-
priority = 10
|
211 |
-
|
212 |
-
def sortby(self):
|
213 |
-
return self.start_line, self.start_col, self.priority
|
214 |
-
|
215 |
-
def __init__(self, start):
|
216 |
-
self.start_line = start[0] - 1 # Shift from 1-index to 0-index
|
217 |
-
self.start_col = start[1]
|
218 |
-
|
219 |
-
@classmethod
|
220 |
-
def find(cls, tokens_by_line):
|
221 |
-
"""Find one instance of special syntax in the provided tokens.
|
222 |
-
|
223 |
-
Tokens are grouped into logical lines for convenience,
|
224 |
-
so it is easy to e.g. look at the first token of each line.
|
225 |
-
*tokens_by_line* is a list of lists of tokenize.TokenInfo objects.
|
226 |
-
|
227 |
-
This should return an instance of its class, pointing to the start
|
228 |
-
position it has found, or None if it found no match.
|
229 |
-
"""
|
230 |
-
raise NotImplementedError
|
231 |
-
|
232 |
-
def transform(self, lines: List[str]):
|
233 |
-
"""Transform one instance of special syntax found by ``find()``
|
234 |
-
|
235 |
-
Takes a list of strings representing physical lines,
|
236 |
-
returns a similar list of transformed lines.
|
237 |
-
"""
|
238 |
-
raise NotImplementedError
|
239 |
-
|
240 |
-
class MagicAssign(TokenTransformBase):
|
241 |
-
"""Transformer for assignments from magics (a = %foo)"""
|
242 |
-
@classmethod
|
243 |
-
def find(cls, tokens_by_line):
|
244 |
-
"""Find the first magic assignment (a = %foo) in the cell.
|
245 |
-
"""
|
246 |
-
for line in tokens_by_line:
|
247 |
-
assign_ix = _find_assign_op(line)
|
248 |
-
if (assign_ix is not None) \
|
249 |
-
and (len(line) >= assign_ix + 2) \
|
250 |
-
and (line[assign_ix+1].string == '%') \
|
251 |
-
and (line[assign_ix+2].type == tokenize.NAME):
|
252 |
-
return cls(line[assign_ix+1].start)
|
253 |
-
|
254 |
-
def transform(self, lines: List[str]):
|
255 |
-
"""Transform a magic assignment found by the ``find()`` classmethod.
|
256 |
-
"""
|
257 |
-
start_line, start_col = self.start_line, self.start_col
|
258 |
-
lhs = lines[start_line][:start_col]
|
259 |
-
end_line = find_end_of_continued_line(lines, start_line)
|
260 |
-
rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
|
261 |
-
assert rhs.startswith('%'), rhs
|
262 |
-
magic_name, _, args = rhs[1:].partition(' ')
|
263 |
-
|
264 |
-
lines_before = lines[:start_line]
|
265 |
-
call = "get_ipython().run_line_magic({!r}, {!r})".format(magic_name, args)
|
266 |
-
new_line = lhs + call + '\n'
|
267 |
-
lines_after = lines[end_line+1:]
|
268 |
-
|
269 |
-
return lines_before + [new_line] + lines_after
|
270 |
-
|
271 |
-
|
272 |
-
class SystemAssign(TokenTransformBase):
|
273 |
-
"""Transformer for assignments from system commands (a = !foo)"""
|
274 |
-
@classmethod
|
275 |
-
def find_pre_312(cls, tokens_by_line):
|
276 |
-
for line in tokens_by_line:
|
277 |
-
assign_ix = _find_assign_op(line)
|
278 |
-
if (assign_ix is not None) \
|
279 |
-
and not line[assign_ix].line.strip().startswith('=') \
|
280 |
-
and (len(line) >= assign_ix + 2) \
|
281 |
-
and (line[assign_ix + 1].type == tokenize.ERRORTOKEN):
|
282 |
-
ix = assign_ix + 1
|
283 |
-
|
284 |
-
while ix < len(line) and line[ix].type == tokenize.ERRORTOKEN:
|
285 |
-
if line[ix].string == '!':
|
286 |
-
return cls(line[ix].start)
|
287 |
-
elif not line[ix].string.isspace():
|
288 |
-
break
|
289 |
-
ix += 1
|
290 |
-
|
291 |
-
@classmethod
|
292 |
-
def find_post_312(cls, tokens_by_line):
|
293 |
-
for line in tokens_by_line:
|
294 |
-
assign_ix = _find_assign_op(line)
|
295 |
-
if (
|
296 |
-
(assign_ix is not None)
|
297 |
-
and not line[assign_ix].line.strip().startswith("=")
|
298 |
-
and (len(line) >= assign_ix + 2)
|
299 |
-
and (line[assign_ix + 1].type == tokenize.OP)
|
300 |
-
and (line[assign_ix + 1].string == "!")
|
301 |
-
):
|
302 |
-
return cls(line[assign_ix + 1].start)
|
303 |
-
|
304 |
-
@classmethod
|
305 |
-
def find(cls, tokens_by_line):
|
306 |
-
"""Find the first system assignment (a = !foo) in the cell."""
|
307 |
-
if sys.version_info < (3, 12):
|
308 |
-
return cls.find_pre_312(tokens_by_line)
|
309 |
-
return cls.find_post_312(tokens_by_line)
|
310 |
-
|
311 |
-
def transform(self, lines: List[str]):
|
312 |
-
"""Transform a system assignment found by the ``find()`` classmethod.
|
313 |
-
"""
|
314 |
-
start_line, start_col = self.start_line, self.start_col
|
315 |
-
|
316 |
-
lhs = lines[start_line][:start_col]
|
317 |
-
end_line = find_end_of_continued_line(lines, start_line)
|
318 |
-
rhs = assemble_continued_line(lines, (start_line, start_col), end_line)
|
319 |
-
assert rhs.startswith('!'), rhs
|
320 |
-
cmd = rhs[1:]
|
321 |
-
|
322 |
-
lines_before = lines[:start_line]
|
323 |
-
call = "get_ipython().getoutput({!r})".format(cmd)
|
324 |
-
new_line = lhs + call + '\n'
|
325 |
-
lines_after = lines[end_line + 1:]
|
326 |
-
|
327 |
-
return lines_before + [new_line] + lines_after
|
328 |
-
|
329 |
-
# The escape sequences that define the syntax transformations IPython will
|
330 |
-
# apply to user input. These can NOT be just changed here: many regular
|
331 |
-
# expressions and other parts of the code may use their hardcoded values, and
|
332 |
-
# for all intents and purposes they constitute the 'IPython syntax', so they
|
333 |
-
# should be considered fixed.
|
334 |
-
|
335 |
-
ESC_SHELL = '!' # Send line to underlying system shell
|
336 |
-
ESC_SH_CAP = '!!' # Send line to system shell and capture output
|
337 |
-
ESC_HELP = '?' # Find information about object
|
338 |
-
ESC_HELP2 = '??' # Find extra-detailed information about object
|
339 |
-
ESC_MAGIC = '%' # Call magic function
|
340 |
-
ESC_MAGIC2 = '%%' # Call cell-magic function
|
341 |
-
ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
|
342 |
-
ESC_QUOTE2 = ';' # Quote all args as a single string, call
|
343 |
-
ESC_PAREN = '/' # Call first argument with rest of line as arguments
|
344 |
-
|
345 |
-
ESCAPE_SINGLES = {'!', '?', '%', ',', ';', '/'}
|
346 |
-
ESCAPE_DOUBLES = {'!!', '??'} # %% (cell magic) is handled separately
|
347 |
-
|
348 |
-
def _make_help_call(target, esc):
|
349 |
-
"""Prepares a pinfo(2)/psearch call from a target name and the escape
|
350 |
-
(i.e. ? or ??)"""
|
351 |
-
method = 'pinfo2' if esc == '??' \
|
352 |
-
else 'psearch' if '*' in target \
|
353 |
-
else 'pinfo'
|
354 |
-
arg = " ".join([method, target])
|
355 |
-
#Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
|
356 |
-
t_magic_name, _, t_magic_arg_s = arg.partition(' ')
|
357 |
-
t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
|
358 |
-
return "get_ipython().run_line_magic(%r, %r)" % (t_magic_name, t_magic_arg_s)
|
359 |
-
|
360 |
-
|
361 |
-
def _tr_help(content):
|
362 |
-
"""Translate lines escaped with: ?
|
363 |
-
|
364 |
-
A naked help line should fire the intro help screen (shell.show_usage())
|
365 |
-
"""
|
366 |
-
if not content:
|
367 |
-
return 'get_ipython().show_usage()'
|
368 |
-
|
369 |
-
return _make_help_call(content, '?')
|
370 |
-
|
371 |
-
def _tr_help2(content):
|
372 |
-
"""Translate lines escaped with: ??
|
373 |
-
|
374 |
-
A naked help line should fire the intro help screen (shell.show_usage())
|
375 |
-
"""
|
376 |
-
if not content:
|
377 |
-
return 'get_ipython().show_usage()'
|
378 |
-
|
379 |
-
return _make_help_call(content, '??')
|
380 |
-
|
381 |
-
def _tr_magic(content):
|
382 |
-
"Translate lines escaped with a percent sign: %"
|
383 |
-
name, _, args = content.partition(' ')
|
384 |
-
return 'get_ipython().run_line_magic(%r, %r)' % (name, args)
|
385 |
-
|
386 |
-
def _tr_quote(content):
|
387 |
-
"Translate lines escaped with a comma: ,"
|
388 |
-
name, _, args = content.partition(' ')
|
389 |
-
return '%s("%s")' % (name, '", "'.join(args.split()) )
|
390 |
-
|
391 |
-
def _tr_quote2(content):
|
392 |
-
"Translate lines escaped with a semicolon: ;"
|
393 |
-
name, _, args = content.partition(' ')
|
394 |
-
return '%s("%s")' % (name, args)
|
395 |
-
|
396 |
-
def _tr_paren(content):
|
397 |
-
"Translate lines escaped with a slash: /"
|
398 |
-
name, _, args = content.partition(" ")
|
399 |
-
if name == "":
|
400 |
-
raise SyntaxError(f'"{ESC_SHELL}" must be followed by a callable name')
|
401 |
-
|
402 |
-
return '%s(%s)' % (name, ", ".join(args.split()))
|
403 |
-
|
404 |
-
tr = { ESC_SHELL : 'get_ipython().system({!r})'.format,
|
405 |
-
ESC_SH_CAP : 'get_ipython().getoutput({!r})'.format,
|
406 |
-
ESC_HELP : _tr_help,
|
407 |
-
ESC_HELP2 : _tr_help2,
|
408 |
-
ESC_MAGIC : _tr_magic,
|
409 |
-
ESC_QUOTE : _tr_quote,
|
410 |
-
ESC_QUOTE2 : _tr_quote2,
|
411 |
-
ESC_PAREN : _tr_paren }
|
412 |
-
|
413 |
-
class EscapedCommand(TokenTransformBase):
|
414 |
-
"""Transformer for escaped commands like %foo, !foo, or /foo"""
|
415 |
-
@classmethod
|
416 |
-
def find(cls, tokens_by_line):
|
417 |
-
"""Find the first escaped command (%foo, !foo, etc.) in the cell.
|
418 |
-
"""
|
419 |
-
for line in tokens_by_line:
|
420 |
-
if not line:
|
421 |
-
continue
|
422 |
-
ix = 0
|
423 |
-
ll = len(line)
|
424 |
-
while ll > ix and line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
|
425 |
-
ix += 1
|
426 |
-
if ix >= ll:
|
427 |
-
continue
|
428 |
-
if line[ix].string in ESCAPE_SINGLES:
|
429 |
-
return cls(line[ix].start)
|
430 |
-
|
431 |
-
def transform(self, lines):
|
432 |
-
"""Transform an escaped line found by the ``find()`` classmethod.
|
433 |
-
"""
|
434 |
-
start_line, start_col = self.start_line, self.start_col
|
435 |
-
|
436 |
-
indent = lines[start_line][:start_col]
|
437 |
-
end_line = find_end_of_continued_line(lines, start_line)
|
438 |
-
line = assemble_continued_line(lines, (start_line, start_col), end_line)
|
439 |
-
|
440 |
-
if len(line) > 1 and line[:2] in ESCAPE_DOUBLES:
|
441 |
-
escape, content = line[:2], line[2:]
|
442 |
-
else:
|
443 |
-
escape, content = line[:1], line[1:]
|
444 |
-
|
445 |
-
if escape in tr:
|
446 |
-
call = tr[escape](content)
|
447 |
-
else:
|
448 |
-
call = ''
|
449 |
-
|
450 |
-
lines_before = lines[:start_line]
|
451 |
-
new_line = indent + call + '\n'
|
452 |
-
lines_after = lines[end_line + 1:]
|
453 |
-
|
454 |
-
return lines_before + [new_line] + lines_after
|
455 |
-
|
456 |
-
|
457 |
-
_help_end_re = re.compile(
|
458 |
-
r"""(%{0,2}
|
459 |
-
(?!\d)[\w*]+ # Variable name
|
460 |
-
(\.(?!\d)[\w*]+|\[-?[0-9]+\])* # .etc.etc or [0], we only support literal integers.
|
461 |
-
)
|
462 |
-
(\?\??)$ # ? or ??
|
463 |
-
""",
|
464 |
-
re.VERBOSE,
|
465 |
-
)
|
466 |
-
|
467 |
-
|
468 |
-
class HelpEnd(TokenTransformBase):
|
469 |
-
"""Transformer for help syntax: obj? and obj??"""
|
470 |
-
# This needs to be higher priority (lower number) than EscapedCommand so
|
471 |
-
# that inspecting magics (%foo?) works.
|
472 |
-
priority = 5
|
473 |
-
|
474 |
-
def __init__(self, start, q_locn):
|
475 |
-
super().__init__(start)
|
476 |
-
self.q_line = q_locn[0] - 1 # Shift from 1-indexed to 0-indexed
|
477 |
-
self.q_col = q_locn[1]
|
478 |
-
|
479 |
-
@classmethod
|
480 |
-
def find(cls, tokens_by_line):
|
481 |
-
"""Find the first help command (foo?) in the cell.
|
482 |
-
"""
|
483 |
-
for line in tokens_by_line:
|
484 |
-
# Last token is NEWLINE; look at last but one
|
485 |
-
if len(line) > 2 and line[-2].string == '?':
|
486 |
-
# Find the first token that's not INDENT/DEDENT
|
487 |
-
ix = 0
|
488 |
-
while line[ix].type in {tokenize.INDENT, tokenize.DEDENT}:
|
489 |
-
ix += 1
|
490 |
-
return cls(line[ix].start, line[-2].start)
|
491 |
-
|
492 |
-
def transform(self, lines):
|
493 |
-
"""Transform a help command found by the ``find()`` classmethod.
|
494 |
-
"""
|
495 |
-
|
496 |
-
piece = "".join(lines[self.start_line : self.q_line + 1])
|
497 |
-
indent, content = piece[: self.start_col], piece[self.start_col :]
|
498 |
-
lines_before = lines[: self.start_line]
|
499 |
-
lines_after = lines[self.q_line + 1 :]
|
500 |
-
|
501 |
-
m = _help_end_re.search(content)
|
502 |
-
if not m:
|
503 |
-
raise SyntaxError(content)
|
504 |
-
assert m is not None, content
|
505 |
-
target = m.group(1)
|
506 |
-
esc = m.group(3)
|
507 |
-
|
508 |
-
|
509 |
-
call = _make_help_call(target, esc)
|
510 |
-
new_line = indent + call + '\n'
|
511 |
-
|
512 |
-
return lines_before + [new_line] + lines_after
|
513 |
-
|
514 |
-
def make_tokens_by_line(lines:List[str]):
|
515 |
-
"""Tokenize a series of lines and group tokens by line.
|
516 |
-
|
517 |
-
The tokens for a multiline Python string or expression are grouped as one
|
518 |
-
line. All lines except the last lines should keep their line ending ('\\n',
|
519 |
-
'\\r\\n') for this to properly work. Use `.splitlines(keeplineending=True)`
|
520 |
-
for example when passing block of text to this function.
|
521 |
-
|
522 |
-
"""
|
523 |
-
# NL tokens are used inside multiline expressions, but also after blank
|
524 |
-
# lines or comments. This is intentional - see https://bugs.python.org/issue17061
|
525 |
-
# We want to group the former case together but split the latter, so we
|
526 |
-
# track parentheses level, similar to the internals of tokenize.
|
527 |
-
|
528 |
-
# reexported from token on 3.7+
|
529 |
-
NEWLINE, NL = tokenize.NEWLINE, tokenize.NL # type: ignore
|
530 |
-
tokens_by_line: List[List[Any]] = [[]]
|
531 |
-
if len(lines) > 1 and not lines[0].endswith(("\n", "\r", "\r\n", "\x0b", "\x0c")):
|
532 |
-
warnings.warn(
|
533 |
-
"`make_tokens_by_line` received a list of lines which do not have lineending markers ('\\n', '\\r', '\\r\\n', '\\x0b', '\\x0c'), behavior will be unspecified",
|
534 |
-
stacklevel=2,
|
535 |
-
)
|
536 |
-
parenlev = 0
|
537 |
-
try:
|
538 |
-
for token in tokenutil.generate_tokens_catch_errors(
|
539 |
-
iter(lines).__next__, extra_errors_to_catch=["expected EOF"]
|
540 |
-
):
|
541 |
-
tokens_by_line[-1].append(token)
|
542 |
-
if (token.type == NEWLINE) \
|
543 |
-
or ((token.type == NL) and (parenlev <= 0)):
|
544 |
-
tokens_by_line.append([])
|
545 |
-
elif token.string in {'(', '[', '{'}:
|
546 |
-
parenlev += 1
|
547 |
-
elif token.string in {')', ']', '}'}:
|
548 |
-
if parenlev > 0:
|
549 |
-
parenlev -= 1
|
550 |
-
except tokenize.TokenError:
|
551 |
-
# Input ended in a multiline string or expression. That's OK for us.
|
552 |
-
pass
|
553 |
-
|
554 |
-
|
555 |
-
if not tokens_by_line[-1]:
|
556 |
-
tokens_by_line.pop()
|
557 |
-
|
558 |
-
|
559 |
-
return tokens_by_line
|
560 |
-
|
561 |
-
|
562 |
-
def has_sunken_brackets(tokens: List[tokenize.TokenInfo]):
|
563 |
-
"""Check if the depth of brackets in the list of tokens drops below 0"""
|
564 |
-
parenlev = 0
|
565 |
-
for token in tokens:
|
566 |
-
if token.string in {"(", "[", "{"}:
|
567 |
-
parenlev += 1
|
568 |
-
elif token.string in {")", "]", "}"}:
|
569 |
-
parenlev -= 1
|
570 |
-
if parenlev < 0:
|
571 |
-
return True
|
572 |
-
return False
|
573 |
-
|
574 |
-
|
575 |
-
def show_linewise_tokens(s: str):
|
576 |
-
"""For investigation and debugging"""
|
577 |
-
warnings.warn(
|
578 |
-
"show_linewise_tokens is deprecated since IPython 8.6",
|
579 |
-
DeprecationWarning,
|
580 |
-
stacklevel=2,
|
581 |
-
)
|
582 |
-
if not s.endswith("\n"):
|
583 |
-
s += "\n"
|
584 |
-
lines = s.splitlines(keepends=True)
|
585 |
-
for line in make_tokens_by_line(lines):
|
586 |
-
print("Line -------")
|
587 |
-
for tokinfo in line:
|
588 |
-
print(" ", tokinfo)
|
589 |
-
|
590 |
-
# Arbitrary limit to prevent getting stuck in infinite loops
|
591 |
-
TRANSFORM_LOOP_LIMIT = 500
|
592 |
-
|
593 |
-
class TransformerManager:
|
594 |
-
"""Applies various transformations to a cell or code block.
|
595 |
-
|
596 |
-
The key methods for external use are ``transform_cell()``
|
597 |
-
and ``check_complete()``.
|
598 |
-
"""
|
599 |
-
def __init__(self):
|
600 |
-
self.cleanup_transforms = [
|
601 |
-
leading_empty_lines,
|
602 |
-
leading_indent,
|
603 |
-
classic_prompt,
|
604 |
-
ipython_prompt,
|
605 |
-
]
|
606 |
-
self.line_transforms = [
|
607 |
-
cell_magic,
|
608 |
-
]
|
609 |
-
self.token_transformers = [
|
610 |
-
MagicAssign,
|
611 |
-
SystemAssign,
|
612 |
-
EscapedCommand,
|
613 |
-
HelpEnd,
|
614 |
-
]
|
615 |
-
|
616 |
-
def do_one_token_transform(self, lines):
|
617 |
-
"""Find and run the transform earliest in the code.
|
618 |
-
|
619 |
-
Returns (changed, lines).
|
620 |
-
|
621 |
-
This method is called repeatedly until changed is False, indicating
|
622 |
-
that all available transformations are complete.
|
623 |
-
|
624 |
-
The tokens following IPython special syntax might not be valid, so
|
625 |
-
the transformed code is retokenised every time to identify the next
|
626 |
-
piece of special syntax. Hopefully long code cells are mostly valid
|
627 |
-
Python, not using lots of IPython special syntax, so this shouldn't be
|
628 |
-
a performance issue.
|
629 |
-
"""
|
630 |
-
tokens_by_line = make_tokens_by_line(lines)
|
631 |
-
candidates = []
|
632 |
-
for transformer_cls in self.token_transformers:
|
633 |
-
transformer = transformer_cls.find(tokens_by_line)
|
634 |
-
if transformer:
|
635 |
-
candidates.append(transformer)
|
636 |
-
|
637 |
-
if not candidates:
|
638 |
-
# Nothing to transform
|
639 |
-
return False, lines
|
640 |
-
ordered_transformers = sorted(candidates, key=TokenTransformBase.sortby)
|
641 |
-
for transformer in ordered_transformers:
|
642 |
-
try:
|
643 |
-
return True, transformer.transform(lines)
|
644 |
-
except SyntaxError:
|
645 |
-
pass
|
646 |
-
return False, lines
|
647 |
-
|
648 |
-
def do_token_transforms(self, lines):
|
649 |
-
for _ in range(TRANSFORM_LOOP_LIMIT):
|
650 |
-
changed, lines = self.do_one_token_transform(lines)
|
651 |
-
if not changed:
|
652 |
-
return lines
|
653 |
-
|
654 |
-
raise RuntimeError("Input transformation still changing after "
|
655 |
-
"%d iterations. Aborting." % TRANSFORM_LOOP_LIMIT)
|
656 |
-
|
657 |
-
def transform_cell(self, cell: str) -> str:
|
658 |
-
"""Transforms a cell of input code"""
|
659 |
-
if not cell.endswith('\n'):
|
660 |
-
cell += '\n' # Ensure the cell has a trailing newline
|
661 |
-
lines = cell.splitlines(keepends=True)
|
662 |
-
for transform in self.cleanup_transforms + self.line_transforms:
|
663 |
-
lines = transform(lines)
|
664 |
-
|
665 |
-
lines = self.do_token_transforms(lines)
|
666 |
-
return ''.join(lines)
|
667 |
-
|
668 |
-
def check_complete(self, cell: str):
|
669 |
-
"""Return whether a block of code is ready to execute, or should be continued
|
670 |
-
|
671 |
-
Parameters
|
672 |
-
----------
|
673 |
-
cell : string
|
674 |
-
Python input code, which can be multiline.
|
675 |
-
|
676 |
-
Returns
|
677 |
-
-------
|
678 |
-
status : str
|
679 |
-
One of 'complete', 'incomplete', or 'invalid' if source is not a
|
680 |
-
prefix of valid code.
|
681 |
-
indent_spaces : int or None
|
682 |
-
The number of spaces by which to indent the next line of code. If
|
683 |
-
status is not 'incomplete', this is None.
|
684 |
-
"""
|
685 |
-
# Remember if the lines ends in a new line.
|
686 |
-
ends_with_newline = False
|
687 |
-
for character in reversed(cell):
|
688 |
-
if character == '\n':
|
689 |
-
ends_with_newline = True
|
690 |
-
break
|
691 |
-
elif character.strip():
|
692 |
-
break
|
693 |
-
else:
|
694 |
-
continue
|
695 |
-
|
696 |
-
if not ends_with_newline:
|
697 |
-
# Append an newline for consistent tokenization
|
698 |
-
# See https://bugs.python.org/issue33899
|
699 |
-
cell += '\n'
|
700 |
-
|
701 |
-
lines = cell.splitlines(keepends=True)
|
702 |
-
|
703 |
-
if not lines:
|
704 |
-
return 'complete', None
|
705 |
-
|
706 |
-
for line in reversed(lines):
|
707 |
-
if not line.strip():
|
708 |
-
continue
|
709 |
-
elif line.strip("\n").endswith("\\"):
|
710 |
-
return "incomplete", find_last_indent(lines)
|
711 |
-
else:
|
712 |
-
break
|
713 |
-
|
714 |
-
try:
|
715 |
-
for transform in self.cleanup_transforms:
|
716 |
-
if not getattr(transform, 'has_side_effects', False):
|
717 |
-
lines = transform(lines)
|
718 |
-
except SyntaxError:
|
719 |
-
return 'invalid', None
|
720 |
-
|
721 |
-
if lines[0].startswith('%%'):
|
722 |
-
# Special case for cell magics - completion marked by blank line
|
723 |
-
if lines[-1].strip():
|
724 |
-
return 'incomplete', find_last_indent(lines)
|
725 |
-
else:
|
726 |
-
return 'complete', None
|
727 |
-
|
728 |
-
try:
|
729 |
-
for transform in self.line_transforms:
|
730 |
-
if not getattr(transform, 'has_side_effects', False):
|
731 |
-
lines = transform(lines)
|
732 |
-
lines = self.do_token_transforms(lines)
|
733 |
-
except SyntaxError:
|
734 |
-
return 'invalid', None
|
735 |
-
|
736 |
-
tokens_by_line = make_tokens_by_line(lines)
|
737 |
-
|
738 |
-
# Bail if we got one line and there are more closing parentheses than
|
739 |
-
# the opening ones
|
740 |
-
if (
|
741 |
-
len(lines) == 1
|
742 |
-
and tokens_by_line
|
743 |
-
and has_sunken_brackets(tokens_by_line[0])
|
744 |
-
):
|
745 |
-
return "invalid", None
|
746 |
-
|
747 |
-
if not tokens_by_line:
|
748 |
-
return 'incomplete', find_last_indent(lines)
|
749 |
-
|
750 |
-
if (
|
751 |
-
tokens_by_line[-1][-1].type != tokenize.ENDMARKER
|
752 |
-
and tokens_by_line[-1][-1].type != tokenize.ERRORTOKEN
|
753 |
-
):
|
754 |
-
# We're in a multiline string or expression
|
755 |
-
return 'incomplete', find_last_indent(lines)
|
756 |
-
|
757 |
-
newline_types = {tokenize.NEWLINE, tokenize.COMMENT, tokenize.ENDMARKER} # type: ignore
|
758 |
-
|
759 |
-
# Pop the last line which only contains DEDENTs and ENDMARKER
|
760 |
-
last_token_line = None
|
761 |
-
if {t.type for t in tokens_by_line[-1]} in [
|
762 |
-
{tokenize.DEDENT, tokenize.ENDMARKER},
|
763 |
-
{tokenize.ENDMARKER}
|
764 |
-
] and len(tokens_by_line) > 1:
|
765 |
-
last_token_line = tokens_by_line.pop()
|
766 |
-
|
767 |
-
while tokens_by_line[-1] and tokens_by_line[-1][-1].type in newline_types:
|
768 |
-
tokens_by_line[-1].pop()
|
769 |
-
|
770 |
-
if not tokens_by_line[-1]:
|
771 |
-
return 'incomplete', find_last_indent(lines)
|
772 |
-
|
773 |
-
if tokens_by_line[-1][-1].string == ':':
|
774 |
-
# The last line starts a block (e.g. 'if foo:')
|
775 |
-
ix = 0
|
776 |
-
while tokens_by_line[-1][ix].type in {tokenize.INDENT, tokenize.DEDENT}:
|
777 |
-
ix += 1
|
778 |
-
|
779 |
-
indent = tokens_by_line[-1][ix].start[1]
|
780 |
-
return 'incomplete', indent + 4
|
781 |
-
|
782 |
-
if tokens_by_line[-1][0].line.endswith('\\'):
|
783 |
-
return 'incomplete', None
|
784 |
-
|
785 |
-
# At this point, our checks think the code is complete (or invalid).
|
786 |
-
# We'll use codeop.compile_command to check this with the real parser
|
787 |
-
try:
|
788 |
-
with warnings.catch_warnings():
|
789 |
-
warnings.simplefilter('error', SyntaxWarning)
|
790 |
-
res = compile_command(''.join(lines), symbol='exec')
|
791 |
-
except (SyntaxError, OverflowError, ValueError, TypeError,
|
792 |
-
MemoryError, SyntaxWarning):
|
793 |
-
return 'invalid', None
|
794 |
-
else:
|
795 |
-
if res is None:
|
796 |
-
return 'incomplete', find_last_indent(lines)
|
797 |
-
|
798 |
-
if last_token_line and last_token_line[0].type == tokenize.DEDENT:
|
799 |
-
if ends_with_newline:
|
800 |
-
return 'complete', None
|
801 |
-
return 'incomplete', find_last_indent(lines)
|
802 |
-
|
803 |
-
# If there's a blank line at the end, assume we're ready to execute
|
804 |
-
if not lines[-1].strip():
|
805 |
-
return 'complete', None
|
806 |
-
|
807 |
-
return 'complete', None
|
808 |
-
|
809 |
-
|
810 |
-
def find_last_indent(lines):
|
811 |
-
m = _indent_re.match(lines[-1])
|
812 |
-
if not m:
|
813 |
-
return 0
|
814 |
-
return len(m.group(0).replace('\t', ' '*4))
|
815 |
-
|
816 |
-
|
817 |
-
class MaybeAsyncCompile(Compile):
|
818 |
-
def __init__(self, extra_flags=0):
|
819 |
-
super().__init__()
|
820 |
-
self.flags |= extra_flags
|
821 |
-
|
822 |
-
|
823 |
-
class MaybeAsyncCommandCompiler(CommandCompiler):
|
824 |
-
def __init__(self, extra_flags=0):
|
825 |
-
self.compiler = MaybeAsyncCompile(extra_flags=extra_flags)
|
826 |
-
|
827 |
-
|
828 |
-
_extra_flags = ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
|
829 |
-
|
830 |
-
compile_command = MaybeAsyncCommandCompiler(extra_flags=_extra_flags)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/interactiveshell.py
DELETED
The diff for this file is too large to render.
See raw diff
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/latex_symbols.py
DELETED
@@ -1,1301 +0,0 @@
|
|
1 |
-
# encoding: utf-8
|
2 |
-
|
3 |
-
# DO NOT EDIT THIS FILE BY HAND.
|
4 |
-
|
5 |
-
# To update this file, run the script /tools/gen_latex_symbols.py using Python 3
|
6 |
-
|
7 |
-
# This file is autogenerated from the file:
|
8 |
-
# https://raw.githubusercontent.com/JuliaLang/julia/master/base/latex_symbols.jl
|
9 |
-
# This original list is filtered to remove any unicode characters that are not valid
|
10 |
-
# Python identifiers.
|
11 |
-
|
12 |
-
latex_symbols = {
|
13 |
-
|
14 |
-
"\\euler" : "ℯ",
|
15 |
-
"\\^a" : "ᵃ",
|
16 |
-
"\\^b" : "ᵇ",
|
17 |
-
"\\^c" : "ᶜ",
|
18 |
-
"\\^d" : "ᵈ",
|
19 |
-
"\\^e" : "ᵉ",
|
20 |
-
"\\^f" : "ᶠ",
|
21 |
-
"\\^g" : "ᵍ",
|
22 |
-
"\\^h" : "ʰ",
|
23 |
-
"\\^i" : "ⁱ",
|
24 |
-
"\\^j" : "ʲ",
|
25 |
-
"\\^k" : "ᵏ",
|
26 |
-
"\\^l" : "ˡ",
|
27 |
-
"\\^m" : "ᵐ",
|
28 |
-
"\\^n" : "ⁿ",
|
29 |
-
"\\^o" : "ᵒ",
|
30 |
-
"\\^p" : "ᵖ",
|
31 |
-
"\\^r" : "ʳ",
|
32 |
-
"\\^s" : "ˢ",
|
33 |
-
"\\^t" : "ᵗ",
|
34 |
-
"\\^u" : "ᵘ",
|
35 |
-
"\\^v" : "ᵛ",
|
36 |
-
"\\^w" : "ʷ",
|
37 |
-
"\\^x" : "ˣ",
|
38 |
-
"\\^y" : "ʸ",
|
39 |
-
"\\^z" : "ᶻ",
|
40 |
-
"\\^A" : "ᴬ",
|
41 |
-
"\\^B" : "ᴮ",
|
42 |
-
"\\^D" : "ᴰ",
|
43 |
-
"\\^E" : "ᴱ",
|
44 |
-
"\\^G" : "ᴳ",
|
45 |
-
"\\^H" : "ᴴ",
|
46 |
-
"\\^I" : "ᴵ",
|
47 |
-
"\\^J" : "ᴶ",
|
48 |
-
"\\^K" : "ᴷ",
|
49 |
-
"\\^L" : "ᴸ",
|
50 |
-
"\\^M" : "ᴹ",
|
51 |
-
"\\^N" : "ᴺ",
|
52 |
-
"\\^O" : "ᴼ",
|
53 |
-
"\\^P" : "ᴾ",
|
54 |
-
"\\^R" : "ᴿ",
|
55 |
-
"\\^T" : "ᵀ",
|
56 |
-
"\\^U" : "ᵁ",
|
57 |
-
"\\^V" : "ⱽ",
|
58 |
-
"\\^W" : "ᵂ",
|
59 |
-
"\\^alpha" : "ᵅ",
|
60 |
-
"\\^beta" : "ᵝ",
|
61 |
-
"\\^gamma" : "ᵞ",
|
62 |
-
"\\^delta" : "ᵟ",
|
63 |
-
"\\^epsilon" : "ᵋ",
|
64 |
-
"\\^theta" : "ᶿ",
|
65 |
-
"\\^iota" : "ᶥ",
|
66 |
-
"\\^phi" : "ᵠ",
|
67 |
-
"\\^chi" : "ᵡ",
|
68 |
-
"\\^Phi" : "ᶲ",
|
69 |
-
"\\_a" : "ₐ",
|
70 |
-
"\\_e" : "ₑ",
|
71 |
-
"\\_h" : "ₕ",
|
72 |
-
"\\_i" : "ᵢ",
|
73 |
-
"\\_j" : "ⱼ",
|
74 |
-
"\\_k" : "ₖ",
|
75 |
-
"\\_l" : "ₗ",
|
76 |
-
"\\_m" : "ₘ",
|
77 |
-
"\\_n" : "ₙ",
|
78 |
-
"\\_o" : "ₒ",
|
79 |
-
"\\_p" : "ₚ",
|
80 |
-
"\\_r" : "ᵣ",
|
81 |
-
"\\_s" : "ₛ",
|
82 |
-
"\\_t" : "ₜ",
|
83 |
-
"\\_u" : "ᵤ",
|
84 |
-
"\\_v" : "ᵥ",
|
85 |
-
"\\_x" : "ₓ",
|
86 |
-
"\\_schwa" : "ₔ",
|
87 |
-
"\\_beta" : "ᵦ",
|
88 |
-
"\\_gamma" : "ᵧ",
|
89 |
-
"\\_rho" : "ᵨ",
|
90 |
-
"\\_phi" : "ᵩ",
|
91 |
-
"\\_chi" : "ᵪ",
|
92 |
-
"\\hbar" : "ħ",
|
93 |
-
"\\sout" : "̶",
|
94 |
-
"\\ordfeminine" : "ª",
|
95 |
-
"\\cdotp" : "·",
|
96 |
-
"\\ordmasculine" : "º",
|
97 |
-
"\\AA" : "Å",
|
98 |
-
"\\AE" : "Æ",
|
99 |
-
"\\DH" : "Ð",
|
100 |
-
"\\O" : "Ø",
|
101 |
-
"\\TH" : "Þ",
|
102 |
-
"\\ss" : "ß",
|
103 |
-
"\\aa" : "å",
|
104 |
-
"\\ae" : "æ",
|
105 |
-
"\\eth" : "ð",
|
106 |
-
"\\dh" : "ð",
|
107 |
-
"\\o" : "ø",
|
108 |
-
"\\th" : "þ",
|
109 |
-
"\\DJ" : "Đ",
|
110 |
-
"\\dj" : "đ",
|
111 |
-
"\\imath" : "ı",
|
112 |
-
"\\jmath" : "ȷ",
|
113 |
-
"\\L" : "Ł",
|
114 |
-
"\\l" : "ł",
|
115 |
-
"\\NG" : "Ŋ",
|
116 |
-
"\\ng" : "ŋ",
|
117 |
-
"\\OE" : "Œ",
|
118 |
-
"\\oe" : "œ",
|
119 |
-
"\\hvlig" : "ƕ",
|
120 |
-
"\\nrleg" : "ƞ",
|
121 |
-
"\\doublepipe" : "ǂ",
|
122 |
-
"\\trna" : "ɐ",
|
123 |
-
"\\trnsa" : "ɒ",
|
124 |
-
"\\openo" : "ɔ",
|
125 |
-
"\\rtld" : "ɖ",
|
126 |
-
"\\schwa" : "ə",
|
127 |
-
"\\varepsilon" : "ε",
|
128 |
-
"\\pgamma" : "ɣ",
|
129 |
-
"\\pbgam" : "ɤ",
|
130 |
-
"\\trnh" : "ɥ",
|
131 |
-
"\\btdl" : "ɬ",
|
132 |
-
"\\rtll" : "ɭ",
|
133 |
-
"\\trnm" : "ɯ",
|
134 |
-
"\\trnmlr" : "ɰ",
|
135 |
-
"\\ltlmr" : "ɱ",
|
136 |
-
"\\ltln" : "ɲ",
|
137 |
-
"\\rtln" : "ɳ",
|
138 |
-
"\\clomeg" : "ɷ",
|
139 |
-
"\\ltphi" : "ɸ",
|
140 |
-
"\\trnr" : "ɹ",
|
141 |
-
"\\trnrl" : "ɺ",
|
142 |
-
"\\rttrnr" : "ɻ",
|
143 |
-
"\\rl" : "ɼ",
|
144 |
-
"\\rtlr" : "ɽ",
|
145 |
-
"\\fhr" : "ɾ",
|
146 |
-
"\\rtls" : "ʂ",
|
147 |
-
"\\esh" : "ʃ",
|
148 |
-
"\\trnt" : "ʇ",
|
149 |
-
"\\rtlt" : "ʈ",
|
150 |
-
"\\pupsil" : "ʊ",
|
151 |
-
"\\pscrv" : "ʋ",
|
152 |
-
"\\invv" : "ʌ",
|
153 |
-
"\\invw" : "ʍ",
|
154 |
-
"\\trny" : "ʎ",
|
155 |
-
"\\rtlz" : "ʐ",
|
156 |
-
"\\yogh" : "ʒ",
|
157 |
-
"\\glst" : "ʔ",
|
158 |
-
"\\reglst" : "ʕ",
|
159 |
-
"\\inglst" : "ʖ",
|
160 |
-
"\\turnk" : "ʞ",
|
161 |
-
"\\dyogh" : "ʤ",
|
162 |
-
"\\tesh" : "ʧ",
|
163 |
-
"\\rasp" : "ʼ",
|
164 |
-
"\\verts" : "ˈ",
|
165 |
-
"\\verti" : "ˌ",
|
166 |
-
"\\lmrk" : "ː",
|
167 |
-
"\\hlmrk" : "ˑ",
|
168 |
-
"\\grave" : "̀",
|
169 |
-
"\\acute" : "́",
|
170 |
-
"\\hat" : "̂",
|
171 |
-
"\\tilde" : "̃",
|
172 |
-
"\\bar" : "̄",
|
173 |
-
"\\breve" : "̆",
|
174 |
-
"\\dot" : "̇",
|
175 |
-
"\\ddot" : "̈",
|
176 |
-
"\\ocirc" : "̊",
|
177 |
-
"\\H" : "̋",
|
178 |
-
"\\check" : "̌",
|
179 |
-
"\\palh" : "̡",
|
180 |
-
"\\rh" : "̢",
|
181 |
-
"\\c" : "̧",
|
182 |
-
"\\k" : "̨",
|
183 |
-
"\\sbbrg" : "̪",
|
184 |
-
"\\strike" : "̶",
|
185 |
-
"\\Alpha" : "Α",
|
186 |
-
"\\Beta" : "Β",
|
187 |
-
"\\Gamma" : "Γ",
|
188 |
-
"\\Delta" : "Δ",
|
189 |
-
"\\Epsilon" : "Ε",
|
190 |
-
"\\Zeta" : "Ζ",
|
191 |
-
"\\Eta" : "Η",
|
192 |
-
"\\Theta" : "Θ",
|
193 |
-
"\\Iota" : "Ι",
|
194 |
-
"\\Kappa" : "Κ",
|
195 |
-
"\\Lambda" : "Λ",
|
196 |
-
"\\Xi" : "Ξ",
|
197 |
-
"\\Pi" : "Π",
|
198 |
-
"\\Rho" : "Ρ",
|
199 |
-
"\\Sigma" : "Σ",
|
200 |
-
"\\Tau" : "Τ",
|
201 |
-
"\\Upsilon" : "Υ",
|
202 |
-
"\\Phi" : "Φ",
|
203 |
-
"\\Chi" : "Χ",
|
204 |
-
"\\Psi" : "Ψ",
|
205 |
-
"\\Omega" : "Ω",
|
206 |
-
"\\alpha" : "α",
|
207 |
-
"\\beta" : "β",
|
208 |
-
"\\gamma" : "γ",
|
209 |
-
"\\delta" : "δ",
|
210 |
-
"\\zeta" : "ζ",
|
211 |
-
"\\eta" : "η",
|
212 |
-
"\\theta" : "θ",
|
213 |
-
"\\iota" : "ι",
|
214 |
-
"\\kappa" : "κ",
|
215 |
-
"\\lambda" : "λ",
|
216 |
-
"\\mu" : "μ",
|
217 |
-
"\\nu" : "ν",
|
218 |
-
"\\xi" : "ξ",
|
219 |
-
"\\pi" : "π",
|
220 |
-
"\\rho" : "ρ",
|
221 |
-
"\\varsigma" : "ς",
|
222 |
-
"\\sigma" : "σ",
|
223 |
-
"\\tau" : "τ",
|
224 |
-
"\\upsilon" : "υ",
|
225 |
-
"\\varphi" : "φ",
|
226 |
-
"\\chi" : "χ",
|
227 |
-
"\\psi" : "ψ",
|
228 |
-
"\\omega" : "ω",
|
229 |
-
"\\vartheta" : "ϑ",
|
230 |
-
"\\phi" : "ϕ",
|
231 |
-
"\\varpi" : "ϖ",
|
232 |
-
"\\Stigma" : "Ϛ",
|
233 |
-
"\\Digamma" : "Ϝ",
|
234 |
-
"\\digamma" : "ϝ",
|
235 |
-
"\\Koppa" : "Ϟ",
|
236 |
-
"\\Sampi" : "Ϡ",
|
237 |
-
"\\varkappa" : "ϰ",
|
238 |
-
"\\varrho" : "ϱ",
|
239 |
-
"\\varTheta" : "ϴ",
|
240 |
-
"\\epsilon" : "ϵ",
|
241 |
-
"\\dddot" : "⃛",
|
242 |
-
"\\ddddot" : "⃜",
|
243 |
-
"\\hslash" : "ℏ",
|
244 |
-
"\\Im" : "ℑ",
|
245 |
-
"\\ell" : "ℓ",
|
246 |
-
"\\wp" : "℘",
|
247 |
-
"\\Re" : "ℜ",
|
248 |
-
"\\aleph" : "ℵ",
|
249 |
-
"\\beth" : "ℶ",
|
250 |
-
"\\gimel" : "ℷ",
|
251 |
-
"\\daleth" : "ℸ",
|
252 |
-
"\\bbPi" : "ℿ",
|
253 |
-
"\\Zbar" : "Ƶ",
|
254 |
-
"\\overbar" : "̅",
|
255 |
-
"\\ovhook" : "̉",
|
256 |
-
"\\candra" : "̐",
|
257 |
-
"\\oturnedcomma" : "̒",
|
258 |
-
"\\ocommatopright" : "̕",
|
259 |
-
"\\droang" : "̚",
|
260 |
-
"\\wideutilde" : "̰",
|
261 |
-
"\\not" : "̸",
|
262 |
-
"\\upMu" : "Μ",
|
263 |
-
"\\upNu" : "Ν",
|
264 |
-
"\\upOmicron" : "Ο",
|
265 |
-
"\\upepsilon" : "ε",
|
266 |
-
"\\upomicron" : "ο",
|
267 |
-
"\\upvarbeta" : "ϐ",
|
268 |
-
"\\upoldKoppa" : "Ϙ",
|
269 |
-
"\\upoldkoppa" : "ϙ",
|
270 |
-
"\\upstigma" : "ϛ",
|
271 |
-
"\\upkoppa" : "ϟ",
|
272 |
-
"\\upsampi" : "ϡ",
|
273 |
-
"\\tieconcat" : "⁀",
|
274 |
-
"\\leftharpoonaccent" : "⃐",
|
275 |
-
"\\rightharpoonaccent" : "⃑",
|
276 |
-
"\\vertoverlay" : "⃒",
|
277 |
-
"\\overleftarrow" : "⃖",
|
278 |
-
"\\vec" : "⃗",
|
279 |
-
"\\overleftrightarrow" : "⃡",
|
280 |
-
"\\annuity" : "⃧",
|
281 |
-
"\\threeunderdot" : "⃨",
|
282 |
-
"\\widebridgeabove" : "⃩",
|
283 |
-
"\\bbC" : "ℂ",
|
284 |
-
"\\eulermascheroni" : "ℇ",
|
285 |
-
"\\scrg" : "ℊ",
|
286 |
-
"\\scrH" : "ℋ",
|
287 |
-
"\\frakH" : "ℌ",
|
288 |
-
"\\bbH" : "ℍ",
|
289 |
-
"\\planck" : "ℎ",
|
290 |
-
"\\scrI" : "ℐ",
|
291 |
-
"\\scrL" : "ℒ",
|
292 |
-
"\\bbN" : "ℕ",
|
293 |
-
"\\bbP" : "ℙ",
|
294 |
-
"\\bbQ" : "ℚ",
|
295 |
-
"\\scrR" : "ℛ",
|
296 |
-
"\\bbR" : "ℝ",
|
297 |
-
"\\bbZ" : "ℤ",
|
298 |
-
"\\frakZ" : "ℨ",
|
299 |
-
"\\Angstrom" : "Å",
|
300 |
-
"\\scrB" : "ℬ",
|
301 |
-
"\\frakC" : "ℭ",
|
302 |
-
"\\scre" : "ℯ",
|
303 |
-
"\\scrE" : "ℰ",
|
304 |
-
"\\scrF" : "ℱ",
|
305 |
-
"\\Finv" : "Ⅎ",
|
306 |
-
"\\scrM" : "ℳ",
|
307 |
-
"\\scro" : "ℴ",
|
308 |
-
"\\bbgamma" : "ℽ",
|
309 |
-
"\\bbGamma" : "ℾ",
|
310 |
-
"\\bbiD" : "ⅅ",
|
311 |
-
"\\bbid" : "ⅆ",
|
312 |
-
"\\bbie" : "ⅇ",
|
313 |
-
"\\bbii" : "ⅈ",
|
314 |
-
"\\bbij" : "ⅉ",
|
315 |
-
"\\bfA" : "𝐀",
|
316 |
-
"\\bfB" : "𝐁",
|
317 |
-
"\\bfC" : "𝐂",
|
318 |
-
"\\bfD" : "𝐃",
|
319 |
-
"\\bfE" : "𝐄",
|
320 |
-
"\\bfF" : "𝐅",
|
321 |
-
"\\bfG" : "𝐆",
|
322 |
-
"\\bfH" : "𝐇",
|
323 |
-
"\\bfI" : "𝐈",
|
324 |
-
"\\bfJ" : "𝐉",
|
325 |
-
"\\bfK" : "𝐊",
|
326 |
-
"\\bfL" : "𝐋",
|
327 |
-
"\\bfM" : "𝐌",
|
328 |
-
"\\bfN" : "𝐍",
|
329 |
-
"\\bfO" : "𝐎",
|
330 |
-
"\\bfP" : "𝐏",
|
331 |
-
"\\bfQ" : "𝐐",
|
332 |
-
"\\bfR" : "𝐑",
|
333 |
-
"\\bfS" : "𝐒",
|
334 |
-
"\\bfT" : "𝐓",
|
335 |
-
"\\bfU" : "𝐔",
|
336 |
-
"\\bfV" : "𝐕",
|
337 |
-
"\\bfW" : "𝐖",
|
338 |
-
"\\bfX" : "𝐗",
|
339 |
-
"\\bfY" : "𝐘",
|
340 |
-
"\\bfZ" : "𝐙",
|
341 |
-
"\\bfa" : "𝐚",
|
342 |
-
"\\bfb" : "𝐛",
|
343 |
-
"\\bfc" : "𝐜",
|
344 |
-
"\\bfd" : "𝐝",
|
345 |
-
"\\bfe" : "𝐞",
|
346 |
-
"\\bff" : "𝐟",
|
347 |
-
"\\bfg" : "𝐠",
|
348 |
-
"\\bfh" : "𝐡",
|
349 |
-
"\\bfi" : "𝐢",
|
350 |
-
"\\bfj" : "𝐣",
|
351 |
-
"\\bfk" : "𝐤",
|
352 |
-
"\\bfl" : "𝐥",
|
353 |
-
"\\bfm" : "𝐦",
|
354 |
-
"\\bfn" : "𝐧",
|
355 |
-
"\\bfo" : "𝐨",
|
356 |
-
"\\bfp" : "𝐩",
|
357 |
-
"\\bfq" : "𝐪",
|
358 |
-
"\\bfr" : "𝐫",
|
359 |
-
"\\bfs" : "𝐬",
|
360 |
-
"\\bft" : "𝐭",
|
361 |
-
"\\bfu" : "𝐮",
|
362 |
-
"\\bfv" : "𝐯",
|
363 |
-
"\\bfw" : "𝐰",
|
364 |
-
"\\bfx" : "𝐱",
|
365 |
-
"\\bfy" : "𝐲",
|
366 |
-
"\\bfz" : "𝐳",
|
367 |
-
"\\itA" : "𝐴",
|
368 |
-
"\\itB" : "𝐵",
|
369 |
-
"\\itC" : "𝐶",
|
370 |
-
"\\itD" : "𝐷",
|
371 |
-
"\\itE" : "𝐸",
|
372 |
-
"\\itF" : "𝐹",
|
373 |
-
"\\itG" : "𝐺",
|
374 |
-
"\\itH" : "𝐻",
|
375 |
-
"\\itI" : "𝐼",
|
376 |
-
"\\itJ" : "𝐽",
|
377 |
-
"\\itK" : "𝐾",
|
378 |
-
"\\itL" : "𝐿",
|
379 |
-
"\\itM" : "𝑀",
|
380 |
-
"\\itN" : "𝑁",
|
381 |
-
"\\itO" : "𝑂",
|
382 |
-
"\\itP" : "𝑃",
|
383 |
-
"\\itQ" : "𝑄",
|
384 |
-
"\\itR" : "𝑅",
|
385 |
-
"\\itS" : "𝑆",
|
386 |
-
"\\itT" : "𝑇",
|
387 |
-
"\\itU" : "𝑈",
|
388 |
-
"\\itV" : "𝑉",
|
389 |
-
"\\itW" : "𝑊",
|
390 |
-
"\\itX" : "𝑋",
|
391 |
-
"\\itY" : "𝑌",
|
392 |
-
"\\itZ" : "𝑍",
|
393 |
-
"\\ita" : "𝑎",
|
394 |
-
"\\itb" : "𝑏",
|
395 |
-
"\\itc" : "𝑐",
|
396 |
-
"\\itd" : "𝑑",
|
397 |
-
"\\ite" : "𝑒",
|
398 |
-
"\\itf" : "𝑓",
|
399 |
-
"\\itg" : "𝑔",
|
400 |
-
"\\iti" : "𝑖",
|
401 |
-
"\\itj" : "𝑗",
|
402 |
-
"\\itk" : "𝑘",
|
403 |
-
"\\itl" : "𝑙",
|
404 |
-
"\\itm" : "𝑚",
|
405 |
-
"\\itn" : "𝑛",
|
406 |
-
"\\ito" : "𝑜",
|
407 |
-
"\\itp" : "𝑝",
|
408 |
-
"\\itq" : "𝑞",
|
409 |
-
"\\itr" : "𝑟",
|
410 |
-
"\\its" : "𝑠",
|
411 |
-
"\\itt" : "𝑡",
|
412 |
-
"\\itu" : "𝑢",
|
413 |
-
"\\itv" : "𝑣",
|
414 |
-
"\\itw" : "𝑤",
|
415 |
-
"\\itx" : "𝑥",
|
416 |
-
"\\ity" : "𝑦",
|
417 |
-
"\\itz" : "𝑧",
|
418 |
-
"\\biA" : "𝑨",
|
419 |
-
"\\biB" : "𝑩",
|
420 |
-
"\\biC" : "𝑪",
|
421 |
-
"\\biD" : "𝑫",
|
422 |
-
"\\biE" : "𝑬",
|
423 |
-
"\\biF" : "𝑭",
|
424 |
-
"\\biG" : "𝑮",
|
425 |
-
"\\biH" : "𝑯",
|
426 |
-
"\\biI" : "𝑰",
|
427 |
-
"\\biJ" : "𝑱",
|
428 |
-
"\\biK" : "𝑲",
|
429 |
-
"\\biL" : "𝑳",
|
430 |
-
"\\biM" : "𝑴",
|
431 |
-
"\\biN" : "𝑵",
|
432 |
-
"\\biO" : "𝑶",
|
433 |
-
"\\biP" : "𝑷",
|
434 |
-
"\\biQ" : "𝑸",
|
435 |
-
"\\biR" : "𝑹",
|
436 |
-
"\\biS" : "𝑺",
|
437 |
-
"\\biT" : "𝑻",
|
438 |
-
"\\biU" : "𝑼",
|
439 |
-
"\\biV" : "𝑽",
|
440 |
-
"\\biW" : "𝑾",
|
441 |
-
"\\biX" : "𝑿",
|
442 |
-
"\\biY" : "𝒀",
|
443 |
-
"\\biZ" : "𝒁",
|
444 |
-
"\\bia" : "𝒂",
|
445 |
-
"\\bib" : "𝒃",
|
446 |
-
"\\bic" : "𝒄",
|
447 |
-
"\\bid" : "𝒅",
|
448 |
-
"\\bie" : "𝒆",
|
449 |
-
"\\bif" : "𝒇",
|
450 |
-
"\\big" : "𝒈",
|
451 |
-
"\\bih" : "𝒉",
|
452 |
-
"\\bii" : "𝒊",
|
453 |
-
"\\bij" : "𝒋",
|
454 |
-
"\\bik" : "𝒌",
|
455 |
-
"\\bil" : "𝒍",
|
456 |
-
"\\bim" : "𝒎",
|
457 |
-
"\\bin" : "𝒏",
|
458 |
-
"\\bio" : "𝒐",
|
459 |
-
"\\bip" : "𝒑",
|
460 |
-
"\\biq" : "𝒒",
|
461 |
-
"\\bir" : "𝒓",
|
462 |
-
"\\bis" : "𝒔",
|
463 |
-
"\\bit" : "𝒕",
|
464 |
-
"\\biu" : "𝒖",
|
465 |
-
"\\biv" : "𝒗",
|
466 |
-
"\\biw" : "𝒘",
|
467 |
-
"\\bix" : "𝒙",
|
468 |
-
"\\biy" : "𝒚",
|
469 |
-
"\\biz" : "𝒛",
|
470 |
-
"\\scrA" : "𝒜",
|
471 |
-
"\\scrC" : "𝒞",
|
472 |
-
"\\scrD" : "𝒟",
|
473 |
-
"\\scrG" : "𝒢",
|
474 |
-
"\\scrJ" : "𝒥",
|
475 |
-
"\\scrK" : "𝒦",
|
476 |
-
"\\scrN" : "𝒩",
|
477 |
-
"\\scrO" : "𝒪",
|
478 |
-
"\\scrP" : "𝒫",
|
479 |
-
"\\scrQ" : "𝒬",
|
480 |
-
"\\scrS" : "𝒮",
|
481 |
-
"\\scrT" : "𝒯",
|
482 |
-
"\\scrU" : "𝒰",
|
483 |
-
"\\scrV" : "𝒱",
|
484 |
-
"\\scrW" : "𝒲",
|
485 |
-
"\\scrX" : "𝒳",
|
486 |
-
"\\scrY" : "𝒴",
|
487 |
-
"\\scrZ" : "𝒵",
|
488 |
-
"\\scra" : "𝒶",
|
489 |
-
"\\scrb" : "𝒷",
|
490 |
-
"\\scrc" : "𝒸",
|
491 |
-
"\\scrd" : "𝒹",
|
492 |
-
"\\scrf" : "𝒻",
|
493 |
-
"\\scrh" : "𝒽",
|
494 |
-
"\\scri" : "𝒾",
|
495 |
-
"\\scrj" : "𝒿",
|
496 |
-
"\\scrk" : "𝓀",
|
497 |
-
"\\scrm" : "𝓂",
|
498 |
-
"\\scrn" : "𝓃",
|
499 |
-
"\\scrp" : "𝓅",
|
500 |
-
"\\scrq" : "𝓆",
|
501 |
-
"\\scrr" : "𝓇",
|
502 |
-
"\\scrs" : "𝓈",
|
503 |
-
"\\scrt" : "𝓉",
|
504 |
-
"\\scru" : "𝓊",
|
505 |
-
"\\scrv" : "𝓋",
|
506 |
-
"\\scrw" : "𝓌",
|
507 |
-
"\\scrx" : "𝓍",
|
508 |
-
"\\scry" : "𝓎",
|
509 |
-
"\\scrz" : "𝓏",
|
510 |
-
"\\bscrA" : "𝓐",
|
511 |
-
"\\bscrB" : "𝓑",
|
512 |
-
"\\bscrC" : "𝓒",
|
513 |
-
"\\bscrD" : "𝓓",
|
514 |
-
"\\bscrE" : "𝓔",
|
515 |
-
"\\bscrF" : "𝓕",
|
516 |
-
"\\bscrG" : "𝓖",
|
517 |
-
"\\bscrH" : "𝓗",
|
518 |
-
"\\bscrI" : "𝓘",
|
519 |
-
"\\bscrJ" : "𝓙",
|
520 |
-
"\\bscrK" : "𝓚",
|
521 |
-
"\\bscrL" : "𝓛",
|
522 |
-
"\\bscrM" : "𝓜",
|
523 |
-
"\\bscrN" : "𝓝",
|
524 |
-
"\\bscrO" : "𝓞",
|
525 |
-
"\\bscrP" : "𝓟",
|
526 |
-
"\\bscrQ" : "𝓠",
|
527 |
-
"\\bscrR" : "𝓡",
|
528 |
-
"\\bscrS" : "𝓢",
|
529 |
-
"\\bscrT" : "𝓣",
|
530 |
-
"\\bscrU" : "𝓤",
|
531 |
-
"\\bscrV" : "𝓥",
|
532 |
-
"\\bscrW" : "𝓦",
|
533 |
-
"\\bscrX" : "𝓧",
|
534 |
-
"\\bscrY" : "𝓨",
|
535 |
-
"\\bscrZ" : "𝓩",
|
536 |
-
"\\bscra" : "𝓪",
|
537 |
-
"\\bscrb" : "𝓫",
|
538 |
-
"\\bscrc" : "𝓬",
|
539 |
-
"\\bscrd" : "𝓭",
|
540 |
-
"\\bscre" : "𝓮",
|
541 |
-
"\\bscrf" : "𝓯",
|
542 |
-
"\\bscrg" : "𝓰",
|
543 |
-
"\\bscrh" : "𝓱",
|
544 |
-
"\\bscri" : "𝓲",
|
545 |
-
"\\bscrj" : "𝓳",
|
546 |
-
"\\bscrk" : "𝓴",
|
547 |
-
"\\bscrl" : "𝓵",
|
548 |
-
"\\bscrm" : "𝓶",
|
549 |
-
"\\bscrn" : "𝓷",
|
550 |
-
"\\bscro" : "𝓸",
|
551 |
-
"\\bscrp" : "𝓹",
|
552 |
-
"\\bscrq" : "𝓺",
|
553 |
-
"\\bscrr" : "𝓻",
|
554 |
-
"\\bscrs" : "𝓼",
|
555 |
-
"\\bscrt" : "𝓽",
|
556 |
-
"\\bscru" : "𝓾",
|
557 |
-
"\\bscrv" : "𝓿",
|
558 |
-
"\\bscrw" : "𝔀",
|
559 |
-
"\\bscrx" : "𝔁",
|
560 |
-
"\\bscry" : "𝔂",
|
561 |
-
"\\bscrz" : "𝔃",
|
562 |
-
"\\frakA" : "𝔄",
|
563 |
-
"\\frakB" : "𝔅",
|
564 |
-
"\\frakD" : "𝔇",
|
565 |
-
"\\frakE" : "𝔈",
|
566 |
-
"\\frakF" : "𝔉",
|
567 |
-
"\\frakG" : "𝔊",
|
568 |
-
"\\frakJ" : "𝔍",
|
569 |
-
"\\frakK" : "𝔎",
|
570 |
-
"\\frakL" : "𝔏",
|
571 |
-
"\\frakM" : "𝔐",
|
572 |
-
"\\frakN" : "𝔑",
|
573 |
-
"\\frakO" : "𝔒",
|
574 |
-
"\\frakP" : "𝔓",
|
575 |
-
"\\frakQ" : "𝔔",
|
576 |
-
"\\frakS" : "𝔖",
|
577 |
-
"\\frakT" : "𝔗",
|
578 |
-
"\\frakU" : "𝔘",
|
579 |
-
"\\frakV" : "𝔙",
|
580 |
-
"\\frakW" : "𝔚",
|
581 |
-
"\\frakX" : "𝔛",
|
582 |
-
"\\frakY" : "𝔜",
|
583 |
-
"\\fraka" : "𝔞",
|
584 |
-
"\\frakb" : "𝔟",
|
585 |
-
"\\frakc" : "𝔠",
|
586 |
-
"\\frakd" : "𝔡",
|
587 |
-
"\\frake" : "𝔢",
|
588 |
-
"\\frakf" : "𝔣",
|
589 |
-
"\\frakg" : "𝔤",
|
590 |
-
"\\frakh" : "𝔥",
|
591 |
-
"\\fraki" : "𝔦",
|
592 |
-
"\\frakj" : "𝔧",
|
593 |
-
"\\frakk" : "𝔨",
|
594 |
-
"\\frakl" : "𝔩",
|
595 |
-
"\\frakm" : "𝔪",
|
596 |
-
"\\frakn" : "𝔫",
|
597 |
-
"\\frako" : "𝔬",
|
598 |
-
"\\frakp" : "𝔭",
|
599 |
-
"\\frakq" : "𝔮",
|
600 |
-
"\\frakr" : "𝔯",
|
601 |
-
"\\fraks" : "𝔰",
|
602 |
-
"\\frakt" : "𝔱",
|
603 |
-
"\\fraku" : "𝔲",
|
604 |
-
"\\frakv" : "𝔳",
|
605 |
-
"\\frakw" : "𝔴",
|
606 |
-
"\\frakx" : "𝔵",
|
607 |
-
"\\fraky" : "𝔶",
|
608 |
-
"\\frakz" : "𝔷",
|
609 |
-
"\\bbA" : "𝔸",
|
610 |
-
"\\bbB" : "𝔹",
|
611 |
-
"\\bbD" : "𝔻",
|
612 |
-
"\\bbE" : "𝔼",
|
613 |
-
"\\bbF" : "𝔽",
|
614 |
-
"\\bbG" : "𝔾",
|
615 |
-
"\\bbI" : "𝕀",
|
616 |
-
"\\bbJ" : "𝕁",
|
617 |
-
"\\bbK" : "𝕂",
|
618 |
-
"\\bbL" : "𝕃",
|
619 |
-
"\\bbM" : "𝕄",
|
620 |
-
"\\bbO" : "𝕆",
|
621 |
-
"\\bbS" : "𝕊",
|
622 |
-
"\\bbT" : "𝕋",
|
623 |
-
"\\bbU" : "𝕌",
|
624 |
-
"\\bbV" : "𝕍",
|
625 |
-
"\\bbW" : "𝕎",
|
626 |
-
"\\bbX" : "𝕏",
|
627 |
-
"\\bbY" : "𝕐",
|
628 |
-
"\\bba" : "𝕒",
|
629 |
-
"\\bbb" : "𝕓",
|
630 |
-
"\\bbc" : "𝕔",
|
631 |
-
"\\bbd" : "𝕕",
|
632 |
-
"\\bbe" : "𝕖",
|
633 |
-
"\\bbf" : "𝕗",
|
634 |
-
"\\bbg" : "𝕘",
|
635 |
-
"\\bbh" : "𝕙",
|
636 |
-
"\\bbi" : "𝕚",
|
637 |
-
"\\bbj" : "𝕛",
|
638 |
-
"\\bbk" : "𝕜",
|
639 |
-
"\\bbl" : "𝕝",
|
640 |
-
"\\bbm" : "𝕞",
|
641 |
-
"\\bbn" : "𝕟",
|
642 |
-
"\\bbo" : "𝕠",
|
643 |
-
"\\bbp" : "𝕡",
|
644 |
-
"\\bbq" : "𝕢",
|
645 |
-
"\\bbr" : "𝕣",
|
646 |
-
"\\bbs" : "𝕤",
|
647 |
-
"\\bbt" : "𝕥",
|
648 |
-
"\\bbu" : "𝕦",
|
649 |
-
"\\bbv" : "𝕧",
|
650 |
-
"\\bbw" : "𝕨",
|
651 |
-
"\\bbx" : "𝕩",
|
652 |
-
"\\bby" : "𝕪",
|
653 |
-
"\\bbz" : "𝕫",
|
654 |
-
"\\bfrakA" : "𝕬",
|
655 |
-
"\\bfrakB" : "𝕭",
|
656 |
-
"\\bfrakC" : "𝕮",
|
657 |
-
"\\bfrakD" : "𝕯",
|
658 |
-
"\\bfrakE" : "𝕰",
|
659 |
-
"\\bfrakF" : "𝕱",
|
660 |
-
"\\bfrakG" : "𝕲",
|
661 |
-
"\\bfrakH" : "𝕳",
|
662 |
-
"\\bfrakI" : "𝕴",
|
663 |
-
"\\bfrakJ" : "𝕵",
|
664 |
-
"\\bfrakK" : "𝕶",
|
665 |
-
"\\bfrakL" : "𝕷",
|
666 |
-
"\\bfrakM" : "𝕸",
|
667 |
-
"\\bfrakN" : "𝕹",
|
668 |
-
"\\bfrakO" : "𝕺",
|
669 |
-
"\\bfrakP" : "𝕻",
|
670 |
-
"\\bfrakQ" : "𝕼",
|
671 |
-
"\\bfrakR" : "𝕽",
|
672 |
-
"\\bfrakS" : "𝕾",
|
673 |
-
"\\bfrakT" : "𝕿",
|
674 |
-
"\\bfrakU" : "𝖀",
|
675 |
-
"\\bfrakV" : "𝖁",
|
676 |
-
"\\bfrakW" : "𝖂",
|
677 |
-
"\\bfrakX" : "𝖃",
|
678 |
-
"\\bfrakY" : "𝖄",
|
679 |
-
"\\bfrakZ" : "𝖅",
|
680 |
-
"\\bfraka" : "𝖆",
|
681 |
-
"\\bfrakb" : "𝖇",
|
682 |
-
"\\bfrakc" : "𝖈",
|
683 |
-
"\\bfrakd" : "𝖉",
|
684 |
-
"\\bfrake" : "𝖊",
|
685 |
-
"\\bfrakf" : "𝖋",
|
686 |
-
"\\bfrakg" : "𝖌",
|
687 |
-
"\\bfrakh" : "𝖍",
|
688 |
-
"\\bfraki" : "𝖎",
|
689 |
-
"\\bfrakj" : "𝖏",
|
690 |
-
"\\bfrakk" : "𝖐",
|
691 |
-
"\\bfrakl" : "𝖑",
|
692 |
-
"\\bfrakm" : "𝖒",
|
693 |
-
"\\bfrakn" : "𝖓",
|
694 |
-
"\\bfrako" : "𝖔",
|
695 |
-
"\\bfrakp" : "𝖕",
|
696 |
-
"\\bfrakq" : "𝖖",
|
697 |
-
"\\bfrakr" : "𝖗",
|
698 |
-
"\\bfraks" : "𝖘",
|
699 |
-
"\\bfrakt" : "𝖙",
|
700 |
-
"\\bfraku" : "𝖚",
|
701 |
-
"\\bfrakv" : "𝖛",
|
702 |
-
"\\bfrakw" : "𝖜",
|
703 |
-
"\\bfrakx" : "𝖝",
|
704 |
-
"\\bfraky" : "𝖞",
|
705 |
-
"\\bfrakz" : "𝖟",
|
706 |
-
"\\sansA" : "𝖠",
|
707 |
-
"\\sansB" : "𝖡",
|
708 |
-
"\\sansC" : "𝖢",
|
709 |
-
"\\sansD" : "𝖣",
|
710 |
-
"\\sansE" : "𝖤",
|
711 |
-
"\\sansF" : "𝖥",
|
712 |
-
"\\sansG" : "𝖦",
|
713 |
-
"\\sansH" : "𝖧",
|
714 |
-
"\\sansI" : "𝖨",
|
715 |
-
"\\sansJ" : "𝖩",
|
716 |
-
"\\sansK" : "𝖪",
|
717 |
-
"\\sansL" : "𝖫",
|
718 |
-
"\\sansM" : "𝖬",
|
719 |
-
"\\sansN" : "𝖭",
|
720 |
-
"\\sansO" : "𝖮",
|
721 |
-
"\\sansP" : "𝖯",
|
722 |
-
"\\sansQ" : "𝖰",
|
723 |
-
"\\sansR" : "𝖱",
|
724 |
-
"\\sansS" : "𝖲",
|
725 |
-
"\\sansT" : "𝖳",
|
726 |
-
"\\sansU" : "𝖴",
|
727 |
-
"\\sansV" : "𝖵",
|
728 |
-
"\\sansW" : "𝖶",
|
729 |
-
"\\sansX" : "𝖷",
|
730 |
-
"\\sansY" : "𝖸",
|
731 |
-
"\\sansZ" : "𝖹",
|
732 |
-
"\\sansa" : "𝖺",
|
733 |
-
"\\sansb" : "𝖻",
|
734 |
-
"\\sansc" : "𝖼",
|
735 |
-
"\\sansd" : "𝖽",
|
736 |
-
"\\sanse" : "𝖾",
|
737 |
-
"\\sansf" : "𝖿",
|
738 |
-
"\\sansg" : "𝗀",
|
739 |
-
"\\sansh" : "𝗁",
|
740 |
-
"\\sansi" : "𝗂",
|
741 |
-
"\\sansj" : "𝗃",
|
742 |
-
"\\sansk" : "𝗄",
|
743 |
-
"\\sansl" : "𝗅",
|
744 |
-
"\\sansm" : "𝗆",
|
745 |
-
"\\sansn" : "𝗇",
|
746 |
-
"\\sanso" : "𝗈",
|
747 |
-
"\\sansp" : "𝗉",
|
748 |
-
"\\sansq" : "𝗊",
|
749 |
-
"\\sansr" : "𝗋",
|
750 |
-
"\\sanss" : "𝗌",
|
751 |
-
"\\sanst" : "𝗍",
|
752 |
-
"\\sansu" : "𝗎",
|
753 |
-
"\\sansv" : "𝗏",
|
754 |
-
"\\sansw" : "𝗐",
|
755 |
-
"\\sansx" : "𝗑",
|
756 |
-
"\\sansy" : "𝗒",
|
757 |
-
"\\sansz" : "𝗓",
|
758 |
-
"\\bsansA" : "𝗔",
|
759 |
-
"\\bsansB" : "𝗕",
|
760 |
-
"\\bsansC" : "𝗖",
|
761 |
-
"\\bsansD" : "𝗗",
|
762 |
-
"\\bsansE" : "𝗘",
|
763 |
-
"\\bsansF" : "𝗙",
|
764 |
-
"\\bsansG" : "𝗚",
|
765 |
-
"\\bsansH" : "𝗛",
|
766 |
-
"\\bsansI" : "𝗜",
|
767 |
-
"\\bsansJ" : "𝗝",
|
768 |
-
"\\bsansK" : "𝗞",
|
769 |
-
"\\bsansL" : "𝗟",
|
770 |
-
"\\bsansM" : "𝗠",
|
771 |
-
"\\bsansN" : "𝗡",
|
772 |
-
"\\bsansO" : "𝗢",
|
773 |
-
"\\bsansP" : "𝗣",
|
774 |
-
"\\bsansQ" : "𝗤",
|
775 |
-
"\\bsansR" : "𝗥",
|
776 |
-
"\\bsansS" : "𝗦",
|
777 |
-
"\\bsansT" : "𝗧",
|
778 |
-
"\\bsansU" : "𝗨",
|
779 |
-
"\\bsansV" : "𝗩",
|
780 |
-
"\\bsansW" : "𝗪",
|
781 |
-
"\\bsansX" : "𝗫",
|
782 |
-
"\\bsansY" : "𝗬",
|
783 |
-
"\\bsansZ" : "𝗭",
|
784 |
-
"\\bsansa" : "𝗮",
|
785 |
-
"\\bsansb" : "𝗯",
|
786 |
-
"\\bsansc" : "𝗰",
|
787 |
-
"\\bsansd" : "𝗱",
|
788 |
-
"\\bsanse" : "𝗲",
|
789 |
-
"\\bsansf" : "𝗳",
|
790 |
-
"\\bsansg" : "𝗴",
|
791 |
-
"\\bsansh" : "𝗵",
|
792 |
-
"\\bsansi" : "𝗶",
|
793 |
-
"\\bsansj" : "𝗷",
|
794 |
-
"\\bsansk" : "𝗸",
|
795 |
-
"\\bsansl" : "𝗹",
|
796 |
-
"\\bsansm" : "𝗺",
|
797 |
-
"\\bsansn" : "𝗻",
|
798 |
-
"\\bsanso" : "𝗼",
|
799 |
-
"\\bsansp" : "𝗽",
|
800 |
-
"\\bsansq" : "𝗾",
|
801 |
-
"\\bsansr" : "𝗿",
|
802 |
-
"\\bsanss" : "𝘀",
|
803 |
-
"\\bsanst" : "𝘁",
|
804 |
-
"\\bsansu" : "𝘂",
|
805 |
-
"\\bsansv" : "𝘃",
|
806 |
-
"\\bsansw" : "𝘄",
|
807 |
-
"\\bsansx" : "𝘅",
|
808 |
-
"\\bsansy" : "𝘆",
|
809 |
-
"\\bsansz" : "𝘇",
|
810 |
-
"\\isansA" : "𝘈",
|
811 |
-
"\\isansB" : "𝘉",
|
812 |
-
"\\isansC" : "𝘊",
|
813 |
-
"\\isansD" : "𝘋",
|
814 |
-
"\\isansE" : "𝘌",
|
815 |
-
"\\isansF" : "𝘍",
|
816 |
-
"\\isansG" : "𝘎",
|
817 |
-
"\\isansH" : "𝘏",
|
818 |
-
"\\isansI" : "𝘐",
|
819 |
-
"\\isansJ" : "𝘑",
|
820 |
-
"\\isansK" : "𝘒",
|
821 |
-
"\\isansL" : "𝘓",
|
822 |
-
"\\isansM" : "𝘔",
|
823 |
-
"\\isansN" : "𝘕",
|
824 |
-
"\\isansO" : "𝘖",
|
825 |
-
"\\isansP" : "𝘗",
|
826 |
-
"\\isansQ" : "𝘘",
|
827 |
-
"\\isansR" : "𝘙",
|
828 |
-
"\\isansS" : "𝘚",
|
829 |
-
"\\isansT" : "𝘛",
|
830 |
-
"\\isansU" : "𝘜",
|
831 |
-
"\\isansV" : "𝘝",
|
832 |
-
"\\isansW" : "𝘞",
|
833 |
-
"\\isansX" : "𝘟",
|
834 |
-
"\\isansY" : "𝘠",
|
835 |
-
"\\isansZ" : "𝘡",
|
836 |
-
"\\isansa" : "𝘢",
|
837 |
-
"\\isansb" : "𝘣",
|
838 |
-
"\\isansc" : "𝘤",
|
839 |
-
"\\isansd" : "𝘥",
|
840 |
-
"\\isanse" : "𝘦",
|
841 |
-
"\\isansf" : "𝘧",
|
842 |
-
"\\isansg" : "𝘨",
|
843 |
-
"\\isansh" : "𝘩",
|
844 |
-
"\\isansi" : "𝘪",
|
845 |
-
"\\isansj" : "𝘫",
|
846 |
-
"\\isansk" : "𝘬",
|
847 |
-
"\\isansl" : "𝘭",
|
848 |
-
"\\isansm" : "𝘮",
|
849 |
-
"\\isansn" : "𝘯",
|
850 |
-
"\\isanso" : "𝘰",
|
851 |
-
"\\isansp" : "𝘱",
|
852 |
-
"\\isansq" : "𝘲",
|
853 |
-
"\\isansr" : "𝘳",
|
854 |
-
"\\isanss" : "𝘴",
|
855 |
-
"\\isanst" : "𝘵",
|
856 |
-
"\\isansu" : "𝘶",
|
857 |
-
"\\isansv" : "𝘷",
|
858 |
-
"\\isansw" : "𝘸",
|
859 |
-
"\\isansx" : "𝘹",
|
860 |
-
"\\isansy" : "𝘺",
|
861 |
-
"\\isansz" : "𝘻",
|
862 |
-
"\\bisansA" : "𝘼",
|
863 |
-
"\\bisansB" : "𝘽",
|
864 |
-
"\\bisansC" : "𝘾",
|
865 |
-
"\\bisansD" : "𝘿",
|
866 |
-
"\\bisansE" : "𝙀",
|
867 |
-
"\\bisansF" : "𝙁",
|
868 |
-
"\\bisansG" : "𝙂",
|
869 |
-
"\\bisansH" : "𝙃",
|
870 |
-
"\\bisansI" : "𝙄",
|
871 |
-
"\\bisansJ" : "𝙅",
|
872 |
-
"\\bisansK" : "𝙆",
|
873 |
-
"\\bisansL" : "𝙇",
|
874 |
-
"\\bisansM" : "𝙈",
|
875 |
-
"\\bisansN" : "𝙉",
|
876 |
-
"\\bisansO" : "𝙊",
|
877 |
-
"\\bisansP" : "𝙋",
|
878 |
-
"\\bisansQ" : "𝙌",
|
879 |
-
"\\bisansR" : "𝙍",
|
880 |
-
"\\bisansS" : "𝙎",
|
881 |
-
"\\bisansT" : "𝙏",
|
882 |
-
"\\bisansU" : "𝙐",
|
883 |
-
"\\bisansV" : "𝙑",
|
884 |
-
"\\bisansW" : "𝙒",
|
885 |
-
"\\bisansX" : "𝙓",
|
886 |
-
"\\bisansY" : "𝙔",
|
887 |
-
"\\bisansZ" : "𝙕",
|
888 |
-
"\\bisansa" : "𝙖",
|
889 |
-
"\\bisansb" : "𝙗",
|
890 |
-
"\\bisansc" : "𝙘",
|
891 |
-
"\\bisansd" : "𝙙",
|
892 |
-
"\\bisanse" : "𝙚",
|
893 |
-
"\\bisansf" : "𝙛",
|
894 |
-
"\\bisansg" : "𝙜",
|
895 |
-
"\\bisansh" : "𝙝",
|
896 |
-
"\\bisansi" : "𝙞",
|
897 |
-
"\\bisansj" : "𝙟",
|
898 |
-
"\\bisansk" : "𝙠",
|
899 |
-
"\\bisansl" : "𝙡",
|
900 |
-
"\\bisansm" : "𝙢",
|
901 |
-
"\\bisansn" : "𝙣",
|
902 |
-
"\\bisanso" : "𝙤",
|
903 |
-
"\\bisansp" : "𝙥",
|
904 |
-
"\\bisansq" : "𝙦",
|
905 |
-
"\\bisansr" : "𝙧",
|
906 |
-
"\\bisanss" : "𝙨",
|
907 |
-
"\\bisanst" : "𝙩",
|
908 |
-
"\\bisansu" : "𝙪",
|
909 |
-
"\\bisansv" : "𝙫",
|
910 |
-
"\\bisansw" : "𝙬",
|
911 |
-
"\\bisansx" : "𝙭",
|
912 |
-
"\\bisansy" : "𝙮",
|
913 |
-
"\\bisansz" : "𝙯",
|
914 |
-
"\\ttA" : "𝙰",
|
915 |
-
"\\ttB" : "𝙱",
|
916 |
-
"\\ttC" : "𝙲",
|
917 |
-
"\\ttD" : "𝙳",
|
918 |
-
"\\ttE" : "𝙴",
|
919 |
-
"\\ttF" : "𝙵",
|
920 |
-
"\\ttG" : "𝙶",
|
921 |
-
"\\ttH" : "𝙷",
|
922 |
-
"\\ttI" : "𝙸",
|
923 |
-
"\\ttJ" : "𝙹",
|
924 |
-
"\\ttK" : "𝙺",
|
925 |
-
"\\ttL" : "𝙻",
|
926 |
-
"\\ttM" : "𝙼",
|
927 |
-
"\\ttN" : "𝙽",
|
928 |
-
"\\ttO" : "𝙾",
|
929 |
-
"\\ttP" : "𝙿",
|
930 |
-
"\\ttQ" : "𝚀",
|
931 |
-
"\\ttR" : "𝚁",
|
932 |
-
"\\ttS" : "𝚂",
|
933 |
-
"\\ttT" : "𝚃",
|
934 |
-
"\\ttU" : "𝚄",
|
935 |
-
"\\ttV" : "𝚅",
|
936 |
-
"\\ttW" : "𝚆",
|
937 |
-
"\\ttX" : "𝚇",
|
938 |
-
"\\ttY" : "𝚈",
|
939 |
-
"\\ttZ" : "𝚉",
|
940 |
-
"\\tta" : "𝚊",
|
941 |
-
"\\ttb" : "𝚋",
|
942 |
-
"\\ttc" : "𝚌",
|
943 |
-
"\\ttd" : "𝚍",
|
944 |
-
"\\tte" : "𝚎",
|
945 |
-
"\\ttf" : "𝚏",
|
946 |
-
"\\ttg" : "𝚐",
|
947 |
-
"\\tth" : "𝚑",
|
948 |
-
"\\tti" : "𝚒",
|
949 |
-
"\\ttj" : "𝚓",
|
950 |
-
"\\ttk" : "𝚔",
|
951 |
-
"\\ttl" : "𝚕",
|
952 |
-
"\\ttm" : "𝚖",
|
953 |
-
"\\ttn" : "𝚗",
|
954 |
-
"\\tto" : "𝚘",
|
955 |
-
"\\ttp" : "𝚙",
|
956 |
-
"\\ttq" : "𝚚",
|
957 |
-
"\\ttr" : "𝚛",
|
958 |
-
"\\tts" : "𝚜",
|
959 |
-
"\\ttt" : "𝚝",
|
960 |
-
"\\ttu" : "𝚞",
|
961 |
-
"\\ttv" : "𝚟",
|
962 |
-
"\\ttw" : "𝚠",
|
963 |
-
"\\ttx" : "𝚡",
|
964 |
-
"\\tty" : "𝚢",
|
965 |
-
"\\ttz" : "𝚣",
|
966 |
-
"\\bfAlpha" : "𝚨",
|
967 |
-
"\\bfBeta" : "𝚩",
|
968 |
-
"\\bfGamma" : "𝚪",
|
969 |
-
"\\bfDelta" : "𝚫",
|
970 |
-
"\\bfEpsilon" : "𝚬",
|
971 |
-
"\\bfZeta" : "𝚭",
|
972 |
-
"\\bfEta" : "𝚮",
|
973 |
-
"\\bfTheta" : "𝚯",
|
974 |
-
"\\bfIota" : "𝚰",
|
975 |
-
"\\bfKappa" : "𝚱",
|
976 |
-
"\\bfLambda" : "𝚲",
|
977 |
-
"\\bfMu" : "𝚳",
|
978 |
-
"\\bfNu" : "𝚴",
|
979 |
-
"\\bfXi" : "𝚵",
|
980 |
-
"\\bfOmicron" : "𝚶",
|
981 |
-
"\\bfPi" : "𝚷",
|
982 |
-
"\\bfRho" : "𝚸",
|
983 |
-
"\\bfvarTheta" : "𝚹",
|
984 |
-
"\\bfSigma" : "𝚺",
|
985 |
-
"\\bfTau" : "𝚻",
|
986 |
-
"\\bfUpsilon" : "𝚼",
|
987 |
-
"\\bfPhi" : "𝚽",
|
988 |
-
"\\bfChi" : "𝚾",
|
989 |
-
"\\bfPsi" : "𝚿",
|
990 |
-
"\\bfOmega" : "𝛀",
|
991 |
-
"\\bfalpha" : "𝛂",
|
992 |
-
"\\bfbeta" : "𝛃",
|
993 |
-
"\\bfgamma" : "𝛄",
|
994 |
-
"\\bfdelta" : "𝛅",
|
995 |
-
"\\bfepsilon" : "𝛆",
|
996 |
-
"\\bfzeta" : "𝛇",
|
997 |
-
"\\bfeta" : "𝛈",
|
998 |
-
"\\bftheta" : "𝛉",
|
999 |
-
"\\bfiota" : "𝛊",
|
1000 |
-
"\\bfkappa" : "𝛋",
|
1001 |
-
"\\bflambda" : "𝛌",
|
1002 |
-
"\\bfmu" : "𝛍",
|
1003 |
-
"\\bfnu" : "𝛎",
|
1004 |
-
"\\bfxi" : "𝛏",
|
1005 |
-
"\\bfomicron" : "𝛐",
|
1006 |
-
"\\bfpi" : "𝛑",
|
1007 |
-
"\\bfrho" : "𝛒",
|
1008 |
-
"\\bfvarsigma" : "𝛓",
|
1009 |
-
"\\bfsigma" : "𝛔",
|
1010 |
-
"\\bftau" : "𝛕",
|
1011 |
-
"\\bfupsilon" : "𝛖",
|
1012 |
-
"\\bfvarphi" : "𝛗",
|
1013 |
-
"\\bfchi" : "𝛘",
|
1014 |
-
"\\bfpsi" : "𝛙",
|
1015 |
-
"\\bfomega" : "𝛚",
|
1016 |
-
"\\bfvarepsilon" : "𝛜",
|
1017 |
-
"\\bfvartheta" : "𝛝",
|
1018 |
-
"\\bfvarkappa" : "𝛞",
|
1019 |
-
"\\bfphi" : "𝛟",
|
1020 |
-
"\\bfvarrho" : "𝛠",
|
1021 |
-
"\\bfvarpi" : "𝛡",
|
1022 |
-
"\\itAlpha" : "𝛢",
|
1023 |
-
"\\itBeta" : "𝛣",
|
1024 |
-
"\\itGamma" : "𝛤",
|
1025 |
-
"\\itDelta" : "𝛥",
|
1026 |
-
"\\itEpsilon" : "𝛦",
|
1027 |
-
"\\itZeta" : "𝛧",
|
1028 |
-
"\\itEta" : "𝛨",
|
1029 |
-
"\\itTheta" : "𝛩",
|
1030 |
-
"\\itIota" : "𝛪",
|
1031 |
-
"\\itKappa" : "𝛫",
|
1032 |
-
"\\itLambda" : "𝛬",
|
1033 |
-
"\\itMu" : "𝛭",
|
1034 |
-
"\\itNu" : "𝛮",
|
1035 |
-
"\\itXi" : "𝛯",
|
1036 |
-
"\\itOmicron" : "𝛰",
|
1037 |
-
"\\itPi" : "𝛱",
|
1038 |
-
"\\itRho" : "𝛲",
|
1039 |
-
"\\itvarTheta" : "𝛳",
|
1040 |
-
"\\itSigma" : "𝛴",
|
1041 |
-
"\\itTau" : "𝛵",
|
1042 |
-
"\\itUpsilon" : "𝛶",
|
1043 |
-
"\\itPhi" : "𝛷",
|
1044 |
-
"\\itChi" : "𝛸",
|
1045 |
-
"\\itPsi" : "𝛹",
|
1046 |
-
"\\itOmega" : "𝛺",
|
1047 |
-
"\\italpha" : "𝛼",
|
1048 |
-
"\\itbeta" : "𝛽",
|
1049 |
-
"\\itgamma" : "𝛾",
|
1050 |
-
"\\itdelta" : "𝛿",
|
1051 |
-
"\\itepsilon" : "𝜀",
|
1052 |
-
"\\itzeta" : "𝜁",
|
1053 |
-
"\\iteta" : "𝜂",
|
1054 |
-
"\\ittheta" : "𝜃",
|
1055 |
-
"\\itiota" : "𝜄",
|
1056 |
-
"\\itkappa" : "𝜅",
|
1057 |
-
"\\itlambda" : "𝜆",
|
1058 |
-
"\\itmu" : "𝜇",
|
1059 |
-
"\\itnu" : "𝜈",
|
1060 |
-
"\\itxi" : "𝜉",
|
1061 |
-
"\\itomicron" : "𝜊",
|
1062 |
-
"\\itpi" : "𝜋",
|
1063 |
-
"\\itrho" : "𝜌",
|
1064 |
-
"\\itvarsigma" : "𝜍",
|
1065 |
-
"\\itsigma" : "𝜎",
|
1066 |
-
"\\ittau" : "𝜏",
|
1067 |
-
"\\itupsilon" : "𝜐",
|
1068 |
-
"\\itphi" : "𝜑",
|
1069 |
-
"\\itchi" : "𝜒",
|
1070 |
-
"\\itpsi" : "𝜓",
|
1071 |
-
"\\itomega" : "𝜔",
|
1072 |
-
"\\itvarepsilon" : "𝜖",
|
1073 |
-
"\\itvartheta" : "𝜗",
|
1074 |
-
"\\itvarkappa" : "𝜘",
|
1075 |
-
"\\itvarphi" : "𝜙",
|
1076 |
-
"\\itvarrho" : "𝜚",
|
1077 |
-
"\\itvarpi" : "𝜛",
|
1078 |
-
"\\biAlpha" : "𝜜",
|
1079 |
-
"\\biBeta" : "𝜝",
|
1080 |
-
"\\biGamma" : "𝜞",
|
1081 |
-
"\\biDelta" : "𝜟",
|
1082 |
-
"\\biEpsilon" : "𝜠",
|
1083 |
-
"\\biZeta" : "𝜡",
|
1084 |
-
"\\biEta" : "𝜢",
|
1085 |
-
"\\biTheta" : "𝜣",
|
1086 |
-
"\\biIota" : "𝜤",
|
1087 |
-
"\\biKappa" : "𝜥",
|
1088 |
-
"\\biLambda" : "𝜦",
|
1089 |
-
"\\biMu" : "𝜧",
|
1090 |
-
"\\biNu" : "𝜨",
|
1091 |
-
"\\biXi" : "𝜩",
|
1092 |
-
"\\biOmicron" : "𝜪",
|
1093 |
-
"\\biPi" : "𝜫",
|
1094 |
-
"\\biRho" : "𝜬",
|
1095 |
-
"\\bivarTheta" : "𝜭",
|
1096 |
-
"\\biSigma" : "𝜮",
|
1097 |
-
"\\biTau" : "𝜯",
|
1098 |
-
"\\biUpsilon" : "𝜰",
|
1099 |
-
"\\biPhi" : "𝜱",
|
1100 |
-
"\\biChi" : "𝜲",
|
1101 |
-
"\\biPsi" : "𝜳",
|
1102 |
-
"\\biOmega" : "𝜴",
|
1103 |
-
"\\bialpha" : "𝜶",
|
1104 |
-
"\\bibeta" : "𝜷",
|
1105 |
-
"\\bigamma" : "𝜸",
|
1106 |
-
"\\bidelta" : "𝜹",
|
1107 |
-
"\\biepsilon" : "𝜺",
|
1108 |
-
"\\bizeta" : "𝜻",
|
1109 |
-
"\\bieta" : "𝜼",
|
1110 |
-
"\\bitheta" : "𝜽",
|
1111 |
-
"\\biiota" : "𝜾",
|
1112 |
-
"\\bikappa" : "𝜿",
|
1113 |
-
"\\bilambda" : "𝝀",
|
1114 |
-
"\\bimu" : "𝝁",
|
1115 |
-
"\\binu" : "𝝂",
|
1116 |
-
"\\bixi" : "𝝃",
|
1117 |
-
"\\biomicron" : "𝝄",
|
1118 |
-
"\\bipi" : "𝝅",
|
1119 |
-
"\\birho" : "𝝆",
|
1120 |
-
"\\bivarsigma" : "𝝇",
|
1121 |
-
"\\bisigma" : "𝝈",
|
1122 |
-
"\\bitau" : "𝝉",
|
1123 |
-
"\\biupsilon" : "𝝊",
|
1124 |
-
"\\biphi" : "𝝋",
|
1125 |
-
"\\bichi" : "𝝌",
|
1126 |
-
"\\bipsi" : "𝝍",
|
1127 |
-
"\\biomega" : "𝝎",
|
1128 |
-
"\\bivarepsilon" : "𝝐",
|
1129 |
-
"\\bivartheta" : "𝝑",
|
1130 |
-
"\\bivarkappa" : "𝝒",
|
1131 |
-
"\\bivarphi" : "𝝓",
|
1132 |
-
"\\bivarrho" : "𝝔",
|
1133 |
-
"\\bivarpi" : "𝝕",
|
1134 |
-
"\\bsansAlpha" : "𝝖",
|
1135 |
-
"\\bsansBeta" : "𝝗",
|
1136 |
-
"\\bsansGamma" : "𝝘",
|
1137 |
-
"\\bsansDelta" : "𝝙",
|
1138 |
-
"\\bsansEpsilon" : "𝝚",
|
1139 |
-
"\\bsansZeta" : "𝝛",
|
1140 |
-
"\\bsansEta" : "𝝜",
|
1141 |
-
"\\bsansTheta" : "𝝝",
|
1142 |
-
"\\bsansIota" : "𝝞",
|
1143 |
-
"\\bsansKappa" : "𝝟",
|
1144 |
-
"\\bsansLambda" : "𝝠",
|
1145 |
-
"\\bsansMu" : "𝝡",
|
1146 |
-
"\\bsansNu" : "𝝢",
|
1147 |
-
"\\bsansXi" : "𝝣",
|
1148 |
-
"\\bsansOmicron" : "𝝤",
|
1149 |
-
"\\bsansPi" : "𝝥",
|
1150 |
-
"\\bsansRho" : "𝝦",
|
1151 |
-
"\\bsansvarTheta" : "𝝧",
|
1152 |
-
"\\bsansSigma" : "𝝨",
|
1153 |
-
"\\bsansTau" : "𝝩",
|
1154 |
-
"\\bsansUpsilon" : "𝝪",
|
1155 |
-
"\\bsansPhi" : "𝝫",
|
1156 |
-
"\\bsansChi" : "𝝬",
|
1157 |
-
"\\bsansPsi" : "𝝭",
|
1158 |
-
"\\bsansOmega" : "𝝮",
|
1159 |
-
"\\bsansalpha" : "𝝰",
|
1160 |
-
"\\bsansbeta" : "𝝱",
|
1161 |
-
"\\bsansgamma" : "𝝲",
|
1162 |
-
"\\bsansdelta" : "𝝳",
|
1163 |
-
"\\bsansepsilon" : "𝝴",
|
1164 |
-
"\\bsanszeta" : "𝝵",
|
1165 |
-
"\\bsanseta" : "𝝶",
|
1166 |
-
"\\bsanstheta" : "𝝷",
|
1167 |
-
"\\bsansiota" : "𝝸",
|
1168 |
-
"\\bsanskappa" : "𝝹",
|
1169 |
-
"\\bsanslambda" : "𝝺",
|
1170 |
-
"\\bsansmu" : "𝝻",
|
1171 |
-
"\\bsansnu" : "𝝼",
|
1172 |
-
"\\bsansxi" : "𝝽",
|
1173 |
-
"\\bsansomicron" : "𝝾",
|
1174 |
-
"\\bsanspi" : "𝝿",
|
1175 |
-
"\\bsansrho" : "𝞀",
|
1176 |
-
"\\bsansvarsigma" : "𝞁",
|
1177 |
-
"\\bsanssigma" : "𝞂",
|
1178 |
-
"\\bsanstau" : "𝞃",
|
1179 |
-
"\\bsansupsilon" : "𝞄",
|
1180 |
-
"\\bsansphi" : "𝞅",
|
1181 |
-
"\\bsanschi" : "𝞆",
|
1182 |
-
"\\bsanspsi" : "𝞇",
|
1183 |
-
"\\bsansomega" : "𝞈",
|
1184 |
-
"\\bsansvarepsilon" : "𝞊",
|
1185 |
-
"\\bsansvartheta" : "𝞋",
|
1186 |
-
"\\bsansvarkappa" : "𝞌",
|
1187 |
-
"\\bsansvarphi" : "𝞍",
|
1188 |
-
"\\bsansvarrho" : "𝞎",
|
1189 |
-
"\\bsansvarpi" : "𝞏",
|
1190 |
-
"\\bisansAlpha" : "𝞐",
|
1191 |
-
"\\bisansBeta" : "𝞑",
|
1192 |
-
"\\bisansGamma" : "𝞒",
|
1193 |
-
"\\bisansDelta" : "𝞓",
|
1194 |
-
"\\bisansEpsilon" : "𝞔",
|
1195 |
-
"\\bisansZeta" : "𝞕",
|
1196 |
-
"\\bisansEta" : "𝞖",
|
1197 |
-
"\\bisansTheta" : "𝞗",
|
1198 |
-
"\\bisansIota" : "𝞘",
|
1199 |
-
"\\bisansKappa" : "𝞙",
|
1200 |
-
"\\bisansLambda" : "𝞚",
|
1201 |
-
"\\bisansMu" : "𝞛",
|
1202 |
-
"\\bisansNu" : "𝞜",
|
1203 |
-
"\\bisansXi" : "𝞝",
|
1204 |
-
"\\bisansOmicron" : "𝞞",
|
1205 |
-
"\\bisansPi" : "𝞟",
|
1206 |
-
"\\bisansRho" : "𝞠",
|
1207 |
-
"\\bisansvarTheta" : "𝞡",
|
1208 |
-
"\\bisansSigma" : "𝞢",
|
1209 |
-
"\\bisansTau" : "𝞣",
|
1210 |
-
"\\bisansUpsilon" : "𝞤",
|
1211 |
-
"\\bisansPhi" : "𝞥",
|
1212 |
-
"\\bisansChi" : "𝞦",
|
1213 |
-
"\\bisansPsi" : "𝞧",
|
1214 |
-
"\\bisansOmega" : "𝞨",
|
1215 |
-
"\\bisansalpha" : "𝞪",
|
1216 |
-
"\\bisansbeta" : "𝞫",
|
1217 |
-
"\\bisansgamma" : "𝞬",
|
1218 |
-
"\\bisansdelta" : "𝞭",
|
1219 |
-
"\\bisansepsilon" : "𝞮",
|
1220 |
-
"\\bisanszeta" : "𝞯",
|
1221 |
-
"\\bisanseta" : "𝞰",
|
1222 |
-
"\\bisanstheta" : "𝞱",
|
1223 |
-
"\\bisansiota" : "𝞲",
|
1224 |
-
"\\bisanskappa" : "𝞳",
|
1225 |
-
"\\bisanslambda" : "𝞴",
|
1226 |
-
"\\bisansmu" : "𝞵",
|
1227 |
-
"\\bisansnu" : "𝞶",
|
1228 |
-
"\\bisansxi" : "𝞷",
|
1229 |
-
"\\bisansomicron" : "𝞸",
|
1230 |
-
"\\bisanspi" : "𝞹",
|
1231 |
-
"\\bisansrho" : "𝞺",
|
1232 |
-
"\\bisansvarsigma" : "𝞻",
|
1233 |
-
"\\bisanssigma" : "𝞼",
|
1234 |
-
"\\bisanstau" : "𝞽",
|
1235 |
-
"\\bisansupsilon" : "𝞾",
|
1236 |
-
"\\bisansphi" : "𝞿",
|
1237 |
-
"\\bisanschi" : "𝟀",
|
1238 |
-
"\\bisanspsi" : "𝟁",
|
1239 |
-
"\\bisansomega" : "𝟂",
|
1240 |
-
"\\bisansvarepsilon" : "𝟄",
|
1241 |
-
"\\bisansvartheta" : "𝟅",
|
1242 |
-
"\\bisansvarkappa" : "𝟆",
|
1243 |
-
"\\bisansvarphi" : "𝟇",
|
1244 |
-
"\\bisansvarrho" : "𝟈",
|
1245 |
-
"\\bisansvarpi" : "𝟉",
|
1246 |
-
"\\bfzero" : "𝟎",
|
1247 |
-
"\\bfone" : "𝟏",
|
1248 |
-
"\\bftwo" : "𝟐",
|
1249 |
-
"\\bfthree" : "𝟑",
|
1250 |
-
"\\bffour" : "𝟒",
|
1251 |
-
"\\bffive" : "𝟓",
|
1252 |
-
"\\bfsix" : "𝟔",
|
1253 |
-
"\\bfseven" : "𝟕",
|
1254 |
-
"\\bfeight" : "𝟖",
|
1255 |
-
"\\bfnine" : "𝟗",
|
1256 |
-
"\\bbzero" : "𝟘",
|
1257 |
-
"\\bbone" : "𝟙",
|
1258 |
-
"\\bbtwo" : "𝟚",
|
1259 |
-
"\\bbthree" : "𝟛",
|
1260 |
-
"\\bbfour" : "𝟜",
|
1261 |
-
"\\bbfive" : "𝟝",
|
1262 |
-
"\\bbsix" : "𝟞",
|
1263 |
-
"\\bbseven" : "𝟟",
|
1264 |
-
"\\bbeight" : "𝟠",
|
1265 |
-
"\\bbnine" : "𝟡",
|
1266 |
-
"\\sanszero" : "𝟢",
|
1267 |
-
"\\sansone" : "𝟣",
|
1268 |
-
"\\sanstwo" : "𝟤",
|
1269 |
-
"\\sansthree" : "𝟥",
|
1270 |
-
"\\sansfour" : "𝟦",
|
1271 |
-
"\\sansfive" : "𝟧",
|
1272 |
-
"\\sanssix" : "𝟨",
|
1273 |
-
"\\sansseven" : "𝟩",
|
1274 |
-
"\\sanseight" : "𝟪",
|
1275 |
-
"\\sansnine" : "𝟫",
|
1276 |
-
"\\bsanszero" : "𝟬",
|
1277 |
-
"\\bsansone" : "𝟭",
|
1278 |
-
"\\bsanstwo" : "𝟮",
|
1279 |
-
"\\bsansthree" : "𝟯",
|
1280 |
-
"\\bsansfour" : "𝟰",
|
1281 |
-
"\\bsansfive" : "𝟱",
|
1282 |
-
"\\bsanssix" : "𝟲",
|
1283 |
-
"\\bsansseven" : "𝟳",
|
1284 |
-
"\\bsanseight" : "𝟴",
|
1285 |
-
"\\bsansnine" : "𝟵",
|
1286 |
-
"\\ttzero" : "𝟶",
|
1287 |
-
"\\ttone" : "𝟷",
|
1288 |
-
"\\tttwo" : "𝟸",
|
1289 |
-
"\\ttthree" : "𝟹",
|
1290 |
-
"\\ttfour" : "𝟺",
|
1291 |
-
"\\ttfive" : "𝟻",
|
1292 |
-
"\\ttsix" : "𝟼",
|
1293 |
-
"\\ttseven" : "𝟽",
|
1294 |
-
"\\tteight" : "𝟾",
|
1295 |
-
"\\ttnine" : "𝟿",
|
1296 |
-
"\\underbar" : "̲",
|
1297 |
-
"\\underleftrightarrow" : "͍",
|
1298 |
-
}
|
1299 |
-
|
1300 |
-
|
1301 |
-
reverse_latex_symbol = { v:k for k,v in latex_symbols.items()}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/logger.py
DELETED
@@ -1,231 +0,0 @@
|
|
1 |
-
"""Logger class for IPython's logging facilities.
|
2 |
-
"""
|
3 |
-
|
4 |
-
#*****************************************************************************
|
5 |
-
# Copyright (C) 2001 Janko Hauser <[email protected]> and
|
6 |
-
# Copyright (C) 2001-2006 Fernando Perez <[email protected]>
|
7 |
-
#
|
8 |
-
# Distributed under the terms of the BSD License. The full license is in
|
9 |
-
# the file COPYING, distributed as part of this software.
|
10 |
-
#*****************************************************************************
|
11 |
-
|
12 |
-
#****************************************************************************
|
13 |
-
# Modules and globals
|
14 |
-
|
15 |
-
# Python standard modules
|
16 |
-
import glob
|
17 |
-
import io
|
18 |
-
import logging
|
19 |
-
import os
|
20 |
-
import time
|
21 |
-
|
22 |
-
|
23 |
-
# prevent jedi/parso's debug messages pipe into interactiveshell
|
24 |
-
logging.getLogger("parso").setLevel(logging.WARNING)
|
25 |
-
|
26 |
-
#****************************************************************************
|
27 |
-
# FIXME: This class isn't a mixin anymore, but it still needs attributes from
|
28 |
-
# ipython and does input cache management. Finish cleanup later...
|
29 |
-
|
30 |
-
class Logger(object):
|
31 |
-
"""A Logfile class with different policies for file creation"""
|
32 |
-
|
33 |
-
def __init__(self, home_dir, logfname='Logger.log', loghead=u'',
|
34 |
-
logmode='over'):
|
35 |
-
|
36 |
-
# this is the full ipython instance, we need some attributes from it
|
37 |
-
# which won't exist until later. What a mess, clean up later...
|
38 |
-
self.home_dir = home_dir
|
39 |
-
|
40 |
-
self.logfname = logfname
|
41 |
-
self.loghead = loghead
|
42 |
-
self.logmode = logmode
|
43 |
-
self.logfile = None
|
44 |
-
|
45 |
-
# Whether to log raw or processed input
|
46 |
-
self.log_raw_input = False
|
47 |
-
|
48 |
-
# whether to also log output
|
49 |
-
self.log_output = False
|
50 |
-
|
51 |
-
# whether to put timestamps before each log entry
|
52 |
-
self.timestamp = False
|
53 |
-
|
54 |
-
# activity control flags
|
55 |
-
self.log_active = False
|
56 |
-
|
57 |
-
# logmode is a validated property
|
58 |
-
def _set_mode(self,mode):
|
59 |
-
if mode not in ['append','backup','global','over','rotate']:
|
60 |
-
raise ValueError('invalid log mode %s given' % mode)
|
61 |
-
self._logmode = mode
|
62 |
-
|
63 |
-
def _get_mode(self):
|
64 |
-
return self._logmode
|
65 |
-
|
66 |
-
logmode = property(_get_mode,_set_mode)
|
67 |
-
|
68 |
-
def logstart(self, logfname=None, loghead=None, logmode=None,
|
69 |
-
log_output=False, timestamp=False, log_raw_input=False):
|
70 |
-
"""Generate a new log-file with a default header.
|
71 |
-
|
72 |
-
Raises RuntimeError if the log has already been started"""
|
73 |
-
|
74 |
-
if self.logfile is not None:
|
75 |
-
raise RuntimeError('Log file is already active: %s' %
|
76 |
-
self.logfname)
|
77 |
-
|
78 |
-
# The parameters can override constructor defaults
|
79 |
-
if logfname is not None: self.logfname = logfname
|
80 |
-
if loghead is not None: self.loghead = loghead
|
81 |
-
if logmode is not None: self.logmode = logmode
|
82 |
-
|
83 |
-
# Parameters not part of the constructor
|
84 |
-
self.timestamp = timestamp
|
85 |
-
self.log_output = log_output
|
86 |
-
self.log_raw_input = log_raw_input
|
87 |
-
|
88 |
-
# init depending on the log mode requested
|
89 |
-
isfile = os.path.isfile
|
90 |
-
logmode = self.logmode
|
91 |
-
|
92 |
-
if logmode == 'append':
|
93 |
-
self.logfile = io.open(self.logfname, 'a', encoding='utf-8')
|
94 |
-
|
95 |
-
elif logmode == 'backup':
|
96 |
-
if isfile(self.logfname):
|
97 |
-
backup_logname = self.logfname+'~'
|
98 |
-
# Manually remove any old backup, since os.rename may fail
|
99 |
-
# under Windows.
|
100 |
-
if isfile(backup_logname):
|
101 |
-
os.remove(backup_logname)
|
102 |
-
os.rename(self.logfname,backup_logname)
|
103 |
-
self.logfile = io.open(self.logfname, 'w', encoding='utf-8')
|
104 |
-
|
105 |
-
elif logmode == 'global':
|
106 |
-
self.logfname = os.path.join(self.home_dir,self.logfname)
|
107 |
-
self.logfile = io.open(self.logfname, 'a', encoding='utf-8')
|
108 |
-
|
109 |
-
elif logmode == 'over':
|
110 |
-
if isfile(self.logfname):
|
111 |
-
os.remove(self.logfname)
|
112 |
-
self.logfile = io.open(self.logfname,'w', encoding='utf-8')
|
113 |
-
|
114 |
-
elif logmode == 'rotate':
|
115 |
-
if isfile(self.logfname):
|
116 |
-
if isfile(self.logfname+'.001~'):
|
117 |
-
old = glob.glob(self.logfname+'.*~')
|
118 |
-
old.sort()
|
119 |
-
old.reverse()
|
120 |
-
for f in old:
|
121 |
-
root, ext = os.path.splitext(f)
|
122 |
-
num = int(ext[1:-1])+1
|
123 |
-
os.rename(f, root+'.'+repr(num).zfill(3)+'~')
|
124 |
-
os.rename(self.logfname, self.logfname+'.001~')
|
125 |
-
self.logfile = io.open(self.logfname, 'w', encoding='utf-8')
|
126 |
-
|
127 |
-
if logmode != 'append':
|
128 |
-
self.logfile.write(self.loghead)
|
129 |
-
|
130 |
-
self.logfile.flush()
|
131 |
-
self.log_active = True
|
132 |
-
|
133 |
-
def switch_log(self,val):
|
134 |
-
"""Switch logging on/off. val should be ONLY a boolean."""
|
135 |
-
|
136 |
-
if val not in [False,True,0,1]:
|
137 |
-
raise ValueError('Call switch_log ONLY with a boolean argument, '
|
138 |
-
'not with: %s' % val)
|
139 |
-
|
140 |
-
label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
|
141 |
-
|
142 |
-
if self.logfile is None:
|
143 |
-
print("""
|
144 |
-
Logging hasn't been started yet (use logstart for that).
|
145 |
-
|
146 |
-
%logon/%logoff are for temporarily starting and stopping logging for a logfile
|
147 |
-
which already exists. But you must first start the logging process with
|
148 |
-
%logstart (optionally giving a logfile name).""")
|
149 |
-
|
150 |
-
else:
|
151 |
-
if self.log_active == val:
|
152 |
-
print('Logging is already',label[val])
|
153 |
-
else:
|
154 |
-
print('Switching logging',label[val])
|
155 |
-
self.log_active = not self.log_active
|
156 |
-
self.log_active_out = self.log_active
|
157 |
-
|
158 |
-
def logstate(self):
|
159 |
-
"""Print a status message about the logger."""
|
160 |
-
if self.logfile is None:
|
161 |
-
print('Logging has not been activated.')
|
162 |
-
else:
|
163 |
-
state = self.log_active and 'active' or 'temporarily suspended'
|
164 |
-
print('Filename :', self.logfname)
|
165 |
-
print('Mode :', self.logmode)
|
166 |
-
print('Output logging :', self.log_output)
|
167 |
-
print('Raw input log :', self.log_raw_input)
|
168 |
-
print('Timestamping :', self.timestamp)
|
169 |
-
print('State :', state)
|
170 |
-
|
171 |
-
def log(self, line_mod, line_ori):
|
172 |
-
"""Write the sources to a log.
|
173 |
-
|
174 |
-
Inputs:
|
175 |
-
|
176 |
-
- line_mod: possibly modified input, such as the transformations made
|
177 |
-
by input prefilters or input handlers of various kinds. This should
|
178 |
-
always be valid Python.
|
179 |
-
|
180 |
-
- line_ori: unmodified input line from the user. This is not
|
181 |
-
necessarily valid Python.
|
182 |
-
"""
|
183 |
-
|
184 |
-
# Write the log line, but decide which one according to the
|
185 |
-
# log_raw_input flag, set when the log is started.
|
186 |
-
if self.log_raw_input:
|
187 |
-
self.log_write(line_ori)
|
188 |
-
else:
|
189 |
-
self.log_write(line_mod)
|
190 |
-
|
191 |
-
def log_write(self, data, kind='input'):
|
192 |
-
"""Write data to the log file, if active"""
|
193 |
-
|
194 |
-
# print('data: %r' % data) # dbg
|
195 |
-
if self.log_active and data:
|
196 |
-
write = self.logfile.write
|
197 |
-
if kind=='input':
|
198 |
-
if self.timestamp:
|
199 |
-
write(time.strftime('# %a, %d %b %Y %H:%M:%S\n', time.localtime()))
|
200 |
-
write(data)
|
201 |
-
elif kind=='output' and self.log_output:
|
202 |
-
odata = u'\n'.join([u'#[Out]# %s' % s
|
203 |
-
for s in data.splitlines()])
|
204 |
-
write(u'%s\n' % odata)
|
205 |
-
try:
|
206 |
-
self.logfile.flush()
|
207 |
-
except OSError:
|
208 |
-
print("Failed to flush the log file.")
|
209 |
-
print(
|
210 |
-
f"Please check that {self.logfname} exists and have the right permissions."
|
211 |
-
)
|
212 |
-
print(
|
213 |
-
"Also consider turning off the log with `%logstop` to avoid this warning."
|
214 |
-
)
|
215 |
-
|
216 |
-
def logstop(self):
|
217 |
-
"""Fully stop logging and close log file.
|
218 |
-
|
219 |
-
In order to start logging again, a new logstart() call needs to be
|
220 |
-
made, possibly (though not necessarily) with a new filename, mode and
|
221 |
-
other options."""
|
222 |
-
|
223 |
-
if self.logfile is not None:
|
224 |
-
self.logfile.close()
|
225 |
-
self.logfile = None
|
226 |
-
else:
|
227 |
-
print("Logging hadn't been started.")
|
228 |
-
self.log_active = False
|
229 |
-
|
230 |
-
# For backwards compatibility, in case anyone was using this.
|
231 |
-
close_log = logstop
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/macro.py
DELETED
@@ -1,53 +0,0 @@
|
|
1 |
-
"""Support for interactive macros in IPython"""
|
2 |
-
|
3 |
-
#*****************************************************************************
|
4 |
-
# Copyright (C) 2001-2005 Fernando Perez <[email protected]>
|
5 |
-
#
|
6 |
-
# Distributed under the terms of the BSD License. The full license is in
|
7 |
-
# the file COPYING, distributed as part of this software.
|
8 |
-
#*****************************************************************************
|
9 |
-
|
10 |
-
import re
|
11 |
-
|
12 |
-
from IPython.utils.encoding import DEFAULT_ENCODING
|
13 |
-
|
14 |
-
coding_declaration = re.compile(r"#\s*coding[:=]\s*([-\w.]+)")
|
15 |
-
|
16 |
-
class Macro(object):
|
17 |
-
"""Simple class to store the value of macros as strings.
|
18 |
-
|
19 |
-
Macro is just a callable that executes a string of IPython
|
20 |
-
input when called.
|
21 |
-
"""
|
22 |
-
|
23 |
-
def __init__(self,code):
|
24 |
-
"""store the macro value, as a single string which can be executed"""
|
25 |
-
lines = []
|
26 |
-
enc = None
|
27 |
-
for line in code.splitlines():
|
28 |
-
coding_match = coding_declaration.match(line)
|
29 |
-
if coding_match:
|
30 |
-
enc = coding_match.group(1)
|
31 |
-
else:
|
32 |
-
lines.append(line)
|
33 |
-
code = "\n".join(lines)
|
34 |
-
if isinstance(code, bytes):
|
35 |
-
code = code.decode(enc or DEFAULT_ENCODING)
|
36 |
-
self.value = code + '\n'
|
37 |
-
|
38 |
-
def __str__(self):
|
39 |
-
return self.value
|
40 |
-
|
41 |
-
def __repr__(self):
|
42 |
-
return 'IPython.macro.Macro(%s)' % repr(self.value)
|
43 |
-
|
44 |
-
def __getstate__(self):
|
45 |
-
""" needed for safe pickling via %store """
|
46 |
-
return {'value': self.value}
|
47 |
-
|
48 |
-
def __add__(self, other):
|
49 |
-
if isinstance(other, Macro):
|
50 |
-
return Macro(self.value + other.value)
|
51 |
-
elif isinstance(other, str):
|
52 |
-
return Macro(self.value + other)
|
53 |
-
raise TypeError
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magic.py
DELETED
@@ -1,759 +0,0 @@
|
|
1 |
-
# encoding: utf-8
|
2 |
-
"""Magic functions for InteractiveShell.
|
3 |
-
"""
|
4 |
-
|
5 |
-
#-----------------------------------------------------------------------------
|
6 |
-
# Copyright (C) 2001 Janko Hauser <[email protected]> and
|
7 |
-
# Copyright (C) 2001 Fernando Perez <[email protected]>
|
8 |
-
# Copyright (C) 2008 The IPython Development Team
|
9 |
-
|
10 |
-
# Distributed under the terms of the BSD License. The full license is in
|
11 |
-
# the file COPYING, distributed as part of this software.
|
12 |
-
#-----------------------------------------------------------------------------
|
13 |
-
|
14 |
-
import os
|
15 |
-
import re
|
16 |
-
import sys
|
17 |
-
from getopt import getopt, GetoptError
|
18 |
-
|
19 |
-
from traitlets.config.configurable import Configurable
|
20 |
-
from . import oinspect
|
21 |
-
from .error import UsageError
|
22 |
-
from .inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
|
23 |
-
from ..utils.ipstruct import Struct
|
24 |
-
from ..utils.process import arg_split
|
25 |
-
from ..utils.text import dedent
|
26 |
-
from traitlets import Bool, Dict, Instance, observe
|
27 |
-
from logging import error
|
28 |
-
|
29 |
-
import typing as t
|
30 |
-
|
31 |
-
#-----------------------------------------------------------------------------
|
32 |
-
# Globals
|
33 |
-
#-----------------------------------------------------------------------------
|
34 |
-
|
35 |
-
# A dict we'll use for each class that has magics, used as temporary storage to
|
36 |
-
# pass information between the @line/cell_magic method decorators and the
|
37 |
-
# @magics_class class decorator, because the method decorators have no
|
38 |
-
# access to the class when they run. See for more details:
|
39 |
-
# http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
|
40 |
-
|
41 |
-
magics: t.Dict = dict(line={}, cell={})
|
42 |
-
|
43 |
-
magic_kinds = ('line', 'cell')
|
44 |
-
magic_spec = ('line', 'cell', 'line_cell')
|
45 |
-
magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
|
46 |
-
|
47 |
-
#-----------------------------------------------------------------------------
|
48 |
-
# Utility classes and functions
|
49 |
-
#-----------------------------------------------------------------------------
|
50 |
-
|
51 |
-
class Bunch: pass
|
52 |
-
|
53 |
-
|
54 |
-
def on_off(tag):
|
55 |
-
"""Return an ON/OFF string for a 1/0 input. Simple utility function."""
|
56 |
-
return ['OFF','ON'][tag]
|
57 |
-
|
58 |
-
|
59 |
-
def compress_dhist(dh):
|
60 |
-
"""Compress a directory history into a new one with at most 20 entries.
|
61 |
-
|
62 |
-
Return a new list made from the first and last 10 elements of dhist after
|
63 |
-
removal of duplicates.
|
64 |
-
"""
|
65 |
-
head, tail = dh[:-10], dh[-10:]
|
66 |
-
|
67 |
-
newhead = []
|
68 |
-
done = set()
|
69 |
-
for h in head:
|
70 |
-
if h in done:
|
71 |
-
continue
|
72 |
-
newhead.append(h)
|
73 |
-
done.add(h)
|
74 |
-
|
75 |
-
return newhead + tail
|
76 |
-
|
77 |
-
|
78 |
-
def needs_local_scope(func):
|
79 |
-
"""Decorator to mark magic functions which need to local scope to run."""
|
80 |
-
func.needs_local_scope = True
|
81 |
-
return func
|
82 |
-
|
83 |
-
#-----------------------------------------------------------------------------
|
84 |
-
# Class and method decorators for registering magics
|
85 |
-
#-----------------------------------------------------------------------------
|
86 |
-
|
87 |
-
def magics_class(cls):
|
88 |
-
"""Class decorator for all subclasses of the main Magics class.
|
89 |
-
|
90 |
-
Any class that subclasses Magics *must* also apply this decorator, to
|
91 |
-
ensure that all the methods that have been decorated as line/cell magics
|
92 |
-
get correctly registered in the class instance. This is necessary because
|
93 |
-
when method decorators run, the class does not exist yet, so they
|
94 |
-
temporarily store their information into a module global. Application of
|
95 |
-
this class decorator copies that global data to the class instance and
|
96 |
-
clears the global.
|
97 |
-
|
98 |
-
Obviously, this mechanism is not thread-safe, which means that the
|
99 |
-
*creation* of subclasses of Magic should only be done in a single-thread
|
100 |
-
context. Instantiation of the classes has no restrictions. Given that
|
101 |
-
these classes are typically created at IPython startup time and before user
|
102 |
-
application code becomes active, in practice this should not pose any
|
103 |
-
problems.
|
104 |
-
"""
|
105 |
-
cls.registered = True
|
106 |
-
cls.magics = dict(line = magics['line'],
|
107 |
-
cell = magics['cell'])
|
108 |
-
magics['line'] = {}
|
109 |
-
magics['cell'] = {}
|
110 |
-
return cls
|
111 |
-
|
112 |
-
|
113 |
-
def record_magic(dct, magic_kind, magic_name, func):
|
114 |
-
"""Utility function to store a function as a magic of a specific kind.
|
115 |
-
|
116 |
-
Parameters
|
117 |
-
----------
|
118 |
-
dct : dict
|
119 |
-
A dictionary with 'line' and 'cell' subdicts.
|
120 |
-
magic_kind : str
|
121 |
-
Kind of magic to be stored.
|
122 |
-
magic_name : str
|
123 |
-
Key to store the magic as.
|
124 |
-
func : function
|
125 |
-
Callable object to store.
|
126 |
-
"""
|
127 |
-
if magic_kind == 'line_cell':
|
128 |
-
dct['line'][magic_name] = dct['cell'][magic_name] = func
|
129 |
-
else:
|
130 |
-
dct[magic_kind][magic_name] = func
|
131 |
-
|
132 |
-
|
133 |
-
def validate_type(magic_kind):
|
134 |
-
"""Ensure that the given magic_kind is valid.
|
135 |
-
|
136 |
-
Check that the given magic_kind is one of the accepted spec types (stored
|
137 |
-
in the global `magic_spec`), raise ValueError otherwise.
|
138 |
-
"""
|
139 |
-
if magic_kind not in magic_spec:
|
140 |
-
raise ValueError('magic_kind must be one of %s, %s given' %
|
141 |
-
magic_kinds, magic_kind)
|
142 |
-
|
143 |
-
|
144 |
-
# The docstrings for the decorator below will be fairly similar for the two
|
145 |
-
# types (method and function), so we generate them here once and reuse the
|
146 |
-
# templates below.
|
147 |
-
_docstring_template = \
|
148 |
-
"""Decorate the given {0} as {1} magic.
|
149 |
-
|
150 |
-
The decorator can be used with or without arguments, as follows.
|
151 |
-
|
152 |
-
i) without arguments: it will create a {1} magic named as the {0} being
|
153 |
-
decorated::
|
154 |
-
|
155 |
-
@deco
|
156 |
-
def foo(...)
|
157 |
-
|
158 |
-
will create a {1} magic named `foo`.
|
159 |
-
|
160 |
-
ii) with one string argument: which will be used as the actual name of the
|
161 |
-
resulting magic::
|
162 |
-
|
163 |
-
@deco('bar')
|
164 |
-
def foo(...)
|
165 |
-
|
166 |
-
will create a {1} magic named `bar`.
|
167 |
-
|
168 |
-
To register a class magic use ``Interactiveshell.register_magic(class or instance)``.
|
169 |
-
"""
|
170 |
-
|
171 |
-
# These two are decorator factories. While they are conceptually very similar,
|
172 |
-
# there are enough differences in the details that it's simpler to have them
|
173 |
-
# written as completely standalone functions rather than trying to share code
|
174 |
-
# and make a single one with convoluted logic.
|
175 |
-
|
176 |
-
def _method_magic_marker(magic_kind):
|
177 |
-
"""Decorator factory for methods in Magics subclasses.
|
178 |
-
"""
|
179 |
-
|
180 |
-
validate_type(magic_kind)
|
181 |
-
|
182 |
-
# This is a closure to capture the magic_kind. We could also use a class,
|
183 |
-
# but it's overkill for just that one bit of state.
|
184 |
-
def magic_deco(arg):
|
185 |
-
if callable(arg):
|
186 |
-
# "Naked" decorator call (just @foo, no args)
|
187 |
-
func = arg
|
188 |
-
name = func.__name__
|
189 |
-
retval = arg
|
190 |
-
record_magic(magics, magic_kind, name, name)
|
191 |
-
elif isinstance(arg, str):
|
192 |
-
# Decorator called with arguments (@foo('bar'))
|
193 |
-
name = arg
|
194 |
-
def mark(func, *a, **kw):
|
195 |
-
record_magic(magics, magic_kind, name, func.__name__)
|
196 |
-
return func
|
197 |
-
retval = mark
|
198 |
-
else:
|
199 |
-
raise TypeError("Decorator can only be called with "
|
200 |
-
"string or function")
|
201 |
-
return retval
|
202 |
-
|
203 |
-
# Ensure the resulting decorator has a usable docstring
|
204 |
-
magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
|
205 |
-
return magic_deco
|
206 |
-
|
207 |
-
|
208 |
-
def _function_magic_marker(magic_kind):
|
209 |
-
"""Decorator factory for standalone functions.
|
210 |
-
"""
|
211 |
-
validate_type(magic_kind)
|
212 |
-
|
213 |
-
# This is a closure to capture the magic_kind. We could also use a class,
|
214 |
-
# but it's overkill for just that one bit of state.
|
215 |
-
def magic_deco(arg):
|
216 |
-
# Find get_ipython() in the caller's namespace
|
217 |
-
caller = sys._getframe(1)
|
218 |
-
for ns in ['f_locals', 'f_globals', 'f_builtins']:
|
219 |
-
get_ipython = getattr(caller, ns).get('get_ipython')
|
220 |
-
if get_ipython is not None:
|
221 |
-
break
|
222 |
-
else:
|
223 |
-
raise NameError('Decorator can only run in context where '
|
224 |
-
'`get_ipython` exists')
|
225 |
-
|
226 |
-
ip = get_ipython()
|
227 |
-
|
228 |
-
if callable(arg):
|
229 |
-
# "Naked" decorator call (just @foo, no args)
|
230 |
-
func = arg
|
231 |
-
name = func.__name__
|
232 |
-
ip.register_magic_function(func, magic_kind, name)
|
233 |
-
retval = arg
|
234 |
-
elif isinstance(arg, str):
|
235 |
-
# Decorator called with arguments (@foo('bar'))
|
236 |
-
name = arg
|
237 |
-
def mark(func, *a, **kw):
|
238 |
-
ip.register_magic_function(func, magic_kind, name)
|
239 |
-
return func
|
240 |
-
retval = mark
|
241 |
-
else:
|
242 |
-
raise TypeError("Decorator can only be called with "
|
243 |
-
"string or function")
|
244 |
-
return retval
|
245 |
-
|
246 |
-
# Ensure the resulting decorator has a usable docstring
|
247 |
-
ds = _docstring_template.format('function', magic_kind)
|
248 |
-
|
249 |
-
ds += dedent("""
|
250 |
-
Note: this decorator can only be used in a context where IPython is already
|
251 |
-
active, so that the `get_ipython()` call succeeds. You can therefore use
|
252 |
-
it in your startup files loaded after IPython initializes, but *not* in the
|
253 |
-
IPython configuration file itself, which is executed before IPython is
|
254 |
-
fully up and running. Any file located in the `startup` subdirectory of
|
255 |
-
your configuration profile will be OK in this sense.
|
256 |
-
""")
|
257 |
-
|
258 |
-
magic_deco.__doc__ = ds
|
259 |
-
return magic_deco
|
260 |
-
|
261 |
-
|
262 |
-
MAGIC_NO_VAR_EXPAND_ATTR = "_ipython_magic_no_var_expand"
|
263 |
-
MAGIC_OUTPUT_CAN_BE_SILENCED = "_ipython_magic_output_can_be_silenced"
|
264 |
-
|
265 |
-
|
266 |
-
def no_var_expand(magic_func):
|
267 |
-
"""Mark a magic function as not needing variable expansion
|
268 |
-
|
269 |
-
By default, IPython interprets `{a}` or `$a` in the line passed to magics
|
270 |
-
as variables that should be interpolated from the interactive namespace
|
271 |
-
before passing the line to the magic function.
|
272 |
-
This is not always desirable, e.g. when the magic executes Python code
|
273 |
-
(%timeit, %time, etc.).
|
274 |
-
Decorate magics with `@no_var_expand` to opt-out of variable expansion.
|
275 |
-
|
276 |
-
.. versionadded:: 7.3
|
277 |
-
"""
|
278 |
-
setattr(magic_func, MAGIC_NO_VAR_EXPAND_ATTR, True)
|
279 |
-
return magic_func
|
280 |
-
|
281 |
-
|
282 |
-
def output_can_be_silenced(magic_func):
|
283 |
-
"""Mark a magic function so its output may be silenced.
|
284 |
-
|
285 |
-
The output is silenced if the Python code used as a parameter of
|
286 |
-
the magic ends in a semicolon, not counting a Python comment that can
|
287 |
-
follow it.
|
288 |
-
"""
|
289 |
-
setattr(magic_func, MAGIC_OUTPUT_CAN_BE_SILENCED, True)
|
290 |
-
return magic_func
|
291 |
-
|
292 |
-
# Create the actual decorators for public use
|
293 |
-
|
294 |
-
# These three are used to decorate methods in class definitions
|
295 |
-
line_magic = _method_magic_marker('line')
|
296 |
-
cell_magic = _method_magic_marker('cell')
|
297 |
-
line_cell_magic = _method_magic_marker('line_cell')
|
298 |
-
|
299 |
-
# These three decorate standalone functions and perform the decoration
|
300 |
-
# immediately. They can only run where get_ipython() works
|
301 |
-
register_line_magic = _function_magic_marker('line')
|
302 |
-
register_cell_magic = _function_magic_marker('cell')
|
303 |
-
register_line_cell_magic = _function_magic_marker('line_cell')
|
304 |
-
|
305 |
-
#-----------------------------------------------------------------------------
|
306 |
-
# Core Magic classes
|
307 |
-
#-----------------------------------------------------------------------------
|
308 |
-
|
309 |
-
class MagicsManager(Configurable):
|
310 |
-
"""Object that handles all magic-related functionality for IPython.
|
311 |
-
"""
|
312 |
-
# Non-configurable class attributes
|
313 |
-
|
314 |
-
# A two-level dict, first keyed by magic type, then by magic function, and
|
315 |
-
# holding the actual callable object as value. This is the dict used for
|
316 |
-
# magic function dispatch
|
317 |
-
magics = Dict()
|
318 |
-
lazy_magics = Dict(
|
319 |
-
help="""
|
320 |
-
Mapping from magic names to modules to load.
|
321 |
-
|
322 |
-
This can be used in IPython/IPykernel configuration to declare lazy magics
|
323 |
-
that will only be imported/registered on first use.
|
324 |
-
|
325 |
-
For example::
|
326 |
-
|
327 |
-
c.MagicsManager.lazy_magics = {
|
328 |
-
"my_magic": "slow.to.import",
|
329 |
-
"my_other_magic": "also.slow",
|
330 |
-
}
|
331 |
-
|
332 |
-
On first invocation of `%my_magic`, `%%my_magic`, `%%my_other_magic` or
|
333 |
-
`%%my_other_magic`, the corresponding module will be loaded as an ipython
|
334 |
-
extensions as if you had previously done `%load_ext ipython`.
|
335 |
-
|
336 |
-
Magics names should be without percent(s) as magics can be both cell
|
337 |
-
and line magics.
|
338 |
-
|
339 |
-
Lazy loading happen relatively late in execution process, and
|
340 |
-
complex extensions that manipulate Python/IPython internal state or global state
|
341 |
-
might not support lazy loading.
|
342 |
-
"""
|
343 |
-
).tag(
|
344 |
-
config=True,
|
345 |
-
)
|
346 |
-
|
347 |
-
# A registry of the original objects that we've been given holding magics.
|
348 |
-
registry = Dict()
|
349 |
-
|
350 |
-
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
|
351 |
-
|
352 |
-
auto_magic = Bool(True, help=
|
353 |
-
"Automatically call line magics without requiring explicit % prefix"
|
354 |
-
).tag(config=True)
|
355 |
-
@observe('auto_magic')
|
356 |
-
def _auto_magic_changed(self, change):
|
357 |
-
self.shell.automagic = change['new']
|
358 |
-
|
359 |
-
_auto_status = [
|
360 |
-
'Automagic is OFF, % prefix IS needed for line magics.',
|
361 |
-
'Automagic is ON, % prefix IS NOT needed for line magics.']
|
362 |
-
|
363 |
-
user_magics = Instance('IPython.core.magics.UserMagics', allow_none=True)
|
364 |
-
|
365 |
-
def __init__(self, shell=None, config=None, user_magics=None, **traits):
|
366 |
-
|
367 |
-
super(MagicsManager, self).__init__(shell=shell, config=config,
|
368 |
-
user_magics=user_magics, **traits)
|
369 |
-
self.magics = dict(line={}, cell={})
|
370 |
-
# Let's add the user_magics to the registry for uniformity, so *all*
|
371 |
-
# registered magic containers can be found there.
|
372 |
-
self.registry[user_magics.__class__.__name__] = user_magics
|
373 |
-
|
374 |
-
def auto_status(self):
|
375 |
-
"""Return descriptive string with automagic status."""
|
376 |
-
return self._auto_status[self.auto_magic]
|
377 |
-
|
378 |
-
def lsmagic(self):
|
379 |
-
"""Return a dict of currently available magic functions.
|
380 |
-
|
381 |
-
The return dict has the keys 'line' and 'cell', corresponding to the
|
382 |
-
two types of magics we support. Each value is a list of names.
|
383 |
-
"""
|
384 |
-
return self.magics
|
385 |
-
|
386 |
-
def lsmagic_docs(self, brief=False, missing=''):
|
387 |
-
"""Return dict of documentation of magic functions.
|
388 |
-
|
389 |
-
The return dict has the keys 'line' and 'cell', corresponding to the
|
390 |
-
two types of magics we support. Each value is a dict keyed by magic
|
391 |
-
name whose value is the function docstring. If a docstring is
|
392 |
-
unavailable, the value of `missing` is used instead.
|
393 |
-
|
394 |
-
If brief is True, only the first line of each docstring will be returned.
|
395 |
-
"""
|
396 |
-
docs = {}
|
397 |
-
for m_type in self.magics:
|
398 |
-
m_docs = {}
|
399 |
-
for m_name, m_func in self.magics[m_type].items():
|
400 |
-
if m_func.__doc__:
|
401 |
-
if brief:
|
402 |
-
m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
|
403 |
-
else:
|
404 |
-
m_docs[m_name] = m_func.__doc__.rstrip()
|
405 |
-
else:
|
406 |
-
m_docs[m_name] = missing
|
407 |
-
docs[m_type] = m_docs
|
408 |
-
return docs
|
409 |
-
|
410 |
-
def register_lazy(self, name: str, fully_qualified_name: str):
|
411 |
-
"""
|
412 |
-
Lazily register a magic via an extension.
|
413 |
-
|
414 |
-
|
415 |
-
Parameters
|
416 |
-
----------
|
417 |
-
name : str
|
418 |
-
Name of the magic you wish to register.
|
419 |
-
fully_qualified_name :
|
420 |
-
Fully qualified name of the module/submodule that should be loaded
|
421 |
-
as an extensions when the magic is first called.
|
422 |
-
It is assumed that loading this extensions will register the given
|
423 |
-
magic.
|
424 |
-
"""
|
425 |
-
|
426 |
-
self.lazy_magics[name] = fully_qualified_name
|
427 |
-
|
428 |
-
def register(self, *magic_objects):
|
429 |
-
"""Register one or more instances of Magics.
|
430 |
-
|
431 |
-
Take one or more classes or instances of classes that subclass the main
|
432 |
-
`core.Magic` class, and register them with IPython to use the magic
|
433 |
-
functions they provide. The registration process will then ensure that
|
434 |
-
any methods that have decorated to provide line and/or cell magics will
|
435 |
-
be recognized with the `%x`/`%%x` syntax as a line/cell magic
|
436 |
-
respectively.
|
437 |
-
|
438 |
-
If classes are given, they will be instantiated with the default
|
439 |
-
constructor. If your classes need a custom constructor, you should
|
440 |
-
instanitate them first and pass the instance.
|
441 |
-
|
442 |
-
The provided arguments can be an arbitrary mix of classes and instances.
|
443 |
-
|
444 |
-
Parameters
|
445 |
-
----------
|
446 |
-
*magic_objects : one or more classes or instances
|
447 |
-
"""
|
448 |
-
# Start by validating them to ensure they have all had their magic
|
449 |
-
# methods registered at the instance level
|
450 |
-
for m in magic_objects:
|
451 |
-
if not m.registered:
|
452 |
-
raise ValueError("Class of magics %r was constructed without "
|
453 |
-
"the @register_magics class decorator")
|
454 |
-
if isinstance(m, type):
|
455 |
-
# If we're given an uninstantiated class
|
456 |
-
m = m(shell=self.shell)
|
457 |
-
|
458 |
-
# Now that we have an instance, we can register it and update the
|
459 |
-
# table of callables
|
460 |
-
self.registry[m.__class__.__name__] = m
|
461 |
-
for mtype in magic_kinds:
|
462 |
-
self.magics[mtype].update(m.magics[mtype])
|
463 |
-
|
464 |
-
def register_function(self, func, magic_kind='line', magic_name=None):
|
465 |
-
"""Expose a standalone function as magic function for IPython.
|
466 |
-
|
467 |
-
This will create an IPython magic (line, cell or both) from a
|
468 |
-
standalone function. The functions should have the following
|
469 |
-
signatures:
|
470 |
-
|
471 |
-
* For line magics: `def f(line)`
|
472 |
-
* For cell magics: `def f(line, cell)`
|
473 |
-
* For a function that does both: `def f(line, cell=None)`
|
474 |
-
|
475 |
-
In the latter case, the function will be called with `cell==None` when
|
476 |
-
invoked as `%f`, and with cell as a string when invoked as `%%f`.
|
477 |
-
|
478 |
-
Parameters
|
479 |
-
----------
|
480 |
-
func : callable
|
481 |
-
Function to be registered as a magic.
|
482 |
-
magic_kind : str
|
483 |
-
Kind of magic, one of 'line', 'cell' or 'line_cell'
|
484 |
-
magic_name : optional str
|
485 |
-
If given, the name the magic will have in the IPython namespace. By
|
486 |
-
default, the name of the function itself is used.
|
487 |
-
"""
|
488 |
-
|
489 |
-
# Create the new method in the user_magics and register it in the
|
490 |
-
# global table
|
491 |
-
validate_type(magic_kind)
|
492 |
-
magic_name = func.__name__ if magic_name is None else magic_name
|
493 |
-
setattr(self.user_magics, magic_name, func)
|
494 |
-
record_magic(self.magics, magic_kind, magic_name, func)
|
495 |
-
|
496 |
-
def register_alias(self, alias_name, magic_name, magic_kind='line', magic_params=None):
|
497 |
-
"""Register an alias to a magic function.
|
498 |
-
|
499 |
-
The alias is an instance of :class:`MagicAlias`, which holds the
|
500 |
-
name and kind of the magic it should call. Binding is done at
|
501 |
-
call time, so if the underlying magic function is changed the alias
|
502 |
-
will call the new function.
|
503 |
-
|
504 |
-
Parameters
|
505 |
-
----------
|
506 |
-
alias_name : str
|
507 |
-
The name of the magic to be registered.
|
508 |
-
magic_name : str
|
509 |
-
The name of an existing magic.
|
510 |
-
magic_kind : str
|
511 |
-
Kind of magic, one of 'line' or 'cell'
|
512 |
-
"""
|
513 |
-
|
514 |
-
# `validate_type` is too permissive, as it allows 'line_cell'
|
515 |
-
# which we do not handle.
|
516 |
-
if magic_kind not in magic_kinds:
|
517 |
-
raise ValueError('magic_kind must be one of %s, %s given' %
|
518 |
-
magic_kinds, magic_kind)
|
519 |
-
|
520 |
-
alias = MagicAlias(self.shell, magic_name, magic_kind, magic_params)
|
521 |
-
setattr(self.user_magics, alias_name, alias)
|
522 |
-
record_magic(self.magics, magic_kind, alias_name, alias)
|
523 |
-
|
524 |
-
# Key base class that provides the central functionality for magics.
|
525 |
-
|
526 |
-
|
527 |
-
class Magics(Configurable):
|
528 |
-
"""Base class for implementing magic functions.
|
529 |
-
|
530 |
-
Shell functions which can be reached as %function_name. All magic
|
531 |
-
functions should accept a string, which they can parse for their own
|
532 |
-
needs. This can make some functions easier to type, eg `%cd ../`
|
533 |
-
vs. `%cd("../")`
|
534 |
-
|
535 |
-
Classes providing magic functions need to subclass this class, and they
|
536 |
-
MUST:
|
537 |
-
|
538 |
-
- Use the method decorators `@line_magic` and `@cell_magic` to decorate
|
539 |
-
individual methods as magic functions, AND
|
540 |
-
|
541 |
-
- Use the class decorator `@magics_class` to ensure that the magic
|
542 |
-
methods are properly registered at the instance level upon instance
|
543 |
-
initialization.
|
544 |
-
|
545 |
-
See :mod:`magic_functions` for examples of actual implementation classes.
|
546 |
-
"""
|
547 |
-
# Dict holding all command-line options for each magic.
|
548 |
-
options_table = None
|
549 |
-
# Dict for the mapping of magic names to methods, set by class decorator
|
550 |
-
magics = None
|
551 |
-
# Flag to check that the class decorator was properly applied
|
552 |
-
registered = False
|
553 |
-
# Instance of IPython shell
|
554 |
-
shell = None
|
555 |
-
|
556 |
-
def __init__(self, shell=None, **kwargs):
|
557 |
-
if not(self.__class__.registered):
|
558 |
-
raise ValueError('Magics subclass without registration - '
|
559 |
-
'did you forget to apply @magics_class?')
|
560 |
-
if shell is not None:
|
561 |
-
if hasattr(shell, 'configurables'):
|
562 |
-
shell.configurables.append(self)
|
563 |
-
if hasattr(shell, 'config'):
|
564 |
-
kwargs.setdefault('parent', shell)
|
565 |
-
|
566 |
-
self.shell = shell
|
567 |
-
self.options_table = {}
|
568 |
-
# The method decorators are run when the instance doesn't exist yet, so
|
569 |
-
# they can only record the names of the methods they are supposed to
|
570 |
-
# grab. Only now, that the instance exists, can we create the proper
|
571 |
-
# mapping to bound methods. So we read the info off the original names
|
572 |
-
# table and replace each method name by the actual bound method.
|
573 |
-
# But we mustn't clobber the *class* mapping, in case of multiple instances.
|
574 |
-
class_magics = self.magics
|
575 |
-
self.magics = {}
|
576 |
-
for mtype in magic_kinds:
|
577 |
-
tab = self.magics[mtype] = {}
|
578 |
-
cls_tab = class_magics[mtype]
|
579 |
-
for magic_name, meth_name in cls_tab.items():
|
580 |
-
if isinstance(meth_name, str):
|
581 |
-
# it's a method name, grab it
|
582 |
-
tab[magic_name] = getattr(self, meth_name)
|
583 |
-
else:
|
584 |
-
# it's the real thing
|
585 |
-
tab[magic_name] = meth_name
|
586 |
-
# Configurable **needs** to be initiated at the end or the config
|
587 |
-
# magics get screwed up.
|
588 |
-
super(Magics, self).__init__(**kwargs)
|
589 |
-
|
590 |
-
def arg_err(self,func):
|
591 |
-
"""Print docstring if incorrect arguments were passed"""
|
592 |
-
print('Error in arguments:')
|
593 |
-
print(oinspect.getdoc(func))
|
594 |
-
|
595 |
-
def format_latex(self, strng):
|
596 |
-
"""Format a string for latex inclusion."""
|
597 |
-
|
598 |
-
# Characters that need to be escaped for latex:
|
599 |
-
escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
|
600 |
-
# Magic command names as headers:
|
601 |
-
cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
|
602 |
-
re.MULTILINE)
|
603 |
-
# Magic commands
|
604 |
-
cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
|
605 |
-
re.MULTILINE)
|
606 |
-
# Paragraph continue
|
607 |
-
par_re = re.compile(r'\\$',re.MULTILINE)
|
608 |
-
|
609 |
-
# The "\n" symbol
|
610 |
-
newline_re = re.compile(r'\\n')
|
611 |
-
|
612 |
-
# Now build the string for output:
|
613 |
-
#strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
|
614 |
-
strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
|
615 |
-
strng)
|
616 |
-
strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
|
617 |
-
strng = par_re.sub(r'\\\\',strng)
|
618 |
-
strng = escape_re.sub(r'\\\1',strng)
|
619 |
-
strng = newline_re.sub(r'\\textbackslash{}n',strng)
|
620 |
-
return strng
|
621 |
-
|
622 |
-
def parse_options(self, arg_str, opt_str, *long_opts, **kw):
|
623 |
-
"""Parse options passed to an argument string.
|
624 |
-
|
625 |
-
The interface is similar to that of :func:`getopt.getopt`, but it
|
626 |
-
returns a :class:`~IPython.utils.struct.Struct` with the options as keys
|
627 |
-
and the stripped argument string still as a string.
|
628 |
-
|
629 |
-
arg_str is quoted as a true sys.argv vector by using shlex.split.
|
630 |
-
This allows us to easily expand variables, glob files, quote
|
631 |
-
arguments, etc.
|
632 |
-
|
633 |
-
Parameters
|
634 |
-
----------
|
635 |
-
arg_str : str
|
636 |
-
The arguments to parse.
|
637 |
-
opt_str : str
|
638 |
-
The options specification.
|
639 |
-
mode : str, default 'string'
|
640 |
-
If given as 'list', the argument string is returned as a list (split
|
641 |
-
on whitespace) instead of a string.
|
642 |
-
list_all : bool, default False
|
643 |
-
Put all option values in lists. Normally only options
|
644 |
-
appearing more than once are put in a list.
|
645 |
-
posix : bool, default True
|
646 |
-
Whether to split the input line in POSIX mode or not, as per the
|
647 |
-
conventions outlined in the :mod:`shlex` module from the standard
|
648 |
-
library.
|
649 |
-
"""
|
650 |
-
|
651 |
-
# inject default options at the beginning of the input line
|
652 |
-
caller = sys._getframe(1).f_code.co_name
|
653 |
-
arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
|
654 |
-
|
655 |
-
mode = kw.get('mode','string')
|
656 |
-
if mode not in ['string','list']:
|
657 |
-
raise ValueError('incorrect mode given: %s' % mode)
|
658 |
-
# Get options
|
659 |
-
list_all = kw.get('list_all',0)
|
660 |
-
posix = kw.get('posix', os.name == 'posix')
|
661 |
-
strict = kw.get('strict', True)
|
662 |
-
|
663 |
-
preserve_non_opts = kw.get("preserve_non_opts", False)
|
664 |
-
remainder_arg_str = arg_str
|
665 |
-
|
666 |
-
# Check if we have more than one argument to warrant extra processing:
|
667 |
-
odict = {} # Dictionary with options
|
668 |
-
args = arg_str.split()
|
669 |
-
if len(args) >= 1:
|
670 |
-
# If the list of inputs only has 0 or 1 thing in it, there's no
|
671 |
-
# need to look for options
|
672 |
-
argv = arg_split(arg_str, posix, strict)
|
673 |
-
# Do regular option processing
|
674 |
-
try:
|
675 |
-
opts,args = getopt(argv, opt_str, long_opts)
|
676 |
-
except GetoptError as e:
|
677 |
-
raise UsageError(
|
678 |
-
'%s ( allowed: "%s" %s)' % (e.msg, opt_str, " ".join(long_opts))
|
679 |
-
) from e
|
680 |
-
for o, a in opts:
|
681 |
-
if mode == "string" and preserve_non_opts:
|
682 |
-
# remove option-parts from the original args-string and preserve remaining-part.
|
683 |
-
# This relies on the arg_split(...) and getopt(...)'s impl spec, that the parsed options are
|
684 |
-
# returned in the original order.
|
685 |
-
remainder_arg_str = remainder_arg_str.replace(o, "", 1).replace(
|
686 |
-
a, "", 1
|
687 |
-
)
|
688 |
-
if o.startswith("--"):
|
689 |
-
o = o[2:]
|
690 |
-
else:
|
691 |
-
o = o[1:]
|
692 |
-
try:
|
693 |
-
odict[o].append(a)
|
694 |
-
except AttributeError:
|
695 |
-
odict[o] = [odict[o],a]
|
696 |
-
except KeyError:
|
697 |
-
if list_all:
|
698 |
-
odict[o] = [a]
|
699 |
-
else:
|
700 |
-
odict[o] = a
|
701 |
-
|
702 |
-
# Prepare opts,args for return
|
703 |
-
opts = Struct(odict)
|
704 |
-
if mode == 'string':
|
705 |
-
if preserve_non_opts:
|
706 |
-
args = remainder_arg_str.lstrip()
|
707 |
-
else:
|
708 |
-
args = " ".join(args)
|
709 |
-
|
710 |
-
return opts,args
|
711 |
-
|
712 |
-
def default_option(self, fn, optstr):
|
713 |
-
"""Make an entry in the options_table for fn, with value optstr"""
|
714 |
-
|
715 |
-
if fn not in self.lsmagic():
|
716 |
-
error("%s is not a magic function" % fn)
|
717 |
-
self.options_table[fn] = optstr
|
718 |
-
|
719 |
-
|
720 |
-
class MagicAlias(object):
|
721 |
-
"""An alias to another magic function.
|
722 |
-
|
723 |
-
An alias is determined by its magic name and magic kind. Lookup
|
724 |
-
is done at call time, so if the underlying magic changes the alias
|
725 |
-
will call the new function.
|
726 |
-
|
727 |
-
Use the :meth:`MagicsManager.register_alias` method or the
|
728 |
-
`%alias_magic` magic function to create and register a new alias.
|
729 |
-
"""
|
730 |
-
def __init__(self, shell, magic_name, magic_kind, magic_params=None):
|
731 |
-
self.shell = shell
|
732 |
-
self.magic_name = magic_name
|
733 |
-
self.magic_params = magic_params
|
734 |
-
self.magic_kind = magic_kind
|
735 |
-
|
736 |
-
self.pretty_target = '%s%s' % (magic_escapes[self.magic_kind], self.magic_name)
|
737 |
-
self.__doc__ = "Alias for `%s`." % self.pretty_target
|
738 |
-
|
739 |
-
self._in_call = False
|
740 |
-
|
741 |
-
def __call__(self, *args, **kwargs):
|
742 |
-
"""Call the magic alias."""
|
743 |
-
fn = self.shell.find_magic(self.magic_name, self.magic_kind)
|
744 |
-
if fn is None:
|
745 |
-
raise UsageError("Magic `%s` not found." % self.pretty_target)
|
746 |
-
|
747 |
-
# Protect against infinite recursion.
|
748 |
-
if self._in_call:
|
749 |
-
raise UsageError("Infinite recursion detected; "
|
750 |
-
"magic aliases cannot call themselves.")
|
751 |
-
self._in_call = True
|
752 |
-
try:
|
753 |
-
if self.magic_params:
|
754 |
-
args_list = list(args)
|
755 |
-
args_list[0] = self.magic_params + " " + args[0]
|
756 |
-
args = tuple(args_list)
|
757 |
-
return fn(*args, **kwargs)
|
758 |
-
finally:
|
759 |
-
self._in_call = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magic_arguments.py
DELETED
@@ -1,310 +0,0 @@
|
|
1 |
-
''' A decorator-based method of constructing IPython magics with `argparse`
|
2 |
-
option handling.
|
3 |
-
|
4 |
-
New magic functions can be defined like so::
|
5 |
-
|
6 |
-
from IPython.core.magic_arguments import (argument, magic_arguments,
|
7 |
-
parse_argstring)
|
8 |
-
|
9 |
-
@magic_arguments()
|
10 |
-
@argument('-o', '--option', help='An optional argument.')
|
11 |
-
@argument('arg', type=int, help='An integer positional argument.')
|
12 |
-
def magic_cool(self, arg):
|
13 |
-
""" A really cool magic command.
|
14 |
-
|
15 |
-
"""
|
16 |
-
args = parse_argstring(magic_cool, arg)
|
17 |
-
...
|
18 |
-
|
19 |
-
The `@magic_arguments` decorator marks the function as having argparse arguments.
|
20 |
-
The `@argument` decorator adds an argument using the same syntax as argparse's
|
21 |
-
`add_argument()` method. More sophisticated uses may also require the
|
22 |
-
`@argument_group` or `@kwds` decorator to customize the formatting and the
|
23 |
-
parsing.
|
24 |
-
|
25 |
-
Help text for the magic is automatically generated from the docstring and the
|
26 |
-
arguments::
|
27 |
-
|
28 |
-
In[1]: %cool?
|
29 |
-
%cool [-o OPTION] arg
|
30 |
-
|
31 |
-
A really cool magic command.
|
32 |
-
|
33 |
-
positional arguments:
|
34 |
-
arg An integer positional argument.
|
35 |
-
|
36 |
-
optional arguments:
|
37 |
-
-o OPTION, --option OPTION
|
38 |
-
An optional argument.
|
39 |
-
|
40 |
-
Here is an elaborated example that uses default parameters in `argument` and calls the `args` in the cell magic::
|
41 |
-
|
42 |
-
from IPython.core.magic import register_cell_magic
|
43 |
-
from IPython.core.magic_arguments import (argument, magic_arguments,
|
44 |
-
parse_argstring)
|
45 |
-
|
46 |
-
|
47 |
-
@magic_arguments()
|
48 |
-
@argument(
|
49 |
-
"--option",
|
50 |
-
"-o",
|
51 |
-
help=("Add an option here"),
|
52 |
-
)
|
53 |
-
@argument(
|
54 |
-
"--style",
|
55 |
-
"-s",
|
56 |
-
default="foo",
|
57 |
-
help=("Add some style arguments"),
|
58 |
-
)
|
59 |
-
@register_cell_magic
|
60 |
-
def my_cell_magic(line, cell):
|
61 |
-
args = parse_argstring(my_cell_magic, line)
|
62 |
-
print(f"{args.option=}")
|
63 |
-
print(f"{args.style=}")
|
64 |
-
print(f"{cell=}")
|
65 |
-
|
66 |
-
In a jupyter notebook, this cell magic can be executed like this::
|
67 |
-
|
68 |
-
%%my_cell_magic -o Hello
|
69 |
-
print("bar")
|
70 |
-
i = 42
|
71 |
-
|
72 |
-
Inheritance diagram:
|
73 |
-
|
74 |
-
.. inheritance-diagram:: IPython.core.magic_arguments
|
75 |
-
:parts: 3
|
76 |
-
|
77 |
-
'''
|
78 |
-
#-----------------------------------------------------------------------------
|
79 |
-
# Copyright (C) 2010-2011, IPython Development Team.
|
80 |
-
#
|
81 |
-
# Distributed under the terms of the Modified BSD License.
|
82 |
-
#
|
83 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
84 |
-
#-----------------------------------------------------------------------------
|
85 |
-
import argparse
|
86 |
-
import re
|
87 |
-
|
88 |
-
# Our own imports
|
89 |
-
from IPython.core.error import UsageError
|
90 |
-
from IPython.utils.decorators import undoc
|
91 |
-
from IPython.utils.process import arg_split
|
92 |
-
from IPython.utils.text import dedent
|
93 |
-
|
94 |
-
NAME_RE = re.compile(r"[a-zA-Z][a-zA-Z0-9_-]*$")
|
95 |
-
|
96 |
-
@undoc
|
97 |
-
class MagicHelpFormatter(argparse.RawDescriptionHelpFormatter):
|
98 |
-
"""A HelpFormatter with a couple of changes to meet our needs.
|
99 |
-
"""
|
100 |
-
# Modified to dedent text.
|
101 |
-
def _fill_text(self, text, width, indent):
|
102 |
-
return argparse.RawDescriptionHelpFormatter._fill_text(self, dedent(text), width, indent)
|
103 |
-
|
104 |
-
# Modified to wrap argument placeholders in <> where necessary.
|
105 |
-
def _format_action_invocation(self, action):
|
106 |
-
if not action.option_strings:
|
107 |
-
metavar, = self._metavar_formatter(action, action.dest)(1)
|
108 |
-
return metavar
|
109 |
-
|
110 |
-
else:
|
111 |
-
parts = []
|
112 |
-
|
113 |
-
# if the Optional doesn't take a value, format is:
|
114 |
-
# -s, --long
|
115 |
-
if action.nargs == 0:
|
116 |
-
parts.extend(action.option_strings)
|
117 |
-
|
118 |
-
# if the Optional takes a value, format is:
|
119 |
-
# -s ARGS, --long ARGS
|
120 |
-
else:
|
121 |
-
default = action.dest.upper()
|
122 |
-
args_string = self._format_args(action, default)
|
123 |
-
# IPYTHON MODIFICATION: If args_string is not a plain name, wrap
|
124 |
-
# it in <> so it's valid RST.
|
125 |
-
if not NAME_RE.match(args_string):
|
126 |
-
args_string = "<%s>" % args_string
|
127 |
-
for option_string in action.option_strings:
|
128 |
-
parts.append('%s %s' % (option_string, args_string))
|
129 |
-
|
130 |
-
return ', '.join(parts)
|
131 |
-
|
132 |
-
# Override the default prefix ('usage') to our % magic escape,
|
133 |
-
# in a code block.
|
134 |
-
def add_usage(self, usage, actions, groups, prefix="::\n\n %"):
|
135 |
-
super(MagicHelpFormatter, self).add_usage(usage, actions, groups, prefix)
|
136 |
-
|
137 |
-
class MagicArgumentParser(argparse.ArgumentParser):
|
138 |
-
""" An ArgumentParser tweaked for use by IPython magics.
|
139 |
-
"""
|
140 |
-
def __init__(self,
|
141 |
-
prog=None,
|
142 |
-
usage=None,
|
143 |
-
description=None,
|
144 |
-
epilog=None,
|
145 |
-
parents=None,
|
146 |
-
formatter_class=MagicHelpFormatter,
|
147 |
-
prefix_chars='-',
|
148 |
-
argument_default=None,
|
149 |
-
conflict_handler='error',
|
150 |
-
add_help=False):
|
151 |
-
if parents is None:
|
152 |
-
parents = []
|
153 |
-
super(MagicArgumentParser, self).__init__(prog=prog, usage=usage,
|
154 |
-
description=description, epilog=epilog,
|
155 |
-
parents=parents, formatter_class=formatter_class,
|
156 |
-
prefix_chars=prefix_chars, argument_default=argument_default,
|
157 |
-
conflict_handler=conflict_handler, add_help=add_help)
|
158 |
-
|
159 |
-
def error(self, message):
|
160 |
-
""" Raise a catchable error instead of exiting.
|
161 |
-
"""
|
162 |
-
raise UsageError(message)
|
163 |
-
|
164 |
-
def parse_argstring(self, argstring):
|
165 |
-
""" Split a string into an argument list and parse that argument list.
|
166 |
-
"""
|
167 |
-
argv = arg_split(argstring)
|
168 |
-
return self.parse_args(argv)
|
169 |
-
|
170 |
-
|
171 |
-
def construct_parser(magic_func):
|
172 |
-
""" Construct an argument parser using the function decorations.
|
173 |
-
"""
|
174 |
-
kwds = getattr(magic_func, 'argcmd_kwds', {})
|
175 |
-
if 'description' not in kwds:
|
176 |
-
kwds['description'] = getattr(magic_func, '__doc__', None)
|
177 |
-
arg_name = real_name(magic_func)
|
178 |
-
parser = MagicArgumentParser(arg_name, **kwds)
|
179 |
-
# Reverse the list of decorators in order to apply them in the
|
180 |
-
# order in which they appear in the source.
|
181 |
-
group = None
|
182 |
-
for deco in magic_func.decorators[::-1]:
|
183 |
-
result = deco.add_to_parser(parser, group)
|
184 |
-
if result is not None:
|
185 |
-
group = result
|
186 |
-
|
187 |
-
# Replace the magic function's docstring with the full help text.
|
188 |
-
magic_func.__doc__ = parser.format_help()
|
189 |
-
|
190 |
-
return parser
|
191 |
-
|
192 |
-
|
193 |
-
def parse_argstring(magic_func, argstring):
|
194 |
-
""" Parse the string of arguments for the given magic function.
|
195 |
-
"""
|
196 |
-
return magic_func.parser.parse_argstring(argstring)
|
197 |
-
|
198 |
-
|
199 |
-
def real_name(magic_func):
|
200 |
-
""" Find the real name of the magic.
|
201 |
-
"""
|
202 |
-
magic_name = magic_func.__name__
|
203 |
-
if magic_name.startswith('magic_'):
|
204 |
-
magic_name = magic_name[len('magic_'):]
|
205 |
-
return getattr(magic_func, 'argcmd_name', magic_name)
|
206 |
-
|
207 |
-
|
208 |
-
class ArgDecorator(object):
|
209 |
-
""" Base class for decorators to add ArgumentParser information to a method.
|
210 |
-
"""
|
211 |
-
|
212 |
-
def __call__(self, func):
|
213 |
-
if not getattr(func, 'has_arguments', False):
|
214 |
-
func.has_arguments = True
|
215 |
-
func.decorators = []
|
216 |
-
func.decorators.append(self)
|
217 |
-
return func
|
218 |
-
|
219 |
-
def add_to_parser(self, parser, group):
|
220 |
-
""" Add this object's information to the parser, if necessary.
|
221 |
-
"""
|
222 |
-
pass
|
223 |
-
|
224 |
-
|
225 |
-
class magic_arguments(ArgDecorator):
|
226 |
-
""" Mark the magic as having argparse arguments and possibly adjust the
|
227 |
-
name.
|
228 |
-
"""
|
229 |
-
|
230 |
-
def __init__(self, name=None):
|
231 |
-
self.name = name
|
232 |
-
|
233 |
-
def __call__(self, func):
|
234 |
-
if not getattr(func, 'has_arguments', False):
|
235 |
-
func.has_arguments = True
|
236 |
-
func.decorators = []
|
237 |
-
if self.name is not None:
|
238 |
-
func.argcmd_name = self.name
|
239 |
-
# This should be the first decorator in the list of decorators, thus the
|
240 |
-
# last to execute. Build the parser.
|
241 |
-
func.parser = construct_parser(func)
|
242 |
-
return func
|
243 |
-
|
244 |
-
|
245 |
-
class ArgMethodWrapper(ArgDecorator):
|
246 |
-
|
247 |
-
"""
|
248 |
-
Base class to define a wrapper for ArgumentParser method.
|
249 |
-
|
250 |
-
Child class must define either `_method_name` or `add_to_parser`.
|
251 |
-
|
252 |
-
"""
|
253 |
-
|
254 |
-
_method_name: str
|
255 |
-
|
256 |
-
def __init__(self, *args, **kwds):
|
257 |
-
self.args = args
|
258 |
-
self.kwds = kwds
|
259 |
-
|
260 |
-
def add_to_parser(self, parser, group):
|
261 |
-
""" Add this object's information to the parser.
|
262 |
-
"""
|
263 |
-
if group is not None:
|
264 |
-
parser = group
|
265 |
-
getattr(parser, self._method_name)(*self.args, **self.kwds)
|
266 |
-
return None
|
267 |
-
|
268 |
-
|
269 |
-
class argument(ArgMethodWrapper):
|
270 |
-
""" Store arguments and keywords to pass to add_argument().
|
271 |
-
|
272 |
-
Instances also serve to decorate command methods.
|
273 |
-
"""
|
274 |
-
_method_name = 'add_argument'
|
275 |
-
|
276 |
-
|
277 |
-
class defaults(ArgMethodWrapper):
|
278 |
-
""" Store arguments and keywords to pass to set_defaults().
|
279 |
-
|
280 |
-
Instances also serve to decorate command methods.
|
281 |
-
"""
|
282 |
-
_method_name = 'set_defaults'
|
283 |
-
|
284 |
-
|
285 |
-
class argument_group(ArgMethodWrapper):
|
286 |
-
""" Store arguments and keywords to pass to add_argument_group().
|
287 |
-
|
288 |
-
Instances also serve to decorate command methods.
|
289 |
-
"""
|
290 |
-
|
291 |
-
def add_to_parser(self, parser, group):
|
292 |
-
""" Add this object's information to the parser.
|
293 |
-
"""
|
294 |
-
return parser.add_argument_group(*self.args, **self.kwds)
|
295 |
-
|
296 |
-
|
297 |
-
class kwds(ArgDecorator):
|
298 |
-
""" Provide other keywords to the sub-parser constructor.
|
299 |
-
"""
|
300 |
-
def __init__(self, **kwds):
|
301 |
-
self.kwds = kwds
|
302 |
-
|
303 |
-
def __call__(self, func):
|
304 |
-
func = super(kwds, self).__call__(func)
|
305 |
-
func.argcmd_kwds = self.kwds
|
306 |
-
return func
|
307 |
-
|
308 |
-
|
309 |
-
__all__ = ['magic_arguments', 'argument', 'argument_group', 'kwds',
|
310 |
-
'parse_argstring']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/__init__.py
DELETED
@@ -1,42 +0,0 @@
|
|
1 |
-
"""Implementation of all the magic functions built into IPython.
|
2 |
-
"""
|
3 |
-
#-----------------------------------------------------------------------------
|
4 |
-
# Copyright (c) 2012 The IPython Development Team.
|
5 |
-
#
|
6 |
-
# Distributed under the terms of the Modified BSD License.
|
7 |
-
#
|
8 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
9 |
-
#-----------------------------------------------------------------------------
|
10 |
-
|
11 |
-
#-----------------------------------------------------------------------------
|
12 |
-
# Imports
|
13 |
-
#-----------------------------------------------------------------------------
|
14 |
-
|
15 |
-
from ..magic import Magics, magics_class
|
16 |
-
from .auto import AutoMagics
|
17 |
-
from .basic import BasicMagics, AsyncMagics
|
18 |
-
from .code import CodeMagics, MacroToEdit
|
19 |
-
from .config import ConfigMagics
|
20 |
-
from .display import DisplayMagics
|
21 |
-
from .execution import ExecutionMagics
|
22 |
-
from .extension import ExtensionMagics
|
23 |
-
from .history import HistoryMagics
|
24 |
-
from .logging import LoggingMagics
|
25 |
-
from .namespace import NamespaceMagics
|
26 |
-
from .osm import OSMagics
|
27 |
-
from .packaging import PackagingMagics
|
28 |
-
from .pylab import PylabMagics
|
29 |
-
from .script import ScriptMagics
|
30 |
-
|
31 |
-
#-----------------------------------------------------------------------------
|
32 |
-
# Magic implementation classes
|
33 |
-
#-----------------------------------------------------------------------------
|
34 |
-
|
35 |
-
@magics_class
|
36 |
-
class UserMagics(Magics):
|
37 |
-
"""Placeholder for user-defined magics to be added at runtime.
|
38 |
-
|
39 |
-
All magics are eventually merged into a single namespace at runtime, but we
|
40 |
-
use this class to isolate the magics defined dynamically by the user into
|
41 |
-
their own class.
|
42 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/ast_mod.py
DELETED
@@ -1,330 +0,0 @@
|
|
1 |
-
"""
|
2 |
-
This module contains utility function and classes to inject simple ast
|
3 |
-
transformations based on code strings into IPython. While it is already possible
|
4 |
-
with ast-transformers it is not easy to directly manipulate ast.
|
5 |
-
|
6 |
-
|
7 |
-
IPython has pre-code and post-code hooks, but are ran from within the IPython
|
8 |
-
machinery so may be inappropriate, for example for performance measurement.
|
9 |
-
|
10 |
-
This module give you tools to simplify this, and expose 2 classes:
|
11 |
-
|
12 |
-
- `ReplaceCodeTransformer` which is a simple ast transformer based on code
|
13 |
-
template,
|
14 |
-
|
15 |
-
and for advance case:
|
16 |
-
|
17 |
-
- `Mangler` which is a simple ast transformer that mangle names in the ast.
|
18 |
-
|
19 |
-
|
20 |
-
Example, let's try to make a simple version of the ``timeit`` magic, that run a
|
21 |
-
code snippet 10 times and print the average time taken.
|
22 |
-
|
23 |
-
Basically we want to run :
|
24 |
-
|
25 |
-
.. code-block:: python
|
26 |
-
|
27 |
-
from time import perf_counter
|
28 |
-
now = perf_counter()
|
29 |
-
for i in range(10):
|
30 |
-
__code__ # our code
|
31 |
-
print(f"Time taken: {(perf_counter() - now)/10}")
|
32 |
-
__ret__ # the result of the last statement
|
33 |
-
|
34 |
-
Where ``__code__`` is the code snippet we want to run, and ``__ret__`` is the
|
35 |
-
result, so that if we for example run `dataframe.head()` IPython still display
|
36 |
-
the head of dataframe instead of nothing.
|
37 |
-
|
38 |
-
Here is a complete example of a file `timit2.py` that define such a magic:
|
39 |
-
|
40 |
-
.. code-block:: python
|
41 |
-
|
42 |
-
from IPython.core.magic import (
|
43 |
-
Magics,
|
44 |
-
magics_class,
|
45 |
-
line_cell_magic,
|
46 |
-
)
|
47 |
-
from IPython.core.magics.ast_mod import ReplaceCodeTransformer
|
48 |
-
from textwrap import dedent
|
49 |
-
import ast
|
50 |
-
|
51 |
-
template = template = dedent('''
|
52 |
-
from time import perf_counter
|
53 |
-
now = perf_counter()
|
54 |
-
for i in range(10):
|
55 |
-
__code__
|
56 |
-
print(f"Time taken: {(perf_counter() - now)/10}")
|
57 |
-
__ret__
|
58 |
-
'''
|
59 |
-
)
|
60 |
-
|
61 |
-
|
62 |
-
@magics_class
|
63 |
-
class AstM(Magics):
|
64 |
-
@line_cell_magic
|
65 |
-
def t2(self, line, cell):
|
66 |
-
transformer = ReplaceCodeTransformer.from_string(template)
|
67 |
-
transformer.debug = True
|
68 |
-
transformer.mangler.debug = True
|
69 |
-
new_code = transformer.visit(ast.parse(cell))
|
70 |
-
return exec(compile(new_code, "<ast>", "exec"))
|
71 |
-
|
72 |
-
|
73 |
-
def load_ipython_extension(ip):
|
74 |
-
ip.register_magics(AstM)
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
.. code-block:: python
|
79 |
-
|
80 |
-
In [1]: %load_ext timit2
|
81 |
-
|
82 |
-
In [2]: %%t2
|
83 |
-
...: import time
|
84 |
-
...: time.sleep(0.05)
|
85 |
-
...:
|
86 |
-
...:
|
87 |
-
Time taken: 0.05435649999999441
|
88 |
-
|
89 |
-
|
90 |
-
If you wish to ran all the code enter in IPython in an ast transformer, you can
|
91 |
-
do so as well:
|
92 |
-
|
93 |
-
.. code-block:: python
|
94 |
-
|
95 |
-
In [1]: from IPython.core.magics.ast_mod import ReplaceCodeTransformer
|
96 |
-
...:
|
97 |
-
...: template = '''
|
98 |
-
...: from time import perf_counter
|
99 |
-
...: now = perf_counter()
|
100 |
-
...: __code__
|
101 |
-
...: print(f"Code ran in {perf_counter()-now}")
|
102 |
-
...: __ret__'''
|
103 |
-
...:
|
104 |
-
...: get_ipython().ast_transformers.append(ReplaceCodeTransformer.from_string(template))
|
105 |
-
|
106 |
-
In [2]: 1+1
|
107 |
-
Code ran in 3.40410006174352e-05
|
108 |
-
Out[2]: 2
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
Hygiene and Mangling
|
113 |
-
--------------------
|
114 |
-
|
115 |
-
The ast transformer above is not hygienic, it may not work if the user code use
|
116 |
-
the same variable names as the ones used in the template. For example.
|
117 |
-
|
118 |
-
To help with this by default the `ReplaceCodeTransformer` will mangle all names
|
119 |
-
staring with 3 underscores. This is a simple heuristic that should work in most
|
120 |
-
case, but can be cumbersome in some case. We provide a `Mangler` class that can
|
121 |
-
be overridden to change the mangling heuristic, or simply use the `mangle_all`
|
122 |
-
utility function. It will _try_ to mangle all names (except `__ret__` and
|
123 |
-
`__code__`), but this include builtins (``print``, ``range``, ``type``) and
|
124 |
-
replace those by invalid identifiers py prepending ``mangle-``:
|
125 |
-
``mangle-print``, ``mangle-range``, ``mangle-type`` etc. This is not a problem
|
126 |
-
as currently Python AST support invalid identifiers, but it may not be the case
|
127 |
-
in the future.
|
128 |
-
|
129 |
-
You can set `ReplaceCodeTransformer.debug=True` and
|
130 |
-
`ReplaceCodeTransformer.mangler.debug=True` to see the code after mangling and
|
131 |
-
transforming:
|
132 |
-
|
133 |
-
.. code-block:: python
|
134 |
-
|
135 |
-
|
136 |
-
In [1]: from IPython.core.magics.ast_mod import ReplaceCodeTransformer, mangle_all
|
137 |
-
...:
|
138 |
-
...: template = '''
|
139 |
-
...: from builtins import type, print
|
140 |
-
...: from time import perf_counter
|
141 |
-
...: now = perf_counter()
|
142 |
-
...: __code__
|
143 |
-
...: print(f"Code ran in {perf_counter()-now}")
|
144 |
-
...: __ret__'''
|
145 |
-
...:
|
146 |
-
...: transformer = ReplaceCodeTransformer.from_string(template, mangling_predicate=mangle_all)
|
147 |
-
|
148 |
-
|
149 |
-
In [2]: transformer.debug = True
|
150 |
-
...: transformer.mangler.debug = True
|
151 |
-
...: get_ipython().ast_transformers.append(transformer)
|
152 |
-
|
153 |
-
In [3]: 1+1
|
154 |
-
Mangling Alias mangle-type
|
155 |
-
Mangling Alias mangle-print
|
156 |
-
Mangling Alias mangle-perf_counter
|
157 |
-
Mangling now
|
158 |
-
Mangling perf_counter
|
159 |
-
Not mangling __code__
|
160 |
-
Mangling print
|
161 |
-
Mangling perf_counter
|
162 |
-
Mangling now
|
163 |
-
Not mangling __ret__
|
164 |
-
---- Transformed code ----
|
165 |
-
from builtins import type as mangle-type, print as mangle-print
|
166 |
-
from time import perf_counter as mangle-perf_counter
|
167 |
-
mangle-now = mangle-perf_counter()
|
168 |
-
ret-tmp = 1 + 1
|
169 |
-
mangle-print(f'Code ran in {mangle-perf_counter() - mangle-now}')
|
170 |
-
ret-tmp
|
171 |
-
---- ---------------- ----
|
172 |
-
Code ran in 0.00013654199938173406
|
173 |
-
Out[3]: 2
|
174 |
-
|
175 |
-
|
176 |
-
"""
|
177 |
-
|
178 |
-
__skip_doctest__ = True
|
179 |
-
|
180 |
-
|
181 |
-
from ast import (
|
182 |
-
NodeTransformer,
|
183 |
-
Store,
|
184 |
-
Load,
|
185 |
-
Name,
|
186 |
-
Expr,
|
187 |
-
Assign,
|
188 |
-
Module,
|
189 |
-
Import,
|
190 |
-
ImportFrom,
|
191 |
-
)
|
192 |
-
import ast
|
193 |
-
import copy
|
194 |
-
|
195 |
-
from typing import Dict, Optional, Union
|
196 |
-
|
197 |
-
|
198 |
-
mangle_all = lambda name: False if name in ("__ret__", "__code__") else True
|
199 |
-
|
200 |
-
|
201 |
-
class Mangler(NodeTransformer):
|
202 |
-
"""
|
203 |
-
Mangle given names in and ast tree to make sure they do not conflict with
|
204 |
-
user code.
|
205 |
-
"""
|
206 |
-
|
207 |
-
enabled: bool = True
|
208 |
-
debug: bool = False
|
209 |
-
|
210 |
-
def log(self, *args, **kwargs):
|
211 |
-
if self.debug:
|
212 |
-
print(*args, **kwargs)
|
213 |
-
|
214 |
-
def __init__(self, predicate=None):
|
215 |
-
if predicate is None:
|
216 |
-
predicate = lambda name: name.startswith("___")
|
217 |
-
self.predicate = predicate
|
218 |
-
|
219 |
-
def visit_Name(self, node):
|
220 |
-
if self.predicate(node.id):
|
221 |
-
self.log("Mangling", node.id)
|
222 |
-
# Once in the ast we do not need
|
223 |
-
# names to be valid identifiers.
|
224 |
-
node.id = "mangle-" + node.id
|
225 |
-
else:
|
226 |
-
self.log("Not mangling", node.id)
|
227 |
-
return node
|
228 |
-
|
229 |
-
def visit_FunctionDef(self, node):
|
230 |
-
if self.predicate(node.name):
|
231 |
-
self.log("Mangling", node.name)
|
232 |
-
node.name = "mangle-" + node.name
|
233 |
-
else:
|
234 |
-
self.log("Not mangling", node.name)
|
235 |
-
|
236 |
-
for arg in node.args.args:
|
237 |
-
if self.predicate(arg.arg):
|
238 |
-
self.log("Mangling function arg", arg.arg)
|
239 |
-
arg.arg = "mangle-" + arg.arg
|
240 |
-
else:
|
241 |
-
self.log("Not mangling function arg", arg.arg)
|
242 |
-
return self.generic_visit(node)
|
243 |
-
|
244 |
-
def visit_ImportFrom(self, node: ImportFrom):
|
245 |
-
return self._visit_Import_and_ImportFrom(node)
|
246 |
-
|
247 |
-
def visit_Import(self, node: Import):
|
248 |
-
return self._visit_Import_and_ImportFrom(node)
|
249 |
-
|
250 |
-
def _visit_Import_and_ImportFrom(self, node: Union[Import, ImportFrom]):
|
251 |
-
for alias in node.names:
|
252 |
-
asname = alias.name if alias.asname is None else alias.asname
|
253 |
-
if self.predicate(asname):
|
254 |
-
new_name: str = "mangle-" + asname
|
255 |
-
self.log("Mangling Alias", new_name)
|
256 |
-
alias.asname = new_name
|
257 |
-
else:
|
258 |
-
self.log("Not mangling Alias", alias.asname)
|
259 |
-
return node
|
260 |
-
|
261 |
-
|
262 |
-
class ReplaceCodeTransformer(NodeTransformer):
|
263 |
-
enabled: bool = True
|
264 |
-
debug: bool = False
|
265 |
-
mangler: Mangler
|
266 |
-
|
267 |
-
def __init__(
|
268 |
-
self, template: Module, mapping: Optional[Dict] = None, mangling_predicate=None
|
269 |
-
):
|
270 |
-
assert isinstance(mapping, (dict, type(None)))
|
271 |
-
assert isinstance(mangling_predicate, (type(None), type(lambda: None)))
|
272 |
-
assert isinstance(template, ast.Module)
|
273 |
-
self.template = template
|
274 |
-
self.mangler = Mangler(predicate=mangling_predicate)
|
275 |
-
if mapping is None:
|
276 |
-
mapping = {}
|
277 |
-
self.mapping = mapping
|
278 |
-
|
279 |
-
@classmethod
|
280 |
-
def from_string(
|
281 |
-
cls, template: str, mapping: Optional[Dict] = None, mangling_predicate=None
|
282 |
-
):
|
283 |
-
return cls(
|
284 |
-
ast.parse(template), mapping=mapping, mangling_predicate=mangling_predicate
|
285 |
-
)
|
286 |
-
|
287 |
-
def visit_Module(self, code):
|
288 |
-
if not self.enabled:
|
289 |
-
return code
|
290 |
-
# if not isinstance(code, ast.Module):
|
291 |
-
# recursively called...
|
292 |
-
# return generic_visit(self, code)
|
293 |
-
last = code.body[-1]
|
294 |
-
if isinstance(last, Expr):
|
295 |
-
code.body.pop()
|
296 |
-
code.body.append(Assign([Name("ret-tmp", ctx=Store())], value=last.value))
|
297 |
-
ast.fix_missing_locations(code)
|
298 |
-
ret = Expr(value=Name("ret-tmp", ctx=Load()))
|
299 |
-
ret = ast.fix_missing_locations(ret)
|
300 |
-
self.mapping["__ret__"] = ret
|
301 |
-
else:
|
302 |
-
self.mapping["__ret__"] = ast.parse("None").body[0]
|
303 |
-
self.mapping["__code__"] = code.body
|
304 |
-
tpl = ast.fix_missing_locations(self.template)
|
305 |
-
|
306 |
-
tx = copy.deepcopy(tpl)
|
307 |
-
tx = self.mangler.visit(tx)
|
308 |
-
node = self.generic_visit(tx)
|
309 |
-
node_2 = ast.fix_missing_locations(node)
|
310 |
-
if self.debug:
|
311 |
-
print("---- Transformed code ----")
|
312 |
-
print(ast.unparse(node_2))
|
313 |
-
print("---- ---------------- ----")
|
314 |
-
return node_2
|
315 |
-
|
316 |
-
# this does not work as the name might be in a list and one might want to extend the list.
|
317 |
-
# def visit_Name(self, name):
|
318 |
-
# if name.id in self.mapping and name.id == "__ret__":
|
319 |
-
# print(name, "in mapping")
|
320 |
-
# if isinstance(name.ctx, ast.Store):
|
321 |
-
# return Name("tmp", ctx=Store())
|
322 |
-
# else:
|
323 |
-
# return copy.deepcopy(self.mapping[name.id])
|
324 |
-
# return name
|
325 |
-
|
326 |
-
def visit_Expr(self, expr):
|
327 |
-
if isinstance(expr.value, Name) and expr.value.id in self.mapping:
|
328 |
-
if self.mapping[expr.value.id] is not None:
|
329 |
-
return copy.deepcopy(self.mapping[expr.value.id])
|
330 |
-
return self.generic_visit(expr)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/auto.py
DELETED
@@ -1,144 +0,0 @@
|
|
1 |
-
"""Implementation of magic functions that control various automatic behaviors.
|
2 |
-
"""
|
3 |
-
#-----------------------------------------------------------------------------
|
4 |
-
# Copyright (c) 2012 The IPython Development Team.
|
5 |
-
#
|
6 |
-
# Distributed under the terms of the Modified BSD License.
|
7 |
-
#
|
8 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
9 |
-
#-----------------------------------------------------------------------------
|
10 |
-
|
11 |
-
#-----------------------------------------------------------------------------
|
12 |
-
# Imports
|
13 |
-
#-----------------------------------------------------------------------------
|
14 |
-
|
15 |
-
# Our own packages
|
16 |
-
from IPython.core.magic import Bunch, Magics, magics_class, line_magic
|
17 |
-
from IPython.testing.skipdoctest import skip_doctest
|
18 |
-
from logging import error
|
19 |
-
|
20 |
-
#-----------------------------------------------------------------------------
|
21 |
-
# Magic implementation classes
|
22 |
-
#-----------------------------------------------------------------------------
|
23 |
-
|
24 |
-
@magics_class
|
25 |
-
class AutoMagics(Magics):
|
26 |
-
"""Magics that control various autoX behaviors."""
|
27 |
-
|
28 |
-
def __init__(self, shell):
|
29 |
-
super(AutoMagics, self).__init__(shell)
|
30 |
-
# namespace for holding state we may need
|
31 |
-
self._magic_state = Bunch()
|
32 |
-
|
33 |
-
@line_magic
|
34 |
-
def automagic(self, parameter_s=''):
|
35 |
-
"""Make magic functions callable without having to type the initial %.
|
36 |
-
|
37 |
-
Without arguments toggles on/off (when off, you must call it as
|
38 |
-
%automagic, of course). With arguments it sets the value, and you can
|
39 |
-
use any of (case insensitive):
|
40 |
-
|
41 |
-
- on, 1, True: to activate
|
42 |
-
|
43 |
-
- off, 0, False: to deactivate.
|
44 |
-
|
45 |
-
Note that magic functions have lowest priority, so if there's a
|
46 |
-
variable whose name collides with that of a magic fn, automagic won't
|
47 |
-
work for that function (you get the variable instead). However, if you
|
48 |
-
delete the variable (del var), the previously shadowed magic function
|
49 |
-
becomes visible to automagic again."""
|
50 |
-
|
51 |
-
arg = parameter_s.lower()
|
52 |
-
mman = self.shell.magics_manager
|
53 |
-
if arg in ('on', '1', 'true'):
|
54 |
-
val = True
|
55 |
-
elif arg in ('off', '0', 'false'):
|
56 |
-
val = False
|
57 |
-
else:
|
58 |
-
val = not mman.auto_magic
|
59 |
-
mman.auto_magic = val
|
60 |
-
print('\n' + self.shell.magics_manager.auto_status())
|
61 |
-
|
62 |
-
@skip_doctest
|
63 |
-
@line_magic
|
64 |
-
def autocall(self, parameter_s=''):
|
65 |
-
"""Make functions callable without having to type parentheses.
|
66 |
-
|
67 |
-
Usage:
|
68 |
-
|
69 |
-
%autocall [mode]
|
70 |
-
|
71 |
-
The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the
|
72 |
-
value is toggled on and off (remembering the previous state).
|
73 |
-
|
74 |
-
In more detail, these values mean:
|
75 |
-
|
76 |
-
0 -> fully disabled
|
77 |
-
|
78 |
-
1 -> active, but do not apply if there are no arguments on the line.
|
79 |
-
|
80 |
-
In this mode, you get::
|
81 |
-
|
82 |
-
In [1]: callable
|
83 |
-
Out[1]: <built-in function callable>
|
84 |
-
|
85 |
-
In [2]: callable 'hello'
|
86 |
-
------> callable('hello')
|
87 |
-
Out[2]: False
|
88 |
-
|
89 |
-
2 -> Active always. Even if no arguments are present, the callable
|
90 |
-
object is called::
|
91 |
-
|
92 |
-
In [2]: float
|
93 |
-
------> float()
|
94 |
-
Out[2]: 0.0
|
95 |
-
|
96 |
-
Note that even with autocall off, you can still use '/' at the start of
|
97 |
-
a line to treat the first argument on the command line as a function
|
98 |
-
and add parentheses to it::
|
99 |
-
|
100 |
-
In [8]: /str 43
|
101 |
-
------> str(43)
|
102 |
-
Out[8]: '43'
|
103 |
-
|
104 |
-
# all-random (note for auto-testing)
|
105 |
-
"""
|
106 |
-
|
107 |
-
valid_modes = {
|
108 |
-
0: "Off",
|
109 |
-
1: "Smart",
|
110 |
-
2: "Full",
|
111 |
-
}
|
112 |
-
|
113 |
-
def errorMessage() -> str:
|
114 |
-
error = "Valid modes: "
|
115 |
-
for k, v in valid_modes.items():
|
116 |
-
error += str(k) + "->" + v + ", "
|
117 |
-
error = error[:-2] # remove tailing `, ` after last element
|
118 |
-
return error
|
119 |
-
|
120 |
-
if parameter_s:
|
121 |
-
if not parameter_s in map(str, valid_modes.keys()):
|
122 |
-
error(errorMessage())
|
123 |
-
return
|
124 |
-
arg = int(parameter_s)
|
125 |
-
else:
|
126 |
-
arg = 'toggle'
|
127 |
-
|
128 |
-
if not arg in (*list(valid_modes.keys()), "toggle"):
|
129 |
-
error(errorMessage())
|
130 |
-
return
|
131 |
-
|
132 |
-
if arg in (valid_modes.keys()):
|
133 |
-
self.shell.autocall = arg
|
134 |
-
else: # toggle
|
135 |
-
if self.shell.autocall:
|
136 |
-
self._magic_state.autocall_save = self.shell.autocall
|
137 |
-
self.shell.autocall = 0
|
138 |
-
else:
|
139 |
-
try:
|
140 |
-
self.shell.autocall = self._magic_state.autocall_save
|
141 |
-
except AttributeError:
|
142 |
-
self.shell.autocall = self._magic_state.autocall_save = 1
|
143 |
-
|
144 |
-
print("Automatic calling is:", list(valid_modes.values())[self.shell.autocall])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/basic.py
DELETED
@@ -1,666 +0,0 @@
|
|
1 |
-
"""Implementation of basic magic functions."""
|
2 |
-
|
3 |
-
|
4 |
-
from logging import error
|
5 |
-
import io
|
6 |
-
import os
|
7 |
-
from pprint import pformat
|
8 |
-
import sys
|
9 |
-
from warnings import warn
|
10 |
-
|
11 |
-
from traitlets.utils.importstring import import_item
|
12 |
-
from IPython.core import magic_arguments, page
|
13 |
-
from IPython.core.error import UsageError
|
14 |
-
from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes
|
15 |
-
from IPython.utils.text import format_screen, dedent, indent
|
16 |
-
from IPython.testing.skipdoctest import skip_doctest
|
17 |
-
from IPython.utils.ipstruct import Struct
|
18 |
-
|
19 |
-
|
20 |
-
class MagicsDisplay(object):
|
21 |
-
def __init__(self, magics_manager, ignore=None):
|
22 |
-
self.ignore = ignore if ignore else []
|
23 |
-
self.magics_manager = magics_manager
|
24 |
-
|
25 |
-
def _lsmagic(self):
|
26 |
-
"""The main implementation of the %lsmagic"""
|
27 |
-
mesc = magic_escapes['line']
|
28 |
-
cesc = magic_escapes['cell']
|
29 |
-
mman = self.magics_manager
|
30 |
-
magics = mman.lsmagic()
|
31 |
-
out = ['Available line magics:',
|
32 |
-
mesc + (' '+mesc).join(sorted([m for m,v in magics['line'].items() if (v not in self.ignore)])),
|
33 |
-
'',
|
34 |
-
'Available cell magics:',
|
35 |
-
cesc + (' '+cesc).join(sorted([m for m,v in magics['cell'].items() if (v not in self.ignore)])),
|
36 |
-
'',
|
37 |
-
mman.auto_status()]
|
38 |
-
return '\n'.join(out)
|
39 |
-
|
40 |
-
def _repr_pretty_(self, p, cycle):
|
41 |
-
p.text(self._lsmagic())
|
42 |
-
|
43 |
-
def __repr__(self):
|
44 |
-
return self.__str__()
|
45 |
-
|
46 |
-
def __str__(self):
|
47 |
-
return self._lsmagic()
|
48 |
-
|
49 |
-
def _jsonable(self):
|
50 |
-
"""turn magics dict into jsonable dict of the same structure
|
51 |
-
|
52 |
-
replaces object instances with their class names as strings
|
53 |
-
"""
|
54 |
-
magic_dict = {}
|
55 |
-
mman = self.magics_manager
|
56 |
-
magics = mman.lsmagic()
|
57 |
-
for key, subdict in magics.items():
|
58 |
-
d = {}
|
59 |
-
magic_dict[key] = d
|
60 |
-
for name, obj in subdict.items():
|
61 |
-
try:
|
62 |
-
classname = obj.__self__.__class__.__name__
|
63 |
-
except AttributeError:
|
64 |
-
classname = 'Other'
|
65 |
-
|
66 |
-
d[name] = classname
|
67 |
-
return magic_dict
|
68 |
-
|
69 |
-
def _repr_json_(self):
|
70 |
-
return self._jsonable()
|
71 |
-
|
72 |
-
|
73 |
-
@magics_class
|
74 |
-
class BasicMagics(Magics):
|
75 |
-
"""Magics that provide central IPython functionality.
|
76 |
-
|
77 |
-
These are various magics that don't fit into specific categories but that
|
78 |
-
are all part of the base 'IPython experience'."""
|
79 |
-
|
80 |
-
@skip_doctest
|
81 |
-
@magic_arguments.magic_arguments()
|
82 |
-
@magic_arguments.argument(
|
83 |
-
'-l', '--line', action='store_true',
|
84 |
-
help="""Create a line magic alias."""
|
85 |
-
)
|
86 |
-
@magic_arguments.argument(
|
87 |
-
'-c', '--cell', action='store_true',
|
88 |
-
help="""Create a cell magic alias."""
|
89 |
-
)
|
90 |
-
@magic_arguments.argument(
|
91 |
-
'name',
|
92 |
-
help="""Name of the magic to be created."""
|
93 |
-
)
|
94 |
-
@magic_arguments.argument(
|
95 |
-
'target',
|
96 |
-
help="""Name of the existing line or cell magic."""
|
97 |
-
)
|
98 |
-
@magic_arguments.argument(
|
99 |
-
'-p', '--params', default=None,
|
100 |
-
help="""Parameters passed to the magic function."""
|
101 |
-
)
|
102 |
-
@line_magic
|
103 |
-
def alias_magic(self, line=''):
|
104 |
-
"""Create an alias for an existing line or cell magic.
|
105 |
-
|
106 |
-
Examples
|
107 |
-
--------
|
108 |
-
::
|
109 |
-
|
110 |
-
In [1]: %alias_magic t timeit
|
111 |
-
Created `%t` as an alias for `%timeit`.
|
112 |
-
Created `%%t` as an alias for `%%timeit`.
|
113 |
-
|
114 |
-
In [2]: %t -n1 pass
|
115 |
-
107 ns ± 43.6 ns per loop (mean ± std. dev. of 7 runs, 1 loop each)
|
116 |
-
|
117 |
-
In [3]: %%t -n1
|
118 |
-
...: pass
|
119 |
-
...:
|
120 |
-
107 ns ± 58.3 ns per loop (mean ± std. dev. of 7 runs, 1 loop each)
|
121 |
-
|
122 |
-
In [4]: %alias_magic --cell whereami pwd
|
123 |
-
UsageError: Cell magic function `%%pwd` not found.
|
124 |
-
In [5]: %alias_magic --line whereami pwd
|
125 |
-
Created `%whereami` as an alias for `%pwd`.
|
126 |
-
|
127 |
-
In [6]: %whereami
|
128 |
-
Out[6]: '/home/testuser'
|
129 |
-
|
130 |
-
In [7]: %alias_magic h history -p "-l 30" --line
|
131 |
-
Created `%h` as an alias for `%history -l 30`.
|
132 |
-
"""
|
133 |
-
|
134 |
-
args = magic_arguments.parse_argstring(self.alias_magic, line)
|
135 |
-
shell = self.shell
|
136 |
-
mman = self.shell.magics_manager
|
137 |
-
escs = ''.join(magic_escapes.values())
|
138 |
-
|
139 |
-
target = args.target.lstrip(escs)
|
140 |
-
name = args.name.lstrip(escs)
|
141 |
-
|
142 |
-
params = args.params
|
143 |
-
if (params and
|
144 |
-
((params.startswith('"') and params.endswith('"'))
|
145 |
-
or (params.startswith("'") and params.endswith("'")))):
|
146 |
-
params = params[1:-1]
|
147 |
-
|
148 |
-
# Find the requested magics.
|
149 |
-
m_line = shell.find_magic(target, 'line')
|
150 |
-
m_cell = shell.find_magic(target, 'cell')
|
151 |
-
if args.line and m_line is None:
|
152 |
-
raise UsageError('Line magic function `%s%s` not found.' %
|
153 |
-
(magic_escapes['line'], target))
|
154 |
-
if args.cell and m_cell is None:
|
155 |
-
raise UsageError('Cell magic function `%s%s` not found.' %
|
156 |
-
(magic_escapes['cell'], target))
|
157 |
-
|
158 |
-
# If --line and --cell are not specified, default to the ones
|
159 |
-
# that are available.
|
160 |
-
if not args.line and not args.cell:
|
161 |
-
if not m_line and not m_cell:
|
162 |
-
raise UsageError(
|
163 |
-
'No line or cell magic with name `%s` found.' % target
|
164 |
-
)
|
165 |
-
args.line = bool(m_line)
|
166 |
-
args.cell = bool(m_cell)
|
167 |
-
|
168 |
-
params_str = "" if params is None else " " + params
|
169 |
-
|
170 |
-
if args.line:
|
171 |
-
mman.register_alias(name, target, 'line', params)
|
172 |
-
print('Created `%s%s` as an alias for `%s%s%s`.' % (
|
173 |
-
magic_escapes['line'], name,
|
174 |
-
magic_escapes['line'], target, params_str))
|
175 |
-
|
176 |
-
if args.cell:
|
177 |
-
mman.register_alias(name, target, 'cell', params)
|
178 |
-
print('Created `%s%s` as an alias for `%s%s%s`.' % (
|
179 |
-
magic_escapes['cell'], name,
|
180 |
-
magic_escapes['cell'], target, params_str))
|
181 |
-
|
182 |
-
@line_magic
|
183 |
-
def lsmagic(self, parameter_s=''):
|
184 |
-
"""List currently available magic functions."""
|
185 |
-
return MagicsDisplay(self.shell.magics_manager, ignore=[])
|
186 |
-
|
187 |
-
def _magic_docs(self, brief=False, rest=False):
|
188 |
-
"""Return docstrings from magic functions."""
|
189 |
-
mman = self.shell.magics_manager
|
190 |
-
docs = mman.lsmagic_docs(brief, missing='No documentation')
|
191 |
-
|
192 |
-
if rest:
|
193 |
-
format_string = '**%s%s**::\n\n%s\n\n'
|
194 |
-
else:
|
195 |
-
format_string = '%s%s:\n%s\n'
|
196 |
-
|
197 |
-
return ''.join(
|
198 |
-
[format_string % (magic_escapes['line'], fname,
|
199 |
-
indent(dedent(fndoc)))
|
200 |
-
for fname, fndoc in sorted(docs['line'].items())]
|
201 |
-
+
|
202 |
-
[format_string % (magic_escapes['cell'], fname,
|
203 |
-
indent(dedent(fndoc)))
|
204 |
-
for fname, fndoc in sorted(docs['cell'].items())]
|
205 |
-
)
|
206 |
-
|
207 |
-
@line_magic
|
208 |
-
def magic(self, parameter_s=''):
|
209 |
-
"""Print information about the magic function system.
|
210 |
-
|
211 |
-
Supported formats: -latex, -brief, -rest
|
212 |
-
"""
|
213 |
-
|
214 |
-
mode = ''
|
215 |
-
try:
|
216 |
-
mode = parameter_s.split()[0][1:]
|
217 |
-
except IndexError:
|
218 |
-
pass
|
219 |
-
|
220 |
-
brief = (mode == 'brief')
|
221 |
-
rest = (mode == 'rest')
|
222 |
-
magic_docs = self._magic_docs(brief, rest)
|
223 |
-
|
224 |
-
if mode == 'latex':
|
225 |
-
print(self.format_latex(magic_docs))
|
226 |
-
return
|
227 |
-
else:
|
228 |
-
magic_docs = format_screen(magic_docs)
|
229 |
-
|
230 |
-
out = ["""
|
231 |
-
IPython's 'magic' functions
|
232 |
-
===========================
|
233 |
-
|
234 |
-
The magic function system provides a series of functions which allow you to
|
235 |
-
control the behavior of IPython itself, plus a lot of system-type
|
236 |
-
features. There are two kinds of magics, line-oriented and cell-oriented.
|
237 |
-
|
238 |
-
Line magics are prefixed with the % character and work much like OS
|
239 |
-
command-line calls: they get as an argument the rest of the line, where
|
240 |
-
arguments are passed without parentheses or quotes. For example, this will
|
241 |
-
time the given statement::
|
242 |
-
|
243 |
-
%timeit range(1000)
|
244 |
-
|
245 |
-
Cell magics are prefixed with a double %%, and they are functions that get as
|
246 |
-
an argument not only the rest of the line, but also the lines below it in a
|
247 |
-
separate argument. These magics are called with two arguments: the rest of the
|
248 |
-
call line and the body of the cell, consisting of the lines below the first.
|
249 |
-
For example::
|
250 |
-
|
251 |
-
%%timeit x = numpy.random.randn((100, 100))
|
252 |
-
numpy.linalg.svd(x)
|
253 |
-
|
254 |
-
will time the execution of the numpy svd routine, running the assignment of x
|
255 |
-
as part of the setup phase, which is not timed.
|
256 |
-
|
257 |
-
In a line-oriented client (the terminal or Qt console IPython), starting a new
|
258 |
-
input with %% will automatically enter cell mode, and IPython will continue
|
259 |
-
reading input until a blank line is given. In the notebook, simply type the
|
260 |
-
whole cell as one entity, but keep in mind that the %% escape can only be at
|
261 |
-
the very start of the cell.
|
262 |
-
|
263 |
-
NOTE: If you have 'automagic' enabled (via the command line option or with the
|
264 |
-
%automagic function), you don't need to type in the % explicitly for line
|
265 |
-
magics; cell magics always require an explicit '%%' escape. By default,
|
266 |
-
IPython ships with automagic on, so you should only rarely need the % escape.
|
267 |
-
|
268 |
-
Example: typing '%cd mydir' (without the quotes) changes your working directory
|
269 |
-
to 'mydir', if it exists.
|
270 |
-
|
271 |
-
For a list of the available magic functions, use %lsmagic. For a description
|
272 |
-
of any of them, type %magic_name?, e.g. '%cd?'.
|
273 |
-
|
274 |
-
Currently the magic system has the following functions:""",
|
275 |
-
magic_docs,
|
276 |
-
"Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
|
277 |
-
str(self.lsmagic()),
|
278 |
-
]
|
279 |
-
page.page('\n'.join(out))
|
280 |
-
|
281 |
-
|
282 |
-
@line_magic
|
283 |
-
def page(self, parameter_s=''):
|
284 |
-
"""Pretty print the object and display it through a pager.
|
285 |
-
|
286 |
-
%page [options] OBJECT
|
287 |
-
|
288 |
-
If no object is given, use _ (last output).
|
289 |
-
|
290 |
-
Options:
|
291 |
-
|
292 |
-
-r: page str(object), don't pretty-print it."""
|
293 |
-
|
294 |
-
# After a function contributed by Olivier Aubert, slightly modified.
|
295 |
-
|
296 |
-
# Process options/args
|
297 |
-
opts, args = self.parse_options(parameter_s, 'r')
|
298 |
-
raw = 'r' in opts
|
299 |
-
|
300 |
-
oname = args and args or '_'
|
301 |
-
info = self.shell._ofind(oname)
|
302 |
-
if info.found:
|
303 |
-
if raw:
|
304 |
-
txt = str(info.obj)
|
305 |
-
else:
|
306 |
-
txt = pformat(info.obj)
|
307 |
-
page.page(txt)
|
308 |
-
else:
|
309 |
-
print('Object `%s` not found' % oname)
|
310 |
-
|
311 |
-
@line_magic
|
312 |
-
def pprint(self, parameter_s=''):
|
313 |
-
"""Toggle pretty printing on/off."""
|
314 |
-
ptformatter = self.shell.display_formatter.formatters['text/plain']
|
315 |
-
ptformatter.pprint = bool(1 - ptformatter.pprint)
|
316 |
-
print('Pretty printing has been turned',
|
317 |
-
['OFF','ON'][ptformatter.pprint])
|
318 |
-
|
319 |
-
@line_magic
|
320 |
-
def colors(self, parameter_s=''):
|
321 |
-
"""Switch color scheme for prompts, info system and exception handlers.
|
322 |
-
|
323 |
-
Currently implemented schemes: NoColor, Linux, LightBG.
|
324 |
-
|
325 |
-
Color scheme names are not case-sensitive.
|
326 |
-
|
327 |
-
Examples
|
328 |
-
--------
|
329 |
-
To get a plain black and white terminal::
|
330 |
-
|
331 |
-
%colors nocolor
|
332 |
-
"""
|
333 |
-
def color_switch_err(name):
|
334 |
-
warn('Error changing %s color schemes.\n%s' %
|
335 |
-
(name, sys.exc_info()[1]), stacklevel=2)
|
336 |
-
|
337 |
-
|
338 |
-
new_scheme = parameter_s.strip()
|
339 |
-
if not new_scheme:
|
340 |
-
raise UsageError(
|
341 |
-
"%colors: you must specify a color scheme. See '%colors?'")
|
342 |
-
# local shortcut
|
343 |
-
shell = self.shell
|
344 |
-
|
345 |
-
# Set shell colour scheme
|
346 |
-
try:
|
347 |
-
shell.colors = new_scheme
|
348 |
-
shell.refresh_style()
|
349 |
-
except:
|
350 |
-
color_switch_err('shell')
|
351 |
-
|
352 |
-
# Set exception colors
|
353 |
-
try:
|
354 |
-
shell.InteractiveTB.set_colors(scheme = new_scheme)
|
355 |
-
shell.SyntaxTB.set_colors(scheme = new_scheme)
|
356 |
-
except:
|
357 |
-
color_switch_err('exception')
|
358 |
-
|
359 |
-
# Set info (for 'object?') colors
|
360 |
-
if shell.color_info:
|
361 |
-
try:
|
362 |
-
shell.inspector.set_active_scheme(new_scheme)
|
363 |
-
except:
|
364 |
-
color_switch_err('object inspector')
|
365 |
-
else:
|
366 |
-
shell.inspector.set_active_scheme('NoColor')
|
367 |
-
|
368 |
-
@line_magic
|
369 |
-
def xmode(self, parameter_s=''):
|
370 |
-
"""Switch modes for the exception handlers.
|
371 |
-
|
372 |
-
Valid modes: Plain, Context, Verbose, and Minimal.
|
373 |
-
|
374 |
-
If called without arguments, acts as a toggle.
|
375 |
-
|
376 |
-
When in verbose mode the value `--show` (and `--hide`)
|
377 |
-
will respectively show (or hide) frames with ``__tracebackhide__ =
|
378 |
-
True`` value set.
|
379 |
-
"""
|
380 |
-
|
381 |
-
def xmode_switch_err(name):
|
382 |
-
warn('Error changing %s exception modes.\n%s' %
|
383 |
-
(name,sys.exc_info()[1]))
|
384 |
-
|
385 |
-
shell = self.shell
|
386 |
-
if parameter_s.strip() == "--show":
|
387 |
-
shell.InteractiveTB.skip_hidden = False
|
388 |
-
return
|
389 |
-
if parameter_s.strip() == "--hide":
|
390 |
-
shell.InteractiveTB.skip_hidden = True
|
391 |
-
return
|
392 |
-
|
393 |
-
new_mode = parameter_s.strip().capitalize()
|
394 |
-
try:
|
395 |
-
shell.InteractiveTB.set_mode(mode=new_mode)
|
396 |
-
print('Exception reporting mode:',shell.InteractiveTB.mode)
|
397 |
-
except:
|
398 |
-
xmode_switch_err('user')
|
399 |
-
|
400 |
-
@line_magic
|
401 |
-
def quickref(self, arg):
|
402 |
-
""" Show a quick reference sheet """
|
403 |
-
from IPython.core.usage import quick_reference
|
404 |
-
qr = quick_reference + self._magic_docs(brief=True)
|
405 |
-
page.page(qr)
|
406 |
-
|
407 |
-
@line_magic
|
408 |
-
def doctest_mode(self, parameter_s=''):
|
409 |
-
"""Toggle doctest mode on and off.
|
410 |
-
|
411 |
-
This mode is intended to make IPython behave as much as possible like a
|
412 |
-
plain Python shell, from the perspective of how its prompts, exceptions
|
413 |
-
and output look. This makes it easy to copy and paste parts of a
|
414 |
-
session into doctests. It does so by:
|
415 |
-
|
416 |
-
- Changing the prompts to the classic ``>>>`` ones.
|
417 |
-
- Changing the exception reporting mode to 'Plain'.
|
418 |
-
- Disabling pretty-printing of output.
|
419 |
-
|
420 |
-
Note that IPython also supports the pasting of code snippets that have
|
421 |
-
leading '>>>' and '...' prompts in them. This means that you can paste
|
422 |
-
doctests from files or docstrings (even if they have leading
|
423 |
-
whitespace), and the code will execute correctly. You can then use
|
424 |
-
'%history -t' to see the translated history; this will give you the
|
425 |
-
input after removal of all the leading prompts and whitespace, which
|
426 |
-
can be pasted back into an editor.
|
427 |
-
|
428 |
-
With these features, you can switch into this mode easily whenever you
|
429 |
-
need to do testing and changes to doctests, without having to leave
|
430 |
-
your existing IPython session.
|
431 |
-
"""
|
432 |
-
|
433 |
-
# Shorthands
|
434 |
-
shell = self.shell
|
435 |
-
meta = shell.meta
|
436 |
-
disp_formatter = self.shell.display_formatter
|
437 |
-
ptformatter = disp_formatter.formatters['text/plain']
|
438 |
-
# dstore is a data store kept in the instance metadata bag to track any
|
439 |
-
# changes we make, so we can undo them later.
|
440 |
-
dstore = meta.setdefault('doctest_mode',Struct())
|
441 |
-
save_dstore = dstore.setdefault
|
442 |
-
|
443 |
-
# save a few values we'll need to recover later
|
444 |
-
mode = save_dstore('mode',False)
|
445 |
-
save_dstore('rc_pprint',ptformatter.pprint)
|
446 |
-
save_dstore('xmode',shell.InteractiveTB.mode)
|
447 |
-
save_dstore('rc_separate_out',shell.separate_out)
|
448 |
-
save_dstore('rc_separate_out2',shell.separate_out2)
|
449 |
-
save_dstore('rc_separate_in',shell.separate_in)
|
450 |
-
save_dstore('rc_active_types',disp_formatter.active_types)
|
451 |
-
|
452 |
-
if not mode:
|
453 |
-
# turn on
|
454 |
-
|
455 |
-
# Prompt separators like plain python
|
456 |
-
shell.separate_in = ''
|
457 |
-
shell.separate_out = ''
|
458 |
-
shell.separate_out2 = ''
|
459 |
-
|
460 |
-
|
461 |
-
ptformatter.pprint = False
|
462 |
-
disp_formatter.active_types = ['text/plain']
|
463 |
-
|
464 |
-
shell.run_line_magic("xmode", "Plain")
|
465 |
-
else:
|
466 |
-
# turn off
|
467 |
-
shell.separate_in = dstore.rc_separate_in
|
468 |
-
|
469 |
-
shell.separate_out = dstore.rc_separate_out
|
470 |
-
shell.separate_out2 = dstore.rc_separate_out2
|
471 |
-
|
472 |
-
ptformatter.pprint = dstore.rc_pprint
|
473 |
-
disp_formatter.active_types = dstore.rc_active_types
|
474 |
-
|
475 |
-
shell.run_line_magic("xmode", dstore.xmode)
|
476 |
-
|
477 |
-
# mode here is the state before we switch; switch_doctest_mode takes
|
478 |
-
# the mode we're switching to.
|
479 |
-
shell.switch_doctest_mode(not mode)
|
480 |
-
|
481 |
-
# Store new mode and inform
|
482 |
-
dstore.mode = bool(not mode)
|
483 |
-
mode_label = ['OFF','ON'][dstore.mode]
|
484 |
-
print('Doctest mode is:', mode_label)
|
485 |
-
|
486 |
-
@line_magic
|
487 |
-
def gui(self, parameter_s=''):
|
488 |
-
"""Enable or disable IPython GUI event loop integration.
|
489 |
-
|
490 |
-
%gui [GUINAME]
|
491 |
-
|
492 |
-
This magic replaces IPython's threaded shells that were activated
|
493 |
-
using the (pylab/wthread/etc.) command line flags. GUI toolkits
|
494 |
-
can now be enabled at runtime and keyboard
|
495 |
-
interrupts should work without any problems. The following toolkits
|
496 |
-
are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
|
497 |
-
|
498 |
-
%gui wx # enable wxPython event loop integration
|
499 |
-
%gui qt # enable PyQt/PySide event loop integration
|
500 |
-
# with the latest version available.
|
501 |
-
%gui qt6 # enable PyQt6/PySide6 event loop integration
|
502 |
-
%gui qt5 # enable PyQt5/PySide2 event loop integration
|
503 |
-
%gui gtk # enable PyGTK event loop integration
|
504 |
-
%gui gtk3 # enable Gtk3 event loop integration
|
505 |
-
%gui gtk4 # enable Gtk4 event loop integration
|
506 |
-
%gui tk # enable Tk event loop integration
|
507 |
-
%gui osx # enable Cocoa event loop integration
|
508 |
-
# (requires %matplotlib 1.1)
|
509 |
-
%gui # disable all event loop integration
|
510 |
-
|
511 |
-
WARNING: after any of these has been called you can simply create
|
512 |
-
an application object, but DO NOT start the event loop yourself, as
|
513 |
-
we have already handled that.
|
514 |
-
"""
|
515 |
-
opts, arg = self.parse_options(parameter_s, '')
|
516 |
-
if arg=='': arg = None
|
517 |
-
try:
|
518 |
-
return self.shell.enable_gui(arg)
|
519 |
-
except Exception as e:
|
520 |
-
# print simple error message, rather than traceback if we can't
|
521 |
-
# hook up the GUI
|
522 |
-
error(str(e))
|
523 |
-
|
524 |
-
@skip_doctest
|
525 |
-
@line_magic
|
526 |
-
def precision(self, s=''):
|
527 |
-
"""Set floating point precision for pretty printing.
|
528 |
-
|
529 |
-
Can set either integer precision or a format string.
|
530 |
-
|
531 |
-
If numpy has been imported and precision is an int,
|
532 |
-
numpy display precision will also be set, via ``numpy.set_printoptions``.
|
533 |
-
|
534 |
-
If no argument is given, defaults will be restored.
|
535 |
-
|
536 |
-
Examples
|
537 |
-
--------
|
538 |
-
::
|
539 |
-
|
540 |
-
In [1]: from math import pi
|
541 |
-
|
542 |
-
In [2]: %precision 3
|
543 |
-
Out[2]: '%.3f'
|
544 |
-
|
545 |
-
In [3]: pi
|
546 |
-
Out[3]: 3.142
|
547 |
-
|
548 |
-
In [4]: %precision %i
|
549 |
-
Out[4]: '%i'
|
550 |
-
|
551 |
-
In [5]: pi
|
552 |
-
Out[5]: 3
|
553 |
-
|
554 |
-
In [6]: %precision %e
|
555 |
-
Out[6]: '%e'
|
556 |
-
|
557 |
-
In [7]: pi**10
|
558 |
-
Out[7]: 9.364805e+04
|
559 |
-
|
560 |
-
In [8]: %precision
|
561 |
-
Out[8]: '%r'
|
562 |
-
|
563 |
-
In [9]: pi**10
|
564 |
-
Out[9]: 93648.047476082982
|
565 |
-
"""
|
566 |
-
ptformatter = self.shell.display_formatter.formatters['text/plain']
|
567 |
-
ptformatter.float_precision = s
|
568 |
-
return ptformatter.float_format
|
569 |
-
|
570 |
-
@magic_arguments.magic_arguments()
|
571 |
-
@magic_arguments.argument(
|
572 |
-
'filename', type=str,
|
573 |
-
help='Notebook name or filename'
|
574 |
-
)
|
575 |
-
@line_magic
|
576 |
-
def notebook(self, s):
|
577 |
-
"""Export and convert IPython notebooks.
|
578 |
-
|
579 |
-
This function can export the current IPython history to a notebook file.
|
580 |
-
For example, to export the history to "foo.ipynb" do "%notebook foo.ipynb".
|
581 |
-
"""
|
582 |
-
args = magic_arguments.parse_argstring(self.notebook, s)
|
583 |
-
outfname = os.path.expanduser(args.filename)
|
584 |
-
|
585 |
-
from nbformat import write, v4
|
586 |
-
|
587 |
-
cells = []
|
588 |
-
hist = list(self.shell.history_manager.get_range())
|
589 |
-
if(len(hist)<=1):
|
590 |
-
raise ValueError('History is empty, cannot export')
|
591 |
-
for session, execution_count, source in hist[:-1]:
|
592 |
-
cells.append(v4.new_code_cell(
|
593 |
-
execution_count=execution_count,
|
594 |
-
source=source
|
595 |
-
))
|
596 |
-
nb = v4.new_notebook(cells=cells)
|
597 |
-
with io.open(outfname, "w", encoding="utf-8") as f:
|
598 |
-
write(nb, f, version=4)
|
599 |
-
|
600 |
-
@magics_class
|
601 |
-
class AsyncMagics(BasicMagics):
|
602 |
-
|
603 |
-
@line_magic
|
604 |
-
def autoawait(self, parameter_s):
|
605 |
-
"""
|
606 |
-
Allow to change the status of the autoawait option.
|
607 |
-
|
608 |
-
This allow you to set a specific asynchronous code runner.
|
609 |
-
|
610 |
-
If no value is passed, print the currently used asynchronous integration
|
611 |
-
and whether it is activated.
|
612 |
-
|
613 |
-
It can take a number of value evaluated in the following order:
|
614 |
-
|
615 |
-
- False/false/off deactivate autoawait integration
|
616 |
-
- True/true/on activate autoawait integration using configured default
|
617 |
-
loop
|
618 |
-
- asyncio/curio/trio activate autoawait integration and use integration
|
619 |
-
with said library.
|
620 |
-
|
621 |
-
- `sync` turn on the pseudo-sync integration (mostly used for
|
622 |
-
`IPython.embed()` which does not run IPython with a real eventloop and
|
623 |
-
deactivate running asynchronous code. Turning on Asynchronous code with
|
624 |
-
the pseudo sync loop is undefined behavior and may lead IPython to crash.
|
625 |
-
|
626 |
-
If the passed parameter does not match any of the above and is a python
|
627 |
-
identifier, get said object from user namespace and set it as the
|
628 |
-
runner, and activate autoawait.
|
629 |
-
|
630 |
-
If the object is a fully qualified object name, attempt to import it and
|
631 |
-
set it as the runner, and activate autoawait.
|
632 |
-
|
633 |
-
The exact behavior of autoawait is experimental and subject to change
|
634 |
-
across version of IPython and Python.
|
635 |
-
"""
|
636 |
-
|
637 |
-
param = parameter_s.strip()
|
638 |
-
d = {True: "on", False: "off"}
|
639 |
-
|
640 |
-
if not param:
|
641 |
-
print("IPython autoawait is `{}`, and set to use `{}`".format(
|
642 |
-
d[self.shell.autoawait],
|
643 |
-
self.shell.loop_runner
|
644 |
-
))
|
645 |
-
return None
|
646 |
-
|
647 |
-
if param.lower() in ('false', 'off'):
|
648 |
-
self.shell.autoawait = False
|
649 |
-
return None
|
650 |
-
if param.lower() in ('true', 'on'):
|
651 |
-
self.shell.autoawait = True
|
652 |
-
return None
|
653 |
-
|
654 |
-
if param in self.shell.loop_runner_map:
|
655 |
-
self.shell.loop_runner, self.shell.autoawait = self.shell.loop_runner_map[param]
|
656 |
-
return None
|
657 |
-
|
658 |
-
if param in self.shell.user_ns :
|
659 |
-
self.shell.loop_runner = self.shell.user_ns[param]
|
660 |
-
self.shell.autoawait = True
|
661 |
-
return None
|
662 |
-
|
663 |
-
runner = import_item(param)
|
664 |
-
|
665 |
-
self.shell.loop_runner = runner
|
666 |
-
self.shell.autoawait = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/code.py
DELETED
@@ -1,757 +0,0 @@
|
|
1 |
-
"""Implementation of code management magic functions.
|
2 |
-
"""
|
3 |
-
#-----------------------------------------------------------------------------
|
4 |
-
# Copyright (c) 2012 The IPython Development Team.
|
5 |
-
#
|
6 |
-
# Distributed under the terms of the Modified BSD License.
|
7 |
-
#
|
8 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
9 |
-
#-----------------------------------------------------------------------------
|
10 |
-
|
11 |
-
#-----------------------------------------------------------------------------
|
12 |
-
# Imports
|
13 |
-
#-----------------------------------------------------------------------------
|
14 |
-
|
15 |
-
# Stdlib
|
16 |
-
import inspect
|
17 |
-
import io
|
18 |
-
import os
|
19 |
-
import re
|
20 |
-
import sys
|
21 |
-
import ast
|
22 |
-
from itertools import chain
|
23 |
-
from urllib.request import Request, urlopen
|
24 |
-
from urllib.parse import urlencode
|
25 |
-
from pathlib import Path
|
26 |
-
|
27 |
-
# Our own packages
|
28 |
-
from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
|
29 |
-
from IPython.core.macro import Macro
|
30 |
-
from IPython.core.magic import Magics, magics_class, line_magic
|
31 |
-
from IPython.core.oinspect import find_file, find_source_lines
|
32 |
-
from IPython.core.release import version
|
33 |
-
from IPython.testing.skipdoctest import skip_doctest
|
34 |
-
from IPython.utils.contexts import preserve_keys
|
35 |
-
from IPython.utils.path import get_py_filename
|
36 |
-
from warnings import warn
|
37 |
-
from logging import error
|
38 |
-
from IPython.utils.text import get_text_list
|
39 |
-
|
40 |
-
#-----------------------------------------------------------------------------
|
41 |
-
# Magic implementation classes
|
42 |
-
#-----------------------------------------------------------------------------
|
43 |
-
|
44 |
-
# Used for exception handling in magic_edit
|
45 |
-
class MacroToEdit(ValueError): pass
|
46 |
-
|
47 |
-
ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
|
48 |
-
|
49 |
-
# To match, e.g. 8-10 1:5 :10 3-
|
50 |
-
range_re = re.compile(r"""
|
51 |
-
(?P<start>\d+)?
|
52 |
-
((?P<sep>[\-:])
|
53 |
-
(?P<end>\d+)?)?
|
54 |
-
$""", re.VERBOSE)
|
55 |
-
|
56 |
-
|
57 |
-
def extract_code_ranges(ranges_str):
|
58 |
-
"""Turn a string of range for %%load into 2-tuples of (start, stop)
|
59 |
-
ready to use as a slice of the content split by lines.
|
60 |
-
|
61 |
-
Examples
|
62 |
-
--------
|
63 |
-
list(extract_input_ranges("5-10 2"))
|
64 |
-
[(4, 10), (1, 2)]
|
65 |
-
"""
|
66 |
-
for range_str in ranges_str.split():
|
67 |
-
rmatch = range_re.match(range_str)
|
68 |
-
if not rmatch:
|
69 |
-
continue
|
70 |
-
sep = rmatch.group("sep")
|
71 |
-
start = rmatch.group("start")
|
72 |
-
end = rmatch.group("end")
|
73 |
-
|
74 |
-
if sep == '-':
|
75 |
-
start = int(start) - 1 if start else None
|
76 |
-
end = int(end) if end else None
|
77 |
-
elif sep == ':':
|
78 |
-
start = int(start) - 1 if start else None
|
79 |
-
end = int(end) - 1 if end else None
|
80 |
-
else:
|
81 |
-
end = int(start)
|
82 |
-
start = int(start) - 1
|
83 |
-
yield (start, end)
|
84 |
-
|
85 |
-
|
86 |
-
def extract_symbols(code, symbols):
|
87 |
-
"""
|
88 |
-
Return a tuple (blocks, not_found)
|
89 |
-
where ``blocks`` is a list of code fragments
|
90 |
-
for each symbol parsed from code, and ``not_found`` are
|
91 |
-
symbols not found in the code.
|
92 |
-
|
93 |
-
For example::
|
94 |
-
|
95 |
-
In [1]: code = '''a = 10
|
96 |
-
...: def b(): return 42
|
97 |
-
...: class A: pass'''
|
98 |
-
|
99 |
-
In [2]: extract_symbols(code, 'A,b,z')
|
100 |
-
Out[2]: (['class A: pass\\n', 'def b(): return 42\\n'], ['z'])
|
101 |
-
"""
|
102 |
-
symbols = symbols.split(',')
|
103 |
-
|
104 |
-
# this will raise SyntaxError if code isn't valid Python
|
105 |
-
py_code = ast.parse(code)
|
106 |
-
|
107 |
-
marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
|
108 |
-
code = code.split('\n')
|
109 |
-
|
110 |
-
symbols_lines = {}
|
111 |
-
|
112 |
-
# we already know the start_lineno of each symbol (marks).
|
113 |
-
# To find each end_lineno, we traverse in reverse order until each
|
114 |
-
# non-blank line
|
115 |
-
end = len(code)
|
116 |
-
for name, start in reversed(marks):
|
117 |
-
while not code[end - 1].strip():
|
118 |
-
end -= 1
|
119 |
-
if name:
|
120 |
-
symbols_lines[name] = (start - 1, end)
|
121 |
-
end = start - 1
|
122 |
-
|
123 |
-
# Now symbols_lines is a map
|
124 |
-
# {'symbol_name': (start_lineno, end_lineno), ...}
|
125 |
-
|
126 |
-
# fill a list with chunks of codes for each requested symbol
|
127 |
-
blocks = []
|
128 |
-
not_found = []
|
129 |
-
for symbol in symbols:
|
130 |
-
if symbol in symbols_lines:
|
131 |
-
start, end = symbols_lines[symbol]
|
132 |
-
blocks.append('\n'.join(code[start:end]) + '\n')
|
133 |
-
else:
|
134 |
-
not_found.append(symbol)
|
135 |
-
|
136 |
-
return blocks, not_found
|
137 |
-
|
138 |
-
def strip_initial_indent(lines):
|
139 |
-
"""For %load, strip indent from lines until finding an unindented line.
|
140 |
-
|
141 |
-
https://github.com/ipython/ipython/issues/9775
|
142 |
-
"""
|
143 |
-
indent_re = re.compile(r'\s+')
|
144 |
-
|
145 |
-
it = iter(lines)
|
146 |
-
first_line = next(it)
|
147 |
-
indent_match = indent_re.match(first_line)
|
148 |
-
|
149 |
-
if indent_match:
|
150 |
-
# First line was indented
|
151 |
-
indent = indent_match.group()
|
152 |
-
yield first_line[len(indent):]
|
153 |
-
|
154 |
-
for line in it:
|
155 |
-
if line.startswith(indent):
|
156 |
-
yield line[len(indent) :]
|
157 |
-
elif line in ("\n", "\r\n") or len(line) == 0:
|
158 |
-
yield line
|
159 |
-
else:
|
160 |
-
# Less indented than the first line - stop dedenting
|
161 |
-
yield line
|
162 |
-
break
|
163 |
-
else:
|
164 |
-
yield first_line
|
165 |
-
|
166 |
-
# Pass the remaining lines through without dedenting
|
167 |
-
for line in it:
|
168 |
-
yield line
|
169 |
-
|
170 |
-
|
171 |
-
class InteractivelyDefined(Exception):
|
172 |
-
"""Exception for interactively defined variable in magic_edit"""
|
173 |
-
def __init__(self, index):
|
174 |
-
self.index = index
|
175 |
-
|
176 |
-
|
177 |
-
@magics_class
|
178 |
-
class CodeMagics(Magics):
|
179 |
-
"""Magics related to code management (loading, saving, editing, ...)."""
|
180 |
-
|
181 |
-
def __init__(self, *args, **kwargs):
|
182 |
-
self._knowntemps = set()
|
183 |
-
super(CodeMagics, self).__init__(*args, **kwargs)
|
184 |
-
|
185 |
-
@line_magic
|
186 |
-
def save(self, parameter_s=''):
|
187 |
-
"""Save a set of lines or a macro to a given filename.
|
188 |
-
|
189 |
-
Usage:\\
|
190 |
-
%save [options] filename [history]
|
191 |
-
|
192 |
-
Options:
|
193 |
-
|
194 |
-
-r: use 'raw' input. By default, the 'processed' history is used,
|
195 |
-
so that magics are loaded in their transformed version to valid
|
196 |
-
Python. If this option is given, the raw input as typed as the
|
197 |
-
command line is used instead.
|
198 |
-
|
199 |
-
-f: force overwrite. If file exists, %save will prompt for overwrite
|
200 |
-
unless -f is given.
|
201 |
-
|
202 |
-
-a: append to the file instead of overwriting it.
|
203 |
-
|
204 |
-
The history argument uses the same syntax as %history for input ranges,
|
205 |
-
then saves the lines to the filename you specify.
|
206 |
-
|
207 |
-
If no ranges are specified, saves history of the current session up to
|
208 |
-
this point.
|
209 |
-
|
210 |
-
It adds a '.py' extension to the file if you don't do so yourself, and
|
211 |
-
it asks for confirmation before overwriting existing files.
|
212 |
-
|
213 |
-
If `-r` option is used, the default extension is `.ipy`.
|
214 |
-
"""
|
215 |
-
|
216 |
-
opts,args = self.parse_options(parameter_s,'fra',mode='list')
|
217 |
-
if not args:
|
218 |
-
raise UsageError('Missing filename.')
|
219 |
-
raw = 'r' in opts
|
220 |
-
force = 'f' in opts
|
221 |
-
append = 'a' in opts
|
222 |
-
mode = 'a' if append else 'w'
|
223 |
-
ext = '.ipy' if raw else '.py'
|
224 |
-
fname, codefrom = args[0], " ".join(args[1:])
|
225 |
-
if not fname.endswith(('.py','.ipy')):
|
226 |
-
fname += ext
|
227 |
-
fname = os.path.expanduser(fname)
|
228 |
-
file_exists = os.path.isfile(fname)
|
229 |
-
if file_exists and not force and not append:
|
230 |
-
try:
|
231 |
-
overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
|
232 |
-
except StdinNotImplementedError:
|
233 |
-
print("File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s))
|
234 |
-
return
|
235 |
-
if not overwrite :
|
236 |
-
print('Operation cancelled.')
|
237 |
-
return
|
238 |
-
try:
|
239 |
-
cmds = self.shell.find_user_code(codefrom,raw)
|
240 |
-
except (TypeError, ValueError) as e:
|
241 |
-
print(e.args[0])
|
242 |
-
return
|
243 |
-
with io.open(fname, mode, encoding="utf-8") as f:
|
244 |
-
if not file_exists or not append:
|
245 |
-
f.write("# coding: utf-8\n")
|
246 |
-
f.write(cmds)
|
247 |
-
# make sure we end on a newline
|
248 |
-
if not cmds.endswith('\n'):
|
249 |
-
f.write('\n')
|
250 |
-
print('The following commands were written to file `%s`:' % fname)
|
251 |
-
print(cmds)
|
252 |
-
|
253 |
-
@line_magic
|
254 |
-
def pastebin(self, parameter_s=''):
|
255 |
-
"""Upload code to dpaste.com, returning the URL.
|
256 |
-
|
257 |
-
Usage:\\
|
258 |
-
%pastebin [-d "Custom description"][-e 24] 1-7
|
259 |
-
|
260 |
-
The argument can be an input history range, a filename, or the name of a
|
261 |
-
string or macro.
|
262 |
-
|
263 |
-
If no arguments are given, uploads the history of this session up to
|
264 |
-
this point.
|
265 |
-
|
266 |
-
Options:
|
267 |
-
|
268 |
-
-d: Pass a custom description. The default will say
|
269 |
-
"Pasted from IPython".
|
270 |
-
-e: Pass number of days for the link to be expired.
|
271 |
-
The default will be 7 days.
|
272 |
-
"""
|
273 |
-
opts, args = self.parse_options(parameter_s, "d:e:")
|
274 |
-
|
275 |
-
try:
|
276 |
-
code = self.shell.find_user_code(args)
|
277 |
-
except (ValueError, TypeError) as e:
|
278 |
-
print(e.args[0])
|
279 |
-
return
|
280 |
-
|
281 |
-
expiry_days = 7
|
282 |
-
try:
|
283 |
-
expiry_days = int(opts.get("e", 7))
|
284 |
-
except ValueError as e:
|
285 |
-
print(e.args[0].capitalize())
|
286 |
-
return
|
287 |
-
if expiry_days < 1 or expiry_days > 365:
|
288 |
-
print("Expiry days should be in range of 1 to 365")
|
289 |
-
return
|
290 |
-
|
291 |
-
post_data = urlencode(
|
292 |
-
{
|
293 |
-
"title": opts.get("d", "Pasted from IPython"),
|
294 |
-
"syntax": "python",
|
295 |
-
"content": code,
|
296 |
-
"expiry_days": expiry_days,
|
297 |
-
}
|
298 |
-
).encode("utf-8")
|
299 |
-
|
300 |
-
request = Request(
|
301 |
-
"https://dpaste.com/api/v2/",
|
302 |
-
headers={"User-Agent": "IPython v{}".format(version)},
|
303 |
-
)
|
304 |
-
response = urlopen(request, post_data)
|
305 |
-
return response.headers.get('Location')
|
306 |
-
|
307 |
-
@line_magic
|
308 |
-
def loadpy(self, arg_s):
|
309 |
-
"""Alias of `%load`
|
310 |
-
|
311 |
-
`%loadpy` has gained some flexibility and dropped the requirement of a `.py`
|
312 |
-
extension. So it has been renamed simply into %load. You can look at
|
313 |
-
`%load`'s docstring for more info.
|
314 |
-
"""
|
315 |
-
self.load(arg_s)
|
316 |
-
|
317 |
-
@line_magic
|
318 |
-
def load(self, arg_s):
|
319 |
-
"""Load code into the current frontend.
|
320 |
-
|
321 |
-
Usage:\\
|
322 |
-
%load [options] source
|
323 |
-
|
324 |
-
where source can be a filename, URL, input history range, macro, or
|
325 |
-
element in the user namespace
|
326 |
-
|
327 |
-
If no arguments are given, loads the history of this session up to this
|
328 |
-
point.
|
329 |
-
|
330 |
-
Options:
|
331 |
-
|
332 |
-
-r <lines>: Specify lines or ranges of lines to load from the source.
|
333 |
-
Ranges could be specified as x-y (x..y) or in python-style x:y
|
334 |
-
(x..(y-1)). Both limits x and y can be left blank (meaning the
|
335 |
-
beginning and end of the file, respectively).
|
336 |
-
|
337 |
-
-s <symbols>: Specify function or classes to load from python source.
|
338 |
-
|
339 |
-
-y : Don't ask confirmation for loading source above 200 000 characters.
|
340 |
-
|
341 |
-
-n : Include the user's namespace when searching for source code.
|
342 |
-
|
343 |
-
This magic command can either take a local filename, a URL, an history
|
344 |
-
range (see %history) or a macro as argument, it will prompt for
|
345 |
-
confirmation before loading source with more than 200 000 characters, unless
|
346 |
-
-y flag is passed or if the frontend does not support raw_input::
|
347 |
-
|
348 |
-
%load
|
349 |
-
%load myscript.py
|
350 |
-
%load 7-27
|
351 |
-
%load myMacro
|
352 |
-
%load http://www.example.com/myscript.py
|
353 |
-
%load -r 5-10 myscript.py
|
354 |
-
%load -r 10-20,30,40: foo.py
|
355 |
-
%load -s MyClass,wonder_function myscript.py
|
356 |
-
%load -n MyClass
|
357 |
-
%load -n my_module.wonder_function
|
358 |
-
"""
|
359 |
-
opts,args = self.parse_options(arg_s,'yns:r:')
|
360 |
-
search_ns = 'n' in opts
|
361 |
-
contents = self.shell.find_user_code(args, search_ns=search_ns)
|
362 |
-
|
363 |
-
if 's' in opts:
|
364 |
-
try:
|
365 |
-
blocks, not_found = extract_symbols(contents, opts['s'])
|
366 |
-
except SyntaxError:
|
367 |
-
# non python code
|
368 |
-
error("Unable to parse the input as valid Python code")
|
369 |
-
return
|
370 |
-
|
371 |
-
if len(not_found) == 1:
|
372 |
-
warn('The symbol `%s` was not found' % not_found[0])
|
373 |
-
elif len(not_found) > 1:
|
374 |
-
warn('The symbols %s were not found' % get_text_list(not_found,
|
375 |
-
wrap_item_with='`')
|
376 |
-
)
|
377 |
-
|
378 |
-
contents = '\n'.join(blocks)
|
379 |
-
|
380 |
-
if 'r' in opts:
|
381 |
-
ranges = opts['r'].replace(',', ' ')
|
382 |
-
lines = contents.split('\n')
|
383 |
-
slices = extract_code_ranges(ranges)
|
384 |
-
contents = [lines[slice(*slc)] for slc in slices]
|
385 |
-
contents = '\n'.join(strip_initial_indent(chain.from_iterable(contents)))
|
386 |
-
|
387 |
-
l = len(contents)
|
388 |
-
|
389 |
-
# 200 000 is ~ 2500 full 80 character lines
|
390 |
-
# so in average, more than 5000 lines
|
391 |
-
if l > 200000 and 'y' not in opts:
|
392 |
-
try:
|
393 |
-
ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
|
394 |
-
" (%d characters). Continue (y/[N]) ?" % l), default='n' )
|
395 |
-
except StdinNotImplementedError:
|
396 |
-
#assume yes if raw input not implemented
|
397 |
-
ans = True
|
398 |
-
|
399 |
-
if ans is False :
|
400 |
-
print('Operation cancelled.')
|
401 |
-
return
|
402 |
-
|
403 |
-
contents = "# %load {}\n".format(arg_s) + contents
|
404 |
-
|
405 |
-
self.shell.set_next_input(contents, replace=True)
|
406 |
-
|
407 |
-
@staticmethod
|
408 |
-
def _find_edit_target(shell, args, opts, last_call):
|
409 |
-
"""Utility method used by magic_edit to find what to edit."""
|
410 |
-
|
411 |
-
def make_filename(arg):
|
412 |
-
"Make a filename from the given args"
|
413 |
-
try:
|
414 |
-
filename = get_py_filename(arg)
|
415 |
-
except IOError:
|
416 |
-
# If it ends with .py but doesn't already exist, assume we want
|
417 |
-
# a new file.
|
418 |
-
if arg.endswith('.py'):
|
419 |
-
filename = arg
|
420 |
-
else:
|
421 |
-
filename = None
|
422 |
-
return filename
|
423 |
-
|
424 |
-
# Set a few locals from the options for convenience:
|
425 |
-
opts_prev = 'p' in opts
|
426 |
-
opts_raw = 'r' in opts
|
427 |
-
|
428 |
-
# custom exceptions
|
429 |
-
class DataIsObject(Exception): pass
|
430 |
-
|
431 |
-
# Default line number value
|
432 |
-
lineno = opts.get('n',None)
|
433 |
-
|
434 |
-
if opts_prev:
|
435 |
-
args = '_%s' % last_call[0]
|
436 |
-
if args not in shell.user_ns:
|
437 |
-
args = last_call[1]
|
438 |
-
|
439 |
-
# by default this is done with temp files, except when the given
|
440 |
-
# arg is a filename
|
441 |
-
use_temp = True
|
442 |
-
|
443 |
-
data = ''
|
444 |
-
|
445 |
-
# First, see if the arguments should be a filename.
|
446 |
-
filename = make_filename(args)
|
447 |
-
if filename:
|
448 |
-
use_temp = False
|
449 |
-
elif args:
|
450 |
-
# Mode where user specifies ranges of lines, like in %macro.
|
451 |
-
data = shell.extract_input_lines(args, opts_raw)
|
452 |
-
if not data:
|
453 |
-
try:
|
454 |
-
# Load the parameter given as a variable. If not a string,
|
455 |
-
# process it as an object instead (below)
|
456 |
-
|
457 |
-
# print('*** args',args,'type',type(args)) # dbg
|
458 |
-
data = eval(args, shell.user_ns)
|
459 |
-
if not isinstance(data, str):
|
460 |
-
raise DataIsObject
|
461 |
-
|
462 |
-
except (NameError,SyntaxError):
|
463 |
-
# given argument is not a variable, try as a filename
|
464 |
-
filename = make_filename(args)
|
465 |
-
if filename is None:
|
466 |
-
warn("Argument given (%s) can't be found as a variable "
|
467 |
-
"or as a filename." % args)
|
468 |
-
return (None, None, None)
|
469 |
-
use_temp = False
|
470 |
-
|
471 |
-
except DataIsObject as e:
|
472 |
-
# macros have a special edit function
|
473 |
-
if isinstance(data, Macro):
|
474 |
-
raise MacroToEdit(data) from e
|
475 |
-
|
476 |
-
# For objects, try to edit the file where they are defined
|
477 |
-
filename = find_file(data)
|
478 |
-
if filename:
|
479 |
-
if 'fakemodule' in filename.lower() and \
|
480 |
-
inspect.isclass(data):
|
481 |
-
# class created by %edit? Try to find source
|
482 |
-
# by looking for method definitions instead, the
|
483 |
-
# __module__ in those classes is FakeModule.
|
484 |
-
attrs = [getattr(data, aname) for aname in dir(data)]
|
485 |
-
for attr in attrs:
|
486 |
-
if not inspect.ismethod(attr):
|
487 |
-
continue
|
488 |
-
filename = find_file(attr)
|
489 |
-
if filename and \
|
490 |
-
'fakemodule' not in filename.lower():
|
491 |
-
# change the attribute to be the edit
|
492 |
-
# target instead
|
493 |
-
data = attr
|
494 |
-
break
|
495 |
-
|
496 |
-
m = ipython_input_pat.match(os.path.basename(filename))
|
497 |
-
if m:
|
498 |
-
raise InteractivelyDefined(int(m.groups()[0])) from e
|
499 |
-
|
500 |
-
datafile = 1
|
501 |
-
if filename is None:
|
502 |
-
filename = make_filename(args)
|
503 |
-
datafile = 1
|
504 |
-
if filename is not None:
|
505 |
-
# only warn about this if we get a real name
|
506 |
-
warn('Could not find file where `%s` is defined.\n'
|
507 |
-
'Opening a file named `%s`' % (args, filename))
|
508 |
-
# Now, make sure we can actually read the source (if it was
|
509 |
-
# in a temp file it's gone by now).
|
510 |
-
if datafile:
|
511 |
-
if lineno is None:
|
512 |
-
lineno = find_source_lines(data)
|
513 |
-
if lineno is None:
|
514 |
-
filename = make_filename(args)
|
515 |
-
if filename is None:
|
516 |
-
warn('The file where `%s` was defined '
|
517 |
-
'cannot be read or found.' % data)
|
518 |
-
return (None, None, None)
|
519 |
-
use_temp = False
|
520 |
-
|
521 |
-
if use_temp:
|
522 |
-
filename = shell.mktempfile(data)
|
523 |
-
print('IPython will make a temporary file named:',filename)
|
524 |
-
|
525 |
-
# use last_call to remember the state of the previous call, but don't
|
526 |
-
# let it be clobbered by successive '-p' calls.
|
527 |
-
try:
|
528 |
-
last_call[0] = shell.displayhook.prompt_count
|
529 |
-
if not opts_prev:
|
530 |
-
last_call[1] = args
|
531 |
-
except:
|
532 |
-
pass
|
533 |
-
|
534 |
-
|
535 |
-
return filename, lineno, use_temp
|
536 |
-
|
537 |
-
def _edit_macro(self,mname,macro):
|
538 |
-
"""open an editor with the macro data in a file"""
|
539 |
-
filename = self.shell.mktempfile(macro.value)
|
540 |
-
self.shell.hooks.editor(filename)
|
541 |
-
|
542 |
-
# and make a new macro object, to replace the old one
|
543 |
-
mvalue = Path(filename).read_text(encoding="utf-8")
|
544 |
-
self.shell.user_ns[mname] = Macro(mvalue)
|
545 |
-
|
546 |
-
@skip_doctest
|
547 |
-
@line_magic
|
548 |
-
def edit(self, parameter_s='',last_call=['','']):
|
549 |
-
"""Bring up an editor and execute the resulting code.
|
550 |
-
|
551 |
-
Usage:
|
552 |
-
%edit [options] [args]
|
553 |
-
|
554 |
-
%edit runs IPython's editor hook. The default version of this hook is
|
555 |
-
set to call the editor specified by your $EDITOR environment variable.
|
556 |
-
If this isn't found, it will default to vi under Linux/Unix and to
|
557 |
-
notepad under Windows. See the end of this docstring for how to change
|
558 |
-
the editor hook.
|
559 |
-
|
560 |
-
You can also set the value of this editor via the
|
561 |
-
``TerminalInteractiveShell.editor`` option in your configuration file.
|
562 |
-
This is useful if you wish to use a different editor from your typical
|
563 |
-
default with IPython (and for Windows users who typically don't set
|
564 |
-
environment variables).
|
565 |
-
|
566 |
-
This command allows you to conveniently edit multi-line code right in
|
567 |
-
your IPython session.
|
568 |
-
|
569 |
-
If called without arguments, %edit opens up an empty editor with a
|
570 |
-
temporary file and will execute the contents of this file when you
|
571 |
-
close it (don't forget to save it!).
|
572 |
-
|
573 |
-
|
574 |
-
Options:
|
575 |
-
|
576 |
-
-n <number>: open the editor at a specified line number. By default,
|
577 |
-
the IPython editor hook uses the unix syntax 'editor +N filename', but
|
578 |
-
you can configure this by providing your own modified hook if your
|
579 |
-
favorite editor supports line-number specifications with a different
|
580 |
-
syntax.
|
581 |
-
|
582 |
-
-p: this will call the editor with the same data as the previous time
|
583 |
-
it was used, regardless of how long ago (in your current session) it
|
584 |
-
was.
|
585 |
-
|
586 |
-
-r: use 'raw' input. This option only applies to input taken from the
|
587 |
-
user's history. By default, the 'processed' history is used, so that
|
588 |
-
magics are loaded in their transformed version to valid Python. If
|
589 |
-
this option is given, the raw input as typed as the command line is
|
590 |
-
used instead. When you exit the editor, it will be executed by
|
591 |
-
IPython's own processor.
|
592 |
-
|
593 |
-
-x: do not execute the edited code immediately upon exit. This is
|
594 |
-
mainly useful if you are editing programs which need to be called with
|
595 |
-
command line arguments, which you can then do using %run.
|
596 |
-
|
597 |
-
|
598 |
-
Arguments:
|
599 |
-
|
600 |
-
If arguments are given, the following possibilities exist:
|
601 |
-
|
602 |
-
- If the argument is a filename, IPython will load that into the
|
603 |
-
editor. It will execute its contents with execfile() when you exit,
|
604 |
-
loading any code in the file into your interactive namespace.
|
605 |
-
|
606 |
-
- The arguments are ranges of input history, e.g. "7 ~1/4-6".
|
607 |
-
The syntax is the same as in the %history magic.
|
608 |
-
|
609 |
-
- If the argument is a string variable, its contents are loaded
|
610 |
-
into the editor. You can thus edit any string which contains
|
611 |
-
python code (including the result of previous edits).
|
612 |
-
|
613 |
-
- If the argument is the name of an object (other than a string),
|
614 |
-
IPython will try to locate the file where it was defined and open the
|
615 |
-
editor at the point where it is defined. You can use `%edit function`
|
616 |
-
to load an editor exactly at the point where 'function' is defined,
|
617 |
-
edit it and have the file be executed automatically.
|
618 |
-
|
619 |
-
- If the object is a macro (see %macro for details), this opens up your
|
620 |
-
specified editor with a temporary file containing the macro's data.
|
621 |
-
Upon exit, the macro is reloaded with the contents of the file.
|
622 |
-
|
623 |
-
Note: opening at an exact line is only supported under Unix, and some
|
624 |
-
editors (like kedit and gedit up to Gnome 2.8) do not understand the
|
625 |
-
'+NUMBER' parameter necessary for this feature. Good editors like
|
626 |
-
(X)Emacs, vi, jed, pico and joe all do.
|
627 |
-
|
628 |
-
After executing your code, %edit will return as output the code you
|
629 |
-
typed in the editor (except when it was an existing file). This way
|
630 |
-
you can reload the code in further invocations of %edit as a variable,
|
631 |
-
via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
|
632 |
-
the output.
|
633 |
-
|
634 |
-
Note that %edit is also available through the alias %ed.
|
635 |
-
|
636 |
-
This is an example of creating a simple function inside the editor and
|
637 |
-
then modifying it. First, start up the editor::
|
638 |
-
|
639 |
-
In [1]: edit
|
640 |
-
Editing... done. Executing edited code...
|
641 |
-
Out[1]: 'def foo():\\n print("foo() was defined in an editing
|
642 |
-
session")\\n'
|
643 |
-
|
644 |
-
We can then call the function foo()::
|
645 |
-
|
646 |
-
In [2]: foo()
|
647 |
-
foo() was defined in an editing session
|
648 |
-
|
649 |
-
Now we edit foo. IPython automatically loads the editor with the
|
650 |
-
(temporary) file where foo() was previously defined::
|
651 |
-
|
652 |
-
In [3]: edit foo
|
653 |
-
Editing... done. Executing edited code...
|
654 |
-
|
655 |
-
And if we call foo() again we get the modified version::
|
656 |
-
|
657 |
-
In [4]: foo()
|
658 |
-
foo() has now been changed!
|
659 |
-
|
660 |
-
Here is an example of how to edit a code snippet successive
|
661 |
-
times. First we call the editor::
|
662 |
-
|
663 |
-
In [5]: edit
|
664 |
-
Editing... done. Executing edited code...
|
665 |
-
hello
|
666 |
-
Out[5]: "print('hello')\\n"
|
667 |
-
|
668 |
-
Now we call it again with the previous output (stored in _)::
|
669 |
-
|
670 |
-
In [6]: edit _
|
671 |
-
Editing... done. Executing edited code...
|
672 |
-
hello world
|
673 |
-
Out[6]: "print('hello world')\\n"
|
674 |
-
|
675 |
-
Now we call it with the output #8 (stored in _8, also as Out[8])::
|
676 |
-
|
677 |
-
In [7]: edit _8
|
678 |
-
Editing... done. Executing edited code...
|
679 |
-
hello again
|
680 |
-
Out[7]: "print('hello again')\\n"
|
681 |
-
|
682 |
-
|
683 |
-
Changing the default editor hook:
|
684 |
-
|
685 |
-
If you wish to write your own editor hook, you can put it in a
|
686 |
-
configuration file which you load at startup time. The default hook
|
687 |
-
is defined in the IPython.core.hooks module, and you can use that as a
|
688 |
-
starting example for further modifications. That file also has
|
689 |
-
general instructions on how to set a new hook for use once you've
|
690 |
-
defined it."""
|
691 |
-
opts,args = self.parse_options(parameter_s,'prxn:')
|
692 |
-
|
693 |
-
try:
|
694 |
-
filename, lineno, is_temp = self._find_edit_target(self.shell,
|
695 |
-
args, opts, last_call)
|
696 |
-
except MacroToEdit as e:
|
697 |
-
self._edit_macro(args, e.args[0])
|
698 |
-
return
|
699 |
-
except InteractivelyDefined as e:
|
700 |
-
print("Editing In[%i]" % e.index)
|
701 |
-
args = str(e.index)
|
702 |
-
filename, lineno, is_temp = self._find_edit_target(self.shell,
|
703 |
-
args, opts, last_call)
|
704 |
-
if filename is None:
|
705 |
-
# nothing was found, warnings have already been issued,
|
706 |
-
# just give up.
|
707 |
-
return
|
708 |
-
|
709 |
-
if is_temp:
|
710 |
-
self._knowntemps.add(filename)
|
711 |
-
elif (filename in self._knowntemps):
|
712 |
-
is_temp = True
|
713 |
-
|
714 |
-
|
715 |
-
# do actual editing here
|
716 |
-
print('Editing...', end=' ')
|
717 |
-
sys.stdout.flush()
|
718 |
-
filepath = Path(filename)
|
719 |
-
try:
|
720 |
-
# Quote filenames that may have spaces in them when opening
|
721 |
-
# the editor
|
722 |
-
quoted = filename = str(filepath.absolute())
|
723 |
-
if " " in quoted:
|
724 |
-
quoted = "'%s'" % quoted
|
725 |
-
self.shell.hooks.editor(quoted, lineno)
|
726 |
-
except TryNext:
|
727 |
-
warn('Could not open editor')
|
728 |
-
return
|
729 |
-
|
730 |
-
# XXX TODO: should this be generalized for all string vars?
|
731 |
-
# For now, this is special-cased to blocks created by cpaste
|
732 |
-
if args.strip() == "pasted_block":
|
733 |
-
self.shell.user_ns["pasted_block"] = filepath.read_text(encoding="utf-8")
|
734 |
-
|
735 |
-
if 'x' in opts: # -x prevents actual execution
|
736 |
-
print()
|
737 |
-
else:
|
738 |
-
print('done. Executing edited code...')
|
739 |
-
with preserve_keys(self.shell.user_ns, '__file__'):
|
740 |
-
if not is_temp:
|
741 |
-
self.shell.user_ns["__file__"] = filename
|
742 |
-
if "r" in opts: # Untranslated IPython code
|
743 |
-
source = filepath.read_text(encoding="utf-8")
|
744 |
-
self.shell.run_cell(source, store_history=False)
|
745 |
-
else:
|
746 |
-
self.shell.safe_execfile(filename, self.shell.user_ns,
|
747 |
-
self.shell.user_ns)
|
748 |
-
|
749 |
-
if is_temp:
|
750 |
-
try:
|
751 |
-
return filepath.read_text(encoding="utf-8")
|
752 |
-
except IOError as msg:
|
753 |
-
if Path(msg.filename) == filepath:
|
754 |
-
warn('File not found. Did you forget to save?')
|
755 |
-
return
|
756 |
-
else:
|
757 |
-
self.shell.showtraceback()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/config.py
DELETED
@@ -1,140 +0,0 @@
|
|
1 |
-
"""Implementation of configuration-related magic functions.
|
2 |
-
"""
|
3 |
-
#-----------------------------------------------------------------------------
|
4 |
-
# Copyright (c) 2012 The IPython Development Team.
|
5 |
-
#
|
6 |
-
# Distributed under the terms of the Modified BSD License.
|
7 |
-
#
|
8 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
9 |
-
#-----------------------------------------------------------------------------
|
10 |
-
|
11 |
-
#-----------------------------------------------------------------------------
|
12 |
-
# Imports
|
13 |
-
#-----------------------------------------------------------------------------
|
14 |
-
|
15 |
-
# Stdlib
|
16 |
-
import re
|
17 |
-
|
18 |
-
# Our own packages
|
19 |
-
from IPython.core.error import UsageError
|
20 |
-
from IPython.core.magic import Magics, magics_class, line_magic
|
21 |
-
from logging import error
|
22 |
-
|
23 |
-
#-----------------------------------------------------------------------------
|
24 |
-
# Magic implementation classes
|
25 |
-
#-----------------------------------------------------------------------------
|
26 |
-
|
27 |
-
reg = re.compile(r'^\w+\.\w+$')
|
28 |
-
@magics_class
|
29 |
-
class ConfigMagics(Magics):
|
30 |
-
|
31 |
-
def __init__(self, shell):
|
32 |
-
super(ConfigMagics, self).__init__(shell)
|
33 |
-
self.configurables = []
|
34 |
-
|
35 |
-
@line_magic
|
36 |
-
def config(self, s):
|
37 |
-
"""configure IPython
|
38 |
-
|
39 |
-
%config Class[.trait=value]
|
40 |
-
|
41 |
-
This magic exposes most of the IPython config system. Any
|
42 |
-
Configurable class should be able to be configured with the simple
|
43 |
-
line::
|
44 |
-
|
45 |
-
%config Class.trait=value
|
46 |
-
|
47 |
-
Where `value` will be resolved in the user's namespace, if it is an
|
48 |
-
expression or variable name.
|
49 |
-
|
50 |
-
Examples
|
51 |
-
--------
|
52 |
-
|
53 |
-
To see what classes are available for config, pass no arguments::
|
54 |
-
|
55 |
-
In [1]: %config
|
56 |
-
Available objects for config:
|
57 |
-
AliasManager
|
58 |
-
DisplayFormatter
|
59 |
-
HistoryManager
|
60 |
-
IPCompleter
|
61 |
-
LoggingMagics
|
62 |
-
MagicsManager
|
63 |
-
OSMagics
|
64 |
-
PrefilterManager
|
65 |
-
ScriptMagics
|
66 |
-
TerminalInteractiveShell
|
67 |
-
|
68 |
-
To view what is configurable on a given class, just pass the class
|
69 |
-
name::
|
70 |
-
|
71 |
-
In [2]: %config LoggingMagics
|
72 |
-
LoggingMagics(Magics) options
|
73 |
-
---------------------------
|
74 |
-
LoggingMagics.quiet=<Bool>
|
75 |
-
Suppress output of log state when logging is enabled
|
76 |
-
Current: False
|
77 |
-
|
78 |
-
but the real use is in setting values::
|
79 |
-
|
80 |
-
In [3]: %config LoggingMagics.quiet = True
|
81 |
-
|
82 |
-
and these values are read from the user_ns if they are variables::
|
83 |
-
|
84 |
-
In [4]: feeling_quiet=False
|
85 |
-
|
86 |
-
In [5]: %config LoggingMagics.quiet = feeling_quiet
|
87 |
-
|
88 |
-
"""
|
89 |
-
from traitlets.config.loader import Config
|
90 |
-
# some IPython objects are Configurable, but do not yet have
|
91 |
-
# any configurable traits. Exclude them from the effects of
|
92 |
-
# this magic, as their presence is just noise:
|
93 |
-
configurables = sorted(set([ c for c in self.shell.configurables
|
94 |
-
if c.__class__.class_traits(config=True)
|
95 |
-
]), key=lambda x: x.__class__.__name__)
|
96 |
-
classnames = [ c.__class__.__name__ for c in configurables ]
|
97 |
-
|
98 |
-
line = s.strip()
|
99 |
-
if not line:
|
100 |
-
# print available configurable names
|
101 |
-
print("Available objects for config:")
|
102 |
-
for name in classnames:
|
103 |
-
print(" ", name)
|
104 |
-
return
|
105 |
-
elif line in classnames:
|
106 |
-
# `%config TerminalInteractiveShell` will print trait info for
|
107 |
-
# TerminalInteractiveShell
|
108 |
-
c = configurables[classnames.index(line)]
|
109 |
-
cls = c.__class__
|
110 |
-
help = cls.class_get_help(c)
|
111 |
-
# strip leading '--' from cl-args:
|
112 |
-
help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
|
113 |
-
print(help)
|
114 |
-
return
|
115 |
-
elif reg.match(line):
|
116 |
-
cls, attr = line.split('.')
|
117 |
-
return getattr(configurables[classnames.index(cls)],attr)
|
118 |
-
elif '=' not in line:
|
119 |
-
msg = "Invalid config statement: %r, "\
|
120 |
-
"should be `Class.trait = value`."
|
121 |
-
|
122 |
-
ll = line.lower()
|
123 |
-
for classname in classnames:
|
124 |
-
if ll == classname.lower():
|
125 |
-
msg = msg + '\nDid you mean %s (note the case)?' % classname
|
126 |
-
break
|
127 |
-
|
128 |
-
raise UsageError( msg % line)
|
129 |
-
|
130 |
-
# otherwise, assume we are setting configurables.
|
131 |
-
# leave quotes on args when splitting, because we want
|
132 |
-
# unquoted args to eval in user_ns
|
133 |
-
cfg = Config()
|
134 |
-
exec("cfg."+line, self.shell.user_ns, locals())
|
135 |
-
|
136 |
-
for configurable in configurables:
|
137 |
-
try:
|
138 |
-
configurable.update_config(cfg)
|
139 |
-
except Exception as e:
|
140 |
-
error(e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/display.py
DELETED
@@ -1,93 +0,0 @@
|
|
1 |
-
"""Simple magics for display formats"""
|
2 |
-
#-----------------------------------------------------------------------------
|
3 |
-
# Copyright (c) 2012 The IPython Development Team.
|
4 |
-
#
|
5 |
-
# Distributed under the terms of the Modified BSD License.
|
6 |
-
#
|
7 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
8 |
-
#-----------------------------------------------------------------------------
|
9 |
-
|
10 |
-
#-----------------------------------------------------------------------------
|
11 |
-
# Imports
|
12 |
-
#-----------------------------------------------------------------------------
|
13 |
-
|
14 |
-
# Our own packages
|
15 |
-
from IPython.display import display, Javascript, Latex, SVG, HTML, Markdown
|
16 |
-
from IPython.core.magic import (
|
17 |
-
Magics, magics_class, cell_magic
|
18 |
-
)
|
19 |
-
from IPython.core import magic_arguments
|
20 |
-
|
21 |
-
#-----------------------------------------------------------------------------
|
22 |
-
# Magic implementation classes
|
23 |
-
#-----------------------------------------------------------------------------
|
24 |
-
|
25 |
-
|
26 |
-
@magics_class
|
27 |
-
class DisplayMagics(Magics):
|
28 |
-
"""Magics for displaying various output types with literals
|
29 |
-
|
30 |
-
Defines javascript/latex/svg/html cell magics for writing
|
31 |
-
blocks in those languages, to be rendered in the frontend.
|
32 |
-
"""
|
33 |
-
|
34 |
-
@cell_magic
|
35 |
-
def js(self, line, cell):
|
36 |
-
"""Run the cell block of Javascript code
|
37 |
-
|
38 |
-
Alias of `%%javascript`
|
39 |
-
|
40 |
-
Starting with IPython 8.0 %%javascript is pending deprecation to be replaced
|
41 |
-
by a more flexible system
|
42 |
-
|
43 |
-
Please See https://github.com/ipython/ipython/issues/13376
|
44 |
-
"""
|
45 |
-
self.javascript(line, cell)
|
46 |
-
|
47 |
-
@cell_magic
|
48 |
-
def javascript(self, line, cell):
|
49 |
-
"""Run the cell block of Javascript code
|
50 |
-
|
51 |
-
Starting with IPython 8.0 %%javascript is pending deprecation to be replaced
|
52 |
-
by a more flexible system
|
53 |
-
|
54 |
-
Please See https://github.com/ipython/ipython/issues/13376
|
55 |
-
"""
|
56 |
-
display(Javascript(cell))
|
57 |
-
|
58 |
-
|
59 |
-
@cell_magic
|
60 |
-
def latex(self, line, cell):
|
61 |
-
"""Render the cell as a block of LaTeX
|
62 |
-
|
63 |
-
The subset of LaTeX which is supported depends on the implementation in
|
64 |
-
the client. In the Jupyter Notebook, this magic only renders the subset
|
65 |
-
of LaTeX defined by MathJax
|
66 |
-
[here](https://docs.mathjax.org/en/v2.5-latest/tex.html)."""
|
67 |
-
display(Latex(cell))
|
68 |
-
|
69 |
-
@cell_magic
|
70 |
-
def svg(self, line, cell):
|
71 |
-
"""Render the cell as an SVG literal"""
|
72 |
-
display(SVG(cell))
|
73 |
-
|
74 |
-
@magic_arguments.magic_arguments()
|
75 |
-
@magic_arguments.argument(
|
76 |
-
'--isolated', action='store_true', default=False,
|
77 |
-
help="""Annotate the cell as 'isolated'.
|
78 |
-
Isolated cells are rendered inside their own <iframe> tag"""
|
79 |
-
)
|
80 |
-
@cell_magic
|
81 |
-
def html(self, line, cell):
|
82 |
-
"""Render the cell as a block of HTML"""
|
83 |
-
args = magic_arguments.parse_argstring(self.html, line)
|
84 |
-
html = HTML(cell)
|
85 |
-
if args.isolated:
|
86 |
-
display(html, metadata={'text/html':{'isolated':True}})
|
87 |
-
else:
|
88 |
-
display(html)
|
89 |
-
|
90 |
-
@cell_magic
|
91 |
-
def markdown(self, line, cell):
|
92 |
-
"""Render the cell as Markdown text block"""
|
93 |
-
display(Markdown(cell))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/execution.py
DELETED
@@ -1,1624 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
"""Implementation of execution-related magic functions."""
|
3 |
-
|
4 |
-
# Copyright (c) IPython Development Team.
|
5 |
-
# Distributed under the terms of the Modified BSD License.
|
6 |
-
|
7 |
-
|
8 |
-
import ast
|
9 |
-
import bdb
|
10 |
-
import builtins as builtin_mod
|
11 |
-
import copy
|
12 |
-
import cProfile as profile
|
13 |
-
import gc
|
14 |
-
import itertools
|
15 |
-
import math
|
16 |
-
import os
|
17 |
-
import pstats
|
18 |
-
import re
|
19 |
-
import shlex
|
20 |
-
import sys
|
21 |
-
import time
|
22 |
-
import timeit
|
23 |
-
from typing import Dict, Any
|
24 |
-
from ast import (
|
25 |
-
Assign,
|
26 |
-
Call,
|
27 |
-
Expr,
|
28 |
-
Load,
|
29 |
-
Module,
|
30 |
-
Name,
|
31 |
-
NodeTransformer,
|
32 |
-
Store,
|
33 |
-
parse,
|
34 |
-
unparse,
|
35 |
-
)
|
36 |
-
from io import StringIO
|
37 |
-
from logging import error
|
38 |
-
from pathlib import Path
|
39 |
-
from pdb import Restart
|
40 |
-
from textwrap import dedent, indent
|
41 |
-
from warnings import warn
|
42 |
-
|
43 |
-
from IPython.core import magic_arguments, oinspect, page
|
44 |
-
from IPython.core.displayhook import DisplayHook
|
45 |
-
from IPython.core.error import UsageError
|
46 |
-
from IPython.core.macro import Macro
|
47 |
-
from IPython.core.magic import (
|
48 |
-
Magics,
|
49 |
-
cell_magic,
|
50 |
-
line_cell_magic,
|
51 |
-
line_magic,
|
52 |
-
magics_class,
|
53 |
-
needs_local_scope,
|
54 |
-
no_var_expand,
|
55 |
-
on_off,
|
56 |
-
output_can_be_silenced,
|
57 |
-
)
|
58 |
-
from IPython.testing.skipdoctest import skip_doctest
|
59 |
-
from IPython.utils.capture import capture_output
|
60 |
-
from IPython.utils.contexts import preserve_keys
|
61 |
-
from IPython.utils.ipstruct import Struct
|
62 |
-
from IPython.utils.module_paths import find_mod
|
63 |
-
from IPython.utils.path import get_py_filename, shellglob
|
64 |
-
from IPython.utils.timing import clock, clock2
|
65 |
-
from IPython.core.magics.ast_mod import ReplaceCodeTransformer
|
66 |
-
|
67 |
-
#-----------------------------------------------------------------------------
|
68 |
-
# Magic implementation classes
|
69 |
-
#-----------------------------------------------------------------------------
|
70 |
-
|
71 |
-
|
72 |
-
class TimeitResult(object):
|
73 |
-
"""
|
74 |
-
Object returned by the timeit magic with info about the run.
|
75 |
-
|
76 |
-
Contains the following attributes :
|
77 |
-
|
78 |
-
loops: (int) number of loops done per measurement
|
79 |
-
repeat: (int) number of times the measurement has been repeated
|
80 |
-
best: (float) best execution time / number
|
81 |
-
all_runs: (list of float) execution time of each run (in s)
|
82 |
-
compile_time: (float) time of statement compilation (s)
|
83 |
-
|
84 |
-
"""
|
85 |
-
def __init__(self, loops, repeat, best, worst, all_runs, compile_time, precision):
|
86 |
-
self.loops = loops
|
87 |
-
self.repeat = repeat
|
88 |
-
self.best = best
|
89 |
-
self.worst = worst
|
90 |
-
self.all_runs = all_runs
|
91 |
-
self.compile_time = compile_time
|
92 |
-
self._precision = precision
|
93 |
-
self.timings = [ dt / self.loops for dt in all_runs]
|
94 |
-
|
95 |
-
@property
|
96 |
-
def average(self):
|
97 |
-
return math.fsum(self.timings) / len(self.timings)
|
98 |
-
|
99 |
-
@property
|
100 |
-
def stdev(self):
|
101 |
-
mean = self.average
|
102 |
-
return (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5
|
103 |
-
|
104 |
-
def __str__(self):
|
105 |
-
pm = '+-'
|
106 |
-
if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
|
107 |
-
try:
|
108 |
-
u'\xb1'.encode(sys.stdout.encoding)
|
109 |
-
pm = u'\xb1'
|
110 |
-
except:
|
111 |
-
pass
|
112 |
-
return "{mean} {pm} {std} per loop (mean {pm} std. dev. of {runs} run{run_plural}, {loops:,} loop{loop_plural} each)".format(
|
113 |
-
pm=pm,
|
114 |
-
runs=self.repeat,
|
115 |
-
loops=self.loops,
|
116 |
-
loop_plural="" if self.loops == 1 else "s",
|
117 |
-
run_plural="" if self.repeat == 1 else "s",
|
118 |
-
mean=_format_time(self.average, self._precision),
|
119 |
-
std=_format_time(self.stdev, self._precision),
|
120 |
-
)
|
121 |
-
|
122 |
-
def _repr_pretty_(self, p , cycle):
|
123 |
-
unic = self.__str__()
|
124 |
-
p.text(u'<TimeitResult : '+unic+u'>')
|
125 |
-
|
126 |
-
|
127 |
-
class TimeitTemplateFiller(ast.NodeTransformer):
|
128 |
-
"""Fill in the AST template for timing execution.
|
129 |
-
|
130 |
-
This is quite closely tied to the template definition, which is in
|
131 |
-
:meth:`ExecutionMagics.timeit`.
|
132 |
-
"""
|
133 |
-
def __init__(self, ast_setup, ast_stmt):
|
134 |
-
self.ast_setup = ast_setup
|
135 |
-
self.ast_stmt = ast_stmt
|
136 |
-
|
137 |
-
def visit_FunctionDef(self, node):
|
138 |
-
"Fill in the setup statement"
|
139 |
-
self.generic_visit(node)
|
140 |
-
if node.name == "inner":
|
141 |
-
node.body[:1] = self.ast_setup.body
|
142 |
-
|
143 |
-
return node
|
144 |
-
|
145 |
-
def visit_For(self, node):
|
146 |
-
"Fill in the statement to be timed"
|
147 |
-
if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
|
148 |
-
node.body = self.ast_stmt.body
|
149 |
-
return node
|
150 |
-
|
151 |
-
|
152 |
-
class Timer(timeit.Timer):
|
153 |
-
"""Timer class that explicitly uses self.inner
|
154 |
-
|
155 |
-
which is an undocumented implementation detail of CPython,
|
156 |
-
not shared by PyPy.
|
157 |
-
"""
|
158 |
-
# Timer.timeit copied from CPython 3.4.2
|
159 |
-
def timeit(self, number=timeit.default_number):
|
160 |
-
"""Time 'number' executions of the main statement.
|
161 |
-
|
162 |
-
To be precise, this executes the setup statement once, and
|
163 |
-
then returns the time it takes to execute the main statement
|
164 |
-
a number of times, as a float measured in seconds. The
|
165 |
-
argument is the number of times through the loop, defaulting
|
166 |
-
to one million. The main statement, the setup statement and
|
167 |
-
the timer function to be used are passed to the constructor.
|
168 |
-
"""
|
169 |
-
it = itertools.repeat(None, number)
|
170 |
-
gcold = gc.isenabled()
|
171 |
-
gc.disable()
|
172 |
-
try:
|
173 |
-
timing = self.inner(it, self.timer)
|
174 |
-
finally:
|
175 |
-
if gcold:
|
176 |
-
gc.enable()
|
177 |
-
return timing
|
178 |
-
|
179 |
-
|
180 |
-
@magics_class
|
181 |
-
class ExecutionMagics(Magics):
|
182 |
-
"""Magics related to code execution, debugging, profiling, etc."""
|
183 |
-
|
184 |
-
_transformers: Dict[str, Any] = {}
|
185 |
-
|
186 |
-
def __init__(self, shell):
|
187 |
-
super(ExecutionMagics, self).__init__(shell)
|
188 |
-
# Default execution function used to actually run user code.
|
189 |
-
self.default_runner = None
|
190 |
-
|
191 |
-
@skip_doctest
|
192 |
-
@no_var_expand
|
193 |
-
@line_cell_magic
|
194 |
-
def prun(self, parameter_s='', cell=None):
|
195 |
-
|
196 |
-
"""Run a statement through the python code profiler.
|
197 |
-
|
198 |
-
**Usage, in line mode:**
|
199 |
-
|
200 |
-
%prun [options] statement
|
201 |
-
|
202 |
-
**Usage, in cell mode:**
|
203 |
-
|
204 |
-
%%prun [options] [statement]
|
205 |
-
|
206 |
-
code...
|
207 |
-
|
208 |
-
code...
|
209 |
-
|
210 |
-
In cell mode, the additional code lines are appended to the (possibly
|
211 |
-
empty) statement in the first line. Cell mode allows you to easily
|
212 |
-
profile multiline blocks without having to put them in a separate
|
213 |
-
function.
|
214 |
-
|
215 |
-
The given statement (which doesn't require quote marks) is run via the
|
216 |
-
python profiler in a manner similar to the profile.run() function.
|
217 |
-
Namespaces are internally managed to work correctly; profile.run
|
218 |
-
cannot be used in IPython because it makes certain assumptions about
|
219 |
-
namespaces which do not hold under IPython.
|
220 |
-
|
221 |
-
Options:
|
222 |
-
|
223 |
-
-l <limit>
|
224 |
-
you can place restrictions on what or how much of the
|
225 |
-
profile gets printed. The limit value can be:
|
226 |
-
|
227 |
-
* A string: only information for function names containing this string
|
228 |
-
is printed.
|
229 |
-
|
230 |
-
* An integer: only these many lines are printed.
|
231 |
-
|
232 |
-
* A float (between 0 and 1): this fraction of the report is printed
|
233 |
-
(for example, use a limit of 0.4 to see the topmost 40% only).
|
234 |
-
|
235 |
-
You can combine several limits with repeated use of the option. For
|
236 |
-
example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
|
237 |
-
information about class constructors.
|
238 |
-
|
239 |
-
-r
|
240 |
-
return the pstats.Stats object generated by the profiling. This
|
241 |
-
object has all the information about the profile in it, and you can
|
242 |
-
later use it for further analysis or in other functions.
|
243 |
-
|
244 |
-
-s <key>
|
245 |
-
sort profile by given key. You can provide more than one key
|
246 |
-
by using the option several times: '-s key1 -s key2 -s key3...'. The
|
247 |
-
default sorting key is 'time'.
|
248 |
-
|
249 |
-
The following is copied verbatim from the profile documentation
|
250 |
-
referenced below:
|
251 |
-
|
252 |
-
When more than one key is provided, additional keys are used as
|
253 |
-
secondary criteria when the there is equality in all keys selected
|
254 |
-
before them.
|
255 |
-
|
256 |
-
Abbreviations can be used for any key names, as long as the
|
257 |
-
abbreviation is unambiguous. The following are the keys currently
|
258 |
-
defined:
|
259 |
-
|
260 |
-
============ =====================
|
261 |
-
Valid Arg Meaning
|
262 |
-
============ =====================
|
263 |
-
"calls" call count
|
264 |
-
"cumulative" cumulative time
|
265 |
-
"file" file name
|
266 |
-
"module" file name
|
267 |
-
"pcalls" primitive call count
|
268 |
-
"line" line number
|
269 |
-
"name" function name
|
270 |
-
"nfl" name/file/line
|
271 |
-
"stdname" standard name
|
272 |
-
"time" internal time
|
273 |
-
============ =====================
|
274 |
-
|
275 |
-
Note that all sorts on statistics are in descending order (placing
|
276 |
-
most time consuming items first), where as name, file, and line number
|
277 |
-
searches are in ascending order (i.e., alphabetical). The subtle
|
278 |
-
distinction between "nfl" and "stdname" is that the standard name is a
|
279 |
-
sort of the name as printed, which means that the embedded line
|
280 |
-
numbers get compared in an odd way. For example, lines 3, 20, and 40
|
281 |
-
would (if the file names were the same) appear in the string order
|
282 |
-
"20" "3" and "40". In contrast, "nfl" does a numeric compare of the
|
283 |
-
line numbers. In fact, sort_stats("nfl") is the same as
|
284 |
-
sort_stats("name", "file", "line").
|
285 |
-
|
286 |
-
-T <filename>
|
287 |
-
save profile results as shown on screen to a text
|
288 |
-
file. The profile is still shown on screen.
|
289 |
-
|
290 |
-
-D <filename>
|
291 |
-
save (via dump_stats) profile statistics to given
|
292 |
-
filename. This data is in a format understood by the pstats module, and
|
293 |
-
is generated by a call to the dump_stats() method of profile
|
294 |
-
objects. The profile is still shown on screen.
|
295 |
-
|
296 |
-
-q
|
297 |
-
suppress output to the pager. Best used with -T and/or -D above.
|
298 |
-
|
299 |
-
If you want to run complete programs under the profiler's control, use
|
300 |
-
``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
|
301 |
-
contains profiler specific options as described here.
|
302 |
-
|
303 |
-
You can read the complete documentation for the profile module with::
|
304 |
-
|
305 |
-
In [1]: import profile; profile.help()
|
306 |
-
|
307 |
-
.. versionchanged:: 7.3
|
308 |
-
User variables are no longer expanded,
|
309 |
-
the magic line is always left unmodified.
|
310 |
-
|
311 |
-
"""
|
312 |
-
opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
|
313 |
-
list_all=True, posix=False)
|
314 |
-
if cell is not None:
|
315 |
-
arg_str += '\n' + cell
|
316 |
-
arg_str = self.shell.transform_cell(arg_str)
|
317 |
-
return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
|
318 |
-
|
319 |
-
def _run_with_profiler(self, code, opts, namespace):
|
320 |
-
"""
|
321 |
-
Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
|
322 |
-
|
323 |
-
Parameters
|
324 |
-
----------
|
325 |
-
code : str
|
326 |
-
Code to be executed.
|
327 |
-
opts : Struct
|
328 |
-
Options parsed by `self.parse_options`.
|
329 |
-
namespace : dict
|
330 |
-
A dictionary for Python namespace (e.g., `self.shell.user_ns`).
|
331 |
-
|
332 |
-
"""
|
333 |
-
|
334 |
-
# Fill default values for unspecified options:
|
335 |
-
opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
|
336 |
-
|
337 |
-
prof = profile.Profile()
|
338 |
-
try:
|
339 |
-
prof = prof.runctx(code, namespace, namespace)
|
340 |
-
sys_exit = ''
|
341 |
-
except SystemExit:
|
342 |
-
sys_exit = """*** SystemExit exception caught in code being profiled."""
|
343 |
-
|
344 |
-
stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
|
345 |
-
|
346 |
-
lims = opts.l
|
347 |
-
if lims:
|
348 |
-
lims = [] # rebuild lims with ints/floats/strings
|
349 |
-
for lim in opts.l:
|
350 |
-
try:
|
351 |
-
lims.append(int(lim))
|
352 |
-
except ValueError:
|
353 |
-
try:
|
354 |
-
lims.append(float(lim))
|
355 |
-
except ValueError:
|
356 |
-
lims.append(lim)
|
357 |
-
|
358 |
-
# Trap output.
|
359 |
-
stdout_trap = StringIO()
|
360 |
-
stats_stream = stats.stream
|
361 |
-
try:
|
362 |
-
stats.stream = stdout_trap
|
363 |
-
stats.print_stats(*lims)
|
364 |
-
finally:
|
365 |
-
stats.stream = stats_stream
|
366 |
-
|
367 |
-
output = stdout_trap.getvalue()
|
368 |
-
output = output.rstrip()
|
369 |
-
|
370 |
-
if 'q' not in opts:
|
371 |
-
page.page(output)
|
372 |
-
print(sys_exit, end=' ')
|
373 |
-
|
374 |
-
dump_file = opts.D[0]
|
375 |
-
text_file = opts.T[0]
|
376 |
-
if dump_file:
|
377 |
-
prof.dump_stats(dump_file)
|
378 |
-
print(
|
379 |
-
f"\n*** Profile stats marshalled to file {repr(dump_file)}.{sys_exit}"
|
380 |
-
)
|
381 |
-
if text_file:
|
382 |
-
pfile = Path(text_file)
|
383 |
-
pfile.touch(exist_ok=True)
|
384 |
-
pfile.write_text(output, encoding="utf-8")
|
385 |
-
|
386 |
-
print(
|
387 |
-
f"\n*** Profile printout saved to text file {repr(text_file)}.{sys_exit}"
|
388 |
-
)
|
389 |
-
|
390 |
-
if 'r' in opts:
|
391 |
-
return stats
|
392 |
-
|
393 |
-
return None
|
394 |
-
|
395 |
-
@line_magic
|
396 |
-
def pdb(self, parameter_s=''):
|
397 |
-
"""Control the automatic calling of the pdb interactive debugger.
|
398 |
-
|
399 |
-
Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
|
400 |
-
argument it works as a toggle.
|
401 |
-
|
402 |
-
When an exception is triggered, IPython can optionally call the
|
403 |
-
interactive pdb debugger after the traceback printout. %pdb toggles
|
404 |
-
this feature on and off.
|
405 |
-
|
406 |
-
The initial state of this feature is set in your configuration
|
407 |
-
file (the option is ``InteractiveShell.pdb``).
|
408 |
-
|
409 |
-
If you want to just activate the debugger AFTER an exception has fired,
|
410 |
-
without having to type '%pdb on' and rerunning your code, you can use
|
411 |
-
the %debug magic."""
|
412 |
-
|
413 |
-
par = parameter_s.strip().lower()
|
414 |
-
|
415 |
-
if par:
|
416 |
-
try:
|
417 |
-
new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
|
418 |
-
except KeyError:
|
419 |
-
print ('Incorrect argument. Use on/1, off/0, '
|
420 |
-
'or nothing for a toggle.')
|
421 |
-
return
|
422 |
-
else:
|
423 |
-
# toggle
|
424 |
-
new_pdb = not self.shell.call_pdb
|
425 |
-
|
426 |
-
# set on the shell
|
427 |
-
self.shell.call_pdb = new_pdb
|
428 |
-
print('Automatic pdb calling has been turned',on_off(new_pdb))
|
429 |
-
|
430 |
-
@magic_arguments.magic_arguments()
|
431 |
-
@magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
|
432 |
-
help="""
|
433 |
-
Set break point at LINE in FILE.
|
434 |
-
"""
|
435 |
-
)
|
436 |
-
@magic_arguments.argument('statement', nargs='*',
|
437 |
-
help="""
|
438 |
-
Code to run in debugger.
|
439 |
-
You can omit this in cell magic mode.
|
440 |
-
"""
|
441 |
-
)
|
442 |
-
@no_var_expand
|
443 |
-
@line_cell_magic
|
444 |
-
@needs_local_scope
|
445 |
-
def debug(self, line="", cell=None, local_ns=None):
|
446 |
-
"""Activate the interactive debugger.
|
447 |
-
|
448 |
-
This magic command support two ways of activating debugger.
|
449 |
-
One is to activate debugger before executing code. This way, you
|
450 |
-
can set a break point, to step through the code from the point.
|
451 |
-
You can use this mode by giving statements to execute and optionally
|
452 |
-
a breakpoint.
|
453 |
-
|
454 |
-
The other one is to activate debugger in post-mortem mode. You can
|
455 |
-
activate this mode simply running %debug without any argument.
|
456 |
-
If an exception has just occurred, this lets you inspect its stack
|
457 |
-
frames interactively. Note that this will always work only on the last
|
458 |
-
traceback that occurred, so you must call this quickly after an
|
459 |
-
exception that you wish to inspect has fired, because if another one
|
460 |
-
occurs, it clobbers the previous one.
|
461 |
-
|
462 |
-
If you want IPython to automatically do this on every exception, see
|
463 |
-
the %pdb magic for more details.
|
464 |
-
|
465 |
-
.. versionchanged:: 7.3
|
466 |
-
When running code, user variables are no longer expanded,
|
467 |
-
the magic line is always left unmodified.
|
468 |
-
|
469 |
-
"""
|
470 |
-
args = magic_arguments.parse_argstring(self.debug, line)
|
471 |
-
|
472 |
-
if not (args.breakpoint or args.statement or cell):
|
473 |
-
self._debug_post_mortem()
|
474 |
-
elif not (args.breakpoint or cell):
|
475 |
-
# If there is no breakpoints, the line is just code to execute
|
476 |
-
self._debug_exec(line, None, local_ns)
|
477 |
-
else:
|
478 |
-
# Here we try to reconstruct the code from the output of
|
479 |
-
# parse_argstring. This might not work if the code has spaces
|
480 |
-
# For example this fails for `print("a b")`
|
481 |
-
code = "\n".join(args.statement)
|
482 |
-
if cell:
|
483 |
-
code += "\n" + cell
|
484 |
-
self._debug_exec(code, args.breakpoint, local_ns)
|
485 |
-
|
486 |
-
def _debug_post_mortem(self):
|
487 |
-
self.shell.debugger(force=True)
|
488 |
-
|
489 |
-
def _debug_exec(self, code, breakpoint, local_ns=None):
|
490 |
-
if breakpoint:
|
491 |
-
(filename, bp_line) = breakpoint.rsplit(':', 1)
|
492 |
-
bp_line = int(bp_line)
|
493 |
-
else:
|
494 |
-
(filename, bp_line) = (None, None)
|
495 |
-
self._run_with_debugger(
|
496 |
-
code, self.shell.user_ns, filename, bp_line, local_ns=local_ns
|
497 |
-
)
|
498 |
-
|
499 |
-
@line_magic
|
500 |
-
def tb(self, s):
|
501 |
-
"""Print the last traceback.
|
502 |
-
|
503 |
-
Optionally, specify an exception reporting mode, tuning the
|
504 |
-
verbosity of the traceback. By default the currently-active exception
|
505 |
-
mode is used. See %xmode for changing exception reporting modes.
|
506 |
-
|
507 |
-
Valid modes: Plain, Context, Verbose, and Minimal.
|
508 |
-
"""
|
509 |
-
interactive_tb = self.shell.InteractiveTB
|
510 |
-
if s:
|
511 |
-
# Switch exception reporting mode for this one call.
|
512 |
-
# Ensure it is switched back.
|
513 |
-
def xmode_switch_err(name):
|
514 |
-
warn('Error changing %s exception modes.\n%s' %
|
515 |
-
(name,sys.exc_info()[1]))
|
516 |
-
|
517 |
-
new_mode = s.strip().capitalize()
|
518 |
-
original_mode = interactive_tb.mode
|
519 |
-
try:
|
520 |
-
try:
|
521 |
-
interactive_tb.set_mode(mode=new_mode)
|
522 |
-
except Exception:
|
523 |
-
xmode_switch_err('user')
|
524 |
-
else:
|
525 |
-
self.shell.showtraceback()
|
526 |
-
finally:
|
527 |
-
interactive_tb.set_mode(mode=original_mode)
|
528 |
-
else:
|
529 |
-
self.shell.showtraceback()
|
530 |
-
|
531 |
-
@skip_doctest
|
532 |
-
@line_magic
|
533 |
-
def run(self, parameter_s='', runner=None,
|
534 |
-
file_finder=get_py_filename):
|
535 |
-
"""Run the named file inside IPython as a program.
|
536 |
-
|
537 |
-
Usage::
|
538 |
-
|
539 |
-
%run [-n -i -e -G]
|
540 |
-
[( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
|
541 |
-
( -m mod | filename ) [args]
|
542 |
-
|
543 |
-
The filename argument should be either a pure Python script (with
|
544 |
-
extension ``.py``), or a file with custom IPython syntax (such as
|
545 |
-
magics). If the latter, the file can be either a script with ``.ipy``
|
546 |
-
extension, or a Jupyter notebook with ``.ipynb`` extension. When running
|
547 |
-
a Jupyter notebook, the output from print statements and other
|
548 |
-
displayed objects will appear in the terminal (even matplotlib figures
|
549 |
-
will open, if a terminal-compliant backend is being used). Note that,
|
550 |
-
at the system command line, the ``jupyter run`` command offers similar
|
551 |
-
functionality for executing notebooks (albeit currently with some
|
552 |
-
differences in supported options).
|
553 |
-
|
554 |
-
Parameters after the filename are passed as command-line arguments to
|
555 |
-
the program (put in sys.argv). Then, control returns to IPython's
|
556 |
-
prompt.
|
557 |
-
|
558 |
-
This is similar to running at a system prompt ``python file args``,
|
559 |
-
but with the advantage of giving you IPython's tracebacks, and of
|
560 |
-
loading all variables into your interactive namespace for further use
|
561 |
-
(unless -p is used, see below).
|
562 |
-
|
563 |
-
The file is executed in a namespace initially consisting only of
|
564 |
-
``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
|
565 |
-
sees its environment as if it were being run as a stand-alone program
|
566 |
-
(except for sharing global objects such as previously imported
|
567 |
-
modules). But after execution, the IPython interactive namespace gets
|
568 |
-
updated with all variables defined in the program (except for __name__
|
569 |
-
and sys.argv). This allows for very convenient loading of code for
|
570 |
-
interactive work, while giving each program a 'clean sheet' to run in.
|
571 |
-
|
572 |
-
Arguments are expanded using shell-like glob match. Patterns
|
573 |
-
'*', '?', '[seq]' and '[!seq]' can be used. Additionally,
|
574 |
-
tilde '~' will be expanded into user's home directory. Unlike
|
575 |
-
real shells, quotation does not suppress expansions. Use
|
576 |
-
*two* back slashes (e.g. ``\\\\*``) to suppress expansions.
|
577 |
-
To completely disable these expansions, you can use -G flag.
|
578 |
-
|
579 |
-
On Windows systems, the use of single quotes `'` when specifying
|
580 |
-
a file is not supported. Use double quotes `"`.
|
581 |
-
|
582 |
-
Options:
|
583 |
-
|
584 |
-
-n
|
585 |
-
__name__ is NOT set to '__main__', but to the running file's name
|
586 |
-
without extension (as python does under import). This allows running
|
587 |
-
scripts and reloading the definitions in them without calling code
|
588 |
-
protected by an ``if __name__ == "__main__"`` clause.
|
589 |
-
|
590 |
-
-i
|
591 |
-
run the file in IPython's namespace instead of an empty one. This
|
592 |
-
is useful if you are experimenting with code written in a text editor
|
593 |
-
which depends on variables defined interactively.
|
594 |
-
|
595 |
-
-e
|
596 |
-
ignore sys.exit() calls or SystemExit exceptions in the script
|
597 |
-
being run. This is particularly useful if IPython is being used to
|
598 |
-
run unittests, which always exit with a sys.exit() call. In such
|
599 |
-
cases you are interested in the output of the test results, not in
|
600 |
-
seeing a traceback of the unittest module.
|
601 |
-
|
602 |
-
-t
|
603 |
-
print timing information at the end of the run. IPython will give
|
604 |
-
you an estimated CPU time consumption for your script, which under
|
605 |
-
Unix uses the resource module to avoid the wraparound problems of
|
606 |
-
time.clock(). Under Unix, an estimate of time spent on system tasks
|
607 |
-
is also given (for Windows platforms this is reported as 0.0).
|
608 |
-
|
609 |
-
If -t is given, an additional ``-N<N>`` option can be given, where <N>
|
610 |
-
must be an integer indicating how many times you want the script to
|
611 |
-
run. The final timing report will include total and per run results.
|
612 |
-
|
613 |
-
For example (testing the script uniq_stable.py)::
|
614 |
-
|
615 |
-
In [1]: run -t uniq_stable
|
616 |
-
|
617 |
-
IPython CPU timings (estimated):
|
618 |
-
User : 0.19597 s.
|
619 |
-
System: 0.0 s.
|
620 |
-
|
621 |
-
In [2]: run -t -N5 uniq_stable
|
622 |
-
|
623 |
-
IPython CPU timings (estimated):
|
624 |
-
Total runs performed: 5
|
625 |
-
Times : Total Per run
|
626 |
-
User : 0.910862 s, 0.1821724 s.
|
627 |
-
System: 0.0 s, 0.0 s.
|
628 |
-
|
629 |
-
-d
|
630 |
-
run your program under the control of pdb, the Python debugger.
|
631 |
-
This allows you to execute your program step by step, watch variables,
|
632 |
-
etc. Internally, what IPython does is similar to calling::
|
633 |
-
|
634 |
-
pdb.run('execfile("YOURFILENAME")')
|
635 |
-
|
636 |
-
with a breakpoint set on line 1 of your file. You can change the line
|
637 |
-
number for this automatic breakpoint to be <N> by using the -bN option
|
638 |
-
(where N must be an integer). For example::
|
639 |
-
|
640 |
-
%run -d -b40 myscript
|
641 |
-
|
642 |
-
will set the first breakpoint at line 40 in myscript.py. Note that
|
643 |
-
the first breakpoint must be set on a line which actually does
|
644 |
-
something (not a comment or docstring) for it to stop execution.
|
645 |
-
|
646 |
-
Or you can specify a breakpoint in a different file::
|
647 |
-
|
648 |
-
%run -d -b myotherfile.py:20 myscript
|
649 |
-
|
650 |
-
When the pdb debugger starts, you will see a (Pdb) prompt. You must
|
651 |
-
first enter 'c' (without quotes) to start execution up to the first
|
652 |
-
breakpoint.
|
653 |
-
|
654 |
-
Entering 'help' gives information about the use of the debugger. You
|
655 |
-
can easily see pdb's full documentation with "import pdb;pdb.help()"
|
656 |
-
at a prompt.
|
657 |
-
|
658 |
-
-p
|
659 |
-
run program under the control of the Python profiler module (which
|
660 |
-
prints a detailed report of execution times, function calls, etc).
|
661 |
-
|
662 |
-
You can pass other options after -p which affect the behavior of the
|
663 |
-
profiler itself. See the docs for %prun for details.
|
664 |
-
|
665 |
-
In this mode, the program's variables do NOT propagate back to the
|
666 |
-
IPython interactive namespace (because they remain in the namespace
|
667 |
-
where the profiler executes them).
|
668 |
-
|
669 |
-
Internally this triggers a call to %prun, see its documentation for
|
670 |
-
details on the options available specifically for profiling.
|
671 |
-
|
672 |
-
There is one special usage for which the text above doesn't apply:
|
673 |
-
if the filename ends with .ipy[nb], the file is run as ipython script,
|
674 |
-
just as if the commands were written on IPython prompt.
|
675 |
-
|
676 |
-
-m
|
677 |
-
specify module name to load instead of script path. Similar to
|
678 |
-
the -m option for the python interpreter. Use this option last if you
|
679 |
-
want to combine with other %run options. Unlike the python interpreter
|
680 |
-
only source modules are allowed no .pyc or .pyo files.
|
681 |
-
For example::
|
682 |
-
|
683 |
-
%run -m example
|
684 |
-
|
685 |
-
will run the example module.
|
686 |
-
|
687 |
-
-G
|
688 |
-
disable shell-like glob expansion of arguments.
|
689 |
-
|
690 |
-
"""
|
691 |
-
|
692 |
-
# Logic to handle issue #3664
|
693 |
-
# Add '--' after '-m <module_name>' to ignore additional args passed to a module.
|
694 |
-
if '-m' in parameter_s and '--' not in parameter_s:
|
695 |
-
argv = shlex.split(parameter_s, posix=(os.name == 'posix'))
|
696 |
-
for idx, arg in enumerate(argv):
|
697 |
-
if arg and arg.startswith('-') and arg != '-':
|
698 |
-
if arg == '-m':
|
699 |
-
argv.insert(idx + 2, '--')
|
700 |
-
break
|
701 |
-
else:
|
702 |
-
# Positional arg, break
|
703 |
-
break
|
704 |
-
parameter_s = ' '.join(shlex.quote(arg) for arg in argv)
|
705 |
-
|
706 |
-
# get arguments and set sys.argv for program to be run.
|
707 |
-
opts, arg_lst = self.parse_options(parameter_s,
|
708 |
-
'nidtN:b:pD:l:rs:T:em:G',
|
709 |
-
mode='list', list_all=1)
|
710 |
-
if "m" in opts:
|
711 |
-
modulename = opts["m"][0]
|
712 |
-
modpath = find_mod(modulename)
|
713 |
-
if modpath is None:
|
714 |
-
msg = '%r is not a valid modulename on sys.path'%modulename
|
715 |
-
raise Exception(msg)
|
716 |
-
arg_lst = [modpath] + arg_lst
|
717 |
-
try:
|
718 |
-
fpath = None # initialize to make sure fpath is in scope later
|
719 |
-
fpath = arg_lst[0]
|
720 |
-
filename = file_finder(fpath)
|
721 |
-
except IndexError as e:
|
722 |
-
msg = 'you must provide at least a filename.'
|
723 |
-
raise Exception(msg) from e
|
724 |
-
except IOError as e:
|
725 |
-
try:
|
726 |
-
msg = str(e)
|
727 |
-
except UnicodeError:
|
728 |
-
msg = e.message
|
729 |
-
if os.name == 'nt' and re.match(r"^'.*'$",fpath):
|
730 |
-
warn('For Windows, use double quotes to wrap a filename: %run "mypath\\myfile.py"')
|
731 |
-
raise Exception(msg) from e
|
732 |
-
except TypeError:
|
733 |
-
if fpath in sys.meta_path:
|
734 |
-
filename = ""
|
735 |
-
else:
|
736 |
-
raise
|
737 |
-
|
738 |
-
if filename.lower().endswith(('.ipy', '.ipynb')):
|
739 |
-
with preserve_keys(self.shell.user_ns, '__file__'):
|
740 |
-
self.shell.user_ns['__file__'] = filename
|
741 |
-
self.shell.safe_execfile_ipy(filename, raise_exceptions=True)
|
742 |
-
return
|
743 |
-
|
744 |
-
# Control the response to exit() calls made by the script being run
|
745 |
-
exit_ignore = 'e' in opts
|
746 |
-
|
747 |
-
# Make sure that the running script gets a proper sys.argv as if it
|
748 |
-
# were run from a system shell.
|
749 |
-
save_argv = sys.argv # save it for later restoring
|
750 |
-
|
751 |
-
if 'G' in opts:
|
752 |
-
args = arg_lst[1:]
|
753 |
-
else:
|
754 |
-
# tilde and glob expansion
|
755 |
-
args = shellglob(map(os.path.expanduser, arg_lst[1:]))
|
756 |
-
|
757 |
-
sys.argv = [filename] + args # put in the proper filename
|
758 |
-
|
759 |
-
if 'n' in opts:
|
760 |
-
name = Path(filename).stem
|
761 |
-
else:
|
762 |
-
name = '__main__'
|
763 |
-
|
764 |
-
if 'i' in opts:
|
765 |
-
# Run in user's interactive namespace
|
766 |
-
prog_ns = self.shell.user_ns
|
767 |
-
__name__save = self.shell.user_ns['__name__']
|
768 |
-
prog_ns['__name__'] = name
|
769 |
-
main_mod = self.shell.user_module
|
770 |
-
|
771 |
-
# Since '%run foo' emulates 'python foo.py' at the cmd line, we must
|
772 |
-
# set the __file__ global in the script's namespace
|
773 |
-
# TK: Is this necessary in interactive mode?
|
774 |
-
prog_ns['__file__'] = filename
|
775 |
-
else:
|
776 |
-
# Run in a fresh, empty namespace
|
777 |
-
|
778 |
-
# The shell MUST hold a reference to prog_ns so after %run
|
779 |
-
# exits, the python deletion mechanism doesn't zero it out
|
780 |
-
# (leaving dangling references). See interactiveshell for details
|
781 |
-
main_mod = self.shell.new_main_mod(filename, name)
|
782 |
-
prog_ns = main_mod.__dict__
|
783 |
-
|
784 |
-
# pickle fix. See interactiveshell for an explanation. But we need to
|
785 |
-
# make sure that, if we overwrite __main__, we replace it at the end
|
786 |
-
main_mod_name = prog_ns['__name__']
|
787 |
-
|
788 |
-
if main_mod_name == '__main__':
|
789 |
-
restore_main = sys.modules['__main__']
|
790 |
-
else:
|
791 |
-
restore_main = False
|
792 |
-
|
793 |
-
# This needs to be undone at the end to prevent holding references to
|
794 |
-
# every single object ever created.
|
795 |
-
sys.modules[main_mod_name] = main_mod
|
796 |
-
|
797 |
-
if 'p' in opts or 'd' in opts:
|
798 |
-
if 'm' in opts:
|
799 |
-
code = 'run_module(modulename, prog_ns)'
|
800 |
-
code_ns = {
|
801 |
-
'run_module': self.shell.safe_run_module,
|
802 |
-
'prog_ns': prog_ns,
|
803 |
-
'modulename': modulename,
|
804 |
-
}
|
805 |
-
else:
|
806 |
-
if 'd' in opts:
|
807 |
-
# allow exceptions to raise in debug mode
|
808 |
-
code = 'execfile(filename, prog_ns, raise_exceptions=True)'
|
809 |
-
else:
|
810 |
-
code = 'execfile(filename, prog_ns)'
|
811 |
-
code_ns = {
|
812 |
-
'execfile': self.shell.safe_execfile,
|
813 |
-
'prog_ns': prog_ns,
|
814 |
-
'filename': get_py_filename(filename),
|
815 |
-
}
|
816 |
-
|
817 |
-
try:
|
818 |
-
stats = None
|
819 |
-
if 'p' in opts:
|
820 |
-
stats = self._run_with_profiler(code, opts, code_ns)
|
821 |
-
else:
|
822 |
-
if 'd' in opts:
|
823 |
-
bp_file, bp_line = parse_breakpoint(
|
824 |
-
opts.get('b', ['1'])[0], filename)
|
825 |
-
self._run_with_debugger(
|
826 |
-
code, code_ns, filename, bp_line, bp_file)
|
827 |
-
else:
|
828 |
-
if 'm' in opts:
|
829 |
-
def run():
|
830 |
-
self.shell.safe_run_module(modulename, prog_ns)
|
831 |
-
else:
|
832 |
-
if runner is None:
|
833 |
-
runner = self.default_runner
|
834 |
-
if runner is None:
|
835 |
-
runner = self.shell.safe_execfile
|
836 |
-
|
837 |
-
def run():
|
838 |
-
runner(filename, prog_ns, prog_ns,
|
839 |
-
exit_ignore=exit_ignore)
|
840 |
-
|
841 |
-
if 't' in opts:
|
842 |
-
# timed execution
|
843 |
-
try:
|
844 |
-
nruns = int(opts['N'][0])
|
845 |
-
if nruns < 1:
|
846 |
-
error('Number of runs must be >=1')
|
847 |
-
return
|
848 |
-
except (KeyError):
|
849 |
-
nruns = 1
|
850 |
-
self._run_with_timing(run, nruns)
|
851 |
-
else:
|
852 |
-
# regular execution
|
853 |
-
run()
|
854 |
-
|
855 |
-
if 'i' in opts:
|
856 |
-
self.shell.user_ns['__name__'] = __name__save
|
857 |
-
else:
|
858 |
-
# update IPython interactive namespace
|
859 |
-
|
860 |
-
# Some forms of read errors on the file may mean the
|
861 |
-
# __name__ key was never set; using pop we don't have to
|
862 |
-
# worry about a possible KeyError.
|
863 |
-
prog_ns.pop('__name__', None)
|
864 |
-
|
865 |
-
with preserve_keys(self.shell.user_ns, '__file__'):
|
866 |
-
self.shell.user_ns.update(prog_ns)
|
867 |
-
finally:
|
868 |
-
# It's a bit of a mystery why, but __builtins__ can change from
|
869 |
-
# being a module to becoming a dict missing some key data after
|
870 |
-
# %run. As best I can see, this is NOT something IPython is doing
|
871 |
-
# at all, and similar problems have been reported before:
|
872 |
-
# http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
|
873 |
-
# Since this seems to be done by the interpreter itself, the best
|
874 |
-
# we can do is to at least restore __builtins__ for the user on
|
875 |
-
# exit.
|
876 |
-
self.shell.user_ns['__builtins__'] = builtin_mod
|
877 |
-
|
878 |
-
# Ensure key global structures are restored
|
879 |
-
sys.argv = save_argv
|
880 |
-
if restore_main:
|
881 |
-
sys.modules['__main__'] = restore_main
|
882 |
-
if '__mp_main__' in sys.modules:
|
883 |
-
sys.modules['__mp_main__'] = restore_main
|
884 |
-
else:
|
885 |
-
# Remove from sys.modules the reference to main_mod we'd
|
886 |
-
# added. Otherwise it will trap references to objects
|
887 |
-
# contained therein.
|
888 |
-
del sys.modules[main_mod_name]
|
889 |
-
|
890 |
-
return stats
|
891 |
-
|
892 |
-
def _run_with_debugger(
|
893 |
-
self, code, code_ns, filename=None, bp_line=None, bp_file=None, local_ns=None
|
894 |
-
):
|
895 |
-
"""
|
896 |
-
Run `code` in debugger with a break point.
|
897 |
-
|
898 |
-
Parameters
|
899 |
-
----------
|
900 |
-
code : str
|
901 |
-
Code to execute.
|
902 |
-
code_ns : dict
|
903 |
-
A namespace in which `code` is executed.
|
904 |
-
filename : str
|
905 |
-
`code` is ran as if it is in `filename`.
|
906 |
-
bp_line : int, optional
|
907 |
-
Line number of the break point.
|
908 |
-
bp_file : str, optional
|
909 |
-
Path to the file in which break point is specified.
|
910 |
-
`filename` is used if not given.
|
911 |
-
local_ns : dict, optional
|
912 |
-
A local namespace in which `code` is executed.
|
913 |
-
|
914 |
-
Raises
|
915 |
-
------
|
916 |
-
UsageError
|
917 |
-
If the break point given by `bp_line` is not valid.
|
918 |
-
|
919 |
-
"""
|
920 |
-
deb = self.shell.InteractiveTB.pdb
|
921 |
-
if not deb:
|
922 |
-
self.shell.InteractiveTB.pdb = self.shell.InteractiveTB.debugger_cls()
|
923 |
-
deb = self.shell.InteractiveTB.pdb
|
924 |
-
|
925 |
-
# deb.checkline() fails if deb.curframe exists but is None; it can
|
926 |
-
# handle it not existing. https://github.com/ipython/ipython/issues/10028
|
927 |
-
if hasattr(deb, 'curframe'):
|
928 |
-
del deb.curframe
|
929 |
-
|
930 |
-
# reset Breakpoint state, which is moronically kept
|
931 |
-
# in a class
|
932 |
-
bdb.Breakpoint.next = 1
|
933 |
-
bdb.Breakpoint.bplist = {}
|
934 |
-
bdb.Breakpoint.bpbynumber = [None]
|
935 |
-
deb.clear_all_breaks()
|
936 |
-
if bp_line is not None:
|
937 |
-
# Set an initial breakpoint to stop execution
|
938 |
-
maxtries = 10
|
939 |
-
bp_file = bp_file or filename
|
940 |
-
checkline = deb.checkline(bp_file, bp_line)
|
941 |
-
if not checkline:
|
942 |
-
for bp in range(bp_line + 1, bp_line + maxtries + 1):
|
943 |
-
if deb.checkline(bp_file, bp):
|
944 |
-
break
|
945 |
-
else:
|
946 |
-
msg = ("\nI failed to find a valid line to set "
|
947 |
-
"a breakpoint\n"
|
948 |
-
"after trying up to line: %s.\n"
|
949 |
-
"Please set a valid breakpoint manually "
|
950 |
-
"with the -b option." % bp)
|
951 |
-
raise UsageError(msg)
|
952 |
-
# if we find a good linenumber, set the breakpoint
|
953 |
-
deb.do_break('%s:%s' % (bp_file, bp_line))
|
954 |
-
|
955 |
-
if filename:
|
956 |
-
# Mimic Pdb._runscript(...)
|
957 |
-
deb._wait_for_mainpyfile = True
|
958 |
-
deb.mainpyfile = deb.canonic(filename)
|
959 |
-
|
960 |
-
# Start file run
|
961 |
-
print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
|
962 |
-
try:
|
963 |
-
if filename:
|
964 |
-
# save filename so it can be used by methods on the deb object
|
965 |
-
deb._exec_filename = filename
|
966 |
-
while True:
|
967 |
-
try:
|
968 |
-
trace = sys.gettrace()
|
969 |
-
deb.run(code, code_ns, local_ns)
|
970 |
-
except Restart:
|
971 |
-
print("Restarting")
|
972 |
-
if filename:
|
973 |
-
deb._wait_for_mainpyfile = True
|
974 |
-
deb.mainpyfile = deb.canonic(filename)
|
975 |
-
continue
|
976 |
-
else:
|
977 |
-
break
|
978 |
-
finally:
|
979 |
-
sys.settrace(trace)
|
980 |
-
|
981 |
-
|
982 |
-
except:
|
983 |
-
etype, value, tb = sys.exc_info()
|
984 |
-
# Skip three frames in the traceback: the %run one,
|
985 |
-
# one inside bdb.py, and the command-line typed by the
|
986 |
-
# user (run by exec in pdb itself).
|
987 |
-
self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
|
988 |
-
|
989 |
-
@staticmethod
|
990 |
-
def _run_with_timing(run, nruns):
|
991 |
-
"""
|
992 |
-
Run function `run` and print timing information.
|
993 |
-
|
994 |
-
Parameters
|
995 |
-
----------
|
996 |
-
run : callable
|
997 |
-
Any callable object which takes no argument.
|
998 |
-
nruns : int
|
999 |
-
Number of times to execute `run`.
|
1000 |
-
|
1001 |
-
"""
|
1002 |
-
twall0 = time.perf_counter()
|
1003 |
-
if nruns == 1:
|
1004 |
-
t0 = clock2()
|
1005 |
-
run()
|
1006 |
-
t1 = clock2()
|
1007 |
-
t_usr = t1[0] - t0[0]
|
1008 |
-
t_sys = t1[1] - t0[1]
|
1009 |
-
print("\nIPython CPU timings (estimated):")
|
1010 |
-
print(" User : %10.2f s." % t_usr)
|
1011 |
-
print(" System : %10.2f s." % t_sys)
|
1012 |
-
else:
|
1013 |
-
runs = range(nruns)
|
1014 |
-
t0 = clock2()
|
1015 |
-
for nr in runs:
|
1016 |
-
run()
|
1017 |
-
t1 = clock2()
|
1018 |
-
t_usr = t1[0] - t0[0]
|
1019 |
-
t_sys = t1[1] - t0[1]
|
1020 |
-
print("\nIPython CPU timings (estimated):")
|
1021 |
-
print("Total runs performed:", nruns)
|
1022 |
-
print(" Times : %10s %10s" % ('Total', 'Per run'))
|
1023 |
-
print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
|
1024 |
-
print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
|
1025 |
-
twall1 = time.perf_counter()
|
1026 |
-
print("Wall time: %10.2f s." % (twall1 - twall0))
|
1027 |
-
|
1028 |
-
@skip_doctest
|
1029 |
-
@no_var_expand
|
1030 |
-
@line_cell_magic
|
1031 |
-
@needs_local_scope
|
1032 |
-
def timeit(self, line='', cell=None, local_ns=None):
|
1033 |
-
"""Time execution of a Python statement or expression
|
1034 |
-
|
1035 |
-
**Usage, in line mode:**
|
1036 |
-
|
1037 |
-
%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
|
1038 |
-
|
1039 |
-
**or in cell mode:**
|
1040 |
-
|
1041 |
-
%%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
|
1042 |
-
|
1043 |
-
code
|
1044 |
-
|
1045 |
-
code...
|
1046 |
-
|
1047 |
-
Time execution of a Python statement or expression using the timeit
|
1048 |
-
module. This function can be used both as a line and cell magic:
|
1049 |
-
|
1050 |
-
- In line mode you can time a single-line statement (though multiple
|
1051 |
-
ones can be chained with using semicolons).
|
1052 |
-
|
1053 |
-
- In cell mode, the statement in the first line is used as setup code
|
1054 |
-
(executed but not timed) and the body of the cell is timed. The cell
|
1055 |
-
body has access to any variables created in the setup code.
|
1056 |
-
|
1057 |
-
Options:
|
1058 |
-
|
1059 |
-
-n<N>: execute the given statement <N> times in a loop. If <N> is not
|
1060 |
-
provided, <N> is determined so as to get sufficient accuracy.
|
1061 |
-
|
1062 |
-
-r<R>: number of repeats <R>, each consisting of <N> loops, and take the
|
1063 |
-
average result.
|
1064 |
-
Default: 7
|
1065 |
-
|
1066 |
-
-t: use time.time to measure the time, which is the default on Unix.
|
1067 |
-
This function measures wall time.
|
1068 |
-
|
1069 |
-
-c: use time.clock to measure the time, which is the default on
|
1070 |
-
Windows and measures wall time. On Unix, resource.getrusage is used
|
1071 |
-
instead and returns the CPU user time.
|
1072 |
-
|
1073 |
-
-p<P>: use a precision of <P> digits to display the timing result.
|
1074 |
-
Default: 3
|
1075 |
-
|
1076 |
-
-q: Quiet, do not print result.
|
1077 |
-
|
1078 |
-
-o: return a TimeitResult that can be stored in a variable to inspect
|
1079 |
-
the result in more details.
|
1080 |
-
|
1081 |
-
.. versionchanged:: 7.3
|
1082 |
-
User variables are no longer expanded,
|
1083 |
-
the magic line is always left unmodified.
|
1084 |
-
|
1085 |
-
Examples
|
1086 |
-
--------
|
1087 |
-
::
|
1088 |
-
|
1089 |
-
In [1]: %timeit pass
|
1090 |
-
8.26 ns ± 0.12 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
|
1091 |
-
|
1092 |
-
In [2]: u = None
|
1093 |
-
|
1094 |
-
In [3]: %timeit u is None
|
1095 |
-
29.9 ns ± 0.643 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
|
1096 |
-
|
1097 |
-
In [4]: %timeit -r 4 u == None
|
1098 |
-
|
1099 |
-
In [5]: import time
|
1100 |
-
|
1101 |
-
In [6]: %timeit -n1 time.sleep(2)
|
1102 |
-
|
1103 |
-
The times reported by %timeit will be slightly higher than those
|
1104 |
-
reported by the timeit.py script when variables are accessed. This is
|
1105 |
-
due to the fact that %timeit executes the statement in the namespace
|
1106 |
-
of the shell, compared with timeit.py, which uses a single setup
|
1107 |
-
statement to import function or create variables. Generally, the bias
|
1108 |
-
does not matter as long as results from timeit.py are not mixed with
|
1109 |
-
those from %timeit."""
|
1110 |
-
|
1111 |
-
opts, stmt = self.parse_options(
|
1112 |
-
line, "n:r:tcp:qo", posix=False, strict=False, preserve_non_opts=True
|
1113 |
-
)
|
1114 |
-
if stmt == "" and cell is None:
|
1115 |
-
return
|
1116 |
-
|
1117 |
-
timefunc = timeit.default_timer
|
1118 |
-
number = int(getattr(opts, "n", 0))
|
1119 |
-
default_repeat = 7 if timeit.default_repeat < 7 else timeit.default_repeat
|
1120 |
-
repeat = int(getattr(opts, "r", default_repeat))
|
1121 |
-
precision = int(getattr(opts, "p", 3))
|
1122 |
-
quiet = 'q' in opts
|
1123 |
-
return_result = 'o' in opts
|
1124 |
-
if hasattr(opts, "t"):
|
1125 |
-
timefunc = time.time
|
1126 |
-
if hasattr(opts, "c"):
|
1127 |
-
timefunc = clock
|
1128 |
-
|
1129 |
-
timer = Timer(timer=timefunc)
|
1130 |
-
# this code has tight coupling to the inner workings of timeit.Timer,
|
1131 |
-
# but is there a better way to achieve that the code stmt has access
|
1132 |
-
# to the shell namespace?
|
1133 |
-
transform = self.shell.transform_cell
|
1134 |
-
|
1135 |
-
if cell is None:
|
1136 |
-
# called as line magic
|
1137 |
-
ast_setup = self.shell.compile.ast_parse("pass")
|
1138 |
-
ast_stmt = self.shell.compile.ast_parse(transform(stmt))
|
1139 |
-
else:
|
1140 |
-
ast_setup = self.shell.compile.ast_parse(transform(stmt))
|
1141 |
-
ast_stmt = self.shell.compile.ast_parse(transform(cell))
|
1142 |
-
|
1143 |
-
ast_setup = self.shell.transform_ast(ast_setup)
|
1144 |
-
ast_stmt = self.shell.transform_ast(ast_stmt)
|
1145 |
-
|
1146 |
-
# Check that these compile to valid Python code *outside* the timer func
|
1147 |
-
# Invalid code may become valid when put inside the function & loop,
|
1148 |
-
# which messes up error messages.
|
1149 |
-
# https://github.com/ipython/ipython/issues/10636
|
1150 |
-
self.shell.compile(ast_setup, "<magic-timeit-setup>", "exec")
|
1151 |
-
self.shell.compile(ast_stmt, "<magic-timeit-stmt>", "exec")
|
1152 |
-
|
1153 |
-
# This codestring is taken from timeit.template - we fill it in as an
|
1154 |
-
# AST, so that we can apply our AST transformations to the user code
|
1155 |
-
# without affecting the timing code.
|
1156 |
-
timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
|
1157 |
-
' setup\n'
|
1158 |
-
' _t0 = _timer()\n'
|
1159 |
-
' for _i in _it:\n'
|
1160 |
-
' stmt\n'
|
1161 |
-
' _t1 = _timer()\n'
|
1162 |
-
' return _t1 - _t0\n')
|
1163 |
-
|
1164 |
-
timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
|
1165 |
-
timeit_ast = ast.fix_missing_locations(timeit_ast)
|
1166 |
-
|
1167 |
-
# Track compilation time so it can be reported if too long
|
1168 |
-
# Minimum time above which compilation time will be reported
|
1169 |
-
tc_min = 0.1
|
1170 |
-
|
1171 |
-
t0 = clock()
|
1172 |
-
code = self.shell.compile(timeit_ast, "<magic-timeit>", "exec")
|
1173 |
-
tc = clock()-t0
|
1174 |
-
|
1175 |
-
ns = {}
|
1176 |
-
glob = self.shell.user_ns
|
1177 |
-
# handles global vars with same name as local vars. We store them in conflict_globs.
|
1178 |
-
conflict_globs = {}
|
1179 |
-
if local_ns and cell is None:
|
1180 |
-
for var_name, var_val in glob.items():
|
1181 |
-
if var_name in local_ns:
|
1182 |
-
conflict_globs[var_name] = var_val
|
1183 |
-
glob.update(local_ns)
|
1184 |
-
|
1185 |
-
exec(code, glob, ns)
|
1186 |
-
timer.inner = ns["inner"]
|
1187 |
-
|
1188 |
-
# This is used to check if there is a huge difference between the
|
1189 |
-
# best and worst timings.
|
1190 |
-
# Issue: https://github.com/ipython/ipython/issues/6471
|
1191 |
-
if number == 0:
|
1192 |
-
# determine number so that 0.2 <= total time < 2.0
|
1193 |
-
for index in range(0, 10):
|
1194 |
-
number = 10 ** index
|
1195 |
-
time_number = timer.timeit(number)
|
1196 |
-
if time_number >= 0.2:
|
1197 |
-
break
|
1198 |
-
|
1199 |
-
all_runs = timer.repeat(repeat, number)
|
1200 |
-
best = min(all_runs) / number
|
1201 |
-
worst = max(all_runs) / number
|
1202 |
-
timeit_result = TimeitResult(number, repeat, best, worst, all_runs, tc, precision)
|
1203 |
-
|
1204 |
-
# Restore global vars from conflict_globs
|
1205 |
-
if conflict_globs:
|
1206 |
-
glob.update(conflict_globs)
|
1207 |
-
|
1208 |
-
if not quiet :
|
1209 |
-
# Check best timing is greater than zero to avoid a
|
1210 |
-
# ZeroDivisionError.
|
1211 |
-
# In cases where the slowest timing is lesser than a microsecond
|
1212 |
-
# we assume that it does not really matter if the fastest
|
1213 |
-
# timing is 4 times faster than the slowest timing or not.
|
1214 |
-
if worst > 4 * best and best > 0 and worst > 1e-6:
|
1215 |
-
print("The slowest run took %0.2f times longer than the "
|
1216 |
-
"fastest. This could mean that an intermediate result "
|
1217 |
-
"is being cached." % (worst / best))
|
1218 |
-
|
1219 |
-
print( timeit_result )
|
1220 |
-
|
1221 |
-
if tc > tc_min:
|
1222 |
-
print("Compiler time: %.2f s" % tc)
|
1223 |
-
if return_result:
|
1224 |
-
return timeit_result
|
1225 |
-
|
1226 |
-
@skip_doctest
|
1227 |
-
@no_var_expand
|
1228 |
-
@needs_local_scope
|
1229 |
-
@line_cell_magic
|
1230 |
-
@output_can_be_silenced
|
1231 |
-
def time(self,line='', cell=None, local_ns=None):
|
1232 |
-
"""Time execution of a Python statement or expression.
|
1233 |
-
|
1234 |
-
The CPU and wall clock times are printed, and the value of the
|
1235 |
-
expression (if any) is returned. Note that under Win32, system time
|
1236 |
-
is always reported as 0, since it can not be measured.
|
1237 |
-
|
1238 |
-
This function can be used both as a line and cell magic:
|
1239 |
-
|
1240 |
-
- In line mode you can time a single-line statement (though multiple
|
1241 |
-
ones can be chained with using semicolons).
|
1242 |
-
|
1243 |
-
- In cell mode, you can time the cell body (a directly
|
1244 |
-
following statement raises an error).
|
1245 |
-
|
1246 |
-
This function provides very basic timing functionality. Use the timeit
|
1247 |
-
magic for more control over the measurement.
|
1248 |
-
|
1249 |
-
.. versionchanged:: 7.3
|
1250 |
-
User variables are no longer expanded,
|
1251 |
-
the magic line is always left unmodified.
|
1252 |
-
|
1253 |
-
Examples
|
1254 |
-
--------
|
1255 |
-
::
|
1256 |
-
|
1257 |
-
In [1]: %time 2**128
|
1258 |
-
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
|
1259 |
-
Wall time: 0.00
|
1260 |
-
Out[1]: 340282366920938463463374607431768211456L
|
1261 |
-
|
1262 |
-
In [2]: n = 1000000
|
1263 |
-
|
1264 |
-
In [3]: %time sum(range(n))
|
1265 |
-
CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
|
1266 |
-
Wall time: 1.37
|
1267 |
-
Out[3]: 499999500000L
|
1268 |
-
|
1269 |
-
In [4]: %time print('hello world')
|
1270 |
-
hello world
|
1271 |
-
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
|
1272 |
-
Wall time: 0.00
|
1273 |
-
|
1274 |
-
.. note::
|
1275 |
-
The time needed by Python to compile the given expression will be
|
1276 |
-
reported if it is more than 0.1s.
|
1277 |
-
|
1278 |
-
In the example below, the actual exponentiation is done by Python
|
1279 |
-
at compilation time, so while the expression can take a noticeable
|
1280 |
-
amount of time to compute, that time is purely due to the
|
1281 |
-
compilation::
|
1282 |
-
|
1283 |
-
In [5]: %time 3**9999;
|
1284 |
-
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
|
1285 |
-
Wall time: 0.00 s
|
1286 |
-
|
1287 |
-
In [6]: %time 3**999999;
|
1288 |
-
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
|
1289 |
-
Wall time: 0.00 s
|
1290 |
-
Compiler : 0.78 s
|
1291 |
-
"""
|
1292 |
-
# fail immediately if the given expression can't be compiled
|
1293 |
-
|
1294 |
-
if line and cell:
|
1295 |
-
raise UsageError("Can't use statement directly after '%%time'!")
|
1296 |
-
|
1297 |
-
if cell:
|
1298 |
-
expr = self.shell.transform_cell(cell)
|
1299 |
-
else:
|
1300 |
-
expr = self.shell.transform_cell(line)
|
1301 |
-
|
1302 |
-
# Minimum time above which parse time will be reported
|
1303 |
-
tp_min = 0.1
|
1304 |
-
|
1305 |
-
t0 = clock()
|
1306 |
-
expr_ast = self.shell.compile.ast_parse(expr)
|
1307 |
-
tp = clock()-t0
|
1308 |
-
|
1309 |
-
# Apply AST transformations
|
1310 |
-
expr_ast = self.shell.transform_ast(expr_ast)
|
1311 |
-
|
1312 |
-
# Minimum time above which compilation time will be reported
|
1313 |
-
tc_min = 0.1
|
1314 |
-
|
1315 |
-
expr_val=None
|
1316 |
-
if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
|
1317 |
-
mode = 'eval'
|
1318 |
-
source = '<timed eval>'
|
1319 |
-
expr_ast = ast.Expression(expr_ast.body[0].value)
|
1320 |
-
else:
|
1321 |
-
mode = 'exec'
|
1322 |
-
source = '<timed exec>'
|
1323 |
-
# multi-line %%time case
|
1324 |
-
if len(expr_ast.body) > 1 and isinstance(expr_ast.body[-1], ast.Expr):
|
1325 |
-
expr_val= expr_ast.body[-1]
|
1326 |
-
expr_ast = expr_ast.body[:-1]
|
1327 |
-
expr_ast = Module(expr_ast, [])
|
1328 |
-
expr_val = ast.Expression(expr_val.value)
|
1329 |
-
|
1330 |
-
t0 = clock()
|
1331 |
-
code = self.shell.compile(expr_ast, source, mode)
|
1332 |
-
tc = clock()-t0
|
1333 |
-
|
1334 |
-
# skew measurement as little as possible
|
1335 |
-
glob = self.shell.user_ns
|
1336 |
-
wtime = time.time
|
1337 |
-
# time execution
|
1338 |
-
wall_st = wtime()
|
1339 |
-
if mode=='eval':
|
1340 |
-
st = clock2()
|
1341 |
-
try:
|
1342 |
-
out = eval(code, glob, local_ns)
|
1343 |
-
except:
|
1344 |
-
self.shell.showtraceback()
|
1345 |
-
return
|
1346 |
-
end = clock2()
|
1347 |
-
else:
|
1348 |
-
st = clock2()
|
1349 |
-
try:
|
1350 |
-
exec(code, glob, local_ns)
|
1351 |
-
out=None
|
1352 |
-
# multi-line %%time case
|
1353 |
-
if expr_val is not None:
|
1354 |
-
code_2 = self.shell.compile(expr_val, source, 'eval')
|
1355 |
-
out = eval(code_2, glob, local_ns)
|
1356 |
-
except:
|
1357 |
-
self.shell.showtraceback()
|
1358 |
-
return
|
1359 |
-
end = clock2()
|
1360 |
-
|
1361 |
-
wall_end = wtime()
|
1362 |
-
# Compute actual times and report
|
1363 |
-
wall_time = wall_end - wall_st
|
1364 |
-
cpu_user = end[0] - st[0]
|
1365 |
-
cpu_sys = end[1] - st[1]
|
1366 |
-
cpu_tot = cpu_user + cpu_sys
|
1367 |
-
# On windows cpu_sys is always zero, so only total is displayed
|
1368 |
-
if sys.platform != "win32":
|
1369 |
-
print(
|
1370 |
-
f"CPU times: user {_format_time(cpu_user)}, sys: {_format_time(cpu_sys)}, total: {_format_time(cpu_tot)}"
|
1371 |
-
)
|
1372 |
-
else:
|
1373 |
-
print(f"CPU times: total: {_format_time(cpu_tot)}")
|
1374 |
-
print(f"Wall time: {_format_time(wall_time)}")
|
1375 |
-
if tc > tc_min:
|
1376 |
-
print(f"Compiler : {_format_time(tc)}")
|
1377 |
-
if tp > tp_min:
|
1378 |
-
print(f"Parser : {_format_time(tp)}")
|
1379 |
-
return out
|
1380 |
-
|
1381 |
-
@skip_doctest
|
1382 |
-
@line_magic
|
1383 |
-
def macro(self, parameter_s=''):
|
1384 |
-
"""Define a macro for future re-execution. It accepts ranges of history,
|
1385 |
-
filenames or string objects.
|
1386 |
-
|
1387 |
-
Usage:\\
|
1388 |
-
%macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
|
1389 |
-
|
1390 |
-
Options:
|
1391 |
-
|
1392 |
-
-r: use 'raw' input. By default, the 'processed' history is used,
|
1393 |
-
so that magics are loaded in their transformed version to valid
|
1394 |
-
Python. If this option is given, the raw input as typed at the
|
1395 |
-
command line is used instead.
|
1396 |
-
|
1397 |
-
-q: quiet macro definition. By default, a tag line is printed
|
1398 |
-
to indicate the macro has been created, and then the contents of
|
1399 |
-
the macro are printed. If this option is given, then no printout
|
1400 |
-
is produced once the macro is created.
|
1401 |
-
|
1402 |
-
This will define a global variable called `name` which is a string
|
1403 |
-
made of joining the slices and lines you specify (n1,n2,... numbers
|
1404 |
-
above) from your input history into a single string. This variable
|
1405 |
-
acts like an automatic function which re-executes those lines as if
|
1406 |
-
you had typed them. You just type 'name' at the prompt and the code
|
1407 |
-
executes.
|
1408 |
-
|
1409 |
-
The syntax for indicating input ranges is described in %history.
|
1410 |
-
|
1411 |
-
Note: as a 'hidden' feature, you can also use traditional python slice
|
1412 |
-
notation, where N:M means numbers N through M-1.
|
1413 |
-
|
1414 |
-
For example, if your history contains (print using %hist -n )::
|
1415 |
-
|
1416 |
-
44: x=1
|
1417 |
-
45: y=3
|
1418 |
-
46: z=x+y
|
1419 |
-
47: print(x)
|
1420 |
-
48: a=5
|
1421 |
-
49: print('x',x,'y',y)
|
1422 |
-
|
1423 |
-
you can create a macro with lines 44 through 47 (included) and line 49
|
1424 |
-
called my_macro with::
|
1425 |
-
|
1426 |
-
In [55]: %macro my_macro 44-47 49
|
1427 |
-
|
1428 |
-
Now, typing `my_macro` (without quotes) will re-execute all this code
|
1429 |
-
in one pass.
|
1430 |
-
|
1431 |
-
You don't need to give the line-numbers in order, and any given line
|
1432 |
-
number can appear multiple times. You can assemble macros with any
|
1433 |
-
lines from your input history in any order.
|
1434 |
-
|
1435 |
-
The macro is a simple object which holds its value in an attribute,
|
1436 |
-
but IPython's display system checks for macros and executes them as
|
1437 |
-
code instead of printing them when you type their name.
|
1438 |
-
|
1439 |
-
You can view a macro's contents by explicitly printing it with::
|
1440 |
-
|
1441 |
-
print(macro_name)
|
1442 |
-
|
1443 |
-
"""
|
1444 |
-
opts,args = self.parse_options(parameter_s,'rq',mode='list')
|
1445 |
-
if not args: # List existing macros
|
1446 |
-
return sorted(k for k,v in self.shell.user_ns.items() if isinstance(v, Macro))
|
1447 |
-
if len(args) == 1:
|
1448 |
-
raise UsageError(
|
1449 |
-
"%macro insufficient args; usage '%macro name n1-n2 n3-4...")
|
1450 |
-
name, codefrom = args[0], " ".join(args[1:])
|
1451 |
-
|
1452 |
-
# print('rng',ranges) # dbg
|
1453 |
-
try:
|
1454 |
-
lines = self.shell.find_user_code(codefrom, 'r' in opts)
|
1455 |
-
except (ValueError, TypeError) as e:
|
1456 |
-
print(e.args[0])
|
1457 |
-
return
|
1458 |
-
macro = Macro(lines)
|
1459 |
-
self.shell.define_macro(name, macro)
|
1460 |
-
if not ( 'q' in opts) :
|
1461 |
-
print('Macro `%s` created. To execute, type its name (without quotes).' % name)
|
1462 |
-
print('=== Macro contents: ===')
|
1463 |
-
print(macro, end=' ')
|
1464 |
-
|
1465 |
-
@magic_arguments.magic_arguments()
|
1466 |
-
@magic_arguments.argument('output', type=str, default='', nargs='?',
|
1467 |
-
help="""The name of the variable in which to store output.
|
1468 |
-
This is a utils.io.CapturedIO object with stdout/err attributes
|
1469 |
-
for the text of the captured output.
|
1470 |
-
|
1471 |
-
CapturedOutput also has a show() method for displaying the output,
|
1472 |
-
and __call__ as well, so you can use that to quickly display the
|
1473 |
-
output.
|
1474 |
-
|
1475 |
-
If unspecified, captured output is discarded.
|
1476 |
-
"""
|
1477 |
-
)
|
1478 |
-
@magic_arguments.argument('--no-stderr', action="store_true",
|
1479 |
-
help="""Don't capture stderr."""
|
1480 |
-
)
|
1481 |
-
@magic_arguments.argument('--no-stdout', action="store_true",
|
1482 |
-
help="""Don't capture stdout."""
|
1483 |
-
)
|
1484 |
-
@magic_arguments.argument('--no-display', action="store_true",
|
1485 |
-
help="""Don't capture IPython's rich display."""
|
1486 |
-
)
|
1487 |
-
@cell_magic
|
1488 |
-
def capture(self, line, cell):
|
1489 |
-
"""run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
|
1490 |
-
args = magic_arguments.parse_argstring(self.capture, line)
|
1491 |
-
out = not args.no_stdout
|
1492 |
-
err = not args.no_stderr
|
1493 |
-
disp = not args.no_display
|
1494 |
-
with capture_output(out, err, disp) as io:
|
1495 |
-
self.shell.run_cell(cell)
|
1496 |
-
if DisplayHook.semicolon_at_end_of_expression(cell):
|
1497 |
-
if args.output in self.shell.user_ns:
|
1498 |
-
del self.shell.user_ns[args.output]
|
1499 |
-
elif args.output:
|
1500 |
-
self.shell.user_ns[args.output] = io
|
1501 |
-
|
1502 |
-
@skip_doctest
|
1503 |
-
@magic_arguments.magic_arguments()
|
1504 |
-
@magic_arguments.argument("name", type=str, default="default", nargs="?")
|
1505 |
-
@magic_arguments.argument(
|
1506 |
-
"--remove", action="store_true", help="remove the current transformer"
|
1507 |
-
)
|
1508 |
-
@magic_arguments.argument(
|
1509 |
-
"--list", action="store_true", help="list existing transformers name"
|
1510 |
-
)
|
1511 |
-
@magic_arguments.argument(
|
1512 |
-
"--list-all",
|
1513 |
-
action="store_true",
|
1514 |
-
help="list existing transformers name and code template",
|
1515 |
-
)
|
1516 |
-
@line_cell_magic
|
1517 |
-
def code_wrap(self, line, cell=None):
|
1518 |
-
"""
|
1519 |
-
Simple magic to quickly define a code transformer for all IPython's future input.
|
1520 |
-
|
1521 |
-
``__code__`` and ``__ret__`` are special variable that represent the code to run
|
1522 |
-
and the value of the last expression of ``__code__`` respectively.
|
1523 |
-
|
1524 |
-
Examples
|
1525 |
-
--------
|
1526 |
-
|
1527 |
-
.. ipython::
|
1528 |
-
|
1529 |
-
In [1]: %%code_wrap before_after
|
1530 |
-
...: print('before')
|
1531 |
-
...: __code__
|
1532 |
-
...: print('after')
|
1533 |
-
...: __ret__
|
1534 |
-
|
1535 |
-
|
1536 |
-
In [2]: 1
|
1537 |
-
before
|
1538 |
-
after
|
1539 |
-
Out[2]: 1
|
1540 |
-
|
1541 |
-
In [3]: %code_wrap --list
|
1542 |
-
before_after
|
1543 |
-
|
1544 |
-
In [4]: %code_wrap --list-all
|
1545 |
-
before_after :
|
1546 |
-
print('before')
|
1547 |
-
__code__
|
1548 |
-
print('after')
|
1549 |
-
__ret__
|
1550 |
-
|
1551 |
-
In [5]: %code_wrap --remove before_after
|
1552 |
-
|
1553 |
-
"""
|
1554 |
-
args = magic_arguments.parse_argstring(self.code_wrap, line)
|
1555 |
-
|
1556 |
-
if args.list:
|
1557 |
-
for name in self._transformers.keys():
|
1558 |
-
print(name)
|
1559 |
-
return
|
1560 |
-
if args.list_all:
|
1561 |
-
for name, _t in self._transformers.items():
|
1562 |
-
print(name, ":")
|
1563 |
-
print(indent(ast.unparse(_t.template), " "))
|
1564 |
-
print()
|
1565 |
-
return
|
1566 |
-
|
1567 |
-
to_remove = self._transformers.pop(args.name, None)
|
1568 |
-
if to_remove in self.shell.ast_transformers:
|
1569 |
-
self.shell.ast_transformers.remove(to_remove)
|
1570 |
-
if cell is None or args.remove:
|
1571 |
-
return
|
1572 |
-
|
1573 |
-
_trs = ReplaceCodeTransformer(ast.parse(cell))
|
1574 |
-
|
1575 |
-
self._transformers[args.name] = _trs
|
1576 |
-
self.shell.ast_transformers.append(_trs)
|
1577 |
-
|
1578 |
-
|
1579 |
-
def parse_breakpoint(text, current_file):
|
1580 |
-
'''Returns (file, line) for file:line and (current_file, line) for line'''
|
1581 |
-
colon = text.find(':')
|
1582 |
-
if colon == -1:
|
1583 |
-
return current_file, int(text)
|
1584 |
-
else:
|
1585 |
-
return text[:colon], int(text[colon+1:])
|
1586 |
-
|
1587 |
-
def _format_time(timespan, precision=3):
|
1588 |
-
"""Formats the timespan in a human readable form"""
|
1589 |
-
|
1590 |
-
if timespan >= 60.0:
|
1591 |
-
# we have more than a minute, format that in a human readable form
|
1592 |
-
# Idea from http://snipplr.com/view/5713/
|
1593 |
-
parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
|
1594 |
-
time = []
|
1595 |
-
leftover = timespan
|
1596 |
-
for suffix, length in parts:
|
1597 |
-
value = int(leftover / length)
|
1598 |
-
if value > 0:
|
1599 |
-
leftover = leftover % length
|
1600 |
-
time.append(u'%s%s' % (str(value), suffix))
|
1601 |
-
if leftover < 1:
|
1602 |
-
break
|
1603 |
-
return " ".join(time)
|
1604 |
-
|
1605 |
-
|
1606 |
-
# Unfortunately characters outside of range(128) can cause problems in
|
1607 |
-
# certain terminals.
|
1608 |
-
# See bug: https://bugs.launchpad.net/ipython/+bug/348466
|
1609 |
-
# Try to prevent crashes by being more secure than it needs to
|
1610 |
-
# E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set.
|
1611 |
-
units = ["s", "ms", "us", "ns"] # the safe value
|
1612 |
-
if hasattr(sys.stdout, "encoding") and sys.stdout.encoding:
|
1613 |
-
try:
|
1614 |
-
"μ".encode(sys.stdout.encoding)
|
1615 |
-
units = ["s", "ms", "μs", "ns"]
|
1616 |
-
except:
|
1617 |
-
pass
|
1618 |
-
scaling = [1, 1e3, 1e6, 1e9]
|
1619 |
-
|
1620 |
-
if timespan > 0.0:
|
1621 |
-
order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
|
1622 |
-
else:
|
1623 |
-
order = 3
|
1624 |
-
return "%.*g %s" % (precision, timespan * scaling[order], units[order])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/extension.py
DELETED
@@ -1,63 +0,0 @@
|
|
1 |
-
"""Implementation of magic functions for the extension machinery.
|
2 |
-
"""
|
3 |
-
#-----------------------------------------------------------------------------
|
4 |
-
# Copyright (c) 2012 The IPython Development Team.
|
5 |
-
#
|
6 |
-
# Distributed under the terms of the Modified BSD License.
|
7 |
-
#
|
8 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
9 |
-
#-----------------------------------------------------------------------------
|
10 |
-
|
11 |
-
#-----------------------------------------------------------------------------
|
12 |
-
# Imports
|
13 |
-
#-----------------------------------------------------------------------------
|
14 |
-
|
15 |
-
|
16 |
-
# Our own packages
|
17 |
-
from IPython.core.error import UsageError
|
18 |
-
from IPython.core.magic import Magics, magics_class, line_magic
|
19 |
-
|
20 |
-
#-----------------------------------------------------------------------------
|
21 |
-
# Magic implementation classes
|
22 |
-
#-----------------------------------------------------------------------------
|
23 |
-
|
24 |
-
@magics_class
|
25 |
-
class ExtensionMagics(Magics):
|
26 |
-
"""Magics to manage the IPython extensions system."""
|
27 |
-
|
28 |
-
@line_magic
|
29 |
-
def load_ext(self, module_str):
|
30 |
-
"""Load an IPython extension by its module name."""
|
31 |
-
if not module_str:
|
32 |
-
raise UsageError('Missing module name.')
|
33 |
-
res = self.shell.extension_manager.load_extension(module_str)
|
34 |
-
|
35 |
-
if res == 'already loaded':
|
36 |
-
print("The %s extension is already loaded. To reload it, use:" % module_str)
|
37 |
-
print(" %reload_ext", module_str)
|
38 |
-
elif res == 'no load function':
|
39 |
-
print("The %s module is not an IPython extension." % module_str)
|
40 |
-
|
41 |
-
@line_magic
|
42 |
-
def unload_ext(self, module_str):
|
43 |
-
"""Unload an IPython extension by its module name.
|
44 |
-
|
45 |
-
Not all extensions can be unloaded, only those which define an
|
46 |
-
``unload_ipython_extension`` function.
|
47 |
-
"""
|
48 |
-
if not module_str:
|
49 |
-
raise UsageError('Missing module name.')
|
50 |
-
|
51 |
-
res = self.shell.extension_manager.unload_extension(module_str)
|
52 |
-
|
53 |
-
if res == 'no unload function':
|
54 |
-
print("The %s extension doesn't define how to unload it." % module_str)
|
55 |
-
elif res == "not loaded":
|
56 |
-
print("The %s extension is not loaded." % module_str)
|
57 |
-
|
58 |
-
@line_magic
|
59 |
-
def reload_ext(self, module_str):
|
60 |
-
"""Reload an IPython extension by its module name."""
|
61 |
-
if not module_str:
|
62 |
-
raise UsageError('Missing module name.')
|
63 |
-
self.shell.extension_manager.reload_extension(module_str)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/history.py
DELETED
@@ -1,338 +0,0 @@
|
|
1 |
-
"""Implementation of magic functions related to History.
|
2 |
-
"""
|
3 |
-
#-----------------------------------------------------------------------------
|
4 |
-
# Copyright (c) 2012, IPython Development Team.
|
5 |
-
#
|
6 |
-
# Distributed under the terms of the Modified BSD License.
|
7 |
-
#
|
8 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
9 |
-
#-----------------------------------------------------------------------------
|
10 |
-
|
11 |
-
#-----------------------------------------------------------------------------
|
12 |
-
# Imports
|
13 |
-
#-----------------------------------------------------------------------------
|
14 |
-
|
15 |
-
# Stdlib
|
16 |
-
import os
|
17 |
-
import sys
|
18 |
-
from io import open as io_open
|
19 |
-
import fnmatch
|
20 |
-
|
21 |
-
# Our own packages
|
22 |
-
from IPython.core.error import StdinNotImplementedError
|
23 |
-
from IPython.core.magic import Magics, magics_class, line_magic
|
24 |
-
from IPython.core.magic_arguments import (argument, magic_arguments,
|
25 |
-
parse_argstring)
|
26 |
-
from IPython.testing.skipdoctest import skip_doctest
|
27 |
-
from IPython.utils import io
|
28 |
-
|
29 |
-
#-----------------------------------------------------------------------------
|
30 |
-
# Magics class implementation
|
31 |
-
#-----------------------------------------------------------------------------
|
32 |
-
|
33 |
-
|
34 |
-
_unspecified = object()
|
35 |
-
|
36 |
-
|
37 |
-
@magics_class
|
38 |
-
class HistoryMagics(Magics):
|
39 |
-
|
40 |
-
@magic_arguments()
|
41 |
-
@argument(
|
42 |
-
'-n', dest='print_nums', action='store_true', default=False,
|
43 |
-
help="""
|
44 |
-
print line numbers for each input.
|
45 |
-
This feature is only available if numbered prompts are in use.
|
46 |
-
""")
|
47 |
-
@argument(
|
48 |
-
'-o', dest='get_output', action='store_true', default=False,
|
49 |
-
help="also print outputs for each input.")
|
50 |
-
@argument(
|
51 |
-
'-p', dest='pyprompts', action='store_true', default=False,
|
52 |
-
help="""
|
53 |
-
print classic '>>>' python prompts before each input.
|
54 |
-
This is useful for making documentation, and in conjunction
|
55 |
-
with -o, for producing doctest-ready output.
|
56 |
-
""")
|
57 |
-
@argument(
|
58 |
-
'-t', dest='raw', action='store_false', default=True,
|
59 |
-
help="""
|
60 |
-
print the 'translated' history, as IPython understands it.
|
61 |
-
IPython filters your input and converts it all into valid Python
|
62 |
-
source before executing it (things like magics or aliases are turned
|
63 |
-
into function calls, for example). With this option, you'll see the
|
64 |
-
native history instead of the user-entered version: '%%cd /' will be
|
65 |
-
seen as 'get_ipython().run_line_magic("cd", "/")' instead of '%%cd /'.
|
66 |
-
""")
|
67 |
-
@argument(
|
68 |
-
'-f', dest='filename',
|
69 |
-
help="""
|
70 |
-
FILENAME: instead of printing the output to the screen, redirect
|
71 |
-
it to the given file. The file is always overwritten, though *when
|
72 |
-
it can*, IPython asks for confirmation first. In particular, running
|
73 |
-
the command 'history -f FILENAME' from the IPython Notebook
|
74 |
-
interface will replace FILENAME even if it already exists *without*
|
75 |
-
confirmation.
|
76 |
-
""")
|
77 |
-
@argument(
|
78 |
-
'-g', dest='pattern', nargs='*', default=None,
|
79 |
-
help="""
|
80 |
-
treat the arg as a glob pattern to search for in (full) history.
|
81 |
-
This includes the saved history (almost all commands ever written).
|
82 |
-
The pattern may contain '?' to match one unknown character and '*'
|
83 |
-
to match any number of unknown characters. Use '%%hist -g' to show
|
84 |
-
full saved history (may be very long).
|
85 |
-
""")
|
86 |
-
@argument(
|
87 |
-
'-l', dest='limit', type=int, nargs='?', default=_unspecified,
|
88 |
-
help="""
|
89 |
-
get the last n lines from all sessions. Specify n as a single
|
90 |
-
arg, or the default is the last 10 lines.
|
91 |
-
""")
|
92 |
-
@argument(
|
93 |
-
'-u', dest='unique', action='store_true',
|
94 |
-
help="""
|
95 |
-
when searching history using `-g`, show only unique history.
|
96 |
-
""")
|
97 |
-
@argument('range', nargs='*')
|
98 |
-
@skip_doctest
|
99 |
-
@line_magic
|
100 |
-
def history(self, parameter_s = ''):
|
101 |
-
"""Print input history (_i<n> variables), with most recent last.
|
102 |
-
|
103 |
-
By default, input history is printed without line numbers so it can be
|
104 |
-
directly pasted into an editor. Use -n to show them.
|
105 |
-
|
106 |
-
By default, all input history from the current session is displayed.
|
107 |
-
Ranges of history can be indicated using the syntax:
|
108 |
-
|
109 |
-
``4``
|
110 |
-
Line 4, current session
|
111 |
-
``4-6``
|
112 |
-
Lines 4-6, current session
|
113 |
-
``243/1-5``
|
114 |
-
Lines 1-5, session 243
|
115 |
-
``~2/7``
|
116 |
-
Line 7, session 2 before current
|
117 |
-
``~8/1-~6/5``
|
118 |
-
From the first line of 8 sessions ago, to the fifth line of 6
|
119 |
-
sessions ago.
|
120 |
-
|
121 |
-
Multiple ranges can be entered, separated by spaces
|
122 |
-
|
123 |
-
The same syntax is used by %macro, %save, %edit, %rerun
|
124 |
-
|
125 |
-
Examples
|
126 |
-
--------
|
127 |
-
::
|
128 |
-
|
129 |
-
In [6]: %history -n 4-6
|
130 |
-
4:a = 12
|
131 |
-
5:print(a**2)
|
132 |
-
6:%history -n 4-6
|
133 |
-
|
134 |
-
"""
|
135 |
-
|
136 |
-
args = parse_argstring(self.history, parameter_s)
|
137 |
-
|
138 |
-
# For brevity
|
139 |
-
history_manager = self.shell.history_manager
|
140 |
-
|
141 |
-
def _format_lineno(session, line):
|
142 |
-
"""Helper function to format line numbers properly."""
|
143 |
-
if session in (0, history_manager.session_number):
|
144 |
-
return str(line)
|
145 |
-
return "%s/%s" % (session, line)
|
146 |
-
|
147 |
-
# Check if output to specific file was requested.
|
148 |
-
outfname = args.filename
|
149 |
-
if not outfname:
|
150 |
-
outfile = sys.stdout # default
|
151 |
-
# We don't want to close stdout at the end!
|
152 |
-
close_at_end = False
|
153 |
-
else:
|
154 |
-
outfname = os.path.expanduser(outfname)
|
155 |
-
if os.path.exists(outfname):
|
156 |
-
try:
|
157 |
-
ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
|
158 |
-
except StdinNotImplementedError:
|
159 |
-
ans = True
|
160 |
-
if not ans:
|
161 |
-
print('Aborting.')
|
162 |
-
return
|
163 |
-
print("Overwriting file.")
|
164 |
-
outfile = io_open(outfname, 'w', encoding='utf-8')
|
165 |
-
close_at_end = True
|
166 |
-
|
167 |
-
print_nums = args.print_nums
|
168 |
-
get_output = args.get_output
|
169 |
-
pyprompts = args.pyprompts
|
170 |
-
raw = args.raw
|
171 |
-
|
172 |
-
pattern = None
|
173 |
-
limit = None if args.limit is _unspecified else args.limit
|
174 |
-
|
175 |
-
range_pattern = False
|
176 |
-
if args.pattern is not None and not args.range:
|
177 |
-
if args.pattern:
|
178 |
-
pattern = "*" + " ".join(args.pattern) + "*"
|
179 |
-
else:
|
180 |
-
pattern = "*"
|
181 |
-
hist = history_manager.search(pattern, raw=raw, output=get_output,
|
182 |
-
n=limit, unique=args.unique)
|
183 |
-
print_nums = True
|
184 |
-
elif args.limit is not _unspecified:
|
185 |
-
n = 10 if limit is None else limit
|
186 |
-
hist = history_manager.get_tail(n, raw=raw, output=get_output)
|
187 |
-
else:
|
188 |
-
if args.pattern:
|
189 |
-
range_pattern = "*" + " ".join(args.pattern) + "*"
|
190 |
-
print_nums = True
|
191 |
-
hist = history_manager.get_range_by_str(
|
192 |
-
" ".join(args.range), raw, get_output
|
193 |
-
)
|
194 |
-
|
195 |
-
# We could be displaying the entire history, so let's not try to pull
|
196 |
-
# it into a list in memory. Anything that needs more space will just
|
197 |
-
# misalign.
|
198 |
-
width = 4
|
199 |
-
|
200 |
-
for session, lineno, inline in hist:
|
201 |
-
# Print user history with tabs expanded to 4 spaces. The GUI
|
202 |
-
# clients use hard tabs for easier usability in auto-indented code,
|
203 |
-
# but we want to produce PEP-8 compliant history for safe pasting
|
204 |
-
# into an editor.
|
205 |
-
if get_output:
|
206 |
-
inline, output = inline
|
207 |
-
if range_pattern:
|
208 |
-
if not fnmatch.fnmatch(inline, range_pattern):
|
209 |
-
continue
|
210 |
-
inline = inline.expandtabs(4).rstrip()
|
211 |
-
|
212 |
-
multiline = "\n" in inline
|
213 |
-
line_sep = '\n' if multiline else ' '
|
214 |
-
if print_nums:
|
215 |
-
print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
|
216 |
-
line_sep), file=outfile, end=u'')
|
217 |
-
if pyprompts:
|
218 |
-
print(u">>> ", end=u"", file=outfile)
|
219 |
-
if multiline:
|
220 |
-
inline = "\n... ".join(inline.splitlines()) + "\n..."
|
221 |
-
print(inline, file=outfile)
|
222 |
-
if get_output and output:
|
223 |
-
print(output, file=outfile)
|
224 |
-
|
225 |
-
if close_at_end:
|
226 |
-
outfile.close()
|
227 |
-
|
228 |
-
@line_magic
|
229 |
-
def recall(self, arg):
|
230 |
-
r"""Repeat a command, or get command to input line for editing.
|
231 |
-
|
232 |
-
%recall and %rep are equivalent.
|
233 |
-
|
234 |
-
- %recall (no arguments):
|
235 |
-
|
236 |
-
Place a string version of last computation result (stored in the
|
237 |
-
special '_' variable) to the next input prompt. Allows you to create
|
238 |
-
elaborate command lines without using copy-paste::
|
239 |
-
|
240 |
-
In[1]: l = ["hei", "vaan"]
|
241 |
-
In[2]: "".join(l)
|
242 |
-
Out[2]: heivaan
|
243 |
-
In[3]: %recall
|
244 |
-
In[4]: heivaan_ <== cursor blinking
|
245 |
-
|
246 |
-
%recall 45
|
247 |
-
|
248 |
-
Place history line 45 on the next input prompt. Use %hist to find
|
249 |
-
out the number.
|
250 |
-
|
251 |
-
%recall 1-4
|
252 |
-
|
253 |
-
Combine the specified lines into one cell, and place it on the next
|
254 |
-
input prompt. See %history for the slice syntax.
|
255 |
-
|
256 |
-
%recall foo+bar
|
257 |
-
|
258 |
-
If foo+bar can be evaluated in the user namespace, the result is
|
259 |
-
placed at the next input prompt. Otherwise, the history is searched
|
260 |
-
for lines which contain that substring, and the most recent one is
|
261 |
-
placed at the next input prompt.
|
262 |
-
"""
|
263 |
-
if not arg: # Last output
|
264 |
-
self.shell.set_next_input(str(self.shell.user_ns["_"]))
|
265 |
-
return
|
266 |
-
# Get history range
|
267 |
-
histlines = self.shell.history_manager.get_range_by_str(arg)
|
268 |
-
cmd = "\n".join(x[2] for x in histlines)
|
269 |
-
if cmd:
|
270 |
-
self.shell.set_next_input(cmd.rstrip())
|
271 |
-
return
|
272 |
-
|
273 |
-
try: # Variable in user namespace
|
274 |
-
cmd = str(eval(arg, self.shell.user_ns))
|
275 |
-
except Exception: # Search for term in history
|
276 |
-
histlines = self.shell.history_manager.search("*"+arg+"*")
|
277 |
-
for h in reversed([x[2] for x in histlines]):
|
278 |
-
if 'recall' in h or 'rep' in h:
|
279 |
-
continue
|
280 |
-
self.shell.set_next_input(h.rstrip())
|
281 |
-
return
|
282 |
-
else:
|
283 |
-
self.shell.set_next_input(cmd.rstrip())
|
284 |
-
return
|
285 |
-
print("Couldn't evaluate or find in history:", arg)
|
286 |
-
|
287 |
-
@line_magic
|
288 |
-
def rerun(self, parameter_s=''):
|
289 |
-
"""Re-run previous input
|
290 |
-
|
291 |
-
By default, you can specify ranges of input history to be repeated
|
292 |
-
(as with %history). With no arguments, it will repeat the last line.
|
293 |
-
|
294 |
-
Options:
|
295 |
-
|
296 |
-
-l <n> : Repeat the last n lines of input, not including the
|
297 |
-
current command.
|
298 |
-
|
299 |
-
-g foo : Repeat the most recent line which contains foo
|
300 |
-
"""
|
301 |
-
opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
|
302 |
-
if "l" in opts: # Last n lines
|
303 |
-
try:
|
304 |
-
n = int(opts["l"])
|
305 |
-
except ValueError:
|
306 |
-
print("Number of lines must be an integer")
|
307 |
-
return
|
308 |
-
|
309 |
-
if n == 0:
|
310 |
-
print("Requested 0 last lines - nothing to run")
|
311 |
-
return
|
312 |
-
elif n < 0:
|
313 |
-
print("Number of lines to rerun cannot be negative")
|
314 |
-
return
|
315 |
-
|
316 |
-
hist = self.shell.history_manager.get_tail(n)
|
317 |
-
elif "g" in opts: # Search
|
318 |
-
p = "*"+opts['g']+"*"
|
319 |
-
hist = list(self.shell.history_manager.search(p))
|
320 |
-
for l in reversed(hist):
|
321 |
-
if "rerun" not in l[2]:
|
322 |
-
hist = [l] # The last match which isn't a %rerun
|
323 |
-
break
|
324 |
-
else:
|
325 |
-
hist = [] # No matches except %rerun
|
326 |
-
elif args: # Specify history ranges
|
327 |
-
hist = self.shell.history_manager.get_range_by_str(args)
|
328 |
-
else: # Last line
|
329 |
-
hist = self.shell.history_manager.get_tail(1)
|
330 |
-
hist = [x[2] for x in hist]
|
331 |
-
if not hist:
|
332 |
-
print("No lines in history match specification")
|
333 |
-
return
|
334 |
-
histlines = "\n".join(hist)
|
335 |
-
print("=== Executing: ===")
|
336 |
-
print(histlines)
|
337 |
-
print("=== Output: ===")
|
338 |
-
self.shell.run_cell("\n".join(hist), store_history=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openalex_env_map/lib/python3.10/site-packages/IPython/core/magics/logging.py
DELETED
@@ -1,195 +0,0 @@
|
|
1 |
-
"""Implementation of magic functions for IPython's own logging.
|
2 |
-
"""
|
3 |
-
#-----------------------------------------------------------------------------
|
4 |
-
# Copyright (c) 2012 The IPython Development Team.
|
5 |
-
#
|
6 |
-
# Distributed under the terms of the Modified BSD License.
|
7 |
-
#
|
8 |
-
# The full license is in the file COPYING.txt, distributed with this software.
|
9 |
-
#-----------------------------------------------------------------------------
|
10 |
-
|
11 |
-
#-----------------------------------------------------------------------------
|
12 |
-
# Imports
|
13 |
-
#-----------------------------------------------------------------------------
|
14 |
-
|
15 |
-
# Stdlib
|
16 |
-
import os
|
17 |
-
import sys
|
18 |
-
|
19 |
-
# Our own packages
|
20 |
-
from IPython.core.magic import Magics, magics_class, line_magic
|
21 |
-
from warnings import warn
|
22 |
-
from traitlets import Bool
|
23 |
-
|
24 |
-
#-----------------------------------------------------------------------------
|
25 |
-
# Magic implementation classes
|
26 |
-
#-----------------------------------------------------------------------------
|
27 |
-
|
28 |
-
@magics_class
|
29 |
-
class LoggingMagics(Magics):
|
30 |
-
"""Magics related to all logging machinery."""
|
31 |
-
|
32 |
-
quiet = Bool(False, help=
|
33 |
-
"""
|
34 |
-
Suppress output of log state when logging is enabled
|
35 |
-
"""
|
36 |
-
).tag(config=True)
|
37 |
-
|
38 |
-
@line_magic
|
39 |
-
def logstart(self, parameter_s=''):
|
40 |
-
"""Start logging anywhere in a session.
|
41 |
-
|
42 |
-
%logstart [-o|-r|-t|-q] [log_name [log_mode]]
|
43 |
-
|
44 |
-
If no name is given, it defaults to a file named 'ipython_log.py' in your
|
45 |
-
current directory, in 'rotate' mode (see below).
|
46 |
-
|
47 |
-
'%logstart name' saves to file 'name' in 'backup' mode. It saves your
|
48 |
-
history up to that point and then continues logging.
|
49 |
-
|
50 |
-
%logstart takes a second optional parameter: logging mode. This can be one
|
51 |
-
of (note that the modes are given unquoted):
|
52 |
-
|
53 |
-
append
|
54 |
-
Keep logging at the end of any existing file.
|
55 |
-
|
56 |
-
backup
|
57 |
-
Rename any existing file to name~ and start name.
|
58 |
-
|
59 |
-
global
|
60 |
-
Append to a single logfile in your home directory.
|
61 |
-
|
62 |
-
over
|
63 |
-
Overwrite any existing log.
|
64 |
-
|
65 |
-
rotate
|
66 |
-
Create rotating logs: name.1~, name.2~, etc.
|
67 |
-
|
68 |
-
Options:
|
69 |
-
|
70 |
-
-o
|
71 |
-
log also IPython's output. In this mode, all commands which
|
72 |
-
generate an Out[NN] prompt are recorded to the logfile, right after
|
73 |
-
their corresponding input line. The output lines are always
|
74 |
-
prepended with a '#[Out]# ' marker, so that the log remains valid
|
75 |
-
Python code.
|
76 |
-
|
77 |
-
Since this marker is always the same, filtering only the output from
|
78 |
-
a log is very easy, using for example a simple awk call::
|
79 |
-
|
80 |
-
awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py
|
81 |
-
|
82 |
-
-r
|
83 |
-
log 'raw' input. Normally, IPython's logs contain the processed
|
84 |
-
input, so that user lines are logged in their final form, converted
|
85 |
-
into valid Python. For example, %Exit is logged as
|
86 |
-
_ip.run_line_magic("Exit"). If the -r flag is given, all input is logged
|
87 |
-
exactly as typed, with no transformations applied.
|
88 |
-
|
89 |
-
-t
|
90 |
-
put timestamps before each input line logged (these are put in
|
91 |
-
comments).
|
92 |
-
|
93 |
-
-q
|
94 |
-
suppress output of logstate message when logging is invoked
|
95 |
-
"""
|
96 |
-
|
97 |
-
opts,par = self.parse_options(parameter_s,'ortq')
|
98 |
-
log_output = 'o' in opts
|
99 |
-
log_raw_input = 'r' in opts
|
100 |
-
timestamp = 't' in opts
|
101 |
-
quiet = 'q' in opts
|
102 |
-
|
103 |
-
logger = self.shell.logger
|
104 |
-
|
105 |
-
# if no args are given, the defaults set in the logger constructor by
|
106 |
-
# ipython remain valid
|
107 |
-
if par:
|
108 |
-
try:
|
109 |
-
logfname,logmode = par.split()
|
110 |
-
except:
|
111 |
-
logfname = par
|
112 |
-
logmode = 'backup'
|
113 |
-
else:
|
114 |
-
logfname = logger.logfname
|
115 |
-
logmode = logger.logmode
|
116 |
-
# put logfname into rc struct as if it had been called on the command
|
117 |
-
# line, so it ends up saved in the log header Save it in case we need
|
118 |
-
# to restore it...
|
119 |
-
old_logfile = self.shell.logfile
|
120 |
-
if logfname:
|
121 |
-
logfname = os.path.expanduser(logfname)
|
122 |
-
self.shell.logfile = logfname
|
123 |
-
|
124 |
-
loghead = u'# IPython log file\n\n'
|
125 |
-
try:
|
126 |
-
logger.logstart(logfname, loghead, logmode, log_output, timestamp,
|
127 |
-
log_raw_input)
|
128 |
-
except:
|
129 |
-
self.shell.logfile = old_logfile
|
130 |
-
warn("Couldn't start log: %s" % sys.exc_info()[1])
|
131 |
-
else:
|
132 |
-
# log input history up to this point, optionally interleaving
|
133 |
-
# output if requested
|
134 |
-
|
135 |
-
if timestamp:
|
136 |
-
# disable timestamping for the previous history, since we've
|
137 |
-
# lost those already (no time machine here).
|
138 |
-
logger.timestamp = False
|
139 |
-
|
140 |
-
if log_raw_input:
|
141 |
-
input_hist = self.shell.history_manager.input_hist_raw
|
142 |
-
else:
|
143 |
-
input_hist = self.shell.history_manager.input_hist_parsed
|
144 |
-
|
145 |
-
if log_output:
|
146 |
-
log_write = logger.log_write
|
147 |
-
output_hist = self.shell.history_manager.output_hist
|
148 |
-
for n in range(1,len(input_hist)-1):
|
149 |
-
log_write(input_hist[n].rstrip() + u'\n')
|
150 |
-
if n in output_hist:
|
151 |
-
log_write(repr(output_hist[n]),'output')
|
152 |
-
else:
|
153 |
-
logger.log_write(u'\n'.join(input_hist[1:]))
|
154 |
-
logger.log_write(u'\n')
|
155 |
-
if timestamp:
|
156 |
-
# re-enable timestamping
|
157 |
-
logger.timestamp = True
|
158 |
-
|
159 |
-
if not (self.quiet or quiet):
|
160 |
-
print ('Activating auto-logging. '
|
161 |
-
'Current session state plus future input saved.')
|
162 |
-
logger.logstate()
|
163 |
-
|
164 |
-
@line_magic
|
165 |
-
def logstop(self, parameter_s=''):
|
166 |
-
"""Fully stop logging and close log file.
|
167 |
-
|
168 |
-
In order to start logging again, a new %logstart call needs to be made,
|
169 |
-
possibly (though not necessarily) with a new filename, mode and other
|
170 |
-
options."""
|
171 |
-
self.shell.logger.logstop()
|
172 |
-
|
173 |
-
@line_magic
|
174 |
-
def logoff(self, parameter_s=''):
|
175 |
-
"""Temporarily stop logging.
|
176 |
-
|
177 |
-
You must have previously started logging."""
|
178 |
-
self.shell.logger.switch_log(0)
|
179 |
-
|
180 |
-
@line_magic
|
181 |
-
def logon(self, parameter_s=''):
|
182 |
-
"""Restart logging.
|
183 |
-
|
184 |
-
This function is for restarting logging which you've temporarily
|
185 |
-
stopped with %logoff. For starting logging for the first time, you
|
186 |
-
must use the %logstart function, which allows you to specify an
|
187 |
-
optional log filename."""
|
188 |
-
|
189 |
-
self.shell.logger.switch_log(1)
|
190 |
-
|
191 |
-
@line_magic
|
192 |
-
def logstate(self, parameter_s=''):
|
193 |
-
"""Print the status of the logging system."""
|
194 |
-
|
195 |
-
self.shell.logger.logstate()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|