##// END OF EJS Templates
Add MIME types to nbconvert exporters
Thomas Kluyver -
Show More
@@ -1,72 +1,83 b''
1 import os
1 import os
2
2
3 from tornado import web
3 from tornado import web
4
4
5 from ..base.handlers import IPythonHandler
5 from ..base.handlers import IPythonHandler
6 from IPython.nbformat.current import to_notebook_json
6 from IPython.nbformat.current import to_notebook_json
7 from IPython.nbconvert.exporters.export import exporter_map
7 from IPython.nbconvert.exporters.export import exporter_map
8 from IPython.utils import tz
8 from IPython.utils import tz
9
9
10
10
11 def has_resource_files(resources):
11 def has_resource_files(resources):
12 output_files_dir = resources.get('output_files_dir', "")
12 output_files_dir = resources.get('output_files_dir', "")
13 return bool(os.path.isdir(output_files_dir) and \
13 return bool(os.path.isdir(output_files_dir) and \
14 os.listdir(output_files_dir))
14 os.listdir(output_files_dir))
15
15
16 class NbconvertFileHandler(IPythonHandler):
16 class NbconvertFileHandler(IPythonHandler):
17
17
18 SUPPORTED_METHODS = ('GET',)
18 SUPPORTED_METHODS = ('GET',)
19
19
20 @web.authenticated
20 @web.authenticated
21 def get(self, format, path='', name=None):
21 def get(self, format, path='', name=None):
22 exporter = exporter_map[format]()
22 exporter = exporter_map[format]()
23
23
24 path = path.strip('/')
24 path = path.strip('/')
25 os_path = self.notebook_manager.get_os_path(name, path)
25 os_path = self.notebook_manager.get_os_path(name, path)
26 if not os.path.isfile(os_path):
26 if not os.path.isfile(os_path):
27 raise web.HTTPError(404, u'Notebook does not exist: %s' % name)
27 raise web.HTTPError(404, u'Notebook does not exist: %s' % name)
28
28
29 info = os.stat(os_path)
29 info = os.stat(os_path)
30 self.set_header('Last-Modified', tz.utcfromtimestamp(info.st_mtime))
30 self.set_header('Last-Modified', tz.utcfromtimestamp(info.st_mtime))
31
32 # Force download if requested
31 if self.get_argument('download', 'false').lower() == 'true':
33 if self.get_argument('download', 'false').lower() == 'true':
32 filename = os.path.splitext(name)[0] + '.' + exporter.file_extension
34 filename = os.path.splitext(name)[0] + '.' + exporter.file_extension
33 self.set_header('Content-Disposition',
35 self.set_header('Content-Disposition',
34 'attachment; filename="%s"' % filename)
36 'attachment; filename="%s"' % filename)
35
37
38 # MIME type
39 if exporter.mime_type:
40 self.set_header('Content-Type', '%s; charset=utf-8' % exporter.mime_type)
41
36 output, resources = exporter.from_filename(os_path)
42 output, resources = exporter.from_filename(os_path)
37
43
38 # TODO: If there are resources, combine them into a zip file
44 # TODO: If there are resources, combine them into a zip file
39 assert not has_resource_files(resources)
45 assert not has_resource_files(resources)
40
46
41 self.finish(output)
47 self.finish(output)
42
48
43 class NbconvertPostHandler(IPythonHandler):
49 class NbconvertPostHandler(IPythonHandler):
44 SUPPORTED_METHODS = ('POST',)
50 SUPPORTED_METHODS = ('POST',)
45
51
46 @web.authenticated
52 @web.authenticated
47 def post(self, format):
53 def post(self, format):
48 exporter = exporter_map[format]()
54 exporter = exporter_map[format]()
49
55
50 model = self.get_json_body()
56 model = self.get_json_body()
51 nbnode = to_notebook_json(model['content'])
57 nbnode = to_notebook_json(model['content'])
52 output, resources = exporter.from_notebook_node(nbnode)
53
58
59 # MIME type
60 if exporter.mime_type:
61 self.set_header('Content-Type', '%s; charset=utf-8' % exporter.mime_type)
62
63 output, resources = exporter.from_notebook_node(nbnode)
64
54 # TODO: If there are resources, combine them into a zip file
65 # TODO: If there are resources, combine them into a zip file
55 assert not has_resource_files(resources)
66 assert not has_resource_files(resources)
56
67
57 self.finish(output)
68 self.finish(output)
58
69
59 #-----------------------------------------------------------------------------
70 #-----------------------------------------------------------------------------
60 # URL to handler mappings
71 # URL to handler mappings
61 #-----------------------------------------------------------------------------
72 #-----------------------------------------------------------------------------
62
73
63 _format_regex = r"(?P<format>\w+)"
74 _format_regex = r"(?P<format>\w+)"
64 _path_regex = r"(?P<path>(?:/.*)*)"
75 _path_regex = r"(?P<path>(?:/.*)*)"
65 _notebook_name_regex = r"(?P<name>[^/]+\.ipynb)"
76 _notebook_name_regex = r"(?P<name>[^/]+\.ipynb)"
66 _notebook_path_regex = "%s/%s" % (_path_regex, _notebook_name_regex)
77 _notebook_path_regex = "%s/%s" % (_path_regex, _notebook_name_regex)
67
78
68 default_handlers = [
79 default_handlers = [
69 (r"/nbconvert/%s%s" % (_format_regex, _notebook_path_regex),
80 (r"/nbconvert/%s%s" % (_format_regex, _notebook_path_regex),
70 NbconvertFileHandler),
81 NbconvertFileHandler),
71 (r"/nbconvert/%s" % _format_regex, NbconvertPostHandler),
82 (r"/nbconvert/%s" % _format_regex, NbconvertPostHandler),
72 ] No newline at end of file
83 ]
@@ -1,90 +1,94 b''
1 import io
1 import io
2 import json
2 import json
3 import os
3 import os
4 from os.path import join as pjoin
4 from os.path import join as pjoin
5 import shutil
5 import shutil
6
6
7 import requests
7 import requests
8
8
9 from IPython.html.utils import url_path_join
9 from IPython.html.utils import url_path_join
10 from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error
10 from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error
11 from IPython.nbformat.current import (new_notebook, write, new_worksheet,
11 from IPython.nbformat.current import (new_notebook, write, new_worksheet,
12 new_heading_cell, new_code_cell)
12 new_heading_cell, new_code_cell)
13
13
14 class NbconvertAPI(object):
14 class NbconvertAPI(object):
15 """Wrapper for nbconvert API calls."""
15 """Wrapper for nbconvert API calls."""
16 def __init__(self, base_url):
16 def __init__(self, base_url):
17 self.base_url = base_url
17 self.base_url = base_url
18
18
19 def _req(self, verb, path, body=None, params=None):
19 def _req(self, verb, path, body=None, params=None):
20 response = requests.request(verb,
20 response = requests.request(verb,
21 url_path_join(self.base_url, 'nbconvert', path),
21 url_path_join(self.base_url, 'nbconvert', path),
22 data=body, params=params,
22 data=body, params=params,
23 )
23 )
24 response.raise_for_status()
24 response.raise_for_status()
25 return response
25 return response
26
26
27 def from_file(self, format, path, name, download=False):
27 def from_file(self, format, path, name, download=False):
28 return self._req('GET', url_path_join(format, path, name),
28 return self._req('GET', url_path_join(format, path, name),
29 params={'download':download})
29 params={'download':download})
30
30
31 def from_post(self, format, nbmodel):
31 def from_post(self, format, nbmodel):
32 body = json.dumps(nbmodel)
32 body = json.dumps(nbmodel)
33 return self._req('POST', format, body)
33 return self._req('POST', format, body)
34
34
35 class APITest(NotebookTestBase):
35 class APITest(NotebookTestBase):
36 def setUp(self):
36 def setUp(self):
37 nbdir = self.notebook_dir.name
37 nbdir = self.notebook_dir.name
38
38
39 if not os.path.isdir(pjoin(nbdir, 'foo')):
39 if not os.path.isdir(pjoin(nbdir, 'foo')):
40 os.mkdir(pjoin(nbdir, 'foo'))
40 os.mkdir(pjoin(nbdir, 'foo'))
41
41
42 nb = new_notebook(name='testnb')
42 nb = new_notebook(name='testnb')
43
43
44 ws = new_worksheet()
44 ws = new_worksheet()
45 nb.worksheets = [ws]
45 nb.worksheets = [ws]
46 ws.cells.append(new_heading_cell(u'Created by test Β³'))
46 ws.cells.append(new_heading_cell(u'Created by test Β³'))
47 ws.cells.append(new_code_cell(input=u'print(2*6)'))
47 ws.cells.append(new_code_cell(input=u'print(2*6)'))
48
48
49 with io.open(pjoin(nbdir, 'foo', 'testnb.ipynb'), 'w',
49 with io.open(pjoin(nbdir, 'foo', 'testnb.ipynb'), 'w',
50 encoding='utf-8') as f:
50 encoding='utf-8') as f:
51 write(nb, f, format='ipynb')
51 write(nb, f, format='ipynb')
52
52
53 self.nbconvert_api = NbconvertAPI(self.base_url())
53 self.nbconvert_api = NbconvertAPI(self.base_url())
54
54
55 def tearDown(self):
55 def tearDown(self):
56 nbdir = self.notebook_dir.name
56 nbdir = self.notebook_dir.name
57
57
58 for dname in ['foo']:
58 for dname in ['foo']:
59 shutil.rmtree(pjoin(nbdir, dname), ignore_errors=True)
59 shutil.rmtree(pjoin(nbdir, dname), ignore_errors=True)
60
60
61 def test_from_file(self):
61 def test_from_file(self):
62 r = self.nbconvert_api.from_file('html', 'foo', 'testnb.ipynb')
62 r = self.nbconvert_api.from_file('html', 'foo', 'testnb.ipynb')
63 self.assertEqual(r.status_code, 200)
63 self.assertEqual(r.status_code, 200)
64 self.assertIn(u'text/html', r.headers['Content-Type'])
64 self.assertIn(u'Created by test', r.text)
65 self.assertIn(u'Created by test', r.text)
65 self.assertIn(u'print', r.text)
66 self.assertIn(u'print', r.text)
66
67
67 r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb')
68 r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb')
69 self.assertIn(u'text/x-python', r.headers['Content-Type'])
68 self.assertIn(u'print(2*6)', r.text)
70 self.assertIn(u'print(2*6)', r.text)
69
71
70 def test_from_file_404(self):
72 def test_from_file_404(self):
71 with assert_http_error(404):
73 with assert_http_error(404):
72 self.nbconvert_api.from_file('html', 'foo', 'thisdoesntexist.ipynb')
74 self.nbconvert_api.from_file('html', 'foo', 'thisdoesntexist.ipynb')
73
75
74 def test_from_file_download(self):
76 def test_from_file_download(self):
75 r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb', download=True)
77 r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb', download=True)
76 content_disposition = r.headers['Content-Disposition']
78 content_disposition = r.headers['Content-Disposition']
77 assert 'attachment' in content_disposition
79 self.assertIn('attachment', content_disposition)
78 assert 'testnb.py' in content_disposition
80 self.assertIn('testnb.py', content_disposition)
79
81
80 def test_from_post(self):
82 def test_from_post(self):
81 nbmodel_url = url_path_join(self.base_url(), 'api/notebooks/foo/testnb.ipynb')
83 nbmodel_url = url_path_join(self.base_url(), 'api/notebooks/foo/testnb.ipynb')
82 nbmodel = requests.get(nbmodel_url).json()
84 nbmodel = requests.get(nbmodel_url).json()
83
85
84 r = self.nbconvert_api.from_post(format='html', nbmodel=nbmodel)
86 r = self.nbconvert_api.from_post(format='html', nbmodel=nbmodel)
85 self.assertEqual(r.status_code, 200)
87 self.assertEqual(r.status_code, 200)
88 self.assertIn(u'text/html', r.headers['Content-Type'])
86 self.assertIn(u'Created by test', r.text)
89 self.assertIn(u'Created by test', r.text)
87 self.assertIn(u'print', r.text)
90 self.assertIn(u'print', r.text)
88
91
89 r = self.nbconvert_api.from_post(format='python', nbmodel=nbmodel)
92 r = self.nbconvert_api.from_post(format='python', nbmodel=nbmodel)
93 self.assertIn(u'text/x-python', r.headers['Content-Type'])
90 self.assertIn(u'print(2*6)', r.text) No newline at end of file
94 self.assertIn(u'print(2*6)', r.text)
@@ -1,270 +1,274 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 = Unicode('', config=True,
57 help="MIME type of the result file, for HTTP response headers."
58 )
59
56 #Configurability, allows the user to easily add filters and preprocessors.
60 #Configurability, allows the user to easily add filters and preprocessors.
57 preprocessors = List(config=True,
61 preprocessors = List(config=True,
58 help="""List of preprocessors, by name or namespace, to enable.""")
62 help="""List of preprocessors, by name or namespace, to enable.""")
59
63
60 _preprocessors = None
64 _preprocessors = None
61
65
62 default_preprocessors = List(['IPython.nbconvert.preprocessors.coalesce_streams',
66 default_preprocessors = List(['IPython.nbconvert.preprocessors.coalesce_streams',
63 'IPython.nbconvert.preprocessors.SVG2PDFPreprocessor',
67 'IPython.nbconvert.preprocessors.SVG2PDFPreprocessor',
64 'IPython.nbconvert.preprocessors.ExtractOutputPreprocessor',
68 'IPython.nbconvert.preprocessors.ExtractOutputPreprocessor',
65 'IPython.nbconvert.preprocessors.CSSHTMLHeaderPreprocessor',
69 'IPython.nbconvert.preprocessors.CSSHTMLHeaderPreprocessor',
66 'IPython.nbconvert.preprocessors.RevealHelpPreprocessor',
70 'IPython.nbconvert.preprocessors.RevealHelpPreprocessor',
67 'IPython.nbconvert.preprocessors.LatexPreprocessor',
71 'IPython.nbconvert.preprocessors.LatexPreprocessor',
68 'IPython.nbconvert.preprocessors.HighlightMagicsPreprocessor'],
72 'IPython.nbconvert.preprocessors.HighlightMagicsPreprocessor'],
69 config=True,
73 config=True,
70 help="""List of preprocessors available by default, by name, namespace,
74 help="""List of preprocessors available by default, by name, namespace,
71 instance, or type.""")
75 instance, or type.""")
72
76
73
77
74 def __init__(self, config=None, **kw):
78 def __init__(self, config=None, **kw):
75 """
79 """
76 Public constructor
80 Public constructor
77
81
78 Parameters
82 Parameters
79 ----------
83 ----------
80 config : config
84 config : config
81 User configuration instance.
85 User configuration instance.
82 """
86 """
83 with_default_config = self.default_config
87 with_default_config = self.default_config
84 if config:
88 if config:
85 with_default_config.merge(config)
89 with_default_config.merge(config)
86
90
87 super(Exporter, self).__init__(config=with_default_config, **kw)
91 super(Exporter, self).__init__(config=with_default_config, **kw)
88
92
89 self._init_preprocessors()
93 self._init_preprocessors()
90
94
91
95
92 @property
96 @property
93 def default_config(self):
97 def default_config(self):
94 return Config()
98 return Config()
95
99
96 @nbformat.docstring_nbformat_mod
100 @nbformat.docstring_nbformat_mod
97 def from_notebook_node(self, nb, resources=None, **kw):
101 def from_notebook_node(self, nb, resources=None, **kw):
98 """
102 """
99 Convert a notebook from a notebook node instance.
103 Convert a notebook from a notebook node instance.
100
104
101 Parameters
105 Parameters
102 ----------
106 ----------
103 nb : :class:`~{nbformat_mod}.nbbase.NotebookNode`
107 nb : :class:`~{nbformat_mod}.nbbase.NotebookNode`
104 Notebook node
108 Notebook node
105 resources : dict
109 resources : dict
106 Additional resources that can be accessed read/write by
110 Additional resources that can be accessed read/write by
107 preprocessors and filters.
111 preprocessors and filters.
108 **kw
112 **kw
109 Ignored (?)
113 Ignored (?)
110 """
114 """
111 nb_copy = copy.deepcopy(nb)
115 nb_copy = copy.deepcopy(nb)
112 resources = self._init_resources(resources)
116 resources = self._init_resources(resources)
113
117
114 # Preprocess
118 # Preprocess
115 nb_copy, resources = self._preprocess(nb_copy, resources)
119 nb_copy, resources = self._preprocess(nb_copy, resources)
116
120
117 return nb_copy, resources
121 return nb_copy, resources
118
122
119
123
120 def from_filename(self, filename, resources=None, **kw):
124 def from_filename(self, filename, resources=None, **kw):
121 """
125 """
122 Convert a notebook from a notebook file.
126 Convert a notebook from a notebook file.
123
127
124 Parameters
128 Parameters
125 ----------
129 ----------
126 filename : str
130 filename : str
127 Full filename of the notebook file to open and convert.
131 Full filename of the notebook file to open and convert.
128 """
132 """
129
133
130 # Pull the metadata from the filesystem.
134 # Pull the metadata from the filesystem.
131 if resources is None:
135 if resources is None:
132 resources = ResourcesDict()
136 resources = ResourcesDict()
133 if not 'metadata' in resources or resources['metadata'] == '':
137 if not 'metadata' in resources or resources['metadata'] == '':
134 resources['metadata'] = ResourcesDict()
138 resources['metadata'] = ResourcesDict()
135 basename = os.path.basename(filename)
139 basename = os.path.basename(filename)
136 notebook_name = basename[:basename.rfind('.')]
140 notebook_name = basename[:basename.rfind('.')]
137 resources['metadata']['name'] = notebook_name
141 resources['metadata']['name'] = notebook_name
138
142
139 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
143 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
140 resources['metadata']['modified_date'] = modified_date.strftime(text.date_format)
144 resources['metadata']['modified_date'] = modified_date.strftime(text.date_format)
141
145
142 with io.open(filename, encoding='utf-8') as f:
146 with io.open(filename, encoding='utf-8') as f:
143 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw)
147 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw)
144
148
145
149
146 def from_file(self, file_stream, resources=None, **kw):
150 def from_file(self, file_stream, resources=None, **kw):
147 """
151 """
148 Convert a notebook from a notebook file.
152 Convert a notebook from a notebook file.
149
153
150 Parameters
154 Parameters
151 ----------
155 ----------
152 file_stream : file-like object
156 file_stream : file-like object
153 Notebook file-like object to convert.
157 Notebook file-like object to convert.
154 """
158 """
155 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
159 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
156
160
157
161
158 def register_preprocessor(self, preprocessor, enabled=False):
162 def register_preprocessor(self, preprocessor, enabled=False):
159 """
163 """
160 Register a preprocessor.
164 Register a preprocessor.
161 Preprocessors are classes that act upon the notebook before it is
165 Preprocessors are classes that act upon the notebook before it is
162 passed into the Jinja templating engine. preprocessors are also
166 passed into the Jinja templating engine. preprocessors are also
163 capable of passing additional information to the Jinja
167 capable of passing additional information to the Jinja
164 templating engine.
168 templating engine.
165
169
166 Parameters
170 Parameters
167 ----------
171 ----------
168 preprocessor : preprocessor
172 preprocessor : preprocessor
169 """
173 """
170 if preprocessor is None:
174 if preprocessor is None:
171 raise TypeError('preprocessor')
175 raise TypeError('preprocessor')
172 isclass = isinstance(preprocessor, type)
176 isclass = isinstance(preprocessor, type)
173 constructed = not isclass
177 constructed = not isclass
174
178
175 # Handle preprocessor's registration based on it's type
179 # Handle preprocessor's registration based on it's type
176 if constructed and isinstance(preprocessor, py3compat.string_types):
180 if constructed and isinstance(preprocessor, py3compat.string_types):
177 # Preprocessor is a string, import the namespace and recursively call
181 # Preprocessor is a string, import the namespace and recursively call
178 # this register_preprocessor method
182 # this register_preprocessor method
179 preprocessor_cls = import_item(preprocessor)
183 preprocessor_cls = import_item(preprocessor)
180 return self.register_preprocessor(preprocessor_cls, enabled)
184 return self.register_preprocessor(preprocessor_cls, enabled)
181
185
182 if constructed and hasattr(preprocessor, '__call__'):
186 if constructed and hasattr(preprocessor, '__call__'):
183 # Preprocessor is a function, no need to construct it.
187 # Preprocessor is a function, no need to construct it.
184 # Register and return the preprocessor.
188 # Register and return the preprocessor.
185 if enabled:
189 if enabled:
186 preprocessor.enabled = True
190 preprocessor.enabled = True
187 self._preprocessors.append(preprocessor)
191 self._preprocessors.append(preprocessor)
188 return preprocessor
192 return preprocessor
189
193
190 elif isclass and isinstance(preprocessor, MetaHasTraits):
194 elif isclass and isinstance(preprocessor, MetaHasTraits):
191 # Preprocessor is configurable. Make sure to pass in new default for
195 # Preprocessor is configurable. Make sure to pass in new default for
192 # the enabled flag if one was specified.
196 # the enabled flag if one was specified.
193 self.register_preprocessor(preprocessor(parent=self), enabled)
197 self.register_preprocessor(preprocessor(parent=self), enabled)
194
198
195 elif isclass:
199 elif isclass:
196 # Preprocessor is not configurable, construct it
200 # Preprocessor is not configurable, construct it
197 self.register_preprocessor(preprocessor(), enabled)
201 self.register_preprocessor(preprocessor(), enabled)
198
202
199 else:
203 else:
200 # Preprocessor is an instance of something without a __call__
204 # Preprocessor is an instance of something without a __call__
201 # attribute.
205 # attribute.
202 raise TypeError('preprocessor')
206 raise TypeError('preprocessor')
203
207
204
208
205 def _init_preprocessors(self):
209 def _init_preprocessors(self):
206 """
210 """
207 Register all of the preprocessors needed for this exporter, disabled
211 Register all of the preprocessors needed for this exporter, disabled
208 unless specified explicitly.
212 unless specified explicitly.
209 """
213 """
210 if self._preprocessors is None:
214 if self._preprocessors is None:
211 self._preprocessors = []
215 self._preprocessors = []
212
216
213 #Load default preprocessors (not necessarly enabled by default).
217 #Load default preprocessors (not necessarly enabled by default).
214 if self.default_preprocessors:
218 if self.default_preprocessors:
215 for preprocessor in self.default_preprocessors:
219 for preprocessor in self.default_preprocessors:
216 self.register_preprocessor(preprocessor)
220 self.register_preprocessor(preprocessor)
217
221
218 #Load user preprocessors. Enable by default.
222 #Load user preprocessors. Enable by default.
219 if self.preprocessors:
223 if self.preprocessors:
220 for preprocessor in self.preprocessors:
224 for preprocessor in self.preprocessors:
221 self.register_preprocessor(preprocessor, enabled=True)
225 self.register_preprocessor(preprocessor, enabled=True)
222
226
223
227
224 def _init_resources(self, resources):
228 def _init_resources(self, resources):
225
229
226 #Make sure the resources dict is of ResourcesDict type.
230 #Make sure the resources dict is of ResourcesDict type.
227 if resources is None:
231 if resources is None:
228 resources = ResourcesDict()
232 resources = ResourcesDict()
229 if not isinstance(resources, ResourcesDict):
233 if not isinstance(resources, ResourcesDict):
230 new_resources = ResourcesDict()
234 new_resources = ResourcesDict()
231 new_resources.update(resources)
235 new_resources.update(resources)
232 resources = new_resources
236 resources = new_resources
233
237
234 #Make sure the metadata extension exists in resources
238 #Make sure the metadata extension exists in resources
235 if 'metadata' in resources:
239 if 'metadata' in resources:
236 if not isinstance(resources['metadata'], ResourcesDict):
240 if not isinstance(resources['metadata'], ResourcesDict):
237 resources['metadata'] = ResourcesDict(resources['metadata'])
241 resources['metadata'] = ResourcesDict(resources['metadata'])
238 else:
242 else:
239 resources['metadata'] = ResourcesDict()
243 resources['metadata'] = ResourcesDict()
240 if not resources['metadata']['name']:
244 if not resources['metadata']['name']:
241 resources['metadata']['name'] = 'Notebook'
245 resources['metadata']['name'] = 'Notebook'
242
246
243 #Set the output extension
247 #Set the output extension
244 resources['output_extension'] = self.file_extension
248 resources['output_extension'] = self.file_extension
245 return resources
249 return resources
246
250
247
251
248 def _preprocess(self, nb, resources):
252 def _preprocess(self, nb, resources):
249 """
253 """
250 Preprocess the notebook before passing it into the Jinja engine.
254 Preprocess the notebook before passing it into the Jinja engine.
251 To preprocess the notebook is to apply all of the
255 To preprocess the notebook is to apply all of the
252
256
253 Parameters
257 Parameters
254 ----------
258 ----------
255 nb : notebook node
259 nb : notebook node
256 notebook that is being exported.
260 notebook that is being exported.
257 resources : a dict of additional resources that
261 resources : a dict of additional resources that
258 can be accessed read/write by preprocessors
262 can be accessed read/write by preprocessors
259 """
263 """
260
264
261 # Do a copy.deepcopy first,
265 # Do a copy.deepcopy first,
262 # we are never safe enough with what the preprocessors could do.
266 # we are never safe enough with what the preprocessors could do.
263 nbc = copy.deepcopy(nb)
267 nbc = copy.deepcopy(nb)
264 resc = copy.deepcopy(resources)
268 resc = copy.deepcopy(resources)
265
269
266 #Run each preprocessor on the notebook. Carry the output along
270 #Run each preprocessor on the notebook. Carry the output along
267 #to each preprocessor
271 #to each preprocessor
268 for preprocessor in self._preprocessors:
272 for preprocessor in self._preprocessors:
269 nbc, resc = preprocessor(nbc, resc)
273 nbc, resc = preprocessor(nbc, resc)
270 return nbc, resc
274 return nbc, resc
@@ -1,56 +1,60 b''
1 """HTML Exporter class"""
1 """HTML Exporter class"""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from IPython.utils.traitlets import Unicode, List
15 from IPython.utils.traitlets import Unicode, List
16
16
17 from IPython.nbconvert import preprocessors
17 from IPython.nbconvert import preprocessors
18 from IPython.config import Config
18 from IPython.config import Config
19
19
20 from .templateexporter import TemplateExporter
20 from .templateexporter import TemplateExporter
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Classes
23 # Classes
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 class HTMLExporter(TemplateExporter):
26 class HTMLExporter(TemplateExporter):
27 """
27 """
28 Exports a basic HTML document. This exporter assists with the export of
28 Exports a basic HTML document. This exporter assists with the export of
29 HTML. Inherit from it if you are writing your own HTML template and need
29 HTML. Inherit from it if you are writing your own HTML template and need
30 custom preprocessors/filters. If you don't need custom preprocessors/
30 custom preprocessors/filters. If you don't need custom preprocessors/
31 filters, just change the 'template_file' config option.
31 filters, just change the 'template_file' config option.
32 """
32 """
33
33
34 file_extension = Unicode(
34 file_extension = Unicode(
35 'html', config=True,
35 'html', config=True,
36 help="Extension of the file that should be written to disk"
36 help="Extension of the file that should be written to disk"
37 )
37 )
38
38
39 mime_type = Unicode('text/html', config=True,
40 help="MIME type of the result file, for HTTP response headers."
41 )
42
39 default_template = Unicode('full', config=True, help="""Flavor of the data
43 default_template = Unicode('full', config=True, help="""Flavor of the data
40 format to use. I.E. 'full' or 'basic'""")
44 format to use. I.E. 'full' or 'basic'""")
41
45
42 def _raw_mimetype_default(self):
46 def _raw_mimetype_default(self):
43 return 'text/html'
47 return 'text/html'
44
48
45 @property
49 @property
46 def default_config(self):
50 def default_config(self):
47 c = Config({
51 c = Config({
48 'CSSHTMLHeaderPreprocessor':{
52 'CSSHTMLHeaderPreprocessor':{
49 'enabled':True
53 'enabled':True
50 },
54 },
51 'HighlightMagicsPreprocessor': {
55 'HighlightMagicsPreprocessor': {
52 'enabled':True
56 'enabled':True
53 }
57 }
54 })
58 })
55 c.merge(super(HTMLExporter,self).default_config)
59 c.merge(super(HTMLExporter,self).default_config)
56 return c
60 return c
@@ -1,93 +1,97 b''
1 """LaTeX Exporter class"""
1 """LaTeX Exporter class"""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib imports
15 # Stdlib imports
16 import os
16 import os
17
17
18 # IPython imports
18 # IPython imports
19 from IPython.utils.traitlets import Unicode, List
19 from IPython.utils.traitlets import Unicode, List
20 from IPython.config import Config
20 from IPython.config import Config
21
21
22 from IPython.nbconvert import filters, preprocessors
22 from IPython.nbconvert import filters, preprocessors
23 from .templateexporter import TemplateExporter
23 from .templateexporter import TemplateExporter
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Classes and functions
26 # Classes and functions
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 class LatexExporter(TemplateExporter):
29 class LatexExporter(TemplateExporter):
30 """
30 """
31 Exports to a Latex template. Inherit from this class if your template is
31 Exports to a Latex template. Inherit from this class if your template is
32 LaTeX based and you need custom tranformers/filters. Inherit from it if
32 LaTeX based and you need custom tranformers/filters. Inherit from it if
33 you are writing your own HTML template and need custom tranformers/filters.
33 you are writing your own HTML template and need custom tranformers/filters.
34 If you don't need custom tranformers/filters, just change the
34 If you don't need custom tranformers/filters, just change the
35 'template_file' config option. Place your template in the special "/latex"
35 'template_file' config option. Place your template in the special "/latex"
36 subfolder of the "../templates" folder.
36 subfolder of the "../templates" folder.
37 """
37 """
38
38
39 file_extension = Unicode(
39 file_extension = Unicode(
40 'tex', config=True,
40 'tex', config=True,
41 help="Extension of the file that should be written to disk")
41 help="Extension of the file that should be written to disk")
42
42
43 mime_type = Unicode('application/x-tex', config=True,
44 help="MIME type of the result file, for HTTP response headers."
45 )
46
43 default_template = Unicode('article', config=True, help="""Template of the
47 default_template = Unicode('article', config=True, help="""Template of the
44 data format to use. I.E. 'article' or 'report'""")
48 data format to use. I.E. 'article' or 'report'""")
45
49
46 #Latex constants
50 #Latex constants
47 default_template_path = Unicode(
51 default_template_path = Unicode(
48 os.path.join("..", "templates", "latex"), config=True,
52 os.path.join("..", "templates", "latex"), config=True,
49 help="Path where the template files are located.")
53 help="Path where the template files are located.")
50
54
51 template_skeleton_path = Unicode(
55 template_skeleton_path = Unicode(
52 os.path.join("..", "templates", "latex", "skeleton"), config=True,
56 os.path.join("..", "templates", "latex", "skeleton"), config=True,
53 help="Path where the template skeleton files are located.")
57 help="Path where the template skeleton files are located.")
54
58
55 #Special Jinja2 syntax that will not conflict when exporting latex.
59 #Special Jinja2 syntax that will not conflict when exporting latex.
56 jinja_comment_block_start = Unicode("((=", config=True)
60 jinja_comment_block_start = Unicode("((=", config=True)
57 jinja_comment_block_end = Unicode("=))", config=True)
61 jinja_comment_block_end = Unicode("=))", config=True)
58 jinja_variable_block_start = Unicode("(((", config=True)
62 jinja_variable_block_start = Unicode("(((", config=True)
59 jinja_variable_block_end = Unicode(")))", config=True)
63 jinja_variable_block_end = Unicode(")))", config=True)
60 jinja_logic_block_start = Unicode("((*", config=True)
64 jinja_logic_block_start = Unicode("((*", config=True)
61 jinja_logic_block_end = Unicode("*))", config=True)
65 jinja_logic_block_end = Unicode("*))", config=True)
62
66
63 #Extension that the template files use.
67 #Extension that the template files use.
64 template_extension = Unicode(".tplx", config=True)
68 template_extension = Unicode(".tplx", config=True)
65
69
66 def _raw_mimetype_default(self):
70 def _raw_mimetype_default(self):
67 return 'text/latex'
71 return 'text/latex'
68
72
69
73
70 @property
74 @property
71 def default_config(self):
75 def default_config(self):
72 c = Config({
76 c = Config({
73 'NbConvertBase': {
77 'NbConvertBase': {
74 'display_data_priority' : ['latex', 'pdf', 'png', 'jpg', 'svg', 'jpeg', 'text']
78 'display_data_priority' : ['latex', 'pdf', 'png', 'jpg', 'svg', 'jpeg', 'text']
75 },
79 },
76 'ExtractOutputPreprocessor': {
80 'ExtractOutputPreprocessor': {
77 'enabled':True
81 'enabled':True
78 },
82 },
79 'SVG2PDFPreprocessor': {
83 'SVG2PDFPreprocessor': {
80 'enabled':True
84 'enabled':True
81 },
85 },
82 'LatexPreprocessor': {
86 'LatexPreprocessor': {
83 'enabled':True
87 'enabled':True
84 },
88 },
85 'SphinxPreprocessor': {
89 'SphinxPreprocessor': {
86 'enabled':True
90 'enabled':True
87 },
91 },
88 'HighlightMagicsPreprocessor': {
92 'HighlightMagicsPreprocessor': {
89 'enabled':True
93 'enabled':True
90 }
94 }
91 })
95 })
92 c.merge(super(LatexExporter,self).default_config)
96 c.merge(super(LatexExporter,self).default_config)
93 return c
97 return c
@@ -1,43 +1,47 b''
1 """Markdown Exporter class"""
1 """Markdown Exporter class"""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from IPython.config import Config
15 from IPython.config import Config
16 from IPython.utils.traitlets import Unicode
16 from IPython.utils.traitlets import Unicode
17
17
18 from .templateexporter import TemplateExporter
18 from .templateexporter import TemplateExporter
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Classes
21 # Classes
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 class MarkdownExporter(TemplateExporter):
24 class MarkdownExporter(TemplateExporter):
25 """
25 """
26 Exports to a markdown document (.md)
26 Exports to a markdown document (.md)
27 """
27 """
28
28
29 file_extension = Unicode(
29 file_extension = Unicode(
30 'md', config=True,
30 'md', config=True,
31 help="Extension of the file that should be written to disk")
31 help="Extension of the file that should be written to disk")
32
32
33 def _raw_mimetype_default(self):
33 def _raw_mimetype_default(self):
34 return 'text/markdown'
34 return 'text/markdown'
35
35
36 def _raw_mimetypes_default(self):
36 def _raw_mimetypes_default(self):
37 return ['text/markdown', 'text/html']
37 return ['text/markdown', 'text/html']
38
38
39 mime_type = Unicode('text/x-markdown', config=True,
40 help="MIME type of the result file, for HTTP response headers."
41 )
42
39 @property
43 @property
40 def default_config(self):
44 def default_config(self):
41 c = Config({'ExtractOutputPreprocessor':{'enabled':True}})
45 c = Config({'ExtractOutputPreprocessor':{'enabled':True}})
42 c.merge(super(MarkdownExporter,self).default_config)
46 c.merge(super(MarkdownExporter,self).default_config)
43 return c
47 return c
@@ -1,34 +1,37 b''
1 """Python script Exporter class"""
1 """Python script Exporter class"""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from IPython.utils.traitlets import Unicode
15 from IPython.utils.traitlets import Unicode
16
16
17 from .templateexporter import TemplateExporter
17 from .templateexporter import TemplateExporter
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Classes
20 # Classes
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 class PythonExporter(TemplateExporter):
23 class PythonExporter(TemplateExporter):
24 """
24 """
25 Exports a Python code file.
25 Exports a Python code file.
26 """
26 """
27
27
28 file_extension = Unicode(
28 file_extension = Unicode(
29 'py', config=True,
29 'py', config=True,
30 help="Extension of the file that should be written to disk")
30 help="Extension of the file that should be written to disk")
31
31
32 def _raw_mimetype_default(self):
32 def _raw_mimetype_default(self):
33 return 'application/x-python'
33 return 'application/x-python'
34
34
35 mime_type = Unicode('text/x-python', config=True,
36 help="MIME type of the result file, for HTTP response headers."
37 )
@@ -1,40 +1,44 b''
1 """restructuredText Exporter class"""
1 """restructuredText Exporter class"""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from IPython.utils.traitlets import Unicode
15 from IPython.utils.traitlets import Unicode
16 from IPython.config import Config
16 from IPython.config import Config
17
17
18 from .templateexporter import TemplateExporter
18 from .templateexporter import TemplateExporter
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Classes
21 # Classes
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 class RSTExporter(TemplateExporter):
24 class RSTExporter(TemplateExporter):
25 """
25 """
26 Exports restructured text documents.
26 Exports restructured text documents.
27 """
27 """
28
28
29 file_extension = Unicode(
29 file_extension = Unicode(
30 'rst', config=True,
30 'rst', config=True,
31 help="Extension of the file that should be written to disk")
31 help="Extension of the file that should be written to disk")
32
32
33 def _raw_mimetype_default(self):
33 def _raw_mimetype_default(self):
34 return 'text/restructuredtext'
34 return 'text/restructuredtext'
35
35
36 mime_type = Unicode('text/x-rst', config=True,
37 help="MIME type of the result file, for HTTP response headers."
38 )
39
36 @property
40 @property
37 def default_config(self):
41 def default_config(self):
38 c = Config({'ExtractOutputPreprocessor':{'enabled':True}})
42 c = Config({'ExtractOutputPreprocessor':{'enabled':True}})
39 c.merge(super(RSTExporter,self).default_config)
43 c.merge(super(RSTExporter,self).default_config)
40 return c
44 return c
@@ -1,45 +1,49 b''
1 """HTML slide show Exporter class"""
1 """HTML slide show Exporter class"""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from IPython.utils.traitlets import Unicode
15 from IPython.utils.traitlets import Unicode
16
16
17 from IPython.nbconvert import preprocessors
17 from IPython.nbconvert import preprocessors
18 from IPython.config import Config
18 from IPython.config import Config
19
19
20 from .html import HTMLExporter
20 from .html import HTMLExporter
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Classes
23 # Classes
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 class SlidesExporter(HTMLExporter):
26 class SlidesExporter(HTMLExporter):
27 """Exports HTML slides with reveal.js"""
27 """Exports HTML slides with reveal.js"""
28
28
29 file_extension = Unicode(
29 file_extension = Unicode(
30 'slides.html', config=True,
30 'slides.html', config=True,
31 help="Extension of the file that should be written to disk"
31 help="Extension of the file that should be written to disk"
32 )
32 )
33
33
34 mime_type = Unicode('text/html', config=True,
35 help="MIME type of the result file, for HTTP response headers."
36 )
37
34 default_template = Unicode('reveal', config=True, help="""Template of the
38 default_template = Unicode('reveal', config=True, help="""Template of the
35 data format to use. I.E. 'reveal'""")
39 data format to use. I.E. 'reveal'""")
36
40
37 @property
41 @property
38 def default_config(self):
42 def default_config(self):
39 c = Config({
43 c = Config({
40 'RevealHelpPreprocessor': {
44 'RevealHelpPreprocessor': {
41 'enabled': True,
45 'enabled': True,
42 },
46 },
43 })
47 })
44 c.merge(super(SlidesExporter,self).default_config)
48 c.merge(super(SlidesExporter,self).default_config)
45 return c
49 return c
General Comments 0
You need to be logged in to leave comments. Login now