Permalink
Browse files

Created new notebook magic that can export/convert notebooks.

* %notebook --export foo will export the current IPython history
  to a file foo.ipynb.
* %notebook --format=json foo.ipynb will convert foo.ipynb to
  foo.json.
  • Loading branch information...
1 parent 53df0ac commit 46fc64626bfe916358e0d4337120ac942afff8a3 @ellisonbg ellisonbg committed Aug 10, 2011
Showing with 120 additions and 9 deletions.
  1. +65 −0 IPython/core/magic.py
  2. +2 −1 IPython/nbformat/current.py
  3. +36 −0 IPython/nbformat/v2/__init__.py
  4. +17 −8 IPython/nbformat/v2/nbpy.py
View
@@ -48,6 +48,7 @@
from IPython.core.fakemodule import FakeModule
from IPython.core.profiledir import ProfileDir
from IPython.core.macro import Macro
+from IPython.core import magic_arguments
from IPython.core import page
from IPython.core.prefilter import ESC_MAGIC
from IPython.lib.pylabtools import mpl_runner
@@ -3495,4 +3496,68 @@ def magic_precision(self, s=''):
ptformatter.float_precision = s
return ptformatter.float_format
+
+ @magic_arguments.magic_arguments()
+ @magic_arguments.argument(
+ '-e', '--export', action='store_true', default=False,
+ help='Export IPython history as a notebook. The filename argument '
+ 'is used to specify the notebook name and format. For example '
+ 'a filename of notebook.ipynb will result in a notebook name '
+ 'of "notebook" and a format of "xml". Likewise using a ".json" '
+ 'or ".py" file extension will write the notebook in the json '
+ 'or py formats.'
+ )
+ @magic_arguments.argument(
+ '-f', '--format',
+ help='Convert an existing IPython notebook to a new format. This option '
+ 'specifies the new format and can have the values: xml, json, py. '
+ 'The target filename is choosen automatically based on the new '
+ 'format. The filename argument gives the name of the source file.'
+ )
+ @magic_arguments.argument(
+ 'filename', type=unicode,
+ help='Notebook name or filename'
+ )
+ def magic_notebook(self, s):
+ """Export and convert IPython notebooks.
+
+ This function can export the current IPython history to a notebook file
+ or can convert an existing notebook file into a different format. For
+ example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb".
+ To export the history to "foo.py" do "%notebook -e foo.py". To convert
+ "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible
+ formats include (xml/ipynb, json, py).
+ """
+ args = magic_arguments.parse_argstring(self.magic_notebook, s)
+ print args
+
+ from IPython.nbformat import current
+ if args.export:
+ fname, name, format = current.parse_filename(args.filename)
+ cells = []
+ hist = list(self.history_manager.get_range())
+ for session, prompt_number, input in hist[:-1]:
+ cells.append(current.new_code_cell(prompt_number=prompt_number, input=input))
+ worksheet = current.new_worksheet(cells=cells)
+ nb = current.new_notebook(name=name,worksheets=[worksheet])
+ with open(fname, 'w') as f:
+ current.write(nb, f, format);
+ elif args.format is not None:
+ old_fname, old_name, old_format = current.parse_filename(args.filename)
+ new_format = args.format
+ if new_format == u'xml' or new_format == u'ipynb':
+ new_fname = old_name + u'.ipynb'
+ new_format = u'xml'
+ elif new_format == u'py':
+ new_fname = old_name + u'.py'
+ elif new_format == u'json':
+ new_fname = old_name + u'.json'
+ else:
+ raise ValueError('Invalid notebook format: %s' % newformat)
+ with open(old_fname, 'r') as f:
+ nb = current.read(f, old_format)
+ with open(new_fname, 'w') as f:
+ current.write(nb, f, new_format)
+
+
# end Magic
@@ -7,7 +7,8 @@
from IPython.nbformat.v2 import (
NotebookNode,
- new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet
+ new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet,
+ parse_filename
)
@@ -19,3 +19,39 @@
from .convert import convert_to_this_nbformat
+def parse_filename(fname):
+ """Parse a notebook filename.
+
+ This function takes a notebook filename and returns the notebook
+ format (xml/json/py) and the notebook name. This logic can be
+ summarized as follows:
+
+ * notebook.ipynb -> (notebook.ipynb, notebook, xml)
+ * notebook.json -> (notebook.json, notebook, json)
+ * notebook.py -> (notebook.py, notebook, py)
+ * notebook -> (notebook.ipynb, notebook, xml)
+
+ Parameters
+ ----------
+ fname : unicode
+ The notebook filename. The filename can use a specific filename
+ extention (.ipynb, .json, .py) or none, in which case .ipynb will
+ be assumed.
+
+ Returns
+ -------
+ (fname, name, format) : (unicode, unicode, unicode)
+ The filename, notebook name and format.
+ """
+ if fname.endswith(u'.ipynb'):
+ format = u'xml'
+ elif fname.endswith(u'.json'):
+ format = u'json'
+ elif fname.endswith(u'.py'):
+ format = u'py'
+ else:
+ fname = fname + u'.ipynb'
+ format = u'xml'
+ name = fname.split('.')[0]
+ return fname, name, format
+
@@ -19,15 +19,19 @@ def to_notebook(self, s, **kwargs):
cell_lines = []
code_cell = False
for line in lines:
- if line.startswith(u'# <codecell>'):
+ if line.startswith(u'# <nbformat>'):
+ pass
+ elif 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))
+ # We can't use the ast to split blocks because there can be
+ # IPython syntax in the files.
+ # 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>'):
+ elif line.startswith(u'# </codecell>'):
if not code_cell:
raise PyReaderError('Unexpected </codecell>')
code = u'\n'.join(cell_lines)
@@ -37,14 +41,19 @@ def to_notebook(self, s, **kwargs):
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))
+ # We can't use the ast to split blocks because there can be
+ # IPython syntax in the files.
+ # if cell_lines:
+ # 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):
+ if len(lines) == 1:
+ yield lines[0]
+ raise StopIteration()
import ast
source = '\n'.join(lines)
code = ast.parse(source)

0 comments on commit 46fc646

Please sign in to comment.