|
| 1 | +"""Reading and writing Jupyter notebooks""" |
| 2 | + |
| 3 | +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/13_nbio.ipynb. |
| 4 | + |
| 5 | +# %% auto #0 |
| 6 | +__all__ = ['NbCell', 'dict2nb', 'read_nb', 'mk_cell', 'new_nb', 'nb2dict', 'nb2str', 'write_nb'] |
| 7 | + |
| 8 | +# %% ../nbs/13_nbio.ipynb #5faca748 |
| 9 | +from .basics import * |
| 10 | +from .xtras import rtoken_hex |
| 11 | +from .imports import * |
| 12 | + |
| 13 | +import ast,functools |
| 14 | +from pprint import pformat,pprint |
| 15 | +from json import loads,dumps |
| 16 | + |
| 17 | +# %% ../nbs/13_nbio.ipynb #9d2e7add |
| 18 | +def _read_json(self, encoding=None, errors=None): |
| 19 | + return loads(Path(self).read_text(encoding=encoding, errors=errors)) |
| 20 | + |
| 21 | +# %% ../nbs/13_nbio.ipynb #49d7bf89 |
| 22 | +class NbCell(AttrDict): |
| 23 | + def __init__(self, idx, cell): |
| 24 | + super().__init__(cell) |
| 25 | + self.idx_ = idx |
| 26 | + if 'id' not in self: self.id = rtoken_hex(4) |
| 27 | + if 'source' in self: self.set_source(self.source) |
| 28 | + |
| 29 | + def set_source(self, source): |
| 30 | + self.source = ''.join(source) |
| 31 | + if '_parsed_' in self: del(self['_parsed_']) |
| 32 | + |
| 33 | + def parsed_(self): |
| 34 | + if self.cell_type!='code' or self.source.strip()[:1] in ['%', '!']: return |
| 35 | + if '_parsed_' not in self: |
| 36 | + try: self._parsed_ = ast.parse(self.source).body |
| 37 | + # you can assign the result of ! to a variable in a notebook cell |
| 38 | + # which will result in a syntax error if parsed with the ast module. |
| 39 | + except SyntaxError: return |
| 40 | + return self._parsed_ |
| 41 | + |
| 42 | + def __hash__(self): return hash(self.source) + hash(self.cell_type) |
| 43 | + def __eq__(self,o): return self.source==o.source and self.cell_type==o.cell_type |
| 44 | + |
| 45 | +# %% ../nbs/13_nbio.ipynb #6c742618 |
| 46 | +def _dict2obj(d, list_func=list, dict_func=AttrDict): |
| 47 | + "Convert (possibly nested) dicts (or lists of dicts) to `AttrDict`" |
| 48 | + if isinstance(d, list): return list(map(_dict2obj, d)) |
| 49 | + if not isinstance(d, dict): return d |
| 50 | + return dict_func(**{k:_dict2obj(v) for k,v in d.items()}) |
| 51 | + |
| 52 | +def dict2nb(js=None, **kwargs): |
| 53 | + "Convert dict `js` to an `AttrDict`, " |
| 54 | + nb = _dict2obj(js or kwargs) |
| 55 | + nb.cells = [NbCell(*o) for o in enumerate(nb.cells)] |
| 56 | + return nb |
| 57 | + |
| 58 | +# %% ../nbs/13_nbio.ipynb #0626f06e |
| 59 | +def read_nb(path): |
| 60 | + "Return notebook at `path`" |
| 61 | + res = dict2nb(_read_json(path, encoding='utf-8')) |
| 62 | + res['path_'] = str(path) |
| 63 | + return res |
| 64 | + |
| 65 | +# %% ../nbs/13_nbio.ipynb #c86fe311 |
| 66 | +def mk_cell(text, # `source` attr in cell |
| 67 | + cell_type='code', # `cell_type` attr in cell |
| 68 | + **kwargs): # any other attrs to add to cell |
| 69 | + "Create an `NbCell` containing `text`" |
| 70 | + assert cell_type in {'code', 'markdown', 'raw'} |
| 71 | + if 'metadata' not in kwargs: kwargs['metadata']={} |
| 72 | + if cell_type == 'code': |
| 73 | + kwargs['outputs']=[] |
| 74 | + kwargs['execution_count']=0 |
| 75 | + return NbCell(0, dict(cell_type=cell_type, source=text, directives_={}, **kwargs)) |
| 76 | + |
| 77 | +# %% ../nbs/13_nbio.ipynb #e7af3290 |
| 78 | +def new_nb(cells=None, meta=None, nbformat=4, nbformat_minor=5): |
| 79 | + "Returns an empty new notebook" |
| 80 | + cells = [o if isinstance(o,dict) else mk_cell(o) for o in cells] |
| 81 | + return dict2nb(cells=cells or [],metadata=meta or {},nbformat=nbformat,nbformat_minor=nbformat_minor) |
| 82 | + |
| 83 | +# %% ../nbs/13_nbio.ipynb #7c7bab22 |
| 84 | +def nb2dict(d, k=None): |
| 85 | + "Convert parsed notebook to `dict`" |
| 86 | + if k=='source': return d.splitlines(keepends=True) |
| 87 | + if isinstance(d, list): return list(map(nb2dict,d)) |
| 88 | + if not isinstance(d, dict): return d |
| 89 | + return dict(**{k:nb2dict(v,k) for k,v in d.items() if k[-1] != '_'}) |
| 90 | + |
| 91 | +# %% ../nbs/13_nbio.ipynb #21ffe533 |
| 92 | +def nb2str(nb): |
| 93 | + "Convert `nb` to a `str`" |
| 94 | + if isinstance(nb, (AttrDict,list)): nb = nb2dict(nb) |
| 95 | + return dumps(nb, sort_keys=True, indent=1, ensure_ascii=False) + "\n" |
| 96 | + |
| 97 | +# %% ../nbs/13_nbio.ipynb #d979e25a |
| 98 | +def write_nb(nb, path): |
| 99 | + "Write `nb` to `path`" |
| 100 | + new = nb2str(nb) |
| 101 | + path = Path(path) |
| 102 | + old = Path(path).read_text(encoding='utf-8') if path.exists() else None |
| 103 | + if new!=old: |
| 104 | + with open(path, 'w', encoding='utf-8') as f: f.write(new) |
0 commit comments