##// END OF EJS Templates
Remove docstring_nbformat_mod decorator
Thomas Kluyver -
Show More
@@ -1,277 +1,276 b''
1 """This module defines a base Exporter class. For Jinja template-based export,
1 """This module defines a base Exporter class. For Jinja template-based export,
2 see templateexporter.py.
2 see templateexporter.py.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from __future__ import print_function, absolute_import
17 from __future__ import print_function, absolute_import
18
18
19 # Stdlib imports
19 # Stdlib imports
20 import io
20 import io
21 import os
21 import os
22 import copy
22 import copy
23 import collections
23 import collections
24 import datetime
24 import datetime
25
25
26
26
27 # IPython imports
27 # IPython imports
28 from IPython.config.configurable import LoggingConfigurable
28 from IPython.config.configurable import LoggingConfigurable
29 from IPython.config import Config
29 from IPython.config import Config
30 from IPython.nbformat import current as nbformat
30 from IPython.nbformat import current as nbformat
31 from IPython.utils.traitlets import MetaHasTraits, Unicode, List
31 from IPython.utils.traitlets import MetaHasTraits, Unicode, List
32 from IPython.utils.importstring import import_item
32 from IPython.utils.importstring import import_item
33 from IPython.utils import text, py3compat
33 from IPython.utils import text, py3compat
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Class
36 # Class
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 class ResourcesDict(collections.defaultdict):
39 class ResourcesDict(collections.defaultdict):
40 def __missing__(self, key):
40 def __missing__(self, key):
41 return ''
41 return ''
42
42
43
43
44 class Exporter(LoggingConfigurable):
44 class Exporter(LoggingConfigurable):
45 """
45 """
46 Class containing methods that sequentially run a list of preprocessors on a
46 Class containing methods that sequentially run a list of preprocessors on a
47 NotebookNode object and then return the modified NotebookNode object and
47 NotebookNode object and then return the modified NotebookNode object and
48 accompanying resources dict.
48 accompanying resources dict.
49 """
49 """
50
50
51 file_extension = Unicode(
51 file_extension = Unicode(
52 'txt', config=True,
52 'txt', config=True,
53 help="Extension of the file that should be written to disk"
53 help="Extension of the file that should be written to disk"
54 )
54 )
55
55
56 # MIME type of the result file, for HTTP response headers.
56 # MIME type of the result file, for HTTP response headers.
57 # This is *not* a traitlet, because we want to be able to access it from
57 # This is *not* a traitlet, because we want to be able to access it from
58 # the class, not just on instances.
58 # the class, not just on instances.
59 output_mimetype = ''
59 output_mimetype = ''
60
60
61 #Configurability, allows the user to easily add filters and preprocessors.
61 #Configurability, allows the user to easily add filters and preprocessors.
62 preprocessors = List(config=True,
62 preprocessors = List(config=True,
63 help="""List of preprocessors, by name or namespace, to enable.""")
63 help="""List of preprocessors, by name or namespace, to enable.""")
64
64
65 _preprocessors = List()
65 _preprocessors = List()
66
66
67 default_preprocessors = List(['IPython.nbconvert.preprocessors.coalesce_streams',
67 default_preprocessors = List(['IPython.nbconvert.preprocessors.coalesce_streams',
68 'IPython.nbconvert.preprocessors.SVG2PDFPreprocessor',
68 'IPython.nbconvert.preprocessors.SVG2PDFPreprocessor',
69 'IPython.nbconvert.preprocessors.ExtractOutputPreprocessor',
69 'IPython.nbconvert.preprocessors.ExtractOutputPreprocessor',
70 'IPython.nbconvert.preprocessors.CSSHTMLHeaderPreprocessor',
70 'IPython.nbconvert.preprocessors.CSSHTMLHeaderPreprocessor',
71 'IPython.nbconvert.preprocessors.RevealHelpPreprocessor',
71 'IPython.nbconvert.preprocessors.RevealHelpPreprocessor',
72 'IPython.nbconvert.preprocessors.LatexPreprocessor',
72 'IPython.nbconvert.preprocessors.LatexPreprocessor',
73 'IPython.nbconvert.preprocessors.ClearOutputPreprocessor',
73 'IPython.nbconvert.preprocessors.ClearOutputPreprocessor',
74 'IPython.nbconvert.preprocessors.ExecutePreprocessor',
74 'IPython.nbconvert.preprocessors.ExecutePreprocessor',
75 'IPython.nbconvert.preprocessors.HighlightMagicsPreprocessor'],
75 'IPython.nbconvert.preprocessors.HighlightMagicsPreprocessor'],
76 config=True,
76 config=True,
77 help="""List of preprocessors available by default, by name, namespace,
77 help="""List of preprocessors available by default, by name, namespace,
78 instance, or type.""")
78 instance, or type.""")
79
79
80
80
81 def __init__(self, config=None, **kw):
81 def __init__(self, config=None, **kw):
82 """
82 """
83 Public constructor
83 Public constructor
84
84
85 Parameters
85 Parameters
86 ----------
86 ----------
87 config : config
87 config : config
88 User configuration instance.
88 User configuration instance.
89 """
89 """
90 with_default_config = self.default_config
90 with_default_config = self.default_config
91 if config:
91 if config:
92 with_default_config.merge(config)
92 with_default_config.merge(config)
93
93
94 super(Exporter, self).__init__(config=with_default_config, **kw)
94 super(Exporter, self).__init__(config=with_default_config, **kw)
95
95
96 self._init_preprocessors()
96 self._init_preprocessors()
97
97
98
98
99 @property
99 @property
100 def default_config(self):
100 def default_config(self):
101 return Config()
101 return Config()
102
102
103 @nbformat.docstring_nbformat_mod
104 def from_notebook_node(self, nb, resources=None, **kw):
103 def from_notebook_node(self, nb, resources=None, **kw):
105 """
104 """
106 Convert a notebook from a notebook node instance.
105 Convert a notebook from a notebook node instance.
107
106
108 Parameters
107 Parameters
109 ----------
108 ----------
110 nb : :class:`~{nbformat_mod}.nbbase.NotebookNode`
109 nb : :class:`~IPython.nbformat.current.NotebookNode`
111 Notebook node
110 Notebook node
112 resources : dict
111 resources : dict
113 Additional resources that can be accessed read/write by
112 Additional resources that can be accessed read/write by
114 preprocessors and filters.
113 preprocessors and filters.
115 **kw
114 **kw
116 Ignored (?)
115 Ignored (?)
117 """
116 """
118 nb_copy = copy.deepcopy(nb)
117 nb_copy = copy.deepcopy(nb)
119 resources = self._init_resources(resources)
118 resources = self._init_resources(resources)
120
119
121 if 'language' in nb['metadata']:
120 if 'language' in nb['metadata']:
122 resources['language'] = nb['metadata']['language'].lower()
121 resources['language'] = nb['metadata']['language'].lower()
123
122
124 # Preprocess
123 # Preprocess
125 nb_copy, resources = self._preprocess(nb_copy, resources)
124 nb_copy, resources = self._preprocess(nb_copy, resources)
126
125
127 return nb_copy, resources
126 return nb_copy, resources
128
127
129
128
130 def from_filename(self, filename, resources=None, **kw):
129 def from_filename(self, filename, resources=None, **kw):
131 """
130 """
132 Convert a notebook from a notebook file.
131 Convert a notebook from a notebook file.
133
132
134 Parameters
133 Parameters
135 ----------
134 ----------
136 filename : str
135 filename : str
137 Full filename of the notebook file to open and convert.
136 Full filename of the notebook file to open and convert.
138 """
137 """
139
138
140 # Pull the metadata from the filesystem.
139 # Pull the metadata from the filesystem.
141 if resources is None:
140 if resources is None:
142 resources = ResourcesDict()
141 resources = ResourcesDict()
143 if not 'metadata' in resources or resources['metadata'] == '':
142 if not 'metadata' in resources or resources['metadata'] == '':
144 resources['metadata'] = ResourcesDict()
143 resources['metadata'] = ResourcesDict()
145 basename = os.path.basename(filename)
144 basename = os.path.basename(filename)
146 notebook_name = basename[:basename.rfind('.')]
145 notebook_name = basename[:basename.rfind('.')]
147 resources['metadata']['name'] = notebook_name
146 resources['metadata']['name'] = notebook_name
148
147
149 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
148 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
150 resources['metadata']['modified_date'] = modified_date.strftime(text.date_format)
149 resources['metadata']['modified_date'] = modified_date.strftime(text.date_format)
151
150
152 with io.open(filename, encoding='utf-8') as f:
151 with io.open(filename, encoding='utf-8') as f:
153 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw)
152 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw)
154
153
155
154
156 def from_file(self, file_stream, resources=None, **kw):
155 def from_file(self, file_stream, resources=None, **kw):
157 """
156 """
158 Convert a notebook from a notebook file.
157 Convert a notebook from a notebook file.
159
158
160 Parameters
159 Parameters
161 ----------
160 ----------
162 file_stream : file-like object
161 file_stream : file-like object
163 Notebook file-like object to convert.
162 Notebook file-like object to convert.
164 """
163 """
165 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
164 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
166
165
167
166
168 def register_preprocessor(self, preprocessor, enabled=False):
167 def register_preprocessor(self, preprocessor, enabled=False):
169 """
168 """
170 Register a preprocessor.
169 Register a preprocessor.
171 Preprocessors are classes that act upon the notebook before it is
170 Preprocessors are classes that act upon the notebook before it is
172 passed into the Jinja templating engine. preprocessors are also
171 passed into the Jinja templating engine. preprocessors are also
173 capable of passing additional information to the Jinja
172 capable of passing additional information to the Jinja
174 templating engine.
173 templating engine.
175
174
176 Parameters
175 Parameters
177 ----------
176 ----------
178 preprocessor : preprocessor
177 preprocessor : preprocessor
179 """
178 """
180 if preprocessor is None:
179 if preprocessor is None:
181 raise TypeError('preprocessor')
180 raise TypeError('preprocessor')
182 isclass = isinstance(preprocessor, type)
181 isclass = isinstance(preprocessor, type)
183 constructed = not isclass
182 constructed = not isclass
184
183
185 # Handle preprocessor's registration based on it's type
184 # Handle preprocessor's registration based on it's type
186 if constructed and isinstance(preprocessor, py3compat.string_types):
185 if constructed and isinstance(preprocessor, py3compat.string_types):
187 # Preprocessor is a string, import the namespace and recursively call
186 # Preprocessor is a string, import the namespace and recursively call
188 # this register_preprocessor method
187 # this register_preprocessor method
189 preprocessor_cls = import_item(preprocessor)
188 preprocessor_cls = import_item(preprocessor)
190 return self.register_preprocessor(preprocessor_cls, enabled)
189 return self.register_preprocessor(preprocessor_cls, enabled)
191
190
192 if constructed and hasattr(preprocessor, '__call__'):
191 if constructed and hasattr(preprocessor, '__call__'):
193 # Preprocessor is a function, no need to construct it.
192 # Preprocessor is a function, no need to construct it.
194 # Register and return the preprocessor.
193 # Register and return the preprocessor.
195 if enabled:
194 if enabled:
196 preprocessor.enabled = True
195 preprocessor.enabled = True
197 self._preprocessors.append(preprocessor)
196 self._preprocessors.append(preprocessor)
198 return preprocessor
197 return preprocessor
199
198
200 elif isclass and isinstance(preprocessor, MetaHasTraits):
199 elif isclass and isinstance(preprocessor, MetaHasTraits):
201 # Preprocessor is configurable. Make sure to pass in new default for
200 # Preprocessor is configurable. Make sure to pass in new default for
202 # the enabled flag if one was specified.
201 # the enabled flag if one was specified.
203 self.register_preprocessor(preprocessor(parent=self), enabled)
202 self.register_preprocessor(preprocessor(parent=self), enabled)
204
203
205 elif isclass:
204 elif isclass:
206 # Preprocessor is not configurable, construct it
205 # Preprocessor is not configurable, construct it
207 self.register_preprocessor(preprocessor(), enabled)
206 self.register_preprocessor(preprocessor(), enabled)
208
207
209 else:
208 else:
210 # Preprocessor is an instance of something without a __call__
209 # Preprocessor is an instance of something without a __call__
211 # attribute.
210 # attribute.
212 raise TypeError('preprocessor')
211 raise TypeError('preprocessor')
213
212
214
213
215 def _init_preprocessors(self):
214 def _init_preprocessors(self):
216 """
215 """
217 Register all of the preprocessors needed for this exporter, disabled
216 Register all of the preprocessors needed for this exporter, disabled
218 unless specified explicitly.
217 unless specified explicitly.
219 """
218 """
220 self._preprocessors = []
219 self._preprocessors = []
221
220
222 # Load default preprocessors (not necessarly enabled by default).
221 # Load default preprocessors (not necessarly enabled by default).
223 for preprocessor in self.default_preprocessors:
222 for preprocessor in self.default_preprocessors:
224 self.register_preprocessor(preprocessor)
223 self.register_preprocessor(preprocessor)
225
224
226 # Load user-specified preprocessors. Enable by default.
225 # Load user-specified preprocessors. Enable by default.
227 for preprocessor in self.preprocessors:
226 for preprocessor in self.preprocessors:
228 self.register_preprocessor(preprocessor, enabled=True)
227 self.register_preprocessor(preprocessor, enabled=True)
229
228
230
229
231 def _init_resources(self, resources):
230 def _init_resources(self, resources):
232
231
233 #Make sure the resources dict is of ResourcesDict type.
232 #Make sure the resources dict is of ResourcesDict type.
234 if resources is None:
233 if resources is None:
235 resources = ResourcesDict()
234 resources = ResourcesDict()
236 if not isinstance(resources, ResourcesDict):
235 if not isinstance(resources, ResourcesDict):
237 new_resources = ResourcesDict()
236 new_resources = ResourcesDict()
238 new_resources.update(resources)
237 new_resources.update(resources)
239 resources = new_resources
238 resources = new_resources
240
239
241 #Make sure the metadata extension exists in resources
240 #Make sure the metadata extension exists in resources
242 if 'metadata' in resources:
241 if 'metadata' in resources:
243 if not isinstance(resources['metadata'], ResourcesDict):
242 if not isinstance(resources['metadata'], ResourcesDict):
244 resources['metadata'] = ResourcesDict(resources['metadata'])
243 resources['metadata'] = ResourcesDict(resources['metadata'])
245 else:
244 else:
246 resources['metadata'] = ResourcesDict()
245 resources['metadata'] = ResourcesDict()
247 if not resources['metadata']['name']:
246 if not resources['metadata']['name']:
248 resources['metadata']['name'] = 'Notebook'
247 resources['metadata']['name'] = 'Notebook'
249
248
250 #Set the output extension
249 #Set the output extension
251 resources['output_extension'] = self.file_extension
250 resources['output_extension'] = self.file_extension
252 return resources
251 return resources
253
252
254
253
255 def _preprocess(self, nb, resources):
254 def _preprocess(self, nb, resources):
256 """
255 """
257 Preprocess the notebook before passing it into the Jinja engine.
256 Preprocess the notebook before passing it into the Jinja engine.
258 To preprocess the notebook is to apply all of the
257 To preprocess the notebook is to apply all of the
259
258
260 Parameters
259 Parameters
261 ----------
260 ----------
262 nb : notebook node
261 nb : notebook node
263 notebook that is being exported.
262 notebook that is being exported.
264 resources : a dict of additional resources that
263 resources : a dict of additional resources that
265 can be accessed read/write by preprocessors
264 can be accessed read/write by preprocessors
266 """
265 """
267
266
268 # Do a copy.deepcopy first,
267 # Do a copy.deepcopy first,
269 # we are never safe enough with what the preprocessors could do.
268 # we are never safe enough with what the preprocessors could do.
270 nbc = copy.deepcopy(nb)
269 nbc = copy.deepcopy(nb)
271 resc = copy.deepcopy(resources)
270 resc = copy.deepcopy(resources)
272
271
273 #Run each preprocessor on the notebook. Carry the output along
272 #Run each preprocessor on the notebook. Carry the output along
274 #to each preprocessor
273 #to each preprocessor
275 for preprocessor in self._preprocessors:
274 for preprocessor in self._preprocessors:
276 nbc, resc = preprocessor(nbc, resc)
275 nbc, resc = preprocessor(nbc, resc)
277 return nbc, resc
276 return nbc, resc
@@ -1,322 +1,320 b''
1 """This module defines TemplateExporter, a highly configurable converter
1 """This module defines TemplateExporter, a highly configurable converter
2 that uses Jinja2 to export notebook files into different formats.
2 that uses Jinja2 to export notebook files into different formats.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from __future__ import print_function, absolute_import
17 from __future__ import print_function, absolute_import
18
18
19 # Stdlib imports
19 # Stdlib imports
20 import os
20 import os
21
21
22 # other libs/dependencies are imported at runtime
22 # other libs/dependencies are imported at runtime
23 # to move ImportErrors to runtime when the requirement is actually needed
23 # to move ImportErrors to runtime when the requirement is actually needed
24
24
25 # IPython imports
25 # IPython imports
26 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Dict, Any
26 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Dict, Any
27 from IPython.utils.importstring import import_item
27 from IPython.utils.importstring import import_item
28 from IPython.utils import py3compat, text
28 from IPython.utils import py3compat, text
29
29
30 from IPython.nbformat.current import docstring_nbformat_mod
31 from IPython.nbconvert import filters
30 from IPython.nbconvert import filters
32 from .exporter import Exporter
31 from .exporter import Exporter
33
32
34 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
35 # Globals and constants
34 # Globals and constants
36 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
37
36
38 #Jinja2 extensions to load.
37 #Jinja2 extensions to load.
39 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
38 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
40
39
41 default_filters = {
40 default_filters = {
42 'indent': text.indent,
41 'indent': text.indent,
43 'markdown2html': filters.markdown2html,
42 'markdown2html': filters.markdown2html,
44 'ansi2html': filters.ansi2html,
43 'ansi2html': filters.ansi2html,
45 'filter_data_type': filters.DataTypeFilter,
44 'filter_data_type': filters.DataTypeFilter,
46 'get_lines': filters.get_lines,
45 'get_lines': filters.get_lines,
47 'highlight2html': filters.Highlight2HTML,
46 'highlight2html': filters.Highlight2HTML,
48 'highlight2latex': filters.Highlight2Latex,
47 'highlight2latex': filters.Highlight2Latex,
49 'ipython2python': filters.ipython2python,
48 'ipython2python': filters.ipython2python,
50 'posix_path': filters.posix_path,
49 'posix_path': filters.posix_path,
51 'markdown2latex': filters.markdown2latex,
50 'markdown2latex': filters.markdown2latex,
52 'markdown2rst': filters.markdown2rst,
51 'markdown2rst': filters.markdown2rst,
53 'comment_lines': filters.comment_lines,
52 'comment_lines': filters.comment_lines,
54 'strip_ansi': filters.strip_ansi,
53 'strip_ansi': filters.strip_ansi,
55 'strip_dollars': filters.strip_dollars,
54 'strip_dollars': filters.strip_dollars,
56 'strip_files_prefix': filters.strip_files_prefix,
55 'strip_files_prefix': filters.strip_files_prefix,
57 'html2text' : filters.html2text,
56 'html2text' : filters.html2text,
58 'add_anchor': filters.add_anchor,
57 'add_anchor': filters.add_anchor,
59 'ansi2latex': filters.ansi2latex,
58 'ansi2latex': filters.ansi2latex,
60 'wrap_text': filters.wrap_text,
59 'wrap_text': filters.wrap_text,
61 'escape_latex': filters.escape_latex,
60 'escape_latex': filters.escape_latex,
62 'citation2latex': filters.citation2latex,
61 'citation2latex': filters.citation2latex,
63 'path2url': filters.path2url,
62 'path2url': filters.path2url,
64 'add_prompts': filters.add_prompts,
63 'add_prompts': filters.add_prompts,
65 'ascii_only': filters.ascii_only,
64 'ascii_only': filters.ascii_only,
66 }
65 }
67
66
68 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
69 # Class
68 # Class
70 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
71
70
72 class TemplateExporter(Exporter):
71 class TemplateExporter(Exporter):
73 """
72 """
74 Exports notebooks into other file formats. Uses Jinja 2 templating engine
73 Exports notebooks into other file formats. Uses Jinja 2 templating engine
75 to output new formats. Inherit from this class if you are creating a new
74 to output new formats. Inherit from this class if you are creating a new
76 template type along with new filters/preprocessors. If the filters/
75 template type along with new filters/preprocessors. If the filters/
77 preprocessors provided by default suffice, there is no need to inherit from
76 preprocessors provided by default suffice, there is no need to inherit from
78 this class. Instead, override the template_file and file_extension
77 this class. Instead, override the template_file and file_extension
79 traits via a config file.
78 traits via a config file.
80
79
81 {filters}
80 {filters}
82 """
81 """
83
82
84 # finish the docstring
83 # finish the docstring
85 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
84 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
86
85
87
86
88 template_file = Unicode(u'default',
87 template_file = Unicode(u'default',
89 config=True,
88 config=True,
90 help="Name of the template file to use")
89 help="Name of the template file to use")
91 def _template_file_changed(self, name, old, new):
90 def _template_file_changed(self, name, old, new):
92 if new == 'default':
91 if new == 'default':
93 self.template_file = self.default_template
92 self.template_file = self.default_template
94 else:
93 else:
95 self.template_file = new
94 self.template_file = new
96 self.template = None
95 self.template = None
97 self._load_template()
96 self._load_template()
98
97
99 default_template = Unicode(u'')
98 default_template = Unicode(u'')
100 template = Any()
99 template = Any()
101 environment = Any()
100 environment = Any()
102
101
103 template_path = List(['.'], config=True)
102 template_path = List(['.'], config=True)
104 def _template_path_changed(self, name, old, new):
103 def _template_path_changed(self, name, old, new):
105 self._load_template()
104 self._load_template()
106
105
107 default_template_path = Unicode(
106 default_template_path = Unicode(
108 os.path.join("..", "templates"),
107 os.path.join("..", "templates"),
109 help="Path where the template files are located.")
108 help="Path where the template files are located.")
110
109
111 template_skeleton_path = Unicode(
110 template_skeleton_path = Unicode(
112 os.path.join("..", "templates", "skeleton"),
111 os.path.join("..", "templates", "skeleton"),
113 help="Path where the template skeleton files are located.")
112 help="Path where the template skeleton files are located.")
114
113
115 #Jinja block definitions
114 #Jinja block definitions
116 jinja_comment_block_start = Unicode("", config=True)
115 jinja_comment_block_start = Unicode("", config=True)
117 jinja_comment_block_end = Unicode("", config=True)
116 jinja_comment_block_end = Unicode("", config=True)
118 jinja_variable_block_start = Unicode("", config=True)
117 jinja_variable_block_start = Unicode("", config=True)
119 jinja_variable_block_end = Unicode("", config=True)
118 jinja_variable_block_end = Unicode("", config=True)
120 jinja_logic_block_start = Unicode("", config=True)
119 jinja_logic_block_start = Unicode("", config=True)
121 jinja_logic_block_end = Unicode("", config=True)
120 jinja_logic_block_end = Unicode("", config=True)
122
121
123 #Extension that the template files use.
122 #Extension that the template files use.
124 template_extension = Unicode(".tpl", config=True)
123 template_extension = Unicode(".tpl", config=True)
125
124
126 filters = Dict(config=True,
125 filters = Dict(config=True,
127 help="""Dictionary of filters, by name and namespace, to add to the Jinja
126 help="""Dictionary of filters, by name and namespace, to add to the Jinja
128 environment.""")
127 environment.""")
129
128
130 raw_mimetypes = List(config=True,
129 raw_mimetypes = List(config=True,
131 help="""formats of raw cells to be included in this Exporter's output."""
130 help="""formats of raw cells to be included in this Exporter's output."""
132 )
131 )
133 def _raw_mimetypes_default(self):
132 def _raw_mimetypes_default(self):
134 return [self.output_mimetype, '']
133 return [self.output_mimetype, '']
135
134
136
135
137 def __init__(self, config=None, extra_loaders=None, **kw):
136 def __init__(self, config=None, extra_loaders=None, **kw):
138 """
137 """
139 Public constructor
138 Public constructor
140
139
141 Parameters
140 Parameters
142 ----------
141 ----------
143 config : config
142 config : config
144 User configuration instance.
143 User configuration instance.
145 extra_loaders : list[of Jinja Loaders]
144 extra_loaders : list[of Jinja Loaders]
146 ordered list of Jinja loader to find templates. Will be tried in order
145 ordered list of Jinja loader to find templates. Will be tried in order
147 before the default FileSystem ones.
146 before the default FileSystem ones.
148 template : str (optional, kw arg)
147 template : str (optional, kw arg)
149 Template to use when exporting.
148 Template to use when exporting.
150 """
149 """
151 super(TemplateExporter, self).__init__(config=config, **kw)
150 super(TemplateExporter, self).__init__(config=config, **kw)
152
151
153 #Init
152 #Init
154 self._init_template()
153 self._init_template()
155 self._init_environment(extra_loaders=extra_loaders)
154 self._init_environment(extra_loaders=extra_loaders)
156 self._init_filters()
155 self._init_filters()
157
156
158
157
159 def _load_template(self):
158 def _load_template(self):
160 """Load the Jinja template object from the template file
159 """Load the Jinja template object from the template file
161
160
162 This is a no-op if the template attribute is already defined,
161 This is a no-op if the template attribute is already defined,
163 or the Jinja environment is not setup yet.
162 or the Jinja environment is not setup yet.
164
163
165 This is triggered by various trait changes that would change the template.
164 This is triggered by various trait changes that would change the template.
166 """
165 """
167 from jinja2 import TemplateNotFound
166 from jinja2 import TemplateNotFound
168
167
169 if self.template is not None:
168 if self.template is not None:
170 return
169 return
171 # called too early, do nothing
170 # called too early, do nothing
172 if self.environment is None:
171 if self.environment is None:
173 return
172 return
174 # Try different template names during conversion. First try to load the
173 # Try different template names during conversion. First try to load the
175 # template by name with extension added, then try loading the template
174 # template by name with extension added, then try loading the template
176 # as if the name is explicitly specified, then try the name as a
175 # as if the name is explicitly specified, then try the name as a
177 # 'flavor', and lastly just try to load the template by module name.
176 # 'flavor', and lastly just try to load the template by module name.
178 try_names = []
177 try_names = []
179 if self.template_file:
178 if self.template_file:
180 try_names.extend([
179 try_names.extend([
181 self.template_file + self.template_extension,
180 self.template_file + self.template_extension,
182 self.template_file,
181 self.template_file,
183 ])
182 ])
184 for try_name in try_names:
183 for try_name in try_names:
185 self.log.debug("Attempting to load template %s", try_name)
184 self.log.debug("Attempting to load template %s", try_name)
186 try:
185 try:
187 self.template = self.environment.get_template(try_name)
186 self.template = self.environment.get_template(try_name)
188 except (TemplateNotFound, IOError):
187 except (TemplateNotFound, IOError):
189 pass
188 pass
190 except Exception as e:
189 except Exception as e:
191 self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
190 self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
192 else:
191 else:
193 self.log.info("Loaded template %s", try_name)
192 self.log.info("Loaded template %s", try_name)
194 break
193 break
195
194
196 @docstring_nbformat_mod
197 def from_notebook_node(self, nb, resources=None, **kw):
195 def from_notebook_node(self, nb, resources=None, **kw):
198 """
196 """
199 Convert a notebook from a notebook node instance.
197 Convert a notebook from a notebook node instance.
200
198
201 Parameters
199 Parameters
202 ----------
200 ----------
203 nb : :class:`~{nbformat_mod}.nbbase.NotebookNode`
201 nb : :class:`~IPython.nbformat.current.NotebookNode`
204 Notebook node
202 Notebook node
205 resources : dict
203 resources : dict
206 Additional resources that can be accessed read/write by
204 Additional resources that can be accessed read/write by
207 preprocessors and filters.
205 preprocessors and filters.
208 """
206 """
209 nb_copy, resources = super(TemplateExporter, self).from_notebook_node(nb, resources, **kw)
207 nb_copy, resources = super(TemplateExporter, self).from_notebook_node(nb, resources, **kw)
210 resources.setdefault('raw_mimetypes', self.raw_mimetypes)
208 resources.setdefault('raw_mimetypes', self.raw_mimetypes)
211
209
212 self._load_template()
210 self._load_template()
213
211
214 if self.template is not None:
212 if self.template is not None:
215 output = self.template.render(nb=nb_copy, resources=resources)
213 output = self.template.render(nb=nb_copy, resources=resources)
216 else:
214 else:
217 raise IOError('template file "%s" could not be found' % self.template_file)
215 raise IOError('template file "%s" could not be found' % self.template_file)
218 return output, resources
216 return output, resources
219
217
220
218
221 def register_filter(self, name, jinja_filter):
219 def register_filter(self, name, jinja_filter):
222 """
220 """
223 Register a filter.
221 Register a filter.
224 A filter is a function that accepts and acts on one string.
222 A filter is a function that accepts and acts on one string.
225 The filters are accesible within the Jinja templating engine.
223 The filters are accesible within the Jinja templating engine.
226
224
227 Parameters
225 Parameters
228 ----------
226 ----------
229 name : str
227 name : str
230 name to give the filter in the Jinja engine
228 name to give the filter in the Jinja engine
231 filter : filter
229 filter : filter
232 """
230 """
233 if jinja_filter is None:
231 if jinja_filter is None:
234 raise TypeError('filter')
232 raise TypeError('filter')
235 isclass = isinstance(jinja_filter, type)
233 isclass = isinstance(jinja_filter, type)
236 constructed = not isclass
234 constructed = not isclass
237
235
238 #Handle filter's registration based on it's type
236 #Handle filter's registration based on it's type
239 if constructed and isinstance(jinja_filter, py3compat.string_types):
237 if constructed and isinstance(jinja_filter, py3compat.string_types):
240 #filter is a string, import the namespace and recursively call
238 #filter is a string, import the namespace and recursively call
241 #this register_filter method
239 #this register_filter method
242 filter_cls = import_item(jinja_filter)
240 filter_cls = import_item(jinja_filter)
243 return self.register_filter(name, filter_cls)
241 return self.register_filter(name, filter_cls)
244
242
245 if constructed and hasattr(jinja_filter, '__call__'):
243 if constructed and hasattr(jinja_filter, '__call__'):
246 #filter is a function, no need to construct it.
244 #filter is a function, no need to construct it.
247 self.environment.filters[name] = jinja_filter
245 self.environment.filters[name] = jinja_filter
248 return jinja_filter
246 return jinja_filter
249
247
250 elif isclass and isinstance(jinja_filter, MetaHasTraits):
248 elif isclass and isinstance(jinja_filter, MetaHasTraits):
251 #filter is configurable. Make sure to pass in new default for
249 #filter is configurable. Make sure to pass in new default for
252 #the enabled flag if one was specified.
250 #the enabled flag if one was specified.
253 filter_instance = jinja_filter(parent=self)
251 filter_instance = jinja_filter(parent=self)
254 self.register_filter(name, filter_instance )
252 self.register_filter(name, filter_instance )
255
253
256 elif isclass:
254 elif isclass:
257 #filter is not configurable, construct it
255 #filter is not configurable, construct it
258 filter_instance = jinja_filter()
256 filter_instance = jinja_filter()
259 self.register_filter(name, filter_instance)
257 self.register_filter(name, filter_instance)
260
258
261 else:
259 else:
262 #filter is an instance of something without a __call__
260 #filter is an instance of something without a __call__
263 #attribute.
261 #attribute.
264 raise TypeError('filter')
262 raise TypeError('filter')
265
263
266
264
267 def _init_template(self):
265 def _init_template(self):
268 """
266 """
269 Make sure a template name is specified. If one isn't specified, try to
267 Make sure a template name is specified. If one isn't specified, try to
270 build one from the information we know.
268 build one from the information we know.
271 """
269 """
272 self._template_file_changed('template_file', self.template_file, self.template_file)
270 self._template_file_changed('template_file', self.template_file, self.template_file)
273
271
274
272
275 def _init_environment(self, extra_loaders=None):
273 def _init_environment(self, extra_loaders=None):
276 """
274 """
277 Create the Jinja templating environment.
275 Create the Jinja templating environment.
278 """
276 """
279 from jinja2 import Environment, ChoiceLoader, FileSystemLoader
277 from jinja2 import Environment, ChoiceLoader, FileSystemLoader
280 here = os.path.dirname(os.path.realpath(__file__))
278 here = os.path.dirname(os.path.realpath(__file__))
281 loaders = []
279 loaders = []
282 if extra_loaders:
280 if extra_loaders:
283 loaders.extend(extra_loaders)
281 loaders.extend(extra_loaders)
284
282
285 paths = self.template_path
283 paths = self.template_path
286 paths.extend([os.path.join(here, self.default_template_path),
284 paths.extend([os.path.join(here, self.default_template_path),
287 os.path.join(here, self.template_skeleton_path)])
285 os.path.join(here, self.template_skeleton_path)])
288 loaders.append(FileSystemLoader(paths))
286 loaders.append(FileSystemLoader(paths))
289
287
290 self.environment = Environment(
288 self.environment = Environment(
291 loader= ChoiceLoader(loaders),
289 loader= ChoiceLoader(loaders),
292 extensions=JINJA_EXTENSIONS
290 extensions=JINJA_EXTENSIONS
293 )
291 )
294
292
295 #Set special Jinja2 syntax that will not conflict with latex.
293 #Set special Jinja2 syntax that will not conflict with latex.
296 if self.jinja_logic_block_start:
294 if self.jinja_logic_block_start:
297 self.environment.block_start_string = self.jinja_logic_block_start
295 self.environment.block_start_string = self.jinja_logic_block_start
298 if self.jinja_logic_block_end:
296 if self.jinja_logic_block_end:
299 self.environment.block_end_string = self.jinja_logic_block_end
297 self.environment.block_end_string = self.jinja_logic_block_end
300 if self.jinja_variable_block_start:
298 if self.jinja_variable_block_start:
301 self.environment.variable_start_string = self.jinja_variable_block_start
299 self.environment.variable_start_string = self.jinja_variable_block_start
302 if self.jinja_variable_block_end:
300 if self.jinja_variable_block_end:
303 self.environment.variable_end_string = self.jinja_variable_block_end
301 self.environment.variable_end_string = self.jinja_variable_block_end
304 if self.jinja_comment_block_start:
302 if self.jinja_comment_block_start:
305 self.environment.comment_start_string = self.jinja_comment_block_start
303 self.environment.comment_start_string = self.jinja_comment_block_start
306 if self.jinja_comment_block_end:
304 if self.jinja_comment_block_end:
307 self.environment.comment_end_string = self.jinja_comment_block_end
305 self.environment.comment_end_string = self.jinja_comment_block_end
308
306
309
307
310 def _init_filters(self):
308 def _init_filters(self):
311 """
309 """
312 Register all of the filters required for the exporter.
310 Register all of the filters required for the exporter.
313 """
311 """
314
312
315 #Add default filters to the Jinja2 environment
313 #Add default filters to the Jinja2 environment
316 for key, value in default_filters.items():
314 for key, value in default_filters.items():
317 self.register_filter(key, value)
315 self.register_filter(key, value)
318
316
319 #Load user filters. Overwrite existing filters if need be.
317 #Load user filters. Overwrite existing filters if need be.
320 if self.filters:
318 if self.filters:
321 for key, user_filter in self.filters.items():
319 for key, user_filter in self.filters.items():
322 self.register_filter(key, user_filter)
320 self.register_filter(key, user_filter)
@@ -1,223 +1,212 b''
1 """The official API for working with notebooks in the current format version."""
1 """The official API for working with notebooks in the current format version."""
2
2
3 from __future__ import print_function
3 from __future__ import print_function
4
4
5 from xml.etree import ElementTree as ET
6 import re
5 import re
7
6
8 from IPython.utils.py3compat import unicode_type
7 from IPython.utils.py3compat import unicode_type
9
8
10 from IPython.nbformat.v3 import (
9 from IPython.nbformat.v3 import (
11 NotebookNode,
10 NotebookNode,
12 new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet,
11 new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet,
13 parse_filename, new_metadata, new_author, new_heading_cell, nbformat,
12 parse_filename, new_metadata, new_author, new_heading_cell, nbformat,
14 nbformat_minor, nbformat_schema, to_notebook_json
13 nbformat_minor, nbformat_schema, to_notebook_json
15 )
14 )
16 from IPython.nbformat import v3 as _v_latest
15 from IPython.nbformat import v3 as _v_latest
17
16
18 from .reader import reads as reader_reads
17 from .reader import reads as reader_reads
19 from .reader import versions
18 from .reader import versions
20 from .convert import convert
19 from .convert import convert
21 from .validator import validate
20 from .validator import validate
22
21
23 from IPython.utils.log import get_logger
22 from IPython.utils.log import get_logger
24
23
25 __all__ = ['NotebookNode', 'new_code_cell', 'new_text_cell', 'new_notebook',
24 __all__ = ['NotebookNode', 'new_code_cell', 'new_text_cell', 'new_notebook',
26 'new_output', 'new_worksheet', 'parse_filename', 'new_metadata', 'new_author',
25 'new_output', 'new_worksheet', 'parse_filename', 'new_metadata', 'new_author',
27 'new_heading_cell', 'nbformat', 'nbformat_minor', 'nbformat_schema',
26 'new_heading_cell', 'nbformat', 'nbformat_minor', 'nbformat_schema',
28 'to_notebook_json', 'convert', 'validate', 'NBFormatError', 'parse_py',
27 'to_notebook_json', 'convert', 'validate', 'NBFormatError', 'parse_py',
29 'reads_json', 'writes_json', 'reads_py', 'writes_py', 'reads', 'writes', 'read',
28 'reads_json', 'writes_json', 'reads_py', 'writes_py', 'reads', 'writes', 'read',
30 'write']
29 'write']
31
30
32 current_nbformat = nbformat
31 current_nbformat = nbformat
33 current_nbformat_minor = nbformat_minor
32 current_nbformat_minor = nbformat_minor
34 current_nbformat_module = _v_latest.__name__
33 current_nbformat_module = _v_latest.__name__
35
34
36
35
37 def docstring_nbformat_mod(func):
38 """Decorator for docstrings referring to classes/functions accessed through
39 nbformat.current.
40
41 Put {nbformat_mod} in the docstring in place of 'IPython.nbformat.v3'.
42 """
43 func.__doc__ = func.__doc__.format(nbformat_mod=current_nbformat_module)
44 return func
45
46
47 class NBFormatError(ValueError):
36 class NBFormatError(ValueError):
48 pass
37 pass
49
38
50
39
51 def parse_py(s, **kwargs):
40 def parse_py(s, **kwargs):
52 """Parse a string into a (nbformat, string) tuple."""
41 """Parse a string into a (nbformat, string) tuple."""
53 nbf = current_nbformat
42 nbf = current_nbformat
54 nbm = current_nbformat_minor
43 nbm = current_nbformat_minor
55
44
56 pattern = r'# <nbformat>(?P<nbformat>\d+[\.\d+]*)</nbformat>'
45 pattern = r'# <nbformat>(?P<nbformat>\d+[\.\d+]*)</nbformat>'
57 m = re.search(pattern,s)
46 m = re.search(pattern,s)
58 if m is not None:
47 if m is not None:
59 digits = m.group('nbformat').split('.')
48 digits = m.group('nbformat').split('.')
60 nbf = int(digits[0])
49 nbf = int(digits[0])
61 if len(digits) > 1:
50 if len(digits) > 1:
62 nbm = int(digits[1])
51 nbm = int(digits[1])
63
52
64 return nbf, nbm, s
53 return nbf, nbm, s
65
54
66
55
67 def reads_json(nbjson, **kwargs):
56 def reads_json(nbjson, **kwargs):
68 """Read a JSON notebook from a string and return the NotebookNode
57 """Read a JSON notebook from a string and return the NotebookNode
69 object. Report if any JSON format errors are detected.
58 object. Report if any JSON format errors are detected.
70
59
71 """
60 """
72 nb = reader_reads(nbjson, **kwargs)
61 nb = reader_reads(nbjson, **kwargs)
73 nb_current = convert(nb, current_nbformat)
62 nb_current = convert(nb, current_nbformat)
74 errors = validate(nb_current)
63 errors = validate(nb_current)
75 if errors:
64 if errors:
76 get_logger().error(
65 get_logger().error(
77 "Notebook JSON is invalid (%d errors detected during read)",
66 "Notebook JSON is invalid (%d errors detected during read)",
78 len(errors))
67 len(errors))
79 return nb_current
68 return nb_current
80
69
81
70
82 def writes_json(nb, **kwargs):
71 def writes_json(nb, **kwargs):
83 """Take a NotebookNode object and write out a JSON string. Report if
72 """Take a NotebookNode object and write out a JSON string. Report if
84 any JSON format errors are detected.
73 any JSON format errors are detected.
85
74
86 """
75 """
87 errors = validate(nb)
76 errors = validate(nb)
88 if errors:
77 if errors:
89 get_logger().error(
78 get_logger().error(
90 "Notebook JSON is invalid (%d errors detected during write)",
79 "Notebook JSON is invalid (%d errors detected during write)",
91 len(errors))
80 len(errors))
92 nbjson = versions[current_nbformat].writes_json(nb, **kwargs)
81 nbjson = versions[current_nbformat].writes_json(nb, **kwargs)
93 return nbjson
82 return nbjson
94
83
95
84
96 def reads_py(s, **kwargs):
85 def reads_py(s, **kwargs):
97 """Read a .py notebook from a string and return the NotebookNode object."""
86 """Read a .py notebook from a string and return the NotebookNode object."""
98 nbf, nbm, s = parse_py(s, **kwargs)
87 nbf, nbm, s = parse_py(s, **kwargs)
99 if nbf in (2, 3):
88 if nbf in (2, 3):
100 nb = versions[nbf].to_notebook_py(s, **kwargs)
89 nb = versions[nbf].to_notebook_py(s, **kwargs)
101 else:
90 else:
102 raise NBFormatError('Unsupported PY nbformat version: %i' % nbf)
91 raise NBFormatError('Unsupported PY nbformat version: %i' % nbf)
103 return nb
92 return nb
104
93
105
94
106 def writes_py(nb, **kwargs):
95 def writes_py(nb, **kwargs):
107 # nbformat 3 is the latest format that supports py
96 # nbformat 3 is the latest format that supports py
108 return versions[3].writes_py(nb, **kwargs)
97 return versions[3].writes_py(nb, **kwargs)
109
98
110
99
111 # High level API
100 # High level API
112
101
113
102
114 def reads(s, format, **kwargs):
103 def reads(s, format, **kwargs):
115 """Read a notebook from a string and return the NotebookNode object.
104 """Read a notebook from a string and return the NotebookNode object.
116
105
117 This function properly handles notebooks of any version. The notebook
106 This function properly handles notebooks of any version. The notebook
118 returned will always be in the current version's format.
107 returned will always be in the current version's format.
119
108
120 Parameters
109 Parameters
121 ----------
110 ----------
122 s : unicode
111 s : unicode
123 The raw unicode string to read the notebook from.
112 The raw unicode string to read the notebook from.
124 format : (u'json', u'ipynb', u'py')
113 format : (u'json', u'ipynb', u'py')
125 The format that the string is in.
114 The format that the string is in.
126
115
127 Returns
116 Returns
128 -------
117 -------
129 nb : NotebookNode
118 nb : NotebookNode
130 The notebook that was read.
119 The notebook that was read.
131 """
120 """
132 format = unicode_type(format)
121 format = unicode_type(format)
133 if format == u'json' or format == u'ipynb':
122 if format == u'json' or format == u'ipynb':
134 return reads_json(s, **kwargs)
123 return reads_json(s, **kwargs)
135 elif format == u'py':
124 elif format == u'py':
136 return reads_py(s, **kwargs)
125 return reads_py(s, **kwargs)
137 else:
126 else:
138 raise NBFormatError('Unsupported format: %s' % format)
127 raise NBFormatError('Unsupported format: %s' % format)
139
128
140
129
141 def writes(nb, format, **kwargs):
130 def writes(nb, format, **kwargs):
142 """Write a notebook to a string in a given format in the current nbformat version.
131 """Write a notebook to a string in a given format in the current nbformat version.
143
132
144 This function always writes the notebook in the current nbformat version.
133 This function always writes the notebook in the current nbformat version.
145
134
146 Parameters
135 Parameters
147 ----------
136 ----------
148 nb : NotebookNode
137 nb : NotebookNode
149 The notebook to write.
138 The notebook to write.
150 format : (u'json', u'ipynb', u'py')
139 format : (u'json', u'ipynb', u'py')
151 The format to write the notebook in.
140 The format to write the notebook in.
152
141
153 Returns
142 Returns
154 -------
143 -------
155 s : unicode
144 s : unicode
156 The notebook string.
145 The notebook string.
157 """
146 """
158 format = unicode_type(format)
147 format = unicode_type(format)
159 if format == u'json' or format == u'ipynb':
148 if format == u'json' or format == u'ipynb':
160 return writes_json(nb, **kwargs)
149 return writes_json(nb, **kwargs)
161 elif format == u'py':
150 elif format == u'py':
162 return writes_py(nb, **kwargs)
151 return writes_py(nb, **kwargs)
163 else:
152 else:
164 raise NBFormatError('Unsupported format: %s' % format)
153 raise NBFormatError('Unsupported format: %s' % format)
165
154
166
155
167 def read(fp, format, **kwargs):
156 def read(fp, format, **kwargs):
168 """Read a notebook from a file and return the NotebookNode object.
157 """Read a notebook from a file and return the NotebookNode object.
169
158
170 This function properly handles notebooks of any version. The notebook
159 This function properly handles notebooks of any version. The notebook
171 returned will always be in the current version's format.
160 returned will always be in the current version's format.
172
161
173 Parameters
162 Parameters
174 ----------
163 ----------
175 fp : file
164 fp : file
176 Any file-like object with a read method.
165 Any file-like object with a read method.
177 format : (u'json', u'ipynb', u'py')
166 format : (u'json', u'ipynb', u'py')
178 The format that the string is in.
167 The format that the string is in.
179
168
180 Returns
169 Returns
181 -------
170 -------
182 nb : NotebookNode
171 nb : NotebookNode
183 The notebook that was read.
172 The notebook that was read.
184 """
173 """
185 return reads(fp.read(), format, **kwargs)
174 return reads(fp.read(), format, **kwargs)
186
175
187
176
188 def write(nb, fp, format, **kwargs):
177 def write(nb, fp, format, **kwargs):
189 """Write a notebook to a file in a given format in the current nbformat version.
178 """Write a notebook to a file in a given format in the current nbformat version.
190
179
191 This function always writes the notebook in the current nbformat version.
180 This function always writes the notebook in the current nbformat version.
192
181
193 Parameters
182 Parameters
194 ----------
183 ----------
195 nb : NotebookNode
184 nb : NotebookNode
196 The notebook to write.
185 The notebook to write.
197 fp : file
186 fp : file
198 Any file-like object with a write method.
187 Any file-like object with a write method.
199 format : (u'json', u'ipynb', u'py')
188 format : (u'json', u'ipynb', u'py')
200 The format to write the notebook in.
189 The format to write the notebook in.
201
190
202 Returns
191 Returns
203 -------
192 -------
204 s : unicode
193 s : unicode
205 The notebook string.
194 The notebook string.
206 """
195 """
207 return fp.write(writes(nb, format, **kwargs))
196 return fp.write(writes(nb, format, **kwargs))
208
197
209 def _convert_to_metadata():
198 def _convert_to_metadata():
210 """Convert to a notebook having notebook metadata."""
199 """Convert to a notebook having notebook metadata."""
211 import glob
200 import glob
212 for fname in glob.glob('*.ipynb'):
201 for fname in glob.glob('*.ipynb'):
213 print('Converting file:',fname)
202 print('Converting file:',fname)
214 with open(fname,'r') as f:
203 with open(fname,'r') as f:
215 nb = read(f,u'json')
204 nb = read(f,u'json')
216 md = new_metadata()
205 md = new_metadata()
217 if u'name' in nb:
206 if u'name' in nb:
218 md.name = nb.name
207 md.name = nb.name
219 del nb[u'name']
208 del nb[u'name']
220 nb.metadata = md
209 nb.metadata = md
221 with open(fname,'w') as f:
210 with open(fname,'w') as f:
222 write(nb, f, u'json')
211 write(nb, f, u'json')
223
212
General Comments 0
You need to be logged in to leave comments. Login now