##// END OF EJS Templates
even more types
Matthias Bussonnier -
Show More
@@ -1,374 +1,377 b''
1 1 # encoding: utf-8
2 2 """Implementations for various useful completers.
3 3
4 4 These are all loaded by default by IPython.
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2010-2011 The IPython Development Team.
8 8 #
9 9 # Distributed under the terms of the BSD License.
10 10 #
11 11 # The full license is in the file COPYING.txt, distributed with this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 # Stdlib imports
19 19 import glob
20 20 import inspect
21 21 import os
22 22 import re
23 23 import sys
24 24 from importlib import import_module
25 25 from importlib.machinery import all_suffixes
26 26
27 27
28 28 # Third-party imports
29 29 from time import time
30 30 from zipimport import zipimporter
31 31
32 32 # Our own imports
33 33 from .completer import expand_user, compress_user
34 34 from .error import TryNext
35 35 from ..utils._process_common import arg_split
36 36
37 37 # FIXME: this should be pulled in with the right call via the component system
38 38 from IPython import get_ipython
39 39
40 40 from typing import List
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Globals and constants
44 44 #-----------------------------------------------------------------------------
45 45 _suffixes = all_suffixes()
46 46
47 47 # Time in seconds after which the rootmodules will be stored permanently in the
48 48 # ipython ip.db database (kept in the user's .ipython dir).
49 49 TIMEOUT_STORAGE = 2
50 50
51 51 # Time in seconds after which we give up
52 52 TIMEOUT_GIVEUP = 20
53 53
54 54 # Regular expression for the python import statement
55 55 import_re = re.compile(r'(?P<name>[^\W\d]\w*?)'
56 56 r'(?P<package>[/\\]__init__)?'
57 57 r'(?P<suffix>%s)$' %
58 58 r'|'.join(re.escape(s) for s in _suffixes))
59 59
60 60 # RE for the ipython %run command (python + ipython scripts)
61 61 magic_run_re = re.compile(r'.*(\.ipy|\.ipynb|\.py[w]?)$')
62 62
63 63 #-----------------------------------------------------------------------------
64 64 # Local utilities
65 65 #-----------------------------------------------------------------------------
66 66
67 def module_list(path):
67
68 def module_list(path: str) -> List[str]:
68 69 """
69 70 Return the list containing the names of the modules available in the given
70 71 folder.
71 72 """
72 73 # sys.path has the cwd as an empty string, but isdir/listdir need it as '.'
73 74 if path == '':
74 75 path = '.'
75 76
76 77 # A few local constants to be used in loops below
77 78 pjoin = os.path.join
78 79
79 80 if os.path.isdir(path):
80 81 # Build a list of all files in the directory and all files
81 82 # in its subdirectories. For performance reasons, do not
82 83 # recurse more than one level into subdirectories.
83 files = []
84 files: List[str] = []
84 85 for root, dirs, nondirs in os.walk(path, followlinks=True):
85 86 subdir = root[len(path)+1:]
86 87 if subdir:
87 88 files.extend(pjoin(subdir, f) for f in nondirs)
88 89 dirs[:] = [] # Do not recurse into additional subdirectories.
89 90 else:
90 91 files.extend(nondirs)
91 92
92 93 else:
93 94 try:
94 files = list(zipimporter(path)._files.keys())
95 except:
95 files = list(zipimporter(path)._files.keys()) # type: ignore
96 except Exception:
96 97 files = []
97 98
98 99 # Build a list of modules which match the import_re regex.
99 100 modules = []
100 101 for f in files:
101 102 m = import_re.match(f)
102 103 if m:
103 104 modules.append(m.group('name'))
104 105 return list(set(modules))
105 106
106 107
107 108 def get_root_modules():
108 109 """
109 110 Returns a list containing the names of all the modules available in the
110 111 folders of the pythonpath.
111 112
112 113 ip.db['rootmodules_cache'] maps sys.path entries to list of modules.
113 114 """
114 115 ip = get_ipython()
115 116 if ip is None:
116 117 # No global shell instance to store cached list of modules.
117 118 # Don't try to scan for modules every time.
118 119 return list(sys.builtin_module_names)
119 120
120 121 if getattr(ip.db, "_mock", False):
121 122 rootmodules_cache = {}
122 123 else:
123 124 rootmodules_cache = ip.db.get("rootmodules_cache", {})
124 125 rootmodules = list(sys.builtin_module_names)
125 126 start_time = time()
126 127 store = False
127 128 for path in sys.path:
128 129 try:
129 130 modules = rootmodules_cache[path]
130 131 except KeyError:
131 132 modules = module_list(path)
132 133 try:
133 134 modules.remove('__init__')
134 135 except ValueError:
135 136 pass
136 137 if path not in ('', '.'): # cwd modules should not be cached
137 138 rootmodules_cache[path] = modules
138 139 if time() - start_time > TIMEOUT_STORAGE and not store:
139 140 store = True
140 141 print("\nCaching the list of root modules, please wait!")
141 142 print("(This will only be done once - type '%rehashx' to "
142 143 "reset cache!)\n")
143 144 sys.stdout.flush()
144 145 if time() - start_time > TIMEOUT_GIVEUP:
145 146 print("This is taking too long, we give up.\n")
146 147 return []
147 148 rootmodules.extend(modules)
148 149 if store:
149 150 ip.db['rootmodules_cache'] = rootmodules_cache
150 151 rootmodules = list(set(rootmodules))
151 152 return rootmodules
152 153
153 154
154 155 def is_importable(module, attr, only_modules):
155 156 if only_modules:
156 157 return inspect.ismodule(getattr(module, attr))
157 158 else:
158 159 return not(attr[:2] == '__' and attr[-2:] == '__')
159 160
160 161 def is_possible_submodule(module, attr):
161 162 try:
162 163 obj = getattr(module, attr)
163 164 except AttributeError:
164 165 # Is possilby an unimported submodule
165 166 return True
166 167 except TypeError:
167 168 # https://github.com/ipython/ipython/issues/9678
168 169 return False
169 170 return inspect.ismodule(obj)
170 171
171 172
172 173 def try_import(mod: str, only_modules=False) -> List[str]:
173 174 """
174 175 Try to import given module and return list of potential completions.
175 176 """
176 177 mod = mod.rstrip('.')
177 178 try:
178 179 m = import_module(mod)
179 180 except:
180 181 return []
181 182
182 183 m_is_init = '__init__' in (getattr(m, '__file__', '') or '')
183 184
184 185 completions = []
185 186 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
186 187 completions.extend( [attr for attr in dir(m) if
187 188 is_importable(m, attr, only_modules)])
188 189
189 190 m_all = getattr(m, "__all__", [])
190 191 if only_modules:
191 192 completions.extend(attr for attr in m_all if is_possible_submodule(m, attr))
192 193 else:
193 194 completions.extend(m_all)
194 195
195 196 if m_is_init:
196 197 file_ = m.__file__
197 completions.extend(module_list(os.path.dirname(file_)))
198 file_path = os.path.dirname(file_) # type: ignore
199 if file_path is not None:
200 completions.extend(module_list(file_path))
198 201 completions_set = {c for c in completions if isinstance(c, str)}
199 202 completions_set.discard('__init__')
200 203 return list(completions_set)
201 204
202 205
203 206 #-----------------------------------------------------------------------------
204 207 # Completion-related functions.
205 208 #-----------------------------------------------------------------------------
206 209
207 210 def quick_completer(cmd, completions):
208 211 r""" Easily create a trivial completer for a command.
209 212
210 213 Takes either a list of completions, or all completions in string (that will
211 214 be split on whitespace).
212 215
213 216 Example::
214 217
215 218 [d:\ipython]|1> import ipy_completers
216 219 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
217 220 [d:\ipython]|3> foo b<TAB>
218 221 bar baz
219 222 [d:\ipython]|3> foo ba
220 223 """
221 224
222 225 if isinstance(completions, str):
223 226 completions = completions.split()
224 227
225 228 def do_complete(self, event):
226 229 return completions
227 230
228 231 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
229 232
230 233 def module_completion(line):
231 234 """
232 235 Returns a list containing the completion possibilities for an import line.
233 236
234 237 The line looks like this :
235 238 'import xml.d'
236 239 'from xml.dom import'
237 240 """
238 241
239 242 words = line.split(' ')
240 243 nwords = len(words)
241 244
242 245 # from whatever <tab> -> 'import '
243 246 if nwords == 3 and words[0] == 'from':
244 247 return ['import ']
245 248
246 249 # 'from xy<tab>' or 'import xy<tab>'
247 250 if nwords < 3 and (words[0] in {'%aimport', 'import', 'from'}) :
248 251 if nwords == 1:
249 252 return get_root_modules()
250 253 mod = words[1].split('.')
251 254 if len(mod) < 2:
252 255 return get_root_modules()
253 256 completion_list = try_import('.'.join(mod[:-1]), True)
254 257 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
255 258
256 259 # 'from xyz import abc<tab>'
257 260 if nwords >= 3 and words[0] == 'from':
258 261 mod = words[1]
259 262 return try_import(mod)
260 263
261 264 #-----------------------------------------------------------------------------
262 265 # Completers
263 266 #-----------------------------------------------------------------------------
264 267 # These all have the func(self, event) signature to be used as custom
265 268 # completers
266 269
267 270 def module_completer(self,event):
268 271 """Give completions after user has typed 'import ...' or 'from ...'"""
269 272
270 273 # This works in all versions of python. While 2.5 has
271 274 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
272 275 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
273 276 # of possibly problematic side effects.
274 277 # This search the folders in the sys.path for available modules.
275 278
276 279 return module_completion(event.line)
277 280
278 281 # FIXME: there's a lot of logic common to the run, cd and builtin file
279 282 # completers, that is currently reimplemented in each.
280 283
281 284 def magic_run_completer(self, event):
282 285 """Complete files that end in .py or .ipy or .ipynb for the %run command.
283 286 """
284 287 comps = arg_split(event.line, strict=False)
285 288 # relpath should be the current token that we need to complete.
286 289 if (len(comps) > 1) and (not event.line.endswith(' ')):
287 290 relpath = comps[-1].strip("'\"")
288 291 else:
289 292 relpath = ''
290 293
291 294 #print("\nev=", event) # dbg
292 295 #print("rp=", relpath) # dbg
293 296 #print('comps=', comps) # dbg
294 297
295 298 lglob = glob.glob
296 299 isdir = os.path.isdir
297 300 relpath, tilde_expand, tilde_val = expand_user(relpath)
298 301
299 302 # Find if the user has already typed the first filename, after which we
300 303 # should complete on all files, since after the first one other files may
301 304 # be arguments to the input script.
302 305
303 306 if any(magic_run_re.match(c) for c in comps):
304 307 matches = [f.replace('\\','/') + ('/' if isdir(f) else '')
305 308 for f in lglob(relpath+'*')]
306 309 else:
307 310 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
308 311 pys = [f.replace('\\','/')
309 312 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
310 313 lglob(relpath+'*.ipynb') + lglob(relpath + '*.pyw')]
311 314
312 315 matches = dirs + pys
313 316
314 317 #print('run comp:', dirs+pys) # dbg
315 318 return [compress_user(p, tilde_expand, tilde_val) for p in matches]
316 319
317 320
318 321 def cd_completer(self, event):
319 322 """Completer function for cd, which only returns directories."""
320 323 ip = get_ipython()
321 324 relpath = event.symbol
322 325
323 326 #print(event) # dbg
324 327 if event.line.endswith('-b') or ' -b ' in event.line:
325 328 # return only bookmark completions
326 329 bkms = self.db.get('bookmarks', None)
327 330 if bkms:
328 331 return bkms.keys()
329 332 else:
330 333 return []
331 334
332 335 if event.symbol == '-':
333 336 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
334 337 # jump in directory history by number
335 338 fmt = '-%0' + width_dh +'d [%s]'
336 339 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
337 340 if len(ents) > 1:
338 341 return ents
339 342 return []
340 343
341 344 if event.symbol.startswith('--'):
342 345 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
343 346
344 347 # Expand ~ in path and normalize directory separators.
345 348 relpath, tilde_expand, tilde_val = expand_user(relpath)
346 349 relpath = relpath.replace('\\','/')
347 350
348 351 found = []
349 352 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
350 353 if os.path.isdir(f)]:
351 354 if ' ' in d:
352 355 # we don't want to deal with any of that, complex code
353 356 # for this is elsewhere
354 357 raise TryNext
355 358
356 359 found.append(d)
357 360
358 361 if not found:
359 362 if os.path.isdir(relpath):
360 363 return [compress_user(relpath, tilde_expand, tilde_val)]
361 364
362 365 # if no completions so far, try bookmarks
363 366 bks = self.db.get('bookmarks',{})
364 367 bkmatches = [s for s in bks if s.startswith(event.symbol)]
365 368 if bkmatches:
366 369 return bkmatches
367 370
368 371 raise TryNext
369 372
370 373 return [compress_user(p, tilde_expand, tilde_val) for p in found]
371 374
372 375 def reset_completer(self, event):
373 376 "A completer for %reset magic"
374 377 return '-f -s in out array dhist'.split()
@@ -1,138 +1,149 b''
1 1 """An interface for publishing rich data to frontends.
2 2
3 3 There are two components of the display system:
4 4
5 5 * Display formatters, which take a Python object and compute the
6 6 representation of the object in various formats (text, HTML, SVG, etc.).
7 7 * The display publisher that is used to send the representation data to the
8 8 various frontends.
9 9
10 10 This module defines the logic display publishing. The display publisher uses
11 11 the ``display_data`` message type that is defined in the IPython messaging
12 12 spec.
13 13 """
14 14
15 15 # Copyright (c) IPython Development Team.
16 16 # Distributed under the terms of the Modified BSD License.
17 17
18 18
19 19 import sys
20 20
21 21 from traitlets.config.configurable import Configurable
22 22 from traitlets import List
23 23
24 24 # This used to be defined here - it is imported for backwards compatibility
25 25 from .display_functions import publish_display_data
26 26
27 import typing as t
28
27 29 #-----------------------------------------------------------------------------
28 30 # Main payload class
29 31 #-----------------------------------------------------------------------------
30 32
31 33
32 34 class DisplayPublisher(Configurable):
33 35 """A traited class that publishes display data to frontends.
34 36
35 37 Instances of this class are created by the main IPython object and should
36 38 be accessed there.
37 39 """
38 40
39 41 def __init__(self, shell=None, *args, **kwargs):
40 42 self.shell = shell
41 43 super().__init__(*args, **kwargs)
42 44
43 45 def _validate_data(self, data, metadata=None):
44 46 """Validate the display data.
45 47
46 48 Parameters
47 49 ----------
48 50 data : dict
49 51 The formata data dictionary.
50 52 metadata : dict
51 53 Any metadata for the data.
52 54 """
53 55
54 56 if not isinstance(data, dict):
55 57 raise TypeError('data must be a dict, got: %r' % data)
56 58 if metadata is not None:
57 59 if not isinstance(metadata, dict):
58 60 raise TypeError('metadata must be a dict, got: %r' % data)
59 61
60 62 # use * to indicate transient, update are keyword-only
61 63 def publish(self, data, metadata=None, source=None, *, transient=None, update=False, **kwargs) -> None:
62 64 """Publish data and metadata to all frontends.
63 65
64 66 See the ``display_data`` message in the messaging documentation for
65 67 more details about this message type.
66 68
67 69 The following MIME types are currently implemented:
68 70
69 71 * text/plain
70 72 * text/html
71 73 * text/markdown
72 74 * text/latex
73 75 * application/json
74 76 * application/javascript
75 77 * image/png
76 78 * image/jpeg
77 79 * image/svg+xml
78 80
79 81 Parameters
80 82 ----------
81 83 data : dict
82 84 A dictionary having keys that are valid MIME types (like
83 85 'text/plain' or 'image/svg+xml') and values that are the data for
84 86 that MIME type. The data itself must be a JSON'able data
85 87 structure. Minimally all data should have the 'text/plain' data,
86 88 which can be displayed by all frontends. If more than the plain
87 89 text is given, it is up to the frontend to decide which
88 90 representation to use.
89 91 metadata : dict
90 92 A dictionary for metadata related to the data. This can contain
91 93 arbitrary key, value pairs that frontends can use to interpret
92 94 the data. Metadata specific to each mime-type can be specified
93 95 in the metadata dict with the same mime-type keys as
94 96 the data itself.
95 97 source : str, deprecated
96 98 Unused.
97 99 transient : dict, keyword-only
98 100 A dictionary for transient data.
99 101 Data in this dictionary should not be persisted as part of saving this output.
100 102 Examples include 'display_id'.
101 103 update : bool, keyword-only, default: False
102 104 If True, only update existing outputs with the same display_id,
103 105 rather than creating a new output.
104 106 """
105 107
106 handlers = {}
108 handlers: t.Dict = {}
107 109 if self.shell is not None:
108 handlers = getattr(self.shell, 'mime_renderers', {})
110 handlers = getattr(self.shell, "mime_renderers", {})
109 111
110 112 for mime, handler in handlers.items():
111 113 if mime in data:
112 114 handler(data[mime], metadata.get(mime, None))
113 115 return
114 116
115 117 if 'text/plain' in data:
116 118 print(data['text/plain'])
117 119
118 120 def clear_output(self, wait=False):
119 121 """Clear the output of the cell receiving output."""
120 122 print('\033[2K\r', end='')
121 123 sys.stdout.flush()
122 124 print('\033[2K\r', end='')
123 125 sys.stderr.flush()
124 126
125 127
126 128 class CapturingDisplayPublisher(DisplayPublisher):
127 129 """A DisplayPublisher that stores"""
128 outputs = List()
129 130
130 def publish(self, data, metadata=None, source=None, *, transient=None, update=False):
131 self.outputs.append({'data':data, 'metadata':metadata,
132 'transient':transient, 'update':update})
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 )
133 144
134 145 def clear_output(self, wait=False):
135 146 super(CapturingDisplayPublisher, self).clear_output(wait)
136 147
137 148 # empty the list, *do not* reassign a new list
138 149 self.outputs.clear()
@@ -1,796 +1,797 b''
1 1 """DEPRECATED: Input handling and transformation machinery.
2 2
3 3 This module was deprecated in IPython 7.0, in favour of inputtransformer2.
4 4
5 5 The first class in this module, :class:`InputSplitter`, is designed to tell when
6 6 input from a line-oriented frontend is complete and should be executed, and when
7 7 the user should be prompted for another line of code instead. The name 'input
8 8 splitter' is largely for historical reasons.
9 9
10 10 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
11 11 with full support for the extended IPython syntax (magics, system calls, etc).
12 12 The code to actually do these transformations is in :mod:`IPython.core.inputtransformer`.
13 13 :class:`IPythonInputSplitter` feeds the raw code to the transformers in order
14 14 and stores the results.
15 15
16 16 For more details, see the class docstrings below.
17 17 """
18 18
19 19 from warnings import warn
20 20
21 21 warn('IPython.core.inputsplitter is deprecated since IPython 7 in favor of `IPython.core.inputtransformer2`',
22 22 DeprecationWarning)
23 23
24 24 # Copyright (c) IPython Development Team.
25 25 # Distributed under the terms of the Modified BSD License.
26 26 import ast
27 27 import codeop
28 28 import io
29 29 import re
30 30 import sys
31 31 import tokenize
32 32 import warnings
33 33
34 from typing import List, Tuple, Union, Optional
35 from typing_extensions import Self
34 from typing import List, Tuple, Union, Optional, TYPE_CHECKING
36 35 from types import CodeType
37 36
38 37 from IPython.core.inputtransformer import (leading_indent,
39 38 classic_prompt,
40 39 ipy_prompt,
41 40 cellmagic,
42 41 assemble_logical_lines,
43 42 help_end,
44 43 escaped_commands,
45 44 assign_from_magic,
46 45 assign_from_system,
47 46 assemble_python_lines,
48 47 )
49 48 from IPython.utils import tokenutil
50 49
51 50 # These are available in this module for backwards compatibility.
52 51 from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
53 52 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
54 53 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
55 54
55 if TYPE_CHECKING:
56 from typing_extensions import Self
56 57 #-----------------------------------------------------------------------------
57 58 # Utilities
58 59 #-----------------------------------------------------------------------------
59 60
60 61 # FIXME: These are general-purpose utilities that later can be moved to the
61 62 # general ward. Kept here for now because we're being very strict about test
62 63 # coverage with this code, and this lets us ensure that we keep 100% coverage
63 64 # while developing.
64 65
65 66 # compiled regexps for autoindent management
66 67 dedent_re = re.compile('|'.join([
67 68 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
68 69 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
69 70 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
70 71 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
71 72 r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
72 73 r'^\s+break\s*$', # break (optionally followed by trailing spaces)
73 74 r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
74 75 ]))
75 76 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
76 77
77 78 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
78 79 # before pure comments
79 80 comment_line_re = re.compile(r'^\s*\#')
80 81
81 82
82 83 def num_ini_spaces(s):
83 84 """Return the number of initial spaces in a string.
84 85
85 86 Note that tabs are counted as a single space. For now, we do *not* support
86 87 mixing of tabs and spaces in the user's input.
87 88
88 89 Parameters
89 90 ----------
90 91 s : string
91 92
92 93 Returns
93 94 -------
94 95 n : int
95 96 """
96 97 warnings.warn(
97 98 "`num_ini_spaces` is Pending Deprecation since IPython 8.17."
98 99 "It is considered fro removal in in future version. "
99 100 "Please open an issue if you believe it should be kept.",
100 101 stacklevel=2,
101 102 category=PendingDeprecationWarning,
102 103 )
103 104 ini_spaces = ini_spaces_re.match(s)
104 105 if ini_spaces:
105 106 return ini_spaces.end()
106 107 else:
107 108 return 0
108 109
109 110 # Fake token types for partial_tokenize:
110 111 INCOMPLETE_STRING = tokenize.N_TOKENS
111 112 IN_MULTILINE_STATEMENT = tokenize.N_TOKENS + 1
112 113
113 114 # The 2 classes below have the same API as TokenInfo, but don't try to look up
114 115 # a token type name that they won't find.
115 116 class IncompleteString:
116 117 type = exact_type = INCOMPLETE_STRING
117 118 def __init__(self, s, start, end, line):
118 119 self.s = s
119 120 self.start = start
120 121 self.end = end
121 122 self.line = line
122 123
123 124 class InMultilineStatement:
124 125 type = exact_type = IN_MULTILINE_STATEMENT
125 126 def __init__(self, pos, line):
126 127 self.s = ''
127 128 self.start = self.end = pos
128 129 self.line = line
129 130
130 131 def partial_tokens(s):
131 132 """Iterate over tokens from a possibly-incomplete string of code.
132 133
133 134 This adds two special token types: INCOMPLETE_STRING and
134 135 IN_MULTILINE_STATEMENT. These can only occur as the last token yielded, and
135 136 represent the two main ways for code to be incomplete.
136 137 """
137 138 readline = io.StringIO(s).readline
138 139 token = tokenize.TokenInfo(tokenize.NEWLINE, '', (1, 0), (1, 0), '')
139 140 try:
140 141 for token in tokenutil.generate_tokens_catch_errors(readline):
141 142 yield token
142 143 except tokenize.TokenError as e:
143 144 # catch EOF error
144 145 lines = s.splitlines(keepends=True)
145 146 end = len(lines), len(lines[-1])
146 147 if 'multi-line string' in e.args[0]:
147 148 l, c = start = token.end
148 149 s = lines[l-1][c:] + ''.join(lines[l:])
149 150 yield IncompleteString(s, start, end, lines[-1])
150 151 elif 'multi-line statement' in e.args[0]:
151 152 yield InMultilineStatement(end, lines[-1])
152 153 else:
153 154 raise
154 155
155 156 def find_next_indent(code) -> int:
156 157 """Find the number of spaces for the next line of indentation"""
157 158 tokens = list(partial_tokens(code))
158 159 if tokens[-1].type == tokenize.ENDMARKER:
159 160 tokens.pop()
160 161 if not tokens:
161 162 return 0
162 163
163 164 while tokens[-1].type in {
164 165 tokenize.DEDENT,
165 166 tokenize.NEWLINE,
166 167 tokenize.COMMENT,
167 168 tokenize.ERRORTOKEN,
168 169 }:
169 170 tokens.pop()
170 171
171 172 # Starting in Python 3.12, the tokenize module adds implicit newlines at the end
172 173 # of input. We need to remove those if we're in a multiline statement
173 174 if tokens[-1].type == IN_MULTILINE_STATEMENT:
174 175 while tokens[-2].type in {tokenize.NL}:
175 176 tokens.pop(-2)
176 177
177 178
178 179 if tokens[-1].type == INCOMPLETE_STRING:
179 180 # Inside a multiline string
180 181 return 0
181 182
182 183 # Find the indents used before
183 184 prev_indents = [0]
184 185 def _add_indent(n):
185 186 if n != prev_indents[-1]:
186 187 prev_indents.append(n)
187 188
188 189 tokiter = iter(tokens)
189 190 for tok in tokiter:
190 191 if tok.type in {tokenize.INDENT, tokenize.DEDENT}:
191 192 _add_indent(tok.end[1])
192 193 elif (tok.type == tokenize.NL):
193 194 try:
194 195 _add_indent(next(tokiter).start[1])
195 196 except StopIteration:
196 197 break
197 198
198 199 last_indent = prev_indents.pop()
199 200
200 201 # If we've just opened a multiline statement (e.g. 'a = ['), indent more
201 202 if tokens[-1].type == IN_MULTILINE_STATEMENT:
202 203 if tokens[-2].exact_type in {tokenize.LPAR, tokenize.LSQB, tokenize.LBRACE}:
203 204 return last_indent + 4
204 205 return last_indent
205 206
206 207 if tokens[-1].exact_type == tokenize.COLON:
207 208 # Line ends with colon - indent
208 209 return last_indent + 4
209 210
210 211 if last_indent:
211 212 # Examine the last line for dedent cues - statements like return or
212 213 # raise which normally end a block of code.
213 214 last_line_starts = 0
214 215 for i, tok in enumerate(tokens):
215 216 if tok.type == tokenize.NEWLINE:
216 217 last_line_starts = i + 1
217 218
218 219 last_line_tokens = tokens[last_line_starts:]
219 220 names = [t.string for t in last_line_tokens if t.type == tokenize.NAME]
220 221 if names and names[0] in {'raise', 'return', 'pass', 'break', 'continue'}:
221 222 # Find the most recent indentation less than the current level
222 223 for indent in reversed(prev_indents):
223 224 if indent < last_indent:
224 225 return indent
225 226
226 227 return last_indent
227 228
228 229
229 230 def last_blank(src):
230 231 """Determine if the input source ends in a blank.
231 232
232 233 A blank is either a newline or a line consisting of whitespace.
233 234
234 235 Parameters
235 236 ----------
236 237 src : string
237 238 A single or multiline string.
238 239 """
239 240 if not src: return False
240 241 ll = src.splitlines()[-1]
241 242 return (ll == '') or ll.isspace()
242 243
243 244
244 245 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
245 246 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
246 247
247 248 def last_two_blanks(src):
248 249 """Determine if the input source ends in two blanks.
249 250
250 251 A blank is either a newline or a line consisting of whitespace.
251 252
252 253 Parameters
253 254 ----------
254 255 src : string
255 256 A single or multiline string.
256 257 """
257 258 if not src: return False
258 259 # The logic here is tricky: I couldn't get a regexp to work and pass all
259 260 # the tests, so I took a different approach: split the source by lines,
260 261 # grab the last two and prepend '###\n' as a stand-in for whatever was in
261 262 # the body before the last two lines. Then, with that structure, it's
262 263 # possible to analyze with two regexps. Not the most elegant solution, but
263 264 # it works. If anyone tries to change this logic, make sure to validate
264 265 # the whole test suite first!
265 266 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
266 267 return (bool(last_two_blanks_re.match(new_src)) or
267 268 bool(last_two_blanks_re2.match(new_src)) )
268 269
269 270
270 271 def remove_comments(src):
271 272 """Remove all comments from input source.
272 273
273 274 Note: comments are NOT recognized inside of strings!
274 275
275 276 Parameters
276 277 ----------
277 278 src : string
278 279 A single or multiline input string.
279 280
280 281 Returns
281 282 -------
282 283 String with all Python comments removed.
283 284 """
284 285
285 286 return re.sub('#.*', '', src)
286 287
287 288
288 289 def get_input_encoding():
289 290 """Return the default standard input encoding.
290 291
291 292 If sys.stdin has no encoding, 'ascii' is returned."""
292 293 # There are strange environments for which sys.stdin.encoding is None. We
293 294 # ensure that a valid encoding is returned.
294 295 encoding = getattr(sys.stdin, 'encoding', None)
295 296 if encoding is None:
296 297 encoding = 'ascii'
297 298 return encoding
298 299
299 300 #-----------------------------------------------------------------------------
300 301 # Classes and functions for normal Python syntax handling
301 302 #-----------------------------------------------------------------------------
302 303
303 304 class InputSplitter(object):
304 305 r"""An object that can accumulate lines of Python source before execution.
305 306
306 307 This object is designed to be fed python source line-by-line, using
307 308 :meth:`push`. It will return on each push whether the currently pushed
308 309 code could be executed already. In addition, it provides a method called
309 310 :meth:`push_accepts_more` that can be used to query whether more input
310 311 can be pushed into a single interactive block.
311 312
312 313 This is a simple example of how an interactive terminal-based client can use
313 314 this tool::
314 315
315 316 isp = InputSplitter()
316 317 while isp.push_accepts_more():
317 318 indent = ' '*isp.indent_spaces
318 319 prompt = '>>> ' + indent
319 320 line = indent + raw_input(prompt)
320 321 isp.push(line)
321 322 print 'Input source was:\n', isp.source_reset(),
322 323 """
323 324 # A cache for storing the current indentation
324 325 # The first value stores the most recently processed source input
325 326 # The second value is the number of spaces for the current indentation
326 327 # If self.source matches the first value, the second value is a valid
327 328 # current indentation. Otherwise, the cache is invalid and the indentation
328 329 # must be recalculated.
329 330 _indent_spaces_cache: Union[Tuple[None, None], Tuple[str, int]] = None, None
330 331 # String, indicating the default input encoding. It is computed by default
331 332 # at initialization time via get_input_encoding(), but it can be reset by a
332 333 # client with specific knowledge of the encoding.
333 334 encoding = ''
334 335 # String where the current full source input is stored, properly encoded.
335 336 # Reading this attribute is the normal way of querying the currently pushed
336 337 # source code, that has been properly encoded.
337 338 source: str = ""
338 339 # Code object corresponding to the current source. It is automatically
339 340 # synced to the source, so it can be queried at any time to obtain the code
340 341 # object; it will be None if the source doesn't compile to valid Python.
341 342 code: Optional[CodeType] = None
342 343
343 344 # Private attributes
344 345
345 346 # List with lines of input accumulated so far
346 347 _buffer: List[str]
347 348 # Command compiler
348 349 _compile: codeop.CommandCompiler
349 350 # Boolean indicating whether the current block is complete
350 351 _is_complete: Optional[bool] = None
351 352 # Boolean indicating whether the current block has an unrecoverable syntax error
352 353 _is_invalid: bool = False
353 354
354 355 def __init__(self) -> None:
355 356 """Create a new InputSplitter instance."""
356 357 self._buffer = []
357 358 self._compile = codeop.CommandCompiler()
358 359 self.encoding = get_input_encoding()
359 360
360 361 def reset(self):
361 362 """Reset the input buffer and associated state."""
362 363 self._buffer[:] = []
363 364 self.source = ''
364 365 self.code = None
365 366 self._is_complete = False
366 367 self._is_invalid = False
367 368
368 369 def source_reset(self):
369 370 """Return the input source and perform a full reset.
370 371 """
371 372 out = self.source
372 373 self.reset()
373 374 return out
374 375
375 376 def check_complete(self, source):
376 377 """Return whether a block of code is ready to execute, or should be continued
377 378
378 379 This is a non-stateful API, and will reset the state of this InputSplitter.
379 380
380 381 Parameters
381 382 ----------
382 383 source : string
383 384 Python input code, which can be multiline.
384 385
385 386 Returns
386 387 -------
387 388 status : str
388 389 One of 'complete', 'incomplete', or 'invalid' if source is not a
389 390 prefix of valid code.
390 391 indent_spaces : int or None
391 392 The number of spaces by which to indent the next line of code. If
392 393 status is not 'incomplete', this is None.
393 394 """
394 395 self.reset()
395 396 try:
396 397 self.push(source)
397 398 except SyntaxError:
398 399 # Transformers in IPythonInputSplitter can raise SyntaxError,
399 400 # which push() will not catch.
400 401 return 'invalid', None
401 402 else:
402 403 if self._is_invalid:
403 404 return 'invalid', None
404 405 elif self.push_accepts_more():
405 406 return 'incomplete', self.get_indent_spaces()
406 407 else:
407 408 return 'complete', None
408 409 finally:
409 410 self.reset()
410 411
411 412 def push(self, lines:str) -> bool:
412 413 """Push one or more lines of input.
413 414
414 415 This stores the given lines and returns a status code indicating
415 416 whether the code forms a complete Python block or not.
416 417
417 418 Any exceptions generated in compilation are swallowed, but if an
418 419 exception was produced, the method returns True.
419 420
420 421 Parameters
421 422 ----------
422 423 lines : string
423 424 One or more lines of Python input.
424 425
425 426 Returns
426 427 -------
427 428 is_complete : boolean
428 429 True if the current input source (the result of the current input
429 430 plus prior inputs) forms a complete Python execution block. Note that
430 431 this value is also stored as a private attribute (``_is_complete``), so it
431 432 can be queried at any time.
432 433 """
433 434 assert isinstance(lines, str)
434 435 self._store(lines)
435 436 source = self.source
436 437
437 438 # Before calling _compile(), reset the code object to None so that if an
438 439 # exception is raised in compilation, we don't mislead by having
439 440 # inconsistent code/source attributes.
440 441 self.code, self._is_complete = None, None
441 442 self._is_invalid = False
442 443
443 444 # Honor termination lines properly
444 445 if source.endswith('\\\n'):
445 446 return False
446 447
447 448 try:
448 449 with warnings.catch_warnings():
449 450 warnings.simplefilter('error', SyntaxWarning)
450 451 self.code = self._compile(source, symbol="exec")
451 452 # Invalid syntax can produce any of a number of different errors from
452 453 # inside the compiler, so we have to catch them all. Syntax errors
453 454 # immediately produce a 'ready' block, so the invalid Python can be
454 455 # sent to the kernel for evaluation with possible ipython
455 456 # special-syntax conversion.
456 457 except (SyntaxError, OverflowError, ValueError, TypeError,
457 458 MemoryError, SyntaxWarning):
458 459 self._is_complete = True
459 460 self._is_invalid = True
460 461 else:
461 462 # Compilation didn't produce any exceptions (though it may not have
462 463 # given a complete code object)
463 464 self._is_complete = self.code is not None
464 465
465 466 return self._is_complete
466 467
467 468 def push_accepts_more(self):
468 469 """Return whether a block of interactive input can accept more input.
469 470
470 471 This method is meant to be used by line-oriented frontends, who need to
471 472 guess whether a block is complete or not based solely on prior and
472 473 current input lines. The InputSplitter considers it has a complete
473 474 interactive block and will not accept more input when either:
474 475
475 476 * A SyntaxError is raised
476 477
477 478 * The code is complete and consists of a single line or a single
478 479 non-compound statement
479 480
480 481 * The code is complete and has a blank line at the end
481 482
482 483 If the current input produces a syntax error, this method immediately
483 484 returns False but does *not* raise the syntax error exception, as
484 485 typically clients will want to send invalid syntax to an execution
485 486 backend which might convert the invalid syntax into valid Python via
486 487 one of the dynamic IPython mechanisms.
487 488 """
488 489
489 490 # With incomplete input, unconditionally accept more
490 491 # A syntax error also sets _is_complete to True - see push()
491 492 if not self._is_complete:
492 493 #print("Not complete") # debug
493 494 return True
494 495
495 496 # The user can make any (complete) input execute by leaving a blank line
496 497 last_line = self.source.splitlines()[-1]
497 498 if (not last_line) or last_line.isspace():
498 499 #print("Blank line") # debug
499 500 return False
500 501
501 502 # If there's just a single line or AST node, and we're flush left, as is
502 503 # the case after a simple statement such as 'a=1', we want to execute it
503 504 # straight away.
504 505 if self.get_indent_spaces() == 0:
505 506 if len(self.source.splitlines()) <= 1:
506 507 return False
507 508
508 509 try:
509 510 code_ast = ast.parse("".join(self._buffer))
510 511 except Exception:
511 512 #print("Can't parse AST") # debug
512 513 return False
513 514 else:
514 515 if len(code_ast.body) == 1 and \
515 516 not hasattr(code_ast.body[0], 'body'):
516 517 #print("Simple statement") # debug
517 518 return False
518 519
519 520 # General fallback - accept more code
520 521 return True
521 522
522 523 def get_indent_spaces(self) -> int:
523 524 sourcefor, n = self._indent_spaces_cache
524 525 if sourcefor == self.source:
525 526 assert n is not None
526 527 return n
527 528
528 529 # self.source always has a trailing newline
529 530 n = find_next_indent(self.source[:-1])
530 531 self._indent_spaces_cache = (self.source, n)
531 532 return n
532 533
533 534 # Backwards compatibility. I think all code that used .indent_spaces was
534 535 # inside IPython, but we can leave this here until IPython 7 in case any
535 536 # other modules are using it. -TK, November 2017
536 537 indent_spaces = property(get_indent_spaces)
537 538
538 539 def _store(self, lines, buffer=None, store='source'):
539 540 """Store one or more lines of input.
540 541
541 542 If input lines are not newline-terminated, a newline is automatically
542 543 appended."""
543 544
544 545 if buffer is None:
545 546 buffer = self._buffer
546 547
547 548 if lines.endswith('\n'):
548 549 buffer.append(lines)
549 550 else:
550 551 buffer.append(lines+'\n')
551 552 setattr(self, store, self._set_source(buffer))
552 553
553 554 def _set_source(self, buffer):
554 555 return u''.join(buffer)
555 556
556 557
557 558 class IPythonInputSplitter(InputSplitter):
558 559 """An input splitter that recognizes all of IPython's special syntax."""
559 560
560 561 # String with raw, untransformed input.
561 562 source_raw = ''
562 563
563 564 # Flag to track when a transformer has stored input that it hasn't given
564 565 # back yet.
565 566 transformer_accumulating = False
566 567
567 568 # Flag to track when assemble_python_lines has stored input that it hasn't
568 569 # given back yet.
569 570 within_python_line = False
570 571
571 572 # Private attributes
572 573
573 574 # List with lines of raw input accumulated so far.
574 575 _buffer_raw: List[str]
575 576
576 577 def __init__(self, line_input_checker=True, physical_line_transforms=None,
577 578 logical_line_transforms=None, python_line_transforms=None):
578 579 super(IPythonInputSplitter, self).__init__()
579 580 self._buffer_raw = []
580 581 self._validate = True
581 582
582 583 if physical_line_transforms is not None:
583 584 self.physical_line_transforms = physical_line_transforms
584 585 else:
585 586 self.physical_line_transforms = [
586 587 leading_indent(),
587 588 classic_prompt(),
588 589 ipy_prompt(),
589 590 cellmagic(end_on_blank_line=line_input_checker),
590 591 ]
591 592
592 593 self.assemble_logical_lines = assemble_logical_lines()
593 594 if logical_line_transforms is not None:
594 595 self.logical_line_transforms = logical_line_transforms
595 596 else:
596 597 self.logical_line_transforms = [
597 598 help_end(),
598 599 escaped_commands(),
599 600 assign_from_magic(),
600 601 assign_from_system(),
601 602 ]
602 603
603 604 self.assemble_python_lines = assemble_python_lines()
604 605 if python_line_transforms is not None:
605 606 self.python_line_transforms = python_line_transforms
606 607 else:
607 608 # We don't use any of these at present
608 609 self.python_line_transforms = []
609 610
610 611 @property
611 612 def transforms(self):
612 613 "Quick access to all transformers."
613 614 return self.physical_line_transforms + \
614 615 [self.assemble_logical_lines] + self.logical_line_transforms + \
615 616 [self.assemble_python_lines] + self.python_line_transforms
616 617
617 618 @property
618 619 def transforms_in_use(self):
619 620 """Transformers, excluding logical line transformers if we're in a
620 621 Python line."""
621 622 t = self.physical_line_transforms[:]
622 623 if not self.within_python_line:
623 624 t += [self.assemble_logical_lines] + self.logical_line_transforms
624 625 return t + [self.assemble_python_lines] + self.python_line_transforms
625 626
626 627 def reset(self):
627 628 """Reset the input buffer and associated state."""
628 629 super(IPythonInputSplitter, self).reset()
629 630 self._buffer_raw[:] = []
630 631 self.source_raw = ''
631 632 self.transformer_accumulating = False
632 633 self.within_python_line = False
633 634
634 635 for t in self.transforms:
635 636 try:
636 637 t.reset()
637 638 except SyntaxError:
638 639 # Nothing that calls reset() expects to handle transformer
639 640 # errors
640 641 pass
641 642
642 643 def flush_transformers(self: Self):
643 644 def _flush(transform, outs: List[str]):
644 645 """yield transformed lines
645 646
646 647 always strings, never None
647 648
648 649 transform: the current transform
649 650 outs: an iterable of previously transformed inputs.
650 651 Each may be multiline, which will be passed
651 652 one line at a time to transform.
652 653 """
653 654 for out in outs:
654 655 for line in out.splitlines():
655 656 # push one line at a time
656 657 tmp = transform.push(line)
657 658 if tmp is not None:
658 659 yield tmp
659 660
660 661 # reset the transform
661 662 tmp = transform.reset()
662 663 if tmp is not None:
663 664 yield tmp
664 665
665 666 out: List[str] = []
666 667 for t in self.transforms_in_use:
667 668 out = _flush(t, out)
668 669
669 670 out = list(out)
670 671 if out:
671 672 self._store('\n'.join(out))
672 673
673 674 def raw_reset(self):
674 675 """Return raw input only and perform a full reset.
675 676 """
676 677 out = self.source_raw
677 678 self.reset()
678 679 return out
679 680
680 681 def source_reset(self):
681 682 try:
682 683 self.flush_transformers()
683 684 return self.source
684 685 finally:
685 686 self.reset()
686 687
687 688 def push_accepts_more(self):
688 689 if self.transformer_accumulating:
689 690 return True
690 691 else:
691 692 return super(IPythonInputSplitter, self).push_accepts_more()
692 693
693 694 def transform_cell(self, cell):
694 695 """Process and translate a cell of input.
695 696 """
696 697 self.reset()
697 698 try:
698 699 self.push(cell)
699 700 self.flush_transformers()
700 701 return self.source
701 702 finally:
702 703 self.reset()
703 704
704 705 def push(self, lines:str) -> bool:
705 706 """Push one or more lines of IPython input.
706 707
707 708 This stores the given lines and returns a status code indicating
708 709 whether the code forms a complete Python block or not, after processing
709 710 all input lines for special IPython syntax.
710 711
711 712 Any exceptions generated in compilation are swallowed, but if an
712 713 exception was produced, the method returns True.
713 714
714 715 Parameters
715 716 ----------
716 717 lines : string
717 718 One or more lines of Python input.
718 719
719 720 Returns
720 721 -------
721 722 is_complete : boolean
722 723 True if the current input source (the result of the current input
723 724 plus prior inputs) forms a complete Python execution block. Note that
724 725 this value is also stored as a private attribute (_is_complete), so it
725 726 can be queried at any time.
726 727 """
727 728 assert isinstance(lines, str)
728 729 # We must ensure all input is pure unicode
729 730 # ''.splitlines() --> [], but we need to push the empty line to transformers
730 731 lines_list = lines.splitlines()
731 732 if not lines_list:
732 733 lines_list = ['']
733 734
734 735 # Store raw source before applying any transformations to it. Note
735 736 # that this must be done *after* the reset() call that would otherwise
736 737 # flush the buffer.
737 738 self._store(lines, self._buffer_raw, 'source_raw')
738 739
739 740 transformed_lines_list = []
740 741 for line in lines_list:
741 742 transformed = self._transform_line(line)
742 743 if transformed is not None:
743 744 transformed_lines_list.append(transformed)
744 745
745 746 if transformed_lines_list:
746 747 transformed_lines = '\n'.join(transformed_lines_list)
747 748 return super(IPythonInputSplitter, self).push(transformed_lines)
748 749 else:
749 750 # Got nothing back from transformers - they must be waiting for
750 751 # more input.
751 752 return False
752 753
753 754 def _transform_line(self, line):
754 755 """Push a line of input code through the various transformers.
755 756
756 757 Returns any output from the transformers, or None if a transformer
757 758 is accumulating lines.
758 759
759 760 Sets self.transformer_accumulating as a side effect.
760 761 """
761 762 def _accumulating(dbg):
762 763 #print(dbg)
763 764 self.transformer_accumulating = True
764 765 return None
765 766
766 767 for transformer in self.physical_line_transforms:
767 768 line = transformer.push(line)
768 769 if line is None:
769 770 return _accumulating(transformer)
770 771
771 772 if not self.within_python_line:
772 773 line = self.assemble_logical_lines.push(line)
773 774 if line is None:
774 775 return _accumulating('acc logical line')
775 776
776 777 for transformer in self.logical_line_transforms:
777 778 line = transformer.push(line)
778 779 if line is None:
779 780 return _accumulating(transformer)
780 781
781 782 line = self.assemble_python_lines.push(line)
782 783 if line is None:
783 784 self.within_python_line = True
784 785 return _accumulating('acc python line')
785 786 else:
786 787 self.within_python_line = False
787 788
788 789 for transformer in self.python_line_transforms:
789 790 line = transformer.push(line)
790 791 if line is None:
791 792 return _accumulating(transformer)
792 793
793 794 #print("transformers clear") #debug
794 795 self.transformer_accumulating = False
795 796 return line
796 797
@@ -1,757 +1,759 b''
1 1 # encoding: utf-8
2 2 """Magic functions for InteractiveShell.
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7 7 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
8 8 # Copyright (C) 2008 The IPython Development Team
9 9
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 import os
15 15 import re
16 16 import sys
17 17 from getopt import getopt, GetoptError
18 18
19 19 from traitlets.config.configurable import Configurable
20 20 from . import oinspect
21 21 from .error import UsageError
22 22 from .inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
23 23 from ..utils.ipstruct import Struct
24 24 from ..utils.process import arg_split
25 25 from ..utils.text import dedent
26 26 from traitlets import Bool, Dict, Instance, observe
27 27 from logging import error
28 28
29 import typing as t
30
29 31 #-----------------------------------------------------------------------------
30 32 # Globals
31 33 #-----------------------------------------------------------------------------
32 34
33 35 # A dict we'll use for each class that has magics, used as temporary storage to
34 36 # pass information between the @line/cell_magic method decorators and the
35 37 # @magics_class class decorator, because the method decorators have no
36 38 # access to the class when they run. See for more details:
37 39 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
38 40
39 magics = dict(line={}, cell={})
41 magics: t.Dict = dict(line={}, cell={})
40 42
41 43 magic_kinds = ('line', 'cell')
42 44 magic_spec = ('line', 'cell', 'line_cell')
43 45 magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
44 46
45 47 #-----------------------------------------------------------------------------
46 48 # Utility classes and functions
47 49 #-----------------------------------------------------------------------------
48 50
49 51 class Bunch: pass
50 52
51 53
52 54 def on_off(tag):
53 55 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
54 56 return ['OFF','ON'][tag]
55 57
56 58
57 59 def compress_dhist(dh):
58 60 """Compress a directory history into a new one with at most 20 entries.
59 61
60 62 Return a new list made from the first and last 10 elements of dhist after
61 63 removal of duplicates.
62 64 """
63 65 head, tail = dh[:-10], dh[-10:]
64 66
65 67 newhead = []
66 68 done = set()
67 69 for h in head:
68 70 if h in done:
69 71 continue
70 72 newhead.append(h)
71 73 done.add(h)
72 74
73 75 return newhead + tail
74 76
75 77
76 78 def needs_local_scope(func):
77 79 """Decorator to mark magic functions which need to local scope to run."""
78 80 func.needs_local_scope = True
79 81 return func
80 82
81 83 #-----------------------------------------------------------------------------
82 84 # Class and method decorators for registering magics
83 85 #-----------------------------------------------------------------------------
84 86
85 87 def magics_class(cls):
86 88 """Class decorator for all subclasses of the main Magics class.
87 89
88 90 Any class that subclasses Magics *must* also apply this decorator, to
89 91 ensure that all the methods that have been decorated as line/cell magics
90 92 get correctly registered in the class instance. This is necessary because
91 93 when method decorators run, the class does not exist yet, so they
92 94 temporarily store their information into a module global. Application of
93 95 this class decorator copies that global data to the class instance and
94 96 clears the global.
95 97
96 98 Obviously, this mechanism is not thread-safe, which means that the
97 99 *creation* of subclasses of Magic should only be done in a single-thread
98 100 context. Instantiation of the classes has no restrictions. Given that
99 101 these classes are typically created at IPython startup time and before user
100 102 application code becomes active, in practice this should not pose any
101 103 problems.
102 104 """
103 105 cls.registered = True
104 106 cls.magics = dict(line = magics['line'],
105 107 cell = magics['cell'])
106 108 magics['line'] = {}
107 109 magics['cell'] = {}
108 110 return cls
109 111
110 112
111 113 def record_magic(dct, magic_kind, magic_name, func):
112 114 """Utility function to store a function as a magic of a specific kind.
113 115
114 116 Parameters
115 117 ----------
116 118 dct : dict
117 119 A dictionary with 'line' and 'cell' subdicts.
118 120 magic_kind : str
119 121 Kind of magic to be stored.
120 122 magic_name : str
121 123 Key to store the magic as.
122 124 func : function
123 125 Callable object to store.
124 126 """
125 127 if magic_kind == 'line_cell':
126 128 dct['line'][magic_name] = dct['cell'][magic_name] = func
127 129 else:
128 130 dct[magic_kind][magic_name] = func
129 131
130 132
131 133 def validate_type(magic_kind):
132 134 """Ensure that the given magic_kind is valid.
133 135
134 136 Check that the given magic_kind is one of the accepted spec types (stored
135 137 in the global `magic_spec`), raise ValueError otherwise.
136 138 """
137 139 if magic_kind not in magic_spec:
138 140 raise ValueError('magic_kind must be one of %s, %s given' %
139 141 magic_kinds, magic_kind)
140 142
141 143
142 144 # The docstrings for the decorator below will be fairly similar for the two
143 145 # types (method and function), so we generate them here once and reuse the
144 146 # templates below.
145 147 _docstring_template = \
146 148 """Decorate the given {0} as {1} magic.
147 149
148 150 The decorator can be used with or without arguments, as follows.
149 151
150 152 i) without arguments: it will create a {1} magic named as the {0} being
151 153 decorated::
152 154
153 155 @deco
154 156 def foo(...)
155 157
156 158 will create a {1} magic named `foo`.
157 159
158 160 ii) with one string argument: which will be used as the actual name of the
159 161 resulting magic::
160 162
161 163 @deco('bar')
162 164 def foo(...)
163 165
164 166 will create a {1} magic named `bar`.
165 167
166 168 To register a class magic use ``Interactiveshell.register_magic(class or instance)``.
167 169 """
168 170
169 171 # These two are decorator factories. While they are conceptually very similar,
170 172 # there are enough differences in the details that it's simpler to have them
171 173 # written as completely standalone functions rather than trying to share code
172 174 # and make a single one with convoluted logic.
173 175
174 176 def _method_magic_marker(magic_kind):
175 177 """Decorator factory for methods in Magics subclasses.
176 178 """
177 179
178 180 validate_type(magic_kind)
179 181
180 182 # This is a closure to capture the magic_kind. We could also use a class,
181 183 # but it's overkill for just that one bit of state.
182 184 def magic_deco(arg):
183 185 if callable(arg):
184 186 # "Naked" decorator call (just @foo, no args)
185 187 func = arg
186 188 name = func.__name__
187 189 retval = arg
188 190 record_magic(magics, magic_kind, name, name)
189 191 elif isinstance(arg, str):
190 192 # Decorator called with arguments (@foo('bar'))
191 193 name = arg
192 194 def mark(func, *a, **kw):
193 195 record_magic(magics, magic_kind, name, func.__name__)
194 196 return func
195 197 retval = mark
196 198 else:
197 199 raise TypeError("Decorator can only be called with "
198 200 "string or function")
199 201 return retval
200 202
201 203 # Ensure the resulting decorator has a usable docstring
202 204 magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
203 205 return magic_deco
204 206
205 207
206 208 def _function_magic_marker(magic_kind):
207 209 """Decorator factory for standalone functions.
208 210 """
209 211 validate_type(magic_kind)
210 212
211 213 # This is a closure to capture the magic_kind. We could also use a class,
212 214 # but it's overkill for just that one bit of state.
213 215 def magic_deco(arg):
214 216 # Find get_ipython() in the caller's namespace
215 217 caller = sys._getframe(1)
216 218 for ns in ['f_locals', 'f_globals', 'f_builtins']:
217 219 get_ipython = getattr(caller, ns).get('get_ipython')
218 220 if get_ipython is not None:
219 221 break
220 222 else:
221 223 raise NameError('Decorator can only run in context where '
222 224 '`get_ipython` exists')
223 225
224 226 ip = get_ipython()
225 227
226 228 if callable(arg):
227 229 # "Naked" decorator call (just @foo, no args)
228 230 func = arg
229 231 name = func.__name__
230 232 ip.register_magic_function(func, magic_kind, name)
231 233 retval = arg
232 234 elif isinstance(arg, str):
233 235 # Decorator called with arguments (@foo('bar'))
234 236 name = arg
235 237 def mark(func, *a, **kw):
236 238 ip.register_magic_function(func, magic_kind, name)
237 239 return func
238 240 retval = mark
239 241 else:
240 242 raise TypeError("Decorator can only be called with "
241 243 "string or function")
242 244 return retval
243 245
244 246 # Ensure the resulting decorator has a usable docstring
245 247 ds = _docstring_template.format('function', magic_kind)
246 248
247 249 ds += dedent("""
248 250 Note: this decorator can only be used in a context where IPython is already
249 251 active, so that the `get_ipython()` call succeeds. You can therefore use
250 252 it in your startup files loaded after IPython initializes, but *not* in the
251 253 IPython configuration file itself, which is executed before IPython is
252 254 fully up and running. Any file located in the `startup` subdirectory of
253 255 your configuration profile will be OK in this sense.
254 256 """)
255 257
256 258 magic_deco.__doc__ = ds
257 259 return magic_deco
258 260
259 261
260 262 MAGIC_NO_VAR_EXPAND_ATTR = "_ipython_magic_no_var_expand"
261 263 MAGIC_OUTPUT_CAN_BE_SILENCED = "_ipython_magic_output_can_be_silenced"
262 264
263 265
264 266 def no_var_expand(magic_func):
265 267 """Mark a magic function as not needing variable expansion
266 268
267 269 By default, IPython interprets `{a}` or `$a` in the line passed to magics
268 270 as variables that should be interpolated from the interactive namespace
269 271 before passing the line to the magic function.
270 272 This is not always desirable, e.g. when the magic executes Python code
271 273 (%timeit, %time, etc.).
272 274 Decorate magics with `@no_var_expand` to opt-out of variable expansion.
273 275
274 276 .. versionadded:: 7.3
275 277 """
276 278 setattr(magic_func, MAGIC_NO_VAR_EXPAND_ATTR, True)
277 279 return magic_func
278 280
279 281
280 282 def output_can_be_silenced(magic_func):
281 283 """Mark a magic function so its output may be silenced.
282 284
283 285 The output is silenced if the Python code used as a parameter of
284 286 the magic ends in a semicolon, not counting a Python comment that can
285 287 follow it.
286 288 """
287 289 setattr(magic_func, MAGIC_OUTPUT_CAN_BE_SILENCED, True)
288 290 return magic_func
289 291
290 292 # Create the actual decorators for public use
291 293
292 294 # These three are used to decorate methods in class definitions
293 295 line_magic = _method_magic_marker('line')
294 296 cell_magic = _method_magic_marker('cell')
295 297 line_cell_magic = _method_magic_marker('line_cell')
296 298
297 299 # These three decorate standalone functions and perform the decoration
298 300 # immediately. They can only run where get_ipython() works
299 301 register_line_magic = _function_magic_marker('line')
300 302 register_cell_magic = _function_magic_marker('cell')
301 303 register_line_cell_magic = _function_magic_marker('line_cell')
302 304
303 305 #-----------------------------------------------------------------------------
304 306 # Core Magic classes
305 307 #-----------------------------------------------------------------------------
306 308
307 309 class MagicsManager(Configurable):
308 310 """Object that handles all magic-related functionality for IPython.
309 311 """
310 312 # Non-configurable class attributes
311 313
312 314 # A two-level dict, first keyed by magic type, then by magic function, and
313 315 # holding the actual callable object as value. This is the dict used for
314 316 # magic function dispatch
315 317 magics = Dict()
316 318 lazy_magics = Dict(
317 319 help="""
318 320 Mapping from magic names to modules to load.
319 321
320 322 This can be used in IPython/IPykernel configuration to declare lazy magics
321 323 that will only be imported/registered on first use.
322 324
323 325 For example::
324 326
325 327 c.MagicsManager.lazy_magics = {
326 328 "my_magic": "slow.to.import",
327 329 "my_other_magic": "also.slow",
328 330 }
329 331
330 332 On first invocation of `%my_magic`, `%%my_magic`, `%%my_other_magic` or
331 333 `%%my_other_magic`, the corresponding module will be loaded as an ipython
332 334 extensions as if you had previously done `%load_ext ipython`.
333 335
334 336 Magics names should be without percent(s) as magics can be both cell
335 337 and line magics.
336 338
337 339 Lazy loading happen relatively late in execution process, and
338 340 complex extensions that manipulate Python/IPython internal state or global state
339 341 might not support lazy loading.
340 342 """
341 343 ).tag(
342 344 config=True,
343 345 )
344 346
345 347 # A registry of the original objects that we've been given holding magics.
346 348 registry = Dict()
347 349
348 350 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
349 351
350 352 auto_magic = Bool(True, help=
351 353 "Automatically call line magics without requiring explicit % prefix"
352 354 ).tag(config=True)
353 355 @observe('auto_magic')
354 356 def _auto_magic_changed(self, change):
355 357 self.shell.automagic = change['new']
356 358
357 359 _auto_status = [
358 360 'Automagic is OFF, % prefix IS needed for line magics.',
359 361 'Automagic is ON, % prefix IS NOT needed for line magics.']
360 362
361 363 user_magics = Instance('IPython.core.magics.UserMagics', allow_none=True)
362 364
363 365 def __init__(self, shell=None, config=None, user_magics=None, **traits):
364 366
365 367 super(MagicsManager, self).__init__(shell=shell, config=config,
366 368 user_magics=user_magics, **traits)
367 369 self.magics = dict(line={}, cell={})
368 370 # Let's add the user_magics to the registry for uniformity, so *all*
369 371 # registered magic containers can be found there.
370 372 self.registry[user_magics.__class__.__name__] = user_magics
371 373
372 374 def auto_status(self):
373 375 """Return descriptive string with automagic status."""
374 376 return self._auto_status[self.auto_magic]
375 377
376 378 def lsmagic(self):
377 379 """Return a dict of currently available magic functions.
378 380
379 381 The return dict has the keys 'line' and 'cell', corresponding to the
380 382 two types of magics we support. Each value is a list of names.
381 383 """
382 384 return self.magics
383 385
384 386 def lsmagic_docs(self, brief=False, missing=''):
385 387 """Return dict of documentation of magic functions.
386 388
387 389 The return dict has the keys 'line' and 'cell', corresponding to the
388 390 two types of magics we support. Each value is a dict keyed by magic
389 391 name whose value is the function docstring. If a docstring is
390 392 unavailable, the value of `missing` is used instead.
391 393
392 394 If brief is True, only the first line of each docstring will be returned.
393 395 """
394 396 docs = {}
395 397 for m_type in self.magics:
396 398 m_docs = {}
397 399 for m_name, m_func in self.magics[m_type].items():
398 400 if m_func.__doc__:
399 401 if brief:
400 402 m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
401 403 else:
402 404 m_docs[m_name] = m_func.__doc__.rstrip()
403 405 else:
404 406 m_docs[m_name] = missing
405 407 docs[m_type] = m_docs
406 408 return docs
407 409
408 410 def register_lazy(self, name: str, fully_qualified_name: str):
409 411 """
410 412 Lazily register a magic via an extension.
411 413
412 414
413 415 Parameters
414 416 ----------
415 417 name : str
416 418 Name of the magic you wish to register.
417 419 fully_qualified_name :
418 420 Fully qualified name of the module/submodule that should be loaded
419 421 as an extensions when the magic is first called.
420 422 It is assumed that loading this extensions will register the given
421 423 magic.
422 424 """
423 425
424 426 self.lazy_magics[name] = fully_qualified_name
425 427
426 428 def register(self, *magic_objects):
427 429 """Register one or more instances of Magics.
428 430
429 431 Take one or more classes or instances of classes that subclass the main
430 432 `core.Magic` class, and register them with IPython to use the magic
431 433 functions they provide. The registration process will then ensure that
432 434 any methods that have decorated to provide line and/or cell magics will
433 435 be recognized with the `%x`/`%%x` syntax as a line/cell magic
434 436 respectively.
435 437
436 438 If classes are given, they will be instantiated with the default
437 439 constructor. If your classes need a custom constructor, you should
438 440 instanitate them first and pass the instance.
439 441
440 442 The provided arguments can be an arbitrary mix of classes and instances.
441 443
442 444 Parameters
443 445 ----------
444 446 *magic_objects : one or more classes or instances
445 447 """
446 448 # Start by validating them to ensure they have all had their magic
447 449 # methods registered at the instance level
448 450 for m in magic_objects:
449 451 if not m.registered:
450 452 raise ValueError("Class of magics %r was constructed without "
451 453 "the @register_magics class decorator")
452 454 if isinstance(m, type):
453 455 # If we're given an uninstantiated class
454 456 m = m(shell=self.shell)
455 457
456 458 # Now that we have an instance, we can register it and update the
457 459 # table of callables
458 460 self.registry[m.__class__.__name__] = m
459 461 for mtype in magic_kinds:
460 462 self.magics[mtype].update(m.magics[mtype])
461 463
462 464 def register_function(self, func, magic_kind='line', magic_name=None):
463 465 """Expose a standalone function as magic function for IPython.
464 466
465 467 This will create an IPython magic (line, cell or both) from a
466 468 standalone function. The functions should have the following
467 469 signatures:
468 470
469 471 * For line magics: `def f(line)`
470 472 * For cell magics: `def f(line, cell)`
471 473 * For a function that does both: `def f(line, cell=None)`
472 474
473 475 In the latter case, the function will be called with `cell==None` when
474 476 invoked as `%f`, and with cell as a string when invoked as `%%f`.
475 477
476 478 Parameters
477 479 ----------
478 480 func : callable
479 481 Function to be registered as a magic.
480 482 magic_kind : str
481 483 Kind of magic, one of 'line', 'cell' or 'line_cell'
482 484 magic_name : optional str
483 485 If given, the name the magic will have in the IPython namespace. By
484 486 default, the name of the function itself is used.
485 487 """
486 488
487 489 # Create the new method in the user_magics and register it in the
488 490 # global table
489 491 validate_type(magic_kind)
490 492 magic_name = func.__name__ if magic_name is None else magic_name
491 493 setattr(self.user_magics, magic_name, func)
492 494 record_magic(self.magics, magic_kind, magic_name, func)
493 495
494 496 def register_alias(self, alias_name, magic_name, magic_kind='line', magic_params=None):
495 497 """Register an alias to a magic function.
496 498
497 499 The alias is an instance of :class:`MagicAlias`, which holds the
498 500 name and kind of the magic it should call. Binding is done at
499 501 call time, so if the underlying magic function is changed the alias
500 502 will call the new function.
501 503
502 504 Parameters
503 505 ----------
504 506 alias_name : str
505 507 The name of the magic to be registered.
506 508 magic_name : str
507 509 The name of an existing magic.
508 510 magic_kind : str
509 511 Kind of magic, one of 'line' or 'cell'
510 512 """
511 513
512 514 # `validate_type` is too permissive, as it allows 'line_cell'
513 515 # which we do not handle.
514 516 if magic_kind not in magic_kinds:
515 517 raise ValueError('magic_kind must be one of %s, %s given' %
516 518 magic_kinds, magic_kind)
517 519
518 520 alias = MagicAlias(self.shell, magic_name, magic_kind, magic_params)
519 521 setattr(self.user_magics, alias_name, alias)
520 522 record_magic(self.magics, magic_kind, alias_name, alias)
521 523
522 524 # Key base class that provides the central functionality for magics.
523 525
524 526
525 527 class Magics(Configurable):
526 528 """Base class for implementing magic functions.
527 529
528 530 Shell functions which can be reached as %function_name. All magic
529 531 functions should accept a string, which they can parse for their own
530 532 needs. This can make some functions easier to type, eg `%cd ../`
531 533 vs. `%cd("../")`
532 534
533 535 Classes providing magic functions need to subclass this class, and they
534 536 MUST:
535 537
536 538 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
537 539 individual methods as magic functions, AND
538 540
539 541 - Use the class decorator `@magics_class` to ensure that the magic
540 542 methods are properly registered at the instance level upon instance
541 543 initialization.
542 544
543 545 See :mod:`magic_functions` for examples of actual implementation classes.
544 546 """
545 547 # Dict holding all command-line options for each magic.
546 548 options_table = None
547 549 # Dict for the mapping of magic names to methods, set by class decorator
548 550 magics = None
549 551 # Flag to check that the class decorator was properly applied
550 552 registered = False
551 553 # Instance of IPython shell
552 554 shell = None
553 555
554 556 def __init__(self, shell=None, **kwargs):
555 557 if not(self.__class__.registered):
556 558 raise ValueError('Magics subclass without registration - '
557 559 'did you forget to apply @magics_class?')
558 560 if shell is not None:
559 561 if hasattr(shell, 'configurables'):
560 562 shell.configurables.append(self)
561 563 if hasattr(shell, 'config'):
562 564 kwargs.setdefault('parent', shell)
563 565
564 566 self.shell = shell
565 567 self.options_table = {}
566 568 # The method decorators are run when the instance doesn't exist yet, so
567 569 # they can only record the names of the methods they are supposed to
568 570 # grab. Only now, that the instance exists, can we create the proper
569 571 # mapping to bound methods. So we read the info off the original names
570 572 # table and replace each method name by the actual bound method.
571 573 # But we mustn't clobber the *class* mapping, in case of multiple instances.
572 574 class_magics = self.magics
573 575 self.magics = {}
574 576 for mtype in magic_kinds:
575 577 tab = self.magics[mtype] = {}
576 578 cls_tab = class_magics[mtype]
577 579 for magic_name, meth_name in cls_tab.items():
578 580 if isinstance(meth_name, str):
579 581 # it's a method name, grab it
580 582 tab[magic_name] = getattr(self, meth_name)
581 583 else:
582 584 # it's the real thing
583 585 tab[magic_name] = meth_name
584 586 # Configurable **needs** to be initiated at the end or the config
585 587 # magics get screwed up.
586 588 super(Magics, self).__init__(**kwargs)
587 589
588 590 def arg_err(self,func):
589 591 """Print docstring if incorrect arguments were passed"""
590 592 print('Error in arguments:')
591 593 print(oinspect.getdoc(func))
592 594
593 595 def format_latex(self, strng):
594 596 """Format a string for latex inclusion."""
595 597
596 598 # Characters that need to be escaped for latex:
597 599 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
598 600 # Magic command names as headers:
599 601 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
600 602 re.MULTILINE)
601 603 # Magic commands
602 604 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
603 605 re.MULTILINE)
604 606 # Paragraph continue
605 607 par_re = re.compile(r'\\$',re.MULTILINE)
606 608
607 609 # The "\n" symbol
608 610 newline_re = re.compile(r'\\n')
609 611
610 612 # Now build the string for output:
611 613 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
612 614 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
613 615 strng)
614 616 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
615 617 strng = par_re.sub(r'\\\\',strng)
616 618 strng = escape_re.sub(r'\\\1',strng)
617 619 strng = newline_re.sub(r'\\textbackslash{}n',strng)
618 620 return strng
619 621
620 622 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
621 623 """Parse options passed to an argument string.
622 624
623 625 The interface is similar to that of :func:`getopt.getopt`, but it
624 626 returns a :class:`~IPython.utils.struct.Struct` with the options as keys
625 627 and the stripped argument string still as a string.
626 628
627 629 arg_str is quoted as a true sys.argv vector by using shlex.split.
628 630 This allows us to easily expand variables, glob files, quote
629 631 arguments, etc.
630 632
631 633 Parameters
632 634 ----------
633 635 arg_str : str
634 636 The arguments to parse.
635 637 opt_str : str
636 638 The options specification.
637 639 mode : str, default 'string'
638 640 If given as 'list', the argument string is returned as a list (split
639 641 on whitespace) instead of a string.
640 642 list_all : bool, default False
641 643 Put all option values in lists. Normally only options
642 644 appearing more than once are put in a list.
643 645 posix : bool, default True
644 646 Whether to split the input line in POSIX mode or not, as per the
645 647 conventions outlined in the :mod:`shlex` module from the standard
646 648 library.
647 649 """
648 650
649 651 # inject default options at the beginning of the input line
650 652 caller = sys._getframe(1).f_code.co_name
651 653 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
652 654
653 655 mode = kw.get('mode','string')
654 656 if mode not in ['string','list']:
655 657 raise ValueError('incorrect mode given: %s' % mode)
656 658 # Get options
657 659 list_all = kw.get('list_all',0)
658 660 posix = kw.get('posix', os.name == 'posix')
659 661 strict = kw.get('strict', True)
660 662
661 663 preserve_non_opts = kw.get("preserve_non_opts", False)
662 664 remainder_arg_str = arg_str
663 665
664 666 # Check if we have more than one argument to warrant extra processing:
665 667 odict = {} # Dictionary with options
666 668 args = arg_str.split()
667 669 if len(args) >= 1:
668 670 # If the list of inputs only has 0 or 1 thing in it, there's no
669 671 # need to look for options
670 672 argv = arg_split(arg_str, posix, strict)
671 673 # Do regular option processing
672 674 try:
673 675 opts,args = getopt(argv, opt_str, long_opts)
674 676 except GetoptError as e:
675 677 raise UsageError(
676 678 '%s ( allowed: "%s" %s)' % (e.msg, opt_str, " ".join(long_opts))
677 679 ) from e
678 680 for o, a in opts:
679 681 if mode == "string" and preserve_non_opts:
680 682 # remove option-parts from the original args-string and preserve remaining-part.
681 683 # This relies on the arg_split(...) and getopt(...)'s impl spec, that the parsed options are
682 684 # returned in the original order.
683 685 remainder_arg_str = remainder_arg_str.replace(o, "", 1).replace(
684 686 a, "", 1
685 687 )
686 688 if o.startswith("--"):
687 689 o = o[2:]
688 690 else:
689 691 o = o[1:]
690 692 try:
691 693 odict[o].append(a)
692 694 except AttributeError:
693 695 odict[o] = [odict[o],a]
694 696 except KeyError:
695 697 if list_all:
696 698 odict[o] = [a]
697 699 else:
698 700 odict[o] = a
699 701
700 702 # Prepare opts,args for return
701 703 opts = Struct(odict)
702 704 if mode == 'string':
703 705 if preserve_non_opts:
704 706 args = remainder_arg_str.lstrip()
705 707 else:
706 708 args = " ".join(args)
707 709
708 710 return opts,args
709 711
710 712 def default_option(self, fn, optstr):
711 713 """Make an entry in the options_table for fn, with value optstr"""
712 714
713 715 if fn not in self.lsmagic():
714 716 error("%s is not a magic function" % fn)
715 717 self.options_table[fn] = optstr
716 718
717 719
718 720 class MagicAlias(object):
719 721 """An alias to another magic function.
720 722
721 723 An alias is determined by its magic name and magic kind. Lookup
722 724 is done at call time, so if the underlying magic changes the alias
723 725 will call the new function.
724 726
725 727 Use the :meth:`MagicsManager.register_alias` method or the
726 728 `%alias_magic` magic function to create and register a new alias.
727 729 """
728 730 def __init__(self, shell, magic_name, magic_kind, magic_params=None):
729 731 self.shell = shell
730 732 self.magic_name = magic_name
731 733 self.magic_params = magic_params
732 734 self.magic_kind = magic_kind
733 735
734 736 self.pretty_target = '%s%s' % (magic_escapes[self.magic_kind], self.magic_name)
735 737 self.__doc__ = "Alias for `%s`." % self.pretty_target
736 738
737 739 self._in_call = False
738 740
739 741 def __call__(self, *args, **kwargs):
740 742 """Call the magic alias."""
741 743 fn = self.shell.find_magic(self.magic_name, self.magic_kind)
742 744 if fn is None:
743 745 raise UsageError("Magic `%s` not found." % self.pretty_target)
744 746
745 747 # Protect against infinite recursion.
746 748 if self._in_call:
747 749 raise UsageError("Infinite recursion detected; "
748 750 "magic aliases cannot call themselves.")
749 751 self._in_call = True
750 752 try:
751 753 if self.magic_params:
752 754 args_list = list(args)
753 755 args_list[0] = self.magic_params + " " + args[0]
754 756 args = tuple(args_list)
755 757 return fn(*args, **kwargs)
756 758 finally:
757 759 self._in_call = False
@@ -1,944 +1,946 b''
1 # -*- coding: utf-8 -*-
2 1 """
3 2 Python advanced pretty printer. This pretty printer is intended to
4 3 replace the old `pprint` python module which does not allow developers
5 4 to provide their own pretty print callbacks.
6 5
7 6 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
8 7
9 8
10 9 Example Usage
11 10 -------------
12 11
13 12 To directly print the representation of an object use `pprint`::
14 13
15 14 from pretty import pprint
16 15 pprint(complex_object)
17 16
18 17 To get a string of the output use `pretty`::
19 18
20 19 from pretty import pretty
21 20 string = pretty(complex_object)
22 21
23 22
24 23 Extending
25 24 ---------
26 25
27 26 The pretty library allows developers to add pretty printing rules for their
28 27 own objects. This process is straightforward. All you have to do is to
29 28 add a `_repr_pretty_` method to your object and call the methods on the
30 29 pretty printer passed::
31 30
32 31 class MyObject(object):
33 32
34 33 def _repr_pretty_(self, p, cycle):
35 34 ...
36 35
37 36 Here's an example for a class with a simple constructor::
38 37
39 38 class MySimpleObject:
40 39
41 40 def __init__(self, a, b, *, c=None):
42 41 self.a = a
43 42 self.b = b
44 43 self.c = c
45 44
46 45 def _repr_pretty_(self, p, cycle):
47 46 ctor = CallExpression.factory(self.__class__.__name__)
48 47 if self.c is None:
49 48 p.pretty(ctor(a, b))
50 49 else:
51 50 p.pretty(ctor(a, b, c=c))
52 51
53 52 Here is an example implementation of a `_repr_pretty_` method for a list
54 53 subclass::
55 54
56 55 class MyList(list):
57 56
58 57 def _repr_pretty_(self, p, cycle):
59 58 if cycle:
60 59 p.text('MyList(...)')
61 60 else:
62 61 with p.group(8, 'MyList([', '])'):
63 62 for idx, item in enumerate(self):
64 63 if idx:
65 64 p.text(',')
66 65 p.breakable()
67 66 p.pretty(item)
68 67
69 68 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
70 69 react to that or the result is an infinite loop. `p.text()` just adds
71 70 non breaking text to the output, `p.breakable()` either adds a whitespace
72 71 or breaks here. If you pass it an argument it's used instead of the
73 72 default space. `p.pretty` prettyprints another object using the pretty print
74 73 method.
75 74
76 75 The first parameter to the `group` function specifies the extra indentation
77 76 of the next line. In this example the next item will either be on the same
78 77 line (if the items are short enough) or aligned with the right edge of the
79 78 opening bracket of `MyList`.
80 79
81 80 If you just want to indent something you can use the group function
82 81 without open / close parameters. You can also use this code::
83 82
84 83 with p.indent(2):
85 84 ...
86 85
87 86 Inheritance diagram:
88 87
89 88 .. inheritance-diagram:: IPython.lib.pretty
90 89 :parts: 3
91 90
92 91 :copyright: 2007 by Armin Ronacher.
93 92 Portions (c) 2009 by Robert Kern.
94 93 :license: BSD License.
95 94 """
96 95
97 96 from contextlib import contextmanager
98 97 import datetime
99 98 import os
100 99 import re
101 100 import sys
102 101 import types
103 102 from collections import deque
104 103 from inspect import signature
105 104 from io import StringIO
106 105 from warnings import warn
107 106
108 107 from IPython.utils.decorators import undoc
109 108 from IPython.utils.py3compat import PYPY
110 109
110 from typing import Dict
111
111 112 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
112 113 'for_type', 'for_type_by_name', 'RawText', 'RawStringLiteral', 'CallExpression']
113 114
114 115
115 116 MAX_SEQ_LENGTH = 1000
116 117 _re_pattern_type = type(re.compile(''))
117 118
118 119 def _safe_getattr(obj, attr, default=None):
119 120 """Safe version of getattr.
120 121
121 122 Same as getattr, but will return ``default`` on any Exception,
122 123 rather than raising.
123 124 """
124 125 try:
125 126 return getattr(obj, attr, default)
126 127 except Exception:
127 128 return default
128 129
129 130 @undoc
130 131 class CUnicodeIO(StringIO):
131 132 def __init__(self, *args, **kwargs):
132 133 super().__init__(*args, **kwargs)
133 134 warn(("CUnicodeIO is deprecated since IPython 6.0. "
134 135 "Please use io.StringIO instead."),
135 136 DeprecationWarning, stacklevel=2)
136 137
137 138 def _sorted_for_pprint(items):
138 139 """
139 140 Sort the given items for pretty printing. Since some predictable
140 141 sorting is better than no sorting at all, we sort on the string
141 142 representation if normal sorting fails.
142 143 """
143 144 items = list(items)
144 145 try:
145 146 return sorted(items)
146 147 except Exception:
147 148 try:
148 149 return sorted(items, key=str)
149 150 except Exception:
150 151 return items
151 152
152 153 def pretty(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
153 154 """
154 155 Pretty print the object's representation.
155 156 """
156 157 stream = StringIO()
157 158 printer = RepresentationPrinter(stream, verbose, max_width, newline, max_seq_length=max_seq_length)
158 159 printer.pretty(obj)
159 160 printer.flush()
160 161 return stream.getvalue()
161 162
162 163
163 164 def pprint(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
164 165 """
165 166 Like `pretty` but print to stdout.
166 167 """
167 168 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length)
168 169 printer.pretty(obj)
169 170 printer.flush()
170 171 sys.stdout.write(newline)
171 172 sys.stdout.flush()
172 173
173 174 class _PrettyPrinterBase(object):
174 175
175 176 @contextmanager
176 177 def indent(self, indent):
177 178 """with statement support for indenting/dedenting."""
178 179 self.indentation += indent
179 180 try:
180 181 yield
181 182 finally:
182 183 self.indentation -= indent
183 184
184 185 @contextmanager
185 186 def group(self, indent=0, open='', close=''):
186 187 """like begin_group / end_group but for the with statement."""
187 188 self.begin_group(indent, open)
188 189 try:
189 190 yield
190 191 finally:
191 192 self.end_group(indent, close)
192 193
193 194 class PrettyPrinter(_PrettyPrinterBase):
194 195 """
195 196 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
196 197 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
197 198 this printer knows nothing about the default pprinters or the `_repr_pretty_`
198 199 callback method.
199 200 """
200 201
201 202 def __init__(self, output, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
202 203 self.output = output
203 204 self.max_width = max_width
204 205 self.newline = newline
205 206 self.max_seq_length = max_seq_length
206 207 self.output_width = 0
207 208 self.buffer_width = 0
208 209 self.buffer = deque()
209 210
210 211 root_group = Group(0)
211 212 self.group_stack = [root_group]
212 213 self.group_queue = GroupQueue(root_group)
213 214 self.indentation = 0
214 215
215 216 def _break_one_group(self, group):
216 217 while group.breakables:
217 218 x = self.buffer.popleft()
218 219 self.output_width = x.output(self.output, self.output_width)
219 220 self.buffer_width -= x.width
220 221 while self.buffer and isinstance(self.buffer[0], Text):
221 222 x = self.buffer.popleft()
222 223 self.output_width = x.output(self.output, self.output_width)
223 224 self.buffer_width -= x.width
224 225
225 226 def _break_outer_groups(self):
226 227 while self.max_width < self.output_width + self.buffer_width:
227 228 group = self.group_queue.deq()
228 229 if not group:
229 230 return
230 231 self._break_one_group(group)
231 232
232 233 def text(self, obj):
233 234 """Add literal text to the output."""
234 235 width = len(obj)
235 236 if self.buffer:
236 237 text = self.buffer[-1]
237 238 if not isinstance(text, Text):
238 239 text = Text()
239 240 self.buffer.append(text)
240 241 text.add(obj, width)
241 242 self.buffer_width += width
242 243 self._break_outer_groups()
243 244 else:
244 245 self.output.write(obj)
245 246 self.output_width += width
246 247
247 248 def breakable(self, sep=' '):
248 249 """
249 250 Add a breakable separator to the output. This does not mean that it
250 251 will automatically break here. If no breaking on this position takes
251 252 place the `sep` is inserted which default to one space.
252 253 """
253 254 width = len(sep)
254 255 group = self.group_stack[-1]
255 256 if group.want_break:
256 257 self.flush()
257 258 self.output.write(self.newline)
258 259 self.output.write(' ' * self.indentation)
259 260 self.output_width = self.indentation
260 261 self.buffer_width = 0
261 262 else:
262 263 self.buffer.append(Breakable(sep, width, self))
263 264 self.buffer_width += width
264 265 self._break_outer_groups()
265 266
266 267 def break_(self):
267 268 """
268 269 Explicitly insert a newline into the output, maintaining correct indentation.
269 270 """
270 271 group = self.group_queue.deq()
271 272 if group:
272 273 self._break_one_group(group)
273 274 self.flush()
274 275 self.output.write(self.newline)
275 276 self.output.write(' ' * self.indentation)
276 277 self.output_width = self.indentation
277 278 self.buffer_width = 0
278 279
279 280
280 281 def begin_group(self, indent=0, open=''):
281 282 """
282 283 Begin a group.
283 284 The first parameter specifies the indentation for the next line (usually
284 285 the width of the opening text), the second the opening text. All
285 286 parameters are optional.
286 287 """
287 288 if open:
288 289 self.text(open)
289 290 group = Group(self.group_stack[-1].depth + 1)
290 291 self.group_stack.append(group)
291 292 self.group_queue.enq(group)
292 293 self.indentation += indent
293 294
294 295 def _enumerate(self, seq):
295 296 """like enumerate, but with an upper limit on the number of items"""
296 297 for idx, x in enumerate(seq):
297 298 if self.max_seq_length and idx >= self.max_seq_length:
298 299 self.text(',')
299 300 self.breakable()
300 301 self.text('...')
301 302 return
302 303 yield idx, x
303 304
304 305 def end_group(self, dedent=0, close=''):
305 306 """End a group. See `begin_group` for more details."""
306 307 self.indentation -= dedent
307 308 group = self.group_stack.pop()
308 309 if not group.breakables:
309 310 self.group_queue.remove(group)
310 311 if close:
311 312 self.text(close)
312 313
313 314 def flush(self):
314 315 """Flush data that is left in the buffer."""
315 316 for data in self.buffer:
316 317 self.output_width += data.output(self.output, self.output_width)
317 318 self.buffer.clear()
318 319 self.buffer_width = 0
319 320
320 321
321 322 def _get_mro(obj_class):
322 323 """ Get a reasonable method resolution order of a class and its superclasses
323 324 for both old-style and new-style classes.
324 325 """
325 326 if not hasattr(obj_class, '__mro__'):
326 327 # Old-style class. Mix in object to make a fake new-style class.
327 328 try:
328 329 obj_class = type(obj_class.__name__, (obj_class, object), {})
329 330 except TypeError:
330 331 # Old-style extension type that does not descend from object.
331 332 # FIXME: try to construct a more thorough MRO.
332 333 mro = [obj_class]
333 334 else:
334 335 mro = obj_class.__mro__[1:-1]
335 336 else:
336 337 mro = obj_class.__mro__
337 338 return mro
338 339
339 340
340 341 class RepresentationPrinter(PrettyPrinter):
341 342 """
342 343 Special pretty printer that has a `pretty` method that calls the pretty
343 344 printer for a python object.
344 345
345 346 This class stores processing data on `self` so you must *never* use
346 347 this class in a threaded environment. Always lock it or reinstanciate
347 348 it.
348 349
349 350 Instances also have a verbose flag callbacks can access to control their
350 351 output. For example the default instance repr prints all attributes and
351 352 methods that are not prefixed by an underscore if the printer is in
352 353 verbose mode.
353 354 """
354 355
355 356 def __init__(self, output, verbose=False, max_width=79, newline='\n',
356 357 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None,
357 358 max_seq_length=MAX_SEQ_LENGTH):
358 359
359 360 PrettyPrinter.__init__(self, output, max_width, newline, max_seq_length=max_seq_length)
360 361 self.verbose = verbose
361 362 self.stack = []
362 363 if singleton_pprinters is None:
363 364 singleton_pprinters = _singleton_pprinters.copy()
364 365 self.singleton_pprinters = singleton_pprinters
365 366 if type_pprinters is None:
366 367 type_pprinters = _type_pprinters.copy()
367 368 self.type_pprinters = type_pprinters
368 369 if deferred_pprinters is None:
369 370 deferred_pprinters = _deferred_type_pprinters.copy()
370 371 self.deferred_pprinters = deferred_pprinters
371 372
372 373 def pretty(self, obj):
373 374 """Pretty print the given object."""
374 375 obj_id = id(obj)
375 376 cycle = obj_id in self.stack
376 377 self.stack.append(obj_id)
377 378 self.begin_group()
378 379 try:
379 380 obj_class = _safe_getattr(obj, '__class__', None) or type(obj)
380 381 # First try to find registered singleton printers for the type.
381 382 try:
382 383 printer = self.singleton_pprinters[obj_id]
383 384 except (TypeError, KeyError):
384 385 pass
385 386 else:
386 387 return printer(obj, self, cycle)
387 388 # Next walk the mro and check for either:
388 389 # 1) a registered printer
389 390 # 2) a _repr_pretty_ method
390 391 for cls in _get_mro(obj_class):
391 392 if cls in self.type_pprinters:
392 393 # printer registered in self.type_pprinters
393 394 return self.type_pprinters[cls](obj, self, cycle)
394 395 else:
395 396 # deferred printer
396 397 printer = self._in_deferred_types(cls)
397 398 if printer is not None:
398 399 return printer(obj, self, cycle)
399 400 else:
400 401 # Finally look for special method names.
401 402 # Some objects automatically create any requested
402 403 # attribute. Try to ignore most of them by checking for
403 404 # callability.
404 405 if '_repr_pretty_' in cls.__dict__:
405 406 meth = cls._repr_pretty_
406 407 if callable(meth):
407 408 return meth(obj, self, cycle)
408 409 if cls is not object \
409 410 and callable(cls.__dict__.get('__repr__')):
410 411 return _repr_pprint(obj, self, cycle)
411 412
412 413 return _default_pprint(obj, self, cycle)
413 414 finally:
414 415 self.end_group()
415 416 self.stack.pop()
416 417
417 418 def _in_deferred_types(self, cls):
418 419 """
419 420 Check if the given class is specified in the deferred type registry.
420 421
421 422 Returns the printer from the registry if it exists, and None if the
422 423 class is not in the registry. Successful matches will be moved to the
423 424 regular type registry for future use.
424 425 """
425 426 mod = _safe_getattr(cls, '__module__', None)
426 427 name = _safe_getattr(cls, '__name__', None)
427 428 key = (mod, name)
428 429 printer = None
429 430 if key in self.deferred_pprinters:
430 431 # Move the printer over to the regular registry.
431 432 printer = self.deferred_pprinters.pop(key)
432 433 self.type_pprinters[cls] = printer
433 434 return printer
434 435
435 436
436 437 class Printable(object):
437 438
438 439 def output(self, stream, output_width):
439 440 return output_width
440 441
441 442
442 443 class Text(Printable):
443 444
444 445 def __init__(self):
445 446 self.objs = []
446 447 self.width = 0
447 448
448 449 def output(self, stream, output_width):
449 450 for obj in self.objs:
450 451 stream.write(obj)
451 452 return output_width + self.width
452 453
453 454 def add(self, obj, width):
454 455 self.objs.append(obj)
455 456 self.width += width
456 457
457 458
458 459 class Breakable(Printable):
459 460
460 461 def __init__(self, seq, width, pretty):
461 462 self.obj = seq
462 463 self.width = width
463 464 self.pretty = pretty
464 465 self.indentation = pretty.indentation
465 466 self.group = pretty.group_stack[-1]
466 467 self.group.breakables.append(self)
467 468
468 469 def output(self, stream, output_width):
469 470 self.group.breakables.popleft()
470 471 if self.group.want_break:
471 472 stream.write(self.pretty.newline)
472 473 stream.write(' ' * self.indentation)
473 474 return self.indentation
474 475 if not self.group.breakables:
475 476 self.pretty.group_queue.remove(self.group)
476 477 stream.write(self.obj)
477 478 return output_width + self.width
478 479
479 480
480 481 class Group(Printable):
481 482
482 483 def __init__(self, depth):
483 484 self.depth = depth
484 485 self.breakables = deque()
485 486 self.want_break = False
486 487
487 488
488 489 class GroupQueue(object):
489 490
490 491 def __init__(self, *groups):
491 492 self.queue = []
492 493 for group in groups:
493 494 self.enq(group)
494 495
495 496 def enq(self, group):
496 497 depth = group.depth
497 498 while depth > len(self.queue) - 1:
498 499 self.queue.append([])
499 500 self.queue[depth].append(group)
500 501
501 502 def deq(self):
502 503 for stack in self.queue:
503 504 for idx, group in enumerate(reversed(stack)):
504 505 if group.breakables:
505 506 del stack[idx]
506 507 group.want_break = True
507 508 return group
508 509 for group in stack:
509 510 group.want_break = True
510 511 del stack[:]
511 512
512 513 def remove(self, group):
513 514 try:
514 515 self.queue[group.depth].remove(group)
515 516 except ValueError:
516 517 pass
517 518
518 519
519 520 class RawText:
520 521 """ Object such that ``p.pretty(RawText(value))`` is the same as ``p.text(value)``.
521 522
522 523 An example usage of this would be to show a list as binary numbers, using
523 524 ``p.pretty([RawText(bin(i)) for i in integers])``.
524 525 """
525 526 def __init__(self, value):
526 527 self.value = value
527 528
528 529 def _repr_pretty_(self, p, cycle):
529 530 p.text(self.value)
530 531
531 532
532 533 class CallExpression:
533 534 """ Object which emits a line-wrapped call expression in the form `__name(*args, **kwargs)` """
534 535 def __init__(__self, __name, *args, **kwargs):
535 536 # dunders are to avoid clashes with kwargs, as python's name manging
536 537 # will kick in.
537 538 self = __self
538 539 self.name = __name
539 540 self.args = args
540 541 self.kwargs = kwargs
541 542
542 543 @classmethod
543 544 def factory(cls, name):
544 545 def inner(*args, **kwargs):
545 546 return cls(name, *args, **kwargs)
546 547 return inner
547 548
548 549 def _repr_pretty_(self, p, cycle):
549 550 # dunders are to avoid clashes with kwargs, as python's name manging
550 551 # will kick in.
551 552
552 553 started = False
553 554 def new_item():
554 555 nonlocal started
555 556 if started:
556 557 p.text(",")
557 558 p.breakable()
558 559 started = True
559 560
560 561 prefix = self.name + "("
561 562 with p.group(len(prefix), prefix, ")"):
562 563 for arg in self.args:
563 564 new_item()
564 565 p.pretty(arg)
565 566 for arg_name, arg in self.kwargs.items():
566 567 new_item()
567 568 arg_prefix = arg_name + "="
568 569 with p.group(len(arg_prefix), arg_prefix):
569 570 p.pretty(arg)
570 571
571 572
572 573 class RawStringLiteral:
573 574 """ Wrapper that shows a string with a `r` prefix """
574 575 def __init__(self, value):
575 576 self.value = value
576 577
577 578 def _repr_pretty_(self, p, cycle):
578 579 base_repr = repr(self.value)
579 580 if base_repr[:1] in 'uU':
580 581 base_repr = base_repr[1:]
581 582 prefix = 'ur'
582 583 else:
583 584 prefix = 'r'
584 585 base_repr = prefix + base_repr.replace('\\\\', '\\')
585 586 p.text(base_repr)
586 587
587 588
588 589 def _default_pprint(obj, p, cycle):
589 590 """
590 591 The default print function. Used if an object does not provide one and
591 592 it's none of the builtin objects.
592 593 """
593 594 klass = _safe_getattr(obj, '__class__', None) or type(obj)
594 595 if _safe_getattr(klass, '__repr__', None) is not object.__repr__:
595 596 # A user-provided repr. Find newlines and replace them with p.break_()
596 597 _repr_pprint(obj, p, cycle)
597 598 return
598 599 p.begin_group(1, '<')
599 600 p.pretty(klass)
600 601 p.text(' at 0x%x' % id(obj))
601 602 if cycle:
602 603 p.text(' ...')
603 604 elif p.verbose:
604 605 first = True
605 606 for key in dir(obj):
606 607 if not key.startswith('_'):
607 608 try:
608 609 value = getattr(obj, key)
609 610 except AttributeError:
610 611 continue
611 612 if isinstance(value, types.MethodType):
612 613 continue
613 614 if not first:
614 615 p.text(',')
615 616 p.breakable()
616 617 p.text(key)
617 618 p.text('=')
618 619 step = len(key) + 1
619 620 p.indentation += step
620 621 p.pretty(value)
621 622 p.indentation -= step
622 623 first = False
623 624 p.end_group(1, '>')
624 625
625 626
626 627 def _seq_pprinter_factory(start, end):
627 628 """
628 629 Factory that returns a pprint function useful for sequences. Used by
629 630 the default pprint for tuples and lists.
630 631 """
631 632 def inner(obj, p, cycle):
632 633 if cycle:
633 634 return p.text(start + '...' + end)
634 635 step = len(start)
635 636 p.begin_group(step, start)
636 637 for idx, x in p._enumerate(obj):
637 638 if idx:
638 639 p.text(',')
639 640 p.breakable()
640 641 p.pretty(x)
641 642 if len(obj) == 1 and isinstance(obj, tuple):
642 643 # Special case for 1-item tuples.
643 644 p.text(',')
644 645 p.end_group(step, end)
645 646 return inner
646 647
647 648
648 649 def _set_pprinter_factory(start, end):
649 650 """
650 651 Factory that returns a pprint function useful for sets and frozensets.
651 652 """
652 653 def inner(obj, p, cycle):
653 654 if cycle:
654 655 return p.text(start + '...' + end)
655 656 if len(obj) == 0:
656 657 # Special case.
657 658 p.text(type(obj).__name__ + '()')
658 659 else:
659 660 step = len(start)
660 661 p.begin_group(step, start)
661 662 # Like dictionary keys, we will try to sort the items if there aren't too many
662 663 if not (p.max_seq_length and len(obj) >= p.max_seq_length):
663 664 items = _sorted_for_pprint(obj)
664 665 else:
665 666 items = obj
666 667 for idx, x in p._enumerate(items):
667 668 if idx:
668 669 p.text(',')
669 670 p.breakable()
670 671 p.pretty(x)
671 672 p.end_group(step, end)
672 673 return inner
673 674
674 675
675 676 def _dict_pprinter_factory(start, end):
676 677 """
677 678 Factory that returns a pprint function used by the default pprint of
678 679 dicts and dict proxies.
679 680 """
680 681 def inner(obj, p, cycle):
681 682 if cycle:
682 683 return p.text('{...}')
683 684 step = len(start)
684 685 p.begin_group(step, start)
685 686 keys = obj.keys()
686 687 for idx, key in p._enumerate(keys):
687 688 if idx:
688 689 p.text(',')
689 690 p.breakable()
690 691 p.pretty(key)
691 692 p.text(': ')
692 693 p.pretty(obj[key])
693 694 p.end_group(step, end)
694 695 return inner
695 696
696 697
697 698 def _super_pprint(obj, p, cycle):
698 699 """The pprint for the super type."""
699 700 p.begin_group(8, '<super: ')
700 701 p.pretty(obj.__thisclass__)
701 702 p.text(',')
702 703 p.breakable()
703 704 if PYPY: # In PyPy, super() objects don't have __self__ attributes
704 705 dself = obj.__repr__.__self__
705 706 p.pretty(None if dself is obj else dself)
706 707 else:
707 708 p.pretty(obj.__self__)
708 709 p.end_group(8, '>')
709 710
710 711
711 712
712 713 class _ReFlags:
713 714 def __init__(self, value):
714 715 self.value = value
715 716
716 717 def _repr_pretty_(self, p, cycle):
717 718 done_one = False
718 719 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
719 720 'UNICODE', 'VERBOSE', 'DEBUG'):
720 721 if self.value & getattr(re, flag):
721 722 if done_one:
722 723 p.text('|')
723 724 p.text('re.' + flag)
724 725 done_one = True
725 726
726 727
727 728 def _re_pattern_pprint(obj, p, cycle):
728 729 """The pprint function for regular expression patterns."""
729 730 re_compile = CallExpression.factory('re.compile')
730 731 if obj.flags:
731 732 p.pretty(re_compile(RawStringLiteral(obj.pattern), _ReFlags(obj.flags)))
732 733 else:
733 734 p.pretty(re_compile(RawStringLiteral(obj.pattern)))
734 735
735 736
736 737 def _types_simplenamespace_pprint(obj, p, cycle):
737 738 """The pprint function for types.SimpleNamespace."""
738 739 namespace = CallExpression.factory('namespace')
739 740 if cycle:
740 741 p.pretty(namespace(RawText("...")))
741 742 else:
742 743 p.pretty(namespace(**obj.__dict__))
743 744
744 745
745 746 def _type_pprint(obj, p, cycle):
746 747 """The pprint for classes and types."""
747 748 # Heap allocated types might not have the module attribute,
748 749 # and others may set it to None.
749 750
750 751 # Checks for a __repr__ override in the metaclass. Can't compare the
751 752 # type(obj).__repr__ directly because in PyPy the representation function
752 753 # inherited from type isn't the same type.__repr__
753 754 if [m for m in _get_mro(type(obj)) if "__repr__" in vars(m)][:1] != [type]:
754 755 _repr_pprint(obj, p, cycle)
755 756 return
756 757
757 758 mod = _safe_getattr(obj, '__module__', None)
758 759 try:
759 760 name = obj.__qualname__
760 761 if not isinstance(name, str):
761 762 # This can happen if the type implements __qualname__ as a property
762 763 # or other descriptor in Python 2.
763 764 raise Exception("Try __name__")
764 765 except Exception:
765 766 name = obj.__name__
766 767 if not isinstance(name, str):
767 768 name = '<unknown type>'
768 769
769 770 if mod in (None, '__builtin__', 'builtins', 'exceptions'):
770 771 p.text(name)
771 772 else:
772 773 p.text(mod + '.' + name)
773 774
774 775
775 776 def _repr_pprint(obj, p, cycle):
776 777 """A pprint that just redirects to the normal repr function."""
777 778 # Find newlines and replace them with p.break_()
778 779 output = repr(obj)
779 780 lines = output.splitlines()
780 781 with p.group():
781 782 for idx, output_line in enumerate(lines):
782 783 if idx:
783 784 p.break_()
784 785 p.text(output_line)
785 786
786 787
787 788 def _function_pprint(obj, p, cycle):
788 789 """Base pprint for all functions and builtin functions."""
789 790 name = _safe_getattr(obj, '__qualname__', obj.__name__)
790 791 mod = obj.__module__
791 792 if mod and mod not in ('__builtin__', 'builtins', 'exceptions'):
792 793 name = mod + '.' + name
793 794 try:
794 795 func_def = name + str(signature(obj))
795 796 except ValueError:
796 797 func_def = name
797 798 p.text('<function %s>' % func_def)
798 799
799 800
800 801 def _exception_pprint(obj, p, cycle):
801 802 """Base pprint for all exceptions."""
802 803 name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__)
803 804 if obj.__class__.__module__ not in ('exceptions', 'builtins'):
804 805 name = '%s.%s' % (obj.__class__.__module__, name)
805 806
806 807 p.pretty(CallExpression(name, *getattr(obj, 'args', ())))
807 808
808 809
809 810 #: the exception base
811 _exception_base: type
810 812 try:
811 813 _exception_base = BaseException
812 814 except NameError:
813 815 _exception_base = Exception
814 816
815 817
816 818 #: printers for builtin types
817 819 _type_pprinters = {
818 820 int: _repr_pprint,
819 821 float: _repr_pprint,
820 822 str: _repr_pprint,
821 823 tuple: _seq_pprinter_factory('(', ')'),
822 824 list: _seq_pprinter_factory('[', ']'),
823 825 dict: _dict_pprinter_factory('{', '}'),
824 826 set: _set_pprinter_factory('{', '}'),
825 827 frozenset: _set_pprinter_factory('frozenset({', '})'),
826 828 super: _super_pprint,
827 829 _re_pattern_type: _re_pattern_pprint,
828 830 type: _type_pprint,
829 831 types.FunctionType: _function_pprint,
830 832 types.BuiltinFunctionType: _function_pprint,
831 833 types.MethodType: _repr_pprint,
832 834 types.SimpleNamespace: _types_simplenamespace_pprint,
833 835 datetime.datetime: _repr_pprint,
834 836 datetime.timedelta: _repr_pprint,
835 837 _exception_base: _exception_pprint
836 838 }
837 839
838 840 # render os.environ like a dict
839 841 _env_type = type(os.environ)
840 842 # future-proof in case os.environ becomes a plain dict?
841 843 if _env_type is not dict:
842 844 _type_pprinters[_env_type] = _dict_pprinter_factory('environ{', '}')
843 845
844 846 _type_pprinters[types.MappingProxyType] = _dict_pprinter_factory("mappingproxy({", "})")
845 847 _type_pprinters[slice] = _repr_pprint
846 848
847 849 _type_pprinters[range] = _repr_pprint
848 850 _type_pprinters[bytes] = _repr_pprint
849 851
850 852 #: printers for types specified by name
851 _deferred_type_pprinters = {
852 }
853 _deferred_type_pprinters: Dict = {}
854
853 855
854 856 def for_type(typ, func):
855 857 """
856 858 Add a pretty printer for a given type.
857 859 """
858 860 oldfunc = _type_pprinters.get(typ, None)
859 861 if func is not None:
860 862 # To support easy restoration of old pprinters, we need to ignore Nones.
861 863 _type_pprinters[typ] = func
862 864 return oldfunc
863 865
864 866 def for_type_by_name(type_module, type_name, func):
865 867 """
866 868 Add a pretty printer for a type specified by the module and name of a type
867 869 rather than the type object itself.
868 870 """
869 871 key = (type_module, type_name)
870 872 oldfunc = _deferred_type_pprinters.get(key, None)
871 873 if func is not None:
872 874 # To support easy restoration of old pprinters, we need to ignore Nones.
873 875 _deferred_type_pprinters[key] = func
874 876 return oldfunc
875 877
876 878
877 879 #: printers for the default singletons
878 880 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
879 881 NotImplemented]), _repr_pprint)
880 882
881 883
882 884 def _defaultdict_pprint(obj, p, cycle):
883 885 cls_ctor = CallExpression.factory(obj.__class__.__name__)
884 886 if cycle:
885 887 p.pretty(cls_ctor(RawText("...")))
886 888 else:
887 889 p.pretty(cls_ctor(obj.default_factory, dict(obj)))
888 890
889 891 def _ordereddict_pprint(obj, p, cycle):
890 892 cls_ctor = CallExpression.factory(obj.__class__.__name__)
891 893 if cycle:
892 894 p.pretty(cls_ctor(RawText("...")))
893 895 elif len(obj):
894 896 p.pretty(cls_ctor(list(obj.items())))
895 897 else:
896 898 p.pretty(cls_ctor())
897 899
898 900 def _deque_pprint(obj, p, cycle):
899 901 cls_ctor = CallExpression.factory(obj.__class__.__name__)
900 902 if cycle:
901 903 p.pretty(cls_ctor(RawText("...")))
902 904 elif obj.maxlen is not None:
903 905 p.pretty(cls_ctor(list(obj), maxlen=obj.maxlen))
904 906 else:
905 907 p.pretty(cls_ctor(list(obj)))
906 908
907 909 def _counter_pprint(obj, p, cycle):
908 910 cls_ctor = CallExpression.factory(obj.__class__.__name__)
909 911 if cycle:
910 912 p.pretty(cls_ctor(RawText("...")))
911 913 elif len(obj):
912 914 p.pretty(cls_ctor(dict(obj.most_common())))
913 915 else:
914 916 p.pretty(cls_ctor())
915 917
916 918
917 919 def _userlist_pprint(obj, p, cycle):
918 920 cls_ctor = CallExpression.factory(obj.__class__.__name__)
919 921 if cycle:
920 922 p.pretty(cls_ctor(RawText("...")))
921 923 else:
922 924 p.pretty(cls_ctor(obj.data))
923 925
924 926
925 927 for_type_by_name('collections', 'defaultdict', _defaultdict_pprint)
926 928 for_type_by_name('collections', 'OrderedDict', _ordereddict_pprint)
927 929 for_type_by_name('collections', 'deque', _deque_pprint)
928 930 for_type_by_name('collections', 'Counter', _counter_pprint)
929 931 for_type_by_name("collections", "UserList", _userlist_pprint)
930 932
931 933 if __name__ == '__main__':
932 934 from random import randrange
933 935 class Foo(object):
934 936 def __init__(self):
935 937 self.foo = 1
936 938 self.bar = re.compile(r'\s+')
937 939 self.blub = dict.fromkeys(range(30), randrange(1, 40))
938 940 self.hehe = 23424.234234
939 941 self.list = ["blub", "blah", self]
940 942
941 943 def get_foo(self):
942 944 print("foo")
943 945
944 946 pprint(Foo(), verbose=True)
@@ -1,84 +1,78 b''
1 1 [build-system]
2 2 requires = ["setuptools >= 51.0.0"]
3 3 # We need access to the 'setupbase' module at build time.
4 4 # Hence we declare a custom build backend.
5 5 build-backend = "_build_meta" # just re-exports setuptools.build_meta definitions
6 6 backend-path = ["."]
7 7
8 8 [tool.mypy]
9 9 python_version = "3.10"
10 10 ignore_missing_imports = true
11 11 follow_imports = 'silent'
12 12 exclude = [
13 13 'test_\.+\.py',
14 14 'IPython.utils.tests.test_wildcard',
15 15 'testing',
16 16 'tests',
17 17 'PyColorize.py',
18 18 '_process_win32_controller.py',
19 19 'IPython/core/application.py',
20 'IPython/core/completerlib.py',
21 'IPython/core/displaypub.py',
22 #'IPython/core/interactiveshell.py',
23 'IPython/core/magic.py',
24 20 'IPython/core/profileapp.py',
25 # 'IPython/core/ultratb.py',
26 21 'IPython/lib/deepreload.py',
27 'IPython/lib/pretty.py',
28 22 'IPython/sphinxext/ipython_directive.py',
29 23 'IPython/terminal/ipapp.py',
30 24 'IPython/utils/_process_win32.py',
31 25 'IPython/utils/path.py',
32 26 ]
33 27
34 28 [tool.pytest.ini_options]
35 29 addopts = [
36 30 "--durations=10",
37 31 "-pIPython.testing.plugin.pytest_ipdoctest",
38 32 "--ipdoctest-modules",
39 33 "--ignore=docs",
40 34 "--ignore=examples",
41 35 "--ignore=htmlcov",
42 36 "--ignore=ipython_kernel",
43 37 "--ignore=ipython_parallel",
44 38 "--ignore=results",
45 39 "--ignore=tmp",
46 40 "--ignore=tools",
47 41 "--ignore=traitlets",
48 42 "--ignore=IPython/core/tests/daft_extension",
49 43 "--ignore=IPython/sphinxext",
50 44 "--ignore=IPython/terminal/pt_inputhooks",
51 45 "--ignore=IPython/__main__.py",
52 46 "--ignore=IPython/external/qt_for_kernel.py",
53 47 "--ignore=IPython/html/widgets/widget_link.py",
54 48 "--ignore=IPython/html/widgets/widget_output.py",
55 49 "--ignore=IPython/terminal/console.py",
56 50 "--ignore=IPython/utils/_process_cli.py",
57 51 "--ignore=IPython/utils/_process_posix.py",
58 52 "--ignore=IPython/utils/_process_win32.py",
59 53 "--ignore=IPython/utils/_process_win32_controller.py",
60 54 "--ignore=IPython/utils/daemonize.py",
61 55 "--ignore=IPython/utils/eventful.py",
62 56 "--ignore=IPython/kernel",
63 57 "--ignore=IPython/consoleapp.py",
64 58 "--ignore=IPython/core/inputsplitter.py",
65 59 "--ignore=IPython/lib/kernel.py",
66 60 "--ignore=IPython/utils/jsonutil.py",
67 61 "--ignore=IPython/utils/localinterfaces.py",
68 62 "--ignore=IPython/utils/log.py",
69 63 "--ignore=IPython/utils/signatures.py",
70 64 "--ignore=IPython/utils/traitlets.py",
71 65 "--ignore=IPython/utils/version.py"
72 66 ]
73 67 doctest_optionflags = [
74 68 "NORMALIZE_WHITESPACE",
75 69 "ELLIPSIS"
76 70 ]
77 71 ipdoctest_optionflags = [
78 72 "NORMALIZE_WHITESPACE",
79 73 "ELLIPSIS"
80 74 ]
81 75 asyncio_mode = "strict"
82 76
83 77 [tool.pyright]
84 78 pythonPlatform="All"
General Comments 0
You need to be logged in to leave comments. Login now