execnb 0.1.6__py3-none-any.whl → 0.1.7__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.
execnb/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.6"
1
+ __version__ = "0.1.7"
execnb/_modidx.py CHANGED
@@ -5,8 +5,7 @@ d = { 'settings': { 'branch': 'master',
5
5
  'doc_host': 'https://fastai.github.io',
6
6
  'git_url': 'https://github.com/fastai/execnb/',
7
7
  'lib_path': 'execnb'},
8
- 'syms': { 'execnb.fastshell': {},
9
- 'execnb.nbio': { 'execnb.nbio.NbCell': ('nbio.html#nbcell', 'execnb/nbio.py'),
8
+ 'syms': { 'execnb.nbio': { 'execnb.nbio.NbCell': ('nbio.html#nbcell', 'execnb/nbio.py'),
10
9
  'execnb.nbio.NbCell.__eq__': ('nbio.html#nbcell.__eq__', 'execnb/nbio.py'),
11
10
  'execnb.nbio.NbCell.__hash__': ('nbio.html#nbcell.__hash__', 'execnb/nbio.py'),
12
11
  'execnb.nbio.NbCell.__init__': ('nbio.html#nbcell.__init__', 'execnb/nbio.py'),
@@ -23,31 +22,36 @@ d = { 'settings': { 'branch': 'master',
23
22
  'execnb.nbio.write_nb': ('nbio.html#write_nb', 'execnb/nbio.py')},
24
23
  'execnb.shell': { 'execnb.shell.CaptureShell': ('shell.html#captureshell', 'execnb/shell.py'),
25
24
  'execnb.shell.CaptureShell.__init__': ('shell.html#captureshell.__init__', 'execnb/shell.py'),
26
- 'execnb.shell.CaptureShell._add_exec': ('shell.html#captureshell._add_exec', 'execnb/shell.py'),
27
- 'execnb.shell.CaptureShell._add_out': ('shell.html#captureshell._add_out', 'execnb/shell.py'),
28
- 'execnb.shell.CaptureShell._result': ('shell.html#captureshell._result', 'execnb/shell.py'),
29
- 'execnb.shell.CaptureShell._showtraceback': ('shell.html#captureshell._showtraceback', 'execnb/shell.py'),
30
- 'execnb.shell.CaptureShell._stream': ('shell.html#captureshell._stream', 'execnb/shell.py'),
31
25
  'execnb.shell.CaptureShell.cell': ('shell.html#captureshell.cell', 'execnb/shell.py'),
26
+ 'execnb.shell.CaptureShell.complete': ('shell.html#captureshell.complete', 'execnb/shell.py'),
32
27
  'execnb.shell.CaptureShell.enable_gui': ('shell.html#captureshell.enable_gui', 'execnb/shell.py'),
33
- 'execnb.shell.CaptureShell.enable_matplotlib': ( 'shell.html#captureshell.enable_matplotlib',
34
- 'execnb/shell.py'),
35
28
  'execnb.shell.CaptureShell.execute': ('shell.html#captureshell.execute', 'execnb/shell.py'),
36
29
  'execnb.shell.CaptureShell.prettytb': ('shell.html#captureshell.prettytb', 'execnb/shell.py'),
37
30
  'execnb.shell.CaptureShell.run': ('shell.html#captureshell.run', 'execnb/shell.py'),
38
31
  'execnb.shell.CaptureShell.run_all': ('shell.html#captureshell.run_all', 'execnb/shell.py'),
32
+ 'execnb.shell.CaptureShell.run_cell': ('shell.html#captureshell.run_cell', 'execnb/shell.py'),
39
33
  'execnb.shell.CaptureShell.set_path': ('shell.html#captureshell.set_path', 'execnb/shell.py'),
40
- 'execnb.shell._CaptureHook': ('shell.html#_capturehook', 'execnb/shell.py'),
41
- 'execnb.shell._CaptureHook.__call__': ('shell.html#_capturehook.__call__', 'execnb/shell.py'),
42
- 'execnb.shell._CaptureHook.quiet': ('shell.html#_capturehook.quiet', 'execnb/shell.py'),
43
- 'execnb.shell._CapturePub': ('shell.html#_capturepub', 'execnb/shell.py'),
44
- 'execnb.shell._CapturePub.publish': ('shell.html#_capturepub.publish', 'execnb/shell.py'),
34
+ 'execnb.shell.ExecutionInfo.__repr__': ('shell.html#executioninfo.__repr__', 'execnb/shell.py'),
35
+ 'execnb.shell.ExecutionResult.__repr__': ('shell.html#executionresult.__repr__', 'execnb/shell.py'),
36
+ 'execnb.shell.SmartCompleter': ('shell.html#smartcompleter', 'execnb/shell.py'),
37
+ 'execnb.shell.SmartCompleter.__call__': ('shell.html#smartcompleter.__call__', 'execnb/shell.py'),
38
+ 'execnb.shell.SmartCompleter.__init__': ('shell.html#smartcompleter.__init__', 'execnb/shell.py'),
39
+ 'execnb.shell._CustDisplayHook': ('shell.html#_custdisplayhook', 'execnb/shell.py'),
40
+ 'execnb.shell._CustDisplayHook.log_output': ('shell.html#_custdisplayhook.log_output', 'execnb/shell.py'),
41
+ 'execnb.shell._CustDisplayHook.write_format_data': ( 'shell.html#_custdisplayhook.write_format_data',
42
+ 'execnb/shell.py'),
43
+ 'execnb.shell._CustDisplayHook.write_output_prompt': ( 'shell.html#_custdisplayhook.write_output_prompt',
44
+ 'execnb/shell.py'),
45
45
  'execnb.shell._false': ('shell.html#_false', 'execnb/shell.py'),
46
46
  'execnb.shell._format_mimedata': ('shell.html#_format_mimedata', 'execnb/shell.py'),
47
+ 'execnb.shell._mk_out': ('shell.html#_mk_out', 'execnb/shell.py'),
47
48
  'execnb.shell._out_exc': ('shell.html#_out_exc', 'execnb/shell.py'),
49
+ 'execnb.shell._out_nb': ('shell.html#_out_nb', 'execnb/shell.py'),
48
50
  'execnb.shell._out_stream': ('shell.html#_out_stream', 'execnb/shell.py'),
49
51
  'execnb.shell.exec_nb': ('shell.html#exec_nb', 'execnb/shell.py'),
50
52
  'execnb.shell.find_output': ('shell.html#find_output', 'execnb/shell.py'),
53
+ 'execnb.shell.format_exc': ('shell.html#format_exc', 'execnb/shell.py'),
51
54
  'execnb.shell.out_error': ('shell.html#out_error', 'execnb/shell.py'),
52
55
  'execnb.shell.out_exec': ('shell.html#out_exec', 'execnb/shell.py'),
53
- 'execnb.shell.out_stream': ('shell.html#out_stream', 'execnb/shell.py')}}}
56
+ 'execnb.shell.out_stream': ('shell.html#out_stream', 'execnb/shell.py'),
57
+ 'execnb.shell.render_outputs': ('shell.html#render_outputs', 'execnb/shell.py')}}}
execnb/nbio.py CHANGED
@@ -1,9 +1,11 @@
1
+ """Reading and writing Jupyter notebooks"""
2
+
1
3
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/01_nbio.ipynb.
2
4
 
3
5
  # %% auto 0
4
6
  __all__ = ['NbCell', 'dict2nb', 'read_nb', 'new_nb', 'mk_cell', 'nb2dict', 'nb2str', 'write_nb']
5
7
 
6
- # %% ../nbs/01_nbio.ipynb 2
8
+ # %% ../nbs/01_nbio.ipynb
7
9
  from fastcore.basics import *
8
10
  from fastcore.imports import *
9
11
 
@@ -11,11 +13,11 @@ import ast,functools
11
13
  from pprint import pformat,pprint
12
14
  from json import loads,dumps
13
15
 
14
- # %% ../nbs/01_nbio.ipynb 6
16
+ # %% ../nbs/01_nbio.ipynb
15
17
  def _read_json(self, encoding=None, errors=None):
16
18
  return loads(Path(self).read_text(encoding=encoding, errors=errors))
17
19
 
18
- # %% ../nbs/01_nbio.ipynb 13
20
+ # %% ../nbs/01_nbio.ipynb
19
21
  class NbCell(AttrDict):
20
22
  def __init__(self, idx, cell):
21
23
  super().__init__(cell)
@@ -38,7 +40,7 @@ class NbCell(AttrDict):
38
40
  def __hash__(self): return hash(self.source) + hash(self.cell_type)
39
41
  def __eq__(self,o): return self.source==o.source and self.cell_type==o.cell_type
40
42
 
41
- # %% ../nbs/01_nbio.ipynb 15
43
+ # %% ../nbs/01_nbio.ipynb
42
44
  def _dict2obj(d, list_func=list, dict_func=AttrDict):
43
45
  "Convert (possibly nested) dicts (or lists of dicts) to `AttrDict`"
44
46
  if isinstance(d, list): return list(map(_dict2obj, d))
@@ -51,19 +53,19 @@ def dict2nb(js=None, **kwargs):
51
53
  nb.cells = [NbCell(*o) for o in enumerate(nb.cells)]
52
54
  return nb
53
55
 
54
- # %% ../nbs/01_nbio.ipynb 20
56
+ # %% ../nbs/01_nbio.ipynb
55
57
  def read_nb(path):
56
58
  "Return notebook at `path`"
57
59
  res = dict2nb(_read_json(path, encoding='utf-8'))
58
60
  res['path_'] = str(path)
59
61
  return res
60
62
 
61
- # %% ../nbs/01_nbio.ipynb 26
63
+ # %% ../nbs/01_nbio.ipynb
62
64
  def new_nb(cells=None, meta=None, nbformat=4, nbformat_minor=5):
63
65
  "Returns an empty new notebook"
64
66
  return dict2nb(cells=cells or [],metadata=meta or {},nbformat=nbformat,nbformat_minor=nbformat_minor)
65
67
 
66
- # %% ../nbs/01_nbio.ipynb 28
68
+ # %% ../nbs/01_nbio.ipynb
67
69
  def mk_cell(text, # `source` attr in cell
68
70
  cell_type='code', # `cell_type` attr in cell
69
71
  **kwargs): # any other attrs to add to cell
@@ -75,7 +77,7 @@ def mk_cell(text, # `source` attr in cell
75
77
  kwargs['execution_count']=0
76
78
  return NbCell(0, dict(cell_type=cell_type, source=text, directives_={}, **kwargs))
77
79
 
78
- # %% ../nbs/01_nbio.ipynb 31
80
+ # %% ../nbs/01_nbio.ipynb
79
81
  def nb2dict(d, k=None):
80
82
  "Convert parsed notebook to `dict`"
81
83
  if k=='source': return d.splitlines(keepends=True)
@@ -83,13 +85,13 @@ def nb2dict(d, k=None):
83
85
  if not isinstance(d, dict): return d
84
86
  return dict(**{k:nb2dict(v,k) for k,v in d.items() if k[-1] != '_'})
85
87
 
86
- # %% ../nbs/01_nbio.ipynb 34
88
+ # %% ../nbs/01_nbio.ipynb
87
89
  def nb2str(nb):
88
90
  "Convert `nb` to a `str`"
89
91
  if isinstance(nb, (AttrDict,list)): nb = nb2dict(nb)
90
92
  return dumps(nb, sort_keys=True, indent=1, ensure_ascii=False) + "\n"
91
93
 
92
- # %% ../nbs/01_nbio.ipynb 37
94
+ # %% ../nbs/01_nbio.ipynb
93
95
  def write_nb(nb, path):
94
96
  "Write `nb` to `path`"
95
97
  new = nb2str(nb)
execnb/shell.py CHANGED
@@ -1,149 +1,164 @@
1
+ """A shell for running notebook code without a notebook server"""
2
+
1
3
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/02_shell.ipynb.
2
4
 
3
5
  # %% ../nbs/02_shell.ipynb 2
4
6
  from __future__ import annotations
5
7
 
6
- import os
7
- os.environ['MPLBACKEND'] = 'module://matplotlib_inline.backend_inline'
8
-
9
- from fastcore.imports import *
10
- from fastcore.basics import *
8
+ from fastcore.utils import *
11
9
  from fastcore.script import call_parse
10
+ from fastcore.ansi import ansi2html
12
11
 
13
- import multiprocessing
12
+ import mistletoe,multiprocessing,types,traceback,signal
14
13
  try:
15
14
  if sys.platform == 'darwin': multiprocessing.set_start_method("fork")
16
15
  except RuntimeError: pass # if re-running cell
17
16
 
18
- import tokenize
19
- from IPython.core.interactiveshell import InteractiveShell
17
+ from IPython.core.interactiveshell import InteractiveShell, ExecutionInfo, ExecutionResult
20
18
  from IPython.core.displayhook import DisplayHook
21
- from IPython.core.displaypub import DisplayPublisher
19
+ from IPython.utils.capture import capture_output
20
+ from IPython.utils.text import strip_ansi
21
+ from IPython.core.completer import IPCompleter,provisionalcompleter
22
+ from IPython.core.hooks import CommandChainDispatcher
23
+ from IPython.core.completerlib import module_completer
24
+ from IPython.utils.strdispatch import StrDispatch
25
+ from IPython.display import display as disp, HTML
26
+
22
27
  from base64 import b64encode
23
- from io import StringIO
28
+ from html import escape
29
+ try: from matplotlib_inline.backend_inline import set_matplotlib_formats
30
+ except ImportError: set_matplotlib_formats = None
31
+
24
32
 
25
- from .fastshell import FastInteractiveShell
26
33
  from .nbio import *
27
34
  from .nbio import _dict2obj
28
35
 
29
- from collections.abc import Callable
30
-
31
36
  # %% auto 0
32
- __all__ = ['CaptureShell', 'find_output', 'out_exec', 'out_stream', 'out_error', 'exec_nb']
33
-
34
- # %% ../nbs/02_shell.ipynb 4
35
- # IPython requires a DisplayHook and DisplayPublisher
36
- # We override `__call__` and `publish` to save outputs instead of printing them
37
- class _CaptureHook(DisplayHook):
38
- "Called when displaying a result"
39
-
40
- def quiet(self):
41
- "Should we silence because of ';'?"
42
- sio = StringIO(self.shell._code)
43
- tokens = list(tokenize.generate_tokens(sio.readline))
44
- for t in reversed(tokens):
45
- if t.type in (tokenize.ENDMARKER, tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT): continue
46
- return t.type == tokenize.OP and t.string == ';'
47
-
48
- def __call__(self, result=None):
49
- if result is None or self.quiet(): return
50
- self.fill_exec_result(result)
51
- self.shell._result(result)
52
-
53
- class _CapturePub(DisplayPublisher):
54
- "Called when adding an output"
55
- def publish(self, data, metadata=None, **kwargs): self.shell._add_out(data, metadata, typ='display_data')
56
-
57
- # %% ../nbs/02_shell.ipynb 5
58
- # These are the standard notebook formats for exception and stream data (e.g stdout)
59
- def _out_exc(ename, evalue, traceback): return dict(ename=str(ename), evalue=str(evalue), output_type='error', traceback=traceback)
60
- def _out_stream(text, name): return dict(name=name, output_type='stream', text=text.splitlines(True))
37
+ __all__ = ['CaptureShell', 'format_exc', 'render_outputs', 'find_output', 'out_exec', 'out_stream', 'out_error', 'exec_nb',
38
+ 'SmartCompleter']
61
39
 
62
- # %% ../nbs/02_shell.ipynb 6
63
- def _format_mimedata(k, v):
64
- "Format mime-type keyed data consistently with Jupyter"
65
- if k.startswith('text/'): return v.splitlines(True)
66
- if k.startswith('image/') and isinstance(v, bytes):
67
- v = b64encode(v).decode()
68
- return v+'\n' if not v.endswith('\n') else v
69
- return v
40
+ # %% ../nbs/02_shell.ipynb
41
+ class _CustDisplayHook(DisplayHook):
42
+ def write_output_prompt(self): pass
43
+ def write_format_data(self, data, md_dict): pass
44
+ def log_output(self, format_dict): pass
70
45
 
71
- # %% ../nbs/02_shell.ipynb 8
72
- class CaptureShell(FastInteractiveShell):
73
- "Execute the IPython/Jupyter source code"
74
- def __init__(self,
75
- path:str|Path=None): # Add `path` to python path
76
- super().__init__(displayhook_class=_CaptureHook, display_pub_class=_CapturePub)
77
- InteractiveShell._instance = self
78
- self.out,self.count = [],1
79
- self.exc = self.result = self._fname = self._cell_idx = self._stdout = self._stderr = None
80
- if IN_NOTEBOOK:
81
- try: self.enable_matplotlib('inline')
82
- except ModuleNotFoundError: pass
83
- if path: self.set_path(path)
46
+ @patch
47
+ def __repr__(self: ExecutionInfo): return f'cell: {self.raw_cell}; id: {self.cell_id}'
48
+
49
+ @patch
50
+ def __repr__(self: ExecutionResult): return f'result: {self.result}; err: {self.error_in_exec}; info: <{self.info}>'
51
+
52
+ # %% ../nbs/02_shell.ipynb
53
+ class CaptureShell(InteractiveShell):
54
+ displayhook_class = _CustDisplayHook
84
55
 
85
- def enable_matplotlib(self, gui=None):
86
- "Enable `matplotlib` in a nested shell"
87
- from matplotlib_inline.backend_inline import configure_inline_support
88
- configure_inline_support.current_backend = 'unset'
89
- return super().enable_matplotlib(gui)
56
+ def __init__(self, path:str|Path=None, mpl_format='retina', history=False, timeout=None):
57
+ super().__init__()
58
+ self.history_manager.enabled = history
59
+ self.timeout = timeout
60
+ self.result,self.exc = None,None
61
+ if path: self.set_path(path)
62
+ self.display_formatter.active = True
63
+ if not IN_NOTEBOOK: InteractiveShell._instance = self
64
+ if set_matplotlib_formats:
65
+ self.enable_matplotlib("inline")
66
+ self.run_cell("from matplotlib_inline.backend_inline import set_matplotlib_formats")
67
+ self.run_cell(f"set_matplotlib_formats('{mpl_format}')")
68
+
69
+ def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True, cell_id=None,
70
+ stdout=True, stderr=True, display=True, timeout=None):
71
+ if not timeout: timeout = self.timeout
72
+ # TODO what if there's a comment?
73
+ semic = raw_cell.rstrip().endswith(';')
74
+ if timeout:
75
+ def handler(*args): raise TimeoutError()
76
+ signal.signal(signal.SIGALRM, handler)
77
+ signal.alarm(timeout)
78
+ with capture_output(display=display, stdout=stdout, stderr=stderr) as c:
79
+ result = super().run_cell(raw_cell, store_history, silent, shell_futures=shell_futures, cell_id=cell_id)
80
+ if timeout: signal.alarm(0)
81
+ return AttrDict(result=result, stdout='' if semic else c.stdout, stderr=c.stderr,
82
+ display_objects=c.outputs, exception=result.error_in_exec, quiet=semic)
90
83
 
91
84
  def set_path(self, path):
92
85
  "Add `path` to python path, or `path.parent` if it's a file"
93
86
  path = Path(path)
94
87
  if path.is_file(): path = path.parent
95
88
  self.run_cell(f"import sys; sys.path.insert(0, '{path.as_posix()}')")
96
-
97
- def enable_gui(self, gui=None):
98
- "Disable GUI (over-ridden; called by IPython)"
99
- pass
100
89
 
101
- def _showtraceback(self, etype, evalue, stb: str):
102
- self.out.append(_out_exc(etype, evalue, stb))
103
- self.exc = (etype, evalue, '\n'.join(stb))
104
-
105
- def _add_out(self, data, meta, typ='execute_result', **kwargs):
106
- self._stream()
107
- fd = {k:_format_mimedata(k,v) for k,v in data.items()}
108
- self.out.append(dict(data=fd, metadata=meta, output_type=typ, **kwargs))
109
-
110
- def _add_exec(self, result, meta, typ='execute_result'):
111
- self._add_out(result, meta, execution_count=self.count)
112
- self.count += 1
113
-
114
- def _result(self, result):
115
- self.result = result
116
- self._add_exec(*self.display_formatter.format(result))
117
-
118
- def _stream(self):
119
- for nm in ('stdout','stderr'):
120
- attr = '_'+nm
121
- std = getattr(self, attr)
122
- if std is not None:
123
- text = std.getvalue()
124
- if text:
125
- self.out.append(_out_stream(text, nm))
126
- setattr(self, attr, StringIO())
127
-
128
- # %% ../nbs/02_shell.ipynb 11
90
+ def enable_gui(self, gui=None): pass
91
+
92
+ # %% ../nbs/02_shell.ipynb
93
+ def format_exc(e):
94
+ "Format exception `e` as a string"
95
+ return ''.join(traceback.format_exception(type(e), e, e.__traceback__))
96
+
97
+ # %% ../nbs/02_shell.ipynb
98
+ def _out_stream(text, name): return dict(name=name, output_type='stream', text=text.splitlines(True))
99
+ def _out_exc(e):
100
+ ename = type(e).__name__
101
+ tb = traceback.extract_tb(e.__traceback__)#.format()
102
+ return dict(ename=str(ename), evalue=str(e), output_type='error', traceback=format_exc(e))
103
+
104
+ def _format_mimedata(k, v):
105
+ "Format mime-type keyed data consistently with Jupyter"
106
+ if k.startswith('text/'): return v.splitlines(True)
107
+ if k.startswith('image/') and isinstance(v, bytes):
108
+ v = b64encode(v).decode()
109
+ return v+'\n' if not v.endswith('\n') else v
110
+ return v
111
+
112
+ def _mk_out(data, meta, output_type='display_data'):
113
+ fd = {k:_format_mimedata(k,v) for k,v in data.items()}
114
+ return dict(data=fd, metadata=meta, output_type=output_type)
115
+
116
+ def _out_nb(o, fmt):
117
+ res = []
118
+ if o.stdout: res.append(_out_stream(o.stdout, 'stdout'))
119
+ if o.stderr: res.append(_out_stream(o.stderr, 'stderr'))
120
+ if o.exception: res.append(_out_exc(o.exception))
121
+ r = o.result.result
122
+ for x in o.display_objects: res.append(_mk_out(x.data, x.metadata))
123
+ if r is not None and not o.quiet:
124
+ res.append(_mk_out(*fmt.format(r), 'execute_result'))
125
+ return res
126
+
127
+ # %% ../nbs/02_shell.ipynb
129
128
  @patch
130
129
  def run(self:CaptureShell,
131
130
  code:str, # Python/IPython code to run
132
131
  stdout=True, # Capture stdout and save as output?
133
132
  stderr=True): # Capture stderr and save as output?
134
133
  "Run `code`, returning a list of all outputs in Jupyter notebook format"
135
- self._code = code
136
- self.exc = False
137
- self.out.clear()
138
- sys_stdout,sys_stderr = sys.stdout,sys.stderr
139
- if stdout: self._stdout = sys.stdout = StringIO()
140
- if stderr: self._stderr = sys.stderr = StringIO()
141
- try: self.run_cell(code)
142
- finally: sys.stdout,sys.stderr = sys_stdout,sys_stderr
143
- self._stream()
144
- return [*self.out]
145
-
146
- # %% ../nbs/02_shell.ipynb 24
134
+ res = self.run_cell(code, stdout=stdout, stderr=stderr)
135
+ self.result = res.result.result
136
+ self.exc = res.exception
137
+ return _out_nb(res, self.display_formatter)
138
+
139
+ # %% ../nbs/02_shell.ipynb
140
+ def render_outputs(outputs, ansi_renderer=strip_ansi):
141
+ def render_output(out):
142
+ otype = out['output_type']
143
+ if otype == 'stream':
144
+ txt = ansi_renderer(''.join(out['text']))
145
+ return f"<pre>{txt}</pre>" if out['name']=='stdout' else f"<pre class='stderr'>{txt}</pre>"
146
+ elif otype in ('display_data','execute_result'):
147
+ data = out['data']
148
+ _g = lambda t: ''.join(data[t]) if t in data else None
149
+ if d := _g('text/html'): return d
150
+ if d := _g('application/javascript'): return f'<script>{d}</script>'
151
+ if d := _g('text/markdown'): return mistletoe.markdown(d)
152
+ if d := _g('image/svg+xml'): return d
153
+ if d := _g('image/jpeg'): return f'<img src="data:image/jpeg;base64,{d}"/>'
154
+ if d := _g('image/png'): return f'<img src="data:image/png;base64,{d}"/>'
155
+ if d := _g('text/latex'): return f'<div class="math">${d}$</div>'
156
+ if d := _g('text/plain'): return f"<pre>{escape(d)}</pre>"
157
+ return ''
158
+
159
+ return '\n'.join(map(render_output, outputs))
160
+
161
+ # %% ../nbs/02_shell.ipynb
147
162
  @patch
148
163
  def cell(self:CaptureShell, cell, stdout=True, stderr=True):
149
164
  "Run `cell`, skipping if not code, and store outputs back in cell"
@@ -155,40 +170,40 @@ def cell(self:CaptureShell, cell, stdout=True, stderr=True):
155
170
  for o in outs:
156
171
  if 'execution_count' in o: cell['execution_count'] = o['execution_count']
157
172
 
158
- # %% ../nbs/02_shell.ipynb 27
173
+ # %% ../nbs/02_shell.ipynb
159
174
  def find_output(outp, # Output from `run`
160
175
  ot='execute_result' # Output_type to find
161
176
  ):
162
177
  "Find first output of type `ot` in `CaptureShell.run` output"
163
178
  return first(o for o in outp if o['output_type']==ot)
164
179
 
165
- # %% ../nbs/02_shell.ipynb 30
180
+ # %% ../nbs/02_shell.ipynb
166
181
  def out_exec(outp):
167
182
  "Get data from execution result in `outp`."
168
183
  out = find_output(outp)
169
184
  if out: return '\n'.join(first(out['data'].values()))
170
185
 
171
- # %% ../nbs/02_shell.ipynb 32
186
+ # %% ../nbs/02_shell.ipynb
172
187
  def out_stream(outp):
173
188
  "Get text from stream in `outp`."
174
189
  out = find_output(outp, 'stream')
175
190
  if out: return ('\n'.join(out['text'])).strip()
176
191
 
177
- # %% ../nbs/02_shell.ipynb 34
192
+ # %% ../nbs/02_shell.ipynb
178
193
  def out_error(outp):
179
194
  "Get traceback from error in `outp`."
180
195
  out = find_output(outp, 'error')
181
196
  if out: return '\n'.join(out['traceback'])
182
197
 
183
- # %% ../nbs/02_shell.ipynb 37
198
+ # %% ../nbs/02_shell.ipynb
184
199
  def _false(o): return False
185
200
 
186
201
  @patch
187
202
  def run_all(self:CaptureShell,
188
203
  nb, # A notebook read with `nbclient` or `read_nb`
189
204
  exc_stop:bool=False, # Stop on exceptions?
190
- preproc:Callable=_false, # Called before each cell is executed
191
- postproc:Callable=_false, # Called after each cell is executed
205
+ preproc:callable=_false, # Called before each cell is executed
206
+ postproc:callable=_false, # Called after each cell is executed
192
207
  inject_code:str|None=None, # Code to inject into a cell
193
208
  inject_idx:int=0 # Cell to replace with `inject_code`
194
209
  ):
@@ -198,16 +213,16 @@ def run_all(self:CaptureShell,
198
213
  if not preproc(cell):
199
214
  self.cell(cell)
200
215
  postproc(cell)
201
- if self.exc and exc_stop: raise self.exc[1] from None
216
+ if self.exc and exc_stop: raise self.exc from None
202
217
 
203
- # %% ../nbs/02_shell.ipynb 51
218
+ # %% ../nbs/02_shell.ipynb
204
219
  @patch
205
220
  def execute(self:CaptureShell,
206
221
  src:str|Path, # Notebook path to read from
207
222
  dest:str|None=None, # Notebook path to write to
208
223
  exc_stop:bool=False, # Stop on exceptions?
209
- preproc:Callable=_false, # Called before each cell is executed
210
- postproc:Callable=_false, # Called after each cell is executed
224
+ preproc:callable=_false, # Called before each cell is executed
225
+ postproc:callable=_false, # Called after each cell is executed
211
226
  inject_code:str|None=None, # Code to inject into a cell
212
227
  inject_path:str|Path|None=None, # Path to file containing code to inject into a cell
213
228
  inject_idx:int=0 # Cell to replace with `inject_code`
@@ -221,7 +236,7 @@ def execute(self:CaptureShell,
221
236
  inject_code=inject_code, inject_idx=inject_idx)
222
237
  if dest: write_nb(nb, dest)
223
238
 
224
- # %% ../nbs/02_shell.ipynb 55
239
+ # %% ../nbs/02_shell.ipynb
225
240
  @patch
226
241
  def prettytb(self:CaptureShell,
227
242
  fname:str|Path=None): # filename to print alongside the traceback
@@ -229,11 +244,11 @@ def prettytb(self:CaptureShell,
229
244
  fname = fname if fname else self._fname
230
245
  _fence = '='*75
231
246
  cell_intro_str = f"While Executing Cell #{self._cell_idx}:" if self._cell_idx else "While Executing:"
232
- cell_str = f"\n{cell_intro_str}\n{self.exc[-1]}"
247
+ cell_str = f"\n{cell_intro_str}\n{format_exc(self.exc)}"
233
248
  fname_str = f' in {fname}' if fname else ''
234
- return f"{type(self.exc[1]).__name__}{fname_str}:\n{_fence}\n{cell_str}\n"
249
+ return f"{type(self.exc).__name__}{fname_str}:\n{_fence}\n{cell_str}\n"
235
250
 
236
- # %% ../nbs/02_shell.ipynb 74
251
+ # %% ../nbs/02_shell.ipynb
237
252
  @call_parse
238
253
  def exec_nb(
239
254
  src:str, # Notebook path to read from
@@ -246,3 +261,29 @@ def exec_nb(
246
261
  "Execute notebook from `src` and save with outputs to `dest`"
247
262
  CaptureShell().execute(src, dest, exc_stop=exc_stop, inject_code=inject_code,
248
263
  inject_path=inject_path, inject_idx=inject_idx)
264
+
265
+ # %% ../nbs/02_shell.ipynb
266
+ class SmartCompleter(IPCompleter):
267
+ def __init__(self, shell, namespace=None, jedi=False):
268
+ if namespace is None: namespace = shell.user_ns
269
+ super().__init__(shell, namespace)
270
+ self.use_jedi = jedi
271
+ sdisp = StrDispatch()
272
+ self.custom_completers = sdisp
273
+ import_disp = CommandChainDispatcher()
274
+ import_disp.add(types.MethodType(module_completer, shell))
275
+ sdisp.add_s('import', import_disp)
276
+ sdisp.add_s('from', import_disp)
277
+
278
+ def __call__(self, c):
279
+ if not c: return []
280
+ with provisionalcompleter():
281
+ return [o.text.rpartition('.')[-1]
282
+ for o in self.completions(c, len(c))
283
+ if o.type not in ('magic', 'path')]
284
+
285
+ # %% ../nbs/02_shell.ipynb
286
+ @patch
287
+ def complete(self:CaptureShell, c):
288
+ if not hasattr(self, '_completer'): self._completer = SmartCompleter(self)
289
+ return self._completer(c)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: execnb
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: A description of your project
5
5
  Home-page: https://github.com/fastai/execnb/
6
6
  Author: Jeremy Howard
@@ -18,6 +18,7 @@ Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
19
  Requires-Dist: fastcore >=1.5.5
20
20
  Requires-Dist: ipython
21
+ Requires-Dist: mistletoe
21
22
  Provides-Extra: dev
22
23
  Requires-Dist: matplotlib ; extra == 'dev'
23
24
  Requires-Dist: Pillow ; extra == 'dev'
@@ -0,0 +1,10 @@
1
+ execnb/__init__.py,sha256=YpKDcdV7CqL8n45u267wKtyloM13FSVbOdrqgNZnSLM,22
2
+ execnb/_modidx.py,sha256=3wJwFT95tiaCPmj7VMQEIim5qLTcOatC2od-ze5WJcc,5771
3
+ execnb/nbio.py,sha256=gs3EGN0sP2j47XUH31rTn2KT57b3wWnBZsn9AoZm2JQ,3677
4
+ execnb/shell.py,sha256=4wuuyphJ0M0NCvjQ2RbJlstDHUXFmnWNJExRdveiLew,11958
5
+ execnb-0.1.7.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
6
+ execnb-0.1.7.dist-info/METADATA,sha256=BqAfeem0tFfd_BxveYlY1_kxWuW35KGZc4AHAaSOSSw,3275
7
+ execnb-0.1.7.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
8
+ execnb-0.1.7.dist-info/entry_points.txt,sha256=jZ8LPZCqnu4hXN_AgQpm05hVnTE-C25YK_4aiVX4i78,84
9
+ execnb-0.1.7.dist-info/top_level.txt,sha256=VGWmzsw8FOlT1r5TdOxaTWIAyRdclcxNdJ2r1hojf5U,7
10
+ execnb-0.1.7.dist-info/RECORD,,
execnb/fastshell.py DELETED
@@ -1,124 +0,0 @@
1
- # Copyright (c) IPython Development Team.
2
- # Modifications by Jeremy Howard
3
- # Distributed under the terms of the Modified BSD License.
4
-
5
- import os, sys, warnings
6
- from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
7
- from IPython.core.history import HistoryAccessorBase
8
- from IPython.core.autocall import ZMQExitAutocall
9
- from IPython.core.magic import magics_class, line_magic, Magics
10
- from IPython.utils.process import system
11
- from traitlets import Instance, Type, Any, default, observe
12
-
13
- @magics_class
14
- class KernelMagics(Magics):
15
- @line_magic
16
- def edit(self, parameter_s='', last_call=['','']): pass
17
-
18
- @line_magic
19
- def clear(self, arg_s): pass
20
-
21
- @line_magic
22
- def less(self, arg_s): pass
23
-
24
- more = line_magic('more')(less)
25
-
26
- # Man calls a pager, so we also need to redefine it
27
- if os.name == 'posix':
28
- @line_magic
29
- def man(self, arg_s): pass
30
-
31
- @line_magic
32
- def autosave(self, arg_s): pass
33
-
34
- def noop(*args, **kwargs): return args
35
-
36
- class DummyHistory(HistoryAccessorBase):
37
- def __init__(self, *args, **kw): self.enabled=False
38
- def __getattr__(self, k): return noop
39
- _log_validate = False
40
-
41
- class FastInteractiveShell(InteractiveShell):
42
- data_pub_class = Any()
43
- parent_header = Any()
44
- exiter = Instance(ZMQExitAutocall)
45
-
46
- def init_history(self): self.history_manager=DummyHistory()
47
- def atexit_operations(self, *args, **kwargs): pass
48
-
49
- @default('exiter')
50
- def _default_exiter(self): return ZMQExitAutocall(self)
51
-
52
- @observe('exit_now')
53
- def _update_exit_now(self, change): pass
54
-
55
- keepkernel_on_exit = None
56
-
57
- def init_environment(self):
58
- "Configure the user's environment."
59
- env = os.environ
60
- env['TERM'] = 'xterm-color'
61
- env['CLICOLOR'] = '1'
62
- env['PAGER'] = 'cat'
63
- env['GIT_PAGER'] = 'cat'
64
-
65
- def init_data_pub(self): pass
66
-
67
- @property
68
- def data_pub(self):
69
- if not hasattr(self, '_data_pub'):
70
- warnings.warn("InteractiveShell.data_pub is deprecated outside IPython parallel.", DeprecationWarning, stacklevel=2)
71
- self._data_pub = self.data_pub_class(parent=self)
72
- self._data_pub.session = self.display_pub.session
73
- self._data_pub.pub_socket = self.display_pub.pub_socket
74
- return self._data_pub
75
-
76
- @data_pub.setter
77
- def data_pub(self, pub): self._data_pub = pub
78
-
79
- def ask_exit(self):
80
- "Engage the exit actions."
81
- self.exit_now = (not self.keepkernel_on_exit)
82
- payload = dict( source='ask_exit', keepkernel=self.keepkernel_on_exit,)
83
- self.payload_manager.write_payload(payload)
84
-
85
- def set_next_input(self, text, replace=False):
86
- "Send the specified text to the frontend to be presented at the next input cell."
87
- payload = dict( source='set_next_input', text=text, replace=replace,)
88
- self.payload_manager.write_payload(payload)
89
-
90
- def set_parent(self, parent):
91
- "Set the parent header for associating output with its triggering input"
92
- self.parent_header = parent
93
- self.displayhook.set_parent(parent)
94
- self.display_pub.set_parent(parent)
95
- if hasattr(self, '_data_pub'): self.data_pub.set_parent(parent)
96
- try: sys.stdout.set_parent(parent)
97
- except AttributeError: pass
98
- try: sys.stderr.set_parent(parent)
99
- except AttributeError: pass
100
-
101
- def get_parent(self): return self.parent_header
102
-
103
- def init_magics(self):
104
- super().init_magics()
105
- self.register_magics(KernelMagics)
106
- self.magics_manager.register_alias('ed', 'edit')
107
-
108
- def init_virtualenv(self): pass
109
-
110
- def system_piped(self, cmd):
111
- "Call the given cmd in a subprocess, piping stdout/err "
112
- if cmd.rstrip().endswith('&'): raise OSError("Background processes not supported.")
113
- if sys.platform == 'win32':
114
- cmd = self.var_expand(cmd, depth=1)
115
- from IPython.utils._process_win32 import AvoidUNCPath
116
- with AvoidUNCPath() as path:
117
- if path is not None: cmd = 'pushd %s &&%s' % (path, cmd)
118
- self.user_ns['_exit_code'] = system(cmd)
119
- else: self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
120
-
121
- system = system_piped
122
-
123
- InteractiveShellABC.register(FastInteractiveShell)
124
-
@@ -1,11 +0,0 @@
1
- execnb/__init__.py,sha256=n3oM6B_EMz93NsTI18NNZd-jKFcUPzUkbIKj5VFK5ok,22
2
- execnb/_modidx.py,sha256=1OsF4WZ4cmkxB9wAj8kWjGMmVVhX4BbH73yWAYGBzCM,5229
3
- execnb/fastshell.py,sha256=ODng8r7-b74lRiCR2nENHuIMubxnkfArh0Su2VMHMSs,4285
4
- execnb/nbio.py,sha256=TOOsiO6VAduLfwbXWgCu4k_fXKEpJw6byBq69BCVXek,3660
5
- execnb/shell.py,sha256=lL1rWX_iCPDPb0hK_UZIoqoRkY-plUL_RU6e4ujnjmE,9782
6
- execnb-0.1.6.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
7
- execnb-0.1.6.dist-info/METADATA,sha256=2FLEW9GK9faxUYwHN6g-43CI90xRcwvm2jQE8Pcm01o,3250
8
- execnb-0.1.6.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
9
- execnb-0.1.6.dist-info/entry_points.txt,sha256=jZ8LPZCqnu4hXN_AgQpm05hVnTE-C25YK_4aiVX4i78,84
10
- execnb-0.1.6.dist-info/top_level.txt,sha256=VGWmzsw8FOlT1r5TdOxaTWIAyRdclcxNdJ2r1hojf5U,7
11
- execnb-0.1.6.dist-info/RECORD,,
File without changes