##// END OF EJS Templates
refactoring of nbmanager and filenbmanager...
refactoring of nbmanager and filenbmanager major clean up of the two managers. We make sure to follow the standard models described in IPEP 16

File last commit:

r13046:116db313
r13046:116db313
Show More
filenbmanager.py
333 lines | 12.6 KiB | text/x-python | PythonLexer
Brian E. Granger
More review changes....
r4609 """A notebook manager that uses the local file system for storage.
Authors:
* Brian Granger
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 * Zach Sailer
Brian E. Granger
More review changes....
r4609 """
Brian E. Granger
Massive work on the notebook document format....
r4484 #-----------------------------------------------------------------------------
Brian Granger
Refactoring notebook managers and adding Azure backed storage....
r8180 # Copyright (C) 2011 The IPython Development Team
Brian E. Granger
Massive work on the notebook document format....
r4484 #
# Distributed under the terms of the BSD License. The full license is in
Brian E. Granger
More review changes....
r4609 # the file COPYING, distributed as part of this software.
Brian E. Granger
Massive work on the notebook document format....
r4484 #-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import datetime
Thomas Kluyver
Save notebook as script using unicode file handle....
r6030 import io
Brian E. Granger
Massive work on the notebook document format....
r4484 import os
Stefan van der Walt
Move glob to global level import.
r4624 import glob
MinRK
add checkpoint API to FileNBManager
r10497 import shutil
Zachary Sailer
manual rebase notebooks web services
r12984
MinRK
normalize unicode notebook filenames...
r10777 from unicodedata import normalize
Brian E. Granger
Massive work on the notebook document format....
r4484
from tornado import web
Brian Granger
Renaming BaseNotebookManager->NotebookManager to preserve config.
r8194 from .nbmanager import NotebookManager
Brian E. Granger
Massive work on the notebook document format....
r4484 from IPython.nbformat import current
Brian Granger
Refactoring notebook managers and adding Azure backed storage....
r8180 from IPython.utils.traitlets import Unicode, Dict, Bool, TraitError
MinRK
add timezone info to `last_modified` in notebook managers...
r11145 from IPython.utils import tz
Brian E. Granger
Massive work on the notebook document format....
r4484
#-----------------------------------------------------------------------------
Fernando Perez
Add --script flag as shorthand for the script autosave notebook option.
r5758 # Classes
#-----------------------------------------------------------------------------
Brian E. Granger
Massive work on the notebook document format....
r4484
Brian Granger
Renaming BaseNotebookManager->NotebookManager to preserve config.
r8194 class FileNotebookManager(NotebookManager):
MinRK
allow saving notebook.py next to notebook.ipynb...
r5653
save_script = Bool(False, config=True,
Fernando Perez
Fix typo in help string
r5760 help="""Automatically create a Python script when saving the notebook.
MinRK
allow saving notebook.py next to notebook.ipynb...
r5653
Matthias BUSSONNIER
remove references to loadpy...
r6765 For easier use of import, %run and %load across notebooks, a
Fernando Perez
Add --script flag as shorthand for the script autosave notebook option.
r5758 <notebook-name>.py script will be created next to any
<notebook-name>.ipynb on each save. This can also be set with the
short `--script` flag.
MinRK
allow saving notebook.py next to notebook.ipynb...
r5653 """
)
MinRK
add checkpoint API to FileNBManager
r10497 checkpoint_dir = Unicode(config=True,
help="""The location in which to keep notebook checkpoints
By default, it is notebook-dir/.ipynb_checkpoints
"""
)
def _checkpoint_dir_default(self):
return os.path.join(self.notebook_dir, '.ipynb_checkpoints')
def _checkpoint_dir_changed(self, name, old, new):
"""do a bit of validation of the checkpoint dir"""
if not os.path.isabs(new):
# If we receive a non-absolute path, make it absolute.
abs_new = os.path.abspath(new)
self.checkpoint_dir = abs_new
return
if os.path.exists(new) and not os.path.isdir(new):
raise TraitError("checkpoint dir %r is not a directory" % new)
if not os.path.exists(new):
self.log.info("Creating checkpoint dir %s", new)
try:
os.mkdir(new)
except:
raise TraitError("Couldn't create checkpoint dir %r" % new)
Brian E. Granger
Massive work on the notebook document format....
r4484 filename_ext = Unicode(u'.ipynb')
Zachary Sailer
manual rebase notebooks web services
r12984 def get_notebook_names(self, path):
Brian Granger
Refactoring notebook managers and adding Azure backed storage....
r8180 """List all notebook names in the notebook dir."""
Zachary Sailer
fixing broken links from recent changes....
r13033 names = glob.glob(self.get_os_path('*'+self.filename_ext, path))
Zachary Sailer
manual rebase notebooks web services
r12984 names = [os.path.basename(name)
Stefan van der Walt
Allow period characters in notebook names.
r4623 for name in names]
Brian Granger
Refactoring notebook managers and adding Azure backed storage....
r8180 return names
Zachary Sailer
Add 'patch' to session & notebook, rename working
r12997
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 def increment_filename(self, basename, path='/'):
"""Return a non-used filename of the form basename<int>.
This searches through the filenames (basename0, basename1, ...)
until is find one that is not already being used. It is used to
create Untitled and Copy names that are unique.
"""
i = 0
while True:
name = u'%s%i.ipynb' % (basename,i)
os_path = self.get_os_path(name, path)
if not os.path.isfile(os_path):
break
else:
i = i+1
return name
Brian E. Granger
Massive work on the notebook document format....
r4484
Zachary Sailer
handle path separators with os.sep and add tests...
r13032 def notebook_exists(self, name, path):
"""Returns a True if the notebook exists. Else, returns False.
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046
Zachary Sailer
handle path separators with os.sep and add tests...
r13032 Parameters
----------
name : string
The name of the notebook you are checking.
path : string
The relative path to the notebook (with '/' as separator)
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046
Zachary Sailer
handle path separators with os.sep and add tests...
r13032 Returns
-------
bool
"""
path = self.get_os_path(name, path)
return os.path.isfile(path)
Zachary Sailer
manual rebase notebooks web services
r12984
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 def list_notebooks(self, path):
"""List all notebooks in the notebook dir."""
notebook_names = self.get_notebook_names(path)
notebooks = []
for name in notebook_names:
model = self.get_notebook_model(name, path, content=False)
notebooks.append(model)
notebooks = sorted(notebooks, key=lambda item: item['name'])
return notebooks
def get_notebook_model(self, name, path='/', content=True):
MinRK
add checkpoint API to FileNBManager
r10497 """read a notebook object from a path"""
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 os_path = self.get_os_path(name, path)
if not os.path.isfile(os_path):
raise web.HTTPError(404, u'Notebook does not exist: %s' % name)
info = os.stat(os_path)
MinRK
add timezone info to `last_modified` in notebook managers...
r11145 last_modified = tz.utcfromtimestamp(info.st_mtime)
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 # Create the notebook model.
model ={}
model['name'] = name
model['path'] = path
model['last_modified'] = last_modified.ctime()
if content is True:
with open(os_path,'r') as f:
s = f.read()
try:
# v1 and v2 and json in the .ipynb files.
nb = current.reads(s, u'json')
except ValueError as e:
raise web.HTTPError(400, u"Unreadable Notebook: %s" % e)
model['content'] = nb
return model
Zachary Sailer
Add 'patch' to session & notebook, rename working
r12997
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 def save_notebook_model(self, model, name, path='/'):
"""Save the notebook model and return the model with no content."""
if 'content' not in model:
raise web.HTTPError(400, u'No notebook JSON data provided')
new_path = model.get('path', path)
new_name = model.get('name', name)
if path != new_path or name != new_name:
self.rename_notebook(name, path, new_name, new_path)
Brian E. Granger
When a notebook is written to file, name the metadata name u''.
r11052
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 # Save the notebook file
ospath = self.get_os_path(new_name, new_path)
nb = model['content']
if 'name' in nb['metadata']:
nb['metadata']['name'] = u''
Brian E. Granger
Massive work on the notebook document format....
r4484 try:
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 self.log.debug("Autosaving notebook %s", ospath)
with open(ospath,'w') as f:
Brian E. Granger
Making JSON the default .ipynb format.
r4633 current.write(nb, f, u'json')
MinRK
include error in 'Unexpected error' message.
r5709 except Exception as e:
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 #raise web.HTTPError(400, u'Unexpected error while autosaving notebook: %s' % ospath)
raise e
Brian Granger
Refactoring notebook managers and adding Azure backed storage....
r8180
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 # Save .py script as well
MinRK
allow saving notebook.py next to notebook.ipynb...
r5653 if self.save_script:
pypath = os.path.splitext(path)[0] + '.py'
MinRK
add checkpoint API to FileNBManager
r10497 self.log.debug("Writing script %s", pypath)
MinRK
allow saving notebook.py next to notebook.ipynb...
r5653 try:
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 with io.open(pypath, 'w', encoding='utf-8') as f:
current.write(model, f, u'py')
MinRK
include error in 'Unexpected error' message.
r5709 except Exception as e:
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 raise web.HTTPError(400, u'Unexpected error while saving notebook as script: %s' % pypath)
model = self.get_notebook_model(name, path, content=False)
return model
def update_notebook_model(self, model, name, path='/'):
"""Update the notebook's path and/or name"""
new_name = model.get('name', name)
new_path = model.get('path', path)
if path != new_path or name != new_name:
self.rename_notebook(name, path, new_name, new_path)
model = self.get_notebook_model(new_name, new_path, content=False)
return model
def delete_notebook_model(self, name, path='/'):
"""Delete notebook by name and path."""
nb_path = self.get_os_path(name, path)
MinRK
deleting a notebook deletes its checkpoints...
r10518 if not os.path.isfile(nb_path):
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 raise web.HTTPError(404, u'Notebook does not exist: %s' % nb_path)
MinRK
add checkpoint API to FileNBManager
r10497
# clear checkpoints
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 for checkpoint in self.list_checkpoints(name):
MinRK
deleting a notebook deletes its checkpoints...
r10518 checkpoint_id = checkpoint['checkpoint_id']
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
self.log.debug(cp_path)
if os.path.isfile(cp_path):
self.log.debug("Unlinking checkpoint %s", cp_path)
os.unlink(cp_path)
MinRK
deleting a notebook deletes its checkpoints...
r10518
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 self.log.debug("Unlinking notebook %s", nb_path)
MinRK
deleting a notebook deletes its checkpoints...
r10518 os.unlink(nb_path)
Brian E. Granger
Massive work on the notebook document format....
r4484
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 def rename_notebook(self, old_name, old_path, new_name, new_path):
"""Rename a notebook."""
if new_name == old_name and new_path == old_path:
return
Brian Granger
Fixing docstring in the notebook manager.
r5877
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 new_full_path = self.get_os_path(new_name, new_path)
old_full_path = self.get_os_path(old_name, old_path)
# Should we proceed with the move?
if os.path.isfile(new_full_path):
raise web.HTTPError(409, u'Notebook with name already exists: ' % new_full_path)
if self.save_script:
old_pypath = os.path.splitext(old_full_path)[0] + '.py'
new_pypath = os.path.splitext(new_full_path)[0] + '.py'
if os.path.isfile(new_pypath):
raise web.HTTPError(409, u'Python script with name already exists: %s' % new_pypath)
# Move the notebook file
try:
os.rename(old_full_path, new_full_path)
except:
raise web.HTTPError(400, u'Unknown error renaming notebook: %s' % old_full_path)
# Move the checkpoints
old_checkpoints = self.list_checkpoints(old_name, old_path)
for cp in old_checkpoints:
checkpoint_id = cp['checkpoint_id']
old_cp_path = self.get_checkpoint_path(checkpoint_id, old_name, path)
new_cp_path = self.get_checkpoint_path(checkpoint_id, new_name, path)
if os.path.isfile(old_cp_path):
self.log.debug("Renaming checkpoint %s -> %s", old_cp_path, new_cp_path)
os.rename(old_cp_path, new_cp_path)
# Move the .py script
if self.save_script:
os.rename(old_pypath, new_pypath)
MinRK
add checkpoint API to FileNBManager
r10497 # Checkpoint-related utilities
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 def get_checkpoint_path(self, checkpoint_id, name, path='/'):
"""find the path to a checkpoint"""
MinRK
normalize unicode notebook filenames...
r10777 filename = u"{name}-{checkpoint_id}{ext}".format(
MinRK
add checkpoint API to FileNBManager
r10497 name=name,
checkpoint_id=checkpoint_id,
ext=self.filename_ext,
)
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 cp_path = os.path.join(path, self.checkpoint_dir, filename)
return cp_path
def get_checkpoint_model(self, checkpoint_id, name, path='/'):
MinRK
checkpoint info is a dict...
r10500 """construct the info dict for a given checkpoint"""
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
stats = os.stat(cp_path)
MinRK
add timezone info to `last_modified` in notebook managers...
r11145 last_modified = tz.utcfromtimestamp(stats.st_mtime)
MinRK
checkpoint info is a dict...
r10500 info = dict(
checkpoint_id = checkpoint_id,
last_modified = last_modified,
)
return info
MinRK
add checkpoint API to FileNBManager
r10497 # public checkpoint API
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 def create_checkpoint(self, name, path='/'):
MinRK
add checkpoint API to FileNBManager
r10497 """Create a checkpoint from the current state of a notebook"""
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 nb_path = self.get_os_path(name, path)
MinRK
checkpoint info is a dict...
r10500 # only the one checkpoint ID:
MinRK
normalize unicode notebook filenames...
r10777 checkpoint_id = u"checkpoint"
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
self.log.debug("creating checkpoint for notebook %s", name)
MinRK
add checkpoint API to FileNBManager
r10497 if not os.path.exists(self.checkpoint_dir):
os.mkdir(self.checkpoint_dir)
shutil.copy2(nb_path, cp_path)
MinRK
checkpoint info is a dict...
r10500
# return the checkpoint info
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 return self.get_checkpoint_model(checkpoint_id, name, path)
MinRK
add checkpoint API to FileNBManager
r10497
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 def list_checkpoints(self, name, path='/'):
MinRK
add checkpoint API to FileNBManager
r10497 """list the checkpoints for a given notebook
Paul Ivanov
print info string on interrupt, log it on startup
r10019
MinRK
add checkpoint API to FileNBManager
r10497 This notebook manager currently only supports one checkpoint per notebook.
"""
Zachary Sailer
manual rebase notebooks web services
r12984 checkpoint_id = "checkpoint"
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 path = self.get_checkpoint_path(checkpoint_id, name, path)
MinRK
checkpoint info is a dict...
r10500 if not os.path.exists(path):
MinRK
add checkpoint API to FileNBManager
r10497 return []
MinRK
checkpoint info is a dict...
r10500 else:
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 return [self.get_checkpoint_model(checkpoint_id, name, path)]
MinRK
checkpoint info is a dict...
r10500
MinRK
add checkpoint API to FileNBManager
r10497
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 def restore_checkpoint(self, checkpoint_id, name, path='/'):
MinRK
add checkpoint API to FileNBManager
r10497 """restore a notebook to a checkpointed state"""
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 self.log.info("restoring Notebook %s from checkpoint %s", name, checkpoint_id)
nb_path = self.get_os_path(name, path)
cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
MinRK
add checkpoint API to FileNBManager
r10497 if not os.path.isfile(cp_path):
MinRK
checkpoint info is a dict...
r10500 self.log.debug("checkpoint file does not exist: %s", cp_path)
MinRK
add checkpoint API to FileNBManager
r10497 raise web.HTTPError(404,
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 u'Notebook checkpoint does not exist: %s-%s' % (name, checkpoint_id)
MinRK
add checkpoint API to FileNBManager
r10497 )
# ensure notebook is readable (never restore from an unreadable notebook)
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 with file(cp_path, 'r') as f:
nb = current.read(f, u'json')
MinRK
add checkpoint API to FileNBManager
r10497 shutil.copy2(cp_path, nb_path)
self.log.debug("copying %s -> %s", cp_path, nb_path)
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 def delete_checkpoint(self, checkpoint_id, name, path='/'):
MinRK
add checkpoint API to FileNBManager
r10497 """delete a notebook's checkpoint"""
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
if not os.path.isfile(cp_path):
MinRK
add checkpoint API to FileNBManager
r10497 raise web.HTTPError(404,
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 u'Notebook checkpoint does not exist: %s-%s' % (name, checkpoint_id)
MinRK
add checkpoint API to FileNBManager
r10497 )
Zachary Sailer
refactoring of nbmanager and filenbmanager...
r13046 self.log.debug("unlinking %s", cp_path)
os.unlink(cp_path)
MinRK
add checkpoint API to FileNBManager
r10497
Paul Ivanov
print info string on interrupt, log it on startup
r10019 def info_string(self):
return "Serving notebooks from local directory: %s" % self.notebook_dir