##// END OF EJS Templates
fix some relative path issues
Matthias BUSSONNIER -
Show More
@@ -1,74 +1,74 b''
1 #-----------------------------------------------------------------------------
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2012, the IPython Development Team.
2 # Copyright (c) 2012, the IPython Development Team.
3 #
3 #
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5 #
5 #
6 # The full license is in the file COPYING.txt, distributed with this software.
6 # The full license is in the file COPYING.txt, distributed with this software.
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 # Stdlib imports
11 # Stdlib imports
12 import re
12 import re
13
13
14 from IPython.utils.text import indent
14 from IPython.utils.text import indent
15 from markdown import markdown
15 from markdown import markdown
16 from .utils import remove_ansi
16 from .utils import remove_ansi
17 from .utils import highlight, ansi2html
17 from .utils import highlight, ansi2html
18 from .utils import markdown2latex
18 from .utils import markdown2latex
19 from .utils import highlight2latex
19 from .utils import highlight2latex
20 from .utils import get_lines
20 from .utils import get_lines
21
21
22 from converters.config import GlobalConfigurable
22 from .config import GlobalConfigurable
23
23
24 from IPython.config.configurable import Configurable
24 from IPython.config.configurable import Configurable
25 from IPython.utils.traitlets import List
25 from IPython.utils.traitlets import List
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Class declarations
28 # Class declarations
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 class ConfigurableFilter(GlobalConfigurable):
31 class ConfigurableFilter(GlobalConfigurable):
32 """Configurable Jinja Filter"""
32 """Configurable Jinja Filter"""
33
33
34 def __init__(self, config=None, **kw):
34 def __init__(self, config=None, **kw):
35 super(ConfigurableFilter, self).__init__(config=config, **kw)
35 super(ConfigurableFilter, self).__init__(config=config, **kw)
36
36
37 def __call__(self, *args, **kwargs):
37 def __call__(self, *args, **kwargs):
38 raise NotImplementedError('should be implemented by subclass')
38 raise NotImplementedError('should be implemented by subclass')
39
39
40
40
41 class FilterDataType(ConfigurableFilter):
41 class FilterDataType(ConfigurableFilter):
42 """ return the preferd displayed format
42 """ return the preferd displayed format
43 """
43 """
44
44
45 def __call__(self, output):
45 def __call__(self, output):
46 """ return the first availlable format in priority """
46 """ return the first availlable format in priority """
47 for fmt in self.display_data_priority:
47 for fmt in self.display_data_priority:
48 if fmt in output:
48 if fmt in output:
49 return [fmt]
49 return [fmt]
50 raise Exception("did not found any format I can extract in output, shoudl at lest have one")
50 raise Exception("did not found any format I can extract in output, shoudl at lest have one")
51
51
52
52
53
53
54 def rm_fake(strng):
54 def rm_fake(strng):
55 return strng.replace('/files/', '')
55 return strng.replace('/files/', '')
56
56
57 def python_comment(string):
57 def python_comment(string):
58 return '# '+'\n# '.join(string.split('\n'))
58 return '# '+'\n# '.join(string.split('\n'))
59
59
60 LATEX_SUBS = (
60 LATEX_SUBS = (
61 (re.compile(r'\\'), r'\\textbackslash'),
61 (re.compile(r'\\'), r'\\textbackslash'),
62 (re.compile(r'([{}_#%&$])'), r'\\\1'),
62 (re.compile(r'([{}_#%&$])'), r'\\\1'),
63 (re.compile(r'~'), r'\~{}'),
63 (re.compile(r'~'), r'\~{}'),
64 (re.compile(r'\^'), r'\^{}'),
64 (re.compile(r'\^'), r'\^{}'),
65 (re.compile(r'"'), r"''"),
65 (re.compile(r'"'), r"''"),
66 (re.compile(r'\.\.\.+'), r'\\ldots'),
66 (re.compile(r'\.\.\.+'), r'\\ldots'),
67 )
67 )
68
68
69 def escape_tex(value):
69 def escape_tex(value):
70 newval = value
70 newval = value
71 for pattern, replacement in LATEX_SUBS:
71 for pattern, replacement in LATEX_SUBS:
72 newval = pattern.sub(replacement, newval)
72 newval = pattern.sub(replacement, newval)
73 return newval
73 return newval
74
74
@@ -1,127 +1,128 b''
1 """
1 """
2 Module that allows latex output notebooks to be conditioned before
2 Module that allows latex output notebooks to be conditioned before
3 they are converted.
3 they are converted.
4 """
4 """
5 from __future__ import absolute_import
5
6
6 # Configurable traitlets
7 # Configurable traitlets
7 from IPython.utils.traitlets import Unicode, Bool
8 from IPython.utils.traitlets import Unicode, Bool
8
9
9 # Needed to override transformer
10 # Needed to override transformer
10 from converters.transformers import (ActivatableTransformer)
11 from .transformers import (ActivatableTransformer)
11
12
12 class LatexTransformer(ActivatableTransformer):
13 class LatexTransformer(ActivatableTransformer):
13 """
14 """
14 Converter for latex destined documents.
15 Converter for latex destined documents.
15 """
16 """
16
17
17 def cell_transform(self, cell, other, index):
18 def cell_transform(self, cell, other, index):
18 """
19 """
19 Apply a transformation on each cell,
20 Apply a transformation on each cell,
20
21
21 receive the current cell, the resource dict and the index of current cell as parameter.
22 receive the current cell, the resource dict and the index of current cell as parameter.
22
23
23 Returns modified cell and resource dict.
24 Returns modified cell and resource dict.
24 """
25 """
25 if hasattr(cell, "source") and cell.cell_type == "markdown":
26 if hasattr(cell, "source") and cell.cell_type == "markdown":
26 cell.source = self.remove_math_space(cell.source)
27 cell.source = self.remove_math_space(cell.source)
27 return cell, other
28 return cell, other
28
29
29 def remove_math_space(self, text):
30 def remove_math_space(self, text):
30 """
31 """
31 Remove the space between latex math commands and enclosing $ symbols.
32 Remove the space between latex math commands and enclosing $ symbols.
32 """
33 """
33
34
34 # First, scan through the markdown looking for $. If
35 # First, scan through the markdown looking for $. If
35 # a $ symbol is found, without a preceding \, assume
36 # a $ symbol is found, without a preceding \, assume
36 # it is the start of a math block. UNLESS that $ is
37 # it is the start of a math block. UNLESS that $ is
37 # not followed by another within two math_lines.
38 # not followed by another within two math_lines.
38 math_regions = []
39 math_regions = []
39 math_lines = 0
40 math_lines = 0
40 within_math = False
41 within_math = False
41 math_start_index = 0
42 math_start_index = 0
42 index = 0
43 index = 0
43 last_character = ""
44 last_character = ""
44 for char in text: #Loop through each character in the text.
45 for char in text: #Loop through each character in the text.
45
46
46 #Make sure the character isn't preceeded by a backslash
47 #Make sure the character isn't preceeded by a backslash
47 if (char == "$" and last_character != "\\"):
48 if (char == "$" and last_character != "\\"):
48
49
49 # Close the math region if this is an ending $
50 # Close the math region if this is an ending $
50 if within_math:
51 if within_math:
51 within_math = False
52 within_math = False
52 math_regions.append([math_start_index, index+1])
53 math_regions.append([math_start_index, index+1])
53 else:
54 else:
54
55
55 # Start a new math region
56 # Start a new math region
56 within_math = True
57 within_math = True
57 math_start_index = index
58 math_start_index = index
58 math_lines = 0
59 math_lines = 0
59
60
60 # If we are in a math region, count the number of lines parsed.
61 # If we are in a math region, count the number of lines parsed.
61 # Cancel the math region if we find two line breaks!
62 # Cancel the math region if we find two line breaks!
62 elif char == "\n":
63 elif char == "\n":
63 if within_math:
64 if within_math:
64 math_lines += 1
65 math_lines += 1
65 if math_lines > 1:
66 if math_lines > 1:
66 within_math = False
67 within_math = False
67
68
68 # Remember the last character so we can easily watch
69 # Remember the last character so we can easily watch
69 # for backslashes
70 # for backslashes
70 last_character = char
71 last_character = char
71
72
72 # Next index
73 # Next index
73 index += 1
74 index += 1
74
75
75 # Reset the index and last char
76 # Reset the index and last char
76 index = 0
77 index = 0
77
78
78 # Now that we know what regions of the text are math and
79 # Now that we know what regions of the text are math and
79 # what regions aren't, we can separate them into "blocks"
80 # what regions aren't, we can separate them into "blocks"
80 text_blocks=[]
81 text_blocks=[]
81 math_blocks=[]
82 math_blocks=[]
82 was_math_block = False
83 was_math_block = False
83 current_block = ""
84 current_block = ""
84 for char in text:
85 for char in text:
85
86
86 # Check if this is a math region.
87 # Check if this is a math region.
87 ismath = False
88 ismath = False
88 for keypair in math_regions:
89 for keypair in math_regions:
89 if (keypair[0] <= index and index <= keypair[1]):
90 if (keypair[0] <= index and index <= keypair[1]):
90 ismath = True
91 ismath = True
91
92
92 # If the region type has changed since the last
93 # If the region type has changed since the last
93 # iteration, commit all read characters to that
94 # iteration, commit all read characters to that
94 # region type and reset the buffer.
95 # region type and reset the buffer.
95 if (ismath and not was_math_block):
96 if (ismath and not was_math_block):
96 was_math_block = True
97 was_math_block = True
97 text_blocks.append(current_block)
98 text_blocks.append(current_block)
98 current_block=""
99 current_block=""
99 elif ((not ismath) and was_math_block):
100 elif ((not ismath) and was_math_block):
100 was_math_block = False
101 was_math_block = False
101 math_blocks.append(current_block)
102 math_blocks.append(current_block)
102 current_block=""
103 current_block=""
103
104
104 # Store the character
105 # Store the character
105 current_block += char
106 current_block += char
106
107
107 # Next index
108 # Next index
108 index += 1
109 index += 1
109
110
110 # Save whatever remains in the buffer that hasn't yet been saved.
111 # Save whatever remains in the buffer that hasn't yet been saved.
111 if was_math_block:
112 if was_math_block:
112 math_blocks.append(current_block)
113 math_blocks.append(current_block)
113 else:
114 else:
114 text_blocks.append(current_block)
115 text_blocks.append(current_block)
115
116
116 # Recombine the regions, while processing every math region, removing
117 # Recombine the regions, while processing every math region, removing
117 # the spaces between the math and the $ symbols.
118 # the spaces between the math and the $ symbols.
118 output = ""
119 output = ""
119 for index in range(0,len(text_blocks) + len(math_blocks)):
120 for index in range(0,len(text_blocks) + len(math_blocks)):
120 if index % 2 == 0:
121 if index % 2 == 0:
121 output += text_blocks[index/2]
122 output += text_blocks[index/2]
122 else:
123 else:
123 mathblock = math_blocks[(index -1)/2]
124 mathblock = math_blocks[(index -1)/2]
124 mathblock = mathblock[1:len(mathblock)-2]
125 mathblock = mathblock[1:len(mathblock)-2]
125 output += "$" + mathblock.strip() + "$"
126 output += "$" + mathblock.strip() + "$"
126 return output
127 return output
127
128
@@ -1,199 +1,200 b''
1 """
1 """
2 Module that allows custom Sphinx parameters to be set on the notebook and
2 Module that allows custom Sphinx parameters to be set on the notebook and
3 on the 'other' object passed into Jinja.
3 on the 'other' object passed into Jinja.
4 """
4 """
5 from __future__ import absolute_import
5
6
6 # Used to find Sphinx package location
7 # Used to find Sphinx package location
7 import sphinx
8 import sphinx
8 import os.path
9 import os.path
9
10
10 # Used to determine python version
11 # Used to determine python version
11 import sys
12 import sys
12
13
13 # Used to set the default date to today's date
14 # Used to set the default date to today's date
14 from datetime import date
15 from datetime import date
15
16
16 # Configurable traitlets
17 # Configurable traitlets
17 from IPython.utils.traitlets import Unicode, Bool
18 from IPython.utils.traitlets import Unicode, Bool
18
19
19 # Needed for Pygments latex definitions.
20 # Needed for Pygments latex definitions.
20 from pygments.formatters import LatexFormatter
21 from pygments.formatters import LatexFormatter
21
22
22 # Needed to override transformer
23 # Needed to override transformer
23 from converters.transformers import (ActivatableTransformer)
24 from .transformers import (ActivatableTransformer)
24
25
25 class SphinxTransformer(ActivatableTransformer):
26 class SphinxTransformer(ActivatableTransformer):
26 """
27 """
27 Sphinx utility transformer.
28 Sphinx utility transformer.
28
29
29 This transformer is used to set variables needed by the latex to build
30 This transformer is used to set variables needed by the latex to build
30 Sphinx stylized templates.
31 Sphinx stylized templates.
31 """
32 """
32
33
33 interactive = Bool(True, config=True, help="""
34 interactive = Bool(True, config=True, help="""
34 Allows you to define whether or not the Sphinx exporter will prompt
35 Allows you to define whether or not the Sphinx exporter will prompt
35 you for input during the conversion process. If this is set to false,
36 you for input during the conversion process. If this is set to false,
36 the author, version, release, date, and chapterstyle traits should
37 the author, version, release, date, and chapterstyle traits should
37 be set.
38 be set.
38 """)
39 """)
39
40
40 author = Unicode("Unknown Author", config=True, help="Author name")
41 author = Unicode("Unknown Author", config=True, help="Author name")
41
42
42 version = Unicode("", config=True, help="""Version number
43 version = Unicode("", config=True, help="""Version number
43 You can leave this blank if you do not want to render a version number.
44 You can leave this blank if you do not want to render a version number.
44 Example: "1.0.0"
45 Example: "1.0.0"
45 """)
46 """)
46
47
47 release = Unicode("", config=True, help="""Release name
48 release = Unicode("", config=True, help="""Release name
48 You can leave this blank if you do not want to render a release name.
49 You can leave this blank if you do not want to render a release name.
49 Example: "Rough Draft"
50 Example: "Rough Draft"
50 """)
51 """)
51
52
52 publishdate = Unicode("", config=True, help="""Publish date
53 publishdate = Unicode("", config=True, help="""Publish date
53 This is the date to render on the document as the publish date.
54 This is the date to render on the document as the publish date.
54 Leave this blank to default to todays date.
55 Leave this blank to default to todays date.
55 Example: "June 12, 1990"
56 Example: "June 12, 1990"
56 """)
57 """)
57
58
58 chapterstyle = Unicode("Bjarne", config=True, help="""Sphinx chapter style
59 chapterstyle = Unicode("Bjarne", config=True, help="""Sphinx chapter style
59 This is the style to use for the chapter headers in the document.
60 This is the style to use for the chapter headers in the document.
60 You may choose one of the following:
61 You may choose one of the following:
61 "Bjarne" (default)
62 "Bjarne" (default)
62 "Lenny"
63 "Lenny"
63 "Glenn"
64 "Glenn"
64 "Conny"
65 "Conny"
65 "Rejne"
66 "Rejne"
66 "Sonny" (used for international documents)
67 "Sonny" (used for international documents)
67 """)
68 """)
68
69
69
70
70 def __call__(self, nb, other):
71 def __call__(self, nb, other):
71 """
72 """
72 Entry
73 Entry
73 Since we are not interested in any additional manipulation on a cell
74 Since we are not interested in any additional manipulation on a cell
74 by cell basis, we do not call the base implementation.
75 by cell basis, we do not call the base implementation.
75 """
76 """
76 if self.enabled:
77 if self.enabled:
77 return self.transform(nb, other)
78 return self.transform(nb, other)
78 else:
79 else:
79 return nb,other
80 return nb,other
80
81
81 def transform(self, nb, other):
82 def transform(self, nb, other):
82 """
83 """
83 Sphinx transformation to apply on each notebook.
84 Sphinx transformation to apply on each notebook.
84 """
85 """
85
86
86 if self.interactive:
87 if self.interactive:
87
88
88 # Prompt the user for additional meta data that doesn't exist currently
89 # Prompt the user for additional meta data that doesn't exist currently
89 # but would be usefull for Sphinx.
90 # but would be usefull for Sphinx.
90 nb.metadata["author"] = self._prompt_author()
91 nb.metadata["author"] = self._prompt_author()
91 nb.metadata["version"] = self._prompt_version()
92 nb.metadata["version"] = self._prompt_version()
92 nb.metadata["release"] = self._prompt_release()
93 nb.metadata["release"] = self._prompt_release()
93 nb.metadata["date"] = self._prompt_date()
94 nb.metadata["date"] = self._prompt_date()
94
95
95 # Prompt the user for the document style.
96 # Prompt the user for the document style.
96 other["sphinx_chapterstyle"] = self._prompt_chapter_title_style()
97 other["sphinx_chapterstyle"] = self._prompt_chapter_title_style()
97 else:
98 else:
98
99
99 # Try to use the traitlets.
100 # Try to use the traitlets.
100 nb.metadata["author"] = self.author
101 nb.metadata["author"] = self.author
101 nb.metadata["version"] = self.version
102 nb.metadata["version"] = self.version
102 nb.metadata["release"] = self.release
103 nb.metadata["release"] = self.release
103
104
104 if len(self.publishdate.strip()) == 0:
105 if len(self.publishdate.strip()) == 0:
105 nb.metadata["date"] = date.today().strftime("%B %-d, %Y")
106 nb.metadata["date"] = date.today().strftime("%B %-d, %Y")
106 else:
107 else:
107 nb.metadata["date"] = self.publishdate
108 nb.metadata["date"] = self.publishdate
108
109
109 other["sphinx_chapterstyle"] = self.chapterstyle
110 other["sphinx_chapterstyle"] = self.chapterstyle
110
111
111 # Find and pass in the path to the Sphinx dependencies.
112 # Find and pass in the path to the Sphinx dependencies.
112 other["sphinx_texinputs"] = os.path.abspath(sphinx.__file__ + "/../texinputs")
113 other["sphinx_texinputs"] = os.path.abspath(sphinx.__file__ + "/../texinputs")
113
114
114 # Generate Pygments definitions for Latex
115 # Generate Pygments definitions for Latex
115 other["pygment_definitions"] = self._generate_pygments_latex_def()
116 other["pygment_definitions"] = self._generate_pygments_latex_def()
116
117
117 # End
118 # End
118 return nb, other
119 return nb, other
119
120
120 def _generate_pygments_latex_def(self):
121 def _generate_pygments_latex_def(self):
121 return LatexFormatter().get_style_defs()
122 return LatexFormatter().get_style_defs()
122
123
123 def _prompt_author(self):
124 def _prompt_author(self):
124 return self._input("Author name: ")
125 return self._input("Author name: ")
125
126
126 def _prompt_version(self):
127 def _prompt_version(self):
127 return self._input("Version (ie ""1.0.0""): ")
128 return self._input("Version (ie ""1.0.0""): ")
128
129
129 def _prompt_release(self):
130 def _prompt_release(self):
130 return self._input("Release Name (ie ""Rough draft""): ")
131 return self._input("Release Name (ie ""Rough draft""): ")
131
132
132 def _prompt_date(self):
133 def _prompt_date(self):
133 default_date = date.today().strftime("%B %-d, %Y")
134 default_date = date.today().strftime("%B %-d, %Y")
134 user_date = self._input("Date (deafults to \"" + default_date + "\"): ")
135 user_date = self._input("Date (deafults to \"" + default_date + "\"): ")
135 if len(user_date.strip()) == 0:
136 if len(user_date.strip()) == 0:
136 user_date = default_date
137 user_date = default_date
137 return user_date
138 return user_date
138
139
139 def _prompt_chapter_title_style(self):
140 def _prompt_chapter_title_style(self):
140
141
141 # Dictionary of available Sphinx styles
142 # Dictionary of available Sphinx styles
142 styles = {1: "Bjarne",
143 styles = {1: "Bjarne",
143 2: "Lenny",
144 2: "Lenny",
144 3: "Glenn",
145 3: "Glenn",
145 4: "Conny",
146 4: "Conny",
146 5: "Rejne",
147 5: "Rejne",
147 6: "Sonny"}
148 6: "Sonny"}
148 default_style = 1
149 default_style = 1
149
150
150 # Build the menu that will be displayed to the user with
151 # Build the menu that will be displayed to the user with
151 # all of the options available.
152 # all of the options available.
152 style_prompt = ""
153 style_prompt = ""
153 for key, value in styles.iteritems():
154 for key, value in styles.iteritems():
154 style_prompt += "%d %s" % (key, value)
155 style_prompt += "%d %s" % (key, value)
155 if key == default_style:
156 if key == default_style:
156 style_prompt += " (default)"
157 style_prompt += " (default)"
157 elif value == "Sonny":
158 elif value == "Sonny":
158 style_prompt += " (for international documents)"
159 style_prompt += " (for international documents)"
159 style_prompt += "\n"
160 style_prompt += "\n"
160
161
161 # Continue to ask the user for a style until an appropriate
162 # Continue to ask the user for a style until an appropriate
162 # one is specified.
163 # one is specified.
163 response = -1
164 response = -1
164 while (0 > response or response > 6):
165 while (0 > response or response > 6):
165 try:
166 try:
166 text_response = self._input(style_prompt)
167 text_response = self._input(style_prompt)
167
168
168 # Use default option if no input.
169 # Use default option if no input.
169 if len(text_response.strip()) == 0:
170 if len(text_response.strip()) == 0:
170 response = 1
171 response = 1
171 else:
172 else:
172 response = int(text_response)
173 response = int(text_response)
173 except:
174 except:
174 print("Error: Value must be a number between 1 and 6, leave blank for default\n")
175 print("Error: Value must be a number between 1 and 6, leave blank for default\n")
175 return styles[response]
176 return styles[response]
176
177
177 def _input(self, prompt_text):
178 def _input(self, prompt_text):
178 """
179 """
179 Prompt the user for input.
180 Prompt the user for input.
180
181
181 The input command will change depending on the version of python
182 The input command will change depending on the version of python
182 installed. To maintain support for 2 and earlier, we must use
183 installed. To maintain support for 2 and earlier, we must use
183 raw_input in that case. Else use input.
184 raw_input in that case. Else use input.
184 """
185 """
185
186
186 # Try to get the python version. This command is only available in
187 # Try to get the python version. This command is only available in
187 # python 2 and later, so it's important that we catch the exception
188 # python 2 and later, so it's important that we catch the exception
188 # if the command isn't found.
189 # if the command isn't found.
189 try:
190 try:
190 majorversion = sys.version_info[0]
191 majorversion = sys.version_info[0]
191 except:
192 except:
192 majorversion = 1
193 majorversion = 1
193
194
194 # Use the correct function to prompt the user for input depending on
195 # Use the correct function to prompt the user for input depending on
195 # what python version the code is running in.
196 # what python version the code is running in.
196 if majorversion >= 3:
197 if majorversion >= 3:
197 return input(prompt_text)
198 return input(prompt_text)
198 else:
199 else:
199 return raw_input(prompt_text)
200 return raw_input(prompt_text)
@@ -1,239 +1,247 b''
1 """Base classes for the notebook conversion pipeline.
1 """Base classes for the notebook conversion pipeline.
2
2
3 This module defines ConverterTemplate, a highly configurable converter
3 This module defines ConverterTemplate, a highly configurable converter
4 that uses Jinja2 to convert notebook files into different format.
4 that uses Jinja2 to convert notebook files into different format.
5
5
6 You can register both pre-transformers that will act on the notebook format
6 You can register both pre-transformers that will act on the notebook format
7 befor conversion and jinja filter that would then be availlable in the templates
7 befor conversion and jinja filter that would then be availlable in the templates
8 """
8 """
9
10 from __future__ import absolute_import
11
9 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
10 # Copyright (c) 2013, the IPython Development Team.
13 # Copyright (c) 2013, the IPython Development Team.
11 #
14 #
12 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
13 #
16 #
14 # The full license is in the file COPYING.txt, distributed with this software.
17 # The full license is in the file COPYING.txt, distributed with this software.
15 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
16
19
17 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
18 # Imports
21 # Imports
19 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
20
23
21 from __future__ import print_function, absolute_import
24 from __future__ import print_function
25 from __future__ import absolute_import
22
26
23 # Stdlib imports
27 # Stdlib imports
24 import io
28 import io
29 import os
25
30
26 # IPython imports
31 # IPython imports
27 from IPython.utils.traitlets import MetaHasTraits
32 from IPython.utils.traitlets import MetaHasTraits
28 from IPython.utils.traitlets import (Unicode, List, Bool)
33 from IPython.utils.traitlets import (Unicode, List, Bool)
29 from IPython.config.configurable import Configurable
34 from IPython.config.configurable import Configurable
30 from IPython.nbformat import current as nbformat
35 from IPython.nbformat import current as nbformat
31
36
32
37
33 # other libs/dependencies
38 # other libs/dependencies
34 from jinja2 import Environment, FileSystemLoader
39 from jinja2 import Environment, FileSystemLoader
35
40
36
41
37 # local import (pre-transformers)
42 # local import (pre-transformers)
38 import converters.transformers as trans
43 from . import transformers as trans
39 from converters.sphinx_transformer import (SphinxTransformer)
44 from .sphinx_transformer import (SphinxTransformer)
40 from converters.latex_transformer import (LatexTransformer)
45 from .latex_transformer import (LatexTransformer)
41
46
42 # some jinja filters
47 # some jinja filters
43 from converters.jinja_filters import (python_comment, indent,
48 from .jinja_filters import (python_comment, indent,
44 rm_fake, remove_ansi, markdown, highlight, highlight2latex,
49 rm_fake, remove_ansi, markdown, highlight, highlight2latex,
45 ansi2html, markdown2latex, get_lines, escape_tex, FilterDataType)
50 ansi2html, markdown2latex, get_lines, escape_tex, FilterDataType)
46
51
47 from converters.utils import markdown2rst
52 from .utils import markdown2rst
48
53
49 import textwrap
54 import textwrap
50
55
51 def wrap(text, width=100):
56 def wrap(text, width=100):
52 """ try to detect and wrap paragraph"""
57 """ try to detect and wrap paragraph"""
53 splitt = text.split('\n')
58 splitt = text.split('\n')
54 wrp = map(lambda x:textwrap.wrap(x,width),splitt)
59 wrp = map(lambda x:textwrap.wrap(x,width),splitt)
55 wrpd = map('\n'.join, wrp)
60 wrpd = map('\n'.join, wrp)
56 return '\n'.join(wrpd)
61 return '\n'.join(wrpd)
57
62
58
63
59
64
60 # define differents environemnt with different
65 # define differents environemnt with different
61 # delimiters not to conflict with languages inside
66 # delimiters not to conflict with languages inside
62
67
63 env = Environment(
68 env = Environment(
64 loader=FileSystemLoader([
69 loader=FileSystemLoader([
65 './templates/',
70 os.path.dirname(os.path.realpath(__file__))+'/../templates/',
66 './templates/skeleton/',
71 os.path.dirname(os.path.realpath(__file__))+'/../templates/skeleton/',
67 ]),
72 ]),
68 extensions=['jinja2.ext.loopcontrols']
73 extensions=['jinja2.ext.loopcontrols']
69 )
74 )
70
75
76 print(os.path.dirname(os.path.realpath(__file__))+'/../templates/')
77
78
71 texenv = Environment(
79 texenv = Environment(
72 loader=FileSystemLoader([
80 loader=FileSystemLoader([
73 './templates/tex/',
81 os.path.dirname(os.path.realpath(__file__))+'/../templates/tex/',
74 './templates/skeleton/tex/',
82 os.path.dirname(os.path.realpath(__file__))+'/../templates/skeleton/tex/',
75 ]),
83 ]),
76 extensions=['jinja2.ext.loopcontrols']
84 extensions=['jinja2.ext.loopcontrols']
77 )
85 )
78
86
79
87
80 texenv.block_start_string = '((*'
88 texenv.block_start_string = '((*'
81 texenv.block_end_string = '*))'
89 texenv.block_end_string = '*))'
82
90
83 texenv.variable_start_string = '((('
91 texenv.variable_start_string = '((('
84 texenv.variable_end_string = ')))'
92 texenv.variable_end_string = ')))'
85
93
86 texenv.comment_start_string = '((='
94 texenv.comment_start_string = '((='
87 texenv.comment_end_string = '=))'
95 texenv.comment_end_string = '=))'
88
96
89 texenv.filters['escape_tex'] = escape_tex
97 texenv.filters['escape_tex'] = escape_tex
90
98
91 #-----------------------------------------------------------------------------
99 #-----------------------------------------------------------------------------
92 # Class declarations
100 # Class declarations
93 #-----------------------------------------------------------------------------
101 #-----------------------------------------------------------------------------
94 class ConversionException(Exception):
102 class ConversionException(Exception):
95 pass
103 pass
96
104
97 class ConverterTemplate(Configurable):
105 class ConverterTemplate(Configurable):
98 """ A Jinja2 base converter templates
106 """ A Jinja2 base converter templates
99
107
100 Preprocess the ipynb files, feed it throug jinja templates,
108 Preprocess the ipynb files, feed it throug jinja templates,
101 and spit an converted files and a data object with other data
109 and spit an converted files and a data object with other data
102
110
103 should be mostly configurable
111 should be mostly configurable
104 """
112 """
105
113
106 pre_transformer_order = List(['haspyout_transformer'],
114 pre_transformer_order = List(['haspyout_transformer'],
107 config=True,
115 config=True,
108 help= """
116 help= """
109 An ordered list of pre transformer to apply to the ipynb
117 An ordered list of pre transformer to apply to the ipynb
110 file before running through templates
118 file before running through templates
111 """
119 """
112 )
120 )
113
121
114 tex_environement = Bool(False,
122 tex_environement = Bool(False,
115 config=True,
123 config=True,
116 help=""" is this a tex environment or not """)
124 help=""" is this a tex environment or not """)
117
125
118 template_file = Unicode('',
126 template_file = Unicode('',
119 config=True,
127 config=True,
120 help=""" Name of the template file to use """ )
128 help=""" Name of the template file to use """ )
121 #-------------------------------------------------------------------------
129 #-------------------------------------------------------------------------
122 # Instance-level attributes that are set in the constructor for this
130 # Instance-level attributes that are set in the constructor for this
123 # class.
131 # class.
124 #-------------------------------------------------------------------------
132 #-------------------------------------------------------------------------
125
133
126
134
127 preprocessors = []
135 preprocessors = []
128
136
129 def __init__(self, preprocessors={}, jinja_filters={}, config=None, **kw):
137 def __init__(self, preprocessors={}, jinja_filters={}, config=None, **kw):
130 """ Init a new converter.
138 """ Init a new converter.
131
139
132 config: the Configurable config object to pass around.
140 config: the Configurable config object to pass around.
133
141
134 preprocessors: dict of **availlable** key/value function to run on
142 preprocessors: dict of **availlable** key/value function to run on
135 ipynb json data before conversion to extract/inline file.
143 ipynb json data before conversion to extract/inline file.
136 See `transformer.py` and `ConfigurableTransformers`
144 See `transformer.py` and `ConfigurableTransformers`
137
145
138 set the order in which the transformers should apply
146 set the order in which the transformers should apply
139 with the `pre_transformer_order` trait of this class
147 with the `pre_transformer_order` trait of this class
140
148
141 transformers registerd by this key will take precedence on
149 transformers registerd by this key will take precedence on
142 default one.
150 default one.
143
151
144
152
145 jinja_filters: dict of supplementary jinja filter that should be made
153 jinja_filters: dict of supplementary jinja filter that should be made
146 availlable in template. If those are of Configurable Class type,
154 availlable in template. If those are of Configurable Class type,
147 they will be instanciated with the config object as argument.
155 they will be instanciated with the config object as argument.
148
156
149 user defined filter will overwrite the one availlable by default.
157 user defined filter will overwrite the one availlable by default.
150 """
158 """
151 super(ConverterTemplate, self).__init__(config=config, **kw)
159 super(ConverterTemplate, self).__init__(config=config, **kw)
152
160
153 # variable parameters depending on the pype of jinja environement
161 # variable parameters depending on the pype of jinja environement
154 self.env = texenv if self.tex_environement else env
162 self.env = texenv if self.tex_environement else env
155 self.ext = '.tplx' if self.tex_environement else '.tpl'
163 self.ext = '.tplx' if self.tex_environement else '.tpl'
156
164
157 for name in self.pre_transformer_order:
165 for name in self.pre_transformer_order:
158 # get the user-defined transformer first
166 # get the user-defined transformer first
159 transformer = preprocessors.get(name, getattr(trans, name, None))
167 transformer = preprocessors.get(name, getattr(trans, name, None))
160 if isinstance(transformer, MetaHasTraits):
168 if isinstance(transformer, MetaHasTraits):
161 transformer = transformer(config=config)
169 transformer = transformer(config=config)
162 self.preprocessors.append(transformer)
170 self.preprocessors.append(transformer)
163
171
164 ## for compat, remove later
172 ## for compat, remove later
165 self.preprocessors.append(trans.coalesce_streams)
173 self.preprocessors.append(trans.coalesce_streams)
166 self.preprocessors.append(trans.ExtractFigureTransformer(config=config))
174 self.preprocessors.append(trans.ExtractFigureTransformer(config=config))
167 self.preprocessors.append(trans.RevealHelpTransformer(config=config))
175 self.preprocessors.append(trans.RevealHelpTransformer(config=config))
168 self.preprocessors.append(trans.CSSHtmlHeaderTransformer(config=config))
176 self.preprocessors.append(trans.CSSHtmlHeaderTransformer(config=config))
169 self.preprocessors.append(SphinxTransformer(config=config))
177 self.preprocessors.append(SphinxTransformer(config=config))
170 self.preprocessors.append(LatexTransformer(config=config))
178 self.preprocessors.append(LatexTransformer(config=config))
171
179
172 ##
180 ##
173 self.env.filters['filter_data_type'] = FilterDataType(config=config)
181 self.env.filters['filter_data_type'] = FilterDataType(config=config)
174 self.env.filters['pycomment'] = python_comment
182 self.env.filters['pycomment'] = python_comment
175 self.env.filters['indent'] = indent
183 self.env.filters['indent'] = indent
176 self.env.filters['rm_fake'] = rm_fake
184 self.env.filters['rm_fake'] = rm_fake
177 self.env.filters['rm_ansi'] = remove_ansi
185 self.env.filters['rm_ansi'] = remove_ansi
178 self.env.filters['markdown'] = markdown
186 self.env.filters['markdown'] = markdown
179 self.env.filters['highlight'] = highlight
187 self.env.filters['highlight'] = highlight
180 self.env.filters['highlight2latex'] = highlight2latex
188 self.env.filters['highlight2latex'] = highlight2latex
181 self.env.filters['ansi2html'] = ansi2html
189 self.env.filters['ansi2html'] = ansi2html
182 self.env.filters['markdown2latex'] = markdown2latex
190 self.env.filters['markdown2latex'] = markdown2latex
183 self.env.filters['markdown2rst'] = markdown2rst
191 self.env.filters['markdown2rst'] = markdown2rst
184 self.env.filters['get_lines'] = get_lines
192 self.env.filters['get_lines'] = get_lines
185 self.env.filters['wrap'] = wrap
193 self.env.filters['wrap'] = wrap
186
194
187 ## user filter will overwrite
195 ## user filter will overwrite
188 for key, filtr in jinja_filters.iteritems():
196 for key, filtr in jinja_filters.iteritems():
189 if isinstance(filtr, MetaHasTraits):
197 if isinstance(filtr, MetaHasTraits):
190 self.env.filters[key] = filtr(config=config)
198 self.env.filters[key] = filtr(config=config)
191 else :
199 else :
192 self.env.filters[key] = filtr
200 self.env.filters[key] = filtr
193
201
194 self.template = self.env.get_template(self.template_file+self.ext)
202 self.template = self.env.get_template(self.template_file+self.ext)
195
203
196
204
197 def process(self, nb):
205 def process(self, nb):
198 """
206 """
199 preprocess the notebook json for easier use with the templates.
207 preprocess the notebook json for easier use with the templates.
200 will call all the `preprocessor`s in order before returning it.
208 will call all the `preprocessor`s in order before returning it.
201 """
209 """
202
210
203 # dict of 'resources' that could be made by the preprocessors
211 # dict of 'resources' that could be made by the preprocessors
204 # like key/value data to extract files from ipynb like in latex conversion
212 # like key/value data to extract files from ipynb like in latex conversion
205 resources = {}
213 resources = {}
206
214
207 for preprocessor in self.preprocessors:
215 for preprocessor in self.preprocessors:
208 nb, resources = preprocessor(nb, resources)
216 nb, resources = preprocessor(nb, resources)
209
217
210 return nb, resources
218 return nb, resources
211
219
212 def convert(self, nb):
220 def convert(self, nb):
213 """ convert the ipynb file
221 """ convert the ipynb file
214
222
215 return both the converted ipynb file and a dict containing potential
223 return both the converted ipynb file and a dict containing potential
216 other resources
224 other resources
217 """
225 """
218 nb, resources = self.process(nb)
226 nb, resources = self.process(nb)
219 return self.template.render(nb=nb, resources=resources), resources
227 return self.template.render(nb=nb, resources=resources), resources
220
228
221
229
222 def from_filename(self, filename):
230 def from_filename(self, filename):
223 """read and convert a notebook from a file name"""
231 """read and convert a notebook from a file name"""
224 with io.open(filename) as f:
232 with io.open(filename) as f:
225 return self.convert(nbformat.read(f, 'json'))
233 return self.convert(nbformat.read(f, 'json'))
226
234
227 def from_file(self, filelike):
235 def from_file(self, filelike):
228 """read and convert a notebook from a filelike object
236 """read and convert a notebook from a filelike object
229
237
230 filelike object will just be "read" and should be json format..
238 filelike object will just be "read" and should be json format..
231 """
239 """
232 return self.convert(nbformat.read(filelike, 'json'))
240 return self.convert(nbformat.read(filelike, 'json'))
233
241
234 def from_json(self, json):
242 def from_json(self, json):
235 """ not implemented
243 """ not implemented
236
244
237 Should convert from a json object
245 Should convert from a json object
238 """
246 """
239 raise NotImplementedError('not implemented (yet?)')
247 raise NotImplementedError('not implemented (yet?)')
@@ -1,269 +1,269 b''
1 """
1 """
2 Module that regroups transformer that woudl be applied to ipynb files
2 Module that regroups transformer that woudl be applied to ipynb files
3 before going through the templating machinery.
3 before going through the templating machinery.
4
4
5 It exposes convenient classes to inherit from to access configurability
5 It exposes convenient classes to inherit from to access configurability
6 as well as decorator to simplify tasks.
6 as well as decorator to simplify tasks.
7 """
7 """
8
8
9 from __future__ import print_function
9 from __future__ import print_function, absolute_import
10
10
11 from IPython.config.configurable import Configurable
11 from IPython.config.configurable import Configurable
12 from IPython.utils.traitlets import Unicode, Bool, Dict, List
12 from IPython.utils.traitlets import Unicode, Bool, Dict, List
13
13
14 from converters.config import GlobalConfigurable
14 from .config import GlobalConfigurable
15
15
16 class ConfigurableTransformers(GlobalConfigurable):
16 class ConfigurableTransformers(GlobalConfigurable):
17 """ A configurable transformer
17 """ A configurable transformer
18
18
19 Inherit from this class if you wish to have configurability for your
19 Inherit from this class if you wish to have configurability for your
20 transformer.
20 transformer.
21
21
22 Any configurable traitlets this class exposed will be configurable in profiles
22 Any configurable traitlets this class exposed will be configurable in profiles
23 using c.SubClassName.atribute=value
23 using c.SubClassName.atribute=value
24
24
25 you can overwrite cell_transform to apply a transformation independently on each cell
25 you can overwrite cell_transform to apply a transformation independently on each cell
26 or __call__ if you prefer your own logic. See orresponding docstring for informations.
26 or __call__ if you prefer your own logic. See orresponding docstring for informations.
27
27
28
28
29 """
29 """
30
30
31 def __init__(self, config=None, **kw):
31 def __init__(self, config=None, **kw):
32 super(ConfigurableTransformers, self).__init__(config=config, **kw)
32 super(ConfigurableTransformers, self).__init__(config=config, **kw)
33
33
34 def __call__(self, nb, other):
34 def __call__(self, nb, other):
35 """transformation to apply on each notebook.
35 """transformation to apply on each notebook.
36
36
37 received a handle to the current notebook as well as a dict of resources
37 received a handle to the current notebook as well as a dict of resources
38 which structure depends on the transformer.
38 which structure depends on the transformer.
39
39
40 You should return modified nb, other.
40 You should return modified nb, other.
41
41
42 If you wish to apply on each cell, you might want to overwrite cell_transform method.
42 If you wish to apply on each cell, you might want to overwrite cell_transform method.
43 """
43 """
44 try :
44 try :
45 for worksheet in nb.worksheets :
45 for worksheet in nb.worksheets :
46 for index, cell in enumerate(worksheet.cells):
46 for index, cell in enumerate(worksheet.cells):
47 worksheet.cells[index], other = self.cell_transform(cell, other, index)
47 worksheet.cells[index], other = self.cell_transform(cell, other, index)
48 return nb, other
48 return nb, other
49 except NotImplementedError:
49 except NotImplementedError:
50 raise NotImplementedError('should be implemented by subclass')
50 raise NotImplementedError('should be implemented by subclass')
51
51
52 def cell_transform(self, cell, other, index):
52 def cell_transform(self, cell, other, index):
53 """
53 """
54 Overwrite if you want to apply a transformation on each cell,
54 Overwrite if you want to apply a transformation on each cell,
55
55
56 receive the current cell, the resource dict and the index of current cell as parameter.
56 receive the current cell, the resource dict and the index of current cell as parameter.
57
57
58 You should return modified cell and resource dict.
58 You should return modified cell and resource dict.
59 """
59 """
60 raise NotImplementedError('should be implemented by subclass')
60 raise NotImplementedError('should be implemented by subclass')
61 return cell, other
61 return cell, other
62
62
63
63
64 class ActivatableTransformer(ConfigurableTransformers):
64 class ActivatableTransformer(ConfigurableTransformers):
65 """A simple ConfigurableTransformers that have an enabled flag
65 """A simple ConfigurableTransformers that have an enabled flag
66
66
67 Inherit from that if you just want to have a transformer which is
67 Inherit from that if you just want to have a transformer which is
68 no-op by default but can be activated in profiles with
68 no-op by default but can be activated in profiles with
69
69
70 c.YourTransformerName.enabled = True
70 c.YourTransformerName.enabled = True
71 """
71 """
72
72
73 enabled = Bool(False, config=True)
73 enabled = Bool(False, config=True)
74
74
75 def __call__(self, nb, other):
75 def __call__(self, nb, other):
76 if not self.enabled :
76 if not self.enabled :
77 return nb, other
77 return nb, other
78 else :
78 else :
79 return super(ActivatableTransformer, self).__call__(nb, other)
79 return super(ActivatableTransformer, self).__call__(nb, other)
80
80
81
81
82 def cell_preprocessor(function):
82 def cell_preprocessor(function):
83 """ wrap a function to be executed on all cells of a notebook
83 """ wrap a function to be executed on all cells of a notebook
84
84
85 wrapped function parameters :
85 wrapped function parameters :
86 cell : the cell
86 cell : the cell
87 other : external resources
87 other : external resources
88 index : index of the cell
88 index : index of the cell
89 """
89 """
90 def wrappedfunc(nb, other):
90 def wrappedfunc(nb, other):
91 for worksheet in nb.worksheets :
91 for worksheet in nb.worksheets :
92 for index, cell in enumerate(worksheet.cells):
92 for index, cell in enumerate(worksheet.cells):
93 worksheet.cells[index], other = function(cell, other, index)
93 worksheet.cells[index], other = function(cell, other, index)
94 return nb, other
94 return nb, other
95 return wrappedfunc
95 return wrappedfunc
96
96
97
97
98 @cell_preprocessor
98 @cell_preprocessor
99 def haspyout_transformer(cell, other, count):
99 def haspyout_transformer(cell, other, count):
100 """
100 """
101 Add a haspyout flag to cell that have it
101 Add a haspyout flag to cell that have it
102
102
103 Easier for templating, where you can't know in advance
103 Easier for templating, where you can't know in advance
104 wether to write the out prompt
104 wether to write the out prompt
105
105
106 """
106 """
107 cell.type = cell.cell_type
107 cell.type = cell.cell_type
108 cell.haspyout = False
108 cell.haspyout = False
109 for out in cell.get('outputs', []):
109 for out in cell.get('outputs', []):
110 if out.output_type == 'pyout':
110 if out.output_type == 'pyout':
111 cell.haspyout = True
111 cell.haspyout = True
112 break
112 break
113 return cell, other
113 return cell, other
114
114
115 @cell_preprocessor
115 @cell_preprocessor
116 def coalesce_streams(cell, other, count):
116 def coalesce_streams(cell, other, count):
117 """merge consecutive sequences of stream output into single stream
117 """merge consecutive sequences of stream output into single stream
118
118
119 to prevent extra newlines inserted at flush calls
119 to prevent extra newlines inserted at flush calls
120
120
121 TODO: handle \r deletion
121 TODO: handle \r deletion
122 """
122 """
123 outputs = cell.get('outputs', [])
123 outputs = cell.get('outputs', [])
124 if not outputs:
124 if not outputs:
125 return cell, other
125 return cell, other
126 new_outputs = []
126 new_outputs = []
127 last = outputs[0]
127 last = outputs[0]
128 new_outputs = [last]
128 new_outputs = [last]
129 for output in outputs[1:]:
129 for output in outputs[1:]:
130 if (output.output_type == 'stream' and
130 if (output.output_type == 'stream' and
131 last.output_type == 'stream' and
131 last.output_type == 'stream' and
132 last.stream == output.stream
132 last.stream == output.stream
133 ):
133 ):
134 last.text += output.text
134 last.text += output.text
135 else:
135 else:
136 new_outputs.append(output)
136 new_outputs.append(output)
137
137
138 cell.outputs = new_outputs
138 cell.outputs = new_outputs
139 return cell, other
139 return cell, other
140
140
141 class ExtractFigureTransformer(ActivatableTransformer):
141 class ExtractFigureTransformer(ActivatableTransformer):
142
142
143
143
144 extra_ext_map = Dict({},
144 extra_ext_map = Dict({},
145 config=True,
145 config=True,
146 help="""extra map to override extension based on type.
146 help="""extra map to override extension based on type.
147 Usefull for latex where svg will be converted to pdf before inclusion
147 Usefull for latex where svg will be converted to pdf before inclusion
148 """
148 """
149 )
149 )
150
150
151 key_format_map = Dict({},
151 key_format_map = Dict({},
152 config=True,
152 config=True,
153 )
153 )
154
154
155 figname_format_map = Dict({},
155 figname_format_map = Dict({},
156 config=True,
156 config=True,
157 )
157 )
158
158
159
159
160 #to do change this to .format {} syntax
160 #to do change this to .format {} syntax
161 default_key_tpl = Unicode('_fig_{count:02d}.{ext}', config=True)
161 default_key_tpl = Unicode('_fig_{count:02d}.{ext}', config=True)
162
162
163 def _get_ext(self, ext):
163 def _get_ext(self, ext):
164 if ext in self.extra_ext_map :
164 if ext in self.extra_ext_map :
165 return self.extra_ext_map[ext]
165 return self.extra_ext_map[ext]
166 return ext
166 return ext
167
167
168 def _new_figure(self, data, fmt, count):
168 def _new_figure(self, data, fmt, count):
169 """Create a new figure file in the given format.
169 """Create a new figure file in the given format.
170
170
171 """
171 """
172 tplf = self.figname_format_map.get(fmt, self.default_key_tpl)
172 tplf = self.figname_format_map.get(fmt, self.default_key_tpl)
173 tplk = self.key_format_map.get(fmt, self.default_key_tpl)
173 tplk = self.key_format_map.get(fmt, self.default_key_tpl)
174
174
175 # option to pass the hash as data ?
175 # option to pass the hash as data ?
176 figname = tplf.format(count=count, ext=self._get_ext(fmt))
176 figname = tplf.format(count=count, ext=self._get_ext(fmt))
177 key = tplk.format(count=count, ext=self._get_ext(fmt))
177 key = tplk.format(count=count, ext=self._get_ext(fmt))
178
178
179 # Binary files are base64-encoded, SVG is already XML
179 # Binary files are base64-encoded, SVG is already XML
180 if fmt in ('png', 'jpg', 'pdf'):
180 if fmt in ('png', 'jpg', 'pdf'):
181 data = data.decode('base64')
181 data = data.decode('base64')
182
182
183 return figname, key, data
183 return figname, key, data
184
184
185
185
186 def cell_transform(self, cell, other, count):
186 def cell_transform(self, cell, other, count):
187 if other.get('figures', None) is None :
187 if other.get('figures', None) is None :
188 other['figures'] = {}
188 other['figures'] = {}
189 for out in cell.get('outputs', []):
189 for out in cell.get('outputs', []):
190 for out_type in self.display_data_priority:
190 for out_type in self.display_data_priority:
191 if out.hasattr(out_type):
191 if out.hasattr(out_type):
192 figname, key, data = self._new_figure(out[out_type], out_type, count)
192 figname, key, data = self._new_figure(out[out_type], out_type, count)
193 out['key_'+out_type] = figname
193 out['key_'+out_type] = figname
194 other['figures'][key] = data
194 other['figures'][key] = data
195 count = count+1
195 count = count+1
196 return cell, other
196 return cell, other
197
197
198
198
199 class RevealHelpTransformer(ConfigurableTransformers):
199 class RevealHelpTransformer(ConfigurableTransformers):
200
200
201 def __call__(self, nb, other):
201 def __call__(self, nb, other):
202 for worksheet in nb.worksheets :
202 for worksheet in nb.worksheets :
203 for i, cell in enumerate(worksheet.cells):
203 for i, cell in enumerate(worksheet.cells):
204 cell.metadata.slide_type = cell.metadata.get('slideshow', {}).get('slide_type', None)
204 cell.metadata.slide_type = cell.metadata.get('slideshow', {}).get('slide_type', None)
205 if cell.metadata.slide_type is None:
205 if cell.metadata.slide_type is None:
206 cell.metadata.slide_type = '-'
206 cell.metadata.slide_type = '-'
207 if cell.metadata.slide_type in ['slide']:
207 if cell.metadata.slide_type in ['slide']:
208 worksheet.cells[i - 1].metadata.slide_helper = 'slide_end'
208 worksheet.cells[i - 1].metadata.slide_helper = 'slide_end'
209 if cell.metadata.slide_type in ['subslide']:
209 if cell.metadata.slide_type in ['subslide']:
210 worksheet.cells[i - 1].metadata.slide_helper = 'subslide_end'
210 worksheet.cells[i - 1].metadata.slide_helper = 'subslide_end'
211 return nb, other
211 return nb, other
212
212
213
213
214 class CSSHtmlHeaderTransformer(ActivatableTransformer):
214 class CSSHtmlHeaderTransformer(ActivatableTransformer):
215
215
216 def __call__(self, nb, resources):
216 def __call__(self, nb, resources):
217 """Fetch and add css to the resource dict
217 """Fetch and add css to the resource dict
218
218
219 Fetch css from IPython adn Pygment to add at the beginning
219 Fetch css from IPython adn Pygment to add at the beginning
220 of the html files.
220 of the html files.
221
221
222 Add this css in resources in the "inlining.css" key
222 Add this css in resources in the "inlining.css" key
223 """
223 """
224 resources['inlining'] = {}
224 resources['inlining'] = {}
225 resources['inlining']['css'] = self.header
225 resources['inlining']['css'] = self.header
226 return nb, resources
226 return nb, resources
227
227
228 header = []
228 header = []
229
229
230 def __init__(self, config=None, **kw):
230 def __init__(self, config=None, **kw):
231 super(CSSHtmlHeaderTransformer, self).__init__(config=config, **kw)
231 super(CSSHtmlHeaderTransformer, self).__init__(config=config, **kw)
232 if self.enabled :
232 if self.enabled :
233 self.regen_header()
233 self.regen_header()
234
234
235 def regen_header(self):
235 def regen_header(self):
236 ## lazy load asa this might not be use in many transformers
236 ## lazy load asa this might not be use in many transformers
237 import os
237 import os
238 from IPython.utils import path
238 from IPython.utils import path
239 import io
239 import io
240 from pygments.formatters import HtmlFormatter
240 from pygments.formatters import HtmlFormatter
241 header = []
241 header = []
242 static = os.path.join(path.get_ipython_package_dir(),
242 static = os.path.join(path.get_ipython_package_dir(),
243 'frontend', 'html', 'notebook', 'static',
243 'frontend', 'html', 'notebook', 'static',
244 )
244 )
245 here = os.path.split(os.path.realpath(__file__))[0]
245 here = os.path.split(os.path.realpath(__file__))[0]
246 css = os.path.join(static, 'css')
246 css = os.path.join(static, 'css')
247 for sheet in [
247 for sheet in [
248 # do we need jquery and prettify?
248 # do we need jquery and prettify?
249 # os.path.join(static, 'jquery', 'css', 'themes', 'base',
249 # os.path.join(static, 'jquery', 'css', 'themes', 'base',
250 # 'jquery-ui.min.css'),
250 # 'jquery-ui.min.css'),
251 # os.path.join(static, 'prettify', 'prettify.css'),
251 # os.path.join(static, 'prettify', 'prettify.css'),
252 os.path.join(css, 'boilerplate.css'),
252 os.path.join(css, 'boilerplate.css'),
253 os.path.join(css, 'fbm.css'),
253 os.path.join(css, 'fbm.css'),
254 os.path.join(css, 'notebook.css'),
254 os.path.join(css, 'notebook.css'),
255 os.path.join(css, 'renderedhtml.css'),
255 os.path.join(css, 'renderedhtml.css'),
256 os.path.join(css, 'style.min.css'),
256 os.path.join(css, 'style.min.css'),
257 ]:
257 ]:
258 try:
258 try:
259 with io.open(sheet, encoding='utf-8') as f:
259 with io.open(sheet, encoding='utf-8') as f:
260 s = f.read()
260 s = f.read()
261 header.append(s)
261 header.append(s)
262 except IOError:
262 except IOError:
263 # new version of ipython with style.min.css, pass
263 # new version of ipython with style.min.css, pass
264 pass
264 pass
265
265
266 pygments_css = HtmlFormatter().get_style_defs('.highlight')
266 pygments_css = HtmlFormatter().get_style_defs('.highlight')
267 header.append(pygments_css)
267 header.append(pygments_css)
268 self.header = header
268 self.header = header
269
269
@@ -1,132 +1,132 b''
1 {%- extends 'display_priority.tpl' -%}
1 {%- extends 'display_priority.tpl' -%}
2
2
3
3
4
4
5 {% block codecell %}
5 {% block codecell %}
6 <div class="cell border-box-sizing code_cell vbox">
6 <div class="cell border-box-sizing code_cell vbox">
7 {{ super() }}</div>
7 {{ super() }}</div>
8 {%- endblock codecell %}
8 {%- endblock codecell %}
9
9
10 {% block input_group -%}
10 {% block input_group -%}
11 <div class="input hbox">
11 <div class="input hbox">
12 {{super()}}
12 {{super()}}
13 </div>
13 </div>
14 {% endblock input_group %}
14 {% endblock input_group %}
15
15
16 {% block output_group -%}
16 {% block output_group -%}
17 <div class="vbox output_wrapper">
17 <div class="vbox output_wrapper">
18 <div class="output vbox">
18 <div class="output vbox">
19 <div class="hbox output_area">
19 <div class="vbox output_area">
20 {{ super() }}
20 {{ super() }}
21 </div>
21 </div>
22 </div>
22 </div>
23 </div>
23 </div>
24 {% endblock output_group %}
24 {% endblock output_group %}
25
25
26
26
27 {% block in_prompt -%}
27 {% block in_prompt -%}
28 <div class="prompt input_prompt">In&nbsp;[{{cell.prompt_number}}]:</div>
28 <div class="prompt input_prompt">In&nbsp;[{{cell.prompt_number}}]:</div>
29 {%- endblock in_prompt %}
29 {%- endblock in_prompt %}
30
30
31 {% block output_prompt -%}
31 {% block output_prompt -%}
32 <div class="prompt output_prompt">
32 <div class="prompt output_prompt">
33 {%- if cell.haspyout -%}
33 {%- if cell.haspyout -%}
34 Out[{{cell.prompt_number}}]:
34 Out[{{cell.prompt_number}}]:
35 {%- endif -%}
35 {%- endif -%}
36 </div>
36 </div>
37 {% endblock output_prompt %}
37 {% endblock output_prompt %}
38
38
39 {% block input %}
39 {% block input %}
40 <div class="input_area box-flex1">
40 <div class="input_area box-flex1">
41 {{cell.input | highlight }}
41 {{cell.input | highlight }}
42 </div>
42 </div>
43 {%- endblock input %}
43 {%- endblock input %}
44
44
45
45
46 {% block markdowncell scoped %}
46 {% block markdowncell scoped %}
47 <div class="text_cell_render border-box-sizing rendered_html">
47 <div class="text_cell_render border-box-sizing rendered_html">
48 {{ cell.source | markdown| rm_fake}}
48 {{ cell.source | markdown| rm_fake}}
49 </div>
49 </div>
50 {%- endblock markdowncell %}
50 {%- endblock markdowncell %}
51
51
52 {% block headingcell scoped %}
52 {% block headingcell scoped %}
53 <div class="text_cell_render border-box-sizing rendered_html">
53 <div class="text_cell_render border-box-sizing rendered_html">
54 <h{{cell.level}}>
54 <h{{cell.level}}>
55 {{cell.source}}
55 {{cell.source}}
56 </h{{cell.level}}>
56 </h{{cell.level}}>
57 </div>
57 </div>
58 {% endblock headingcell %}
58 {% endblock headingcell %}
59
59
60 {% block rawcell scoped %}
60 {% block rawcell scoped %}
61 {{ cell.source }}
61 {{ cell.source }}
62 {% endblock rawcell %}
62 {% endblock rawcell %}
63
63
64 {% block unknowncell scoped %}
64 {% block unknowncell scoped %}
65 unknown type {{cell.type}}
65 unknown type {{cell.type}}
66 {% endblock unknowncell %}
66 {% endblock unknowncell %}
67
67
68
68
69 {% block pyout -%}
69 {% block pyout -%}
70 <div class="box-flex1 output_subarea output_pyout">
70 <div class="box-flex1 output_subarea output_pyout">
71 {% block data_priority scoped %}{{ super()}}{% endblock %}
71 {% block data_priority scoped %}{{ super()}}{% endblock %}
72 </div>
72 </div>
73 {%- endblock pyout %}
73 {%- endblock pyout %}
74
74
75 {% block stream_stdout -%}
75 {% block stream_stdout -%}
76 <div class="box-flex1 output_subarea output_stream output_stdout">
76 <div class="box-flex1 output_subarea output_stream output_stdout">
77 <pre>{{output.text |ansi2html}}</pre>
77 <pre>{{output.text |ansi2html}}</pre>
78 </div>
78 </div>
79 {%- endblock stream_stdout %}
79 {%- endblock stream_stdout %}
80
80
81 {% block stream_stderr -%}
81 {% block stream_stderr -%}
82 <div class="box-flex1 output_subarea output_stream output_stderr">
82 <div class="box-flex1 output_subarea output_stream output_stderr">
83 <pre>{{output.text |ansi2html}}</pre>
83 <pre>{{output.text |ansi2html}}</pre>
84 </div>
84 </div>
85 {%- endblock stream_stderr %}
85 {%- endblock stream_stderr %}
86
86
87 {% block data_svg -%}
87 {% block data_svg -%}
88 {{output.svg}}
88 {{output.svg}}
89 {%- endblock data_svg %}
89 {%- endblock data_svg %}
90
90
91
91
92 {% block data_html -%}
92 {% block data_html -%}
93 <div class="output_html rendered_html">
93 <div class="output_html rendered_html">
94 {{output.html}}
94 {{output.html}}
95 </div>
95 </div>
96 {%- endblock data_html %}
96 {%- endblock data_html %}
97
97
98 {% block data_png %}
98 {% block data_png %}
99 <img src="data:image/png;base64,{{output.png}}"></img>
99 <img src="data:image/png;base64,{{output.png}}"></img>
100 {%- endblock data_png %}
100 {%- endblock data_png %}
101
101
102
102
103 {% block data_jpg %}
103 {% block data_jpg %}
104 <img src="data:image/jpeg;base64,{{output.jpeg}}"></img>
104 <img src="data:image/jpeg;base64,{{output.jpeg}}"></img>
105 {%- endblock data_jpg %}
105 {%- endblock data_jpg %}
106
106
107
107
108 {% block data_latex %}
108 {% block data_latex %}
109 {{output.latex}}
109 {{output.latex}}
110 {%- endblock data_latex %}
110 {%- endblock data_latex %}
111
111
112 {% block pyerr -%}
112 {% block pyerr -%}
113 <div class="box-flex1 output_subarea output_pyerr">
113 <div class="box-flex1 output_subarea output_pyerr">
114 <pre>{{super()}}</pre>
114 <pre>{{super()}}</pre>
115 </div>
115 </div>
116 {%- endblock pyerr %}
116 {%- endblock pyerr %}
117
117
118 {%- block traceback_line %}
118 {%- block traceback_line %}
119 {{line| ansi2html}}
119 {{line| ansi2html}}
120 {%- endblock traceback_line %}
120 {%- endblock traceback_line %}
121
121
122
122
123 {%- block data_text %}
123 {%- block data_text %}
124 <pre>{{output.text | ansi2html}}</pre>
124 <pre>{{output.text | ansi2html}}</pre>
125 {%- endblock -%}
125 {%- endblock -%}
126
126
127
127
128 {%- block display_data scoped -%}
128 {%- block display_data scoped -%}
129 <div class="box-flex1 output_subarea output_display_data">
129 <div class="box-flex1 output_subarea output_display_data">
130 {{super()}}
130 {{super()}}
131 </div>
131 </div>
132 {%- endblock display_data -%} No newline at end of file
132 {%- endblock display_data -%}
General Comments 0
You need to be logged in to leave comments. Login now