749749"""
750750
751751
752+ class Writer (nbconvert .preprocessors .Preprocessor ):
753+ def preprocess (self , nb , resources ):
754+ if 'nbsphinx_save_notebook' in resources :
755+ # Save *executed* notebook *before* the Exporter can change it:
756+ nbformat .write (nb , resources ['nbsphinx_save_notebook' ])
757+ return nb , resources
758+
752759class Exporter (nbconvert .RSTExporter ):
753760 """Convert Jupyter notebooks to reStructuredText.
754761
@@ -760,8 +767,6 @@ class Exporter(nbconvert.RSTExporter):
760767
761768 """
762769
763- # TODO: define default preprocessors to include our one to write out notebook just after execution
764-
765770 def __init__ (self , execute = 'auto' , kernel_name = '' , execute_arguments = [],
766771 allow_errors = False , timeout = None , codecell_lexer = 'none' ,
767772 nbconvert_config = None ):
@@ -804,7 +809,6 @@ def replace_attachments(text):
804809 # Work around https://github.com/jupyter/nbconvert/issues/720:
805810 'RegexRemovePreprocessor' : {'enabled' : False },
806811 }
807-
808812 super (Exporter , self ).__init__ (
809813 template_file = 'nbsphinx-rst.tpl' , extra_loaders = [loader ],
810814 config = traitlets .config .Config (nbconvert_config ),
@@ -848,23 +852,29 @@ def from_notebook_node(self, nb, resources=None, **kw):
848852 not any (c .get ('outputs' ) or c .get ('execution_count' )
849853 for c in nb .cells if c .cell_type == 'code' )
850854 )
855+ preprocessors = []
851856 if auto_execute or execute == 'always' :
852857 allow_errors = nbsphinx_metadata .get (
853858 'allow_errors' , self ._allow_errors )
854859 timeout = nbsphinx_metadata .get ('timeout' , self ._timeout )
855- # TODO: Here, just add the execute preprocessor to the exporter list of preprocessors
856- # rather than executing directly. We can still pass appropriate config values in
857- # and that way the tag remove preprocessor is run *before* execution rather than after.
858- pp = nbconvert .preprocessors .ExecutePreprocessor (
860+ preprocessors .append (nbconvert .preprocessors .ExecutePreprocessor (
859861 kernel_name = self ._kernel_name ,
860862 extra_arguments = self ._execute_arguments ,
861- allow_errors = allow_errors , timeout = timeout )
862- nb , resources = pp .preprocess (nb , resources )
863-
864- if 'nbsphinx_save_notebook' in resources :
865- # TODO: maybe we write our *own* preprocessor to hook into this stage, right after the execute preprocessor, to save the notebook
866- # Save *executed* notebook *before* the Exporter can change it:
867- nbformat .write (nb , resources ['nbsphinx_save_notebook' ])
863+ allow_errors = allow_errors , timeout = timeout ))
864+ # pp = nbconvert.preprocessors.ExecutePreprocessor(
865+ # kernel_name=self._kernel_name,
866+ # extra_arguments=self._execute_arguments,
867+ # allow_errors=allow_errors, timeout=timeout)
868+ # nb, resources = pp.preprocess(nb, resources)
869+
870+ # if 'nbsphinx_save_notebook' in resources:
871+ # # Save *executed* notebook *before* the Exporter can change it:
872+ # nbformat.write(nb, resources['nbsphinx_save_notebook'])
873+
874+ preprocessors .append (Writer ())
875+ # Find the existing execute preprocessor and replace it
876+ i = next ((i for i ,p in enumerate (self ._preprocessors ) if isinstance (p , nbconvert .preprocessors .ExecutePreprocessor )), len (self ._preprocessors ))
877+ self ._preprocessors [i :i + 1 ] = preprocessors
868878
869879 # Call into RSTExporter
870880 rststr , resources = super (Exporter , self ).from_notebook_node (
0 commit comments