##// END OF EJS Templates
Merge pull request #6978 from takluyver/nbconvert-script...
Min RK -
r19053:38e12544 merge
parent child Browse files
Show More
@@ -0,0 +1,14 b''
1 """Generic script exporter class for any kernel language"""
2
3 from .templateexporter import TemplateExporter
4
5 class ScriptExporter(TemplateExporter):
6 def _template_file_default(self):
7 return 'script'
8
9 def from_notebook_node(self, nb, resources=None, **kw):
10 langinfo = nb.metadata.get('language_info', {})
11 self.file_extension = langinfo.get('file_extension', '.txt')
12 self.output_mimetype = langinfo.get('mimetype', 'text/plain')
13
14 return super(ScriptExporter, self).from_notebook_node(nb, resources, **kw)
@@ -0,0 +1,5 b''
1 {%- extends 'null.tpl' -%}
2
3 {% block input %}
4 {{ cell.source }}
5 {% endblock input %}
@@ -43,7 +43,7 b' def respond_zip(handler, name, output, resources):'
43 # Prepare the zip file
43 # Prepare the zip file
44 buffer = io.BytesIO()
44 buffer = io.BytesIO()
45 zipf = zipfile.ZipFile(buffer, mode='w', compression=zipfile.ZIP_DEFLATED)
45 zipf = zipfile.ZipFile(buffer, mode='w', compression=zipfile.ZIP_DEFLATED)
46 output_filename = os.path.splitext(name)[0] + '.' + resources['output_extension']
46 output_filename = os.path.splitext(name)[0] + resources['output_extension']
47 zipf.writestr(output_filename, cast_bytes(output, 'utf-8'))
47 zipf.writestr(output_filename, cast_bytes(output, 'utf-8'))
48 for filename, data in output_files.items():
48 for filename, data in output_files.items():
49 zipf.writestr(os.path.basename(filename), data)
49 zipf.writestr(os.path.basename(filename), data)
@@ -96,7 +96,7 b' class NbconvertFileHandler(IPythonHandler):'
96
96
97 # Force download if requested
97 # Force download if requested
98 if self.get_argument('download', 'false').lower() == 'true':
98 if self.get_argument('download', 'false').lower() == 'true':
99 filename = os.path.splitext(name)[0] + '.' + resources['output_extension']
99 filename = os.path.splitext(name)[0] + resources['output_extension']
100 self.set_header('Content-Disposition',
100 self.set_header('Content-Disposition',
101 'attachment; filename="%s"' % filename)
101 'attachment; filename="%s"' % filename)
102
102
@@ -69,17 +69,21 b' define(['
69 MenuBar.prototype._nbconvert = function (format, download) {
69 MenuBar.prototype._nbconvert = function (format, download) {
70 download = download || false;
70 download = download || false;
71 var notebook_path = this.notebook.notebook_path;
71 var notebook_path = this.notebook.notebook_path;
72 if (this.notebook.dirty) {
73 this.notebook.save_notebook({async : false});
74 }
75 var url = utils.url_join_encode(
72 var url = utils.url_join_encode(
76 this.base_url,
73 this.base_url,
77 'nbconvert',
74 'nbconvert',
78 format,
75 format,
79 notebook_path
76 notebook_path
80 ) + "?download=" + download.toString();
77 ) + "?download=" + download.toString();
81
78
82 window.open(url);
79 var w = window.open()
80 if (this.notebook.dirty) {
81 this.notebook.save_notebook().then(function() {
82 w.location = url;
83 });
84 } else {
85 w.location = url;
86 }
83 };
87 };
84
88
85 MenuBar.prototype.bind_events = function () {
89 MenuBar.prototype.bind_events = function () {
@@ -129,10 +133,6 b' define(['
129 that._nbconvert('html', false);
133 that._nbconvert('html', false);
130 });
134 });
131
135
132 this.element.find('#download_py').click(function () {
133 that._nbconvert('python', true);
134 });
135
136 this.element.find('#download_html').click(function () {
136 this.element.find('#download_html').click(function () {
137 that._nbconvert('html', true);
137 that._nbconvert('html', true);
138 });
138 });
@@ -308,6 +308,16 b' define(['
308 this.events.on('checkpoint_created.Notebook', function (event, data) {
308 this.events.on('checkpoint_created.Notebook', function (event, data) {
309 that.update_restore_checkpoint(that.notebook.checkpoints);
309 that.update_restore_checkpoint(that.notebook.checkpoints);
310 });
310 });
311
312 this.events.on('notebook_loaded.Notebook', function() {
313 var langinfo = that.notebook.metadata.language_info || {};
314 that.update_nbconvert_script(langinfo);
315 });
316
317 this.events.on('kernel_ready.Kernel', function(event, data) {
318 var langinfo = data.kernel.info_reply.language_info || {};
319 that.update_nbconvert_script(langinfo);
320 });
311 };
321 };
312
322
313 MenuBar.prototype.update_restore_checkpoint = function(checkpoints) {
323 MenuBar.prototype.update_restore_checkpoint = function(checkpoints) {
@@ -340,6 +350,31 b' define(['
340 );
350 );
341 });
351 });
342 };
352 };
353
354 MenuBar.prototype.update_nbconvert_script = function(langinfo) {
355 // Set the 'Download as foo' menu option for the relevant language.
356 var el = this.element.find('#download_script');
357 var that = this;
358
359 // Set menu entry text to e.g. "Python (.py)"
360 var langname = (langinfo.name || 'Script')
361 langname = langname.charAt(0).toUpperCase()+langname.substr(1) // Capitalise
362 el.find('a').text(langname + ' ('+(langinfo.file_extension || 'txt')+')');
363
364 // Unregister any previously registered handlers
365 el.off('click');
366 if (langinfo.nbconvert_exporter) {
367 // Metadata specifies a specific exporter, e.g. 'python'
368 el.click(function() {
369 that._nbconvert(langinfo.nbconvert_exporter, true);
370 });
371 } else {
372 // Use generic 'script' exporter
373 el.click(function() {
374 that._nbconvert('script', true);
375 });
376 }
377 };
343
378
344 // Backwards compatability.
379 // Backwards compatability.
345 IPython.MenuBar = MenuBar;
380 IPython.MenuBar = MenuBar;
@@ -1944,7 +1944,7 b' define(['
1944 var start = new Date().getTime();
1944 var start = new Date().getTime();
1945
1945
1946 var that = this;
1946 var that = this;
1947 this.contents.save(this.notebook_path, model).then(
1947 return this.contents.save(this.notebook_path, model).then(
1948 $.proxy(this.save_notebook_success, this, start),
1948 $.proxy(this.save_notebook_success, this, start),
1949 function (error) {
1949 function (error) {
1950 that.events.trigger('notebook_save_failed.Notebook', error);
1950 that.events.trigger('notebook_save_failed.Notebook', error);
@@ -105,7 +105,7 b' class="notebook_app"'
105 <li class="dropdown-submenu"><a href="#">Download as</a>
105 <li class="dropdown-submenu"><a href="#">Download as</a>
106 <ul class="dropdown-menu">
106 <ul class="dropdown-menu">
107 <li id="download_ipynb"><a href="#">IPython Notebook (.ipynb)</a></li>
107 <li id="download_ipynb"><a href="#">IPython Notebook (.ipynb)</a></li>
108 <li id="download_py"><a href="#">Python (.py)</a></li>
108 <li id="download_script"><a href="#">Script</a></li>
109 <li id="download_html"><a href="#">HTML (.html)</a></li>
109 <li id="download_html"><a href="#">HTML (.html)</a></li>
110 <li id="download_rst"><a href="#">reST (.rst)</a></li>
110 <li id="download_rst"><a href="#">reST (.rst)</a></li>
111 <li id="download_pdf"><a href="#">PDF (.pdf)</a></li>
111 <li id="download_pdf"><a href="#">PDF (.pdf)</a></li>
@@ -75,6 +75,8 b' class IPythonKernel(KernelBase):'
75 'codemirror_mode': {'name': 'ipython',
75 'codemirror_mode': {'name': 'ipython',
76 'version': sys.version_info[0]},
76 'version': sys.version_info[0]},
77 'pygments_lexer': 'ipython%d' % (3 if PY3 else 2),
77 'pygments_lexer': 'ipython%d' % (3 if PY3 else 2),
78 'nbconvert_exporter': 'python',
79 'file_extension': '.py'
78 }
80 }
79 @property
81 @property
80 def banner(self):
82 def banner(self):
@@ -19,6 +19,7 b' from .markdown import MarkdownExporter'
19 from .python import PythonExporter
19 from .python import PythonExporter
20 from .rst import RSTExporter
20 from .rst import RSTExporter
21 from .notebook import NotebookExporter
21 from .notebook import NotebookExporter
22 from .script import ScriptExporter
22
23
23 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
24 # Classes
25 # Classes
@@ -74,6 +75,7 b' __all__ = ['
74 'export_pdf',
75 'export_pdf',
75 'export_markdown',
76 'export_markdown',
76 'export_python',
77 'export_python',
78 'export_script',
77 'export_rst',
79 'export_rst',
78 'export_by_name',
80 'export_by_name',
79 'get_export_names',
81 'get_export_names',
@@ -132,6 +134,7 b' exporter_map = dict('
132 python=PythonExporter,
134 python=PythonExporter,
133 rst=RSTExporter,
135 rst=RSTExporter,
134 notebook=NotebookExporter,
136 notebook=NotebookExporter,
137 script=ScriptExporter,
135 )
138 )
136
139
137 def _make_exporter(name, E):
140 def _make_exporter(name, E):
@@ -32,7 +32,7 b' class Exporter(LoggingConfigurable):'
32 """
32 """
33
33
34 file_extension = Unicode(
34 file_extension = Unicode(
35 'txt', config=True,
35 '.txt', 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
@@ -32,7 +32,7 b' class HTMLExporter(TemplateExporter):'
32 """
32 """
33
33
34 def _file_extension_default(self):
34 def _file_extension_default(self):
35 return 'html'
35 return '.html'
36
36
37 def _default_template_path_default(self):
37 def _default_template_path_default(self):
38 return os.path.join("..", "templates", "html")
38 return os.path.join("..", "templates", "html")
@@ -37,7 +37,7 b' class LatexExporter(TemplateExporter):'
37 """
37 """
38
38
39 def _file_extension_default(self):
39 def _file_extension_default(self):
40 return 'tex'
40 return '.tex'
41
41
42 def _template_file_default(self):
42 def _template_file_default(self):
43 return 'article'
43 return 'article'
@@ -135,7 +135,7 b' class PDFExporter(LatexExporter):'
135
135
136 # convert output extension to pdf
136 # convert output extension to pdf
137 # the writer above required it to be tex
137 # the writer above required it to be tex
138 resources['output_extension'] = 'pdf'
138 resources['output_extension'] = '.pdf'
139
139
140 return pdf_data, resources
140 return pdf_data, resources
141
141
@@ -23,7 +23,7 b' class PythonExporter(TemplateExporter):'
23 Exports a Python code file.
23 Exports a Python code file.
24 """
24 """
25 def _file_extension_default(self):
25 def _file_extension_default(self):
26 return 'py'
26 return '.py'
27
27
28 def _template_file_default(self):
28 def _template_file_default(self):
29 return 'python'
29 return 'python'
@@ -26,7 +26,7 b' class RSTExporter(TemplateExporter):'
26 """
26 """
27
27
28 def _file_extension_default(self):
28 def _file_extension_default(self):
29 return 'rst'
29 return '.rst'
30
30
31 def _template_file_default(self):
31 def _template_file_default(self):
32 return 'rst'
32 return 'rst'
@@ -25,7 +25,7 b' class SlidesExporter(HTMLExporter):'
25 """Exports HTML slides with reveal.js"""
25 """Exports HTML slides with reveal.js"""
26
26
27 def _file_extension_default(self):
27 def _file_extension_default(self):
28 return 'slides.html'
28 return '.slides.html'
29
29
30 def _template_file_default(self):
30 def _template_file_default(self):
31 return 'slides_reveal'
31 return 'slides_reveal'
@@ -286,7 +286,7 b' class NbConvertApp(BaseIPythonApplication):'
286 # strip duplicate extension from output_base, to avoid Basname.ext.ext
286 # strip duplicate extension from output_base, to avoid Basname.ext.ext
287 if getattr(exporter, 'file_extension', False):
287 if getattr(exporter, 'file_extension', False):
288 base, ext = os.path.splitext(self.output_base)
288 base, ext = os.path.splitext(self.output_base)
289 if ext == '.' + exporter.file_extension:
289 if ext == exporter.file_extension:
290 self.output_base = base
290 self.output_base = base
291 notebook_name = self.output_base
291 notebook_name = self.output_base
292 resources = {}
292 resources = {}
@@ -93,7 +93,7 b' class FilesWriter(WriterBase):'
93
93
94 # Determine where to write conversion results.
94 # Determine where to write conversion results.
95 if output_extension is not None:
95 if output_extension is not None:
96 dest = notebook_name + '.' + output_extension
96 dest = notebook_name + output_extension
97 else:
97 else:
98 dest = notebook_name
98 dest = notebook_name
99 if self.build_directory:
99 if self.build_directory:
@@ -59,7 +59,7 b' class Testfiles(TestsBase):'
59 with self.create_temp_cwd():
59 with self.create_temp_cwd():
60
60
61 # Create the resoruces dictionary
61 # Create the resoruces dictionary
62 res = {'output_extension': 'txt'}
62 res = {'output_extension': '.txt'}
63
63
64 # Create files writer, test output
64 # Create files writer, test output
65 writer = FilesWriter()
65 writer = FilesWriter()
@@ -735,6 +735,9 b' Message type: ``kernel_info_reply``::'
735 'language_info': {
735 'language_info': {
736 'mimetype': str,
736 'mimetype': str,
737
737
738 # Extension without the dot, e.g. 'py'
739 'file_extension': str,
740
738 # Pygments lexer, for highlighting
741 # Pygments lexer, for highlighting
739 # Only needed if it differs from the top level 'language' field.
742 # Only needed if it differs from the top level 'language' field.
740 'pygments_lexer': str,
743 'pygments_lexer': str,
@@ -742,6 +745,11 b' Message type: ``kernel_info_reply``::'
742 # Codemirror mode, for for highlighting in the notebook.
745 # Codemirror mode, for for highlighting in the notebook.
743 # Only needed if it differs from the top level 'language' field.
746 # Only needed if it differs from the top level 'language' field.
744 'codemirror_mode': str or dict,
747 'codemirror_mode': str or dict,
748
749 # Nbconvert exporter, if notebooks written with this kernel should
750 # be exported with something other than the general 'script'
751 # exporter.
752 'nbconvert_exporter': str,
745 },
753 },
746
754
747 # A banner of information about the kernel,
755 # A banner of information about the kernel,
@@ -38,9 +38,10 b' following methods and attributes:'
38
38
39 Language information for :ref:`msging_kernel_info` replies, in a dictionary.
39 Language information for :ref:`msging_kernel_info` replies, in a dictionary.
40 This should contain the key ``mimetype`` with the mimetype of code in the
40 This should contain the key ``mimetype`` with the mimetype of code in the
41 target language (e.g. ``'text/x-python'``). It may also contain keys
41 target language (e.g. ``'text/x-python'``), and ``file_extension`` (e.g.
42 ``codemirror_mode`` and ``pygments_lexer`` if they need to differ from
42 ``'py'``).
43 :attr:`language`.
43 It may also contain keys ``codemirror_mode`` and ``pygments_lexer`` if they
44 need to differ from :attr:`language`.
44
45
45 Other keys may be added to this later.
46 Other keys may be added to this later.
46
47
General Comments 0
You need to be logged in to leave comments. Login now