MNghia commited on
Commit
7ea5134
·
verified ·
1 Parent(s): 81cbf9f

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.10/site-packages/IPython/__pycache__/__init__.cpython-310.pyc +0 -0
  2. lib/python3.10/site-packages/IPython/__pycache__/__main__.cpython-310.pyc +0 -0
  3. lib/python3.10/site-packages/IPython/__pycache__/conftest.cpython-310.pyc +0 -0
  4. lib/python3.10/site-packages/IPython/__pycache__/consoleapp.cpython-310.pyc +0 -0
  5. lib/python3.10/site-packages/IPython/__pycache__/display.cpython-310.pyc +0 -0
  6. lib/python3.10/site-packages/IPython/__pycache__/paths.cpython-310.pyc +0 -0
  7. lib/python3.10/site-packages/IPython/core/__init__.py +0 -0
  8. lib/python3.10/site-packages/IPython/core/alias.py +267 -0
  9. lib/python3.10/site-packages/IPython/core/application.py +492 -0
  10. lib/python3.10/site-packages/IPython/core/async_helpers.py +155 -0
  11. lib/python3.10/site-packages/IPython/core/autocall.py +70 -0
  12. lib/python3.10/site-packages/IPython/core/builtin_trap.py +86 -0
  13. lib/python3.10/site-packages/IPython/core/compilerop.py +214 -0
  14. lib/python3.10/site-packages/IPython/core/completer.py +0 -0
  15. lib/python3.10/site-packages/IPython/core/completerlib.py +382 -0
  16. lib/python3.10/site-packages/IPython/core/crashhandler.py +248 -0
  17. lib/python3.10/site-packages/IPython/core/debugger.py +1136 -0
  18. lib/python3.10/site-packages/IPython/core/display.py +1373 -0
  19. lib/python3.10/site-packages/IPython/core/display_functions.py +391 -0
  20. lib/python3.10/site-packages/IPython/core/display_trap.py +70 -0
  21. lib/python3.10/site-packages/IPython/core/displayhook.py +336 -0
  22. lib/python3.10/site-packages/IPython/core/displaypub.py +149 -0
  23. lib/python3.10/site-packages/IPython/core/error.py +60 -0
  24. lib/python3.10/site-packages/IPython/core/events.py +158 -0
  25. lib/python3.10/site-packages/IPython/core/excolors.py +192 -0
  26. lib/python3.10/site-packages/IPython/core/extensions.py +135 -0
  27. lib/python3.10/site-packages/IPython/core/formatters.py +1090 -0
  28. lib/python3.10/site-packages/IPython/core/getipython.py +24 -0
  29. lib/python3.10/site-packages/IPython/core/guarded_eval.py +895 -0
  30. lib/python3.10/site-packages/IPython/core/history.py +989 -0
  31. lib/python3.10/site-packages/IPython/core/historyapp.py +158 -0
  32. lib/python3.10/site-packages/IPython/core/hooks.py +173 -0
  33. lib/python3.10/site-packages/IPython/core/inputsplitter.py +799 -0
  34. lib/python3.10/site-packages/IPython/core/inputtransformer.py +577 -0
  35. lib/python3.10/site-packages/IPython/core/inputtransformer2.py +830 -0
  36. lib/python3.10/site-packages/IPython/core/interactiveshell.py +0 -0
  37. lib/python3.10/site-packages/IPython/core/latex_symbols.py +1301 -0
  38. lib/python3.10/site-packages/IPython/core/logger.py +231 -0
  39. lib/python3.10/site-packages/IPython/core/macro.py +53 -0
  40. lib/python3.10/site-packages/IPython/core/magic.py +759 -0
  41. lib/python3.10/site-packages/IPython/core/magic_arguments.py +310 -0
  42. lib/python3.10/site-packages/IPython/core/magics/__init__.py +42 -0
  43. lib/python3.10/site-packages/IPython/core/magics/__pycache__/__init__.cpython-310.pyc +0 -0
  44. lib/python3.10/site-packages/IPython/core/magics/__pycache__/ast_mod.cpython-310.pyc +0 -0
  45. lib/python3.10/site-packages/IPython/core/magics/__pycache__/auto.cpython-310.pyc +0 -0
  46. lib/python3.10/site-packages/IPython/core/magics/__pycache__/basic.cpython-310.pyc +0 -0
  47. lib/python3.10/site-packages/IPython/core/magics/__pycache__/code.cpython-310.pyc +0 -0
  48. lib/python3.10/site-packages/IPython/core/magics/__pycache__/config.cpython-310.pyc +0 -0
  49. lib/python3.10/site-packages/IPython/core/magics/__pycache__/display.cpython-310.pyc +0 -0
  50. lib/python3.10/site-packages/IPython/core/magics/__pycache__/execution.cpython-310.pyc +0 -0
lib/python3.10/site-packages/IPython/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (5.43 kB). View file
 
lib/python3.10/site-packages/IPython/__pycache__/__main__.cpython-310.pyc ADDED
Binary file (247 Bytes). View file
 
lib/python3.10/site-packages/IPython/__pycache__/conftest.cpython-310.pyc ADDED
Binary file (2.5 kB). View file
 
lib/python3.10/site-packages/IPython/__pycache__/consoleapp.cpython-310.pyc ADDED
Binary file (485 Bytes). View file
 
lib/python3.10/site-packages/IPython/__pycache__/display.cpython-310.pyc ADDED
Binary file (870 Bytes). View file
 
lib/python3.10/site-packages/IPython/__pycache__/paths.cpython-310.pyc ADDED
Binary file (3.62 kB). View file
 
lib/python3.10/site-packages/IPython/core/__init__.py ADDED
File without changes
lib/python3.10/site-packages/IPython/core/alias.py ADDED
@@ -0,0 +1,267 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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)
lib/python3.10/site-packages/IPython/core/application.py ADDED
@@ -0,0 +1,492 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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)
lib/python3.10/site-packages/IPython/core/async_helpers.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
lib/python3.10/site-packages/IPython/core/autocall.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()
lib/python3.10/site-packages/IPython/core/builtin_trap.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
lib/python3.10/site-packages/IPython/core/compilerop.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()
lib/python3.10/site-packages/IPython/core/completer.py ADDED
The diff for this file is too large to render. See raw diff
 
lib/python3.10/site-packages/IPython/core/completerlib.py ADDED
@@ -0,0 +1,382 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()
lib/python3.10/site-packages/IPython/core/crashhandler.py ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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. <fperez@colorado.edu>
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
+
lib/python3.10/site-packages/IPython/core/debugger.py ADDED
@@ -0,0 +1,1136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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. <fperez@colorado.edu>
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)
lib/python3.10/site-packages/IPython/core/display.py ADDED
@@ -0,0 +1,1373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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)
lib/python3.10/site-packages/IPython/core/display_functions.py ADDED
@@ -0,0 +1,391 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()
lib/python3.10/site-packages/IPython/core/display_trap.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
lib/python3.10/site-packages/IPython/core/displayhook.py ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 })
lib/python3.10/site-packages/IPython/core/displaypub.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()
lib/python3.10/site-packages/IPython/core/error.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """
lib/python3.10/site-packages/IPython/core/events.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
lib/python3.10/site-packages/IPython/core/excolors.py ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 <fperez@colorado.edu>
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
lib/python3.10/site-packages/IPython/core/extensions.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
lib/python3.10/site-packages/IPython/core/formatters.py ADDED
@@ -0,0 +1,1090 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ )
lib/python3.10/site-packages/IPython/core/getipython.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()
lib/python3.10/site-packages/IPython/core/guarded_eval.py ADDED
@@ -0,0 +1,895 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ ]
lib/python3.10/site-packages/IPython/core/history.py ADDED
@@ -0,0 +1,989 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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)
lib/python3.10/site-packages/IPython/core/historyapp.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()
lib/python3.10/site-packages/IPython/core/hooks.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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. <fperez@colorado.edu>
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
lib/python3.10/site-packages/IPython/core/inputsplitter.py ADDED
@@ -0,0 +1,799 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
lib/python3.10/site-packages/IPython/core/inputtransformer.py ADDED
@@ -0,0 +1,577 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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)
lib/python3.10/site-packages/IPython/core/inputtransformer2.py ADDED
@@ -0,0 +1,830 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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)
lib/python3.10/site-packages/IPython/core/interactiveshell.py ADDED
The diff for this file is too large to render. See raw diff
 
lib/python3.10/site-packages/IPython/core/latex_symbols.py ADDED
@@ -0,0 +1,1301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()}
lib/python3.10/site-packages/IPython/core/logger.py ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Logger class for IPython's logging facilities.
2
+ """
3
+
4
+ #*****************************************************************************
5
+ # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
6
+ # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
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
lib/python3.10/site-packages/IPython/core/macro.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Support for interactive macros in IPython"""
2
+
3
+ #*****************************************************************************
4
+ # Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu>
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
lib/python3.10/site-packages/IPython/core/magic.py ADDED
@@ -0,0 +1,759 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # encoding: utf-8
2
+ """Magic functions for InteractiveShell.
3
+ """
4
+
5
+ #-----------------------------------------------------------------------------
6
+ # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7
+ # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
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
lib/python3.10/site-packages/IPython/core/magic_arguments.py ADDED
@@ -0,0 +1,310 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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']
lib/python3.10/site-packages/IPython/core/magics/__init__.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """
lib/python3.10/site-packages/IPython/core/magics/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (1.38 kB). View file
 
lib/python3.10/site-packages/IPython/core/magics/__pycache__/ast_mod.cpython-310.pyc ADDED
Binary file (10.1 kB). View file
 
lib/python3.10/site-packages/IPython/core/magics/__pycache__/auto.cpython-310.pyc ADDED
Binary file (3.94 kB). View file
 
lib/python3.10/site-packages/IPython/core/magics/__pycache__/basic.cpython-310.pyc ADDED
Binary file (20.6 kB). View file
 
lib/python3.10/site-packages/IPython/core/magics/__pycache__/code.cpython-310.pyc ADDED
Binary file (21.5 kB). View file
 
lib/python3.10/site-packages/IPython/core/magics/__pycache__/config.cpython-310.pyc ADDED
Binary file (3.86 kB). View file
 
lib/python3.10/site-packages/IPython/core/magics/__pycache__/display.cpython-310.pyc ADDED
Binary file (2.92 kB). View file
 
lib/python3.10/site-packages/IPython/core/magics/__pycache__/execution.cpython-310.pyc ADDED
Binary file (47.9 kB). View file