Show More
@@ -71,8 +71,7 b' class NotebookHandler(IPythonHandler):' | |||
|
71 | 71 | @web.authenticated |
|
72 | 72 | @json_errors |
|
73 | 73 | def patch(self, path='', name=None): |
|
74 | """patch is currently used strictly for notebook renaming. | |
|
75 | Changes the notebook name to the name given in data.""" | |
|
74 | """PATCH renames a notebook without re-uploading content.""" | |
|
76 | 75 | nbm = self.notebook_manager |
|
77 | 76 | if name is None: |
|
78 | 77 | raise web.HTTPError(400, u'Notebook name missing') |
@@ -90,10 +89,31 b' class NotebookHandler(IPythonHandler):' | |||
|
90 | 89 | @web.authenticated |
|
91 | 90 | @json_errors |
|
92 | 91 | def post(self, path='', name=None): |
|
93 |
"""Create a new notebook in the |
|
|
92 | """Create a new notebook in the specified path. | |
|
93 | ||
|
94 | POST creates new notebooks. | |
|
95 | ||
|
96 | POST /api/notebooks/path : new untitled notebook in path | |
|
97 | POST /api/notebooks/path/notebook.ipynb : new notebook with name in path | |
|
98 | If content specified upload notebook, otherwise start empty. | |
|
99 | """ | |
|
94 | 100 | nbm = self.notebook_manager |
|
95 | 101 | model = self.get_json_body() |
|
96 | model = nbm.create_notebook_model(model, path) | |
|
102 | if name is None: | |
|
103 | # creating new notebook, model doesn't make sense | |
|
104 | if model is not None: | |
|
105 | raise web.HTTPError(400, "Model not valid when creating untitled notebooks.") | |
|
106 | model = nbm.create_notebook_model(path=path) | |
|
107 | else: | |
|
108 | if model is None: | |
|
109 | self.log.info("Creating new Notebook at %s/%s", path, name) | |
|
110 | model = {} | |
|
111 | else: | |
|
112 | self.log.info("Uploading Notebook to %s/%s", path, name) | |
|
113 | # set the model name from the URL | |
|
114 | model['name'] = name | |
|
115 | model = nbm.create_notebook_model(model, path) | |
|
116 | ||
|
97 | 117 | location = self.notebook_location(model[u'name'], model[u'path']) |
|
98 | 118 | self.set_header(u'Location', location) |
|
99 | 119 | self.set_header(u'Last-Modified', model[u'last_modified']) |
@@ -120,6 +140,29 b' class NotebookHandler(IPythonHandler):' | |||
|
120 | 140 | self.set_status(204) |
|
121 | 141 | self.finish() |
|
122 | 142 | |
|
143 | class NotebookCopyHandler(IPythonHandler): | |
|
144 | ||
|
145 | SUPPORTED_METHODS = ('POST') | |
|
146 | ||
|
147 | @web.authenticated | |
|
148 | @json_errors | |
|
149 | def post(self, path='', name=None): | |
|
150 | """Copy an existing notebook.""" | |
|
151 | nbm = self.notebook_manager | |
|
152 | model = self.get_json_body() | |
|
153 | if name is None: | |
|
154 | raise web.HTTPError(400, "Notebook name required") | |
|
155 | self.log.info("Copying Notebook %s/%s", path, name) | |
|
156 | model = nbm.copy_notebook(name, path) | |
|
157 | location = url_path_join( | |
|
158 | self.base_project_url, 'api', 'notebooks', | |
|
159 | model['path'], model['name'], | |
|
160 | ) | |
|
161 | self.set_header(u'Location', location) | |
|
162 | self.set_header(u'Last-Modified', model[u'last_modified']) | |
|
163 | self.set_status(201) | |
|
164 | self.finish(json.dumps(model, default=date_default)) | |
|
165 | ||
|
123 | 166 | |
|
124 | 167 | class NotebookCheckpointsHandler(IPythonHandler): |
|
125 | 168 | |
@@ -180,6 +223,7 b' _notebook_name_regex = r"(?P<name>[^/]+\\.ipynb)"' | |||
|
180 | 223 | _notebook_path_regex = "%s/%s" % (_path_regex, _notebook_name_regex) |
|
181 | 224 | |
|
182 | 225 | default_handlers = [ |
|
226 | (r"/api/notebooks/?%s/copy" % _notebook_path_regex, NotebookCopyHandler), | |
|
183 | 227 | (r"/api/notebooks/?%s/checkpoints" % _notebook_path_regex, NotebookCheckpointsHandler), |
|
184 | 228 | (r"/api/notebooks/?%s/checkpoints/%s" % (_notebook_path_regex, _checkpoint_id_regex), |
|
185 | 229 | ModifyNotebookCheckpointsHandler), |
@@ -87,7 +87,7 b' class NotebookManager(LoggingConfigurable):' | |||
|
87 | 87 | """ |
|
88 | 88 | return basename |
|
89 | 89 | |
|
90 | def list_notebooks(self): | |
|
90 | def list_notebooks(self, path=''): | |
|
91 | 91 | """Return a list of notebook dicts without content. |
|
92 | 92 | |
|
93 | 93 | This returns a list of dicts, each of the form:: |
@@ -112,53 +112,51 b' class NotebookManager(LoggingConfigurable):' | |||
|
112 | 112 | """Update the notebook model and return the model with no content.""" |
|
113 | 113 | raise NotImplementedError('must be implemented in a subclass') |
|
114 | 114 | |
|
115 | def delete_notebook_model(self, name, path): | |
|
115 | def delete_notebook_model(self, name, path=''): | |
|
116 | 116 | """Delete notebook by name and path.""" |
|
117 | 117 | raise NotImplementedError('must be implemented in a subclass') |
|
118 | 118 | |
|
119 | 119 | def create_notebook_model(self, model=None, path=''): |
|
120 | 120 | """Create a new untitled notebook and return its model with no content.""" |
|
121 | untitled = self.increment_filename('Untitled', path) | |
|
122 | 121 | if model is None: |
|
123 | 122 | model = {} |
|
123 | if 'content' not in model: | |
|
124 | 124 | metadata = current.new_metadata(name=u'') |
|
125 |
|
|
|
126 | model['content'] = nb | |
|
127 |
model['name'] = name |
|
|
128 | model['path'] = path | |
|
129 | else: | |
|
130 | name = model.setdefault('name', untitled) | |
|
131 | model['path'] = path | |
|
132 | model = self.save_notebook_model(model, name, path) | |
|
125 | model['content'] = current.new_notebook(metadata=metadata) | |
|
126 | if 'name' not in model: | |
|
127 | model['name'] = self.increment_filename('Untitled', path) | |
|
128 | ||
|
129 | model['path'] = path | |
|
130 | model = self.save_notebook_model(model, model['name'], model['path']) | |
|
133 | 131 | return model |
|
134 | 132 | |
|
135 |
def copy_notebook(self, name, path=' |
|
|
133 | def copy_notebook(self, name, path=''): | |
|
136 | 134 | """Copy an existing notebook and return its new model.""" |
|
137 | 135 | model = self.get_notebook_model(name, path) |
|
138 | 136 | name = os.path.splitext(name)[0] + '-Copy' |
|
139 | 137 | name = self.increment_filename(name, path) + self.filename_ext |
|
140 | 138 | model['name'] = name |
|
141 |
model = self.save_notebook_model(model, name, path |
|
|
139 | model = self.save_notebook_model(model, name, path) | |
|
142 | 140 | return model |
|
143 | 141 | |
|
144 | 142 | # Checkpoint-related |
|
145 | 143 | |
|
146 |
def create_checkpoint(self, name, path=' |
|
|
144 | def create_checkpoint(self, name, path=''): | |
|
147 | 145 | """Create a checkpoint of the current state of a notebook |
|
148 | 146 | |
|
149 | 147 | Returns a checkpoint_id for the new checkpoint. |
|
150 | 148 | """ |
|
151 | 149 | raise NotImplementedError("must be implemented in a subclass") |
|
152 | 150 | |
|
153 |
def list_checkpoints(self, name, path=' |
|
|
151 | def list_checkpoints(self, name, path=''): | |
|
154 | 152 | """Return a list of checkpoints for a given notebook""" |
|
155 | 153 | return [] |
|
156 | 154 | |
|
157 |
def restore_checkpoint(self, checkpoint_id, name, path=' |
|
|
155 | def restore_checkpoint(self, checkpoint_id, name, path=''): | |
|
158 | 156 | """Restore a notebook from one of its checkpoints""" |
|
159 | 157 | raise NotImplementedError("must be implemented in a subclass") |
|
160 | 158 | |
|
161 |
def delete_checkpoint(self, checkpoint_id, name, path=' |
|
|
159 | def delete_checkpoint(self, checkpoint_id, name, path=''): | |
|
162 | 160 | """delete a checkpoint for a notebook""" |
|
163 | 161 | raise NotImplementedError("must be implemented in a subclass") |
|
164 | 162 |
@@ -1768,15 +1768,12 b' var IPython = (function (IPython) {' | |||
|
1768 | 1768 | |
|
1769 | 1769 | Notebook.prototype.copy_notebook = function(){ |
|
1770 | 1770 | var path = this.notebookPath(); |
|
1771 | var name = {'name': this.notebook_name} | |
|
1772 | 1771 | var settings = { |
|
1773 | 1772 | processData : false, |
|
1774 | 1773 | cache : false, |
|
1775 | 1774 | type : "POST", |
|
1776 | data: JSON.stringify(name), | |
|
1777 | dataType : "json", | |
|
1778 | 1775 | success:$.proxy(function (data, status, xhr){ |
|
1779 | notebook_name = data.name; | |
|
1776 | var notebook_name = data.name; | |
|
1780 | 1777 | window.open(utils.url_path_join( |
|
1781 | 1778 | this._baseProjectUrl, |
|
1782 | 1779 | 'notebooks', |
@@ -1787,8 +1784,10 b' var IPython = (function (IPython) {' | |||
|
1787 | 1784 | }; |
|
1788 | 1785 | var url = utils.url_path_join( |
|
1789 | 1786 | this._baseProjectUrl, |
|
1790 | 'notebooks', | |
|
1791 | path | |
|
1787 | 'api/notebooks', | |
|
1788 | path, | |
|
1789 | this.notebook_name, | |
|
1790 | 'copy' | |
|
1792 | 1791 | ); |
|
1793 | 1792 | $.ajax(url,settings); |
|
1794 | 1793 | }; |
@@ -312,7 +312,7 b' var IPython = (function (IPython) {' | |||
|
312 | 312 | var upload_button = $('<button/>').text("Upload") |
|
313 | 313 | .addClass('btn btn-primary btn-mini upload_button') |
|
314 | 314 | .click(function (e) { |
|
315 |
var nbname = item.find('.item_name > input'). |
|
|
315 | var nbname = item.find('.item_name > input').val(); | |
|
316 | 316 | var nbformat = item.data('nbformat'); |
|
317 | 317 | var nbdata = item.data('nbdata'); |
|
318 | 318 | var content_type = 'application/json'; |
@@ -323,8 +323,6 b' var IPython = (function (IPython) {' | |||
|
323 | 323 | } |
|
324 | 324 | var model = { |
|
325 | 325 | content : JSON.parse(nbdata), |
|
326 | name : nbname, | |
|
327 | path : that.notebookPath() | |
|
328 | 326 | }; |
|
329 | 327 | var settings = { |
|
330 | 328 | processData : false, |
@@ -345,7 +343,8 b' var IPython = (function (IPython) {' | |||
|
345 | 343 | var url = utils.url_path_join( |
|
346 | 344 | that.baseProjectUrl(), |
|
347 | 345 | 'api/notebooks', |
|
348 | that.notebookPath() | |
|
346 | that.notebookPath(), | |
|
347 | nbname + '.ipynb' | |
|
349 | 348 | ); |
|
350 | 349 | $.ajax(url, settings); |
|
351 | 350 | return false; |
General Comments 0
You need to be logged in to leave comments.
Login now