##// END OF EJS Templates
Add method notebook_exists to NotebookManager....
Konrad Hinsen -
Show More
@@ -1,235 +1,251 b''
1 """A base class notebook manager.
1 """A base class notebook manager.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 * Zach Sailer
6 * Zach Sailer
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2011 The IPython Development Team
10 # Copyright (C) 2011 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 import os
20 import os
21
21
22 from IPython.config.configurable import LoggingConfigurable
22 from IPython.config.configurable import LoggingConfigurable
23 from IPython.nbformat import current, sign
23 from IPython.nbformat import current, sign
24 from IPython.utils import py3compat
24 from IPython.utils import py3compat
25 from IPython.utils.traitlets import Instance, Unicode, TraitError
25 from IPython.utils.traitlets import Instance, Unicode, TraitError
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Classes
28 # Classes
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 class NotebookManager(LoggingConfigurable):
31 class NotebookManager(LoggingConfigurable):
32
32
33 # Todo:
33 # Todo:
34 # The notebook_dir attribute is used to mean a couple of different things:
34 # The notebook_dir attribute is used to mean a couple of different things:
35 # 1. Where the notebooks are stored if FileNotebookManager is used.
35 # 1. Where the notebooks are stored if FileNotebookManager is used.
36 # 2. The cwd of the kernel for a project.
36 # 2. The cwd of the kernel for a project.
37 # Right now we use this attribute in a number of different places and
37 # Right now we use this attribute in a number of different places and
38 # we are going to have to disentangle all of this.
38 # we are going to have to disentangle all of this.
39 notebook_dir = Unicode(py3compat.getcwd(), config=True, help="""
39 notebook_dir = Unicode(py3compat.getcwd(), config=True, help="""
40 The directory to use for notebooks.
40 The directory to use for notebooks.
41 """)
41 """)
42
42
43 filename_ext = Unicode(u'.ipynb')
43 filename_ext = Unicode(u'.ipynb')
44
44
45 notary = Instance(sign.NotebookNotary)
45 notary = Instance(sign.NotebookNotary)
46 def _notary_default(self):
46 def _notary_default(self):
47 return sign.NotebookNotary(parent=self)
47 return sign.NotebookNotary(parent=self)
48
48
49 def check_and_sign(self, nb, path, name):
49 def check_and_sign(self, nb, path, name):
50 """Check for trusted cells, and sign the notebook.
50 """Check for trusted cells, and sign the notebook.
51
51
52 Called as a part of saving notebooks.
52 Called as a part of saving notebooks.
53 """
53 """
54 if self.notary.check_cells(nb):
54 if self.notary.check_cells(nb):
55 self.notary.sign(nb)
55 self.notary.sign(nb)
56 else:
56 else:
57 self.log.warn("Saving untrusted notebook %s/%s", path, name)
57 self.log.warn("Saving untrusted notebook %s/%s", path, name)
58
58
59 def mark_trusted_cells(self, nb, path, name):
59 def mark_trusted_cells(self, nb, path, name):
60 """Mark cells as trusted if the notebook signature matches.
60 """Mark cells as trusted if the notebook signature matches.
61
61
62 Called as a part of loading notebooks.
62 Called as a part of loading notebooks.
63 """
63 """
64 trusted = self.notary.check_signature(nb)
64 trusted = self.notary.check_signature(nb)
65 if not trusted:
65 if not trusted:
66 self.log.warn("Notebook %s/%s is not trusted", path, name)
66 self.log.warn("Notebook %s/%s is not trusted", path, name)
67 self.notary.mark_cells(nb, trusted)
67 self.notary.mark_cells(nb, trusted)
68
68
69 def path_exists(self, path):
69 def path_exists(self, path):
70 """Does the API-style path (directory) actually exist?
70 """Does the API-style path (directory) actually exist?
71
71
72 Override this method in subclasses.
72 Override this method in subclasses.
73
73
74 Parameters
74 Parameters
75 ----------
75 ----------
76 path : string
76 path : string
77 The
77 The
78
78
79 Returns
79 Returns
80 -------
80 -------
81 exists : bool
81 exists : bool
82 Whether the path does indeed exist.
82 Whether the path does indeed exist.
83 """
83 """
84 raise NotImplementedError
84 raise NotImplementedError
85
85
86 def is_hidden(self, path):
86 def is_hidden(self, path):
87 """Does the API style path correspond to a hidden directory or file?
87 """Does the API style path correspond to a hidden directory or file?
88
88
89 Parameters
89 Parameters
90 ----------
90 ----------
91 path : string
91 path : string
92 The path to check. This is an API path (`/` separated,
92 The path to check. This is an API path (`/` separated,
93 relative to base notebook-dir).
93 relative to base notebook-dir).
94
94
95 Returns
95 Returns
96 -------
96 -------
97 exists : bool
97 exists : bool
98 Whether the path is hidden.
98 Whether the path is hidden.
99
99
100 """
100 """
101 raise NotImplementedError
101 raise NotImplementedError
102
102
103 def _notebook_dir_changed(self, name, old, new):
103 def _notebook_dir_changed(self, name, old, new):
104 """Do a bit of validation of the notebook dir."""
104 """Do a bit of validation of the notebook dir."""
105 if not os.path.isabs(new):
105 if not os.path.isabs(new):
106 # If we receive a non-absolute path, make it absolute.
106 # If we receive a non-absolute path, make it absolute.
107 self.notebook_dir = os.path.abspath(new)
107 self.notebook_dir = os.path.abspath(new)
108 return
108 return
109 if os.path.exists(new) and not os.path.isdir(new):
109 if os.path.exists(new) and not os.path.isdir(new):
110 raise TraitError("notebook dir %r is not a directory" % new)
110 raise TraitError("notebook dir %r is not a directory" % new)
111 if not os.path.exists(new):
111 if not os.path.exists(new):
112 self.log.info("Creating notebook dir %s", new)
112 self.log.info("Creating notebook dir %s", new)
113 try:
113 try:
114 os.mkdir(new)
114 os.mkdir(new)
115 except:
115 except:
116 raise TraitError("Couldn't create notebook dir %r" % new)
116 raise TraitError("Couldn't create notebook dir %r" % new)
117
117
118 # Main notebook API
118 # Main notebook API
119
119
120 def increment_filename(self, basename, path=''):
120 def increment_filename(self, basename, path=''):
121 """Increment a notebook filename without the .ipynb to make it unique.
121 """Increment a notebook filename without the .ipynb to make it unique.
122
122
123 Parameters
123 Parameters
124 ----------
124 ----------
125 basename : unicode
125 basename : unicode
126 The name of a notebook without the ``.ipynb`` file extension.
126 The name of a notebook without the ``.ipynb`` file extension.
127 path : unicode
127 path : unicode
128 The URL path of the notebooks directory
128 The URL path of the notebooks directory
129 """
129 """
130 return basename
130 return basename
131
131
132 def notebook_exists(self, name, path=''):
133 """Returns a True if the notebook exists. Else, returns False.
134
135 Parameters
136 ----------
137 name : string
138 The name of the notebook you are checking.
139 path : string
140 The relative path to the notebook (with '/' as separator)
141
142 Returns
143 -------
144 bool
145 """
146 raise NotImplementedError('must be implemented in a subclass')
147
132 # TODO: Remove this after we create the contents web service and directories are
148 # TODO: Remove this after we create the contents web service and directories are
133 # no longer listed by the notebook web service.
149 # no longer listed by the notebook web service.
134 def list_dirs(self, path):
150 def list_dirs(self, path):
135 """List the directory models for a given API style path."""
151 """List the directory models for a given API style path."""
136 raise NotImplementedError('must be implemented in a subclass')
152 raise NotImplementedError('must be implemented in a subclass')
137
153
138 # TODO: Remove this after we create the contents web service and directories are
154 # TODO: Remove this after we create the contents web service and directories are
139 # no longer listed by the notebook web service.
155 # no longer listed by the notebook web service.
140 def get_dir_model(self, name, path=''):
156 def get_dir_model(self, name, path=''):
141 """Get the directory model given a directory name and its API style path.
157 """Get the directory model given a directory name and its API style path.
142
158
143 The keys in the model should be:
159 The keys in the model should be:
144 * name
160 * name
145 * path
161 * path
146 * last_modified
162 * last_modified
147 * created
163 * created
148 * type='directory'
164 * type='directory'
149 """
165 """
150 raise NotImplementedError('must be implemented in a subclass')
166 raise NotImplementedError('must be implemented in a subclass')
151
167
152 def list_notebooks(self, path=''):
168 def list_notebooks(self, path=''):
153 """Return a list of notebook dicts without content.
169 """Return a list of notebook dicts without content.
154
170
155 This returns a list of dicts, each of the form::
171 This returns a list of dicts, each of the form::
156
172
157 dict(notebook_id=notebook,name=name)
173 dict(notebook_id=notebook,name=name)
158
174
159 This list of dicts should be sorted by name::
175 This list of dicts should be sorted by name::
160
176
161 data = sorted(data, key=lambda item: item['name'])
177 data = sorted(data, key=lambda item: item['name'])
162 """
178 """
163 raise NotImplementedError('must be implemented in a subclass')
179 raise NotImplementedError('must be implemented in a subclass')
164
180
165 def get_notebook(self, name, path='', content=True):
181 def get_notebook(self, name, path='', content=True):
166 """Get the notebook model with or without content."""
182 """Get the notebook model with or without content."""
167 raise NotImplementedError('must be implemented in a subclass')
183 raise NotImplementedError('must be implemented in a subclass')
168
184
169 def save_notebook(self, model, name, path=''):
185 def save_notebook(self, model, name, path=''):
170 """Save the notebook and return the model with no content."""
186 """Save the notebook and return the model with no content."""
171 raise NotImplementedError('must be implemented in a subclass')
187 raise NotImplementedError('must be implemented in a subclass')
172
188
173 def update_notebook(self, model, name, path=''):
189 def update_notebook(self, model, name, path=''):
174 """Update the notebook and return the model with no content."""
190 """Update the notebook and return the model with no content."""
175 raise NotImplementedError('must be implemented in a subclass')
191 raise NotImplementedError('must be implemented in a subclass')
176
192
177 def delete_notebook(self, name, path=''):
193 def delete_notebook(self, name, path=''):
178 """Delete notebook by name and path."""
194 """Delete notebook by name and path."""
179 raise NotImplementedError('must be implemented in a subclass')
195 raise NotImplementedError('must be implemented in a subclass')
180
196
181 def create_notebook(self, model=None, path=''):
197 def create_notebook(self, model=None, path=''):
182 """Create a new notebook and return its model with no content."""
198 """Create a new notebook and return its model with no content."""
183 path = path.strip('/')
199 path = path.strip('/')
184 if model is None:
200 if model is None:
185 model = {}
201 model = {}
186 if 'content' not in model:
202 if 'content' not in model:
187 metadata = current.new_metadata(name=u'')
203 metadata = current.new_metadata(name=u'')
188 model['content'] = current.new_notebook(metadata=metadata)
204 model['content'] = current.new_notebook(metadata=metadata)
189 if 'name' not in model:
205 if 'name' not in model:
190 model['name'] = self.increment_filename('Untitled', path)
206 model['name'] = self.increment_filename('Untitled', path)
191
207
192 model['path'] = path
208 model['path'] = path
193 model = self.save_notebook(model, model['name'], model['path'])
209 model = self.save_notebook(model, model['name'], model['path'])
194 return model
210 return model
195
211
196 def copy_notebook(self, from_name, to_name=None, path=''):
212 def copy_notebook(self, from_name, to_name=None, path=''):
197 """Copy an existing notebook and return its new model.
213 """Copy an existing notebook and return its new model.
198
214
199 If to_name not specified, increment `from_name-Copy#.ipynb`.
215 If to_name not specified, increment `from_name-Copy#.ipynb`.
200 """
216 """
201 path = path.strip('/')
217 path = path.strip('/')
202 model = self.get_notebook(from_name, path)
218 model = self.get_notebook(from_name, path)
203 if not to_name:
219 if not to_name:
204 base = os.path.splitext(from_name)[0] + '-Copy'
220 base = os.path.splitext(from_name)[0] + '-Copy'
205 to_name = self.increment_filename(base, path)
221 to_name = self.increment_filename(base, path)
206 model['name'] = to_name
222 model['name'] = to_name
207 model = self.save_notebook(model, to_name, path)
223 model = self.save_notebook(model, to_name, path)
208 return model
224 return model
209
225
210 # Checkpoint-related
226 # Checkpoint-related
211
227
212 def create_checkpoint(self, name, path=''):
228 def create_checkpoint(self, name, path=''):
213 """Create a checkpoint of the current state of a notebook
229 """Create a checkpoint of the current state of a notebook
214
230
215 Returns a checkpoint_id for the new checkpoint.
231 Returns a checkpoint_id for the new checkpoint.
216 """
232 """
217 raise NotImplementedError("must be implemented in a subclass")
233 raise NotImplementedError("must be implemented in a subclass")
218
234
219 def list_checkpoints(self, name, path=''):
235 def list_checkpoints(self, name, path=''):
220 """Return a list of checkpoints for a given notebook"""
236 """Return a list of checkpoints for a given notebook"""
221 return []
237 return []
222
238
223 def restore_checkpoint(self, checkpoint_id, name, path=''):
239 def restore_checkpoint(self, checkpoint_id, name, path=''):
224 """Restore a notebook from one of its checkpoints"""
240 """Restore a notebook from one of its checkpoints"""
225 raise NotImplementedError("must be implemented in a subclass")
241 raise NotImplementedError("must be implemented in a subclass")
226
242
227 def delete_checkpoint(self, checkpoint_id, name, path=''):
243 def delete_checkpoint(self, checkpoint_id, name, path=''):
228 """delete a checkpoint for a notebook"""
244 """delete a checkpoint for a notebook"""
229 raise NotImplementedError("must be implemented in a subclass")
245 raise NotImplementedError("must be implemented in a subclass")
230
246
231 def log_info(self):
247 def log_info(self):
232 self.log.info(self.info_string())
248 self.log.info(self.info_string())
233
249
234 def info_string(self):
250 def info_string(self):
235 return "Serving notebooks"
251 return "Serving notebooks"
General Comments 0
You need to be logged in to leave comments. Login now