ZhengyangZhang commited on
Commit
a239196
·
verified ·
1 Parent(s): 9832690

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.12/site-packages/IPython/core/magics/__init__.py +42 -0
  2. lib/python3.12/site-packages/IPython/core/magics/__pycache__/__init__.cpython-312.pyc +0 -0
  3. lib/python3.12/site-packages/IPython/core/magics/__pycache__/ast_mod.cpython-312.pyc +0 -0
  4. lib/python3.12/site-packages/IPython/core/magics/__pycache__/auto.cpython-312.pyc +0 -0
  5. lib/python3.12/site-packages/IPython/core/magics/__pycache__/basic.cpython-312.pyc +0 -0
  6. lib/python3.12/site-packages/IPython/core/magics/__pycache__/code.cpython-312.pyc +0 -0
  7. lib/python3.12/site-packages/IPython/core/magics/__pycache__/config.cpython-312.pyc +0 -0
  8. lib/python3.12/site-packages/IPython/core/magics/__pycache__/display.cpython-312.pyc +0 -0
  9. lib/python3.12/site-packages/IPython/core/magics/__pycache__/execution.cpython-312.pyc +0 -0
  10. lib/python3.12/site-packages/IPython/core/magics/__pycache__/extension.cpython-312.pyc +0 -0
  11. lib/python3.12/site-packages/IPython/core/magics/__pycache__/history.cpython-312.pyc +0 -0
  12. lib/python3.12/site-packages/IPython/core/magics/__pycache__/logging.cpython-312.pyc +0 -0
  13. lib/python3.12/site-packages/IPython/core/magics/__pycache__/namespace.cpython-312.pyc +0 -0
  14. lib/python3.12/site-packages/IPython/core/magics/__pycache__/osm.cpython-312.pyc +0 -0
  15. lib/python3.12/site-packages/IPython/core/magics/__pycache__/packaging.cpython-312.pyc +0 -0
  16. lib/python3.12/site-packages/IPython/core/magics/__pycache__/pylab.cpython-312.pyc +0 -0
  17. lib/python3.12/site-packages/IPython/core/magics/__pycache__/script.cpython-312.pyc +0 -0
  18. lib/python3.12/site-packages/IPython/core/magics/ast_mod.py +330 -0
  19. lib/python3.12/site-packages/IPython/core/magics/auto.py +144 -0
  20. lib/python3.12/site-packages/IPython/core/magics/config.py +140 -0
  21. lib/python3.12/site-packages/IPython/core/magics/display.py +93 -0
  22. lib/python3.12/site-packages/IPython/core/magics/execution.py +1707 -0
  23. lib/python3.12/site-packages/IPython/core/magics/history.py +361 -0
  24. lib/python3.12/site-packages/IPython/core/magics/namespace.py +723 -0
  25. lib/python3.12/site-packages/IPython/core/magics/osm.py +855 -0
  26. lib/python3.12/site-packages/IPython/core/magics/packaging.py +181 -0
  27. lib/python3.12/site-packages/IPython/core/magics/pylab.py +173 -0
  28. lib/python3.12/site-packages/IPython/external/__init__.py +7 -0
  29. lib/python3.12/site-packages/IPython/external/__pycache__/__init__.cpython-312.pyc +0 -0
  30. lib/python3.12/site-packages/IPython/external/__pycache__/pickleshare.cpython-312.pyc +0 -0
  31. lib/python3.12/site-packages/IPython/external/__pycache__/qt_for_kernel.cpython-312.pyc +0 -0
  32. lib/python3.12/site-packages/IPython/external/__pycache__/qt_loaders.cpython-312.pyc +0 -0
  33. lib/python3.12/site-packages/IPython/external/pickleshare.py +303 -0
  34. lib/python3.12/site-packages/IPython/external/qt_for_kernel.py +124 -0
  35. lib/python3.12/site-packages/IPython/external/qt_loaders.py +423 -0
  36. lib/python3.12/site-packages/IPython/utils/PyColorize.py +577 -0
  37. lib/python3.12/site-packages/IPython/utils/__init__.py +0 -0
  38. lib/python3.12/site-packages/IPython/utils/__pycache__/PyColorize.cpython-312.pyc +0 -0
  39. lib/python3.12/site-packages/IPython/utils/__pycache__/_process_cli.cpython-312.pyc +0 -0
  40. lib/python3.12/site-packages/IPython/utils/__pycache__/_process_common.cpython-312.pyc +0 -0
  41. lib/python3.12/site-packages/IPython/utils/__pycache__/_process_emscripten.cpython-312.pyc +0 -0
  42. lib/python3.12/site-packages/IPython/utils/__pycache__/_process_posix.cpython-312.pyc +0 -0
  43. lib/python3.12/site-packages/IPython/utils/__pycache__/_process_win32.cpython-312.pyc +0 -0
  44. lib/python3.12/site-packages/IPython/utils/__pycache__/_process_win32_controller.cpython-312.pyc +0 -0
  45. lib/python3.12/site-packages/IPython/utils/__pycache__/_sysinfo.cpython-312.pyc +0 -0
  46. lib/python3.12/site-packages/IPython/utils/__pycache__/coloransi.cpython-312.pyc +0 -0
  47. lib/python3.12/site-packages/IPython/utils/__pycache__/contexts.cpython-312.pyc +0 -0
  48. lib/python3.12/site-packages/IPython/utils/__pycache__/data.cpython-312.pyc +0 -0
  49. lib/python3.12/site-packages/IPython/utils/__pycache__/docs.cpython-312.pyc +0 -0
  50. lib/python3.12/site-packages/IPython/utils/__pycache__/eventful.cpython-312.pyc +0 -0
lib/python3.12/site-packages/IPython/core/magics/__init__.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of all the magic functions built into IPython.
2
+ """
3
+ #-----------------------------------------------------------------------------
4
+ # Copyright (c) 2012 The IPython Development Team.
5
+ #
6
+ # Distributed under the terms of the Modified BSD License.
7
+ #
8
+ # The full license is in the file COPYING.txt, distributed with this software.
9
+ #-----------------------------------------------------------------------------
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Imports
13
+ #-----------------------------------------------------------------------------
14
+
15
+ from ..magic import Magics, magics_class
16
+ from .auto import AutoMagics
17
+ from .basic import BasicMagics, AsyncMagics
18
+ from .code import CodeMagics, MacroToEdit
19
+ from .config import ConfigMagics
20
+ from .display import DisplayMagics
21
+ from .execution import ExecutionMagics
22
+ from .extension import ExtensionMagics
23
+ from .history import HistoryMagics
24
+ from .logging import LoggingMagics
25
+ from .namespace import NamespaceMagics
26
+ from .osm import OSMagics
27
+ from .packaging import PackagingMagics
28
+ from .pylab import PylabMagics
29
+ from .script import ScriptMagics
30
+
31
+ #-----------------------------------------------------------------------------
32
+ # Magic implementation classes
33
+ #-----------------------------------------------------------------------------
34
+
35
+ @magics_class
36
+ class UserMagics(Magics):
37
+ """Placeholder for user-defined magics to be added at runtime.
38
+
39
+ All magics are eventually merged into a single namespace at runtime, but we
40
+ use this class to isolate the magics defined dynamically by the user into
41
+ their own class.
42
+ """
lib/python3.12/site-packages/IPython/core/magics/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (1.48 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/ast_mod.cpython-312.pyc ADDED
Binary file (13.2 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/auto.cpython-312.pyc ADDED
Binary file (5.39 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/basic.cpython-312.pyc ADDED
Binary file (31.7 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/code.cpython-312.pyc ADDED
Binary file (29.1 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/config.cpython-312.pyc ADDED
Binary file (5.09 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/display.cpython-312.pyc ADDED
Binary file (3.68 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/execution.cpython-312.pyc ADDED
Binary file (67.6 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/extension.cpython-312.pyc ADDED
Binary file (2.61 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/history.cpython-312.pyc ADDED
Binary file (13.8 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/logging.cpython-312.pyc ADDED
Binary file (7.07 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/namespace.cpython-312.pyc ADDED
Binary file (26.7 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/osm.cpython-312.pyc ADDED
Binary file (36.2 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/packaging.cpython-312.pyc ADDED
Binary file (6.97 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/pylab.cpython-312.pyc ADDED
Binary file (6.95 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/__pycache__/script.cpython-312.pyc ADDED
Binary file (18.1 kB). View file
 
lib/python3.12/site-packages/IPython/core/magics/ast_mod.py ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ This module contains utility function and classes to inject simple ast
3
+ transformations based on code strings into IPython. While it is already possible
4
+ with ast-transformers it is not easy to directly manipulate ast.
5
+
6
+
7
+ IPython has pre-code and post-code hooks, but are ran from within the IPython
8
+ machinery so may be inappropriate, for example for performance measurement.
9
+
10
+ This module give you tools to simplify this, and expose 2 classes:
11
+
12
+ - `ReplaceCodeTransformer` which is a simple ast transformer based on code
13
+ template,
14
+
15
+ and for advance case:
16
+
17
+ - `Mangler` which is a simple ast transformer that mangle names in the ast.
18
+
19
+
20
+ Example, let's try to make a simple version of the ``timeit`` magic, that run a
21
+ code snippet 10 times and print the average time taken.
22
+
23
+ Basically we want to run :
24
+
25
+ .. code-block:: python
26
+
27
+ from time import perf_counter
28
+ now = perf_counter()
29
+ for i in range(10):
30
+ __code__ # our code
31
+ print(f"Time taken: {(perf_counter() - now)/10}")
32
+ __ret__ # the result of the last statement
33
+
34
+ Where ``__code__`` is the code snippet we want to run, and ``__ret__`` is the
35
+ result, so that if we for example run `dataframe.head()` IPython still display
36
+ the head of dataframe instead of nothing.
37
+
38
+ Here is a complete example of a file `timit2.py` that define such a magic:
39
+
40
+ .. code-block:: python
41
+
42
+ from IPython.core.magic import (
43
+ Magics,
44
+ magics_class,
45
+ line_cell_magic,
46
+ )
47
+ from IPython.core.magics.ast_mod import ReplaceCodeTransformer
48
+ from textwrap import dedent
49
+ import ast
50
+
51
+ template = template = dedent('''
52
+ from time import perf_counter
53
+ now = perf_counter()
54
+ for i in range(10):
55
+ __code__
56
+ print(f"Time taken: {(perf_counter() - now)/10}")
57
+ __ret__
58
+ '''
59
+ )
60
+
61
+
62
+ @magics_class
63
+ class AstM(Magics):
64
+ @line_cell_magic
65
+ def t2(self, line, cell):
66
+ transformer = ReplaceCodeTransformer.from_string(template)
67
+ transformer.debug = True
68
+ transformer.mangler.debug = True
69
+ new_code = transformer.visit(ast.parse(cell))
70
+ return exec(compile(new_code, "<ast>", "exec"))
71
+
72
+
73
+ def load_ipython_extension(ip):
74
+ ip.register_magics(AstM)
75
+
76
+
77
+
78
+ .. code-block:: python
79
+
80
+ In [1]: %load_ext timit2
81
+
82
+ In [2]: %%t2
83
+ ...: import time
84
+ ...: time.sleep(0.05)
85
+ ...:
86
+ ...:
87
+ Time taken: 0.05435649999999441
88
+
89
+
90
+ If you wish to ran all the code enter in IPython in an ast transformer, you can
91
+ do so as well:
92
+
93
+ .. code-block:: python
94
+
95
+ In [1]: from IPython.core.magics.ast_mod import ReplaceCodeTransformer
96
+ ...:
97
+ ...: template = '''
98
+ ...: from time import perf_counter
99
+ ...: now = perf_counter()
100
+ ...: __code__
101
+ ...: print(f"Code ran in {perf_counter()-now}")
102
+ ...: __ret__'''
103
+ ...:
104
+ ...: get_ipython().ast_transformers.append(ReplaceCodeTransformer.from_string(template))
105
+
106
+ In [2]: 1+1
107
+ Code ran in 3.40410006174352e-05
108
+ Out[2]: 2
109
+
110
+
111
+
112
+ Hygiene and Mangling
113
+ --------------------
114
+
115
+ The ast transformer above is not hygienic, it may not work if the user code use
116
+ the same variable names as the ones used in the template. For example.
117
+
118
+ To help with this by default the `ReplaceCodeTransformer` will mangle all names
119
+ staring with 3 underscores. This is a simple heuristic that should work in most
120
+ case, but can be cumbersome in some case. We provide a `Mangler` class that can
121
+ be overridden to change the mangling heuristic, or simply use the `mangle_all`
122
+ utility function. It will _try_ to mangle all names (except `__ret__` and
123
+ `__code__`), but this include builtins (``print``, ``range``, ``type``) and
124
+ replace those by invalid identifiers py prepending ``mangle-``:
125
+ ``mangle-print``, ``mangle-range``, ``mangle-type`` etc. This is not a problem
126
+ as currently Python AST support invalid identifiers, but it may not be the case
127
+ in the future.
128
+
129
+ You can set `ReplaceCodeTransformer.debug=True` and
130
+ `ReplaceCodeTransformer.mangler.debug=True` to see the code after mangling and
131
+ transforming:
132
+
133
+ .. code-block:: python
134
+
135
+
136
+ In [1]: from IPython.core.magics.ast_mod import ReplaceCodeTransformer, mangle_all
137
+ ...:
138
+ ...: template = '''
139
+ ...: from builtins import type, print
140
+ ...: from time import perf_counter
141
+ ...: now = perf_counter()
142
+ ...: __code__
143
+ ...: print(f"Code ran in {perf_counter()-now}")
144
+ ...: __ret__'''
145
+ ...:
146
+ ...: transformer = ReplaceCodeTransformer.from_string(template, mangling_predicate=mangle_all)
147
+
148
+
149
+ In [2]: transformer.debug = True
150
+ ...: transformer.mangler.debug = True
151
+ ...: get_ipython().ast_transformers.append(transformer)
152
+
153
+ In [3]: 1+1
154
+ Mangling Alias mangle-type
155
+ Mangling Alias mangle-print
156
+ Mangling Alias mangle-perf_counter
157
+ Mangling now
158
+ Mangling perf_counter
159
+ Not mangling __code__
160
+ Mangling print
161
+ Mangling perf_counter
162
+ Mangling now
163
+ Not mangling __ret__
164
+ ---- Transformed code ----
165
+ from builtins import type as mangle-type, print as mangle-print
166
+ from time import perf_counter as mangle-perf_counter
167
+ mangle-now = mangle-perf_counter()
168
+ ret-tmp = 1 + 1
169
+ mangle-print(f'Code ran in {mangle-perf_counter() - mangle-now}')
170
+ ret-tmp
171
+ ---- ---------------- ----
172
+ Code ran in 0.00013654199938173406
173
+ Out[3]: 2
174
+
175
+
176
+ """
177
+
178
+ __skip_doctest__ = True
179
+
180
+
181
+ from ast import (
182
+ NodeTransformer,
183
+ Store,
184
+ Load,
185
+ Name,
186
+ Expr,
187
+ Assign,
188
+ Module,
189
+ Import,
190
+ ImportFrom,
191
+ )
192
+ import ast
193
+ import copy
194
+
195
+ from typing import Dict, Optional, Union
196
+
197
+
198
+ mangle_all = lambda name: False if name in ("__ret__", "__code__") else True
199
+
200
+
201
+ class Mangler(NodeTransformer):
202
+ """
203
+ Mangle given names in and ast tree to make sure they do not conflict with
204
+ user code.
205
+ """
206
+
207
+ enabled: bool = True
208
+ debug: bool = False
209
+
210
+ def log(self, *args, **kwargs):
211
+ if self.debug:
212
+ print(*args, **kwargs)
213
+
214
+ def __init__(self, predicate=None):
215
+ if predicate is None:
216
+ predicate = lambda name: name.startswith("___")
217
+ self.predicate = predicate
218
+
219
+ def visit_Name(self, node):
220
+ if self.predicate(node.id):
221
+ self.log("Mangling", node.id)
222
+ # Once in the ast we do not need
223
+ # names to be valid identifiers.
224
+ node.id = "mangle-" + node.id
225
+ else:
226
+ self.log("Not mangling", node.id)
227
+ return node
228
+
229
+ def visit_FunctionDef(self, node):
230
+ if self.predicate(node.name):
231
+ self.log("Mangling", node.name)
232
+ node.name = "mangle-" + node.name
233
+ else:
234
+ self.log("Not mangling", node.name)
235
+
236
+ for arg in node.args.args:
237
+ if self.predicate(arg.arg):
238
+ self.log("Mangling function arg", arg.arg)
239
+ arg.arg = "mangle-" + arg.arg
240
+ else:
241
+ self.log("Not mangling function arg", arg.arg)
242
+ return self.generic_visit(node)
243
+
244
+ def visit_ImportFrom(self, node: ImportFrom):
245
+ return self._visit_Import_and_ImportFrom(node)
246
+
247
+ def visit_Import(self, node: Import):
248
+ return self._visit_Import_and_ImportFrom(node)
249
+
250
+ def _visit_Import_and_ImportFrom(self, node: Union[Import, ImportFrom]):
251
+ for alias in node.names:
252
+ asname = alias.name if alias.asname is None else alias.asname
253
+ if self.predicate(asname):
254
+ new_name: str = "mangle-" + asname
255
+ self.log("Mangling Alias", new_name)
256
+ alias.asname = new_name
257
+ else:
258
+ self.log("Not mangling Alias", alias.asname)
259
+ return node
260
+
261
+
262
+ class ReplaceCodeTransformer(NodeTransformer):
263
+ enabled: bool = True
264
+ debug: bool = False
265
+ mangler: Mangler
266
+
267
+ def __init__(
268
+ self, template: Module, mapping: Optional[Dict] = None, mangling_predicate=None
269
+ ):
270
+ assert isinstance(mapping, (dict, type(None)))
271
+ assert isinstance(mangling_predicate, (type(None), type(lambda: None)))
272
+ assert isinstance(template, ast.Module)
273
+ self.template = template
274
+ self.mangler = Mangler(predicate=mangling_predicate)
275
+ if mapping is None:
276
+ mapping = {}
277
+ self.mapping = mapping
278
+
279
+ @classmethod
280
+ def from_string(
281
+ cls, template: str, mapping: Optional[Dict] = None, mangling_predicate=None
282
+ ):
283
+ return cls(
284
+ ast.parse(template), mapping=mapping, mangling_predicate=mangling_predicate
285
+ )
286
+
287
+ def visit_Module(self, code):
288
+ if not self.enabled:
289
+ return code
290
+ # if not isinstance(code, ast.Module):
291
+ # recursively called...
292
+ # return generic_visit(self, code)
293
+ last = code.body[-1]
294
+ if isinstance(last, Expr):
295
+ code.body.pop()
296
+ code.body.append(Assign([Name("ret-tmp", ctx=Store())], value=last.value))
297
+ ast.fix_missing_locations(code)
298
+ ret = Expr(value=Name("ret-tmp", ctx=Load()))
299
+ ret = ast.fix_missing_locations(ret)
300
+ self.mapping["__ret__"] = ret
301
+ else:
302
+ self.mapping["__ret__"] = ast.parse("None").body[0]
303
+ self.mapping["__code__"] = code.body
304
+ tpl = ast.fix_missing_locations(self.template)
305
+
306
+ tx = copy.deepcopy(tpl)
307
+ tx = self.mangler.visit(tx)
308
+ node = self.generic_visit(tx)
309
+ node_2 = ast.fix_missing_locations(node)
310
+ if self.debug:
311
+ print("---- Transformed code ----")
312
+ print(ast.unparse(node_2))
313
+ print("---- ---------------- ----")
314
+ return node_2
315
+
316
+ # this does not work as the name might be in a list and one might want to extend the list.
317
+ # def visit_Name(self, name):
318
+ # if name.id in self.mapping and name.id == "__ret__":
319
+ # print(name, "in mapping")
320
+ # if isinstance(name.ctx, ast.Store):
321
+ # return Name("tmp", ctx=Store())
322
+ # else:
323
+ # return copy.deepcopy(self.mapping[name.id])
324
+ # return name
325
+
326
+ def visit_Expr(self, expr):
327
+ if isinstance(expr.value, Name) and expr.value.id in self.mapping:
328
+ if self.mapping[expr.value.id] is not None:
329
+ return copy.deepcopy(self.mapping[expr.value.id])
330
+ return self.generic_visit(expr)
lib/python3.12/site-packages/IPython/core/magics/auto.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of magic functions that control various automatic behaviors.
2
+ """
3
+ #-----------------------------------------------------------------------------
4
+ # Copyright (c) 2012 The IPython Development Team.
5
+ #
6
+ # Distributed under the terms of the Modified BSD License.
7
+ #
8
+ # The full license is in the file COPYING.txt, distributed with this software.
9
+ #-----------------------------------------------------------------------------
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Imports
13
+ #-----------------------------------------------------------------------------
14
+
15
+ # Our own packages
16
+ from IPython.core.magic import Bunch, Magics, magics_class, line_magic
17
+ from IPython.testing.skipdoctest import skip_doctest
18
+ from logging import error
19
+
20
+ #-----------------------------------------------------------------------------
21
+ # Magic implementation classes
22
+ #-----------------------------------------------------------------------------
23
+
24
+ @magics_class
25
+ class AutoMagics(Magics):
26
+ """Magics that control various autoX behaviors."""
27
+
28
+ def __init__(self, shell):
29
+ super(AutoMagics, self).__init__(shell)
30
+ # namespace for holding state we may need
31
+ self._magic_state = Bunch()
32
+
33
+ @line_magic
34
+ def automagic(self, parameter_s=''):
35
+ """Make magic functions callable without having to type the initial %.
36
+
37
+ Without arguments toggles on/off (when off, you must call it as
38
+ %automagic, of course). With arguments it sets the value, and you can
39
+ use any of (case insensitive):
40
+
41
+ - on, 1, True: to activate
42
+
43
+ - off, 0, False: to deactivate.
44
+
45
+ Note that magic functions have lowest priority, so if there's a
46
+ variable whose name collides with that of a magic fn, automagic won't
47
+ work for that function (you get the variable instead). However, if you
48
+ delete the variable (del var), the previously shadowed magic function
49
+ becomes visible to automagic again."""
50
+
51
+ arg = parameter_s.lower()
52
+ mman = self.shell.magics_manager
53
+ if arg in ('on', '1', 'true'):
54
+ val = True
55
+ elif arg in ('off', '0', 'false'):
56
+ val = False
57
+ else:
58
+ val = not mman.auto_magic
59
+ mman.auto_magic = val
60
+ print('\n' + self.shell.magics_manager.auto_status())
61
+
62
+ @skip_doctest
63
+ @line_magic
64
+ def autocall(self, parameter_s=''):
65
+ """Make functions callable without having to type parentheses.
66
+
67
+ Usage:
68
+
69
+ %autocall [mode]
70
+
71
+ The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the
72
+ value is toggled on and off (remembering the previous state).
73
+
74
+ In more detail, these values mean:
75
+
76
+ 0 -> fully disabled
77
+
78
+ 1 -> active, but do not apply if there are no arguments on the line.
79
+
80
+ In this mode, you get::
81
+
82
+ In [1]: callable
83
+ Out[1]: <built-in function callable>
84
+
85
+ In [2]: callable 'hello'
86
+ ------> callable('hello')
87
+ Out[2]: False
88
+
89
+ 2 -> Active always. Even if no arguments are present, the callable
90
+ object is called::
91
+
92
+ In [2]: float
93
+ ------> float()
94
+ Out[2]: 0.0
95
+
96
+ Note that even with autocall off, you can still use '/' at the start of
97
+ a line to treat the first argument on the command line as a function
98
+ and add parentheses to it::
99
+
100
+ In [8]: /str 43
101
+ ------> str(43)
102
+ Out[8]: '43'
103
+
104
+ # all-random (note for auto-testing)
105
+ """
106
+
107
+ valid_modes = {
108
+ 0: "Off",
109
+ 1: "Smart",
110
+ 2: "Full",
111
+ }
112
+
113
+ def errorMessage() -> str:
114
+ error = "Valid modes: "
115
+ for k, v in valid_modes.items():
116
+ error += str(k) + "->" + v + ", "
117
+ error = error[:-2] # remove tailing `, ` after last element
118
+ return error
119
+
120
+ if parameter_s:
121
+ if parameter_s not in map(str, valid_modes.keys()):
122
+ error(errorMessage())
123
+ return
124
+ arg = int(parameter_s)
125
+ else:
126
+ arg = 'toggle'
127
+
128
+ if arg not in (*list(valid_modes.keys()), "toggle"):
129
+ error(errorMessage())
130
+ return
131
+
132
+ if arg in (valid_modes.keys()):
133
+ self.shell.autocall = arg
134
+ else: # toggle
135
+ if self.shell.autocall:
136
+ self._magic_state.autocall_save = self.shell.autocall
137
+ self.shell.autocall = 0
138
+ else:
139
+ try:
140
+ self.shell.autocall = self._magic_state.autocall_save
141
+ except AttributeError:
142
+ self.shell.autocall = self._magic_state.autocall_save = 1
143
+
144
+ print("Automatic calling is:", list(valid_modes.values())[self.shell.autocall])
lib/python3.12/site-packages/IPython/core/magics/config.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of configuration-related magic functions.
2
+ """
3
+ #-----------------------------------------------------------------------------
4
+ # Copyright (c) 2012 The IPython Development Team.
5
+ #
6
+ # Distributed under the terms of the Modified BSD License.
7
+ #
8
+ # The full license is in the file COPYING.txt, distributed with this software.
9
+ #-----------------------------------------------------------------------------
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Imports
13
+ #-----------------------------------------------------------------------------
14
+
15
+ # Stdlib
16
+ import re
17
+
18
+ # Our own packages
19
+ from IPython.core.error import UsageError
20
+ from IPython.core.magic import Magics, magics_class, line_magic
21
+ from logging import error
22
+
23
+ #-----------------------------------------------------------------------------
24
+ # Magic implementation classes
25
+ #-----------------------------------------------------------------------------
26
+
27
+ reg = re.compile(r'^\w+\.\w+$')
28
+ @magics_class
29
+ class ConfigMagics(Magics):
30
+
31
+ def __init__(self, shell):
32
+ super(ConfigMagics, self).__init__(shell)
33
+ self.configurables = []
34
+
35
+ @line_magic
36
+ def config(self, s):
37
+ """configure IPython
38
+
39
+ %config Class[.trait=value]
40
+
41
+ This magic exposes most of the IPython config system. Any
42
+ Configurable class should be able to be configured with the simple
43
+ line::
44
+
45
+ %config Class.trait=value
46
+
47
+ Where `value` will be resolved in the user's namespace, if it is an
48
+ expression or variable name.
49
+
50
+ Examples
51
+ --------
52
+
53
+ To see what classes are available for config, pass no arguments::
54
+
55
+ In [1]: %config
56
+ Available objects for config:
57
+ AliasManager
58
+ DisplayFormatter
59
+ HistoryManager
60
+ IPCompleter
61
+ LoggingMagics
62
+ MagicsManager
63
+ OSMagics
64
+ PrefilterManager
65
+ ScriptMagics
66
+ TerminalInteractiveShell
67
+
68
+ To view what is configurable on a given class, just pass the class
69
+ name::
70
+
71
+ In [2]: %config LoggingMagics
72
+ LoggingMagics(Magics) options
73
+ ---------------------------
74
+ LoggingMagics.quiet=<Bool>
75
+ Suppress output of log state when logging is enabled
76
+ Current: False
77
+
78
+ but the real use is in setting values::
79
+
80
+ In [3]: %config LoggingMagics.quiet = True
81
+
82
+ and these values are read from the user_ns if they are variables::
83
+
84
+ In [4]: feeling_quiet=False
85
+
86
+ In [5]: %config LoggingMagics.quiet = feeling_quiet
87
+
88
+ """
89
+ from traitlets.config.loader import Config
90
+ # some IPython objects are Configurable, but do not yet have
91
+ # any configurable traits. Exclude them from the effects of
92
+ # this magic, as their presence is just noise:
93
+ configurables = sorted(set([ c for c in self.shell.configurables
94
+ if c.__class__.class_traits(config=True)
95
+ ]), key=lambda x: x.__class__.__name__)
96
+ classnames = [ c.__class__.__name__ for c in configurables ]
97
+
98
+ line = s.strip()
99
+ if not line:
100
+ # print available configurable names
101
+ print("Available objects for config:")
102
+ for name in classnames:
103
+ print(" ", name)
104
+ return
105
+ elif line in classnames:
106
+ # `%config TerminalInteractiveShell` will print trait info for
107
+ # TerminalInteractiveShell
108
+ c = configurables[classnames.index(line)]
109
+ cls = c.__class__
110
+ help = cls.class_get_help(c)
111
+ # strip leading '--' from cl-args:
112
+ help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
113
+ print(help)
114
+ return
115
+ elif reg.match(line):
116
+ cls, attr = line.split('.')
117
+ return getattr(configurables[classnames.index(cls)],attr)
118
+ elif '=' not in line:
119
+ msg = "Invalid config statement: %r, "\
120
+ "should be `Class.trait = value`."
121
+
122
+ ll = line.lower()
123
+ for classname in classnames:
124
+ if ll == classname.lower():
125
+ msg = msg + '\nDid you mean %s (note the case)?' % classname
126
+ break
127
+
128
+ raise UsageError( msg % line)
129
+
130
+ # otherwise, assume we are setting configurables.
131
+ # leave quotes on args when splitting, because we want
132
+ # unquoted args to eval in user_ns
133
+ cfg = Config()
134
+ exec("cfg."+line, self.shell.user_ns, locals())
135
+
136
+ for configurable in configurables:
137
+ try:
138
+ configurable.update_config(cfg)
139
+ except Exception as e:
140
+ error(e)
lib/python3.12/site-packages/IPython/core/magics/display.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Simple magics for display formats"""
2
+ #-----------------------------------------------------------------------------
3
+ # Copyright (c) 2012 The IPython Development Team.
4
+ #
5
+ # Distributed under the terms of the Modified BSD License.
6
+ #
7
+ # The full license is in the file COPYING.txt, distributed with this software.
8
+ #-----------------------------------------------------------------------------
9
+
10
+ #-----------------------------------------------------------------------------
11
+ # Imports
12
+ #-----------------------------------------------------------------------------
13
+
14
+ # Our own packages
15
+ from IPython.display import display, Javascript, Latex, SVG, HTML, Markdown
16
+ from IPython.core.magic import (
17
+ Magics, magics_class, cell_magic
18
+ )
19
+ from IPython.core import magic_arguments
20
+
21
+ #-----------------------------------------------------------------------------
22
+ # Magic implementation classes
23
+ #-----------------------------------------------------------------------------
24
+
25
+
26
+ @magics_class
27
+ class DisplayMagics(Magics):
28
+ """Magics for displaying various output types with literals
29
+
30
+ Defines javascript/latex/svg/html cell magics for writing
31
+ blocks in those languages, to be rendered in the frontend.
32
+ """
33
+
34
+ @cell_magic
35
+ def js(self, line, cell):
36
+ """Run the cell block of Javascript code
37
+
38
+ Alias of `%%javascript`
39
+
40
+ Starting with IPython 8.0 %%javascript is pending deprecation to be replaced
41
+ by a more flexible system
42
+
43
+ Please See https://github.com/ipython/ipython/issues/13376
44
+ """
45
+ self.javascript(line, cell)
46
+
47
+ @cell_magic
48
+ def javascript(self, line, cell):
49
+ """Run the cell block of Javascript code
50
+
51
+ Starting with IPython 8.0 %%javascript is pending deprecation to be replaced
52
+ by a more flexible system
53
+
54
+ Please See https://github.com/ipython/ipython/issues/13376
55
+ """
56
+ display(Javascript(cell))
57
+
58
+
59
+ @cell_magic
60
+ def latex(self, line, cell):
61
+ """Render the cell as a block of LaTeX
62
+
63
+ The subset of LaTeX which is supported depends on the implementation in
64
+ the client. In the Jupyter Notebook, this magic only renders the subset
65
+ of LaTeX defined by MathJax
66
+ [here](https://docs.mathjax.org/en/v2.5-latest/tex.html)."""
67
+ display(Latex(cell))
68
+
69
+ @cell_magic
70
+ def svg(self, line, cell):
71
+ """Render the cell as an SVG literal"""
72
+ display(SVG(cell))
73
+
74
+ @magic_arguments.magic_arguments()
75
+ @magic_arguments.argument(
76
+ '--isolated', action='store_true', default=False,
77
+ help="""Annotate the cell as 'isolated'.
78
+ Isolated cells are rendered inside their own <iframe> tag"""
79
+ )
80
+ @cell_magic
81
+ def html(self, line, cell):
82
+ """Render the cell as a block of HTML"""
83
+ args = magic_arguments.parse_argstring(self.html, line)
84
+ html = HTML(cell)
85
+ if args.isolated:
86
+ display(html, metadata={'text/html':{'isolated':True}})
87
+ else:
88
+ display(html)
89
+
90
+ @cell_magic
91
+ def markdown(self, line, cell):
92
+ """Render the cell as Markdown text block"""
93
+ display(Markdown(cell))
lib/python3.12/site-packages/IPython/core/magics/execution.py ADDED
@@ -0,0 +1,1707 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """Implementation of execution-related magic functions."""
3
+
4
+ # Copyright (c) IPython Development Team.
5
+ # Distributed under the terms of the Modified BSD License.
6
+
7
+
8
+ import ast
9
+ import bdb
10
+ import builtins as builtin_mod
11
+ import copy
12
+ import cProfile as profile
13
+ import gc
14
+ import itertools
15
+ import math
16
+ import os
17
+ import pstats
18
+ import re
19
+ import shlex
20
+ import sys
21
+ import time
22
+ import timeit
23
+ import signal
24
+ from typing import Dict, Any
25
+ from ast import (
26
+ Assign,
27
+ Call,
28
+ Expr,
29
+ Load,
30
+ Module,
31
+ Name,
32
+ NodeTransformer,
33
+ Store,
34
+ parse,
35
+ unparse,
36
+ )
37
+ from io import StringIO
38
+ from logging import error
39
+ from pathlib import Path
40
+ from pdb import Restart
41
+ from textwrap import dedent, indent
42
+ from warnings import warn
43
+
44
+ from IPython.core import magic_arguments, oinspect, page
45
+ from IPython.core.displayhook import DisplayHook
46
+ from IPython.core.error import UsageError
47
+ from IPython.core.macro import Macro
48
+ from IPython.core.magic import (
49
+ Magics,
50
+ cell_magic,
51
+ line_cell_magic,
52
+ line_magic,
53
+ magics_class,
54
+ needs_local_scope,
55
+ no_var_expand,
56
+ on_off,
57
+ output_can_be_silenced,
58
+ )
59
+ from IPython.testing.skipdoctest import skip_doctest
60
+ from IPython.utils.capture import capture_output
61
+ from IPython.utils.contexts import preserve_keys
62
+ from IPython.utils.ipstruct import Struct
63
+ from IPython.utils.module_paths import find_mod
64
+ from IPython.utils.path import get_py_filename, shellglob
65
+ from IPython.utils.timing import clock, clock2
66
+ from IPython.core.magics.ast_mod import ReplaceCodeTransformer
67
+
68
+ #-----------------------------------------------------------------------------
69
+ # Magic implementation classes
70
+ #-----------------------------------------------------------------------------
71
+
72
+
73
+ class TimeitResult:
74
+ """
75
+ Object returned by the timeit magic with info about the run.
76
+
77
+ Contains the following attributes:
78
+
79
+ loops: int
80
+ number of loops done per measurement
81
+
82
+ repeat: int
83
+ number of times the measurement was repeated
84
+
85
+ best: float
86
+ best execution time / number
87
+
88
+ all_runs : list[float]
89
+ execution time of each run (in s)
90
+
91
+ compile_time: float
92
+ time of statement compilation (s)
93
+
94
+ """
95
+ def __init__(self, loops, repeat, best, worst, all_runs, compile_time, precision):
96
+ self.loops = loops
97
+ self.repeat = repeat
98
+ self.best = best
99
+ self.worst = worst
100
+ self.all_runs = all_runs
101
+ self.compile_time = compile_time
102
+ self._precision = precision
103
+ self.timings = [dt / self.loops for dt in all_runs]
104
+
105
+ @property
106
+ def average(self):
107
+ return math.fsum(self.timings) / len(self.timings)
108
+
109
+ @property
110
+ def stdev(self):
111
+ mean = self.average
112
+ return (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5
113
+
114
+ def __str__(self):
115
+ pm = '+-'
116
+ if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
117
+ try:
118
+ "\xb1".encode(sys.stdout.encoding)
119
+ pm = "\xb1"
120
+ except:
121
+ pass
122
+ return "{mean} {pm} {std} per loop (mean {pm} std. dev. of {runs} run{run_plural}, {loops:,} loop{loop_plural} each)".format(
123
+ pm=pm,
124
+ runs=self.repeat,
125
+ loops=self.loops,
126
+ loop_plural="" if self.loops == 1 else "s",
127
+ run_plural="" if self.repeat == 1 else "s",
128
+ mean=_format_time(self.average, self._precision),
129
+ std=_format_time(self.stdev, self._precision),
130
+ )
131
+
132
+ def _repr_pretty_(self, p , cycle):
133
+ unic = self.__str__()
134
+ p.text("<TimeitResult : " + unic + ">")
135
+
136
+
137
+ class TimeitTemplateFiller(ast.NodeTransformer):
138
+ """Fill in the AST template for timing execution.
139
+
140
+ This is quite closely tied to the template definition, which is in
141
+ :meth:`ExecutionMagics.timeit`.
142
+ """
143
+ def __init__(self, ast_setup, ast_stmt):
144
+ self.ast_setup = ast_setup
145
+ self.ast_stmt = ast_stmt
146
+
147
+ def visit_FunctionDef(self, node):
148
+ "Fill in the setup statement"
149
+ self.generic_visit(node)
150
+ if node.name == "inner":
151
+ node.body[:1] = self.ast_setup.body
152
+
153
+ return node
154
+
155
+ def visit_For(self, node):
156
+ "Fill in the statement to be timed"
157
+ if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
158
+ node.body = self.ast_stmt.body
159
+ return node
160
+
161
+
162
+ class Timer(timeit.Timer):
163
+ """Timer class that explicitly uses self.inner
164
+
165
+ which is an undocumented implementation detail of CPython,
166
+ not shared by PyPy.
167
+ """
168
+
169
+ # Timer.timeit copied from CPython 3.4.2
170
+ def timeit(self, number=timeit.default_number):
171
+ """Time 'number' executions of the main statement.
172
+
173
+ To be precise, this executes the setup statement once, and
174
+ then returns the time it takes to execute the main statement
175
+ a number of times, as a float measured in seconds. The
176
+ argument is the number of times through the loop, defaulting
177
+ to one million. The main statement, the setup statement and
178
+ the timer function to be used are passed to the constructor.
179
+ """
180
+ it = itertools.repeat(None, number)
181
+ gcold = gc.isenabled()
182
+ gc.disable()
183
+ try:
184
+ timing = self.inner(it, self.timer)
185
+ finally:
186
+ if gcold:
187
+ gc.enable()
188
+ return timing
189
+
190
+
191
+ @magics_class
192
+ class ExecutionMagics(Magics):
193
+ """Magics related to code execution, debugging, profiling, etc."""
194
+
195
+ _transformers: Dict[str, Any] = {}
196
+
197
+ def __init__(self, shell):
198
+ super(ExecutionMagics, self).__init__(shell)
199
+ # Default execution function used to actually run user code.
200
+ self.default_runner = None
201
+
202
+ @skip_doctest
203
+ @no_var_expand
204
+ @line_cell_magic
205
+ def prun(self, parameter_s='', cell=None):
206
+ """Run a statement through the python code profiler.
207
+
208
+ **Usage, in line mode**::
209
+
210
+ %prun [options] statement
211
+
212
+ **Usage, in cell mode**::
213
+
214
+ %%prun [options] [statement]
215
+ code...
216
+ code...
217
+
218
+ In cell mode, the additional code lines are appended to the (possibly
219
+ empty) statement in the first line. Cell mode allows you to easily
220
+ profile multiline blocks without having to put them in a separate
221
+ function.
222
+
223
+ The given statement (which doesn't require quote marks) is run via the
224
+ python profiler in a manner similar to the profile.run() function.
225
+ Namespaces are internally managed to work correctly; profile.run
226
+ cannot be used in IPython because it makes certain assumptions about
227
+ namespaces which do not hold under IPython.
228
+
229
+ Options:
230
+
231
+ -l <limit>
232
+ you can place restrictions on what or how much of the
233
+ profile gets printed. The limit value can be:
234
+
235
+ * A string: only information for function names containing this string
236
+ is printed.
237
+
238
+ * An integer: only these many lines are printed.
239
+
240
+ * A float (between 0 and 1): this fraction of the report is printed
241
+ (for example, use a limit of 0.4 to see the topmost 40% only).
242
+
243
+ You can combine several limits with repeated use of the option. For
244
+ example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
245
+ information about class constructors.
246
+
247
+ -r
248
+ return the pstats.Stats object generated by the profiling. This
249
+ object has all the information about the profile in it, and you can
250
+ later use it for further analysis or in other functions.
251
+
252
+ -s <key>
253
+ sort profile by given key. You can provide more than one key
254
+ by using the option several times: '-s key1 -s key2 -s key3...'. The
255
+ default sorting key is 'time'.
256
+
257
+ The following is copied verbatim from the profile documentation
258
+ referenced below:
259
+
260
+ When more than one key is provided, additional keys are used as
261
+ secondary criteria when the there is equality in all keys selected
262
+ before them.
263
+
264
+ Abbreviations can be used for any key names, as long as the
265
+ abbreviation is unambiguous. The following are the keys currently
266
+ defined:
267
+
268
+ ============ =====================
269
+ Valid Arg Meaning
270
+ ============ =====================
271
+ "calls" call count
272
+ "cumulative" cumulative time
273
+ "file" file name
274
+ "module" file name
275
+ "pcalls" primitive call count
276
+ "line" line number
277
+ "name" function name
278
+ "nfl" name/file/line
279
+ "stdname" standard name
280
+ "time" internal time
281
+ ============ =====================
282
+
283
+ Note that all sorts on statistics are in descending order (placing
284
+ most time consuming items first), where as name, file, and line number
285
+ searches are in ascending order (i.e., alphabetical). The subtle
286
+ distinction between "nfl" and "stdname" is that the standard name is a
287
+ sort of the name as printed, which means that the embedded line
288
+ numbers get compared in an odd way. For example, lines 3, 20, and 40
289
+ would (if the file names were the same) appear in the string order
290
+ "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
291
+ line numbers. In fact, sort_stats("nfl") is the same as
292
+ sort_stats("name", "file", "line").
293
+
294
+ -T <filename>
295
+ save profile results as shown on screen to a text
296
+ file. The profile is still shown on screen.
297
+
298
+ -D <filename>
299
+ save (via dump_stats) profile statistics to given
300
+ filename. This data is in a format understood by the pstats module, and
301
+ is generated by a call to the dump_stats() method of profile
302
+ objects. The profile is still shown on screen.
303
+
304
+ -q
305
+ suppress output to the pager. Best used with -T and/or -D above.
306
+
307
+ If you want to run complete programs under the profiler's control, use
308
+ ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
309
+ contains profiler specific options as described here.
310
+
311
+ You can read the complete documentation for the profile module with::
312
+
313
+ In [1]: import profile; profile.help()
314
+
315
+ .. versionchanged:: 7.3
316
+ User variables are no longer expanded,
317
+ the magic line is always left unmodified.
318
+
319
+ """
320
+ # TODO: port to magic_arguments as currently this is duplicated in IPCompleter._extract_code
321
+ opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
322
+ list_all=True, posix=False)
323
+ if cell is not None:
324
+ arg_str += '\n' + cell
325
+ arg_str = self.shell.transform_cell(arg_str)
326
+ return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
327
+
328
+ def _run_with_profiler(self, code, opts, namespace):
329
+ """
330
+ Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
331
+
332
+ Parameters
333
+ ----------
334
+ code : str
335
+ Code to be executed.
336
+ opts : Struct
337
+ Options parsed by `self.parse_options`.
338
+ namespace : dict
339
+ A dictionary for Python namespace (e.g., `self.shell.user_ns`).
340
+
341
+ """
342
+
343
+ # Fill default values for unspecified options:
344
+ opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
345
+
346
+ prof = profile.Profile()
347
+ try:
348
+ prof = prof.runctx(code, namespace, namespace)
349
+ sys_exit = ''
350
+ except SystemExit:
351
+ sys_exit = """*** SystemExit exception caught in code being profiled."""
352
+
353
+ stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
354
+
355
+ lims = opts.l
356
+ if lims:
357
+ lims = [] # rebuild lims with ints/floats/strings
358
+ for lim in opts.l:
359
+ try:
360
+ lims.append(int(lim))
361
+ except ValueError:
362
+ try:
363
+ lims.append(float(lim))
364
+ except ValueError:
365
+ lims.append(lim)
366
+
367
+ # Trap output.
368
+ stdout_trap = StringIO()
369
+ stats_stream = stats.stream
370
+ try:
371
+ stats.stream = stdout_trap
372
+ stats.print_stats(*lims)
373
+ finally:
374
+ stats.stream = stats_stream
375
+
376
+ output = stdout_trap.getvalue()
377
+ output = output.rstrip()
378
+
379
+ if 'q' not in opts:
380
+ page.page(output)
381
+ print(sys_exit, end=' ')
382
+
383
+ dump_file = opts.D[0]
384
+ text_file = opts.T[0]
385
+ if dump_file:
386
+ prof.dump_stats(dump_file)
387
+ print(
388
+ f"\n*** Profile stats marshalled to file {repr(dump_file)}.{sys_exit}"
389
+ )
390
+ if text_file:
391
+ pfile = Path(text_file)
392
+ pfile.touch(exist_ok=True)
393
+ pfile.write_text(output, encoding="utf-8")
394
+
395
+ print(
396
+ f"\n*** Profile printout saved to text file {repr(text_file)}.{sys_exit}"
397
+ )
398
+
399
+ if 'r' in opts:
400
+ return stats
401
+
402
+ return None
403
+
404
+ @line_magic
405
+ def pdb(self, parameter_s=''):
406
+ """Control the automatic calling of the pdb interactive debugger.
407
+
408
+ Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
409
+ argument it works as a toggle.
410
+
411
+ When an exception is triggered, IPython can optionally call the
412
+ interactive pdb debugger after the traceback printout. %pdb toggles
413
+ this feature on and off.
414
+
415
+ The initial state of this feature is set in your configuration
416
+ file (the option is ``InteractiveShell.pdb``).
417
+
418
+ If you want to just activate the debugger AFTER an exception has fired,
419
+ without having to type '%pdb on' and rerunning your code, you can use
420
+ the %debug magic."""
421
+
422
+ par = parameter_s.strip().lower()
423
+
424
+ if par:
425
+ try:
426
+ new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
427
+ except KeyError:
428
+ print ('Incorrect argument. Use on/1, off/0, '
429
+ 'or nothing for a toggle.')
430
+ return
431
+ else:
432
+ # toggle
433
+ new_pdb = not self.shell.call_pdb
434
+
435
+ # set on the shell
436
+ self.shell.call_pdb = new_pdb
437
+ print('Automatic pdb calling has been turned',on_off(new_pdb))
438
+
439
+ @magic_arguments.magic_arguments()
440
+ @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
441
+ help="""
442
+ Set break point at LINE in FILE.
443
+ """
444
+ )
445
+ @magic_arguments.kwds(
446
+ epilog="""
447
+ Any remaining arguments will be treated as code to run in the debugger.
448
+ """
449
+ )
450
+ @no_var_expand
451
+ @line_cell_magic
452
+ @needs_local_scope
453
+ def debug(self, line="", cell=None, local_ns=None):
454
+ """Activate the interactive debugger.
455
+
456
+ This magic command support two ways of activating debugger.
457
+ One is to activate debugger before executing code. This way, you
458
+ can set a break point, to step through the code from the point.
459
+ You can use this mode by giving statements to execute and optionally
460
+ a breakpoint.
461
+
462
+ The other one is to activate debugger in post-mortem mode. You can
463
+ activate this mode simply running %debug without any argument.
464
+ If an exception has just occurred, this lets you inspect its stack
465
+ frames interactively. Note that this will always work only on the last
466
+ traceback that occurred, so you must call this quickly after an
467
+ exception that you wish to inspect has fired, because if another one
468
+ occurs, it clobbers the previous one.
469
+
470
+ If you want IPython to automatically do this on every exception, see
471
+ the %pdb magic for more details.
472
+
473
+ .. versionchanged:: 7.3
474
+ When running code, user variables are no longer expanded,
475
+ the magic line is always left unmodified.
476
+
477
+ """
478
+ args, extra = magic_arguments.parse_argstring(self.debug, line, partial=True)
479
+
480
+ if not (args.breakpoint or extra or cell):
481
+ self._debug_post_mortem()
482
+ elif not (args.breakpoint or cell):
483
+ # If there is no breakpoints, the line is just code to execute
484
+ self._debug_exec(line, None, local_ns)
485
+ else:
486
+ # Here we try to reconstruct the code from the output of
487
+ # parse_argstring. This might not work if the code has spaces
488
+ # For example this fails for `print("a b")`
489
+ code = " ".join(extra)
490
+ if cell:
491
+ code += "\n" + cell
492
+ self._debug_exec(code, args.breakpoint, local_ns)
493
+
494
+ def _debug_post_mortem(self):
495
+ self.shell.debugger(force=True)
496
+
497
+ def _debug_exec(self, code, breakpoint, local_ns=None):
498
+ if breakpoint:
499
+ (filename, bp_line) = breakpoint.rsplit(':', 1)
500
+ bp_line = int(bp_line)
501
+ else:
502
+ (filename, bp_line) = (None, None)
503
+ self._run_with_debugger(
504
+ code, self.shell.user_ns, filename, bp_line, local_ns=local_ns
505
+ )
506
+
507
+ @line_magic
508
+ def tb(self, s):
509
+ """Print the last traceback.
510
+
511
+ Optionally, specify an exception reporting mode, tuning the
512
+ verbosity of the traceback. By default the currently-active exception
513
+ mode is used. See %xmode for changing exception reporting modes.
514
+
515
+ Valid modes: Plain, Context, Verbose, and Minimal.
516
+ """
517
+ interactive_tb = self.shell.InteractiveTB
518
+ if s:
519
+ # Switch exception reporting mode for this one call.
520
+ # Ensure it is switched back.
521
+ def xmode_switch_err(name):
522
+ warn('Error changing %s exception modes.\n%s' %
523
+ (name,sys.exc_info()[1]))
524
+
525
+ new_mode = s.strip().capitalize()
526
+ original_mode = interactive_tb.mode
527
+ try:
528
+ try:
529
+ interactive_tb.set_mode(mode=new_mode)
530
+ except Exception:
531
+ xmode_switch_err('user')
532
+ else:
533
+ self.shell.showtraceback()
534
+ finally:
535
+ interactive_tb.set_mode(mode=original_mode)
536
+ else:
537
+ self.shell.showtraceback()
538
+
539
+ @skip_doctest
540
+ @line_magic
541
+ def run(self, parameter_s='', runner=None,
542
+ file_finder=get_py_filename):
543
+ """Run the named file inside IPython as a program.
544
+
545
+ Usage::
546
+
547
+ %run [-n -i -e -G]
548
+ [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
549
+ ( -m mod | filename ) [args]
550
+
551
+ The filename argument should be either a pure Python script (with
552
+ extension ``.py``), or a file with custom IPython syntax (such as
553
+ magics). If the latter, the file can be either a script with ``.ipy``
554
+ extension, or a Jupyter notebook with ``.ipynb`` extension. When running
555
+ a Jupyter notebook, the output from print statements and other
556
+ displayed objects will appear in the terminal (even matplotlib figures
557
+ will open, if a terminal-compliant backend is being used). Note that,
558
+ at the system command line, the ``jupyter run`` command offers similar
559
+ functionality for executing notebooks (albeit currently with some
560
+ differences in supported options).
561
+
562
+ Parameters after the filename are passed as command-line arguments to
563
+ the program (put in sys.argv). Then, control returns to IPython's
564
+ prompt.
565
+
566
+ This is similar to running at a system prompt ``python file args``,
567
+ but with the advantage of giving you IPython's tracebacks, and of
568
+ loading all variables into your interactive namespace for further use
569
+ (unless -p is used, see below).
570
+
571
+ The file is executed in a namespace initially consisting only of
572
+ ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
573
+ sees its environment as if it were being run as a stand-alone program
574
+ (except for sharing global objects such as previously imported
575
+ modules). But after execution, the IPython interactive namespace gets
576
+ updated with all variables defined in the program (except for ``__name__``
577
+ and ``sys.argv``). This allows for very convenient loading of code for
578
+ interactive work, while giving each program a 'clean sheet' to run in.
579
+
580
+ Arguments are expanded using shell-like glob match. Patterns
581
+ '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
582
+ tilde '~' will be expanded into user's home directory. Unlike
583
+ real shells, quotation does not suppress expansions. Use
584
+ *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
585
+ To completely disable these expansions, you can use -G flag.
586
+
587
+ On Windows systems, the use of single quotes `'` when specifying
588
+ a file is not supported. Use double quotes `"`.
589
+
590
+ Options:
591
+
592
+ -n
593
+ __name__ is NOT set to '__main__', but to the running file's name
594
+ without extension (as python does under import). This allows running
595
+ scripts and reloading the definitions in them without calling code
596
+ protected by an ``if __name__ == "__main__"`` clause.
597
+
598
+ -i
599
+ run the file in IPython's namespace instead of an empty one. This
600
+ is useful if you are experimenting with code written in a text editor
601
+ which depends on variables defined interactively.
602
+
603
+ -e
604
+ ignore sys.exit() calls or SystemExit exceptions in the script
605
+ being run. This is particularly useful if IPython is being used to
606
+ run unittests, which always exit with a sys.exit() call. In such
607
+ cases you are interested in the output of the test results, not in
608
+ seeing a traceback of the unittest module.
609
+
610
+ -t
611
+ print timing information at the end of the run. IPython will give
612
+ you an estimated CPU time consumption for your script, which under
613
+ Unix uses the resource module to avoid the wraparound problems of
614
+ time.clock(). Under Unix, an estimate of time spent on system tasks
615
+ is also given (for Windows platforms this is reported as 0.0).
616
+
617
+ If -t is given, an additional ``-N<N>`` option can be given, where <N>
618
+ must be an integer indicating how many times you want the script to
619
+ run. The final timing report will include total and per run results.
620
+
621
+ For example (testing the script myscript.py)::
622
+
623
+ In [1]: run -t myscript
624
+
625
+ IPython CPU timings (estimated):
626
+ User : 0.19597 s.
627
+ System: 0.0 s.
628
+
629
+ In [2]: run -t -N5 myscript
630
+
631
+ IPython CPU timings (estimated):
632
+ Total runs performed: 5
633
+ Times : Total Per run
634
+ User : 0.910862 s, 0.1821724 s.
635
+ System: 0.0 s, 0.0 s.
636
+
637
+ -d
638
+ run your program under the control of pdb, the Python debugger.
639
+ This allows you to execute your program step by step, watch variables,
640
+ etc. Internally, what IPython does is similar to calling::
641
+
642
+ pdb.run('execfile("YOURFILENAME")')
643
+
644
+ with a breakpoint set on line 1 of your file. You can change the line
645
+ number for this automatic breakpoint to be <N> by using the -bN option
646
+ (where N must be an integer). For example::
647
+
648
+ %run -d -b40 myscript
649
+
650
+ will set the first breakpoint at line 40 in myscript.py. Note that
651
+ the first breakpoint must be set on a line which actually does
652
+ something (not a comment or docstring) for it to stop execution.
653
+
654
+ Or you can specify a breakpoint in a different file::
655
+
656
+ %run -d -b myotherfile.py:20 myscript
657
+
658
+ When the pdb debugger starts, you will see a (Pdb) prompt. You must
659
+ first enter 'c' (without quotes) to start execution up to the first
660
+ breakpoint.
661
+
662
+ Entering 'help' gives information about the use of the debugger. You
663
+ can easily see pdb's full documentation with "import pdb;pdb.help()"
664
+ at a prompt.
665
+
666
+ -p
667
+ run program under the control of the Python profiler module (which
668
+ prints a detailed report of execution times, function calls, etc).
669
+
670
+ You can pass other options after -p which affect the behavior of the
671
+ profiler itself. See the docs for %prun for details.
672
+
673
+ In this mode, the program's variables do NOT propagate back to the
674
+ IPython interactive namespace (because they remain in the namespace
675
+ where the profiler executes them).
676
+
677
+ Internally this triggers a call to %prun, see its documentation for
678
+ details on the options available specifically for profiling.
679
+
680
+ There is one special usage for which the text above doesn't apply:
681
+ if the filename ends with .ipy[nb], the file is run as ipython script,
682
+ just as if the commands were written on IPython prompt.
683
+
684
+ -m
685
+ specify module name to load instead of script path. Similar to
686
+ the -m option for the python interpreter. Use this option last if you
687
+ want to combine with other %run options. Unlike the python interpreter
688
+ only source modules are allowed no .pyc or .pyo files.
689
+ For example::
690
+
691
+ %run -m example
692
+
693
+ will run the example module.
694
+
695
+ -G
696
+ disable shell-like glob expansion of arguments.
697
+
698
+ """
699
+
700
+ # Logic to handle issue #3664
701
+ # Add '--' after '-m <module_name>' to ignore additional args passed to a module.
702
+ if '-m' in parameter_s and '--' not in parameter_s:
703
+ argv = shlex.split(parameter_s, posix=(os.name == 'posix'))
704
+ for idx, arg in enumerate(argv):
705
+ if arg and arg.startswith('-') and arg != '-':
706
+ if arg == '-m':
707
+ argv.insert(idx + 2, '--')
708
+ break
709
+ else:
710
+ # Positional arg, break
711
+ break
712
+ parameter_s = ' '.join(shlex.quote(arg) for arg in argv)
713
+
714
+ # get arguments and set sys.argv for program to be run.
715
+ opts, arg_lst = self.parse_options(parameter_s,
716
+ 'nidtN:b:pD:l:rs:T:em:G',
717
+ mode='list', list_all=1)
718
+ if "m" in opts:
719
+ modulename = opts["m"][0]
720
+ modpath = find_mod(modulename)
721
+ if modpath is None:
722
+ msg = '%r is not a valid modulename on sys.path'%modulename
723
+ raise Exception(msg)
724
+ arg_lst = [modpath] + arg_lst
725
+ try:
726
+ fpath = None # initialize to make sure fpath is in scope later
727
+ fpath = arg_lst[0]
728
+ filename = file_finder(fpath)
729
+ except IndexError as e:
730
+ msg = 'you must provide at least a filename.'
731
+ raise Exception(msg) from e
732
+ except IOError as e:
733
+ try:
734
+ msg = str(e)
735
+ except UnicodeError:
736
+ msg = e.message
737
+ if os.name == 'nt' and re.match(r"^'.*'$",fpath):
738
+ warn('For Windows, use double quotes to wrap a filename: %run "mypath\\myfile.py"')
739
+ raise Exception(msg) from e
740
+ except TypeError:
741
+ if fpath in sys.meta_path:
742
+ filename = ""
743
+ else:
744
+ raise
745
+
746
+ if filename.lower().endswith(('.ipy', '.ipynb')):
747
+ with preserve_keys(self.shell.user_ns, '__file__'):
748
+ self.shell.user_ns['__file__'] = filename
749
+ self.shell.safe_execfile_ipy(filename, raise_exceptions=True)
750
+ return
751
+
752
+ # Control the response to exit() calls made by the script being run
753
+ exit_ignore = 'e' in opts
754
+
755
+ # Make sure that the running script gets a proper sys.argv as if it
756
+ # were run from a system shell.
757
+ save_argv = sys.argv # save it for later restoring
758
+
759
+ if 'G' in opts:
760
+ args = arg_lst[1:]
761
+ else:
762
+ # tilde and glob expansion
763
+ args = shellglob(map(os.path.expanduser, arg_lst[1:]))
764
+
765
+ sys.argv = [filename] + args # put in the proper filename
766
+
767
+ if 'n' in opts:
768
+ name = Path(filename).stem
769
+ else:
770
+ name = '__main__'
771
+
772
+ if 'i' in opts:
773
+ # Run in user's interactive namespace
774
+ prog_ns = self.shell.user_ns
775
+ __name__save = self.shell.user_ns['__name__']
776
+ prog_ns['__name__'] = name
777
+ main_mod = self.shell.user_module
778
+
779
+ # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
780
+ # set the __file__ global in the script's namespace
781
+ # TK: Is this necessary in interactive mode?
782
+ prog_ns['__file__'] = filename
783
+ else:
784
+ # Run in a fresh, empty namespace
785
+
786
+ # The shell MUST hold a reference to prog_ns so after %run
787
+ # exits, the python deletion mechanism doesn't zero it out
788
+ # (leaving dangling references). See interactiveshell for details
789
+ main_mod = self.shell.new_main_mod(filename, name)
790
+ prog_ns = main_mod.__dict__
791
+
792
+ # pickle fix. See interactiveshell for an explanation. But we need to
793
+ # make sure that, if we overwrite __main__, we replace it at the end
794
+ main_mod_name = prog_ns['__name__']
795
+
796
+ if main_mod_name == '__main__':
797
+ restore_main = sys.modules['__main__']
798
+ else:
799
+ restore_main = False
800
+
801
+ # This needs to be undone at the end to prevent holding references to
802
+ # every single object ever created.
803
+ sys.modules[main_mod_name] = main_mod
804
+
805
+ if 'p' in opts or 'd' in opts:
806
+ if 'm' in opts:
807
+ code = 'run_module(modulename, prog_ns)'
808
+ code_ns = {
809
+ 'run_module': self.shell.safe_run_module,
810
+ 'prog_ns': prog_ns,
811
+ 'modulename': modulename,
812
+ }
813
+ else:
814
+ if 'd' in opts:
815
+ # allow exceptions to raise in debug mode
816
+ code = 'execfile(filename, prog_ns, raise_exceptions=True)'
817
+ else:
818
+ code = 'execfile(filename, prog_ns)'
819
+ code_ns = {
820
+ 'execfile': self.shell.safe_execfile,
821
+ 'prog_ns': prog_ns,
822
+ 'filename': get_py_filename(filename),
823
+ }
824
+
825
+ try:
826
+ stats = None
827
+ if 'p' in opts:
828
+ stats = self._run_with_profiler(code, opts, code_ns)
829
+ else:
830
+ if 'd' in opts:
831
+ bp_file, bp_line = parse_breakpoint(
832
+ opts.get('b', ['1'])[0], filename)
833
+ self._run_with_debugger(
834
+ code, code_ns, filename, bp_line, bp_file)
835
+ else:
836
+ if 'm' in opts:
837
+ def run():
838
+ self.shell.safe_run_module(modulename, prog_ns)
839
+ else:
840
+ if runner is None:
841
+ runner = self.default_runner
842
+ if runner is None:
843
+ runner = self.shell.safe_execfile
844
+
845
+ def run():
846
+ runner(filename, prog_ns, prog_ns,
847
+ exit_ignore=exit_ignore)
848
+
849
+ if 't' in opts:
850
+ # timed execution
851
+ try:
852
+ nruns = int(opts['N'][0])
853
+ if nruns < 1:
854
+ error('Number of runs must be >=1')
855
+ return
856
+ except (KeyError):
857
+ nruns = 1
858
+ self._run_with_timing(run, nruns)
859
+ else:
860
+ # regular execution
861
+ run()
862
+
863
+ if 'i' in opts:
864
+ self.shell.user_ns['__name__'] = __name__save
865
+ else:
866
+ # update IPython interactive namespace
867
+
868
+ # Some forms of read errors on the file may mean the
869
+ # __name__ key was never set; using pop we don't have to
870
+ # worry about a possible KeyError.
871
+ prog_ns.pop('__name__', None)
872
+
873
+ with preserve_keys(self.shell.user_ns, '__file__'):
874
+ self.shell.user_ns.update(prog_ns)
875
+ finally:
876
+ # It's a bit of a mystery why, but __builtins__ can change from
877
+ # being a module to becoming a dict missing some key data after
878
+ # %run. As best I can see, this is NOT something IPython is doing
879
+ # at all, and similar problems have been reported before:
880
+ # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
881
+ # Since this seems to be done by the interpreter itself, the best
882
+ # we can do is to at least restore __builtins__ for the user on
883
+ # exit.
884
+ self.shell.user_ns['__builtins__'] = builtin_mod
885
+
886
+ # Ensure key global structures are restored
887
+ sys.argv = save_argv
888
+ if restore_main:
889
+ sys.modules['__main__'] = restore_main
890
+ if '__mp_main__' in sys.modules:
891
+ sys.modules['__mp_main__'] = restore_main
892
+ else:
893
+ # Remove from sys.modules the reference to main_mod we'd
894
+ # added. Otherwise it will trap references to objects
895
+ # contained therein.
896
+ del sys.modules[main_mod_name]
897
+
898
+ return stats
899
+
900
+ def _run_with_debugger(
901
+ self, code, code_ns, filename=None, bp_line=None, bp_file=None, local_ns=None
902
+ ):
903
+ """
904
+ Run `code` in debugger with a break point.
905
+
906
+ Parameters
907
+ ----------
908
+ code : str
909
+ Code to execute.
910
+ code_ns : dict
911
+ A namespace in which `code` is executed.
912
+ filename : str
913
+ `code` is ran as if it is in `filename`.
914
+ bp_line : int, optional
915
+ Line number of the break point.
916
+ bp_file : str, optional
917
+ Path to the file in which break point is specified.
918
+ `filename` is used if not given.
919
+ local_ns : dict, optional
920
+ A local namespace in which `code` is executed.
921
+
922
+ Raises
923
+ ------
924
+ UsageError
925
+ If the break point given by `bp_line` is not valid.
926
+
927
+ """
928
+ deb = self.shell.InteractiveTB.pdb
929
+ if not deb:
930
+ self.shell.InteractiveTB.pdb = self.shell.InteractiveTB.debugger_cls()
931
+ deb = self.shell.InteractiveTB.pdb
932
+
933
+ # reset Breakpoint state, which is moronically kept
934
+ # in a class
935
+ bdb.Breakpoint.next = 1
936
+ bdb.Breakpoint.bplist = {}
937
+ bdb.Breakpoint.bpbynumber = [None]
938
+ deb.clear_all_breaks()
939
+ if bp_line is not None:
940
+ # Set an initial breakpoint to stop execution
941
+ maxtries = 10
942
+ bp_file = bp_file or filename
943
+ checkline = deb.checkline(bp_file, bp_line)
944
+ if not checkline:
945
+ for bp in range(bp_line + 1, bp_line + maxtries + 1):
946
+ if deb.checkline(bp_file, bp):
947
+ break
948
+ else:
949
+ msg = ("\nI failed to find a valid line to set "
950
+ "a breakpoint\n"
951
+ "after trying up to line: %s.\n"
952
+ "Please set a valid breakpoint manually "
953
+ "with the -b option." % bp)
954
+ raise UsageError(msg)
955
+ # if we find a good linenumber, set the breakpoint
956
+ deb.do_break('%s:%s' % (bp_file, bp_line))
957
+
958
+ if filename:
959
+ # Mimic Pdb._runscript(...)
960
+ deb._wait_for_mainpyfile = True
961
+ deb.mainpyfile = deb.canonic(filename)
962
+
963
+ # Start file run
964
+ print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
965
+ try:
966
+ if filename:
967
+ # save filename so it can be used by methods on the deb object
968
+ deb._exec_filename = filename
969
+ while True:
970
+ try:
971
+ trace = sys.gettrace()
972
+ deb.run(code, code_ns, local_ns)
973
+ except Restart:
974
+ print("Restarting")
975
+ if filename:
976
+ deb._wait_for_mainpyfile = True
977
+ deb.mainpyfile = deb.canonic(filename)
978
+ continue
979
+ else:
980
+ break
981
+ finally:
982
+ sys.settrace(trace)
983
+
984
+ # Perform proper cleanup of the session in case if
985
+ # it exited with "continue" and not "quit" command
986
+ if hasattr(deb, "rcLines"):
987
+ # Run this code defensively in case if custom debugger
988
+ # class does not implement rcLines, which although public
989
+ # is an implementation detail of `pdb.Pdb` and not part of
990
+ # the more generic basic debugger framework (`bdb.Bdb`).
991
+ deb.set_quit()
992
+ deb.rcLines.extend(["q"])
993
+ try:
994
+ deb.run("", code_ns, local_ns)
995
+ except StopIteration:
996
+ # Stop iteration is raised on quit command
997
+ pass
998
+
999
+ except Exception:
1000
+ etype, value, tb = sys.exc_info()
1001
+ # Skip three frames in the traceback: the %run one,
1002
+ # one inside bdb.py, and the command-line typed by the
1003
+ # user (run by exec in pdb itself).
1004
+ self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
1005
+
1006
+ @staticmethod
1007
+ def _run_with_timing(run, nruns):
1008
+ """
1009
+ Run function `run` and print timing information.
1010
+
1011
+ Parameters
1012
+ ----------
1013
+ run : callable
1014
+ Any callable object which takes no argument.
1015
+ nruns : int
1016
+ Number of times to execute `run`.
1017
+
1018
+ """
1019
+ twall0 = time.perf_counter()
1020
+ if nruns == 1:
1021
+ t0 = clock2()
1022
+ run()
1023
+ t1 = clock2()
1024
+ t_usr = t1[0] - t0[0]
1025
+ t_sys = t1[1] - t0[1]
1026
+ print("\nIPython CPU timings (estimated):")
1027
+ print(" User : %10.2f s." % t_usr)
1028
+ print(" System : %10.2f s." % t_sys)
1029
+ else:
1030
+ runs = range(nruns)
1031
+ t0 = clock2()
1032
+ for nr in runs:
1033
+ run()
1034
+ t1 = clock2()
1035
+ t_usr = t1[0] - t0[0]
1036
+ t_sys = t1[1] - t0[1]
1037
+ print("\nIPython CPU timings (estimated):")
1038
+ print("Total runs performed:", nruns)
1039
+ print(" Times : %10s %10s" % ('Total', 'Per run'))
1040
+ print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
1041
+ print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
1042
+ twall1 = time.perf_counter()
1043
+ print("Wall time: %10.2f s." % (twall1 - twall0))
1044
+
1045
+ @skip_doctest
1046
+ @no_var_expand
1047
+ @line_cell_magic
1048
+ @needs_local_scope
1049
+ def timeit(self, line='', cell=None, local_ns=None):
1050
+ """Time execution of a Python statement or expression
1051
+
1052
+ **Usage, in line mode**::
1053
+
1054
+ %timeit [-n<N> -r<R> [-t|-c] -q -p<P> [-o|-v <V>]] statement
1055
+
1056
+ **or in cell mode**::
1057
+
1058
+ %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> [-o|-v <V>]] setup_code
1059
+ code
1060
+ code...
1061
+
1062
+ Time execution of a Python statement or expression using the timeit
1063
+ module. This function can be used both as a line and cell magic:
1064
+
1065
+ - In line mode you can time a single-line statement (though multiple
1066
+ ones can be chained with using semicolons).
1067
+
1068
+ - In cell mode, the statement in the first line is used as setup code
1069
+ (executed but not timed) and the body of the cell is timed. The cell
1070
+ body has access to any variables created in the setup code.
1071
+
1072
+ Options:
1073
+
1074
+ -n<N>
1075
+ Execute the given statement N times in a loop. If N is not
1076
+ provided, N is determined so as to get sufficient accuracy.
1077
+
1078
+ -r<R>
1079
+ Number of repeats R, each consisting of N loops, and take the
1080
+ average result.
1081
+ Default: 7
1082
+
1083
+ -t
1084
+ Use ``time.time`` to measure the time, which is the default on Unix.
1085
+ This function measures wall time.
1086
+
1087
+ -c
1088
+ Use ``time.clock`` to measure the time, which is the default on
1089
+ Windows and measures wall time. On Unix, ``resource.getrusage`` is used
1090
+ instead and returns the CPU user time.
1091
+
1092
+ -p<P>
1093
+ Use a precision of P digits to display the timing result.
1094
+ Default: 3
1095
+
1096
+ -q
1097
+ Quiet, do not print result.
1098
+
1099
+ -o
1100
+ Return a ``TimeitResult`` that can be stored in a variable to inspect
1101
+ the result in more details.
1102
+
1103
+ -v <V>
1104
+ Like ``-o``, but save the ``TimeitResult`` directly to variable <V>.
1105
+
1106
+ .. versionchanged:: 7.3
1107
+ User variables are no longer expanded,
1108
+ the magic line is always left unmodified.
1109
+
1110
+ Examples
1111
+ --------
1112
+ ::
1113
+
1114
+ In [1]: %timeit pass
1115
+ 8.26 ns ± 0.12 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
1116
+
1117
+ In [2]: u = None
1118
+
1119
+ In [3]: %timeit u is None
1120
+ 29.9 ns ± 0.643 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
1121
+
1122
+ In [4]: %timeit -r 4 u == None
1123
+
1124
+ In [5]: import time
1125
+
1126
+ In [6]: %timeit -n1 time.sleep(2)
1127
+
1128
+ The times reported by ``%timeit`` will be slightly higher than those
1129
+ reported by the timeit.py script when variables are accessed. This is
1130
+ due to the fact that ``%timeit`` executes the statement in the namespace
1131
+ of the shell, compared with timeit.py, which uses a single setup
1132
+ statement to import function or create variables. Generally, the bias
1133
+ does not matter as long as results from timeit.py are not mixed with
1134
+ those from ``%timeit``."""
1135
+
1136
+ # TODO: port to magic_arguments as currently this is duplicated in IPCompleter._extract_code
1137
+ opts, stmt = self.parse_options(
1138
+ line, "n:r:tcp:qov:", posix=False, strict=False, preserve_non_opts=True
1139
+ )
1140
+ if stmt == "" and cell is None:
1141
+ return
1142
+
1143
+ timefunc = timeit.default_timer
1144
+ number = int(getattr(opts, "n", 0))
1145
+ default_repeat = 7 if timeit.default_repeat < 7 else timeit.default_repeat
1146
+ repeat = int(getattr(opts, "r", default_repeat))
1147
+ precision = int(getattr(opts, "p", 3))
1148
+ quiet = "q" in opts
1149
+ return_result = "o" in opts
1150
+ save_result = "v" in opts
1151
+ if hasattr(opts, "t"):
1152
+ timefunc = time.time
1153
+ if hasattr(opts, "c"):
1154
+ timefunc = clock
1155
+
1156
+ timer = Timer(timer=timefunc)
1157
+ # this code has tight coupling to the inner workings of timeit.Timer,
1158
+ # but is there a better way to achieve that the code stmt has access
1159
+ # to the shell namespace?
1160
+ transform = self.shell.transform_cell
1161
+
1162
+ if cell is None:
1163
+ # called as line magic
1164
+ ast_setup = self.shell.compile.ast_parse("pass")
1165
+ ast_stmt = self.shell.compile.ast_parse(transform(stmt))
1166
+ else:
1167
+ ast_setup = self.shell.compile.ast_parse(transform(stmt))
1168
+ ast_stmt = self.shell.compile.ast_parse(transform(cell))
1169
+
1170
+ ast_setup = self.shell.transform_ast(ast_setup)
1171
+ ast_stmt = self.shell.transform_ast(ast_stmt)
1172
+
1173
+ # Check that these compile to valid Python code *outside* the timer func
1174
+ # Invalid code may become valid when put inside the function & loop,
1175
+ # which messes up error messages.
1176
+ # https://github.com/ipython/ipython/issues/10636
1177
+ self.shell.compile(ast_setup, "<magic-timeit-setup>", "exec")
1178
+ self.shell.compile(ast_stmt, "<magic-timeit-stmt>", "exec")
1179
+
1180
+ # This codestring is taken from timeit.template - we fill it in as an
1181
+ # AST, so that we can apply our AST transformations to the user code
1182
+ # without affecting the timing code.
1183
+ timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
1184
+ ' setup\n'
1185
+ ' _t0 = _timer()\n'
1186
+ ' for _i in _it:\n'
1187
+ ' stmt\n'
1188
+ ' _t1 = _timer()\n'
1189
+ ' return _t1 - _t0\n')
1190
+
1191
+ timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
1192
+ timeit_ast = ast.fix_missing_locations(timeit_ast)
1193
+
1194
+ # Track compilation time so it can be reported if too long
1195
+ # Minimum time above which compilation time will be reported
1196
+ tc_min = 0.1
1197
+
1198
+ t0 = clock()
1199
+ code = self.shell.compile(timeit_ast, "<magic-timeit>", "exec")
1200
+ tc = clock()-t0
1201
+
1202
+ ns = {}
1203
+ glob = self.shell.user_ns
1204
+ # handles global vars with same name as local vars. We store them in conflict_globs.
1205
+ conflict_globs = {}
1206
+ if local_ns and cell is None:
1207
+ for var_name, var_val in glob.items():
1208
+ if var_name in local_ns:
1209
+ conflict_globs[var_name] = var_val
1210
+ glob.update(local_ns)
1211
+
1212
+ exec(code, glob, ns)
1213
+ timer.inner = ns["inner"]
1214
+
1215
+ # This is used to check if there is a huge difference between the
1216
+ # best and worst timings.
1217
+ # Issue: https://github.com/ipython/ipython/issues/6471
1218
+ if number == 0:
1219
+ # determine number so that 0.2 <= total time < 2.0
1220
+ for index in range(0, 10):
1221
+ number = 10 ** index
1222
+ time_number = timer.timeit(number)
1223
+ if time_number >= 0.2:
1224
+ break
1225
+
1226
+ all_runs = timer.repeat(repeat, number)
1227
+ best = min(all_runs) / number
1228
+ worst = max(all_runs) / number
1229
+ timeit_result = TimeitResult(number, repeat, best, worst, all_runs, tc, precision)
1230
+
1231
+ # Restore global vars from conflict_globs
1232
+ if conflict_globs:
1233
+ glob.update(conflict_globs)
1234
+
1235
+ if not quiet:
1236
+ # Check best timing is greater than zero to avoid a
1237
+ # ZeroDivisionError.
1238
+ # In cases where the slowest timing is lesser than a microsecond
1239
+ # we assume that it does not really matter if the fastest
1240
+ # timing is 4 times faster than the slowest timing or not.
1241
+ if worst > 4 * best and best > 0 and worst > 1e-6:
1242
+ print("The slowest run took %0.2f times longer than the "
1243
+ "fastest. This could mean that an intermediate result "
1244
+ "is being cached." % (worst / best))
1245
+
1246
+ print( timeit_result )
1247
+
1248
+ if tc > tc_min:
1249
+ print("Compiler time: %.2f s" % tc)
1250
+
1251
+ if save_result:
1252
+ self.shell.user_ns[opts.v] = timeit_result
1253
+
1254
+ if return_result:
1255
+ return timeit_result
1256
+
1257
+ @no_var_expand
1258
+ @magic_arguments.magic_arguments()
1259
+ @magic_arguments.argument(
1260
+ "--no-raise-error",
1261
+ action="store_true",
1262
+ dest="no_raise_error",
1263
+ help="If given, don't re-raise exceptions",
1264
+ )
1265
+ @magic_arguments.kwds(
1266
+ epilog="""
1267
+ Any remaining arguments will be treated as code to run.
1268
+ """
1269
+ )
1270
+ @skip_doctest
1271
+ @needs_local_scope
1272
+ @line_cell_magic
1273
+ @output_can_be_silenced
1274
+ def time(self, line="", cell=None, local_ns=None):
1275
+ """Time execution of a Python statement or expression.
1276
+
1277
+ The CPU and wall clock times are printed, and the value of the
1278
+ expression (if any) is returned. Note that under Win32, system time
1279
+ is always reported as 0, since it can not be measured.
1280
+
1281
+ This function can be used both as a line and cell magic:
1282
+
1283
+ - In line mode you can time a single-line statement (though multiple
1284
+ ones can be chained with using semicolons).
1285
+
1286
+ - In cell mode, you can time the cell body (a directly
1287
+ following statement raises an error).
1288
+
1289
+ This function provides very basic timing functionality. Use the timeit
1290
+ magic for more control over the measurement.
1291
+
1292
+ .. versionchanged:: 7.3
1293
+ User variables are no longer expanded,
1294
+ the magic line is always left unmodified.
1295
+
1296
+ .. versionchanged:: 8.3
1297
+ The time magic now correctly propagates system-exiting exceptions
1298
+ (such as ``KeyboardInterrupt`` invoked when interrupting execution)
1299
+ rather than just printing out the exception traceback.
1300
+ The non-system-exception will still be caught as before.
1301
+
1302
+ Examples
1303
+ --------
1304
+ ::
1305
+
1306
+ In [1]: %time 2**128
1307
+ CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1308
+ Wall time: 0.00
1309
+ Out[1]: 340282366920938463463374607431768211456L
1310
+
1311
+ In [2]: n = 1000000
1312
+
1313
+ In [3]: %time sum(range(n))
1314
+ CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1315
+ Wall time: 1.37
1316
+ Out[3]: 499999500000L
1317
+
1318
+ In [4]: %time print('hello world')
1319
+ hello world
1320
+ CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1321
+ Wall time: 0.00
1322
+
1323
+ .. note::
1324
+ The time needed by Python to compile the given expression will be
1325
+ reported if it is more than 0.1s.
1326
+
1327
+ In the example below, the actual exponentiation is done by Python
1328
+ at compilation time, so while the expression can take a noticeable
1329
+ amount of time to compute, that time is purely due to the
1330
+ compilation::
1331
+
1332
+ In [5]: %time 3**9999;
1333
+ CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1334
+ Wall time: 0.00 s
1335
+
1336
+ In [6]: %time 3**999999;
1337
+ CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1338
+ Wall time: 0.00 s
1339
+ Compiler : 0.78 s
1340
+ """
1341
+ args, extra = magic_arguments.parse_argstring(self.time, line, partial=True)
1342
+ line = " ".join(extra)
1343
+
1344
+ if line and cell:
1345
+ raise UsageError("Can't use statement directly after '%%time'!")
1346
+
1347
+ if cell:
1348
+ expr = self.shell.transform_cell(cell)
1349
+ else:
1350
+ expr = self.shell.transform_cell(line)
1351
+
1352
+ # Minimum time above which parse time will be reported
1353
+ tp_min = 0.1
1354
+
1355
+ t0 = clock()
1356
+ expr_ast = self.shell.compile.ast_parse(expr)
1357
+ tp = clock() - t0
1358
+
1359
+ # Apply AST transformations
1360
+ expr_ast = self.shell.transform_ast(expr_ast)
1361
+
1362
+ # Minimum time above which compilation time will be reported
1363
+ tc_min = 0.1
1364
+
1365
+ expr_val = None
1366
+ if len(expr_ast.body) == 1 and isinstance(expr_ast.body[0], ast.Expr):
1367
+ mode = 'eval'
1368
+ source = '<timed eval>'
1369
+ expr_ast = ast.Expression(expr_ast.body[0].value)
1370
+ else:
1371
+ mode = 'exec'
1372
+ source = '<timed exec>'
1373
+ # multi-line %%time case
1374
+ if len(expr_ast.body) > 1 and isinstance(expr_ast.body[-1], ast.Expr):
1375
+ expr_val = expr_ast.body[-1]
1376
+ expr_ast = expr_ast.body[:-1]
1377
+ expr_ast = Module(expr_ast, [])
1378
+ expr_val = ast.Expression(expr_val.value)
1379
+
1380
+ t0 = clock()
1381
+ code = self.shell.compile(expr_ast, source, mode)
1382
+ tc = clock() - t0
1383
+
1384
+ # skew measurement as little as possible
1385
+ glob = self.shell.user_ns
1386
+ wtime = time.time
1387
+ # time execution
1388
+ wall_st = wtime()
1389
+ # Track whether to propagate exceptions or exit
1390
+ exit_on_interrupt = False
1391
+ interrupt_occured = False
1392
+ captured_exception = None
1393
+
1394
+ if mode == "eval":
1395
+ st = clock2()
1396
+ try:
1397
+ out = eval(code, glob, local_ns)
1398
+ except KeyboardInterrupt as e:
1399
+ captured_exception = e
1400
+ interrupt_occured = True
1401
+ exit_on_interrupt = True
1402
+ except Exception as e:
1403
+ captured_exception = e
1404
+ interrupt_occured = True
1405
+ if not args.no_raise_error:
1406
+ exit_on_interrupt = True
1407
+ end = clock2()
1408
+ else:
1409
+ st = clock2()
1410
+ try:
1411
+ exec(code, glob, local_ns)
1412
+ out = None
1413
+ # multi-line %%time case
1414
+ if expr_val is not None:
1415
+ code_2 = self.shell.compile(expr_val, source, 'eval')
1416
+ out = eval(code_2, glob, local_ns)
1417
+ except KeyboardInterrupt as e:
1418
+ captured_exception = e
1419
+ interrupt_occured = True
1420
+ exit_on_interrupt = True
1421
+ except Exception as e:
1422
+ captured_exception = e
1423
+ interrupt_occured = True
1424
+ if not args.no_raise_error:
1425
+ exit_on_interrupt = True
1426
+ end = clock2()
1427
+ wall_end = wtime()
1428
+ # Compute actual times and report
1429
+ wall_time = wall_end - wall_st
1430
+ cpu_user = end[0] - st[0]
1431
+ cpu_sys = end[1] - st[1]
1432
+ cpu_tot = cpu_user + cpu_sys
1433
+ # On windows cpu_sys is always zero, so only total is displayed
1434
+ if sys.platform != "win32":
1435
+ print(
1436
+ f"CPU times: user {_format_time(cpu_user)}, sys: {_format_time(cpu_sys)}, total: {_format_time(cpu_tot)}"
1437
+ )
1438
+ else:
1439
+ print(f"CPU times: total: {_format_time(cpu_tot)}")
1440
+ print(f"Wall time: {_format_time(wall_time)}")
1441
+ if tc > tc_min:
1442
+ print(f"Compiler : {_format_time(tc)}")
1443
+ if tp > tp_min:
1444
+ print(f"Parser : {_format_time(tp)}")
1445
+ if interrupt_occured:
1446
+ if exit_on_interrupt and captured_exception:
1447
+ raise captured_exception
1448
+ return
1449
+ return out
1450
+
1451
+ @skip_doctest
1452
+ @line_magic
1453
+ def macro(self, parameter_s=''):
1454
+ """Define a macro for future re-execution. It accepts ranges of history,
1455
+ filenames or string objects.
1456
+
1457
+ Usage::
1458
+
1459
+ %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1460
+
1461
+ Options:
1462
+
1463
+ -r
1464
+ Use 'raw' input. By default, the 'processed' history is used,
1465
+ so that magics are loaded in their transformed version to valid
1466
+ Python. If this option is given, the raw input as typed at the
1467
+ command line is used instead.
1468
+
1469
+ -q
1470
+ Quiet macro definition. By default, a tag line is printed
1471
+ to indicate the macro has been created, and then the contents of
1472
+ the macro are printed. If this option is given, then no printout
1473
+ is produced once the macro is created.
1474
+
1475
+ This will define a global variable called `name` which is a string
1476
+ made of joining the slices and lines you specify (n1,n2,... numbers
1477
+ above) from your input history into a single string. This variable
1478
+ acts like an automatic function which re-executes those lines as if
1479
+ you had typed them. You just type 'name' at the prompt and the code
1480
+ executes.
1481
+
1482
+ The syntax for indicating input ranges is described in %history.
1483
+
1484
+ Note: as a 'hidden' feature, you can also use traditional python slice
1485
+ notation, where N:M means numbers N through M-1.
1486
+
1487
+ For example, if your history contains (print using %hist -n )::
1488
+
1489
+ 44: x=1
1490
+ 45: y=3
1491
+ 46: z=x+y
1492
+ 47: print(x)
1493
+ 48: a=5
1494
+ 49: print('x',x,'y',y)
1495
+
1496
+ you can create a macro with lines 44 through 47 (included) and line 49
1497
+ called my_macro with::
1498
+
1499
+ In [55]: %macro my_macro 44-47 49
1500
+
1501
+ Now, typing `my_macro` (without quotes) will re-execute all this code
1502
+ in one pass.
1503
+
1504
+ You don't need to give the line-numbers in order, and any given line
1505
+ number can appear multiple times. You can assemble macros with any
1506
+ lines from your input history in any order.
1507
+
1508
+ The macro is a simple object which holds its value in an attribute,
1509
+ but IPython's display system checks for macros and executes them as
1510
+ code instead of printing them when you type their name.
1511
+
1512
+ You can view a macro's contents by explicitly printing it with::
1513
+
1514
+ print(macro_name)
1515
+
1516
+ """
1517
+ opts,args = self.parse_options(parameter_s,'rq',mode='list')
1518
+ if not args: # List existing macros
1519
+ return sorted(k for k,v in self.shell.user_ns.items() if isinstance(v, Macro))
1520
+ if len(args) == 1:
1521
+ raise UsageError(
1522
+ "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1523
+ name, codefrom = args[0], " ".join(args[1:])
1524
+
1525
+ # print('rng',ranges) # dbg
1526
+ try:
1527
+ lines = self.shell.find_user_code(codefrom, 'r' in opts)
1528
+ except (ValueError, TypeError) as e:
1529
+ print(e.args[0])
1530
+ return
1531
+ macro = Macro(lines)
1532
+ self.shell.define_macro(name, macro)
1533
+ if "q" not in opts:
1534
+ print(
1535
+ "Macro `%s` created. To execute, type its name (without quotes)." % name
1536
+ )
1537
+ print("=== Macro contents: ===")
1538
+ print(macro, end=" ")
1539
+
1540
+ @magic_arguments.magic_arguments()
1541
+ @magic_arguments.argument(
1542
+ "output",
1543
+ type=str,
1544
+ default="",
1545
+ nargs="?",
1546
+ help="""
1547
+
1548
+ The name of the variable in which to store output.
1549
+ This is a ``utils.io.CapturedIO`` object with stdout/err attributes
1550
+ for the text of the captured output.
1551
+
1552
+ CapturedOutput also has a ``show()`` method for displaying the output,
1553
+ and ``__call__`` as well, so you can use that to quickly display the
1554
+ output.
1555
+
1556
+ If unspecified, captured output is discarded.
1557
+ """,
1558
+ )
1559
+ @magic_arguments.argument(
1560
+ "--no-stderr", action="store_true", help="""Don't capture stderr."""
1561
+ )
1562
+ @magic_arguments.argument(
1563
+ "--no-stdout", action="store_true", help="""Don't capture stdout."""
1564
+ )
1565
+ @magic_arguments.argument(
1566
+ "--no-display",
1567
+ action="store_true",
1568
+ help="""Don't capture IPython's rich display."""
1569
+ )
1570
+ @cell_magic
1571
+ def capture(self, line, cell):
1572
+ """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1573
+ args = magic_arguments.parse_argstring(self.capture, line)
1574
+ out = not args.no_stdout
1575
+ err = not args.no_stderr
1576
+ disp = not args.no_display
1577
+ with capture_output(out, err, disp) as io:
1578
+ self.shell.run_cell(cell)
1579
+ if DisplayHook.semicolon_at_end_of_expression(cell):
1580
+ if args.output in self.shell.user_ns:
1581
+ del self.shell.user_ns[args.output]
1582
+ elif args.output:
1583
+ self.shell.user_ns[args.output] = io
1584
+
1585
+ @skip_doctest
1586
+ @magic_arguments.magic_arguments()
1587
+ @magic_arguments.argument("name", type=str, default="default", nargs="?")
1588
+ @magic_arguments.argument(
1589
+ "--remove", action="store_true", help="remove the current transformer"
1590
+ )
1591
+ @magic_arguments.argument(
1592
+ "--list", action="store_true", help="list existing transformers name"
1593
+ )
1594
+ @magic_arguments.argument(
1595
+ "--list-all",
1596
+ action="store_true",
1597
+ help="list existing transformers name and code template",
1598
+ )
1599
+ @line_cell_magic
1600
+ def code_wrap(self, line, cell=None):
1601
+ """
1602
+ Simple magic to quickly define a code transformer for all IPython's future input.
1603
+
1604
+ ``__code__`` and ``__ret__`` are special variable that represent the code to run
1605
+ and the value of the last expression of ``__code__`` respectively.
1606
+
1607
+ Examples
1608
+ --------
1609
+
1610
+ .. ipython::
1611
+
1612
+ In [1]: %%code_wrap before_after
1613
+ ...: print('before')
1614
+ ...: __code__
1615
+ ...: print('after')
1616
+ ...: __ret__
1617
+
1618
+
1619
+ In [2]: 1
1620
+ before
1621
+ after
1622
+ Out[2]: 1
1623
+
1624
+ In [3]: %code_wrap --list
1625
+ before_after
1626
+
1627
+ In [4]: %code_wrap --list-all
1628
+ before_after :
1629
+ print('before')
1630
+ __code__
1631
+ print('after')
1632
+ __ret__
1633
+
1634
+ In [5]: %code_wrap --remove before_after
1635
+
1636
+ """
1637
+ args = magic_arguments.parse_argstring(self.code_wrap, line)
1638
+
1639
+ if args.list:
1640
+ for name in self._transformers.keys():
1641
+ print(name)
1642
+ return
1643
+ if args.list_all:
1644
+ for name, _t in self._transformers.items():
1645
+ print(name, ":")
1646
+ print(indent(ast.unparse(_t.template), " "))
1647
+ print()
1648
+ return
1649
+
1650
+ to_remove = self._transformers.pop(args.name, None)
1651
+ if to_remove in self.shell.ast_transformers:
1652
+ self.shell.ast_transformers.remove(to_remove)
1653
+ if cell is None or args.remove:
1654
+ return
1655
+
1656
+ _trs = ReplaceCodeTransformer(ast.parse(cell))
1657
+
1658
+ self._transformers[args.name] = _trs
1659
+ self.shell.ast_transformers.append(_trs)
1660
+
1661
+
1662
+ def parse_breakpoint(text, current_file):
1663
+ '''Returns (file, line) for file:line and (current_file, line) for line'''
1664
+ colon = text.find(':')
1665
+ if colon == -1:
1666
+ return current_file, int(text)
1667
+ else:
1668
+ return text[:colon], int(text[colon+1:])
1669
+
1670
+
1671
+ def _format_time(timespan, precision=3):
1672
+ """Formats the timespan in a human readable form"""
1673
+
1674
+ if timespan >= 60.0:
1675
+ # we have more than a minute, format that in a human readable form
1676
+ # Idea from http://snipplr.com/view/5713/
1677
+ parts = [("d", 60 * 60 * 24), ("h", 60 * 60), ("min", 60), ("s", 1)]
1678
+ time = []
1679
+ leftover = timespan
1680
+ for suffix, length in parts:
1681
+ value = int(leftover / length)
1682
+ if value > 0:
1683
+ leftover = leftover % length
1684
+ time.append("%s%s" % (str(value), suffix))
1685
+ if leftover < 1:
1686
+ break
1687
+ return " ".join(time)
1688
+
1689
+ # Unfortunately characters outside of range(128) can cause problems in
1690
+ # certain terminals.
1691
+ # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1692
+ # Try to prevent crashes by being more secure than it needs to
1693
+ # E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set.
1694
+ units = ["s", "ms", "us", "ns"] # the safe value
1695
+ if hasattr(sys.stdout, "encoding") and sys.stdout.encoding:
1696
+ try:
1697
+ "μ".encode(sys.stdout.encoding)
1698
+ units = ["s", "ms", "μs", "ns"]
1699
+ except:
1700
+ pass
1701
+ scaling = [1, 1e3, 1e6, 1e9]
1702
+
1703
+ if timespan > 0.0:
1704
+ order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1705
+ else:
1706
+ order = 3
1707
+ return "%.*g %s" % (precision, timespan * scaling[order], units[order])
lib/python3.12/site-packages/IPython/core/magics/history.py ADDED
@@ -0,0 +1,361 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of magic functions related to History.
2
+ """
3
+ #-----------------------------------------------------------------------------
4
+ # Copyright (c) 2012, IPython Development Team.
5
+ #
6
+ # Distributed under the terms of the Modified BSD License.
7
+ #
8
+ # The full license is in the file COPYING.txt, distributed with this software.
9
+ #-----------------------------------------------------------------------------
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Imports
13
+ #-----------------------------------------------------------------------------
14
+
15
+ # Stdlib
16
+ import os
17
+ import sys
18
+ from io import open as io_open
19
+ import fnmatch
20
+
21
+ # Our own packages
22
+ from IPython.core.error import StdinNotImplementedError
23
+ from IPython.core.magic import Magics, magics_class, line_magic
24
+ from IPython.core.magic_arguments import (argument, magic_arguments,
25
+ parse_argstring)
26
+ from IPython.testing.skipdoctest import skip_doctest
27
+ from IPython.utils import io
28
+
29
+ #-----------------------------------------------------------------------------
30
+ # Magics class implementation
31
+ #-----------------------------------------------------------------------------
32
+
33
+
34
+ _unspecified = object()
35
+
36
+
37
+ @magics_class
38
+ class HistoryMagics(Magics):
39
+
40
+ @magic_arguments()
41
+ @argument(
42
+ '-n', dest='print_nums', action='store_true', default=False,
43
+ help="""
44
+ print line numbers for each input.
45
+ This feature is only available if numbered prompts are in use.
46
+ """)
47
+ @argument(
48
+ '-o', dest='get_output', action='store_true', default=False,
49
+ help="also print outputs for each input.")
50
+ @argument(
51
+ '-p', dest='pyprompts', action='store_true', default=False,
52
+ help="""
53
+ print classic '>>>' python prompts before each input.
54
+ This is useful for making documentation, and in conjunction
55
+ with -o, for producing doctest-ready output.
56
+ """)
57
+ @argument(
58
+ '-t', dest='raw', action='store_false', default=True,
59
+ help="""
60
+ print the 'translated' history, as IPython understands it.
61
+ IPython filters your input and converts it all into valid Python
62
+ source before executing it (things like magics or aliases are turned
63
+ into function calls, for example). With this option, you'll see the
64
+ native history instead of the user-entered version: '%%cd /' will be
65
+ seen as 'get_ipython().run_line_magic("cd", "/")' instead of '%%cd /'.
66
+ """)
67
+ @argument(
68
+ '-f', dest='filename',
69
+ help="""
70
+ FILENAME: instead of printing the output to the screen, redirect
71
+ it to the given file. The file is always overwritten, though *when
72
+ it can*, IPython asks for confirmation first. In particular, running
73
+ the command 'history -f FILENAME' from the IPython Notebook
74
+ interface will replace FILENAME even if it already exists *without*
75
+ confirmation.
76
+ """,
77
+ )
78
+ @argument(
79
+ "-y",
80
+ dest="overwrite",
81
+ help="yes, overwrite filename even if exists",
82
+ action="store_true",
83
+ default=None,
84
+ )
85
+ @argument(
86
+ "-g",
87
+ dest="pattern",
88
+ nargs="*",
89
+ default=None,
90
+ help="""
91
+ treat the arg as a glob pattern to search for in (full) history.
92
+ This includes the saved history (almost all commands ever written).
93
+ The pattern may contain '?' to match one unknown character and '*'
94
+ to match any number of unknown characters. Use '%%hist -g' to show
95
+ full saved history (may be very long).
96
+ """)
97
+ @argument(
98
+ '-l', dest='limit', type=int, nargs='?', default=_unspecified,
99
+ help="""
100
+ get the last n lines from all sessions. Specify n as a single
101
+ arg, or the default is the last 10 lines.
102
+ """)
103
+ @argument(
104
+ '-u', dest='unique', action='store_true',
105
+ help="""
106
+ when searching history using `-g`, show only unique history.
107
+ """)
108
+ @argument('range', nargs='*')
109
+ @skip_doctest
110
+ @line_magic
111
+ def history(self, parameter_s = ''):
112
+ """Print input history (_i<n> variables), with most recent last.
113
+
114
+ By default, input history is printed without line numbers so it can be
115
+ directly pasted into an editor. Use -n to show them.
116
+
117
+ By default, all input history from the current session is displayed.
118
+ Ranges of history can be indicated using the syntax:
119
+
120
+ ``4``
121
+ Line 4, current session
122
+ ``4-6``
123
+ Lines 4-6, current session
124
+ ``4-``
125
+ Lines 4 onward (to end), current session
126
+ ``243/1-5``
127
+ Lines 1-5, session 243
128
+ ``~2/``
129
+ All lines of session 2 before current
130
+ ``~4/4-``
131
+ Lines 4 onward (to end), session 4 before current
132
+ ``~2/7``
133
+ Line 7, session 2 before current
134
+ ``~8/1-~6/5``
135
+ From the first line of 8 sessions ago, to the fifth line of 6
136
+ sessions ago.
137
+
138
+ Multiple ranges can be entered, separated by spaces
139
+
140
+ The same syntax is used by %macro, %save, %edit, %rerun
141
+
142
+ Examples
143
+ --------
144
+ ::
145
+
146
+ In [6]: %history -n 4-6
147
+ 4:a = 12
148
+ 5:print(a**2)
149
+ 6:%history -n 4-6
150
+
151
+ """
152
+
153
+ args = parse_argstring(self.history, parameter_s)
154
+
155
+ # For brevity
156
+ history_manager = self.shell.history_manager
157
+
158
+ def _format_lineno(session, line):
159
+ """Helper function to format line numbers properly."""
160
+ if session in (0, history_manager.session_number):
161
+ return str(line)
162
+ return "%s/%s" % (session, line)
163
+
164
+ # Check if output to specific file was requested.
165
+ outfname = args.filename
166
+ if not outfname:
167
+ outfile = sys.stdout # default
168
+ # We don't want to close stdout at the end!
169
+ close_at_end = False
170
+ else:
171
+ outfname = os.path.expanduser(outfname)
172
+ if args.overwrite is True:
173
+ ans = True
174
+ elif os.path.exists(outfname):
175
+ ans = True
176
+ if sys.stdin.isatty():
177
+ ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
178
+ else:
179
+ try:
180
+ ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
181
+ except StdinNotImplementedError:
182
+ ans = True
183
+ if not ans:
184
+ print("Aborting.")
185
+ return
186
+ print("Overwriting file.")
187
+ outfile = io_open(outfname, 'w', encoding='utf-8')
188
+ close_at_end = True
189
+
190
+ print_nums = args.print_nums
191
+ get_output = args.get_output
192
+ pyprompts = args.pyprompts
193
+ raw = args.raw
194
+
195
+ pattern = None
196
+ limit = None if args.limit is _unspecified else args.limit
197
+
198
+ range_pattern = False
199
+ if args.pattern is not None and not args.range:
200
+ if args.pattern:
201
+ pattern = "*" + " ".join(args.pattern) + "*"
202
+ else:
203
+ pattern = "*"
204
+ hist = history_manager.search(pattern, raw=raw, output=get_output,
205
+ n=limit, unique=args.unique)
206
+ print_nums = True
207
+ elif args.limit is not _unspecified:
208
+ n = 10 if limit is None else limit
209
+ hist = history_manager.get_tail(n, raw=raw, output=get_output)
210
+ else:
211
+ if args.pattern:
212
+ range_pattern = "*" + " ".join(args.pattern) + "*"
213
+ print_nums = True
214
+ hist = history_manager.get_range_by_str(
215
+ " ".join(args.range), raw, get_output
216
+ )
217
+
218
+ # We could be displaying the entire history, so let's not try to pull
219
+ # it into a list in memory. Anything that needs more space will just
220
+ # misalign.
221
+ width = 4
222
+
223
+ for session, lineno, inline in hist:
224
+ # Print user history with tabs expanded to 4 spaces. The GUI
225
+ # clients use hard tabs for easier usability in auto-indented code,
226
+ # but we want to produce PEP-8 compliant history for safe pasting
227
+ # into an editor.
228
+ if get_output:
229
+ inline, output = inline
230
+ if range_pattern:
231
+ if not fnmatch.fnmatch(inline, range_pattern):
232
+ continue
233
+ inline = inline.expandtabs(4).rstrip()
234
+
235
+ multiline = "\n" in inline
236
+ line_sep = '\n' if multiline else ' '
237
+ if print_nums:
238
+ print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
239
+ line_sep), file=outfile, end=u'')
240
+ if pyprompts:
241
+ print(u">>> ", end=u"", file=outfile)
242
+ if multiline:
243
+ inline = "\n... ".join(inline.splitlines()) + "\n..."
244
+ print(inline, file=outfile)
245
+ if get_output and output:
246
+ print(output, file=outfile)
247
+
248
+ if close_at_end:
249
+ outfile.close()
250
+
251
+ @line_magic
252
+ def recall(self, arg):
253
+ r"""Repeat a command, or get command to input line for editing.
254
+
255
+ %recall and %rep are equivalent.
256
+
257
+ - %recall (no arguments):
258
+
259
+ Place a string version of last computation result (stored in the
260
+ special '_' variable) to the next input prompt. Allows you to create
261
+ elaborate command lines without using copy-paste::
262
+
263
+ In[1]: l = ["hei", "vaan"]
264
+ In[2]: "".join(l)
265
+ Out[2]: heivaan
266
+ In[3]: %recall
267
+ In[4]: heivaan_ <== cursor blinking
268
+
269
+ %recall 45
270
+
271
+ Place history line 45 on the next input prompt. Use %hist to find
272
+ out the number.
273
+
274
+ %recall 1-4
275
+
276
+ Combine the specified lines into one cell, and place it on the next
277
+ input prompt. See %history for the slice syntax.
278
+
279
+ %recall foo+bar
280
+
281
+ If foo+bar can be evaluated in the user namespace, the result is
282
+ placed at the next input prompt. Otherwise, the history is searched
283
+ for lines which contain that substring, and the most recent one is
284
+ placed at the next input prompt.
285
+ """
286
+ if not arg: # Last output
287
+ self.shell.set_next_input(str(self.shell.user_ns["_"]))
288
+ return
289
+ # Get history range
290
+ histlines = self.shell.history_manager.get_range_by_str(arg)
291
+ cmd = "\n".join(x[2] for x in histlines)
292
+ if cmd:
293
+ self.shell.set_next_input(cmd.rstrip())
294
+ return
295
+
296
+ try: # Variable in user namespace
297
+ cmd = str(eval(arg, self.shell.user_ns))
298
+ except Exception: # Search for term in history
299
+ histlines = self.shell.history_manager.search("*"+arg+"*")
300
+ for h in reversed([x[2] for x in histlines]):
301
+ if 'recall' in h or 'rep' in h:
302
+ continue
303
+ self.shell.set_next_input(h.rstrip())
304
+ return
305
+ else:
306
+ self.shell.set_next_input(cmd.rstrip())
307
+ return
308
+ print("Couldn't evaluate or find in history:", arg)
309
+
310
+ @line_magic
311
+ def rerun(self, parameter_s=''):
312
+ """Re-run previous input
313
+
314
+ By default, you can specify ranges of input history to be repeated
315
+ (as with %history). With no arguments, it will repeat the last line.
316
+
317
+ Options:
318
+
319
+ -l <n> : Repeat the last n lines of input, not including the
320
+ current command.
321
+
322
+ -g foo : Repeat the most recent line which contains foo
323
+ """
324
+ opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
325
+ if "l" in opts: # Last n lines
326
+ try:
327
+ n = int(opts["l"])
328
+ except ValueError:
329
+ print("Number of lines must be an integer")
330
+ return
331
+
332
+ if n == 0:
333
+ print("Requested 0 last lines - nothing to run")
334
+ return
335
+ elif n < 0:
336
+ print("Number of lines to rerun cannot be negative")
337
+ return
338
+
339
+ hist = self.shell.history_manager.get_tail(n)
340
+ elif "g" in opts: # Search
341
+ p = "*"+opts['g']+"*"
342
+ hist = list(self.shell.history_manager.search(p))
343
+ for l in reversed(hist):
344
+ if "rerun" not in l[2]:
345
+ hist = [l] # The last match which isn't a %rerun
346
+ break
347
+ else:
348
+ hist = [] # No matches except %rerun
349
+ elif args: # Specify history ranges
350
+ hist = self.shell.history_manager.get_range_by_str(args)
351
+ else: # Last line
352
+ hist = self.shell.history_manager.get_tail(1)
353
+ hist = [x[2] for x in hist]
354
+ if not hist:
355
+ print("No lines in history match specification")
356
+ return
357
+ histlines = "\n".join(hist)
358
+ print("=== Executing: ===")
359
+ print(histlines)
360
+ print("=== Output: ===")
361
+ self.shell.run_cell("\n".join(hist), store_history=False)
lib/python3.12/site-packages/IPython/core/magics/namespace.py ADDED
@@ -0,0 +1,723 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of namespace-related magic functions.
2
+ """
3
+ #-----------------------------------------------------------------------------
4
+ # Copyright (c) 2012 The IPython Development Team.
5
+ #
6
+ # Distributed under the terms of the Modified BSD License.
7
+ #
8
+ # The full license is in the file COPYING.txt, distributed with this software.
9
+ #-----------------------------------------------------------------------------
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Imports
13
+ #-----------------------------------------------------------------------------
14
+
15
+ # Stdlib
16
+ import gc
17
+ import re
18
+ import sys
19
+
20
+ # Our own packages
21
+ from IPython.core import page
22
+ from IPython.core.error import StdinNotImplementedError, UsageError
23
+ from IPython.core.magic import Magics, magics_class, line_magic
24
+ from IPython.testing.skipdoctest import skip_doctest
25
+ from IPython.utils.encoding import DEFAULT_ENCODING
26
+ from IPython.utils.openpy import read_py_file
27
+ from IPython.utils.path import get_py_filename
28
+
29
+ #-----------------------------------------------------------------------------
30
+ # Magic implementation classes
31
+ #-----------------------------------------------------------------------------
32
+
33
+ @magics_class
34
+ class NamespaceMagics(Magics):
35
+ """Magics to manage various aspects of the user's namespace.
36
+
37
+ These include listing variables, introspecting into them, etc.
38
+ """
39
+
40
+ @line_magic
41
+ def pinfo(self, parameter_s='', namespaces=None):
42
+ """Provide detailed information about an object.
43
+
44
+ '%pinfo object' is just a synonym for object? or ?object."""
45
+
46
+ # print('pinfo par: <%s>' % parameter_s) # dbg
47
+ # detail_level: 0 -> obj? , 1 -> obj??
48
+ detail_level = 0
49
+ # We need to detect if we got called as 'pinfo pinfo foo', which can
50
+ # happen if the user types 'pinfo foo?' at the cmd line.
51
+ pinfo,qmark1,oname,qmark2 = \
52
+ re.match(r'(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups()
53
+ if pinfo or qmark1 or qmark2:
54
+ detail_level = 1
55
+ if "*" in oname:
56
+ self.psearch(oname)
57
+ else:
58
+ self.shell._inspect('pinfo', oname, detail_level=detail_level,
59
+ namespaces=namespaces)
60
+
61
+ @line_magic
62
+ def pinfo2(self, parameter_s='', namespaces=None):
63
+ """Provide extra detailed information about an object.
64
+
65
+ '%pinfo2 object' is just a synonym for object?? or ??object."""
66
+ self.shell._inspect('pinfo', parameter_s, detail_level=1,
67
+ namespaces=namespaces)
68
+
69
+ @skip_doctest
70
+ @line_magic
71
+ def pdef(self, parameter_s='', namespaces=None):
72
+ """Print the call signature for any callable object.
73
+
74
+ If the object is a class, print the constructor information.
75
+
76
+ Examples
77
+ --------
78
+ ::
79
+
80
+ In [3]: %pdef urllib.urlopen
81
+ urllib.urlopen(url, data=None, proxies=None)
82
+ """
83
+ self.shell._inspect('pdef',parameter_s, namespaces)
84
+
85
+ @line_magic
86
+ def pdoc(self, parameter_s='', namespaces=None):
87
+ """Print the docstring for an object.
88
+
89
+ If the given object is a class, it will print both the class and the
90
+ constructor docstrings."""
91
+ self.shell._inspect('pdoc',parameter_s, namespaces)
92
+
93
+ @line_magic
94
+ def psource(self, parameter_s='', namespaces=None):
95
+ """Print (or run through pager) the source code for an object."""
96
+ if not parameter_s:
97
+ raise UsageError('Missing object name.')
98
+ self.shell._inspect('psource',parameter_s, namespaces)
99
+
100
+ @line_magic
101
+ def pfile(self, parameter_s='', namespaces=None):
102
+ """Print (or run through pager) the file where an object is defined.
103
+
104
+ The file opens at the line where the object definition begins. IPython
105
+ will honor the environment variable PAGER if set, and otherwise will
106
+ do its best to print the file in a convenient form.
107
+
108
+ If the given argument is not an object currently defined, IPython will
109
+ try to interpret it as a filename (automatically adding a .py extension
110
+ if needed). You can thus use %pfile as a syntax highlighting code
111
+ viewer."""
112
+
113
+ # first interpret argument as an object name
114
+ out = self.shell._inspect('pfile',parameter_s, namespaces)
115
+ # if not, try the input as a filename
116
+ if out == 'not found':
117
+ try:
118
+ filename = get_py_filename(parameter_s)
119
+ except IOError as msg:
120
+ print(msg)
121
+ return
122
+ page.page(self.shell.pycolorize(read_py_file(filename, skip_encoding_cookie=False)))
123
+
124
+ @line_magic
125
+ def psearch(self, parameter_s=''):
126
+ """Search for object in namespaces by wildcard.
127
+
128
+ %psearch [options] PATTERN [OBJECT TYPE]
129
+
130
+ Note: ? can be used as a synonym for %psearch, at the beginning or at
131
+ the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the
132
+ rest of the command line must be unchanged (options come first), so
133
+ for example the following forms are equivalent
134
+
135
+ %psearch -i a* function
136
+ -i a* function?
137
+ ?-i a* function
138
+
139
+ Arguments:
140
+
141
+ PATTERN
142
+
143
+ where PATTERN is a string containing * as a wildcard similar to its
144
+ use in a shell. The pattern is matched in all namespaces on the
145
+ search path. By default objects starting with a single _ are not
146
+ matched, many IPython generated objects have a single
147
+ underscore. The default is case insensitive matching. Matching is
148
+ also done on the attributes of objects and not only on the objects
149
+ in a module.
150
+
151
+ [OBJECT TYPE]
152
+
153
+ Is the name of a python type from the types module. The name is
154
+ given in lowercase without the ending type, ex. StringType is
155
+ written string. By adding a type here only objects matching the
156
+ given type are matched. Using all here makes the pattern match all
157
+ types (this is the default).
158
+
159
+ Options:
160
+
161
+ -a: makes the pattern match even objects whose names start with a
162
+ single underscore. These names are normally omitted from the
163
+ search.
164
+
165
+ -i/-c: make the pattern case insensitive/sensitive. If neither of
166
+ these options are given, the default is read from your configuration
167
+ file, with the option ``InteractiveShell.wildcards_case_sensitive``.
168
+ If this option is not specified in your configuration file, IPython's
169
+ internal default is to do a case sensitive search.
170
+
171
+ -e/-s NAMESPACE: exclude/search a given namespace. The pattern you
172
+ specify can be searched in any of the following namespaces:
173
+ 'builtin', 'user', 'user_global','internal', 'alias', where
174
+ 'builtin' and 'user' are the search defaults. Note that you should
175
+ not use quotes when specifying namespaces.
176
+
177
+ -l: List all available object types for object matching. This function
178
+ can be used without arguments.
179
+
180
+ 'Builtin' contains the python module builtin, 'user' contains all
181
+ user data, 'alias' only contain the shell aliases and no python
182
+ objects, 'internal' contains objects used by IPython. The
183
+ 'user_global' namespace is only used by embedded IPython instances,
184
+ and it contains module-level globals. You can add namespaces to the
185
+ search with -s or exclude them with -e (these options can be given
186
+ more than once).
187
+
188
+ Examples
189
+ --------
190
+ ::
191
+
192
+ %psearch a* -> objects beginning with an a
193
+ %psearch -e builtin a* -> objects NOT in the builtin space starting in a
194
+ %psearch a* function -> all functions beginning with an a
195
+ %psearch re.e* -> objects beginning with an e in module re
196
+ %psearch r*.e* -> objects that start with e in modules starting in r
197
+ %psearch r*.* string -> all strings in modules beginning with r
198
+
199
+ Case sensitive search::
200
+
201
+ %psearch -c a* list all object beginning with lower case a
202
+
203
+ Show objects beginning with a single _::
204
+
205
+ %psearch -a _* list objects beginning with a single underscore
206
+
207
+ List available objects::
208
+
209
+ %psearch -l list all available object types
210
+ """
211
+ # default namespaces to be searched
212
+ def_search = ['user_local', 'user_global', 'builtin']
213
+
214
+ # Process options/args
215
+ opts,args = self.parse_options(parameter_s,'cias:e:l',list_all=True)
216
+ opt = opts.get
217
+ shell = self.shell
218
+ psearch = shell.inspector.psearch
219
+
220
+ # select list object types
221
+ list_types = False
222
+ if 'l' in opts:
223
+ list_types = True
224
+
225
+ # select case options
226
+ if 'i' in opts:
227
+ ignore_case = True
228
+ elif 'c' in opts:
229
+ ignore_case = False
230
+ else:
231
+ ignore_case = not shell.wildcards_case_sensitive
232
+
233
+ # Build list of namespaces to search from user options
234
+ def_search.extend(opt('s',[]))
235
+ ns_exclude = ns_exclude=opt('e',[])
236
+ ns_search = [nm for nm in def_search if nm not in ns_exclude]
237
+
238
+ # Call the actual search
239
+ try:
240
+ psearch(args,shell.ns_table,ns_search,
241
+ show_all=opt('a'),ignore_case=ignore_case, list_types=list_types)
242
+ except:
243
+ shell.showtraceback()
244
+
245
+ @skip_doctest
246
+ @line_magic
247
+ def who_ls(self, parameter_s=''):
248
+ """Return a sorted list of all interactive variables.
249
+
250
+ If arguments are given, only variables of types matching these
251
+ arguments are returned.
252
+
253
+ Examples
254
+ --------
255
+ Define two variables and list them with who_ls::
256
+
257
+ In [1]: alpha = 123
258
+
259
+ In [2]: beta = 'test'
260
+
261
+ In [3]: %who_ls
262
+ Out[3]: ['alpha', 'beta']
263
+
264
+ In [4]: %who_ls int
265
+ Out[4]: ['alpha']
266
+
267
+ In [5]: %who_ls str
268
+ Out[5]: ['beta']
269
+ """
270
+
271
+ user_ns = self.shell.user_ns
272
+ user_ns_hidden = self.shell.user_ns_hidden
273
+ nonmatching = object() # This can never be in user_ns
274
+ out = [ i for i in user_ns
275
+ if not i.startswith('_') \
276
+ and (user_ns[i] is not user_ns_hidden.get(i, nonmatching)) ]
277
+
278
+ typelist = parameter_s.split()
279
+ if typelist:
280
+ typeset = set(typelist)
281
+ out = [i for i in out if type(user_ns[i]).__name__ in typeset]
282
+
283
+ out.sort()
284
+ return out
285
+
286
+ @skip_doctest
287
+ @line_magic
288
+ def who(self, parameter_s=''):
289
+ """Print all interactive variables, with some minimal formatting.
290
+
291
+ If any arguments are given, only variables whose type matches one of
292
+ these are printed. For example::
293
+
294
+ %who function str
295
+
296
+ will only list functions and strings, excluding all other types of
297
+ variables. To find the proper type names, simply use type(var) at a
298
+ command line to see how python prints type names. For example:
299
+
300
+ ::
301
+
302
+ In [1]: type('hello')\\
303
+ Out[1]: <type 'str'>
304
+
305
+ indicates that the type name for strings is 'str'.
306
+
307
+ ``%who`` always excludes executed names loaded through your configuration
308
+ file and things which are internal to IPython.
309
+
310
+ This is deliberate, as typically you may load many modules and the
311
+ purpose of %who is to show you only what you've manually defined.
312
+
313
+ Examples
314
+ --------
315
+
316
+ Define two variables and list them with who::
317
+
318
+ In [1]: alpha = 123
319
+
320
+ In [2]: beta = 'test'
321
+
322
+ In [3]: %who
323
+ alpha beta
324
+
325
+ In [4]: %who int
326
+ alpha
327
+
328
+ In [5]: %who str
329
+ beta
330
+ """
331
+
332
+ varlist = self.who_ls(parameter_s)
333
+ if not varlist:
334
+ if parameter_s:
335
+ print('No variables match your requested type.')
336
+ else:
337
+ print('Interactive namespace is empty.')
338
+ return
339
+
340
+ # if we have variables, move on...
341
+ count = 0
342
+ for i in varlist:
343
+ print(i+'\t', end=' ')
344
+ count += 1
345
+ if count > 8:
346
+ count = 0
347
+ print()
348
+ print()
349
+
350
+ @skip_doctest
351
+ @line_magic
352
+ def whos(self, parameter_s=''):
353
+ """Like %who, but gives some extra information about each variable.
354
+
355
+ The same type filtering of %who can be applied here.
356
+
357
+ For all variables, the type is printed. Additionally it prints:
358
+
359
+ - For {},[],(): their length.
360
+
361
+ - For numpy arrays, a summary with shape, number of
362
+ elements, typecode and size in memory.
363
+
364
+ - For DataFrame and Series types: their shape.
365
+
366
+ - Everything else: a string representation, snipping their middle if
367
+ too long.
368
+
369
+ Examples
370
+ --------
371
+ Define two variables and list them with whos::
372
+
373
+ In [1]: alpha = 123
374
+
375
+ In [2]: beta = 'test'
376
+
377
+ In [3]: df = pd.DataFrame({"a": range(10), "b": range(10,20)})
378
+
379
+ In [4]: s = df["a"]
380
+
381
+ In [5]: %whos
382
+ Variable Type Data/Info
383
+ --------------------------------
384
+ alpha int 123
385
+ beta str test
386
+ df DataFrame Shape: (10, 2)
387
+ s Series Shape: (10, )
388
+ """
389
+
390
+ varnames = self.who_ls(parameter_s)
391
+ if not varnames:
392
+ if parameter_s:
393
+ print('No variables match your requested type.')
394
+ else:
395
+ print('Interactive namespace is empty.')
396
+ return
397
+
398
+ # if we have variables, move on...
399
+
400
+ # for these types, show len() instead of data:
401
+ seq_types = ['dict', 'list', 'tuple']
402
+
403
+ # for numpy arrays, display summary info
404
+ ndarray_type = None
405
+ if 'numpy' in sys.modules:
406
+ try:
407
+ from numpy import ndarray
408
+ except ImportError:
409
+ pass
410
+ else:
411
+ ndarray_type = ndarray.__name__
412
+
413
+ # Find all variable names and types so we can figure out column sizes
414
+
415
+ # some types are well known and can be shorter
416
+ abbrevs = {'IPython.core.macro.Macro' : 'Macro'}
417
+ def type_name(v):
418
+ tn = type(v).__name__
419
+ return abbrevs.get(tn,tn)
420
+
421
+ varlist = [self.shell.user_ns[n] for n in varnames]
422
+
423
+ typelist = []
424
+ for vv in varlist:
425
+ tt = type_name(vv)
426
+
427
+ if tt=='instance':
428
+ typelist.append( abbrevs.get(str(vv.__class__),
429
+ str(vv.__class__)))
430
+ else:
431
+ typelist.append(tt)
432
+
433
+ # column labels and # of spaces as separator
434
+ varlabel = 'Variable'
435
+ typelabel = 'Type'
436
+ datalabel = 'Data/Info'
437
+ colsep = 3
438
+ # variable format strings
439
+ vformat = "{0:<{varwidth}}{1:<{typewidth}}"
440
+ aformat = "%s: %s elems, type `%s`, %s bytes"
441
+ # find the size of the columns to format the output nicely
442
+ varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep
443
+ typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep
444
+ # table header
445
+ print(varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \
446
+ ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1))
447
+ # and the table itself
448
+ kb = 1024
449
+ Mb = 1048576 # kb**2
450
+ for vname,var,vtype in zip(varnames,varlist,typelist):
451
+ print(vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth), end=' ')
452
+ if vtype in seq_types:
453
+ print("n="+str(len(var)))
454
+ elif vtype == ndarray_type:
455
+ vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1]
456
+ if vtype==ndarray_type:
457
+ # numpy
458
+ vsize = var.size
459
+ vbytes = vsize*var.itemsize
460
+ vdtype = var.dtype
461
+
462
+ if vbytes < 100000:
463
+ print(aformat % (vshape, vsize, vdtype, vbytes))
464
+ else:
465
+ print(aformat % (vshape, vsize, vdtype, vbytes), end=' ')
466
+ if vbytes < Mb:
467
+ print("(%s kb)" % (vbytes / kb,))
468
+ else:
469
+ print("(%s Mb)" % (vbytes / Mb,))
470
+ elif vtype in ["DataFrame", "Series"]:
471
+ # Useful for DataFrames and Series
472
+ # Ought to work for both pandas and polars
473
+ print(f"Shape: {var.shape}")
474
+ else:
475
+ try:
476
+ vstr = str(var)
477
+ except UnicodeEncodeError:
478
+ vstr = var.encode(DEFAULT_ENCODING,
479
+ 'backslashreplace')
480
+ except:
481
+ vstr = "<object with id %d (str() failed)>" % id(var)
482
+ vstr = vstr.replace('\n', '\\n')
483
+ if len(vstr) < 50:
484
+ print(vstr)
485
+ else:
486
+ print(vstr[:25] + "<...>" + vstr[-25:])
487
+
488
+ @line_magic
489
+ def reset(self, parameter_s=''):
490
+ """Resets the namespace by removing all names defined by the user, if
491
+ called without arguments, or by removing some types of objects, such
492
+ as everything currently in IPython's In[] and Out[] containers (see
493
+ the parameters for details).
494
+
495
+ Parameters
496
+ ----------
497
+ -f
498
+ force reset without asking for confirmation.
499
+ -s
500
+ 'Soft' reset: Only clears your namespace, leaving history intact.
501
+ References to objects may be kept. By default (without this option),
502
+ we do a 'hard' reset, giving you a new session and removing all
503
+ references to objects from the current session.
504
+ --aggressive
505
+ Try to aggressively remove modules from sys.modules ; this
506
+ may allow you to reimport Python modules that have been updated and
507
+ pick up changes, but can have unintended consequences.
508
+
509
+ in
510
+ reset input history
511
+ out
512
+ reset output history
513
+ dhist
514
+ reset directory history
515
+ array
516
+ reset only variables that are NumPy arrays
517
+
518
+ See Also
519
+ --------
520
+ reset_selective : invoked as ``%reset_selective``
521
+
522
+ Examples
523
+ --------
524
+ ::
525
+
526
+ In [6]: a = 1
527
+
528
+ In [7]: a
529
+ Out[7]: 1
530
+
531
+ In [8]: 'a' in get_ipython().user_ns
532
+ Out[8]: True
533
+
534
+ In [9]: %reset -f
535
+
536
+ In [1]: 'a' in get_ipython().user_ns
537
+ Out[1]: False
538
+
539
+ In [2]: %reset -f in
540
+ Flushing input history
541
+
542
+ In [3]: %reset -f dhist in
543
+ Flushing directory history
544
+ Flushing input history
545
+
546
+ Notes
547
+ -----
548
+ Calling this magic from clients that do not implement standard input,
549
+ such as the ipython notebook interface, will reset the namespace
550
+ without confirmation.
551
+ """
552
+ opts, args = self.parse_options(parameter_s, "sf", "aggressive", mode="list")
553
+ if "f" in opts:
554
+ ans = True
555
+ else:
556
+ try:
557
+ ans = self.shell.ask_yes_no(
558
+ "Once deleted, variables cannot be recovered. Proceed (y/[n])?",
559
+ default='n')
560
+ except StdinNotImplementedError:
561
+ ans = True
562
+ if not ans:
563
+ print('Nothing done.')
564
+ return
565
+
566
+ if 's' in opts: # Soft reset
567
+ user_ns = self.shell.user_ns
568
+ for i in self.who_ls():
569
+ del(user_ns[i])
570
+ elif len(args) == 0: # Hard reset
571
+ self.shell.reset(new_session=False, aggressive=("aggressive" in opts))
572
+
573
+ # reset in/out/dhist/array: previously extensinions/clearcmd.py
574
+ ip = self.shell
575
+ user_ns = self.shell.user_ns # local lookup, heavily used
576
+
577
+ for target in args:
578
+ target = target.lower() # make matches case insensitive
579
+ if target == 'out':
580
+ print("Flushing output cache (%d entries)" % len(user_ns['_oh']))
581
+ self.shell.displayhook.flush()
582
+
583
+ elif target == 'in':
584
+ print("Flushing input history")
585
+ pc = self.shell.displayhook.prompt_count + 1
586
+ for n in range(1, pc):
587
+ key = '_i'+repr(n)
588
+ user_ns.pop(key,None)
589
+ user_ns.update(dict(_i=u'',_ii=u'',_iii=u''))
590
+ hm = ip.history_manager
591
+ # don't delete these, as %save and %macro depending on the
592
+ # length of these lists to be preserved
593
+ hm.input_hist_parsed[:] = [''] * pc
594
+ hm.input_hist_raw[:] = [''] * pc
595
+ # hm has internal machinery for _i,_ii,_iii, clear it out
596
+ hm._i = hm._ii = hm._iii = hm._i00 = u''
597
+
598
+ elif target == 'array':
599
+ # Support cleaning up numpy arrays
600
+ try:
601
+ from numpy import ndarray
602
+ # This must be done with items and not iteritems because
603
+ # we're going to modify the dict in-place.
604
+ for x,val in list(user_ns.items()):
605
+ if isinstance(val,ndarray):
606
+ del user_ns[x]
607
+ except ImportError:
608
+ print("reset array only works if Numpy is available.")
609
+
610
+ elif target == 'dhist':
611
+ print("Flushing directory history")
612
+ del user_ns['_dh'][:]
613
+
614
+ else:
615
+ print("Don't know how to reset ", end=' ')
616
+ print(target + ", please run `%reset?` for details")
617
+
618
+ gc.collect()
619
+
620
+ @line_magic
621
+ def reset_selective(self, parameter_s=''):
622
+ """Resets the namespace by removing names defined by the user.
623
+
624
+ Input/Output history are left around in case you need them.
625
+
626
+ %reset_selective [-f] regex
627
+
628
+ No action is taken if regex is not included
629
+
630
+ Options
631
+ -f : force reset without asking for confirmation.
632
+
633
+ See Also
634
+ --------
635
+ reset : invoked as ``%reset``
636
+
637
+ Examples
638
+ --------
639
+ We first fully reset the namespace so your output looks identical to
640
+ this example for pedagogical reasons; in practice you do not need a
641
+ full reset::
642
+
643
+ In [1]: %reset -f
644
+
645
+ Now, with a clean namespace we can make a few variables and use
646
+ ``%reset_selective`` to only delete names that match our regexp::
647
+
648
+ In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8
649
+
650
+ In [3]: who_ls
651
+ Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c']
652
+
653
+ In [4]: %reset_selective -f b[2-3]m
654
+
655
+ In [5]: who_ls
656
+ Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
657
+
658
+ In [6]: %reset_selective -f d
659
+
660
+ In [7]: who_ls
661
+ Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
662
+
663
+ In [8]: %reset_selective -f c
664
+
665
+ In [9]: who_ls
666
+ Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m']
667
+
668
+ In [10]: %reset_selective -f b
669
+
670
+ In [11]: who_ls
671
+ Out[11]: ['a']
672
+
673
+ Notes
674
+ -----
675
+ Calling this magic from clients that do not implement standard input,
676
+ such as the ipython notebook interface, will reset the namespace
677
+ without confirmation.
678
+ """
679
+
680
+ opts, regex = self.parse_options(parameter_s,'f')
681
+
682
+ if 'f' in opts:
683
+ ans = True
684
+ else:
685
+ try:
686
+ ans = self.shell.ask_yes_no(
687
+ "Once deleted, variables cannot be recovered. Proceed (y/[n])? ",
688
+ default='n')
689
+ except StdinNotImplementedError:
690
+ ans = True
691
+ if not ans:
692
+ print('Nothing done.')
693
+ return
694
+ user_ns = self.shell.user_ns
695
+ if not regex:
696
+ print('No regex pattern specified. Nothing done.')
697
+ return
698
+ else:
699
+ try:
700
+ m = re.compile(regex)
701
+ except TypeError as e:
702
+ raise TypeError('regex must be a string or compiled pattern') from e
703
+ for i in self.who_ls():
704
+ if m.search(i):
705
+ del(user_ns[i])
706
+
707
+ @line_magic
708
+ def xdel(self, parameter_s=''):
709
+ """Delete a variable, trying to clear it from anywhere that
710
+ IPython's machinery has references to it. By default, this uses
711
+ the identity of the named object in the user namespace to remove
712
+ references held under other names. The object is also removed
713
+ from the output history.
714
+
715
+ Options
716
+ -n : Delete the specified name from all namespaces, without
717
+ checking their identity.
718
+ """
719
+ opts, varname = self.parse_options(parameter_s,'n')
720
+ try:
721
+ self.shell.del_var(varname, ('n' in opts))
722
+ except (NameError, ValueError) as e:
723
+ print(type(e).__name__ +": "+ str(e))
lib/python3.12/site-packages/IPython/core/magics/osm.py ADDED
@@ -0,0 +1,855 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of magic functions for interaction with the OS.
2
+
3
+ Note: this module is named 'osm' instead of 'os' to avoid a collision with the
4
+ builtin.
5
+ """
6
+ # Copyright (c) IPython Development Team.
7
+ # Distributed under the terms of the Modified BSD License.
8
+
9
+ import io
10
+ import os
11
+ import pathlib
12
+ import re
13
+ import sys
14
+ from pprint import pformat
15
+
16
+ from IPython.core import magic_arguments
17
+ from IPython.core import oinspect
18
+ from IPython.core import page
19
+ from IPython.core.alias import AliasError, Alias
20
+ from IPython.core.error import UsageError
21
+ from IPython.core.magic import (
22
+ Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
23
+ )
24
+ from IPython.testing.skipdoctest import skip_doctest
25
+ from IPython.utils.openpy import source_to_unicode
26
+ from IPython.utils.process import abbrev_cwd
27
+ from IPython.utils.terminal import set_term_title
28
+ from traitlets import Bool
29
+ from warnings import warn
30
+
31
+
32
+ @magics_class
33
+ class OSMagics(Magics):
34
+ """Magics to interact with the underlying OS (shell-type functionality).
35
+ """
36
+
37
+ cd_force_quiet = Bool(False,
38
+ help="Force %cd magic to be quiet even if -q is not passed."
39
+ ).tag(config=True)
40
+
41
+ def __init__(self, shell=None, **kwargs):
42
+
43
+ # Now define isexec in a cross platform manner.
44
+ self.is_posix = False
45
+ self.execre = None
46
+ if os.name == 'posix':
47
+ self.is_posix = True
48
+ else:
49
+ try:
50
+ winext = os.environ['pathext'].replace(';','|').replace('.','')
51
+ except KeyError:
52
+ winext = 'exe|com|bat|py'
53
+ try:
54
+ self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
55
+ except re.error:
56
+ warn("Seems like your pathext environmental "
57
+ "variable is malformed. Please check it to "
58
+ "enable a proper handle of file extensions "
59
+ "managed for your system")
60
+ winext = 'exe|com|bat|py'
61
+ self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
62
+
63
+ # call up the chain
64
+ super().__init__(shell=shell, **kwargs)
65
+
66
+
67
+ def _isexec_POSIX(self, file):
68
+ """
69
+ Test for executable on a POSIX system
70
+ """
71
+ if os.access(file.path, os.X_OK):
72
+ # will fail on maxOS if access is not X_OK
73
+ return file.is_file()
74
+ return False
75
+
76
+
77
+
78
+ def _isexec_WIN(self, file):
79
+ """
80
+ Test for executable file on non POSIX system
81
+ """
82
+ return file.is_file() and self.execre.match(file.name) is not None
83
+
84
+ def isexec(self, file):
85
+ """
86
+ Test for executable file on non POSIX system
87
+ """
88
+ if self.is_posix:
89
+ return self._isexec_POSIX(file)
90
+ else:
91
+ return self._isexec_WIN(file)
92
+
93
+
94
+ @skip_doctest
95
+ @line_magic
96
+ def alias(self, parameter_s=''):
97
+ """Define an alias for a system command.
98
+
99
+ '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
100
+
101
+ Then, typing 'alias_name params' will execute the system command 'cmd
102
+ params' (from your underlying operating system).
103
+
104
+ Aliases have lower precedence than magic functions and Python normal
105
+ variables, so if 'foo' is both a Python variable and an alias, the
106
+ alias can not be executed until 'del foo' removes the Python variable.
107
+
108
+ You can use the %l specifier in an alias definition to represent the
109
+ whole line when the alias is called. For example::
110
+
111
+ In [2]: alias bracket echo "Input in brackets: <%l>"
112
+ In [3]: bracket hello world
113
+ Input in brackets: <hello world>
114
+
115
+ You can also define aliases with parameters using %s specifiers (one
116
+ per parameter)::
117
+
118
+ In [1]: alias parts echo first %s second %s
119
+ In [2]: %parts A B
120
+ first A second B
121
+ In [3]: %parts A
122
+ Incorrect number of arguments: 2 expected.
123
+ parts is an alias to: 'echo first %s second %s'
124
+
125
+ Note that %l and %s are mutually exclusive. You can only use one or
126
+ the other in your aliases.
127
+
128
+ Aliases expand Python variables just like system calls using ! or !!
129
+ do: all expressions prefixed with '$' get expanded. For details of
130
+ the semantic rules, see PEP-215:
131
+ https://peps.python.org/pep-0215/. This is the library used by
132
+ IPython for variable expansion. If you want to access a true shell
133
+ variable, an extra $ is necessary to prevent its expansion by
134
+ IPython::
135
+
136
+ In [6]: alias show echo
137
+ In [7]: PATH='A Python string'
138
+ In [8]: show $PATH
139
+ A Python string
140
+ In [9]: show $$PATH
141
+ /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
142
+
143
+ You can use the alias facility to access all of $PATH. See the %rehashx
144
+ function, which automatically creates aliases for the contents of your
145
+ $PATH.
146
+
147
+ If called with no parameters, %alias prints the current alias table
148
+ for your system. For posix systems, the default aliases are 'cat',
149
+ 'cp', 'mv', 'rm', 'rmdir', and 'mkdir', and other platform-specific
150
+ aliases are added. For windows-based systems, the default aliases are
151
+ 'copy', 'ddir', 'echo', 'ls', 'ldir', 'mkdir', 'ren', and 'rmdir'.
152
+
153
+ You can see the definition of alias by adding a question mark in the
154
+ end::
155
+
156
+ In [1]: cat?
157
+ Repr: <alias cat for 'cat'>"""
158
+
159
+ par = parameter_s.strip()
160
+ if not par:
161
+ aliases = sorted(self.shell.alias_manager.aliases)
162
+ # stored = self.shell.db.get('stored_aliases', {} )
163
+ # for k, v in stored:
164
+ # atab.append(k, v[0])
165
+
166
+ print("Total number of aliases:", len(aliases))
167
+ sys.stdout.flush()
168
+ return aliases
169
+
170
+ # Now try to define a new one
171
+ try:
172
+ alias,cmd = par.split(None, 1)
173
+ except TypeError:
174
+ print(oinspect.getdoc(self.alias))
175
+ return
176
+
177
+ try:
178
+ self.shell.alias_manager.define_alias(alias, cmd)
179
+ except AliasError as e:
180
+ print(e)
181
+ # end magic_alias
182
+
183
+ @line_magic
184
+ def unalias(self, parameter_s=''):
185
+ """Remove an alias"""
186
+
187
+ aname = parameter_s.strip()
188
+ try:
189
+ self.shell.alias_manager.undefine_alias(aname)
190
+ except ValueError as e:
191
+ print(e)
192
+ return
193
+
194
+ stored = self.shell.db.get('stored_aliases', {} )
195
+ if aname in stored:
196
+ print("Removing %stored alias",aname)
197
+ del stored[aname]
198
+ self.shell.db['stored_aliases'] = stored
199
+
200
+ @line_magic
201
+ def rehashx(self, parameter_s=''):
202
+ """Update the alias table with all executable files in $PATH.
203
+
204
+ rehashx explicitly checks that every entry in $PATH is a file
205
+ with execute access (os.X_OK).
206
+
207
+ Under Windows, it checks executability as a match against a
208
+ '|'-separated string of extensions, stored in the IPython config
209
+ variable win_exec_ext. This defaults to 'exe|com|bat'.
210
+
211
+ This function also resets the root module cache of module completer,
212
+ used on slow filesystems.
213
+ """
214
+ from IPython.core.alias import InvalidAliasError
215
+
216
+ # for the benefit of module completer in ipy_completers.py
217
+ del self.shell.db['rootmodules_cache']
218
+
219
+ path = [os.path.abspath(os.path.expanduser(p)) for p in
220
+ os.environ.get('PATH','').split(os.pathsep)]
221
+
222
+ syscmdlist = []
223
+ savedir = os.getcwd()
224
+
225
+ # Now walk the paths looking for executables to alias.
226
+ try:
227
+ # write the whole loop for posix/Windows so we don't have an if in
228
+ # the innermost part
229
+ if self.is_posix:
230
+ for pdir in path:
231
+ try:
232
+ os.chdir(pdir)
233
+ except OSError:
234
+ continue
235
+
236
+ # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
237
+ dirlist = os.scandir(path=pdir)
238
+ for ff in dirlist:
239
+ if self.isexec(ff):
240
+ fname = ff.name
241
+ try:
242
+ # Removes dots from the name since ipython
243
+ # will assume names with dots to be python.
244
+ if not self.shell.alias_manager.is_alias(fname):
245
+ self.shell.alias_manager.define_alias(
246
+ fname.replace('.',''), fname)
247
+ except InvalidAliasError:
248
+ pass
249
+ else:
250
+ syscmdlist.append(fname)
251
+ else:
252
+ no_alias = Alias.blacklist
253
+ for pdir in path:
254
+ try:
255
+ os.chdir(pdir)
256
+ except OSError:
257
+ continue
258
+
259
+ # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
260
+ dirlist = os.scandir(pdir)
261
+ for ff in dirlist:
262
+ fname = ff.name
263
+ base, ext = os.path.splitext(fname)
264
+ if self.isexec(ff) and base.lower() not in no_alias:
265
+ if ext.lower() == '.exe':
266
+ fname = base
267
+ try:
268
+ # Removes dots from the name since ipython
269
+ # will assume names with dots to be python.
270
+ self.shell.alias_manager.define_alias(
271
+ base.lower().replace('.',''), fname)
272
+ except InvalidAliasError:
273
+ pass
274
+ syscmdlist.append(fname)
275
+
276
+ self.shell.db['syscmdlist'] = syscmdlist
277
+ finally:
278
+ os.chdir(savedir)
279
+
280
+ @skip_doctest
281
+ @line_magic
282
+ def pwd(self, parameter_s=''):
283
+ """Return the current working directory path.
284
+
285
+ Examples
286
+ --------
287
+ ::
288
+
289
+ In [9]: pwd
290
+ Out[9]: '/home/tsuser/sprint/ipython'
291
+ """
292
+ try:
293
+ return os.getcwd()
294
+ except FileNotFoundError as e:
295
+ raise UsageError("CWD no longer exists - please use %cd to change directory.") from e
296
+
297
+ @skip_doctest
298
+ @line_magic
299
+ def cd(self, parameter_s=''):
300
+ """Change the current working directory.
301
+
302
+ This command automatically maintains an internal list of directories
303
+ you visit during your IPython session, in the variable ``_dh``. The
304
+ command :magic:`%dhist` shows this history nicely formatted. You can
305
+ also do ``cd -<tab>`` to see directory history conveniently.
306
+ Usage:
307
+
308
+ - ``cd 'dir'``: changes to directory 'dir'.
309
+ - ``cd -``: changes to the last visited directory.
310
+ - ``cd -<n>``: changes to the n-th directory in the directory history.
311
+ - ``cd --foo``: change to directory that matches 'foo' in history
312
+ - ``cd -b <bookmark_name>``: jump to a bookmark set by %bookmark
313
+ - Hitting a tab key after ``cd -b`` allows you to tab-complete
314
+ bookmark names.
315
+
316
+ .. note::
317
+ ``cd <bookmark_name>`` is enough if there is no directory
318
+ ``<bookmark_name>``, but a bookmark with the name exists.
319
+
320
+ Options:
321
+
322
+ -q Be quiet. Do not print the working directory after the
323
+ cd command is executed. By default IPython's cd
324
+ command does print this directory, since the default
325
+ prompts do not display path information.
326
+
327
+ .. note::
328
+ Note that ``!cd`` doesn't work for this purpose because the shell
329
+ where ``!command`` runs is immediately discarded after executing
330
+ 'command'.
331
+
332
+ Examples
333
+ --------
334
+ ::
335
+
336
+ In [10]: cd parent/child
337
+ /home/tsuser/parent/child
338
+ """
339
+
340
+ try:
341
+ oldcwd = os.getcwd()
342
+ except FileNotFoundError:
343
+ # Happens if the CWD has been deleted.
344
+ oldcwd = None
345
+
346
+ numcd = re.match(r'(-)(\d+)$',parameter_s)
347
+ # jump in directory history by number
348
+ if numcd:
349
+ nn = int(numcd.group(2))
350
+ try:
351
+ ps = self.shell.user_ns['_dh'][nn]
352
+ except IndexError:
353
+ print('The requested directory does not exist in history.')
354
+ return
355
+ else:
356
+ opts = {}
357
+ elif parameter_s.startswith('--'):
358
+ ps = None
359
+ fallback = None
360
+ pat = parameter_s[2:]
361
+ dh = self.shell.user_ns['_dh']
362
+ # first search only by basename (last component)
363
+ for ent in reversed(dh):
364
+ if pat in os.path.basename(ent) and os.path.isdir(ent):
365
+ ps = ent
366
+ break
367
+
368
+ if fallback is None and pat in ent and os.path.isdir(ent):
369
+ fallback = ent
370
+
371
+ # if we have no last part match, pick the first full path match
372
+ if ps is None:
373
+ ps = fallback
374
+
375
+ if ps is None:
376
+ print("No matching entry in directory history")
377
+ return
378
+ else:
379
+ opts = {}
380
+
381
+
382
+ else:
383
+ opts, ps = self.parse_options(parameter_s, 'qb', mode='string')
384
+ # jump to previous
385
+ if ps == '-':
386
+ try:
387
+ ps = self.shell.user_ns['_dh'][-2]
388
+ except IndexError as e:
389
+ raise UsageError('%cd -: No previous directory to change to.') from e
390
+ # jump to bookmark if needed
391
+ else:
392
+ if not os.path.isdir(ps) or 'b' in opts:
393
+ bkms = self.shell.db.get('bookmarks', {})
394
+
395
+ if ps in bkms:
396
+ target = bkms[ps]
397
+ print('(bookmark:%s) -> %s' % (ps, target))
398
+ ps = target
399
+ else:
400
+ if 'b' in opts:
401
+ raise UsageError("Bookmark '%s' not found. "
402
+ "Use '%%bookmark -l' to see your bookmarks." % ps)
403
+
404
+ # at this point ps should point to the target dir
405
+ if ps:
406
+ try:
407
+ os.chdir(os.path.expanduser(ps))
408
+ if hasattr(self.shell, 'term_title') and self.shell.term_title:
409
+ set_term_title(self.shell.term_title_format.format(cwd=abbrev_cwd()))
410
+ except OSError:
411
+ print(sys.exc_info()[1])
412
+ else:
413
+ cwd = pathlib.Path.cwd()
414
+ dhist = self.shell.user_ns['_dh']
415
+ if oldcwd != cwd:
416
+ dhist.append(cwd)
417
+ self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
418
+
419
+ else:
420
+ os.chdir(self.shell.home_dir)
421
+ if hasattr(self.shell, 'term_title') and self.shell.term_title:
422
+ set_term_title(self.shell.term_title_format.format(cwd="~"))
423
+ cwd = pathlib.Path.cwd()
424
+ dhist = self.shell.user_ns['_dh']
425
+
426
+ if oldcwd != cwd:
427
+ dhist.append(cwd)
428
+ self.shell.db["dhist"] = compress_dhist(dhist)[-100:]
429
+ if "q" not in opts and not self.cd_force_quiet and self.shell.user_ns["_dh"]:
430
+ print(self.shell.user_ns["_dh"][-1])
431
+
432
+ @line_magic
433
+ def env(self, parameter_s=''):
434
+ """Get, set, or list environment variables.
435
+
436
+ Usage:\\
437
+
438
+ :``%env``: lists all environment variables/values
439
+ :``%env var``: get value for var
440
+ :``%env var val``: set value for var
441
+ :``%env var=val``: set value for var
442
+ :``%env var=$val``: set value for var, using python expansion if possible
443
+ """
444
+ if parameter_s.strip():
445
+ split = '=' if '=' in parameter_s else ' '
446
+ bits = parameter_s.split(split)
447
+ if len(bits) == 1:
448
+ key = parameter_s.strip()
449
+ if key in os.environ:
450
+ return os.environ[key]
451
+ else:
452
+ err = "Environment does not have key: {0}".format(key)
453
+ raise UsageError(err)
454
+ if len(bits) > 1:
455
+ return self.set_env(parameter_s)
456
+ env = dict(os.environ)
457
+ # hide likely secrets when printing the whole environment
458
+ for key in list(env):
459
+ if any(s in key.lower() for s in ('key', 'token', 'secret')):
460
+ env[key] = '<hidden>'
461
+
462
+ return env
463
+
464
+ @line_magic
465
+ def set_env(self, parameter_s):
466
+ """Set environment variables. Assumptions are that either "val" is a
467
+ name in the user namespace, or val is something that evaluates to a
468
+ string.
469
+
470
+ Usage:\\
471
+ :``%set_env var val``: set value for var
472
+ :``%set_env var=val``: set value for var
473
+ :``%set_env var=$val``: set value for var, using python expansion if possible
474
+ """
475
+ split = '=' if '=' in parameter_s else ' '
476
+ bits = parameter_s.split(split, 1)
477
+ if not parameter_s.strip() or len(bits)<2:
478
+ raise UsageError("usage is 'set_env var=val'")
479
+ var = bits[0].strip()
480
+ val = bits[1].strip()
481
+ if re.match(r'.*\s.*', var):
482
+ # an environment variable with whitespace is almost certainly
483
+ # not what the user intended. what's more likely is the wrong
484
+ # split was chosen, ie for "set_env cmd_args A=B", we chose
485
+ # '=' for the split and should have chosen ' '. to get around
486
+ # this, users should just assign directly to os.environ or use
487
+ # standard magic {var} expansion.
488
+ err = "refusing to set env var with whitespace: '{0}'"
489
+ err = err.format(val)
490
+ raise UsageError(err)
491
+ os.environ[var] = val
492
+ print('env: {0}={1}'.format(var,val))
493
+
494
+ @line_magic
495
+ def pushd(self, parameter_s=''):
496
+ """Place the current dir on stack and change directory.
497
+
498
+ Usage:\\
499
+ %pushd ['dirname']
500
+ """
501
+
502
+ dir_s = self.shell.dir_stack
503
+ tgt = os.path.expanduser(parameter_s)
504
+ cwd = os.getcwd().replace(self.shell.home_dir,'~')
505
+ if tgt:
506
+ self.cd(parameter_s)
507
+ dir_s.insert(0,cwd)
508
+ return self.shell.run_line_magic('dirs', '')
509
+
510
+ @line_magic
511
+ def popd(self, parameter_s=''):
512
+ """Change to directory popped off the top of the stack.
513
+ """
514
+ if not self.shell.dir_stack:
515
+ raise UsageError("%popd on empty stack")
516
+ top = self.shell.dir_stack.pop(0)
517
+ self.cd(top)
518
+ print("popd ->",top)
519
+
520
+ @line_magic
521
+ def dirs(self, parameter_s=''):
522
+ """Return the current directory stack."""
523
+
524
+ return self.shell.dir_stack
525
+
526
+ @line_magic
527
+ def dhist(self, parameter_s=''):
528
+ """Print your history of visited directories.
529
+
530
+ %dhist -> print full history\\
531
+ %dhist n -> print last n entries only\\
532
+ %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
533
+
534
+ This history is automatically maintained by the %cd command, and
535
+ always available as the global list variable _dh. You can use %cd -<n>
536
+ to go to directory number <n>.
537
+
538
+ Note that most of time, you should view directory history by entering
539
+ cd -<TAB>.
540
+
541
+ """
542
+
543
+ dh = self.shell.user_ns['_dh']
544
+ if parameter_s:
545
+ try:
546
+ args = map(int,parameter_s.split())
547
+ except:
548
+ self.arg_err(self.dhist)
549
+ return
550
+ if len(args) == 1:
551
+ ini,fin = max(len(dh)-(args[0]),0),len(dh)
552
+ elif len(args) == 2:
553
+ ini,fin = args
554
+ fin = min(fin, len(dh))
555
+ else:
556
+ self.arg_err(self.dhist)
557
+ return
558
+ else:
559
+ ini,fin = 0,len(dh)
560
+ print('Directory history (kept in _dh)')
561
+ for i in range(ini, fin):
562
+ print("%d: %s" % (i, dh[i]))
563
+
564
+ @skip_doctest
565
+ @line_magic
566
+ def sc(self, parameter_s=''):
567
+ """Shell capture - run shell command and capture output (DEPRECATED use !).
568
+
569
+ DEPRECATED. Suboptimal, retained for backwards compatibility.
570
+
571
+ You should use the form 'var = !command' instead. Example:
572
+
573
+ "%sc -l myfiles = ls ~" should now be written as
574
+
575
+ "myfiles = !ls ~"
576
+
577
+ myfiles.s, myfiles.l and myfiles.n still apply as documented
578
+ below.
579
+
580
+ --
581
+ %sc [options] varname=command
582
+
583
+ IPython will run the given command using commands.getoutput(), and
584
+ will then update the user's interactive namespace with a variable
585
+ called varname, containing the value of the call. Your command can
586
+ contain shell wildcards, pipes, etc.
587
+
588
+ The '=' sign in the syntax is mandatory, and the variable name you
589
+ supply must follow Python's standard conventions for valid names.
590
+
591
+ (A special format without variable name exists for internal use)
592
+
593
+ Options:
594
+
595
+ -l: list output. Split the output on newlines into a list before
596
+ assigning it to the given variable. By default the output is stored
597
+ as a single string.
598
+
599
+ -v: verbose. Print the contents of the variable.
600
+
601
+ In most cases you should not need to split as a list, because the
602
+ returned value is a special type of string which can automatically
603
+ provide its contents either as a list (split on newlines) or as a
604
+ space-separated string. These are convenient, respectively, either
605
+ for sequential processing or to be passed to a shell command.
606
+
607
+ For example::
608
+
609
+ # Capture into variable a
610
+ In [1]: sc a=ls *py
611
+
612
+ # a is a string with embedded newlines
613
+ In [2]: a
614
+ Out[2]: 'setup.py\\nwin32_manual_post_install.py'
615
+
616
+ # which can be seen as a list:
617
+ In [3]: a.l
618
+ Out[3]: ['setup.py', 'win32_manual_post_install.py']
619
+
620
+ # or as a whitespace-separated string:
621
+ In [4]: a.s
622
+ Out[4]: 'setup.py win32_manual_post_install.py'
623
+
624
+ # a.s is useful to pass as a single command line:
625
+ In [5]: !wc -l $a.s
626
+ 146 setup.py
627
+ 130 win32_manual_post_install.py
628
+ 276 total
629
+
630
+ # while the list form is useful to loop over:
631
+ In [6]: for f in a.l:
632
+ ...: !wc -l $f
633
+ ...:
634
+ 146 setup.py
635
+ 130 win32_manual_post_install.py
636
+
637
+ Similarly, the lists returned by the -l option are also special, in
638
+ the sense that you can equally invoke the .s attribute on them to
639
+ automatically get a whitespace-separated string from their contents::
640
+
641
+ In [7]: sc -l b=ls *py
642
+
643
+ In [8]: b
644
+ Out[8]: ['setup.py', 'win32_manual_post_install.py']
645
+
646
+ In [9]: b.s
647
+ Out[9]: 'setup.py win32_manual_post_install.py'
648
+
649
+ In summary, both the lists and strings used for output capture have
650
+ the following special attributes::
651
+
652
+ .l (or .list) : value as list.
653
+ .n (or .nlstr): value as newline-separated string.
654
+ .s (or .spstr): value as space-separated string.
655
+ """
656
+
657
+ opts,args = self.parse_options(parameter_s, 'lv')
658
+ # Try to get a variable name and command to run
659
+ try:
660
+ # the variable name must be obtained from the parse_options
661
+ # output, which uses shlex.split to strip options out.
662
+ var,_ = args.split('=', 1)
663
+ var = var.strip()
664
+ # But the command has to be extracted from the original input
665
+ # parameter_s, not on what parse_options returns, to avoid the
666
+ # quote stripping which shlex.split performs on it.
667
+ _,cmd = parameter_s.split('=', 1)
668
+ except ValueError:
669
+ var,cmd = '',''
670
+ # If all looks ok, proceed
671
+ split = 'l' in opts
672
+ out = self.shell.getoutput(cmd, split=split)
673
+ if 'v' in opts:
674
+ print('%s ==\n%s' % (var, pformat(out)))
675
+ if var:
676
+ self.shell.user_ns.update({var:out})
677
+ else:
678
+ return out
679
+
680
+ @line_cell_magic
681
+ def sx(self, line='', cell=None):
682
+ """Shell execute - run shell command and capture output (!! is short-hand).
683
+
684
+ %sx command
685
+
686
+ IPython will run the given command using commands.getoutput(), and
687
+ return the result formatted as a list (split on '\\n'). Since the
688
+ output is _returned_, it will be stored in ipython's regular output
689
+ cache Out[N] and in the '_N' automatic variables.
690
+
691
+ Notes:
692
+
693
+ 1) If an input line begins with '!!', then %sx is automatically
694
+ invoked. That is, while::
695
+
696
+ !ls
697
+
698
+ causes ipython to simply issue system('ls'), typing::
699
+
700
+ !!ls
701
+
702
+ is a shorthand equivalent to::
703
+
704
+ %sx ls
705
+
706
+ 2) %sx differs from %sc in that %sx automatically splits into a list,
707
+ like '%sc -l'. The reason for this is to make it as easy as possible
708
+ to process line-oriented shell output via further python commands.
709
+ %sc is meant to provide much finer control, but requires more
710
+ typing.
711
+
712
+ 3) Just like %sc -l, this is a list with special attributes:
713
+ ::
714
+
715
+ .l (or .list) : value as list.
716
+ .n (or .nlstr): value as newline-separated string.
717
+ .s (or .spstr): value as whitespace-separated string.
718
+
719
+ This is very useful when trying to use such lists as arguments to
720
+ system commands."""
721
+
722
+ if cell is None:
723
+ # line magic
724
+ return self.shell.getoutput(line)
725
+ else:
726
+ opts,args = self.parse_options(line, '', 'out=')
727
+ output = self.shell.getoutput(cell)
728
+ out_name = opts.get('out', opts.get('o'))
729
+ if out_name:
730
+ self.shell.user_ns[out_name] = output
731
+ else:
732
+ return output
733
+
734
+ system = line_cell_magic('system')(sx)
735
+ bang = cell_magic('!')(sx)
736
+
737
+ @line_magic
738
+ def bookmark(self, parameter_s=''):
739
+ """Manage IPython's bookmark system.
740
+
741
+ %bookmark <name> - set bookmark to current dir
742
+ %bookmark <name> <dir> - set bookmark to <dir>
743
+ %bookmark -l - list all bookmarks
744
+ %bookmark -d <name> - remove bookmark
745
+ %bookmark -r - remove all bookmarks
746
+
747
+ You can later on access a bookmarked folder with::
748
+
749
+ %cd -b <name>
750
+
751
+ or simply '%cd <name>' if there is no directory called <name> AND
752
+ there is such a bookmark defined.
753
+
754
+ Your bookmarks persist through IPython sessions, but they are
755
+ associated with each profile."""
756
+
757
+ opts,args = self.parse_options(parameter_s,'drl',mode='list')
758
+ if len(args) > 2:
759
+ raise UsageError("%bookmark: too many arguments")
760
+
761
+ bkms = self.shell.db.get('bookmarks',{})
762
+
763
+ if 'd' in opts:
764
+ try:
765
+ todel = args[0]
766
+ except IndexError as e:
767
+ raise UsageError(
768
+ "%bookmark -d: must provide a bookmark to delete") from e
769
+ else:
770
+ try:
771
+ del bkms[todel]
772
+ except KeyError as e:
773
+ raise UsageError(
774
+ "%%bookmark -d: Can't delete bookmark '%s'" % todel) from e
775
+
776
+ elif 'r' in opts:
777
+ bkms = {}
778
+ elif 'l' in opts:
779
+ bks = sorted(bkms)
780
+ if bks:
781
+ size = max(map(len, bks))
782
+ else:
783
+ size = 0
784
+ fmt = '%-'+str(size)+'s -> %s'
785
+ print('Current bookmarks:')
786
+ for bk in bks:
787
+ print(fmt % (bk, bkms[bk]))
788
+ else:
789
+ if not args:
790
+ raise UsageError("%bookmark: You must specify the bookmark name")
791
+ elif len(args)==1:
792
+ bkms[args[0]] = os.getcwd()
793
+ elif len(args)==2:
794
+ bkms[args[0]] = args[1]
795
+ self.shell.db['bookmarks'] = bkms
796
+
797
+ @line_magic
798
+ def pycat(self, parameter_s=''):
799
+ """Show a syntax-highlighted file through a pager.
800
+
801
+ This magic is similar to the cat utility, but it will assume the file
802
+ to be Python source and will show it with syntax highlighting.
803
+
804
+ This magic command can either take a local filename, an url,
805
+ an history range (see %history) or a macro as argument.
806
+
807
+ If no parameter is given, prints out history of current session up to
808
+ this point. ::
809
+
810
+ %pycat myscript.py
811
+ %pycat 7-27
812
+ %pycat myMacro
813
+ %pycat http://www.example.com/myscript.py
814
+ """
815
+ try:
816
+ cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
817
+ except (ValueError, IOError):
818
+ print("Error: no such file, variable, URL, history range or macro")
819
+ return
820
+
821
+ page.page(self.shell.pycolorize(source_to_unicode(cont)))
822
+
823
+ @magic_arguments.magic_arguments()
824
+ @magic_arguments.argument(
825
+ '-a', '--append', action='store_true', default=False,
826
+ help='Append contents of the cell to an existing file. '
827
+ 'The file will be created if it does not exist.'
828
+ )
829
+ @magic_arguments.argument(
830
+ 'filename', type=str,
831
+ help='file to write'
832
+ )
833
+ @cell_magic
834
+ def writefile(self, line, cell):
835
+ """Write the contents of the cell to a file.
836
+
837
+ The file will be overwritten unless the -a (--append) flag is specified.
838
+ """
839
+ args = magic_arguments.parse_argstring(self.writefile, line)
840
+ if re.match(r'^(\'.*\')|(".*")$', args.filename):
841
+ filename = os.path.expanduser(args.filename[1:-1])
842
+ else:
843
+ filename = os.path.expanduser(args.filename)
844
+
845
+ if os.path.exists(filename):
846
+ if args.append:
847
+ print("Appending to %s" % filename)
848
+ else:
849
+ print("Overwriting %s" % filename)
850
+ else:
851
+ print("Writing %s" % filename)
852
+
853
+ mode = 'a' if args.append else 'w'
854
+ with io.open(filename, mode, encoding='utf-8') as f:
855
+ f.write(cell)
lib/python3.12/site-packages/IPython/core/magics/packaging.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of packaging-related magic functions.
2
+ """
3
+ #-----------------------------------------------------------------------------
4
+ # Copyright (c) 2018 The IPython Development Team.
5
+ #
6
+ # Distributed under the terms of the Modified BSD License.
7
+ #
8
+ # The full license is in the file COPYING.txt, distributed with this software.
9
+ #-----------------------------------------------------------------------------
10
+
11
+ import functools
12
+ import os
13
+ import re
14
+ import shlex
15
+ import sys
16
+ from pathlib import Path
17
+
18
+ from IPython.core.magic import Magics, magics_class, line_magic
19
+
20
+
21
+ def is_conda_environment(func):
22
+ @functools.wraps(func)
23
+ def wrapper(*args, **kwargs):
24
+ """Return True if the current Python executable is in a conda env"""
25
+ # TODO: does this need to change on windows?
26
+ if not Path(sys.prefix, "conda-meta", "history").exists():
27
+ raise ValueError(
28
+ "The python kernel does not appear to be a conda environment. "
29
+ "Please use ``%pip install`` instead."
30
+ )
31
+ return func(*args, **kwargs)
32
+
33
+ return wrapper
34
+
35
+
36
+ def _get_conda_like_executable(command):
37
+ """Find the path to the given executable
38
+
39
+ Parameters
40
+ ----------
41
+
42
+ executable: string
43
+ Value should be: conda, mamba or micromamba
44
+ """
45
+ # Check for a environment variable bound to the base executable, both conda and mamba
46
+ # set these when activating an environment.
47
+ base_executable = "CONDA_EXE"
48
+ if "mamba" in command.lower():
49
+ base_executable = "MAMBA_EXE"
50
+ if base_executable in os.environ:
51
+ executable = Path(os.environ[base_executable])
52
+ if executable.is_file():
53
+ return str(executable.resolve())
54
+
55
+ # Check if there is a conda executable in the same directory as the Python executable.
56
+ # This is the case within conda's root environment.
57
+ executable = Path(sys.executable).parent / command
58
+ if executable.is_file():
59
+ return str(executable)
60
+
61
+ # Otherwise, attempt to extract the executable from conda history.
62
+ # This applies in any conda environment. Parsing this way is error prone because
63
+ # different versions of conda and mamba include differing cmd values such as
64
+ # `conda`, `conda-script.py`, or `path/to/conda`, here use the raw command provided.
65
+ history = Path(sys.prefix, "conda-meta", "history").read_text(encoding="utf-8")
66
+ match = re.search(
67
+ rf"^#\s*cmd:\s*(?P<command>.*{command})\s[create|install]",
68
+ history,
69
+ flags=re.MULTILINE,
70
+ )
71
+ if match:
72
+ return match.groupdict()["command"]
73
+
74
+ # Fallback: assume the executable is available on the system path.
75
+ return command
76
+
77
+
78
+ CONDA_COMMANDS_REQUIRING_PREFIX = {
79
+ 'install', 'list', 'remove', 'uninstall', 'update', 'upgrade',
80
+ }
81
+ CONDA_COMMANDS_REQUIRING_YES = {
82
+ 'install', 'remove', 'uninstall', 'update', 'upgrade',
83
+ }
84
+ CONDA_ENV_FLAGS = {'-p', '--prefix', '-n', '--name'}
85
+ CONDA_YES_FLAGS = {'-y', '--y'}
86
+
87
+
88
+ @magics_class
89
+ class PackagingMagics(Magics):
90
+ """Magics related to packaging & installation"""
91
+
92
+ @line_magic
93
+ def pip(self, line):
94
+ """Run the pip package manager within the current kernel.
95
+
96
+ Usage:
97
+ %pip install [pkgs]
98
+ """
99
+ python = sys.executable
100
+ if sys.platform == "win32":
101
+ python = '"' + python + '"'
102
+ else:
103
+ python = shlex.quote(python)
104
+
105
+ self.shell.system(" ".join([python, "-m", "pip", line]))
106
+
107
+ print("Note: you may need to restart the kernel to use updated packages.")
108
+
109
+ def _run_command(self, cmd, line):
110
+ args = shlex.split(line)
111
+ command = args[0] if len(args) > 0 else ""
112
+ args = args[1:] if len(args) > 1 else [""]
113
+
114
+ extra_args = []
115
+
116
+ # When the subprocess does not allow us to respond "yes" during the installation,
117
+ # we need to insert --yes in the argument list for some commands
118
+ stdin_disabled = getattr(self.shell, 'kernel', None) is not None
119
+ needs_yes = command in CONDA_COMMANDS_REQUIRING_YES
120
+ has_yes = set(args).intersection(CONDA_YES_FLAGS)
121
+ if stdin_disabled and needs_yes and not has_yes:
122
+ extra_args.append("--yes")
123
+
124
+ # Add --prefix to point conda installation to the current environment
125
+ needs_prefix = command in CONDA_COMMANDS_REQUIRING_PREFIX
126
+ has_prefix = set(args).intersection(CONDA_ENV_FLAGS)
127
+ if needs_prefix and not has_prefix:
128
+ extra_args.extend(["--prefix", sys.prefix])
129
+
130
+ self.shell.system(" ".join([cmd, command] + extra_args + args))
131
+ print("\nNote: you may need to restart the kernel to use updated packages.")
132
+
133
+ @line_magic
134
+ @is_conda_environment
135
+ def conda(self, line):
136
+ """Run the conda package manager within the current kernel.
137
+
138
+ Usage:
139
+ %conda install [pkgs]
140
+ """
141
+ conda = _get_conda_like_executable("conda")
142
+ self._run_command(conda, line)
143
+
144
+ @line_magic
145
+ @is_conda_environment
146
+ def mamba(self, line):
147
+ """Run the mamba package manager within the current kernel.
148
+
149
+ Usage:
150
+ %mamba install [pkgs]
151
+ """
152
+ mamba = _get_conda_like_executable("mamba")
153
+ self._run_command(mamba, line)
154
+
155
+ @line_magic
156
+ @is_conda_environment
157
+ def micromamba(self, line):
158
+ """Run the conda package manager within the current kernel.
159
+
160
+ Usage:
161
+ %micromamba install [pkgs]
162
+ """
163
+ micromamba = _get_conda_like_executable("micromamba")
164
+ self._run_command(micromamba, line)
165
+
166
+ @line_magic
167
+ def uv(self, line):
168
+ """Run the uv package manager within the current kernel.
169
+
170
+ Usage:
171
+ %uv pip install [pkgs]
172
+ """
173
+ python = sys.executable
174
+ if sys.platform == "win32":
175
+ python = '"' + python + '"'
176
+ else:
177
+ python = shlex.quote(python)
178
+
179
+ self.shell.system(" ".join([python, "-m", "uv", line]))
180
+
181
+ print("Note: you may need to restart the kernel to use updated packages.")
lib/python3.12/site-packages/IPython/core/magics/pylab.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of magic functions for matplotlib/pylab support.
2
+ """
3
+ #-----------------------------------------------------------------------------
4
+ # Copyright (c) 2012 The IPython Development Team.
5
+ #
6
+ # Distributed under the terms of the Modified BSD License.
7
+ #
8
+ # The full license is in the file COPYING.txt, distributed with this software.
9
+ #-----------------------------------------------------------------------------
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Imports
13
+ #-----------------------------------------------------------------------------
14
+
15
+ # Our own packages
16
+ from traitlets.config.application import Application
17
+ from IPython.core import magic_arguments
18
+ from IPython.core.magic import Magics, magics_class, line_magic
19
+ from IPython.testing.skipdoctest import skip_doctest
20
+ from warnings import warn
21
+
22
+ #-----------------------------------------------------------------------------
23
+ # Magic implementation classes
24
+ #-----------------------------------------------------------------------------
25
+
26
+ magic_gui_arg = magic_arguments.argument(
27
+ "gui",
28
+ nargs="?",
29
+ help="""Name of the matplotlib backend to use such as 'qt' or 'widget'.
30
+ If given, the corresponding matplotlib backend is used,
31
+ otherwise it will be matplotlib's default
32
+ (which you can set in your matplotlib config file).
33
+ """,
34
+ )
35
+
36
+
37
+ @magics_class
38
+ class PylabMagics(Magics):
39
+ """Magics related to matplotlib's pylab support"""
40
+
41
+ @skip_doctest
42
+ @line_magic
43
+ @magic_arguments.magic_arguments()
44
+ @magic_arguments.argument('-l', '--list', action='store_true',
45
+ help='Show available matplotlib backends')
46
+ @magic_gui_arg
47
+ def matplotlib(self, line=''):
48
+ """Set up matplotlib to work interactively.
49
+
50
+ This function lets you activate matplotlib interactive support
51
+ at any point during an IPython session. It does not import anything
52
+ into the interactive namespace.
53
+
54
+ If you are using the inline matplotlib backend in the IPython Notebook
55
+ you can set which figure formats are enabled using the following::
56
+
57
+ In [1]: from matplotlib_inline.backend_inline import set_matplotlib_formats
58
+
59
+ In [2]: set_matplotlib_formats('pdf', 'svg')
60
+
61
+ The default for inline figures sets `bbox_inches` to 'tight'. This can
62
+ cause discrepancies between the displayed image and the identical
63
+ image created using `savefig`. This behavior can be disabled using the
64
+ `%config` magic::
65
+
66
+ In [3]: %config InlineBackend.print_figure_kwargs = {'bbox_inches':None}
67
+
68
+ In addition, see the docstrings of
69
+ `matplotlib_inline.backend_inline.set_matplotlib_formats` and
70
+ `matplotlib_inline.backend_inline.set_matplotlib_close` for more information on
71
+ changing additional behaviors of the inline backend.
72
+
73
+ Examples
74
+ --------
75
+ To enable the inline backend for usage with the IPython Notebook::
76
+
77
+ In [1]: %matplotlib inline
78
+
79
+ In this case, where the matplotlib default is TkAgg::
80
+
81
+ In [2]: %matplotlib
82
+ Using matplotlib backend: TkAgg
83
+
84
+ But you can explicitly request a different GUI backend::
85
+
86
+ In [3]: %matplotlib qt
87
+
88
+ You can list the available backends using the -l/--list option::
89
+
90
+ In [4]: %matplotlib --list
91
+ Available matplotlib backends: ['osx', 'qt4', 'qt5', 'gtk3', 'gtk4', 'notebook', 'wx', 'qt', 'nbagg',
92
+ 'gtk', 'tk', 'inline']
93
+ """
94
+ args = magic_arguments.parse_argstring(self.matplotlib, line)
95
+ if args.list:
96
+ from IPython.core.pylabtools import _list_matplotlib_backends_and_gui_loops
97
+
98
+ print(
99
+ "Available matplotlib backends: %s"
100
+ % _list_matplotlib_backends_and_gui_loops()
101
+ )
102
+ else:
103
+ gui, backend = self.shell.enable_matplotlib(args.gui)
104
+ self._show_matplotlib_backend(args.gui, backend)
105
+
106
+ @skip_doctest
107
+ @line_magic
108
+ @magic_arguments.magic_arguments()
109
+ @magic_arguments.argument(
110
+ '--no-import-all', action='store_true', default=None,
111
+ help="""Prevent IPython from performing ``import *`` into the interactive namespace.
112
+
113
+ You can govern the default behavior of this flag with the
114
+ InteractiveShellApp.pylab_import_all configurable.
115
+ """
116
+ )
117
+ @magic_gui_arg
118
+ def pylab(self, line=''):
119
+ """Load numpy and matplotlib to work interactively.
120
+
121
+ This function lets you activate pylab (matplotlib, numpy and
122
+ interactive support) at any point during an IPython session.
123
+
124
+ %pylab makes the following imports::
125
+
126
+ import numpy
127
+ import matplotlib
128
+ from matplotlib import pylab, mlab, pyplot
129
+ np = numpy
130
+ plt = pyplot
131
+
132
+ from IPython.display import display
133
+ from IPython.core.pylabtools import figsize, getfigs
134
+
135
+ from pylab import *
136
+ from numpy import *
137
+
138
+ If you pass `--no-import-all`, the last two `*` imports will be excluded.
139
+
140
+ See the %matplotlib magic for more details about activating matplotlib
141
+ without affecting the interactive namespace.
142
+ """
143
+ args = magic_arguments.parse_argstring(self.pylab, line)
144
+ if args.no_import_all is None:
145
+ # get default from Application
146
+ if Application.initialized():
147
+ app = Application.instance()
148
+ try:
149
+ import_all = app.pylab_import_all
150
+ except AttributeError:
151
+ import_all = True
152
+ else:
153
+ # nothing specified, no app - default True
154
+ import_all = True
155
+ else:
156
+ # invert no-import flag
157
+ import_all = not args.no_import_all
158
+
159
+ gui, backend, clobbered = self.shell.enable_pylab(args.gui, import_all=import_all)
160
+ self._show_matplotlib_backend(args.gui, backend)
161
+ print(
162
+ "%pylab is deprecated, use %matplotlib inline and import the required libraries."
163
+ )
164
+ print("Populating the interactive namespace from numpy and matplotlib")
165
+ if clobbered:
166
+ warn("pylab import has clobbered these variables: %s" % clobbered +
167
+ "\n`%matplotlib` prevents importing * from pylab and numpy"
168
+ )
169
+
170
+ def _show_matplotlib_backend(self, gui, backend):
171
+ """show matplotlib message backend message"""
172
+ if not gui or gui == 'auto':
173
+ print("Using matplotlib backend: %s" % backend)
lib/python3.12/site-packages/IPython/external/__init__.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ """
2
+ This package contains all third-party modules bundled with IPython.
3
+ """
4
+
5
+ from typing import List
6
+
7
+ __all__: List[str] = []
lib/python3.12/site-packages/IPython/external/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (396 Bytes). View file
 
lib/python3.12/site-packages/IPython/external/__pycache__/pickleshare.cpython-312.pyc ADDED
Binary file (13.2 kB). View file
 
lib/python3.12/site-packages/IPython/external/__pycache__/qt_for_kernel.cpython-312.pyc ADDED
Binary file (3.69 kB). View file
 
lib/python3.12/site-packages/IPython/external/__pycache__/qt_loaders.cpython-312.pyc ADDED
Binary file (14.2 kB). View file
 
lib/python3.12/site-packages/IPython/external/pickleshare.py ADDED
@@ -0,0 +1,303 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Vendoring of pickleshare, reduced to used functionalities.
3
+
4
+ ---
5
+
6
+ PickleShare - a small 'shelve' like datastore with concurrency support
7
+
8
+ Like shelve, a PickleShareDB object acts like a normal dictionary. Unlike
9
+ shelve, many processes can access the database simultaneously. Changing a
10
+ value in database is immediately visible to other processes accessing the
11
+ same database.
12
+
13
+ Concurrency is possible because the values are stored in separate files. Hence
14
+ the "database" is a directory where *all* files are governed by PickleShare.
15
+
16
+ Example usage::
17
+
18
+ from pickleshare import *
19
+ db = PickleShareDB('~/testpickleshare')
20
+ db.clear()
21
+ print "Should be empty:",db.items()
22
+ db['hello'] = 15
23
+ db['aku ankka'] = [1,2,313]
24
+ db['paths/are/ok/key'] = [1,(5,46)]
25
+ print db.keys()
26
+ del db['aku ankka']
27
+
28
+ This module is certainly not ZODB, but can be used for low-load
29
+ (non-mission-critical) situations where tiny code size trumps the
30
+ advanced features of a "real" object database.
31
+
32
+ Installation guide: pip install pickleshare
33
+
34
+ Author: Ville Vainio <vivainio@gmail.com>
35
+ License: MIT open source license.
36
+
37
+ """
38
+
39
+ __version__ = "0.7.5"
40
+
41
+ from pathlib import Path
42
+
43
+
44
+ import os, stat, time
45
+
46
+ try:
47
+ import collections.abc as collections_abc
48
+ except ImportError:
49
+ import collections as collections_abc
50
+ try:
51
+ import cPickle as pickle
52
+ except ImportError:
53
+ import pickle
54
+ import errno
55
+ import sys
56
+
57
+
58
+ def gethashfile(key):
59
+ return ("%02x" % abs(hash(key) % 256))[-2:]
60
+
61
+
62
+ _sentinel = object()
63
+
64
+
65
+ class PickleShareDB(collections_abc.MutableMapping):
66
+ """The main 'connection' object for PickleShare database"""
67
+
68
+ def __init__(self, root):
69
+ """Return a db object that will manage the specied directory"""
70
+ if not isinstance(root, str):
71
+ root = str(root)
72
+ root = os.path.abspath(os.path.expanduser(root))
73
+ self.root = Path(root)
74
+ if not self.root.is_dir():
75
+ # catching the exception is necessary if multiple processes are concurrently trying to create a folder
76
+ # exists_ok keyword argument of mkdir does the same but only from Python 3.5
77
+ try:
78
+ self.root.mkdir(parents=True)
79
+ except OSError as e:
80
+ if e.errno != errno.EEXIST:
81
+ raise
82
+ # cache has { 'key' : (obj, orig_mod_time) }
83
+ self.cache = {}
84
+
85
+ def __getitem__(self, key):
86
+ """db['key'] reading"""
87
+ fil = self.root / key
88
+ try:
89
+ mtime = fil.stat()[stat.ST_MTIME]
90
+ except OSError:
91
+ raise KeyError(key)
92
+
93
+ if fil in self.cache and mtime == self.cache[fil][1]:
94
+ return self.cache[fil][0]
95
+ try:
96
+ # The cached item has expired, need to read
97
+ with fil.open("rb") as f:
98
+ obj = pickle.loads(f.read())
99
+ except:
100
+ raise KeyError(key)
101
+
102
+ self.cache[fil] = (obj, mtime)
103
+ return obj
104
+
105
+ def __setitem__(self, key, value):
106
+ """db['key'] = 5"""
107
+ fil = self.root / key
108
+ parent = fil.parent
109
+ if parent and not parent.is_dir():
110
+ parent.mkdir(parents=True)
111
+ # We specify protocol 2, so that we can mostly go between Python 2
112
+ # and Python 3. We can upgrade to protocol 3 when Python 2 is obsolete.
113
+ with fil.open("wb") as f:
114
+ pickle.dump(value, f, protocol=2)
115
+ try:
116
+ self.cache[fil] = (value, fil.stat().st_mtime)
117
+ except OSError as e:
118
+ if e.errno != errno.ENOENT:
119
+ raise
120
+
121
+ def hset(self, hashroot, key, value):
122
+ """hashed set"""
123
+ hroot = self.root / hashroot
124
+ if not hroot.is_dir():
125
+ hroot.mkdir()
126
+ hfile = hroot / gethashfile(key)
127
+ d = self.get(hfile, {})
128
+ d.update({key: value})
129
+ self[hfile] = d
130
+
131
+ def hget(self, hashroot, key, default=_sentinel, fast_only=True):
132
+ """hashed get"""
133
+ hroot = self.root / hashroot
134
+ hfile = hroot / gethashfile(key)
135
+
136
+ d = self.get(hfile, _sentinel)
137
+ # print "got dict",d,"from",hfile
138
+ if d is _sentinel:
139
+ if fast_only:
140
+ if default is _sentinel:
141
+ raise KeyError(key)
142
+
143
+ return default
144
+
145
+ # slow mode ok, works even after hcompress()
146
+ d = self.hdict(hashroot)
147
+
148
+ return d.get(key, default)
149
+
150
+ def hdict(self, hashroot):
151
+ """Get all data contained in hashed category 'hashroot' as dict"""
152
+ hfiles = self.keys(hashroot + "/*")
153
+ hfiles.sort()
154
+ last = len(hfiles) and hfiles[-1] or ""
155
+ if last.endswith("xx"):
156
+ # print "using xx"
157
+ hfiles = [last] + hfiles[:-1]
158
+
159
+ all = {}
160
+
161
+ for f in hfiles:
162
+ # print "using",f
163
+ try:
164
+ all.update(self[f])
165
+ except KeyError:
166
+ print("Corrupt", f, "deleted - hset is not threadsafe!")
167
+ del self[f]
168
+
169
+ self.uncache(f)
170
+
171
+ return all
172
+
173
+ def hcompress(self, hashroot):
174
+ """Compress category 'hashroot', so hset is fast again
175
+
176
+ hget will fail if fast_only is True for compressed items (that were
177
+ hset before hcompress).
178
+
179
+ """
180
+ hfiles = self.keys(hashroot + "/*")
181
+ all = {}
182
+ for f in hfiles:
183
+ # print "using",f
184
+ all.update(self[f])
185
+ self.uncache(f)
186
+
187
+ self[hashroot + "/xx"] = all
188
+ for f in hfiles:
189
+ p = self.root / f
190
+ if p.name == "xx":
191
+ continue
192
+ p.unlink()
193
+
194
+ def __delitem__(self, key):
195
+ """del db["key"]"""
196
+ fil = self.root / key
197
+ self.cache.pop(fil, None)
198
+ try:
199
+ fil.unlink()
200
+ except OSError:
201
+ # notfound and permission denied are ok - we
202
+ # lost, the other process wins the conflict
203
+ pass
204
+
205
+ def _normalized(self, p):
206
+ """Make a key suitable for user's eyes"""
207
+ return str(p.relative_to(self.root)).replace("\\", "/")
208
+
209
+ def keys(self, globpat=None):
210
+ """All keys in DB, or all keys matching a glob"""
211
+
212
+ if globpat is None:
213
+ files = self.root.rglob("*")
214
+ else:
215
+ files = self.root.glob(globpat)
216
+ return [self._normalized(p) for p in files if p.is_file()]
217
+
218
+ def __iter__(self):
219
+ return iter(self.keys())
220
+
221
+ def __len__(self):
222
+ return len(self.keys())
223
+
224
+ def uncache(self, *items):
225
+ """Removes all, or specified items from cache
226
+
227
+ Use this after reading a large amount of large objects
228
+ to free up memory, when you won't be needing the objects
229
+ for a while.
230
+
231
+ """
232
+ if not items:
233
+ self.cache = {}
234
+ for it in items:
235
+ self.cache.pop(it, None)
236
+
237
+ def waitget(self, key, maxwaittime=60):
238
+ """Wait (poll) for a key to get a value
239
+
240
+ Will wait for `maxwaittime` seconds before raising a KeyError.
241
+ The call exits normally if the `key` field in db gets a value
242
+ within the timeout period.
243
+
244
+ Use this for synchronizing different processes or for ensuring
245
+ that an unfortunately timed "db['key'] = newvalue" operation
246
+ in another process (which causes all 'get' operation to cause a
247
+ KeyError for the duration of pickling) won't screw up your program
248
+ logic.
249
+ """
250
+
251
+ wtimes = [0.2] * 3 + [0.5] * 2 + [1]
252
+ tries = 0
253
+ waited = 0
254
+ while 1:
255
+ try:
256
+ val = self[key]
257
+ return val
258
+ except KeyError:
259
+ pass
260
+
261
+ if waited > maxwaittime:
262
+ raise KeyError(key)
263
+
264
+ time.sleep(wtimes[tries])
265
+ waited += wtimes[tries]
266
+ if tries < len(wtimes) - 1:
267
+ tries += 1
268
+
269
+ def getlink(self, folder):
270
+ """Get a convenient link for accessing items"""
271
+ return PickleShareLink(self, folder)
272
+
273
+ def __repr__(self):
274
+ return "PickleShareDB('%s')" % self.root
275
+
276
+
277
+ class PickleShareLink:
278
+ """A shortdand for accessing nested PickleShare data conveniently.
279
+
280
+ Created through PickleShareDB.getlink(), example::
281
+
282
+ lnk = db.getlink('myobjects/test')
283
+ lnk.foo = 2
284
+ lnk.bar = lnk.foo + 5
285
+
286
+ """
287
+
288
+ def __init__(self, db, keydir):
289
+ self.__dict__.update(locals())
290
+
291
+ def __getattr__(self, key):
292
+ return self.__dict__["db"][self.__dict__["keydir"] + "/" + key]
293
+
294
+ def __setattr__(self, key, val):
295
+ self.db[self.keydir + "/" + key] = val
296
+
297
+ def __repr__(self):
298
+ db = self.__dict__["db"]
299
+ keys = db.keys(self.__dict__["keydir"] + "/*")
300
+ return "<PickleShareLink '%s': %s>" % (
301
+ self.__dict__["keydir"],
302
+ ";".join([Path(k).basename() for k in keys]),
303
+ )
lib/python3.12/site-packages/IPython/external/qt_for_kernel.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Import Qt in a manner suitable for an IPython kernel.
2
+
3
+ This is the import used for the `gui=qt` or `matplotlib=qt` initialization.
4
+
5
+ Import Priority:
6
+
7
+ if Qt has been imported anywhere else:
8
+ use that
9
+
10
+ if matplotlib has been imported and doesn't support v2 (<= 1.0.1):
11
+ use PyQt4 @v1
12
+
13
+ Next, ask QT_API env variable
14
+
15
+ if QT_API not set:
16
+ ask matplotlib what it's using. If Qt4Agg or Qt5Agg, then use the
17
+ version matplotlib is configured with
18
+
19
+ else: (matplotlib said nothing)
20
+ # this is the default path - nobody told us anything
21
+ try in this order:
22
+ PyQt default version, PySide, PyQt5
23
+ else:
24
+ use what QT_API says
25
+
26
+ Note that %gui's implementation will always set a `QT_API`, see
27
+ `IPython.terminal.pt_inputhooks.get_inputhook_name_and_func`
28
+
29
+ """
30
+ # NOTE: This is no longer an external, third-party module, and should be
31
+ # considered part of IPython. For compatibility however, it is being kept in
32
+ # IPython/external.
33
+
34
+ import os
35
+ import sys
36
+
37
+ from IPython.external.qt_loaders import (
38
+ load_qt,
39
+ loaded_api,
40
+ enum_factory,
41
+ # QT6
42
+ QT_API_PYQT6,
43
+ QT_API_PYSIDE6,
44
+ # QT5
45
+ QT_API_PYQT5,
46
+ QT_API_PYSIDE2,
47
+ # QT4
48
+ QT_API_PYQT,
49
+ QT_API_PYSIDE,
50
+ # default
51
+ QT_API_PYQT_DEFAULT,
52
+ )
53
+
54
+ _qt_apis = (
55
+ # QT6
56
+ QT_API_PYQT6,
57
+ QT_API_PYSIDE6,
58
+ # QT5
59
+ QT_API_PYQT5,
60
+ QT_API_PYSIDE2,
61
+ # default
62
+ QT_API_PYQT_DEFAULT,
63
+ )
64
+
65
+
66
+ def matplotlib_options(mpl):
67
+ """Constraints placed on an imported matplotlib."""
68
+ if mpl is None:
69
+ return
70
+ backend = mpl.rcParams.get('backend', None)
71
+ if backend == 'Qt4Agg':
72
+ mpqt = mpl.rcParams.get('backend.qt4', None)
73
+ if mpqt is None:
74
+ return None
75
+ if mpqt.lower() == 'pyside':
76
+ return [QT_API_PYSIDE]
77
+ elif mpqt.lower() == 'pyqt4':
78
+ return [QT_API_PYQT_DEFAULT]
79
+ elif mpqt.lower() == 'pyqt4v2':
80
+ return [QT_API_PYQT]
81
+ raise ImportError("unhandled value for backend.qt4 from matplotlib: %r" %
82
+ mpqt)
83
+ elif backend == 'Qt5Agg':
84
+ mpqt = mpl.rcParams.get('backend.qt5', None)
85
+ if mpqt is None:
86
+ return None
87
+ if mpqt.lower() == 'pyqt5':
88
+ return [QT_API_PYQT5]
89
+ raise ImportError("unhandled value for backend.qt5 from matplotlib: %r" %
90
+ mpqt)
91
+
92
+ def get_options():
93
+ """Return a list of acceptable QT APIs, in decreasing order of preference."""
94
+ #already imported Qt somewhere. Use that
95
+ loaded = loaded_api()
96
+ if loaded is not None:
97
+ return [loaded]
98
+
99
+ mpl = sys.modules.get("matplotlib", None)
100
+
101
+ if mpl is not None and tuple(mpl.__version__.split(".")) < ("1", "0", "2"):
102
+ # 1.0.1 only supports PyQt4 v1
103
+ return [QT_API_PYQT_DEFAULT]
104
+
105
+ qt_api = os.environ.get('QT_API', None)
106
+ if qt_api is None:
107
+ #no ETS variable. Ask mpl, then use default fallback path
108
+ return matplotlib_options(mpl) or [
109
+ QT_API_PYQT_DEFAULT,
110
+ QT_API_PYQT6,
111
+ QT_API_PYSIDE6,
112
+ QT_API_PYQT5,
113
+ QT_API_PYSIDE2,
114
+ ]
115
+ elif qt_api not in _qt_apis:
116
+ raise RuntimeError("Invalid Qt API %r, valid values are: %r" %
117
+ (qt_api, ', '.join(_qt_apis)))
118
+ else:
119
+ return [qt_api]
120
+
121
+
122
+ api_opts = get_options()
123
+ QtCore, QtGui, QtSvg, QT_API = load_qt(api_opts)
124
+ enum_helper = enum_factory(QT_API, QtCore)
lib/python3.12/site-packages/IPython/external/qt_loaders.py ADDED
@@ -0,0 +1,423 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ This module contains factory functions that attempt
3
+ to return Qt submodules from the various python Qt bindings.
4
+
5
+ It also protects against double-importing Qt with different
6
+ bindings, which is unstable and likely to crash
7
+
8
+ This is used primarily by qt and qt_for_kernel, and shouldn't
9
+ be accessed directly from the outside
10
+ """
11
+
12
+ import importlib.abc
13
+ import sys
14
+ import os
15
+ import types
16
+ from functools import partial, lru_cache
17
+ import operator
18
+
19
+ # ### Available APIs.
20
+ # Qt6
21
+ QT_API_PYQT6 = "pyqt6"
22
+ QT_API_PYSIDE6 = "pyside6"
23
+
24
+ # Qt5
25
+ QT_API_PYQT5 = 'pyqt5'
26
+ QT_API_PYSIDE2 = 'pyside2'
27
+
28
+ # Qt4
29
+ # NOTE: Here for legacy matplotlib compatibility, but not really supported on the IPython side.
30
+ QT_API_PYQT = "pyqt" # Force version 2
31
+ QT_API_PYQTv1 = "pyqtv1" # Force version 2
32
+ QT_API_PYSIDE = "pyside"
33
+
34
+ QT_API_PYQT_DEFAULT = "pyqtdefault" # use system default for version 1 vs. 2
35
+
36
+ api_to_module = {
37
+ # Qt6
38
+ QT_API_PYQT6: "PyQt6",
39
+ QT_API_PYSIDE6: "PySide6",
40
+ # Qt5
41
+ QT_API_PYQT5: "PyQt5",
42
+ QT_API_PYSIDE2: "PySide2",
43
+ # Qt4
44
+ QT_API_PYSIDE: "PySide",
45
+ QT_API_PYQT: "PyQt4",
46
+ QT_API_PYQTv1: "PyQt4",
47
+ # default
48
+ QT_API_PYQT_DEFAULT: "PyQt6",
49
+ }
50
+
51
+
52
+ class ImportDenier(importlib.abc.MetaPathFinder):
53
+ """Import Hook that will guard against bad Qt imports
54
+ once IPython commits to a specific binding
55
+ """
56
+
57
+ def __init__(self):
58
+ self.__forbidden = set()
59
+
60
+ def forbid(self, module_name):
61
+ sys.modules.pop(module_name, None)
62
+ self.__forbidden.add(module_name)
63
+
64
+ def find_spec(self, fullname, path, target=None):
65
+ if path:
66
+ return
67
+ if fullname in self.__forbidden:
68
+ raise ImportError(
69
+ """
70
+ Importing %s disabled by IPython, which has
71
+ already imported an Incompatible QT Binding: %s
72
+ """
73
+ % (fullname, loaded_api())
74
+ )
75
+
76
+
77
+ ID = ImportDenier()
78
+ sys.meta_path.insert(0, ID)
79
+
80
+
81
+ def commit_api(api):
82
+ """Commit to a particular API, and trigger ImportErrors on subsequent
83
+ dangerous imports"""
84
+ modules = set(api_to_module.values())
85
+
86
+ modules.remove(api_to_module[api])
87
+ for mod in modules:
88
+ ID.forbid(mod)
89
+
90
+
91
+ def loaded_api():
92
+ """Return which API is loaded, if any
93
+
94
+ If this returns anything besides None,
95
+ importing any other Qt binding is unsafe.
96
+
97
+ Returns
98
+ -------
99
+ None, 'pyside6', 'pyqt6', 'pyside2', 'pyside', 'pyqt', 'pyqt5', 'pyqtv1'
100
+ """
101
+ if sys.modules.get("PyQt6.QtCore"):
102
+ return QT_API_PYQT6
103
+ elif sys.modules.get("PySide6.QtCore"):
104
+ return QT_API_PYSIDE6
105
+ elif sys.modules.get("PyQt5.QtCore"):
106
+ return QT_API_PYQT5
107
+ elif sys.modules.get("PySide2.QtCore"):
108
+ return QT_API_PYSIDE2
109
+ elif sys.modules.get("PyQt4.QtCore"):
110
+ if qtapi_version() == 2:
111
+ return QT_API_PYQT
112
+ else:
113
+ return QT_API_PYQTv1
114
+ elif sys.modules.get("PySide.QtCore"):
115
+ return QT_API_PYSIDE
116
+
117
+ return None
118
+
119
+
120
+ def has_binding(api):
121
+ """Safely check for PyQt4/5, PySide or PySide2, without importing submodules
122
+
123
+ Parameters
124
+ ----------
125
+ api : str [ 'pyqtv1' | 'pyqt' | 'pyqt5' | 'pyside' | 'pyside2' | 'pyqtdefault']
126
+ Which module to check for
127
+
128
+ Returns
129
+ -------
130
+ True if the relevant module appears to be importable
131
+ """
132
+ module_name = api_to_module[api]
133
+ from importlib.util import find_spec
134
+
135
+ required = ['QtCore', 'QtGui', 'QtSvg']
136
+ if api in (QT_API_PYQT5, QT_API_PYSIDE2, QT_API_PYQT6, QT_API_PYSIDE6):
137
+ # QT5 requires QtWidgets too
138
+ required.append('QtWidgets')
139
+
140
+ for submod in required:
141
+ try:
142
+ spec = find_spec('%s.%s' % (module_name, submod))
143
+ except ImportError:
144
+ # Package (e.g. PyQt5) not found
145
+ return False
146
+ else:
147
+ if spec is None:
148
+ # Submodule (e.g. PyQt5.QtCore) not found
149
+ return False
150
+
151
+ if api == QT_API_PYSIDE:
152
+ # We can also safely check PySide version
153
+ import PySide
154
+
155
+ return PySide.__version_info__ >= (1, 0, 3)
156
+
157
+ return True
158
+
159
+
160
+ def qtapi_version():
161
+ """Return which QString API has been set, if any
162
+
163
+ Returns
164
+ -------
165
+ The QString API version (1 or 2), or None if not set
166
+ """
167
+ try:
168
+ import sip
169
+ except ImportError:
170
+ # as of PyQt5 5.11, sip is no longer available as a top-level
171
+ # module and needs to be imported from the PyQt5 namespace
172
+ try:
173
+ from PyQt5 import sip
174
+ except ImportError:
175
+ return
176
+ try:
177
+ return sip.getapi('QString')
178
+ except ValueError:
179
+ return
180
+
181
+
182
+ def can_import(api):
183
+ """Safely query whether an API is importable, without importing it"""
184
+ if not has_binding(api):
185
+ return False
186
+
187
+ current = loaded_api()
188
+ if api == QT_API_PYQT_DEFAULT:
189
+ return current in [QT_API_PYQT6, None]
190
+ else:
191
+ return current in [api, None]
192
+
193
+
194
+ def import_pyqt4(version=2):
195
+ """
196
+ Import PyQt4
197
+
198
+ Parameters
199
+ ----------
200
+ version : 1, 2, or None
201
+ Which QString/QVariant API to use. Set to None to use the system
202
+ default
203
+ ImportErrors raised within this function are non-recoverable
204
+ """
205
+ # The new-style string API (version=2) automatically
206
+ # converts QStrings to Unicode Python strings. Also, automatically unpacks
207
+ # QVariants to their underlying objects.
208
+ import sip
209
+
210
+ if version is not None:
211
+ sip.setapi('QString', version)
212
+ sip.setapi('QVariant', version)
213
+
214
+ from PyQt4 import QtGui, QtCore, QtSvg
215
+
216
+ if QtCore.PYQT_VERSION < 0x040700:
217
+ raise ImportError("IPython requires PyQt4 >= 4.7, found %s" %
218
+ QtCore.PYQT_VERSION_STR)
219
+
220
+ # Alias PyQt-specific functions for PySide compatibility.
221
+ QtCore.Signal = QtCore.pyqtSignal
222
+ QtCore.Slot = QtCore.pyqtSlot
223
+
224
+ # query for the API version (in case version == None)
225
+ version = sip.getapi('QString')
226
+ api = QT_API_PYQTv1 if version == 1 else QT_API_PYQT
227
+ return QtCore, QtGui, QtSvg, api
228
+
229
+
230
+ def import_pyqt5():
231
+ """
232
+ Import PyQt5
233
+
234
+ ImportErrors raised within this function are non-recoverable
235
+ """
236
+
237
+ from PyQt5 import QtCore, QtSvg, QtWidgets, QtGui
238
+
239
+ # Alias PyQt-specific functions for PySide compatibility.
240
+ QtCore.Signal = QtCore.pyqtSignal
241
+ QtCore.Slot = QtCore.pyqtSlot
242
+
243
+ # Join QtGui and QtWidgets for Qt4 compatibility.
244
+ QtGuiCompat = types.ModuleType('QtGuiCompat')
245
+ QtGuiCompat.__dict__.update(QtGui.__dict__)
246
+ QtGuiCompat.__dict__.update(QtWidgets.__dict__)
247
+
248
+ api = QT_API_PYQT5
249
+ return QtCore, QtGuiCompat, QtSvg, api
250
+
251
+
252
+ def import_pyqt6():
253
+ """
254
+ Import PyQt6
255
+
256
+ ImportErrors raised within this function are non-recoverable
257
+ """
258
+
259
+ from PyQt6 import QtCore, QtSvg, QtWidgets, QtGui
260
+
261
+ # Alias PyQt-specific functions for PySide compatibility.
262
+ QtCore.Signal = QtCore.pyqtSignal
263
+ QtCore.Slot = QtCore.pyqtSlot
264
+
265
+ # Join QtGui and QtWidgets for Qt4 compatibility.
266
+ QtGuiCompat = types.ModuleType("QtGuiCompat")
267
+ QtGuiCompat.__dict__.update(QtGui.__dict__)
268
+ QtGuiCompat.__dict__.update(QtWidgets.__dict__)
269
+
270
+ api = QT_API_PYQT6
271
+ return QtCore, QtGuiCompat, QtSvg, api
272
+
273
+
274
+ def import_pyside():
275
+ """
276
+ Import PySide
277
+
278
+ ImportErrors raised within this function are non-recoverable
279
+ """
280
+ from PySide import QtGui, QtCore, QtSvg
281
+ return QtCore, QtGui, QtSvg, QT_API_PYSIDE
282
+
283
+ def import_pyside2():
284
+ """
285
+ Import PySide2
286
+
287
+ ImportErrors raised within this function are non-recoverable
288
+ """
289
+ from PySide2 import QtGui, QtCore, QtSvg, QtWidgets, QtPrintSupport
290
+
291
+ # Join QtGui and QtWidgets for Qt4 compatibility.
292
+ QtGuiCompat = types.ModuleType('QtGuiCompat')
293
+ QtGuiCompat.__dict__.update(QtGui.__dict__)
294
+ QtGuiCompat.__dict__.update(QtWidgets.__dict__)
295
+ QtGuiCompat.__dict__.update(QtPrintSupport.__dict__)
296
+
297
+ return QtCore, QtGuiCompat, QtSvg, QT_API_PYSIDE2
298
+
299
+
300
+ def import_pyside6():
301
+ """
302
+ Import PySide6
303
+
304
+ ImportErrors raised within this function are non-recoverable
305
+ """
306
+
307
+ def get_attrs(module):
308
+ return {
309
+ name: getattr(module, name)
310
+ for name in dir(module)
311
+ if not name.startswith("_")
312
+ }
313
+
314
+ from PySide6 import QtGui, QtCore, QtSvg, QtWidgets, QtPrintSupport
315
+
316
+ # Join QtGui and QtWidgets for Qt4 compatibility.
317
+ QtGuiCompat = types.ModuleType("QtGuiCompat")
318
+ QtGuiCompat.__dict__.update(QtGui.__dict__)
319
+ if QtCore.__version_info__ < (6, 7):
320
+ QtGuiCompat.__dict__.update(QtWidgets.__dict__)
321
+ QtGuiCompat.__dict__.update(QtPrintSupport.__dict__)
322
+ else:
323
+ QtGuiCompat.__dict__.update(get_attrs(QtWidgets))
324
+ QtGuiCompat.__dict__.update(get_attrs(QtPrintSupport))
325
+
326
+ return QtCore, QtGuiCompat, QtSvg, QT_API_PYSIDE6
327
+
328
+
329
+ def load_qt(api_options):
330
+ """
331
+ Attempt to import Qt, given a preference list
332
+ of permissible bindings
333
+
334
+ It is safe to call this function multiple times.
335
+
336
+ Parameters
337
+ ----------
338
+ api_options : List of strings
339
+ The order of APIs to try. Valid items are 'pyside', 'pyside2',
340
+ 'pyqt', 'pyqt5', 'pyqtv1' and 'pyqtdefault'
341
+
342
+ Returns
343
+ -------
344
+ A tuple of QtCore, QtGui, QtSvg, QT_API
345
+ The first three are the Qt modules. The last is the
346
+ string indicating which module was loaded.
347
+
348
+ Raises
349
+ ------
350
+ ImportError, if it isn't possible to import any requested
351
+ bindings (either because they aren't installed, or because
352
+ an incompatible library has already been installed)
353
+ """
354
+ loaders = {
355
+ # Qt6
356
+ QT_API_PYQT6: import_pyqt6,
357
+ QT_API_PYSIDE6: import_pyside6,
358
+ # Qt5
359
+ QT_API_PYQT5: import_pyqt5,
360
+ QT_API_PYSIDE2: import_pyside2,
361
+ # Qt4
362
+ QT_API_PYSIDE: import_pyside,
363
+ QT_API_PYQT: import_pyqt4,
364
+ QT_API_PYQTv1: partial(import_pyqt4, version=1),
365
+ # default
366
+ QT_API_PYQT_DEFAULT: import_pyqt6,
367
+ }
368
+
369
+ for api in api_options:
370
+
371
+ if api not in loaders:
372
+ raise RuntimeError(
373
+ "Invalid Qt API %r, valid values are: %s" %
374
+ (api, ", ".join(["%r" % k for k in loaders.keys()])))
375
+
376
+ if not can_import(api):
377
+ continue
378
+
379
+ #cannot safely recover from an ImportError during this
380
+ result = loaders[api]()
381
+ api = result[-1] # changed if api = QT_API_PYQT_DEFAULT
382
+ commit_api(api)
383
+ return result
384
+ else:
385
+ # Clear the environment variable since it doesn't work.
386
+ if "QT_API" in os.environ:
387
+ del os.environ["QT_API"]
388
+
389
+ raise ImportError(
390
+ """
391
+ Could not load requested Qt binding. Please ensure that
392
+ PyQt4 >= 4.7, PyQt5, PyQt6, PySide >= 1.0.3, PySide2, or
393
+ PySide6 is available, and only one is imported per session.
394
+
395
+ Currently-imported Qt library: %r
396
+ PyQt5 available (requires QtCore, QtGui, QtSvg, QtWidgets): %s
397
+ PyQt6 available (requires QtCore, QtGui, QtSvg, QtWidgets): %s
398
+ PySide2 installed: %s
399
+ PySide6 installed: %s
400
+ Tried to load: %r
401
+ """
402
+ % (
403
+ loaded_api(),
404
+ has_binding(QT_API_PYQT5),
405
+ has_binding(QT_API_PYQT6),
406
+ has_binding(QT_API_PYSIDE2),
407
+ has_binding(QT_API_PYSIDE6),
408
+ api_options,
409
+ )
410
+ )
411
+
412
+
413
+ def enum_factory(QT_API, QtCore):
414
+ """Construct an enum helper to account for PyQt5 <-> PyQt6 changes."""
415
+
416
+ @lru_cache(None)
417
+ def _enum(name):
418
+ # foo.bar.Enum.Entry (PyQt6) <=> foo.bar.Entry (non-PyQt6).
419
+ return operator.attrgetter(
420
+ name if QT_API == QT_API_PYQT6 else name.rpartition(".")[0]
421
+ )(sys.modules[QtCore.__package__])
422
+
423
+ return _enum
lib/python3.12/site-packages/IPython/utils/PyColorize.py ADDED
@@ -0,0 +1,577 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import keyword
2
+ import os
3
+ import sys
4
+ import token
5
+ import tokenize
6
+ import warnings
7
+ from io import StringIO
8
+ from typing import Any, Type, TypeAlias
9
+
10
+ import pygments
11
+ from pygments.formatters.terminal256 import Terminal256Formatter
12
+ from pygments.style import Style
13
+ from pygments.styles import get_style_by_name
14
+ from pygments.token import Token, _TokenType
15
+ from functools import cache
16
+
17
+ from typing import TypedDict
18
+
19
+
20
+ TokenStream: TypeAlias = list[tuple[_TokenType, str]]
21
+
22
+
23
+ __all__ = ["Parser", "Theme"]
24
+
25
+
26
+ class Symbols(TypedDict):
27
+ top_line: str
28
+ arrow_body: str
29
+ arrow_head: str
30
+
31
+
32
+ _default_symbols: Symbols = Symbols(
33
+ top_line="-",
34
+ arrow_body="-",
35
+ arrow_head=">",
36
+ )
37
+
38
+
39
+ class Theme:
40
+ name: str
41
+ base: str | None
42
+ extra_style: dict[_TokenType, str]
43
+ symbols: Symbols
44
+
45
+ def __init__(
46
+ self,
47
+ name: str,
48
+ base: str | None,
49
+ extra_style: dict[_TokenType, str],
50
+ *,
51
+ symbols: Symbols | None = None,
52
+ ) -> None:
53
+ self.name = name
54
+ self.base = base
55
+ self.extra_style = extra_style
56
+ s: Symbols = symbols if symbols is not None else _default_symbols
57
+ self.symbols = {**_default_symbols, **s}
58
+ self._formatter = Terminal256Formatter(style=self.as_pygments_style())
59
+
60
+ @cache
61
+ def as_pygments_style(self) -> Type[Style]:
62
+ if self.base is not None:
63
+ base_styles = get_style_by_name(self.base).styles
64
+ else:
65
+ base_styles = {}
66
+
67
+ class MyStyle(Style):
68
+ styles = {**base_styles, **self.extra_style}
69
+
70
+ return MyStyle
71
+
72
+ def format(self, stream: TokenStream) -> str:
73
+ return pygments.format(stream, self._formatter)
74
+
75
+ def make_arrow(self, width: int) -> str:
76
+ """generate the leading arrow in front of traceback or debugger"""
77
+ if width >= 2:
78
+ return (
79
+ self.symbols["arrow_body"] * (width - 2)
80
+ + self.symbols["arrow_head"]
81
+ + " "
82
+ )
83
+ elif width == 1:
84
+ return self.symbols["arrow_head"]
85
+ return ""
86
+
87
+
88
+ generate_tokens = tokenize.generate_tokens
89
+
90
+
91
+ #############################################################################
92
+ ### Python Source Parser (does Highlighting)
93
+ #############################################################################
94
+
95
+ _KEYWORD = token.NT_OFFSET + 1
96
+ _TEXT = token.NT_OFFSET + 2
97
+
98
+ # ****************************************************************************
99
+
100
+ _pygment_token_mapping: dict[int, _TokenType] = {
101
+ token.NUMBER: Token.Literal.Number,
102
+ token.OP: Token.Operator,
103
+ token.STRING: Token.Literal.String,
104
+ token.COMMENT: Token.Comment,
105
+ token.NAME: Token.Name,
106
+ token.ERRORTOKEN: Token.Error,
107
+ _KEYWORD: Token.Keyword,
108
+ _TEXT: Token.Text,
109
+ }
110
+
111
+ # technically BW is not nocolor, we should have a no-style, style
112
+ nocolors_theme = Theme("nocolor", None, {})
113
+
114
+
115
+ linux_theme = Theme(
116
+ "linux",
117
+ "monokai",
118
+ {
119
+ Token.Header: "ansibrightred",
120
+ Token.LinenoEm: "ansibrightgreen",
121
+ Token.Lineno: "ansigreen",
122
+ Token.ValEm: "ansibrightblue",
123
+ Token.VName: "ansicyan",
124
+ Token.Caret: "",
125
+ Token.Filename: "ansibrightgreen",
126
+ Token.ExcName: "ansibrightred",
127
+ Token.Topline: "ansibrightred",
128
+ Token.FilenameEm: "ansigreen",
129
+ Token.Normal: "",
130
+ Token.NormalEm: "ansibrightcyan",
131
+ Token.Line: "ansiyellow",
132
+ Token.TB.Name: "ansimagenta",
133
+ Token.TB.NameEm: "ansibrightmagenta",
134
+ Token.Breakpoint: "",
135
+ Token.Breakpoint.Enabled: "ansibrightred",
136
+ Token.Breakpoint.Disabled: "ansired",
137
+ Token.Prompt: "ansibrightgreen",
138
+ Token.PromptNum: "ansigreen bold",
139
+ Token.OutPrompt: "ansibrightred",
140
+ Token.OutPromptNum: "ansired bold",
141
+ },
142
+ )
143
+
144
+ neutral_pygments_equiv = {
145
+ Token.Header: "ansired",
146
+ Token.LinenoEm: "ansigreen",
147
+ Token.Lineno: "ansibrightgreen",
148
+ Token.ValEm: "ansiblue",
149
+ Token.VName: "ansicyan",
150
+ Token.Caret: "",
151
+ Token.Filename: "ansibrightgreen",
152
+ Token.FilenameEm: "ansigreen",
153
+ Token.ExcName: "ansired",
154
+ Token.Topline: "ansired",
155
+ Token.Normal: "",
156
+ Token.NormalEm: "ansicyan",
157
+ Token.Line: "ansired",
158
+ Token.TB.Name: "ansibrightmagenta",
159
+ Token.TB.NameEm: "ansimagenta",
160
+ Token.Breakpoint: "",
161
+ Token.Breakpoint.Enabled: "ansibrightred",
162
+ Token.Breakpoint.Disabled: "ansired",
163
+ ## specific override of pygments defaults for visibility
164
+ Token.Number: "ansigreen",
165
+ Token.Operator: "noinherit",
166
+ Token.String: "ansiyellow",
167
+ Token.Name.Function: "ansiblue",
168
+ Token.Name.Class: "bold ansiblue",
169
+ Token.Name.Namespace: "bold ansiblue",
170
+ Token.Name.Variable.Magic: "ansiblue",
171
+ Token.Prompt: "ansigreen",
172
+ Token.OutPrompt: "ansired",
173
+ }
174
+
175
+
176
+ neutral_pygments_nt = {
177
+ **neutral_pygments_equiv,
178
+ Token.PromptNum: "ansigreen bold",
179
+ Token.OutPromptNum: "ansired bold",
180
+ }
181
+ neutral_pygments_posix = {
182
+ **neutral_pygments_equiv,
183
+ Token.PromptNum: "ansibrightgreen bold",
184
+ Token.OutPromptNum: "ansibrightred bold",
185
+ }
186
+
187
+
188
+ neutral_nt = Theme("neutral:nt", "default", neutral_pygments_nt)
189
+ neutral_posix = Theme("neutral:posix", "default", neutral_pygments_posix)
190
+
191
+
192
+ # Hack: the 'neutral' colours are not very visible on a dark background on
193
+ # Windows. Since Windows command prompts have a dark background by default, and
194
+ # relatively few users are likely to alter that, we will use the 'Linux' colours,
195
+ # designed for a dark background, as the default on Windows. Changing it here
196
+ # avoids affecting the prompt colours rendered by prompt_toolkit, where the
197
+ # neutral defaults do work OK.
198
+ if os.name == "nt":
199
+ neutral_theme = neutral_nt
200
+ else:
201
+ neutral_theme = neutral_posix
202
+
203
+
204
+ lightbg_theme = Theme(
205
+ "lightbg",
206
+ "pastie",
207
+ {
208
+ Token.Header: "ansired",
209
+ Token.LinenoEm: "ansigreen",
210
+ Token.Lineno: "ansibrightgreen",
211
+ Token.ValEm: "ansiblue",
212
+ Token.VName: "ansicyan",
213
+ Token.Caret: "",
214
+ Token.Filename: "ansigreen",
215
+ Token.FilenameEm: "ansibrightgreen",
216
+ Token.ExcName: "ansired",
217
+ Token.Topline: "ansired",
218
+ Token.Normal: "",
219
+ Token.NormalEm: "ansicyan",
220
+ Token.Line: "ansired",
221
+ Token.TB.Name: "ansibrightmagenta",
222
+ Token.TB.NameEm: "ansimagenta",
223
+ Token.Breakpoint: "",
224
+ Token.Breakpoint.Enabled: "ansibrightred",
225
+ Token.Breakpoint.Disabled: "ansired",
226
+ Token.Prompt: "ansibrightblue",
227
+ Token.PromptNum: "ansiblue bold",
228
+ Token.OutPrompt: "ansibrightred",
229
+ Token.OutPromptNum: "ansired bold",
230
+ },
231
+ )
232
+
233
+ PRIDE_RED = "#E40303"
234
+ PRIDE_ORANGE = "#FF8C00"
235
+ PRIDE_YELLOW = "#FFED00"
236
+ PRIDE_GREEN = "#008026"
237
+ PRIDE_INDIGO = "#004CFF"
238
+ PRIDE_VIOLET = "#732982"
239
+ pride_theme = Theme(
240
+ "pride",
241
+ "pastie",
242
+ {
243
+ Token.Header: PRIDE_INDIGO,
244
+ Token.LinenoEm: f"{PRIDE_GREEN} italic",
245
+ Token.Lineno: f"{PRIDE_GREEN} bold",
246
+ Token.ValEm: f"{PRIDE_INDIGO} italic",
247
+ Token.VName: "ansicyan",
248
+ Token.Caret: "",
249
+ Token.Filename: f"{PRIDE_YELLOW}",
250
+ Token.FilenameEm: f"bg:{PRIDE_VIOLET}",
251
+ Token.ExcName: f"{PRIDE_ORANGE}",
252
+ Token.Topline: f"{PRIDE_RED}",
253
+ Token.Normal: "",
254
+ Token.NormalEm: "bold",
255
+ Token.Line: "ansired",
256
+ Token.TB.Name: "ansibrightmagenta",
257
+ Token.TB.NameEm: "ansimagenta",
258
+ Token.Breakpoint: "",
259
+ Token.Breakpoint.Enabled: "ansibrightred",
260
+ Token.Breakpoint.Disabled: "ansired",
261
+ Token.Prompt: "ansibrightblue",
262
+ Token.Prompt.Continuation.L1: f"ansiwhite bg:{PRIDE_RED}",
263
+ Token.Prompt.Continuation.L2: f"ansiwhite bg:{PRIDE_ORANGE}",
264
+ Token.Prompt.Continuation.L3: f"ansiblack bg:{PRIDE_YELLOW}",
265
+ Token.Prompt.Continuation.L4: f"ansiwhite bg:{PRIDE_GREEN}",
266
+ Token.Prompt.Continuation.L5: f"ansiwhite bg:{PRIDE_INDIGO}",
267
+ Token.Prompt.Continuation.L6: f"ansiwhite bg:{PRIDE_VIOLET}",
268
+ Token.PromptNum: "ansiblue bold",
269
+ Token.OutPrompt: "ansibrightred",
270
+ Token.OutPromptNum: "ansired bold",
271
+ },
272
+ symbols={"arrow_body": "\u2500", "arrow_head": "\u25b6", "top_line": "\u2500"},
273
+ )
274
+
275
+
276
+ C1 = "#D52D00"
277
+ C2 = "#EF7627"
278
+ C3 = "#FF9A56"
279
+ White = "#FFFFFF"
280
+ C5 = "#D162A4"
281
+ C6 = "#B55690"
282
+ C7 = "#A30262"
283
+
284
+ pl = {
285
+ # Token.Whitespace: "#bbbbbb",
286
+ Token.Comment: "#888888",
287
+ Token.String: C5,
288
+ Token.String.Escape: C1,
289
+ Token.Keyword: f"italic {C2}",
290
+ Token.Name.Class: C2,
291
+ Token.Name.Exception: C1,
292
+ Token.Name.Builtin: C3,
293
+ Token.Name.Variable: C6,
294
+ Token.Name.Constant: C7,
295
+ Token.Name.Decorator: C2,
296
+ Token.Number: C7,
297
+ Token.Generic.Deleted: f"bg:{C1} #000000",
298
+ Token.Generic.Emph: "italic",
299
+ Token.Generic.Strong: "bold",
300
+ Token.Generic.EmphStrong: "bold italic",
301
+ }
302
+
303
+ pridel_theme = Theme(
304
+ "pride:l",
305
+ None,
306
+ {
307
+ Token.Header: C3,
308
+ Token.LinenoEm: C3,
309
+ Token.Lineno: C2,
310
+ Token.ValEm: C2,
311
+ Token.VName: C2,
312
+ Token.Caret: "",
313
+ Token.Filename: C2,
314
+ Token.FilenameEm: C3,
315
+ Token.ExcName: C1,
316
+ Token.Topline: C1,
317
+ Token.Normal: "",
318
+ Token.NormalEm: "bold",
319
+ Token.Line: C2,
320
+ Token.TB.Name: C6,
321
+ Token.TB.NameEm: C7,
322
+ Token.Breakpoint: "",
323
+ Token.Breakpoint.Enabled: C1,
324
+ Token.Breakpoint.Disabled: C7,
325
+ Token.Prompt: C1,
326
+ Token.PromptNum: C2,
327
+ Token.Prompt.Continuation: C7,
328
+ Token.Prompt.Continuation.L1: C2,
329
+ Token.Prompt.Continuation.L2: C3,
330
+ Token.Prompt.Continuation.L3: White,
331
+ Token.Prompt.Continuation.L4: C5,
332
+ Token.Prompt.Continuation.L5: C6,
333
+ Token.Prompt.Continuation.L6: C7,
334
+ Token.OutPrompt: C6,
335
+ Token.OutPromptNum: C5,
336
+ **pl,
337
+ },
338
+ symbols={"arrow_body": "\u2500", "arrow_head": "\u25b6", "top_line": "\u2500"},
339
+ )
340
+
341
+ GRUVBOX_VAL_EM = "#D79921"
342
+ GRUVBOX_V_NAME = "#83A598"
343
+ GRUVBOX_FILENAME = "#FBF1C7"
344
+ GRUVBOX_EXCEPTION_NAME = "#FB4934"
345
+ GRUVBOX_TOPLINE = "#CC241D"
346
+ GRUVBOX_BREAKPOINT_ENABLED = "#FB4934"
347
+ GRUVBOX_BREAKPOINT_DISABLED = "#CC241D"
348
+ GRUVBOX_PROMPT = "#689D6A"
349
+ GRUVBOX_PROMPT_NUM = "#8EC07C"
350
+ GRUVBOX_OUT_PROMPT = "#B16286"
351
+ GRUVBOX_OUT_PROMPT_NUM = "#D3869B"
352
+ gruvbox_dark_theme = Theme(
353
+ "gruvbox-dark",
354
+ "gruvbox-dark",
355
+ {
356
+ Token.Lineno: GRUVBOX_PROMPT_NUM,
357
+ Token.LinenoEm: f"{GRUVBOX_PROMPT_NUM} bold",
358
+ Token.ValEm: f"{GRUVBOX_VAL_EM} bold",
359
+ Token.VName: GRUVBOX_V_NAME,
360
+ Token.Caret: "",
361
+ Token.Filename: GRUVBOX_FILENAME,
362
+ Token.FilenameEm: f"{GRUVBOX_FILENAME} bold",
363
+ Token.ExcName: f"{GRUVBOX_EXCEPTION_NAME} bold",
364
+ Token.Topline: GRUVBOX_TOPLINE,
365
+ Token.Breakpoint.Enabled: GRUVBOX_BREAKPOINT_ENABLED,
366
+ Token.Breakpoint.Disabled: GRUVBOX_BREAKPOINT_DISABLED,
367
+ Token.Prompt: GRUVBOX_PROMPT,
368
+ Token.PromptNum: f"{GRUVBOX_PROMPT_NUM} bold",
369
+ Token.OutPrompt: GRUVBOX_OUT_PROMPT,
370
+ Token.OutPromptNum: f"{GRUVBOX_OUT_PROMPT_NUM} bold",
371
+ },
372
+ symbols={"arrow_body": "\u2500", "arrow_head": "\u25b6", "top_line": "\u2500"},
373
+ )
374
+
375
+ theme_table: dict[str, Theme] = {
376
+ "nocolor": nocolors_theme,
377
+ "linux": linux_theme,
378
+ "neutral": neutral_theme,
379
+ "neutral:nt": neutral_nt,
380
+ "neutral:posix": neutral_posix,
381
+ "lightbg": lightbg_theme,
382
+ "pride": pride_theme,
383
+ "pride:l": pridel_theme,
384
+ "gruvbox-dark": gruvbox_dark_theme,
385
+ }
386
+
387
+
388
+ class Parser:
389
+ """Format colored Python source."""
390
+
391
+ _theme_name: str
392
+ out: Any
393
+ pos: int
394
+ lines: list[int]
395
+ raw: str
396
+
397
+ def __init__(self, out: Any = sys.stdout, *, theme_name: str | None = None) -> None:
398
+ """Create a parser with a specified color table and output channel.
399
+
400
+ Call format() to process code.
401
+ """
402
+
403
+ assert theme_name is not None
404
+
405
+ self.out = out
406
+ self.pos = 0
407
+ self.lines = []
408
+ self.raw = ""
409
+ if theme_name is not None:
410
+ if theme_name in ["Linux", "LightBG", "Neutral", "NoColor"]:
411
+ warnings.warn(
412
+ f"Theme names and color schemes are lowercase in IPython 9.0 use {theme_name.lower()} instead",
413
+ DeprecationWarning,
414
+ stacklevel=2,
415
+ )
416
+ theme_name = theme_name.lower()
417
+ if not theme_name:
418
+ self.theme_name = "nocolor"
419
+ else:
420
+ self.theme_name = theme_name
421
+
422
+ @property
423
+ def theme_name(self) -> str:
424
+ return self._theme_name
425
+
426
+ @theme_name.setter
427
+ def theme_name(self, value: str) -> None:
428
+ assert value == value.lower()
429
+ self._theme_name = value
430
+
431
+ @property
432
+ def style(self) -> str:
433
+ assert False
434
+ return self._theme_name
435
+
436
+ @style.setter
437
+ def style(self, val: str) -> None:
438
+ assert False
439
+ assert val == val.lower()
440
+ self._theme_name = val
441
+
442
+ def format(self, raw: str, out: Any = None) -> str | None:
443
+ return self.format2(raw, out)[0]
444
+
445
+ def format2(self, raw: str, out: Any = None) -> tuple[str | None, bool]:
446
+ """Parse and send the colored source.
447
+
448
+ If out is not specified, the defaults (given to constructor) are used.
449
+
450
+ out should be a file-type object. Optionally, out can be given as the
451
+ string 'str' and the parser will automatically return the output in a
452
+ string."""
453
+
454
+ string_output = 0
455
+ if out == "str" or self.out == "str" or isinstance(self.out, StringIO):
456
+ # XXX - I don't really like this state handling logic, but at this
457
+ # point I don't want to make major changes, so adding the
458
+ # isinstance() check is the simplest I can do to ensure correct
459
+ # behavior.
460
+ out_old = self.out
461
+ self.out = StringIO()
462
+ string_output = 1
463
+ elif out is not None:
464
+ self.out = out
465
+ else:
466
+ raise ValueError(
467
+ '`out` or `self.out` should be file-like or the value `"str"`'
468
+ )
469
+
470
+ # Fast return of the unmodified input for nocolor scheme
471
+ # TODO:
472
+ if self.theme_name == "nocolor":
473
+ error = False
474
+ self.out.write(raw)
475
+ if string_output:
476
+ return raw, error
477
+ return None, error
478
+
479
+ # local shorthands
480
+
481
+ # Remove trailing whitespace and normalize tabs
482
+ self.raw = raw.expandtabs().rstrip()
483
+
484
+ # store line offsets in self.lines
485
+ self.lines = [0, 0]
486
+ pos = 0
487
+ raw_find = self.raw.find
488
+ lines_append = self.lines.append
489
+ while True:
490
+ pos = raw_find("\n", pos) + 1
491
+ if not pos:
492
+ break
493
+ lines_append(pos)
494
+ lines_append(len(self.raw))
495
+
496
+ # parse the source and write it
497
+ self.pos = 0
498
+ text = StringIO(self.raw)
499
+
500
+ error = False
501
+ try:
502
+ for atoken in generate_tokens(text.readline):
503
+ self(*atoken)
504
+ except tokenize.TokenError as ex:
505
+ msg = ex.args[0]
506
+ line = ex.args[1][0]
507
+ self.out.write(
508
+ theme_table[self.theme_name].format(
509
+ [
510
+ (Token, "\n\n"),
511
+ (
512
+ Token.Error,
513
+ f"*** ERROR: {msg}{self.raw[self.lines[line] :]}",
514
+ ),
515
+ (Token, "\n"),
516
+ ]
517
+ )
518
+ )
519
+ error = True
520
+ self.out.write(
521
+ theme_table[self.theme_name].format(
522
+ [
523
+ (Token, "\n"),
524
+ ]
525
+ )
526
+ )
527
+
528
+ if string_output:
529
+ output = self.out.getvalue()
530
+ self.out = out_old
531
+ return (output, error)
532
+ return (None, error)
533
+
534
+ def _inner_call_(
535
+ self, toktype: int, toktext: str, start_pos: tuple[int, int]
536
+ ) -> str:
537
+ """like call but write to a temporary buffer"""
538
+ srow, scol = start_pos
539
+
540
+ # calculate new positions
541
+ oldpos = self.pos
542
+ newpos = self.lines[srow] + scol
543
+ self.pos = newpos + len(toktext)
544
+
545
+ # send the original whitespace, if needed
546
+ if newpos > oldpos:
547
+ acc = self.raw[oldpos:newpos]
548
+ else:
549
+ acc = ""
550
+
551
+ # skip indenting tokens
552
+ if toktype in [token.INDENT, token.DEDENT]:
553
+ self.pos = newpos
554
+ return acc
555
+
556
+ # map token type to a color group
557
+ if token.LPAR <= toktype <= token.OP:
558
+ toktype = token.OP
559
+ elif toktype == token.NAME and keyword.iskeyword(toktext):
560
+ toktype = _KEYWORD
561
+ pyg_tok_type = _pygment_token_mapping.get(toktype, Token.Text)
562
+
563
+ # send text, pygments should take care of splitting on newline and resending
564
+ # the correct self.colors after the new line, which is necessary for pagers
565
+ acc += theme_table[self.theme_name].format([(pyg_tok_type, toktext)])
566
+ return acc
567
+
568
+ def __call__(
569
+ self,
570
+ toktype: int,
571
+ toktext: str,
572
+ start_pos: tuple[int, int],
573
+ end_pos: tuple[int, int],
574
+ line: str,
575
+ ) -> None:
576
+ """Token handler, with syntax highlighting."""
577
+ self.out.write(self._inner_call_(toktype, toktext, start_pos))
lib/python3.12/site-packages/IPython/utils/__init__.py ADDED
File without changes
lib/python3.12/site-packages/IPython/utils/__pycache__/PyColorize.cpython-312.pyc ADDED
Binary file (22 kB). View file
 
lib/python3.12/site-packages/IPython/utils/__pycache__/_process_cli.cpython-312.pyc ADDED
Binary file (2.87 kB). View file
 
lib/python3.12/site-packages/IPython/utils/__pycache__/_process_common.cpython-312.pyc ADDED
Binary file (8.25 kB). View file
 
lib/python3.12/site-packages/IPython/utils/__pycache__/_process_emscripten.cpython-312.pyc ADDED
Binary file (850 Bytes). View file
 
lib/python3.12/site-packages/IPython/utils/__pycache__/_process_posix.cpython-312.pyc ADDED
Binary file (6.27 kB). View file
 
lib/python3.12/site-packages/IPython/utils/__pycache__/_process_win32.cpython-312.pyc ADDED
Binary file (8.49 kB). View file
 
lib/python3.12/site-packages/IPython/utils/__pycache__/_process_win32_controller.cpython-312.pyc ADDED
Binary file (21.7 kB). View file
 
lib/python3.12/site-packages/IPython/utils/__pycache__/_sysinfo.cpython-312.pyc ADDED
Binary file (215 Bytes). View file
 
lib/python3.12/site-packages/IPython/utils/__pycache__/coloransi.cpython-312.pyc ADDED
Binary file (408 Bytes). View file
 
lib/python3.12/site-packages/IPython/utils/__pycache__/contexts.cpython-312.pyc ADDED
Binary file (2.22 kB). View file
 
lib/python3.12/site-packages/IPython/utils/__pycache__/data.cpython-312.pyc ADDED
Binary file (1.97 kB). View file
 
lib/python3.12/site-packages/IPython/utils/__pycache__/docs.cpython-312.pyc ADDED
Binary file (354 Bytes). View file
 
lib/python3.12/site-packages/IPython/utils/__pycache__/eventful.cpython-312.pyc ADDED
Binary file (376 Bytes). View file