##// END OF EJS Templates
Merge pull request #1480 from minrk/npmagic...
Fernando Perez -
r6479:c4cf9403 merge
parent child Browse files
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 py3compat.open(fname,'w', encoding="utf-8") as f:
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 s = f.read()
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.py3compat import str_to_bytes
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 return fp.write(self.writes(nb,**kwargs))
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 a',
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 # print
13 # print pprint.pformat(nb0,indent=2)
14 # print
15 # print pprint.pformat(reads(s),indent=2)
16 # print
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 ..nbbase import (
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