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') # 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 or name != new_name: self.rename_notebook(name, path, new_name, new_path) # Save the notebook file os_path = self._get_os_path(new_name, new_path) nb = current.to_notebook_json(model['content']) self.check_and_sign(nb, new_name, new_path) if 'name' in nb['metadata']: nb['metadata']['name'] = u'' try: self.log.debug("Autosaving notebook %s", os_path) with atomic_writing(os_path, encoding='utf-8') as f: current.write(nb, f, u'json') except Exception as e: raise web.HTTPError( 400, u'Unexpected error while autosaving notebook: %s %s' % (os_path, e)) # Save .py script as well if self.save_script: py_path = os.path.splitext(os_path)[0] + '.py' self.log.debug("Writing script %s", py_path) try: with atomic_writing(py_path, encoding='utf-8') as f: current.write(nb, f, u'py') except Exception as e: raise web.HTTPError( 400, u'Unexpected error while saving notebook as script: %s %s' % (py_path, e)) model = self.get_notebook(new_name, new_path, content=False) return model
def test_atomic_writing(): class CustomExc(Exception): pass with TemporaryDirectory() as td: f1 = os.path.join(td, "penguin") with stdlib_io.open(f1, "w") as f: f.write(u"Before") if os.name != "nt": os.chmod(f1, 0o701) orig_mode = stat.S_IMODE(os.stat(f1).st_mode) f2 = os.path.join(td, "flamingo") try: os.symlink(f1, f2) have_symlink = True except (AttributeError, NotImplementedError, OSError): # AttributeError: Python doesn't support it # NotImplementedError: The system doesn't support it # OSError: The user lacks the privilege (Windows) have_symlink = False with nt.assert_raises(CustomExc): with atomic_writing(f1) as f: f.write(u"Failing write") raise CustomExc # Because of the exception, the file should not have been modified with stdlib_io.open(f1, "r") as f: nt.assert_equal(f.read(), u"Before") with atomic_writing(f1) as f: f.write(u"Overwritten") with stdlib_io.open(f1, "r") as f: nt.assert_equal(f.read(), u"Overwritten") if os.name != "nt": mode = stat.S_IMODE(os.stat(f1).st_mode) nt.assert_equal(mode, orig_mode) if have_symlink: # Check that writing over a file preserves a symlink with atomic_writing(f2) as f: f.write(u"written from symlink") with stdlib_io.open(f1, "r") as f: nt.assert_equal(f.read(), u"written from symlink")
def test_atomic_writing(): class CustomExc(Exception): pass with TemporaryDirectory() as td: f1 = os.path.join(td, 'penguin') with stdlib_io.open(f1, 'w') as f: f.write(u'Before') if os.name != 'nt': os.chmod(f1, 0o701) orig_mode = stat.S_IMODE(os.stat(f1).st_mode) f2 = os.path.join(td, 'flamingo') try: os.symlink(f1, f2) have_symlink = True except (AttributeError, NotImplementedError, OSError): # AttributeError: Python doesn't support it # NotImplementedError: The system doesn't support it # OSError: The user lacks the privilege (Windows) have_symlink = False with nt.assert_raises(CustomExc): with atomic_writing(f1) as f: f.write(u'Failing write') raise CustomExc # Because of the exception, the file should not have been modified with stdlib_io.open(f1, 'r') as f: nt.assert_equal(f.read(), u'Before') with atomic_writing(f1) as f: f.write(u'Overwritten') with stdlib_io.open(f1, 'r') as f: nt.assert_equal(f.read(), u'Overwritten') if os.name != 'nt': mode = stat.S_IMODE(os.stat(f1).st_mode) nt.assert_equal(mode, orig_mode) if have_symlink: # Check that writing over a file preserves a symlink with atomic_writing(f2) as f: f.write(u'written from symlink') with stdlib_io.open(f1, 'r') as f: nt.assert_equal(f.read(), u'written from symlink')
def test_atomic_writing_umask(): with TemporaryDirectory() as td: os.umask(0o022) f1 = os.path.join(td, '1') with atomic_writing(f1) as f: f.write(u'1') mode = stat.S_IMODE(os.stat(f1).st_mode) nt.assert_equal(mode, 0o644, '{:o} != 644'.format(mode)) os.umask(0o057) f2 = os.path.join(td, '2') with atomic_writing(f2) as f: f.write(u'2') mode = stat.S_IMODE(os.stat(f2).st_mode) nt.assert_equal(mode, 0o620, '{:o} != 620'.format(mode))
def test_atomic_writing_umask(): with TemporaryDirectory() as td: os.umask(0o022) f1 = os.path.join(td, "1") with atomic_writing(f1) as f: f.write(u"1") mode = stat.S_IMODE(os.stat(f1).st_mode) nt.assert_equal(mode, 0o644, "{:o} != 644".format(mode)) os.umask(0o057) f2 = os.path.join(td, "2") with atomic_writing(f2) as f: f.write(u"2") mode = stat.S_IMODE(os.stat(f2).st_mode) nt.assert_equal(mode, 0o620, "{:o} != 620".format(mode))
def test_atomic_writing(): class CustomExc(Exception): pass with TemporaryDirectory() as td: f1 = os.path.join(td, 'penguin') with stdlib_io.open(f1, 'w') as f: f.write(u'Before') if os.name != 'nt': os.chmod(f1, 0o701) orig_mode = stat.S_IMODE(os.stat(f1).st_mode) f2 = os.path.join(td, 'flamingo') try: os.symlink(f1, f2) have_symlink = True except (AttributeError, NotImplementedError): have_symlink = False with nt.assert_raises(CustomExc): with atomic_writing(f1) as f: f.write(u'Failing write') raise CustomExc # Because of the exception, the file should not have been modified with stdlib_io.open(f1, 'r') as f: nt.assert_equal(f.read(), u'Before') with atomic_writing(f1) as f: f.write(u'Overwritten') with stdlib_io.open(f1, 'r') as f: nt.assert_equal(f.read(), u'Overwritten') if os.name != 'nt': mode = stat.S_IMODE(os.stat(f1).st_mode) nt.assert_equal(mode, orig_mode) if have_symlink: # Check that writing over a file preserves a symlink with atomic_writing(f2) as f: f.write(u'written from symlink') with stdlib_io.open(f1, 'r') as f: nt.assert_equal(f.read(), u'written from symlink')
def _save_notebook(self, os_path, model, path=""): """save a notebook file""" # Save the notebook file nb = nbformat.from_dict(model["content"]) self.check_and_sign(nb, path) with atomic_writing(os_path, encoding="utf-8") as f: nbformat.write(nb, f, version=nbformat.NO_CONVERT)
def _save_notebook(self, os_path, model, path=''): """save a notebook file""" # Save the notebook file nb = nbformat.from_dict(model['content']) self.check_and_sign(nb, path) with atomic_writing(os_path, encoding='utf-8') as f: nbformat.write(nb, f, version=nbformat.NO_CONVERT)
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') # 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 or name != new_name: self.rename_notebook(name, path, new_name, new_path) # Save the notebook file os_path = self._get_os_path(new_name, new_path) nb = current.to_notebook_json(model['content']) self.check_and_sign(nb, new_name, new_path) if 'name' in nb['metadata']: nb['metadata']['name'] = u'' try: self.log.debug("Autosaving notebook %s", os_path) with atomic_writing(os_path, encoding='utf-8') as f: current.write(nb, f, u'json') except Exception as e: raise web.HTTPError(400, u'Unexpected error while autosaving notebook: %s %s' % (os_path, e)) # Save .py script as well if self.save_script: py_path = os.path.splitext(os_path)[0] + '.py' self.log.debug("Writing script %s", py_path) try: with atomic_writing(py_path, encoding='utf-8') as f: current.write(nb, f, u'py') except Exception as e: raise web.HTTPError(400, u'Unexpected error while saving notebook as script: %s %s' % (py_path, e)) model = self.get_notebook(new_name, new_path, content=False) return model
def _save_notebook(self, os_path, model, name='', path=''): """save a notebook file""" # Save the notebook file nb = nbformat.from_dict(model['content']) self.check_and_sign(nb, name, path) if 'name' in nb['metadata']: nb['metadata']['name'] = u'' with atomic_writing(os_path, encoding='utf-8') as f: nbformat.write(nb, f, version=nbformat.NO_CONVERT)
def _save_notebook(self, os_path, model, name="", path=""): """save a notebook file""" # Save the notebook file nb = current.to_notebook_json(model["content"]) self.check_and_sign(nb, name, path) if "name" in nb["metadata"]: nb["metadata"]["name"] = u"" with atomic_writing(os_path, encoding="utf-8") as f: current.write(nb, f, u"json")
def _save_notebook(self, os_path, model, name='', path=''): """save a notebook file""" # Save the notebook file nb = current.to_notebook_json(model['content']) self.check_and_sign(nb, name, path) if 'name' in nb['metadata']: nb['metadata']['name'] = u'' with atomic_writing(os_path, encoding='utf-8') as f: current.write(nb, f, u'json')
def _save_notebook(self, os_path, model, name='', path=''): """save a notebook file""" # Save the notebook file nb = current.to_notebook_json(model['content']) self.check_and_sign(nb, name, path) if 'name' in nb['metadata']: nb['metadata']['name'] = u'' with atomic_writing(os_path, encoding='utf-8') as f: current.write(nb, f, version=nb.nbformat)
def sign_notebook(self, notebook_path): if not os.path.exists(notebook_path): self.log.error("Notebook missing: %s" % notebook_path) self.exit(1) with io.open(notebook_path, encoding="utf8") as f: nb = read(f, NO_CONVERT) if self.notary.check_signature(nb): print("Notebook already signed: %s" % notebook_path) else: print("Signing notebook: %s" % notebook_path) self.notary.sign(nb) with atomic_writing(notebook_path) as f: write(nb, f, NO_CONVERT)
def sign_notebook(self, notebook_path): if not os.path.exists(notebook_path): self.log.error("Notebook missing: %s" % notebook_path) self.exit(1) with io.open(notebook_path, encoding='utf8') as f: nb = read(f, NO_CONVERT) if self.notary.check_signature(nb): print("Notebook already signed: %s" % notebook_path) else: print("Signing notebook: %s" % notebook_path) self.notary.sign(nb) with atomic_writing(notebook_path) as f: write(nb, f, NO_CONVERT)
def test_atomic_writing(): class CustomExc(Exception): pass with TemporaryDirectory() as td: f1 = os.path.join(td, 'penguin') with stdlib_io.open(f1, 'w') as f: f.write(u'Before') with nt.assert_raises(CustomExc): with atomic_writing(f1) as f: f.write(u'Failing write') raise CustomExc # Because of the exception, the file should not have been modified with stdlib_io.open(f1, 'r') as f: nt.assert_equal(f.read(), u'Before') with atomic_writing(f1) as f: f.write(u'Overwritten') with stdlib_io.open(f1, 'r') as f: nt.assert_equal(f.read(), u'Overwritten')
def test_atomic_writing_newlines(): with TemporaryDirectory() as td: path = os.path.join(td, "testfile") lf = u"a\nb\nc\n" plat = lf.replace(u"\n", os.linesep) crlf = lf.replace(u"\n", u"\r\n") # test default with stdlib_io.open(path, "w") as f: f.write(lf) with stdlib_io.open(path, "r", newline="") as f: read = f.read() nt.assert_equal(read, plat) # test newline=LF with stdlib_io.open(path, "w", newline="\n") as f: f.write(lf) with stdlib_io.open(path, "r", newline="") as f: read = f.read() nt.assert_equal(read, lf) # test newline=CRLF with atomic_writing(path, newline="\r\n") as f: f.write(lf) with stdlib_io.open(path, "r", newline="") as f: read = f.read() nt.assert_equal(read, crlf) # test newline=no convert text = u"crlf\r\ncr\rlf\n" with atomic_writing(path, newline="") as f: f.write(text) with stdlib_io.open(path, "r", newline="") as f: read = f.read() nt.assert_equal(read, text)
def test_atomic_writing_newlines(): with TemporaryDirectory() as td: path = os.path.join(td, 'testfile') lf = u'a\nb\nc\n' plat = lf.replace(u'\n', os.linesep) crlf = lf.replace(u'\n', u'\r\n') # test default with stdlib_io.open(path, 'w') as f: f.write(lf) with stdlib_io.open(path, 'r', newline='') as f: read = f.read() nt.assert_equal(read, plat) # test newline=LF with stdlib_io.open(path, 'w', newline='\n') as f: f.write(lf) with stdlib_io.open(path, 'r', newline='') as f: read = f.read() nt.assert_equal(read, lf) # test newline=CRLF with atomic_writing(path, newline='\r\n') as f: f.write(lf) with stdlib_io.open(path, 'r', newline='') as f: read = f.read() nt.assert_equal(read, crlf) # test newline=no convert text = u'crlf\r\ncr\rlf\n' with atomic_writing(path, newline='') as f: f.write(text) with stdlib_io.open(path, 'r', newline='') as f: read = f.read() nt.assert_equal(read, text)
def _save_file(self, os_path, model, name='', path=''): """save a non-notebook file""" fmt = model.get('format', None) if fmt not in {'text', 'base64'}: raise web.HTTPError(400, "Must specify format of file contents as 'text' or 'base64'") try: content = model['content'] if fmt == 'text': bcontent = content.encode('utf8') else: b64_bytes = content.encode('ascii') bcontent = base64.decodestring(b64_bytes) except Exception as e: raise web.HTTPError(400, u'Encoding error saving %s: %s' % (os_path, e)) with atomic_writing(os_path, text=False) as f: f.write(bcontent)
def _save_file(self, os_path, model, path=""): """save a non-notebook file""" fmt = model.get("format", None) if fmt not in {"text", "base64"}: raise web.HTTPError(400, "Must specify format of file contents as 'text' or 'base64'") try: content = model["content"] if fmt == "text": bcontent = content.encode("utf8") else: b64_bytes = content.encode("ascii") bcontent = base64.decodestring(b64_bytes) except Exception as e: raise web.HTTPError(400, u"Encoding error saving %s: %s" % (os_path, e)) with atomic_writing(os_path, text=False) as f: f.write(bcontent)
def _save_file(self, os_path, model, name='', path=''): """save a non-notebook file""" fmt = model.get('format', None) if fmt not in {'text', 'base64'}: raise web.HTTPError( 400, "Must specify format of file contents as 'text' or 'base64'") try: content = model['content'] if fmt == 'text': bcontent = content.encode('utf8') else: b64_bytes = content.encode('ascii') bcontent = base64.decodestring(b64_bytes) except Exception as e: raise web.HTTPError(400, u'Encoding error saving %s: %s' % (os_path, e)) with atomic_writing(os_path, text=False) as f: f.write(bcontent)
def atomic_writing(self, os_path, *args, **kwargs): """wrapper around atomic_writing that turns permission errors into 403""" with self.perm_to_403(os_path): with atomic_writing(os_path, *args, **kwargs) as f: yield f