##// END OF EJS Templates
trust method docstrings
MinRK -
Show More
@@ -1,260 +1,283 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 from fnmatch import fnmatch
20 from fnmatch import fnmatch
21 import itertools
21 import itertools
22 import os
22 import os
23
23
24 from IPython.config.configurable import LoggingConfigurable
24 from IPython.config.configurable import LoggingConfigurable
25 from IPython.nbformat import current, sign
25 from IPython.nbformat import current, sign
26 from IPython.utils.traitlets import Instance, Unicode, List
26 from IPython.utils.traitlets import Instance, Unicode, List
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Classes
29 # Classes
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 class NotebookManager(LoggingConfigurable):
32 class NotebookManager(LoggingConfigurable):
33
33
34 filename_ext = Unicode(u'.ipynb')
34 filename_ext = Unicode(u'.ipynb')
35
35
36 notary = Instance(sign.NotebookNotary)
36 notary = Instance(sign.NotebookNotary)
37 def _notary_default(self):
37 def _notary_default(self):
38 return sign.NotebookNotary(parent=self)
38 return sign.NotebookNotary(parent=self)
39
39
40 hide_globs = List(Unicode, [u'__pycache__'], config=True, help="""
40 hide_globs = List(Unicode, [u'__pycache__'], config=True, help="""
41 Glob patterns to hide in file and directory listings.
41 Glob patterns to hide in file and directory listings.
42 """)
42 """)
43
43
44 # NotebookManager API part 1: methods that must be
44 # NotebookManager API part 1: methods that must be
45 # implemented in subclasses.
45 # implemented in subclasses.
46
46
47 def path_exists(self, path):
47 def path_exists(self, path):
48 """Does the API-style path (directory) actually exist?
48 """Does the API-style path (directory) actually exist?
49
49
50 Override this method in subclasses.
50 Override this method in subclasses.
51
51
52 Parameters
52 Parameters
53 ----------
53 ----------
54 path : string
54 path : string
55 The
55 The path to check
56
56
57 Returns
57 Returns
58 -------
58 -------
59 exists : bool
59 exists : bool
60 Whether the path does indeed exist.
60 Whether the path does indeed exist.
61 """
61 """
62 raise NotImplementedError
62 raise NotImplementedError
63
63
64 def is_hidden(self, path):
64 def is_hidden(self, path):
65 """Does the API style path correspond to a hidden directory or file?
65 """Does the API style path correspond to a hidden directory or file?
66
66
67 Parameters
67 Parameters
68 ----------
68 ----------
69 path : string
69 path : string
70 The path to check. This is an API path (`/` separated,
70 The path to check. This is an API path (`/` separated,
71 relative to base notebook-dir).
71 relative to base notebook-dir).
72
72
73 Returns
73 Returns
74 -------
74 -------
75 exists : bool
75 exists : bool
76 Whether the path is hidden.
76 Whether the path is hidden.
77
77
78 """
78 """
79 raise NotImplementedError
79 raise NotImplementedError
80
80
81 def notebook_exists(self, name, path=''):
81 def notebook_exists(self, name, path=''):
82 """Returns a True if the notebook exists. Else, returns False.
82 """Returns a True if the notebook exists. Else, returns False.
83
83
84 Parameters
84 Parameters
85 ----------
85 ----------
86 name : string
86 name : string
87 The name of the notebook you are checking.
87 The name of the notebook you are checking.
88 path : string
88 path : string
89 The relative path to the notebook (with '/' as separator)
89 The relative path to the notebook (with '/' as separator)
90
90
91 Returns
91 Returns
92 -------
92 -------
93 bool
93 bool
94 """
94 """
95 raise NotImplementedError('must be implemented in a subclass')
95 raise NotImplementedError('must be implemented in a subclass')
96
96
97 # TODO: Remove this after we create the contents web service and directories are
97 # TODO: Remove this after we create the contents web service and directories are
98 # no longer listed by the notebook web service.
98 # no longer listed by the notebook web service.
99 def list_dirs(self, path):
99 def list_dirs(self, path):
100 """List the directory models for a given API style path."""
100 """List the directory models for a given API style path."""
101 raise NotImplementedError('must be implemented in a subclass')
101 raise NotImplementedError('must be implemented in a subclass')
102
102
103 # TODO: Remove this after we create the contents web service and directories are
103 # TODO: Remove this after we create the contents web service and directories are
104 # no longer listed by the notebook web service.
104 # no longer listed by the notebook web service.
105 def get_dir_model(self, name, path=''):
105 def get_dir_model(self, name, path=''):
106 """Get the directory model given a directory name and its API style path.
106 """Get the directory model given a directory name and its API style path.
107
107
108 The keys in the model should be:
108 The keys in the model should be:
109 * name
109 * name
110 * path
110 * path
111 * last_modified
111 * last_modified
112 * created
112 * created
113 * type='directory'
113 * type='directory'
114 """
114 """
115 raise NotImplementedError('must be implemented in a subclass')
115 raise NotImplementedError('must be implemented in a subclass')
116
116
117 def list_notebooks(self, path=''):
117 def list_notebooks(self, path=''):
118 """Return a list of notebook dicts without content.
118 """Return a list of notebook dicts without content.
119
119
120 This returns a list of dicts, each of the form::
120 This returns a list of dicts, each of the form::
121
121
122 dict(notebook_id=notebook,name=name)
122 dict(notebook_id=notebook,name=name)
123
123
124 This list of dicts should be sorted by name::
124 This list of dicts should be sorted by name::
125
125
126 data = sorted(data, key=lambda item: item['name'])
126 data = sorted(data, key=lambda item: item['name'])
127 """
127 """
128 raise NotImplementedError('must be implemented in a subclass')
128 raise NotImplementedError('must be implemented in a subclass')
129
129
130 def get_notebook(self, name, path='', content=True):
130 def get_notebook(self, name, path='', content=True):
131 """Get the notebook model with or without content."""
131 """Get the notebook model with or without content."""
132 raise NotImplementedError('must be implemented in a subclass')
132 raise NotImplementedError('must be implemented in a subclass')
133
133
134 def save_notebook(self, model, name, path=''):
134 def save_notebook(self, model, name, path=''):
135 """Save the notebook and return the model with no content."""
135 """Save the notebook and return the model with no content."""
136 raise NotImplementedError('must be implemented in a subclass')
136 raise NotImplementedError('must be implemented in a subclass')
137
137
138 def update_notebook(self, model, name, path=''):
138 def update_notebook(self, model, name, path=''):
139 """Update the notebook and return the model with no content."""
139 """Update the notebook and return the model with no content."""
140 raise NotImplementedError('must be implemented in a subclass')
140 raise NotImplementedError('must be implemented in a subclass')
141
141
142 def delete_notebook(self, name, path=''):
142 def delete_notebook(self, name, path=''):
143 """Delete notebook by name and path."""
143 """Delete notebook by name and path."""
144 raise NotImplementedError('must be implemented in a subclass')
144 raise NotImplementedError('must be implemented in a subclass')
145
145
146 def create_checkpoint(self, name, path=''):
146 def create_checkpoint(self, name, path=''):
147 """Create a checkpoint of the current state of a notebook
147 """Create a checkpoint of the current state of a notebook
148
148
149 Returns a checkpoint_id for the new checkpoint.
149 Returns a checkpoint_id for the new checkpoint.
150 """
150 """
151 raise NotImplementedError("must be implemented in a subclass")
151 raise NotImplementedError("must be implemented in a subclass")
152
152
153 def list_checkpoints(self, name, path=''):
153 def list_checkpoints(self, name, path=''):
154 """Return a list of checkpoints for a given notebook"""
154 """Return a list of checkpoints for a given notebook"""
155 return []
155 return []
156
156
157 def restore_checkpoint(self, checkpoint_id, name, path=''):
157 def restore_checkpoint(self, checkpoint_id, name, path=''):
158 """Restore a notebook from one of its checkpoints"""
158 """Restore a notebook from one of its checkpoints"""
159 raise NotImplementedError("must be implemented in a subclass")
159 raise NotImplementedError("must be implemented in a subclass")
160
160
161 def delete_checkpoint(self, checkpoint_id, name, path=''):
161 def delete_checkpoint(self, checkpoint_id, name, path=''):
162 """delete a checkpoint for a notebook"""
162 """delete a checkpoint for a notebook"""
163 raise NotImplementedError("must be implemented in a subclass")
163 raise NotImplementedError("must be implemented in a subclass")
164
164
165 def info_string(self):
165 def info_string(self):
166 return "Serving notebooks"
166 return "Serving notebooks"
167
167
168 # NotebookManager API part 2: methods that have useable default
168 # NotebookManager API part 2: methods that have useable default
169 # implementations, but can be overridden in subclasses.
169 # implementations, but can be overridden in subclasses.
170
170
171 def increment_filename(self, basename, path=''):
171 def increment_filename(self, basename, path=''):
172 """Increment a notebook filename without the .ipynb to make it unique.
172 """Increment a notebook filename without the .ipynb to make it unique.
173
173
174 Parameters
174 Parameters
175 ----------
175 ----------
176 basename : unicode
176 basename : unicode
177 The name of a notebook without the ``.ipynb`` file extension.
177 The name of a notebook without the ``.ipynb`` file extension.
178 path : unicode
178 path : unicode
179 The URL path of the notebooks directory
179 The URL path of the notebooks directory
180
180
181 Returns
181 Returns
182 -------
182 -------
183 name : unicode
183 name : unicode
184 A notebook name (with the .ipynb extension) that starts
184 A notebook name (with the .ipynb extension) that starts
185 with basename and does not refer to any existing notebook.
185 with basename and does not refer to any existing notebook.
186 """
186 """
187 path = path.strip('/')
187 path = path.strip('/')
188 for i in itertools.count():
188 for i in itertools.count():
189 name = u'{basename}{i}{ext}'.format(basename=basename, i=i,
189 name = u'{basename}{i}{ext}'.format(basename=basename, i=i,
190 ext=self.filename_ext)
190 ext=self.filename_ext)
191 if not self.notebook_exists(name, path):
191 if not self.notebook_exists(name, path):
192 break
192 break
193 return name
193 return name
194
194
195 def create_notebook(self, model=None, path=''):
195 def create_notebook(self, model=None, path=''):
196 """Create a new notebook and return its model with no content."""
196 """Create a new notebook and return its model with no content."""
197 path = path.strip('/')
197 path = path.strip('/')
198 if model is None:
198 if model is None:
199 model = {}
199 model = {}
200 if 'content' not in model:
200 if 'content' not in model:
201 metadata = current.new_metadata(name=u'')
201 metadata = current.new_metadata(name=u'')
202 model['content'] = current.new_notebook(metadata=metadata)
202 model['content'] = current.new_notebook(metadata=metadata)
203 if 'name' not in model:
203 if 'name' not in model:
204 model['name'] = self.increment_filename('Untitled', path)
204 model['name'] = self.increment_filename('Untitled', path)
205
205
206 model['path'] = path
206 model['path'] = path
207 model = self.save_notebook(model, model['name'], model['path'])
207 model = self.save_notebook(model, model['name'], model['path'])
208 return model
208 return model
209
209
210 def copy_notebook(self, from_name, to_name=None, path=''):
210 def copy_notebook(self, from_name, to_name=None, path=''):
211 """Copy an existing notebook and return its new model.
211 """Copy an existing notebook and return its new model.
212
212
213 If to_name not specified, increment `from_name-Copy#.ipynb`.
213 If to_name not specified, increment `from_name-Copy#.ipynb`.
214 """
214 """
215 path = path.strip('/')
215 path = path.strip('/')
216 model = self.get_notebook(from_name, path)
216 model = self.get_notebook(from_name, path)
217 if not to_name:
217 if not to_name:
218 base = os.path.splitext(from_name)[0] + '-Copy'
218 base = os.path.splitext(from_name)[0] + '-Copy'
219 to_name = self.increment_filename(base, path)
219 to_name = self.increment_filename(base, path)
220 model['name'] = to_name
220 model['name'] = to_name
221 model = self.save_notebook(model, to_name, path)
221 model = self.save_notebook(model, to_name, path)
222 return model
222 return model
223
223
224 def log_info(self):
224 def log_info(self):
225 self.log.info(self.info_string())
225 self.log.info(self.info_string())
226
226
227 def trust_notebook(self, name, path=''):
227 def trust_notebook(self, name, path=''):
228 """Check for trusted cells, and sign the notebook.
228 """Explicitly trust a notebook
229
229
230 Called as a part of saving notebooks.
230 Parameters
231 ----------
232 name : string
233 The filename of the notebook
234 path : string
235 The notebook's directory
231 """
236 """
232 model = self.get_notebook(name, path)
237 model = self.get_notebook(name, path)
233 nb = model['content']
238 nb = model['content']
234 self.log.warn("Trusting notebook %s/%s", path, name)
239 self.log.warn("Trusting notebook %s/%s", path, name)
235 self.notary.mark_cells(nb, True)
240 self.notary.mark_cells(nb, True)
236 self.save_notebook(model, name, path)
241 self.save_notebook(model, name, path)
237
242
238 def check_and_sign(self, nb, name, path=''):
243 def check_and_sign(self, nb, name, path=''):
239 """Check for trusted cells, and sign the notebook.
244 """Check for trusted cells, and sign the notebook.
240
245
241 Called as a part of saving notebooks.
246 Called as a part of saving notebooks.
247
248 Parameters
249 ----------
250 nb : dict
251 The notebook structure
252 name : string
253 The filename of the notebook
254 path : string
255 The notebook's directory
242 """
256 """
243 if self.notary.check_cells(nb):
257 if self.notary.check_cells(nb):
244 self.notary.sign(nb)
258 self.notary.sign(nb)
245 else:
259 else:
246 self.log.warn("Saving untrusted notebook %s/%s", path, name)
260 self.log.warn("Saving untrusted notebook %s/%s", path, name)
247
261
248 def mark_trusted_cells(self, nb, name, path=''):
262 def mark_trusted_cells(self, nb, name, path=''):
249 """Mark cells as trusted if the notebook signature matches.
263 """Mark cells as trusted if the notebook signature matches.
250
264
251 Called as a part of loading notebooks.
265 Called as a part of loading notebooks.
266
267 Parameters
268 ----------
269 nb : dict
270 The notebook structure
271 name : string
272 The filename of the notebook
273 path : string
274 The notebook's directory
252 """
275 """
253 trusted = self.notary.check_signature(nb)
276 trusted = self.notary.check_signature(nb)
254 if not trusted:
277 if not trusted:
255 self.log.warn("Notebook %s/%s is not trusted", path, name)
278 self.log.warn("Notebook %s/%s is not trusted", path, name)
256 self.notary.mark_cells(nb, trusted)
279 self.notary.mark_cells(nb, trusted)
257
280
258 def should_list(self, name):
281 def should_list(self, name):
259 """Should this file/directory name be displayed in a listing?"""
282 """Should this file/directory name be displayed in a listing?"""
260 return not any(fnmatch(name, glob) for glob in self.hide_globs)
283 return not any(fnmatch(name, glob) for glob in self.hide_globs)
General Comments 0
You need to be logged in to leave comments. Login now