##// 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 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.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 b' import __future__'
20 import bdb
20 import bdb
21 import inspect
21 import inspect
22 import imp
22 import imp
23 import io
23 import os
24 import os
24 import sys
25 import sys
25 import shutil
26 import shutil
@@ -2222,7 +2223,7 b' Currently the magic system has the following functions:\\n"""'
2222 except (TypeError, ValueError) as e:
2223 except (TypeError, ValueError) as e:
2223 print e.args[0]
2224 print e.args[0]
2224 return
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 f.write(u"# coding: utf-8\n")
2227 f.write(u"# coding: utf-8\n")
2227 f.write(py3compat.cast_unicode(cmds))
2228 f.write(py3compat.cast_unicode(cmds))
2228 print 'The following commands were written to file `%s`:' % fname
2229 print 'The following commands were written to file `%s`:' % fname
@@ -3663,7 +3664,7 b' Defaulting color scheme to \'NoColor\'"""'
3663 cells.append(current.new_code_cell(prompt_number=prompt_number, input=input))
3664 cells.append(current.new_code_cell(prompt_number=prompt_number, input=input))
3664 worksheet = current.new_worksheet(cells=cells)
3665 worksheet = current.new_worksheet(cells=cells)
3665 nb = current.new_notebook(name=name,worksheets=[worksheet])
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 current.write(nb, f, format);
3668 current.write(nb, f, format);
3668 elif args.format is not None:
3669 elif args.format is not None:
3669 old_fname, old_name, old_format = current.parse_filename(args.filename)
3670 old_fname, old_name, old_format = current.parse_filename(args.filename)
@@ -3677,13 +3678,9 b' Defaulting color scheme to \'NoColor\'"""'
3677 new_fname = old_name + u'.py'
3678 new_fname = old_name + u'.py'
3678 else:
3679 else:
3679 raise ValueError('Invalid notebook format: %s' % new_format)
3680 raise ValueError('Invalid notebook format: %s' % new_format)
3680 with open(old_fname, 'r') as f:
3681 with io.open(old_fname, 'r', encoding='utf-8') as f:
3681 s = f.read()
3682 nb = current.read(f, old_format)
3682 try:
3683 with io.open(new_fname, 'w', encoding='utf-8') as f:
3683 nb = current.reads(s, old_format)
3684 except:
3685 nb = current.reads(s, u'xml')
3686 with open(new_fname, 'w') as f:
3687 current.write(nb, f, new_format)
3684 current.write(nb, f, new_format)
3688
3685
3689 def magic_config(self, s):
3686 def magic_config(self, s):
@@ -1,3 +1,4 b''
1 # -*- coding: utf-8 -*-
1 """Tests for various magic functions.
2 """Tests for various magic functions.
2
3
3 Needs to be run by nose (to make ipython session available).
4 Needs to be run by nose (to make ipython session available).
@@ -8,12 +9,15 b' from __future__ import absolute_import'
8 # Imports
9 # Imports
9 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
10
11
12 import io
11 import os
13 import os
12 import sys
14 import sys
13 from StringIO import StringIO
15 from StringIO import StringIO
14
16
15 import nose.tools as nt
17 import nose.tools as nt
16
18
19 from IPython.nbformat.v3.tests.nbexamples import nb0
20 from IPython.nbformat import current
17 from IPython.testing import decorators as dec
21 from IPython.testing import decorators as dec
18 from IPython.testing import tools as tt
22 from IPython.testing import tools as tt
19 from IPython.utils import py3compat
23 from IPython.utils import py3compat
@@ -23,6 +27,7 b' from IPython.utils.tempdir import TemporaryDirectory'
23 # Test functions begin
27 # Test functions begin
24 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
25
29
30
26 def test_rehashx():
31 def test_rehashx():
27 # clear up everything
32 # clear up everything
28 _ip = get_ipython()
33 _ip = get_ipython()
@@ -431,3 +436,34 b' def test_extension():'
431 finally:
436 finally:
432 _ip.ipython_dir = orig_ipython_dir
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 b' def new_worksheet(name=None, cells=None):'
146 return ws
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 """Create a notebook by name, id and a list of worksheets."""
150 """Create a notebook by name, id and a list of worksheets."""
151 nb = NotebookNode()
151 nb = NotebookNode()
152 nb.nbformat = nbformat
152 nb.nbformat = nbformat
@@ -158,6 +158,8 b' def new_notebook(metadata=None, worksheets=None):'
158 nb.metadata = new_metadata()
158 nb.metadata = new_metadata()
159 else:
159 else:
160 nb.metadata = NotebookNode(metadata)
160 nb.metadata = NotebookNode(metadata)
161 if name is not None:
162 nb.metadata.name = unicode(name)
161 return nb
163 return nb
162
164
163
165
@@ -24,6 +24,8 b' from .rwbase import ('
24 NotebookReader, NotebookWriter, restore_bytes, rejoin_lines, split_lines
24 NotebookReader, NotebookWriter, restore_bytes, rejoin_lines, split_lines
25 )
25 )
26
26
27 from IPython.utils import py3compat
28
27 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
28 # Code
30 # Code
29 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
@@ -56,7 +58,7 b' class JSONWriter(NotebookWriter):'
56 kwargs['separators'] = (',',': ')
58 kwargs['separators'] = (',',': ')
57 if kwargs.pop('split_lines', True):
59 if kwargs.pop('split_lines', True):
58 nb = split_lines(copy.deepcopy(nb))
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 _reader = JSONReader()
64 _reader = JSONReader()
@@ -19,7 +19,9 b' Authors:'
19 from base64 import encodestring, decodestring
19 from base64 import encodestring, decodestring
20 import pprint
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 # Code
27 # Code
@@ -84,17 +86,17 b' def split_lines(nb):'
84 for cell in ws.cells:
86 for cell in ws.cells:
85 if cell.cell_type == 'code':
87 if cell.cell_type == 'code':
86 if 'input' in cell and isinstance(cell.input, basestring):
88 if 'input' in cell and isinstance(cell.input, basestring):
87 cell.input = cell.input.splitlines()
89 cell.input = (cell.input + '\n').splitlines()
88 for output in cell.outputs:
90 for output in cell.outputs:
89 for key in _multiline_outputs:
91 for key in _multiline_outputs:
90 item = output.get(key, None)
92 item = output.get(key, None)
91 if isinstance(item, basestring):
93 if isinstance(item, basestring):
92 output[key] = item.splitlines()
94 output[key] = (item + '\n').splitlines()
93 else: # text, heading cell
95 else: # text, heading cell
94 for key in ['source', 'rendered']:
96 for key in ['source', 'rendered']:
95 item = cell.get(key, None)
97 item = cell.get(key, None)
96 if isinstance(item, basestring):
98 if isinstance(item, basestring):
97 cell[key] = item.splitlines()
99 cell[key] = (item + '\n').splitlines()
98 return nb
100 return nb
99
101
100 # b64 encode/decode are never actually used, because all bytes objects in
102 # b64 encode/decode are never actually used, because all bytes objects in
@@ -147,7 +149,10 b' class NotebookReader(object):'
147
149
148 def read(self, fp, **kwargs):
150 def read(self, fp, **kwargs):
149 """Read a notebook from a file like object"""
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 class NotebookWriter(object):
158 class NotebookWriter(object):
@@ -159,7 +164,11 b' class NotebookWriter(object):'
159
164
160 def write(self, nb, fp, **kwargs):
165 def write(self, nb, fp, **kwargs):
161 """Write a notebook to a file like object"""
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 b''
1 # -*- coding: utf-8 -*-
2
1 import os
3 import os
2 from base64 import encodestring
4 from base64 import encodestring
3
5
@@ -47,9 +49,17 b' ws.cells.append(new_code_cell('
47 prompt_number=2,
49 prompt_number=2,
48 collapsed=True
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 ws.cells.append(new_code_cell(
61 ws.cells.append(new_code_cell(
52 input='print a',
62 input=u'print "ünîcødé"',
53 prompt_number=3,
63 prompt_number=3,
54 collapsed=False,
64 collapsed=False,
55 outputs=[new_output(
65 outputs=[new_output(
@@ -91,7 +101,7 b' nb0 = new_notebook('
91 metadata=md
101 metadata=md
92 )
102 )
93
103
94 nb0_py = """# -*- coding: utf-8 -*-
104 nb0_py = u"""# -*- coding: utf-8 -*-
95 # <nbformat>%i</nbformat>
105 # <nbformat>%i</nbformat>
96
106
97 # <htmlcell>
107 # <htmlcell>
@@ -120,7 +130,17 b' a = numpy.random.rand(100)'
120
130
121 # <codecell>
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 """ % nbformat
145 """ % nbformat
126
146
@@ -2,33 +2,32 b' import pprint'
2 from unittest import TestCase
2 from unittest import TestCase
3
3
4 from ..nbjson import reads, writes
4 from ..nbjson import reads, writes
5 from .. import nbjson
5 from .nbexamples import nb0
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 def test_roundtrip_nosplit(self):
19 def test_roundtrip_nosplit(self):
21 """Ensure that multiline blobs are still readable"""
20 """Ensure that multiline blobs are still readable"""
22 # ensures that notebooks written prior to splitlines change
21 # ensures that notebooks written prior to splitlines change
23 # are still readable.
22 # are still readable.
24 s = writes(nb0, split_lines=False)
23 s = writes(nb0, split_lines=False)
25 self.assertEquals(reads(s),nb0)
24 self.assertEquals(nbjson.reads(s),nb0)
26
25
27 def test_roundtrip_split(self):
26 def test_roundtrip_split(self):
28 """Ensure that splitting multiline blocks is safe"""
27 """Ensure that splitting multiline blocks is safe"""
29 # This won't differ from test_roundtrip unless the default changes
28 # This won't differ from test_roundtrip unless the default changes
30 s = writes(nb0, split_lines=True)
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 b' class TestNotebook(TestCase):'
112 self.assertEquals(nb.worksheets,worksheets)
112 self.assertEquals(nb.worksheets,worksheets)
113 self.assertEquals(nb.nbformat,nbformat)
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 class TestMetadata(TestCase):
122 class TestMetadata(TestCase):
116
123
117 def test_empty_metadata(self):
124 def test_empty_metadata(self):
@@ -1,17 +1,46 b''
1 # -*- coding: utf8 -*-
2
1 from unittest import TestCase
3 from unittest import TestCase
2
4
3 from ..nbbase import (
5 from . import formattest
4 NotebookNode,
5 new_code_cell, new_text_cell, new_worksheet, new_notebook
6 )
7
6
8 from ..nbpy import reads, writes
7 from .. import nbpy
9 from .nbexamples import nb0, nb0_py
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):
13 nb0_ref = nb0_py
15 s = writes(nb0)
14 ext = 'py'
16 self.assertEquals(s,nb0_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 b' def cast_bytes(s, encoding=None):'
32 def _modify_str_or_docstring(str_change_func):
32 def _modify_str_or_docstring(str_change_func):
33 @functools.wraps(str_change_func)
33 @functools.wraps(str_change_func)
34 def wrapper(func_or_str):
34 def wrapper(func_or_str):
35 if isinstance(func_or_str, str):
35 if isinstance(func_or_str, basestring):
36 func = None
36 func = None
37 doc = func_or_str
37 doc = func_or_str
38 else:
38 else:
General Comments 0
You need to be logged in to leave comments. Login now