diff --git a/execnb/shell.py b/execnb/shell.py index 021f227..4e9d6ca 100644 --- a/execnb/shell.py +++ b/execnb/shell.py @@ -32,6 +32,7 @@ from .nbio import * from .nbio import _dict2obj + # %% auto 0 __all__ = ['CaptureShell', 'format_exc', 'render_outputs', 'find_output', 'out_exec', 'out_stream', 'out_error', 'exec_nb', 'SmartCompleter'] @@ -160,12 +161,13 @@ async def run_async(self:CaptureShell, def _pre(s, xtra=''): return f"
{escape(s)}"
def _strip(s): return strip_ansi(escape(s))
-def render_outputs(outputs, ansi_renderer=_strip, include_imgs=True, pygments=False):
+def render_outputs(outputs, ansi_renderer=_strip, include_imgs=True, pygments=False, md_tfm=noop, html_tfm=noop):
try:
from mistletoe import markdown, HTMLRenderer
from mistletoe.contrib.pygments_renderer import PygmentsRenderer
except ImportError: return print('mistletoe not found -- please install it')
renderer = PygmentsRenderer if pygments else HTMLRenderer
+
def render_output(out):
otype = out['output_type']
if otype == 'stream':
@@ -176,9 +178,9 @@ def render_output(out):
elif otype in ('display_data','execute_result'):
data = out['data']
_g = lambda t: ''.join(data[t]) if t in data else None
- if d := _g('text/html'): return d
+ if d := _g('text/html'): return html_tfm(d)
if d := _g('application/javascript'): return f''
- if d := _g('text/markdown'): return markdown(d, renderer=renderer)
+ if d := _g('text/markdown'): return md_tfm(markdown(d, renderer=renderer))
if d := _g('text/latex'): return f'| \n", + " | A | \n", + "B | \n", + "
|---|---|---|
| 0 | \n", + "1 | \n", + "3 | \n", + "
| 1 | \n", + "2 | \n", + "4 | \n", + "
{escape(s)}\"\n",
"def _strip(s): return strip_ansi(escape(s))\n",
"\n",
- "def render_outputs(outputs, ansi_renderer=_strip, include_imgs=True, pygments=False):\n",
+ "def render_outputs(outputs, ansi_renderer=_strip, include_imgs=True, pygments=False, md_tfm=noop, html_tfm=noop):\n",
" try:\n",
" from mistletoe import markdown, HTMLRenderer\n",
" from mistletoe.contrib.pygments_renderer import PygmentsRenderer\n",
" except ImportError: return print('mistletoe not found -- please install it')\n",
" renderer = PygmentsRenderer if pygments else HTMLRenderer\n",
+ " \n",
" def render_output(out):\n",
" otype = out['output_type']\n",
" if otype == 'stream':\n",
@@ -1035,9 +1070,9 @@
" elif otype in ('display_data','execute_result'):\n",
" data = out['data']\n",
" _g = lambda t: ''.join(data[t]) if t in data else None\n",
- " if d := _g('text/html'): return d\n",
+ " if d := _g('text/html'): return html_tfm(d)\n",
" if d := _g('application/javascript'): return f''\n",
- " if d := _g('text/markdown'): return markdown(d, renderer=renderer)\n",
+ " if d := _g('text/markdown'): return md_tfm(markdown(d, renderer=renderer))\n",
" if d := _g('text/latex'): return f'---------------------------------------------------------------------------\n",
+ "---------------------------------------------------------------------------\n",
"TimeoutError Traceback (most recent call last)\n",
"File <ipython-input-1-a5c3817716b6>:1\n",
"----> 1 import time; time.sleep(1.1)\n",
"\n",
"Cell In[6], line 7, in run_cell.<locals>.handler(*args)\n",
- "----> 7 def handler(*args): raise TimeoutError()\n",
+ " 5 if not timeout: timeout = self.timeout\n",
+ " 6 if timeout:\n",
+ "----> 7 def handler(*args): raise TimeoutError()\n",
+ " 8 signal.signal(signal.SIGALRM, handler)\n",
+ " 9 signal.alarm(timeout)\n",
"\n",
"TimeoutError: \n",
"
\n"
@@ -1097,13 +1136,17 @@
{
"data": {
"text/html": [
- "---------------------------------------------------------------------------\n",
+ "---------------------------------------------------------------------------\n",
"TimeoutError Traceback (most recent call last)\n",
- "File <ipython-input-1-a5c3817716b6>:1\n",
- "----> 1 import time; time.sleep(1.1)\n",
+ "File <ipython-input-1-a5c3817716b6>:1\n",
+ "----> 1 import time; time.sleep(1.1)\n",
"\n",
- "Cell In[6], line 7, in run_cell.<locals>.handler(*args)\n",
- "----> 7 def handler(*args): raise TimeoutError()\n",
+ "Cell In[6], line 7, in run_cell.<locals>.handler(*args)\n",
+ " 5 if not timeout: timeout = self.timeout\n",
+ " 6 if timeout:\n",
+ "----> 7 def handler(*args): raise TimeoutError()\n",
+ " 8 signal.signal(signal.SIGALRM, handler)\n",
+ " 9 signal.alarm(timeout)\n",
"\n",
"TimeoutError: \n",
"
\n"
@@ -1136,7 +1179,7 @@
{
"data": {
"text/html": [
- "
"
+ "
"
],
"text/plain": [
""
@@ -1172,17 +1215,17 @@
"text/plain": [
"[{'name': 'stdout',\n",
" 'output_type': 'stream',\n",
- " 'text': ['\\x1b[0;31m---------------------------------------------------------------------------\\x1b[0m\\n',\n",
- " '\\x1b[0;31mException\\x1b[0m Traceback (most recent call last)\\n',\n",
- " 'File \\x1b[0;32m:1\\x1b[0m\\n',\n",
- " '\\x1b[0;32m----> 1\\x1b[0m \\x1b[38;5;28;01mraise\\x1b[39;00m \\x1b[38;5;167;01mException\\x1b[39;00m(\\x1b[38;5;124m\"\\x1b[39m\\x1b[38;5;124mOops\\x1b[39m\\x1b[38;5;124m\"\\x1b[39m)\\n',\n",
+ " 'text': ['\\x1b[31m---------------------------------------------------------------------------\\x1b[39m\\n',\n",
+ " '\\x1b[31mException\\x1b[39m Traceback (most recent call last)\\n',\n",
+ " '\\x1b[36mFile \\x1b[39m\\x1b[32m:1\\x1b[39m\\n',\n",
+ " '\\x1b[32m----> \\x1b[39m\\x1b[32m1\\x1b[39m \\x1b[38;5;28;01mraise\\x1b[39;00m \\x1b[38;5;167;01mException\\x1b[39;00m(\\x1b[33m\"\\x1b[39m\\x1b[33mOops\\x1b[39m\\x1b[33m\"\\x1b[39m)\\n',\n",
" '\\n',\n",
- " '\\x1b[0;31mException\\x1b[0m: Oops\\n']},\n",
+ " '\\x1b[31mException\\x1b[39m: Oops\\n']},\n",
" {'ename': 'Exception',\n",
" 'evalue': 'Oops',\n",
" 'output_type': 'error',\n",
" 'traceback': ['Traceback (most recent call last):\\n',\n",
- " ' File \"/Users/jhoward/miniconda3/lib/python3.11/site-packages/IPython/core/interactiveshell.py\", line 3577, in run_code\\n exec(code_obj, self.user_global_ns, self.user_ns)\\n',\n",
+ " ' File \"/Users/iflath/.venv/lib/python3.12/site-packages/IPython/core/interactiveshell.py\", line 3546, in run_code\\n exec(code_obj, self.user_global_ns, self.user_ns)\\n',\n",
" ' File \"\", line 1, in \\n raise Exception(\"Oops\")\\n',\n",
" 'Exception: Oops\\n']}]"
]
@@ -1552,17 +1595,17 @@
"text/plain": [
"[{'name': 'stdout',\n",
" 'output_type': 'stream',\n",
- " 'text': ['\\x1b[0;31m---------------------------------------------------------------------------\\x1b[0m\\n',\n",
- " '\\x1b[0;31mException\\x1b[0m Traceback (most recent call last)\\n',\n",
- " 'File \\x1b[0;32m:1\\x1b[0m\\n',\n",
- " '\\x1b[0;32m----> 1\\x1b[0m \\x1b[38;5;28;01mraise\\x1b[39;00m \\x1b[38;5;167;01mException\\x1b[39;00m(\\x1b[38;5;124m\"\\x1b[39m\\x1b[38;5;124mOopsie!\\x1b[39m\\x1b[38;5;124m\"\\x1b[39m)\\n',\n",
+ " 'text': ['\\x1b[31m---------------------------------------------------------------------------\\x1b[39m\\n',\n",
+ " '\\x1b[31mException\\x1b[39m Traceback (most recent call last)\\n',\n",
+ " '\\x1b[36mFile \\x1b[39m\\x1b[32m:1\\x1b[39m\\n',\n",
+ " '\\x1b[32m----> \\x1b[39m\\x1b[32m1\\x1b[39m \\x1b[38;5;28;01mraise\\x1b[39;00m \\x1b[38;5;167;01mException\\x1b[39;00m(\\x1b[33m\"\\x1b[39m\\x1b[33mOopsie!\\x1b[39m\\x1b[33m\"\\x1b[39m)\\n',\n",
" '\\n',\n",
- " '\\x1b[0;31mException\\x1b[0m: Oopsie!\\n']},\n",
+ " '\\x1b[31mException\\x1b[39m: Oopsie!\\n']},\n",
" {'ename': 'Exception',\n",
" 'evalue': 'Oopsie!',\n",
" 'output_type': 'error',\n",
" 'traceback': ['Traceback (most recent call last):\\n',\n",
- " ' File \"/Users/jhoward/miniconda3/lib/python3.11/site-packages/IPython/core/interactiveshell.py\", line 3577, in run_code\\n exec(code_obj, self.user_global_ns, self.user_ns)\\n',\n",
+ " ' File \"/Users/iflath/.venv/lib/python3.12/site-packages/IPython/core/interactiveshell.py\", line 3546, in run_code\\n exec(code_obj, self.user_global_ns, self.user_ns)\\n',\n",
" ' File \"\", line 1, in \\n raise Exception(\"Oopsie!\")\\n',\n",
" 'Exception: Oopsie!\\n']}]"
]
@@ -1756,7 +1799,7 @@
" fname = fname if fname else self._fname\n",
" _fence = '='*75\n",
" cell_intro_str = f\"While Executing Cell #{self._cell_idx}:\" if self._cell_idx else \"While Executing:\"\n",
- " cell_str = f\"\\n{cell_intro_str}\\n{format_exc(self.exc)}\"\n",
+ " cell_str = f\"\\n{cell_intro_str}\\n{''.join(format_exc(self.exc))}\"\n",
" fname_str = f' in {fname}' if fname else ''\n",
" return f\"{type(self.exc).__name__}{fname_str}:\\n{_fence}\\n{cell_str}\\n\""
]
@@ -1781,7 +1824,23 @@
"===========================================================================\n",
"\n",
"While Executing Cell #2:\n",
- "['Traceback (most recent call last):\\n', ' File \"/var/folders/ss/34z569j921v58v8n1n_8z7h40000gn/T/ipykernel_37071/1421292703.py\", line 3, in \\n s.execute(\\'../tests/error.ipynb\\', exc_stop=True)\\n', ' File \"/var/folders/ss/34z569j921v58v8n1n_8z7h40000gn/T/ipykernel_37071/3609882568.py\", line 18, in execute\\n self.run_all(nb, exc_stop=exc_stop, preproc=preproc, postproc=postproc,\\n', ' File \"/var/folders/ss/34z569j921v58v8n1n_8z7h40000gn/T/ipykernel_37071/3068237356.py\", line 19, in run_all\\n if self.exc and exc_stop: raise self.exc from None\\n ^^^^^^^^^^^^^^^^^^^^^^^^\\n', ' File \"/Users/jhoward/miniconda3/lib/python3.11/site-packages/IPython/core/interactiveshell.py\", line 3577, in run_code\\n exec(code_obj, self.user_global_ns, self.user_ns)\\n', ' File \"\", line 3, in \\n foo()\\n', ' File \"/Users/jhoward/subs_aai/execnb/tests/err.py\", line 2, in foo\\n assert 13 == 98\\n ^^^^^^^^\\n', 'AssertionError\\n']\n",
+ "Traceback (most recent call last):\n",
+ " File \"/var/folders/_8/cpj54rdn0w1fjskv7g8bn2fr0000gn/T/ipykernel_8573/1421292703.py\", line 3, in \n",
+ " s.execute('../tests/error.ipynb', exc_stop=True)\n",
+ " File \"/var/folders/_8/cpj54rdn0w1fjskv7g8bn2fr0000gn/T/ipykernel_8573/3609882568.py\", line 18, in execute\n",
+ " self.run_all(nb, exc_stop=exc_stop, preproc=preproc, postproc=postproc,\n",
+ " File \"/var/folders/_8/cpj54rdn0w1fjskv7g8bn2fr0000gn/T/ipykernel_8573/3068237356.py\", line 19, in run_all\n",
+ " if self.exc and exc_stop: raise self.exc from None\n",
+ " ^^^^^^^^^^^^^^^^^^^^^^^^\n",
+ " File \"/Users/iflath/.venv/lib/python3.12/site-packages/IPython/core/interactiveshell.py\", line 3546, in run_code\n",
+ " exec(code_obj, self.user_global_ns, self.user_ns)\n",
+ " File \"\", line 3, in \n",
+ " foo()\n",
+ " File \"/Users/iflath/git/fastai/execnb/tests/err.py\", line 2, in foo\n",
+ " assert 13 == 98\n",
+ " ^^^^^^^^\n",
+ "AssertionError\n",
+ "\n",
"\n"
]
}
@@ -2188,13 +2247,6 @@
"#|hide\n",
"import nbdev; nbdev.nbdev_export()"
]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": []
}
],
"metadata": {