Show More
@@ -1,174 +1,174 b'' | |||
|
1 | 1 | """Module containing single call export functions.""" |
|
2 | 2 | |
|
3 | 3 | # Copyright (c) IPython Development Team. |
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 | 6 | from functools import wraps |
|
7 | 7 | |
|
8 |
from IPython.nbformat. |
|
|
8 | from IPython.nbformat.v4 import NotebookNode | |
|
9 | 9 | from IPython.utils.decorators import undoc |
|
10 | 10 | from IPython.utils.py3compat import string_types |
|
11 | 11 | |
|
12 | 12 | from .exporter import Exporter |
|
13 | 13 | from .templateexporter import TemplateExporter |
|
14 | 14 | from .html import HTMLExporter |
|
15 | 15 | from .slides import SlidesExporter |
|
16 | 16 | from .latex import LatexExporter |
|
17 | 17 | from .pdf import PDFExporter |
|
18 | 18 | from .markdown import MarkdownExporter |
|
19 | 19 | from .python import PythonExporter |
|
20 | 20 | from .rst import RSTExporter |
|
21 | 21 | from .notebook import NotebookExporter |
|
22 | 22 | |
|
23 | 23 | #----------------------------------------------------------------------------- |
|
24 | 24 | # Classes |
|
25 | 25 | #----------------------------------------------------------------------------- |
|
26 | 26 | |
|
27 | 27 | @undoc |
|
28 | 28 | def DocDecorator(f): |
|
29 | 29 | |
|
30 | 30 | #Set docstring of function |
|
31 | 31 | f.__doc__ = f.__doc__ + """ |
|
32 | 32 | nb : :class:`~{nbnode_mod}.NotebookNode` |
|
33 | 33 | The notebook to export. |
|
34 | 34 | config : config (optional, keyword arg) |
|
35 | 35 | User configuration instance. |
|
36 | 36 | resources : dict (optional, keyword arg) |
|
37 | 37 | Resources used in the conversion process. |
|
38 | 38 | |
|
39 | 39 | Returns |
|
40 | 40 | ------- |
|
41 | 41 | tuple- output, resources, exporter_instance |
|
42 | 42 | output : str |
|
43 | 43 | Jinja 2 output. This is the resulting converted notebook. |
|
44 | 44 | resources : dictionary |
|
45 | 45 | Dictionary of resources used prior to and during the conversion |
|
46 | 46 | process. |
|
47 | 47 | exporter_instance : Exporter |
|
48 | 48 | Instance of the Exporter class used to export the document. Useful |
|
49 | 49 | to caller because it provides a 'file_extension' property which |
|
50 | 50 | specifies what extension the output should be saved as. |
|
51 | 51 | |
|
52 | 52 | Notes |
|
53 | 53 | ----- |
|
54 | 54 | WARNING: API WILL CHANGE IN FUTURE RELEASES OF NBCONVERT |
|
55 | 55 | """.format(nbnode_mod=NotebookNode.__module__) |
|
56 | 56 | |
|
57 | 57 | @wraps(f) |
|
58 | 58 | def decorator(*args, **kwargs): |
|
59 | 59 | return f(*args, **kwargs) |
|
60 | 60 | |
|
61 | 61 | return decorator |
|
62 | 62 | |
|
63 | 63 | |
|
64 | 64 | #----------------------------------------------------------------------------- |
|
65 | 65 | # Functions |
|
66 | 66 | #----------------------------------------------------------------------------- |
|
67 | 67 | |
|
68 | 68 | __all__ = [ |
|
69 | 69 | 'export', |
|
70 | 70 | 'export_html', |
|
71 | 71 | 'export_custom', |
|
72 | 72 | 'export_slides', |
|
73 | 73 | 'export_latex', |
|
74 | 74 | 'export_pdf', |
|
75 | 75 | 'export_markdown', |
|
76 | 76 | 'export_python', |
|
77 | 77 | 'export_rst', |
|
78 | 78 | 'export_by_name', |
|
79 | 79 | 'get_export_names', |
|
80 | 80 | 'ExporterNameError' |
|
81 | 81 | ] |
|
82 | 82 | |
|
83 | 83 | |
|
84 | 84 | class ExporterNameError(NameError): |
|
85 | 85 | pass |
|
86 | 86 | |
|
87 | 87 | @DocDecorator |
|
88 | 88 | def export(exporter, nb, **kw): |
|
89 | 89 | """ |
|
90 | 90 | Export a notebook object using specific exporter class. |
|
91 | 91 | |
|
92 | 92 | Parameters |
|
93 | 93 | ---------- |
|
94 | 94 | exporter : class:`~IPython.nbconvert.exporters.exporter.Exporter` class or instance |
|
95 | 95 | Class type or instance of the exporter that should be used. If the |
|
96 | 96 | method initializes it's own instance of the class, it is ASSUMED that |
|
97 | 97 | the class type provided exposes a constructor (``__init__``) with the same |
|
98 | 98 | signature as the base Exporter class. |
|
99 | 99 | """ |
|
100 | 100 | |
|
101 | 101 | #Check arguments |
|
102 | 102 | if exporter is None: |
|
103 | 103 | raise TypeError("Exporter is None") |
|
104 | 104 | elif not isinstance(exporter, Exporter) and not issubclass(exporter, Exporter): |
|
105 | 105 | raise TypeError("exporter does not inherit from Exporter (base)") |
|
106 | 106 | if nb is None: |
|
107 | 107 | raise TypeError("nb is None") |
|
108 | 108 | |
|
109 | 109 | #Create the exporter |
|
110 | 110 | resources = kw.pop('resources', None) |
|
111 | 111 | if isinstance(exporter, Exporter): |
|
112 | 112 | exporter_instance = exporter |
|
113 | 113 | else: |
|
114 | 114 | exporter_instance = exporter(**kw) |
|
115 | 115 | |
|
116 | 116 | #Try to convert the notebook using the appropriate conversion function. |
|
117 | 117 | if isinstance(nb, NotebookNode): |
|
118 | 118 | output, resources = exporter_instance.from_notebook_node(nb, resources) |
|
119 | 119 | elif isinstance(nb, string_types): |
|
120 | 120 | output, resources = exporter_instance.from_filename(nb, resources) |
|
121 | 121 | else: |
|
122 | 122 | output, resources = exporter_instance.from_file(nb, resources) |
|
123 | 123 | return output, resources |
|
124 | 124 | |
|
125 | 125 | exporter_map = dict( |
|
126 | 126 | custom=TemplateExporter, |
|
127 | 127 | html=HTMLExporter, |
|
128 | 128 | slides=SlidesExporter, |
|
129 | 129 | latex=LatexExporter, |
|
130 | 130 | pdf=PDFExporter, |
|
131 | 131 | markdown=MarkdownExporter, |
|
132 | 132 | python=PythonExporter, |
|
133 | 133 | rst=RSTExporter, |
|
134 | 134 | notebook=NotebookExporter, |
|
135 | 135 | ) |
|
136 | 136 | |
|
137 | 137 | def _make_exporter(name, E): |
|
138 | 138 | """make an export_foo function from a short key and Exporter class E""" |
|
139 | 139 | def _export(nb, **kw): |
|
140 | 140 | return export(E, nb, **kw) |
|
141 | 141 | _export.__doc__ = """Export a notebook object to {0} format""".format(name) |
|
142 | 142 | return _export |
|
143 | 143 | |
|
144 | 144 | g = globals() |
|
145 | 145 | |
|
146 | 146 | for name, E in exporter_map.items(): |
|
147 | 147 | g['export_%s' % name] = DocDecorator(_make_exporter(name, E)) |
|
148 | 148 | |
|
149 | 149 | @DocDecorator |
|
150 | 150 | def export_by_name(format_name, nb, **kw): |
|
151 | 151 | """ |
|
152 | 152 | Export a notebook object to a template type by its name. Reflection |
|
153 | 153 | (Inspect) is used to find the template's corresponding explicit export |
|
154 | 154 | method defined in this module. That method is then called directly. |
|
155 | 155 | |
|
156 | 156 | Parameters |
|
157 | 157 | ---------- |
|
158 | 158 | format_name : str |
|
159 | 159 | Name of the template style to export to. |
|
160 | 160 | """ |
|
161 | 161 | |
|
162 | 162 | function_name = "export_" + format_name.lower() |
|
163 | 163 | |
|
164 | 164 | if function_name in globals(): |
|
165 | 165 | return globals()[function_name](nb, **kw) |
|
166 | 166 | else: |
|
167 | 167 | raise ExporterNameError("template for `%s` not found" % function_name) |
|
168 | 168 | |
|
169 | 169 | |
|
170 | 170 | def get_export_names(): |
|
171 | 171 | """Return a list of the currently supported export targets |
|
172 | 172 | |
|
173 | 173 | WARNING: API WILL CHANGE IN FUTURE RELEASES OF NBCONVERT""" |
|
174 | 174 | return sorted(exporter_map.keys()) |
@@ -1,276 +1,259 b'' | |||
|
1 | 1 | """This module defines a base Exporter class. For Jinja template-based export, |
|
2 | 2 | see templateexporter.py. |
|
3 | 3 | """ |
|
4 | 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 | 5 | |
|
17 | 6 | from __future__ import print_function, absolute_import |
|
18 | 7 | |
|
19 | # Stdlib imports | |
|
20 | 8 | import io |
|
21 | 9 | import os |
|
22 | 10 | import copy |
|
23 | 11 | import collections |
|
24 | 12 | import datetime |
|
25 | 13 | |
|
26 | ||
|
27 | # IPython imports | |
|
28 | 14 | from IPython.config.configurable import LoggingConfigurable |
|
29 | 15 | from IPython.config import Config |
|
30 |
from IPython |
|
|
16 | from IPython import nbformat | |
|
31 | 17 | from IPython.utils.traitlets import MetaHasTraits, Unicode, List |
|
32 | 18 | from IPython.utils.importstring import import_item |
|
33 | 19 | from IPython.utils import text, py3compat |
|
34 | 20 | |
|
35 | #----------------------------------------------------------------------------- | |
|
36 | # Class | |
|
37 | #----------------------------------------------------------------------------- | |
|
38 | 21 | |
|
39 | 22 | class ResourcesDict(collections.defaultdict): |
|
40 | 23 | def __missing__(self, key): |
|
41 | 24 | return '' |
|
42 | 25 | |
|
43 | 26 | |
|
44 | 27 | class Exporter(LoggingConfigurable): |
|
45 | 28 | """ |
|
46 | 29 | Class containing methods that sequentially run a list of preprocessors on a |
|
47 | 30 | NotebookNode object and then return the modified NotebookNode object and |
|
48 | 31 | accompanying resources dict. |
|
49 | 32 | """ |
|
50 | 33 | |
|
51 | 34 | file_extension = Unicode( |
|
52 | 35 | 'txt', config=True, |
|
53 | 36 | help="Extension of the file that should be written to disk" |
|
54 | 37 | ) |
|
55 | 38 | |
|
56 | 39 | # MIME type of the result file, for HTTP response headers. |
|
57 | 40 | # This is *not* a traitlet, because we want to be able to access it from |
|
58 | 41 | # the class, not just on instances. |
|
59 | 42 | output_mimetype = '' |
|
60 | 43 | |
|
61 | 44 | #Configurability, allows the user to easily add filters and preprocessors. |
|
62 | 45 | preprocessors = List(config=True, |
|
63 | 46 | help="""List of preprocessors, by name or namespace, to enable.""") |
|
64 | 47 | |
|
65 | 48 | _preprocessors = List() |
|
66 | 49 | |
|
67 | 50 | default_preprocessors = List(['IPython.nbconvert.preprocessors.coalesce_streams', |
|
68 | 51 | 'IPython.nbconvert.preprocessors.SVG2PDFPreprocessor', |
|
69 | 52 | 'IPython.nbconvert.preprocessors.ExtractOutputPreprocessor', |
|
70 | 53 | 'IPython.nbconvert.preprocessors.CSSHTMLHeaderPreprocessor', |
|
71 | 54 | 'IPython.nbconvert.preprocessors.RevealHelpPreprocessor', |
|
72 | 55 | 'IPython.nbconvert.preprocessors.LatexPreprocessor', |
|
73 | 56 | 'IPython.nbconvert.preprocessors.ClearOutputPreprocessor', |
|
74 | 57 | 'IPython.nbconvert.preprocessors.ExecutePreprocessor', |
|
75 | 58 | 'IPython.nbconvert.preprocessors.HighlightMagicsPreprocessor'], |
|
76 | 59 | config=True, |
|
77 | 60 | help="""List of preprocessors available by default, by name, namespace, |
|
78 | 61 | instance, or type.""") |
|
79 | 62 | |
|
80 | 63 | |
|
81 | 64 | def __init__(self, config=None, **kw): |
|
82 | 65 | """ |
|
83 | 66 | Public constructor |
|
84 | 67 | |
|
85 | 68 | Parameters |
|
86 | 69 | ---------- |
|
87 | 70 | config : config |
|
88 | 71 | User configuration instance. |
|
89 | 72 | """ |
|
90 | 73 | with_default_config = self.default_config |
|
91 | 74 | if config: |
|
92 | 75 | with_default_config.merge(config) |
|
93 | 76 | |
|
94 | 77 | super(Exporter, self).__init__(config=with_default_config, **kw) |
|
95 | 78 | |
|
96 | 79 | self._init_preprocessors() |
|
97 | 80 | |
|
98 | 81 | |
|
99 | 82 | @property |
|
100 | 83 | def default_config(self): |
|
101 | 84 | return Config() |
|
102 | 85 | |
|
103 | 86 | def from_notebook_node(self, nb, resources=None, **kw): |
|
104 | 87 | """ |
|
105 | 88 | Convert a notebook from a notebook node instance. |
|
106 | 89 | |
|
107 | 90 | Parameters |
|
108 | 91 | ---------- |
|
109 | 92 | nb : :class:`~IPython.nbformat.current.NotebookNode` |
|
110 | Notebook node | |
|
93 | Notebook node (dict-like with attr-access) | |
|
111 | 94 | resources : dict |
|
112 | 95 | Additional resources that can be accessed read/write by |
|
113 | 96 | preprocessors and filters. |
|
114 | 97 | **kw |
|
115 | 98 | Ignored (?) |
|
116 | 99 | """ |
|
117 | 100 | nb_copy = copy.deepcopy(nb) |
|
118 | 101 | resources = self._init_resources(resources) |
|
119 | 102 | |
|
120 | 103 | if 'language' in nb['metadata']: |
|
121 | 104 | resources['language'] = nb['metadata']['language'].lower() |
|
122 | 105 | |
|
123 | 106 | # Preprocess |
|
124 | 107 | nb_copy, resources = self._preprocess(nb_copy, resources) |
|
125 | 108 | |
|
126 | 109 | return nb_copy, resources |
|
127 | 110 | |
|
128 | 111 | |
|
129 | 112 | def from_filename(self, filename, resources=None, **kw): |
|
130 | 113 | """ |
|
131 | 114 | Convert a notebook from a notebook file. |
|
132 | 115 | |
|
133 | 116 | Parameters |
|
134 | 117 | ---------- |
|
135 | 118 | filename : str |
|
136 | 119 | Full filename of the notebook file to open and convert. |
|
137 | 120 | """ |
|
138 | 121 | |
|
139 | 122 | # Pull the metadata from the filesystem. |
|
140 | 123 | if resources is None: |
|
141 | 124 | resources = ResourcesDict() |
|
142 | 125 | if not 'metadata' in resources or resources['metadata'] == '': |
|
143 | 126 | resources['metadata'] = ResourcesDict() |
|
144 | 127 | basename = os.path.basename(filename) |
|
145 | 128 | notebook_name = basename[:basename.rfind('.')] |
|
146 | 129 | resources['metadata']['name'] = notebook_name |
|
147 | 130 | |
|
148 | 131 | modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename)) |
|
149 | 132 | resources['metadata']['modified_date'] = modified_date.strftime(text.date_format) |
|
150 | 133 | |
|
151 | 134 | with io.open(filename, encoding='utf-8') as f: |
|
152 |
return self.from_notebook_node(nbformat.read(f, |
|
|
135 | return self.from_notebook_node(nbformat.read(f, as_version=4), resources=resources, **kw) | |
|
153 | 136 | |
|
154 | 137 | |
|
155 | 138 | def from_file(self, file_stream, resources=None, **kw): |
|
156 | 139 | """ |
|
157 | 140 | Convert a notebook from a notebook file. |
|
158 | 141 | |
|
159 | 142 | Parameters |
|
160 | 143 | ---------- |
|
161 | 144 | file_stream : file-like object |
|
162 | 145 | Notebook file-like object to convert. |
|
163 | 146 | """ |
|
164 |
return self.from_notebook_node(nbformat.read(file_stream, |
|
|
147 | return self.from_notebook_node(nbformat.read(file_stream, as_version=4), resources=resources, **kw) | |
|
165 | 148 | |
|
166 | 149 | |
|
167 | 150 | def register_preprocessor(self, preprocessor, enabled=False): |
|
168 | 151 | """ |
|
169 | 152 | Register a preprocessor. |
|
170 | 153 | Preprocessors are classes that act upon the notebook before it is |
|
171 | 154 | passed into the Jinja templating engine. preprocessors are also |
|
172 | 155 | capable of passing additional information to the Jinja |
|
173 | 156 | templating engine. |
|
174 | 157 | |
|
175 | 158 | Parameters |
|
176 | 159 | ---------- |
|
177 | 160 | preprocessor : preprocessor |
|
178 | 161 | """ |
|
179 | 162 | if preprocessor is None: |
|
180 | 163 | raise TypeError('preprocessor') |
|
181 | 164 | isclass = isinstance(preprocessor, type) |
|
182 | 165 | constructed = not isclass |
|
183 | 166 | |
|
184 | 167 | # Handle preprocessor's registration based on it's type |
|
185 | 168 | if constructed and isinstance(preprocessor, py3compat.string_types): |
|
186 | 169 | # Preprocessor is a string, import the namespace and recursively call |
|
187 | 170 | # this register_preprocessor method |
|
188 | 171 | preprocessor_cls = import_item(preprocessor) |
|
189 | 172 | return self.register_preprocessor(preprocessor_cls, enabled) |
|
190 | 173 | |
|
191 | 174 | if constructed and hasattr(preprocessor, '__call__'): |
|
192 | 175 | # Preprocessor is a function, no need to construct it. |
|
193 | 176 | # Register and return the preprocessor. |
|
194 | 177 | if enabled: |
|
195 | 178 | preprocessor.enabled = True |
|
196 | 179 | self._preprocessors.append(preprocessor) |
|
197 | 180 | return preprocessor |
|
198 | 181 | |
|
199 | 182 | elif isclass and isinstance(preprocessor, MetaHasTraits): |
|
200 | 183 | # Preprocessor is configurable. Make sure to pass in new default for |
|
201 | 184 | # the enabled flag if one was specified. |
|
202 | 185 | self.register_preprocessor(preprocessor(parent=self), enabled) |
|
203 | 186 | |
|
204 | 187 | elif isclass: |
|
205 | 188 | # Preprocessor is not configurable, construct it |
|
206 | 189 | self.register_preprocessor(preprocessor(), enabled) |
|
207 | 190 | |
|
208 | 191 | else: |
|
209 | 192 | # Preprocessor is an instance of something without a __call__ |
|
210 | 193 | # attribute. |
|
211 | 194 | raise TypeError('preprocessor') |
|
212 | 195 | |
|
213 | 196 | |
|
214 | 197 | def _init_preprocessors(self): |
|
215 | 198 | """ |
|
216 | 199 | Register all of the preprocessors needed for this exporter, disabled |
|
217 | 200 | unless specified explicitly. |
|
218 | 201 | """ |
|
219 | 202 | self._preprocessors = [] |
|
220 | 203 | |
|
221 | 204 | # Load default preprocessors (not necessarly enabled by default). |
|
222 | 205 | for preprocessor in self.default_preprocessors: |
|
223 | 206 | self.register_preprocessor(preprocessor) |
|
224 | 207 | |
|
225 | 208 | # Load user-specified preprocessors. Enable by default. |
|
226 | 209 | for preprocessor in self.preprocessors: |
|
227 | 210 | self.register_preprocessor(preprocessor, enabled=True) |
|
228 | 211 | |
|
229 | 212 | |
|
230 | 213 | def _init_resources(self, resources): |
|
231 | 214 | |
|
232 | 215 | #Make sure the resources dict is of ResourcesDict type. |
|
233 | 216 | if resources is None: |
|
234 | 217 | resources = ResourcesDict() |
|
235 | 218 | if not isinstance(resources, ResourcesDict): |
|
236 | 219 | new_resources = ResourcesDict() |
|
237 | 220 | new_resources.update(resources) |
|
238 | 221 | resources = new_resources |
|
239 | 222 | |
|
240 | 223 | #Make sure the metadata extension exists in resources |
|
241 | 224 | if 'metadata' in resources: |
|
242 | 225 | if not isinstance(resources['metadata'], ResourcesDict): |
|
243 | 226 | resources['metadata'] = ResourcesDict(resources['metadata']) |
|
244 | 227 | else: |
|
245 | 228 | resources['metadata'] = ResourcesDict() |
|
246 | 229 | if not resources['metadata']['name']: |
|
247 | 230 | resources['metadata']['name'] = 'Notebook' |
|
248 | 231 | |
|
249 | 232 | #Set the output extension |
|
250 | 233 | resources['output_extension'] = self.file_extension |
|
251 | 234 | return resources |
|
252 | 235 | |
|
253 | 236 | |
|
254 | 237 | def _preprocess(self, nb, resources): |
|
255 | 238 | """ |
|
256 | 239 | Preprocess the notebook before passing it into the Jinja engine. |
|
257 | 240 | To preprocess the notebook is to apply all of the |
|
258 | 241 | |
|
259 | 242 | Parameters |
|
260 | 243 | ---------- |
|
261 | 244 | nb : notebook node |
|
262 | 245 | notebook that is being exported. |
|
263 | 246 | resources : a dict of additional resources that |
|
264 | 247 | can be accessed read/write by preprocessors |
|
265 | 248 | """ |
|
266 | 249 | |
|
267 | 250 | # Do a copy.deepcopy first, |
|
268 | 251 | # we are never safe enough with what the preprocessors could do. |
|
269 | 252 | nbc = copy.deepcopy(nb) |
|
270 | 253 | resc = copy.deepcopy(resources) |
|
271 | 254 | |
|
272 | 255 | #Run each preprocessor on the notebook. Carry the output along |
|
273 | 256 | #to each preprocessor |
|
274 | 257 | for preprocessor in self._preprocessors: |
|
275 | 258 | nbc, resc = preprocessor(nbc, resc) |
|
276 | 259 | return nbc, resc |
@@ -1,32 +1,32 b'' | |||
|
1 | 1 | """NotebookExporter class""" |
|
2 | 2 | |
|
3 | 3 | # Copyright (c) IPython Development Team. |
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 | 6 | from .exporter import Exporter |
|
7 |
from IPython |
|
|
7 | from IPython import nbformat | |
|
8 | 8 | from IPython.utils.traitlets import Enum |
|
9 | 9 | |
|
10 | 10 | class NotebookExporter(Exporter): |
|
11 | 11 | """Exports to an IPython notebook.""" |
|
12 | 12 | |
|
13 |
nbformat_version = Enum(list( |
|
|
13 | nbformat_version = Enum(list(nbformat.versions), | |
|
14 | 14 | default_value=nbformat.current_nbformat, |
|
15 | 15 | config=True, |
|
16 | 16 | help="""The nbformat version to write. |
|
17 | 17 | Use this to downgrade notebooks. |
|
18 | 18 | """ |
|
19 | 19 | ) |
|
20 | 20 | def _file_extension_default(self): |
|
21 | 21 | return 'ipynb' |
|
22 | 22 | |
|
23 | 23 | output_mimetype = 'application/json' |
|
24 | 24 | |
|
25 | 25 | def from_notebook_node(self, nb, resources=None, **kw): |
|
26 | 26 | nb_copy, resources = super(NotebookExporter, self).from_notebook_node(nb, resources, **kw) |
|
27 |
if self.nbformat_version != nbformat |
|
|
27 | if self.nbformat_version != nb_copy.nbformat: | |
|
28 | 28 | resources['output_suffix'] = '.v%i' % self.nbformat_version |
|
29 | 29 | else: |
|
30 | 30 | resources['output_suffix'] = '.nbconvert' |
|
31 | 31 | output = nbformat.writes(nb_copy, version=self.nbformat_version) |
|
32 | 32 | return output, resources |
@@ -1,102 +1,90 b'' | |||
|
1 | 1 | """ |
|
2 | 2 | Module with tests for export.py |
|
3 | 3 | """ |
|
4 | 4 | |
|
5 | #----------------------------------------------------------------------------- | |
|
6 | # Copyright (c) 2013, the IPython Development Team. | |
|
7 | # | |
|
5 | # Copyright (c) IPython Development Team. | |
|
8 | 6 | # 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 | 7 | |
|
17 | 8 | import os |
|
18 | 9 | |
|
19 |
from IPython |
|
|
10 | from IPython import nbformat | |
|
20 | 11 | |
|
21 | 12 | from .base import ExportersTestsBase |
|
22 | 13 | from ..export import * |
|
23 | 14 | from ..python import PythonExporter |
|
24 | 15 | |
|
25 | #----------------------------------------------------------------------------- | |
|
26 | # Class | |
|
27 | #----------------------------------------------------------------------------- | |
|
28 | 16 | |
|
29 | 17 | class TestExport(ExportersTestsBase): |
|
30 | 18 | """Contains test functions for export.py""" |
|
31 | 19 | |
|
32 | 20 | |
|
33 | 21 | def test_export_wrong_name(self): |
|
34 | 22 | """ |
|
35 | 23 | Is the right error thrown when a bad template name is used? |
|
36 | 24 | """ |
|
37 | 25 | try: |
|
38 | 26 | export_by_name('not_a_name', self._get_notebook()) |
|
39 | 27 | except ExporterNameError as e: |
|
40 | 28 | pass |
|
41 | 29 | |
|
42 | 30 | |
|
43 | 31 | def test_export_filename(self): |
|
44 | 32 | """ |
|
45 | 33 | Can a notebook be exported by filename? |
|
46 | 34 | """ |
|
47 | 35 | (output, resources) = export_by_name('python', self._get_notebook()) |
|
48 | 36 | assert len(output) > 0 |
|
49 | 37 | |
|
50 | 38 | |
|
51 | 39 | def test_export_nbnode(self): |
|
52 | 40 | """ |
|
53 | 41 | Can a notebook be exported by a notebook node handle? |
|
54 | 42 | """ |
|
55 | 43 | with open(self._get_notebook(), 'r') as f: |
|
56 |
notebook = nbformat.read(f, |
|
|
44 | notebook = nbformat.read(f, 4) | |
|
57 | 45 | (output, resources) = export_by_name('python', notebook) |
|
58 | 46 | assert len(output) > 0 |
|
59 | 47 | |
|
60 | 48 | |
|
61 | 49 | def test_export_filestream(self): |
|
62 | 50 | """ |
|
63 | 51 | Can a notebook be exported by a filesteam? |
|
64 | 52 | """ |
|
65 | 53 | with open(self._get_notebook(), 'r') as f: |
|
66 | 54 | (output, resources) = export_by_name('python', f) |
|
67 | 55 | assert len(output) > 0 |
|
68 | 56 | |
|
69 | 57 | |
|
70 | 58 | def test_export_using_exporter(self): |
|
71 | 59 | """ |
|
72 | 60 | Can a notebook be exported using an instanciated exporter? |
|
73 | 61 | """ |
|
74 | 62 | (output, resources) = export(PythonExporter(), self._get_notebook()) |
|
75 | 63 | assert len(output) > 0 |
|
76 | 64 | |
|
77 | 65 | |
|
78 | 66 | def test_export_using_exporter_class(self): |
|
79 | 67 | """ |
|
80 | 68 | Can a notebook be exported using an exporter class type? |
|
81 | 69 | """ |
|
82 | 70 | (output, resources) = export(PythonExporter, self._get_notebook()) |
|
83 | 71 | assert len(output) > 0 |
|
84 | 72 | |
|
85 | 73 | |
|
86 | 74 | def test_export_resources(self): |
|
87 | 75 | """ |
|
88 | 76 | Can a notebook be exported along with a custom resources dict? |
|
89 | 77 | """ |
|
90 | 78 | (output, resources) = export(PythonExporter, self._get_notebook(), resources={}) |
|
91 | 79 | assert len(output) > 0 |
|
92 | 80 | |
|
93 | 81 | |
|
94 | 82 | def test_no_exporter(self): |
|
95 | 83 | """ |
|
96 | 84 | Is the right error thrown if no exporter is provided? |
|
97 | 85 | """ |
|
98 | 86 | try: |
|
99 | 87 | (output, resources) = export(None, self._get_notebook()) |
|
100 | 88 | except TypeError: |
|
101 | 89 | pass |
|
102 | 90 |
@@ -1,116 +1,117 b'' | |||
|
1 | 1 | """Tests for Latex exporter""" |
|
2 | 2 | |
|
3 | 3 | # Copyright (c) IPython Development Team. |
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 | 6 | import os.path |
|
7 | 7 | import textwrap |
|
8 | 8 | import re |
|
9 | 9 | |
|
10 | 10 | from .base import ExportersTestsBase |
|
11 | 11 | from ..latex import LatexExporter |
|
12 |
from IPython.nbformat import |
|
|
12 | from IPython.nbformat import write | |
|
13 | from IPython.nbformat import v4 | |
|
13 | 14 | from IPython.testing.decorators import onlyif_cmds_exist |
|
14 | 15 | from IPython.utils.tempdir import TemporaryDirectory |
|
15 | 16 | |
|
16 | 17 | |
|
17 | 18 | class TestLatexExporter(ExportersTestsBase): |
|
18 | 19 | """Contains test functions for latex.py""" |
|
19 | 20 | |
|
20 | 21 | exporter_class = LatexExporter |
|
21 | 22 | should_include_raw = ['latex'] |
|
22 | 23 | |
|
23 | 24 | def test_constructor(self): |
|
24 | 25 | """ |
|
25 | 26 | Can a LatexExporter be constructed? |
|
26 | 27 | """ |
|
27 | 28 | LatexExporter() |
|
28 | 29 | |
|
29 | 30 | |
|
30 | 31 | @onlyif_cmds_exist('pandoc') |
|
31 | 32 | def test_export(self): |
|
32 | 33 | """ |
|
33 | 34 | Can a LatexExporter export something? |
|
34 | 35 | """ |
|
35 | 36 | (output, resources) = LatexExporter().from_filename(self._get_notebook()) |
|
36 | 37 | assert len(output) > 0 |
|
37 | 38 | |
|
38 | 39 | |
|
39 | 40 | @onlyif_cmds_exist('pandoc') |
|
40 | 41 | def test_export_book(self): |
|
41 | 42 | """ |
|
42 | 43 | Can a LatexExporter export using 'report' template? |
|
43 | 44 | """ |
|
44 | 45 | (output, resources) = LatexExporter(template_file='report').from_filename(self._get_notebook()) |
|
45 | 46 | assert len(output) > 0 |
|
46 | 47 | |
|
47 | 48 | |
|
48 | 49 | @onlyif_cmds_exist('pandoc') |
|
49 | 50 | def test_export_basic(self): |
|
50 | 51 | """ |
|
51 | 52 | Can a LatexExporter export using 'article' template? |
|
52 | 53 | """ |
|
53 | 54 | (output, resources) = LatexExporter(template_file='article').from_filename(self._get_notebook()) |
|
54 | 55 | assert len(output) > 0 |
|
55 | 56 | |
|
56 | 57 | |
|
57 | 58 | @onlyif_cmds_exist('pandoc') |
|
58 | 59 | def test_export_article(self): |
|
59 | 60 | """ |
|
60 | 61 | Can a LatexExporter export using 'article' template? |
|
61 | 62 | """ |
|
62 | 63 | (output, resources) = LatexExporter(template_file='article').from_filename(self._get_notebook()) |
|
63 | 64 | assert len(output) > 0 |
|
64 | 65 | |
|
65 | 66 | @onlyif_cmds_exist('pandoc') |
|
66 | 67 | def test_very_long_cells(self): |
|
67 | 68 | """ |
|
68 | 69 | Torture test that long cells do not cause issues |
|
69 | 70 | """ |
|
70 | 71 | lorem_ipsum_text = textwrap.dedent("""\ |
|
71 | 72 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec |
|
72 | 73 | dignissim, ipsum non facilisis tempus, dui felis tincidunt metus, |
|
73 | 74 | nec pulvinar neque odio eget risus. Nulla nisi lectus, cursus |
|
74 | 75 | suscipit interdum at, ultrices sit amet orci. Mauris facilisis |
|
75 | 76 | imperdiet elit, vitae scelerisque ipsum dignissim non. Integer |
|
76 | 77 | consequat malesuada neque sit amet pulvinar. Curabitur pretium |
|
77 | 78 | ut turpis eget aliquet. Maecenas sagittis lacus sed lectus |
|
78 | 79 | volutpat, eu adipiscing purus pulvinar. Maecenas consequat |
|
79 | 80 | luctus urna, eget cursus quam mollis a. Aliquam vitae ornare |
|
80 | 81 | erat, non hendrerit urna. Sed eu diam nec massa egestas pharetra |
|
81 | 82 | at nec tellus. Fusce feugiat lacus quis urna sollicitudin volutpat. |
|
82 | 83 | Quisque at sapien non nibh feugiat tempus ac ultricies purus. |
|
83 | 84 | """) |
|
84 | 85 | lorem_ipsum_text = lorem_ipsum_text.replace("\n"," ") + "\n\n" |
|
85 | 86 | large_lorem_ipsum_text = "".join([lorem_ipsum_text]*3000) |
|
86 | 87 | |
|
87 | 88 | notebook_name = "lorem_ipsum_long.ipynb" |
|
88 |
nb = |
|
|
89 | nb = v4.new_notebook( | |
|
89 | 90 | cells=[ |
|
90 |
|
|
|
91 | v4.new_markdown_cell(source=large_lorem_ipsum_text) | |
|
91 | 92 | ] |
|
92 | 93 | ) |
|
93 | 94 | |
|
94 | 95 | with TemporaryDirectory() as td: |
|
95 | 96 | nbfile = os.path.join(td, notebook_name) |
|
96 | 97 | with open(nbfile, 'w') as f: |
|
97 |
|
|
|
98 | write(f, nb, 4) | |
|
98 | 99 | |
|
99 |
(output, resources) = LatexExporter(template_file='article').from_filename(nbfile) |
|
|
100 | (output, resources) = LatexExporter(template_file='article').from_filename(nbfile) | |
|
100 | 101 | assert len(output) > 0 |
|
101 | 102 | |
|
102 | 103 | @onlyif_cmds_exist('pandoc') |
|
103 | 104 | def test_prompt_number_color(self): |
|
104 | 105 | """ |
|
105 | 106 | Does LatexExporter properly format input and output prompts in color? |
|
106 | 107 | """ |
|
107 | 108 | (output, resources) = LatexExporter().from_filename( |
|
108 | 109 | self._get_notebook(nb_name="prompt_numbers.ipynb")) |
|
109 | 110 | in_regex = r"In \[\{\\color\{incolor\}(.*)\}\]:" |
|
110 | 111 | out_regex = r"Out\[\{\\color\{outcolor\}(.*)\}\]:" |
|
111 | 112 | |
|
112 | 113 | ins = ["2", "10", " ", " ", "*", "0"] |
|
113 | 114 | outs = ["10"] |
|
114 | 115 | |
|
115 | 116 | assert re.findall(in_regex, output) == ins |
|
116 | 117 | assert re.findall(out_regex, output) == outs |
@@ -1,39 +1,39 b'' | |||
|
1 | 1 | """Tests for notebook.py""" |
|
2 | 2 | |
|
3 | 3 | # Copyright (c) IPython Development Team. |
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 | 6 | import json |
|
7 | 7 | |
|
8 | 8 | from .base import ExportersTestsBase |
|
9 | 9 | from ..notebook import NotebookExporter |
|
10 | 10 | |
|
11 |
from IPython.nbformat |
|
|
11 | from IPython.nbformat import validate | |
|
12 | 12 | from IPython.testing.tools import assert_big_text_equal |
|
13 | 13 | |
|
14 | 14 | class TestNotebookExporter(ExportersTestsBase): |
|
15 | 15 | """Contains test functions for notebook.py""" |
|
16 | 16 | |
|
17 | 17 | exporter_class = NotebookExporter |
|
18 | 18 | |
|
19 | 19 | def test_export(self): |
|
20 | 20 | """ |
|
21 | 21 | Does the NotebookExporter return the file unchanged? |
|
22 | 22 | """ |
|
23 | 23 | with open(self._get_notebook()) as f: |
|
24 | 24 | file_contents = f.read() |
|
25 | 25 | (output, resources) = self.exporter_class().from_filename(self._get_notebook()) |
|
26 | 26 | assert len(output) > 0 |
|
27 | 27 | assert_big_text_equal(output, file_contents) |
|
28 | 28 | |
|
29 | 29 | def test_downgrade_3(self): |
|
30 | 30 | exporter = self.exporter_class(nbformat_version=3) |
|
31 | 31 | (output, resources) = exporter.from_filename(self._get_notebook()) |
|
32 | 32 | nb = json.loads(output) |
|
33 | 33 | validate(nb) |
|
34 | 34 | |
|
35 | 35 | def test_downgrade_2(self): |
|
36 | 36 | exporter = self.exporter_class(nbformat_version=2) |
|
37 | 37 | (output, resources) = exporter.from_filename(self._get_notebook()) |
|
38 | 38 | nb = json.loads(output) |
|
39 | 39 | self.assertEqual(nb['nbformat'], 2) |
@@ -1,62 +1,54 b'' | |||
|
1 | 1 | """Tests for RSTExporter""" |
|
2 | 2 | |
|
3 | #----------------------------------------------------------------------------- | |
|
4 | # Copyright (c) 2013, the IPython Development Team. | |
|
5 | # | |
|
3 | # Copyright (c) IPython Development Team. | |
|
6 | 4 | # 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 | 5 | |
|
15 | 6 | import io |
|
16 | 7 | |
|
17 |
from IPython |
|
|
8 | from IPython import nbformat | |
|
9 | from IPython.nbformat import v4 | |
|
18 | 10 | |
|
19 | 11 | from .base import ExportersTestsBase |
|
20 | 12 | from ..rst import RSTExporter |
|
21 | 13 | from IPython.testing.decorators import onlyif_cmds_exist |
|
22 | 14 | |
|
23 | 15 | |
|
24 | 16 | class TestRSTExporter(ExportersTestsBase): |
|
25 | 17 | """Tests for RSTExporter""" |
|
26 | 18 | |
|
27 | 19 | exporter_class = RSTExporter |
|
28 | 20 | should_include_raw = ['rst'] |
|
29 | 21 | |
|
30 | 22 | def test_constructor(self): |
|
31 | 23 | """ |
|
32 | 24 | Can a RSTExporter be constructed? |
|
33 | 25 | """ |
|
34 | 26 | RSTExporter() |
|
35 | 27 | |
|
36 | 28 | |
|
37 | 29 | @onlyif_cmds_exist('pandoc') |
|
38 | 30 | def test_export(self): |
|
39 | 31 | """ |
|
40 | 32 | Can a RSTExporter export something? |
|
41 | 33 | """ |
|
42 | 34 | (output, resources) = RSTExporter().from_filename(self._get_notebook()) |
|
43 | 35 | assert len(output) > 0 |
|
44 | 36 | |
|
45 | 37 | @onlyif_cmds_exist('pandoc') |
|
46 | 38 | def test_empty_code_cell(self): |
|
47 | 39 | """No empty code cells in rst""" |
|
48 | 40 | nbname = self._get_notebook() |
|
49 | 41 | with io.open(nbname, encoding='utf8') as f: |
|
50 |
nb = |
|
|
42 | nb = nbformat.read(f, 4) | |
|
51 | 43 | |
|
52 | 44 | exporter = self.exporter_class() |
|
53 | 45 | |
|
54 | 46 | (output, resources) = exporter.from_notebook_node(nb) |
|
55 | 47 | # add an empty code cell |
|
56 | 48 | nb.cells.append( |
|
57 |
|
|
|
49 | v4.new_code_cell(source="") | |
|
58 | 50 | ) |
|
59 | 51 | (output2, resources) = exporter.from_notebook_node(nb) |
|
60 | 52 | # adding an empty code cell shouldn't change output |
|
61 | 53 | self.assertEqual(output.strip(), output2.strip()) |
|
62 | 54 |
@@ -1,111 +1,111 b'' | |||
|
1 | 1 | """Module containing a preprocessor that removes the outputs from code cells""" |
|
2 | 2 | |
|
3 | 3 | # Copyright (c) IPython Development Team. |
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 | 6 | import os |
|
7 | import sys | |
|
8 | 7 | |
|
9 | 8 | try: |
|
10 | 9 | from queue import Empty # Py 3 |
|
11 | 10 | except ImportError: |
|
12 | 11 | from Queue import Empty # Py 2 |
|
13 | 12 | |
|
14 | 13 | from IPython.utils.traitlets import List, Unicode |
|
15 | 14 | |
|
16 |
from IPython.nbformat. |
|
|
15 | from IPython.nbformat.v4 import output_from_msg | |
|
17 | 16 | from .base import Preprocessor |
|
18 | 17 | from IPython.utils.traitlets import Integer |
|
19 | 18 | |
|
19 | ||
|
20 | 20 | class ExecutePreprocessor(Preprocessor): |
|
21 | 21 | """ |
|
22 | 22 | Executes all the cells in a notebook |
|
23 | 23 | """ |
|
24 | 24 | |
|
25 | 25 | timeout = Integer(30, config=True, |
|
26 | 26 | help="The time to wait (in seconds) for output from executions." |
|
27 | 27 | ) |
|
28 | 28 | |
|
29 | 29 | extra_arguments = List(Unicode) |
|
30 | 30 | |
|
31 | 31 | def preprocess(self, nb, resources): |
|
32 | 32 | from IPython.kernel import run_kernel |
|
33 | 33 | kernel_name = nb.metadata.get('kernelspec', {}).get('name', 'python') |
|
34 | 34 | self.log.info("Executing notebook with kernel: %s" % kernel_name) |
|
35 | 35 | with run_kernel(kernel_name=kernel_name, |
|
36 | 36 | extra_arguments=self.extra_arguments, |
|
37 | 37 | stderr=open(os.devnull, 'w')) as kc: |
|
38 | 38 | self.kc = kc |
|
39 | 39 | nb, resources = super(ExecutePreprocessor, self).preprocess(nb, resources) |
|
40 | 40 | return nb, resources |
|
41 | 41 | |
|
42 | 42 | def preprocess_cell(self, cell, resources, cell_index): |
|
43 | 43 | """ |
|
44 | 44 | Apply a transformation on each code cell. See base.py for details. |
|
45 | 45 | """ |
|
46 | 46 | if cell.cell_type != 'code': |
|
47 | 47 | return cell, resources |
|
48 | 48 | try: |
|
49 | 49 | outputs = self.run_cell(self.kc.shell_channel, self.kc.iopub_channel, cell) |
|
50 | 50 | except Exception as e: |
|
51 | 51 | self.log.error("failed to run cell: " + repr(e)) |
|
52 | 52 | self.log.error(str(cell.source)) |
|
53 | 53 | raise |
|
54 | 54 | cell.outputs = outputs |
|
55 | 55 | return cell, resources |
|
56 | 56 | |
|
57 | 57 | def run_cell(self, shell, iopub, cell): |
|
58 | 58 | msg_id = shell.execute(cell.source) |
|
59 | 59 | self.log.debug("Executing cell:\n%s", cell.source) |
|
60 | 60 | # wait for finish, with timeout |
|
61 | 61 | while True: |
|
62 | 62 | try: |
|
63 | 63 | msg = shell.get_msg(timeout=self.timeout) |
|
64 | 64 | except Empty: |
|
65 | 65 | self.log.error("Timeout waiting for execute reply") |
|
66 | 66 | raise |
|
67 | 67 | if msg['parent_header'].get('msg_id') == msg_id: |
|
68 | 68 | break |
|
69 | 69 | else: |
|
70 | 70 | # not our reply |
|
71 | 71 | continue |
|
72 | 72 | |
|
73 | 73 | outs = [] |
|
74 | 74 | |
|
75 | 75 | while True: |
|
76 | 76 | try: |
|
77 | 77 | msg = iopub.get_msg(timeout=self.timeout) |
|
78 | 78 | except Empty: |
|
79 | 79 | self.log.warn("Timeout waiting for IOPub output") |
|
80 | 80 | break |
|
81 | 81 | if msg['parent_header'].get('msg_id') != msg_id: |
|
82 | 82 | # not an output from our execution |
|
83 | 83 | continue |
|
84 | 84 | |
|
85 | 85 | msg_type = msg['msg_type'] |
|
86 | 86 | self.log.debug("output: %s", msg_type) |
|
87 | 87 | content = msg['content'] |
|
88 | 88 | |
|
89 | 89 | # set the prompt number for the input and the output |
|
90 | 90 | if 'execution_count' in content: |
|
91 | 91 | cell['execution_count'] = content['execution_count'] |
|
92 | 92 | |
|
93 | 93 | if msg_type == 'status': |
|
94 | 94 | if content['execution_state'] == 'idle': |
|
95 | 95 | break |
|
96 | 96 | else: |
|
97 | 97 | continue |
|
98 | 98 | elif msg_type == 'execute_input': |
|
99 | 99 | continue |
|
100 | 100 | elif msg_type == 'clear_output': |
|
101 | 101 | outs = [] |
|
102 | 102 | continue |
|
103 | 103 | |
|
104 | 104 | try: |
|
105 | 105 | out = output_from_msg(msg) |
|
106 | 106 | except ValueError: |
|
107 | 107 | self.log.error("unhandled iopub msg: " + msg_type) |
|
108 | 108 | else: |
|
109 | 109 | outs.append(out) |
|
110 | 110 | |
|
111 | 111 | return outs |
@@ -1,41 +1,41 b'' | |||
|
1 | 1 | """utility functions for preprocessor tests""" |
|
2 | 2 | |
|
3 | 3 | # Copyright (c) IPython Development Team. |
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 |
from IPython.nbformat import |
|
|
6 | from IPython.nbformat import v4 as nbformat | |
|
7 | 7 | |
|
8 | 8 | from ...tests.base import TestsBase |
|
9 | 9 | from ...exporters.exporter import ResourcesDict |
|
10 | 10 | |
|
11 | 11 | |
|
12 | 12 | class PreprocessorTestsBase(TestsBase): |
|
13 | 13 | """Contains test functions preprocessor tests""" |
|
14 | 14 | |
|
15 | 15 | |
|
16 | 16 | def build_notebook(self): |
|
17 | 17 | """Build a notebook in memory for use with preprocessor tests""" |
|
18 | 18 | |
|
19 | 19 | outputs = [ |
|
20 | 20 | nbformat.new_output("stream", name="stdout", text="a"), |
|
21 | 21 | nbformat.new_output("display_data", data={'text/plain': 'b'}), |
|
22 | 22 | nbformat.new_output("stream", name="stdout", text="c"), |
|
23 | 23 | nbformat.new_output("stream", name="stdout", text="d"), |
|
24 | 24 | nbformat.new_output("stream", name="stderr", text="e"), |
|
25 | 25 | nbformat.new_output("stream", name="stderr", text="f"), |
|
26 | 26 | nbformat.new_output("display_data", data={'image/png': 'Zw=='}), # g |
|
27 | 27 | nbformat.new_output("display_data", data={'application/pdf': 'aA=='}), # h |
|
28 | 28 | ] |
|
29 | 29 | |
|
30 | 30 | cells=[nbformat.new_code_cell(source="$ e $", execution_count=1, outputs=outputs), |
|
31 | 31 | nbformat.new_markdown_cell(source="$ e $")] |
|
32 | 32 | |
|
33 | 33 | return nbformat.new_notebook(cells=cells) |
|
34 | 34 | |
|
35 | 35 | |
|
36 | 36 | def build_resources(self): |
|
37 | 37 | """Build an empty resources dictionary.""" |
|
38 | 38 | |
|
39 | 39 | res = ResourcesDict() |
|
40 | 40 | res['metadata'] = ResourcesDict() |
|
41 | 41 | return res |
@@ -1,35 +1,33 b'' | |||
|
1 | 1 | """ |
|
2 | 2 | Module with tests for the clearoutput preprocessor. |
|
3 | 3 | """ |
|
4 | 4 | |
|
5 | 5 | # Copyright (c) IPython Development Team. |
|
6 | 6 | # Distributed under the terms of the Modified BSD License. |
|
7 | 7 | |
|
8 | from IPython.nbformat import current as nbformat | |
|
9 | ||
|
10 | 8 | from .base import PreprocessorTestsBase |
|
11 | 9 | from ..clearoutput import ClearOutputPreprocessor |
|
12 | 10 | |
|
13 | 11 | |
|
14 | 12 | class TestClearOutput(PreprocessorTestsBase): |
|
15 | 13 | """Contains test functions for clearoutput.py""" |
|
16 | 14 | |
|
17 | 15 | |
|
18 | 16 | def build_preprocessor(self): |
|
19 | 17 | """Make an instance of a preprocessor""" |
|
20 | 18 | preprocessor = ClearOutputPreprocessor() |
|
21 | 19 | preprocessor.enabled = True |
|
22 | 20 | return preprocessor |
|
23 | 21 | |
|
24 | 22 | def test_constructor(self): |
|
25 | 23 | """Can a ClearOutputPreprocessor be constructed?""" |
|
26 | 24 | self.build_preprocessor() |
|
27 | 25 | |
|
28 | 26 | def test_output(self): |
|
29 | 27 | """Test the output of the ClearOutputPreprocessor""" |
|
30 | 28 | nb = self.build_notebook() |
|
31 | 29 | res = self.build_resources() |
|
32 | 30 | preprocessor = self.build_preprocessor() |
|
33 | 31 | nb, res = preprocessor(nb, res) |
|
34 | 32 | assert nb.cells[0].outputs == [] |
|
35 | 33 | assert nb.cells[0].execution_count is None |
@@ -1,58 +1,58 b'' | |||
|
1 | 1 | """Tests for the coalescestreams preprocessor""" |
|
2 | 2 | |
|
3 | 3 | # Copyright (c) IPython Development Team. |
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 |
from IPython.nbformat import |
|
|
6 | from IPython.nbformat import v4 as nbformat | |
|
7 | 7 | |
|
8 | 8 | from .base import PreprocessorTestsBase |
|
9 | 9 | from ..coalescestreams import coalesce_streams |
|
10 | 10 | |
|
11 | 11 | |
|
12 | 12 | class TestCoalesceStreams(PreprocessorTestsBase): |
|
13 | 13 | """Contains test functions for coalescestreams.py""" |
|
14 | 14 | |
|
15 | 15 | def test_coalesce_streams(self): |
|
16 | 16 | """coalesce_streams preprocessor output test""" |
|
17 | 17 | nb = self.build_notebook() |
|
18 | 18 | res = self.build_resources() |
|
19 | 19 | nb, res = coalesce_streams(nb, res) |
|
20 | 20 | outputs = nb.cells[0].outputs |
|
21 | 21 | self.assertEqual(outputs[0].text, "a") |
|
22 | 22 | self.assertEqual(outputs[1].output_type, "display_data") |
|
23 | 23 | self.assertEqual(outputs[2].text, "cd") |
|
24 | 24 | self.assertEqual(outputs[3].text, "ef") |
|
25 | 25 | |
|
26 | 26 | def test_coalesce_sequenced_streams(self): |
|
27 | 27 | """Can the coalesce streams preprocessor merge a sequence of streams?""" |
|
28 | 28 | outputs = [nbformat.new_output(output_type="stream", name="stdout", text="0"), |
|
29 | 29 | nbformat.new_output(output_type="stream", name="stdout", text="1"), |
|
30 | 30 | nbformat.new_output(output_type="stream", name="stdout", text="2"), |
|
31 | 31 | nbformat.new_output(output_type="stream", name="stdout", text="3"), |
|
32 | 32 | nbformat.new_output(output_type="stream", name="stdout", text="4"), |
|
33 | 33 | nbformat.new_output(output_type="stream", name="stdout", text="5"), |
|
34 | 34 | nbformat.new_output(output_type="stream", name="stdout", text="6"), |
|
35 | 35 | nbformat.new_output(output_type="stream", name="stdout", text="7")] |
|
36 | 36 | cells=[nbformat.new_code_cell(source="# None", execution_count=1,outputs=outputs)] |
|
37 | 37 | |
|
38 | 38 | nb = nbformat.new_notebook(cells=cells) |
|
39 | 39 | res = self.build_resources() |
|
40 | 40 | nb, res = coalesce_streams(nb, res) |
|
41 | 41 | outputs = nb.cells[0].outputs |
|
42 | 42 | self.assertEqual(outputs[0].text, u'01234567') |
|
43 | 43 | |
|
44 | 44 | def test_coalesce_replace_streams(self): |
|
45 | 45 | """Are \\r characters handled?""" |
|
46 | 46 | outputs = [nbformat.new_output(output_type="stream", name="stdout", text="z"), |
|
47 | 47 | nbformat.new_output(output_type="stream", name="stdout", text="\ra"), |
|
48 | 48 | nbformat.new_output(output_type="stream", name="stdout", text="\nz\rb"), |
|
49 | 49 | nbformat.new_output(output_type="stream", name="stdout", text="\nz"), |
|
50 | 50 | nbformat.new_output(output_type="stream", name="stdout", text="\rc\n"), |
|
51 | 51 | nbformat.new_output(output_type="stream", name="stdout", text="z\rz\rd")] |
|
52 | 52 | cells=[nbformat.new_code_cell(source="# None", execution_count=1,outputs=outputs)] |
|
53 | 53 | |
|
54 | 54 | nb = nbformat.new_notebook(cells=cells) |
|
55 | 55 | res = self.build_resources() |
|
56 | 56 | nb, res = coalesce_streams(nb, res) |
|
57 | 57 | outputs = nb.cells[0].outputs |
|
58 | 58 | self.assertEqual(outputs[0].text, u'a\nb\nc\nd') |
@@ -1,91 +1,92 b'' | |||
|
1 | 1 | """ |
|
2 | 2 | Module with tests for the execute preprocessor. |
|
3 | 3 | """ |
|
4 | 4 | |
|
5 | 5 | # Copyright (c) IPython Development Team. |
|
6 | 6 | # Distributed under the terms of the Modified BSD License. |
|
7 | 7 | |
|
8 | 8 | import copy |
|
9 | 9 | import glob |
|
10 | import io | |
|
10 | 11 | import os |
|
11 | 12 | import re |
|
12 | 13 | |
|
13 |
from IPython |
|
|
14 | from IPython import nbformat | |
|
14 | 15 | |
|
15 | 16 | from .base import PreprocessorTestsBase |
|
16 | 17 | from ..execute import ExecutePreprocessor |
|
17 | 18 | |
|
18 | 19 | from IPython.nbconvert.filters import strip_ansi |
|
19 | 20 | |
|
20 | 21 | addr_pat = re.compile(r'0x[0-9a-f]{7,9}') |
|
21 | 22 | |
|
22 | 23 | class TestExecute(PreprocessorTestsBase): |
|
23 | 24 | """Contains test functions for execute.py""" |
|
24 | 25 | |
|
25 | 26 | @staticmethod |
|
26 | 27 | def normalize_output(output): |
|
27 | 28 | """ |
|
28 | 29 | Normalizes outputs for comparison. |
|
29 | 30 | """ |
|
30 | 31 | output = dict(output) |
|
31 | 32 | if 'metadata' in output: |
|
32 | 33 | del output['metadata'] |
|
33 | 34 | if 'text' in output: |
|
34 | 35 | output['text'] = re.sub(addr_pat, '<HEXADDR>', output['text']) |
|
35 | 36 | if 'text/plain' in output.get('data', {}): |
|
36 | 37 | output['data']['text/plain'] = \ |
|
37 | 38 | re.sub(addr_pat, '<HEXADDR>', output['data']['text/plain']) |
|
38 | 39 | if 'traceback' in output: |
|
39 | 40 | tb = [] |
|
40 | 41 | for line in output['traceback']: |
|
41 | 42 | tb.append(strip_ansi(line)) |
|
42 | 43 | output['traceback'] = tb |
|
43 | 44 | |
|
44 | 45 | return output |
|
45 | 46 | |
|
46 | 47 | |
|
47 | 48 | def assert_notebooks_equal(self, expected, actual): |
|
48 | 49 | expected_cells = expected['cells'] |
|
49 | 50 | actual_cells = actual['cells'] |
|
50 | 51 | self.assertEqual(len(expected_cells), len(actual_cells)) |
|
51 | 52 | |
|
52 | 53 | for expected_cell, actual_cell in zip(expected_cells, actual_cells): |
|
53 | 54 | expected_outputs = expected_cell.get('outputs', []) |
|
54 | 55 | actual_outputs = actual_cell.get('outputs', []) |
|
55 | 56 | normalized_expected_outputs = list(map(self.normalize_output, expected_outputs)) |
|
56 | 57 | normalized_actual_outputs = list(map(self.normalize_output, actual_outputs)) |
|
57 | 58 | self.assertEqual(normalized_expected_outputs, normalized_actual_outputs) |
|
58 | 59 | |
|
59 | 60 | expected_execution_count = expected_cell.get('execution_count', None) |
|
60 | 61 | actual_execution_count = actual_cell.get('execution_count', None) |
|
61 | 62 | self.assertEqual(expected_execution_count, actual_execution_count) |
|
62 | 63 | |
|
63 | 64 | |
|
64 | 65 | def build_preprocessor(self): |
|
65 | 66 | """Make an instance of a preprocessor""" |
|
66 | 67 | preprocessor = ExecutePreprocessor() |
|
67 | 68 | preprocessor.enabled = True |
|
68 | 69 | return preprocessor |
|
69 | 70 | |
|
70 | 71 | |
|
71 | 72 | def test_constructor(self): |
|
72 | 73 | """Can a ExecutePreprocessor be constructed?""" |
|
73 | 74 | self.build_preprocessor() |
|
74 | 75 | |
|
75 | 76 | |
|
76 | 77 | def test_run_notebooks(self): |
|
77 | 78 | """Runs a series of test notebooks and compares them to their actual output""" |
|
78 | 79 | current_dir = os.path.dirname(__file__) |
|
79 | 80 | input_files = glob.glob(os.path.join(current_dir, 'files', '*.ipynb')) |
|
80 | 81 | for filename in input_files: |
|
81 | with open(os.path.join(current_dir, 'files', filename)) as f: | |
|
82 |
input_nb = nbformat.read(f, |
|
|
82 | with io.open(os.path.join(current_dir, 'files', filename)) as f: | |
|
83 | input_nb = nbformat.read(f, 4) | |
|
83 | 84 | res = self.build_resources() |
|
84 | 85 | preprocessor = self.build_preprocessor() |
|
85 | 86 | cleaned_input_nb = copy.deepcopy(input_nb) |
|
86 | 87 | for cell in cleaned_input_nb.cells: |
|
87 | 88 | if 'execution_count' in cell: |
|
88 | 89 | del cell['execution_count'] |
|
89 | 90 | cell['outputs'] = [] |
|
90 | 91 | output_nb, _ = preprocessor(cleaned_input_nb, res) |
|
91 | 92 | self.assert_notebooks_equal(output_nb, input_nb) |
@@ -1,78 +1,78 b'' | |||
|
1 | 1 | """Tests for the revealhelp preprocessor""" |
|
2 | 2 | |
|
3 | 3 | # Copyright (c) IPython Development Team. |
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 |
from IPython.nbformat import |
|
|
6 | from IPython.nbformat import v4 as nbformat | |
|
7 | 7 | |
|
8 | 8 | from .base import PreprocessorTestsBase |
|
9 | 9 | from ..revealhelp import RevealHelpPreprocessor |
|
10 | 10 | |
|
11 | 11 | |
|
12 | 12 | class Testrevealhelp(PreprocessorTestsBase): |
|
13 | 13 | """Contains test functions for revealhelp.py""" |
|
14 | 14 | |
|
15 | 15 | def build_notebook(self): |
|
16 | 16 | """Build a reveal slides notebook in memory for use with tests. |
|
17 | 17 | Overrides base in PreprocessorTestsBase""" |
|
18 | 18 | |
|
19 | 19 | outputs = [nbformat.new_output(output_type="stream", name="stdout", text="a")] |
|
20 | 20 | |
|
21 | 21 | slide_metadata = {'slideshow' : {'slide_type': 'slide'}} |
|
22 | 22 | subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}} |
|
23 | 23 | |
|
24 | 24 | cells=[nbformat.new_code_cell(source="", execution_count=1, outputs=outputs), |
|
25 | 25 | nbformat.new_markdown_cell(source="", metadata=slide_metadata), |
|
26 | 26 | nbformat.new_code_cell(source="", execution_count=2, outputs=outputs), |
|
27 | 27 | nbformat.new_markdown_cell(source="", metadata=slide_metadata), |
|
28 | 28 | nbformat.new_markdown_cell(source="", metadata=subslide_metadata)] |
|
29 | 29 | |
|
30 | 30 | return nbformat.new_notebook(cells=cells) |
|
31 | 31 | |
|
32 | 32 | |
|
33 | 33 | def build_preprocessor(self): |
|
34 | 34 | """Make an instance of a preprocessor""" |
|
35 | 35 | preprocessor = RevealHelpPreprocessor() |
|
36 | 36 | preprocessor.enabled = True |
|
37 | 37 | return preprocessor |
|
38 | 38 | |
|
39 | 39 | |
|
40 | 40 | def test_constructor(self): |
|
41 | 41 | """Can a RevealHelpPreprocessor be constructed?""" |
|
42 | 42 | self.build_preprocessor() |
|
43 | 43 | |
|
44 | 44 | |
|
45 | 45 | def test_reveal_attribute(self): |
|
46 | 46 | """Make sure the reveal url_prefix resources is set""" |
|
47 | 47 | nb = self.build_notebook() |
|
48 | 48 | res = self.build_resources() |
|
49 | 49 | preprocessor = self.build_preprocessor() |
|
50 | 50 | nb, res = preprocessor(nb, res) |
|
51 | 51 | assert 'reveal' in res |
|
52 | 52 | assert 'url_prefix' in res['reveal'] |
|
53 | 53 | |
|
54 | 54 | |
|
55 | 55 | def test_reveal_output(self): |
|
56 | 56 | """Make sure that the reveal preprocessor """ |
|
57 | 57 | nb = self.build_notebook() |
|
58 | 58 | res = self.build_resources() |
|
59 | 59 | preprocessor = self.build_preprocessor() |
|
60 | 60 | nb, res = preprocessor(nb, res) |
|
61 | 61 | cells = nb.cells |
|
62 | 62 | |
|
63 | 63 | # Make sure correct metadata tags are available on every cell. |
|
64 | 64 | for cell in cells: |
|
65 | 65 | assert 'slide_type' in cell.metadata |
|
66 | 66 | |
|
67 | 67 | # Make sure slide end is only applied to the cells preceeding slide |
|
68 | 68 | # cells. |
|
69 | 69 | assert 'slide_helper' in cells[1].metadata |
|
70 | 70 | self.assertEqual(cells[1].metadata['slide_helper'], '-') |
|
71 | 71 | |
|
72 | 72 | # Verify 'slide-end' |
|
73 | 73 | assert 'slide_helper' in cells[0].metadata |
|
74 | 74 | self.assertEqual(cells[0].metadata['slide_helper'], 'slide_end') |
|
75 | 75 | assert 'slide_helper' in cells[2].metadata |
|
76 | 76 | self.assertEqual(cells[2].metadata['slide_helper'], 'slide_end') |
|
77 | 77 | assert 'slide_helper' in cells[3].metadata |
|
78 | 78 | self.assertEqual(cells[3].metadata['slide_helper'], 'subslide_end') |
@@ -1,74 +1,74 b'' | |||
|
1 | 1 | """Tests for the svg2pdf preprocessor""" |
|
2 | 2 | |
|
3 | 3 | # Copyright (c) IPython Development Team. |
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 | 6 | from IPython.testing import decorators as dec |
|
7 |
from IPython.nbformat import |
|
|
7 | from IPython.nbformat import v4 as nbformat | |
|
8 | 8 | |
|
9 | 9 | from .base import PreprocessorTestsBase |
|
10 | 10 | from ..svg2pdf import SVG2PDFPreprocessor |
|
11 | 11 | |
|
12 | 12 | |
|
13 | 13 | class Testsvg2pdf(PreprocessorTestsBase): |
|
14 | 14 | """Contains test functions for svg2pdf.py""" |
|
15 | 15 | |
|
16 | 16 | simple_svg = """<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
|
17 | 17 | <!-- Created with Inkscape (http://www.inkscape.org/) --> |
|
18 | 18 | <svg |
|
19 | 19 | xmlns:svg="http://www.w3.org/2000/svg" |
|
20 | 20 | xmlns="http://www.w3.org/2000/svg" |
|
21 | 21 | version="1.0" |
|
22 | 22 | x="0.00000000" |
|
23 | 23 | y="0.00000000" |
|
24 | 24 | width="500.00000" |
|
25 | 25 | height="500.00000" |
|
26 | 26 | id="svg2"> |
|
27 | 27 | <defs |
|
28 | 28 | id="defs4" /> |
|
29 | 29 | <g |
|
30 | 30 | id="layer1"> |
|
31 | 31 | <rect |
|
32 | 32 | width="300.00000" |
|
33 | 33 | height="300.00000" |
|
34 | 34 | x="100.00000" |
|
35 | 35 | y="100.00000" |
|
36 | 36 | style="opacity:1.0000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:8.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000" |
|
37 | 37 | id="rect5719" /> |
|
38 | 38 | </g> |
|
39 | 39 | </svg>""" |
|
40 | 40 | |
|
41 | 41 | def build_notebook(self): |
|
42 | 42 | """Build a reveal slides notebook in memory for use with tests. |
|
43 | 43 | Overrides base in PreprocessorTestsBase""" |
|
44 | 44 | |
|
45 | 45 | outputs = [nbformat.new_output(output_type="image/svg+xml", output_svg=self.simple_svg)] |
|
46 | 46 | |
|
47 | 47 | slide_metadata = {'slideshow' : {'slide_type': 'slide'}} |
|
48 | 48 | subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}} |
|
49 | 49 | |
|
50 | 50 | cells=[nbformat.new_code_cell(source="", execution_count=1, outputs=outputs)] |
|
51 | 51 | |
|
52 | 52 | return nbformat.new_notebook(cells=cells) |
|
53 | 53 | |
|
54 | 54 | |
|
55 | 55 | def build_preprocessor(self): |
|
56 | 56 | """Make an instance of a preprocessor""" |
|
57 | 57 | preprocessor = SVG2PDFPreprocessor() |
|
58 | 58 | preprocessor.enabled = True |
|
59 | 59 | return preprocessor |
|
60 | 60 | |
|
61 | 61 | |
|
62 | 62 | def test_constructor(self): |
|
63 | 63 | """Can a SVG2PDFPreprocessor be constructed?""" |
|
64 | 64 | self.build_preprocessor() |
|
65 | 65 | |
|
66 | 66 | |
|
67 | 67 | @dec.onlyif_cmds_exist('inkscape') |
|
68 | 68 | def test_output(self): |
|
69 | 69 | """Test the output of the SVG2PDFPreprocessor""" |
|
70 | 70 | nb = self.build_notebook() |
|
71 | 71 | res = self.build_resources() |
|
72 | 72 | preprocessor = self.build_preprocessor() |
|
73 | 73 | nb, res = preprocessor(nb, res) |
|
74 | 74 | self.assertIn('application/pdf', nb.cells[0].outputs[0]) |
@@ -1,149 +1,148 b'' | |||
|
1 | 1 | """Base test class for nbconvert""" |
|
2 | 2 | |
|
3 | 3 | # Copyright (c) IPython Development Team. |
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 | 6 | import io |
|
7 | 7 | import os |
|
8 | 8 | import glob |
|
9 | 9 | import shutil |
|
10 | 10 | import unittest |
|
11 | 11 | |
|
12 | 12 | import IPython |
|
13 |
from IPython.nbformat import |
|
|
13 | from IPython.nbformat import v4, write | |
|
14 | 14 | from IPython.utils.tempdir import TemporaryWorkingDirectory |
|
15 | 15 | from IPython.utils.path import get_ipython_package_dir |
|
16 | 16 | from IPython.utils.process import get_output_error_code |
|
17 | 17 | from IPython.testing.tools import get_ipython_cmd |
|
18 | 18 | |
|
19 | 19 | # a trailing space allows for simpler concatenation with the other arguments |
|
20 | 20 | ipy_cmd = get_ipython_cmd(as_string=True) + " " |
|
21 | 21 | |
|
22 | 22 | |
|
23 | 23 | class TestsBase(unittest.TestCase): |
|
24 | 24 | """Base tests class. Contains useful fuzzy comparison and nbconvert |
|
25 | 25 | functions.""" |
|
26 | 26 | |
|
27 | 27 | |
|
28 | 28 | def fuzzy_compare(self, a, b, newlines_are_spaces=True, tabs_are_spaces=True, |
|
29 | 29 | fuzzy_spacing=True, ignore_spaces=False, |
|
30 | 30 | ignore_newlines=False, case_sensitive=False, leave_padding=False): |
|
31 | 31 | """ |
|
32 | 32 | Performs a fuzzy comparison of two strings. A fuzzy comparison is a |
|
33 | 33 | comparison that ignores insignificant differences in the two comparands. |
|
34 | 34 | The significance of certain differences can be specified via the keyword |
|
35 | 35 | parameters of this method. |
|
36 | 36 | """ |
|
37 | 37 | |
|
38 | 38 | if not leave_padding: |
|
39 | 39 | a = a.strip() |
|
40 | 40 | b = b.strip() |
|
41 | 41 | |
|
42 | 42 | if ignore_newlines: |
|
43 | 43 | a = a.replace('\n', '') |
|
44 | 44 | b = b.replace('\n', '') |
|
45 | 45 | |
|
46 | 46 | if newlines_are_spaces: |
|
47 | 47 | a = a.replace('\n', ' ') |
|
48 | 48 | b = b.replace('\n', ' ') |
|
49 | 49 | |
|
50 | 50 | if tabs_are_spaces: |
|
51 | 51 | a = a.replace('\t', ' ') |
|
52 | 52 | b = b.replace('\t', ' ') |
|
53 | 53 | |
|
54 | 54 | if ignore_spaces: |
|
55 | 55 | a = a.replace(' ', '') |
|
56 | 56 | b = b.replace(' ', '') |
|
57 | 57 | |
|
58 | 58 | if fuzzy_spacing: |
|
59 | 59 | a = self.recursive_replace(a, ' ', ' ') |
|
60 | 60 | b = self.recursive_replace(b, ' ', ' ') |
|
61 | 61 | |
|
62 | 62 | if not case_sensitive: |
|
63 | 63 | a = a.lower() |
|
64 | 64 | b = b.lower() |
|
65 | 65 | |
|
66 | 66 | self.assertEqual(a, b) |
|
67 | 67 | |
|
68 | 68 | |
|
69 | 69 | def recursive_replace(self, text, search, replacement): |
|
70 | 70 | """ |
|
71 | 71 | Performs a recursive replacement operation. Replaces all instances |
|
72 | 72 | of a search string in a text string with a replacement string until |
|
73 | 73 | the search string no longer exists. Recursion is needed because the |
|
74 | 74 | replacement string may generate additional search strings. |
|
75 | 75 | |
|
76 | 76 | For example: |
|
77 | 77 | Replace "ii" with "i" in the string "Hiiii" yields "Hii" |
|
78 | 78 | Another replacement cds "Hi" (the desired output) |
|
79 | 79 | |
|
80 | 80 | Parameters |
|
81 | 81 | ---------- |
|
82 | 82 | text : string |
|
83 | 83 | Text to replace in. |
|
84 | 84 | search : string |
|
85 | 85 | String to search for within "text" |
|
86 | 86 | replacement : string |
|
87 | 87 | String to replace "search" with |
|
88 | 88 | """ |
|
89 | 89 | while search in text: |
|
90 | 90 | text = text.replace(search, replacement) |
|
91 | 91 | return text |
|
92 | 92 | |
|
93 | 93 | def create_temp_cwd(self, copy_filenames=None): |
|
94 | 94 | temp_dir = TemporaryWorkingDirectory() |
|
95 | 95 | |
|
96 | 96 | #Copy the files if requested. |
|
97 | 97 | if copy_filenames is not None: |
|
98 | 98 | self.copy_files_to(copy_filenames, dest=temp_dir.name) |
|
99 | 99 | |
|
100 | 100 | #Return directory handler |
|
101 | 101 | return temp_dir |
|
102 | 102 | |
|
103 | 103 | def create_empty_notebook(self, path): |
|
104 |
nb = |
|
|
104 | nb = v4.new_notebook() | |
|
105 | 105 | with io.open(path, 'w', encoding='utf-8') as f: |
|
106 |
|
|
|
107 | ||
|
106 | write(f, nb, 4) | |
|
108 | 107 | |
|
109 | 108 | def copy_files_to(self, copy_filenames, dest='.'): |
|
110 | 109 | "Copy test files into the destination directory" |
|
111 | 110 | if not os.path.isdir(dest): |
|
112 | 111 | os.makedirs(dest) |
|
113 | 112 | files_path = self._get_files_path() |
|
114 | 113 | for pattern in copy_filenames: |
|
115 | 114 | for match in glob.glob(os.path.join(files_path, pattern)): |
|
116 | 115 | shutil.copyfile(match, os.path.join(dest, os.path.basename(match))) |
|
117 | 116 | |
|
118 | 117 | |
|
119 | 118 | def _get_files_path(self): |
|
120 | 119 | |
|
121 | 120 | #Get the relative path to this module in the IPython directory. |
|
122 | 121 | names = self.__module__.split('.')[1:-1] |
|
123 | 122 | names.append('files') |
|
124 | 123 | |
|
125 | 124 | #Build a path using the IPython directory and the relative path we just |
|
126 | 125 | #found. |
|
127 | 126 | path = get_ipython_package_dir() |
|
128 | 127 | for name in names: |
|
129 | 128 | path = os.path.join(path, name) |
|
130 | 129 | return path |
|
131 | 130 | |
|
132 | 131 | |
|
133 | 132 | def call(self, parameters, ignore_return_code=False): |
|
134 | 133 | """ |
|
135 | 134 | Execute a, IPython shell command, listening for both Errors and non-zero |
|
136 | 135 | return codes. |
|
137 | 136 | |
|
138 | 137 | Parameters |
|
139 | 138 | ---------- |
|
140 | 139 | parameters : str |
|
141 | 140 | List of parameters to pass to IPython. |
|
142 | 141 | ignore_return_code : optional bool (default False) |
|
143 | 142 | Throw an OSError if the return code |
|
144 | 143 | """ |
|
145 | 144 | |
|
146 | 145 | stdout, stderr, retcode = get_output_error_code(ipy_cmd + parameters) |
|
147 | 146 | if not (retcode == 0 or ignore_return_code): |
|
148 | 147 | raise OSError(stderr) |
|
149 | 148 | return stdout, stderr |
General Comments 0
You need to be logged in to leave comments.
Login now