2016-03-04 39 views
3

我有一个Jupyter笔记本,其包括像这样在降价细胞蟒变量直列降价:执行一个Jupyter笔记本包括与nbconvert

码单元:

x = 10 

降价细胞:

The value of x is {{x}}. 

IPython-notebook-extension Python Markdown允许我动态显示这些变量,如果我在笔记本中使用shift-enter执行降格单元格。

降价细胞:

The value of x is 10. 

我想以编程方式执行所有电池在笔记本电脑和使用这样的事情将它们保存到一个新的笔记本:

import nbformat 
from nbconvert.preprocessors import ExecutePreprocessor 

with open('report.ipynb') as f: 
    nb = nbformat.read(f, as_version=4) 
     ep = ExecutePreprocessor(timeout=600, kernel_name='python3') 
     ep.preprocess(nb, {}) 
with open('report_executed.ipynb', 'wt') as f: 
    nbformat.write(nb, f) 

这将执行代码细胞但不是降价单元格。他们仍然是这样的:

The value of x is {{x}}. 

我认为问题是笔记本电脑不受信任。有没有办法告诉ExecutePreprocessor信任笔记本?是否有另一种方式来编程执行包含降格单元格中的python变量的笔记本?

+1

将变量放入降价单元的笔记本扩展可能不会影响使用ExecutePreprocessor运行笔记本。 –

回答

3

ExecutePreprocessor only looks at code cells,所以你的减价单元格是完全不变的。如您所述,要进行降价处理,您需要使用Python Markdown预处理器。

不幸的是,Python Markdown预处理器系统仅执行实时笔记本中的代码,它在modifying the javascript involved with rendering cells中执行代码。修改将代码片断的执行结果存储在单元元数据中。

PyMarkdownPreprocessor类(pre_pymarkdown.py)设计用于在笔记本电脑上运行的nbconvert,该笔记本电脑已在现场笔记本电脑设置中首先渲染。它处理降价单元格,用存储在元数据中的值替换{{}}模式。

但是,在您的情况下,您没有实时笔记本元数据。我也有类似的问题,我写我自己的执行预处理器,其中还包括逻辑来处理降价细胞解决了这个问题:

from nbconvert.preprocessors import ExecutePreprocessor, Preprocessor 
import nbformat, nbconvert 
from textwrap import dedent 

class ExecuteCodeMarkdownPreprocessor(ExecutePreprocessor): 

    def __init__(self, **kw): 
     self.sections = {'default': True} # maps section ID to true or false 
     self.EmptyCell = nbformat.v4.nbbase.new_raw_cell("") 

     return super().__init__(**kw) 

    def preprocess_cell(self, cell, resources, cell_index): 
     """ 
     Executes a single code cell. See base.py for details. 
     To execute all cells see :meth:`preprocess`. 
     """ 

     if cell.cell_type not in ['code','markdown']: 
      return cell, resources 

     if cell.cell_type == 'code': 
      # Do code stuff 
      return self.preprocess_code_cell(cell, resources, cell_index) 

     elif cell.cell_type == 'markdown': 
      # Do markdown stuff 
      return self.preprocess_markdown_cell(cell, resources, cell_index) 
     else: 
      # Don't do anything 
      return cell, resources 

    def preprocess_code_cell(self, cell, resources, cell_index): 
     ''' Process code cell. 
     ''' 
     outputs = self.run_cell(cell) 
     cell.outputs = outputs 

     if not self.allow_errors: 
      for out in outputs: 
       if out.output_type == 'error': 
        pattern = u"""\ 
         An error occurred while executing the following cell: 
         ------------------ 
         {cell.source} 
         ------------------ 
         {out.ename}: {out.evalue} 
         """ 
        msg = dedent(pattern).format(out=out, cell=cell) 
        raise nbconvert.preprocessors.execute.CellExecutionError(msg) 

     return cell, resources 

    def preprocess_markdown_cell(self, cell, resources, cell_index): 
     # Find and execute snippets of code 
     cell['metadata']['variables'] = {} 
     for m in re.finditer("{{(.*?)}}", cell.source): 
      # Execute code 
      fakecell = nbformat.v4.nbbase.new_code_cell(m.group(1)) 
      fakecell, resources = self.preprocess_code_cell(fakecell, resources, cell_index) 

      # Output found in cell.outputs 
      # Put output in cell['metadata']['variables'] 
      for output in fakecell.outputs: 
       html = self.convert_output_to_html(output) 
       if html is not None: 
        cell['metadata']['variables'][fakecell.source] = html 
        break 
     return cell, resources 

    def convert_output_to_html(self, output): 
     '''Convert IOpub output to HTML 

     See https://github.com/ipython-contrib/IPython-notebook-extensions/blob/master/nbextensions/usability/python-markdown/main.js 
     ''' 
     if output['output_type'] == 'error': 
      text = '**' + output.ename + '**: ' + output.evalue; 
      return text 
     elif output.output_type == 'execute_result' or output.output_type == 'display_data': 
      data = output.data 
      if 'text/latex' in data: 
       html = data['text/latex'] 
       return html 
      elif 'image/svg+xml' in data: 
       # Not supported 
       #var svg = ul['image/svg+xml']; 
       #/* embed SVG in an <img> tag, still get eaten by sanitizer... */ 
       #svg = btoa(svg); 
       #html = '<img src="data:image/svg+xml;base64,' + svg + '"/>'; 
       return None 
      elif 'image/jpeg' in data: 
       jpeg = data['image/jpeg'] 
       html = '<img src="data:image/jpeg;base64,' + jpeg + '"/>' 
       return html 
      elif 'image/png' in data: 
       png = data['image/png'] 
       html = '<img src="data:image/png;base64,' + png + '"/>' 
       return html 
      elif 'text/markdown' in data: 
       text = data['text/markdown'] 
       return text 
      elif 'text/html' in data: 
       html = data['text/html'] 
       return html 
      elif 'text/plain' in data: 
       text = data['text/plain'] 
       # Strip <p> and </p> tags 
       # Strip quotes 
       # html.match(/<p>([\s\S]*?)<\/p>/)[1] 
       text = re.sub(r'<p>([\s\S]*?)<\/p>', r'\1', text) 
       text = re.sub(r"'([\s\S]*?)'",r'\1', text) 
       return text 
      else: 
      # Some tag we don't support 
       return None 
     else: 
      return None 

然后,您可以处理你与类似于您发布的代码逻辑笔记本:

import nbformat 
from nbconvert.preprocessors import ExecutePreprocessor 
import ExecuteCodeMarkdownPreprocessor # from wherever you put it 
import PyMarkdownPreprocessor # from pre_pymarkdown.py 

with open('report.ipynb') as f: 
    nb = nbformat.read(f, as_version=4) 
    ep = ExecuteCodeMarkdownPreprocessor(timeout=600, kernel_name='python3') 
    ep.preprocess(nb, {}) 
    pymk = PyMarkdownPreprocessor() 
    pymk.preprocess(nb, {}) 

with open('report_executed.ipynb', 'wt') as f: 
    nbformat.write(nb, f) 

请注意,通过包含Python Markdown预处理,您的结果笔记本文件在降格单元格中将不再具有{{}}语法 - 降格将具有静态内容。如果生成笔记本的收件人更改了代码并再次执行,则减价不会更新。但是,如果要导出为其他格式(例如HTML),那么您确实需要用静态内容替换{{}}语法。