Show More
@@ -0,0 +1,74 b'' | |||||
|
1 | """The main API for the v3 notebook format. | |||
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | ||||
|
19 | from .nbbase import ( | |||
|
20 | NotebookNode, | |||
|
21 | new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet, | |||
|
22 | new_metadata, new_author, new_heading_cell, nbformat, nbformat_minor, | |||
|
23 | nbformat_schema | |||
|
24 | ) | |||
|
25 | ||||
|
26 | from .nbjson import reads as reads_json, writes as writes_json | |||
|
27 | from .nbjson import reads as read_json, writes as write_json | |||
|
28 | from .nbjson import to_notebook as to_notebook_json | |||
|
29 | ||||
|
30 | from .nbpy import reads as reads_py, writes as writes_py | |||
|
31 | from .nbpy import reads as read_py, writes as write_py | |||
|
32 | from .nbpy import to_notebook as to_notebook_py | |||
|
33 | ||||
|
34 | from .convert import downgrade, upgrade | |||
|
35 | ||||
|
36 | #----------------------------------------------------------------------------- | |||
|
37 | # Code | |||
|
38 | #----------------------------------------------------------------------------- | |||
|
39 | ||||
|
40 | def parse_filename(fname): | |||
|
41 | """Parse a notebook filename. | |||
|
42 | ||||
|
43 | This function takes a notebook filename and returns the notebook | |||
|
44 | format (json/py) and the notebook name. This logic can be | |||
|
45 | summarized as follows: | |||
|
46 | ||||
|
47 | * notebook.ipynb -> (notebook.ipynb, notebook, json) | |||
|
48 | * notebook.json -> (notebook.json, notebook, json) | |||
|
49 | * notebook.py -> (notebook.py, notebook, py) | |||
|
50 | * notebook -> (notebook.ipynb, notebook, json) | |||
|
51 | ||||
|
52 | Parameters | |||
|
53 | ---------- | |||
|
54 | fname : unicode | |||
|
55 | The notebook filename. The filename can use a specific filename | |||
|
56 | extention (.ipynb, .json, .py) or none, in which case .ipynb will | |||
|
57 | be assumed. | |||
|
58 | ||||
|
59 | Returns | |||
|
60 | ------- | |||
|
61 | (fname, name, format) : (unicode, unicode, unicode) | |||
|
62 | The filename, notebook name and format. | |||
|
63 | """ | |||
|
64 | if fname.endswith(u'.ipynb'): | |||
|
65 | format = u'json' | |||
|
66 | elif fname.endswith(u'.json'): | |||
|
67 | format = u'json' | |||
|
68 | elif fname.endswith(u'.py'): | |||
|
69 | format = u'py' | |||
|
70 | else: | |||
|
71 | fname = fname + u'.ipynb' | |||
|
72 | format = u'json' | |||
|
73 | name = fname.split('.')[0] | |||
|
74 | return fname, name, format |
@@ -0,0 +1,90 b'' | |||||
|
1 | """Code for converting notebooks to and from the v2 format. | |||
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | * Min RK | |||
|
7 | * Jonathan Frederic | |||
|
8 | """ | |||
|
9 | ||||
|
10 | #----------------------------------------------------------------------------- | |||
|
11 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
12 | # | |||
|
13 | # Distributed under the terms of the BSD License. The full license is in | |||
|
14 | # the file COPYING, distributed as part of this software. | |||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | ||||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | # Imports | |||
|
19 | #----------------------------------------------------------------------------- | |||
|
20 | ||||
|
21 | from .nbbase import ( | |||
|
22 | new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output, | |||
|
23 | nbformat, nbformat_minor | |||
|
24 | ) | |||
|
25 | ||||
|
26 | from IPython.nbformat import v2 | |||
|
27 | ||||
|
28 | #----------------------------------------------------------------------------- | |||
|
29 | # Code | |||
|
30 | #----------------------------------------------------------------------------- | |||
|
31 | ||||
|
32 | def upgrade(nb, from_version=2, from_minor=0): | |||
|
33 | """Convert a notebook to v3. | |||
|
34 | ||||
|
35 | Parameters | |||
|
36 | ---------- | |||
|
37 | nb : NotebookNode | |||
|
38 | The Python representation of the notebook to convert. | |||
|
39 | from_version : int | |||
|
40 | The original version of the notebook to convert. | |||
|
41 | from_minor : int | |||
|
42 | The original minor version of the notebook to convert (only relevant for v >= 3). | |||
|
43 | """ | |||
|
44 | if from_version == 2: | |||
|
45 | # Mark the original nbformat so consumers know it has been converted. | |||
|
46 | nb.nbformat = nbformat | |||
|
47 | nb.nbformat_minor = nbformat_minor | |||
|
48 | ||||
|
49 | nb.orig_nbformat = 2 | |||
|
50 | return nb | |||
|
51 | elif from_version == 3: | |||
|
52 | if from_minor != nbformat_minor: | |||
|
53 | nb.orig_nbformat_minor = from_minor | |||
|
54 | nb.nbformat_minor = nbformat_minor | |||
|
55 | return nb | |||
|
56 | else: | |||
|
57 | raise ValueError('Cannot convert a notebook directly from v%s to v3. ' \ | |||
|
58 | 'Try using the IPython.nbformat.convert module.' % from_version) | |||
|
59 | ||||
|
60 | ||||
|
61 | def heading_to_md(cell): | |||
|
62 | """turn heading cell into corresponding markdown""" | |||
|
63 | cell.cell_type = "markdown" | |||
|
64 | level = cell.pop('level', 1) | |||
|
65 | cell.source = '#'*level + ' ' + cell.source | |||
|
66 | ||||
|
67 | ||||
|
68 | def raw_to_md(cell): | |||
|
69 | """let raw passthrough as markdown""" | |||
|
70 | cell.cell_type = "markdown" | |||
|
71 | ||||
|
72 | ||||
|
73 | def downgrade(nb): | |||
|
74 | """Convert a v3 notebook to v2. | |||
|
75 | ||||
|
76 | Parameters | |||
|
77 | ---------- | |||
|
78 | nb : NotebookNode | |||
|
79 | The Python representation of the notebook to convert. | |||
|
80 | """ | |||
|
81 | if nb.nbformat != 3: | |||
|
82 | return nb | |||
|
83 | nb.nbformat = 2 | |||
|
84 | for ws in nb.worksheets: | |||
|
85 | for cell in ws.cells: | |||
|
86 | if cell.cell_type == 'heading': | |||
|
87 | heading_to_md(cell) | |||
|
88 | elif cell.cell_type == 'raw': | |||
|
89 | raw_to_md(cell) | |||
|
90 | return nb No newline at end of file |
@@ -0,0 +1,204 b'' | |||||
|
1 | """The basic dict based notebook format. | |||
|
2 | ||||
|
3 | The Python representation of a notebook is a nested structure of | |||
|
4 | dictionary subclasses that support attribute access | |||
|
5 | (IPython.utils.ipstruct.Struct). The functions in this module are merely | |||
|
6 | helpers to build the structs in the right form. | |||
|
7 | """ | |||
|
8 | ||||
|
9 | # Copyright (c) IPython Development Team. | |||
|
10 | # Distributed under the terms of the Modified BSD License. | |||
|
11 | ||||
|
12 | import pprint | |||
|
13 | import uuid | |||
|
14 | ||||
|
15 | from IPython.utils.ipstruct import Struct | |||
|
16 | from IPython.utils.py3compat import cast_unicode, unicode_type | |||
|
17 | ||||
|
18 | #----------------------------------------------------------------------------- | |||
|
19 | # Code | |||
|
20 | #----------------------------------------------------------------------------- | |||
|
21 | ||||
|
22 | # Change this when incrementing the nbformat version | |||
|
23 | nbformat = 3 | |||
|
24 | nbformat_minor = 0 | |||
|
25 | nbformat_schema = 'v3.withref.json' | |||
|
26 | ||||
|
27 | class NotebookNode(Struct): | |||
|
28 | pass | |||
|
29 | ||||
|
30 | ||||
|
31 | def from_dict(d): | |||
|
32 | if isinstance(d, dict): | |||
|
33 | newd = NotebookNode() | |||
|
34 | for k,v in d.items(): | |||
|
35 | newd[k] = from_dict(v) | |||
|
36 | return newd | |||
|
37 | elif isinstance(d, (tuple, list)): | |||
|
38 | return [from_dict(i) for i in d] | |||
|
39 | else: | |||
|
40 | return d | |||
|
41 | ||||
|
42 | ||||
|
43 | def new_output(output_type, output_text=None, output_png=None, | |||
|
44 | output_html=None, output_svg=None, output_latex=None, output_json=None, | |||
|
45 | output_javascript=None, output_jpeg=None, prompt_number=None, | |||
|
46 | ename=None, evalue=None, traceback=None, stream=None, metadata=None): | |||
|
47 | """Create a new output, to go in the ``cell.outputs`` list of a code cell. | |||
|
48 | """ | |||
|
49 | output = NotebookNode() | |||
|
50 | output.output_type = unicode_type(output_type) | |||
|
51 | ||||
|
52 | if metadata is None: | |||
|
53 | metadata = {} | |||
|
54 | if not isinstance(metadata, dict): | |||
|
55 | raise TypeError("metadata must be dict") | |||
|
56 | output.metadata = metadata | |||
|
57 | ||||
|
58 | if output_type != 'pyerr': | |||
|
59 | if output_text is not None: | |||
|
60 | output.text = cast_unicode(output_text) | |||
|
61 | if output_png is not None: | |||
|
62 | output.png = cast_unicode(output_png) | |||
|
63 | if output_jpeg is not None: | |||
|
64 | output.jpeg = cast_unicode(output_jpeg) | |||
|
65 | if output_html is not None: | |||
|
66 | output.html = cast_unicode(output_html) | |||
|
67 | if output_svg is not None: | |||
|
68 | output.svg = cast_unicode(output_svg) | |||
|
69 | if output_latex is not None: | |||
|
70 | output.latex = cast_unicode(output_latex) | |||
|
71 | if output_json is not None: | |||
|
72 | output.json = cast_unicode(output_json) | |||
|
73 | if output_javascript is not None: | |||
|
74 | output.javascript = cast_unicode(output_javascript) | |||
|
75 | ||||
|
76 | if output_type == u'pyout': | |||
|
77 | if prompt_number is not None: | |||
|
78 | output.prompt_number = int(prompt_number) | |||
|
79 | ||||
|
80 | if output_type == u'pyerr': | |||
|
81 | if ename is not None: | |||
|
82 | output.ename = cast_unicode(ename) | |||
|
83 | if evalue is not None: | |||
|
84 | output.evalue = cast_unicode(evalue) | |||
|
85 | if traceback is not None: | |||
|
86 | output.traceback = [cast_unicode(frame) for frame in list(traceback)] | |||
|
87 | ||||
|
88 | if output_type == u'stream': | |||
|
89 | output.stream = 'stdout' if stream is None else cast_unicode(stream) | |||
|
90 | ||||
|
91 | return output | |||
|
92 | ||||
|
93 | ||||
|
94 | def new_code_cell(input=None, prompt_number=None, outputs=None, | |||
|
95 | language=u'python', collapsed=False, metadata=None): | |||
|
96 | """Create a new code cell with input and output""" | |||
|
97 | cell = NotebookNode() | |||
|
98 | cell.cell_type = u'code' | |||
|
99 | if language is not None: | |||
|
100 | cell.language = cast_unicode(language) | |||
|
101 | if input is not None: | |||
|
102 | cell.input = cast_unicode(input) | |||
|
103 | if prompt_number is not None: | |||
|
104 | cell.prompt_number = int(prompt_number) | |||
|
105 | if outputs is None: | |||
|
106 | cell.outputs = [] | |||
|
107 | else: | |||
|
108 | cell.outputs = outputs | |||
|
109 | if collapsed is not None: | |||
|
110 | cell.collapsed = bool(collapsed) | |||
|
111 | cell.metadata = NotebookNode(metadata or {}) | |||
|
112 | ||||
|
113 | return cell | |||
|
114 | ||||
|
115 | def new_text_cell(cell_type, source=None, rendered=None, metadata=None): | |||
|
116 | """Create a new text cell.""" | |||
|
117 | cell = NotebookNode() | |||
|
118 | # VERSIONHACK: plaintext -> raw | |||
|
119 | # handle never-released plaintext name for raw cells | |||
|
120 | if cell_type == 'plaintext': | |||
|
121 | cell_type = 'raw' | |||
|
122 | if source is not None: | |||
|
123 | cell.source = cast_unicode(source) | |||
|
124 | if rendered is not None: | |||
|
125 | cell.rendered = cast_unicode(rendered) | |||
|
126 | cell.metadata = NotebookNode(metadata or {}) | |||
|
127 | cell.cell_type = cell_type | |||
|
128 | return cell | |||
|
129 | ||||
|
130 | ||||
|
131 | def new_heading_cell(source=None, rendered=None, level=1, metadata=None): | |||
|
132 | """Create a new section cell with a given integer level.""" | |||
|
133 | cell = NotebookNode() | |||
|
134 | cell.cell_type = u'heading' | |||
|
135 | if source is not None: | |||
|
136 | cell.source = cast_unicode(source) | |||
|
137 | if rendered is not None: | |||
|
138 | cell.rendered = cast_unicode(rendered) | |||
|
139 | cell.level = int(level) | |||
|
140 | cell.metadata = NotebookNode(metadata or {}) | |||
|
141 | return cell | |||
|
142 | ||||
|
143 | ||||
|
144 | def new_worksheet(name=None, cells=None, metadata=None): | |||
|
145 | """Create a worksheet by name with with a list of cells.""" | |||
|
146 | ws = NotebookNode() | |||
|
147 | if name is not None: | |||
|
148 | ws.name = cast_unicode(name) | |||
|
149 | if cells is None: | |||
|
150 | ws.cells = [] | |||
|
151 | else: | |||
|
152 | ws.cells = list(cells) | |||
|
153 | ws.metadata = NotebookNode(metadata or {}) | |||
|
154 | return ws | |||
|
155 | ||||
|
156 | ||||
|
157 | def new_notebook(name=None, metadata=None, worksheets=None): | |||
|
158 | """Create a notebook by name, id and a list of worksheets.""" | |||
|
159 | nb = NotebookNode() | |||
|
160 | nb.nbformat = nbformat | |||
|
161 | nb.nbformat_minor = nbformat_minor | |||
|
162 | if worksheets is None: | |||
|
163 | nb.worksheets = [] | |||
|
164 | else: | |||
|
165 | nb.worksheets = list(worksheets) | |||
|
166 | if metadata is None: | |||
|
167 | nb.metadata = new_metadata() | |||
|
168 | else: | |||
|
169 | nb.metadata = NotebookNode(metadata) | |||
|
170 | if name is not None: | |||
|
171 | nb.metadata.name = cast_unicode(name) | |||
|
172 | return nb | |||
|
173 | ||||
|
174 | ||||
|
175 | def new_metadata(name=None, authors=None, license=None, created=None, | |||
|
176 | modified=None, gistid=None): | |||
|
177 | """Create a new metadata node.""" | |||
|
178 | metadata = NotebookNode() | |||
|
179 | if name is not None: | |||
|
180 | metadata.name = cast_unicode(name) | |||
|
181 | if authors is not None: | |||
|
182 | metadata.authors = list(authors) | |||
|
183 | if created is not None: | |||
|
184 | metadata.created = cast_unicode(created) | |||
|
185 | if modified is not None: | |||
|
186 | metadata.modified = cast_unicode(modified) | |||
|
187 | if license is not None: | |||
|
188 | metadata.license = cast_unicode(license) | |||
|
189 | if gistid is not None: | |||
|
190 | metadata.gistid = cast_unicode(gistid) | |||
|
191 | return metadata | |||
|
192 | ||||
|
193 | def new_author(name=None, email=None, affiliation=None, url=None): | |||
|
194 | """Create a new author.""" | |||
|
195 | author = NotebookNode() | |||
|
196 | if name is not None: | |||
|
197 | author.name = cast_unicode(name) | |||
|
198 | if email is not None: | |||
|
199 | author.email = cast_unicode(email) | |||
|
200 | if affiliation is not None: | |||
|
201 | author.affiliation = cast_unicode(affiliation) | |||
|
202 | if url is not None: | |||
|
203 | author.url = cast_unicode(url) | |||
|
204 | return author |
@@ -0,0 +1,71 b'' | |||||
|
1 | """Read and write notebooks in JSON format. | |||
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | ||||
|
19 | import copy | |||
|
20 | import json | |||
|
21 | ||||
|
22 | from .nbbase import from_dict | |||
|
23 | from .rwbase import ( | |||
|
24 | NotebookReader, NotebookWriter, restore_bytes, rejoin_lines, split_lines | |||
|
25 | ) | |||
|
26 | ||||
|
27 | from IPython.utils import py3compat | |||
|
28 | ||||
|
29 | #----------------------------------------------------------------------------- | |||
|
30 | # Code | |||
|
31 | #----------------------------------------------------------------------------- | |||
|
32 | ||||
|
33 | class BytesEncoder(json.JSONEncoder): | |||
|
34 | """A JSON encoder that accepts b64 (and other *ascii*) bytestrings.""" | |||
|
35 | def default(self, obj): | |||
|
36 | if isinstance(obj, bytes): | |||
|
37 | return obj.decode('ascii') | |||
|
38 | return json.JSONEncoder.default(self, obj) | |||
|
39 | ||||
|
40 | ||||
|
41 | class JSONReader(NotebookReader): | |||
|
42 | ||||
|
43 | def reads(self, s, **kwargs): | |||
|
44 | nb = json.loads(s, **kwargs) | |||
|
45 | nb = self.to_notebook(nb, **kwargs) | |||
|
46 | return nb | |||
|
47 | ||||
|
48 | def to_notebook(self, d, **kwargs): | |||
|
49 | return rejoin_lines(from_dict(d)) | |||
|
50 | ||||
|
51 | ||||
|
52 | class JSONWriter(NotebookWriter): | |||
|
53 | ||||
|
54 | def writes(self, nb, **kwargs): | |||
|
55 | kwargs['cls'] = BytesEncoder | |||
|
56 | kwargs['indent'] = 1 | |||
|
57 | kwargs['sort_keys'] = True | |||
|
58 | kwargs['separators'] = (',',': ') | |||
|
59 | if kwargs.pop('split_lines', True): | |||
|
60 | nb = split_lines(copy.deepcopy(nb)) | |||
|
61 | return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8') | |||
|
62 | ||||
|
63 | ||||
|
64 | _reader = JSONReader() | |||
|
65 | _writer = JSONWriter() | |||
|
66 | ||||
|
67 | reads = _reader.reads | |||
|
68 | read = _reader.read | |||
|
69 | to_notebook = _reader.to_notebook | |||
|
70 | write = _writer.write | |||
|
71 | writes = _writer.writes |
@@ -0,0 +1,188 b'' | |||||
|
1 | """Base classes and utilities for readers and writers. | |||
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Brian Granger | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2008-2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | ||||
|
19 | from base64 import encodestring, decodestring | |||
|
20 | import pprint | |||
|
21 | ||||
|
22 | from IPython.utils import py3compat | |||
|
23 | from IPython.utils.py3compat import str_to_bytes, unicode_type, string_types | |||
|
24 | ||||
|
25 | #----------------------------------------------------------------------------- | |||
|
26 | # Code | |||
|
27 | #----------------------------------------------------------------------------- | |||
|
28 | ||||
|
29 | def restore_bytes(nb): | |||
|
30 | """Restore bytes of image data from unicode-only formats. | |||
|
31 | ||||
|
32 | Base64 encoding is handled elsewhere. Bytes objects in the notebook are | |||
|
33 | always b64-encoded. We DO NOT encode/decode around file formats. | |||
|
34 | ||||
|
35 | Note: this is never used | |||
|
36 | """ | |||
|
37 | for ws in nb.worksheets: | |||
|
38 | for cell in ws.cells: | |||
|
39 | if cell.cell_type == 'code': | |||
|
40 | for output in cell.outputs: | |||
|
41 | if 'png' in output: | |||
|
42 | output.png = str_to_bytes(output.png, 'ascii') | |||
|
43 | if 'jpeg' in output: | |||
|
44 | output.jpeg = str_to_bytes(output.jpeg, 'ascii') | |||
|
45 | return nb | |||
|
46 | ||||
|
47 | # output keys that are likely to have multiline values | |||
|
48 | _multiline_outputs = ['text', 'html', 'svg', 'latex', 'javascript', 'json'] | |||
|
49 | ||||
|
50 | ||||
|
51 | # FIXME: workaround for old splitlines() | |||
|
52 | def _join_lines(lines): | |||
|
53 | """join lines that have been written by splitlines() | |||
|
54 | ||||
|
55 | Has logic to protect against `splitlines()`, which | |||
|
56 | should have been `splitlines(True)` | |||
|
57 | """ | |||
|
58 | if lines and lines[0].endswith(('\n', '\r')): | |||
|
59 | # created by splitlines(True) | |||
|
60 | return u''.join(lines) | |||
|
61 | else: | |||
|
62 | # created by splitlines() | |||
|
63 | return u'\n'.join(lines) | |||
|
64 | ||||
|
65 | ||||
|
66 | def rejoin_lines(nb): | |||
|
67 | """rejoin multiline text into strings | |||
|
68 | ||||
|
69 | For reversing effects of ``split_lines(nb)``. | |||
|
70 | ||||
|
71 | This only rejoins lines that have been split, so if text objects were not split | |||
|
72 | they will pass through unchanged. | |||
|
73 | ||||
|
74 | Used when reading JSON files that may have been passed through split_lines. | |||
|
75 | """ | |||
|
76 | for ws in nb.worksheets: | |||
|
77 | for cell in ws.cells: | |||
|
78 | if cell.cell_type == 'code': | |||
|
79 | if 'input' in cell and isinstance(cell.input, list): | |||
|
80 | cell.input = _join_lines(cell.input) | |||
|
81 | for output in cell.outputs: | |||
|
82 | for key in _multiline_outputs: | |||
|
83 | item = output.get(key, None) | |||
|
84 | if isinstance(item, list): | |||
|
85 | output[key] = _join_lines(item) | |||
|
86 | else: # text, heading cell | |||
|
87 | for key in ['source', 'rendered']: | |||
|
88 | item = cell.get(key, None) | |||
|
89 | if isinstance(item, list): | |||
|
90 | cell[key] = _join_lines(item) | |||
|
91 | return nb | |||
|
92 | ||||
|
93 | ||||
|
94 | def split_lines(nb): | |||
|
95 | """split likely multiline text into lists of strings | |||
|
96 | ||||
|
97 | For file output more friendly to line-based VCS. ``rejoin_lines(nb)`` will | |||
|
98 | reverse the effects of ``split_lines(nb)``. | |||
|
99 | ||||
|
100 | Used when writing JSON files. | |||
|
101 | """ | |||
|
102 | for ws in nb.worksheets: | |||
|
103 | for cell in ws.cells: | |||
|
104 | if cell.cell_type == 'code': | |||
|
105 | if 'input' in cell and isinstance(cell.input, string_types): | |||
|
106 | cell.input = cell.input.splitlines(True) | |||
|
107 | for output in cell.outputs: | |||
|
108 | for key in _multiline_outputs: | |||
|
109 | item = output.get(key, None) | |||
|
110 | if isinstance(item, string_types): | |||
|
111 | output[key] = item.splitlines(True) | |||
|
112 | else: # text, heading cell | |||
|
113 | for key in ['source', 'rendered']: | |||
|
114 | item = cell.get(key, None) | |||
|
115 | if isinstance(item, string_types): | |||
|
116 | cell[key] = item.splitlines(True) | |||
|
117 | return nb | |||
|
118 | ||||
|
119 | # b64 encode/decode are never actually used, because all bytes objects in | |||
|
120 | # the notebook are already b64-encoded, and we don't need/want to double-encode | |||
|
121 | ||||
|
122 | def base64_decode(nb): | |||
|
123 | """Restore all bytes objects in the notebook from base64-encoded strings. | |||
|
124 | ||||
|
125 | Note: This is never used | |||
|
126 | """ | |||
|
127 | for ws in nb.worksheets: | |||
|
128 | for cell in ws.cells: | |||
|
129 | if cell.cell_type == 'code': | |||
|
130 | for output in cell.outputs: | |||
|
131 | if 'png' in output: | |||
|
132 | if isinstance(output.png, unicode_type): | |||
|
133 | output.png = output.png.encode('ascii') | |||
|
134 | output.png = decodestring(output.png) | |||
|
135 | if 'jpeg' in output: | |||
|
136 | if isinstance(output.jpeg, unicode_type): | |||
|
137 | output.jpeg = output.jpeg.encode('ascii') | |||
|
138 | output.jpeg = decodestring(output.jpeg) | |||
|
139 | return nb | |||
|
140 | ||||
|
141 | ||||
|
142 | def base64_encode(nb): | |||
|
143 | """Base64 encode all bytes objects in the notebook. | |||
|
144 | ||||
|
145 | These will be b64-encoded unicode strings | |||
|
146 | ||||
|
147 | Note: This is never used | |||
|
148 | """ | |||
|
149 | for ws in nb.worksheets: | |||
|
150 | for cell in ws.cells: | |||
|
151 | if cell.cell_type == 'code': | |||
|
152 | for output in cell.outputs: | |||
|
153 | if 'png' in output: | |||
|
154 | output.png = encodestring(output.png).decode('ascii') | |||
|
155 | if 'jpeg' in output: | |||
|
156 | output.jpeg = encodestring(output.jpeg).decode('ascii') | |||
|
157 | return nb | |||
|
158 | ||||
|
159 | ||||
|
160 | class NotebookReader(object): | |||
|
161 | """A class for reading notebooks.""" | |||
|
162 | ||||
|
163 | def reads(self, s, **kwargs): | |||
|
164 | """Read a notebook from a string.""" | |||
|
165 | raise NotImplementedError("loads must be implemented in a subclass") | |||
|
166 | ||||
|
167 | def read(self, fp, **kwargs): | |||
|
168 | """Read a notebook from a file like object""" | |||
|
169 | nbs = fp.read() | |||
|
170 | if not py3compat.PY3 and not isinstance(nbs, unicode_type): | |||
|
171 | nbs = py3compat.str_to_unicode(nbs) | |||
|
172 | return self.reads(nbs, **kwargs) | |||
|
173 | ||||
|
174 | ||||
|
175 | class NotebookWriter(object): | |||
|
176 | """A class for writing notebooks.""" | |||
|
177 | ||||
|
178 | def writes(self, nb, **kwargs): | |||
|
179 | """Write a notebook to a string.""" | |||
|
180 | raise NotImplementedError("loads must be implemented in a subclass") | |||
|
181 | ||||
|
182 | def write(self, nb, fp, **kwargs): | |||
|
183 | """Write a notebook to a file like object""" | |||
|
184 | nbs = self.writes(nb,**kwargs) | |||
|
185 | if not py3compat.PY3 and not isinstance(nbs, unicode_type): | |||
|
186 | # this branch is likely only taken for JSON on Python 2 | |||
|
187 | nbs = py3compat.str_to_unicode(nbs) | |||
|
188 | return fp.write(nbs) |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
@@ -0,0 +1,60 b'' | |||||
|
1 | # -*- coding: utf8 -*- | |||
|
2 | import io | |||
|
3 | import os | |||
|
4 | import shutil | |||
|
5 | import tempfile | |||
|
6 | ||||
|
7 | pjoin = os.path.join | |||
|
8 | ||||
|
9 | from ..nbbase import ( | |||
|
10 | NotebookNode, | |||
|
11 | new_code_cell, new_text_cell, new_worksheet, new_notebook | |||
|
12 | ) | |||
|
13 | ||||
|
14 | from ..nbpy import reads, writes, read, write | |||
|
15 | from .nbexamples import nb0, nb0_py | |||
|
16 | ||||
|
17 | ||||
|
18 | def open_utf8(fname, mode): | |||
|
19 | return io.open(fname, mode=mode, encoding='utf-8') | |||
|
20 | ||||
|
21 | class NBFormatTest: | |||
|
22 | """Mixin for writing notebook format tests""" | |||
|
23 | ||||
|
24 | # override with appropriate values in subclasses | |||
|
25 | nb0_ref = None | |||
|
26 | ext = None | |||
|
27 | mod = None | |||
|
28 | ||||
|
29 | def setUp(self): | |||
|
30 | self.wd = tempfile.mkdtemp() | |||
|
31 | ||||
|
32 | def tearDown(self): | |||
|
33 | shutil.rmtree(self.wd) | |||
|
34 | ||||
|
35 | def assertNBEquals(self, nba, nbb): | |||
|
36 | self.assertEqual(nba, nbb) | |||
|
37 | ||||
|
38 | def test_writes(self): | |||
|
39 | s = self.mod.writes(nb0) | |||
|
40 | if self.nb0_ref: | |||
|
41 | self.assertEqual(s, self.nb0_ref) | |||
|
42 | ||||
|
43 | def test_reads(self): | |||
|
44 | s = self.mod.writes(nb0) | |||
|
45 | nb = self.mod.reads(s) | |||
|
46 | ||||
|
47 | def test_roundtrip(self): | |||
|
48 | s = self.mod.writes(nb0) | |||
|
49 | self.assertNBEquals(self.mod.reads(s),nb0) | |||
|
50 | ||||
|
51 | def test_write_file(self): | |||
|
52 | with open_utf8(pjoin(self.wd, "nb0.%s" % self.ext), 'w') as f: | |||
|
53 | self.mod.write(nb0, f) | |||
|
54 | ||||
|
55 | def test_read_file(self): | |||
|
56 | with open_utf8(pjoin(self.wd, "nb0.%s" % self.ext), 'w') as f: | |||
|
57 | self.mod.write(nb0, f) | |||
|
58 | ||||
|
59 | with open_utf8(pjoin(self.wd, "nb0.%s" % self.ext), 'r') as f: | |||
|
60 | nb = self.mod.read(f) |
@@ -0,0 +1,152 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | import os | |||
|
4 | from base64 import encodestring | |||
|
5 | ||||
|
6 | from ..nbbase import ( | |||
|
7 | NotebookNode, | |||
|
8 | new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output, | |||
|
9 | new_metadata, new_author, new_heading_cell, nbformat, nbformat_minor | |||
|
10 | ) | |||
|
11 | ||||
|
12 | # some random base64-encoded *text* | |||
|
13 | png = encodestring(os.urandom(5)).decode('ascii') | |||
|
14 | jpeg = encodestring(os.urandom(6)).decode('ascii') | |||
|
15 | ||||
|
16 | ws = new_worksheet(name='worksheet1') | |||
|
17 | ||||
|
18 | ws.cells.append(new_text_cell( | |||
|
19 | u'html', | |||
|
20 | source='Some NumPy Examples', | |||
|
21 | rendered='Some NumPy Examples' | |||
|
22 | )) | |||
|
23 | ||||
|
24 | ||||
|
25 | ws.cells.append(new_code_cell( | |||
|
26 | input='import numpy', | |||
|
27 | prompt_number=1, | |||
|
28 | collapsed=False | |||
|
29 | )) | |||
|
30 | ||||
|
31 | ws.cells.append(new_text_cell( | |||
|
32 | u'markdown', | |||
|
33 | source='A random array', | |||
|
34 | rendered='A random array' | |||
|
35 | )) | |||
|
36 | ||||
|
37 | ws.cells.append(new_text_cell( | |||
|
38 | u'raw', | |||
|
39 | source='A random array', | |||
|
40 | )) | |||
|
41 | ||||
|
42 | ws.cells.append(new_heading_cell( | |||
|
43 | u'My Heading', | |||
|
44 | level=2 | |||
|
45 | )) | |||
|
46 | ||||
|
47 | ws.cells.append(new_code_cell( | |||
|
48 | input='a = numpy.random.rand(100)', | |||
|
49 | prompt_number=2, | |||
|
50 | collapsed=True | |||
|
51 | )) | |||
|
52 | ws.cells.append(new_code_cell( | |||
|
53 | input='a = 10\nb = 5\n', | |||
|
54 | prompt_number=3, | |||
|
55 | )) | |||
|
56 | ws.cells.append(new_code_cell( | |||
|
57 | input='a = 10\nb = 5', | |||
|
58 | prompt_number=4, | |||
|
59 | )) | |||
|
60 | ||||
|
61 | ws.cells.append(new_code_cell( | |||
|
62 | input=u'print "ünîcødé"', | |||
|
63 | prompt_number=3, | |||
|
64 | collapsed=False, | |||
|
65 | outputs=[new_output( | |||
|
66 | output_type=u'pyout', | |||
|
67 | output_text=u'<array a>', | |||
|
68 | output_html=u'The HTML rep', | |||
|
69 | output_latex=u'$a$', | |||
|
70 | output_png=png, | |||
|
71 | output_jpeg=jpeg, | |||
|
72 | output_svg=u'<svg>', | |||
|
73 | output_json=u'json data', | |||
|
74 | output_javascript=u'var i=0;', | |||
|
75 | prompt_number=3 | |||
|
76 | ),new_output( | |||
|
77 | output_type=u'display_data', | |||
|
78 | output_text=u'<array a>', | |||
|
79 | output_html=u'The HTML rep', | |||
|
80 | output_latex=u'$a$', | |||
|
81 | output_png=png, | |||
|
82 | output_jpeg=jpeg, | |||
|
83 | output_svg=u'<svg>', | |||
|
84 | output_json=u'json data', | |||
|
85 | output_javascript=u'var i=0;' | |||
|
86 | ),new_output( | |||
|
87 | output_type=u'pyerr', | |||
|
88 | ename=u'NameError', | |||
|
89 | evalue=u'NameError was here', | |||
|
90 | traceback=[u'frame 0', u'frame 1', u'frame 2'] | |||
|
91 | ),new_output( | |||
|
92 | output_type=u'stream', | |||
|
93 | output_text='foo\rbar\r\n' | |||
|
94 | ),new_output( | |||
|
95 | output_type=u'stream', | |||
|
96 | stream='stderr', | |||
|
97 | output_text='\rfoo\rbar\n' | |||
|
98 | )] | |||
|
99 | )) | |||
|
100 | ||||
|
101 | authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com', | |||
|
102 | affiliation=u'Fox',url=u'http://www.fox.com')] | |||
|
103 | md = new_metadata(name=u'My Notebook',license=u'BSD',created=u'8601_goes_here', | |||
|
104 | modified=u'8601_goes_here',gistid=u'21341231',authors=authors) | |||
|
105 | ||||
|
106 | nb0 = new_notebook( | |||
|
107 | worksheets=[ws, new_worksheet(name='worksheet2')], | |||
|
108 | metadata=md | |||
|
109 | ) | |||
|
110 | ||||
|
111 | nb0_py = u"""# -*- coding: utf-8 -*- | |||
|
112 | # <nbformat>%i.%i</nbformat> | |||
|
113 | ||||
|
114 | # <htmlcell> | |||
|
115 | ||||
|
116 | # Some NumPy Examples | |||
|
117 | ||||
|
118 | # <codecell> | |||
|
119 | ||||
|
120 | import numpy | |||
|
121 | ||||
|
122 | # <markdowncell> | |||
|
123 | ||||
|
124 | # A random array | |||
|
125 | ||||
|
126 | # <rawcell> | |||
|
127 | ||||
|
128 | # A random array | |||
|
129 | ||||
|
130 | # <headingcell level=2> | |||
|
131 | ||||
|
132 | # My Heading | |||
|
133 | ||||
|
134 | # <codecell> | |||
|
135 | ||||
|
136 | a = numpy.random.rand(100) | |||
|
137 | ||||
|
138 | # <codecell> | |||
|
139 | ||||
|
140 | a = 10 | |||
|
141 | b = 5 | |||
|
142 | ||||
|
143 | # <codecell> | |||
|
144 | ||||
|
145 | a = 10 | |||
|
146 | b = 5 | |||
|
147 | ||||
|
148 | # <codecell> | |||
|
149 | ||||
|
150 | print "ünîcødé" | |||
|
151 | ||||
|
152 | """ % (nbformat, nbformat_minor) |
@@ -0,0 +1,68 b'' | |||||
|
1 | import pprint | |||
|
2 | from base64 import decodestring | |||
|
3 | from unittest import TestCase | |||
|
4 | ||||
|
5 | from IPython.utils.py3compat import unicode_type | |||
|
6 | from ..nbjson import reads, writes | |||
|
7 | from .. import nbjson | |||
|
8 | from .nbexamples import nb0 | |||
|
9 | ||||
|
10 | from . import formattest | |||
|
11 | ||||
|
12 | from .nbexamples import nb0 | |||
|
13 | ||||
|
14 | ||||
|
15 | class TestJSON(formattest.NBFormatTest, TestCase): | |||
|
16 | ||||
|
17 | nb0_ref = None | |||
|
18 | ext = 'ipynb' | |||
|
19 | mod = nbjson | |||
|
20 | ||||
|
21 | def test_roundtrip_nosplit(self): | |||
|
22 | """Ensure that multiline blobs are still readable""" | |||
|
23 | # ensures that notebooks written prior to splitlines change | |||
|
24 | # are still readable. | |||
|
25 | s = writes(nb0, split_lines=False) | |||
|
26 | self.assertEqual(nbjson.reads(s),nb0) | |||
|
27 | ||||
|
28 | def test_roundtrip_split(self): | |||
|
29 | """Ensure that splitting multiline blocks is safe""" | |||
|
30 | # This won't differ from test_roundtrip unless the default changes | |||
|
31 | s = writes(nb0, split_lines=True) | |||
|
32 | self.assertEqual(nbjson.reads(s),nb0) | |||
|
33 | ||||
|
34 | def test_read_png(self): | |||
|
35 | """PNG output data is b64 unicode""" | |||
|
36 | s = writes(nb0) | |||
|
37 | nb1 = nbjson.reads(s) | |||
|
38 | found_png = False | |||
|
39 | for cell in nb1.worksheets[0].cells: | |||
|
40 | if not 'outputs' in cell: | |||
|
41 | continue | |||
|
42 | for output in cell.outputs: | |||
|
43 | if 'png' in output: | |||
|
44 | found_png = True | |||
|
45 | pngdata = output['png'] | |||
|
46 | self.assertEqual(type(pngdata), unicode_type) | |||
|
47 | # test that it is valid b64 data | |||
|
48 | b64bytes = pngdata.encode('ascii') | |||
|
49 | raw_bytes = decodestring(b64bytes) | |||
|
50 | assert found_png, "never found png output" | |||
|
51 | ||||
|
52 | def test_read_jpeg(self): | |||
|
53 | """JPEG output data is b64 unicode""" | |||
|
54 | s = writes(nb0) | |||
|
55 | nb1 = nbjson.reads(s) | |||
|
56 | found_jpeg = False | |||
|
57 | for cell in nb1.worksheets[0].cells: | |||
|
58 | if not 'outputs' in cell: | |||
|
59 | continue | |||
|
60 | for output in cell.outputs: | |||
|
61 | if 'jpeg' in output: | |||
|
62 | found_jpeg = True | |||
|
63 | jpegdata = output['jpeg'] | |||
|
64 | self.assertEqual(type(jpegdata), unicode_type) | |||
|
65 | # test that it is valid b64 data | |||
|
66 | b64bytes = jpegdata.encode('ascii') | |||
|
67 | raw_bytes = decodestring(b64bytes) | |||
|
68 | assert found_jpeg, "never found jpeg output" |
@@ -0,0 +1,155 b'' | |||||
|
1 | from unittest import TestCase | |||
|
2 | ||||
|
3 | from ..nbbase import ( | |||
|
4 | NotebookNode, | |||
|
5 | new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output, | |||
|
6 | new_author, new_metadata, new_heading_cell, nbformat | |||
|
7 | ) | |||
|
8 | ||||
|
9 | class TestCell(TestCase): | |||
|
10 | ||||
|
11 | def test_empty_code_cell(self): | |||
|
12 | cc = new_code_cell() | |||
|
13 | self.assertEqual(cc.cell_type,u'code') | |||
|
14 | self.assertEqual(u'input' not in cc, True) | |||
|
15 | self.assertEqual(u'prompt_number' not in cc, True) | |||
|
16 | self.assertEqual(cc.outputs, []) | |||
|
17 | self.assertEqual(cc.collapsed, False) | |||
|
18 | ||||
|
19 | def test_code_cell(self): | |||
|
20 | cc = new_code_cell(input='a=10', prompt_number=0, collapsed=True) | |||
|
21 | cc.outputs = [new_output(output_type=u'pyout', | |||
|
22 | output_svg=u'foo',output_text=u'10',prompt_number=0)] | |||
|
23 | self.assertEqual(cc.input, u'a=10') | |||
|
24 | self.assertEqual(cc.prompt_number, 0) | |||
|
25 | self.assertEqual(cc.language, u'python') | |||
|
26 | self.assertEqual(cc.outputs[0].svg, u'foo') | |||
|
27 | self.assertEqual(cc.outputs[0].text, u'10') | |||
|
28 | self.assertEqual(cc.outputs[0].prompt_number, 0) | |||
|
29 | self.assertEqual(cc.collapsed, True) | |||
|
30 | ||||
|
31 | def test_pyerr(self): | |||
|
32 | o = new_output(output_type=u'pyerr', ename=u'NameError', | |||
|
33 | evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2'] | |||
|
34 | ) | |||
|
35 | self.assertEqual(o.output_type, u'pyerr') | |||
|
36 | self.assertEqual(o.ename, u'NameError') | |||
|
37 | self.assertEqual(o.evalue, u'Name not found') | |||
|
38 | self.assertEqual(o.traceback, [u'frame 0', u'frame 1', u'frame 2']) | |||
|
39 | ||||
|
40 | def test_empty_html_cell(self): | |||
|
41 | tc = new_text_cell(u'html') | |||
|
42 | self.assertEqual(tc.cell_type, u'html') | |||
|
43 | self.assertEqual(u'source' not in tc, True) | |||
|
44 | self.assertEqual(u'rendered' not in tc, True) | |||
|
45 | ||||
|
46 | def test_html_cell(self): | |||
|
47 | tc = new_text_cell(u'html', 'hi', 'hi') | |||
|
48 | self.assertEqual(tc.source, u'hi') | |||
|
49 | self.assertEqual(tc.rendered, u'hi') | |||
|
50 | ||||
|
51 | def test_empty_markdown_cell(self): | |||
|
52 | tc = new_text_cell(u'markdown') | |||
|
53 | self.assertEqual(tc.cell_type, u'markdown') | |||
|
54 | self.assertEqual(u'source' not in tc, True) | |||
|
55 | self.assertEqual(u'rendered' not in tc, True) | |||
|
56 | ||||
|
57 | def test_markdown_cell(self): | |||
|
58 | tc = new_text_cell(u'markdown', 'hi', 'hi') | |||
|
59 | self.assertEqual(tc.source, u'hi') | |||
|
60 | self.assertEqual(tc.rendered, u'hi') | |||
|
61 | ||||
|
62 | def test_empty_raw_cell(self): | |||
|
63 | tc = new_text_cell(u'raw') | |||
|
64 | self.assertEqual(tc.cell_type, u'raw') | |||
|
65 | self.assertEqual(u'source' not in tc, True) | |||
|
66 | self.assertEqual(u'rendered' not in tc, True) | |||
|
67 | ||||
|
68 | def test_raw_cell(self): | |||
|
69 | tc = new_text_cell(u'raw', 'hi', 'hi') | |||
|
70 | self.assertEqual(tc.source, u'hi') | |||
|
71 | self.assertEqual(tc.rendered, u'hi') | |||
|
72 | ||||
|
73 | def test_empty_heading_cell(self): | |||
|
74 | tc = new_heading_cell() | |||
|
75 | self.assertEqual(tc.cell_type, u'heading') | |||
|
76 | self.assertEqual(u'source' not in tc, True) | |||
|
77 | self.assertEqual(u'rendered' not in tc, True) | |||
|
78 | ||||
|
79 | def test_heading_cell(self): | |||
|
80 | tc = new_heading_cell(u'hi', u'hi', level=2) | |||
|
81 | self.assertEqual(tc.source, u'hi') | |||
|
82 | self.assertEqual(tc.rendered, u'hi') | |||
|
83 | self.assertEqual(tc.level, 2) | |||
|
84 | ||||
|
85 | ||||
|
86 | class TestWorksheet(TestCase): | |||
|
87 | ||||
|
88 | def test_empty_worksheet(self): | |||
|
89 | ws = new_worksheet() | |||
|
90 | self.assertEqual(ws.cells,[]) | |||
|
91 | self.assertEqual(u'name' not in ws, True) | |||
|
92 | ||||
|
93 | def test_worksheet(self): | |||
|
94 | cells = [new_code_cell(), new_text_cell(u'html')] | |||
|
95 | ws = new_worksheet(cells=cells,name=u'foo') | |||
|
96 | self.assertEqual(ws.cells,cells) | |||
|
97 | self.assertEqual(ws.name,u'foo') | |||
|
98 | ||||
|
99 | class TestNotebook(TestCase): | |||
|
100 | ||||
|
101 | def test_empty_notebook(self): | |||
|
102 | nb = new_notebook() | |||
|
103 | self.assertEqual(nb.worksheets, []) | |||
|
104 | self.assertEqual(nb.metadata, NotebookNode()) | |||
|
105 | self.assertEqual(nb.nbformat,nbformat) | |||
|
106 | ||||
|
107 | def test_notebook(self): | |||
|
108 | worksheets = [new_worksheet(),new_worksheet()] | |||
|
109 | metadata = new_metadata(name=u'foo') | |||
|
110 | nb = new_notebook(metadata=metadata,worksheets=worksheets) | |||
|
111 | self.assertEqual(nb.metadata.name,u'foo') | |||
|
112 | self.assertEqual(nb.worksheets,worksheets) | |||
|
113 | self.assertEqual(nb.nbformat,nbformat) | |||
|
114 | ||||
|
115 | def test_notebook_name(self): | |||
|
116 | worksheets = [new_worksheet(),new_worksheet()] | |||
|
117 | nb = new_notebook(name='foo',worksheets=worksheets) | |||
|
118 | self.assertEqual(nb.metadata.name,u'foo') | |||
|
119 | self.assertEqual(nb.worksheets,worksheets) | |||
|
120 | self.assertEqual(nb.nbformat,nbformat) | |||
|
121 | ||||
|
122 | class TestMetadata(TestCase): | |||
|
123 | ||||
|
124 | def test_empty_metadata(self): | |||
|
125 | md = new_metadata() | |||
|
126 | self.assertEqual(u'name' not in md, True) | |||
|
127 | self.assertEqual(u'authors' not in md, True) | |||
|
128 | self.assertEqual(u'license' not in md, True) | |||
|
129 | self.assertEqual(u'saved' not in md, True) | |||
|
130 | self.assertEqual(u'modified' not in md, True) | |||
|
131 | self.assertEqual(u'gistid' not in md, True) | |||
|
132 | ||||
|
133 | def test_metadata(self): | |||
|
134 | authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com')] | |||
|
135 | md = new_metadata(name=u'foo',license=u'BSD',created=u'today', | |||
|
136 | modified=u'now',gistid=u'21341231',authors=authors) | |||
|
137 | self.assertEqual(md.name, u'foo') | |||
|
138 | self.assertEqual(md.license, u'BSD') | |||
|
139 | self.assertEqual(md.created, u'today') | |||
|
140 | self.assertEqual(md.modified, u'now') | |||
|
141 | self.assertEqual(md.gistid, u'21341231') | |||
|
142 | self.assertEqual(md.authors, authors) | |||
|
143 | ||||
|
144 | class TestOutputs(TestCase): | |||
|
145 | def test_binary_png(self): | |||
|
146 | out = new_output(output_png=b'\x89PNG\r\n\x1a\n', output_type='display_data') | |||
|
147 | ||||
|
148 | def test_b64b6tes_png(self): | |||
|
149 | out = new_output(output_png=b'iVBORw0KG', output_type='display_data') | |||
|
150 | ||||
|
151 | def test_binary_jpeg(self): | |||
|
152 | out = new_output(output_jpeg=b'\xff\xd8', output_type='display_data') | |||
|
153 | ||||
|
154 | def test_b64b6tes_jpeg(self): | |||
|
155 | out = new_output(output_jpeg=b'/9', output_type='display_data') |
General Comments 0
You need to be logged in to leave comments.
Login now