##// END OF EJS Templates
Merge pull request #3500 from ipython/nbconvert...
Brian E. Granger -
r11104:fba37dfd merge
parent child Browse files
Show More
@@ -0,0 +1,5 b''
1 """Utilities for converting notebooks to and from different formats."""
2
3 from .exporters import *
4 import filters
5 import transformers
@@ -0,0 +1,10 b''
1 from .basichtml import BasicHtmlExporter
2 from .export import *
3 from .exporter import Exporter
4 from .fullhtml import FullHtmlExporter
5 from .latex import LatexExporter
6 from .markdown import MarkdownExporter
7 from .python import PythonExporter
8 from .rst import RstExporter
9 from .sphinx_howto import SphinxHowtoExporter
10 from .sphinx_manual import SphinxManualExporter
@@ -0,0 +1,55 b''
1 """
2 Exporter that exports Basic HTML.
3 """
4
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 from IPython.utils.traitlets import Unicode
18
19 from ..transformers.csshtmlheader import CSSHtmlHeaderTransformer
20
21 from .exporter import Exporter
22
23 #-----------------------------------------------------------------------------
24 # Classes
25 #-----------------------------------------------------------------------------
26
27 class BasicHtmlExporter(Exporter):
28 """
29 Exports a basic HTML document. This exporter assists with the export of
30 HTML. Inherit from it if you are writing your own HTML template and need
31 custom transformers/filters. If you don't need custom transformers/
32 filters, just change the 'template_file' config option.
33 """
34
35 file_extension = Unicode(
36 'html', config=True,
37 help="Extension of the file that should be written to disk"
38 )
39
40 template_file = Unicode(
41 'basichtml', config=True,
42 help="Name of the template file to use")
43
44
45 def _register_transformers(self):
46 """
47 Register all of the transformers needed for this exporter.
48 """
49
50 #Register the transformers of the base class.
51 super(BasicHtmlExporter, self)._register_transformers()
52
53 #Register CSSHtmlHeaderTransformer transformer
54 self.register_transformer(CSSHtmlHeaderTransformer)
55
@@ -0,0 +1,225 b''
1 """
2 Module containing single call export functions.
3 """
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15
16 from functools import wraps
17
18 from IPython.nbformat.v3.nbbase import NotebookNode
19
20 from .exporter import Exporter
21 from .basichtml import BasicHtmlExporter
22 from .fullhtml import FullHtmlExporter
23 from .latex import LatexExporter
24 from .markdown import MarkdownExporter
25 from .python import PythonExporter
26 from .python_armor import PythonArmorExporter
27 from .reveal import RevealExporter
28 from .rst import RstExporter
29 from .sphinx_howto import SphinxHowtoExporter
30 from .sphinx_manual import SphinxManualExporter
31
32 #-----------------------------------------------------------------------------
33 # Classes
34 #-----------------------------------------------------------------------------
35
36 def DocDecorator(f):
37
38 #Set docstring of function
39 f.__doc__ = f.__doc__ + """
40 nb : Notebook node
41 config : config
42 User configuration instance.
43 transformers : list[of transformer]
44 Custom transformers to apply to the notebook prior to engaging
45 the Jinja template engine. Any transformers specified here
46 will override existing transformers if a naming conflict
47 occurs.
48 filters : list[of filter]
49 Custom filters to make accessible to the Jinja templates. Any
50 filters specified here will override existing filters if a
51 naming conflict occurs.
52
53 Returns
54 ----------
55 tuple- output, resources, exporter_instance
56 output : str
57 Jinja 2 output. This is the resulting converted notebook.
58 resources : dictionary
59 Dictionary of resources used prior to and during the conversion
60 process.
61 exporter_instance : Exporter
62 Instance of the Exporter class used to export the document. Useful
63 to caller because it provides a 'file_extension' property which
64 specifies what extension the output should be saved as."""
65
66 @wraps(f)
67 def decorator(*args, **kwargs):
68 return f(*args, **kwargs)
69
70 return decorator
71
72
73 #-----------------------------------------------------------------------------
74 # Functions
75 #-----------------------------------------------------------------------------
76
77 __all__ = [
78 'export',
79 'export_sphinx_manual',
80 'export_sphinx_howto',
81 'export_basic_html',
82 'export_full_html',
83 'export_latex',
84 'export_markdown',
85 'export_python',
86 'export_python_armor',
87 'export_reveal',
88 'export_rst',
89 'export_by_name'
90 ]
91
92 @DocDecorator
93 def export(exporter_type, nb, config=None, transformers=None, filters=None):
94 """
95 Export a notebook object using specific exporter class.
96
97 exporter_type : Exporter class type
98 Class type of the exporter that should be used. This method
99 will initialize it's own instance of the class. It is
100 ASSUMED that the class type provided exposes a
101 constructor (__init__) with the same signature as the
102 base Exporter class.}
103 """
104
105 #Check arguments
106 if exporter_type is None:
107 raise TypeError("Exporter is None")
108 elif not issubclass(exporter_type, Exporter):
109 raise TypeError("Exporter type does not inherit from Exporter (base)")
110
111 if nb is None:
112 raise TypeError("nb is None")
113
114 #Create the exporter
115 exporter_instance = exporter_type(preprocessors=transformers,
116 jinja_filters=filters, config=config)
117
118 #Try to convert the notebook using the appropriate conversion function.
119 if isinstance(nb, NotebookNode):
120 output, resources = exporter_instance.from_notebook_node(nb)
121 elif isinstance(nb, basestring):
122 output, resources = exporter_instance.from_filename(nb)
123 else:
124 output, resources = exporter_instance.from_file(nb)
125 return output, resources, exporter_instance
126
127
128 @DocDecorator
129 def export_sphinx_manual(nb, config=None, transformers=None, filters=None):
130 """
131 Export a notebook object to Sphinx Manual LaTeX
132 """
133 return export(SphinxManualExporter, nb, config, transformers, filters)
134
135
136 @DocDecorator
137 def export_sphinx_howto(nb, config=None, transformers=None, filters=None):
138 """
139 Export a notebook object to Sphinx HowTo LaTeX
140 """
141 return export(SphinxHowtoExporter, nb, config, transformers, filters)
142
143
144 @DocDecorator
145 def export_basic_html(nb, config=None, transformers=None, filters=None):
146 """
147 Export a notebook object to Basic HTML
148 """
149 return export(BasicHtmlExporter, nb, config, transformers, filters)
150
151
152 @DocDecorator
153 def export_full_html(nb, config=None, transformers=None, filters=None):
154 """
155 Export a notebook object to Full HTML
156 """
157 return export(FullHtmlExporter, nb, config, transformers, filters)
158
159
160 @DocDecorator
161 def export_latex(nb, config=None, transformers=None, filters=None):
162 """
163 Export a notebook object to LaTeX
164 """
165 return export(LatexExporter, nb, config, transformers, filters)
166
167
168 @DocDecorator
169 def export_markdown(nb, config=None, transformers=None, filters=None):
170 """
171 Export a notebook object to Markdown
172 """
173 return export(MarkdownExporter, nb, config, transformers, filters)
174
175
176 @DocDecorator
177 def export_python(nb, config=None, transformers=None, filters=None):
178 """
179 Export a notebook object to Python
180 """
181 return export(PythonExporter, nb, config, transformers, filters)
182
183
184 @DocDecorator
185 def export_python_armor(nb, config=None, transformers=None, filters=None):
186 """
187 Export a notebook object to Python (Armor)
188 """
189 return export(PythonArmorExporter, nb, config, transformers, filters)
190
191
192 @DocDecorator
193 def export_reveal(nb, config=None, transformers=None, filters=None):
194 """
195 Export a notebook object to Reveal
196 """
197 return export(RevealExporter, nb, config, transformers, filters)
198
199
200 @DocDecorator
201 def export_rst(nb, config=None, transformers=None, filters=None):
202 """
203 Export a notebook object to RST
204 """
205 return export(RstExporter, nb, config, transformers, filters)
206
207
208 @DocDecorator
209 def export_by_name(template_name, nb, config=None, transformers=None, filters=None):
210 """
211 Export a notebook object to a template type by its name. Reflection
212 (Inspect) is used to find the template's corresponding explicit export
213 method defined in this module. That method is then called directly.
214
215 template_name : str
216 Name of the template style to export to.
217 """
218
219 function_name = "export_" + template_name.lower()
220
221 if function_name in globals():
222 return globals()[function_name](nb, config, transformers, filters)
223 else:
224 return None
225
@@ -0,0 +1,341 b''
1 """This module defines Exporter, a highly configurable converter
2 that uses Jinja2 to export notebook files into different formats.
3 """
4
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 from __future__ import print_function, absolute_import
18
19 # Stdlib imports
20 import io
21 import os
22 import inspect
23 from copy import deepcopy
24
25 # other libs/dependencies
26 from jinja2 import Environment, FileSystemLoader
27 from markdown import markdown
28
29 # IPython imports
30 from IPython.config.configurable import Configurable
31 from IPython.config import Config
32 from IPython.nbformat import current as nbformat
33 from IPython.utils.traitlets import MetaHasTraits, Unicode
34 from IPython.utils.text import indent
35
36 from IPython.nbconvert import filters
37 from IPython.nbconvert import transformers
38
39 #-----------------------------------------------------------------------------
40 # Globals and constants
41 #-----------------------------------------------------------------------------
42
43 #Jinja2 extensions to load.
44 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
45
46 default_filters = {
47 'indent': indent,
48 'markdown': markdown,
49 'ansi2html': filters.ansi2html,
50 'filter_data_type': filters.DataTypeFilter,
51 'get_lines': filters.get_lines,
52 'highlight': filters.highlight,
53 'highlight2html': filters.highlight,
54 'highlight2latex': filters.highlight2latex,
55 'markdown2latex': filters.markdown2latex,
56 'markdown2rst': filters.markdown2rst,
57 'pycomment': filters.python_comment,
58 'rm_ansi': filters.remove_ansi,
59 'rm_dollars': filters.strip_dollars,
60 'rm_fake': filters.rm_fake,
61 'ansi2latex': filters.ansi2latex,
62 'rm_math_space': filters.rm_math_space,
63 'wrap': filters.wrap
64 }
65
66 #-----------------------------------------------------------------------------
67 # Class
68 #-----------------------------------------------------------------------------
69
70 class Exporter(Configurable):
71 """
72 Exports notebooks into other file formats. Uses Jinja 2 templating engine
73 to output new formats. Inherit from this class if you are creating a new
74 template type along with new filters/transformers. If the filters/
75 transformers provided by default suffice, there is no need to inherit from
76 this class. Instead, override the template_file and file_extension
77 traits via a config file.
78
79 {filters}
80 """
81
82 # finish the docstring
83 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
84
85
86 template_file = Unicode(
87 '', config=True,
88 help="Name of the template file to use")
89
90 file_extension = Unicode(
91 'txt', config=True,
92 help="Extension of the file that should be written to disk"
93 )
94
95 template_path = Unicode(
96 "/../templates/", config=True,
97 help="Path where the template files are located.")
98
99 template_skeleton_path = Unicode(
100 "/../templates/skeleton/", config=True,
101 help="Path where the template skeleton files are located.")
102
103 #Jinja block definitions
104 jinja_comment_block_start = Unicode("", config=True)
105 jinja_comment_block_end = Unicode("", config=True)
106 jinja_variable_block_start = Unicode("", config=True)
107 jinja_variable_block_end = Unicode("", config=True)
108 jinja_logic_block_start = Unicode("", config=True)
109 jinja_logic_block_end = Unicode("", config=True)
110
111 #Extension that the template files use.
112 template_extension = Unicode(".tpl", config=True)
113
114 #Processors that process the input data prior to the export, set in the
115 #constructor for this class.
116 transformers = None
117
118
119 def __init__(self, transformers=None, filters=None, config=None, **kw):
120 """
121 Public constructor
122
123 Parameters
124 ----------
125 transformers : list[of transformer]
126 Custom transformers to apply to the notebook prior to engaging
127 the Jinja template engine. Any transformers specified here
128 will override existing transformers if a naming conflict
129 occurs.
130 filters : dict[of filter]
131 filters specified here will override existing filters if a naming
132 conflict occurs. Filters are availlable in jinja template through
133 the name of the corresponding key. Cf class docstring for
134 availlable default filters.
135 config : config
136 User configuration instance.
137 """
138
139 #Call the base class constructor
140 c = self.default_config
141 if config:
142 c.merge(config)
143
144 super(Exporter, self).__init__(config=c, **kw)
145
146 #Standard environment
147 self._init_environment()
148
149 #Add transformers
150 self._register_transformers()
151
152 #Add filters to the Jinja2 environment
153 self._register_filters()
154
155 #Load user transformers. Overwrite existing transformers if need be.
156 if transformers :
157 for transformer in transformers:
158 self.register_transformer(transformer)
159
160 #Load user filters. Overwrite existing filters if need be.
161 if not filters is None:
162 for key, user_filter in filters.iteritems():
163 if issubclass(user_filter, MetaHasTraits):
164 self.environment.filters[key] = user_filter(config=config)
165 else:
166 self.environment.filters[key] = user_filter
167
168 @property
169 def default_config(self):
170 return Config()
171
172
173
174 def from_notebook_node(self, nb, resources=None):
175 """
176 Convert a notebook from a notebook node instance.
177
178 Parameters
179 ----------
180 nb : Notebook node
181 resources : a dict of additional resources that
182 can be accessed read/write by transformers
183 and filters.
184 """
185 if resources is None:
186 resources = {}
187 nb, resources = self._preprocess(nb, resources)
188
189 #Load the template file.
190 self.template = self.environment.get_template(self.template_file+self.template_extension)
191
192 return self.template.render(nb=nb, resources=resources), resources
193
194
195 def from_filename(self, filename):
196 """
197 Convert a notebook from a notebook file.
198
199 Parameters
200 ----------
201 filename : str
202 Full filename of the notebook file to open and convert.
203 """
204
205 with io.open(filename) as f:
206 return self.from_notebook_node(nbformat.read(f, 'json'))
207
208
209 def from_file(self, file_stream):
210 """
211 Convert a notebook from a notebook file.
212
213 Parameters
214 ----------
215 file_stream : file-like object
216 Notebook file-like object to convert.
217 """
218 return self.from_notebook_node(nbformat.read(file_stream, 'json'))
219
220
221 def register_transformer(self, transformer):
222 """
223 Register a transformer.
224 Transformers are classes that act upon the notebook before it is
225 passed into the Jinja templating engine. Transformers are also
226 capable of passing additional information to the Jinja
227 templating engine.
228
229 Parameters
230 ----------
231 transformer : transformer
232 """
233 if self.transformers is None:
234 self.transformers = []
235
236 if inspect.isfunction(transformer):
237 self.transformers.append(transformer)
238 return transformer
239 elif isinstance(transformer, MetaHasTraits):
240 transformer_instance = transformer(config=self.config)
241 self.transformers.append(transformer_instance)
242 return transformer_instance
243 else:
244 transformer_instance = transformer()
245 self.transformers.append(transformer_instance)
246 return transformer_instance
247
248
249 def register_filter(self, name, filter):
250 """
251 Register a filter.
252 A filter is a function that accepts and acts on one string.
253 The filters are accesible within the Jinja templating engine.
254
255 Parameters
256 ----------
257 name : str
258 name to give the filter in the Jinja engine
259 filter : filter
260 """
261 if inspect.isfunction(filter):
262 self.environment.filters[name] = filter
263 elif isinstance(filter, MetaHasTraits):
264 self.environment.filters[name] = filter(config=self.config)
265 else:
266 self.environment.filters[name] = filter()
267 return self.environment.filters[name]
268
269
270 def _register_transformers(self):
271 """
272 Register all of the transformers needed for this exporter.
273 """
274
275 self.register_transformer(transformers.coalesce_streams)
276
277 #Remember the figure extraction transformer so it can be enabled and
278 #disabled easily later.
279 self.extract_figure_transformer = self.register_transformer(transformers.ExtractFigureTransformer)
280
281
282 def _register_filters(self):
283 """
284 Register all of the filters required for the exporter.
285 """
286 for k, v in default_filters.iteritems():
287 self.register_filter(k, v)
288
289
290 def _init_environment(self):
291 """
292 Create the Jinja templating environment.
293 """
294
295 self.environment = Environment(
296 loader=FileSystemLoader([
297 os.path.dirname(os.path.realpath(__file__)) + self.template_path,
298 os.path.dirname(os.path.realpath(__file__)) + self.template_skeleton_path,
299 ]),
300 extensions=JINJA_EXTENSIONS
301 )
302
303 #Set special Jinja2 syntax that will not conflict with latex.
304 if self.jinja_logic_block_start:
305 self.environment.block_start_string = self.jinja_logic_block_start
306 if self.jinja_logic_block_end:
307 self.environment.block_end_string = self.jinja_logic_block_end
308 if self.jinja_variable_block_start:
309 self.environment.variable_start_string = self.jinja_variable_block_start
310 if self.jinja_variable_block_end:
311 self.environment.variable_end_string = self.jinja_variable_block_end
312 if self.jinja_comment_block_start:
313 self.environment.comment_start_string = self.jinja_comment_block_start
314 if self.jinja_comment_block_end:
315 self.environment.comment_end_string = self.jinja_comment_block_end
316
317
318 def _preprocess(self, nb, resources):
319 """
320 Preprocess the notebook before passing it into the Jinja engine.
321 To preprocess the notebook is to apply all of the
322
323 Parameters
324 ----------
325 nb : notebook node
326 notebook that is being exported.
327 resources : a dict of additional resources that
328 can be accessed read/write by transformers
329 and filters.
330 """
331
332 # Do a deepcopy first,
333 # we are never safe enough with what the transformers could do.
334 nbc = deepcopy(nb)
335 resc = deepcopy(resources)
336 #Run each transformer on the notebook. Carry the output along
337 #to each transformer
338 for transformer in self.transformers:
339 nb, resources = transformer(nbc, resc)
340 return nb, resources
341
@@ -0,0 +1,39 b''
1 """
2 Exporter for exporting full HTML documents.
3 """
4
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 from IPython.utils.traitlets import Unicode
18
19 from .basichtml import BasicHtmlExporter
20 from IPython.config import Config
21
22 #-----------------------------------------------------------------------------
23 # Classes
24 #-----------------------------------------------------------------------------
25
26 class FullHtmlExporter(BasicHtmlExporter):
27 """
28 Exports a full HTML document.
29 """
30
31 template_file = Unicode(
32 'fullhtml', config=True,
33 help="Name of the template file to use")
34
35 @property
36 def default_config(self):
37 c = Config({'CSSHtmlHeaderTransformer':{'enabled':True}})
38 c.merge(super(FullHtmlExporter,self).default_config)
39 return c
@@ -0,0 +1,105 b''
1 """
2 Exporter that allows Latex Jinja templates to work. Contains logic to
3 appropriately prepare IPYNB files for export to LaTeX. Including but
4 not limited to escaping LaTeX, fixing math region tags, using special
5 tags to circumvent Jinja/Latex syntax conflicts.
6 """
7 #-----------------------------------------------------------------------------
8 # Copyright (c) 2013, the IPython Development Team.
9 #
10 # Distributed under the terms of the Modified BSD License.
11 #
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
14
15 #-----------------------------------------------------------------------------
16 # Imports
17 #-----------------------------------------------------------------------------
18
19 # IPython imports
20 from IPython.utils.traitlets import Unicode
21 from IPython.config import Config
22
23 from IPython.nbconvert import filters, transformers
24 from .exporter import Exporter
25
26 #-----------------------------------------------------------------------------
27 # Classes and functions
28 #-----------------------------------------------------------------------------
29
30 class LatexExporter(Exporter):
31 """
32 Exports to a Latex template. Inherit from this class if your template is
33 LaTeX based and you need custom tranformers/filters. Inherit from it if
34 you are writing your own HTML template and need custom tranformers/filters.
35 If you don't need custom tranformers/filters, just change the
36 'template_file' config option. Place your template in the special "/latex"
37 subfolder of the "../templates" folder.
38 """
39
40 file_extension = Unicode(
41 'tex', config=True,
42 help="Extension of the file that should be written to disk")
43
44 template_file = Unicode(
45 'base', config=True,
46 help="Name of the template file to use")
47
48 #Latex constants
49 template_path = Unicode(
50 "/../templates/latex/", config=True,
51 help="Path where the template files are located.")
52
53 template_skeleton_path = Unicode(
54 "/../templates/latex/skeleton/", config=True,
55 help="Path where the template skeleton files are located.")
56
57 #Special Jinja2 syntax that will not conflict when exporting latex.
58 jinja_comment_block_start = Unicode("((=", config=True)
59 jinja_comment_block_end = Unicode("=))", config=True)
60 jinja_variable_block_start = Unicode("(((", config=True)
61 jinja_variable_block_end = Unicode(")))", config=True)
62 jinja_logic_block_start = Unicode("((*", config=True)
63 jinja_logic_block_end = Unicode("*))", config=True)
64
65 #Extension that the template files use.
66 template_extension = Unicode(".tplx", config=True)
67
68 def _register_filters(self):
69 """
70 Register all of the filters required for the exporter.
71 """
72
73 #Register the filters of the base class.
74 super(LatexExporter, self)._register_filters()
75
76 #Add latex filters to the Jinja2 environment
77 self.register_filter('escape_tex', filters.escape_latex)
78 self.register_filter('highlight', filters.highlight2latex)
79
80
81 def _register_transformers(self):
82 """
83 Register all of the transformers needed for this exporter.
84 """
85
86 #Register the transformers of the base class.
87 super(LatexExporter, self)._register_transformers()
88
89 #Register latex transformer
90 self.register_transformer(transformers.LatexTransformer)
91
92 @property
93 def default_config(self):
94 c = Config({
95 'GlobalConfigurable': {
96 'display_data_priority' : ['latex', 'svg', 'png', 'jpg', 'jpeg' , 'text']
97 },
98 'ExtractFigureTransformer': {
99 'enabled':True,
100 'extra_ext_map':{'svg':'pdf'},
101 }
102 })
103 c.merge(super(LatexExporter,self).default_config)
104 return c
105
@@ -0,0 +1,35 b''
1 """
2 Exporter that will export your ipynb to Markdown.
3 """
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15
16 from IPython.utils.traitlets import Unicode
17
18 from .exporter import Exporter
19
20 #-----------------------------------------------------------------------------
21 # Classes
22 #-----------------------------------------------------------------------------
23
24 class MarkdownExporter(Exporter):
25 """
26 Exports to a markdown document (.md)
27 """
28
29 file_extension = Unicode(
30 'md', config=True,
31 help="Extension of the file that should be written to disk")
32
33 template_file = Unicode(
34 'markdown', config=True,
35 help="Name of the template file to use")
@@ -0,0 +1,35 b''
1 """
2 Python exporter which exports Notebook code into a PY file.
3 """
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15
16 from IPython.utils.traitlets import Unicode
17
18 from .exporter import Exporter
19
20 #-----------------------------------------------------------------------------
21 # Classes
22 #-----------------------------------------------------------------------------
23
24 class PythonExporter(Exporter):
25 """
26 Exports a Python code file.
27 """
28
29 file_extension = Unicode(
30 'py', config=True,
31 help="Extension of the file that should be written to disk")
32
33 template_file = Unicode(
34 'python', config=True,
35 help="Name of the template file to use")
@@ -0,0 +1,32 b''
1 """
2 Exporter that exports a Python-Armor code file (.py)
3 """
4
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 from IPython.utils.traitlets import Unicode
18
19 from .python import PythonExporter
20
21 #-----------------------------------------------------------------------------
22 # Classes
23 #-----------------------------------------------------------------------------
24
25 class PythonArmorExporter(PythonExporter):
26 """
27 Exports a Python-Armor code file (.py)
28 """
29
30 template_file = Unicode(
31 'python_armor', config=True,
32 help="Name of the template file to use")
@@ -0,0 +1,54 b''
1 """
2 Reveal slide show exporter.
3 """
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15
16 from IPython.utils.traitlets import Unicode
17 from IPython.config import Config
18
19 from .basichtml import BasicHtmlExporter
20 from IPython.nbconvert import transformers
21
22 #-----------------------------------------------------------------------------
23 # Classes
24 #-----------------------------------------------------------------------------
25
26 class RevealExporter(BasicHtmlExporter):
27 """
28 Exports a Reveal slide show (.HTML) which may be rendered in a web browser.
29 """
30
31 file_extension = Unicode(
32 'reveal.html', config=True,
33 help="Extension of the file that should be written to disk")
34
35 template_file = Unicode(
36 'reveal', config=True,
37 help="Name of the template file to use")
38
39 def _register_transformers(self):
40 """
41 Register all of the transformers needed for this exporter.
42 """
43
44 #Register the transformers of the base class.
45 super(RevealExporter, self)._register_transformers()
46
47 #Register reveal help transformer
48 self.register_transformer(transformers.RevealHelpTransformer)
49
50 @property
51 def default_config(self):
52 c = Config({'CSSHtmlHeaderTransformer':{'enabled':True}})
53 c.merge(super(RevealExporter,self).default_config)
54 return c
@@ -0,0 +1,42 b''
1 """
2 Exporter for exporting notebooks to restructured text.
3 """
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15
16 from IPython.utils.traitlets import Unicode
17 from IPython.config import Config
18
19 from .exporter import Exporter
20
21 #-----------------------------------------------------------------------------
22 # Classes
23 #-----------------------------------------------------------------------------
24
25 class RstExporter(Exporter):
26 """
27 Exports restructured text documents.
28 """
29
30 file_extension = Unicode(
31 'rst', config=True,
32 help="Extension of the file that should be written to disk")
33
34 template_file = Unicode(
35 'rst', config=True,
36 help="Name of the template file to use")
37
38 @property
39 def default_config(self):
40 c = Config({'ExtractFigureTransformer':{'enabled':True}})
41 c.merge(super(RstExporter,self).default_config)
42 return c
@@ -0,0 +1,54 b''
1 """
2 Exporter for exporting notebooks to Sphinx 'HowTo' style latex. Latex
3 formatted for use with PDFLatex.
4 """
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 from IPython.utils.traitlets import Unicode
18 from IPython.config import Config
19
20 # local import
21 from .latex import LatexExporter
22
23 from IPython.nbconvert import transformers
24
25 #-----------------------------------------------------------------------------
26 # Classes
27 #-----------------------------------------------------------------------------
28
29 class SphinxHowtoExporter(LatexExporter):
30 """
31 Exports Sphinx "HowTo" LaTeX documents. The Sphinx "HowTo" exporter
32 produces short document format latex for use with PDFLatex.
33 """
34
35 template_file = Unicode(
36 'sphinx_howto', config=True,
37 help="Name of the template file to use")
38
39 def _register_transformers(self):
40
41 #Register the transformers of the base class.
42 super(SphinxHowtoExporter, self)._register_transformers()
43
44 #Register sphinx latex transformer
45 self.register_transformer(transformers.SphinxTransformer)
46
47 @property
48 def default_config(self):
49 c = Config({
50 'SphinxTransformer': {'enabled':True}
51 })
52 c.merge(super(SphinxHowtoExporter,self).default_config)
53 return c
54
@@ -0,0 +1,34 b''
1 """
2 Exporter for exporting notebooks to Sphinx 'Manual' style latex. Latex
3 formatted for use with PDFLatex.
4 """
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 from IPython.utils.traitlets import Unicode
18
19 from .sphinx_howto import SphinxHowtoExporter
20
21 #-----------------------------------------------------------------------------
22 # Classes
23 #-----------------------------------------------------------------------------
24
25 class SphinxManualExporter(SphinxHowtoExporter):
26 """
27 Exports Sphinx "Manual" LaTeX documents. The Sphinx "Manual" exporter
28 produces book like latex output for use with PDFLatex.
29 """
30
31 template_file = Unicode(
32 'sphinx_manual', config=True,
33 help="Name of the template file to use")
34 No newline at end of file
@@ -0,0 +1,6 b''
1 from .ansi import *
2 from .datatypefilter import *
3 from .highlight import *
4 from .latex import *
5 from .markdown import *
6 from .strings import * No newline at end of file
@@ -0,0 +1,145 b''
1 """Filters for processing ANSI colors within Jinja templates.
2 """
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
5 #
6 # Distributed under the terms of the Modified BSD License.
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10
11 #-----------------------------------------------------------------------------
12 # Imports
13 #-----------------------------------------------------------------------------
14
15 import re
16 from IPython.utils import coloransi
17
18 #-----------------------------------------------------------------------------
19 # Classes and functions
20 #-----------------------------------------------------------------------------
21
22 __all__ = [
23 'remove_ansi',
24 'ansi2html',
25 'single_ansi2latex',
26 'ansi2latex'
27 ]
28
29 def remove_ansi(source):
30 """
31 Remove ansi from text
32
33 Parameters
34 ----------
35 source : str
36 Source to remove the ansi from
37 """
38
39 return re.sub(r'\033\[(0|\d;\d\d)m', '', source)
40
41
42 def ansi2html(text):
43 """
44 Conver ansi colors to html colors.
45
46 Parameters
47 ----------
48 text : str
49 Text containing ansi colors to convert to html
50 """
51
52 ansi_colormap = {
53 '30': 'ansiblack',
54 '31': 'ansired',
55 '32': 'ansigreen',
56 '33': 'ansiyellow',
57 '34': 'ansiblue',
58 '35': 'ansipurple',
59 '36': 'ansicyan',
60 '37': 'ansigrey',
61 '01': 'ansibold',
62 }
63
64 # do ampersand first
65 text = text.replace('&', '&')
66 html_escapes = {
67 '<': '&lt;',
68 '>': '&gt;',
69 "'": '&apos;',
70 '"': '&quot;',
71 '`': '&#96;',
72 }
73
74 for c, escape in html_escapes.iteritems():
75 text = text.replace(c, escape)
76
77 ansi_re = re.compile('\x1b' + r'\[([\dA-Fa-f;]*?)m')
78 m = ansi_re.search(text)
79 opened = False
80 cmds = []
81 opener = ''
82 closer = ''
83 while m:
84 cmds = m.groups()[0].split(';')
85 closer = '</span>' if opened else ''
86
87 # True if there is there more than one element in cmds, *or*
88 # if there is only one but it is not equal to a string of zeroes.
89 opened = len(cmds) > 1 or cmds[0] != '0' * len(cmds[0])
90 classes = []
91 for cmd in cmds:
92 if cmd in ansi_colormap:
93 classes.append(ansi_colormap.get(cmd))
94
95 if classes:
96 opener = '<span class="%s">' % (' '.join(classes))
97 else:
98 opener = ''
99 text = re.sub(ansi_re, closer + opener, text, 1)
100
101 m = ansi_re.search(text)
102
103 if opened:
104 text += '</span>'
105 return text
106
107
108 def single_ansi2latex(code):
109 """Converts single ansi markup to latex format
110
111 Return latex code and number of open brackets.
112 """
113 for color in coloransi.color_templates:
114 colcode = getattr(coloransi.TermColors,color[0])
115 # regular fonts
116 if code == colcode:
117 return '\\'+color[0].lower()+'{', 1
118 # bold fonts
119 if code == colcode[:3]+str(1)+colcode[3:]:
120 return '\\textbf{\\textcolor{'+color[0].lower()+'}{', 2
121 return '', 0
122
123 def ansi2latex(text):
124 """Converts ansi formated text to latex version
125
126 based on https://bitbucket.org/birkenfeld/sphinx-contrib/ansi.py
127 """
128 color_pattern = re.compile('\x1b\\[([^m]+)m')
129 last_end = 0
130 openbrack = 0
131 outstring = ''
132 for match in color_pattern.finditer(text):
133 head = text[last_end:match.start()]
134 outstring += head
135 if openbrack:
136 outstring += '}'*openbrack
137 openbrack = 0
138 if match.group() <> coloransi.TermColors.Normal and not openbrack:
139 texform, openbrack = single_ansi2latex(match.group())
140 outstring += texform
141 last_end = match.end()
142 if openbrack:
143 outstring += '}'*openbrack
144 outstring += text[last_end:]
145 return outstring.strip()
@@ -0,0 +1,33 b''
1 """Filter used to select the first preferred output format available.
2
3 The filter contained in the file allows the converter templates to select
4 the output format that is most valuable to the active export format. The
5 value of the different formats is set via
6 GlobalConfigurable.display_data_priority
7 """
8 #-----------------------------------------------------------------------------
9 # Copyright (c) 2013, the IPython Development Team.
10 #
11 # Distributed under the terms of the Modified BSD License.
12 #
13 # The full license is in the file COPYING.txt, distributed with this software.
14 #-----------------------------------------------------------------------------
15
16 #-----------------------------------------------------------------------------
17 # Classes and functions
18 #-----------------------------------------------------------------------------
19
20 from ..utils.config import GlobalConfigurable
21
22 __all__ = ['DataTypeFilter']
23
24 class DataTypeFilter(GlobalConfigurable):
25 """ Returns the preferred display format """
26
27 def __call__(self, output):
28 """ Return the first available format in the priority """
29
30 for fmt in self.display_data_priority:
31 if fmt in output:
32 return [fmt]
33 return []
@@ -0,0 +1,88 b''
1 """
2 Module containing filter functions that allow code to be highlighted
3 from within Jinja templates.
4 """
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 from pygments import highlight as pygements_highlight
18 from pygments.lexers import get_lexer_by_name
19 from pygments.formatters import HtmlFormatter
20 from pygments.formatters import LatexFormatter
21
22 # Our own imports
23 from IPython.nbconvert.utils.lexers import IPythonLexer
24
25 #-----------------------------------------------------------------------------
26 # Globals and constants
27 #-----------------------------------------------------------------------------
28
29 MULTILINE_OUTPUTS = ['text', 'html', 'svg', 'latex', 'javascript', 'json']
30
31 #-----------------------------------------------------------------------------
32 # Utility functions
33 #-----------------------------------------------------------------------------
34
35 __all__ = [
36 'highlight',
37 'highlight2latex'
38 ]
39
40
41 def highlight(source, language='ipython'):
42 """
43 Return a syntax-highlighted version of the input source as html output.
44
45 Parameters
46 ----------
47 source : str
48 Source code to highlight the syntax of.
49 language : str
50 Language to highlight the syntax of.
51 """
52
53 return _pygment_highlight(source, HtmlFormatter(), language)
54
55
56 def highlight2latex(source, language='ipython'):
57 """
58 Return a syntax-highlighted version of the input source as latex output.
59
60 Parameters
61 ----------
62 source : str
63 Source code to highlight the syntax of.
64 language : str
65 Language to highlight the syntax of.
66 """
67 return _pygment_highlight(source, LatexFormatter(), language)
68
69
70 def _pygment_highlight(source, output_formatter, language='ipython'):
71 """
72 Return a syntax-highlighted version of the input source
73
74 Parameters
75 ----------
76 source : str
77 Source code to highlight the syntax of.
78 output_formatter : Pygments formatter
79 language : str
80 Language to highlight the syntax of.
81 """
82
83 if language == 'ipython':
84 lexer = IPythonLexer()
85 else:
86 lexer = get_lexer_by_name(language, stripall=True)
87
88 return pygements_highlight(source, lexer, output_formatter)
@@ -0,0 +1,115 b''
1 """Latex filters.
2
3 Module of useful filters for processing Latex within Jinja latex templates.
4 """
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16 import re
17
18 #-----------------------------------------------------------------------------
19 # Globals and constants
20 #-----------------------------------------------------------------------------
21
22 #Latex substitutions for escaping latex.
23 LATEX_SUBS = (
24 (re.compile('\033\[[0-9;]+m'),''), # handle console escapes
25 (re.compile(r'\\'), r'\\textbackslash'),
26 (re.compile(r'([{}_#%&$])'), r'\\\1'),
27 (re.compile(r'~'), r'\~{}'),
28 (re.compile(r'\^'), r'\^{}'),
29 (re.compile(r'"'), r"''"),
30 (re.compile(r'\.\.\.+'), r'\\ldots'),
31 )
32
33 #-----------------------------------------------------------------------------
34 # Functions
35 #-----------------------------------------------------------------------------
36
37 __all__ = [
38 'escape_latex',
39 'rm_math_space'
40 ]
41
42
43 def escape_latex(text):
44 """
45 Escape characters that may conflict with latex.
46
47 Parameters
48 ----------
49 text : str
50 Text containing characters that may conflict with Latex
51 """
52 return_text = text
53 for pattern, replacement in LATEX_SUBS:
54 return_text = pattern.sub(replacement, return_text)
55 return return_text
56
57
58 def rm_math_space(text):
59 """
60 Remove the space between latex math commands and enclosing $ symbols.
61 This filter is important because latex isn't as flexible as the notebook
62 front end when it comes to flagging math using ampersand symbols.
63
64 Parameters
65 ----------
66 text : str
67 Text to filter.
68 """
69
70 # First, scan through the markdown looking for $. If
71 # a $ symbol is found, without a preceding \, assume
72 # it is the start of a math block. UNLESS that $ is
73 # not followed by another within two math_lines.
74 math_regions = []
75 math_lines = 0
76 within_math = False
77 math_start_index = 0
78 ptext = ''
79 last_character = ""
80 skip = False
81 for index, char in enumerate(text):
82
83 #Make sure the character isn't preceeded by a backslash
84 if (char == "$" and last_character != "\\"):
85
86 # Close the math region if this is an ending $
87 if within_math:
88 within_math = False
89 skip = True
90 ptext = ptext+'$'+text[math_start_index+1:index].strip()+'$'
91 math_regions.append([math_start_index, index+1])
92 else:
93
94 # Start a new math region
95 within_math = True
96 math_start_index = index
97 math_lines = 0
98
99 # If we are in a math region, count the number of lines parsed.
100 # Cancel the math region if we find two line breaks!
101 elif char == "\n":
102 if within_math:
103 math_lines += 1
104 if math_lines > 1:
105 within_math = False
106 ptext = ptext+text[math_start_index:index]
107
108 # Remember the last character so we can easily watch
109 # for backslashes
110 last_character = char
111 if not within_math and not skip:
112 ptext = ptext+char
113 if skip:
114 skip = False
115 return ptext
@@ -0,0 +1,85 b''
1 """Markdown filters
2 This file contains a collection of utility filters for dealing with
3 markdown within Jinja templates.
4 """
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
17
18 # Stdlib imports
19 import sys
20 import subprocess
21
22 #-----------------------------------------------------------------------------
23 # Functions
24 #-----------------------------------------------------------------------------
25
26 __all__ = [
27 'markdown2latex',
28 'markdown2rst'
29 ]
30
31
32 def markdown2latex(source):
33 """Convert a markdown string to LaTeX via pandoc.
34
35 This function will raise an error if pandoc is not installed.
36 Any error messages generated by pandoc are printed to stderr.
37
38 Parameters
39 ----------
40 source : string
41 Input string, assumed to be valid markdown.
42
43 Returns
44 -------
45 out : string
46 Output as returned by pandoc.
47 """
48 p = subprocess.Popen('pandoc -f markdown -t latex'.split(),
49 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
50
51 out, err = p.communicate(source.encode('utf-8'))
52
53 if err:
54 print(err, file=sys.stderr)
55 #print('*'*20+'\n', out, '\n'+'*'*20) # dbg
56
57 return unicode(out, 'utf-8')[:-1]
58
59
60 def markdown2rst(source):
61 """Convert a markdown string to LaTeX via pandoc.
62
63 This function will raise an error if pandoc is not installed.
64 Any error messages generated by pandoc are printed to stderr.
65
66 Parameters
67 ----------
68 source : string
69 Input string, assumed to be valid markdown.
70
71 Returns
72 -------
73 out : string
74 Output as returned by pandoc.
75 """
76 p = subprocess.Popen('pandoc -f markdown -t rst'.split(),
77 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
78
79 out, err = p.communicate(source.encode('utf-8'))
80
81 if err:
82 print(err, file=sys.stderr)
83 #print('*'*20+'\n', out, '\n'+'*'*20) # dbg
84
85 return unicode(out, 'utf-8')
@@ -0,0 +1,113 b''
1 """String filters.
2
3 Contains a collection of useful string manipulation filters for use in Jinja
4 templates.
5 """
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2013, the IPython Development Team.
8 #
9 # Distributed under the terms of the Modified BSD License.
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
13
14 #-----------------------------------------------------------------------------
15 # Imports
16 #-----------------------------------------------------------------------------
17
18 # Our own imports
19 import textwrap
20
21 #-----------------------------------------------------------------------------
22 # Functions
23 #-----------------------------------------------------------------------------
24
25 __all__ = [
26 'wrap',
27 'strip_dollars',
28 'rm_fake',
29 'python_comment',
30 'get_lines'
31 ]
32
33
34 def wrap(text, width=100):
35 """
36 Intelligently wrap text.
37 Wrap text without breaking words if possible.
38
39 Parameters
40 ----------
41 text : str
42 Text to wrap.
43 width : int, optional
44 Number of characters to wrap to, default 100.
45 """
46
47 split_text = text.split('\n')
48 wrp = map(lambda x:textwrap.wrap(x,width), split_text)
49 wrpd = map('\n'.join, wrp)
50 return '\n'.join(wrpd)
51
52
53 def strip_dollars(text):
54 """
55 Remove all dollar symbols from text
56
57 Parameters
58 ----------
59 text : str
60 Text to remove dollars from
61 """
62
63 return text.strip('$')
64
65
66 def rm_fake(text):
67 """
68 Remove all occurrences of '/files/' from text
69
70 Parameters
71 ----------
72 text : str
73 Text to remove '/files/' from
74 """
75 return text.replace('/files/', '')
76
77
78 def python_comment(text):
79 """
80 Build a Python comment line from input text.
81
82 Parameters
83 ----------
84 text : str
85 Text to comment out.
86 """
87
88 #Replace line breaks with line breaks and comment symbols.
89 #Also add a comment symbol at the beginning to comment out
90 #the first line.
91 return '# '+'\n# '.join(text.split('\n'))
92
93
94 def get_lines(text, start=None,end=None):
95 """
96 Split the input text into separate lines and then return the
97 lines that the caller is interested in.
98
99 Parameters
100 ----------
101 text : str
102 Text to parse lines from.
103 start : int, optional
104 First line to grab from.
105 end : int, optional
106 Last line to grab from.
107 """
108
109 # Split the input into lines.
110 lines = text.split("\n")
111
112 # Return the right lines.
113 return "\n".join(lines[start:end]) #re-join
@@ -0,0 +1,212 b''
1 #!/usr/bin/env python
2 """NBConvert is a utility for conversion of IPYNB files.
3
4 Commandline interface for the NBConvert conversion utility. Read the
5 readme.rst for usage information
6 """
7 #-----------------------------------------------------------------------------
8 #Copyright (c) 2013, the IPython Development Team.
9 #
10 #Distributed under the terms of the Modified BSD License.
11 #
12 #The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
14
15 #-----------------------------------------------------------------------------
16 #Imports
17 #-----------------------------------------------------------------------------
18
19 #Stdlib imports
20 from __future__ import print_function
21 import sys
22 import io
23 import os
24
25 #From IPython
26 from IPython.config.application import Application
27 from IPython.utils.traitlets import Bool
28
29 from .exporters.export import export_by_name
30 from .exporters.exporter import Exporter
31 from .transformers import extractfigure
32 from .utils.config import GlobalConfigurable
33
34 #-----------------------------------------------------------------------------
35 #Globals and constants
36 #-----------------------------------------------------------------------------
37
38 #'Keys in resources' user prompt.
39 KEYS_PROMPT_HEAD = "====================== Keys in Resources =================================="
40 KEYS_PROMPT_BODY = """
41 ===========================================================================
42 You are responsible for writting these files into the appropriate
43 directorie(s) if need be. If you do not want to see this message, enable
44 the 'write' (boolean) flag of the converter.
45 ===========================================================================
46 """
47
48 #-----------------------------------------------------------------------------
49 #Classes and functions
50 #-----------------------------------------------------------------------------
51
52 class NbConvertApp(Application):
53 """Application used to convert to and from notebook file type (*.ipynb)"""
54
55 stdout = Bool(
56 False, config=True,
57 help="""Whether to print the converted IPYNB file to stdout
58 use full do diff files without actually writing a new file"""
59 )
60
61 write = Bool(
62 True, config=True,
63 help="""Should the converted notebook file be written to disk
64 along with potential extracted resources."""
65 )
66
67 aliases = {
68 'stdout':'NbConvertApp.stdout',
69 'write':'NbConvertApp.write',
70 }
71
72 flags = {}
73
74 flags['stdout'] = (
75 {'NbConvertApp' : {'stdout' : True}},
76 """Print converted file to stdout, equivalent to --stdout=True
77 """
78 )
79
80 flags['no-write'] = (
81 {'NbConvertApp' : {'write' : True}},
82 """Do not write to disk, equivalent to --write=False
83 """
84 )
85
86
87 def __init__(self, **kwargs):
88 """Public constructor"""
89
90 #Call base class
91 super(NbConvertApp, self).__init__(**kwargs)
92
93 #Register class here to have help with help all
94 self.classes.insert(0, Exporter)
95 self.classes.insert(0, GlobalConfigurable)
96
97
98 def start(self, argv=None):
99 """Entrypoint of NbConvert application.
100
101 Parameters
102 ----------
103 argv : list
104 Commandline arguments
105 """
106
107 #Parse the commandline options.
108 self.parse_command_line(argv)
109
110 #Call base
111 super(NbConvertApp, self).start()
112
113 #The last arguments in list will be used by nbconvert
114 if len(self.extra_args) is not 3:
115 print( "Wrong number of arguments, use --help flag for usage", file=sys.stderr)
116 sys.exit(-1)
117 export_type = (self.extra_args)[1]
118 ipynb_file = (self.extra_args)[2]
119
120 #Export
121 return_value = export_by_name(export_type, ipynb_file)
122 if return_value is None:
123 print("Error: '%s' template not found." % export_type)
124 return
125 else:
126 (output, resources, exporter) = return_value
127
128 #TODO: Allow user to set output directory and file.
129 destination_filename = None
130 destination_directory = None
131 if self.write:
132
133 #Get the file name without the '.ipynb' (6 chars) extension and then
134 #remove any addition periods and spaces. The resulting name will
135 #be used to create the directory that the files will be exported
136 #into.
137 out_root = ipynb_file[:-6].replace('.', '_').replace(' ', '_')
138 destination_filename = os.path.join(out_root+'.'+exporter.file_extension)
139
140 destination_directory = out_root+'_files'
141 if not os.path.exists(destination_directory):
142 os.mkdir(destination_directory)
143
144 #Write the results
145 if self.stdout or not (destination_filename is None and destination_directory is None):
146 self._write_results(output, resources, destination_filename, destination_directory)
147
148
149 def _write_results(self, output, resources, destination_filename=None, destination_directory=None):
150 """Output the conversion results to the console and/or filesystem
151
152 Parameters
153 ----------
154 output : str
155 Output of conversion
156 resources : dictionary
157 Additional input/output used by the transformers. For
158 example, the ExtractFigure transformer outputs the
159 figures it extracts into this dictionary. This method
160 relies on the figures being in this dictionary when
161 attempting to write the figures to the file system.
162 destination_filename : str, Optional
163 Filename to write output into. If None, output is not
164 written to a file.
165 destination_directory : str, Optional
166 Directory to write notebook data (i.e. figures) to. If
167 None, figures are not written to the file system.
168 """
169
170 if self.stdout:
171 print(output.encode('utf-8'))
172
173 #Write file output from conversion.
174 if not destination_filename is None:
175 with io.open(destination_filename, 'w') as f:
176 f.write(output)
177
178 #Get the key names used by the extract figure transformer
179 figures_key = extractfigure.FIGURES_KEY
180 binary_key = extractfigure.BINARY_KEY
181 text_key = extractfigure.TEXT_KEY
182
183 #Output any associate figures into the same "root" directory.
184 binkeys = resources.get(figures_key, {}).get(binary_key,{}).keys()
185 textkeys = resources.get(figures_key, {}).get(text_key,{}).keys()
186 if binkeys or textkeys :
187 if not destination_directory is None:
188 for key in binkeys:
189 with io.open(os.path.join(destination_directory, key), 'wb') as f:
190 f.write(resources[figures_key][binary_key][key])
191 for key in textkeys:
192 with io.open(os.path.join(destination_directory, key), 'w') as f:
193 f.write(resources[figures_key][text_key][key])
194
195 #Figures that weren't exported which will need to be created by the
196 #user. Tell the user what figures these are.
197 if self.stdout:
198 print(KEYS_PROMPT_HEAD, file=sys.stderr)
199 print(resources[figures_key].keys(), file=sys.stderr)
200 print(KEYS_PROMPT_BODY , file=sys.stderr)
201
202 #-----------------------------------------------------------------------------
203 # Main entry point
204 #-----------------------------------------------------------------------------
205
206 def launch_new_instance():
207 """Application entry point"""
208
209 app = NbConvertApp.instance()
210 app.description = __doc__
211 app.start(argv=sys.argv)
212
@@ -0,0 +1,17 b''
1 {%- extends 'reveal_cells.tpl' -%}
2
3
4
5 {%- block any_cell scoped -%}
6 {%- if cell.metadata.align_type in ['Left'] -%}
7 {{ super() }}
8 {%- elif cell.metadata.align_type in ['center'] -%}
9 <div style="text-align:center">
10 {{ super() }}
11 </div>
12 {%- elif cell.metadata.align_type in ['right'] -%}
13 <div style="text-align:right">
14 {{ super() }}
15 </div>
16 {%- endif -%}
17 {%- endblock any_cell -%}
@@ -0,0 +1,143 b''
1 {%- extends 'display_priority.tpl' -%}
2
3
4
5 {% block codecell %}
6 <div class="cell border-box-sizing code_cell vbox">
7 {{ super() }}</div>
8 {%- endblock codecell %}
9
10 {% block input_group -%}
11 <div class="input hbox">
12 {{super()}}
13 </div>
14 {% endblock input_group %}
15
16 {% block output_group %}
17 <div class="vbox output_wrapper">
18 <div class="output vbox">
19 {{ super() }}
20 </div>
21 </div>
22 {% endblock output_group %}
23
24 {% block in_prompt -%}
25 <div class="prompt input_prompt">In&nbsp;[{{cell.prompt_number}}]:</div>
26 {%- endblock in_prompt %}
27
28 {#
29 output_prompt doesn't do anything in HTML,
30 because there is a prompt div in each output area (see output block)
31 #}
32 {% block output_prompt %}
33 {% endblock output_prompt %}
34
35 {% block input %}
36 <div class="input_area box-flex1">
37 {{cell.input | highlight }}
38 </div>
39 {%- endblock input %}
40
41 {% block output %}
42 <div class="hbox output_area">
43 {%- if output.output_type == 'pyout' -%}
44 <div class="prompt output_prompt">
45 Out[{{cell.prompt_number}}]:
46 {%- else -%}
47 <div class="prompt">
48 {%- endif -%}
49 </div>
50 {{ super() }}
51 </div>
52 {% endblock output %}
53
54 {% block markdowncell scoped %}
55 <div class="text_cell_render border-box-sizing rendered_html">
56 {{ cell.source | markdown| rm_fake}}
57 </div>
58 {%- endblock markdowncell %}
59
60 {% block headingcell scoped %}
61 <div class="text_cell_render border-box-sizing rendered_html">
62 <h{{cell.level}}>
63 {% set source = cell.source | replace(' ','_') %}
64 <a class="heading-anchor" id="{{source}}" href="#{{source}}">
65 {{cell.source}}
66 </a>
67 </h{{cell.level}}>
68 </div>
69 {% endblock headingcell %}
70
71 {% block rawcell scoped %}
72 {{ cell.source }}
73 {% endblock rawcell %}
74
75 {% block unknowncell scoped %}
76 unknown type {{cell.type}}
77 {% endblock unknowncell %}
78
79
80 {% block pyout -%}
81 <div class="box-flex1 output_subarea output_pyout">
82 {% block data_priority scoped %}{{ super()}}{% endblock %}
83 </div>
84 {%- endblock pyout %}
85
86 {% block stream_stdout -%}
87 <div class="box-flex1 output_subarea output_stream output_stdout">
88 <pre>{{output.text |ansi2html}}</pre>
89 </div>
90 {%- endblock stream_stdout %}
91
92 {% block stream_stderr -%}
93 <div class="box-flex1 output_subarea output_stream output_stderr">
94 <pre>{{output.text |ansi2html}}</pre>
95 </div>
96 {%- endblock stream_stderr %}
97
98 {% block data_svg -%}
99 {{output.svg}}
100 {%- endblock data_svg %}
101
102
103 {% block data_html -%}
104 <div class="output_html rendered_html">
105 {{output.html}}
106 </div>
107 {%- endblock data_html %}
108
109 {% block data_png %}
110 <img src="data:image/png;base64,{{output.png}}">
111 {%- endblock data_png %}
112
113
114 {% block data_jpg %}
115 <img src="data:image/jpeg;base64,{{output.jpeg}}">
116 {%- endblock data_jpg %}
117
118
119 {% block data_latex %}
120 {{output.latex}}
121 {%- endblock data_latex %}
122
123 {% block pyerr -%}
124 <div class="box-flex1 output_subarea output_pyerr">
125 <pre>{{super()}}</pre>
126 </div>
127 {%- endblock pyerr %}
128
129 {%- block traceback_line %}
130 {{line| ansi2html}}
131 {%- endblock traceback_line %}
132
133
134 {%- block data_text %}
135 <pre>{{output.text | ansi2html}}</pre>
136 {%- endblock -%}
137
138
139 {%- block display_data scoped -%}
140 <div class="box-flex1 output_subarea output_display_data">
141 {{super()}}
142 </div>
143 {%- endblock display_data -%}
@@ -0,0 +1,64 b''
1 {%- extends 'basichtml.tpl' -%}
2
3 {%- block header -%}<!DOCTYPE html>
4 <html>
5 <head>
6 <meta charset="UTF-8">
7 <title>[{{nb.metadata.name}}]</title>
8 {% for css in resources.inlining.css -%}
9 <style type="text/css">
10 {{css}}
11 </style>
12 {% endfor %}
13
14 <style type="text/css">
15 /* Overrides of notebook CSS for static HTML export */
16 body {
17 overflow: visible;
18 padding: 8px;
19 }
20 .input_area {
21 padding: 0.2em;
22 }
23
24 pre {
25 border: none;
26 margin: 0px;
27 font-size: 13px;
28 }
29 </style>
30
31 <script src="https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" type="text/javascript">
32
33 </script>
34 <script type="text/javascript">
35 init_mathjax = function() {
36 if (window.MathJax) {
37 // MathJax loaded
38 MathJax.Hub.Config({
39 tex2jax: {
40 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
41 displayMath: [ ['$$','$$'], ["\\[","\\]"] ]
42 },
43 displayAlign: 'left', // Change this to 'center' to center equations.
44 "HTML-CSS": {
45 styles: {'.MathJax_Display': {"margin": 0}}
46 }
47 });
48 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
49 }
50 }
51 init_mathjax();
52 </script>
53 </head>
54 {%- endblock header -%}
55
56
57 {% block body %}
58 <body>{{ super() }}
59 </body>
60 {%- endblock body %}
61
62
63 {% block footer %}
64 </html>{% endblock footer %}
@@ -0,0 +1,263 b''
1 ((*- extends 'display_priority.tplx' -*))
2
3 ((* block in_prompt *))((* endblock in_prompt *))
4
5 ((* block output_prompt *))((* endblock output_prompt *))
6
7 ((* block codecell *))\begin{codecell}((( super() )))
8 \end{codecell}
9 ((* endblock *))
10
11 ((* block input *))
12 \begin{codeinput}
13 \begin{lstlisting}
14 ((( cell.input )))
15 \end{lstlisting}
16 \end{codeinput}
17 ((* endblock input *))
18
19
20 ((= Those Two are for error displaying
21 even if the first one seem to do nothing,
22 it introduces a new line
23
24 =))
25 ((* block pyerr *))
26 \begin{traceback}
27 \begin{verbatim}((( super() )))
28 \end{verbatim}
29 \end{traceback}
30 ((* endblock pyerr *))
31
32 ((* block traceback_line *))
33 ((( line |indent| rm_ansi )))((* endblock traceback_line *))
34 ((= .... =))
35
36
37 ((*- block output_group -*))
38 \begin{codeoutput}
39 ((( super() )))
40 \end{codeoutput}((* endblock *))
41
42 ((*- block data_png -*))
43 \begin{center}
44 \includegraphics[width=0.7\textwidth, height=0.9\textheight, keepaspectratio]{(((output.key_png)))}
45 \par
46 \end{center}
47 ((*- endblock -*))
48
49 ((*- block data_jpg -*))
50 \begin{center}
51 \includegraphics[width=0.7\textwidth, height=0.9\textheight, keepaspectratio]{(((output.key_jpeg)))}
52 \par
53 \end{center}
54 ((*- endblock -*))
55
56 ((*- block data_svg -*))
57 \begin{center}
58 \includegraphics[width=0.7\textwidth]{(((output.key_svg)))}
59 \par
60 \end{center}
61 ((*- endblock -*))
62
63 ((* block pyout *))
64 ((* block data_priority scoped *))((( super() )))((* endblock *))
65 ((* endblock pyout *))
66
67 ((* block data_text *))
68 \begin{verbatim}
69 ((( output.text )))
70 \end{verbatim}
71 ((* endblock *))
72
73 ((* block data_latex -*))
74 ((*- if output.latex.startswith('$'): -*)) \begin{equation*}
75 ((( output.latex | rm_dollars)))
76 \end{equation*}
77 ((*- else -*)) ((( output.latex ))) ((*- endif *))
78 ((* endblock *))
79
80 ((* block stream *))
81 \begin{Verbatim}[commandchars=\\\{\}]
82 ((( output.text | ansi2latex)))
83 \end{Verbatim}
84 ((* endblock stream *))
85
86 ((* block markdowncell scoped *))((( cell.source | markdown2latex )))
87 ((* endblock markdowncell *))
88
89 ((* block headingcell scoped -*))
90 \
91 ((*- if cell.level == 1 -*))
92 ((* block h1 -*))section((* endblock h1 -*))
93 ((*- elif cell.level == 2 -*))
94 ((* block h2 -*))subsection((* endblock h2 -*))
95 ((*- elif cell.level == 3 -*))
96 ((* block h3 -*))subsubsection((* endblock h3 -*))
97 ((*- elif cell.level == 4 -*))
98 ((* block h4 -*))paragraph((* endblock h4 -*))
99 ((*- elif cell.level == 5 -*))
100 ((* block h5 -*))subparagraph((* endblock h5 -*))
101 ((*- elif cell.level == 6 -*))
102 ((* block h6 -*))subparagraph((* endblock h6 -*))
103 ((= 6th level not available in standard latex =))
104
105 ((*- endif -*)){((( cell.source | markdown2latex )))}
106 ((* endblock headingcell *))
107
108 ((* block rawcell scoped *))
109 ((( cell.source | pycomment )))
110 ((* endblock rawcell *))
111
112 ((* block unknowncell scoped *))
113 unknown type (((cell.type)))
114 ((* endblock unknowncell *))
115
116
117
118 ((* block body *))
119
120 ((* block bodyBegin *))
121 \begin{document}
122 ((* endblock bodyBegin *))
123
124 ((( super() )))
125
126 ((* block bodyEnd *))
127 \end{document}
128 ((* endblock bodyEnd *))
129 ((* endblock body *))
130
131 ((* block header *))
132 %% This file was auto-generated by IPython.
133 %% Conversion from the original notebook file:
134 %%
135 \documentclass[11pt,english]{article}
136
137 %% This is the automatic preamble used by IPython. Note that it does *not*
138 %% include a documentclass declaration, that is added at runtime to the overall
139 %% document.
140
141 \usepackage{amsmath}
142 \usepackage{amssymb}
143 \usepackage{graphicx}
144 \usepackage{ucs}
145 \usepackage[utf8x]{inputenc}
146
147 %fancy verbatim
148 \usepackage{fancyvrb}
149 % needed for markdown enumerations to work
150 \usepackage{enumerate}
151
152 % Slightly bigger margins than the latex defaults
153 \usepackage{geometry}
154 \geometry{verbose,tmargin=3cm,bmargin=3cm,lmargin=2.5cm,rmargin=2.5cm}
155
156 % Define a few colors for use in code, links and cell shading
157 \usepackage{color}
158 \definecolor{orange}{cmyk}{0,0.4,0.8,0.2}
159 \definecolor{darkorange}{rgb}{.71,0.21,0.01}
160 \definecolor{darkgreen}{rgb}{.12,.54,.11}
161 \definecolor{myteal}{rgb}{.26, .44, .56}
162 \definecolor{gray}{gray}{0.45}
163 \definecolor{lightgray}{gray}{.95}
164 \definecolor{mediumgray}{gray}{.8}
165 \definecolor{inputbackground}{rgb}{.95, .95, .85}
166 \definecolor{outputbackground}{rgb}{.95, .95, .95}
167 \definecolor{traceback}{rgb}{1, .95, .95}
168
169 % new ansi colors
170 \definecolor{brown}{rgb}{0.54,0.27,0.07}
171 \definecolor{purple}{rgb}{0.5,0.0,0.5}
172 \definecolor{darkgray}{gray}{0.25}
173 \definecolor{lightred}{rgb}{1.0,0.39,0.28}
174 \definecolor{lightgreen}{rgb}{0.48,0.99,0.0}
175 \definecolor{lightblue}{rgb}{0.53,0.81,0.92}
176 \definecolor{lightpurple}{rgb}{0.87,0.63,0.87}
177 \definecolor{lightcyan}{rgb}{0.5,1.0,0.83}
178
179 % Framed environments for code cells (inputs, outputs, errors, ...). The
180 % various uses of \unskip (or not) at the end were fine-tuned by hand, so don't
181 % randomly change them unless you're sure of the effect it will have.
182 \usepackage{framed}
183
184 % remove extraneous vertical space in boxes
185 \setlength\fboxsep{0pt}
186
187 % codecell is the whole input+output set of blocks that a Code cell can
188 % generate.
189
190 % TODO: unfortunately, it seems that using a framed codecell environment breaks
191 % the ability of the frames inside of it to be broken across pages. This
192 % causes at least the problem of having lots of empty space at the bottom of
193 % pages as new frames are moved to the next page, and if a single frame is too
194 % long to fit on a page, will completely stop latex from compiling the
195 % document. So unless we figure out a solution to this, we'll have to instead
196 % leave the codecell env. as empty. I'm keeping the original codecell
197 % definition here (a thin vertical bar) for reference, in case we find a
198 % solution to the page break issue.
199
200 %% \newenvironment{codecell}{%
201 %% \def\FrameCommand{\color{mediumgray} \vrule width 1pt \hspace{5pt}}%
202 %% \MakeFramed{\vspace{-0.5em}}}
203 %% {\unskip\endMakeFramed}
204
205 % For now, make this a no-op...
206 \newenvironment{codecell}{}
207
208 \newenvironment{codeinput}{%
209 \def\FrameCommand{\colorbox{inputbackground}}%
210 \MakeFramed{\advance\hsize-\width \FrameRestore}}
211 {\unskip\endMakeFramed}
212
213 \newenvironment{codeoutput}{%
214 \def\FrameCommand{\colorbox{outputbackground}}%
215 \vspace{-1.4em}
216 \MakeFramed{\advance\hsize-\width \FrameRestore}}
217 {\unskip\medskip\endMakeFramed}
218
219 \newenvironment{traceback}{%
220 \def\FrameCommand{\colorbox{traceback}}%
221 \MakeFramed{\advance\hsize-\width \FrameRestore}}
222 {\endMakeFramed}
223
224 % Use and configure listings package for nicely formatted code
225 \usepackage{listingsutf8}
226 \lstset{
227 language=python,
228 inputencoding=utf8x,
229 extendedchars=\true,
230 aboveskip=\smallskipamount,
231 belowskip=\smallskipamount,
232 xleftmargin=2mm,
233 breaklines=true,
234 basicstyle=\small \ttfamily,
235 showstringspaces=false,
236 keywordstyle=\color{blue}\bfseries,
237 commentstyle=\color{myteal},
238 stringstyle=\color{darkgreen},
239 identifierstyle=\color{darkorange},
240 columns=fullflexible, % tighter character kerning, like verb
241 }
242
243 % The hyperref package gives us a pdf with properly built
244 % internal navigation ('pdf bookmarks' for the table of contents,
245 % internal cross-reference links, web links for URLs, etc.)
246 \usepackage{hyperref}
247 \hypersetup{
248 breaklinks=true, % so long urls are correctly broken across lines
249 colorlinks=true,
250 urlcolor=blue,
251 linkcolor=darkorange,
252 citecolor=darkgreen,
253 }
254
255 % hardcode size of all verbatim environments to be a bit smaller
256 \makeatletter
257 \g@addto@macro\@verbatim\small\topsep=0.5em\partopsep=0pt
258 \makeatother
259
260 % Prevent overflowing lines due to urls and other hard-to-break entities.
261 \sloppy
262
263 ((* endblock *))
@@ -0,0 +1,39 b''
1 ((= autogenerated file do not edit =))
2 ((*- extends 'null.tplx' -*))
3
4 ((=display data priority=))
5
6
7 ((*- block data_priority scoped -*))
8 ((*- for type in output | filter_data_type -*))
9 ((*- if type in ['pdf']*))
10 ((*- block data_pdf -*))
11 ((*- endblock -*))
12 ((*- endif -*))
13 ((*- if type in ['svg']*))
14 ((*- block data_svg -*))
15 ((*- endblock -*))
16 ((*- endif -*))
17 ((*- if type in ['png']*))
18 ((*- block data_png -*))
19 ((*- endblock -*))
20 ((*- endif -*))
21 ((*- if type in ['html']*))
22 ((*- block data_html -*))
23 ((*- endblock -*))
24 ((*- endif -*))
25 ((*- if type in ['jpeg']*))
26 ((*- block data_jpg -*))
27 ((*- endblock -*))
28 ((*- endif -*))
29 ((*- if type in ['text']*))
30 ((*- block data_text -*))
31 ((*- endblock -*))
32 ((*- endif -*))
33
34 ((*- if type in ['latex']*))
35 ((*- block data_latex -*))
36 ((*- endblock -*))
37 ((*- endif -*))
38 ((*- endfor -*))
39 ((*- endblock data_priority -*))
@@ -0,0 +1,92 b''
1 ((= autogenerated file do not edit =))
2 ((=
3
4 DO NOT USE THIS AS A BASE WORK,
5 IF YOU ARE COPY AND PASTING THIS FILE
6 YOU ARE PROBABLY DOING THINGS WRONG.
7
8 Null template, Does nothing except defining a basic structure
9 To layout the different blocks of a notebook.
10
11 Subtemplates can override blocks to define their custom representation.
12
13 If one of the block you do overwrite is not a leave block, consider
14 calling super.
15
16 ((*- block nonLeaveBlock -*))
17 #add stuff at beginning
18 ((( super() )))
19 #add stuff at end
20 ((*- endblock nonLeaveBlock -*))
21
22 consider calling super even if it is a leave block, we might insert more blocks later.
23
24 =))
25 ((*- block header -*))
26 ((*- endblock header -*))
27 ((*- block body -*))
28 ((*- for worksheet in nb.worksheets -*))
29 ((*- for cell in worksheet.cells -*))
30 ((*- block any_cell scoped -*))
31 ((*- if cell.cell_type in ['code'] -*))
32 ((*- block codecell scoped -*))
33 ((*- block input_group -*))
34 ((*- block in_prompt -*))((*- endblock in_prompt -*))
35 ((*- block input -*))((*- endblock input -*))
36 ((*- endblock input_group -*))
37 ((*- if cell.outputs -*))
38 ((*- block output_group -*))
39 ((*- block output_prompt -*))((*- endblock output_prompt -*))
40 ((*- block outputs scoped -*))
41 ((*- for output in cell.outputs -*))
42 ((*- block output scoped -*))
43 ((*- if output.output_type in ['pyout'] -*))
44 ((*- block pyout scoped -*))((*- endblock pyout -*))
45 ((*- elif output.output_type in ['stream'] -*))
46 ((*- block stream scoped -*))
47 ((*- if output.stream in ['stdout'] -*))
48 ((*- block stream_stdout scoped -*))
49 ((*- endblock stream_stdout -*))
50 ((*- elif output.stream in ['stderr'] -*))
51 ((*- block stream_stderr scoped -*))
52 ((*- endblock stream_stderr -*))
53 ((*- endif -*))
54 ((*- endblock stream -*))
55 ((*- elif output.output_type in ['display_data'] -*))
56 ((*- block display_data scoped -*))
57 ((*- block data_priority scoped -*))
58 ((*- endblock data_priority -*))
59 ((*- endblock display_data -*))
60 ((*- elif output.output_type in ['pyerr'] -*))
61 ((*- block pyerr scoped -*))
62 ((*- for line in output.traceback -*))
63 ((*- block traceback_line scoped -*))((*- endblock traceback_line -*))
64 ((*- endfor -*))
65 ((*- endblock pyerr -*))
66 ((*- endif -*))
67 ((*- endblock output -*))
68 ((*- endfor -*))
69 ((*- endblock outputs -*))
70 ((*- endblock output_group -*))
71 ((*- endif -*))
72 ((*- endblock codecell -*))
73 ((*- elif cell.cell_type in ['markdown'] -*))
74 ((*- block markdowncell scoped-*))
75 ((*- endblock markdowncell -*))
76 ((*- elif cell.cell_type in ['heading'] -*))
77 ((*- block headingcell scoped-*))
78 ((*- endblock headingcell -*))
79 ((*- elif cell.cell_type in ['raw'] -*))
80 ((*- block rawcell scoped-*))
81 ((*- endblock rawcell -*))
82 ((*- else -*))
83 ((*- block unknowncell scoped-*))
84 ((*- endblock unknowncell -*))
85 ((*- endif -*))
86 ((*- endblock any_cell -*))
87 ((*- endfor -*))
88 ((*- endfor -*))
89 ((*- endblock body -*))
90
91 ((*- block footer -*))
92 ((*- endblock footer -*))
@@ -0,0 +1,442 b''
1 ((= NBConvert Sphinx-Latex Template
2
3 Purpose: Allow export of PDF friendly Latex inspired by Sphinx. Most of the
4 template is derived directly from Sphinx source.
5
6 Inheritance: null>display_priority
7
8 Note: For best display, use latex syntax highlighting. =))
9
10 ((*- extends 'display_priority.tplx' -*))
11
12 %==============================================================================
13 % Declarations
14 %==============================================================================
15
16 % In order to make sure that the input/output header follows the code it
17 % preceeds, the needspace package is used to request that a certain
18 % amount of lines (specified by this variable) are reserved. If those
19 % lines aren't available on the current page, the documenter will break
20 % to the next page and the header along with accomanying lines will be
21 % rendered together. This value specifies the number of lines that
22 % the header will be forced to group with without a page break.
23 ((*- set min_header_lines = 4 -*))
24
25 % This is the number of characters that are permitted per line. It's
26 % important that this limit is set so characters do not run off the
27 % edges of latex pages (since latex does not always seem smart enough
28 % to prevent this in some cases.) This is only applied to textual output
29 ((* if resources.sphinx.outputstyle == 'simple' *))
30 ((*- set wrap_size = 85 -*))
31 ((* elif resources.sphinx.outputstyle == 'notebook' *))
32 ((*- set wrap_size = 70 -*))
33 ((* endif *))
34
35 %==============================================================================
36 % Header
37 %==============================================================================
38 ((* block header *))
39
40 % Header, overrides base
41
42 % Make sure that the sphinx doc style knows who it inherits from.
43 \def\sphinxdocclass{(((parentdocumentclass)))}
44
45 % Declare the document class
46 \documentclass[letterpaper,10pt,english]{((( resources.sphinx.texinputs )))/sphinx(((documentclass)))}
47
48 % Imports
49 \usepackage[utf8]{inputenc}
50 \DeclareUnicodeCharacter{00A0}{\\nobreakspace}
51 \usepackage[T1]{fontenc}
52 \usepackage{babel}
53 \usepackage{times}
54 \usepackage{import}
55 \usepackage[((( resources.sphinx.chapterstyle )))]{((( resources.sphinx.texinputs )))/fncychap}
56 \usepackage{longtable}
57 \usepackage{((( resources.sphinx.texinputs )))/sphinx}
58 \usepackage{multirow}
59
60 \usepackage{amsmath}
61 \usepackage{amssymb}
62 \usepackage{ucs}
63 \usepackage{enumerate}
64
65 % Used to make the Input/Output rules follow around the contents.
66 \usepackage{needspace}
67
68 % Pygments requirements
69 \usepackage{fancyvrb}
70 \usepackage{color}
71 % ansi colors additions
72 \definecolor{darkgreen}{rgb}{.12,.54,.11}
73 \definecolor{lightgray}{gray}{.95}
74 \definecolor{brown}{rgb}{0.54,0.27,0.07}
75 \definecolor{purple}{rgb}{0.5,0.0,0.5}
76 \definecolor{darkgray}{gray}{0.25}
77 \definecolor{lightred}{rgb}{1.0,0.39,0.28}
78 \definecolor{lightgreen}{rgb}{0.48,0.99,0.0}
79 \definecolor{lightblue}{rgb}{0.53,0.81,0.92}
80 \definecolor{lightpurple}{rgb}{0.87,0.63,0.87}
81 \definecolor{lightcyan}{rgb}{0.5,1.0,0.83}
82
83 % Needed to box output/input
84 \usepackage{tikz}
85 \usetikzlibrary{calc,arrows,shadows}
86 \usepackage[framemethod=tikz]{mdframed}
87
88 \usepackage{alltt}
89
90 % Used to load and display graphics
91 \usepackage{graphicx}
92 \graphicspath{ {figs/} }
93 \usepackage[Export]{adjustbox} % To resize
94
95
96 % For formatting output while also word wrapping.
97 \usepackage{listings}
98 \lstset{breaklines=true}
99 \lstset{basicstyle=\small\ttfamily}
100 \def\smaller{\fontsize{9.5pt}{9.5pt}\selectfont}
101
102 %Pygments definitions
103 ((( resources.sphinx.pygment_definitions )))
104
105 %Set pygments styles if needed...
106 ((* if resources.sphinx.outputstyle == 'notebook' *))
107 \definecolor{nbframe-border}{rgb}{0.867,0.867,0.867}
108 \definecolor{nbframe-bg}{rgb}{0.969,0.969,0.969}
109 \definecolor{nbframe-in-prompt}{rgb}{0.0,0.0,0.502}
110 \definecolor{nbframe-out-prompt}{rgb}{0.545,0.0,0.0}
111
112 \newenvironment{ColorVerbatim}
113 {\begin{mdframed}[%
114 roundcorner=1.0pt, %
115 backgroundcolor=nbframe-bg, %
116 userdefinedwidth=1\linewidth, %
117 leftmargin=0.1\linewidth, %
118 innerleftmargin=0pt, %
119 innerrightmargin=0pt, %
120 linecolor=nbframe-border, %
121 linewidth=1pt, %
122 usetwoside=false, %
123 everyline=true, %
124 innerlinewidth=3pt, %
125 innerlinecolor=nbframe-bg, %
126 middlelinewidth=1pt, %
127 middlelinecolor=nbframe-bg, %
128 outerlinewidth=0.5pt, %
129 outerlinecolor=nbframe-border, %
130 needspace=0pt
131 ]}
132 {\end{mdframed}}
133
134 \newenvironment{InvisibleVerbatim}
135 {\begin{mdframed}[leftmargin=0.1\linewidth,innerleftmargin=3pt,innerrightmargin=3pt, userdefinedwidth=1\linewidth, linewidth=0pt, linecolor=white, usetwoside=false]}
136 {\end{mdframed}}
137
138 \renewenvironment{Verbatim}[1][\unskip]
139 {\begin{alltt}\smaller}
140 {\end{alltt}}
141 ((* endif *))
142
143 % Help prevent overflowing lines due to urls and other hard-to-break
144 % entities. This doesn't catch everything...
145 \sloppy
146
147 % Document level variables
148 \title{((( nb.metadata.name | escape_tex )))}
149 \date{((( nb.metadata._draft.date | escape_tex )))}
150 \release{((( nb.metadata._draft.version | escape_tex )))}
151 \author{((( nb.metadata._draft.author | escape_tex )))}
152 \renewcommand{\releasename}{((( nb.metadata._draft.release | escape_tex )))}
153
154 % TODO: Add option for the user to specify a logo for his/her export.
155 \newcommand{\sphinxlogo}{}
156
157 % Make the index page of the document.
158 \makeindex
159
160 % Import sphinx document type specifics.
161 ((* block sphinxheader *))((* endblock sphinxheader *))
162 ((* endblock header *))
163
164 %==============================================================================
165 % Body
166 %==============================================================================
167 ((* block body *))
168 ((* block bodyBegin *))
169 % Body
170
171 % Start of the document
172 \begin{document}
173
174 ((* if resources.sphinx.header *))
175 \maketitle
176 ((* endif *))
177
178 ((* block toc *))
179 \tableofcontents
180 ((* endblock toc *))
181
182 ((* endblock bodyBegin *))((( super() )))((* block bodyEnd *))
183
184 \renewcommand{\indexname}{Index}
185 \printindex
186
187 % End of document
188 \end{document}
189 ((* endblock bodyEnd *))
190 ((* endblock body *))
191
192 %==============================================================================
193 % Footer
194 %==============================================================================
195 ((* block footer *))
196 ((* endblock footer *))
197
198 %==============================================================================
199 % Headings
200 %
201 % Purpose: Format pynb headers as sphinx headers. Depending on the Sphinx
202 % style that is active, this will change. Thus sphinx styles will
203 % override the values here.
204 %==============================================================================
205 ((* block headingcell -*))
206 \
207 ((*- if cell.level == 1 -*))
208 ((* block h1 -*))part((* endblock h1 -*))
209 ((*- elif cell.level == 2 -*))
210 ((* block h2 -*))chapter((* endblock h2 -*))
211 ((*- elif cell.level == 3 -*))
212 ((* block h3 -*))section((* endblock h3 -*))
213 ((*- elif cell.level == 4 -*))
214 ((* block h4 -*))subsection((* endblock h4 -*))
215 ((*- elif cell.level == 5 -*))
216 ((* block h5 -*))subsubsection((* endblock h5 -*))
217 ((*- elif cell.level == 6 -*))
218 ((* block h6 -*))paragraph((* endblock h6 -*))
219
220 ((= It's important to make sure that underscores (which tend to be common
221 in IPYNB file titles) do not make their way into latex. Sometimes this
222 causes latex to barf. =))
223 ((*- endif -*)){((( cell.source | markdown2latex )))}
224 ((*- endblock headingcell *))
225
226 %==============================================================================
227 % Markdown
228 %
229 % Purpose: Convert markdown to latex. Here markdown2latex is explicitly
230 % called since we know we want latex output.
231 %==============================================================================
232 ((*- block markdowncell scoped-*))
233 ((( cell.source | markdown2latex )))
234 ((*- endblock markdowncell -*))
235
236 %==============================================================================
237 % Rawcell
238 %
239 % Purpose: Raw text cells allow the user to manually inject document code that
240 % will not get touched by the templating system.
241 %==============================================================================
242 ((*- block rawcell *))
243 ((( cell.source | wrap(wrap_size) )))
244 ((* endblock rawcell -*))
245
246 %==============================================================================
247 % Unknowncell
248 %
249 % Purpose: This is the catch anything unhandled. To display this data, we
250 % remove all possible latex conflicts and wrap the characters so they
251 % can't flow off of the page.
252 %==============================================================================
253 ((* block unknowncell scoped*))
254
255 % Unsupported cell type, no formatting
256 ((( cell.source | wrap | escape_tex )))
257 ((* endblock unknowncell *))
258
259 %==============================================================================
260 % Input
261 %==============================================================================
262 ((* block input *))
263
264 % Make sure that atleast 4 lines are below the HR
265 \needspace{((( min_header_lines )))\baselineskip}
266
267 ((* if resources.sphinx.outputstyle == 'simple' *))
268
269 % Add a horizantal break, along with break title.
270 \vspace{10pt}
271 {\scriptsize Input}\\*
272 \rule[10pt]{\linewidth}{0.5pt}
273 \vspace{-25pt}
274
275 % Add contents below.
276 ((( cell.input | highlight )))
277
278 ((* elif resources.sphinx.outputstyle == 'notebook' *))
279 \vspace{6pt}
280 ((( write_prompt("In", cell.prompt_number, "nbframe-in-prompt") )))
281 \vspace{-2.65\baselineskip}
282 \begin{ColorVerbatim}
283 \vspace{-0.7\baselineskip}
284 ((( cell.input | highlight )))
285 ((* if cell.input == None or cell.input == '' *))
286 \vspace{0.3\baselineskip}
287 ((* else *))
288 \vspace{-0.2\baselineskip}
289 ((* endif *))
290 \end{ColorVerbatim}
291 ((* endif *))
292 ((* endblock input *))
293
294 %==============================================================================
295 % Output_Group
296 %
297 % Purpose: Make sure that only one header bar only attaches to the output
298 % once. By keeping track of when an input group is started
299 %==============================================================================
300 ((* block output_group *))
301 ((* if cell.outputs.__len__() > 0 *))
302
303 % If the first block is an image, minipage the image. Else
304 % request a certain amount of space for the input text.
305 ((( iff_figure(cell.outputs[0], "\\begin{minipage}{1.0\\textwidth}", "\\needspace{" ~ min_header_lines ~ "\\baselineskip}") )))
306
307 ((* if resources.sphinx.outputstyle == 'simple' *))
308
309 % Add a horizantal break, along with break title.
310 \vspace{10pt}
311 {\scriptsize Output}\\*
312 \rule[10pt]{\linewidth}{0.5pt}
313 \vspace{-20pt}
314
315 % Add the contents of the first block.
316 ((( render_output(cell.outputs[0]) )))
317
318 % Close the minipage.
319 ((( iff_figure(cell.outputs[0], "\\end{minipage}", "") )))
320
321 % Add remainer of the document contents below.
322 ((* for output in cell.outputs[1:] *))
323 ((( render_output(output, cell.prompt_number) )))
324 ((* endfor *))
325 ((* elif resources.sphinx.outputstyle == 'notebook' *))
326
327 % Add document contents.
328 ((* for output in cell.outputs *))
329 ((( render_output(output, cell.prompt_number) )))
330 ((* endfor *))
331 ((* endif *))
332 ((* endif *))
333 ((* endblock *))
334
335 %==============================================================================
336 % Additional formating
337 %==============================================================================
338 ((* block data_text *))
339 ((( custom_verbatim(output.text) | ansi2latex)))
340 ((* endblock *))
341
342 ((* block traceback_line *))
343 ((( conditionally_center_output(line | indent| rm_ansi) )))
344 ((* endblock traceback_line *))
345
346 %==============================================================================
347 % Supported image formats
348 %==============================================================================
349 ((*- block data_png -*))
350 ((( conditionally_center_output(insert_graphics(output.key_png)) )))
351 ((*- endblock -*))
352
353 ((*- block data_svg -*))
354 ((( conditionally_center_output(insert_graphics(output.key_svg)) )))
355 ((*- endblock -*))
356
357 ((*- block data_latex *))
358 ((* if resources.sphinx.centeroutput *))\begin{center}((* endif -*))((( output.latex | rm_math_space )))((*- if resources.sphinx.centeroutput *))\end{center} ((* endif -*))
359 ((*- endblock -*))
360
361 %==============================================================================
362 % Support Macros
363 %==============================================================================
364
365 % Name: write_prompt
366 % Purpose: Renders an output/input prompt for notebook style pdfs
367 ((* macro write_prompt(prompt, number, color) -*))
368 \makebox[0.1\linewidth]{\smaller\hfill\tt\color{((( color )))}((( prompt )))\hspace{4pt}{[}((( number ))){]}:\hspace{4pt}}\\*
369 ((*- endmacro *))
370
371 % Name: render_output
372 % Purpose: Renders an output block appropriately.
373 ((* macro render_output(output, prompt_number) -*))
374 ((*- if output.output_type == 'pyerr' -*))
375 ((*- block pyerr scoped *))
376 ((( custom_verbatim(super()) )))
377 ((* endblock pyerr -*))
378 ((*- else -*))
379
380 ((* if resources.sphinx.outputstyle == 'notebook' *))
381 ((*- if output.output_type == 'pyout' -*))
382 ((( write_prompt("Out", prompt_number, "nbframe-out-prompt") )))
383 \vspace{-2.55\baselineskip}
384 ((*- endif -*))
385
386 \begin{InvisibleVerbatim}
387 \vspace{-0.5\baselineskip}
388 ((*- endif -*))
389
390 ((*- block display_data scoped -*))
391 ((( super() )))
392 ((*- endblock display_data -*))
393
394 ((* if resources.sphinx.outputstyle == 'notebook' *))
395 \end{InvisibleVerbatim}
396 ((*- endif -*))
397 ((*- endif -*))
398 ((*- endmacro *))
399
400 % Name: iff_figure
401 % Purpose: If the output block provided is a figure type, the 'true_content'
402 % parameter will be returned. Else, the 'false_content'.
403 ((* macro iff_figure(output, true_content, false_content) -*))
404 ((*- set is_figure = false -*))
405 ((*- for type in output | filter_data_type -*))
406 ((*- if type in ['pdf', 'svg', 'png', 'jpeg','html']*))
407 ((*- set is_figure = true -*))
408 ((*- endif -*))
409 ((*- endfor -*))
410
411 ((* if is_figure -*))
412 ((( true_content )))
413 ((*- else -*))
414 ((( false_content )))
415 ((*- endif *))
416 ((*- endmacro *))
417
418 % Name: custom_verbatim
419 % Purpose: This macro creates a verbatim style block that fits the existing
420 % sphinx style more readily than standard verbatim blocks.
421 ((* macro custom_verbatim(text) -*))
422 \begin{alltt}
423 ((*- if resources.sphinx.centeroutput *))\begin{center} ((* endif -*))
424 ((( text | wrap(wrap_size) )))
425 ((*- if resources.sphinx.centeroutput *))\end{center}((* endif -*))
426 \end{alltt}
427 ((*- endmacro *))
428
429 % Name: conditionally_center_output
430 % Purpose: This macro centers the output if the output centering is enabled.
431 ((* macro conditionally_center_output(text) -*))
432 ((* if resources.sphinx.centeroutput *)){\centering ((* endif *))((( text )))((* if resources.sphinx.centeroutput *))}((* endif *))
433 ((*- endmacro *))
434
435 % Name: insert_graphics
436 % Purpose: This macro will insert an image in the latex document given a path.
437 ((* macro insert_graphics(path) -*))
438 \begin{center}
439 \includegraphics[max size={\textwidth}{\textheight}]{(((path)))}
440 \par
441 \end{center}
442 ((*- endmacro *))
@@ -0,0 +1,25 b''
1 ((============================================================================
2 NBConvert Sphinx-Latex HowTo Template
3
4 Purpose: Allow export of PDF friendly Latex inspired by Sphinx HowTo
5 document style. Most of the is derived directly from Sphinx source.
6
7 Inheritance: null>display_priority>latex_base->latex_sphinx_base
8
9 ==========================================================================))
10
11 ((*- extends 'sphinx_base.tplx' -*))
12
13 ((* set parentdocumentclass = 'article' *))
14 ((* set documentclass = 'howto' *))
15
16 ((* block h1 -*))part((* endblock h1 -*))
17 ((* block h2 -*))section((* endblock h2 -*))
18 ((* block h3 -*))subsection((* endblock h3 -*))
19 ((* block h4 -*))subsubsection((* endblock h4 -*))
20 ((* block h5 -*))paragraph((* endblock h5 -*))
21 ((* block h6 -*))subparagraph((* endblock h6 -*))
22
23 % Diasble table of contents for howto
24 ((* block toc *))
25 ((* endblock toc *))
@@ -0,0 +1,21 b''
1 ((============================================================================
2 NBConvert Sphinx-Latex Manual Template
3
4 Purpose: Allow export of PDF friendly Latex inspired by Sphinx Manual
5 document style. Most of the is derived directly from Sphinx source.
6
7 Inheritance: null>display_priority>latex_base->latex_sphinx_base
8
9 ==========================================================================))
10
11 ((*- extends 'sphinx_base.tplx' -*))
12
13 ((* set parentdocumentclass = 'report' *))
14 ((* set documentclass = 'manual' *))
15
16 ((* block h1 -*))part((* endblock h1 -*))
17 ((* block h2 -*))chapter((* endblock h2 -*))
18 ((* block h3 -*))section((* endblock h3 -*))
19 ((* block h4 -*))subsection((* endblock h4 -*))
20 ((* block h5 -*))subsubsection((* endblock h5 -*))
21 ((* block h6 -*))paragraph((* endblock h6 -*))
@@ -0,0 +1,73 b''
1 {% extends 'display_priority.tpl' %}
2 {% block in_prompt %}
3 In[{{cell.prompt_number if cell.prompt_number else ' '}}]:{% endblock in_prompt %}
4
5 {% block output_prompt %}{% if cell.haspyout %}Out[{{cell.prompt_number}}]:
6 {%- endif %}{%- endblock output_prompt %}
7
8 {% block input %}
9 ```
10 {{ cell.input}}
11 ```
12 {% endblock input %}
13
14 {% block pyerr %}
15 {{ super() }}
16 {% endblock pyerr %}
17
18 {% block traceback_line %}
19 {{ line |indent| rm_ansi }}{% endblock traceback_line %}
20
21 {% block pyout %}
22 {% block data_priority scoped %}{{ super()}}{% endblock %}
23 {% endblock pyout %}
24
25 {% block stream %}
26 {{ output.text| indent }}
27 {% endblock stream %}
28
29
30
31
32 {% block data_svg %}
33 [!image]({{output.key_svg}})
34 {% endblock data_svg %}
35
36 {% block data_png %}
37 [!image]({{output.key_png}})
38 {% endblock data_png %}
39
40 {% block data_jpg %}
41 [!image]({{output.key_jpg}})
42 {% endblock data_jpg %}
43
44
45
46 {% block data_latex %}
47 $$
48 {{output.latex}}
49 $$
50 {% endblock data_latex %}
51
52 {% block data_text scoped %}
53
54 {{output.text | indent}}
55
56 {% endblock data_text %}
57
58 {% block markdowncell scoped %}
59 {{ cell.source | wrap(80)}}
60 {% endblock markdowncell %}
61
62 {% block headingcell scoped %}
63
64 {{ '#' * cell.level }} {{ cell.source}}
65
66 {% endblock headingcell %}
67
68 {% block rawcell scoped %}{{ cell.source }}
69 {% endblock rawcell %}
70
71 {% block unknowncell scoped %}
72 unknown type {{cell.type}}
73 {% endblock unknowncell %}
@@ -0,0 +1,56 b''
1 {%- extends 'null.tpl' -%}
2
3 {% block in_prompt %}
4 # In[{{cell.prompt_number if cell.prompt_number else ' '}}]:
5 {% endblock in_prompt %}
6
7 {% block output_prompt %}
8 # Out[{{cell.prompt_number}}]:{% endblock output_prompt %}
9
10 {% block input %}{{ cell.input }}
11 {% endblock input %}
12
13
14 {# Those Two are for error displaying
15 even if the first one seem to do nothing,
16 it introduces a new line
17
18 #}
19 {% block pyerr %}{{ super() }}
20 {% endblock pyerr %}
21
22 {% block traceback_line %}
23 {{ line |indent| rm_ansi }}{% endblock traceback_line %}
24 {# .... #}
25
26
27 {% block pyout %}
28 {{ output.text| indent | pycomment}}
29 {% endblock pyout %}
30
31 {% block stream %}
32 {{ output.text| indent | pycomment}}
33 {% endblock stream %}
34
35
36
37
38 {% block display_data scoped %}
39 # image file:
40 {% endblock display_data %}
41
42 {% block markdowncell scoped %}
43 {{ cell.source | pycomment }}
44 {% endblock markdowncell %}
45
46 {% block headingcell scoped %}
47 {{ '#' * cell.level }}{{ cell.source | pycomment}}
48 {% endblock headingcell %}
49
50 {% block rawcell scoped %}
51 {{ cell.source | pycomment }}
52 {% endblock rawcell %}
53
54 {% block unknowncell scoped %}
55 unknown type {{cell.type}}
56 {% endblock unknowncell %}
@@ -0,0 +1,31 b''
1 {%- extends 'python.tpl' -%}
2
3 {#% block any_cell %}
4 ==============================
5 =======start {{cell.type}}=========
6 {{ super() }}
7 ======= end {{cell.type}} =========
8 =============================={% endblock any_cell %#}
9
10
11
12 {% block markdowncell %}---- Start MD ----{{ super() }}
13 ---- End MD ----
14 {% endblock markdowncell %}
15
16 {% block codecell %}---- Start Code ----{{ super() }}
17 ---- End Code ----
18 {% endblock codecell %}
19
20 {% block headingcell scoped %}---- Start heading ----{{ super() }}
21 ---- End heading ----
22 {% endblock headingcell %}
23
24 {% block rawcell scoped %}---- Start Raw ----
25 {{ super() }}
26 ---- End Raw ----{% endblock rawcell %}
27
28 {% block unknowncell scoped %}
29 unknown type {{cell.type}}
30 {% endblock unknowncell %}
31
@@ -0,0 +1,180 b''
1 {%- extends 'slides.tpl' -%}
2
3
4 {% block header %}
5 <!DOCTYPE html>
6 <html>
7 <head>
8
9 <meta charset="utf-8" />
10 <meta http-equiv="X-UA-Compatible" content="chrome=1">
11
12 <meta name="apple-mobile-web-app-capable" content="yes" />
13 <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
14
15 <link rel="stylesheet" href="reveal.js/css/reveal.css">
16 <link rel="stylesheet" href="reveal.js/css/theme/simple.css" id="theme">
17
18 <!-- For syntax highlighting -->
19 <link rel="stylesheet" href="reveal.js/lib/css/zenburn.css">
20
21 <!-- If the query includes 'print-pdf', use the PDF print sheet -->
22 <script>
23 document.write( '<link rel="stylesheet" href="reveal.js/css/print/' + ( window.location.search.match( /print-pdf/gi ) ? 'pdf' : 'paper' ) + '.css" type="text/css" media="print">' );
24 </script>
25
26 <!--[if lt IE 9]>
27 <script src="reveal.js/lib/js/html5shiv.js"></script>
28 <![endif]-->
29
30 {% for css in resources.inlining.css -%}
31 <style type="text/css">
32 {{css}}
33 </style>
34 {% endfor %}
35
36 <style type="text/css">
37 /* Overrides of notebook CSS for static HTML export */
38 .reveal {
39 font-size: 20px;
40 overflow-y: auto;
41 overflow-x: hidden;
42 }
43 .reveal pre {
44 width: 95%;
45 padding: 0.4em;
46 margin: 0px;
47 font-family: monospace, sans-serif;
48 font-size: 80%;
49 box-shadow: 0px 0px 0px rgba(0, 0, 0, 0);
50 }
51 .reveal section img {
52 border: 0px solid black;
53 box-shadow: 0 0 10px rgba(0, 0, 0, 0);
54 }
55 .reveal .slides {
56 text-align: left;
57 }
58 .reveal.fade {
59 opacity: 1;
60 }
61 div.input_area {
62 padding: 0.06em;
63 }
64 div.code_cell {
65 background-color: transparent;
66 }
67 div.prompt {
68 width: 11ex;
69 padding: 0.4em;
70 margin: 0px;
71 font-family: monospace, sans-serif;
72 font-size: 80%;
73 text-align: right;
74 }
75 div.output_area pre {
76 font-family: monospace, sans-serif;
77 font-size: 80%;
78 }
79 div.output_prompt {
80 /* 5px right shift to account for margin in parent container */
81 margin: 5px 5px 0 -5px;
82 }
83 .rendered_html p {
84 text-align: inherit;
85 }
86 </style>
87 </head>
88 {% endblock header%}
89
90
91 {% block body %}
92 <body>
93 <div class="reveal"><div class="slides">
94
95 {{ super() }}
96
97 </div></div>
98
99 <!--
100 Uncomment the following block and the addthis_widget.js (see below inside dependencies)
101 to get enable social buttons.
102 -->
103
104 <!--
105 <div class="addthis_toolbox addthis_floating_style addthis_32x32_style" style="left:20px;top:20px;">
106 <a class="addthis_button_twitter"></a>
107 <a class="addthis_button_google_plusone_share"></a>
108 <a class="addthis_button_linkedin"></a>
109 <a class="addthis_button_facebook"></a>
110 <a class="addthis_button_more"></a>
111 </div>
112 -->
113
114 <script src="reveal.js/lib/js/head.min.js"></script>
115
116 <script src="reveal.js/js/reveal.min.js"></script>
117
118 <script>
119
120 // Full list of configuration options available here: https://github.com/hakimel/reveal.js#configuration
121 Reveal.initialize({
122 controls: true,
123 progress: true,
124 history: true,
125
126 theme: Reveal.getQueryHash().theme, // available themes are in /css/theme
127 transition: Reveal.getQueryHash().transition || 'linear', // default/cube/page/concave/zoom/linear/none
128
129 // Optional libraries used to extend on reveal.js
130 dependencies: [
131 { src: 'reveal.js/lib/js/classList.js', condition: function() { return !document.body.classList; } },
132 { src: 'reveal.js/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
133 { src: 'reveal.js/plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }
134 // { src: 'http://s7.addthis.com/js/300/addthis_widget.js', async: true},
135 ]
136 });
137 </script>
138
139 <!-- MathJax configuration -->
140 <script type="text/x-mathjax-config">
141 MathJax.Hub.Config({
142 tex2jax: {
143 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
144 displayMath: [ ['$$','$$'], ["\\[","\\]"] ]
145 },
146 displayAlign: 'left', // Change this to 'center' to center equations.
147 "HTML-CSS": {
148 styles: {'.MathJax_Display': {"margin": 0}}
149 }
150 });
151 </script>
152 <!-- End of mathjax configuration -->
153
154 <script>
155 // We wait for the onload function to load MathJax after the page is completely loaded.
156 // MathJax is loaded 1 unit of time after the page is ready.
157 // This hack prevent problems when you load multiple js files (i.e. social button from addthis).
158 //
159 window.onload = function () {
160 setTimeout(function () {
161 var script = document.createElement("script");
162 script.type = "text/javascript";
163 script.src = "https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS_HTML";
164 document.getElementsByTagName("head")[0].appendChild(script);
165 },1)
166 }
167 </script>
168
169 <script>
170 Reveal.addEventListener( 'slidechanged', function( event ) {
171 MathJax.Hub.Rerender(event.currentSlide);
172 });
173 </script>
174
175 </body>
176 {% endblock body %}
177
178 {% block footer %}
179 </html>
180 {% endblock footer %}
@@ -0,0 +1,21 b''
1 {%- extends 'basichtml.tpl' -%}
2
3
4
5 {%- block any_cell scoped -%}
6 {%- if cell.metadata.slide_type in ['-', 'slide', 'subslide'] -%}
7 {{ super() }}
8 {%- elif cell.metadata.slide_type in ['skip'] -%}
9 <div style=display:none>
10 {{ super() }}
11 </div>
12 {%- elif cell.metadata.slide_type in ['notes'] -%}
13 <aside class="notes">
14 {{ super() }}
15 </aside>
16 {%- elif cell.metadata.slide_type in ['fragment'] -%}
17 <div class="fragment">
18 {{ super() }}
19 </div>
20 {%- endif -%}
21 {%- endblock any_cell -%}
@@ -0,0 +1,89 b''
1 {%- extends 'display_priority.tpl' -%}
2 {% block in_prompt -%}
3 In[{{cell.prompt_number if cell.prompt_number else ' '}}]:
4
5 .. code:: python
6
7 {% endblock in_prompt %}
8
9 {% block output_prompt %}{% if cell.haspyout -%}
10 Out[{{cell.prompt_number}}]:{% endif %}{% endblock output_prompt %}
11
12 {% block input %}{{ cell.input | indent}}
13
14 {% endblock input %}
15
16 {% block pyerr %}::
17 {{ super() }}
18 {% endblock pyerr %}
19
20 {% block traceback_line %}
21 {{ line |indent| rm_ansi }}{% endblock traceback_line %}
22
23 {% block pyout %}
24 {% block data_priority scoped %}{{ super()}}{% endblock %}
25 {% endblock pyout %}
26
27 {% block stream %}
28 .. parsed-literal::
29
30 {{ output.text| indent }}
31 {% endblock stream %}
32
33
34
35
36 {% block data_svg %}.. image:: {{output.key_svg}}
37
38 {% endblock data_svg %}
39
40 {% block data_png %}.. image:: {{output.key_png}}
41
42 {% endblock data_png %}
43
44 {% block data_jpg %}..jpg image:: {{output.key_jpg}}
45
46 {% endblock data_jpg %}
47
48
49
50 {% block data_latex %}.. math::
51
52 {{output.latex| indent}}
53
54 {% endblock data_latex %}
55
56 {% block data_text scoped %}.. parsed-literal::
57
58 {{output.text | indent}}
59
60 {% endblock data_text %}
61
62 {% block markdowncell scoped %}{{ cell.source | markdown2rst }}
63 {% endblock markdowncell %}
64
65 {% block headingcell scoped %}
66 {%- set len = cell.source|length -%}
67 {{ cell.source}}
68 {% if cell.level == 1 %}
69 {{- '=' * len }}
70 {%- elif cell.level == 2 %}
71 {{- '-' * len }}
72 {%- elif cell.level == 3 %}
73 {{- '~' * len }}
74 {%- elif cell.level == 4 %}
75 {{- '.' * len }}
76 {%- elif cell.level == 5 %}
77 {{- '\\' * len }}
78 {%- elif cell.level == 6 %}
79 {{- '`' * len }}
80 {% endif %}
81
82 {% endblock headingcell %}
83
84 {% block rawcell scoped %}{{ cell.source }}
85 {% endblock rawcell %}
86
87 {% block unknowncell scoped %}
88 unknown type {{cell.type}}
89 {% endblock unknowncell %}
@@ -0,0 +1,23 b''
1
2
3 all: tex/null.tplx tex/display_priority.tplx
4
5 # convert jinja syntax to tex
6 # cf http://flask.pocoo.org/snippets/55/
7 tex/%.tplx: %.tpl
8 @echo 'generating tex equivalent of $^: $@'
9 @echo '((= autogenerated file do not edit =))' > $@
10 @sed \
11 -e 's/{%/((*/g' \
12 -e 's/%}/*))/g' \
13 -e 's/{{/(((/g' \
14 -e 's/}}/)))/g' \
15 -e 's/{#/((=/g' \
16 -e 's/#}/=))/g' \
17 -e "s/tpl'/tplx'/g" \
18 $^ >> $@
19
20
21 clean:
22 @echo "cleaning generated tplx files..."
23 @rm tex/*
@@ -0,0 +1,6 b''
1 ## Template skeleton
2
3 This contain skeleton template that you probably don't want
4 to inherit directly.
5
6 do not moify the content of the 'tex' folder which is generated by running 'make' in this folder.
@@ -0,0 +1,38 b''
1 {%- extends 'null.tpl' -%}
2
3 {#display data priority#}
4
5
6 {%- block data_priority scoped -%}
7 {%- for type in output | filter_data_type -%}
8 {%- if type in ['pdf']%}
9 {%- block data_pdf -%}
10 {%- endblock -%}
11 {%- endif -%}
12 {%- if type in ['svg']%}
13 {%- block data_svg -%}
14 {%- endblock -%}
15 {%- endif -%}
16 {%- if type in ['png']%}
17 {%- block data_png -%}
18 {%- endblock -%}
19 {%- endif -%}
20 {%- if type in ['html']%}
21 {%- block data_html -%}
22 {%- endblock -%}
23 {%- endif -%}
24 {%- if type in ['jpeg']%}
25 {%- block data_jpg -%}
26 {%- endblock -%}
27 {%- endif -%}
28 {%- if type in ['text']%}
29 {%- block data_text -%}
30 {%- endblock -%}
31 {%- endif -%}
32
33 {%- if type in ['latex']%}
34 {%- block data_latex -%}
35 {%- endblock -%}
36 {%- endif -%}
37 {%- endfor -%}
38 {%- endblock data_priority -%}
@@ -0,0 +1,91 b''
1 {#
2
3 DO NOT USE THIS AS A BASE WORK,
4 IF YOU ARE COPY AND PASTING THIS FILE
5 YOU ARE PROBABLY DOING THINGS WRONG.
6
7 Null template, Does nothing except defining a basic structure
8 To layout the different blocks of a notebook.
9
10 Subtemplates can override blocks to define their custom representation.
11
12 If one of the block you do overwrite is not a leave block, consider
13 calling super.
14
15 {%- block nonLeaveBlock -%}
16 #add stuff at beginning
17 {{ super() }}
18 #add stuff at end
19 {%- endblock nonLeaveBlock -%}
20
21 consider calling super even if it is a leave block, we might insert more blocks later.
22
23 #}
24 {%- block header -%}
25 {%- endblock header -%}
26 {%- block body -%}
27 {%- for worksheet in nb.worksheets -%}
28 {%- for cell in worksheet.cells -%}
29 {%- block any_cell scoped -%}
30 {%- if cell.cell_type in ['code'] -%}
31 {%- block codecell scoped -%}
32 {%- block input_group -%}
33 {%- block in_prompt -%}{%- endblock in_prompt -%}
34 {%- block input -%}{%- endblock input -%}
35 {%- endblock input_group -%}
36 {%- if cell.outputs -%}
37 {%- block output_group -%}
38 {%- block output_prompt -%}{%- endblock output_prompt -%}
39 {%- block outputs scoped -%}
40 {%- for output in cell.outputs -%}
41 {%- block output scoped -%}
42 {%- if output.output_type in ['pyout'] -%}
43 {%- block pyout scoped -%}{%- endblock pyout -%}
44 {%- elif output.output_type in ['stream'] -%}
45 {%- block stream scoped -%}
46 {%- if output.stream in ['stdout'] -%}
47 {%- block stream_stdout scoped -%}
48 {%- endblock stream_stdout -%}
49 {%- elif output.stream in ['stderr'] -%}
50 {%- block stream_stderr scoped -%}
51 {%- endblock stream_stderr -%}
52 {%- endif -%}
53 {%- endblock stream -%}
54 {%- elif output.output_type in ['display_data'] -%}
55 {%- block display_data scoped -%}
56 {%- block data_priority scoped -%}
57 {%- endblock data_priority -%}
58 {%- endblock display_data -%}
59 {%- elif output.output_type in ['pyerr'] -%}
60 {%- block pyerr scoped -%}
61 {%- for line in output.traceback -%}
62 {%- block traceback_line scoped -%}{%- endblock traceback_line -%}
63 {%- endfor -%}
64 {%- endblock pyerr -%}
65 {%- endif -%}
66 {%- endblock output -%}
67 {%- endfor -%}
68 {%- endblock outputs -%}
69 {%- endblock output_group -%}
70 {%- endif -%}
71 {%- endblock codecell -%}
72 {%- elif cell.cell_type in ['markdown'] -%}
73 {%- block markdowncell scoped-%}
74 {%- endblock markdowncell -%}
75 {%- elif cell.cell_type in ['heading'] -%}
76 {%- block headingcell scoped-%}
77 {%- endblock headingcell -%}
78 {%- elif cell.cell_type in ['raw'] -%}
79 {%- block rawcell scoped-%}
80 {%- endblock rawcell -%}
81 {%- else -%}
82 {%- block unknowncell scoped-%}
83 {%- endblock unknowncell -%}
84 {%- endif -%}
85 {%- endblock any_cell -%}
86 {%- endfor -%}
87 {%- endfor -%}
88 {%- endblock body -%}
89
90 {%- block footer -%}
91 {%- endblock footer -%}
@@ -0,0 +1,17 b''
1 {%- extends 'subslides.tpl' -%}
2
3
4
5 {%- block any_cell scoped -%}
6 {%- if cell.metadata.slide_type in ['slide'] -%}
7 <section>
8 <section>
9 {%- endif -%}
10
11 {{ super() }}
12
13 {%- if cell.metadata.slide_helper in ['slide_end'] -%}
14 </section>
15 </section>
16 {%- endif -%}
17 {%- endblock any_cell -%}
@@ -0,0 +1,15 b''
1 {%- extends 'align_reveal_cells.tpl' -%}
2
3
4
5 {%- block any_cell scoped -%}
6 {%- if cell.metadata.slide_type in ['subslide'] -%}
7 <section>
8 {%- endif -%}
9
10 {{ super() }}
11
12 {%- if cell.metadata.slide_helper in ['subslide_end'] -%}
13 </section>
14 {%- endif -%}
15 {%- endblock any_cell -%}
@@ -0,0 +1,9 b''
1 # Class base Transformers
2 from .activatable import ActivatableTransformer
3 from .base import ConfigurableTransformer
4 from .extractfigure import ExtractFigureTransformer
5 from .latex import LatexTransformer
6 from .sphinx import SphinxTransformer
7
8 # decorated function Transformers
9 from .coalescestreams import coalesce_streams
@@ -0,0 +1,53 b''
1 """
2 Contains base transformer with an enable/disable flag.
3 """
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15
16 from .base import ConfigurableTransformer
17 from IPython.utils.traitlets import (Bool)
18
19 #-----------------------------------------------------------------------------
20 # Classes and Functions
21 #-----------------------------------------------------------------------------
22
23 class ActivatableTransformer(ConfigurableTransformer):
24 """ConfigurableTransformer that has an enabled flag
25
26 Inherit from this if you just want to have a transformer which is
27 disable by default and can be enabled via the config by
28 'c.YourTransformerName.enabled = True'
29 """
30
31 enabled = Bool(False, config=True)
32
33 def __call__(self, nb, resources):
34 """
35 Transformation to apply on each notebook.
36
37 You should return modified nb, resources.
38 If you wish to apply your transform on each cell, you might want to
39 overwrite cell_transform method instead.
40
41 Parameters
42 ----------
43 nb : NotebookNode
44 Notebook being converted
45 resources : dictionary
46 Additional resources used in the conversion process. Allows
47 transformers to pass variables into the Jinja engine.
48 """
49
50 if not self.enabled :
51 return nb, resources
52 else :
53 return super(ActivatableTransformer, self).__call__(nb, resources)
@@ -0,0 +1,99 b''
1 """
2 Module that re-groups transformer that would be applied to ipynb files
3 before going through the templating machinery.
4
5 It exposes a convenient class to inherit from to access configurability.
6 """
7 #-----------------------------------------------------------------------------
8 # Copyright (c) 2013, the IPython Development Team.
9 #
10 # Distributed under the terms of the Modified BSD License.
11 #
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
14
15 #-----------------------------------------------------------------------------
16 # Imports
17 #-----------------------------------------------------------------------------
18
19 from ..utils.config import GlobalConfigurable
20
21 #-----------------------------------------------------------------------------
22 # Classes and Functions
23 #-----------------------------------------------------------------------------
24
25 class ConfigurableTransformer(GlobalConfigurable):
26 """ A configurable transformer
27
28 Inherit from this class if you wish to have configurability for your
29 transformer.
30
31 Any configurable traitlets this class exposed will be configurable in profiles
32 using c.SubClassName.atribute=value
33
34 you can overwrite cell_transform to apply a transformation independently on each cell
35 or __call__ if you prefer your own logic. See corresponding docstring for informations.
36 """
37
38 def __init__(self, config=None, **kw):
39 """
40 Public constructor
41
42 Parameters
43 ----------
44 config : Config
45 Configuration file structure
46 **kw : misc
47 Additional arguments
48 """
49
50 super(ConfigurableTransformer, self).__init__(config=config, **kw)
51
52
53 def __call__(self, nb, resources):
54 return self.call(nb,resources)
55
56 def call(self, nb, resources):
57 """
58 Transformation to apply on each notebook.
59
60 You should return modified nb, resources.
61 If you wish to apply your transform on each cell, you might want to
62 overwrite cell_transform method instead.
63
64 Parameters
65 ----------
66 nb : NotebookNode
67 Notebook being converted
68 resources : dictionary
69 Additional resources used in the conversion process. Allows
70 transformers to pass variables into the Jinja engine.
71 """
72 try :
73 for worksheet in nb.worksheets :
74 for index, cell in enumerate(worksheet.cells):
75 worksheet.cells[index], resources = self.cell_transform(cell, resources, index)
76 return nb, resources
77 except NotImplementedError:
78 raise NotImplementedError('should be implemented by subclass')
79
80
81 def cell_transform(self, cell, resources, index):
82 """
83 Overwrite if you want to apply a transformation on each cell. You
84 should return modified cell and resource dictionary.
85
86 Parameters
87 ----------
88 cell : NotebookNode cell
89 Notebook cell being processed
90 resources : dictionary
91 Additional resources used in the conversion process. Allows
92 transformers to pass variables into the Jinja engine.
93 index : int
94 Index of the cell being processed
95 """
96
97 raise NotImplementedError('should be implemented by subclass')
98 return cell, resources
99
@@ -0,0 +1,75 b''
1 """Module that allows latex output notebooks to be conditioned before
2 they are converted. Exposes a decorator (@cell_preprocessor) in
3 addition to the coalesce_streams pre-proccessor.
4 """
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Functions
15 #-----------------------------------------------------------------------------
16
17 def cell_preprocessor(function):
18 """
19 Wrap a function to be executed on all cells of a notebook
20
21 Wrapped Parameters
22 ----------
23 cell : NotebookNode cell
24 Notebook cell being processed
25 resources : dictionary
26 Additional resources used in the conversion process. Allows
27 transformers to pass variables into the Jinja engine.
28 index : int
29 Index of the cell being processed
30 """
31
32 def wrappedfunc(nb, resources):
33 for worksheet in nb.worksheets :
34 for index, cell in enumerate(worksheet.cells):
35 worksheet.cells[index], resources = function(cell, resources, index)
36 return nb, resources
37 return wrappedfunc
38
39
40 @cell_preprocessor
41 def coalesce_streams(cell, resources, index):
42 """
43 Merge consecutive sequences of stream output into single stream
44 to prevent extra newlines inserted at flush calls
45
46 Parameters
47 ----------
48 cell : NotebookNode cell
49 Notebook cell being processed
50 resources : dictionary
51 Additional resources used in the conversion process. Allows
52 transformers to pass variables into the Jinja engine.
53 index : int
54 Index of the cell being processed
55 """
56
57 outputs = cell.get('outputs', [])
58 if not outputs:
59 return cell, resources
60
61 last = outputs[0]
62 new_outputs = [last]
63
64 for output in outputs[1:]:
65 if (output.output_type == 'stream' and
66 last.output_type == 'stream' and
67 last.stream == output.stream
68 ):
69 last.text += output.text
70 else:
71 new_outputs.append(output)
72
73 cell.outputs = new_outputs
74 return cell, resources
75
@@ -0,0 +1,105 b''
1 """Module that pre-processes the notebook for export to HTML.
2 """
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
5 #
6 # Distributed under the terms of the Modified BSD License.
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10
11 #-----------------------------------------------------------------------------
12 # Imports
13 #-----------------------------------------------------------------------------
14
15 import os
16 import io
17
18 from pygments.formatters import HtmlFormatter
19
20 from IPython.utils import path
21
22 from .activatable import ActivatableTransformer
23
24 #-----------------------------------------------------------------------------
25 # Classes and functions
26 #-----------------------------------------------------------------------------
27
28 class CSSHtmlHeaderTransformer(ActivatableTransformer):
29 """
30 Transformer used to pre-process notebook for HTML output. Adds IPython notebook
31 front-end CSS and Pygments CSS to HTML output.
32 """
33
34 header = []
35
36 def __init__(self, config=None, **kw):
37 """
38 Public constructor
39
40 Parameters
41 ----------
42 config : Config
43 Configuration file structure
44 **kw : misc
45 Additional arguments
46 """
47
48 super(CSSHtmlHeaderTransformer, self).__init__(config=config, **kw)
49
50 if self.enabled :
51 self._regen_header()
52
53
54 def __call__(self, nb, resources):
55 """Fetch and add CSS to the resource dictionary
56
57 Fetch CSS from IPython and Pygments to add at the beginning
58 of the html files. Add this css in resources in the
59 "inlining.css" key
60
61 Parameters
62 ----------
63 nb : NotebookNode
64 Notebook being converted
65 resources : dictionary
66 Additional resources used in the conversion process. Allows
67 transformers to pass variables into the Jinja engine.
68 """
69
70 resources['inlining'] = {}
71 resources['inlining']['css'] = self.header
72
73 return nb, resources
74
75
76 def _regen_header(self):
77 """
78 Fills self.header with lines of CSS extracted from IPython
79 and Pygments.
80 """
81
82 #Clear existing header.
83 header = []
84
85 #Construct path to IPy CSS
86 sheet_filename = os.path.join(path.get_ipython_package_dir(),
87 'html', 'static', 'style', 'style.min.css')
88
89 #Load style CSS file.
90 try:
91 with io.open(sheet_filename, encoding='utf-8') as file:
92 file_text = file.read()
93 header.append(file_text)
94 except IOError:
95
96 # New version of IPython with style.min.css, pass
97 pass
98
99 #Add pygments CSS
100 pygments_css = HtmlFormatter().get_style_defs('.highlight')
101 header.append(pygments_css)
102
103 #Set header
104 self.header = header
105
@@ -0,0 +1,143 b''
1 """Module containing a transformer that extracts all of the figures from the
2 notebook file. The extracted figures are returned in the 'resources' dictionary.
3 """
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15 import itertools
16
17 from IPython.utils.traitlets import Dict, Unicode
18 from .activatable import ActivatableTransformer
19
20 #-----------------------------------------------------------------------------
21 # Constants
22 #-----------------------------------------------------------------------------
23
24 FIGURES_KEY = "figures"
25 BINARY_KEY = "binary"
26 TEXT_KEY = "text"
27
28 #-----------------------------------------------------------------------------
29 # Classes
30 #-----------------------------------------------------------------------------
31
32 class ExtractFigureTransformer(ActivatableTransformer):
33 """
34 Extracts all of the figures from the notebook file. The extracted
35 figures are returned in the 'resources' dictionary.
36 """
37
38 extra_extension_map = Dict({},
39 config=True,
40 help="""Extra map to override extension based on type.
41 Useful for latex where SVG will be converted to PDF before inclusion
42 """)
43
44 key_format_map = Dict({}, config=True,)
45 figure_name_format_map = Dict({}, config=True)
46
47 #TODO: Change this to .format {} syntax
48 default_key_template = Unicode('_fig_{index:02d}.{ext}', config=True)
49
50 def __init__(self, config=None, **kw):
51 """
52 Public constructor
53
54 Parameters
55 ----------
56 config : Config
57 Configuration file structure
58 **kw : misc
59 Additional arguments
60 """
61
62 super(ExtractFigureTransformer, self).__init__(config=config, **kw)
63
64 # A unique index for association with extracted figures
65 self.index_generator = itertools.count(1)
66
67 def cell_transform(self, cell, resources, index):
68 """
69 Apply a transformation on each cell,
70
71 Parameters
72 ----------
73 cell : NotebookNode cell
74 Notebook cell being processed
75 resources : dictionary
76 Additional resources used in the conversion process. Allows
77 transformers to pass variables into the Jinja engine.
78 index : int
79 Index of the cell being processed (see base.py)
80 """
81
82 if resources.get(FIGURES_KEY, None) is None :
83 resources[FIGURES_KEY] = {TEXT_KEY:{},BINARY_KEY:{}}
84
85 for out in cell.get('outputs', []):
86 for out_type in self.display_data_priority:
87
88 if out.hasattr(out_type):
89 figname, key, data, binary = self._new_figure(out[out_type], out_type)
90 out['key_'+out_type] = figname
91
92 if binary :
93 resources[FIGURES_KEY][BINARY_KEY][key] = data
94 else :
95 resources[FIGURES_KEY][TEXT_KEY][key] = data
96
97 index += 1
98 return cell, resources
99
100
101 def _get_override_extension(self, extension):
102 """Gets the overriden extension if it exists, else returns extension.
103
104 Parameters
105 ----------
106 extension : str
107 File extension.
108 """
109
110 if extension in self.extra_extension_map :
111 return self.extra_extension_map[extension]
112
113 return extension
114
115
116 def _new_figure(self, data, format):
117 """Create a new figure file in the given format.
118
119 Parameters
120 ----------
121 data : str
122 Cell data (from Notebook node cell)
123 format : str
124 Figure format
125 index : int
126 Index of the figure being extracted
127 """
128
129 figure_name_template = self.figure_name_format_map.get(format, self.default_key_template)
130 key_template = self.key_format_map.get(format, self.default_key_template)
131
132 #TODO: option to pass the hash as data?
133 index = next(self.index_generator)
134 figure_name = figure_name_template.format(index=index, ext=self._get_override_extension(format))
135 key = key_template.format(index=index, ext=self._get_override_extension(format))
136
137 #Binary files are base64-encoded, SVG is already XML
138 binary = False
139 if format in ('png', 'jpg', 'pdf'):
140 data = data.decode('base64')
141 binary = True
142
143 return figure_name, key, data, binary
@@ -0,0 +1,53 b''
1 """Module that allows latex output notebooks to be conditioned before
2 they are converted.
3 """
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15
16 from __future__ import print_function, absolute_import
17
18 # Our own imports
19 # Needed to override transformer
20 from .activatable import (ActivatableTransformer)
21 from IPython.nbconvert import filters
22
23 #-----------------------------------------------------------------------------
24 # Classes
25 #-----------------------------------------------------------------------------
26
27 class LatexTransformer(ActivatableTransformer):
28 """
29 Converter for latex destined documents.
30 """
31
32 def cell_transform(self, cell, resources, index):
33 """
34 Apply a transformation on each cell,
35
36 Parameters
37 ----------
38 cell : NotebookNode cell
39 Notebook cell being processed
40 resources : dictionary
41 Additional resources used in the conversion process. Allows
42 transformers to pass variables into the Jinja engine.
43 index : int
44 Modified index of the cell being processed (see base.py)
45 """
46
47 #If the cell is a markdown cell, preprocess the ampersands used to
48 #remove the space between them and their contents. Latex will complain
49 #if spaces exist between the ampersands and the math content.
50 #See filters.latex.rm_math_space for more information.
51 if hasattr(cell, "source") and cell.cell_type == "markdown":
52 cell.source = filters.rm_math_space(cell.source)
53 return cell, resources
@@ -0,0 +1,52 b''
1 """Module that pre-processes the notebook for export via Reveal.
2 """
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
5 #
6 # Distributed under the terms of the Modified BSD License.
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10
11 #-----------------------------------------------------------------------------
12 # Imports
13 #-----------------------------------------------------------------------------
14
15 from .base import ConfigurableTransformer
16
17 #-----------------------------------------------------------------------------
18 # Classes and functions
19 #-----------------------------------------------------------------------------
20
21 class RevealHelpTransformer(ConfigurableTransformer):
22
23 def call(self, nb, resources):
24 """
25 Called once to 'transform' contents of the notebook.
26
27 Parameters
28 ----------
29 nb : NotebookNode
30 Notebook being converted
31 resources : dictionary
32 Additional resources used in the conversion process. Allows
33 transformers to pass variables into the Jinja engine.
34 """
35
36
37 for worksheet in nb.worksheets :
38 for i, cell in enumerate(worksheet.cells):
39
40 #Make sure the cell has slideshow metadata.
41 cell.metadata.align_type = cell.get('metadata', {}).get('slideshow', {}).get('align_type', 'Left')
42 cell.metadata.slide_type = cell.get('metadata', {}).get('slideshow', {}).get('slide_type', '-')
43
44 #Get the slide type. If type is start of subslide or slide,
45 #end the last subslide/slide.
46 if cell.metadata.slide_type in ['slide']:
47 worksheet.cells[i - 1].metadata.slide_helper = 'slide_end'
48 if cell.metadata.slide_type in ['subslide']:
49 worksheet.cells[i - 1].metadata.slide_helper = 'subslide_end'
50
51 return nb, resources
52 No newline at end of file
@@ -0,0 +1,261 b''
1 """Module that allows custom Sphinx parameters to be set on the notebook and
2 on the 'other' object passed into Jinja. Called prior to Jinja conversion
3 process.
4 """
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 from __future__ import print_function, absolute_import
18
19 # Stdlib imports
20 # Used to find Sphinx package location
21 import sphinx
22 import os.path
23
24 # Used to set the default date to today's date
25 from datetime import date
26
27 # Third-party imports
28 # Needed for Pygments latex definitions.
29 from pygments.formatters import LatexFormatter
30
31 # Our own imports
32 # Configurable traitlets
33 from IPython.utils.traitlets import Unicode, Bool
34
35 # Needed to override transformer
36 from .activatable import (ActivatableTransformer) #TODO
37
38 from IPython.nbconvert.utils import console
39
40 #-----------------------------------------------------------------------------
41 # Classes and functions
42 #-----------------------------------------------------------------------------
43
44 class SphinxTransformer(ActivatableTransformer):
45 """
46 Sphinx utility transformer.
47
48 This transformer is used to set variables needed by the latex to build
49 Sphinx stylized templates.
50 """
51
52 interactive = Bool(False, config=True, help="""
53 Allows you to define whether or not the Sphinx exporter will prompt
54 you for input during the conversion process. If this is set to false,
55 the author, version, release, date, and chapter_style traits should
56 be set.
57 """)
58
59 author = Unicode("Unknown Author", config=True, help="Author name")
60
61 version = Unicode("", config=True, help="""
62 Version number
63 You can leave this blank if you do not want to render a version number.
64 Example: "1.0.0"
65 """)
66
67 release = Unicode("", config=True, help="""
68 Release name
69 You can leave this blank if you do not want to render a release name.
70 Example: "Rough Draft"
71 """)
72
73 publish_date = Unicode("", config=True, help="""
74 Publish date
75 This is the date to render on the document as the publish date.
76 Leave this blank to default to todays date.
77 Example: "June 12, 1990"
78 """)
79
80 chapter_style = Unicode("Bjarne", config=True, help="""
81 Sphinx chapter style
82 This is the style to use for the chapter headers in the document.
83 You may choose one of the following:
84 "Bjarne" (default)
85 "Lenny"
86 "Glenn"
87 "Conny"
88 "Rejne"
89 "Sonny" (used for international documents)
90 """)
91
92 output_style = Unicode("notebook", config=True, help="""
93 Nbconvert Ipython
94 notebook input/output formatting style.
95 You may choose one of the following:
96 "simple (recommended for long code segments)"
97 "notebook" (default)
98 """)
99
100 center_output = Bool(False, config=True, help="""
101 Optional attempt to center all output. If this is false, no additional
102 formatting is applied.
103 """)
104
105 use_headers = Bool(True, config=True, help="""
106 Whether not a header should be added to the document.
107 """)
108
109 #Allow the user to override the title of the notebook (useful for
110 #fancy document titles that the file system doesn't support.)
111 overridetitle = Unicode("", config=True, help="")
112
113
114 def call(self, nb, resources):
115 """
116 Sphinx transformation to apply on each notebook.
117
118 Parameters
119 ----------
120 nb : NotebookNode
121 Notebook being converted
122 resources : dictionary
123 Additional resources used in the conversion process. Allows
124 transformers to pass variables into the Jinja engine.
125 """
126
127 # TODO: Add versatile method of additional notebook metadata. Include
128 # handling of multiple files. For now use a temporay namespace,
129 # '_draft' to signify that this needs to change.
130 if not "_draft" in nb.metadata:
131 nb.metadata._draft = {}
132
133 if not "sphinx" in resources:
134 resources["sphinx"] = {}
135
136 if self.interactive:
137
138 # Prompt the user for additional meta data that doesn't exist currently
139 # but would be usefull for Sphinx.
140 nb.metadata._draft["author"] = self._prompt_author()
141 nb.metadata._draft["version"] = self._prompt_version()
142 nb.metadata._draft["release"] = self._prompt_release()
143 nb.metadata._draft["date"] = self._prompt_date()
144
145 # Prompt the user for the document style.
146 resources["sphinx"]["chapterstyle"] = self._prompt_chapter_title_style()
147 resources["sphinx"]["outputstyle"] = self._prompt_output_style()
148
149 # Small options
150 resources["sphinx"]["centeroutput"] = console.prompt_boolean("Do you want to center the output? (false)", False)
151 resources["sphinx"]["header"] = console.prompt_boolean("Should a Sphinx document header be used? (true)", True)
152 else:
153
154 # Try to use the traitlets.
155 nb.metadata._draft["author"] = self.author
156 nb.metadata._draft["version"] = self.version
157 nb.metadata._draft["release"] = self.release
158
159 # Use todays date if none is provided.
160 if len(self.publish_date.strip()) == 0:
161 nb.metadata._draft["date"] = date.today().strftime("%B %-d, %Y")
162 else:
163 nb.metadata._draft["date"] = self.publish_date
164
165 # Sphinx traitlets.
166 resources["sphinx"]["chapterstyle"] = self.chapter_style
167 resources["sphinx"]["outputstyle"] = self.output_style
168 resources["sphinx"]["centeroutput"] = self.center_output
169 resources["sphinx"]["header"] = self.use_headers
170
171 # Find and pass in the path to the Sphinx dependencies.
172 resources["sphinx"]["texinputs"] = os.path.abspath(sphinx.__file__ + "/../texinputs")
173
174 # Generate Pygments definitions for Latex
175 resources["sphinx"]["pygment_definitions"] = self._generate_pygments_latex_def()
176
177 if not (self.overridetitle == None or len(self.overridetitle.strip()) == 0):
178 nb.metadata.name = self.overridetitle
179
180 # End
181 return nb, resources
182
183
184 def _generate_pygments_latex_def(self):
185 """
186 Generate the pygments latex definitions that allows pygments
187 to work in latex.
188 """
189
190 return LatexFormatter().get_style_defs()
191
192
193 def _prompt_author(self):
194 """
195 Prompt the user to input an Author name
196 """
197 return console.input("Author name: ")
198
199
200 def _prompt_version(self):
201 """
202 prompt the user to enter a version number
203 """
204 return console.input("Version (ie ""1.0.0""): ")
205
206
207 def _prompt_release(self):
208 """
209 Prompt the user to input a release name
210 """
211
212 return console.input("Release Name (ie ""Rough draft""): ")
213
214
215 def _prompt_date(self):
216 """
217 Prompt the user to enter a date
218 """
219
220 default_date = date.today().strftime("%B %-d, %Y")
221 user_date = console.input("Date (deafults to \"" + default_date + "\"): ")
222 if len(user_date.strip()) == 0:
223 user_date = default_date
224 return user_date
225
226
227 def _prompt_output_style(self):
228 """
229 Prompts the user to pick an IPython output style.
230 """
231
232 # Dictionary of available output styles
233 styles = {1: "simple",
234 2: "notebook"}
235
236 #Append comments to the menu when displaying it to the user.
237 comments = {1: "(recommended for long code segments)",
238 2: "(default)"}
239
240 return console.prompt_dictionary(styles, default_style=2, menu_comments=comments)
241
242
243 def _prompt_chapter_title_style(self):
244 """
245 Prompts the user to pick a Sphinx chapter style
246 """
247
248 # Dictionary of available Sphinx styles
249 styles = {1: "Bjarne",
250 2: "Lenny",
251 3: "Glenn",
252 4: "Conny",
253 5: "Rejne",
254 6: "Sonny"}
255
256 #Append comments to the menu when displaying it to the user.
257 comments = {1: "(default)",
258 6: "(for international documents)"}
259
260 return console.prompt_dictionary(styles, menu_comments=comments)
261
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
@@ -0,0 +1,37 b''
1 """Global configuration class."""
2 #-----------------------------------------------------------------------------
3 # Copyright (c) 2013, the IPython Development Team.
4 #
5 # Distributed under the terms of the Modified BSD License.
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
14 from IPython.utils.traitlets import List
15 from IPython.config.configurable import Configurable
16
17 #-----------------------------------------------------------------------------
18 # Classes and functions
19 #-----------------------------------------------------------------------------
20
21 class GlobalConfigurable(Configurable):
22 """Global configurable class for shared config
23
24 Usefull for display data priority that might be use by many trasnformers
25 """
26
27 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
28 config=True,
29 help= """
30 An ordered list of prefered output type, the first
31 encounterd will usually be used when converting discarding
32 the others.
33 """
34 )
35
36 def __init__(self, config=None, **kw):
37 super(GlobalConfigurable, self).__init__( config=config, **kw)
@@ -0,0 +1,120 b''
1 """Utility functions for interacting with the console"""
2 #-----------------------------------------------------------------------------
3 # Copyright (c) 2013, the IPython Development Team.
4 #
5 # Distributed under the terms of the Modified BSD License.
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
14 # Used to determine python version
15 import sys
16
17 #-----------------------------------------------------------------------------
18 # Classes and functions
19 #-----------------------------------------------------------------------------
20
21 def input(prompt_text):
22 """
23 Prompt the user for input.
24
25 The input command will change depending on the version of python
26 installed. To maintain support for 2 and earlier, we must use
27 raw_input in that case. Else use input.
28
29 Parameters
30 ----------
31 prompt_text : str
32 Prompt to display to the user.
33 """
34
35 # Try to get the python version. This command is only available in
36 # python 2 and later, so it's important that we catch the exception
37 # if the command isn't found.
38 try:
39 majorversion = sys.version_info[0]
40 except AttributeError:
41 majorversion = 1
42
43 # Use the correct function to prompt the user for input depending on
44 # what python version the code is running in.
45 if majorversion >= 3:
46 return input(prompt_text)
47 else:
48 return raw_input(prompt_text).decode(sys.stdin.encoding)
49
50
51 def prompt_boolean(prompt, default=False):
52 """
53 Prompt the user for a boolean response.
54
55 Parameters
56 ----------
57 prompt : str
58 prompt to display to the user
59 default : bool, optional
60 response to return if none is given by the user
61 """
62
63 response = input(prompt)
64 response = response.strip().lower()
65
66 #Catch 1, true, yes as True
67 if len(response) > 0 and (response == "1" or response[0] == "t" or response[0] == "y"):
68 return True
69
70 #Catch 0, false, no as False
71 elif len(response) > 0 and (response == "0" or response[0] == "f" or response[0] == "n"):
72 return False
73
74 else:
75 return default
76
77
78 def prompt_dictionary(choices, default_style=1, menu_comments={}):
79 """
80 Prompt the user to chose one of many selections from a menu.
81
82 Parameters
83 ----------
84 choices : dictionary
85 Keys - choice numbers (int)
86 Values - choice value (str), this is what the function will return
87 default_style : int, optional
88 Choice to select if the user doesn't respond
89 menu_comments : dictionary, optional
90 Additional comments to append to the menu as it is displayed
91 in the console.
92 Keys - choice numbers (int)
93 Values - comment (str), what will be appended to the
94 corresponding choice
95 """
96
97 # Build the menu that will be displayed to the user with
98 # all of the options available.
99 prompt = ""
100 for key, value in choices.iteritems():
101 prompt += "%d %s " % (key, value)
102 if key in menu_comments:
103 prompt += menu_comments[key]
104 prompt += "\n"
105
106 # Continue to ask the user for a style until an appropriate
107 # one is specified.
108 response = -1
109 while (not response in choices):
110 try:
111 text_response = input(prompt)
112
113 # Use default option if no input.
114 if len(text_response.strip()) == 0:
115 response = default_style
116 else:
117 response = int(text_response)
118 except ValueError:
119 print("Error: Value is not an available option. 0 selects the default.\n")
120 return choices[response]
@@ -0,0 +1,17 b''
1 """NbConvert specific exceptions"""
2 #-----------------------------------------------------------------------------
3 # Copyright (c) 2013, the IPython Development Team.
4 #
5 # Distributed under the terms of the Modified BSD License.
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Classes and functions
12 #-----------------------------------------------------------------------------
13
14 class ConversionException(Exception):
15 """An exception raised by the conversion process."""
16
17 pass No newline at end of file
@@ -0,0 +1,46 b''
1 """A custom pygments lexer for IPython code cells.
2
3 Informs The pygments highlighting library of the quirks of IPython's superset
4 of Python -- magic commands, !shell commands, etc.
5 """
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2013, the IPython Development Team.
8 #
9 # Distributed under the terms of the Modified BSD License.
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
13
14 #-----------------------------------------------------------------------------
15 # Imports
16 #-----------------------------------------------------------------------------
17
18 # Third-party imports
19 from pygments.lexers import PythonLexer, BashLexer
20 from pygments.lexer import bygroups, using
21 from pygments.token import Keyword, Operator, Text
22
23 #-----------------------------------------------------------------------------
24 # Class declarations
25 #-----------------------------------------------------------------------------
26
27 class IPythonLexer(PythonLexer):
28 """
29 Pygments Lexer for use with IPython code. Inherits from
30 PythonLexer and adds information about IPython specific
31 keywords (i.e. magic commands, shell commands, etc.)
32 """
33
34 #Basic properties
35 name = 'IPython'
36 aliases = ['ip', 'ipython']
37 filenames = ['*.ipy']
38
39 #Highlighting information
40 tokens = PythonLexer.tokens.copy()
41 tokens['root'] = [
42 (r'(\%+)(\w+)\s+(\.*)(\n)', bygroups(Operator, Keyword,
43 using(BashLexer), Text)),
44 (r'(\%+)(\w+)\b', bygroups(Operator, Keyword)),
45 (r'^(!)(.+)(\n)', bygroups(Operator, using(BashLexer), Text)),
46 ] + tokens['root']
@@ -1,395 +1,400 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The :class:`~IPython.core.application.Application` object for the command
4 The :class:`~IPython.core.application.Application` object for the command
5 line :command:`ipython` program.
5 line :command:`ipython` program.
6
6
7 Authors
7 Authors
8 -------
8 -------
9
9
10 * Brian Granger
10 * Brian Granger
11 * Fernando Perez
11 * Fernando Perez
12 * Min Ragan-Kelley
12 * Min Ragan-Kelley
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2011 The IPython Development Team
16 # Copyright (C) 2008-2011 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 from __future__ import absolute_import
26 from __future__ import absolute_import
27
27
28 import logging
28 import logging
29 import os
29 import os
30 import sys
30 import sys
31
31
32 from IPython.config.loader import (
32 from IPython.config.loader import (
33 Config, PyFileConfigLoader, ConfigFileNotFound
33 Config, PyFileConfigLoader, ConfigFileNotFound
34 )
34 )
35 from IPython.config.application import boolean_flag, catch_config_error
35 from IPython.config.application import boolean_flag, catch_config_error
36 from IPython.core import release
36 from IPython.core import release
37 from IPython.core import usage
37 from IPython.core import usage
38 from IPython.core.completer import IPCompleter
38 from IPython.core.completer import IPCompleter
39 from IPython.core.crashhandler import CrashHandler
39 from IPython.core.crashhandler import CrashHandler
40 from IPython.core.formatters import PlainTextFormatter
40 from IPython.core.formatters import PlainTextFormatter
41 from IPython.core.history import HistoryManager
41 from IPython.core.history import HistoryManager
42 from IPython.core.prompts import PromptManager
42 from IPython.core.prompts import PromptManager
43 from IPython.core.application import (
43 from IPython.core.application import (
44 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
44 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
45 )
45 )
46 from IPython.core.magics import ScriptMagics
46 from IPython.core.magics import ScriptMagics
47 from IPython.core.shellapp import (
47 from IPython.core.shellapp import (
48 InteractiveShellApp, shell_flags, shell_aliases
48 InteractiveShellApp, shell_flags, shell_aliases
49 )
49 )
50 from IPython.terminal.interactiveshell import TerminalInteractiveShell
50 from IPython.terminal.interactiveshell import TerminalInteractiveShell
51 from IPython.utils import warn
51 from IPython.utils import warn
52 from IPython.utils.path import get_ipython_dir, check_for_old_config
52 from IPython.utils.path import get_ipython_dir, check_for_old_config
53 from IPython.utils.traitlets import (
53 from IPython.utils.traitlets import (
54 Bool, List, Dict, CaselessStrEnum
54 Bool, List, Dict, CaselessStrEnum
55 )
55 )
56
56
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58 # Globals, utilities and helpers
58 # Globals, utilities and helpers
59 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
60
60
61 #: The default config file name for this application.
61 #: The default config file name for this application.
62 default_config_file_name = u'ipython_config.py'
62 default_config_file_name = u'ipython_config.py'
63
63
64 _examples = """
64 _examples = """
65 ipython --pylab # start in pylab mode
65 ipython --pylab # start in pylab mode
66 ipython --pylab=qt # start in pylab mode with the qt4 backend
66 ipython --pylab=qt # start in pylab mode with the qt4 backend
67 ipython --log-level=DEBUG # set logging to DEBUG
67 ipython --log-level=DEBUG # set logging to DEBUG
68 ipython --profile=foo # start with profile foo
68 ipython --profile=foo # start with profile foo
69
69
70 ipython qtconsole # start the qtconsole GUI application
70 ipython qtconsole # start the qtconsole GUI application
71 ipython help qtconsole # show the help for the qtconsole subcmd
71 ipython help qtconsole # show the help for the qtconsole subcmd
72
72
73 ipython console # start the terminal-based console application
73 ipython console # start the terminal-based console application
74 ipython help console # show the help for the console subcmd
74 ipython help console # show the help for the console subcmd
75
75
76 ipython notebook # start the IPython notebook
76 ipython notebook # start the IPython notebook
77 ipython help notebook # show the help for the notebook subcmd
77 ipython help notebook # show the help for the notebook subcmd
78
78
79 ipython profile create foo # create profile foo w/ default config files
79 ipython profile create foo # create profile foo w/ default config files
80 ipython help profile # show the help for the profile subcmd
80 ipython help profile # show the help for the profile subcmd
81
81
82 ipython locate # print the path to the IPython directory
82 ipython locate # print the path to the IPython directory
83 ipython locate profile foo # print the path to the directory for profile `foo`
83 ipython locate profile foo # print the path to the directory for profile `foo`
84
85 ipython nbconvert # convert notebooks to/from other formats
84 """
86 """
85
87
86 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
87 # Crash handler for this application
89 # Crash handler for this application
88 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
89
91
90 class IPAppCrashHandler(CrashHandler):
92 class IPAppCrashHandler(CrashHandler):
91 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
93 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
92
94
93 def __init__(self, app):
95 def __init__(self, app):
94 contact_name = release.author
96 contact_name = release.author
95 contact_email = release.author_email
97 contact_email = release.author_email
96 bug_tracker = 'https://github.com/ipython/ipython/issues'
98 bug_tracker = 'https://github.com/ipython/ipython/issues'
97 super(IPAppCrashHandler,self).__init__(
99 super(IPAppCrashHandler,self).__init__(
98 app, contact_name, contact_email, bug_tracker
100 app, contact_name, contact_email, bug_tracker
99 )
101 )
100
102
101 def make_report(self,traceback):
103 def make_report(self,traceback):
102 """Return a string containing a crash report."""
104 """Return a string containing a crash report."""
103
105
104 sec_sep = self.section_sep
106 sec_sep = self.section_sep
105 # Start with parent report
107 # Start with parent report
106 report = [super(IPAppCrashHandler, self).make_report(traceback)]
108 report = [super(IPAppCrashHandler, self).make_report(traceback)]
107 # Add interactive-specific info we may have
109 # Add interactive-specific info we may have
108 rpt_add = report.append
110 rpt_add = report.append
109 try:
111 try:
110 rpt_add(sec_sep+"History of session input:")
112 rpt_add(sec_sep+"History of session input:")
111 for line in self.app.shell.user_ns['_ih']:
113 for line in self.app.shell.user_ns['_ih']:
112 rpt_add(line)
114 rpt_add(line)
113 rpt_add('\n*** Last line of input (may not be in above history):\n')
115 rpt_add('\n*** Last line of input (may not be in above history):\n')
114 rpt_add(self.app.shell._last_input_line+'\n')
116 rpt_add(self.app.shell._last_input_line+'\n')
115 except:
117 except:
116 pass
118 pass
117
119
118 return ''.join(report)
120 return ''.join(report)
119
121
120 #-----------------------------------------------------------------------------
122 #-----------------------------------------------------------------------------
121 # Aliases and Flags
123 # Aliases and Flags
122 #-----------------------------------------------------------------------------
124 #-----------------------------------------------------------------------------
123 flags = dict(base_flags)
125 flags = dict(base_flags)
124 flags.update(shell_flags)
126 flags.update(shell_flags)
125 frontend_flags = {}
127 frontend_flags = {}
126 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
128 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
127 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
129 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
128 'Turn on auto editing of files with syntax errors.',
130 'Turn on auto editing of files with syntax errors.',
129 'Turn off auto editing of files with syntax errors.'
131 'Turn off auto editing of files with syntax errors.'
130 )
132 )
131 addflag('banner', 'TerminalIPythonApp.display_banner',
133 addflag('banner', 'TerminalIPythonApp.display_banner',
132 "Display a banner upon starting IPython.",
134 "Display a banner upon starting IPython.",
133 "Don't display a banner upon starting IPython."
135 "Don't display a banner upon starting IPython."
134 )
136 )
135 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
137 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
136 """Set to confirm when you try to exit IPython with an EOF (Control-D
138 """Set to confirm when you try to exit IPython with an EOF (Control-D
137 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
139 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
138 you can force a direct exit without any confirmation.""",
140 you can force a direct exit without any confirmation.""",
139 "Don't prompt the user when exiting."
141 "Don't prompt the user when exiting."
140 )
142 )
141 addflag('term-title', 'TerminalInteractiveShell.term_title',
143 addflag('term-title', 'TerminalInteractiveShell.term_title',
142 "Enable auto setting the terminal title.",
144 "Enable auto setting the terminal title.",
143 "Disable auto setting the terminal title."
145 "Disable auto setting the terminal title."
144 )
146 )
145 classic_config = Config()
147 classic_config = Config()
146 classic_config.InteractiveShell.cache_size = 0
148 classic_config.InteractiveShell.cache_size = 0
147 classic_config.PlainTextFormatter.pprint = False
149 classic_config.PlainTextFormatter.pprint = False
148 classic_config.PromptManager.in_template = '>>> '
150 classic_config.PromptManager.in_template = '>>> '
149 classic_config.PromptManager.in2_template = '... '
151 classic_config.PromptManager.in2_template = '... '
150 classic_config.PromptManager.out_template = ''
152 classic_config.PromptManager.out_template = ''
151 classic_config.InteractiveShell.separate_in = ''
153 classic_config.InteractiveShell.separate_in = ''
152 classic_config.InteractiveShell.separate_out = ''
154 classic_config.InteractiveShell.separate_out = ''
153 classic_config.InteractiveShell.separate_out2 = ''
155 classic_config.InteractiveShell.separate_out2 = ''
154 classic_config.InteractiveShell.colors = 'NoColor'
156 classic_config.InteractiveShell.colors = 'NoColor'
155 classic_config.InteractiveShell.xmode = 'Plain'
157 classic_config.InteractiveShell.xmode = 'Plain'
156
158
157 frontend_flags['classic']=(
159 frontend_flags['classic']=(
158 classic_config,
160 classic_config,
159 "Gives IPython a similar feel to the classic Python prompt."
161 "Gives IPython a similar feel to the classic Python prompt."
160 )
162 )
161 # # log doesn't make so much sense this way anymore
163 # # log doesn't make so much sense this way anymore
162 # paa('--log','-l',
164 # paa('--log','-l',
163 # action='store_true', dest='InteractiveShell.logstart',
165 # action='store_true', dest='InteractiveShell.logstart',
164 # help="Start logging to the default log file (./ipython_log.py).")
166 # help="Start logging to the default log file (./ipython_log.py).")
165 #
167 #
166 # # quick is harder to implement
168 # # quick is harder to implement
167 frontend_flags['quick']=(
169 frontend_flags['quick']=(
168 {'TerminalIPythonApp' : {'quick' : True}},
170 {'TerminalIPythonApp' : {'quick' : True}},
169 "Enable quick startup with no config files."
171 "Enable quick startup with no config files."
170 )
172 )
171
173
172 frontend_flags['i'] = (
174 frontend_flags['i'] = (
173 {'TerminalIPythonApp' : {'force_interact' : True}},
175 {'TerminalIPythonApp' : {'force_interact' : True}},
174 """If running code from the command line, become interactive afterwards.
176 """If running code from the command line, become interactive afterwards.
175 Note: can also be given simply as '-i.'"""
177 Note: can also be given simply as '-i.'"""
176 )
178 )
177 flags.update(frontend_flags)
179 flags.update(frontend_flags)
178
180
179 aliases = dict(base_aliases)
181 aliases = dict(base_aliases)
180 aliases.update(shell_aliases)
182 aliases.update(shell_aliases)
181
183
182 #-----------------------------------------------------------------------------
184 #-----------------------------------------------------------------------------
183 # Main classes and functions
185 # Main classes and functions
184 #-----------------------------------------------------------------------------
186 #-----------------------------------------------------------------------------
185
187
186
188
187 class LocateIPythonApp(BaseIPythonApplication):
189 class LocateIPythonApp(BaseIPythonApplication):
188 description = """print the path to the IPython dir"""
190 description = """print the path to the IPython dir"""
189 subcommands = Dict(dict(
191 subcommands = Dict(dict(
190 profile=('IPython.core.profileapp.ProfileLocate',
192 profile=('IPython.core.profileapp.ProfileLocate',
191 "print the path to an IPython profile directory",
193 "print the path to an IPython profile directory",
192 ),
194 ),
193 ))
195 ))
194 def start(self):
196 def start(self):
195 if self.subapp is not None:
197 if self.subapp is not None:
196 return self.subapp.start()
198 return self.subapp.start()
197 else:
199 else:
198 print self.ipython_dir
200 print self.ipython_dir
199
201
200
202
201 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
203 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
202 name = u'ipython'
204 name = u'ipython'
203 description = usage.cl_usage
205 description = usage.cl_usage
204 default_config_file_name = default_config_file_name
206 default_config_file_name = default_config_file_name
205 crash_handler_class = IPAppCrashHandler
207 crash_handler_class = IPAppCrashHandler
206 examples = _examples
208 examples = _examples
207
209
208 flags = Dict(flags)
210 flags = Dict(flags)
209 aliases = Dict(aliases)
211 aliases = Dict(aliases)
210 classes = List()
212 classes = List()
211 def _classes_default(self):
213 def _classes_default(self):
212 """This has to be in a method, for TerminalIPythonApp to be available."""
214 """This has to be in a method, for TerminalIPythonApp to be available."""
213 return [
215 return [
214 InteractiveShellApp, # ShellApp comes before TerminalApp, because
216 InteractiveShellApp, # ShellApp comes before TerminalApp, because
215 self.__class__, # it will also affect subclasses (e.g. QtConsole)
217 self.__class__, # it will also affect subclasses (e.g. QtConsole)
216 TerminalInteractiveShell,
218 TerminalInteractiveShell,
217 PromptManager,
219 PromptManager,
218 HistoryManager,
220 HistoryManager,
219 ProfileDir,
221 ProfileDir,
220 PlainTextFormatter,
222 PlainTextFormatter,
221 IPCompleter,
223 IPCompleter,
222 ScriptMagics,
224 ScriptMagics,
223 ]
225 ]
224
226
225 subcommands = Dict(dict(
227 subcommands = Dict(dict(
226 qtconsole=('IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
228 qtconsole=('IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
227 """Launch the IPython Qt Console."""
229 """Launch the IPython Qt Console."""
228 ),
230 ),
229 notebook=('IPython.html.notebookapp.NotebookApp',
231 notebook=('IPython.html.notebookapp.NotebookApp',
230 """Launch the IPython HTML Notebook Server."""
232 """Launch the IPython HTML Notebook Server."""
231 ),
233 ),
232 profile = ("IPython.core.profileapp.ProfileApp",
234 profile = ("IPython.core.profileapp.ProfileApp",
233 "Create and manage IPython profiles."
235 "Create and manage IPython profiles."
234 ),
236 ),
235 kernel = ("IPython.kernel.zmq.kernelapp.IPKernelApp",
237 kernel = ("IPython.kernel.zmq.kernelapp.IPKernelApp",
236 "Start a kernel without an attached frontend."
238 "Start a kernel without an attached frontend."
237 ),
239 ),
238 console=('IPython.terminal.console.app.ZMQTerminalIPythonApp',
240 console=('IPython.terminal.console.app.ZMQTerminalIPythonApp',
239 """Launch the IPython terminal-based Console."""
241 """Launch the IPython terminal-based Console."""
240 ),
242 ),
241 locate=('IPython.terminal.ipapp.LocateIPythonApp',
243 locate=('IPython.terminal.ipapp.LocateIPythonApp',
242 LocateIPythonApp.description
244 LocateIPythonApp.description
243 ),
245 ),
244 history=('IPython.core.historyapp.HistoryApp',
246 history=('IPython.core.historyapp.HistoryApp',
245 "Manage the IPython history database."
247 "Manage the IPython history database."
246 ),
248 ),
249 nbconvert=('IPython.nbconvert.nbconvertapp.NbConvertApp',
250 "Convert notebooks to/from other formats."
251 ),
247 ))
252 ))
248
253
249 # *do* autocreate requested profile, but don't create the config file.
254 # *do* autocreate requested profile, but don't create the config file.
250 auto_create=Bool(True)
255 auto_create=Bool(True)
251 # configurables
256 # configurables
252 ignore_old_config=Bool(False, config=True,
257 ignore_old_config=Bool(False, config=True,
253 help="Suppress warning messages about legacy config files"
258 help="Suppress warning messages about legacy config files"
254 )
259 )
255 quick = Bool(False, config=True,
260 quick = Bool(False, config=True,
256 help="""Start IPython quickly by skipping the loading of config files."""
261 help="""Start IPython quickly by skipping the loading of config files."""
257 )
262 )
258 def _quick_changed(self, name, old, new):
263 def _quick_changed(self, name, old, new):
259 if new:
264 if new:
260 self.load_config_file = lambda *a, **kw: None
265 self.load_config_file = lambda *a, **kw: None
261 self.ignore_old_config=True
266 self.ignore_old_config=True
262
267
263 display_banner = Bool(True, config=True,
268 display_banner = Bool(True, config=True,
264 help="Whether to display a banner upon starting IPython."
269 help="Whether to display a banner upon starting IPython."
265 )
270 )
266
271
267 # if there is code of files to run from the cmd line, don't interact
272 # if there is code of files to run from the cmd line, don't interact
268 # unless the --i flag (App.force_interact) is true.
273 # unless the --i flag (App.force_interact) is true.
269 force_interact = Bool(False, config=True,
274 force_interact = Bool(False, config=True,
270 help="""If a command or file is given via the command-line,
275 help="""If a command or file is given via the command-line,
271 e.g. 'ipython foo.py"""
276 e.g. 'ipython foo.py"""
272 )
277 )
273 def _force_interact_changed(self, name, old, new):
278 def _force_interact_changed(self, name, old, new):
274 if new:
279 if new:
275 self.interact = True
280 self.interact = True
276
281
277 def _file_to_run_changed(self, name, old, new):
282 def _file_to_run_changed(self, name, old, new):
278 if new:
283 if new:
279 self.something_to_run = True
284 self.something_to_run = True
280 if new and not self.force_interact:
285 if new and not self.force_interact:
281 self.interact = False
286 self.interact = False
282 _code_to_run_changed = _file_to_run_changed
287 _code_to_run_changed = _file_to_run_changed
283 _module_to_run_changed = _file_to_run_changed
288 _module_to_run_changed = _file_to_run_changed
284
289
285 # internal, not-configurable
290 # internal, not-configurable
286 interact=Bool(True)
291 interact=Bool(True)
287 something_to_run=Bool(False)
292 something_to_run=Bool(False)
288
293
289 def parse_command_line(self, argv=None):
294 def parse_command_line(self, argv=None):
290 """override to allow old '-pylab' flag with deprecation warning"""
295 """override to allow old '-pylab' flag with deprecation warning"""
291
296
292 argv = sys.argv[1:] if argv is None else argv
297 argv = sys.argv[1:] if argv is None else argv
293
298
294 if '-pylab' in argv:
299 if '-pylab' in argv:
295 # deprecated `-pylab` given,
300 # deprecated `-pylab` given,
296 # warn and transform into current syntax
301 # warn and transform into current syntax
297 argv = argv[:] # copy, don't clobber
302 argv = argv[:] # copy, don't clobber
298 idx = argv.index('-pylab')
303 idx = argv.index('-pylab')
299 warn.warn("`-pylab` flag has been deprecated.\n"
304 warn.warn("`-pylab` flag has been deprecated.\n"
300 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
305 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
301 sub = '--pylab'
306 sub = '--pylab'
302 if len(argv) > idx+1:
307 if len(argv) > idx+1:
303 # check for gui arg, as in '-pylab qt'
308 # check for gui arg, as in '-pylab qt'
304 gui = argv[idx+1]
309 gui = argv[idx+1]
305 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
310 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
306 sub = '--pylab='+gui
311 sub = '--pylab='+gui
307 argv.pop(idx+1)
312 argv.pop(idx+1)
308 argv[idx] = sub
313 argv[idx] = sub
309
314
310 return super(TerminalIPythonApp, self).parse_command_line(argv)
315 return super(TerminalIPythonApp, self).parse_command_line(argv)
311
316
312 @catch_config_error
317 @catch_config_error
313 def initialize(self, argv=None):
318 def initialize(self, argv=None):
314 """Do actions after construct, but before starting the app."""
319 """Do actions after construct, but before starting the app."""
315 super(TerminalIPythonApp, self).initialize(argv)
320 super(TerminalIPythonApp, self).initialize(argv)
316 if self.subapp is not None:
321 if self.subapp is not None:
317 # don't bother initializing further, starting subapp
322 # don't bother initializing further, starting subapp
318 return
323 return
319 if not self.ignore_old_config:
324 if not self.ignore_old_config:
320 check_for_old_config(self.ipython_dir)
325 check_for_old_config(self.ipython_dir)
321 # print self.extra_args
326 # print self.extra_args
322 if self.extra_args and not self.something_to_run:
327 if self.extra_args and not self.something_to_run:
323 self.file_to_run = self.extra_args[0]
328 self.file_to_run = self.extra_args[0]
324 self.init_path()
329 self.init_path()
325 # create the shell
330 # create the shell
326 self.init_shell()
331 self.init_shell()
327 # and draw the banner
332 # and draw the banner
328 self.init_banner()
333 self.init_banner()
329 # Now a variety of things that happen after the banner is printed.
334 # Now a variety of things that happen after the banner is printed.
330 self.init_gui_pylab()
335 self.init_gui_pylab()
331 self.init_extensions()
336 self.init_extensions()
332 self.init_code()
337 self.init_code()
333
338
334 def init_shell(self):
339 def init_shell(self):
335 """initialize the InteractiveShell instance"""
340 """initialize the InteractiveShell instance"""
336 # Create an InteractiveShell instance.
341 # Create an InteractiveShell instance.
337 # shell.display_banner should always be False for the terminal
342 # shell.display_banner should always be False for the terminal
338 # based app, because we call shell.show_banner() by hand below
343 # based app, because we call shell.show_banner() by hand below
339 # so the banner shows *before* all extension loading stuff.
344 # so the banner shows *before* all extension loading stuff.
340 self.shell = TerminalInteractiveShell.instance(parent=self,
345 self.shell = TerminalInteractiveShell.instance(parent=self,
341 display_banner=False, profile_dir=self.profile_dir,
346 display_banner=False, profile_dir=self.profile_dir,
342 ipython_dir=self.ipython_dir)
347 ipython_dir=self.ipython_dir)
343 self.shell.configurables.append(self)
348 self.shell.configurables.append(self)
344
349
345 def init_banner(self):
350 def init_banner(self):
346 """optionally display the banner"""
351 """optionally display the banner"""
347 if self.display_banner and self.interact:
352 if self.display_banner and self.interact:
348 self.shell.show_banner()
353 self.shell.show_banner()
349 # Make sure there is a space below the banner.
354 # Make sure there is a space below the banner.
350 if self.log_level <= logging.INFO: print
355 if self.log_level <= logging.INFO: print
351
356
352 def _pylab_changed(self, name, old, new):
357 def _pylab_changed(self, name, old, new):
353 """Replace --pylab='inline' with --pylab='auto'"""
358 """Replace --pylab='inline' with --pylab='auto'"""
354 if new == 'inline':
359 if new == 'inline':
355 warn.warn("'inline' not available as pylab backend, "
360 warn.warn("'inline' not available as pylab backend, "
356 "using 'auto' instead.")
361 "using 'auto' instead.")
357 self.pylab = 'auto'
362 self.pylab = 'auto'
358
363
359 def start(self):
364 def start(self):
360 if self.subapp is not None:
365 if self.subapp is not None:
361 return self.subapp.start()
366 return self.subapp.start()
362 # perform any prexec steps:
367 # perform any prexec steps:
363 if self.interact:
368 if self.interact:
364 self.log.debug("Starting IPython's mainloop...")
369 self.log.debug("Starting IPython's mainloop...")
365 self.shell.mainloop()
370 self.shell.mainloop()
366 else:
371 else:
367 self.log.debug("IPython not interactive...")
372 self.log.debug("IPython not interactive...")
368
373
369
374
370 def load_default_config(ipython_dir=None):
375 def load_default_config(ipython_dir=None):
371 """Load the default config file from the default ipython_dir.
376 """Load the default config file from the default ipython_dir.
372
377
373 This is useful for embedded shells.
378 This is useful for embedded shells.
374 """
379 """
375 if ipython_dir is None:
380 if ipython_dir is None:
376 ipython_dir = get_ipython_dir()
381 ipython_dir = get_ipython_dir()
377 profile_dir = os.path.join(ipython_dir, 'profile_default')
382 profile_dir = os.path.join(ipython_dir, 'profile_default')
378 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
383 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
379 try:
384 try:
380 config = cl.load_config()
385 config = cl.load_config()
381 except ConfigFileNotFound:
386 except ConfigFileNotFound:
382 # no config found
387 # no config found
383 config = Config()
388 config = Config()
384 return config
389 return config
385
390
386
391
387 def launch_new_instance():
392 def launch_new_instance():
388 """Create and run a full blown IPython instance"""
393 """Create and run a full blown IPython instance"""
389 app = TerminalIPythonApp.instance()
394 app = TerminalIPythonApp.instance()
390 app.initialize()
395 app.initialize()
391 app.start()
396 app.start()
392
397
393
398
394 if __name__ == '__main__':
399 if __name__ == '__main__':
395 launch_new_instance()
400 launch_new_instance()
@@ -1,624 +1,632 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Test Suite Runner.
2 """IPython Test Suite Runner.
3
3
4 This module provides a main entry point to a user script to test IPython
4 This module provides a main entry point to a user script to test IPython
5 itself from the command line. There are two ways of running this script:
5 itself from the command line. There are two ways of running this script:
6
6
7 1. With the syntax `iptest all`. This runs our entire test suite by
7 1. With the syntax `iptest all`. This runs our entire test suite by
8 calling this script (with different arguments) recursively. This
8 calling this script (with different arguments) recursively. This
9 causes modules and package to be tested in different processes, using nose
9 causes modules and package to be tested in different processes, using nose
10 or trial where appropriate.
10 or trial where appropriate.
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 the script simply calls nose, but with special command line flags and
12 the script simply calls nose, but with special command line flags and
13 plugins loaded.
13 plugins loaded.
14
14
15 """
15 """
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2009-2011 The IPython Development Team
18 # Copyright (C) 2009-2011 The IPython Development Team
19 #
19 #
20 # Distributed under the terms of the BSD License. The full license is in
20 # Distributed under the terms of the BSD License. The full license is in
21 # the file COPYING, distributed as part of this software.
21 # the file COPYING, distributed as part of this software.
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Imports
25 # Imports
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 from __future__ import print_function
27 from __future__ import print_function
28
28
29 # Stdlib
29 # Stdlib
30 import glob
30 import glob
31 import os
31 import os
32 import os.path as path
32 import os.path as path
33 import signal
33 import signal
34 import sys
34 import sys
35 import subprocess
35 import subprocess
36 import tempfile
36 import tempfile
37 import time
37 import time
38 import warnings
38 import warnings
39
39
40 # Note: monkeypatch!
40 # Note: monkeypatch!
41 # We need to monkeypatch a small problem in nose itself first, before importing
41 # We need to monkeypatch a small problem in nose itself first, before importing
42 # it for actual use. This should get into nose upstream, but its release cycle
42 # it for actual use. This should get into nose upstream, but its release cycle
43 # is slow and we need it for our parametric tests to work correctly.
43 # is slow and we need it for our parametric tests to work correctly.
44 from IPython.testing import nosepatch
44 from IPython.testing import nosepatch
45
45
46 # Monkeypatch extra assert methods into nose.tools if they're not already there.
46 # Monkeypatch extra assert methods into nose.tools if they're not already there.
47 # This can be dropped once we no longer test on Python 2.6
47 # This can be dropped once we no longer test on Python 2.6
48 from IPython.testing import nose_assert_methods
48 from IPython.testing import nose_assert_methods
49
49
50 # Now, proceed to import nose itself
50 # Now, proceed to import nose itself
51 import nose.plugins.builtin
51 import nose.plugins.builtin
52 from nose.plugins.xunit import Xunit
52 from nose.plugins.xunit import Xunit
53 from nose import SkipTest
53 from nose import SkipTest
54 from nose.core import TestProgram
54 from nose.core import TestProgram
55
55
56 # Our own imports
56 # Our own imports
57 from IPython.utils import py3compat
57 from IPython.utils import py3compat
58 from IPython.utils.importstring import import_item
58 from IPython.utils.importstring import import_item
59 from IPython.utils.path import get_ipython_module_path, get_ipython_package_dir
59 from IPython.utils.path import get_ipython_module_path, get_ipython_package_dir
60 from IPython.utils.process import find_cmd, pycmd2argv
60 from IPython.utils.process import find_cmd, pycmd2argv
61 from IPython.utils.sysinfo import sys_info
61 from IPython.utils.sysinfo import sys_info
62 from IPython.utils.tempdir import TemporaryDirectory
62 from IPython.utils.tempdir import TemporaryDirectory
63 from IPython.utils.warn import warn
63 from IPython.utils.warn import warn
64
64
65 from IPython.testing import globalipapp
65 from IPython.testing import globalipapp
66 from IPython.testing.plugin.ipdoctest import IPythonDoctest
66 from IPython.testing.plugin.ipdoctest import IPythonDoctest
67 from IPython.external.decorators import KnownFailure, knownfailureif
67 from IPython.external.decorators import KnownFailure, knownfailureif
68
68
69 pjoin = path.join
69 pjoin = path.join
70
70
71
71
72 #-----------------------------------------------------------------------------
72 #-----------------------------------------------------------------------------
73 # Globals
73 # Globals
74 #-----------------------------------------------------------------------------
74 #-----------------------------------------------------------------------------
75
75
76
76
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78 # Warnings control
78 # Warnings control
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80
80
81 # Twisted generates annoying warnings with Python 2.6, as will do other code
81 # Twisted generates annoying warnings with Python 2.6, as will do other code
82 # that imports 'sets' as of today
82 # that imports 'sets' as of today
83 warnings.filterwarnings('ignore', 'the sets module is deprecated',
83 warnings.filterwarnings('ignore', 'the sets module is deprecated',
84 DeprecationWarning )
84 DeprecationWarning )
85
85
86 # This one also comes from Twisted
86 # This one also comes from Twisted
87 warnings.filterwarnings('ignore', 'the sha module is deprecated',
87 warnings.filterwarnings('ignore', 'the sha module is deprecated',
88 DeprecationWarning)
88 DeprecationWarning)
89
89
90 # Wx on Fedora11 spits these out
90 # Wx on Fedora11 spits these out
91 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
91 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
92 UserWarning)
92 UserWarning)
93
93
94 # ------------------------------------------------------------------------------
94 # ------------------------------------------------------------------------------
95 # Monkeypatch Xunit to count known failures as skipped.
95 # Monkeypatch Xunit to count known failures as skipped.
96 # ------------------------------------------------------------------------------
96 # ------------------------------------------------------------------------------
97 def monkeypatch_xunit():
97 def monkeypatch_xunit():
98 try:
98 try:
99 knownfailureif(True)(lambda: None)()
99 knownfailureif(True)(lambda: None)()
100 except Exception as e:
100 except Exception as e:
101 KnownFailureTest = type(e)
101 KnownFailureTest = type(e)
102
102
103 def addError(self, test, err, capt=None):
103 def addError(self, test, err, capt=None):
104 if issubclass(err[0], KnownFailureTest):
104 if issubclass(err[0], KnownFailureTest):
105 err = (SkipTest,) + err[1:]
105 err = (SkipTest,) + err[1:]
106 return self.orig_addError(test, err, capt)
106 return self.orig_addError(test, err, capt)
107
107
108 Xunit.orig_addError = Xunit.addError
108 Xunit.orig_addError = Xunit.addError
109 Xunit.addError = addError
109 Xunit.addError = addError
110
110
111 #-----------------------------------------------------------------------------
111 #-----------------------------------------------------------------------------
112 # Logic for skipping doctests
112 # Logic for skipping doctests
113 #-----------------------------------------------------------------------------
113 #-----------------------------------------------------------------------------
114 def extract_version(mod):
114 def extract_version(mod):
115 return mod.__version__
115 return mod.__version__
116
116
117 def test_for(item, min_version=None, callback=extract_version):
117 def test_for(item, min_version=None, callback=extract_version):
118 """Test to see if item is importable, and optionally check against a minimum
118 """Test to see if item is importable, and optionally check against a minimum
119 version.
119 version.
120
120
121 If min_version is given, the default behavior is to check against the
121 If min_version is given, the default behavior is to check against the
122 `__version__` attribute of the item, but specifying `callback` allows you to
122 `__version__` attribute of the item, but specifying `callback` allows you to
123 extract the value you are interested in. e.g::
123 extract the value you are interested in. e.g::
124
124
125 In [1]: import sys
125 In [1]: import sys
126
126
127 In [2]: from IPython.testing.iptest import test_for
127 In [2]: from IPython.testing.iptest import test_for
128
128
129 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
129 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
130 Out[3]: True
130 Out[3]: True
131
131
132 """
132 """
133 try:
133 try:
134 check = import_item(item)
134 check = import_item(item)
135 except (ImportError, RuntimeError):
135 except (ImportError, RuntimeError):
136 # GTK reports Runtime error if it can't be initialized even if it's
136 # GTK reports Runtime error if it can't be initialized even if it's
137 # importable.
137 # importable.
138 return False
138 return False
139 else:
139 else:
140 if min_version:
140 if min_version:
141 if callback:
141 if callback:
142 # extra processing step to get version to compare
142 # extra processing step to get version to compare
143 check = callback(check)
143 check = callback(check)
144
144
145 return check >= min_version
145 return check >= min_version
146 else:
146 else:
147 return True
147 return True
148
148
149 # Global dict where we can store information on what we have and what we don't
149 # Global dict where we can store information on what we have and what we don't
150 # have available at test run time
150 # have available at test run time
151 have = {}
151 have = {}
152
152
153 have['curses'] = test_for('_curses')
153 have['curses'] = test_for('_curses')
154 have['matplotlib'] = test_for('matplotlib')
154 have['matplotlib'] = test_for('matplotlib')
155 have['numpy'] = test_for('numpy')
155 have['numpy'] = test_for('numpy')
156 have['pexpect'] = test_for('IPython.external.pexpect')
156 have['pexpect'] = test_for('IPython.external.pexpect')
157 have['pymongo'] = test_for('pymongo')
157 have['pymongo'] = test_for('pymongo')
158 have['pygments'] = test_for('pygments')
158 have['pygments'] = test_for('pygments')
159 have['qt'] = test_for('IPython.external.qt')
159 have['qt'] = test_for('IPython.external.qt')
160 have['rpy2'] = test_for('rpy2')
160 have['rpy2'] = test_for('rpy2')
161 have['sqlite3'] = test_for('sqlite3')
161 have['sqlite3'] = test_for('sqlite3')
162 have['cython'] = test_for('Cython')
162 have['cython'] = test_for('Cython')
163 have['oct2py'] = test_for('oct2py')
163 have['oct2py'] = test_for('oct2py')
164 have['tornado'] = test_for('tornado.version_info', (2,1,0), callback=None)
164 have['tornado'] = test_for('tornado.version_info', (2,1,0), callback=None)
165 have['jinja2'] = test_for('jinja2')
165 have['jinja2'] = test_for('jinja2')
166 have['wx'] = test_for('wx')
166 have['wx'] = test_for('wx')
167 have['wx.aui'] = test_for('wx.aui')
167 have['wx.aui'] = test_for('wx.aui')
168 have['azure'] = test_for('azure')
168 have['azure'] = test_for('azure')
169 have['sphinx'] = test_for('sphinx')
170 have['markdown'] = test_for('markdown')
169
171
170 min_zmq = (2,1,11)
172 min_zmq = (2,1,11)
171
173
172 have['zmq'] = test_for('zmq.pyzmq_version_info', min_zmq, callback=lambda x: x())
174 have['zmq'] = test_for('zmq.pyzmq_version_info', min_zmq, callback=lambda x: x())
173
175
174 #-----------------------------------------------------------------------------
176 #-----------------------------------------------------------------------------
175 # Functions and classes
177 # Functions and classes
176 #-----------------------------------------------------------------------------
178 #-----------------------------------------------------------------------------
177
179
178 def report():
180 def report():
179 """Return a string with a summary report of test-related variables."""
181 """Return a string with a summary report of test-related variables."""
180
182
181 out = [ sys_info(), '\n']
183 out = [ sys_info(), '\n']
182
184
183 avail = []
185 avail = []
184 not_avail = []
186 not_avail = []
185
187
186 for k, is_avail in have.items():
188 for k, is_avail in have.items():
187 if is_avail:
189 if is_avail:
188 avail.append(k)
190 avail.append(k)
189 else:
191 else:
190 not_avail.append(k)
192 not_avail.append(k)
191
193
192 if avail:
194 if avail:
193 out.append('\nTools and libraries available at test time:\n')
195 out.append('\nTools and libraries available at test time:\n')
194 avail.sort()
196 avail.sort()
195 out.append(' ' + ' '.join(avail)+'\n')
197 out.append(' ' + ' '.join(avail)+'\n')
196
198
197 if not_avail:
199 if not_avail:
198 out.append('\nTools and libraries NOT available at test time:\n')
200 out.append('\nTools and libraries NOT available at test time:\n')
199 not_avail.sort()
201 not_avail.sort()
200 out.append(' ' + ' '.join(not_avail)+'\n')
202 out.append(' ' + ' '.join(not_avail)+'\n')
201
203
202 return ''.join(out)
204 return ''.join(out)
203
205
204
206
205 def make_exclude():
207 def make_exclude():
206 """Make patterns of modules and packages to exclude from testing.
208 """Make patterns of modules and packages to exclude from testing.
207
209
208 For the IPythonDoctest plugin, we need to exclude certain patterns that
210 For the IPythonDoctest plugin, we need to exclude certain patterns that
209 cause testing problems. We should strive to minimize the number of
211 cause testing problems. We should strive to minimize the number of
210 skipped modules, since this means untested code.
212 skipped modules, since this means untested code.
211
213
212 These modules and packages will NOT get scanned by nose at all for tests.
214 These modules and packages will NOT get scanned by nose at all for tests.
213 """
215 """
214 # Simple utility to make IPython paths more readably, we need a lot of
216 # Simple utility to make IPython paths more readably, we need a lot of
215 # these below
217 # these below
216 ipjoin = lambda *paths: pjoin('IPython', *paths)
218 ipjoin = lambda *paths: pjoin('IPython', *paths)
217
219
218 exclusions = [ipjoin('external'),
220 exclusions = [ipjoin('external'),
219 ipjoin('quarantine'),
221 ipjoin('quarantine'),
220 ipjoin('deathrow'),
222 ipjoin('deathrow'),
221 # This guy is probably attic material
223 # This guy is probably attic material
222 ipjoin('testing', 'mkdoctests'),
224 ipjoin('testing', 'mkdoctests'),
223 # Testing inputhook will need a lot of thought, to figure out
225 # Testing inputhook will need a lot of thought, to figure out
224 # how to have tests that don't lock up with the gui event
226 # how to have tests that don't lock up with the gui event
225 # loops in the picture
227 # loops in the picture
226 ipjoin('lib', 'inputhook'),
228 ipjoin('lib', 'inputhook'),
227 # Config files aren't really importable stand-alone
229 # Config files aren't really importable stand-alone
228 ipjoin('config', 'profile'),
230 ipjoin('config', 'profile'),
229 # The notebook 'static' directory contains JS, css and other
231 # The notebook 'static' directory contains JS, css and other
230 # files for web serving. Occasionally projects may put a .py
232 # files for web serving. Occasionally projects may put a .py
231 # file in there (MathJax ships a conf.py), so we might as
233 # file in there (MathJax ships a conf.py), so we might as
232 # well play it safe and skip the whole thing.
234 # well play it safe and skip the whole thing.
233 ipjoin('html', 'static'),
235 ipjoin('html', 'static'),
234 ipjoin('html', 'fabfile'),
236 ipjoin('html', 'fabfile'),
235 ]
237 ]
236 if not have['sqlite3']:
238 if not have['sqlite3']:
237 exclusions.append(ipjoin('core', 'tests', 'test_history'))
239 exclusions.append(ipjoin('core', 'tests', 'test_history'))
238 exclusions.append(ipjoin('core', 'history'))
240 exclusions.append(ipjoin('core', 'history'))
239 if not have['wx']:
241 if not have['wx']:
240 exclusions.append(ipjoin('lib', 'inputhookwx'))
242 exclusions.append(ipjoin('lib', 'inputhookwx'))
241
243
242 if 'IPython.kernel.inprocess' not in sys.argv:
244 if 'IPython.kernel.inprocess' not in sys.argv:
243 exclusions.append(ipjoin('kernel', 'inprocess'))
245 exclusions.append(ipjoin('kernel', 'inprocess'))
244
246
245 # FIXME: temporarily disable autoreload tests, as they can produce
247 # FIXME: temporarily disable autoreload tests, as they can produce
246 # spurious failures in subsequent tests (cythonmagic).
248 # spurious failures in subsequent tests (cythonmagic).
247 exclusions.append(ipjoin('extensions', 'autoreload'))
249 exclusions.append(ipjoin('extensions', 'autoreload'))
248 exclusions.append(ipjoin('extensions', 'tests', 'test_autoreload'))
250 exclusions.append(ipjoin('extensions', 'tests', 'test_autoreload'))
249
251
250 # We do this unconditionally, so that the test suite doesn't import
252 # We do this unconditionally, so that the test suite doesn't import
251 # gtk, changing the default encoding and masking some unicode bugs.
253 # gtk, changing the default encoding and masking some unicode bugs.
252 exclusions.append(ipjoin('lib', 'inputhookgtk'))
254 exclusions.append(ipjoin('lib', 'inputhookgtk'))
253 exclusions.append(ipjoin('kernel', 'zmq', 'gui', 'gtkembed'))
255 exclusions.append(ipjoin('kernel', 'zmq', 'gui', 'gtkembed'))
254
256
255 # These have to be skipped on win32 because the use echo, rm, cd, etc.
257 # These have to be skipped on win32 because the use echo, rm, cd, etc.
256 # See ticket https://github.com/ipython/ipython/issues/87
258 # See ticket https://github.com/ipython/ipython/issues/87
257 if sys.platform == 'win32':
259 if sys.platform == 'win32':
258 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
260 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
259 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
261 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
260
262
261 if not have['pexpect']:
263 if not have['pexpect']:
262 exclusions.extend([ipjoin('lib', 'irunner'),
264 exclusions.extend([ipjoin('lib', 'irunner'),
263 ipjoin('lib', 'tests', 'test_irunner'),
265 ipjoin('lib', 'tests', 'test_irunner'),
264 ipjoin('terminal', 'console'),
266 ipjoin('terminal', 'console'),
265 ])
267 ])
266
268
267 if not have['zmq']:
269 if not have['zmq']:
268 exclusions.append(ipjoin('kernel'))
270 exclusions.append(ipjoin('kernel'))
269 exclusions.append(ipjoin('qt'))
271 exclusions.append(ipjoin('qt'))
270 exclusions.append(ipjoin('html'))
272 exclusions.append(ipjoin('html'))
271 exclusions.append(ipjoin('consoleapp.py'))
273 exclusions.append(ipjoin('consoleapp.py'))
272 exclusions.append(ipjoin('terminal', 'console'))
274 exclusions.append(ipjoin('terminal', 'console'))
273 exclusions.append(ipjoin('parallel'))
275 exclusions.append(ipjoin('parallel'))
274 elif not have['qt'] or not have['pygments']:
276 elif not have['qt'] or not have['pygments']:
275 exclusions.append(ipjoin('qt'))
277 exclusions.append(ipjoin('qt'))
276
278
277 if not have['pymongo']:
279 if not have['pymongo']:
278 exclusions.append(ipjoin('parallel', 'controller', 'mongodb'))
280 exclusions.append(ipjoin('parallel', 'controller', 'mongodb'))
279 exclusions.append(ipjoin('parallel', 'tests', 'test_mongodb'))
281 exclusions.append(ipjoin('parallel', 'tests', 'test_mongodb'))
280
282
281 if not have['matplotlib']:
283 if not have['matplotlib']:
282 exclusions.extend([ipjoin('core', 'pylabtools'),
284 exclusions.extend([ipjoin('core', 'pylabtools'),
283 ipjoin('core', 'tests', 'test_pylabtools'),
285 ipjoin('core', 'tests', 'test_pylabtools'),
284 ipjoin('kernel', 'zmq', 'pylab'),
286 ipjoin('kernel', 'zmq', 'pylab'),
285 ])
287 ])
286
288
287 if not have['cython']:
289 if not have['cython']:
288 exclusions.extend([ipjoin('extensions', 'cythonmagic')])
290 exclusions.extend([ipjoin('extensions', 'cythonmagic')])
289 exclusions.extend([ipjoin('extensions', 'tests', 'test_cythonmagic')])
291 exclusions.extend([ipjoin('extensions', 'tests', 'test_cythonmagic')])
290
292
291 if not have['oct2py']:
293 if not have['oct2py']:
292 exclusions.extend([ipjoin('extensions', 'octavemagic')])
294 exclusions.extend([ipjoin('extensions', 'octavemagic')])
293 exclusions.extend([ipjoin('extensions', 'tests', 'test_octavemagic')])
295 exclusions.extend([ipjoin('extensions', 'tests', 'test_octavemagic')])
294
296
295 if not have['tornado']:
297 if not have['tornado']:
296 exclusions.append(ipjoin('html'))
298 exclusions.append(ipjoin('html'))
297
299
298 if not have['jinja2']:
300 if not have['jinja2']:
299 exclusions.append(ipjoin('html', 'notebookapp'))
301 exclusions.append(ipjoin('html', 'notebookapp'))
300
302
301 if not have['rpy2'] or not have['numpy']:
303 if not have['rpy2'] or not have['numpy']:
302 exclusions.append(ipjoin('extensions', 'rmagic'))
304 exclusions.append(ipjoin('extensions', 'rmagic'))
303 exclusions.append(ipjoin('extensions', 'tests', 'test_rmagic'))
305 exclusions.append(ipjoin('extensions', 'tests', 'test_rmagic'))
304
306
305 if not have['azure']:
307 if not have['azure']:
306 exclusions.append(ipjoin('html', 'services', 'notebooks', 'azurenbmanager'))
308 exclusions.append(ipjoin('html', 'services', 'notebooks', 'azurenbmanager'))
307
309
310 if not all((have['pygments'], have['jinja2'], have['markdown'], have['sphinx'])):
311 exclusions.append(ipjoin('nbconvert'))
312
308 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
313 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
309 if sys.platform == 'win32':
314 if sys.platform == 'win32':
310 exclusions = [s.replace('\\','\\\\') for s in exclusions]
315 exclusions = [s.replace('\\','\\\\') for s in exclusions]
311
316
312 # check for any exclusions that don't seem to exist:
317 # check for any exclusions that don't seem to exist:
313 parent, _ = os.path.split(get_ipython_package_dir())
318 parent, _ = os.path.split(get_ipython_package_dir())
314 for exclusion in exclusions:
319 for exclusion in exclusions:
315 if exclusion.endswith(('deathrow', 'quarantine')):
320 if exclusion.endswith(('deathrow', 'quarantine')):
316 # ignore deathrow/quarantine, which exist in dev, but not install
321 # ignore deathrow/quarantine, which exist in dev, but not install
317 continue
322 continue
318 fullpath = pjoin(parent, exclusion)
323 fullpath = pjoin(parent, exclusion)
319 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
324 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
320 warn("Excluding nonexistent file: %r" % exclusion)
325 warn("Excluding nonexistent file: %r" % exclusion)
321
326
322 return exclusions
327 return exclusions
323
328
324
329
325 class IPTester(object):
330 class IPTester(object):
326 """Call that calls iptest or trial in a subprocess.
331 """Call that calls iptest or trial in a subprocess.
327 """
332 """
328 #: string, name of test runner that will be called
333 #: string, name of test runner that will be called
329 runner = None
334 runner = None
330 #: list, parameters for test runner
335 #: list, parameters for test runner
331 params = None
336 params = None
332 #: list, arguments of system call to be made to call test runner
337 #: list, arguments of system call to be made to call test runner
333 call_args = None
338 call_args = None
334 #: list, subprocesses we start (for cleanup)
339 #: list, subprocesses we start (for cleanup)
335 processes = None
340 processes = None
336 #: str, coverage xml output file
341 #: str, coverage xml output file
337 coverage_xml = None
342 coverage_xml = None
338
343
339 def __init__(self, runner='iptest', params=None):
344 def __init__(self, runner='iptest', params=None):
340 """Create new test runner."""
345 """Create new test runner."""
341 p = os.path
346 p = os.path
342 if runner == 'iptest':
347 if runner == 'iptest':
343 iptest_app = os.path.abspath(get_ipython_module_path('IPython.testing.iptest'))
348 iptest_app = os.path.abspath(get_ipython_module_path('IPython.testing.iptest'))
344 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
349 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
345 else:
350 else:
346 raise Exception('Not a valid test runner: %s' % repr(runner))
351 raise Exception('Not a valid test runner: %s' % repr(runner))
347 if params is None:
352 if params is None:
348 params = []
353 params = []
349 if isinstance(params, str):
354 if isinstance(params, str):
350 params = [params]
355 params = [params]
351 self.params = params
356 self.params = params
352
357
353 # Assemble call
358 # Assemble call
354 self.call_args = self.runner+self.params
359 self.call_args = self.runner+self.params
355
360
356 # Find the section we're testing (IPython.foo)
361 # Find the section we're testing (IPython.foo)
357 for sect in self.params:
362 for sect in self.params:
358 if sect.startswith('IPython') or sect in special_test_suites: break
363 if sect.startswith('IPython') or sect in special_test_suites: break
359 else:
364 else:
360 raise ValueError("Section not found", self.params)
365 raise ValueError("Section not found", self.params)
361
366
362 if '--with-xunit' in self.call_args:
367 if '--with-xunit' in self.call_args:
363
368
364 self.call_args.append('--xunit-file')
369 self.call_args.append('--xunit-file')
365 # FIXME: when Windows uses subprocess.call, these extra quotes are unnecessary:
370 # FIXME: when Windows uses subprocess.call, these extra quotes are unnecessary:
366 xunit_file = path.abspath(sect+'.xunit.xml')
371 xunit_file = path.abspath(sect+'.xunit.xml')
367 if sys.platform == 'win32':
372 if sys.platform == 'win32':
368 xunit_file = '"%s"' % xunit_file
373 xunit_file = '"%s"' % xunit_file
369 self.call_args.append(xunit_file)
374 self.call_args.append(xunit_file)
370
375
371 if '--with-xml-coverage' in self.call_args:
376 if '--with-xml-coverage' in self.call_args:
372 self.coverage_xml = path.abspath(sect+".coverage.xml")
377 self.coverage_xml = path.abspath(sect+".coverage.xml")
373 self.call_args.remove('--with-xml-coverage')
378 self.call_args.remove('--with-xml-coverage')
374 self.call_args = ["coverage", "run", "--source="+sect] + self.call_args[1:]
379 self.call_args = ["coverage", "run", "--source="+sect] + self.call_args[1:]
375
380
376 # Store anything we start to clean up on deletion
381 # Store anything we start to clean up on deletion
377 self.processes = []
382 self.processes = []
378
383
379 def _run_cmd(self):
384 def _run_cmd(self):
380 with TemporaryDirectory() as IPYTHONDIR:
385 with TemporaryDirectory() as IPYTHONDIR:
381 env = os.environ.copy()
386 env = os.environ.copy()
382 env['IPYTHONDIR'] = IPYTHONDIR
387 env['IPYTHONDIR'] = IPYTHONDIR
383 # print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
388 # print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
384 subp = subprocess.Popen(self.call_args, env=env)
389 subp = subprocess.Popen(self.call_args, env=env)
385 self.processes.append(subp)
390 self.processes.append(subp)
386 # If this fails, the process will be left in self.processes and
391 # If this fails, the process will be left in self.processes and
387 # cleaned up later, but if the wait call succeeds, then we can
392 # cleaned up later, but if the wait call succeeds, then we can
388 # clear the stored process.
393 # clear the stored process.
389 retcode = subp.wait()
394 retcode = subp.wait()
390 self.processes.pop()
395 self.processes.pop()
391 return retcode
396 return retcode
392
397
393 def run(self):
398 def run(self):
394 """Run the stored commands"""
399 """Run the stored commands"""
395 try:
400 try:
396 retcode = self._run_cmd()
401 retcode = self._run_cmd()
397 except KeyboardInterrupt:
402 except KeyboardInterrupt:
398 return -signal.SIGINT
403 return -signal.SIGINT
399 except:
404 except:
400 import traceback
405 import traceback
401 traceback.print_exc()
406 traceback.print_exc()
402 return 1 # signal failure
407 return 1 # signal failure
403
408
404 if self.coverage_xml:
409 if self.coverage_xml:
405 subprocess.call(["coverage", "xml", "-o", self.coverage_xml])
410 subprocess.call(["coverage", "xml", "-o", self.coverage_xml])
406 return retcode
411 return retcode
407
412
408 def __del__(self):
413 def __del__(self):
409 """Cleanup on exit by killing any leftover processes."""
414 """Cleanup on exit by killing any leftover processes."""
410 for subp in self.processes:
415 for subp in self.processes:
411 if subp.poll() is not None:
416 if subp.poll() is not None:
412 continue # process is already dead
417 continue # process is already dead
413
418
414 try:
419 try:
415 print('Cleaning up stale PID: %d' % subp.pid)
420 print('Cleaning up stale PID: %d' % subp.pid)
416 subp.kill()
421 subp.kill()
417 except: # (OSError, WindowsError) ?
422 except: # (OSError, WindowsError) ?
418 # This is just a best effort, if we fail or the process was
423 # This is just a best effort, if we fail or the process was
419 # really gone, ignore it.
424 # really gone, ignore it.
420 pass
425 pass
421 else:
426 else:
422 for i in range(10):
427 for i in range(10):
423 if subp.poll() is None:
428 if subp.poll() is None:
424 time.sleep(0.1)
429 time.sleep(0.1)
425 else:
430 else:
426 break
431 break
427
432
428 if subp.poll() is None:
433 if subp.poll() is None:
429 # The process did not die...
434 # The process did not die...
430 print('... failed. Manual cleanup may be required.')
435 print('... failed. Manual cleanup may be required.')
431
436
432
437
433 special_test_suites = {
438 special_test_suites = {
434 'autoreload': ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'],
439 'autoreload': ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'],
435 }
440 }
436
441
437 def make_runners(inc_slow=False):
442 def make_runners(inc_slow=False):
438 """Define the top-level packages that need to be tested.
443 """Define the top-level packages that need to be tested.
439 """
444 """
440
445
441 # Packages to be tested via nose, that only depend on the stdlib
446 # Packages to be tested via nose, that only depend on the stdlib
442 nose_pkg_names = ['config', 'core', 'extensions', 'lib', 'terminal',
447 nose_pkg_names = ['config', 'core', 'extensions', 'lib', 'terminal',
443 'testing', 'utils', 'nbformat' ]
448 'testing', 'utils', 'nbformat']
444
449
445 if have['qt']:
450 if have['qt']:
446 nose_pkg_names.append('qt')
451 nose_pkg_names.append('qt')
447
452
448 if have['tornado']:
453 if have['tornado']:
449 nose_pkg_names.append('html')
454 nose_pkg_names.append('html')
450
455
451 if have['zmq']:
456 if have['zmq']:
452 nose_pkg_names.append('kernel')
457 nose_pkg_names.append('kernel')
453 nose_pkg_names.append('kernel.inprocess')
458 nose_pkg_names.append('kernel.inprocess')
454 if inc_slow:
459 if inc_slow:
455 nose_pkg_names.append('parallel')
460 nose_pkg_names.append('parallel')
456
461
462 if all((have['pygments'], have['jinja2'], have['markdown'], have['sphinx'])):
463 nose_pkg_names.append('nbconvert')
464
457 # For debugging this code, only load quick stuff
465 # For debugging this code, only load quick stuff
458 #nose_pkg_names = ['core', 'extensions'] # dbg
466 #nose_pkg_names = ['core', 'extensions'] # dbg
459
467
460 # Make fully qualified package names prepending 'IPython.' to our name lists
468 # Make fully qualified package names prepending 'IPython.' to our name lists
461 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
469 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
462
470
463 # Make runners
471 # Make runners
464 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
472 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
465
473
466 for name in special_test_suites:
474 for name in special_test_suites:
467 runners.append((name, IPTester('iptest', params=name)))
475 runners.append((name, IPTester('iptest', params=name)))
468
476
469 return runners
477 return runners
470
478
471
479
472 def run_iptest():
480 def run_iptest():
473 """Run the IPython test suite using nose.
481 """Run the IPython test suite using nose.
474
482
475 This function is called when this script is **not** called with the form
483 This function is called when this script is **not** called with the form
476 `iptest all`. It simply calls nose with appropriate command line flags
484 `iptest all`. It simply calls nose with appropriate command line flags
477 and accepts all of the standard nose arguments.
485 and accepts all of the standard nose arguments.
478 """
486 """
479 # Apply our monkeypatch to Xunit
487 # Apply our monkeypatch to Xunit
480 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
488 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
481 monkeypatch_xunit()
489 monkeypatch_xunit()
482
490
483 warnings.filterwarnings('ignore',
491 warnings.filterwarnings('ignore',
484 'This will be removed soon. Use IPython.testing.util instead')
492 'This will be removed soon. Use IPython.testing.util instead')
485
493
486 if sys.argv[1] in special_test_suites:
494 if sys.argv[1] in special_test_suites:
487 sys.argv[1:2] = special_test_suites[sys.argv[1]]
495 sys.argv[1:2] = special_test_suites[sys.argv[1]]
488 special_suite = True
496 special_suite = True
489 else:
497 else:
490 special_suite = False
498 special_suite = False
491
499
492 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
500 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
493
501
494 '--with-ipdoctest',
502 '--with-ipdoctest',
495 '--ipdoctest-tests','--ipdoctest-extension=txt',
503 '--ipdoctest-tests','--ipdoctest-extension=txt',
496
504
497 # We add --exe because of setuptools' imbecility (it
505 # We add --exe because of setuptools' imbecility (it
498 # blindly does chmod +x on ALL files). Nose does the
506 # blindly does chmod +x on ALL files). Nose does the
499 # right thing and it tries to avoid executables,
507 # right thing and it tries to avoid executables,
500 # setuptools unfortunately forces our hand here. This
508 # setuptools unfortunately forces our hand here. This
501 # has been discussed on the distutils list and the
509 # has been discussed on the distutils list and the
502 # setuptools devs refuse to fix this problem!
510 # setuptools devs refuse to fix this problem!
503 '--exe',
511 '--exe',
504 ]
512 ]
505 if '-a' not in argv and '-A' not in argv:
513 if '-a' not in argv and '-A' not in argv:
506 argv = argv + ['-a', '!crash']
514 argv = argv + ['-a', '!crash']
507
515
508 if nose.__version__ >= '0.11':
516 if nose.__version__ >= '0.11':
509 # I don't fully understand why we need this one, but depending on what
517 # I don't fully understand why we need this one, but depending on what
510 # directory the test suite is run from, if we don't give it, 0 tests
518 # directory the test suite is run from, if we don't give it, 0 tests
511 # get run. Specifically, if the test suite is run from the source dir
519 # get run. Specifically, if the test suite is run from the source dir
512 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
520 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
513 # even if the same call done in this directory works fine). It appears
521 # even if the same call done in this directory works fine). It appears
514 # that if the requested package is in the current dir, nose bails early
522 # that if the requested package is in the current dir, nose bails early
515 # by default. Since it's otherwise harmless, leave it in by default
523 # by default. Since it's otherwise harmless, leave it in by default
516 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
524 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
517 argv.append('--traverse-namespace')
525 argv.append('--traverse-namespace')
518
526
519 # use our plugin for doctesting. It will remove the standard doctest plugin
527 # use our plugin for doctesting. It will remove the standard doctest plugin
520 # if it finds it enabled
528 # if it finds it enabled
521 ipdt = IPythonDoctest() if special_suite else IPythonDoctest(make_exclude())
529 ipdt = IPythonDoctest() if special_suite else IPythonDoctest(make_exclude())
522 plugins = [ipdt, KnownFailure()]
530 plugins = [ipdt, KnownFailure()]
523
531
524 # We need a global ipython running in this process, but the special
532 # We need a global ipython running in this process, but the special
525 # in-process group spawns its own IPython kernels, so for *that* group we
533 # in-process group spawns its own IPython kernels, so for *that* group we
526 # must avoid also opening the global one (otherwise there's a conflict of
534 # must avoid also opening the global one (otherwise there's a conflict of
527 # singletons). Ultimately the solution to this problem is to refactor our
535 # singletons). Ultimately the solution to this problem is to refactor our
528 # assumptions about what needs to be a singleton and what doesn't (app
536 # assumptions about what needs to be a singleton and what doesn't (app
529 # objects should, individual shells shouldn't). But for now, this
537 # objects should, individual shells shouldn't). But for now, this
530 # workaround allows the test suite for the inprocess module to complete.
538 # workaround allows the test suite for the inprocess module to complete.
531 if not 'IPython.kernel.inprocess' in sys.argv:
539 if not 'IPython.kernel.inprocess' in sys.argv:
532 globalipapp.start_ipython()
540 globalipapp.start_ipython()
533
541
534 # Now nose can run
542 # Now nose can run
535 TestProgram(argv=argv, addplugins=plugins)
543 TestProgram(argv=argv, addplugins=plugins)
536
544
537
545
538 def run_iptestall(inc_slow=False):
546 def run_iptestall(inc_slow=False):
539 """Run the entire IPython test suite by calling nose and trial.
547 """Run the entire IPython test suite by calling nose and trial.
540
548
541 This function constructs :class:`IPTester` instances for all IPython
549 This function constructs :class:`IPTester` instances for all IPython
542 modules and package and then runs each of them. This causes the modules
550 modules and package and then runs each of them. This causes the modules
543 and packages of IPython to be tested each in their own subprocess using
551 and packages of IPython to be tested each in their own subprocess using
544 nose.
552 nose.
545
553
546 Parameters
554 Parameters
547 ----------
555 ----------
548
556
549 inc_slow : bool, optional
557 inc_slow : bool, optional
550 Include slow tests, like IPython.parallel. By default, these tests aren't
558 Include slow tests, like IPython.parallel. By default, these tests aren't
551 run.
559 run.
552 """
560 """
553
561
554 runners = make_runners(inc_slow=inc_slow)
562 runners = make_runners(inc_slow=inc_slow)
555
563
556 # Run the test runners in a temporary dir so we can nuke it when finished
564 # Run the test runners in a temporary dir so we can nuke it when finished
557 # to clean up any junk files left over by accident. This also makes it
565 # to clean up any junk files left over by accident. This also makes it
558 # robust against being run in non-writeable directories by mistake, as the
566 # robust against being run in non-writeable directories by mistake, as the
559 # temp dir will always be user-writeable.
567 # temp dir will always be user-writeable.
560 curdir = os.getcwdu()
568 curdir = os.getcwdu()
561 testdir = tempfile.gettempdir()
569 testdir = tempfile.gettempdir()
562 os.chdir(testdir)
570 os.chdir(testdir)
563
571
564 # Run all test runners, tracking execution time
572 # Run all test runners, tracking execution time
565 failed = []
573 failed = []
566 t_start = time.time()
574 t_start = time.time()
567 try:
575 try:
568 for (name, runner) in runners:
576 for (name, runner) in runners:
569 print('*'*70)
577 print('*'*70)
570 print('IPython test group:',name)
578 print('IPython test group:',name)
571 res = runner.run()
579 res = runner.run()
572 if res:
580 if res:
573 failed.append( (name, runner) )
581 failed.append( (name, runner) )
574 if res == -signal.SIGINT:
582 if res == -signal.SIGINT:
575 print("Interrupted")
583 print("Interrupted")
576 break
584 break
577 finally:
585 finally:
578 os.chdir(curdir)
586 os.chdir(curdir)
579 t_end = time.time()
587 t_end = time.time()
580 t_tests = t_end - t_start
588 t_tests = t_end - t_start
581 nrunners = len(runners)
589 nrunners = len(runners)
582 nfail = len(failed)
590 nfail = len(failed)
583 # summarize results
591 # summarize results
584 print()
592 print()
585 print('*'*70)
593 print('*'*70)
586 print('Test suite completed for system with the following information:')
594 print('Test suite completed for system with the following information:')
587 print(report())
595 print(report())
588 print('Ran %s test groups in %.3fs' % (nrunners, t_tests))
596 print('Ran %s test groups in %.3fs' % (nrunners, t_tests))
589 print()
597 print()
590 print('Status:')
598 print('Status:')
591 if not failed:
599 if not failed:
592 print('OK')
600 print('OK')
593 else:
601 else:
594 # If anything went wrong, point out what command to rerun manually to
602 # If anything went wrong, point out what command to rerun manually to
595 # see the actual errors and individual summary
603 # see the actual errors and individual summary
596 print('ERROR - %s out of %s test groups failed.' % (nfail, nrunners))
604 print('ERROR - %s out of %s test groups failed.' % (nfail, nrunners))
597 for name, failed_runner in failed:
605 for name, failed_runner in failed:
598 print('-'*40)
606 print('-'*40)
599 print('Runner failed:',name)
607 print('Runner failed:',name)
600 print('You may wish to rerun this one individually, with:')
608 print('You may wish to rerun this one individually, with:')
601 failed_call_args = [py3compat.cast_unicode(x) for x in failed_runner.call_args]
609 failed_call_args = [py3compat.cast_unicode(x) for x in failed_runner.call_args]
602 print(u' '.join(failed_call_args))
610 print(u' '.join(failed_call_args))
603 print()
611 print()
604 # Ensure that our exit code indicates failure
612 # Ensure that our exit code indicates failure
605 sys.exit(1)
613 sys.exit(1)
606
614
607
615
608 def main():
616 def main():
609 for arg in sys.argv[1:]:
617 for arg in sys.argv[1:]:
610 if arg.startswith('IPython') or arg in special_test_suites:
618 if arg.startswith('IPython') or arg in special_test_suites:
611 # This is in-process
619 # This is in-process
612 run_iptest()
620 run_iptest()
613 else:
621 else:
614 if "--all" in sys.argv:
622 if "--all" in sys.argv:
615 sys.argv.remove("--all")
623 sys.argv.remove("--all")
616 inc_slow = True
624 inc_slow = True
617 else:
625 else:
618 inc_slow = False
626 inc_slow = False
619 # This starts subprocesses
627 # This starts subprocesses
620 run_iptestall(inc_slow=inc_slow)
628 run_iptestall(inc_slow=inc_slow)
621
629
622
630
623 if __name__ == '__main__':
631 if __name__ == '__main__':
624 main()
632 main()
@@ -1,347 +1,348 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
2 # -*- coding: utf-8 -*-
3 """Setup script for IPython.
3 """Setup script for IPython.
4
4
5 Under Posix environments it works like a typical setup.py script.
5 Under Posix environments it works like a typical setup.py script.
6 Under Windows, the command sdist is not supported, since IPython
6 Under Windows, the command sdist is not supported, since IPython
7 requires utilities which are not available under Windows."""
7 requires utilities which are not available under Windows."""
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (c) 2008-2011, IPython Development Team.
10 # Copyright (c) 2008-2011, IPython Development Team.
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14 #
14 #
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16 #
16 #
17 # 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.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Minimal Python version sanity check
21 # Minimal Python version sanity check
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 from __future__ import print_function
23 from __future__ import print_function
24
24
25 import sys
25 import sys
26
26
27 # This check is also made in IPython/__init__, don't forget to update both when
27 # This check is also made in IPython/__init__, don't forget to update both when
28 # changing Python version requirements.
28 # changing Python version requirements.
29 #~ if sys.version[0:3] < '2.6':
29 #~ if sys.version[0:3] < '2.6':
30 #~ error = """\
30 #~ error = """\
31 #~ ERROR: 'IPython requires Python Version 2.6 or above.'
31 #~ ERROR: 'IPython requires Python Version 2.6 or above.'
32 #~ Exiting."""
32 #~ Exiting."""
33 #~ print >> sys.stderr, error
33 #~ print >> sys.stderr, error
34 #~ sys.exit(1)
34 #~ sys.exit(1)
35
35
36 PY3 = (sys.version_info[0] >= 3)
36 PY3 = (sys.version_info[0] >= 3)
37
37
38 # At least we're on the python version we need, move on.
38 # At least we're on the python version we need, move on.
39
39
40 #-------------------------------------------------------------------------------
40 #-------------------------------------------------------------------------------
41 # Imports
41 # Imports
42 #-------------------------------------------------------------------------------
42 #-------------------------------------------------------------------------------
43
43
44 # Stdlib imports
44 # Stdlib imports
45 import os
45 import os
46 import shutil
46 import shutil
47
47
48 from glob import glob
48 from glob import glob
49
49
50 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
50 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
51 # update it when the contents of directories change.
51 # update it when the contents of directories change.
52 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
52 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
53
53
54 from distutils.core import setup
54 from distutils.core import setup
55
55
56 # On Python 3, we need distribute (new setuptools) to do the 2to3 conversion
56 # On Python 3, we need distribute (new setuptools) to do the 2to3 conversion
57 if PY3:
57 if PY3:
58 import setuptools
58 import setuptools
59
59
60 # Our own imports
60 # Our own imports
61 from setupbase import target_update
61 from setupbase import target_update
62
62
63 from setupbase import (
63 from setupbase import (
64 setup_args,
64 setup_args,
65 find_packages,
65 find_packages,
66 find_package_data,
66 find_package_data,
67 find_scripts,
67 find_scripts,
68 find_data_files,
68 find_data_files,
69 check_for_dependencies,
69 check_for_dependencies,
70 git_prebuild,
70 git_prebuild,
71 check_submodule_status,
71 check_submodule_status,
72 update_submodules,
72 update_submodules,
73 require_submodules,
73 require_submodules,
74 UpdateSubmodules,
74 UpdateSubmodules,
75 )
75 )
76 from setupext import setupext
76 from setupext import setupext
77
77
78 isfile = os.path.isfile
78 isfile = os.path.isfile
79 pjoin = os.path.join
79 pjoin = os.path.join
80
80
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 # Function definitions
82 # Function definitions
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84
84
85 def cleanup():
85 def cleanup():
86 """Clean up the junk left around by the build process"""
86 """Clean up the junk left around by the build process"""
87 if "develop" not in sys.argv and "egg_info" not in sys.argv:
87 if "develop" not in sys.argv and "egg_info" not in sys.argv:
88 try:
88 try:
89 shutil.rmtree('ipython.egg-info')
89 shutil.rmtree('ipython.egg-info')
90 except:
90 except:
91 try:
91 try:
92 os.unlink('ipython.egg-info')
92 os.unlink('ipython.egg-info')
93 except:
93 except:
94 pass
94 pass
95
95
96 #-------------------------------------------------------------------------------
96 #-------------------------------------------------------------------------------
97 # Handle OS specific things
97 # Handle OS specific things
98 #-------------------------------------------------------------------------------
98 #-------------------------------------------------------------------------------
99
99
100 if os.name in ('nt','dos'):
100 if os.name in ('nt','dos'):
101 os_name = 'windows'
101 os_name = 'windows'
102 else:
102 else:
103 os_name = os.name
103 os_name = os.name
104
104
105 # Under Windows, 'sdist' has not been supported. Now that the docs build with
105 # Under Windows, 'sdist' has not been supported. Now that the docs build with
106 # Sphinx it might work, but let's not turn it on until someone confirms that it
106 # Sphinx it might work, but let's not turn it on until someone confirms that it
107 # actually works.
107 # actually works.
108 if os_name == 'windows' and 'sdist' in sys.argv:
108 if os_name == 'windows' and 'sdist' in sys.argv:
109 print('The sdist command is not available under Windows. Exiting.')
109 print('The sdist command is not available under Windows. Exiting.')
110 sys.exit(1)
110 sys.exit(1)
111
111
112 #-------------------------------------------------------------------------------
112 #-------------------------------------------------------------------------------
113 # Make sure we aren't trying to run without submodules
113 # Make sure we aren't trying to run without submodules
114 #-------------------------------------------------------------------------------
114 #-------------------------------------------------------------------------------
115 here = os.path.abspath(os.path.dirname(__file__))
115 here = os.path.abspath(os.path.dirname(__file__))
116
116
117 def require_clean_submodules():
117 def require_clean_submodules():
118 """Check on git submodules before distutils can do anything
118 """Check on git submodules before distutils can do anything
119
119
120 Since distutils cannot be trusted to update the tree
120 Since distutils cannot be trusted to update the tree
121 after everything has been set in motion,
121 after everything has been set in motion,
122 this is not a distutils command.
122 this is not a distutils command.
123 """
123 """
124 # PACKAGERS: Add a return here to skip checks for git submodules
124 # PACKAGERS: Add a return here to skip checks for git submodules
125
125
126 # don't do anything if nothing is actually supposed to happen
126 # don't do anything if nothing is actually supposed to happen
127 for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule'):
127 for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule'):
128 if do_nothing in sys.argv:
128 if do_nothing in sys.argv:
129 return
129 return
130
130
131 status = check_submodule_status(here)
131 status = check_submodule_status(here)
132
132
133 if status == "missing":
133 if status == "missing":
134 print("checking out submodules for the first time")
134 print("checking out submodules for the first time")
135 update_submodules(here)
135 update_submodules(here)
136 elif status == "unclean":
136 elif status == "unclean":
137 print('\n'.join([
137 print('\n'.join([
138 "Cannot build / install IPython with unclean submodules",
138 "Cannot build / install IPython with unclean submodules",
139 "Please update submodules with",
139 "Please update submodules with",
140 " python setup.py submodule",
140 " python setup.py submodule",
141 "or",
141 "or",
142 " git submodule update",
142 " git submodule update",
143 "or commit any submodule changes you have made."
143 "or commit any submodule changes you have made."
144 ]))
144 ]))
145 sys.exit(1)
145 sys.exit(1)
146
146
147 require_clean_submodules()
147 require_clean_submodules()
148
148
149 #-------------------------------------------------------------------------------
149 #-------------------------------------------------------------------------------
150 # Things related to the IPython documentation
150 # Things related to the IPython documentation
151 #-------------------------------------------------------------------------------
151 #-------------------------------------------------------------------------------
152
152
153 # update the manuals when building a source dist
153 # update the manuals when building a source dist
154 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
154 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
155 import textwrap
155 import textwrap
156
156
157 # List of things to be updated. Each entry is a triplet of args for
157 # List of things to be updated. Each entry is a triplet of args for
158 # target_update()
158 # target_update()
159 to_update = [
159 to_update = [
160 # FIXME - Disabled for now: we need to redo an automatic way
160 # FIXME - Disabled for now: we need to redo an automatic way
161 # of generating the magic info inside the rst.
161 # of generating the magic info inside the rst.
162 #('docs/magic.tex',
162 #('docs/magic.tex',
163 #['IPython/Magic.py'],
163 #['IPython/Magic.py'],
164 #"cd doc && ./update_magic.sh" ),
164 #"cd doc && ./update_magic.sh" ),
165
165
166 ('docs/man/ipcluster.1.gz',
166 ('docs/man/ipcluster.1.gz',
167 ['docs/man/ipcluster.1'],
167 ['docs/man/ipcluster.1'],
168 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
168 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
169
169
170 ('docs/man/ipcontroller.1.gz',
170 ('docs/man/ipcontroller.1.gz',
171 ['docs/man/ipcontroller.1'],
171 ['docs/man/ipcontroller.1'],
172 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
172 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
173
173
174 ('docs/man/ipengine.1.gz',
174 ('docs/man/ipengine.1.gz',
175 ['docs/man/ipengine.1'],
175 ['docs/man/ipengine.1'],
176 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
176 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
177
177
178 ('docs/man/iplogger.1.gz',
178 ('docs/man/iplogger.1.gz',
179 ['docs/man/iplogger.1'],
179 ['docs/man/iplogger.1'],
180 'cd docs/man && gzip -9c iplogger.1 > iplogger.1.gz'),
180 'cd docs/man && gzip -9c iplogger.1 > iplogger.1.gz'),
181
181
182 ('docs/man/ipython.1.gz',
182 ('docs/man/ipython.1.gz',
183 ['docs/man/ipython.1'],
183 ['docs/man/ipython.1'],
184 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
184 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
185
185
186 ('docs/man/irunner.1.gz',
186 ('docs/man/irunner.1.gz',
187 ['docs/man/irunner.1'],
187 ['docs/man/irunner.1'],
188 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
188 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
189
189
190 ('docs/man/pycolor.1.gz',
190 ('docs/man/pycolor.1.gz',
191 ['docs/man/pycolor.1'],
191 ['docs/man/pycolor.1'],
192 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
192 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
193 ]
193 ]
194
194
195
195
196 [ target_update(*t) for t in to_update ]
196 [ target_update(*t) for t in to_update ]
197
197
198 #---------------------------------------------------------------------------
198 #---------------------------------------------------------------------------
199 # Find all the packages, package data, and data_files
199 # Find all the packages, package data, and data_files
200 #---------------------------------------------------------------------------
200 #---------------------------------------------------------------------------
201
201
202 packages = find_packages()
202 packages = find_packages()
203 package_data = find_package_data()
203 package_data = find_package_data()
204 data_files = find_data_files()
204 data_files = find_data_files()
205
205
206 setup_args['packages'] = packages
206 setup_args['packages'] = packages
207 setup_args['package_data'] = package_data
207 setup_args['package_data'] = package_data
208 setup_args['data_files'] = data_files
208 setup_args['data_files'] = data_files
209
209
210 #---------------------------------------------------------------------------
210 #---------------------------------------------------------------------------
211 # custom distutils commands
211 # custom distutils commands
212 #---------------------------------------------------------------------------
212 #---------------------------------------------------------------------------
213 # imports here, so they are after setuptools import if there was one
213 # imports here, so they are after setuptools import if there was one
214 from distutils.command.sdist import sdist
214 from distutils.command.sdist import sdist
215 from distutils.command.upload import upload
215 from distutils.command.upload import upload
216
216
217 class UploadWindowsInstallers(upload):
217 class UploadWindowsInstallers(upload):
218
218
219 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
219 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
220 user_options = upload.user_options + [
220 user_options = upload.user_options + [
221 ('files=', 'f', 'exe file (or glob) to upload')
221 ('files=', 'f', 'exe file (or glob) to upload')
222 ]
222 ]
223 def initialize_options(self):
223 def initialize_options(self):
224 upload.initialize_options(self)
224 upload.initialize_options(self)
225 meta = self.distribution.metadata
225 meta = self.distribution.metadata
226 base = '{name}-{version}'.format(
226 base = '{name}-{version}'.format(
227 name=meta.get_name(),
227 name=meta.get_name(),
228 version=meta.get_version()
228 version=meta.get_version()
229 )
229 )
230 self.files = os.path.join('dist', '%s.*.exe' % base)
230 self.files = os.path.join('dist', '%s.*.exe' % base)
231
231
232 def run(self):
232 def run(self):
233 for dist_file in glob(self.files):
233 for dist_file in glob(self.files):
234 self.upload_file('bdist_wininst', 'any', dist_file)
234 self.upload_file('bdist_wininst', 'any', dist_file)
235
235
236 setup_args['cmdclass'] = {
236 setup_args['cmdclass'] = {
237 'build_py': git_prebuild('IPython'),
237 'build_py': git_prebuild('IPython'),
238 'sdist' : git_prebuild('IPython', sdist),
238 'sdist' : git_prebuild('IPython', sdist),
239 'upload_wininst' : UploadWindowsInstallers,
239 'upload_wininst' : UploadWindowsInstallers,
240 'submodule' : UpdateSubmodules,
240 'submodule' : UpdateSubmodules,
241 }
241 }
242
242
243 #---------------------------------------------------------------------------
243 #---------------------------------------------------------------------------
244 # Handle scripts, dependencies, and setuptools specific things
244 # Handle scripts, dependencies, and setuptools specific things
245 #---------------------------------------------------------------------------
245 #---------------------------------------------------------------------------
246
246
247 # For some commands, use setuptools. Note that we do NOT list install here!
247 # For some commands, use setuptools. Note that we do NOT list install here!
248 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
248 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
249 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
249 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
250 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
250 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
251 'egg_info', 'easy_install', 'upload',
251 'egg_info', 'easy_install', 'upload',
252 ))
252 ))
253 if sys.platform == 'win32':
253 if sys.platform == 'win32':
254 # Depend on setuptools for install on *Windows only*
254 # Depend on setuptools for install on *Windows only*
255 # If we get script-installation working without setuptools,
255 # If we get script-installation working without setuptools,
256 # then we can back off, but until then use it.
256 # then we can back off, but until then use it.
257 # See Issue #369 on GitHub for more
257 # See Issue #369 on GitHub for more
258 needs_setuptools.add('install')
258 needs_setuptools.add('install')
259
259
260 if len(needs_setuptools.intersection(sys.argv)) > 0:
260 if len(needs_setuptools.intersection(sys.argv)) > 0:
261 import setuptools
261 import setuptools
262
262
263 # This dict is used for passing extra arguments that are setuptools
263 # This dict is used for passing extra arguments that are setuptools
264 # specific to setup
264 # specific to setup
265 setuptools_extra_args = {}
265 setuptools_extra_args = {}
266
266
267 if 'setuptools' in sys.modules:
267 if 'setuptools' in sys.modules:
268 # setup.py develop should check for submodules
268 # setup.py develop should check for submodules
269 from setuptools.command.develop import develop
269 from setuptools.command.develop import develop
270 setup_args['cmdclass']['develop'] = require_submodules(develop)
270 setup_args['cmdclass']['develop'] = require_submodules(develop)
271
271
272 setuptools_extra_args['zip_safe'] = False
272 setuptools_extra_args['zip_safe'] = False
273 setuptools_extra_args['entry_points'] = find_scripts(True)
273 setuptools_extra_args['entry_points'] = find_scripts(True)
274 setup_args['extras_require'] = dict(
274 setup_args['extras_require'] = dict(
275 parallel = 'pyzmq>=2.1.11',
275 parallel = 'pyzmq>=2.1.11',
276 qtconsole = ['pyzmq>=2.1.11', 'pygments'],
276 qtconsole = ['pyzmq>=2.1.11', 'pygments'],
277 zmq = 'pyzmq>=2.1.11',
277 zmq = 'pyzmq>=2.1.11',
278 doc = 'Sphinx>=0.3',
278 doc = 'Sphinx>=0.3',
279 test = 'nose>=0.10.1',
279 test = 'nose>=0.10.1',
280 notebook = ['tornado>=2.0', 'pyzmq>=2.1.11', 'jinja2'],
280 notebook = ['tornado>=2.0', 'pyzmq>=2.1.11', 'jinja2'],
281 nbconvert = ['pygments', 'markdown', 'jinja2', 'Sphinx>=0.3']
281 )
282 )
282 requires = setup_args.setdefault('install_requires', [])
283 requires = setup_args.setdefault('install_requires', [])
283 setupext.display_status = False
284 setupext.display_status = False
284 if not setupext.check_for_readline():
285 if not setupext.check_for_readline():
285 if sys.platform == 'darwin':
286 if sys.platform == 'darwin':
286 requires.append('readline')
287 requires.append('readline')
287 elif sys.platform.startswith('win'):
288 elif sys.platform.startswith('win'):
288 # Pyreadline 64 bit windows issue solved in versions >=1.7.1
289 # Pyreadline 64 bit windows issue solved in versions >=1.7.1
289 # Also solves issues with some older versions of pyreadline that
290 # Also solves issues with some older versions of pyreadline that
290 # satisfy the unconstrained depdendency.
291 # satisfy the unconstrained depdendency.
291 requires.append('pyreadline>=1.7.1')
292 requires.append('pyreadline>=1.7.1')
292 else:
293 else:
293 pass
294 pass
294 # do we want to install readline here?
295 # do we want to install readline here?
295
296
296 # Script to be run by the windows binary installer after the default setup
297 # Script to be run by the windows binary installer after the default setup
297 # routine, to add shortcuts and similar windows-only things. Windows
298 # routine, to add shortcuts and similar windows-only things. Windows
298 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
299 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
299 # doesn't find them.
300 # doesn't find them.
300 if 'bdist_wininst' in sys.argv:
301 if 'bdist_wininst' in sys.argv:
301 if len(sys.argv) > 2 and \
302 if len(sys.argv) > 2 and \
302 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
303 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
303 print >> sys.stderr, "ERROR: bdist_wininst must be run alone. Exiting."
304 print >> sys.stderr, "ERROR: bdist_wininst must be run alone. Exiting."
304 sys.exit(1)
305 sys.exit(1)
305 setup_args['data_files'].append(
306 setup_args['data_files'].append(
306 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
307 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
307 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
308 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
308 setup_args['options'] = {"bdist_wininst":
309 setup_args['options'] = {"bdist_wininst":
309 {"install_script":
310 {"install_script":
310 "ipython_win_post_install.py"}}
311 "ipython_win_post_install.py"}}
311
312
312 if PY3:
313 if PY3:
313 setuptools_extra_args['use_2to3'] = True
314 setuptools_extra_args['use_2to3'] = True
314 # we try to make a 2.6, 2.7, and 3.1 to 3.3 python compatible code
315 # we try to make a 2.6, 2.7, and 3.1 to 3.3 python compatible code
315 # so we explicitly disable some 2to3 fixes to be sure we aren't forgetting
316 # so we explicitly disable some 2to3 fixes to be sure we aren't forgetting
316 # anything.
317 # anything.
317 setuptools_extra_args['use_2to3_exclude_fixers'] = [
318 setuptools_extra_args['use_2to3_exclude_fixers'] = [
318 'lib2to3.fixes.fix_apply',
319 'lib2to3.fixes.fix_apply',
319 'lib2to3.fixes.fix_except',
320 'lib2to3.fixes.fix_except',
320 'lib2to3.fixes.fix_has_key',
321 'lib2to3.fixes.fix_has_key',
321 'lib2to3.fixes.fix_next',
322 'lib2to3.fixes.fix_next',
322 'lib2to3.fixes.fix_repr',
323 'lib2to3.fixes.fix_repr',
323 'lib2to3.fixes.fix_tuple_params',
324 'lib2to3.fixes.fix_tuple_params',
324 ]
325 ]
325 from setuptools.command.build_py import build_py
326 from setuptools.command.build_py import build_py
326 setup_args['cmdclass'] = {'build_py': git_prebuild('IPython', build_cmd=build_py)}
327 setup_args['cmdclass'] = {'build_py': git_prebuild('IPython', build_cmd=build_py)}
327 setuptools_extra_args['entry_points'] = find_scripts(True, suffix='3')
328 setuptools_extra_args['entry_points'] = find_scripts(True, suffix='3')
328 setuptools._dont_write_bytecode = True
329 setuptools._dont_write_bytecode = True
329 else:
330 else:
330 # If we are running without setuptools, call this function which will
331 # If we are running without setuptools, call this function which will
331 # check for dependencies an inform the user what is needed. This is
332 # check for dependencies an inform the user what is needed. This is
332 # just to make life easy for users.
333 # just to make life easy for users.
333 check_for_dependencies()
334 check_for_dependencies()
334 setup_args['scripts'] = find_scripts(False)
335 setup_args['scripts'] = find_scripts(False)
335
336
336 #---------------------------------------------------------------------------
337 #---------------------------------------------------------------------------
337 # Do the actual setup now
338 # Do the actual setup now
338 #---------------------------------------------------------------------------
339 #---------------------------------------------------------------------------
339
340
340 setup_args.update(setuptools_extra_args)
341 setup_args.update(setuptools_extra_args)
341
342
342 def main():
343 def main():
343 setup(**setup_args)
344 setup(**setup_args)
344 cleanup()
345 cleanup()
345
346
346 if __name__ == '__main__':
347 if __name__ == '__main__':
347 main()
348 main()
@@ -1,469 +1,474 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 This module defines the things that are used in setup.py for building IPython
3 This module defines the things that are used in setup.py for building IPython
4
4
5 This includes:
5 This includes:
6
6
7 * The basic arguments to setup
7 * The basic arguments to setup
8 * Functions for finding things like packages, package data, etc.
8 * Functions for finding things like packages, package data, etc.
9 * A function for checking dependencies.
9 * A function for checking dependencies.
10 """
10 """
11 from __future__ import print_function
11 from __future__ import print_function
12
12
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19
19
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-------------------------------------------------------------------------------
22 #-------------------------------------------------------------------------------
23 import os
23 import os
24 import sys
24 import sys
25
25
26 try:
26 try:
27 from configparser import ConfigParser
27 from configparser import ConfigParser
28 except:
28 except:
29 from ConfigParser import ConfigParser
29 from ConfigParser import ConfigParser
30 from distutils.command.build_py import build_py
30 from distutils.command.build_py import build_py
31 from distutils.cmd import Command
31 from distutils.cmd import Command
32 from glob import glob
32 from glob import glob
33
33
34 from setupext import install_data_ext
34 from setupext import install_data_ext
35
35
36 #-------------------------------------------------------------------------------
36 #-------------------------------------------------------------------------------
37 # Useful globals and utility functions
37 # Useful globals and utility functions
38 #-------------------------------------------------------------------------------
38 #-------------------------------------------------------------------------------
39
39
40 # A few handy globals
40 # A few handy globals
41 isfile = os.path.isfile
41 isfile = os.path.isfile
42 pjoin = os.path.join
42 pjoin = os.path.join
43 repo_root = os.path.dirname(os.path.abspath(__file__))
43 repo_root = os.path.dirname(os.path.abspath(__file__))
44
44
45 def oscmd(s):
45 def oscmd(s):
46 print(">", s)
46 print(">", s)
47 os.system(s)
47 os.system(s)
48
48
49 # Py3 compatibility hacks, without assuming IPython itself is installed with
49 # Py3 compatibility hacks, without assuming IPython itself is installed with
50 # the full py3compat machinery.
50 # the full py3compat machinery.
51
51
52 try:
52 try:
53 execfile
53 execfile
54 except NameError:
54 except NameError:
55 def execfile(fname, globs, locs=None):
55 def execfile(fname, globs, locs=None):
56 locs = locs or globs
56 locs = locs or globs
57 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
57 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
58
58
59 # A little utility we'll need below, since glob() does NOT allow you to do
59 # A little utility we'll need below, since glob() does NOT allow you to do
60 # exclusion on multiple endings!
60 # exclusion on multiple endings!
61 def file_doesnt_endwith(test,endings):
61 def file_doesnt_endwith(test,endings):
62 """Return true if test is a file and its name does NOT end with any
62 """Return true if test is a file and its name does NOT end with any
63 of the strings listed in endings."""
63 of the strings listed in endings."""
64 if not isfile(test):
64 if not isfile(test):
65 return False
65 return False
66 for e in endings:
66 for e in endings:
67 if test.endswith(e):
67 if test.endswith(e):
68 return False
68 return False
69 return True
69 return True
70
70
71 #---------------------------------------------------------------------------
71 #---------------------------------------------------------------------------
72 # Basic project information
72 # Basic project information
73 #---------------------------------------------------------------------------
73 #---------------------------------------------------------------------------
74
74
75 # release.py contains version, authors, license, url, keywords, etc.
75 # release.py contains version, authors, license, url, keywords, etc.
76 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
76 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
77
77
78 # Create a dict with the basic information
78 # Create a dict with the basic information
79 # This dict is eventually passed to setup after additional keys are added.
79 # This dict is eventually passed to setup after additional keys are added.
80 setup_args = dict(
80 setup_args = dict(
81 name = name,
81 name = name,
82 version = version,
82 version = version,
83 description = description,
83 description = description,
84 long_description = long_description,
84 long_description = long_description,
85 author = author,
85 author = author,
86 author_email = author_email,
86 author_email = author_email,
87 url = url,
87 url = url,
88 download_url = download_url,
88 download_url = download_url,
89 license = license,
89 license = license,
90 platforms = platforms,
90 platforms = platforms,
91 keywords = keywords,
91 keywords = keywords,
92 classifiers = classifiers,
92 classifiers = classifiers,
93 cmdclass = {'install_data': install_data_ext},
93 cmdclass = {'install_data': install_data_ext},
94 )
94 )
95
95
96
96
97 #---------------------------------------------------------------------------
97 #---------------------------------------------------------------------------
98 # Find packages
98 # Find packages
99 #---------------------------------------------------------------------------
99 #---------------------------------------------------------------------------
100
100
101 def find_packages():
101 def find_packages():
102 """
102 """
103 Find all of IPython's packages.
103 Find all of IPython's packages.
104 """
104 """
105 excludes = ['deathrow', 'quarantine']
105 excludes = ['deathrow', 'quarantine']
106 packages = []
106 packages = []
107 for dir,subdirs,files in os.walk('IPython'):
107 for dir,subdirs,files in os.walk('IPython'):
108 package = dir.replace(os.path.sep, '.')
108 package = dir.replace(os.path.sep, '.')
109 if any(package.startswith('IPython.'+exc) for exc in excludes):
109 if any(package.startswith('IPython.'+exc) for exc in excludes):
110 # package is to be excluded (e.g. deathrow)
110 # package is to be excluded (e.g. deathrow)
111 continue
111 continue
112 if '__init__.py' not in files:
112 if '__init__.py' not in files:
113 # not a package
113 # not a package
114 continue
114 continue
115 packages.append(package)
115 packages.append(package)
116 return packages
116 return packages
117
117
118 #---------------------------------------------------------------------------
118 #---------------------------------------------------------------------------
119 # Find package data
119 # Find package data
120 #---------------------------------------------------------------------------
120 #---------------------------------------------------------------------------
121
121
122 def find_package_data():
122 def find_package_data():
123 """
123 """
124 Find IPython's package_data.
124 Find IPython's package_data.
125 """
125 """
126 # This is not enough for these things to appear in an sdist.
126 # This is not enough for these things to appear in an sdist.
127 # We need to muck with the MANIFEST to get this to work
127 # We need to muck with the MANIFEST to get this to work
128
128
129 # exclude static things that we don't ship (e.g. mathjax)
129 # exclude static things that we don't ship (e.g. mathjax)
130 excludes = ['mathjax']
130 excludes = ['mathjax']
131
131
132 # add 'static/' prefix to exclusions, and tuplify for use in startswith
132 # add 'static/' prefix to exclusions, and tuplify for use in startswith
133 excludes = tuple([os.path.join('static', ex) for ex in excludes])
133 excludes = tuple([os.path.join('static', ex) for ex in excludes])
134
134
135 # walk notebook resources:
135 # walk notebook resources:
136 cwd = os.getcwd()
136 cwd = os.getcwd()
137 os.chdir(os.path.join('IPython', 'html'))
137 os.chdir(os.path.join('IPython', 'html'))
138 static_walk = list(os.walk('static'))
138 static_walk = list(os.walk('static'))
139 os.chdir(cwd)
139 os.chdir(cwd)
140 static_data = []
140 static_data = []
141 for parent, dirs, files in static_walk:
141 for parent, dirs, files in static_walk:
142 if parent.startswith(excludes):
142 if parent.startswith(excludes):
143 continue
143 continue
144 for f in files:
144 for f in files:
145 static_data.append(os.path.join(parent, f))
145 static_data.append(os.path.join(parent, f))
146
146
147 package_data = {
147 package_data = {
148 'IPython.config.profile' : ['README*', '*/*.py'],
148 'IPython.config.profile' : ['README*', '*/*.py'],
149 'IPython.core.tests' : ['*.png', '*.jpg'],
149 'IPython.core.tests' : ['*.png', '*.jpg'],
150 'IPython.testing' : ['*.txt'],
150 'IPython.testing' : ['*.txt'],
151 'IPython.testing.plugin' : ['*.txt'],
151 'IPython.testing.plugin' : ['*.txt'],
152 'IPython.html' : ['templates/*'] + static_data,
152 'IPython.html' : ['templates/*'] + static_data,
153 'IPython.qt.console' : ['resources/icon/*.svg'],
153 'IPython.qt.console' : ['resources/icon/*.svg'],
154 'IPython.nbconvert.templates' : ['*.tpl', 'latex/*.tpl',
155 'latex/skeleton/*.tplx', 'skeleton/*']
154 }
156 }
155 return package_data
157 return package_data
156
158
157
159
158 #---------------------------------------------------------------------------
160 #---------------------------------------------------------------------------
159 # Find data files
161 # Find data files
160 #---------------------------------------------------------------------------
162 #---------------------------------------------------------------------------
161
163
162 def make_dir_struct(tag,base,out_base):
164 def make_dir_struct(tag,base,out_base):
163 """Make the directory structure of all files below a starting dir.
165 """Make the directory structure of all files below a starting dir.
164
166
165 This is just a convenience routine to help build a nested directory
167 This is just a convenience routine to help build a nested directory
166 hierarchy because distutils is too stupid to do this by itself.
168 hierarchy because distutils is too stupid to do this by itself.
167
169
168 XXX - this needs a proper docstring!
170 XXX - this needs a proper docstring!
169 """
171 """
170
172
171 # we'll use these a lot below
173 # we'll use these a lot below
172 lbase = len(base)
174 lbase = len(base)
173 pathsep = os.path.sep
175 pathsep = os.path.sep
174 lpathsep = len(pathsep)
176 lpathsep = len(pathsep)
175
177
176 out = []
178 out = []
177 for (dirpath,dirnames,filenames) in os.walk(base):
179 for (dirpath,dirnames,filenames) in os.walk(base):
178 # we need to strip out the dirpath from the base to map it to the
180 # we need to strip out the dirpath from the base to map it to the
179 # output (installation) path. This requires possibly stripping the
181 # output (installation) path. This requires possibly stripping the
180 # path separator, because otherwise pjoin will not work correctly
182 # path separator, because otherwise pjoin will not work correctly
181 # (pjoin('foo/','/bar') returns '/bar').
183 # (pjoin('foo/','/bar') returns '/bar').
182
184
183 dp_eff = dirpath[lbase:]
185 dp_eff = dirpath[lbase:]
184 if dp_eff.startswith(pathsep):
186 if dp_eff.startswith(pathsep):
185 dp_eff = dp_eff[lpathsep:]
187 dp_eff = dp_eff[lpathsep:]
186 # The output path must be anchored at the out_base marker
188 # The output path must be anchored at the out_base marker
187 out_path = pjoin(out_base,dp_eff)
189 out_path = pjoin(out_base,dp_eff)
188 # Now we can generate the final filenames. Since os.walk only produces
190 # Now we can generate the final filenames. Since os.walk only produces
189 # filenames, we must join back with the dirpath to get full valid file
191 # filenames, we must join back with the dirpath to get full valid file
190 # paths:
192 # paths:
191 pfiles = [pjoin(dirpath,f) for f in filenames]
193 pfiles = [pjoin(dirpath,f) for f in filenames]
192 # Finally, generate the entry we need, which is a pari of (output
194 # Finally, generate the entry we need, which is a pari of (output
193 # path, files) for use as a data_files parameter in install_data.
195 # path, files) for use as a data_files parameter in install_data.
194 out.append((out_path, pfiles))
196 out.append((out_path, pfiles))
195
197
196 return out
198 return out
197
199
198
200
199 def find_data_files():
201 def find_data_files():
200 """
202 """
201 Find IPython's data_files.
203 Find IPython's data_files.
202
204
203 Most of these are docs.
205 Most of these are docs.
204 """
206 """
205
207
206 docdirbase = pjoin('share', 'doc', 'ipython')
208 docdirbase = pjoin('share', 'doc', 'ipython')
207 manpagebase = pjoin('share', 'man', 'man1')
209 manpagebase = pjoin('share', 'man', 'man1')
208
210
209 # Simple file lists can be made by hand
211 # Simple file lists can be made by hand
210 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
212 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
211 if not manpages:
213 if not manpages:
212 # When running from a source tree, the manpages aren't gzipped
214 # When running from a source tree, the manpages aren't gzipped
213 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
215 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
214
216
215 igridhelpfiles = [f for f in glob(pjoin('IPython','extensions','igrid_help.*')) if isfile(f)]
217 igridhelpfiles = [f for f in glob(pjoin('IPython','extensions','igrid_help.*')) if isfile(f)]
216
218
217 # For nested structures, use the utility above
219 # For nested structures, use the utility above
218 example_files = make_dir_struct(
220 example_files = make_dir_struct(
219 'data',
221 'data',
220 pjoin('docs','examples'),
222 pjoin('docs','examples'),
221 pjoin(docdirbase,'examples')
223 pjoin(docdirbase,'examples')
222 )
224 )
223 manual_files = make_dir_struct(
225 manual_files = make_dir_struct(
224 'data',
226 'data',
225 pjoin('docs','html'),
227 pjoin('docs','html'),
226 pjoin(docdirbase,'manual')
228 pjoin(docdirbase,'manual')
227 )
229 )
228
230
229 # And assemble the entire output list
231 # And assemble the entire output list
230 data_files = [ (manpagebase, manpages),
232 data_files = [ (manpagebase, manpages),
231 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
233 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
232 ] + manual_files + example_files
234 ] + manual_files + example_files
233
235
234 return data_files
236 return data_files
235
237
236
238
237 def make_man_update_target(manpage):
239 def make_man_update_target(manpage):
238 """Return a target_update-compliant tuple for the given manpage.
240 """Return a target_update-compliant tuple for the given manpage.
239
241
240 Parameters
242 Parameters
241 ----------
243 ----------
242 manpage : string
244 manpage : string
243 Name of the manpage, must include the section number (trailing number).
245 Name of the manpage, must include the section number (trailing number).
244
246
245 Example
247 Example
246 -------
248 -------
247
249
248 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
250 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
249 ('docs/man/ipython.1.gz',
251 ('docs/man/ipython.1.gz',
250 ['docs/man/ipython.1'],
252 ['docs/man/ipython.1'],
251 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
253 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
252 """
254 """
253 man_dir = pjoin('docs', 'man')
255 man_dir = pjoin('docs', 'man')
254 manpage_gz = manpage + '.gz'
256 manpage_gz = manpage + '.gz'
255 manpath = pjoin(man_dir, manpage)
257 manpath = pjoin(man_dir, manpage)
256 manpath_gz = pjoin(man_dir, manpage_gz)
258 manpath_gz = pjoin(man_dir, manpage_gz)
257 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
259 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
258 locals() )
260 locals() )
259 return (manpath_gz, [manpath], gz_cmd)
261 return (manpath_gz, [manpath], gz_cmd)
260
262
261 # The two functions below are copied from IPython.utils.path, so we don't need
263 # The two functions below are copied from IPython.utils.path, so we don't need
262 # to import IPython during setup, which fails on Python 3.
264 # to import IPython during setup, which fails on Python 3.
263
265
264 def target_outdated(target,deps):
266 def target_outdated(target,deps):
265 """Determine whether a target is out of date.
267 """Determine whether a target is out of date.
266
268
267 target_outdated(target,deps) -> 1/0
269 target_outdated(target,deps) -> 1/0
268
270
269 deps: list of filenames which MUST exist.
271 deps: list of filenames which MUST exist.
270 target: single filename which may or may not exist.
272 target: single filename which may or may not exist.
271
273
272 If target doesn't exist or is older than any file listed in deps, return
274 If target doesn't exist or is older than any file listed in deps, return
273 true, otherwise return false.
275 true, otherwise return false.
274 """
276 """
275 try:
277 try:
276 target_time = os.path.getmtime(target)
278 target_time = os.path.getmtime(target)
277 except os.error:
279 except os.error:
278 return 1
280 return 1
279 for dep in deps:
281 for dep in deps:
280 dep_time = os.path.getmtime(dep)
282 dep_time = os.path.getmtime(dep)
281 if dep_time > target_time:
283 if dep_time > target_time:
282 #print "For target",target,"Dep failed:",dep # dbg
284 #print "For target",target,"Dep failed:",dep # dbg
283 #print "times (dep,tar):",dep_time,target_time # dbg
285 #print "times (dep,tar):",dep_time,target_time # dbg
284 return 1
286 return 1
285 return 0
287 return 0
286
288
287
289
288 def target_update(target,deps,cmd):
290 def target_update(target,deps,cmd):
289 """Update a target with a given command given a list of dependencies.
291 """Update a target with a given command given a list of dependencies.
290
292
291 target_update(target,deps,cmd) -> runs cmd if target is outdated.
293 target_update(target,deps,cmd) -> runs cmd if target is outdated.
292
294
293 This is just a wrapper around target_outdated() which calls the given
295 This is just a wrapper around target_outdated() which calls the given
294 command if target is outdated."""
296 command if target is outdated."""
295
297
296 if target_outdated(target,deps):
298 if target_outdated(target,deps):
297 os.system(cmd)
299 os.system(cmd)
298
300
299 #---------------------------------------------------------------------------
301 #---------------------------------------------------------------------------
300 # Find scripts
302 # Find scripts
301 #---------------------------------------------------------------------------
303 #---------------------------------------------------------------------------
302
304
303 def find_scripts(entry_points=False, suffix=''):
305 def find_scripts(entry_points=False, suffix=''):
304 """Find IPython's scripts.
306 """Find IPython's scripts.
305
307
306 if entry_points is True:
308 if entry_points is True:
307 return setuptools entry_point-style definitions
309 return setuptools entry_point-style definitions
308 else:
310 else:
309 return file paths of plain scripts [default]
311 return file paths of plain scripts [default]
310
312
311 suffix is appended to script names if entry_points is True, so that the
313 suffix is appended to script names if entry_points is True, so that the
312 Python 3 scripts get named "ipython3" etc.
314 Python 3 scripts get named "ipython3" etc.
313 """
315 """
314 if entry_points:
316 if entry_points:
315 console_scripts = [s % suffix for s in [
317 console_scripts = [s % suffix for s in [
316 'ipython%s = IPython.terminal.ipapp:launch_new_instance',
318 'ipython%s = IPython.terminal.ipapp:launch_new_instance',
317 'pycolor%s = IPython.utils.PyColorize:main',
319 'pycolor%s = IPython.utils.PyColorize:main',
318 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
320 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
319 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
321 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
320 'iplogger%s = IPython.parallel.apps.iploggerapp:launch_new_instance',
322 'iplogger%s = IPython.parallel.apps.iploggerapp:launch_new_instance',
321 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
323 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
322 'iptest%s = IPython.testing.iptest:main',
324 'iptest%s = IPython.testing.iptest:main',
323 'irunner%s = IPython.lib.irunner:main'
325 'irunner%s = IPython.lib.irunner:main',
324 ]]
326 ]]
325 gui_scripts = []
327 gui_scripts = []
326 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
328 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
327 else:
329 else:
328 parallel_scripts = pjoin('IPython','parallel','scripts')
330 parallel_scripts = pjoin('IPython','parallel','scripts')
329 main_scripts = pjoin('IPython','scripts')
331 main_scripts = pjoin('IPython','scripts')
330 scripts = [
332 scripts = [
331 pjoin(parallel_scripts, 'ipengine'),
333 pjoin(parallel_scripts, 'ipengine'),
332 pjoin(parallel_scripts, 'ipcontroller'),
334 pjoin(parallel_scripts, 'ipcontroller'),
333 pjoin(parallel_scripts, 'ipcluster'),
335 pjoin(parallel_scripts, 'ipcluster'),
334 pjoin(parallel_scripts, 'iplogger'),
336 pjoin(parallel_scripts, 'iplogger'),
335 pjoin(main_scripts, 'ipython'),
337 pjoin(main_scripts, 'ipython'),
336 pjoin(main_scripts, 'pycolor'),
338 pjoin(main_scripts, 'pycolor'),
337 pjoin(main_scripts, 'irunner'),
339 pjoin(main_scripts, 'irunner'),
338 pjoin(main_scripts, 'iptest')
340 pjoin(main_scripts, 'iptest')
339 ]
341 ]
340 return scripts
342 return scripts
341
343
342 #---------------------------------------------------------------------------
344 #---------------------------------------------------------------------------
343 # Verify all dependencies
345 # Verify all dependencies
344 #---------------------------------------------------------------------------
346 #---------------------------------------------------------------------------
345
347
346 def check_for_dependencies():
348 def check_for_dependencies():
347 """Check for IPython's dependencies.
349 """Check for IPython's dependencies.
348
350
349 This function should NOT be called if running under setuptools!
351 This function should NOT be called if running under setuptools!
350 """
352 """
351 from setupext.setupext import (
353 from setupext.setupext import (
352 print_line, print_raw, print_status,
354 print_line, print_raw, print_status,
353 check_for_sphinx, check_for_pygments,
355 check_for_sphinx, check_for_pygments,
354 check_for_nose, check_for_pexpect,
356 check_for_nose, check_for_pexpect,
355 check_for_pyzmq, check_for_readline
357 check_for_pyzmq, check_for_readline,
358 check_for_jinja2, check_for_markdown
356 )
359 )
357 print_line()
360 print_line()
358 print_raw("BUILDING IPYTHON")
361 print_raw("BUILDING IPYTHON")
359 print_status('python', sys.version)
362 print_status('python', sys.version)
360 print_status('platform', sys.platform)
363 print_status('platform', sys.platform)
361 if sys.platform == 'win32':
364 if sys.platform == 'win32':
362 print_status('Windows version', sys.getwindowsversion())
365 print_status('Windows version', sys.getwindowsversion())
363
366
364 print_raw("")
367 print_raw("")
365 print_raw("OPTIONAL DEPENDENCIES")
368 print_raw("OPTIONAL DEPENDENCIES")
366
369
367 check_for_sphinx()
370 check_for_sphinx()
368 check_for_pygments()
371 check_for_pygments()
369 check_for_nose()
372 check_for_nose()
370 check_for_pexpect()
373 check_for_pexpect()
371 check_for_pyzmq()
374 check_for_pyzmq()
372 check_for_readline()
375 check_for_readline()
376 check_for_jinja2()
377 check_for_markdown()
373
378
374 #---------------------------------------------------------------------------
379 #---------------------------------------------------------------------------
375 # VCS related
380 # VCS related
376 #---------------------------------------------------------------------------
381 #---------------------------------------------------------------------------
377
382
378 # utils.submodule has checks for submodule status
383 # utils.submodule has checks for submodule status
379 execfile(pjoin('IPython','utils','submodule.py'), globals())
384 execfile(pjoin('IPython','utils','submodule.py'), globals())
380
385
381 class UpdateSubmodules(Command):
386 class UpdateSubmodules(Command):
382 """Update git submodules
387 """Update git submodules
383
388
384 IPython's external javascript dependencies live in a separate repo.
389 IPython's external javascript dependencies live in a separate repo.
385 """
390 """
386 description = "Update git submodules"
391 description = "Update git submodules"
387 user_options = []
392 user_options = []
388
393
389 def initialize_options(self):
394 def initialize_options(self):
390 pass
395 pass
391
396
392 def finalize_options(self):
397 def finalize_options(self):
393 pass
398 pass
394
399
395 def run(self):
400 def run(self):
396 failure = False
401 failure = False
397 try:
402 try:
398 self.spawn('git submodule init'.split())
403 self.spawn('git submodule init'.split())
399 self.spawn('git submodule update --recursive'.split())
404 self.spawn('git submodule update --recursive'.split())
400 except Exception as e:
405 except Exception as e:
401 failure = e
406 failure = e
402 print(e)
407 print(e)
403
408
404 if not check_submodule_status(repo_root) == 'clean':
409 if not check_submodule_status(repo_root) == 'clean':
405 print("submodules could not be checked out")
410 print("submodules could not be checked out")
406 sys.exit(1)
411 sys.exit(1)
407
412
408
413
409 def git_prebuild(pkg_dir, build_cmd=build_py):
414 def git_prebuild(pkg_dir, build_cmd=build_py):
410 """Return extended build or sdist command class for recording commit
415 """Return extended build or sdist command class for recording commit
411
416
412 records git commit in IPython.utils._sysinfo.commit
417 records git commit in IPython.utils._sysinfo.commit
413
418
414 for use in IPython.utils.sysinfo.sys_info() calls after installation.
419 for use in IPython.utils.sysinfo.sys_info() calls after installation.
415
420
416 Also ensures that submodules exist prior to running
421 Also ensures that submodules exist prior to running
417 """
422 """
418
423
419 class MyBuildPy(build_cmd):
424 class MyBuildPy(build_cmd):
420 ''' Subclass to write commit data into installation tree '''
425 ''' Subclass to write commit data into installation tree '''
421 def run(self):
426 def run(self):
422 build_cmd.run(self)
427 build_cmd.run(self)
423 # this one will only fire for build commands
428 # this one will only fire for build commands
424 if hasattr(self, 'build_lib'):
429 if hasattr(self, 'build_lib'):
425 self._record_commit(self.build_lib)
430 self._record_commit(self.build_lib)
426
431
427 def make_release_tree(self, base_dir, files):
432 def make_release_tree(self, base_dir, files):
428 # this one will fire for sdist
433 # this one will fire for sdist
429 build_cmd.make_release_tree(self, base_dir, files)
434 build_cmd.make_release_tree(self, base_dir, files)
430 self._record_commit(base_dir)
435 self._record_commit(base_dir)
431
436
432 def _record_commit(self, base_dir):
437 def _record_commit(self, base_dir):
433 import subprocess
438 import subprocess
434 proc = subprocess.Popen('git rev-parse --short HEAD',
439 proc = subprocess.Popen('git rev-parse --short HEAD',
435 stdout=subprocess.PIPE,
440 stdout=subprocess.PIPE,
436 stderr=subprocess.PIPE,
441 stderr=subprocess.PIPE,
437 shell=True)
442 shell=True)
438 repo_commit, _ = proc.communicate()
443 repo_commit, _ = proc.communicate()
439 repo_commit = repo_commit.strip().decode("ascii")
444 repo_commit = repo_commit.strip().decode("ascii")
440
445
441 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
446 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
442 if os.path.isfile(out_pth) and not repo_commit:
447 if os.path.isfile(out_pth) and not repo_commit:
443 # nothing to write, don't clobber
448 # nothing to write, don't clobber
444 return
449 return
445
450
446 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
451 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
447
452
448 # remove to avoid overwriting original via hard link
453 # remove to avoid overwriting original via hard link
449 try:
454 try:
450 os.remove(out_pth)
455 os.remove(out_pth)
451 except (IOError, OSError):
456 except (IOError, OSError):
452 pass
457 pass
453 with open(out_pth, 'w') as out_file:
458 with open(out_pth, 'w') as out_file:
454 out_file.writelines([
459 out_file.writelines([
455 '# GENERATED BY setup.py\n',
460 '# GENERATED BY setup.py\n',
456 'commit = "%s"\n' % repo_commit,
461 'commit = "%s"\n' % repo_commit,
457 ])
462 ])
458 return require_submodules(MyBuildPy)
463 return require_submodules(MyBuildPy)
459
464
460
465
461 def require_submodules(command):
466 def require_submodules(command):
462 """decorator for instructing a command to check for submodules before running"""
467 """decorator for instructing a command to check for submodules before running"""
463 class DecoratedCommand(command):
468 class DecoratedCommand(command):
464 def run(self):
469 def run(self):
465 if not check_submodule_status(repo_root) == 'clean':
470 if not check_submodule_status(repo_root) == 'clean':
466 print("submodules missing! Run `setup.py submodule` and try again")
471 print("submodules missing! Run `setup.py submodule` and try again")
467 sys.exit(1)
472 sys.exit(1)
468 command.run(self)
473 command.run(self)
469 return DecoratedCommand
474 return DecoratedCommand
@@ -1,172 +1,162 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 from __future__ import print_function
2 from __future__ import print_function
3
3
4 __docformat__ = "restructuredtext en"
4 __docformat__ = "restructuredtext en"
5
5
6 #-------------------------------------------------------------------------------
6 #-------------------------------------------------------------------------------
7 # Copyright (C) 2008 The IPython Development Team
7 # Copyright (C) 2008 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-------------------------------------------------------------------------------
11 #-------------------------------------------------------------------------------
12
12
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16
16
17 import sys, os
17 import sys, os
18 from textwrap import fill
18 from textwrap import fill
19
19
20 display_status=True
20 display_status=True
21
21
22 def check_display(f):
22 def check_display(f):
23 """decorator to allow display methods to be muted by mod.display_status"""
23 """decorator to allow display methods to be muted by mod.display_status"""
24 def maybe_display(*args, **kwargs):
24 def maybe_display(*args, **kwargs):
25 if display_status:
25 if display_status:
26 return f(*args, **kwargs)
26 return f(*args, **kwargs)
27 return maybe_display
27 return maybe_display
28
28
29 @check_display
29 @check_display
30 def print_line(char='='):
30 def print_line(char='='):
31 print(char * 76)
31 print(char * 76)
32
32
33 @check_display
33 @check_display
34 def print_status(package, status):
34 def print_status(package, status):
35 initial_indent = "%22s: " % package
35 initial_indent = "%22s: " % package
36 indent = ' ' * 24
36 indent = ' ' * 24
37 print(fill(str(status), width=76,
37 print(fill(str(status), width=76,
38 initial_indent=initial_indent,
38 initial_indent=initial_indent,
39 subsequent_indent=indent))
39 subsequent_indent=indent))
40
40
41 @check_display
41 @check_display
42 def print_message(message):
42 def print_message(message):
43 indent = ' ' * 24 + "* "
43 indent = ' ' * 24 + "* "
44 print(fill(str(message), width=76,
44 print(fill(str(message), width=76,
45 initial_indent=indent,
45 initial_indent=indent,
46 subsequent_indent=indent))
46 subsequent_indent=indent))
47
47
48 @check_display
48 @check_display
49 def print_raw(section):
49 def print_raw(section):
50 print(section)
50 print(section)
51
51
52 #-------------------------------------------------------------------------------
52 #-------------------------------------------------------------------------------
53 # Tests for specific packages
53 # Tests for specific packages
54 #-------------------------------------------------------------------------------
54 #-------------------------------------------------------------------------------
55
55
56 def check_for_ipython():
56 def check_for_ipython():
57 try:
57 try:
58 import IPython
58 import IPython
59 except ImportError:
59 except ImportError:
60 print_status("IPython", "Not found")
60 print_status("IPython", "Not found")
61 return False
61 return False
62 else:
62 else:
63 print_status("IPython", IPython.__version__)
63 print_status("IPython", IPython.__version__)
64 return True
64 return True
65
65
66 def check_for_sphinx():
66 def check_for_sphinx():
67 try:
67 try:
68 import sphinx
68 import sphinx
69 except ImportError:
69 except ImportError:
70 print_status('sphinx', "Not found (required for building documentation)")
70 print_status('sphinx', "Not found (required for docs and nbconvert)")
71 return False
71 return False
72 else:
72 else:
73 print_status('sphinx', sphinx.__version__)
73 print_status('sphinx', sphinx.__version__)
74 return True
74 return True
75
75
76 def check_for_pygments():
76 def check_for_pygments():
77 try:
77 try:
78 import pygments
78 import pygments
79 except ImportError:
79 except ImportError:
80 print_status('pygments', "Not found (required for syntax highlighting documentation)")
80 print_status('pygments', "Not found (required for docs and nbconvert)")
81 return False
81 return False
82 else:
82 else:
83 print_status('pygments', pygments.__version__)
83 print_status('pygments', pygments.__version__)
84 return True
84 return True
85
85
86 def check_for_nose():
86 def check_for_jinja2():
87 try:
88 import nose
89 except ImportError:
90 print_status('nose', "Not found (required for running the test suite)")
91 return False
92 else:
93 print_status('nose', nose.__version__)
94 return True
95
96 def check_for_pexpect():
97 try:
87 try:
98 import pexpect
88 import jinja2
99 except ImportError:
89 except ImportError:
100 print_status("pexpect", "no (required for running standalone doctests)")
90 print_status('jinja2', "Not found (required for notebook and nbconvert)")
101 return False
91 return False
102 else:
92 else:
103 print_status("pexpect", pexpect.__version__)
93 print_status('jinja2', jinja2.__version__)
104 return True
94 return True
105
95
106 def check_for_httplib2():
96 def check_for_markdown():
107 try:
97 try:
108 import httplib2
98 import markdown
109 except ImportError:
99 except ImportError:
110 print_status("httplib2", "no (required for blocking http clients)")
100 print_status('pygments', "Not found (required for nbconvert)")
111 return False
101 return False
112 else:
102 else:
113 print_status("httplib2","yes")
103 print_status('markdown', markdown.version)
114 return True
104 return True
115
105
116 def check_for_sqlalchemy():
106 def check_for_nose():
117 try:
107 try:
118 import sqlalchemy
108 import nose
119 except ImportError:
109 except ImportError:
120 print_status("sqlalchemy", "no (required for the ipython1 notebook)")
110 print_status('nose', "Not found (required for running the test suite)")
121 return False
111 return False
122 else:
112 else:
123 print_status("sqlalchemy","yes")
113 print_status('nose', nose.__version__)
124 return True
114 return True
125
115
126 def check_for_simplejson():
116 def check_for_pexpect():
127 try:
117 try:
128 import simplejson
118 import pexpect
129 except ImportError:
119 except ImportError:
130 print_status("simplejson", "no (required for the ipython1 notebook)")
120 print_status("pexpect", "no (required for running standalone doctests)")
131 return False
121 return False
132 else:
122 else:
133 print_status("simplejson","yes")
123 print_status("pexpect", pexpect.__version__)
134 return True
124 return True
135
125
136 def check_for_pyzmq():
126 def check_for_pyzmq():
137 try:
127 try:
138 import zmq
128 import zmq
139 except ImportError:
129 except ImportError:
140 print_status('pyzmq', "no (required for qtconsole, notebook, and parallel computing capabilities)")
130 print_status('pyzmq', "no (required for qtconsole, notebook, and parallel computing capabilities)")
141 return False
131 return False
142 else:
132 else:
143 # pyzmq 2.1.10 adds pyzmq_version_info funtion for returning
133 # pyzmq 2.1.10 adds pyzmq_version_info funtion for returning
144 # version as a tuple
134 # version as a tuple
145 if hasattr(zmq, 'pyzmq_version_info') and zmq.pyzmq_version_info() >= (2,1,11):
135 if hasattr(zmq, 'pyzmq_version_info') and zmq.pyzmq_version_info() >= (2,1,11):
146 print_status("pyzmq", zmq.__version__)
136 print_status("pyzmq", zmq.__version__)
147 return True
137 return True
148 else:
138 else:
149 print_status('pyzmq', "no (have %s, but require >= 2.1.11 for"
139 print_status('pyzmq', "no (have %s, but require >= 2.1.11 for"
150 " qtconsole, notebook, and parallel computing capabilities)" % zmq.__version__)
140 " qtconsole, notebook, and parallel computing capabilities)" % zmq.__version__)
151 return False
141 return False
152
142
153 def check_for_readline():
143 def check_for_readline():
154 from distutils.version import LooseVersion
144 from distutils.version import LooseVersion
155 try:
145 try:
156 import readline
146 import readline
157 except ImportError:
147 except ImportError:
158 try:
148 try:
159 import pyreadline
149 import pyreadline
160 vs = pyreadline.release.version
150 vs = pyreadline.release.version
161 except (ImportError, AttributeError):
151 except (ImportError, AttributeError):
162 print_status('readline', "no (required for good interactive behavior)")
152 print_status('readline', "no (required for good interactive behavior)")
163 return False
153 return False
164 if LooseVersion(vs).version >= [1,7,1]:
154 if LooseVersion(vs).version >= [1,7,1]:
165 print_status('readline', "yes pyreadline-" + vs)
155 print_status('readline', "yes pyreadline-" + vs)
166 return True
156 return True
167 else:
157 else:
168 print_status('readline', "no pyreadline-%s < 1.7.1" % vs)
158 print_status('readline', "no pyreadline-%s < 1.7.1" % vs)
169 return False
159 return False
170 else:
160 else:
171 print_status('readline', "yes")
161 print_status('readline', "yes")
172 return True
162 return True
General Comments 0
You need to be logged in to leave comments. Login now