##// END OF EJS Templates
more doc and future API
more doc and future API

File last commit:

r9494:2abd4893
r9527:0d83c7e3
Show More
transformers.py
328 lines | 10.5 KiB | text/x-python | PythonLexer
"""
"""
from __future__ import print_function
from IPython.config.configurable import Configurable
from IPython.utils.traitlets import Unicode, Bool, Dict, List
class ConfigurableTransformers(Configurable):
""" A configurable transformer """
def __init__(self, config=None, **kw):
super(ConfigurableTransformers, self).__init__(config=config, **kw)
def __call__(self, nb, other):
try :
for worksheet in nb.worksheets :
for index, cell in enumerate(worksheet.cells):
worksheet.cells[index], other = self.cell_transform(cell, other, index)
return nb, other
except NotImplementedError:
raise NotImplementedError('should be implemented by subclass')
def cell_transform(self, cell, other, index):
"""
Overwrite if you want to apply a transformation on each cell
"""
raise NotImplementedError('should be implemented by subclass')
class ActivatableTransformer(ConfigurableTransformers):
enabled = Bool(False, config=True)
def __call__(self, nb, other):
if not self.enabled :
return nb, other
else :
return super(ActivatableTransformer, self).__call__(nb, other)
def cell_preprocessor(function):
""" wrap a function to be executed on all cells of a notebook
wrapped function parameters :
cell : the cell
other : external resources
index : index of the cell
"""
def wrappedfunc(nb, other):
for worksheet in nb.worksheets :
for index, cell in enumerate(worksheet.cells):
worksheet.cells[index], other = function(cell, other, index)
return nb, other
return wrappedfunc
@cell_preprocessor
def haspyout_transformer(cell, other, count):
"""
Add a haspyout flag to cell that have it
Easier for templating, where you can't know in advance
wether to write the out prompt
"""
cell.type = cell.cell_type
cell.haspyout = False
for out in cell.get('outputs', []):
if out.output_type == 'pyout':
cell.haspyout = True
break
return cell, other
@cell_preprocessor
def coalesce_streams(cell, other, count):
"""merge consecutive sequences of stream output into single stream
to prevent extra newlines inserted at flush calls
TODO: handle \r deletion
"""
outputs = cell.get('outputs', [])
if not outputs:
return cell, other
new_outputs = []
last = outputs[0]
new_outputs = [last]
for output in outputs[1:]:
if (output.output_type == 'stream' and
last.output_type == 'stream' and
last.stream == output.stream
):
last.text += output.text
else:
new_outputs.append(output)
cell.outputs = new_outputs
return cell, other
class ExtractFigureTransformer(ActivatableTransformer):
extra_ext_map = Dict({},
config=True,
help="""extra map to override extension based on type.
Usefull for latex where svg will be converted to pdf before inclusion
"""
)
display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
config=True,
help= """
An ordered list of prefered output type, the first
encounterd will usually be used when converting discarding
the others.
"""
)
key_format_map = Dict({},
config=True,
)
figname_format_map = Dict({},
config=True,
)
#to do change this to .format {} syntax
default_key_tpl = Unicode('_fig_{count:02d}.{ext}', config=True)
def _get_ext(self, ext):
if ext in self.extra_ext_map :
return self.extra_ext_map[ext]
return ext
def _new_figure(self, data, fmt, count):
"""Create a new figure file in the given format.
"""
tplf = self.figname_format_map.get(fmt,self.default_key_tpl)
tplk = self.key_format_map.get(fmt,self.default_key_tpl)
# option to pass the hash as data ?
figname = tplf.format(count=count, ext=self._get_ext(fmt))
key = tplk.format(count=count, ext=self._get_ext(fmt))
# Binary files are base64-encoded, SVG is already XML
if fmt in ('png', 'jpg', 'pdf'):
data = data.decode('base64')
return figname, key, data
def cell_transform(self, cell, other, count):
if other.get('figures', None) is None :
other['figures'] = {}
for out in cell.get('outputs', []):
for out_type in self.display_data_priority:
if out.hasattr(out_type):
figname, key, data = self._new_figure(out[out_type], out_type, count)
out['key_'+out_type] = figname
other['figures'][key] = data
count = count+1
return cell, other
class RevealHelpTransformer(ConfigurableTransformers):
section_open = False
subsection_open = False
fragment_open = False
def open_subsection(self):
self.subsection_open = True
return True
def open_section(self):
self.section_open = True
return True
def open_fragment(self):
self.fragment_open = True
return True
# could probaly write those maybe_close/open
# with a function functor
def maybe_close_section(self):
"""return True is already open, false otherwise
and change state to close
"""
if self.section_open :
self.section_open = False
return True
else :
return False
def maybe_open_section(self):
"""return True is already open, false otherwise
and change state to close
"""
if not self.section_open :
self.section_open = True
return True
else :
return False
def maybe_open_subsection(self):
"""return True is already open, false otherwise
and change state to close
"""
if not self.subsection_open :
self.subsection_open = True
return True
else :
return False
def maybe_close_subsection(self):
"""return True is already open, false otherwise
and change state to close
"""
if self.subsection_open :
self.subsection_open = False
return True
else :
return False
def maybe_close_fragment(self):
"""return True is already open, false otherwise
and change state to close
"""
if self.fragment_open :
self.fragment_open = False
return True
else :
return False
def cell_transform(self, cell, other, count):
ctype = cell.metadata.get('slideshow', {}).get('slide_type', None)
if ctype in [None, '-'] :
cell.metadata.slideshow = {}
cell.metadata.slideshow['slide_type'] = None
elif ctype == 'fragment':
cell.metadata.slideshow.close_fragment = self.maybe_close_fragment()
cell.metadata.slideshow.close_subsection = False
cell.metadata.slideshow.close_section = False
cell.metadata.slideshow.open_section = self.maybe_open_section()
cell.metadata.slideshow.open_subsection = self.maybe_open_subsection()
cell.metadata.slideshow.open_fragment = self.open_fragment()
elif ctype == 'subslide':
cell.metadata.slideshow.close_fragment = self.maybe_close_fragment()
cell.metadata.slideshow.close_subsection = self.maybe_close_subsection()
cell.metadata.slideshow.close_section = False
cell.metadata.slideshow.open_section = self.maybe_open_section()
cell.metadata.slideshow.open_subsection = self.open_subsection()
cell.metadata.slideshow.open_fragment = False
elif ctype == 'slide':
cell.metadata.slideshow.close_fragment = self.maybe_close_fragment()
cell.metadata.slideshow.close_subsection = self.maybe_close_subsection()
cell.metadata.slideshow.close_section = self.maybe_close_section()
cell.metadata.slideshow.open_section = self.open_section()
cell.metadata.slideshow.open_subsection = self.open_subsection()
cell.metadata.slideshow.open_fragment = False
return cell, other
class CSSHtmlHeaderTransformer(ActivatableTransformer):
def __call__(self, nb, resources):
"""Fetch and add css to the resource dict
Fetch css from IPython adn Pygment to add at the beginning
of the html files.
Add this css in resources in the "inlining.css" key
"""
resources['inlining'] = {}
resources['inlining']['css'] = self.header
return nb, resources
header = []
def __init__(self, config=None, **kw):
super(CSSHtmlHeaderTransformer, self).__init__(config=config, **kw)
if self.enabled :
self.regen_header()
def regen_header(self):
## lazy load asa this might not be use in many transformers
import os
from IPython.utils import path
import io
from pygments.formatters import HtmlFormatter
header = []
static = os.path.join(path.get_ipython_package_dir(),
'frontend', 'html', 'notebook', 'static',
)
here = os.path.split(os.path.realpath(__file__))[0]
css = os.path.join(static, 'css')
for sheet in [
# do we need jquery and prettify?
# os.path.join(static, 'jquery', 'css', 'themes', 'base',
# 'jquery-ui.min.css'),
# os.path.join(static, 'prettify', 'prettify.css'),
os.path.join(css, 'boilerplate.css'),
os.path.join(css, 'fbm.css'),
os.path.join(css, 'notebook.css'),
os.path.join(css, 'renderedhtml.css'),
os.path.join(css, 'style.min.css'),
# our overrides:
os.path.join(here, '..', 'css', 'static_html.css'),
]:
try:
with io.open(sheet, encoding='utf-8') as f:
s = f.read()
header.append(s)
except IOError:
# new version of ipython with style.min.css, pass
pass
pygments_css = HtmlFormatter().get_style_defs('.highlight')
header.append(pygments_css)
self.header = header