Show More
@@ -0,0 +1,63 | |||
|
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.assertEquals(nba, nbb) | |
|
37 | ||
|
38 | def test_writes(self): | |
|
39 | s = self.mod.writes(nb0) | |
|
40 | if self.nb0_ref: | |
|
41 | self.assertEquals(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) | |
|
61 | ||
|
62 | ||
|
63 |
@@ -20,6 +20,7 import __future__ | |||
|
20 | 20 | import bdb |
|
21 | 21 | import inspect |
|
22 | 22 | import imp |
|
23 | import io | |
|
23 | 24 | import os |
|
24 | 25 | import sys |
|
25 | 26 | import shutil |
@@ -2222,7 +2223,7 Currently the magic system has the following functions:\n""" | |||
|
2222 | 2223 | except (TypeError, ValueError) as e: |
|
2223 | 2224 | print e.args[0] |
|
2224 | 2225 | return |
|
2225 |
with |
|
|
2226 | with io.open(fname,'w', encoding="utf-8") as f: | |
|
2226 | 2227 | f.write(u"# coding: utf-8\n") |
|
2227 | 2228 | f.write(py3compat.cast_unicode(cmds)) |
|
2228 | 2229 | print 'The following commands were written to file `%s`:' % fname |
@@ -3663,7 +3664,7 Defaulting color scheme to 'NoColor'""" | |||
|
3663 | 3664 | cells.append(current.new_code_cell(prompt_number=prompt_number, input=input)) |
|
3664 | 3665 | worksheet = current.new_worksheet(cells=cells) |
|
3665 | 3666 | nb = current.new_notebook(name=name,worksheets=[worksheet]) |
|
3666 | with open(fname, 'w') as f: | |
|
3667 | with io.open(fname, 'w', encoding='utf-8') as f: | |
|
3667 | 3668 | current.write(nb, f, format); |
|
3668 | 3669 | elif args.format is not None: |
|
3669 | 3670 | old_fname, old_name, old_format = current.parse_filename(args.filename) |
@@ -3677,13 +3678,9 Defaulting color scheme to 'NoColor'""" | |||
|
3677 | 3678 | new_fname = old_name + u'.py' |
|
3678 | 3679 | else: |
|
3679 | 3680 | raise ValueError('Invalid notebook format: %s' % new_format) |
|
3680 | with open(old_fname, 'r') as f: | |
|
3681 |
|
|
|
3682 | try: | |
|
3683 | nb = current.reads(s, old_format) | |
|
3684 | except: | |
|
3685 | nb = current.reads(s, u'xml') | |
|
3686 | with open(new_fname, 'w') as f: | |
|
3681 | with io.open(old_fname, 'r', encoding='utf-8') as f: | |
|
3682 | nb = current.read(f, old_format) | |
|
3683 | with io.open(new_fname, 'w', encoding='utf-8') as f: | |
|
3687 | 3684 | current.write(nb, f, new_format) |
|
3688 | 3685 | |
|
3689 | 3686 | def magic_config(self, s): |
@@ -1,3 +1,4 | |||
|
1 | # -*- coding: utf-8 -*- | |
|
1 | 2 | """Tests for various magic functions. |
|
2 | 3 | |
|
3 | 4 | Needs to be run by nose (to make ipython session available). |
@@ -8,12 +9,15 from __future__ import absolute_import | |||
|
8 | 9 | # Imports |
|
9 | 10 | #----------------------------------------------------------------------------- |
|
10 | 11 | |
|
12 | import io | |
|
11 | 13 | import os |
|
12 | 14 | import sys |
|
13 | 15 | from StringIO import StringIO |
|
14 | 16 | |
|
15 | 17 | import nose.tools as nt |
|
16 | 18 | |
|
19 | from IPython.nbformat.v3.tests.nbexamples import nb0 | |
|
20 | from IPython.nbformat import current | |
|
17 | 21 | from IPython.testing import decorators as dec |
|
18 | 22 | from IPython.testing import tools as tt |
|
19 | 23 | from IPython.utils import py3compat |
@@ -23,6 +27,7 from IPython.utils.tempdir import TemporaryDirectory | |||
|
23 | 27 | # Test functions begin |
|
24 | 28 | #----------------------------------------------------------------------------- |
|
25 | 29 | |
|
30 | ||
|
26 | 31 | def test_rehashx(): |
|
27 | 32 | # clear up everything |
|
28 | 33 | _ip = get_ipython() |
@@ -431,3 +436,34 def test_extension(): | |||
|
431 | 436 | finally: |
|
432 | 437 | _ip.ipython_dir = orig_ipython_dir |
|
433 | 438 | |
|
439 | def test_notebook_export_json(): | |
|
440 | with TemporaryDirectory() as td: | |
|
441 | outfile = os.path.join(td, "nb.ipynb") | |
|
442 | _ip.ex(py3compat.u_format(u"u = {u}'héllo'")) | |
|
443 | _ip.magic("notebook -e %s" % outfile) | |
|
444 | ||
|
445 | def test_notebook_export_py(): | |
|
446 | with TemporaryDirectory() as td: | |
|
447 | outfile = os.path.join(td, "nb.py") | |
|
448 | _ip.ex(py3compat.u_format(u"u = {u}'héllo'")) | |
|
449 | _ip.magic("notebook -e %s" % outfile) | |
|
450 | ||
|
451 | def test_notebook_reformat_py(): | |
|
452 | with TemporaryDirectory() as td: | |
|
453 | infile = os.path.join(td, "nb.ipynb") | |
|
454 | with io.open(infile, 'w') as f: | |
|
455 | current.write(nb0, f, 'json') | |
|
456 | ||
|
457 | _ip.ex(py3compat.u_format(u"u = {u}'héllo'")) | |
|
458 | _ip.magic("notebook -f py %s" % infile) | |
|
459 | ||
|
460 | def test_notebook_reformat_json(): | |
|
461 | with TemporaryDirectory() as td: | |
|
462 | infile = os.path.join(td, "nb.py") | |
|
463 | with io.open(infile, 'w') as f: | |
|
464 | current.write(nb0, f, 'py') | |
|
465 | ||
|
466 | _ip.ex(py3compat.u_format(u"u = {u}'héllo'")) | |
|
467 | _ip.magic("notebook -f ipynb %s" % infile) | |
|
468 | _ip.magic("notebook -f json %s" % infile) | |
|
469 |
@@ -146,7 +146,7 def new_worksheet(name=None, cells=None): | |||
|
146 | 146 | return ws |
|
147 | 147 | |
|
148 | 148 | |
|
149 | def new_notebook(metadata=None, worksheets=None): | |
|
149 | def new_notebook(name=None, metadata=None, worksheets=None): | |
|
150 | 150 | """Create a notebook by name, id and a list of worksheets.""" |
|
151 | 151 | nb = NotebookNode() |
|
152 | 152 | nb.nbformat = nbformat |
@@ -158,6 +158,8 def new_notebook(metadata=None, worksheets=None): | |||
|
158 | 158 | nb.metadata = new_metadata() |
|
159 | 159 | else: |
|
160 | 160 | nb.metadata = NotebookNode(metadata) |
|
161 | if name is not None: | |
|
162 | nb.metadata.name = unicode(name) | |
|
161 | 163 | return nb |
|
162 | 164 | |
|
163 | 165 |
@@ -24,6 +24,8 from .rwbase import ( | |||
|
24 | 24 | NotebookReader, NotebookWriter, restore_bytes, rejoin_lines, split_lines |
|
25 | 25 | ) |
|
26 | 26 | |
|
27 | from IPython.utils import py3compat | |
|
28 | ||
|
27 | 29 | #----------------------------------------------------------------------------- |
|
28 | 30 | # Code |
|
29 | 31 | #----------------------------------------------------------------------------- |
@@ -56,7 +58,7 class JSONWriter(NotebookWriter): | |||
|
56 | 58 | kwargs['separators'] = (',',': ') |
|
57 | 59 | if kwargs.pop('split_lines', True): |
|
58 | 60 | nb = split_lines(copy.deepcopy(nb)) |
|
59 | return json.dumps(nb, **kwargs) | |
|
61 | return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8') | |
|
60 | 62 | |
|
61 | 63 | |
|
62 | 64 | _reader = JSONReader() |
@@ -19,7 +19,9 Authors: | |||
|
19 | 19 | from base64 import encodestring, decodestring |
|
20 | 20 | import pprint |
|
21 | 21 | |
|
22 |
from IPython.utils |
|
|
22 | from IPython.utils import py3compat | |
|
23 | ||
|
24 | str_to_bytes = py3compat.str_to_bytes | |
|
23 | 25 | |
|
24 | 26 | #----------------------------------------------------------------------------- |
|
25 | 27 | # Code |
@@ -84,17 +86,17 def split_lines(nb): | |||
|
84 | 86 | for cell in ws.cells: |
|
85 | 87 | if cell.cell_type == 'code': |
|
86 | 88 | if 'input' in cell and isinstance(cell.input, basestring): |
|
87 | cell.input = cell.input.splitlines() | |
|
89 | cell.input = (cell.input + '\n').splitlines() | |
|
88 | 90 | for output in cell.outputs: |
|
89 | 91 | for key in _multiline_outputs: |
|
90 | 92 | item = output.get(key, None) |
|
91 | 93 | if isinstance(item, basestring): |
|
92 | output[key] = item.splitlines() | |
|
94 | output[key] = (item + '\n').splitlines() | |
|
93 | 95 | else: # text, heading cell |
|
94 | 96 | for key in ['source', 'rendered']: |
|
95 | 97 | item = cell.get(key, None) |
|
96 | 98 | if isinstance(item, basestring): |
|
97 | cell[key] = item.splitlines() | |
|
99 | cell[key] = (item + '\n').splitlines() | |
|
98 | 100 | return nb |
|
99 | 101 | |
|
100 | 102 | # b64 encode/decode are never actually used, because all bytes objects in |
@@ -147,7 +149,10 class NotebookReader(object): | |||
|
147 | 149 | |
|
148 | 150 | def read(self, fp, **kwargs): |
|
149 | 151 | """Read a notebook from a file like object""" |
|
150 | return self.read(fp.read(), **kwargs) | |
|
152 | nbs = fp.read() | |
|
153 | if not py3compat.PY3 and not isinstance(nbs, unicode): | |
|
154 | nbs = py3compat.str_to_unicode(nbs) | |
|
155 | return self.reads(nbs, **kwargs) | |
|
151 | 156 | |
|
152 | 157 | |
|
153 | 158 | class NotebookWriter(object): |
@@ -159,7 +164,11 class NotebookWriter(object): | |||
|
159 | 164 | |
|
160 | 165 | def write(self, nb, fp, **kwargs): |
|
161 | 166 | """Write a notebook to a file like object""" |
|
162 |
|
|
|
167 | nbs = self.writes(nb,**kwargs) | |
|
168 | if not py3compat.PY3 and not isinstance(nbs, unicode): | |
|
169 | # this branch is likely only taken for JSON on Python 2 | |
|
170 | nbs = py3compat.str_to_unicode(nbs) | |
|
171 | return fp.write(nbs) | |
|
163 | 172 | |
|
164 | 173 | |
|
165 | 174 |
@@ -1,3 +1,5 | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
1 | 3 | import os |
|
2 | 4 | from base64 import encodestring |
|
3 | 5 | |
@@ -47,9 +49,17 ws.cells.append(new_code_cell( | |||
|
47 | 49 | prompt_number=2, |
|
48 | 50 | collapsed=True |
|
49 | 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 | )) | |
|
50 | 60 | |
|
51 | 61 | ws.cells.append(new_code_cell( |
|
52 |
input='print |
|
|
62 | input=u'print "ünîcødé"', | |
|
53 | 63 | prompt_number=3, |
|
54 | 64 | collapsed=False, |
|
55 | 65 | outputs=[new_output( |
@@ -91,7 +101,7 nb0 = new_notebook( | |||
|
91 | 101 | metadata=md |
|
92 | 102 | ) |
|
93 | 103 | |
|
94 | nb0_py = """# -*- coding: utf-8 -*- | |
|
104 | nb0_py = u"""# -*- coding: utf-8 -*- | |
|
95 | 105 | # <nbformat>%i</nbformat> |
|
96 | 106 | |
|
97 | 107 | # <htmlcell> |
@@ -120,7 +130,17 a = numpy.random.rand(100) | |||
|
120 | 130 | |
|
121 | 131 | # <codecell> |
|
122 | 132 | |
|
123 | print a | |
|
133 | a = 10 | |
|
134 | b = 5 | |
|
135 | ||
|
136 | # <codecell> | |
|
137 | ||
|
138 | a = 10 | |
|
139 | b = 5 | |
|
140 | ||
|
141 | # <codecell> | |
|
142 | ||
|
143 | print "ünîcødé" | |
|
124 | 144 | |
|
125 | 145 | """ % nbformat |
|
126 | 146 |
@@ -2,33 +2,32 import pprint | |||
|
2 | 2 | from unittest import TestCase |
|
3 | 3 | |
|
4 | 4 | from ..nbjson import reads, writes |
|
5 | from .. import nbjson | |
|
5 | 6 | from .nbexamples import nb0 |
|
6 | 7 | |
|
8 | from . import formattest | |
|
7 | 9 | |
|
8 | class TestJSON(TestCase): | |
|
10 | from .nbexamples import nb0 | |
|
11 | ||
|
12 | ||
|
13 | class TestJSON(formattest.NBFormatTest, TestCase): | |
|
14 | ||
|
15 | nb0_ref = None | |
|
16 | ext = 'ipynb' | |
|
17 | mod = nbjson | |
|
9 | 18 | |
|
10 | def test_roundtrip(self): | |
|
11 | s = writes(nb0) | |
|
12 | ||
|
13 | # print pprint.pformat(nb0,indent=2) | |
|
14 | ||
|
15 | # print pprint.pformat(reads(s),indent=2) | |
|
16 | ||
|
17 | # print s | |
|
18 | self.assertEquals(reads(s),nb0) | |
|
19 | ||
|
20 | 19 | def test_roundtrip_nosplit(self): |
|
21 | 20 | """Ensure that multiline blobs are still readable""" |
|
22 | 21 | # ensures that notebooks written prior to splitlines change |
|
23 | 22 | # are still readable. |
|
24 | 23 | s = writes(nb0, split_lines=False) |
|
25 | self.assertEquals(reads(s),nb0) | |
|
24 | self.assertEquals(nbjson.reads(s),nb0) | |
|
26 | 25 | |
|
27 | 26 | def test_roundtrip_split(self): |
|
28 | 27 | """Ensure that splitting multiline blocks is safe""" |
|
29 | 28 | # This won't differ from test_roundtrip unless the default changes |
|
30 | 29 | s = writes(nb0, split_lines=True) |
|
31 | self.assertEquals(reads(s),nb0) | |
|
30 | self.assertEquals(nbjson.reads(s),nb0) | |
|
32 | 31 | |
|
33 | 32 | |
|
34 | 33 |
@@ -112,6 +112,13 class TestNotebook(TestCase): | |||
|
112 | 112 | self.assertEquals(nb.worksheets,worksheets) |
|
113 | 113 | self.assertEquals(nb.nbformat,nbformat) |
|
114 | 114 | |
|
115 | def test_notebook_name(self): | |
|
116 | worksheets = [new_worksheet(),new_worksheet()] | |
|
117 | nb = new_notebook(name='foo',worksheets=worksheets) | |
|
118 | self.assertEquals(nb.metadata.name,u'foo') | |
|
119 | self.assertEquals(nb.worksheets,worksheets) | |
|
120 | self.assertEquals(nb.nbformat,nbformat) | |
|
121 | ||
|
115 | 122 | class TestMetadata(TestCase): |
|
116 | 123 | |
|
117 | 124 | def test_empty_metadata(self): |
@@ -1,17 +1,46 | |||
|
1 | # -*- coding: utf8 -*- | |
|
2 | ||
|
1 | 3 | from unittest import TestCase |
|
2 | 4 | |
|
3 |
from . |
|
|
4 | NotebookNode, | |
|
5 | new_code_cell, new_text_cell, new_worksheet, new_notebook | |
|
6 | ) | |
|
5 | from . import formattest | |
|
7 | 6 | |
|
8 | from ..nbpy import reads, writes | |
|
7 | from .. import nbpy | |
|
9 | 8 | from .nbexamples import nb0, nb0_py |
|
10 | 9 | |
|
11 | 10 | |
|
12 | class TestPy(TestCase): | |
|
11 | class TestPy(formattest.NBFormatTest, TestCase): | |
|
13 | 12 | |
|
14 | def test_write(self): | |
|
15 | s = writes(nb0) | |
|
16 | self.assertEquals(s,nb0_py) | |
|
13 | nb0_ref = nb0_py | |
|
14 | ext = 'py' | |
|
15 | mod = nbpy | |
|
16 | ignored_keys = ['collapsed', 'outputs', 'prompt_number', 'metadata'] | |
|
17 | 17 | |
|
18 | def assertSubset(self, da, db): | |
|
19 | """assert that da is a subset of db, ignoring self.ignored_keys. | |
|
20 | ||
|
21 | Called recursively on containers, ultimately comparing individual | |
|
22 | elements. | |
|
23 | """ | |
|
24 | if isinstance(da, dict): | |
|
25 | for k,v in da.iteritems(): | |
|
26 | if k in self.ignored_keys: | |
|
27 | continue | |
|
28 | self.assertTrue(k in db) | |
|
29 | self.assertSubset(v, db[k]) | |
|
30 | elif isinstance(da, list): | |
|
31 | for a,b in zip(da, db): | |
|
32 | self.assertSubset(a,b) | |
|
33 | else: | |
|
34 | if isinstance(da, basestring) and isinstance(db, basestring): | |
|
35 | # pyfile is not sensitive to preserving leading/trailing | |
|
36 | # newlines in blocks through roundtrip | |
|
37 | da = da.strip('\n') | |
|
38 | db = db.strip('\n') | |
|
39 | self.assertEquals(da, db) | |
|
40 | return True | |
|
41 | ||
|
42 | def assertNBEquals(self, nba, nbb): | |
|
43 | # since roundtrip is lossy, only compare keys that are preserved | |
|
44 | # assumes nba is read from my file format | |
|
45 | return self.assertSubset(nba, nbb) | |
|
46 |
@@ -32,7 +32,7 def cast_bytes(s, encoding=None): | |||
|
32 | 32 | def _modify_str_or_docstring(str_change_func): |
|
33 | 33 | @functools.wraps(str_change_func) |
|
34 | 34 | def wrapper(func_or_str): |
|
35 | if isinstance(func_or_str, str): | |
|
35 | if isinstance(func_or_str, basestring): | |
|
36 | 36 | func = None |
|
37 | 37 | doc = func_or_str |
|
38 | 38 | else: |
General Comments 0
You need to be logged in to leave comments.
Login now