Skip to content

Instantly share code, notes, and snippets.

@bollwyvl
Last active March 27, 2020 02:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bollwyvl/97f9fc665c10db7ad3e6295490f30493 to your computer and use it in GitHub Desktop.
Save bollwyvl/97f9fc665c10db7ad3e6295490f30493 to your computer and use it in GitHub Desktop.

yaml-notebook-contents

Binder

A dirty hack to write .ipynb as YAML instead of JSON. A more thorough implementation would demand .ipynb.yml, but proxy the file naming out the manager.

There's really no reason to use this

  • open notebook/lab
  • make a notebook
  • save it
  • view it with Editor
    • Lab's default JSON viewer won't work
name: yamlcontents
channels:
- conda-forge
dependencies:
- jupyterlab >=2
- ruamel.yaml >=0.16
- ujson
- python >=3.7,<3.8.0a0
import os
import ujson as json
from tornado.web import HTTPError
import traitlets
import nbformat
from ruamel.yaml import YAML
from notebook.services.contents.largefilemanager import LargeFileManager
from notebook.services.contents.fileio import path_to_intermediate, path_to_invalid, replace_file
class YamlContentsManager(LargeFileManager):
yaml: YAML = traitlets.Instance(YAML)
@traitlets.default("yaml")
def _default_yaml(self):
yaml = YAML(typ='safe')
yaml.default_flow_style = False
return yaml
def _save_notebook(self, os_path, nb):
"""Save a notebook to an os_path."""
nb_json = nbformat.writes(nb, version=nbformat.NO_CONVERT)
yaml = self.yaml.load(nb_json)
with self.atomic_writing(os_path, encoding='utf-8') as f:
self.yaml.dump(yaml, f)
def _read_notebook(self, os_path, as_version=4):
"""Read a notebook from an os path."""
with self.open(os_path, 'r', encoding='utf-8') as f:
try:
nb_json = self.yaml.load(f.read() or "{}")
return nbformat.from_dict(nb_json)
except Exception as e:
e_orig = e
# If use_atomic_writing is enabled, we'll guess that it was also
# enabled when this notebook was written and look for a valid
# atomic intermediate.
tmp_path = path_to_intermediate(os_path)
if not self.use_atomic_writing or not os.path.exists(tmp_path):
raise HTTPError(
400,
u"Unreadable Notebook: %s %r" % (os_path, e_orig),
)
# Move the bad file aside, restore the intermediate, and try again.
invalid_file = path_to_invalid(os_path)
replace_file(os_path, invalid_file)
replace_file(tmp_path, os_path)
return self._read_notebook(os_path, as_version)
c.NotebookApp.contents_manager_class = YamlContentsManager
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment