Browse files

Improvements to file uploaded, mime types and .py reader.

* The .py notebook reader now uses that ast module to split
  a plain python file into blocks. These blocks become cells in
  the notebook.
* Proper mime types are used for xml (application/xml), json
  (application/json) and python (application/x-python).
* Other fixes to file uploading.
  • Loading branch information...
1 parent 53c7ec7 commit 8f4eb628a7c787b686736d5f89917f79a79d9dfd @ellisonbg ellisonbg committed Aug 6, 2011
View
13 IPython/frontend/html/notebook/handlers.py
@@ -41,12 +41,12 @@ def get(self, notebook_id):
class KernelHandler(web.RequestHandler):
def get(self):
- self.write(json.dumps(self.application.kernel_ids))
+ self.finish(json.dumps(self.application.kernel_ids))
def post(self):
kernel_id = self.application.start_kernel()
self.set_header('Location', '/'+kernel_id)
- self.write(json.dumps(kernel_id))
+ self.finish(json.dumps(kernel_id))
class KernelActionHandler(web.RequestHandler):
@@ -58,6 +58,7 @@ def post(self, kernel_id, action):
if action == 'restart':
new_kernel_id = self.application.restart_kernel(kernel_id)
self.write(json.dumps(new_kernel_id))
+ self.finish()
class ZMQStreamHandler(websocket.WebSocketHandler):
@@ -83,7 +84,7 @@ class NotebookRootHandler(web.RequestHandler):
def get(self):
nbm = self.application.notebook_manager
files = nbm.list_notebooks()
- self.write(json.dumps(files))
+ self.finish(json.dumps(files))
def post(self):
nbm = self.application.notebook_manager
@@ -95,7 +96,7 @@ def post(self):
else:
notebook_id = nbm.new_notebook()
self.set_header('Location', '/'+notebook_id)
- self.write(json.dumps(notebook_id))
+ self.finish(json.dumps(notebook_id))
class NotebookHandler(web.RequestHandler):
@@ -110,10 +111,10 @@ def get(self, notebook_id):
self.set_header('Content-Type', 'application/json')
self.set_header('Content-Disposition','attachment; filename=%s.json' % name)
elif format == u'xml':
- self.set_header('Content-Type', 'text/xml')
+ self.set_header('Content-Type', 'application/xml')
self.set_header('Content-Disposition','attachment; filename=%s.ipynb' % name)
elif format == u'py':
- self.set_header('Content-Type', 'text/plain')
+ self.set_header('Content-Type', 'application/x-python')
self.set_header('Content-Disposition','attachment; filename=%s.py' % name)
self.set_header('Last-Modified', last_mod)
self.finish(data)
View
11 IPython/frontend/html/notebook/static/js/notebook.js
@@ -559,11 +559,12 @@ var IPython = (function (IPython) {
data.id = notebook_id
// We do the call with settings so we can set cache to false.
var settings = {
- processData : false,
- cache : false,
- type : "PUT",
- data : JSON.stringify(data),
- success : $.proxy(this.notebook_saved,this)
+ processData : false,
+ cache : false,
+ type : "PUT",
+ data : JSON.stringify(data),
+ headers : {'Content-Type': 'application/json'},
+ success : $.proxy(this.notebook_saved,this)
};
IPython.save_widget.status_saving();
$.ajax("/notebooks/" + notebook_id, settings);
View
15 IPython/frontend/html/notebook/static/js/notebooklist.js
@@ -191,20 +191,29 @@ var IPython = (function (IPython) {
var nbname = item.find('.item_name > input').attr('value');
var nbformat = item.data('nbformat');
var nbdata = item.data('nbdata');
+ var content_type = 'text/plain';
+ if (nbformat === 'xml') {
+ content_type = 'application/xml';
+ } else if (nbformat === 'json') {
+ content_type = 'application/json';
+ } else if (nbformat === 'py') {
+ content_type = 'application/x-python';
+ };
var settings = {
processData : false,
cache : false,
- type : "POST",
- dataType : "json",
+ type : 'POST',
+ dataType : 'json',
data : nbdata,
+ headers : {'Content-Type': content_type},
success : function (data, status, xhr) {
that.add_link(data, nbname, item);
that.add_delete_button(item);
}
};
var qs = $.param({name:nbname, format:nbformat});
- $.ajax("/notebooks?" + qs, settings);
+ $.ajax('/notebooks?' + qs, settings);
});
var cancel_button = $('<button>Cancel</button>').button().
click(function (e) {
View
2 IPython/nbformat/current.py
@@ -43,7 +43,7 @@ def parse_py(s, **kwargs):
if m is not None:
nbformat = int(m.group('nbformat'))
else:
- raise NBFormatError('No nbformat version found')
+ nbformat = 2
return nbformat, s
View
26 IPython/nbformat/v2/nbpy.py
@@ -4,6 +4,10 @@
from .nbbase import new_code_cell, new_worksheet, new_notebook
+class PyReaderError(Exception):
+ pass
+
+
class PyReader(NotebookReader):
def reads(self, s, **kwargs):
@@ -13,20 +17,42 @@ def to_notebook(self, s, **kwargs):
lines = s.splitlines()
cells = []
cell_lines = []
+ code_cell = False
for line in lines:
if line.startswith(u'# <codecell>'):
+ if code_cell:
+ raise PyReaderError('Unexpected <codecell>')
+ if cell_lines:
+ for block in self.split_lines_into_blocks(cell_lines):
+ cells.append(new_code_cell(input=block))
cell_lines = []
+ code_cell = True
if line.startswith(u'# </codecell>'):
+ if not code_cell:
+ raise PyReaderError('Unexpected </codecell>')
code = u'\n'.join(cell_lines)
code = code.strip(u'\n')
if code:
cells.append(new_code_cell(input=code))
+ code_cell = False
else:
cell_lines.append(line)
+ # For lines we were not able to process,
+ for block in self.split_lines_into_blocks(cell_lines):
+ cells.append(new_code_cell(input=block))
ws = new_worksheet(cells=cells)
nb = new_notebook(worksheets=[ws])
return nb
+ def split_lines_into_blocks(self, lines):
+ import ast
+ source = '\n'.join(lines)
+ code = ast.parse(source)
+ starts = [x.lineno-1 for x in code.body]
+ for i in range(len(starts)-1):
+ yield '\n'.join(lines[starts[i]:starts[i+1]]).strip('\n')
+ yield '\n'.join(lines[starts[-1]:]).strip('\n')
+
class PyWriter(NotebookWriter):
View
1 IPython/nbformat/v2/tests/test_nbpy.py
@@ -15,4 +15,3 @@ def test_write(self):
s = writes(nb0)
self.assertEquals(s,nb0_py)
-

0 comments on commit 8f4eb62

Please sign in to comment.