nbpy.py
200 lines
| 7.2 KiB
| text/x-python
|
PythonLexer
Brian E. Granger
|
r4609 | """Read and write notebooks as regular .py files. | ||
Authors: | ||||
* Brian Granger | ||||
""" | ||||
#----------------------------------------------------------------------------- | ||||
# Copyright (C) 2008-2011 The IPython Development Team | ||||
# | ||||
# Distributed under the terms of the BSD License. The full license is in | ||||
# the file COPYING, distributed as part of this software. | ||||
#----------------------------------------------------------------------------- | ||||
#----------------------------------------------------------------------------- | ||||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
Brian E. Granger
|
r4392 | |||
Thomas Kluyver
|
r5739 | import re | ||
Brian E. Granger
|
r4401 | from .rwbase import NotebookReader, NotebookWriter | ||
Brian Granger
|
r6016 | from .nbbase import ( | ||
new_code_cell, new_text_cell, new_worksheet, | ||||
new_notebook, new_heading_cell | ||||
) | ||||
Brian E. Granger
|
r4392 | |||
Brian E. Granger
|
r4609 | #----------------------------------------------------------------------------- | ||
# Code | ||||
#----------------------------------------------------------------------------- | ||||
Brian E. Granger
|
r4392 | |||
Thomas Kluyver
|
r5745 | _encoding_declaration_re = re.compile(r"^#.*coding[:=]\s*([-\w.]+)") | ||
Thomas Kluyver
|
r5739 | |||
Brian E. Granger
|
r4493 | class PyReaderError(Exception): | ||
pass | ||||
Brian E. Granger
|
r4392 | class PyReader(NotebookReader): | ||
Brian E. Granger
|
r4401 | def reads(self, s, **kwargs): | ||
Brian E. Granger
|
r4406 | return self.to_notebook(s,**kwargs) | ||
def to_notebook(self, s, **kwargs): | ||||
Brian E. Granger
|
r4392 | lines = s.splitlines() | ||
cells = [] | ||||
cell_lines = [] | ||||
Brian Granger
|
r6016 | kwargs = {} | ||
Brian E. Granger
|
r4536 | state = u'codecell' | ||
Brian E. Granger
|
r4392 | for line in lines: | ||
Thomas Kluyver
|
r5739 | if line.startswith(u'# <nbformat>') or _encoding_declaration_re.match(line): | ||
Brian E. Granger
|
r4520 | pass | ||
elif line.startswith(u'# <codecell>'): | ||||
Brian Granger
|
r6016 | cell = self.new_cell(state, cell_lines, **kwargs) | ||
Brian E. Granger
|
r4536 | if cell is not None: | ||
cells.append(cell) | ||||
state = u'codecell' | ||||
cell_lines = [] | ||||
Brian Granger
|
r6016 | kwargs = {} | ||
Bernardo B. Marques
|
r4872 | elif line.startswith(u'# <htmlcell>'): | ||
Brian Granger
|
r6016 | cell = self.new_cell(state, cell_lines, **kwargs) | ||
Brian E. Granger
|
r4536 | if cell is not None: | ||
cells.append(cell) | ||||
state = u'htmlcell' | ||||
cell_lines = [] | ||||
Brian Granger
|
r6016 | kwargs = {} | ||
Brian E. Granger
|
r4536 | elif line.startswith(u'# <markdowncell>'): | ||
Brian Granger
|
r6016 | cell = self.new_cell(state, cell_lines, **kwargs) | ||
Brian E. Granger
|
r4536 | if cell is not None: | ||
cells.append(cell) | ||||
state = u'markdowncell' | ||||
Brian E. Granger
|
r4406 | cell_lines = [] | ||
Brian Granger
|
r6016 | kwargs = {} | ||
elif line.startswith(u'# <rstcell>'): | ||||
cell = self.new_cell(state, cell_lines, **kwargs) | ||||
if cell is not None: | ||||
cells.append(cell) | ||||
state = u'rstcell' | ||||
cell_lines = [] | ||||
kwargs = {} | ||||
elif line.startswith(u'# <headingcell'): | ||||
cell = self.new_cell(state, cell_lines, **kwargs) | ||||
if cell is not None: | ||||
cells.append(cell) | ||||
cell_lines = [] | ||||
m = re.match(r'# <headingcell level=(?P<level>\d)>',line) | ||||
if m is not None: | ||||
state = u'headingcell' | ||||
kwargs = {} | ||||
kwargs['level'] = int(m.group('level')) | ||||
else: | ||||
state = u'codecell' | ||||
kwargs = {} | ||||
cell_lines = [] | ||||
Brian E. Granger
|
r4392 | else: | ||
cell_lines.append(line) | ||||
Brian E. Granger
|
r4536 | if cell_lines and state == u'codecell': | ||
cell = self.new_cell(state, cell_lines) | ||||
if cell is not None: | ||||
cells.append(cell) | ||||
Brian E. Granger
|
r4392 | ws = new_worksheet(cells=cells) | ||
nb = new_notebook(worksheets=[ws]) | ||||
return nb | ||||
Brian Granger
|
r6016 | def new_cell(self, state, lines, **kwargs): | ||
Brian E. Granger
|
r4536 | if state == u'codecell': | ||
input = u'\n'.join(lines) | ||||
input = input.strip(u'\n') | ||||
if input: | ||||
return new_code_cell(input=input) | ||||
elif state == u'htmlcell': | ||||
text = self._remove_comments(lines) | ||||
if text: | ||||
return new_text_cell(u'html',source=text) | ||||
elif state == u'markdowncell': | ||||
text = self._remove_comments(lines) | ||||
if text: | ||||
return new_text_cell(u'markdown',source=text) | ||||
Brian Granger
|
r6016 | elif state == u'rstcell': | ||
text = self._remove_comments(lines) | ||||
if text: | ||||
return new_text_cell(u'rst',source=text) | ||||
elif state == u'headingcell': | ||||
text = self._remove_comments(lines) | ||||
level = kwargs.get('level',1) | ||||
if text: | ||||
return new_heading_cell(source=text,level=level) | ||||
Brian E. Granger
|
r4536 | |||
def _remove_comments(self, lines): | ||||
new_lines = [] | ||||
for line in lines: | ||||
if line.startswith(u'#'): | ||||
new_lines.append(line[2:]) | ||||
else: | ||||
new_lines.append(line) | ||||
text = u'\n'.join(new_lines) | ||||
text = text.strip(u'\n') | ||||
return text | ||||
Brian E. Granger
|
r4493 | def split_lines_into_blocks(self, lines): | ||
Brian E. Granger
|
r4520 | if len(lines) == 1: | ||
yield lines[0] | ||||
raise StopIteration() | ||||
Brian E. Granger
|
r4493 | 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') | ||||
Brian E. Granger
|
r4392 | |||
class PyWriter(NotebookWriter): | ||||
Brian E. Granger
|
r4401 | def writes(self, nb, **kwargs): | ||
Thomas Kluyver
|
r5745 | lines = [u'# -*- coding: utf-8 -*-'] | ||
Thomas Kluyver
|
r5742 | lines.extend([u'# <nbformat>2</nbformat>','']) | ||
Brian E. Granger
|
r4401 | for ws in nb.worksheets: | ||
for cell in ws.cells: | ||||
Brian E. Granger
|
r4536 | if cell.cell_type == u'code': | ||
input = cell.get(u'input') | ||||
Brian E. Granger
|
r4484 | if input is not None: | ||
lines.extend([u'# <codecell>',u'']) | ||||
lines.extend(input.splitlines()) | ||||
Brian E. Granger
|
r4536 | lines.append(u'') | ||
elif cell.cell_type == u'html': | ||||
input = cell.get(u'source') | ||||
if input is not None: | ||||
lines.extend([u'# <htmlcell>',u'']) | ||||
lines.extend([u'# ' + line for line in input.splitlines()]) | ||||
lines.append(u'') | ||||
elif cell.cell_type == u'markdown': | ||||
input = cell.get(u'source') | ||||
if input is not None: | ||||
lines.extend([u'# <markdowncell>',u'']) | ||||
lines.extend([u'# ' + line for line in input.splitlines()]) | ||||
lines.append(u'') | ||||
Brian Granger
|
r6016 | elif cell.cell_type == u'rst': | ||
input = cell.get(u'source') | ||||
if input is not None: | ||||
lines.extend([u'# <rstcell>',u'']) | ||||
lines.extend([u'# ' + line for line in input.splitlines()]) | ||||
lines.append(u'') | ||||
elif cell.cell_type == u'heading': | ||||
input = cell.get(u'source') | ||||
level = cell.get(u'level',1) | ||||
if input is not None: | ||||
lines.extend([u'# <headingcell level=%s>' % level,u'']) | ||||
lines.extend([u'# ' + line for line in input.splitlines()]) | ||||
lines.append(u'') | ||||
Brian E. Granger
|
r4406 | lines.append('') | ||
Brian E. Granger
|
r4401 | return unicode('\n'.join(lines)) | ||
Brian E. Granger
|
r4392 | |||
_reader = PyReader() | ||||
_writer = PyWriter() | ||||
reads = _reader.reads | ||||
read = _reader.read | ||||
Brian E. Granger
|
r4406 | to_notebook = _reader.to_notebook | ||
Brian E. Granger
|
r4392 | write = _writer.write | ||
writes = _writer.writes | ||||
Brian E. Granger
|
r4406 | |||