Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion IPython/core/completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

Only valid Python identifiers will complete. Combining characters (like arrow or
dots) are also available, unlike latex they need to be put after the their
counterpart that is to say, `F\\\\vec<tab>` is correct, not `\\\\vec<tab>F`.
counterpart that is to say, ``F\\\\vec<tab>`` is correct, not ``\\\\vec<tab>F``.

Some browsers are known to display combining characters incorrectly.

Expand Down
52 changes: 40 additions & 12 deletions IPython/core/interactiveshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,19 +199,29 @@ class ExecutionInfo(object):
store_history = False
silent = False
shell_futures = True
cell_id = None

def __init__(self, raw_cell, store_history, silent, shell_futures):
def __init__(self, raw_cell, store_history, silent, shell_futures, cell_id):
self.raw_cell = raw_cell
self.store_history = store_history
self.silent = silent
self.shell_futures = shell_futures
self.cell_id = cell_id

def __repr__(self):
name = self.__class__.__qualname__
raw_cell = ((self.raw_cell[:50] + '..')
if len(self.raw_cell) > 50 else self.raw_cell)
return '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s>' %\
(name, id(self), raw_cell, self.store_history, self.silent, self.shell_futures)
raw_cell = (
(self.raw_cell[:50] + "..") if len(self.raw_cell) > 50 else self.raw_cell
)
return '<%s object at %x, raw_cell="%s" store_history=%s silent=%s shell_futures=%s cell_id=%s>' % (
name,
id(self),
raw_cell,
self.store_history,
self.silent,
self.shell_futures,
self.cell_id,
)


class ExecutionResult(object):
Expand Down Expand Up @@ -2834,7 +2844,14 @@ def safe_run_module(self, mod_name, where):
self.showtraceback()
warn('Unknown failure executing module: <%s>' % mod_name)

def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
def run_cell(
self,
raw_cell,
store_history=False,
silent=False,
shell_futures=True,
cell_id=None,
):
"""Run a complete IPython cell.

Parameters
Expand All @@ -2861,14 +2878,22 @@ def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=Tr
result = None
try:
result = self._run_cell(
raw_cell, store_history, silent, shell_futures)
raw_cell, store_history, silent, shell_futures, cell_id
)
finally:
self.events.trigger('post_execute')
if not silent:
self.events.trigger('post_run_cell', result)
return result

def _run_cell(self, raw_cell:str, store_history:bool, silent:bool, shell_futures:bool) -> ExecutionResult:
def _run_cell(
self,
raw_cell: str,
store_history: bool,
silent: bool,
shell_futures: bool,
cell_id: str,
) -> ExecutionResult:
"""Internal method to run a complete IPython cell."""

# we need to avoid calling self.transform_cell multiple time on the same thing
Expand All @@ -2888,6 +2913,7 @@ def _run_cell(self, raw_cell:str, store_history:bool, silent:bool, shell_futures
shell_futures=shell_futures,
transformed_cell=transformed_cell,
preprocessing_exc_tuple=preprocessing_exc_tuple,
cell_id=cell_id,
)

# run_cell_async is async, but may not actually need an eventloop.
Expand All @@ -2908,7 +2934,9 @@ def _run_cell(self, raw_cell:str, store_history:bool, silent:bool, shell_futures
try:
return runner(coro)
except BaseException as e:
info = ExecutionInfo(raw_cell, store_history, silent, shell_futures)
info = ExecutionInfo(
raw_cell, store_history, silent, shell_futures, cell_id
)
result = ExecutionResult(info)
result.error_in_exec = e
self.showtraceback(running_compiled_code=True)
Expand Down Expand Up @@ -2964,7 +2992,8 @@ async def run_cell_async(
shell_futures=True,
*,
transformed_cell: Optional[str] = None,
preprocessing_exc_tuple: Optional[Any] = None
preprocessing_exc_tuple: Optional[Any] = None,
cell_id=None,
) -> ExecutionResult:
"""Run a complete IPython cell asynchronously.

Expand Down Expand Up @@ -2995,8 +3024,7 @@ async def run_cell_async(

.. versionadded:: 7.0
"""
info = ExecutionInfo(
raw_cell, store_history, silent, shell_futures)
info = ExecutionInfo(raw_cell, store_history, silent, shell_futures, cell_id)
result = ExecutionResult(info)

if (not raw_cell) or raw_cell.isspace():
Expand Down
4 changes: 2 additions & 2 deletions IPython/lib/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ class Audio(DisplayObject):

From a File:

>>> Audio('/path/to/sound.wav') # doctest: +SKIP
>>> Audio(filename='/path/to/sound.ogg') # doctest: +SKIP
>>> Audio('IPython/lib/tests/test.wav') # doctest: +SKIP
>>> Audio(filename='IPython/lib/tests/test.wav') # doctest: +SKIP

From Bytes:

Expand Down
2 changes: 1 addition & 1 deletion IPython/terminal/ipapp.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# encoding: utf-8
"""
The :class:`~IPython.core.application.Application` object for the command
The :class:`~traitlets.config.application.Application` object for the command
line :command:`ipython` program.
"""

Expand Down
32 changes: 23 additions & 9 deletions docs/source/config/callbacks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,43 @@ For example::
def __init__(self, ip):
self.shell = ip
self.last_x = None

def pre_execute(self):
self.last_x = self.shell.user_ns.get('x', None)

def pre_run_cell(self, info):
print('Cell code: "%s"' % info.raw_cell)

print('info.raw_cell =', info.raw_cell)
print('info.store_history =', info.store_history)
print('info.silent =', info.silent)
print('info.shell_futures =', info.shell_futures)
print('info.cell_id =', info.cell_id)
print(dir(info))

def post_execute(self):
if self.shell.user_ns.get('x', None) != self.last_x:
print("x changed!")

def post_run_cell(self, result):
print('Cell code: "%s"' % result.info.raw_cell)
if result.error_before_exec:
print('Error before execution: %s' % result.error_before_exec)

print('result.execution_count = ', result.execution_count)
print('result.error_before_exec = ', result.error_before_exec)
print('result.error_in_exec = ', result.error_in_exec)
print('result.info = ', result.info)
print('result.result = ', result.result)

def load_ipython_extension(ip):
vw = VarWatcher(ip)
ip.events.register('pre_execute', vw.pre_execute)
ip.events.register('pre_run_cell', vw.pre_run_cell)
ip.events.register('post_execute', vw.post_execute)
ip.events.register('post_run_cell', vw.post_run_cell)

.. versionadded:: 8.3

Since IPython 8.3 and ipykernel 6.12.1, the ``info`` objects in the callback
now have a the ``cell_id`` that will be set to the value sent by the
frontened, when those send it.



Events
======
Expand Down
8 changes: 8 additions & 0 deletions docs/source/whatsnew/version8.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
============


.. _version 8.3.0:

IPython 8.3.0
-------------

- :ghpull:`13600`, ``pre_run_*``-hooks will now have a ``cell_id`` attribute on
the info object when frontend provide it.

.. _version 8.2.0:

IPython 8.2.0
Expand Down