execnb 0.1.5__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.5"
1
+ __version__ = "0.1.7"
execnb/_modidx.py CHANGED
@@ -3,10 +3,9 @@
3
3
  d = { 'settings': { 'branch': 'master',
4
4
  'doc_baseurl': '/execnb/',
5
5
  'doc_host': 'https://fastai.github.io',
6
- 'git_url': 'https://github.com/fastai/execnb/tree/master/',
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,27 +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
- 'execnb.shell.exec_nb': ('shell.html#exec_nb', 'execnb/shell.py')}}}
51
+ 'execnb.shell.exec_nb': ('shell.html#exec_nb', 'execnb/shell.py'),
52
+ 'execnb.shell.find_output': ('shell.html#find_output', 'execnb/shell.py'),
53
+ 'execnb.shell.format_exc': ('shell.html#format_exc', 'execnb/shell.py'),
54
+ 'execnb.shell.out_error': ('shell.html#out_error', 'execnb/shell.py'),
55
+ 'execnb.shell.out_exec': ('shell.html#out_exec', '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)
@@ -28,7 +30,7 @@ class NbCell(AttrDict):
28
30
 
29
31
  def parsed_(self):
30
32
  if self.cell_type!='code' or self.source.strip()[:1] in ['%', '!']: return
31
- if '_parsed_' not in self:
33
+ if '_parsed_' not in self:
32
34
  try: self._parsed_ = ast.parse(self.source).body
33
35
  # you can assign the result of ! to a variable in a notebook cell
34
36
  # which will result in a syntax error if parsed with the ast module.
@@ -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,28 +53,31 @@ 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
70
72
  "Create an `NbCell` containing `text`"
71
73
  assert cell_type in {'code', 'markdown', 'raw'}
72
74
  if 'metadata' not in kwargs: kwargs['metadata']={}
75
+ if cell_type == 'code':
76
+ kwargs['outputs']=[]
77
+ kwargs['execution_count']=0
73
78
  return NbCell(0, dict(cell_type=cell_type, source=text, directives_={}, **kwargs))
74
79
 
75
- # %% ../nbs/01_nbio.ipynb 31
80
+ # %% ../nbs/01_nbio.ipynb
76
81
  def nb2dict(d, k=None):
77
82
  "Convert parsed notebook to `dict`"
78
83
  if k=='source': return d.splitlines(keepends=True)
@@ -80,13 +85,13 @@ def nb2dict(d, k=None):
80
85
  if not isinstance(d, dict): return d
81
86
  return dict(**{k:nb2dict(v,k) for k,v in d.items() if k[-1] != '_'})
82
87
 
83
- # %% ../nbs/01_nbio.ipynb 34
88
+ # %% ../nbs/01_nbio.ipynb
84
89
  def nb2str(nb):
85
90
  "Convert `nb` to a `str`"
86
91
  if isinstance(nb, (AttrDict,list)): nb = nb2dict(nb)
87
92
  return dumps(nb, sort_keys=True, indent=1, ensure_ascii=False) + "\n"
88
93
 
89
- # %% ../nbs/01_nbio.ipynb 37
94
+ # %% ../nbs/01_nbio.ipynb
90
95
  def write_nb(nb, path):
91
96
  "Write `nb` to `path`"
92
97
  new = nb2str(nb)
execnb/shell.py CHANGED
@@ -1,65 +1,106 @@
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', '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)
37
+ __all__ = ['CaptureShell', 'format_exc', 'render_outputs', 'find_output', 'out_exec', 'out_stream', 'out_error', 'exec_nb',
38
+ 'SmartCompleter']
39
+
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
45
+
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
55
+
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)
83
+
84
+ def set_path(self, path):
85
+ "Add `path` to python path, or `path.parent` if it's a file"
86
+ path = Path(path)
87
+ if path.is_file(): path = path.parent
88
+ self.run_cell(f"import sys; sys.path.insert(0, '{path.as_posix()}')")
89
+
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
60
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))
61
103
 
62
- # %% ../nbs/02_shell.ipynb 6
63
104
  def _format_mimedata(k, v):
64
105
  "Format mime-type keyed data consistently with Jupyter"
65
106
  if k.startswith('text/'): return v.splitlines(True)
@@ -68,82 +109,56 @@ def _format_mimedata(k, v):
68
109
  return v+'\n' if not v.endswith('\n') else v
69
110
  return v
70
111
 
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)
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)
84
115
 
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)
90
-
91
- def set_path(self, path):
92
- "Add `path` to python path, or `path.parent` if it's a file"
93
- path = Path(path)
94
- if path.is_file(): path = path.parent
95
- self.run_cell(f"import sys; sys.path.insert(0, '{path.as_posix()}')")
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
96
126
 
97
- def enable_gui(self, gui=None):
98
- "Disable GUI (over-ridden; called by IPython)"
99
- pass
100
-
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
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,15 +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 28
173
+ # %% ../nbs/02_shell.ipynb
174
+ def find_output(outp, # Output from `run`
175
+ ot='execute_result' # Output_type to find
176
+ ):
177
+ "Find first output of type `ot` in `CaptureShell.run` output"
178
+ return first(o for o in outp if o['output_type']==ot)
179
+
180
+ # %% ../nbs/02_shell.ipynb
181
+ def out_exec(outp):
182
+ "Get data from execution result in `outp`."
183
+ out = find_output(outp)
184
+ if out: return '\n'.join(first(out['data'].values()))
185
+
186
+ # %% ../nbs/02_shell.ipynb
187
+ def out_stream(outp):
188
+ "Get text from stream in `outp`."
189
+ out = find_output(outp, 'stream')
190
+ if out: return ('\n'.join(out['text'])).strip()
191
+
192
+ # %% ../nbs/02_shell.ipynb
193
+ def out_error(outp):
194
+ "Get traceback from error in `outp`."
195
+ out = find_output(outp, 'error')
196
+ if out: return '\n'.join(out['traceback'])
197
+
198
+ # %% ../nbs/02_shell.ipynb
159
199
  def _false(o): return False
160
200
 
161
201
  @patch
162
202
  def run_all(self:CaptureShell,
163
203
  nb, # A notebook read with `nbclient` or `read_nb`
164
204
  exc_stop:bool=False, # Stop on exceptions?
165
- preproc:Callable=_false, # Called before each cell is executed
166
- 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
167
207
  inject_code:str|None=None, # Code to inject into a cell
168
208
  inject_idx:int=0 # Cell to replace with `inject_code`
169
209
  ):
@@ -173,16 +213,16 @@ def run_all(self:CaptureShell,
173
213
  if not preproc(cell):
174
214
  self.cell(cell)
175
215
  postproc(cell)
176
- if self.exc and exc_stop: raise self.exc[1] from None
216
+ if self.exc and exc_stop: raise self.exc from None
177
217
 
178
- # %% ../nbs/02_shell.ipynb 42
218
+ # %% ../nbs/02_shell.ipynb
179
219
  @patch
180
220
  def execute(self:CaptureShell,
181
221
  src:str|Path, # Notebook path to read from
182
222
  dest:str|None=None, # Notebook path to write to
183
223
  exc_stop:bool=False, # Stop on exceptions?
184
- preproc:Callable=_false, # Called before each cell is executed
185
- 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
186
226
  inject_code:str|None=None, # Code to inject into a cell
187
227
  inject_path:str|Path|None=None, # Path to file containing code to inject into a cell
188
228
  inject_idx:int=0 # Cell to replace with `inject_code`
@@ -196,7 +236,7 @@ def execute(self:CaptureShell,
196
236
  inject_code=inject_code, inject_idx=inject_idx)
197
237
  if dest: write_nb(nb, dest)
198
238
 
199
- # %% ../nbs/02_shell.ipynb 46
239
+ # %% ../nbs/02_shell.ipynb
200
240
  @patch
201
241
  def prettytb(self:CaptureShell,
202
242
  fname:str|Path=None): # filename to print alongside the traceback
@@ -204,11 +244,11 @@ def prettytb(self:CaptureShell,
204
244
  fname = fname if fname else self._fname
205
245
  _fence = '='*75
206
246
  cell_intro_str = f"While Executing Cell #{self._cell_idx}:" if self._cell_idx else "While Executing:"
207
- cell_str = f"\n{cell_intro_str}\n{self.exc[-1]}"
247
+ cell_str = f"\n{cell_intro_str}\n{format_exc(self.exc)}"
208
248
  fname_str = f' in {fname}' if fname else ''
209
- 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"
210
250
 
211
- # %% ../nbs/02_shell.ipynb 65
251
+ # %% ../nbs/02_shell.ipynb
212
252
  @call_parse
213
253
  def exec_nb(
214
254
  src:str, # Notebook path to read from
@@ -221,3 +261,29 @@ def exec_nb(
221
261
  "Execute notebook from `src` and save with outputs to `dest`"
222
262
  CaptureShell().execute(src, dest, exc_stop=exc_stop, inject_code=inject_code,
223
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,8 +1,8 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: execnb
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Summary: A description of your project
5
- Home-page: https://github.com/fastai/execnb/tree/master/
5
+ Home-page: https://github.com/fastai/execnb/
6
6
  Author: Jeremy Howard
7
7
  Author-email: j@fast.ai
8
8
  License: Apache Software License 2.0
@@ -16,14 +16,15 @@ Classifier: License :: OSI Approved :: Apache Software License
16
16
  Requires-Python: >=3.7
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: fastcore (>=1.5.5)
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'
24
25
 
25
- execnb
26
- ================
26
+ # execnb
27
+
27
28
 
28
29
  <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
29
30
 
@@ -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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.38.4)
2
+ Generator: bdist_wheel (0.41.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
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=rPSfWgIeq2YWVPyESOAwCBt8vftsTpIkuLAGDEzyRQc,22
2
- execnb/_modidx.py,sha256=gpQj6i1HkFABwB73tBR5iaLqNDZNUY3wilOxlO7P5FQ,4833
3
- execnb/fastshell.py,sha256=ODng8r7-b74lRiCR2nENHuIMubxnkfArh0Su2VMHMSs,4285
4
- execnb/nbio.py,sha256=9k15675BTHIWDNVbbN_B93g6pCDECBDX4g7HgxHvyys,3568
5
- execnb/shell.py,sha256=se6sLSEql-zTbHWOH0P_fQ8Qg1WJCEv4s2HCfoaaOfE,8911
6
- execnb-0.1.5.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
7
- execnb-0.1.5.dist-info/METADATA,sha256=t5lJC6cUeocujmRxcvQ0nSnMUo4L3VJ8IfbB6lsyfxc,3278
8
- execnb-0.1.5.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
9
- execnb-0.1.5.dist-info/entry_points.txt,sha256=jZ8LPZCqnu4hXN_AgQpm05hVnTE-C25YK_4aiVX4i78,84
10
- execnb-0.1.5.dist-info/top_level.txt,sha256=VGWmzsw8FOlT1r5TdOxaTWIAyRdclcxNdJ2r1hojf5U,7
11
- execnb-0.1.5.dist-info/RECORD,,