Skip to content

Commit 604b9f8

Browse files
committed
Add --verbose flag to exec_nb for real-time output
- Added verbose parameter throughout the execution chain - Modified CaptureShell._run to conditionally capture stdout/stderr - When --verbose is used, output streams to terminal in real-time - Updated documentation in README.md and help text
1 parent 5337ae0 commit 604b9f8

File tree

5 files changed

+85
-75
lines changed

5 files changed

+85
-75
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ You can also execute notebooks from the command line with
6464

6565
usage: exec_nb [-h] [--dest DEST] [--exc_stop] [--inject_code INJECT_CODE]
6666
[--inject_path INJECT_PATH] [--inject_idx INJECT_IDX]
67+
[--verbose]
6768
src
6869

6970
Execute notebook from `src` and save with outputs to `dest`
@@ -78,3 +79,4 @@ You can also execute notebooks from the command line with
7879
--inject_code INJECT_CODE Code to inject into a cell
7980
--inject_path INJECT_PATH Path to file containing code to inject into a cell
8081
--inject_idx INJECT_IDX Cell to replace with `inject_code` (default: 0)
82+
--verbose Show stdout/stderr during execution (default: False)

execnb/shell.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,12 @@ def __init__(self, path:str|Path=None, mpl_format='retina', history=False, timeo
6767
self._run(f"set_matplotlib_formats('{mpl_format}')")
6868

6969
def _run(self, raw_cell, store_history=False, silent=False, shell_futures=True, cell_id=None,
70-
stdout=True, stderr=True, display=True):
70+
stdout=True, stderr=True, display=True, verbose=False):
7171
# TODO what if there's a comment?
7272
semic = raw_cell.rstrip().endswith(';')
73-
with capture_output(display=display, stdout=stdout, stderr=stderr) as c:
73+
capture_stdout = stdout and not verbose
74+
capture_stderr = stderr and not verbose
75+
with capture_output(display=display, stdout=capture_stdout, stderr=capture_stderr) as c:
7476
result = super().run_cell(raw_cell, store_history, silent, shell_futures=shell_futures, cell_id=cell_id)
7577
return AttrDict(result=result, stdout='' if semic else c.stdout, stderr=c.stderr,
7678
display_objects=c.outputs, exception=result.error_in_exec, quiet=semic)
@@ -86,14 +88,14 @@ def enable_gui(self, gui=None): pass
8688
# %% ../nbs/02_shell.ipynb
8789
@patch
8890
def run_cell(self:CaptureShell, raw_cell, store_history=False, silent=False, shell_futures=True, cell_id=None,
89-
stdout=True, stderr=True, display=True, timeout=None):
91+
stdout=True, stderr=True, display=True, timeout=None, verbose=False):
9092
if not timeout: timeout = self.timeout
9193
if timeout:
9294
def handler(*args): raise TimeoutError()
9395
signal.signal(signal.SIGALRM, handler)
9496
signal.alarm(timeout)
9597
try: return self._run(raw_cell, store_history, silent, shell_futures, cell_id=cell_id,
96-
stdout=stdout, stderr=stderr, display=display)
98+
stdout=stdout, stderr=stderr, display=display, verbose=verbose)
9799
finally:
98100
if timeout: signal.alarm(0)
99101

@@ -144,9 +146,10 @@ def run(self:CaptureShell,
144146
code:str, # Python/IPython code to run
145147
stdout=True, # Capture stdout and save as output?
146148
stderr=True, # Capture stderr and save as output?
147-
timeout:Optional[int]=None): # Shell command will time out after {timeout} seconds
149+
timeout:Optional[int]=None, # Shell command will time out after {timeout} seconds
150+
verbose:bool=False): # Show stdout/stderr during execution
148151
"Run `code`, returning a list of all outputs in Jupyter notebook format"
149-
res = self.run_cell(code, stdout=stdout, stderr=stderr, timeout=timeout)
152+
res = self.run_cell(code, stdout=stdout, stderr=stderr, timeout=timeout, verbose=verbose)
150153
self.result = res.result.result
151154
self.exc = res.exception
152155
return _out_nb(res, self.display_formatter)
@@ -157,8 +160,9 @@ async def run_async(self:CaptureShell,
157160
code: str, # Python/IPython code to run
158161
stdout=True, # Capture stdout and save as output?
159162
stderr=True, # Capture stderr and save as output?
160-
timeout:Optional[int]=None): # Shell command will time out after {timeout} seconds
161-
return self.run(code, stdout=stdout, stderr=stderr, timeout=timeout)
163+
timeout:Optional[int]=None, # Shell command will time out after {timeout} seconds
164+
verbose:bool=False): # Show stdout/stderr during execution
165+
return self.run(code, stdout=stdout, stderr=stderr, timeout=timeout, verbose=verbose)
162166

163167
# %% ../nbs/02_shell.ipynb
164168
def _pre(s, xtra=''): return f"<pre {xtra}><code>{escape(s)}</code></pre>"
@@ -197,11 +201,11 @@ def render_output(out):
197201

198202
# %% ../nbs/02_shell.ipynb
199203
@patch
200-
def cell(self:CaptureShell, cell, stdout=True, stderr=True):
204+
def cell(self:CaptureShell, cell, stdout=True, stderr=True, verbose=False):
201205
"Run `cell`, skipping if not code, and store outputs back in cell"
202206
if cell.cell_type!='code': return
203207
self._cell_idx = cell.idx_ + 1
204-
outs = self.run(cell.source)
208+
outs = self.run(cell.source, verbose=verbose)
205209
if outs: cell.outputs = _dict2obj(outs)
206210

207211
# %% ../nbs/02_shell.ipynb
@@ -239,13 +243,14 @@ def run_all(self:CaptureShell,
239243
preproc:callable=_false, # Called before each cell is executed
240244
postproc:callable=_false, # Called after each cell is executed
241245
inject_code:str|None=None, # Code to inject into a cell
242-
inject_idx:int=0 # Cell to replace with `inject_code`
246+
inject_idx:int=0, # Cell to replace with `inject_code`
247+
verbose:bool=False # Show stdout/stderr during execution
243248
):
244249
"Run all cells in `nb`, stopping at first exception if `exc_stop`"
245250
if inject_code is not None: nb.cells[inject_idx].source = inject_code
246251
for cell in nb.cells:
247252
if not preproc(cell):
248-
self.cell(cell)
253+
self.cell(cell, verbose=verbose)
249254
postproc(cell)
250255
if self.exc and exc_stop: raise self.exc from None
251256

@@ -259,15 +264,16 @@ def execute(self:CaptureShell,
259264
postproc:callable=_false, # Called after each cell is executed
260265
inject_code:str|None=None, # Code to inject into a cell
261266
inject_path:str|Path|None=None, # Path to file containing code to inject into a cell
262-
inject_idx:int=0 # Cell to replace with `inject_code`
267+
inject_idx:int=0, # Cell to replace with `inject_code`
268+
verbose:bool=False # Show stdout/stderr during execution
263269
):
264270
"Execute notebook from `src` and save with outputs to `dest"
265271
nb = read_nb(src)
266272
self._fname = src
267273
self.set_path(Path(src).parent.resolve())
268274
if inject_path is not None: inject_code = Path(inject_path).read_text()
269275
self.run_all(nb, exc_stop=exc_stop, preproc=preproc, postproc=postproc,
270-
inject_code=inject_code, inject_idx=inject_idx)
276+
inject_code=inject_code, inject_idx=inject_idx, verbose=verbose)
271277
if dest: write_nb(nb, dest)
272278

273279
# %% ../nbs/02_shell.ipynb
@@ -290,11 +296,12 @@ def exec_nb(
290296
exc_stop:bool=False, # Stop on exceptions?
291297
inject_code:str=None, # Code to inject into a cell
292298
inject_path:str=None, # Path to file containing code to inject into a cell
293-
inject_idx:int=0 # Cell to replace with `inject_code`
299+
inject_idx:int=0, # Cell to replace with `inject_code`
300+
verbose:bool=False # Show stdout/stderr during execution
294301
):
295302
"Execute notebook from `src` and save with outputs to `dest`"
296303
CaptureShell().execute(src, dest, exc_stop=exc_stop, inject_code=inject_code,
297-
inject_path=inject_path, inject_idx=inject_idx)
304+
inject_path=inject_path, inject_idx=inject_idx, verbose=verbose)
298305

299306
# %% ../nbs/02_shell.ipynb
300307
class SmartCompleter(IPCompleter):

nbs/01_nbio.ipynb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@
414414
" 'execution_count': 0,\n",
415415
" 'idx_': 0,\n",
416416
" 'metadata': {},\n",
417+
" 'outputs': [],\n",
417418
" 'source': 'print(1)'}\n",
418419
"```"
419420
],
@@ -423,6 +424,7 @@
423424
" 'directives_': {},\n",
424425
" 'execution_count': 0,\n",
425426
" 'metadata': {},\n",
427+
" 'outputs': [],\n",
426428
" 'idx_': 0}"
427429
]
428430
},
@@ -570,7 +572,7 @@
570572
"name": "stdout",
571573
"output_type": "stream",
572574
"text": [
573-
"[{'cell_type': 'code', 'metadata': {}, 'source': 'print(1)', 'idx_': 0}]\n"
575+
"[{'cell_type': 'code', 'execution_count': 0, 'metadata': {}, 'outputs': [], 'source': 'print(1)', 'idx_': 0}]\n"
574576
]
575577
}
576578
],

nbs/02_shell.ipynb

Lines changed: 37 additions & 40 deletions
Large diffs are not rendered by default.

nbs/index.ipynb

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
"[{'data': {'text/plain': ['2']},\n",
7575
" 'metadata': {},\n",
7676
" 'output_type': 'execute_result',\n",
77-
" 'execution_count': 1}]"
77+
" 'execution_count': None}]"
7878
]
7979
},
8080
"execution_count": null,
@@ -103,7 +103,7 @@
103103
"name": "stdout",
104104
"output_type": "stream",
105105
"text": [
106-
"[{'name': 'stdout', 'output_type': 'stream', 'text': ['1\\n']}, {'data': {'text/plain': ['2']}, 'execution_count': 3, 'metadata': {}, 'output_type': 'execute_result'}]\n"
106+
"[{'name': 'stdout', 'output_type': 'stream', 'text': ['1\\n']}, {'data': {'text/plain': ['2']}, 'execution_count': None, 'metadata': {}, 'output_type': 'execute_result'}]\n"
107107
]
108108
}
109109
],
@@ -130,22 +130,24 @@
130130
"name": "stdout",
131131
"output_type": "stream",
132132
"text": [
133-
"usage: exec_nb [-h] [--dest DEST] [--exc_stop] [--inject_code INJECT_CODE]\r\n",
134-
" [--inject_path INJECT_PATH] [--inject_idx INJECT_IDX]\r\n",
135-
" src\r\n",
136-
"\r\n",
137-
"Execute notebook from `src` and save with outputs to `dest`\r\n",
138-
"\r\n",
139-
"positional arguments:\r\n",
140-
" src Notebook path to read from\r\n",
141-
"\r\n",
142-
"optional arguments:\r\n",
143-
" -h, --help show this help message and exit\r\n",
144-
" --dest DEST Notebook path to write to (default: )\r\n",
145-
" --exc_stop Stop on exceptions? (default: False)\r\n",
146-
" --inject_code INJECT_CODE Code to inject into a cell\r\n",
147-
" --inject_path INJECT_PATH Path to file containing code to inject into a cell\r\n",
148-
" --inject_idx INJECT_IDX Cell to replace with `inject_code` (default: 0)\r\n"
133+
"usage: exec_nb [-h] [--dest DEST] [--exc_stop] [--inject_code INJECT_CODE]\n",
134+
" [--inject_path INJECT_PATH] [--inject_idx INJECT_IDX] [--verbose]\n",
135+
" src\n",
136+
"\n",
137+
"Execute notebook from `src` and save with outputs to `dest`\n",
138+
"\n",
139+
"positional arguments:\n",
140+
" src Notebook path to read from\n",
141+
"\n",
142+
"options:\n",
143+
" -h, --help show this help message and exit\n",
144+
" --dest DEST Notebook path to write to (default: )\n",
145+
" --exc_stop Stop on exceptions? (default: False)\n",
146+
" --inject_code INJECT_CODE Code to inject into a cell\n",
147+
" --inject_path INJECT_PATH Path to file containing code to inject into a cell\n",
148+
" --inject_idx INJECT_IDX Cell to replace with `inject_code` (default: 0)\n",
149+
" --verbose Show stdout/stderr during execution (default:\n",
150+
" False)\n"
149151
]
150152
}
151153
],

0 commit comments

Comments
 (0)