def test_save(self): resp = self.api.read('foo/a.ipynb') nbcontent = json.loads(resp.text)['content'] nb = from_dict(nbcontent) nb.cells.append(new_markdown_cell(u'Created by test ³')) nbmodel = {'content': nb, 'type': 'notebook'} resp = self.api.save('foo/a.ipynb', body=json.dumps(nbmodel)) nbcontent = self.api.read('foo/a.ipynb').json()['content'] newnb = from_dict(nbcontent) self.assertEqual(newnb.cells[0].source, u'Created by test ³')
def sanitize_outputs(self, outputs, skip_sanitize=('metadata', 'traceback', 'text/latex', 'prompt_number', 'output_type', 'name', 'execution_count' )): sanitized_outputs = [] for output in outputs: sanitized = {} for key in output.keys(): if key in skip_sanitize: sanitized[key] = output[key] else: if key == 'data': sanitized[key] = {} for data_key in output[key].keys(): # Filter the keys in the SUB-dictionary again if data_key in skip_sanitize: sanitized[key][data_key] = output[key][data_key] else: sanitized[key][data_key] = self.sanitize(output[key][data_key]) # Otherwise, just create a normal dictionary entry from # one of the keys of the dictionary else: # Create the dictionary entries on the fly, from the # existing ones to be compared sanitized[key] = self.sanitize(output[key]) sanitized_outputs.append(nbformat.from_dict(sanitized)) return sanitized_outputs
def test_checkpoints_follow_file(self): # Read initial file state orig = self.api.read('foo/a.ipynb') # Create a checkpoint of initial state r = self.api.new_checkpoint('foo/a.ipynb') cp1 = r.json() # Modify file and save nbcontent = json.loads(orig.text)['content'] nb = from_dict(nbcontent) hcell = new_markdown_cell('Created by test') nb.cells.append(hcell) nbmodel = {'content': nb, 'type': 'notebook'} self.api.save('foo/a.ipynb', body=json.dumps(nbmodel)) # Rename the file. self.api.rename('foo/a.ipynb', 'foo/z.ipynb') # Looking for checkpoints in the old location should yield no results. self.assertEqual(self.api.get_checkpoints('foo/a.ipynb').json(), []) # Looking for checkpoints in the new location should work. cps = self.api.get_checkpoints('foo/z.ipynb').json() self.assertEqual(cps, [cp1]) # Delete the file. The checkpoint should be deleted as well. self.api.delete('foo/z.ipynb') cps = self.api.get_checkpoints('foo/z.ipynb').json() self.assertEqual(cps, [])
def write_notebook(self, include_html=True): suffix = "_responses_with_names" if self.include_usernames else "_responses" nb_name = self.nb_name_stem + suffix output_file = os.path.join(PROCESSED_NOTEBOOK_DIR, nb_name + '.ipynb') html_output = os.path.join(PROCESSED_NOTEBOOK_DIR, nb_name + '.html') remove_duplicate_answers = not self.include_usernames filtered_cells = [] for prompt in self.question_prompts: filtered_cells += prompt.cells answers = prompt.answers_without_duplicates if remove_duplicate_answers else prompt.answers for gh_username, response_cells in answers.items(): if self.include_usernames: filtered_cells.append( NotebookUtils.markdown_heading_cell(self.gh_username_to_fullname(gh_username), 4)) filtered_cells.extend(response_cells) answer_book = deepcopy(self.template) answer_book['cells'] = filtered_cells nb = nbformat.from_dict(answer_book) print "Writing", output_file with io.open(output_file, 'wt') as fp: nbformat.write(nb, fp, version=4) if include_html: # TODO why is the following necessary? nb = nbformat.reads(nbformat.writes(nb, version=4), as_version=4) html_content, _ = nbconvert.export_html(nb) print "Writing", html_output with io.open(html_output, 'w') as fp: fp.write(html_content)
def main(): arguments = docopt(__doc__, version='nbgen 2.0') cmd = subprocess.run([arguments["<path>"]] + arguments["<arguments>"], stdout=subprocess.PIPE) cmd.check_returncode() cells = json.loads(cmd.stdout.decode("utf-8")) nb_dict = { "metadata": {}, "nbformat": 4, "nbformat_minor": 0, "cells": cells, } notebook = nbformat.from_dict(nb_dict) ep = ExecutePreprocessor(timeout=600, kernel_name='python3') ep.preprocess(notebook, {'metadata': {}}) if arguments["nb"]: nbformat.write(notebook, "{}.ipynb".format(arguments["<name>"])) elif arguments["slides"]: config = Config() reveal_cdn = "https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.3.0/" config.SlidesExporter.reveal_url_prefix = (arguments["--reveal"] or reveal_cdn) slides, __ = export_slides(nb=notebook, config=config) with open("{}.html".format(arguments["<name>"]), "w") as html_file: html_file.write(slides)
def setUp(self): if self.metadata is None: metadata = self.default_metadata else: metadata = self.metadata self.orig = nbformat.from_dict({ "nbformat": NBFORMAT_VERSION, "nbformat_minor": 0, "metadata": metadata, "cells": self.cells }) with tempfile.TemporaryDirectory() as d: ipynb0_name = d + "/0" rmd_name = d + "/1" ipynb1_name = d + "/2" with open(ipynb0_name, "w") as f: nbformat.write(self.orig, f) if self.use_rmd: ipyrmd.ipynb_to_rmd(ipynb0_name, rmd_name) ipyrmd.rmd_to_ipynb(rmd_name, ipynb1_name) else: ipyrmd.ipynb_to_spin(ipynb0_name, rmd_name) ipyrmd.spin_to_ipynb(rmd_name, ipynb1_name) with open(rmd_name) as f: self.rmd = f.read() with open(ipynb1_name) as f: self.roundtrip = nbformat.read(f, NBFORMAT_VERSION)
def post(self, format): exporter = get_exporter(format, config=self.config) model = self.get_json_body() name = model.get("name", "notebook.ipynb") nbnode = from_dict(model["content"]) try: output, resources = exporter.from_notebook_node( nbnode, resources={ "metadata": {"name": name[: name.rfind(".")]}, "config_dir": self.application.settings["config_dir"], }, ) except Exception as e: raise web.HTTPError(500, "nbconvert failed: %s" % e) if respond_zip(self, name, output, resources): return # MIME type if exporter.output_mimetype: self.set_header("Content-Type", "%s; charset=utf-8" % exporter.output_mimetype) self.finish(output)
def _runTest(self): kernel = 'python%d' % sys.version_info[0] cur_dir = os.path.dirname(self.nbfile) with open(self.nbfile) as f: nb = nbformat.read(f, as_version=4) if self.cov: covdict = {'cell_type': 'code', 'execution_count': 1, 'metadata': {'collapsed': True}, 'outputs': [], 'nbsphinx': 'hidden', 'source': 'import coverage\n' 'coverage.process_startup()\n' 'import sys\n' 'sys.path.append("{0}")\n'.format(cur_dir) } nb['cells'].insert(0, nbformat.from_dict(covdict)) exproc = ExecutePreprocessor(kernel_name=kernel, timeout=600) try: run_dir = os.getenv('WRADLIB_BUILD_DIR', cur_dir) exproc.preprocess(nb, {'metadata': {'path': run_dir}}) except CellExecutionError as e: raise e if self.cov: nb['cells'].pop(0) with io.open(self.nbfile, 'wt') as f: nbformat.write(nb, f) self.assertTrue(True)
def save(self, model, path=''): """Save the file model and return the model with no content.""" path = path.strip('/') if 'type' not in model: # pragma: no cover raise web.HTTPError(400, u'No file type provided') if ('content' not in model and model['type'] != 'directory'): # pragma: no cover raise web.HTTPError(400, u'No file content provided') self.run_pre_save_hook(model=model, path=path) os_path = self._get_os_path(path) self.log.debug("Saving %s", os_path) try: if model['type'] == 'notebook': file_ext = _file_extension(os_path) nb = nbformat.from_dict(model['content']) if file_ext == '.ipynb': self.check_and_sign(nb, path) self._save_notebook(os_path, nb) else: p = self._podoc lang = p.get_lang_for_file_ext(file_ext) p.convert(nb, source='notebook', target=lang, resources=None, # TODO output=os_path, ) # One checkpoint should always exist for notebooks. if not self.checkpoints.list_checkpoints(path): self.create_checkpoint(path) elif model['type'] == 'file': # Missing format will be handled internally by _save_file. self._save_file(os_path, model['content'], model.get('format')) elif model['type'] == 'directory': self._save_directory(os_path, model, path) else: # pragma: no cover raise web.HTTPError(400, "Unhandled contents type: %s" % model['type']) # noqa except web.HTTPError: # pragma: no cover raise except Exception as e: # pragma: no cover self.log.error(u'Error while saving file: %s %s', path, e, exc_info=True) # noqa raise web.HTTPError(500, u'Unexpected error while saving file: %s %s' % (path, e)) # noqa validation_message = None if model['type'] == 'notebook': self.validate_notebook_model(model) validation_message = model.get('message', None) model = self.get(path, content=False) if validation_message: # pragma: no cover model['message'] = validation_message self.run_post_save_hook(model=model, os_path=os_path) return model
def merge_notebooks(base, local, remote): """Merge changes introduced by notebooks local and remote from a shared ancestor base. Return new (partially) merged notebook and unapplied diffs from the local and remote side. """ merged, local_conflict_diffs, remote_conflict_diffs = merge(base, local, remote) merged = nbformat.from_dict(merged) return merged, local_conflict_diffs, remote_conflict_diffs
def add_codecell(self, code): self.nb.cells.append(nbformat.from_dict({ "cell_type": "code", "execution_count": None, "metadata": {}, "source": code.strip(), "outputs": [] }))
def save(self, model, path=''): """Save the file model and return the model with no content.""" import json path = path.strip('/') with self.library_context as l: b, f = self._file_from_path(l, path) if 'type' not in model: raise web.HTTPError(400, u'No file type provided') if 'content' not in model and model['type'] != 'directory': raise web.HTTPError(400, u'No file content provided') self.run_pre_save_hook(model=model, path=f.record.id) if not f.record.size: f.record.update_contents(f.default, 'application/json') else: f.record.update_contents(json.dumps(model['content']), 'application/json') try: if model['type'] == 'notebook': nb = nbformat.from_dict(model['content']) self.check_and_sign(nb, path) # One checkpoint should always exist for notebooks. if not self.checkpoints.list_checkpoints(path): self.create_checkpoint(path) elif model['type'] == 'file': pass elif model['type'] == 'directory': pass else: raise web.HTTPError(400, "Unhandled contents type: %s" % model['type']) except web.HTTPError: raise except Exception as e: self.log.error(u'Error while saving file: %s %s', path, e, exc_info=True) raise web.HTTPError(500, u'Unexpected error while saving file: %s %s' % (path, e)) validation_message = None if model['type'] == 'notebook': self.validate_notebook_model(model) validation_message = model.get('message', None) model = self.get(path, content=False) if validation_message: model['message'] = validation_message return model
def post(self, *args, **kwargs): # Given a list of nb cells, save to ipynb format v4 filepath = self.get_argument('filepath') if filepath[-6:] != '.ipynb': filepath = '{}.ipynb'.format(filepath) cells = json.loads(self.request.body)['cells'] nb_cells = [] for cell in cells: cinput = cell.get('input', '') coutput = cell.get('output', '') ctype = cell.get('type') tmp_cell = { "cell_type": ctype, "metadata": { "collapsed" : False, # whether the output of the cell is collapsed "autoscroll": "auto", # any of true, false or "auto" }, "source": cinput, } if ctype=='code': tmp_cell.update({ "execution_count": None, "outputs": [{ "output_type" : "stream", "name" : "stdout", "text" : coutput, }] }) nb_cells.append(tmp_cell) base_nb = { 'metadata': { 'kernelspec': { 'name': 'bash', "display_name": "Bash", "language": "bash" }, "language_info": { "codemirror_mode": "shell", "file_extension": ".sh", "mimetype": "text/x-sh", "name": "bash" } }, 'nbformat': 4, 'nbformat_minor': 0, 'cells': nb_cells } try: nbformat.validate(base_nb,version=4) nb = nbformat.from_dict(base_nb) nbformat.write(nb,filepath) self.write({'res':'File saved to {}'.format(filepath)}) except nbformat.ValidationError: self.set_status(400) return
def _save_notebook(self, model, key): nbcontents = from_dict(model['content']) self.check_and_sign(nbcontents, key) content = self._nb_encode_b64(nbcontents) s3file = S3File(key, None, 'application/octet-stream') self.write_content(content, s3file) self.validate_notebook_model(model) return model.get('message')
def write_markdown(self, text): if self.nb.cells[-1].cell_type != "markdown": self.nb.cells.append(nbformat.from_dict({ "cell_type": "markdown", "metadata": {}, "source": [] })) self.nb.cells[-1].source.append( text.replace("\n", "\n" + " " * self.indent) )
def _save_notebook(self, model, path): """ Save a notebook. Returns a validation message. """ with fileManager.session_scope() as session: nb_contents = nbformat.from_dict(model['content']) self.check_and_sign(nb_contents, path) self.fm.save_file(path, writes_base64(nb_contents),session) # It's awkward that this writes to the model instead of returning. self.validate_notebook_model(model) return model.get('message')
def compute_imports(self): if self.lookup is None: notebook = nbformat.from_dict(self.contents['notebook']) code = "" for cell in notebook.cells: if cell.cell_type == "code": code += "\n" + cell.source self.lookup = ImportsLookup() self.lookup.visit(ast.parse(self.ast_parse(code))) self.contents['notebook']['metadata']['pixiedust'].update({ "imports": {p[0]:{"version":p[1],"install":p[2]} for p in self.lookup.imports} })
def save(self, model, path=''): """Save the file model and return the model with no content.""" path = path.strip('/') if 'type' not in model: raise web.HTTPError(400, u'No file type provided') if 'content' not in model and model['type'] != 'directory': raise web.HTTPError(400, u'No file content provided') self.log.debug("Saving %s", path) self.run_pre_save_hook(model=model, path=path) try: if model['type'] == 'notebook': nb = nbformat.from_dict(model['content']) self.check_and_sign(nb, path) self._save_notebook(path, nb) # TODO: decide how to handle checkpoints for non-local fs. # For now, checkpoint pathing seems to be borked. # One checkpoint should always exist for notebooks. # if not self.checkpoints.list_checkpoints(path): # self.create_checkpoint(path) elif model['type'] == 'file': # Missing format will be handled internally by _save_file. self._save_file(path, model['content'], model.get('format')) elif model['type'] == 'directory': self._save_directory(path, model) else: raise web.HTTPError( 400, "Unhandled contents type: %s" % model['type']) except web.HTTPError: raise except Exception as e: self.log.error(u'Error while saving file: %s %s', path, e, exc_info=True) raise web.HTTPError( 500, u'Unexpected error while saving file: %s %s' % (path, e)) validation_message = None if model['type'] == 'notebook': self.validate_notebook_model(model) validation_message = model.get('message', None) model = self.get(path, content=False) if validation_message: model['message'] = validation_message self.run_post_save_hook(model=model, os_path=path) return model
def test_nb(fn, flags=None): "Execute tests in notebook in `fn` with `flags`" os.environ["IN_TEST"] = '1' if flags is None: flags = [] try: nb = read_nb(fn) for f in get_all_flags(nb['cells']): if f not in flags: return ep = NoExportPreprocessor(flags, timeout=600, kernel_name='python3') pnb = nbformat.from_dict(nb) ep.preprocess(pnb, {}) finally: os.environ.pop("IN_TEST")
def save(self, model, path): assert isinstance(path, str) try: seahorse_notebook_path = SeahorseNotebookPath.deserialize(path) except SeahorseNotebookPath.DeserializationFailed as e: raise web.HTTPError(400, str(e)) if model['type'] != "notebook": model['message'] = "Cannot save object of type: {}".format(model['type']) return model content_json = writes(from_dict(model['content']), NBFORMAT_VERSION) return self._save_notebook(seahorse_notebook_path, content_json, False)
def make_cell(cell_type, **kwargs): """Returns a NotebookNode object populated with kwargs. cell_type should be either 'markdown' or 'code'""" defaults = dict( cell_type=cell_type, metadata={}, source=[], ) if cell_type == "code": defaults['execution_count'] = None defaults['outputs'] = [] defaults.update(kwargs) return nbformat.from_dict(defaults)
def convert_notebook(notebook_data: dict, exporter_type: str, config: dict = None) -> dict: notebook = nbformat.from_dict(notebook_data) exporter = create_exporter(exporter_type, config) body, resources = exporter.from_notebook_node(notebook) return { 'body': body, 'mime-type': get_mime_response(exporter), 'resources': resources }
def recombine_output(cell_dir, i, info): if info in {'stdout', 'stderr'}: with (cell_dir / ('output%d.txt' % i)).open() as f: return nbf.v4.new_output('stream', name=info, text=f.read()) elif info == 'error': with (cell_dir / ('error%d.json' % i)).open() as f: err_data = json.load(f) return nbf.v4.new_output('error', **err_data) else: m = _exec_result_re.search(info) if m: info = info[:-(len(m.group(0)) + 1)] op = nbf.v4.new_output('execute_result', execution_count=int(m.group(1))) else: op = nbf.v4.new_output('display_data') mimebundle = {} for mimetype in info.split(", "): file = "output{}{}".format(i, _mime_to_ext[mimetype]) if _is_binary(mimetype): with (cell_dir / file).open('rb') as f: mimebundle[mimetype] = base64.b64encode( f.read()).decode('ascii') else: with (cell_dir / file).open() as f: mimebundle[mimetype] = f.read() op.data = nbf.from_dict(mimebundle) metadata_file = cell_dir / "output{}-metadata.json".format(i) if metadata_file.exists(): with metadata_file.open() as f: op.metadata = nbf.from_dict(json.load(f)) return op
def save(self, model, path=''): if (model["type"] == "notebook" or path.endswith(".ipynb")): path = path.strip('/') nb = nbf.from_dict(model["content"]) directory = pathlib.Path(path + '.exploded') if directory.exists(): shutil.rmtree(path + '.exploded') directory.mkdir() self.log.info(model) explode(nb, directory) return self.get(path, content=False) return super(NBExplodeManager, self).save(model, path)
async def test_save(fetch, contents): r = await fetch( 'api', 'contents', 'foo/a.ipynb', method='GET' ) model = json.loads(r.body.decode()) nbmodel = model['content'] nb = from_dict(nbmodel) nb.cells.append(new_markdown_cell('Created by test ³')) nbmodel = {'content': nb, 'type': 'notebook'} r = await fetch( 'api', 'contents', 'foo/a.ipynb', method='PUT', body=json.dumps(nbmodel) ) # Round trip. r = await fetch( 'api', 'contents', 'foo/a.ipynb', method='GET' ) model = json.loads(r.body.decode()) newnb = from_dict(model['content']) assert newnb.cells[0].source == 'Created by test ³'
def test_nb(fn, flags=None): "Execute `nb` (or only the `show_doc` cells) with `metadata`" os.environ["IN_TEST"] = '1' try: nb = read_nb(fn) all_flag = check_all_flag(nb['cells']) if all_flag is not None and all_flag not in L(flags): return mod = find_default_export(nb['cells']) if mod is not None: nb['cells'].insert(0, _add_import_cell(mod)) ep = NoExportPreprocessor(L(flags), timeout=600, kernel_name='python3') pnb = nbformat.from_dict(nb) ep.preprocess(pnb) finally: os.environ.pop("IN_TEST")
def post(self, name): payload = self.request.body.decode('utf-8') try: notebook = nbformat.from_dict(json.loads(payload)) pixieapp_model = yield NotebookMgr.instance().publish(name, notebook) if "url" in pixieapp_model: server = self.request.protocol + "://" + self.request.host pixieapp_model["url"] = server + pixieapp_model["url"] self.set_status(200) self.write(json.dumps(pixieapp_model)) self.finish() except Exception as exc: app_log.error(traceback.print_exc()) raise web.HTTPError(400, u'Publish PixieApp error: {}'.format(exc))
def save(self, model, path): """ Save a file or directory model to path. Should return the saved model with no content. Save implementations should call self.run_pre_save_hook(model=model, path=path) prior to writing any data. """ path = path.strip('/') girder_path = self._get_girder_path(path) if 'type' not in model: raise web.HTTPError(400, u'No file type provided') if 'content' not in model and model['type'] != 'directory': raise web.HTTPError(400, u'No file content provided') try: if model['type'] == 'notebook': nb = nbformat.from_dict(model['content']) self.check_and_sign(nb, path) nb = nbformat.writes(nb, version=nbformat.NO_CONVERT) self._upload_to_path(nb, 'application/json', 'text', girder_path) elif model['type'] == 'file': self._upload_to_path(model.get('content'), model.get('mimetype'), model.get('format'), girder_path) elif model['type'] == 'directory': self._create_folders(girder_path) else: raise web.HTTPError( 400, "Unhandled contents type: %s" % model['type']) except web.HTTPError: raise except Exception as e: self.log.error(u'Error while saving file: %s %s', path, e, exc_info=True) raise web.HTTPError( 500, u'Unexpected error while saving file: %s %s' % (path, e)) validation_message = None if model['type'] == 'notebook': self.validate_notebook_model(model) validation_message = model.get('message', None) model = self.get(path, content=False) model['message'] = validation_message return model
def extract_title_ipynb(cell0): source = cell0["source"] pattern = r"[Tt]itle: (.*)?\n" match = re.search(pattern, source) try: title = match.group(1) except: title = "(Lesson title not found)" newcell = { 'cell_type': 'markdown', 'metadata': {}, 'source': '# {}'.format(title) } return nbformat.from_dict(newcell)
def test_checkpoints(self): resp = self.api.read('foo/a.ipynb') r = self.api.new_checkpoint('foo/a.ipynb') self.assertEqual(r.status_code, 201) cp1 = r.json() self.assertEqual(set(cp1), {'id', 'last_modified'}) self.assertEqual(r.headers['Location'].split('/')[-1], cp1['id']) # Modify it nbcontent = json.loads(resp.text)['content'] nb = from_dict(nbcontent) hcell = new_markdown_cell('Created by test') nb.cells.append(hcell) # Save nbmodel = {'content': nb, 'type': 'notebook'} resp = self.api.save('foo/a.ipynb', body=json.dumps(nbmodel)) # List checkpoints cps = self.api.get_checkpoints('foo/a.ipynb').json() self.assertEqual(cps, [cp1]) nbcontent = self.api.read('foo/a.ipynb').json()['content'] nb = from_dict(nbcontent) self.assertEqual(nb.cells[0].source, 'Created by test') # Restore cp1 r = self.api.restore_checkpoint('foo/a.ipynb', cp1['id']) self.assertEqual(r.status_code, 204) nbcontent = self.api.read('foo/a.ipynb').json()['content'] nb = from_dict(nbcontent) self.assertEqual(nb.cells, []) # Delete cp1 r = self.api.delete_checkpoint('foo/a.ipynb', cp1['id']) self.assertEqual(r.status_code, 204) cps = self.api.get_checkpoints('foo/a.ipynb').json() self.assertEqual(cps, [])
def test_checkpoints(self): resp = self.api.read('foo/a.ipynb') r = self.api.new_checkpoint('foo/a.ipynb') self.assertEqual(r.status_code, 201) cp1 = r.json() self.assertEqual(set(cp1), {'id', 'last_modified'}) self.assertEqual(r.headers['Location'].split('/')[-1], cp1['id']) # Modify it nbcontent = json.loads(resp.text)['content'] nb = from_dict(nbcontent) hcell = new_markdown_cell('Created by test') nb.cells.append(hcell) # Save nbmodel= {'content': nb, 'type': 'notebook'} resp = self.api.save('foo/a.ipynb', body=json.dumps(nbmodel)) # List checkpoints cps = self.api.get_checkpoints('foo/a.ipynb').json() self.assertEqual(cps, [cp1]) nbcontent = self.api.read('foo/a.ipynb').json()['content'] nb = from_dict(nbcontent) self.assertEqual(nb.cells[0].source, 'Created by test') # Restore cp1 r = self.api.restore_checkpoint('foo/a.ipynb', cp1['id']) self.assertEqual(r.status_code, 204) nbcontent = self.api.read('foo/a.ipynb').json()['content'] nb = from_dict(nbcontent) self.assertEqual(nb.cells, []) # Delete cp1 r = self.api.delete_checkpoint('foo/a.ipynb', cp1['id']) self.assertEqual(r.status_code, 204) cps = self.api.get_checkpoints('foo/a.ipynb').json() self.assertEqual(cps, [])
def to_nb_json(content, version_specific=False): if not version_specific: return nbformat.from_dict(content) else: # Not sure why this is needed instead of from_dict, sometimes versions = { 1: v1, 2: v2, 3: v3, 4: v4, } major = content.get('nbformat', 1) minor = content.get('nbformat_minor', 0) nb = versions[major].to_notebook_json(content, minor=minor) return nb
def save_notebook(self, model, name='', path=''): """Save the notebook model and return the model with no content.""" path = path.strip('/') if 'content' not in model: raise web.HTTPError(400, u'No notebook JSON data provided') if not path: raise web.HTTPError(400, u'We require path for saving.') nb = nbformat.from_dict(model['content']) gist = self._get_gist(name, path) if gist is None: tags = parse_tags(name) if path: tags.append(path) content = nbformat.writes(nb, version=nbformat.NO_CONVERT) gist = self.gisthub.create_gist(name, tags, content) # One checkpoint should always exist #if self.notebook_exists(name, path) and not self.list_checkpoints(name, path): # self.create_checkpoint(name, path) new_path = model.get('path', path).strip('/') new_name = model.get('name', name) if path != new_path: raise web.HTTPError(400, u'Gist backend does not support path change') # remove [gist_id] if we're being sent old key_name gist.name = gist.strip_gist_id(new_name) gist.notebook_content = nb self.check_and_sign(nb, self.fullpath(new_path, new_name)) if 'name' in nb['metadata']: nb['metadata']['name'] = u'' try: self.log.debug("Autosaving notebook %s %s", path, name) self.gisthub.save(gist) except Exception as e: raise web.HTTPError(400, u'Unexpected error while autosaving notebook: %s %s %s' % (path, name, e)) # NOTE: since gist.name might not have [gist_id] suffix on rename # we use gist.key_name model = self.get_notebook(gist.key_name, new_path, content=False) return model
def get_references(self): """ Get references in all the cells and build a bibliography in the last cell. """ logger.info(' Rewriting references') for cell in self.cells: if cell.cell_type == 'markdown': cell.find_reference_keys(self.refs, keys=self.keys) if '## References' in self.cells[-1].source: self.cells = self.cells[:-1] if self.keys: self.cells.append(JupyterCell.as_references(self.refs, self.keys)) self.contents['cells'] = [c.to_dict() for c in self.cells] self.contents = nbformat.from_dict(self.contents)
def save(self, model, path=""): """Save the file model and return the model with no content.""" path = path.strip("/") if "type" not in model: raise web.HTTPError(400, u"No file type provided") if "content" not in model and model["type"] != "directory": raise web.HTTPError(400, u"No file content provided") os_path = self._get_os_path(path) self.log.debug("Saving %s", os_path) self.run_pre_save_hook(model=model, path=path) try: if model["type"] == "notebook": nb = nbformat.from_dict(model["content"]) self.check_and_sign(nb, path) self._save_notebook(os_path, nb) # One checkpoint should always exist for notebooks. if not self.checkpoints.list_checkpoints(path): self.create_checkpoint(path) elif model["type"] == "file": # Missing format will be handled internally by _save_file. self._save_file(os_path, model["content"], model.get("format")) elif model["type"] == "directory": self._save_directory(os_path, model, path) else: raise web.HTTPError(400, "Unhandled contents type: %s" % model["type"]) except web.HTTPError: raise except Exception as e: self.log.error(u"Error while saving file: %s %s", path, e, exc_info=True) raise web.HTTPError(500, u"Unexpected error while saving file: %s %s" % (path, e)) validation_message = None if model["type"] == "notebook": self.validate_notebook_model(model) validation_message = model.get("message", None) model = self.get(path, content=False) if validation_message: model["message"] = validation_message self.run_post_save_hook(model=model, os_path=os_path) return model
def save(self, model, path): """ save an entry in the store this is called by the contents engine to store a notebook """ om = self.omega path = unquote(path).strip('/') type = model.get('type') name = model.get('name') self.run_pre_save_hook(model=model, path=path) if type is None: raise web.HTTPError(400, u'No file type provided') try: if type == 'notebook': content = model.get('content') if content is None: raise web.HTTPError(400, u'No file content provided') nb = nbformat.from_dict(model['content']) self.check_and_sign(nb, path) self.omega.jobs.put(nb, path) self.validate_notebook_model(model) validation_message = model.get('message', None) model = self.get(path, content=False, type=type) if validation_message: model['message'] = validation_message elif type == 'directory': ph_name = '{path}/{self._dir_placeholder}'.format( **locals()).strip('/') self.omega.jobs.create("#placeholder", ph_name) model = self.get(path, content=False, type=type) model['content'] = None model['format'] = None validation_message = None else: raise web.HTTPError( 400, "Unhandled contents type: %s" % model['type']) except web.HTTPError: raise except Exception as e: self.log.error(u'Error while saving file: %s %s', path, e, exc_info=True) raise web.HTTPError( 500, u'Unexpected error while saving file: %s %s' % (path, e)) return model
def save(self, model, path=''): """Save the file model and return the model with no content.""" path = path.strip('/') if 'type' not in model: raise web.HTTPError(400, u'No file type provided') if 'content' not in model and model['type'] != 'directory': raise web.HTTPError(400, u'No file content provided') os_path = self._get_os_path(path) self.log.debug("Saving %s", os_path) self.run_pre_save_hook(model=model, path=path) try: if model['type'] == 'notebook': nb = nbformat.from_dict(model['content']) self.check_and_sign(nb, path) self._save_notebook(os_path, nb) # One checkpoint should always exist for notebooks. if not self.checkpoints.list_checkpoints(path): self.create_checkpoint(path) elif model['type'] == 'file': # Missing format will be handled internally by _save_file. self._save_file(os_path, model['content'], model.get('format')) elif model['type'] == 'directory': self._save_directory(os_path, model, path) else: raise web.HTTPError(400, "Unhandled contents type: %s" % model['type']) except web.HTTPError: raise except Exception as e: self.log.error(u'Error while saving file: %s %s', path, e, exc_info=True) raise web.HTTPError(500, u'Unexpected error while saving file: %s %s' % (path, e)) validation_message = None if model['type'] == 'notebook': self.validate_notebook_model(model) validation_message = model.get('message', None) model = self.get(path, content=False) if validation_message: model['message'] = validation_message self.run_post_save_hook(model=model, os_path=os_path) return model
def recombine(directory): directory = pathlib.Path(directory) with (directory / 'metadata.json').open() as f: metadata = json.load(f) nb = nbf.v4.new_notebook(metadata=metadata) with (directory / 'cells_sequence').open() as f: cells_sequence = f.read().splitlines() for cell_id in cells_sequence: cell_dir = directory / cell_id source_file = list(cell_dir.glob('source.*'))[0] if source_file.suffix == '.md': with source_file.open() as f: cell = nbf.v4.new_markdown_cell(f.read()) elif source_file.suffix == '.txt': with source_file.open() as f: cell = nbf.NotebookNode(cell_type='raw', source=f.read(), metadata=nbf.NotebookNode()) else: with source_file.open() as f: cell = nbf.v4.new_code_cell(f.read()) nb.cells.append(cell) if (cell_dir / 'metadata.json').exists(): with (cell_dir / 'metadata.json').open() as f: cell.metadata = nbf.from_dict(json.load(f)) cell.metadata['nbexplode_cell_id'] = cell_id if not (cell_dir / 'outputs_sequence').exists(): continue with (cell_dir / 'outputs_sequence').open() as f: outputs_seq = f.read().splitlines() cell.outputs = [ recombine_output(cell_dir, i, info) for (i, info) in enumerate(outputs_seq, start=1) ] return nb
def test_reporting(line, title, input, expected): dct = yaml.safe_load(input) dct.setdefault("metadata", {}) ntbk = nbformat.from_dict(dct) md, env, tokens = nb_to_tokens(ntbk, MdParserConfig(), "default") document = make_document("source/path") messages = [] def observer(msg_node): if msg_node["level"] > 1: messages.append(msg_node.astext()) document.reporter.attach_observer(observer) with mock_sphinx_env(document=document): tokens_to_docutils(md, env, tokens, document) assert "\n".join(messages).rstrip() == expected.rstrip()
def save(self, model, path): """Save the file or directory and return the model with no content. Save implementations should call self.run_pre_save_hook(model=model, path=path) prior to writing any data. """ path = path.strip('/') if 'type' not in model: raise HTTPError(400, u'No IPython model type provided') if model['type'] != 'notebook': raise HTTPError(400, u'We currently only support saving Narratives!') if 'content' not in model and model['type'] != 'directory': raise HTTPError( 400, u'No Narrative content found while trying to save') self.log.debug(u"writing Narrative %s." % path) nb = nbformat.from_dict(model['content']) self.check_and_sign(nb, path) try: result = self.write_narrative(self._obj_ref_from_path(path), nb, self.get_userid()) new_id = u"ws.%s.obj.%s" % (result[1], result[2]) util.kbase_env.narrative = new_id nb = result[0] self.validate_notebook_model(model) validation_message = model.get(u'message', None) model = self.get(path, content=False) if validation_message: model[u'message'] = validation_message self.narrative_logger.narrative_save( u'{}/{}'.format(result[1], result[2]), result[3]) return model except PermissionsError as err: raise HTTPError(403, err.message) except Exception as err: raise HTTPError( 500, u'An error occurred while saving your Narrative: {}'.format( err))
def main_merge(args): bfn = args.base lfn = args.local rfn = args.remote mfn = args.output for fn in (bfn, lfn, rfn): if not os.path.exists(fn): print("Cannot find file '{}'".format(fn)) return 1 b = nbformat.read(bfn, as_version=4) l = nbformat.read(lfn, as_version=4) r = nbformat.read(rfn, as_version=4) m, decisions = merge_notebooks(b, l, r, args) conflicted = [d for d in decisions if d.conflict] returncode = 1 if conflicted else 0 if conflicted: print("Conflicts occured during merge operation.") else: print("Merge completed successfully with no unresolvable conflicts.") if mfn: # Add remaining conflicts to metadata if conflicted: m["metadata"]["nbdime-conflicts"] = conflicted # Write partial or fully completed merge to given foo.ipynb filename with open(mfn, "wb") as mf: # FIXME: We currently write this way as git needs \n line endings, # when used as merge driver. However, we should write using OS # line endings otherwise. nb = nbformat.from_dict(m) s = nbformat.writes(nb) + u'\n' mf.write(s.encode()) else: # FIXME: Display conflicts in a useful way if conflicted: print("Conflicts:") pprint(conflicted) print("Merge result:") pprint(m) return returncode
def run_notebook(notebook, root_path=".", timeout=30, prerun=None): """Run a notebook in Jupyter This function will copy all of the files in ``root_path`` to a temporary directory, run the notebook and then return a ``NotebookResult`` object containing the outputs for each cell. The notebook is run in a separate process and only objects that are serializable will be returned in their entirety, otherwise the string representation will be returned instead. Parameters ---------- notebook : str The notebook to run relative to ``root_path`` root_path : str The root notebook folder (default ".") timeout : int Length of time to run the notebook in seconds (default 30) prerun : function Function to run prior to starting the notebook, takes the temporary copy of root_path as a parameter """ import nbformat from nbconvert.preprocessors import ExecutePreprocessor with tempfile.TemporaryDirectory() as td: workdir = os.path.join(td, 'work') notebook_dir = os.path.join(workdir, os.path.dirname(notebook)) shutil.copytree(root_path, workdir) if prerun is not None: prerun(workdir) fullpath = os.path.join(workdir, notebook) with open(fullpath, "r") as f: nb = nbformat.read(f, as_version=4) ep = ExecutePreprocessor(kernel_name='python3', timeout=timeout) code_cells = [c for c in nb['cells'] if c['cell_type'] == 'code'] nb['cells'].append( nbformat.from_dict({ 'cell_type': 'code', 'metadata': {}, 'source': _create_code(len(code_cells)) })) ep.preprocess(nb, {'metadata': {'path': notebook_dir}}) return NotebookResult(nb)
def _nb_node_from_nb_node_and_cells(nb_node: nbformat.NotebookNode, cells: Union[nbformat.NotebookNode, List[nbformat.NotebookNode]] ) -> nbformat.NotebookNode: if not isinstance(cells, list): cells = [cells] # get other data from original notebook nb_dict = dict( cells=cells, metadata=nb_node['metadata'], nbformat=nb_node['nbformat'], nbformat_minor=nb_node['nbformat_minor'] ) nbformat.validate(nb_dict) small_nb = nbformat.from_dict(nb_dict) return small_nb
def _save_notebook(self, db, model, path): """ Save a notebook. Returns a validation message. """ nb_contents = from_dict(model['content']) self.check_and_sign(nb_contents, path) save_file( db, self.user_id, path, writes_base64(nb_contents), self.max_file_size_bytes, ) # It's awkward that this writes to the model instead of returning. self.validate_notebook_model(model) return model.get('message')
def merge_notebooks(base, local, remote, args): """Merge changes introduced by notebooks local and remote from a shared ancestor base. Return new (partially) merged notebook and unapplied diffs from the local and remote side. """ # Compute notebook specific diffs local_diffs = diff_notebooks(base, local) remote_diffs = diff_notebooks(base, remote) # Execute a generic merge operation merged, local_diffs, remote_diffs = merge_with_diff(base, local, remote, local_diffs, remote_diffs) # Try to resolve conflicts based on behavioural options resolved, local_diffs, remote_diffs = \ autoresolve_notebook_conflicts(merged, local_diffs, remote_diffs, args) resolved = nbformat.from_dict(resolved) return resolved, local_diffs, remote_diffs
def compute_imports(self): if self.lookup is None: notebook = nbformat.from_dict(self.contents['notebook']) code = "" for cell in notebook.cells: if cell.cell_type == "code": code += "\n" + cell.source self.lookup = ImportsLookup() self.lookup.visit(ast.parse(self.ast_parse(code))) self.contents['notebook']['metadata']['pixiedust'].update({ "imports": { p[0]: { "version": p[1], "install": p[2] } for p in self.lookup.imports } })
def __init__(self, document, app, docpath): nodes.NodeVisitor.__init__(self, document) self.section_level = 0 self.indent = 0 self.paragraph_prefix = "" self.app = app self.config = app.config self.docpath = docpath self.nb = nbformat.from_dict({ "cells": [], "metadata": {}, "nbformat": nbformat.current_nbformat, "nbformat_minor": nbformat.current_nbformat_minor }) if self.config.nbexport_pre_code: self.write_code(self.config.nbexport_pre_code)
def overwrite(self, model, path): """Overwrite a model back to the original function """ resource = self._get(path) resource.interactive.overwrite(nbformat.from_dict(model['content'])) return { 'name': resource.task.name, 'type': 'notebook', 'path': path, 'writable': True, 'created': datetime.datetime.now(), 'last_modified': datetime.datetime.now(), 'content': None, 'mimetype': 'text/x-python', 'format': None, }
def contribution(request, collection, cid): material = {} if request.user.is_authenticated(): API_KEY = request.user.api_key ENDPOINT = request.build_absolute_uri(get_endpoint()) with MPContribsRester(API_KEY, endpoint=ENDPOINT) as mpr: material = mpr.query_contributions(criteria={'_id': ObjectId(cid)}, collection=collection, projection={'_id': 0})[0] material['nb'], material['nb_js'] = export_notebook( nbformat.from_dict(material['nb']), cid, set_div_names=False, separate_script=True) material['detail_id'] = collection[:-1] ctx = RequestContext(request, {'material': jsanitize(material)}) return render_to_response("mpcontribs_explorer_contribution.html", locals(), ctx)
def merge_notebooks(base, local, remote, args): """Merge changes introduced by notebooks local and remote from a shared ancestor base. Return new (partially) merged notebook and unapplied diffs from the local and remote side. """ # Compute notebook specific diffs local_diffs = diff_notebooks(base, local) remote_diffs = diff_notebooks(base, remote) # Execute a generic merge operation merged, local_diffs, remote_diffs = merge_with_diff( base, local, remote, local_diffs, remote_diffs) # Try to resolve conflicts based on behavioural options resolved, local_diffs, remote_diffs = \ autoresolve_notebook_conflicts(merged, local_diffs, remote_diffs, args) resolved = nbformat.from_dict(resolved) return resolved, local_diffs, remote_diffs
def save(self, model, path): """ save an entry in the store this is called by the contents engine to store a notebook """ path = path.strip('/') if 'type' not in model: raise web.HTTPError(400, u'No file type provided') if 'content' not in model and model['type'] != 'directory': raise web.HTTPError(400, u'No file content provided') self.run_pre_save_hook(model=model, path=path) om = self.omega try: if model['type'] == 'notebook': nb = nbformat.from_dict(model['content']) self.check_and_sign(nb, path) self.omega.jobs.put(nb, path) else: raise web.HTTPError( 400, "Unhandled contents type: %s" % model['type']) except web.HTTPError: raise except Exception as e: self.log.error(u'Error while saving file: %s %s', path, e, exc_info=True) raise web.HTTPError( 500, u'Unexpected error while saving file: %s %s' % (path, e)) validation_message = None if model['type'] == 'notebook': self.validate_notebook_model(model) validation_message = model.get('message', None) model = self.get(path, content=False) if validation_message: model['message'] = validation_message return model
def _code_to_notebook(self, code, path): import nbformat nb = nbformat.v4.new_notebook() for m in re.finditer(NOTEBOOK_PATTERN, code, re.MULTILINE | re.DOTALL): cell = { 'cell_type': m.group('cell_type'), 'source': m.group('source'), 'metadata': {} } if m.group('cell_type') == 'code': cell['execution_count'] = 0 cell['outputs'] = [] elif m.group('cell_type') == 'markdown': cell['source'] = \ cell['source'].lstrip(u'"""\n').rstrip(u'\n"""') nb['cells'].append(nbformat.from_dict(cell)) nbformat.write(nb, path)
def test_image_mimetype_uri(doctree): # tests the image uri paths on conversion to docutils image nodes priority = ['image/png', 'image/jpeg', 'text/latex', 'text/plain'] output_dir = '/_build/jupyter_execute' img_locs = [ '/_build/jupyter_execute/docs/image_1.png', '/_build/jupyter_execute/image_2.png' ] cells = [{ 'outputs': [{ 'data': { 'image/png': 'Vxb6L1wAAAABJRU5ErkJggg==\n', 'text/plain': '<Figure size 432x288 with 1 Axes>' }, 'metadata': { 'filenames': { 'image/png': img_locs[0] } }, 'output_type': 'display_data' }] }, { 'outputs': [{ 'data': { 'image/png': 'iVBOJggg==\n', 'text/plain': '<Figure size 432x288 with 1 Axes>' }, 'metadata': { 'filenames': { 'image/png': img_locs[1] } }, 'output_type': 'display_data' }] }] for index, cell in enumerate(cells): cell = from_dict(cell) output_node = cell_output_to_nodes(cell, priority, True, output_dir, None) assert output_node[0].attributes['uri'] == img_locs[index]
def export_notebook(nb, cid): nb = nbformat.from_dict(nb) html_exporter = HTMLExporter() html_exporter.template_file = 'basic' body = html_exporter.from_notebook_node(nb)[0] soup = BeautifulSoup(body, 'html.parser') # mark cells with special name for toggling, and # TODO make element id's unique by appending cid for div in soup.find_all('div', 'output_wrapper'): tag = div.find('h2') div['name'] = tag.text.split()[0] # name divs for toggling code_cells for div in soup.find_all('div', 'input'): div['name'] = 'Input' # separate script script = [] for s in soup.find_all('script'): script.append(s.text) s.extract() # remove javascript return soup.prettify(), '\n'.join(script)
def test_nosource_with_output(self): """ Test that the check_conditions returns true when given a code-cell that has non-empty outputs but no source. """ cell = { 'cell_type': 'code', 'execution_count': 2, 'metadata': {}, 'outputs': [{ 'name': 'stdout', 'output_type': 'stream', 'text': 'I exist.\n' }], 'source': '' } preprocessor = self.build_preprocessor() node = from_dict(cell) assert preprocessor.check_conditions(node)
def post(self): # I don't think we want to accept arbitrary filenames # to write to from the http request, only allowing # this operation if the server was run with an output # filename as a commandline argument: fn = self.params.get("outputfilename", None) if not fn: raise web.HTTPError(400, "Server does not accept storing merge result.") path = os.path.join(self.params["cwd"], fn) nbdime.log.info("Saving merge result in %s", path) body = json.loads(escape.to_unicode(self.request.body)) merged = body["merged"] merged_nb = nbformat.from_dict(merged) # Somehow store unsolved conflicts? # conflicts = body["conflicts"] with io.open(path, "w", encoding="utf8") as f: nbformat.write(merged_nb, f) self.finish()
def post(self, format): exporter = get_exporter(format, config=self.config) model = self.get_json_body() name = model.get('name', 'notebook.ipynb') nbnode = from_dict(model['content']) try: output, resources = exporter.from_notebook_node(nbnode) except Exception as e: raise web.HTTPError(500, "nbconvert failed: %s" % e) if respond_zip(self, name, output, resources): return # MIME type if exporter.output_mimetype: self.set_header('Content-Type', '%s; charset=utf-8' % exporter.output_mimetype) self.finish(output)
def save(self, model, path): """Save the file or directory and return the model with no content. Save implementations should call self.run_pre_save_hook(model=model, path=path) prior to writing any data. """ path = path.strip("/") match = self.ws_regex.match(path) if "type" not in model: raise HTTPError(400, u"No IPython model type provided") if model["type"] != "notebook": raise HTTPError(400, u"We currently only support saving Narratives!") if "content" not in model and model["type"] != "directory": raise HTTPError(400, u"No Narrative content found while trying to save") self.log.debug(u"writing Narrative %s." % path) nb = nbformat.from_dict(model["content"]) self.check_and_sign(nb, path) try: result = self.write_narrative(self._obj_ref_from_path(path), nb, self.get_userid()) new_id = u"ws.%s.obj.%s" % (result[1], result[2]) util.kbase_env.narrative = new_id nb = result[0] self.validate_notebook_model(model) validation_message = model.get(u"message", None) model = self.get(path, content=False) if validation_message: model[u"message"] = validation_message return model except PermissionsError as err: raise HTTPError(403, err.message) except Exception as err: raise HTTPError(500, u"An error occurred while saving your Narrative: {}".format(err))
def save(self, model, path): """Save the file or directory and return the model with no content. Save implementations should call self.run_pre_save_hook(model=model, path=path) prior to writing any data. """ path = path.strip('/') if 'type' not in model: raise HTTPError(400, u'No IPython model type provided') if model['type'] != 'notebook': raise HTTPError(400, u'We currently only support saving Narratives!') if 'content' not in model and model['type'] != 'directory': raise HTTPError(400, u'No Narrative content found while trying to save') self.log.debug(u"writing Narrative %s." % path) nb = nbformat.from_dict(model['content']) self.check_and_sign(nb, path) try: ref = self._parse_path(path) result = self.write_narrative(ref, nb, self.get_userid()) new_id = u"ws.%s.obj.%s" % (result[1], result[2]) util.kbase_env.narrative = new_id nb = result[0] self.validate_notebook_model(model) validation_message = model.get(u'message', None) model = self.get(path, content=False) if validation_message: model[u'message'] = validation_message self.narrative_logger.narrative_save(u'{}/{}'.format(result[1], result[2]), result[3]) return model except WorkspaceError as err: raise HTTPError(err.http_code, "While saving your Narrative: {}".format(err.message))