Skip to content

Commit 508b73c

Browse files
committed
strip ansi
1 parent a21e314 commit 508b73c

File tree

2 files changed

+57
-24
lines changed

2 files changed

+57
-24
lines changed

execnb/shell.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from IPython.core.interactiveshell import InteractiveShell, ExecutionInfo, ExecutionResult
1717
from IPython.core.displayhook import DisplayHook
1818
from IPython.utils.capture import capture_output
19+
from IPython.utils.text import strip_ansi
1920
from IPython.core.completer import IPCompleter,provisionalcompleter
2021
from IPython.core.hooks import CommandChainDispatcher
2122
from IPython.core.completerlib import module_completer
@@ -123,12 +124,12 @@ def run(self:CaptureShell,
123124
self.exc = res.exception
124125
return _out_nb(res, self.display_formatter)
125126

126-
# %% ../nbs/02_shell.ipynb 29
127+
# %% ../nbs/02_shell.ipynb 30
127128
def render_outputs(outputs):
128129
def render_output(out):
129130
otype = out['output_type']
130131
if otype == 'stream':
131-
txt = ''.join(out['text'])
132+
txt = strip_ansi(''.join(out['text']))
132133
return f"<pre>{txt}</pre>" if out['name']=='stdout' else f"<pre class='stderr'>{txt}</pre>"
133134
elif otype in ('display_data','execute_result'):
134135
data = out['data']
@@ -141,13 +142,11 @@ def render_output(out):
141142
if d := _g('image/png'): return f'<img src="data:image/png;base64,{d}"/>'
142143
if d := _g('text/latex'): return f'<div class="math">${d}$</div>'
143144
if d := _g('text/plain'): return f"<pre>{escape(d)}</pre>"
144-
elif otype == 'error':
145-
return f"<pre class='error'>{out['ename']}: {out['evalue']}\n{''.join(out['traceback'])}</pre>"
146145
return ''
147146

148147
return '\n'.join(map(render_output, outputs))
149148

150-
# %% ../nbs/02_shell.ipynb 40
149+
# %% ../nbs/02_shell.ipynb 41
151150
@patch
152151
def cell(self:CaptureShell, cell, stdout=True, stderr=True):
153152
"Run `cell`, skipping if not code, and store outputs back in cell"
@@ -159,32 +158,32 @@ def cell(self:CaptureShell, cell, stdout=True, stderr=True):
159158
for o in outs:
160159
if 'execution_count' in o: cell['execution_count'] = o['execution_count']
161160

162-
# %% ../nbs/02_shell.ipynb 43
161+
# %% ../nbs/02_shell.ipynb 44
163162
def find_output(outp, # Output from `run`
164163
ot='execute_result' # Output_type to find
165164
):
166165
"Find first output of type `ot` in `CaptureShell.run` output"
167166
return first(o for o in outp if o['output_type']==ot)
168167

169-
# %% ../nbs/02_shell.ipynb 46
168+
# %% ../nbs/02_shell.ipynb 47
170169
def out_exec(outp):
171170
"Get data from execution result in `outp`."
172171
out = find_output(outp)
173172
if out: return '\n'.join(first(out['data'].values()))
174173

175-
# %% ../nbs/02_shell.ipynb 48
174+
# %% ../nbs/02_shell.ipynb 49
176175
def out_stream(outp):
177176
"Get text from stream in `outp`."
178177
out = find_output(outp, 'stream')
179178
if out: return ('\n'.join(out['text'])).strip()
180179

181-
# %% ../nbs/02_shell.ipynb 50
180+
# %% ../nbs/02_shell.ipynb 51
182181
def out_error(outp):
183182
"Get traceback from error in `outp`."
184183
out = find_output(outp, 'error')
185184
if out: return '\n'.join(out['traceback'])
186185

187-
# %% ../nbs/02_shell.ipynb 52
186+
# %% ../nbs/02_shell.ipynb 53
188187
def _false(o): return False
189188

190189
@patch
@@ -204,7 +203,7 @@ def run_all(self:CaptureShell,
204203
postproc(cell)
205204
if self.exc and exc_stop: raise self.exc from None
206205

207-
# %% ../nbs/02_shell.ipynb 66
206+
# %% ../nbs/02_shell.ipynb 67
208207
@patch
209208
def execute(self:CaptureShell,
210209
src:str|Path, # Notebook path to read from
@@ -225,7 +224,7 @@ def execute(self:CaptureShell,
225224
inject_code=inject_code, inject_idx=inject_idx)
226225
if dest: write_nb(nb, dest)
227226

228-
# %% ../nbs/02_shell.ipynb 70
227+
# %% ../nbs/02_shell.ipynb 71
229228
@patch
230229
def prettytb(self:CaptureShell,
231230
fname:str|Path=None): # filename to print alongside the traceback
@@ -237,7 +236,7 @@ def prettytb(self:CaptureShell,
237236
fname_str = f' in {fname}' if fname else ''
238237
return f"{type(self.exc).__name__}{fname_str}:\n{_fence}\n{cell_str}\n"
239238

240-
# %% ../nbs/02_shell.ipynb 89
239+
# %% ../nbs/02_shell.ipynb 90
241240
@call_parse
242241
def exec_nb(
243242
src:str, # Notebook path to read from
@@ -251,7 +250,7 @@ def exec_nb(
251250
CaptureShell().execute(src, dest, exc_stop=exc_stop, inject_code=inject_code,
252251
inject_path=inject_path, inject_idx=inject_idx)
253252

254-
# %% ../nbs/02_shell.ipynb 92
253+
# %% ../nbs/02_shell.ipynb 93
255254
class SmartCompleter(IPCompleter):
256255
def __init__(self, shell, namespace=None, jedi=False):
257256
if namespace is None: namespace = shell.user_ns
@@ -271,7 +270,7 @@ def __call__(self, c):
271270
for o in self.completions(c, len(c))
272271
if o.type=='<unknown>']
273272

274-
# %% ../nbs/02_shell.ipynb 94
273+
# %% ../nbs/02_shell.ipynb 95
275274
@patch
276275
def complete(self:CaptureShell, c):
277276
if not hasattr(self, '_completer'): self._completer = SmartCompleter(self)

nbs/02_shell.ipynb

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"from IPython.core.interactiveshell import InteractiveShell, ExecutionInfo, ExecutionResult\n",
4040
"from IPython.core.displayhook import DisplayHook\n",
4141
"from IPython.utils.capture import capture_output\n",
42+
"from IPython.utils.text import strip_ansi\n",
4243
"from IPython.core.completer import IPCompleter,provisionalcompleter\n",
4344
"from IPython.core.hooks import CommandChainDispatcher\n",
4445
"from IPython.core.completerlib import module_completer\n",
@@ -706,8 +707,8 @@
706707
"text/plain": [
707708
"[{'name': 'stdout',\n",
708709
" 'output_type': 'stream',\n",
709-
" 'text': ['CPU times: user 1e+03 ns, sys: 1e+03 ns, total: 2 us\\n',\n",
710-
" 'Wall time: 3.1 us\\n']},\n",
710+
" 'text': ['CPU times: user 2 us, sys: 0 ns, total: 2 us\\n',\n",
711+
" 'Wall time: 3.81 us\\n']},\n",
711712
" {'data': {'text/plain': ['2']},\n",
712713
" 'metadata': {},\n",
713714
" 'output_type': 'execute_result'}]"
@@ -723,6 +724,38 @@
723724
"o"
724725
]
725726
},
727+
{
728+
"cell_type": "code",
729+
"execution_count": null,
730+
"metadata": {},
731+
"outputs": [
732+
{
733+
"data": {
734+
"text/plain": [
735+
"[{'name': 'stdout',\n",
736+
" 'output_type': 'stream',\n",
737+
" 'text': ['\\x1b[0;31m---------------------------------------------------------------------------\\x1b[0m\\n',\n",
738+
" '\\x1b[0;31mZeroDivisionError\\x1b[0m Traceback (most recent call last)\\n',\n",
739+
" 'File \\x1b[0;32m<ipython-input-1-9e1622b385b6>:1\\x1b[0m\\n',\n",
740+
" '\\x1b[0;32m----> 1\\x1b[0m \\x1b[38;5;241m1\\x1b[39m\\x1b[38;5;241m/\\x1b[39m\\x1b[38;5;241m0\\x1b[39m\\n',\n",
741+
" '\\n',\n",
742+
" '\\x1b[0;31mZeroDivisionError\\x1b[0m: division by zero\\n']},\n",
743+
" {'ename': 'ZeroDivisionError',\n",
744+
" 'evalue': 'division by zero',\n",
745+
" 'output_type': 'error',\n",
746+
" 'traceback': 'Traceback (most recent call last):\\n File \"/Users/jhoward/miniconda3/lib/python3.11/site-packages/IPython/core/interactiveshell.py\", line 3553, in run_code\\n exec(code_obj, self.user_global_ns, self.user_ns)\\n File \"<ipython-input-1-9e1622b385b6>\", line 1, in <module>\\n 1/0\\n ~^~\\nZeroDivisionError: division by zero\\n'}]"
747+
]
748+
},
749+
"execution_count": null,
750+
"metadata": {},
751+
"output_type": "execute_result"
752+
}
753+
],
754+
"source": [
755+
"o = s.run(\"1/0\")\n",
756+
"o"
757+
]
758+
},
726759
{
727760
"cell_type": "code",
728761
"execution_count": null,
@@ -734,7 +767,7 @@
734767
" def render_output(out):\n",
735768
" otype = out['output_type']\n",
736769
" if otype == 'stream':\n",
737-
" txt = ''.join(out['text'])\n",
770+
" txt = strip_ansi(''.join(out['text']))\n",
738771
" return f\"<pre>{txt}</pre>\" if out['name']=='stdout' else f\"<pre class='stderr'>{txt}</pre>\"\n",
739772
" elif otype in ('display_data','execute_result'):\n",
740773
" data = out['data']\n",
@@ -747,8 +780,6 @@
747780
" if d := _g('image/png'): return f'<img src=\"data:image/png;base64,{d}\"/>'\n",
748781
" if d := _g('text/latex'): return f'<div class=\"math\">${d}$</div>'\n",
749782
" if d := _g('text/plain'): return f\"<pre>{escape(d)}</pre>\"\n",
750-
" elif otype == 'error':\n",
751-
" return f\"<pre class='error'>{out['ename']}: {out['evalue']}\\n{''.join(out['traceback'])}</pre>\"\n",
752783
" return ''\n",
753784
" \n",
754785
" return '\\n'.join(map(render_output, outputs))"
@@ -762,10 +793,13 @@
762793
{
763794
"data": {
764795
"text/html": [
765-
"<pre>CPU times: user 1e+03 ns, sys: 1e+03 ns, total: 2 us\n",
766-
"Wall time: 3.1 us\n",
767-
"</pre>\n",
768-
"<pre>2</pre>"
796+
"<pre>---------------------------------------------------------------------------\n",
797+
"ZeroDivisionError Traceback (most recent call last)\n",
798+
"File <ipython-input-1-9e1622b385b6>:1\n",
799+
"----> 1 1/0\n",
800+
"\n",
801+
"ZeroDivisionError: division by zero\n",
802+
"</pre>\n"
769803
],
770804
"text/plain": [
771805
"<IPython.core.display.HTML object>"

0 commit comments

Comments
 (0)