mirror of
https://github.com/jupyter/notebook.git
synced 2024-12-09 03:50:45 +08:00
Merge pull request #1253 from ryanlovett/master
Restore atomic intermediate if notebook is invalid.
This commit is contained in:
commit
6b220c949b
@ -42,6 +42,17 @@ def copy2_safe(src, dst, log=None):
|
||||
if log:
|
||||
log.debug("copystat on %s failed", dst, exc_info=True)
|
||||
|
||||
def path_to_intermediate(path):
|
||||
'''Name of the intermediate file used in atomic writes.
|
||||
|
||||
The .~ prefix will make Dropbox ignore the temporary file.'''
|
||||
dirname, basename = os.path.split(path)
|
||||
return os.path.join(dirname, '.~'+basename)
|
||||
|
||||
def path_to_invalid(path):
|
||||
'''Name of invalid file after a failed atomic write and subsequent read.'''
|
||||
dirname, basename = os.path.split(path)
|
||||
return os.path.join(dirname, basename+'.invalid')
|
||||
|
||||
@contextmanager
|
||||
def atomic_writing(path, text=True, encoding='utf-8', log=None, **kwargs):
|
||||
@ -73,9 +84,8 @@ def atomic_writing(path, text=True, encoding='utf-8', log=None, **kwargs):
|
||||
if os.path.islink(path):
|
||||
path = os.path.join(os.path.dirname(path), os.readlink(path))
|
||||
|
||||
dirname, basename = os.path.split(path)
|
||||
# The .~ prefix will make Dropbox ignore the temporary file.
|
||||
tmp_path = os.path.join(dirname, '.~'+basename)
|
||||
tmp_path = path_to_intermediate(path)
|
||||
|
||||
if os.path.isfile(path):
|
||||
copy2_safe(path, tmp_path, log=log)
|
||||
|
||||
@ -249,11 +259,28 @@ class FileManagerMixin(Configurable):
|
||||
try:
|
||||
return nbformat.read(f, as_version=as_version)
|
||||
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),
|
||||
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)
|
||||
# Rename over existing file doesn't work on Windows
|
||||
if os.name == 'nt' and os.path.exists(invalid_file):
|
||||
os.remove(invalid_file)
|
||||
os.rename(os_path, invalid_file)
|
||||
os.rename(tmp_path, os_path)
|
||||
return self._read_notebook(os_path, as_version)
|
||||
|
||||
def _save_notebook(self, os_path, nb):
|
||||
"""Save a notebook to an os_path."""
|
||||
with self.atomic_writing(os_path, encoding='utf-8') as f:
|
||||
|
Loading…
Reference in New Issue
Block a user