ipython 9.0.2__py3-none-any.whl → 9.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
IPython/core/completer.py CHANGED
@@ -1137,7 +1137,7 @@ class Completer(Configurable):
1137
1137
  def _attr_matches(
1138
1138
  self, text: str, include_prefix: bool = True
1139
1139
  ) -> tuple[Sequence[str], str]:
1140
- m2 = self._ATTR_MATCH_RE.match(self.line_buffer)
1140
+ m2 = self._ATTR_MATCH_RE.match(text)
1141
1141
  if not m2:
1142
1142
  return [], ""
1143
1143
  expr, attr = m2.group(1, 2)
@@ -2360,11 +2360,163 @@ class IPCompleter(Completer):
2360
2360
  else:
2361
2361
  return iter([])
2362
2362
 
2363
+ class _CompletionContextType(enum.Enum):
2364
+ ATTRIBUTE = "attribute" # For attribute completion
2365
+ GLOBAL = "global" # For global completion
2366
+
2367
+ def _determine_completion_context(self, line):
2368
+ """
2369
+ Determine whether the cursor is in an attribute or global completion context.
2370
+ """
2371
+ # Cursor in string/comment → GLOBAL.
2372
+ is_string, is_in_expression = self._is_in_string_or_comment(line)
2373
+ if is_string and not is_in_expression:
2374
+ return self._CompletionContextType.GLOBAL
2375
+
2376
+ # If we're in a template string expression, handle specially
2377
+ if is_string and is_in_expression:
2378
+ # Extract the expression part - look for the last { that isn't closed
2379
+ expr_start = line.rfind("{")
2380
+ if expr_start >= 0:
2381
+ # We're looking at the expression inside a template string
2382
+ expr = line[expr_start + 1 :]
2383
+ # Recursively determine the context of the expression
2384
+ return self._determine_completion_context(expr)
2385
+
2386
+ # Handle plain number literals - should be global context
2387
+ # Ex: 3. -42.14 but not 3.1.
2388
+ if re.search(r"(?<!\w)(?<!\d\.)([-+]?\d+\.(\d+)?)(?!\w)$", line):
2389
+ return self._CompletionContextType.GLOBAL
2390
+
2391
+ # Handle all other attribute matches np.ran, d[0].k, (a,b).count
2392
+ chain_match = re.search(r".*(.+\.(?:[a-zA-Z]\w*)?)$", line)
2393
+ if chain_match:
2394
+ return self._CompletionContextType.ATTRIBUTE
2395
+
2396
+ return self._CompletionContextType.GLOBAL
2397
+
2398
+ def _is_in_string_or_comment(self, text):
2399
+ """
2400
+ Determine if the cursor is inside a string or comment.
2401
+ Returns (is_string, is_in_expression) tuple:
2402
+ - is_string: True if in any kind of string
2403
+ - is_in_expression: True if inside an f-string/t-string expression
2404
+ """
2405
+ in_single_quote = False
2406
+ in_double_quote = False
2407
+ in_triple_single = False
2408
+ in_triple_double = False
2409
+ in_template_string = False # Covers both f-strings and t-strings
2410
+ in_expression = False # For expressions in f/t-strings
2411
+ expression_depth = 0 # Track nested braces in expressions
2412
+ i = 0
2413
+
2414
+ while i < len(text):
2415
+ # Check for f-string or t-string start
2416
+ if (
2417
+ i + 1 < len(text)
2418
+ and text[i] in ("f", "t")
2419
+ and (text[i + 1] == '"' or text[i + 1] == "'")
2420
+ and not (
2421
+ in_single_quote
2422
+ or in_double_quote
2423
+ or in_triple_single
2424
+ or in_triple_double
2425
+ )
2426
+ ):
2427
+ in_template_string = True
2428
+ i += 1 # Skip the 'f' or 't'
2429
+
2430
+ # Handle triple quotes
2431
+ if i + 2 < len(text):
2432
+ if (
2433
+ text[i : i + 3] == '"""'
2434
+ and not in_single_quote
2435
+ and not in_triple_single
2436
+ ):
2437
+ in_triple_double = not in_triple_double
2438
+ if not in_triple_double:
2439
+ in_template_string = False
2440
+ i += 3
2441
+ continue
2442
+ if (
2443
+ text[i : i + 3] == "'''"
2444
+ and not in_double_quote
2445
+ and not in_triple_double
2446
+ ):
2447
+ in_triple_single = not in_triple_single
2448
+ if not in_triple_single:
2449
+ in_template_string = False
2450
+ i += 3
2451
+ continue
2452
+
2453
+ # Handle escapes
2454
+ if text[i] == "\\" and i + 1 < len(text):
2455
+ i += 2
2456
+ continue
2457
+
2458
+ # Handle nested braces within f-strings
2459
+ if in_template_string:
2460
+ # Special handling for consecutive opening braces
2461
+ if i + 1 < len(text) and text[i : i + 2] == "{{":
2462
+ i += 2
2463
+ continue
2464
+
2465
+ # Detect start of an expression
2466
+ if text[i] == "{":
2467
+ # Only increment depth and mark as expression if not already in an expression
2468
+ # or if we're at a top-level nested brace
2469
+ if not in_expression or (in_expression and expression_depth == 0):
2470
+ in_expression = True
2471
+ expression_depth += 1
2472
+ i += 1
2473
+ continue
2474
+
2475
+ # Detect end of an expression
2476
+ if text[i] == "}":
2477
+ expression_depth -= 1
2478
+ if expression_depth <= 0:
2479
+ in_expression = False
2480
+ expression_depth = 0
2481
+ i += 1
2482
+ continue
2483
+
2484
+ in_triple_quote = in_triple_single or in_triple_double
2485
+
2486
+ # Handle quotes - also reset template string when closing quotes are encountered
2487
+ if text[i] == '"' and not in_single_quote and not in_triple_quote:
2488
+ in_double_quote = not in_double_quote
2489
+ if not in_double_quote and not in_triple_quote:
2490
+ in_template_string = False
2491
+ elif text[i] == "'" and not in_double_quote and not in_triple_quote:
2492
+ in_single_quote = not in_single_quote
2493
+ if not in_single_quote and not in_triple_quote:
2494
+ in_template_string = False
2495
+
2496
+ # Check for comment
2497
+ if text[i] == "#" and not (
2498
+ in_single_quote or in_double_quote or in_triple_quote
2499
+ ):
2500
+ return True, False
2501
+
2502
+ i += 1
2503
+
2504
+ is_string = (
2505
+ in_single_quote or in_double_quote or in_triple_single or in_triple_double
2506
+ )
2507
+
2508
+ # Return tuple (is_string, is_in_expression)
2509
+ return (
2510
+ is_string or (in_template_string and not in_expression),
2511
+ in_expression and expression_depth > 0,
2512
+ )
2513
+
2363
2514
  @context_matcher()
2364
2515
  def python_matcher(self, context: CompletionContext) -> SimpleMatcherResult:
2365
2516
  """Match attributes or global python names"""
2366
- text = context.line_with_cursor
2367
- if "." in text:
2517
+ text = context.text_until_cursor
2518
+ completion_type = self._determine_completion_context(text)
2519
+ if completion_type == self._CompletionContextType.ATTRIBUTE:
2368
2520
  try:
2369
2521
  matches, fragment = self._attr_matches(text, include_prefix=False)
2370
2522
  if text.endswith(".") and self.omit__names:
@@ -58,6 +58,10 @@ class DisplayTrap(Configurable):
58
58
  # Returning False will cause exceptions to propagate
59
59
  return False
60
60
 
61
+ @property
62
+ def is_active(self) -> bool:
63
+ return self._nested_level != 0
64
+
61
65
  def set(self):
62
66
  """Set the hook."""
63
67
  if sys.displayhook is not self.hook:
@@ -16,6 +16,8 @@ from traitlets.config.configurable import Configurable
16
16
  from traitlets import Instance, Float
17
17
  from warnings import warn
18
18
 
19
+ from .history import HistoryOutput
20
+
19
21
  # TODO: Move the various attributes (cache_size, [others now moved]). Some
20
22
  # of these are also attributes of InteractiveShell. They should be on ONE object
21
23
  # only and the other objects should ask that one object for their values.
@@ -35,6 +37,7 @@ class DisplayHook(Configurable):
35
37
 
36
38
  def __init__(self, shell=None, cache_size=1000, **kwargs):
37
39
  super(DisplayHook, self).__init__(shell=shell, **kwargs)
40
+ self._is_active = False
38
41
  cache_size_min = 3
39
42
  if cache_size <= 0:
40
43
  self.do_full_cache = 0
@@ -51,7 +54,7 @@ class DisplayHook(Configurable):
51
54
 
52
55
  # we need a reference to the user-level namespace
53
56
  self.shell = shell
54
-
57
+
55
58
  self._,self.__,self.___ = '','',''
56
59
 
57
60
  # these are deliberately global:
@@ -84,13 +87,13 @@ class DisplayHook(Configurable):
84
87
  def quiet(self):
85
88
  """Should we silence the display hook because of ';'?"""
86
89
  # do not print output if input ends in ';'
87
-
90
+
88
91
  try:
89
92
  cell = self.shell.history_manager.input_hist_parsed[-1]
90
93
  except IndexError:
91
94
  # some uses of ipshellembed may fail here
92
95
  return False
93
-
96
+
94
97
  return self.semicolon_at_end_of_expression(cell)
95
98
 
96
99
  @staticmethod
@@ -110,7 +113,11 @@ class DisplayHook(Configurable):
110
113
 
111
114
  def start_displayhook(self):
112
115
  """Start the displayhook, initializing resources."""
113
- pass
116
+ self._is_active = True
117
+
118
+ @property
119
+ def is_active(self):
120
+ return self._is_active
114
121
 
115
122
  def write_output_prompt(self):
116
123
  """Write the output prompt.
@@ -242,7 +249,10 @@ class DisplayHook(Configurable):
242
249
 
243
250
  def log_output(self, format_dict):
244
251
  """Log the output."""
245
- if 'text/plain' not in format_dict:
252
+ self.shell.history_manager.outputs[self.prompt_count].append(
253
+ HistoryOutput(output_type="execute_result", bundle=format_dict)
254
+ )
255
+ if "text/plain" not in format_dict:
246
256
  # nothing to do
247
257
  return
248
258
  if self.shell.logger.log_output:
@@ -254,6 +264,7 @@ class DisplayHook(Configurable):
254
264
  """Finish up all displayhook activities."""
255
265
  sys.stdout.write(self.shell.separate_out2)
256
266
  sys.stdout.flush()
267
+ self._is_active = False
257
268
 
258
269
  def __call__(self, result=None):
259
270
  """Printing with history cache management.
@@ -280,13 +291,12 @@ class DisplayHook(Configurable):
280
291
  cull_count = max(int(sz * self.cull_fraction), 2)
281
292
  warn('Output cache limit (currently {sz} entries) hit.\n'
282
293
  'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
283
-
294
+
284
295
  for i, n in enumerate(sorted(oh)):
285
296
  if i >= cull_count:
286
297
  break
287
298
  self.shell.user_ns.pop('_%i' % n, None)
288
299
  oh.pop(n, None)
289
-
290
300
 
291
301
  def flush(self):
292
302
  if not self.do_full_cache:
@@ -22,6 +22,7 @@ from traitlets import List
22
22
 
23
23
  # This used to be defined here - it is imported for backwards compatibility
24
24
  from .display_functions import publish_display_data
25
+ from .history import HistoryOutput
25
26
 
26
27
  import typing as t
27
28
 
@@ -41,6 +42,7 @@ class DisplayPublisher(Configurable):
41
42
 
42
43
  def __init__(self, shell=None, *args, **kwargs):
43
44
  self.shell = shell
45
+ self._is_publishing = False
44
46
  super().__init__(*args, **kwargs)
45
47
 
46
48
  def _validate_data(self, data, metadata=None):
@@ -129,13 +131,25 @@ class DisplayPublisher(Configurable):
129
131
  if self.shell is not None:
130
132
  handlers = getattr(self.shell, "mime_renderers", {})
131
133
 
134
+ outputs = self.shell.history_manager.outputs
135
+
136
+ outputs[self.shell.execution_count].append(
137
+ HistoryOutput(output_type="display_data", bundle=data)
138
+ )
139
+
132
140
  for mime, handler in handlers.items():
133
141
  if mime in data:
134
142
  handler(data[mime], metadata.get(mime, None))
135
143
  return
136
144
 
145
+ self._is_publishing = True
137
146
  if "text/plain" in data:
138
147
  print(data["text/plain"])
148
+ self._is_publishing = False
149
+
150
+ @property
151
+ def is_publishing(self):
152
+ return self._is_publishing
139
153
 
140
154
  def clear_output(self, wait=False):
141
155
  """Clear the output of the cell receiving output."""
IPython/core/history.py CHANGED
@@ -14,7 +14,9 @@ import re
14
14
  import threading
15
15
  from pathlib import Path
16
16
 
17
+ from collections import defaultdict
17
18
  from contextlib import contextmanager
19
+ from dataclasses import dataclass
18
20
  from decorator import decorator
19
21
  from traitlets import (
20
22
  Any,
@@ -583,6 +585,14 @@ class HistoryAccessor(HistoryAccessorBase):
583
585
  yield from self.get_range(sess, s, e, raw=raw, output=output)
584
586
 
585
587
 
588
+ @dataclass
589
+ class HistoryOutput:
590
+ output_type: typing.Literal[
591
+ "out_stream", "err_stream", "display_data", "execute_result"
592
+ ]
593
+ bundle: typing.Dict[str, str]
594
+
595
+
586
596
  class HistoryManager(HistoryAccessor):
587
597
  """A class to organize all history-related functionality in one place."""
588
598
 
@@ -610,7 +620,11 @@ class HistoryManager(HistoryAccessor):
610
620
  # execution count.
611
621
  output_hist = Dict()
612
622
  # The text/plain repr of outputs.
613
- output_hist_reprs: dict[int, str] = Dict() # type: ignore [assignment]
623
+ output_hist_reprs: typing.Dict[int, str] = Dict() # type: ignore [assignment]
624
+ # Maps execution_count to MIME bundles
625
+ outputs: typing.Dict[int, typing.List[HistoryOutput]] = defaultdict(list)
626
+ # Maps execution_count to exception tracebacks
627
+ exceptions: typing.Dict[int, typing.Dict[str, Any]] = Dict() # type: ignore [assignment]
614
628
 
615
629
  # The number of the current session in the history database
616
630
  session_number: int = Integer() # type: ignore [assignment]
@@ -749,6 +763,9 @@ class HistoryManager(HistoryAccessor):
749
763
  """Clear the session history, releasing all object references, and
750
764
  optionally open a new session."""
751
765
  self.output_hist.clear()
766
+ self.outputs.clear()
767
+ self.exceptions.clear()
768
+
752
769
  # The directory history can't be completely empty
753
770
  self.dir_hist[:] = [Path.cwd()]
754
771
 
@@ -59,9 +59,9 @@ class HistoryTrim(BaseIPythonApplication):
59
59
  print("There are already at most %d entries in the history database." % self.keep)
60
60
  print("Not doing anything. Use --keep= argument to keep fewer entries")
61
61
  return
62
-
62
+
63
63
  print("Trimming history to the most recent %d entries." % self.keep)
64
-
64
+
65
65
  inputs.pop() # Remove the extra element we got to check the length.
66
66
  inputs.reverse()
67
67
  if inputs:
@@ -71,7 +71,7 @@ class HistoryTrim(BaseIPythonApplication):
71
71
  sessions = list(con.execute('SELECT session, start, end, num_cmds, remark FROM '
72
72
  'sessions WHERE session >= ?', (first_session,)))
73
73
  con.close()
74
-
74
+
75
75
  # Create the new history database.
76
76
  new_hist_file = profile_dir / "history.sqlite.new"
77
77
  i = 0
@@ -28,12 +28,13 @@ import traceback
28
28
  import types
29
29
  import warnings
30
30
  from ast import stmt
31
+ from contextlib import contextmanager
31
32
  from io import open as io_open
32
33
  from logging import error
33
34
  from pathlib import Path
34
35
  from typing import Callable
35
36
  from typing import List as ListType, Any as AnyType
36
- from typing import Optional, Sequence, Tuple
37
+ from typing import Literal, Optional, Sequence, Tuple
37
38
  from warnings import warn
38
39
 
39
40
  from IPython.external.pickleshare import PickleShareDB
@@ -71,7 +72,7 @@ from IPython.core.error import InputRejected, UsageError
71
72
  from IPython.core.events import EventManager, available_events
72
73
  from IPython.core.extensions import ExtensionManager
73
74
  from IPython.core.formatters import DisplayFormatter
74
- from IPython.core.history import HistoryManager
75
+ from IPython.core.history import HistoryManager, HistoryOutput
75
76
  from IPython.core.inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
76
77
  from IPython.core.logger import Logger
77
78
  from IPython.core.macro import Macro
@@ -324,6 +325,7 @@ def _modified_open(file, *args, **kwargs):
324
325
 
325
326
  return io_open(file, *args, **kwargs)
326
327
 
328
+
327
329
  class InteractiveShell(SingletonConfigurable):
328
330
  """An enhanced, interactive shell for Python."""
329
331
 
@@ -466,7 +468,7 @@ class InteractiveShell(SingletonConfigurable):
466
468
  # Monotonically increasing execution counter
467
469
  execution_count = Integer(1)
468
470
  filename = Unicode("<ipython console>")
469
- ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__
471
+ ipython_dir = Unicode("").tag(config=True) # Set to get_ipython_dir() in __init__
470
472
 
471
473
  # Used to transform cells before running them, and check whether code is complete
472
474
  input_transformer_manager = Instance('IPython.core.inputtransformer2.TransformerManager',
@@ -661,6 +663,7 @@ class InteractiveShell(SingletonConfigurable):
661
663
  # inside a single Trio event loop. If used, it is set from
662
664
  # `ipykernel.kernelapp`.
663
665
  self.trio_runner = None
666
+ self.showing_traceback = False
664
667
 
665
668
  @property
666
669
  def user_ns(self):
@@ -868,7 +871,7 @@ class InteractiveShell(SingletonConfigurable):
868
871
  cache_size=self.cache_size,
869
872
  )
870
873
  self.configurables.append(self.displayhook)
871
- # This is a context manager that installs/revmoes the displayhook at
874
+ # This is a context manager that installs/removes the displayhook at
872
875
  # the appropriate time.
873
876
  self.display_trap = DisplayTrap(hook=self.displayhook)
874
877
 
@@ -2200,10 +2203,12 @@ class InteractiveShell(SingletonConfigurable):
2200
2203
  place, like a side channel.
2201
2204
  """
2202
2205
  val = self.InteractiveTB.stb2text(stb)
2206
+ self.showing_traceback = True
2203
2207
  try:
2204
2208
  print(val)
2205
2209
  except UnicodeEncodeError:
2206
2210
  print(val.encode("utf-8", "backslashreplace").decode())
2211
+ self.showing_traceback = False
2207
2212
 
2208
2213
  def showsyntaxerror(self, filename=None, running_compiled_code=False):
2209
2214
  """Display the syntax error that just occurred.
@@ -3006,6 +3011,51 @@ class InteractiveShell(SingletonConfigurable):
3006
3011
  self.showtraceback()
3007
3012
  warn('Unknown failure executing module: <%s>' % mod_name)
3008
3013
 
3014
+ @contextmanager
3015
+ def _tee(self, channel: Literal["stdout", "stderr"]):
3016
+ """Capture output of a given standard stream and store it in history.
3017
+
3018
+ Uses patching of write method for maximal compatibility,
3019
+ because ipykernel checks for instances of the stream class,
3020
+ and stream classes in ipykernel implement more complex logic.
3021
+ """
3022
+ stream = getattr(sys, channel)
3023
+ original_write = stream.write
3024
+
3025
+ def write(data, *args, **kwargs):
3026
+ """Write data to both the original destination and the capture dictionary."""
3027
+ result = original_write(data, *args, **kwargs)
3028
+ if any(
3029
+ [
3030
+ self.display_pub.is_publishing,
3031
+ self.displayhook.is_active,
3032
+ self.showing_traceback,
3033
+ ]
3034
+ ):
3035
+ return result
3036
+ if not data:
3037
+ return result
3038
+ execution_count = self.execution_count
3039
+ output_stream = None
3040
+ outputs_by_counter = self.history_manager.outputs
3041
+ output_type = "out_stream" if channel == "stdout" else "err_stream"
3042
+ if execution_count in outputs_by_counter:
3043
+ outputs = outputs_by_counter[execution_count]
3044
+ if outputs[-1].output_type == output_type:
3045
+ output_stream = outputs[-1]
3046
+ if output_stream is None:
3047
+ output_stream = HistoryOutput(
3048
+ output_type=output_type, bundle={"stream": ""}
3049
+ )
3050
+ outputs_by_counter[execution_count].append(output_stream)
3051
+
3052
+ output_stream.bundle["stream"] += data # Append to existing stream
3053
+ return result
3054
+
3055
+ stream.write = write
3056
+ yield
3057
+ stream.write = original_write
3058
+
3009
3059
  def run_cell(
3010
3060
  self,
3011
3061
  raw_cell,
@@ -3043,14 +3093,15 @@ class InteractiveShell(SingletonConfigurable):
3043
3093
  result : :class:`ExecutionResult`
3044
3094
  """
3045
3095
  result = None
3046
- try:
3047
- result = self._run_cell(
3048
- raw_cell, store_history, silent, shell_futures, cell_id
3049
- )
3050
- finally:
3051
- self.events.trigger('post_execute')
3052
- if not silent:
3053
- self.events.trigger('post_run_cell', result)
3096
+ with self._tee(channel="stdout"), self._tee(channel="stderr"):
3097
+ try:
3098
+ result = self._run_cell(
3099
+ raw_cell, store_history, silent, shell_futures, cell_id
3100
+ )
3101
+ finally:
3102
+ self.events.trigger("post_execute")
3103
+ if not silent:
3104
+ self.events.trigger("post_run_cell", result)
3054
3105
  return result
3055
3106
 
3056
3107
  def _run_cell(
@@ -3208,6 +3259,11 @@ class InteractiveShell(SingletonConfigurable):
3208
3259
 
3209
3260
  def error_before_exec(value):
3210
3261
  if store_history:
3262
+ if self.history_manager:
3263
+ # Store formatted traceback and error details
3264
+ self.history_manager.exceptions[self.execution_count] = (
3265
+ self._format_exception_for_storage(value)
3266
+ )
3211
3267
  self.execution_count += 1
3212
3268
  result.error_before_exec = value
3213
3269
  self.last_execution_succeeded = False
@@ -3318,11 +3374,73 @@ class InteractiveShell(SingletonConfigurable):
3318
3374
  # Write output to the database. Does nothing unless
3319
3375
  # history output logging is enabled.
3320
3376
  self.history_manager.store_output(self.execution_count)
3377
+ exec_count = self.execution_count
3378
+ if result.error_in_exec:
3379
+ # Store formatted traceback and error details
3380
+ self.history_manager.exceptions[exec_count] = (
3381
+ self._format_exception_for_storage(result.error_in_exec)
3382
+ )
3383
+
3321
3384
  # Each cell is a *single* input, regardless of how many lines it has
3322
3385
  self.execution_count += 1
3323
3386
 
3324
3387
  return result
3325
3388
 
3389
+ def _format_exception_for_storage(
3390
+ self, exception, filename=None, running_compiled_code=False
3391
+ ):
3392
+ """
3393
+ Format an exception's traceback and details for storage, with special handling
3394
+ for different types of errors.
3395
+ """
3396
+ etype = type(exception)
3397
+ evalue = exception
3398
+ tb = exception.__traceback__
3399
+
3400
+ # Handle SyntaxError and IndentationError with specific formatting
3401
+ if issubclass(etype, (SyntaxError, IndentationError)):
3402
+ if filename and isinstance(evalue, SyntaxError):
3403
+ try:
3404
+ evalue.filename = filename
3405
+ except:
3406
+ pass # Keep the original filename if modification fails
3407
+
3408
+ # Extract traceback if the error happened during compiled code execution
3409
+ elist = traceback.extract_tb(tb) if running_compiled_code else []
3410
+ stb = self.SyntaxTB.structured_traceback(etype, evalue, elist)
3411
+
3412
+ # Handle UsageError with a simple message
3413
+ elif etype is UsageError:
3414
+ stb = [f"UsageError: {evalue}"]
3415
+
3416
+ else:
3417
+ # Check if the exception (or its context) is an ExceptionGroup.
3418
+ def contains_exceptiongroup(val):
3419
+ if val is None:
3420
+ return False
3421
+ return isinstance(val, BaseExceptionGroup) or contains_exceptiongroup(
3422
+ val.__context__
3423
+ )
3424
+
3425
+ if contains_exceptiongroup(evalue):
3426
+ # Fallback: use the standard library's formatting for exception groups.
3427
+ stb = traceback.format_exception(etype, evalue, tb)
3428
+ else:
3429
+ try:
3430
+ # If the exception has a custom traceback renderer, use it.
3431
+ if hasattr(evalue, "_render_traceback_"):
3432
+ stb = evalue._render_traceback_()
3433
+ else:
3434
+ # Otherwise, use InteractiveTB to format the traceback.
3435
+ stb = self.InteractiveTB.structured_traceback(
3436
+ etype, evalue, tb, tb_offset=1
3437
+ )
3438
+ except Exception:
3439
+ # In case formatting fails, fallback to Python's built-in formatting.
3440
+ stb = traceback.format_exception(etype, evalue, tb)
3441
+
3442
+ return {"ename": etype.__name__, "evalue": str(evalue), "traceback": stb}
3443
+
3326
3444
  def transform_cell(self, raw_cell):
3327
3445
  """Transform an input cell before parsing it.
3328
3446
 
@@ -21,7 +21,7 @@ class MagicsDisplay:
21
21
  def __init__(self, magics_manager, ignore=None):
22
22
  self.ignore = ignore if ignore else []
23
23
  self.magics_manager = magics_manager
24
-
24
+
25
25
  def _lsmagic(self):
26
26
  """The main implementation of the %lsmagic"""
27
27
  mesc = magic_escapes['line']
@@ -39,13 +39,13 @@ class MagicsDisplay:
39
39
 
40
40
  def _repr_pretty_(self, p, cycle):
41
41
  p.text(self._lsmagic())
42
-
42
+
43
43
  def __repr__(self):
44
44
  return self.__str__()
45
45
 
46
46
  def __str__(self):
47
47
  return self._lsmagic()
48
-
48
+
49
49
  def _jsonable(self):
50
50
  """turn magics dict into jsonable dict of the same structure
51
51
 
@@ -62,10 +62,10 @@ class MagicsDisplay:
62
62
  classname = obj.__self__.__class__.__name__
63
63
  except AttributeError:
64
64
  classname = 'Other'
65
-
65
+
66
66
  d[name] = classname
67
67
  return magic_dict
68
-
68
+
69
69
  def _repr_json_(self):
70
70
  return self._jsonable()
71
71
 
@@ -561,13 +561,46 @@ Currently the magic system has the following functions:""",
561
561
 
562
562
  cells = []
563
563
  hist = list(self.shell.history_manager.get_range())
564
+ outputs = self.shell.history_manager.outputs
565
+ exceptions = self.shell.history_manager.exceptions
566
+
564
567
  if(len(hist)<=1):
565
568
  raise ValueError('History is empty, cannot export')
566
569
  for session, execution_count, source in hist[:-1]:
567
- cells.append(v4.new_code_cell(
568
- execution_count=execution_count,
569
- source=source
570
- ))
570
+ cell = v4.new_code_cell(execution_count=execution_count, source=source)
571
+ for output in outputs[execution_count]:
572
+ for mime_type, data in output.bundle.items():
573
+ if output.output_type == "out_stream":
574
+ cell.outputs.append(v4.new_output("stream", text=[data]))
575
+ elif output.output_type == "err_stream":
576
+ err_output = v4.new_output("stream", text=[data])
577
+ err_output.name = "stderr"
578
+ cell.outputs.append(err_output)
579
+ elif output.output_type == "execute_result":
580
+ cell.outputs.append(
581
+ v4.new_output(
582
+ "execute_result",
583
+ data={mime_type: data},
584
+ execution_count=execution_count,
585
+ )
586
+ )
587
+ elif output.output_type == "display_data":
588
+ cell.outputs.append(
589
+ v4.new_output(
590
+ "display_data",
591
+ data={mime_type: data},
592
+ )
593
+ )
594
+ else:
595
+ raise ValueError(f"Unknown output type: {output.output_type}")
596
+
597
+ # Check if this execution_count is in exceptions (current session)
598
+ if execution_count in exceptions:
599
+ cell.outputs.append(
600
+ v4.new_output("error", **exceptions[execution_count])
601
+ )
602
+ cells.append(cell)
603
+
571
604
  nb = v4.new_notebook(cells=cells)
572
605
  with io.open(outfname, "w", encoding="utf-8") as f:
573
606
  write(nb, f, version=4)
@@ -1055,11 +1055,11 @@ class ExecutionMagics(Magics):
1055
1055
 
1056
1056
  **Usage, in line mode**::
1057
1057
 
1058
- %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
1058
+ %timeit [-n<N> -r<R> [-t|-c] -q -p<P> [-o|-v <V>]] statement
1059
1059
 
1060
1060
  **or in cell mode**::
1061
1061
 
1062
- %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
1062
+ %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> [-o|-v <V>]] setup_code
1063
1063
  code
1064
1064
  code...
1065
1065
 
@@ -1104,6 +1104,9 @@ class ExecutionMagics(Magics):
1104
1104
  Return a ``TimeitResult`` that can be stored in a variable to inspect
1105
1105
  the result in more details.
1106
1106
 
1107
+ -v <V>
1108
+ Like ``-o``, but save the ``TimeitResult`` directly to variable <V>.
1109
+
1107
1110
  .. versionchanged:: 7.3
1108
1111
  User variables are no longer expanded,
1109
1112
  the magic line is always left unmodified.
@@ -1135,7 +1138,7 @@ class ExecutionMagics(Magics):
1135
1138
  those from ``%timeit``."""
1136
1139
 
1137
1140
  opts, stmt = self.parse_options(
1138
- line, "n:r:tcp:qo", posix=False, strict=False, preserve_non_opts=True
1141
+ line, "n:r:tcp:qov:", posix=False, strict=False, preserve_non_opts=True
1139
1142
  )
1140
1143
  if stmt == "" and cell is None:
1141
1144
  return
@@ -1145,8 +1148,9 @@ class ExecutionMagics(Magics):
1145
1148
  default_repeat = 7 if timeit.default_repeat < 7 else timeit.default_repeat
1146
1149
  repeat = int(getattr(opts, "r", default_repeat))
1147
1150
  precision = int(getattr(opts, "p", 3))
1148
- quiet = 'q' in opts
1149
- return_result = 'o' in opts
1151
+ quiet = "q" in opts
1152
+ return_result = "o" in opts
1153
+ save_result = "v" in opts
1150
1154
  if hasattr(opts, "t"):
1151
1155
  timefunc = time.time
1152
1156
  if hasattr(opts, "c"):
@@ -1207,7 +1211,7 @@ class ExecutionMagics(Magics):
1207
1211
  if var_name in local_ns:
1208
1212
  conflict_globs[var_name] = var_val
1209
1213
  glob.update(local_ns)
1210
-
1214
+
1211
1215
  exec(code, glob, ns)
1212
1216
  timer.inner = ns["inner"]
1213
1217
 
@@ -1229,9 +1233,9 @@ class ExecutionMagics(Magics):
1229
1233
 
1230
1234
  # Restore global vars from conflict_globs
1231
1235
  if conflict_globs:
1232
- glob.update(conflict_globs)
1233
-
1234
- if not quiet :
1236
+ glob.update(conflict_globs)
1237
+
1238
+ if not quiet:
1235
1239
  # Check best timing is greater than zero to avoid a
1236
1240
  # ZeroDivisionError.
1237
1241
  # In cases where the slowest timing is lesser than a microsecond
@@ -1241,11 +1245,15 @@ class ExecutionMagics(Magics):
1241
1245
  print("The slowest run took %0.2f times longer than the "
1242
1246
  "fastest. This could mean that an intermediate result "
1243
1247
  "is being cached." % (worst / best))
1244
-
1248
+
1245
1249
  print( timeit_result )
1246
1250
 
1247
1251
  if tc > tc_min:
1248
1252
  print("Compiler time: %.2f s" % tc)
1253
+
1254
+ if save_result:
1255
+ self.shell.user_ns[opts.v] = timeit_result
1256
+
1249
1257
  if return_result:
1250
1258
  return timeit_result
1251
1259
 
IPython/core/release.py CHANGED
@@ -16,8 +16,8 @@
16
16
  # release. 'dev' as a _version_extra string means this is a development
17
17
  # version
18
18
  _version_major = 9
19
- _version_minor = 0
20
- _version_patch = 2
19
+ _version_minor = 1
20
+ _version_patch = 0
21
21
  _version_extra = ".dev"
22
22
  # _version_extra = "b2"
23
23
  _version_extra = "" # Uncomment this for full releases
IPython/core/tips.py CHANGED
@@ -48,7 +48,7 @@ _tips: Any = {
48
48
  (
49
49
  10,
50
50
  11,
51
- ): "IPython first line of code was written {} years ago by Fernando Pérez".format(
51
+ ): "IPython's first line of code was written {} years ago by Fernando Pérez".format(
52
52
  datetime.now().year - 2001
53
53
  ),
54
54
  (
@@ -60,11 +60,11 @@ _tips: Any = {
60
60
  (
61
61
  3,
62
62
  8,
63
- ): "Today is international Women's Day: https://www.internationalwomensday.com/",
63
+ ): "Today is International Women's Day: https://www.internationalwomensday.com/",
64
64
  (
65
65
  3,
66
66
  31,
67
- ): "Happy trans day of visibility! You are valid. You matter. https://en.wikipedia.org/wiki/International_Transgender_Day_of_Visibility",
67
+ ): "Happy International Transgender Day of Visibility! You are valid. You matter. https://en.wikipedia.org/wiki/International_Transgender_Day_of_Visibility",
68
68
  },
69
69
  "random": [
70
70
  "Use `F2` or %edit with no arguments to open an empty editor with a temporary file.",
@@ -73,22 +73,22 @@ _tips: Any = {
73
73
  "Use the IPython.lib.demo.Demo class to load any Python script as an interactive demo.",
74
74
  "Put a ';' at the end of a line to suppress the printing of output.",
75
75
  "You can use Ctrl-O to force a new line in terminal IPython",
76
- "Use `object?` to see the help on `object`, `object??` to view it's source",
76
+ "Use `object?` to see the help on `object`, `object??` to view its source",
77
77
  "`?` alone on a line will brings up IPython's help",
78
78
  "You can use `%hist` to view history, see the options with `%history?`",
79
79
  "You can change the editing mode of IPython to behave more like vi, or emacs.",
80
- "IPython 9.0+ have hooks to integrate AI/LLM completions.",
80
+ "IPython 9.0+ has hooks to integrate AI/LLM completions.",
81
81
  "Use `%timeit` or `%%timeit`, and the `-r`, `-n`, and `-o` options to easily profile your code.",
82
- "Use `ipython --help-all | less` to view all the IPython configurations options.",
83
- "Use `--theme`, or the `%colors` magic to change ipython themes and colors.",
84
- "The `%timeit` magic has an `-o` flag, which returns the results, making it easy to plot. See `%timeit?`.",
82
+ "Use `ipython --help-all | less` to view all the IPython configuration options.",
83
+ "Use `--theme`, or the `%colors` magic to change IPython's themes and colors.",
84
+ "The `%timeit` magic has a `-o` flag, which returns the results, making it easy to plot. See `%timeit?`.",
85
85
  ],
86
86
  }
87
87
 
88
88
  if os.name == "nt":
89
89
  _tips["random"].extend(
90
90
  [
91
- "We can't show you all tips on windows as sometime Unicode characters crash windows console, please help us debug it."
91
+ "We can't show you all tips on Windows as sometimes Unicode characters crash the Windows console, please help us debug it."
92
92
  ]
93
93
  )
94
94
  # unicode may crash windows console, so we filter out tips with non-ASCII characters.
@@ -100,10 +100,10 @@ if os.name == "nt":
100
100
  else:
101
101
  _tips["random"].extend(
102
102
  [
103
- "You can use latex or unicode completion, `\\alpha<tab>` will insert the α symbol.",
104
- "You can find how to type a latex symbol by back completing it `\\θ<tab>` will expand to `\\theta`.",
105
- "You can find how to type a unicode symbol by back completing it `\\Ⅷ<tab>` will expand to `\\ROMAN NUMERAL EIGHT`.",
106
- "IPython support combining unicode identifiers, F\\vec<tab> will become F⃗, usefull for physics equations. Play with \\dot \\ddot and others.",
103
+ "You can use LaTeX or Unicode completion, `\\alpha<tab>` will insert the α symbol.",
104
+ "You can find how to type a LaTeX symbol by back-completing it, eg `\\θ<tab>` will expand to `\\theta`.",
105
+ "You can find how to type a Unicode symbol by back-completing it, eg `\\Ⅷ<tab>` will expand to `\\ROMAN NUMERAL EIGHT`.",
106
+ "IPython supports combining unicode identifiers, eg F\\vec<tab> will become F⃗, useful for physics equations. Play with \\dot \\ddot and others.",
107
107
  ]
108
108
  )
109
109
 
IPython/terminal/embed.py CHANGED
@@ -395,12 +395,13 @@ def embed(*, header="", compile_flags=None, **kwargs):
395
395
  config.InteractiveShellEmbed = config.TerminalInteractiveShell
396
396
  kwargs["config"] = config
397
397
  using = kwargs.get("using", "sync")
398
+ colors = kwargs.pop("colors", "nocolor")
398
399
  if using:
399
400
  kwargs["config"].update(
400
401
  {
401
402
  "TerminalInteractiveShell": {
402
403
  "loop_runner": using,
403
- "colors": "nocolor",
404
+ "colors": colors,
404
405
  "autoawait": using != "sync",
405
406
  }
406
407
  }
@@ -355,7 +355,7 @@ class TerminalInteractiveShell(InteractiveShell):
355
355
  return
356
356
 
357
357
  def refresh_style(self):
358
- self._style = self._make_style_from_name_or_cls(self.highlighting_style)
358
+ self._style = self._make_style_from_name_or_cls("legacy")
359
359
 
360
360
  # TODO: deprecate this
361
361
  highlighting_style_overrides = Dict(
@@ -518,7 +518,6 @@ class TerminalInteractiveShell(InteractiveShell):
518
518
  name = self.llm_prefix_from_history
519
519
 
520
520
  if name == "no_prefix":
521
- print("set tofun1", self.llm_prefix_from_history)
522
521
 
523
522
  def no_prefix(history_manager):
524
523
  return ""
@@ -974,7 +973,7 @@ class TerminalInteractiveShell(InteractiveShell):
974
973
  self.alias_manager.soft_define_alias(cmd, cmd)
975
974
 
976
975
  def __init__(self, *args, **kwargs) -> None:
977
- super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
976
+ super().__init__(*args, **kwargs)
978
977
  self._set_autosuggestions(self.autosuggestions_provider)
979
978
  self.init_prompt_toolkit_cli()
980
979
  self.init_term_title()
@@ -9,7 +9,7 @@ import prompt_toolkit
9
9
  from prompt_toolkit.buffer import Buffer
10
10
  from prompt_toolkit.key_binding import KeyPressEvent
11
11
  from prompt_toolkit.key_binding.bindings import named_commands as nc
12
- from prompt_toolkit.auto_suggest import AutoSuggestFromHistory, Suggestion, AutoSuggest
12
+ from prompt_toolkit.auto_suggest import AutoSuggestFromHistory, Suggestion
13
13
  from prompt_toolkit.document import Document
14
14
  from prompt_toolkit.history import History
15
15
  from prompt_toolkit.shortcuts import PromptSession
@@ -103,9 +103,6 @@ class AppendAutoSuggestionInAnyLine(Processor):
103
103
  if len(suggestions) == 0:
104
104
  return noop("noop: no suggestions")
105
105
 
106
- suggestions_longer_than_buffer: bool = (
107
- len(suggestions) + ti.document.cursor_position_row > ti.document.line_count
108
- )
109
106
  if prompt_toolkit.VERSION < (3, 0, 49):
110
107
  if len(suggestions) > 1 and prompt_toolkit.VERSION < (3, 0, 49):
111
108
  if ti.lineno == ti.document.cursor_position_row:
@@ -132,7 +129,6 @@ class AppendAutoSuggestionInAnyLine(Processor):
132
129
  return Transformation(fragments=ti.fragments + [(self.style, suggestion)])
133
130
  if is_last_line:
134
131
  if delta < len(suggestions):
135
- extra = f"; {len(suggestions) - delta} line(s) hidden"
136
132
  suggestion = f"… rest of suggestion ({len(suggestions) - delta} lines) and code hidden"
137
133
  return Transformation([(self.style, suggestion)])
138
134
 
@@ -171,7 +167,7 @@ class NavigableAutoSuggestFromHistory(AutoSuggestFromHistory):
171
167
  _connected_apps: list[PromptSession]
172
168
 
173
169
  # handle to the currently running llm task that appends suggestions to the
174
- # current buffer; we keep a handle to it in order to cancell it when there is a cursor movement, or
170
+ # current buffer; we keep a handle to it in order to cancel it when there is a cursor movement, or
175
171
  # another request.
176
172
  _llm_task: asyncio.Task | None = None
177
173
 
@@ -185,6 +181,7 @@ class NavigableAutoSuggestFromHistory(AutoSuggestFromHistory):
185
181
  self.skip_lines = 0
186
182
  self._connected_apps = []
187
183
  self._llm_provider = None
184
+ self._request_number = 0
188
185
 
189
186
  def reset_history_position(self, _: Buffer) -> None:
190
187
  self.skip_lines = 0
@@ -306,7 +303,7 @@ class NavigableAutoSuggestFromHistory(AutoSuggestFromHistory):
306
303
 
307
304
  def _cancel_running_llm_task(self) -> None:
308
305
  """
309
- Try to cancell the currently running llm_task if exists, and set it to None.
306
+ Try to cancel the currently running llm_task if exists, and set it to None.
310
307
  """
311
308
  if self._llm_task is not None:
312
309
  if self._llm_task.done():
@@ -350,10 +347,10 @@ class NavigableAutoSuggestFromHistory(AutoSuggestFromHistory):
350
347
  try:
351
348
  await self._trigger_llm_core(buffer)
352
349
  except Exception as e:
353
- get_ipython().log.error("error")
350
+ get_ipython().log.error("error %s", e)
354
351
  raise
355
352
 
356
- # here we need a cancellable task so we can't just await the error catched
353
+ # here we need a cancellable task so we can't just await the error caught
357
354
  self._llm_task = asyncio.create_task(error_catcher(buffer))
358
355
  await self._llm_task
359
356
 
@@ -365,9 +362,8 @@ class NavigableAutoSuggestFromHistory(AutoSuggestFromHistory):
365
362
  provider to stream it's response back to us iteratively setting it as
366
363
  the suggestion on the current buffer.
367
364
 
368
- Unlike with JupyterAi, as we do not have multiple cell, the cell number
369
- is always set to `0`, note that we _could_ set it to a new number each
370
- time and ignore threply from past numbers.
365
+ Unlike with JupyterAi, as we do not have multiple cell, the cell id
366
+ is always set to `None`.
371
367
 
372
368
  We set the prefix to the current cell content, but could also inset the
373
369
  rest of the history or even just the non-fail history.
@@ -389,10 +385,12 @@ class NavigableAutoSuggestFromHistory(AutoSuggestFromHistory):
389
385
 
390
386
  hm = buffer.history.shell.history_manager
391
387
  prefix = self._llm_prefixer(hm)
392
- print(prefix)
388
+ get_ipython().log.debug("prefix: %s", prefix)
393
389
 
390
+ self._request_number += 1
391
+ request_number = self._request_number
394
392
  request = jai_models.InlineCompletionRequest(
395
- number=0,
393
+ number=request_number,
396
394
  prefix=prefix + buffer.document.text,
397
395
  suffix="",
398
396
  mime="text/x-python",
@@ -405,6 +403,9 @@ class NavigableAutoSuggestFromHistory(AutoSuggestFromHistory):
405
403
  async for reply_and_chunks in self._llm_provider.stream_inline_completions(
406
404
  request
407
405
  ):
406
+ if self._request_number != request_number:
407
+ # If a new suggestion was requested, skip processing this one.
408
+ return
408
409
  if isinstance(reply_and_chunks, jai_models.InlineCompletionReply):
409
410
  if len(reply_and_chunks.list.items) > 1:
410
411
  raise ValueError(
@@ -427,7 +428,7 @@ async def llm_autosuggestion(event: KeyPressEvent):
427
428
  This will first make sure that the current buffer have _MIN_LINES (7)
428
429
  available lines to insert the LLM completion
429
430
 
430
- Provisional as of 8.32, may change without warnigns
431
+ Provisional as of 8.32, may change without warnings
431
432
 
432
433
  """
433
434
  _MIN_LINES = 5
@@ -47,6 +47,7 @@ class Theme:
47
47
  self.base = base
48
48
  self.extra_style = extra_style
49
49
  self.symbols = {**_default_symbols, **symbols}
50
+ self._formatter = Terminal256Formatter(style=self.as_pygments_style())
50
51
 
51
52
  @cache
52
53
  def as_pygments_style(self):
@@ -61,9 +62,8 @@ class Theme:
61
62
  return MyStyle
62
63
 
63
64
  def format(self, stream: TokenStream) -> str:
64
- style = self.as_pygments_style()
65
65
 
66
- return pygments.format(stream, Terminal256Formatter(style=style))
66
+ return pygments.format(stream, self._formatter)
67
67
 
68
68
  def make_arrow(self, width: int):
69
69
  """generate the leading arrow in front of traceback or debugger"""
IPython/utils/_sysinfo.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # GENERATED BY setup.py
2
- commit = "9970f5e4b"
2
+ commit = "f9097f68a"
@@ -1,13 +1,13 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: ipython
3
- Version: 9.0.2
3
+ Version: 9.1.0
4
4
  Summary: IPython: Productive Interactive Computing
5
5
  Author: The IPython Development Team
6
6
  Author-email: ipython-dev@python.org
7
7
  License: BSD-3-Clause
8
8
  Project-URL: Homepage, https://ipython.org
9
9
  Project-URL: Documentation, https://ipython.readthedocs.io/
10
- Project-URL: Funding, https://numfocus.org/
10
+ Project-URL: Funding, https://jupyter.org/about#donate
11
11
  Project-URL: Source, https://github.com/ipython/ipython
12
12
  Project-URL: Tracker, https://github.com/ipython/ipython/issues
13
13
  Keywords: Interactive,Interpreter,Shell,Embedding
@@ -59,8 +59,11 @@ Requires-Dist: packaging; extra == "test"
59
59
  Provides-Extra: test-extra
60
60
  Requires-Dist: ipython[test]; extra == "test-extra"
61
61
  Requires-Dist: curio; extra == "test-extra"
62
+ Requires-Dist: jupyter_ai; extra == "test-extra"
62
63
  Requires-Dist: matplotlib!=3.2.0; extra == "test-extra"
63
64
  Requires-Dist: nbformat; extra == "test-extra"
65
+ Requires-Dist: nbclient; extra == "test-extra"
66
+ Requires-Dist: ipykernel; extra == "test-extra"
64
67
  Requires-Dist: numpy>=1.23; extra == "test-extra"
65
68
  Requires-Dist: pandas; extra == "test-extra"
66
69
  Requires-Dist: trio; extra == "test-extra"
@@ -71,6 +74,7 @@ Requires-Dist: ipython[doc,matplotlib,test,test_extra]; extra == "all"
71
74
  Dynamic: author
72
75
  Dynamic: author-email
73
76
  Dynamic: license
77
+ Dynamic: license-file
74
78
 
75
79
  IPython provides a rich toolkit to help you make the most out of using Python
76
80
  interactively. Its main components are:
@@ -10,15 +10,15 @@ IPython/core/async_helpers.py,sha256=4x_ZSrPImXi0oXzwImaLc3eXlkdLi-4RXh2HcX8YDQg
10
10
  IPython/core/autocall.py,sha256=zw7siKc1ocagCuXn4OuT0o7YbyZSuW3a7la204ANRk4,1983
11
11
  IPython/core/builtin_trap.py,sha256=4Bls1x1Xaf3oGbj6GFXE--G6qZlNq7AYFjp_vyu55p8,3006
12
12
  IPython/core/compilerop.py,sha256=tA8xHh10gp85brI2OYmvl7kW0TgDghdKbzmZE7nS4sw,6990
13
- IPython/core/completer.py,sha256=grT260S45DxAthhOeZZfp1YmZRhCKwvXstvxRnxMytQ,120548
13
+ IPython/core/completer.py,sha256=X9gKNDyuOsDgdr4dDnFNdhyAlcFrCnHR-DwPZwj9rNc,126652
14
14
  IPython/core/completerlib.py,sha256=C_1uFwR4eiqIsemMRbluMQV1WJ3qSfnGxO01PsGSpr8,12641
15
15
  IPython/core/crashhandler.py,sha256=8-kyI6aNkqbaB_lBlbNKAOFv34HDBCpLggMfiu4oIDg,8747
16
16
  IPython/core/debugger.py,sha256=I3LA4HQFEP5cy-kbbRvJqlLlSgVHSWBbp0cbPs3nU8M,41806
17
17
  IPython/core/display.py,sha256=wQgVFY_U1O-a-jJSLb00nJ9m2w9-NsBhEBGnQUcWUd0,41129
18
18
  IPython/core/display_functions.py,sha256=hlj1gXXrcIQU_ita03dHFesltOCViP1N3RcoLtLuyFI,12407
19
- IPython/core/display_trap.py,sha256=31jM26B3PhNSLJhpyRHuTWscObwVMOlH9PDC2v8HmsU,2098
20
- IPython/core/displayhook.py,sha256=HUERj6OeEiuoeuMQBZyYMk9MjAIu21vlxrkaQOX8gnA,12954
21
- IPython/core/displaypub.py,sha256=TxR1G-W3adCWGnCzSpun6PtuQ3NKTbEGS1lxKwhWAhU,5541
19
+ IPython/core/display_trap.py,sha256=r9AeMqllLicJvY8JfrGTQMkyxz37QT7X_RwwXxNk7R0,2185
20
+ IPython/core/displayhook.py,sha256=pArnwIsvICOivqoxLqg215F9O1V3NEEWnk8KktvYcvE,13258
21
+ IPython/core/displaypub.py,sha256=6i3-uceIUZ_ceqXiEr8RiPWebhoLiRObXk_cXvO84xo,5946
22
22
  IPython/core/doctb.py,sha256=WTEOyUTAAnpyB2NCHhCA4fF7TyDRlW6H9tyRsoVVPjA,15617
23
23
  IPython/core/error.py,sha256=lL5WP3E0sGNWkBTQL0u795wLQJCSrDCf328ft8TfCjk,1734
24
24
  IPython/core/events.py,sha256=U-Qm93khPgrLrB09zqH8Hvb6QldPVES-LIuSdGsxLXk,5243
@@ -26,11 +26,11 @@ IPython/core/extensions.py,sha256=KgohNiowl71W-V0WYXWKw7g-q85QN9c_FxtraJoEOvY,50
26
26
  IPython/core/formatters.py,sha256=9hyrvbkIxbO26VQvOsKVI3xbnLgJOAmJiQUo8U95V6k,36500
27
27
  IPython/core/getipython.py,sha256=RjTylt9N3c8AFZ-Y440A8My4tfFCgO-lVkyOL0xoOzQ,894
28
28
  IPython/core/guarded_eval.py,sha256=dQXW-e3wM6z9WGcszdJLhqiK0UCii303GOOXd3z3ze8,29400
29
- IPython/core/history.py,sha256=aTBJxCtZ_gPPJbzhAj6bOqII8AJClVWTH7xZX44m5jk,40602
30
- IPython/core/historyapp.py,sha256=xVVF2UmWH7UUYg6L4bmpMnSgC1C7QXwNEDbQ1Waedkc,5871
29
+ IPython/core/history.py,sha256=5hmGOe1H93tCtWj_d8HdFixDCr0kdEqahGJ-zUo03RQ,41183
30
+ IPython/core/historyapp.py,sha256=5H38INsWXRacscKz_5PQHYrEnHEayDtc1D1qcSyHRBU,5847
31
31
  IPython/core/hooks.py,sha256=xBWTZqycxZi97yj01IFc-SoJBzV5B73IoDHbAAlKUpQ,5193
32
32
  IPython/core/inputtransformer2.py,sha256=7sRleytrcAbp5PZMOrDw59MjUAGXg5BbaRbPkSW83-I,28909
33
- IPython/core/interactiveshell.py,sha256=uAGkI0JslwYzc2WEhl3R38gqLG2w9xQpAJjhLuCVZ0g,153787
33
+ IPython/core/interactiveshell.py,sha256=W6T0ImqgQShGLXjnx2-7t1cyJBVJz_WsZb3rlDw5BcU,158899
34
34
  IPython/core/latex_symbols.py,sha256=DzFecvqWVSsdN7vWAsp0mlYAHRDQKfZGAmvuDUh0M-s,30127
35
35
  IPython/core/logger.py,sha256=Iwe4xKMmxEdvSwHYPMfsTWkmdaqVCgvZT3R3I3qTmrU,8436
36
36
  IPython/core/macro.py,sha256=OhvXWNhLe393rI2wTpMgbUVHWSnmC_ycHiYqzqSHXZU,1726
@@ -44,21 +44,21 @@ IPython/core/prefilter.py,sha256=JHQ3feaD4bhoBDqZcEgmlDjQ2sfRXC1DNjgJhpaMU7E,257
44
44
  IPython/core/profileapp.py,sha256=bFMFIyehxeF9pDUtxw_6D3b0nxeqsupKTe7XhH7GMkc,10711
45
45
  IPython/core/profiledir.py,sha256=-vjOa1I_UajMZJblJRYXh16Y0RaAUn5a2swQBsw2qEU,8459
46
46
  IPython/core/pylabtools.py,sha256=LfNV9xCJ3flCfJXmv1NaCRYj9jZDtHAQ5oSEHWo3Gmg,17376
47
- IPython/core/release.py,sha256=Xh10_c3N-D5TcMiswCtqiR5brz6KpxliDhScbJLcRuI,1505
47
+ IPython/core/release.py,sha256=XcLV70aE1VVBrEWoihRzaJS3zSNXH3BAqhmKVKu4BY8,1505
48
48
  IPython/core/shellapp.py,sha256=oZIzj_sqIXrN3qyyhinZ1gLXvFviKYHkmS4H3wVEb74,19307
49
49
  IPython/core/splitinput.py,sha256=bAX1puQjvYB-otJyqiqeOhWj6dooWuQeNVx2YdaKQs8,5006
50
50
  IPython/core/tbtools.py,sha256=X4iB5zKAT2y4TK1R9l3d3kiW5htrzKn3qxalFFe2xzI,16880
51
- IPython/core/tips.py,sha256=EBvLHsSwa5EwXjIJDotgm_t5r_dWWvnkJy-e1WvphoU,6164
51
+ IPython/core/tips.py,sha256=oLWJtS_nnd2s1fQunXXvvHxItmbtargZWPCkr5mVGj8,6200
52
52
  IPython/core/ultratb.py,sha256=ItaUt56wPnptv6f5ecbcBR3FtHljTDoIRHKsU-ZWGqI,46265
53
53
  IPython/core/usage.py,sha256=agrZE5eZIvJnXoqI8VV9e-oWZx5LbLxUq9MdQpEyts4,13542
54
54
  IPython/core/magics/__init__.py,sha256=pkd-UfzjDGp5UHuFKjw192vZnigpTP9ftXzG3oLdiS8,1619
55
55
  IPython/core/magics/ast_mod.py,sha256=06OoRO7Z7Jzfc-cflf8Z3wyqF17fkYv6fJ_Nw4d7eQE,10295
56
56
  IPython/core/magics/auto.py,sha256=yEouIjsQ6LmfSEfNvkZbNmNDFl19KLRnaJciYdR7a1A,4816
57
- IPython/core/magics/basic.py,sha256=hvqMBRbn4rwvjDhjuZkZotMV__oSRpmKc08zQy81QhM,22356
57
+ IPython/core/magics/basic.py,sha256=uFkd-gTzlSVkNDSu8Rg4fbS_IK2raEhx1SYA6kWZ4hg,23968
58
58
  IPython/core/magics/code.py,sha256=h_dho9niPvtf_IpoOZf5GAD6CYbT0EQGsfLfutyX-7I,28144
59
59
  IPython/core/magics/config.py,sha256=QBL5uY7m-Q7C46mO3q1Yio9s73w1TnI9y__j5E-j44Y,4881
60
60
  IPython/core/magics/display.py,sha256=STRq66GlZwcvFyBxbkqslclpP_s9LnqD0ew9Z3S4-Jo,3130
61
- IPython/core/magics/execution.py,sha256=KHggud3yvtJ-w7PX7qXRF7Y9IsBqS8sZmzgzdmoP1YI,61879
61
+ IPython/core/magics/execution.py,sha256=eKILRIhGdzKPI2jauYMkmhXFoDh88Y-YHaRhetDccLI,62070
62
62
  IPython/core/magics/extension.py,sha256=Jj6OlkM71PS0j1HfEMDc-jU2Exwo9Ff_K0nD7e_W4N0,2477
63
63
  IPython/core/magics/history.py,sha256=Aw9gBzK4AJbe-gvRdMW7n-_zxxHuMyHvHJtRDuCwwug,12629
64
64
  IPython/core/magics/logging.py,sha256=VuDiF5QZrgzTT7Lr1NkkMCtUM1EHoGCw2pYlKsSQc4Q,6867
@@ -95,8 +95,8 @@ IPython/sphinxext/ipython_console_highlighting.py,sha256=VzlykN7guz3dQV9nFuZM_x2
95
95
  IPython/sphinxext/ipython_directive.py,sha256=hOQCdWx2N7WzBJVHMw7qVvAwLJxBZJxFCElqR4uXvqY,45154
96
96
  IPython/terminal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
97
97
  IPython/terminal/debugger.py,sha256=0LdBmCKVHKNGpmBKdb4bBgKlyuTVyfz2Dg2Y8wE4FTM,6937
98
- IPython/terminal/embed.py,sha256=9PnL6nL6mOklg77Zrn6bqw9TUswjH2d7VNRtcuAi0FI,16122
99
- IPython/terminal/interactiveshell.py,sha256=yd-33C6tvN0Oc-_ftLbhPMmq6HufyNUo7fygO753p5k,39931
98
+ IPython/terminal/embed.py,sha256=uR1Z7wp5z5SpYto7sa9A63sPDtX5h0XD048Y3gDE_V0,16164
99
+ IPython/terminal/interactiveshell.py,sha256=QdoTKJmFHEIVBG9COJkpzbU4HgILzCXfR8DmsFEJmic,39820
100
100
  IPython/terminal/ipapp.py,sha256=d2Rog4DRkVv0_fReqZOuorKMXAtEqsCskwPejtjj0Lg,12512
101
101
  IPython/terminal/magics.py,sha256=49ZVJzbAUkG_EFpebxIBEqm3tEClvqefoeM6QnxGrrk,7705
102
102
  IPython/terminal/prompts.py,sha256=5IoXb-pXA4MWu3gAfEuyIwZUbDg6mxxJuMkOqRBmYa0,4555
@@ -114,7 +114,7 @@ IPython/terminal/pt_inputhooks/tk.py,sha256=FjejvtwbvpeBZLoBCci1RDo_jWD5qElMy7PP
114
114
  IPython/terminal/pt_inputhooks/wx.py,sha256=9yI52lDSZ3O_5Gww_3IeenEk_3PepLIME3Onh4X3kW0,7126
115
115
  IPython/terminal/shortcuts/__init__.py,sha256=irSX9mwHzeLDQ95fXRGdZxduRknwATtESvm2NIov7KU,18563
116
116
  IPython/terminal/shortcuts/auto_match.py,sha256=9uT1fDb-c4Ew7TSIs_zET1jSxDlbfWGluxfW_pj39tk,3066
117
- IPython/terminal/shortcuts/auto_suggest.py,sha256=dJGZGymi8xEmCurPYsqYeWHMP5kfqcnCcezDdBlv9wk,23177
117
+ IPython/terminal/shortcuts/auto_suggest.py,sha256=9ecW0Su5xSuwl2wzbnflTLZJ1p97DjlwnvZ7h2U5-as,23163
118
118
  IPython/terminal/shortcuts/filters.py,sha256=MgRTQWq8YfIyWvMASuQ9BGKq5RQwiEY5trSyMnMtJAo,10998
119
119
  IPython/testing/__init__.py,sha256=9t97XO03Ez9GdZA5FWZYmfyHZt2c3AqQe2dj_0AiPJY,784
120
120
  IPython/testing/decorators.py,sha256=0MmtdZsh0EehAIV73V3hTCM9gr-elFr4QTRP7sJqPc8,4430
@@ -134,7 +134,7 @@ IPython/testing/plugin/test_example.txt,sha256=CGM8aZIYHlePDdAnR1yX3MfDGu0OceZpU
134
134
  IPython/testing/plugin/test_exampleip.txt,sha256=5gLcj8iCk-WCOGz0ObpQpuZMhGwS1jUMyH3mouGxQJI,814
135
135
  IPython/testing/plugin/test_ipdoctest.py,sha256=Lc3qQdZ3amXf9EKA7JlXf30b3BzP8RwdNS9-SMRe2P0,1907
136
136
  IPython/testing/plugin/test_refs.py,sha256=y-Y2Q8niRIbaanbwpIzvEwwaHkJfAq10HYfb4bAXHBc,715
137
- IPython/utils/PyColorize.py,sha256=VyNAE6pgw8sCrS2-1v4p30TZIHe6SFz_0YqLUdsOc4k,15553
137
+ IPython/utils/PyColorize.py,sha256=crC0QJ6WwmXD-5YfVtT2MJHGzUtizfZaubrs2ZAL7KU,15573
138
138
  IPython/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
139
139
  IPython/utils/_process_cli.py,sha256=tJWYMEgNYgeMx9v-n3YLbKW0tPbFtpczfDH28RC3n4A,2020
140
140
  IPython/utils/_process_common.py,sha256=hMFRGOJh-n-uBcSAOnr2qetQXAthMVpS8mwRcZuQqlo,7306
@@ -142,7 +142,7 @@ IPython/utils/_process_emscripten.py,sha256=lGLQb2IgmanNtb502KflfuKIhgOF119Ji3cw
142
142
  IPython/utils/_process_posix.py,sha256=aOEtguhS3vdWngBpws1XQURO8Ozqd5gRiCk9VLky6tA,7502
143
143
  IPython/utils/_process_win32.py,sha256=Pcf6ZiqMbqDT79edzegE_AX3D367UtE8bbhT41no54A,6775
144
144
  IPython/utils/_process_win32_controller.py,sha256=hi2eR7mLbl3TTMCVbgps85GppxdtYbhOYK_l13WvYaM,21343
145
- IPython/utils/_sysinfo.py,sha256=k_tFtBwenx5P8zcV-6FTx5UbGvbQ9A6h5D7WevWmHoI,45
145
+ IPython/utils/_sysinfo.py,sha256=X56pgylat0KRjRqiH-0qv-TF0np8n9Kytjg4vfzVfBI,45
146
146
  IPython/utils/capture.py,sha256=h5yL5Lxq8bgO1SFpoNDYjEi6mh1IW_2X9CE7vOsUxE4,5137
147
147
  IPython/utils/coloransi.py,sha256=CML-SkzLa7oaIK1qypb3uwcfPXDeKHxZQiMJ0IWvUY0,293
148
148
  IPython/utils/contexts.py,sha256=w5_uXc0WTU3KKV1kcCW9A0_Mz5mGRoeGWMq_P_eo-Dg,1610
@@ -174,11 +174,11 @@ IPython/utils/text.py,sha256=6s-y4KvDmnJxLs0urf5D-1auZGSnj2xmXgQ-9jVu0N8,18788
174
174
  IPython/utils/timing.py,sha256=nND-ZUBkHWfYevvbRG-YfOSIFczz_epzMqWK5PH6nqA,4275
175
175
  IPython/utils/tokenutil.py,sha256=x6KQ6ZCGOY7j5GQcr7byJRZSBFgyBcfkTiLtjxkl9f8,6552
176
176
  IPython/utils/wildcard.py,sha256=6EEc3OEYp-IuSoidL6nwpaHg--GxnzbAJTmFiz77CNE,4612
177
- ipython-9.0.2.data/data/share/man/man1/ipython.1,sha256=PVdQP2hHmHyUEwzLOPcgavnCe9jTDVrM1jKZt4cnF_Q,2058
178
- ipython-9.0.2.dist-info/COPYING.rst,sha256=NBr8vXKYh7cEb-e5j8T07f867Y048G7v2bMGcPBD3xc,1639
179
- ipython-9.0.2.dist-info/LICENSE,sha256=4OOQdI7UQKuJPKHxNaiKkgqvVAnbuQpbQnx1xeUSaPs,1720
180
- ipython-9.0.2.dist-info/METADATA,sha256=7S5uSfcEcaNZ9JJsCMTJ_lBitQ-QnvsIZjPLk6DZc6Q,4254
181
- ipython-9.0.2.dist-info/WHEEL,sha256=RnOlZk4WRTvz4xhLM2LyBNUiU6tTosLZam4r642KGVM,90
182
- ipython-9.0.2.dist-info/entry_points.txt,sha256=z5BEEohWgg0SHdgdeNABf4T3fu-lr9W6F_bWOQHLdVs,83
183
- ipython-9.0.2.dist-info/top_level.txt,sha256=PKjvHtNCBZ9EHTmd2mwJ1J_k3j0F6D1lTFzIcJFFPEU,8
184
- ipython-9.0.2.dist-info/RECORD,,
177
+ ipython-9.1.0.data/data/share/man/man1/ipython.1,sha256=PVdQP2hHmHyUEwzLOPcgavnCe9jTDVrM1jKZt4cnF_Q,2058
178
+ ipython-9.1.0.dist-info/licenses/COPYING.rst,sha256=NBr8vXKYh7cEb-e5j8T07f867Y048G7v2bMGcPBD3xc,1639
179
+ ipython-9.1.0.dist-info/licenses/LICENSE,sha256=4OOQdI7UQKuJPKHxNaiKkgqvVAnbuQpbQnx1xeUSaPs,1720
180
+ ipython-9.1.0.dist-info/METADATA,sha256=FYcWyhwJGVxHfAZZkEYIalF34kXVo3AIhLmxW6wvDr4,4431
181
+ ipython-9.1.0.dist-info/WHEEL,sha256=yXGKzRL_Pyu4U5B7OsZI5LuVpv54e1VlLBvthN9VZ6E,90
182
+ ipython-9.1.0.dist-info/entry_points.txt,sha256=z5BEEohWgg0SHdgdeNABf4T3fu-lr9W6F_bWOQHLdVs,83
183
+ ipython-9.1.0.dist-info/top_level.txt,sha256=PKjvHtNCBZ9EHTmd2mwJ1J_k3j0F6D1lTFzIcJFFPEU,8
184
+ ipython-9.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (9.0.2)
2
+ Generator: setuptools (9.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5