##// END OF EJS Templates
Merge pull request #8255 from minrk/testing-tools...
Min RK -
r21152:da7c86a3 merge
parent child Browse files
Show More
@@ -0,0 +1,2 b''
1 from .nbconvertapp import launch_new_instance
2 launch_new_instance()
@@ -0,0 +1,40 b''
1 import sys
2 import nose.tools as nt
3
4 from subprocess import Popen, PIPE
5
6 def get_output_error_code(cmd):
7 """Get stdout, stderr, and exit code from running a command"""
8 p = Popen(cmd, stdout=PIPE, stderr=PIPE)
9 out, err = p.communicate()
10 out = out.decode('utf8', 'replace')
11 err = err.decode('utf8', 'replace')
12 return out, err, p.returncode
13
14
15 def check_help_output(pkg, subcommand=None):
16 """test that `python -m PKG [subcommand] -h` works"""
17 cmd = [sys.executable, '-m', pkg]
18 if subcommand:
19 cmd.extend(subcommand)
20 cmd.append('-h')
21 out, err, rc = get_output_error_code(cmd)
22 nt.assert_equal(rc, 0, err)
23 nt.assert_not_in("Traceback", err)
24 nt.assert_in("Options", out)
25 nt.assert_in("--help-all", out)
26 return out, err
27
28
29 def check_help_all_output(pkg, subcommand=None):
30 """test that `python -m PKG --help-all` works"""
31 cmd = [sys.executable, '-m', pkg]
32 if subcommand:
33 cmd.extend(subcommand)
34 cmd.append('--help-all')
35 out, err, rc = get_output_error_code(cmd)
36 nt.assert_equal(rc, 0, err)
37 nt.assert_not_in("Traceback", err)
38 nt.assert_in("Options", out)
39 nt.assert_in("Class parameters", out)
40 return out, err
@@ -1,332 +1,342 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Test installation of notebook extensions"""
2 """Test installation of notebook extensions"""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import glob
7 import glob
8 import os
8 import os
9 import re
9 import re
10 import sys
10 import tarfile
11 import tarfile
11 import zipfile
12 import zipfile
12 from io import BytesIO
13 from io import BytesIO, StringIO
13 from os.path import basename, join as pjoin
14 from os.path import basename, join as pjoin
14 from unittest import TestCase
15 from unittest import TestCase
15
16
16 import IPython.testing.tools as tt
17 try:
18 from unittest import mock
19 except ImportError:
20 import mock # py2
21
17 import IPython.testing.decorators as dec
22 import IPython.testing.decorators as dec
18 from IPython.utils import py3compat
23 from IPython.utils import py3compat
19 from IPython.utils.tempdir import TemporaryDirectory
24 from IPython.utils.tempdir import TemporaryDirectory
20 from IPython.html import nbextensions
25 from IPython.html import nbextensions
21 from IPython.html.nbextensions import install_nbextension, check_nbextension
26 from IPython.html.nbextensions import install_nbextension, check_nbextension
22
27
23
28
24 def touch(file, mtime=None):
29 def touch(file, mtime=None):
25 """ensure a file exists, and set its modification time
30 """ensure a file exists, and set its modification time
26
31
27 returns the modification time of the file
32 returns the modification time of the file
28 """
33 """
29 open(file, 'a').close()
34 open(file, 'a').close()
30 # set explicit mtime
35 # set explicit mtime
31 if mtime:
36 if mtime:
32 atime = os.stat(file).st_atime
37 atime = os.stat(file).st_atime
33 os.utime(file, (atime, mtime))
38 os.utime(file, (atime, mtime))
34 return os.stat(file).st_mtime
39 return os.stat(file).st_mtime
35
40
36 class TestInstallNBExtension(TestCase):
41 class TestInstallNBExtension(TestCase):
37
42
38 def tempdir(self):
43 def tempdir(self):
39 td = TemporaryDirectory()
44 td = TemporaryDirectory()
40 self.tempdirs.append(td)
45 self.tempdirs.append(td)
41 return py3compat.cast_unicode(td.name)
46 return py3compat.cast_unicode(td.name)
42
47
43 def setUp(self):
48 def setUp(self):
44 self.tempdirs = []
49 self.tempdirs = []
45 src = self.src = self.tempdir()
50 src = self.src = self.tempdir()
46 self.files = files = [
51 self.files = files = [
47 pjoin(u'ƒile'),
52 pjoin(u'ƒile'),
48 pjoin(u'∂ir', u'ƒile1'),
53 pjoin(u'∂ir', u'ƒile1'),
49 pjoin(u'∂ir', u'∂ir2', u'ƒile2'),
54 pjoin(u'∂ir', u'∂ir2', u'ƒile2'),
50 ]
55 ]
51 for file in files:
56 for file in files:
52 fullpath = os.path.join(self.src, file)
57 fullpath = os.path.join(self.src, file)
53 parent = os.path.dirname(fullpath)
58 parent = os.path.dirname(fullpath)
54 if not os.path.exists(parent):
59 if not os.path.exists(parent):
55 os.makedirs(parent)
60 os.makedirs(parent)
56 touch(fullpath)
61 touch(fullpath)
57
62
58 self.ipdir = self.tempdir()
63 self.ipdir = self.tempdir()
59 self.save_get_ipython_dir = nbextensions.get_ipython_dir
64 self.save_get_ipython_dir = nbextensions.get_ipython_dir
60 nbextensions.get_ipython_dir = lambda : self.ipdir
65 nbextensions.get_ipython_dir = lambda : self.ipdir
61 self.save_system_dir = nbextensions.SYSTEM_NBEXTENSIONS_INSTALL_DIR
66 self.save_system_dir = nbextensions.SYSTEM_NBEXTENSIONS_INSTALL_DIR
62 nbextensions.SYSTEM_NBEXTENSIONS_INSTALL_DIR = self.system_nbext = self.tempdir()
67 nbextensions.SYSTEM_NBEXTENSIONS_INSTALL_DIR = self.system_nbext = self.tempdir()
63
68
64 def tearDown(self):
69 def tearDown(self):
65 nbextensions.get_ipython_dir = self.save_get_ipython_dir
70 nbextensions.get_ipython_dir = self.save_get_ipython_dir
66 nbextensions.SYSTEM_NBEXTENSIONS_INSTALL_DIR = self.save_system_dir
71 nbextensions.SYSTEM_NBEXTENSIONS_INSTALL_DIR = self.save_system_dir
67 for td in self.tempdirs:
72 for td in self.tempdirs:
68 td.cleanup()
73 td.cleanup()
69
74
70 def assert_dir_exists(self, path):
75 def assert_dir_exists(self, path):
71 if not os.path.exists(path):
76 if not os.path.exists(path):
72 do_exist = os.listdir(os.path.dirname(path))
77 do_exist = os.listdir(os.path.dirname(path))
73 self.fail(u"%s should exist (found %s)" % (path, do_exist))
78 self.fail(u"%s should exist (found %s)" % (path, do_exist))
74
79
75 def assert_not_dir_exists(self, path):
80 def assert_not_dir_exists(self, path):
76 if os.path.exists(path):
81 if os.path.exists(path):
77 self.fail(u"%s should not exist" % path)
82 self.fail(u"%s should not exist" % path)
78
83
79 def assert_installed(self, relative_path, user=False):
84 def assert_installed(self, relative_path, user=False):
80 if user:
85 if user:
81 nbext = pjoin(self.ipdir, u'nbextensions')
86 nbext = pjoin(self.ipdir, u'nbextensions')
82 else:
87 else:
83 nbext = self.system_nbext
88 nbext = self.system_nbext
84 self.assert_dir_exists(
89 self.assert_dir_exists(
85 pjoin(nbext, relative_path)
90 pjoin(nbext, relative_path)
86 )
91 )
87
92
88 def assert_not_installed(self, relative_path, user=False):
93 def assert_not_installed(self, relative_path, user=False):
89 if user:
94 if user:
90 nbext = pjoin(self.ipdir, u'nbextensions')
95 nbext = pjoin(self.ipdir, u'nbextensions')
91 else:
96 else:
92 nbext = self.system_nbext
97 nbext = self.system_nbext
93 self.assert_not_dir_exists(
98 self.assert_not_dir_exists(
94 pjoin(nbext, relative_path)
99 pjoin(nbext, relative_path)
95 )
100 )
96
101
97 def test_create_ipython_dir(self):
102 def test_create_ipython_dir(self):
98 """install_nbextension when ipython_dir doesn't exist"""
103 """install_nbextension when ipython_dir doesn't exist"""
99 with TemporaryDirectory() as td:
104 with TemporaryDirectory() as td:
100 self.ipdir = ipdir = pjoin(td, u'ipython')
105 self.ipdir = ipdir = pjoin(td, u'ipython')
101 install_nbextension(self.src, user=True)
106 install_nbextension(self.src, user=True)
102 self.assert_dir_exists(ipdir)
107 self.assert_dir_exists(ipdir)
103 for file in self.files:
108 for file in self.files:
104 self.assert_installed(
109 self.assert_installed(
105 pjoin(basename(self.src), file),
110 pjoin(basename(self.src), file),
106 user=bool(ipdir)
111 user=bool(ipdir)
107 )
112 )
108
113
109 def test_create_nbextensions_user(self):
114 def test_create_nbextensions_user(self):
110 with TemporaryDirectory() as td:
115 with TemporaryDirectory() as td:
111 self.ipdir = ipdir = pjoin(td, u'ipython')
116 self.ipdir = ipdir = pjoin(td, u'ipython')
112 install_nbextension(self.src, user=True)
117 install_nbextension(self.src, user=True)
113 self.assert_installed(
118 self.assert_installed(
114 pjoin(basename(self.src), u'ƒile'),
119 pjoin(basename(self.src), u'ƒile'),
115 user=True
120 user=True
116 )
121 )
117
122
118 def test_create_nbextensions_system(self):
123 def test_create_nbextensions_system(self):
119 with TemporaryDirectory() as td:
124 with TemporaryDirectory() as td:
120 nbextensions.SYSTEM_NBEXTENSIONS_INSTALL_DIR = self.system_nbext = pjoin(td, u'nbextensions')
125 nbextensions.SYSTEM_NBEXTENSIONS_INSTALL_DIR = self.system_nbext = pjoin(td, u'nbextensions')
121 install_nbextension(self.src, user=False)
126 install_nbextension(self.src, user=False)
122 self.assert_installed(
127 self.assert_installed(
123 pjoin(basename(self.src), u'ƒile'),
128 pjoin(basename(self.src), u'ƒile'),
124 user=False
129 user=False
125 )
130 )
126
131
127 def test_single_file(self):
132 def test_single_file(self):
128 file = self.files[0]
133 file = self.files[0]
129 install_nbextension(pjoin(self.src, file))
134 install_nbextension(pjoin(self.src, file))
130 self.assert_installed(file)
135 self.assert_installed(file)
131
136
132 def test_single_dir(self):
137 def test_single_dir(self):
133 d = u'∂ir'
138 d = u'∂ir'
134 install_nbextension(pjoin(self.src, d))
139 install_nbextension(pjoin(self.src, d))
135 self.assert_installed(self.files[-1])
140 self.assert_installed(self.files[-1])
136
141
137
142
138 def test_destination_file(self):
143 def test_destination_file(self):
139 file = self.files[0]
144 file = self.files[0]
140 install_nbextension(pjoin(self.src, file), destination = u'ƒiledest')
145 install_nbextension(pjoin(self.src, file), destination = u'ƒiledest')
141 self.assert_installed(u'ƒiledest')
146 self.assert_installed(u'ƒiledest')
142
147
143 def test_destination_dir(self):
148 def test_destination_dir(self):
144 d = u'∂ir'
149 d = u'∂ir'
145 install_nbextension(pjoin(self.src, d), destination = u'ƒiledest2')
150 install_nbextension(pjoin(self.src, d), destination = u'ƒiledest2')
146 self.assert_installed(pjoin(u'ƒiledest2', u'∂ir2', u'ƒile2'))
151 self.assert_installed(pjoin(u'ƒiledest2', u'∂ir2', u'ƒile2'))
147
152
148 def test_install_nbextension(self):
153 def test_install_nbextension(self):
149 with self.assertRaises(TypeError):
154 with self.assertRaises(TypeError):
150 install_nbextension(glob.glob(pjoin(self.src, '*')))
155 install_nbextension(glob.glob(pjoin(self.src, '*')))
151
156
152 def test_overwrite_file(self):
157 def test_overwrite_file(self):
153 with TemporaryDirectory() as d:
158 with TemporaryDirectory() as d:
154 fname = u'ƒ.js'
159 fname = u'ƒ.js'
155 src = pjoin(d, fname)
160 src = pjoin(d, fname)
156 with open(src, 'w') as f:
161 with open(src, 'w') as f:
157 f.write('first')
162 f.write('first')
158 mtime = touch(src)
163 mtime = touch(src)
159 dest = pjoin(self.system_nbext, fname)
164 dest = pjoin(self.system_nbext, fname)
160 install_nbextension(src)
165 install_nbextension(src)
161 with open(src, 'w') as f:
166 with open(src, 'w') as f:
162 f.write('overwrite')
167 f.write('overwrite')
163 mtime = touch(src, mtime - 100)
168 mtime = touch(src, mtime - 100)
164 install_nbextension(src, overwrite=True)
169 install_nbextension(src, overwrite=True)
165 with open(dest) as f:
170 with open(dest) as f:
166 self.assertEqual(f.read(), 'overwrite')
171 self.assertEqual(f.read(), 'overwrite')
167
172
168 def test_overwrite_dir(self):
173 def test_overwrite_dir(self):
169 with TemporaryDirectory() as src:
174 with TemporaryDirectory() as src:
170 base = basename(src)
175 base = basename(src)
171 fname = u'ƒ.js'
176 fname = u'ƒ.js'
172 touch(pjoin(src, fname))
177 touch(pjoin(src, fname))
173 install_nbextension(src)
178 install_nbextension(src)
174 self.assert_installed(pjoin(base, fname))
179 self.assert_installed(pjoin(base, fname))
175 os.remove(pjoin(src, fname))
180 os.remove(pjoin(src, fname))
176 fname2 = u'∂.js'
181 fname2 = u'∂.js'
177 touch(pjoin(src, fname2))
182 touch(pjoin(src, fname2))
178 install_nbextension(src, overwrite=True)
183 install_nbextension(src, overwrite=True)
179 self.assert_installed(pjoin(base, fname2))
184 self.assert_installed(pjoin(base, fname2))
180 self.assert_not_installed(pjoin(base, fname))
185 self.assert_not_installed(pjoin(base, fname))
181
186
182 def test_update_file(self):
187 def test_update_file(self):
183 with TemporaryDirectory() as d:
188 with TemporaryDirectory() as d:
184 fname = u'ƒ.js'
189 fname = u'ƒ.js'
185 src = pjoin(d, fname)
190 src = pjoin(d, fname)
186 with open(src, 'w') as f:
191 with open(src, 'w') as f:
187 f.write('first')
192 f.write('first')
188 mtime = touch(src)
193 mtime = touch(src)
189 install_nbextension(src)
194 install_nbextension(src)
190 self.assert_installed(fname)
195 self.assert_installed(fname)
191 dest = pjoin(self.system_nbext, fname)
196 dest = pjoin(self.system_nbext, fname)
192 old_mtime = os.stat(dest).st_mtime
197 old_mtime = os.stat(dest).st_mtime
193 with open(src, 'w') as f:
198 with open(src, 'w') as f:
194 f.write('overwrite')
199 f.write('overwrite')
195 touch(src, mtime + 10)
200 touch(src, mtime + 10)
196 install_nbextension(src)
201 install_nbextension(src)
197 with open(dest) as f:
202 with open(dest) as f:
198 self.assertEqual(f.read(), 'overwrite')
203 self.assertEqual(f.read(), 'overwrite')
199
204
200 def test_skip_old_file(self):
205 def test_skip_old_file(self):
201 with TemporaryDirectory() as d:
206 with TemporaryDirectory() as d:
202 fname = u'ƒ.js'
207 fname = u'ƒ.js'
203 src = pjoin(d, fname)
208 src = pjoin(d, fname)
204 mtime = touch(src)
209 mtime = touch(src)
205 install_nbextension(src)
210 install_nbextension(src)
206 self.assert_installed(fname)
211 self.assert_installed(fname)
207 dest = pjoin(self.system_nbext, fname)
212 dest = pjoin(self.system_nbext, fname)
208 old_mtime = os.stat(dest).st_mtime
213 old_mtime = os.stat(dest).st_mtime
209
214
210 mtime = touch(src, mtime - 100)
215 mtime = touch(src, mtime - 100)
211 install_nbextension(src)
216 install_nbextension(src)
212 new_mtime = os.stat(dest).st_mtime
217 new_mtime = os.stat(dest).st_mtime
213 self.assertEqual(new_mtime, old_mtime)
218 self.assertEqual(new_mtime, old_mtime)
214
219
215 def test_quiet(self):
220 def test_quiet(self):
216 with tt.AssertNotPrints(re.compile(r'.+')):
221 stdout = StringIO()
222 stderr = StringIO()
223 with mock.patch.object(sys, 'stdout', stdout), \
224 mock.patch.object(sys, 'stderr', stderr):
217 install_nbextension(self.src, verbose=0)
225 install_nbextension(self.src, verbose=0)
226 self.assertEqual(stdout.getvalue(), '')
227 self.assertEqual(stderr.getvalue(), '')
218
228
219 def test_install_zip(self):
229 def test_install_zip(self):
220 path = pjoin(self.src, "myjsext.zip")
230 path = pjoin(self.src, "myjsext.zip")
221 with zipfile.ZipFile(path, 'w') as f:
231 with zipfile.ZipFile(path, 'w') as f:
222 f.writestr("a.js", b"b();")
232 f.writestr("a.js", b"b();")
223 f.writestr("foo/a.js", b"foo();")
233 f.writestr("foo/a.js", b"foo();")
224 install_nbextension(path)
234 install_nbextension(path)
225 self.assert_installed("a.js")
235 self.assert_installed("a.js")
226 self.assert_installed(pjoin("foo", "a.js"))
236 self.assert_installed(pjoin("foo", "a.js"))
227
237
228 def test_install_tar(self):
238 def test_install_tar(self):
229 def _add_file(f, fname, buf):
239 def _add_file(f, fname, buf):
230 info = tarfile.TarInfo(fname)
240 info = tarfile.TarInfo(fname)
231 info.size = len(buf)
241 info.size = len(buf)
232 f.addfile(info, BytesIO(buf))
242 f.addfile(info, BytesIO(buf))
233
243
234 for i,ext in enumerate((".tar.gz", ".tgz", ".tar.bz2")):
244 for i,ext in enumerate((".tar.gz", ".tgz", ".tar.bz2")):
235 path = pjoin(self.src, "myjsext" + ext)
245 path = pjoin(self.src, "myjsext" + ext)
236 with tarfile.open(path, 'w') as f:
246 with tarfile.open(path, 'w') as f:
237 _add_file(f, "b%i.js" % i, b"b();")
247 _add_file(f, "b%i.js" % i, b"b();")
238 _add_file(f, "foo/b%i.js" % i, b"foo();")
248 _add_file(f, "foo/b%i.js" % i, b"foo();")
239 install_nbextension(path)
249 install_nbextension(path)
240 self.assert_installed("b%i.js" % i)
250 self.assert_installed("b%i.js" % i)
241 self.assert_installed(pjoin("foo", "b%i.js" % i))
251 self.assert_installed(pjoin("foo", "b%i.js" % i))
242
252
243 def test_install_url(self):
253 def test_install_url(self):
244 def fake_urlretrieve(url, dest):
254 def fake_urlretrieve(url, dest):
245 touch(dest)
255 touch(dest)
246 save_urlretrieve = nbextensions.urlretrieve
256 save_urlretrieve = nbextensions.urlretrieve
247 nbextensions.urlretrieve = fake_urlretrieve
257 nbextensions.urlretrieve = fake_urlretrieve
248 try:
258 try:
249 install_nbextension("http://example.com/path/to/foo.js")
259 install_nbextension("http://example.com/path/to/foo.js")
250 self.assert_installed("foo.js")
260 self.assert_installed("foo.js")
251 install_nbextension("https://example.com/path/to/another/bar.js")
261 install_nbextension("https://example.com/path/to/another/bar.js")
252 self.assert_installed("bar.js")
262 self.assert_installed("bar.js")
253 install_nbextension("https://example.com/path/to/another/bar.js",
263 install_nbextension("https://example.com/path/to/another/bar.js",
254 destination = 'foobar.js')
264 destination = 'foobar.js')
255 self.assert_installed("foobar.js")
265 self.assert_installed("foobar.js")
256 finally:
266 finally:
257 nbextensions.urlretrieve = save_urlretrieve
267 nbextensions.urlretrieve = save_urlretrieve
258
268
259 def test_check_nbextension(self):
269 def test_check_nbextension(self):
260 with TemporaryDirectory() as d:
270 with TemporaryDirectory() as d:
261 f = u'ƒ.js'
271 f = u'ƒ.js'
262 src = pjoin(d, f)
272 src = pjoin(d, f)
263 touch(src)
273 touch(src)
264 install_nbextension(src, user=True)
274 install_nbextension(src, user=True)
265
275
266 assert check_nbextension(f, user=True)
276 assert check_nbextension(f, user=True)
267 assert check_nbextension([f], user=True)
277 assert check_nbextension([f], user=True)
268 assert not check_nbextension([f, pjoin('dne', f)], user=True)
278 assert not check_nbextension([f, pjoin('dne', f)], user=True)
269
279
270 @dec.skip_win32
280 @dec.skip_win32
271 def test_install_symlink(self):
281 def test_install_symlink(self):
272 with TemporaryDirectory() as d:
282 with TemporaryDirectory() as d:
273 f = u'ƒ.js'
283 f = u'ƒ.js'
274 src = pjoin(d, f)
284 src = pjoin(d, f)
275 touch(src)
285 touch(src)
276 install_nbextension(src, symlink=True)
286 install_nbextension(src, symlink=True)
277 dest = pjoin(self.system_nbext, f)
287 dest = pjoin(self.system_nbext, f)
278 assert os.path.islink(dest)
288 assert os.path.islink(dest)
279 link = os.readlink(dest)
289 link = os.readlink(dest)
280 self.assertEqual(link, src)
290 self.assertEqual(link, src)
281
291
282 @dec.skip_win32
292 @dec.skip_win32
283 def test_overwrite_broken_symlink(self):
293 def test_overwrite_broken_symlink(self):
284 with TemporaryDirectory() as d:
294 with TemporaryDirectory() as d:
285 f = u'ƒ.js'
295 f = u'ƒ.js'
286 f2 = u'ƒ2.js'
296 f2 = u'ƒ2.js'
287 src = pjoin(d, f)
297 src = pjoin(d, f)
288 src2 = pjoin(d, f2)
298 src2 = pjoin(d, f2)
289 touch(src)
299 touch(src)
290 install_nbextension(src, symlink=True)
300 install_nbextension(src, symlink=True)
291 os.rename(src, src2)
301 os.rename(src, src2)
292 install_nbextension(src2, symlink=True, overwrite=True, destination=f)
302 install_nbextension(src2, symlink=True, overwrite=True, destination=f)
293 dest = pjoin(self.system_nbext, f)
303 dest = pjoin(self.system_nbext, f)
294 assert os.path.islink(dest)
304 assert os.path.islink(dest)
295 link = os.readlink(dest)
305 link = os.readlink(dest)
296 self.assertEqual(link, src2)
306 self.assertEqual(link, src2)
297
307
298 @dec.skip_win32
308 @dec.skip_win32
299 def test_install_symlink_destination(self):
309 def test_install_symlink_destination(self):
300 with TemporaryDirectory() as d:
310 with TemporaryDirectory() as d:
301 f = u'ƒ.js'
311 f = u'ƒ.js'
302 flink = u'ƒlink.js'
312 flink = u'ƒlink.js'
303 src = pjoin(d, f)
313 src = pjoin(d, f)
304 touch(src)
314 touch(src)
305 install_nbextension(src, symlink=True, destination=flink)
315 install_nbextension(src, symlink=True, destination=flink)
306 dest = pjoin(self.system_nbext, flink)
316 dest = pjoin(self.system_nbext, flink)
307 assert os.path.islink(dest)
317 assert os.path.islink(dest)
308 link = os.readlink(dest)
318 link = os.readlink(dest)
309 self.assertEqual(link, src)
319 self.assertEqual(link, src)
310
320
311 def test_install_symlink_bad(self):
321 def test_install_symlink_bad(self):
312 with self.assertRaises(ValueError):
322 with self.assertRaises(ValueError):
313 install_nbextension("http://example.com/foo.js", symlink=True)
323 install_nbextension("http://example.com/foo.js", symlink=True)
314
324
315 with TemporaryDirectory() as d:
325 with TemporaryDirectory() as d:
316 zf = u'ƒ.zip'
326 zf = u'ƒ.zip'
317 zsrc = pjoin(d, zf)
327 zsrc = pjoin(d, zf)
318 with zipfile.ZipFile(zsrc, 'w') as z:
328 with zipfile.ZipFile(zsrc, 'w') as z:
319 z.writestr("a.js", b"b();")
329 z.writestr("a.js", b"b();")
320
330
321 with self.assertRaises(ValueError):
331 with self.assertRaises(ValueError):
322 install_nbextension(zsrc, symlink=True)
332 install_nbextension(zsrc, symlink=True)
323
333
324 def test_install_destination_bad(self):
334 def test_install_destination_bad(self):
325 with TemporaryDirectory() as d:
335 with TemporaryDirectory() as d:
326 zf = u'ƒ.zip'
336 zf = u'ƒ.zip'
327 zsrc = pjoin(d, zf)
337 zsrc = pjoin(d, zf)
328 with zipfile.ZipFile(zsrc, 'w') as z:
338 with zipfile.ZipFile(zsrc, 'w') as z:
329 z.writestr("a.js", b"b();")
339 z.writestr("a.js", b"b();")
330
340
331 with self.assertRaises(ValueError):
341 with self.assertRaises(ValueError):
332 install_nbextension(zsrc, destination='foo')
342 install_nbextension(zsrc, destination='foo')
@@ -1,74 +1,62 b''
1 """Test NotebookApp"""
1 """Test NotebookApp"""
2
2
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2013 The IPython Development Team
5 #
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
3
14 import logging
4 import logging
15 import os
5 import os
16 from tempfile import NamedTemporaryFile
6 from tempfile import NamedTemporaryFile
17
7
18 import nose.tools as nt
8 import nose.tools as nt
19
9
10 from traitlets.tests.utils import check_help_all_output
11
20 from IPython.utils.tempdir import TemporaryDirectory
12 from IPython.utils.tempdir import TemporaryDirectory
21 from IPython.utils.traitlets import TraitError
13 from IPython.utils.traitlets import TraitError
22 import IPython.testing.tools as tt
23 from IPython.html import notebookapp
14 from IPython.html import notebookapp
24 NotebookApp = notebookapp.NotebookApp
15 NotebookApp = notebookapp.NotebookApp
25
16
26 #-----------------------------------------------------------------------------
27 # Test functions
28 #-----------------------------------------------------------------------------
29
17
30 def test_help_output():
18 def test_help_output():
31 """ipython notebook --help-all works"""
19 """ipython notebook --help-all works"""
32 tt.help_all_output_test('notebook')
20 check_help_all_output('IPython.html')
33
21
34 def test_server_info_file():
22 def test_server_info_file():
35 nbapp = NotebookApp(profile='nbserver_file_test', log=logging.getLogger())
23 nbapp = NotebookApp(profile='nbserver_file_test', log=logging.getLogger())
36 def get_servers():
24 def get_servers():
37 return list(notebookapp.list_running_servers(profile='nbserver_file_test'))
25 return list(notebookapp.list_running_servers(profile='nbserver_file_test'))
38 nbapp.initialize(argv=[])
26 nbapp.initialize(argv=[])
39 nbapp.write_server_info_file()
27 nbapp.write_server_info_file()
40 servers = get_servers()
28 servers = get_servers()
41 nt.assert_equal(len(servers), 1)
29 nt.assert_equal(len(servers), 1)
42 nt.assert_equal(servers[0]['port'], nbapp.port)
30 nt.assert_equal(servers[0]['port'], nbapp.port)
43 nt.assert_equal(servers[0]['url'], nbapp.connection_url)
31 nt.assert_equal(servers[0]['url'], nbapp.connection_url)
44 nbapp.remove_server_info_file()
32 nbapp.remove_server_info_file()
45 nt.assert_equal(get_servers(), [])
33 nt.assert_equal(get_servers(), [])
46
34
47 # The ENOENT error should be silenced.
35 # The ENOENT error should be silenced.
48 nbapp.remove_server_info_file()
36 nbapp.remove_server_info_file()
49
37
50 def test_nb_dir():
38 def test_nb_dir():
51 with TemporaryDirectory() as td:
39 with TemporaryDirectory() as td:
52 app = NotebookApp(notebook_dir=td)
40 app = NotebookApp(notebook_dir=td)
53 nt.assert_equal(app.notebook_dir, td)
41 nt.assert_equal(app.notebook_dir, td)
54
42
55 def test_no_create_nb_dir():
43 def test_no_create_nb_dir():
56 with TemporaryDirectory() as td:
44 with TemporaryDirectory() as td:
57 nbdir = os.path.join(td, 'notebooks')
45 nbdir = os.path.join(td, 'notebooks')
58 app = NotebookApp()
46 app = NotebookApp()
59 with nt.assert_raises(TraitError):
47 with nt.assert_raises(TraitError):
60 app.notebook_dir = nbdir
48 app.notebook_dir = nbdir
61
49
62 def test_missing_nb_dir():
50 def test_missing_nb_dir():
63 with TemporaryDirectory() as td:
51 with TemporaryDirectory() as td:
64 nbdir = os.path.join(td, 'notebook', 'dir', 'is', 'missing')
52 nbdir = os.path.join(td, 'notebook', 'dir', 'is', 'missing')
65 app = NotebookApp()
53 app = NotebookApp()
66 with nt.assert_raises(TraitError):
54 with nt.assert_raises(TraitError):
67 app.notebook_dir = nbdir
55 app.notebook_dir = nbdir
68
56
69 def test_invalid_nb_dir():
57 def test_invalid_nb_dir():
70 with NamedTemporaryFile() as tf:
58 with NamedTemporaryFile() as tf:
71 app = NotebookApp()
59 app = NotebookApp()
72 with nt.assert_raises(TraitError):
60 with nt.assert_raises(TraitError):
73 app.notebook_dir = tf
61 app.notebook_dir = tf
74
62
@@ -1,76 +1,66 b''
1 """Test HTML utils"""
1 """Test HTML utils"""
2
2
3 #-----------------------------------------------------------------------------
3 # Copyright (c) Jupyter Development Team.
4 # Copyright (C) 2013 The IPython Development Team
4 # Distributed under the terms of the Modified BSD License.
5 #
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
5
14 import os
6 import os
15
7
16 import nose.tools as nt
8 import nose.tools as nt
17
9
18 import IPython.testing.tools as tt
10 from traitlets.tests.utils import check_help_all_output
19 from IPython.html.utils import url_escape, url_unescape, is_hidden
11 from IPython.html.utils import url_escape, url_unescape, is_hidden
20 from IPython.utils.tempdir import TemporaryDirectory
12 from IPython.utils.tempdir import TemporaryDirectory
21
13
22 #-----------------------------------------------------------------------------
23 # Test functions
24 #-----------------------------------------------------------------------------
25
14
26 def test_help_output():
15 def test_help_output():
27 """ipython notebook --help-all works"""
16 """jupyter notebook --help-all works"""
28 tt.help_all_output_test('notebook')
17 # FIXME: will be jupyter_notebook
18 check_help_all_output('IPython.html')
29
19
30
20
31 def test_url_escape():
21 def test_url_escape():
32
22
33 # changes path or notebook name with special characters to url encoding
23 # changes path or notebook name with special characters to url encoding
34 # these tests specifically encode paths with spaces
24 # these tests specifically encode paths with spaces
35 path = url_escape('/this is a test/for spaces/')
25 path = url_escape('/this is a test/for spaces/')
36 nt.assert_equal(path, '/this%20is%20a%20test/for%20spaces/')
26 nt.assert_equal(path, '/this%20is%20a%20test/for%20spaces/')
37
27
38 path = url_escape('notebook with space.ipynb')
28 path = url_escape('notebook with space.ipynb')
39 nt.assert_equal(path, 'notebook%20with%20space.ipynb')
29 nt.assert_equal(path, 'notebook%20with%20space.ipynb')
40
30
41 path = url_escape('/path with a/notebook and space.ipynb')
31 path = url_escape('/path with a/notebook and space.ipynb')
42 nt.assert_equal(path, '/path%20with%20a/notebook%20and%20space.ipynb')
32 nt.assert_equal(path, '/path%20with%20a/notebook%20and%20space.ipynb')
43
33
44 path = url_escape('/ !@$#%^&* / test %^ notebook @#$ name.ipynb')
34 path = url_escape('/ !@$#%^&* / test %^ notebook @#$ name.ipynb')
45 nt.assert_equal(path,
35 nt.assert_equal(path,
46 '/%20%21%40%24%23%25%5E%26%2A%20/%20test%20%25%5E%20notebook%20%40%23%24%20name.ipynb')
36 '/%20%21%40%24%23%25%5E%26%2A%20/%20test%20%25%5E%20notebook%20%40%23%24%20name.ipynb')
47
37
48 def test_url_unescape():
38 def test_url_unescape():
49
39
50 # decodes a url string to a plain string
40 # decodes a url string to a plain string
51 # these tests decode paths with spaces
41 # these tests decode paths with spaces
52 path = url_unescape('/this%20is%20a%20test/for%20spaces/')
42 path = url_unescape('/this%20is%20a%20test/for%20spaces/')
53 nt.assert_equal(path, '/this is a test/for spaces/')
43 nt.assert_equal(path, '/this is a test/for spaces/')
54
44
55 path = url_unescape('notebook%20with%20space.ipynb')
45 path = url_unescape('notebook%20with%20space.ipynb')
56 nt.assert_equal(path, 'notebook with space.ipynb')
46 nt.assert_equal(path, 'notebook with space.ipynb')
57
47
58 path = url_unescape('/path%20with%20a/notebook%20and%20space.ipynb')
48 path = url_unescape('/path%20with%20a/notebook%20and%20space.ipynb')
59 nt.assert_equal(path, '/path with a/notebook and space.ipynb')
49 nt.assert_equal(path, '/path with a/notebook and space.ipynb')
60
50
61 path = url_unescape(
51 path = url_unescape(
62 '/%20%21%40%24%23%25%5E%26%2A%20/%20test%20%25%5E%20notebook%20%40%23%24%20name.ipynb')
52 '/%20%21%40%24%23%25%5E%26%2A%20/%20test%20%25%5E%20notebook%20%40%23%24%20name.ipynb')
63 nt.assert_equal(path, '/ !@$#%^&* / test %^ notebook @#$ name.ipynb')
53 nt.assert_equal(path, '/ !@$#%^&* / test %^ notebook @#$ name.ipynb')
64
54
65 def test_is_hidden():
55 def test_is_hidden():
66 with TemporaryDirectory() as root:
56 with TemporaryDirectory() as root:
67 subdir1 = os.path.join(root, 'subdir')
57 subdir1 = os.path.join(root, 'subdir')
68 os.makedirs(subdir1)
58 os.makedirs(subdir1)
69 nt.assert_equal(is_hidden(subdir1, root), False)
59 nt.assert_equal(is_hidden(subdir1, root), False)
70 subdir2 = os.path.join(root, '.subdir2')
60 subdir2 = os.path.join(root, '.subdir2')
71 os.makedirs(subdir2)
61 os.makedirs(subdir2)
72 nt.assert_equal(is_hidden(subdir2, root), True)
62 nt.assert_equal(is_hidden(subdir2, root), True)
73 subdir34 = os.path.join(root, 'subdir3', '.subdir4')
63 subdir34 = os.path.join(root, 'subdir3', '.subdir4')
74 os.makedirs(subdir34)
64 os.makedirs(subdir34)
75 nt.assert_equal(is_hidden(subdir34, root), True)
65 nt.assert_equal(is_hidden(subdir34, root), True)
76 nt.assert_equal(is_hidden(subdir34), True)
66 nt.assert_equal(is_hidden(subdir34), True)
@@ -1,487 +1,467 b''
1 """Generic testing tools.
1 """Generic testing tools.
2
2
3 Authors
3 Authors
4 -------
4 -------
5 - Fernando Perez <Fernando.Perez@berkeley.edu>
5 - Fernando Perez <Fernando.Perez@berkeley.edu>
6 """
6 """
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2009 The IPython Development Team
11 # Copyright (C) 2009 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 import os
21 import os
22 import re
22 import re
23 import sys
23 import sys
24 import tempfile
24 import tempfile
25
25
26 from contextlib import contextmanager
26 from contextlib import contextmanager
27 from io import StringIO
27 from io import StringIO
28 from subprocess import Popen, PIPE
28 from subprocess import Popen, PIPE
29
29
30 try:
30 try:
31 # These tools are used by parts of the runtime, so we make the nose
31 # These tools are used by parts of the runtime, so we make the nose
32 # dependency optional at this point. Nose is a hard dependency to run the
32 # dependency optional at this point. Nose is a hard dependency to run the
33 # test suite, but NOT to use ipython itself.
33 # test suite, but NOT to use ipython itself.
34 import nose.tools as nt
34 import nose.tools as nt
35 has_nose = True
35 has_nose = True
36 except ImportError:
36 except ImportError:
37 has_nose = False
37 has_nose = False
38
38
39 from IPython.config.loader import Config
39 from IPython.config.loader import Config
40 from IPython.utils.process import get_output_error_code
40 from IPython.utils.process import get_output_error_code
41 from IPython.utils.text import list_strings
41 from IPython.utils.text import list_strings
42 from IPython.utils.io import temp_pyfile, Tee
42 from IPython.utils.io import temp_pyfile, Tee
43 from IPython.utils import py3compat
43 from IPython.utils import py3compat
44 from IPython.utils.encoding import DEFAULT_ENCODING
44 from IPython.utils.encoding import DEFAULT_ENCODING
45
45
46 from . import decorators as dec
46 from . import decorators as dec
47 from . import skipdoctest
47 from . import skipdoctest
48
48
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50 # Functions and classes
50 # Functions and classes
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52
52
53 # The docstring for full_path doctests differently on win32 (different path
53 # The docstring for full_path doctests differently on win32 (different path
54 # separator) so just skip the doctest there. The example remains informative.
54 # separator) so just skip the doctest there. The example remains informative.
55 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
55 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
56
56
57 @doctest_deco
57 @doctest_deco
58 def full_path(startPath,files):
58 def full_path(startPath,files):
59 """Make full paths for all the listed files, based on startPath.
59 """Make full paths for all the listed files, based on startPath.
60
60
61 Only the base part of startPath is kept, since this routine is typically
61 Only the base part of startPath is kept, since this routine is typically
62 used with a script's ``__file__`` variable as startPath. The base of startPath
62 used with a script's ``__file__`` variable as startPath. The base of startPath
63 is then prepended to all the listed files, forming the output list.
63 is then prepended to all the listed files, forming the output list.
64
64
65 Parameters
65 Parameters
66 ----------
66 ----------
67 startPath : string
67 startPath : string
68 Initial path to use as the base for the results. This path is split
68 Initial path to use as the base for the results. This path is split
69 using os.path.split() and only its first component is kept.
69 using os.path.split() and only its first component is kept.
70
70
71 files : string or list
71 files : string or list
72 One or more files.
72 One or more files.
73
73
74 Examples
74 Examples
75 --------
75 --------
76
76
77 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
77 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
78 ['/foo/a.txt', '/foo/b.txt']
78 ['/foo/a.txt', '/foo/b.txt']
79
79
80 >>> full_path('/foo',['a.txt','b.txt'])
80 >>> full_path('/foo',['a.txt','b.txt'])
81 ['/a.txt', '/b.txt']
81 ['/a.txt', '/b.txt']
82
82
83 If a single file is given, the output is still a list::
83 If a single file is given, the output is still a list::
84
84
85 >>> full_path('/foo','a.txt')
85 >>> full_path('/foo','a.txt')
86 ['/a.txt']
86 ['/a.txt']
87 """
87 """
88
88
89 files = list_strings(files)
89 files = list_strings(files)
90 base = os.path.split(startPath)[0]
90 base = os.path.split(startPath)[0]
91 return [ os.path.join(base,f) for f in files ]
91 return [ os.path.join(base,f) for f in files ]
92
92
93
93
94 def parse_test_output(txt):
94 def parse_test_output(txt):
95 """Parse the output of a test run and return errors, failures.
95 """Parse the output of a test run and return errors, failures.
96
96
97 Parameters
97 Parameters
98 ----------
98 ----------
99 txt : str
99 txt : str
100 Text output of a test run, assumed to contain a line of one of the
100 Text output of a test run, assumed to contain a line of one of the
101 following forms::
101 following forms::
102
102
103 'FAILED (errors=1)'
103 'FAILED (errors=1)'
104 'FAILED (failures=1)'
104 'FAILED (failures=1)'
105 'FAILED (errors=1, failures=1)'
105 'FAILED (errors=1, failures=1)'
106
106
107 Returns
107 Returns
108 -------
108 -------
109 nerr, nfail
109 nerr, nfail
110 number of errors and failures.
110 number of errors and failures.
111 """
111 """
112
112
113 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
113 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
114 if err_m:
114 if err_m:
115 nerr = int(err_m.group(1))
115 nerr = int(err_m.group(1))
116 nfail = 0
116 nfail = 0
117 return nerr, nfail
117 return nerr, nfail
118
118
119 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
119 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
120 if fail_m:
120 if fail_m:
121 nerr = 0
121 nerr = 0
122 nfail = int(fail_m.group(1))
122 nfail = int(fail_m.group(1))
123 return nerr, nfail
123 return nerr, nfail
124
124
125 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
125 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
126 re.MULTILINE)
126 re.MULTILINE)
127 if both_m:
127 if both_m:
128 nerr = int(both_m.group(1))
128 nerr = int(both_m.group(1))
129 nfail = int(both_m.group(2))
129 nfail = int(both_m.group(2))
130 return nerr, nfail
130 return nerr, nfail
131
131
132 # If the input didn't match any of these forms, assume no error/failures
132 # If the input didn't match any of these forms, assume no error/failures
133 return 0, 0
133 return 0, 0
134
134
135
135
136 # So nose doesn't think this is a test
136 # So nose doesn't think this is a test
137 parse_test_output.__test__ = False
137 parse_test_output.__test__ = False
138
138
139
139
140 def default_argv():
140 def default_argv():
141 """Return a valid default argv for creating testing instances of ipython"""
141 """Return a valid default argv for creating testing instances of ipython"""
142
142
143 return ['--quick', # so no config file is loaded
143 return ['--quick', # so no config file is loaded
144 # Other defaults to minimize side effects on stdout
144 # Other defaults to minimize side effects on stdout
145 '--colors=NoColor', '--no-term-title','--no-banner',
145 '--colors=NoColor', '--no-term-title','--no-banner',
146 '--autocall=0']
146 '--autocall=0']
147
147
148
148
149 def default_config():
149 def default_config():
150 """Return a config object with good defaults for testing."""
150 """Return a config object with good defaults for testing."""
151 config = Config()
151 config = Config()
152 config.TerminalInteractiveShell.colors = 'NoColor'
152 config.TerminalInteractiveShell.colors = 'NoColor'
153 config.TerminalTerminalInteractiveShell.term_title = False,
153 config.TerminalTerminalInteractiveShell.term_title = False,
154 config.TerminalInteractiveShell.autocall = 0
154 config.TerminalInteractiveShell.autocall = 0
155 f = tempfile.NamedTemporaryFile(suffix=u'test_hist.sqlite', delete=False)
155 f = tempfile.NamedTemporaryFile(suffix=u'test_hist.sqlite', delete=False)
156 config.HistoryManager.hist_file = f.name
156 config.HistoryManager.hist_file = f.name
157 f.close()
157 f.close()
158 config.HistoryManager.db_cache_size = 10000
158 config.HistoryManager.db_cache_size = 10000
159 return config
159 return config
160
160
161
161
162 def get_ipython_cmd(as_string=False):
162 def get_ipython_cmd(as_string=False):
163 """
163 """
164 Return appropriate IPython command line name. By default, this will return
164 Return appropriate IPython command line name. By default, this will return
165 a list that can be used with subprocess.Popen, for example, but passing
165 a list that can be used with subprocess.Popen, for example, but passing
166 `as_string=True` allows for returning the IPython command as a string.
166 `as_string=True` allows for returning the IPython command as a string.
167
167
168 Parameters
168 Parameters
169 ----------
169 ----------
170 as_string: bool
170 as_string: bool
171 Flag to allow to return the command as a string.
171 Flag to allow to return the command as a string.
172 """
172 """
173 ipython_cmd = [sys.executable, "-m", "IPython"]
173 ipython_cmd = [sys.executable, "-m", "IPython"]
174
174
175 if as_string:
175 if as_string:
176 ipython_cmd = " ".join(ipython_cmd)
176 ipython_cmd = " ".join(ipython_cmd)
177
177
178 return ipython_cmd
178 return ipython_cmd
179
179
180 def ipexec(fname, options=None, commands=()):
180 def ipexec(fname, options=None, commands=()):
181 """Utility to call 'ipython filename'.
181 """Utility to call 'ipython filename'.
182
182
183 Starts IPython with a minimal and safe configuration to make startup as fast
183 Starts IPython with a minimal and safe configuration to make startup as fast
184 as possible.
184 as possible.
185
185
186 Note that this starts IPython in a subprocess!
186 Note that this starts IPython in a subprocess!
187
187
188 Parameters
188 Parameters
189 ----------
189 ----------
190 fname : str
190 fname : str
191 Name of file to be executed (should have .py or .ipy extension).
191 Name of file to be executed (should have .py or .ipy extension).
192
192
193 options : optional, list
193 options : optional, list
194 Extra command-line flags to be passed to IPython.
194 Extra command-line flags to be passed to IPython.
195
195
196 commands : optional, list
196 commands : optional, list
197 Commands to send in on stdin
197 Commands to send in on stdin
198
198
199 Returns
199 Returns
200 -------
200 -------
201 (stdout, stderr) of ipython subprocess.
201 (stdout, stderr) of ipython subprocess.
202 """
202 """
203 if options is None: options = []
203 if options is None: options = []
204
204
205 # For these subprocess calls, eliminate all prompt printing so we only see
205 # For these subprocess calls, eliminate all prompt printing so we only see
206 # output from script execution
206 # output from script execution
207 prompt_opts = [ '--PromptManager.in_template=""',
207 prompt_opts = [ '--PromptManager.in_template=""',
208 '--PromptManager.in2_template=""',
208 '--PromptManager.in2_template=""',
209 '--PromptManager.out_template=""'
209 '--PromptManager.out_template=""'
210 ]
210 ]
211 cmdargs = default_argv() + prompt_opts + options
211 cmdargs = default_argv() + prompt_opts + options
212
212
213 test_dir = os.path.dirname(__file__)
213 test_dir = os.path.dirname(__file__)
214
214
215 ipython_cmd = get_ipython_cmd()
215 ipython_cmd = get_ipython_cmd()
216 # Absolute path for filename
216 # Absolute path for filename
217 full_fname = os.path.join(test_dir, fname)
217 full_fname = os.path.join(test_dir, fname)
218 full_cmd = ipython_cmd + cmdargs + [full_fname]
218 full_cmd = ipython_cmd + cmdargs + [full_fname]
219 env = os.environ.copy()
219 env = os.environ.copy()
220 # FIXME: ignore all warnings in ipexec while we have shims
220 # FIXME: ignore all warnings in ipexec while we have shims
221 # should we keep suppressing warnings here, even after removing shims?
221 # should we keep suppressing warnings here, even after removing shims?
222 env['PYTHONWARNINGS'] = 'ignore'
222 env['PYTHONWARNINGS'] = 'ignore'
223 # env.pop('PYTHONWARNINGS', None) # Avoid extraneous warnings appearing on stderr
223 # env.pop('PYTHONWARNINGS', None) # Avoid extraneous warnings appearing on stderr
224 for k, v in env.items():
224 for k, v in env.items():
225 # Debug a bizarre failure we've seen on Windows:
225 # Debug a bizarre failure we've seen on Windows:
226 # TypeError: environment can only contain strings
226 # TypeError: environment can only contain strings
227 if not isinstance(v, str):
227 if not isinstance(v, str):
228 print(k, v)
228 print(k, v)
229 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, env=env)
229 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, env=env)
230 out, err = p.communicate(input=py3compat.str_to_bytes('\n'.join(commands)) or None)
230 out, err = p.communicate(input=py3compat.str_to_bytes('\n'.join(commands)) or None)
231 out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
231 out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
232 # `import readline` causes 'ESC[?1034h' to be output sometimes,
232 # `import readline` causes 'ESC[?1034h' to be output sometimes,
233 # so strip that out before doing comparisons
233 # so strip that out before doing comparisons
234 if out:
234 if out:
235 out = re.sub(r'\x1b\[[^h]+h', '', out)
235 out = re.sub(r'\x1b\[[^h]+h', '', out)
236 return out, err
236 return out, err
237
237
238
238
239 def ipexec_validate(fname, expected_out, expected_err='',
239 def ipexec_validate(fname, expected_out, expected_err='',
240 options=None, commands=()):
240 options=None, commands=()):
241 """Utility to call 'ipython filename' and validate output/error.
241 """Utility to call 'ipython filename' and validate output/error.
242
242
243 This function raises an AssertionError if the validation fails.
243 This function raises an AssertionError if the validation fails.
244
244
245 Note that this starts IPython in a subprocess!
245 Note that this starts IPython in a subprocess!
246
246
247 Parameters
247 Parameters
248 ----------
248 ----------
249 fname : str
249 fname : str
250 Name of the file to be executed (should have .py or .ipy extension).
250 Name of the file to be executed (should have .py or .ipy extension).
251
251
252 expected_out : str
252 expected_out : str
253 Expected stdout of the process.
253 Expected stdout of the process.
254
254
255 expected_err : optional, str
255 expected_err : optional, str
256 Expected stderr of the process.
256 Expected stderr of the process.
257
257
258 options : optional, list
258 options : optional, list
259 Extra command-line flags to be passed to IPython.
259 Extra command-line flags to be passed to IPython.
260
260
261 Returns
261 Returns
262 -------
262 -------
263 None
263 None
264 """
264 """
265
265
266 import nose.tools as nt
266 import nose.tools as nt
267
267
268 out, err = ipexec(fname, options, commands)
268 out, err = ipexec(fname, options, commands)
269 #print 'OUT', out # dbg
269 #print 'OUT', out # dbg
270 #print 'ERR', err # dbg
270 #print 'ERR', err # dbg
271 # If there are any errors, we must check those befor stdout, as they may be
271 # If there are any errors, we must check those befor stdout, as they may be
272 # more informative than simply having an empty stdout.
272 # more informative than simply having an empty stdout.
273 if err:
273 if err:
274 if expected_err:
274 if expected_err:
275 nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
275 nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
276 else:
276 else:
277 raise ValueError('Running file %r produced error: %r' %
277 raise ValueError('Running file %r produced error: %r' %
278 (fname, err))
278 (fname, err))
279 # If no errors or output on stderr was expected, match stdout
279 # If no errors or output on stderr was expected, match stdout
280 nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
280 nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
281
281
282
282
283 class TempFileMixin(object):
283 class TempFileMixin(object):
284 """Utility class to create temporary Python/IPython files.
284 """Utility class to create temporary Python/IPython files.
285
285
286 Meant as a mixin class for test cases."""
286 Meant as a mixin class for test cases."""
287
287
288 def mktmp(self, src, ext='.py'):
288 def mktmp(self, src, ext='.py'):
289 """Make a valid python temp file."""
289 """Make a valid python temp file."""
290 fname, f = temp_pyfile(src, ext)
290 fname, f = temp_pyfile(src, ext)
291 self.tmpfile = f
291 self.tmpfile = f
292 self.fname = fname
292 self.fname = fname
293
293
294 def tearDown(self):
294 def tearDown(self):
295 if hasattr(self, 'tmpfile'):
295 if hasattr(self, 'tmpfile'):
296 # If the tmpfile wasn't made because of skipped tests, like in
296 # If the tmpfile wasn't made because of skipped tests, like in
297 # win32, there's nothing to cleanup.
297 # win32, there's nothing to cleanup.
298 self.tmpfile.close()
298 self.tmpfile.close()
299 try:
299 try:
300 os.unlink(self.fname)
300 os.unlink(self.fname)
301 except:
301 except:
302 # On Windows, even though we close the file, we still can't
302 # On Windows, even though we close the file, we still can't
303 # delete it. I have no clue why
303 # delete it. I have no clue why
304 pass
304 pass
305
305
306 pair_fail_msg = ("Testing {0}\n\n"
306 pair_fail_msg = ("Testing {0}\n\n"
307 "In:\n"
307 "In:\n"
308 " {1!r}\n"
308 " {1!r}\n"
309 "Expected:\n"
309 "Expected:\n"
310 " {2!r}\n"
310 " {2!r}\n"
311 "Got:\n"
311 "Got:\n"
312 " {3!r}\n")
312 " {3!r}\n")
313 def check_pairs(func, pairs):
313 def check_pairs(func, pairs):
314 """Utility function for the common case of checking a function with a
314 """Utility function for the common case of checking a function with a
315 sequence of input/output pairs.
315 sequence of input/output pairs.
316
316
317 Parameters
317 Parameters
318 ----------
318 ----------
319 func : callable
319 func : callable
320 The function to be tested. Should accept a single argument.
320 The function to be tested. Should accept a single argument.
321 pairs : iterable
321 pairs : iterable
322 A list of (input, expected_output) tuples.
322 A list of (input, expected_output) tuples.
323
323
324 Returns
324 Returns
325 -------
325 -------
326 None. Raises an AssertionError if any output does not match the expected
326 None. Raises an AssertionError if any output does not match the expected
327 value.
327 value.
328 """
328 """
329 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
329 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
330 for inp, expected in pairs:
330 for inp, expected in pairs:
331 out = func(inp)
331 out = func(inp)
332 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
332 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
333
333
334
334
335 if py3compat.PY3:
335 if py3compat.PY3:
336 MyStringIO = StringIO
336 MyStringIO = StringIO
337 else:
337 else:
338 # In Python 2, stdout/stderr can have either bytes or unicode written to them,
338 # In Python 2, stdout/stderr can have either bytes or unicode written to them,
339 # so we need a class that can handle both.
339 # so we need a class that can handle both.
340 class MyStringIO(StringIO):
340 class MyStringIO(StringIO):
341 def write(self, s):
341 def write(self, s):
342 s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
342 s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
343 super(MyStringIO, self).write(s)
343 super(MyStringIO, self).write(s)
344
344
345 _re_type = type(re.compile(r''))
345 _re_type = type(re.compile(r''))
346
346
347 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
347 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
348 -------
348 -------
349 {2!s}
349 {2!s}
350 -------
350 -------
351 """
351 """
352
352
353 class AssertPrints(object):
353 class AssertPrints(object):
354 """Context manager for testing that code prints certain text.
354 """Context manager for testing that code prints certain text.
355
355
356 Examples
356 Examples
357 --------
357 --------
358 >>> with AssertPrints("abc", suppress=False):
358 >>> with AssertPrints("abc", suppress=False):
359 ... print("abcd")
359 ... print("abcd")
360 ... print("def")
360 ... print("def")
361 ...
361 ...
362 abcd
362 abcd
363 def
363 def
364 """
364 """
365 def __init__(self, s, channel='stdout', suppress=True):
365 def __init__(self, s, channel='stdout', suppress=True):
366 self.s = s
366 self.s = s
367 if isinstance(self.s, (py3compat.string_types, _re_type)):
367 if isinstance(self.s, (py3compat.string_types, _re_type)):
368 self.s = [self.s]
368 self.s = [self.s]
369 self.channel = channel
369 self.channel = channel
370 self.suppress = suppress
370 self.suppress = suppress
371
371
372 def __enter__(self):
372 def __enter__(self):
373 self.orig_stream = getattr(sys, self.channel)
373 self.orig_stream = getattr(sys, self.channel)
374 self.buffer = MyStringIO()
374 self.buffer = MyStringIO()
375 self.tee = Tee(self.buffer, channel=self.channel)
375 self.tee = Tee(self.buffer, channel=self.channel)
376 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
376 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
377
377
378 def __exit__(self, etype, value, traceback):
378 def __exit__(self, etype, value, traceback):
379 try:
379 try:
380 if value is not None:
380 if value is not None:
381 # If an error was raised, don't check anything else
381 # If an error was raised, don't check anything else
382 return False
382 return False
383 self.tee.flush()
383 self.tee.flush()
384 setattr(sys, self.channel, self.orig_stream)
384 setattr(sys, self.channel, self.orig_stream)
385 printed = self.buffer.getvalue()
385 printed = self.buffer.getvalue()
386 for s in self.s:
386 for s in self.s:
387 if isinstance(s, _re_type):
387 if isinstance(s, _re_type):
388 assert s.search(printed), notprinted_msg.format(s.pattern, self.channel, printed)
388 assert s.search(printed), notprinted_msg.format(s.pattern, self.channel, printed)
389 else:
389 else:
390 assert s in printed, notprinted_msg.format(s, self.channel, printed)
390 assert s in printed, notprinted_msg.format(s, self.channel, printed)
391 return False
391 return False
392 finally:
392 finally:
393 self.tee.close()
393 self.tee.close()
394
394
395 printed_msg = """Found {0!r} in printed output (on {1}):
395 printed_msg = """Found {0!r} in printed output (on {1}):
396 -------
396 -------
397 {2!s}
397 {2!s}
398 -------
398 -------
399 """
399 """
400
400
401 class AssertNotPrints(AssertPrints):
401 class AssertNotPrints(AssertPrints):
402 """Context manager for checking that certain output *isn't* produced.
402 """Context manager for checking that certain output *isn't* produced.
403
403
404 Counterpart of AssertPrints"""
404 Counterpart of AssertPrints"""
405 def __exit__(self, etype, value, traceback):
405 def __exit__(self, etype, value, traceback):
406 try:
406 try:
407 if value is not None:
407 if value is not None:
408 # If an error was raised, don't check anything else
408 # If an error was raised, don't check anything else
409 self.tee.close()
409 self.tee.close()
410 return False
410 return False
411 self.tee.flush()
411 self.tee.flush()
412 setattr(sys, self.channel, self.orig_stream)
412 setattr(sys, self.channel, self.orig_stream)
413 printed = self.buffer.getvalue()
413 printed = self.buffer.getvalue()
414 for s in self.s:
414 for s in self.s:
415 if isinstance(s, _re_type):
415 if isinstance(s, _re_type):
416 assert not s.search(printed),printed_msg.format(
416 assert not s.search(printed),printed_msg.format(
417 s.pattern, self.channel, printed)
417 s.pattern, self.channel, printed)
418 else:
418 else:
419 assert s not in printed, printed_msg.format(
419 assert s not in printed, printed_msg.format(
420 s, self.channel, printed)
420 s, self.channel, printed)
421 return False
421 return False
422 finally:
422 finally:
423 self.tee.close()
423 self.tee.close()
424
424
425 @contextmanager
425 @contextmanager
426 def mute_warn():
426 def mute_warn():
427 from IPython.utils import warn
427 from IPython.utils import warn
428 save_warn = warn.warn
428 save_warn = warn.warn
429 warn.warn = lambda *a, **kw: None
429 warn.warn = lambda *a, **kw: None
430 try:
430 try:
431 yield
431 yield
432 finally:
432 finally:
433 warn.warn = save_warn
433 warn.warn = save_warn
434
434
435 @contextmanager
435 @contextmanager
436 def make_tempfile(name):
436 def make_tempfile(name):
437 """ Create an empty, named, temporary file for the duration of the context.
437 """ Create an empty, named, temporary file for the duration of the context.
438 """
438 """
439 f = open(name, 'w')
439 f = open(name, 'w')
440 f.close()
440 f.close()
441 try:
441 try:
442 yield
442 yield
443 finally:
443 finally:
444 os.unlink(name)
444 os.unlink(name)
445
445
446
446
447 def help_output_test(subcommand=''):
447 def help_output_test(subcommand=''):
448 """test that `ipython [subcommand] -h` works"""
448 """test that `ipython [subcommand] -h` works"""
449 cmd = get_ipython_cmd() + [subcommand, '-h']
449 cmd = get_ipython_cmd() + [subcommand, '-h']
450 out, err, rc = get_output_error_code(cmd)
450 out, err, rc = get_output_error_code(cmd)
451 nt.assert_equal(rc, 0, err)
451 nt.assert_equal(rc, 0, err)
452 nt.assert_not_in("Traceback", err)
452 nt.assert_not_in("Traceback", err)
453 nt.assert_in("Options", out)
453 nt.assert_in("Options", out)
454 nt.assert_in("--help-all", out)
454 nt.assert_in("--help-all", out)
455 return out, err
455 return out, err
456
456
457
457
458 def help_all_output_test(subcommand=''):
458 def help_all_output_test(subcommand=''):
459 """test that `ipython [subcommand] --help-all` works"""
459 """test that `ipython [subcommand] --help-all` works"""
460 cmd = get_ipython_cmd() + [subcommand, '--help-all']
460 cmd = get_ipython_cmd() + [subcommand, '--help-all']
461 out, err, rc = get_output_error_code(cmd)
461 out, err, rc = get_output_error_code(cmd)
462 nt.assert_equal(rc, 0, err)
462 nt.assert_equal(rc, 0, err)
463 nt.assert_not_in("Traceback", err)
463 nt.assert_not_in("Traceback", err)
464 nt.assert_in("Options", out)
464 nt.assert_in("Options", out)
465 nt.assert_in("Class parameters", out)
465 nt.assert_in("Class parameters", out)
466 return out, err
466 return out, err
467
467
468 def assert_big_text_equal(a, b, chunk_size=80):
469 """assert that large strings are equal
470
471 Zooms in on first chunk that differs,
472 to give better info than vanilla assertEqual for large text blobs.
473 """
474 for i in range(0, len(a), chunk_size):
475 chunk_a = a[i:i + chunk_size]
476 chunk_b = b[i:i + chunk_size]
477 nt.assert_equal(chunk_a, chunk_b, "[offset: %i]\n%r != \n%r" % (
478 i, chunk_a, chunk_b))
479
480 if len(a) > len(b):
481 nt.fail("Length doesn't match (%i > %i). Extra text:\n%r" % (
482 len(a), len(b), a[len(b):]
483 ))
484 elif len(a) < len(b):
485 nt.fail("Length doesn't match (%i < %i). Extra text:\n%r" % (
486 len(a), len(b), b[len(a):]
487 ))
@@ -1,78 +1,64 b''
1 """Tests for two-process terminal frontend
1 """Tests for two-process terminal frontend"""
2
2
3 Currently only has the most simple test possible, starting a console and running
3 # Copyright (c) Jupyter Development Team.
4 a single command.
4 # Distributed under the terms of the Modified BSD License.
5
6 Authors:
7
8 * Min RK
9 """
10
11 #-----------------------------------------------------------------------------
12 # Imports
13 #-----------------------------------------------------------------------------
14
5
15 import sys
6 import sys
16
7
17 from nose import SkipTest
8 from nose import SkipTest
18
9
19 import IPython.testing.tools as tt
10 from traitlets.tests.utils import check_help_all_output
20 from IPython.testing import decorators as dec
11 from IPython.testing import decorators as dec
21
12
22 #-----------------------------------------------------------------------------
23 # Tests
24 #-----------------------------------------------------------------------------
25
26 @dec.skip_win32
13 @dec.skip_win32
27 def test_console_starts():
14 def test_console_starts():
28 """test that `ipython console` starts a terminal"""
15 """test that `ipython console` starts a terminal"""
29 p, pexpect, t = start_console()
16 p, pexpect, t = start_console()
30 p.sendline('5')
17 p.sendline('5')
31 idx = p.expect([r'Out\[\d+\]: 5', pexpect.EOF], timeout=t)
18 idx = p.expect([r'Out\[\d+\]: 5', pexpect.EOF], timeout=t)
32 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t)
19 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t)
33 stop_console(p, pexpect, t)
20 stop_console(p, pexpect, t)
34
21
35 def test_help_output():
22 def test_help_output():
36 """ipython console --help-all works"""
23 """ipython console --help-all works"""
37 tt.help_all_output_test('console')
24 check_help_all_output('jupyter_console')
38
39
25
40 def test_display_text():
26 def test_display_text():
41 "Ensure display protocol plain/text key is supported"
27 "Ensure display protocol plain/text key is supported"
42 # equivalent of:
28 # equivalent of:
43 #
29 #
44 # x = %lsmagic
30 # x = %lsmagic
45 # from IPython.display import display; display(x);
31 # from IPython.display import display; display(x);
46 p, pexpect, t = start_console()
32 p, pexpect, t = start_console()
47 p.sendline('x = %lsmagic')
33 p.sendline('x = %lsmagic')
48 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t)
34 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t)
49 p.sendline('from IPython.display import display; display(x);')
35 p.sendline('from IPython.display import display; display(x);')
50 p.expect([r'Available line magics:', pexpect.EOF], timeout=t)
36 p.expect([r'Available line magics:', pexpect.EOF], timeout=t)
51 stop_console(p, pexpect, t)
37 stop_console(p, pexpect, t)
52
38
53 def stop_console(p, pexpect, t):
39 def stop_console(p, pexpect, t):
54 "Stop a running `ipython console` running via pexpect"
40 "Stop a running `ipython console` running via pexpect"
55 # send ctrl-D;ctrl-D to exit
41 # send ctrl-D;ctrl-D to exit
56 p.sendeof()
42 p.sendeof()
57 p.sendeof()
43 p.sendeof()
58 p.expect([pexpect.EOF, pexpect.TIMEOUT], timeout=t)
44 p.expect([pexpect.EOF, pexpect.TIMEOUT], timeout=t)
59 if p.isalive():
45 if p.isalive():
60 p.terminate()
46 p.terminate()
61
47
62
48
63 def start_console():
49 def start_console():
64 "Start `ipython console` using pexpect"
50 "Start `ipython console` using pexpect"
65 import pexpect
51 import pexpect
66
52
67 args = ['-m', 'IPython', 'console', '--colors=NoColor']
53 args = ['-m', 'IPython', 'console', '--colors=NoColor']
68 cmd = sys.executable
54 cmd = sys.executable
69
55
70 try:
56 try:
71 p = pexpect.spawn(cmd, args=args)
57 p = pexpect.spawn(cmd, args=args)
72 except IOError:
58 except IOError:
73 raise SkipTest("Couldn't find command %s" % cmd)
59 raise SkipTest("Couldn't find command %s" % cmd)
74
60
75 # timeout after one minute
61 # timeout after one minute
76 t = 60
62 t = 60
77 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t)
63 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t)
78 return p, pexpect, t
64 return p, pexpect, t
@@ -1,95 +1,94 b''
1 # Copyright (c) IPython Development Team.
1 # Copyright (c) IPython Development Team.
2 # Distributed under the terms of the Modified BSD License.
2 # Distributed under the terms of the Modified BSD License.
3
3
4 import os
4 import os
5 import sys
5 import sys
6 import unittest
6 import unittest
7 import base64
7 import base64
8
8
9 try:
9 try:
10 from unittest.mock import patch
10 from unittest.mock import patch
11 except ImportError:
11 except ImportError:
12 from mock import patch
12 from mock import patch
13
13
14 from IPython.kernel import KernelClient
14 from IPython.kernel import KernelClient
15 from IPython.terminal.console.interactiveshell import ZMQTerminalInteractiveShell
15 from IPython.terminal.console.interactiveshell import ZMQTerminalInteractiveShell
16 from IPython.utils.tempdir import TemporaryDirectory
16 from IPython.utils.tempdir import TemporaryDirectory
17 from IPython.testing.tools import monkeypatch
18 from IPython.testing.decorators import skip_without
17 from IPython.testing.decorators import skip_without
19 from IPython.utils.ipstruct import Struct
18 from IPython.utils.ipstruct import Struct
20
19
21
20
22 SCRIPT_PATH = os.path.join(
21 SCRIPT_PATH = os.path.join(
23 os.path.abspath(os.path.dirname(__file__)), 'writetofile.py')
22 os.path.abspath(os.path.dirname(__file__)), 'writetofile.py')
24
23
25
24
26 class ZMQTerminalInteractiveShellTestCase(unittest.TestCase):
25 class ZMQTerminalInteractiveShellTestCase(unittest.TestCase):
27
26
28 def setUp(self):
27 def setUp(self):
29 client = KernelClient()
28 client = KernelClient()
30 self.shell = ZMQTerminalInteractiveShell(kernel_client=client)
29 self.shell = ZMQTerminalInteractiveShell(kernel_client=client)
31 self.raw = b'dummy data'
30 self.raw = b'dummy data'
32 self.mime = 'image/png'
31 self.mime = 'image/png'
33 self.data = {self.mime: base64.encodestring(self.raw).decode('ascii')}
32 self.data = {self.mime: base64.encodestring(self.raw).decode('ascii')}
34
33
35 def test_no_call_by_default(self):
34 def test_no_call_by_default(self):
36 def raise_if_called(*args, **kwds):
35 def raise_if_called(*args, **kwds):
37 assert False
36 assert False
38
37
39 shell = self.shell
38 shell = self.shell
40 shell.handle_image_PIL = raise_if_called
39 shell.handle_image_PIL = raise_if_called
41 shell.handle_image_stream = raise_if_called
40 shell.handle_image_stream = raise_if_called
42 shell.handle_image_tempfile = raise_if_called
41 shell.handle_image_tempfile = raise_if_called
43 shell.handle_image_callable = raise_if_called
42 shell.handle_image_callable = raise_if_called
44
43
45 shell.handle_image(None, None) # arguments are dummy
44 shell.handle_image(None, None) # arguments are dummy
46
45
47 @skip_without('PIL')
46 @skip_without('PIL')
48 def test_handle_image_PIL(self):
47 def test_handle_image_PIL(self):
49 import PIL.Image
48 import PIL.Image
50
49
51 open_called_with = []
50 open_called_with = []
52 show_called_with = []
51 show_called_with = []
53
52
54 def fake_open(arg):
53 def fake_open(arg):
55 open_called_with.append(arg)
54 open_called_with.append(arg)
56 return Struct(show=lambda: show_called_with.append(None))
55 return Struct(show=lambda: show_called_with.append(None))
57
56
58 with patch.object(PIL.Image, 'open', fake_open):
57 with patch.object(PIL.Image, 'open', fake_open):
59 self.shell.handle_image_PIL(self.data, self.mime)
58 self.shell.handle_image_PIL(self.data, self.mime)
60
59
61 self.assertEqual(len(open_called_with), 1)
60 self.assertEqual(len(open_called_with), 1)
62 self.assertEqual(len(show_called_with), 1)
61 self.assertEqual(len(show_called_with), 1)
63 self.assertEqual(open_called_with[0].getvalue(), self.raw)
62 self.assertEqual(open_called_with[0].getvalue(), self.raw)
64
63
65 def check_handler_with_file(self, inpath, handler):
64 def check_handler_with_file(self, inpath, handler):
66 shell = self.shell
65 shell = self.shell
67 configname = '{0}_image_handler'.format(handler)
66 configname = '{0}_image_handler'.format(handler)
68 funcname = 'handle_image_{0}'.format(handler)
67 funcname = 'handle_image_{0}'.format(handler)
69
68
70 assert hasattr(shell, configname)
69 assert hasattr(shell, configname)
71 assert hasattr(shell, funcname)
70 assert hasattr(shell, funcname)
72
71
73 with TemporaryDirectory() as tmpdir:
72 with TemporaryDirectory() as tmpdir:
74 outpath = os.path.join(tmpdir, 'data')
73 outpath = os.path.join(tmpdir, 'data')
75 cmd = [sys.executable, SCRIPT_PATH, inpath, outpath]
74 cmd = [sys.executable, SCRIPT_PATH, inpath, outpath]
76 setattr(shell, configname, cmd)
75 setattr(shell, configname, cmd)
77 getattr(shell, funcname)(self.data, self.mime)
76 getattr(shell, funcname)(self.data, self.mime)
78 # cmd is called and file is closed. So it's safe to open now.
77 # cmd is called and file is closed. So it's safe to open now.
79 with open(outpath, 'rb') as file:
78 with open(outpath, 'rb') as file:
80 transferred = file.read()
79 transferred = file.read()
81
80
82 self.assertEqual(transferred, self.raw)
81 self.assertEqual(transferred, self.raw)
83
82
84 def test_handle_image_stream(self):
83 def test_handle_image_stream(self):
85 self.check_handler_with_file('-', 'stream')
84 self.check_handler_with_file('-', 'stream')
86
85
87 def test_handle_image_tempfile(self):
86 def test_handle_image_tempfile(self):
88 self.check_handler_with_file('{file}', 'tempfile')
87 self.check_handler_with_file('{file}', 'tempfile')
89
88
90 def test_handle_image_callable(self):
89 def test_handle_image_callable(self):
91 called_with = []
90 called_with = []
92 self.shell.callable_image_handler = called_with.append
91 self.shell.callable_image_handler = called_with.append
93 self.shell.handle_image_callable(self.data, self.mime)
92 self.shell.handle_image_callable(self.data, self.mime)
94 self.assertEqual(len(called_with), 1)
93 self.assertEqual(len(called_with), 1)
95 assert called_with[0] is self.data
94 assert called_with[0] is self.data
@@ -1,39 +1,39 b''
1 """Tests for notebook.py"""
1 """Tests for notebook.py"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import json
6 import json
7
7
8 from .base import ExportersTestsBase
8 from .base import ExportersTestsBase
9 from ..notebook import NotebookExporter
9 from ..notebook import NotebookExporter
10
10
11 from IPython.nbformat import validate
11 from IPython.nbformat import validate
12 from IPython.testing.tools import assert_big_text_equal
12 from jupyter_nbconvert.tests.base import assert_big_text_equal
13
13
14 class TestNotebookExporter(ExportersTestsBase):
14 class TestNotebookExporter(ExportersTestsBase):
15 """Contains test functions for notebook.py"""
15 """Contains test functions for notebook.py"""
16
16
17 exporter_class = NotebookExporter
17 exporter_class = NotebookExporter
18
18
19 def test_export(self):
19 def test_export(self):
20 """
20 """
21 Does the NotebookExporter return the file unchanged?
21 Does the NotebookExporter return the file unchanged?
22 """
22 """
23 with open(self._get_notebook()) as f:
23 with open(self._get_notebook()) as f:
24 file_contents = f.read()
24 file_contents = f.read()
25 (output, resources) = self.exporter_class().from_filename(self._get_notebook())
25 (output, resources) = self.exporter_class().from_filename(self._get_notebook())
26 assert len(output) > 0
26 assert len(output) > 0
27 assert_big_text_equal(output.strip(), file_contents.strip())
27 assert_big_text_equal(output.strip(), file_contents.strip())
28
28
29 def test_downgrade_3(self):
29 def test_downgrade_3(self):
30 exporter = self.exporter_class(nbformat_version=3)
30 exporter = self.exporter_class(nbformat_version=3)
31 (output, resources) = exporter.from_filename(self._get_notebook())
31 (output, resources) = exporter.from_filename(self._get_notebook())
32 nb = json.loads(output)
32 nb = json.loads(output)
33 validate(nb)
33 validate(nb)
34
34
35 def test_downgrade_2(self):
35 def test_downgrade_2(self):
36 exporter = self.exporter_class(nbformat_version=2)
36 exporter = self.exporter_class(nbformat_version=2)
37 (output, resources) = exporter.from_filename(self._get_notebook())
37 (output, resources) = exporter.from_filename(self._get_notebook())
38 nb = json.loads(output)
38 nb = json.loads(output)
39 self.assertEqual(nb['nbformat'], 2)
39 self.assertEqual(nb['nbformat'], 2)
@@ -1,145 +1,168 b''
1 """Base test class for nbconvert"""
1 """Base test class for nbconvert"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import io
6 import io
7 import os
7 import os
8 import glob
8 import glob
9 import shlex
9 import shutil
10 import shutil
11 import sys
10 import unittest
12 import unittest
11
13
14 import nose.tools as nt
15
12 from IPython.nbformat import v4, write
16 from IPython.nbformat import v4, write
13 from IPython.utils.tempdir import TemporaryWorkingDirectory
17 from IPython.utils.tempdir import TemporaryWorkingDirectory
14 from IPython.utils.process import get_output_error_code
18 from IPython.utils.process import get_output_error_code
15 from IPython.testing.tools import get_ipython_cmd
19 from IPython.utils.py3compat import string_types
16
17 # a trailing space allows for simpler concatenation with the other arguments
18 ipy_cmd = get_ipython_cmd(as_string=True) + " "
19
20
20
21 class TestsBase(unittest.TestCase):
21 class TestsBase(unittest.TestCase):
22 """Base tests class. Contains useful fuzzy comparison and nbconvert
22 """Base tests class. Contains useful fuzzy comparison and nbconvert
23 functions."""
23 functions."""
24
24
25
25
26 def fuzzy_compare(self, a, b, newlines_are_spaces=True, tabs_are_spaces=True,
26 def fuzzy_compare(self, a, b, newlines_are_spaces=True, tabs_are_spaces=True,
27 fuzzy_spacing=True, ignore_spaces=False,
27 fuzzy_spacing=True, ignore_spaces=False,
28 ignore_newlines=False, case_sensitive=False, leave_padding=False):
28 ignore_newlines=False, case_sensitive=False, leave_padding=False):
29 """
29 """
30 Performs a fuzzy comparison of two strings. A fuzzy comparison is a
30 Performs a fuzzy comparison of two strings. A fuzzy comparison is a
31 comparison that ignores insignificant differences in the two comparands.
31 comparison that ignores insignificant differences in the two comparands.
32 The significance of certain differences can be specified via the keyword
32 The significance of certain differences can be specified via the keyword
33 parameters of this method.
33 parameters of this method.
34 """
34 """
35
35
36 if not leave_padding:
36 if not leave_padding:
37 a = a.strip()
37 a = a.strip()
38 b = b.strip()
38 b = b.strip()
39
39
40 if ignore_newlines:
40 if ignore_newlines:
41 a = a.replace('\n', '')
41 a = a.replace('\n', '')
42 b = b.replace('\n', '')
42 b = b.replace('\n', '')
43
43
44 if newlines_are_spaces:
44 if newlines_are_spaces:
45 a = a.replace('\n', ' ')
45 a = a.replace('\n', ' ')
46 b = b.replace('\n', ' ')
46 b = b.replace('\n', ' ')
47
47
48 if tabs_are_spaces:
48 if tabs_are_spaces:
49 a = a.replace('\t', ' ')
49 a = a.replace('\t', ' ')
50 b = b.replace('\t', ' ')
50 b = b.replace('\t', ' ')
51
51
52 if ignore_spaces:
52 if ignore_spaces:
53 a = a.replace(' ', '')
53 a = a.replace(' ', '')
54 b = b.replace(' ', '')
54 b = b.replace(' ', '')
55
55
56 if fuzzy_spacing:
56 if fuzzy_spacing:
57 a = self.recursive_replace(a, ' ', ' ')
57 a = self.recursive_replace(a, ' ', ' ')
58 b = self.recursive_replace(b, ' ', ' ')
58 b = self.recursive_replace(b, ' ', ' ')
59
59
60 if not case_sensitive:
60 if not case_sensitive:
61 a = a.lower()
61 a = a.lower()
62 b = b.lower()
62 b = b.lower()
63
63
64 self.assertEqual(a, b)
64 self.assertEqual(a, b)
65
65
66
66
67 def recursive_replace(self, text, search, replacement):
67 def recursive_replace(self, text, search, replacement):
68 """
68 """
69 Performs a recursive replacement operation. Replaces all instances
69 Performs a recursive replacement operation. Replaces all instances
70 of a search string in a text string with a replacement string until
70 of a search string in a text string with a replacement string until
71 the search string no longer exists. Recursion is needed because the
71 the search string no longer exists. Recursion is needed because the
72 replacement string may generate additional search strings.
72 replacement string may generate additional search strings.
73
73
74 For example:
74 For example:
75 Replace "ii" with "i" in the string "Hiiii" yields "Hii"
75 Replace "ii" with "i" in the string "Hiiii" yields "Hii"
76 Another replacement cds "Hi" (the desired output)
76 Another replacement cds "Hi" (the desired output)
77
77
78 Parameters
78 Parameters
79 ----------
79 ----------
80 text : string
80 text : string
81 Text to replace in.
81 Text to replace in.
82 search : string
82 search : string
83 String to search for within "text"
83 String to search for within "text"
84 replacement : string
84 replacement : string
85 String to replace "search" with
85 String to replace "search" with
86 """
86 """
87 while search in text:
87 while search in text:
88 text = text.replace(search, replacement)
88 text = text.replace(search, replacement)
89 return text
89 return text
90
90
91 def create_temp_cwd(self, copy_filenames=None):
91 def create_temp_cwd(self, copy_filenames=None):
92 temp_dir = TemporaryWorkingDirectory()
92 temp_dir = TemporaryWorkingDirectory()
93
93
94 #Copy the files if requested.
94 #Copy the files if requested.
95 if copy_filenames is not None:
95 if copy_filenames is not None:
96 self.copy_files_to(copy_filenames, dest=temp_dir.name)
96 self.copy_files_to(copy_filenames, dest=temp_dir.name)
97
97
98 #Return directory handler
98 #Return directory handler
99 return temp_dir
99 return temp_dir
100
100
101 def create_empty_notebook(self, path):
101 def create_empty_notebook(self, path):
102 nb = v4.new_notebook()
102 nb = v4.new_notebook()
103 with io.open(path, 'w', encoding='utf-8') as f:
103 with io.open(path, 'w', encoding='utf-8') as f:
104 write(nb, f, 4)
104 write(nb, f, 4)
105
105
106 def copy_files_to(self, copy_filenames, dest='.'):
106 def copy_files_to(self, copy_filenames, dest='.'):
107 "Copy test files into the destination directory"
107 "Copy test files into the destination directory"
108 if not os.path.isdir(dest):
108 if not os.path.isdir(dest):
109 os.makedirs(dest)
109 os.makedirs(dest)
110 files_path = self._get_files_path()
110 files_path = self._get_files_path()
111 for pattern in copy_filenames:
111 for pattern in copy_filenames:
112 for match in glob.glob(os.path.join(files_path, pattern)):
112 for match in glob.glob(os.path.join(files_path, pattern)):
113 shutil.copyfile(match, os.path.join(dest, os.path.basename(match)))
113 shutil.copyfile(match, os.path.join(dest, os.path.basename(match)))
114
114
115
115
116 def _get_files_path(self):
116 def _get_files_path(self):
117
117
118 #Get the relative path to this module in the IPython directory.
118 #Get the relative path to this module in the IPython directory.
119 names = self.__module__.split('.')[1:-1]
119 names = self.__module__.split('.')[1:-1]
120 names.append('files')
120 names.append('files')
121
121
122 #Build a path using the nbconvert directory and the relative path we just
122 #Build a path using the nbconvert directory and the relative path we just
123 #found.
123 #found.
124 import jupyter_nbconvert
124 import jupyter_nbconvert
125 path = os.path.dirname(jupyter_nbconvert.__file__)
125 path = os.path.dirname(jupyter_nbconvert.__file__)
126 return os.path.join(path, *names)
126 return os.path.join(path, *names)
127
127
128
128
129 def call(self, parameters, ignore_return_code=False):
129 def nbconvert(self, parameters, ignore_return_code=False):
130 """
130 """
131 Execute a, IPython shell command, listening for both Errors and non-zero
131 Run nbconvert a, IPython shell command, listening for both Errors and non-zero
132 return codes.
132 return codes.
133
133
134 Parameters
134 Parameters
135 ----------
135 ----------
136 parameters : str
136 parameters : str, list(str)
137 List of parameters to pass to IPython.
137 List of parameters to pass to IPython.
138 ignore_return_code : optional bool (default False)
138 ignore_return_code : optional bool (default False)
139 Throw an OSError if the return code
139 Throw an OSError if the return code
140 """
140 """
141
141 if isinstance(parameters, string_types):
142 stdout, stderr, retcode = get_output_error_code(ipy_cmd + parameters)
142 parameters = shlex.split(parameters)
143 cmd = [sys.executable, '-m', 'jupyter_nbconvert'] + parameters
144 stdout, stderr, retcode = get_output_error_code(cmd)
143 if not (retcode == 0 or ignore_return_code):
145 if not (retcode == 0 or ignore_return_code):
144 raise OSError(stderr)
146 raise OSError(stderr)
145 return stdout, stderr
147 return stdout, stderr
148
149 def assert_big_text_equal(a, b, chunk_size=80):
150 """assert that large strings are equal
151
152 Zooms in on first chunk that differs,
153 to give better info than vanilla assertEqual for large text blobs.
154 """
155 for i in range(0, len(a), chunk_size):
156 chunk_a = a[i:i + chunk_size]
157 chunk_b = b[i:i + chunk_size]
158 nt.assert_equal(chunk_a, chunk_b, "[offset: %i]\n%r != \n%r" % (
159 i, chunk_a, chunk_b))
160
161 if len(a) > len(b):
162 nt.fail("Length doesn't match (%i > %i). Extra text:\n%r" % (
163 len(a), len(b), a[len(b):]
164 ))
165 elif len(a) < len(b):
166 nt.fail("Length doesn't match (%i < %i). Extra text:\n%r" % (
167 len(a), len(b), b[len(a):]
168 ))
@@ -1,243 +1,243 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Test NbConvertApp"""
2 """Test NbConvertApp"""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 import glob
8 import glob
9 import sys
9 import sys
10
10
11 from .base import TestsBase
11 from .base import TestsBase
12 from ..postprocessors import PostProcessorBase
12 from ..postprocessors import PostProcessorBase
13
13
14 import IPython.testing.tools as tt
14 from traitlets.tests.utils import check_help_all_output
15 from IPython.testing import decorators as dec
15 from IPython.testing import decorators as dec
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Classes and functions
18 # Classes and functions
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 class DummyPost(PostProcessorBase):
21 class DummyPost(PostProcessorBase):
22 def postprocess(self, filename):
22 def postprocess(self, filename):
23 print("Dummy:%s" % filename)
23 print("Dummy:%s" % filename)
24
24
25 class TestNbConvertApp(TestsBase):
25 class TestNbConvertApp(TestsBase):
26 """Collection of NbConvertApp tests"""
26 """Collection of NbConvertApp tests"""
27
27
28
28
29 def test_notebook_help(self):
29 def test_notebook_help(self):
30 """Will help show if no notebooks are specified?"""
30 """Will help show if no notebooks are specified?"""
31 with self.create_temp_cwd():
31 with self.create_temp_cwd():
32 out, err = self.call('nbconvert --log-level 0', ignore_return_code=True)
32 out, err = self.nbconvert('--log-level 0', ignore_return_code=True)
33 self.assertIn("see '--help-all'", out)
33 self.assertIn("see '--help-all'", out)
34
34
35 def test_help_output(self):
35 def test_help_output(self):
36 """ipython nbconvert --help-all works"""
36 """ipython nbconvert --help-all works"""
37 tt.help_all_output_test('nbconvert')
37 check_help_all_output('jupyter_nbconvert')
38
38
39 def test_glob(self):
39 def test_glob(self):
40 """
40 """
41 Do search patterns work for notebook names?
41 Do search patterns work for notebook names?
42 """
42 """
43 with self.create_temp_cwd(['notebook*.ipynb']):
43 with self.create_temp_cwd(['notebook*.ipynb']):
44 self.call('nbconvert --to python *.ipynb --log-level 0')
44 self.nbconvert('--to python *.ipynb --log-level 0')
45 assert os.path.isfile('notebook1.py')
45 assert os.path.isfile('notebook1.py')
46 assert os.path.isfile('notebook2.py')
46 assert os.path.isfile('notebook2.py')
47
47
48
48
49 def test_glob_subdir(self):
49 def test_glob_subdir(self):
50 """
50 """
51 Do search patterns work for subdirectory notebook names?
51 Do search patterns work for subdirectory notebook names?
52 """
52 """
53 with self.create_temp_cwd():
53 with self.create_temp_cwd():
54 self.copy_files_to(['notebook*.ipynb'], 'subdir/')
54 self.copy_files_to(['notebook*.ipynb'], 'subdir/')
55 self.call('nbconvert --to python --log-level 0 ' +
55 self.nbconvert('--to python --log-level 0 ' +
56 os.path.join('subdir', '*.ipynb'))
56 os.path.join('subdir', '*.ipynb'))
57 assert os.path.isfile('notebook1.py')
57 assert os.path.isfile('notebook1.py')
58 assert os.path.isfile('notebook2.py')
58 assert os.path.isfile('notebook2.py')
59
59
60
60
61 def test_explicit(self):
61 def test_explicit(self):
62 """
62 """
63 Do explicit notebook names work?
63 Do explicit notebook names work?
64 """
64 """
65 with self.create_temp_cwd(['notebook*.ipynb']):
65 with self.create_temp_cwd(['notebook*.ipynb']):
66 self.call('nbconvert --log-level 0 --to python notebook2')
66 self.nbconvert('--log-level 0 --to python notebook2')
67 assert not os.path.isfile('notebook1.py')
67 assert not os.path.isfile('notebook1.py')
68 assert os.path.isfile('notebook2.py')
68 assert os.path.isfile('notebook2.py')
69
69
70
70
71 @dec.onlyif_cmds_exist('pdflatex')
71 @dec.onlyif_cmds_exist('pdflatex')
72 @dec.onlyif_cmds_exist('pandoc')
72 @dec.onlyif_cmds_exist('pandoc')
73 def test_filename_spaces(self):
73 def test_filename_spaces(self):
74 """
74 """
75 Generate PDFs with graphics if notebooks have spaces in the name?
75 Generate PDFs with graphics if notebooks have spaces in the name?
76 """
76 """
77 with self.create_temp_cwd(['notebook2.ipynb']):
77 with self.create_temp_cwd(['notebook2.ipynb']):
78 os.rename('notebook2.ipynb', 'notebook with spaces.ipynb')
78 os.rename('notebook2.ipynb', 'notebook with spaces.ipynb')
79 self.call('nbconvert --log-level 0 --to pdf'
79 self.nbconvert('--log-level 0 --to pdf'
80 ' "notebook with spaces"'
80 ' "notebook with spaces"'
81 ' --PDFExporter.latex_count=1'
81 ' --PDFExporter.latex_count=1'
82 ' --PDFExporter.verbose=True'
82 ' --PDFExporter.verbose=True'
83 )
83 )
84 assert os.path.isfile('notebook with spaces.pdf')
84 assert os.path.isfile('notebook with spaces.pdf')
85
85
86 def test_post_processor(self):
86 def test_post_processor(self):
87 """Do post processors work?"""
87 """Do post processors work?"""
88 with self.create_temp_cwd(['notebook1.ipynb']):
88 with self.create_temp_cwd(['notebook1.ipynb']):
89 out, err = self.call('nbconvert --log-level 0 --to python notebook1 '
89 out, err = self.nbconvert('--log-level 0 --to python notebook1 '
90 '--post jupyter_nbconvert.tests.test_nbconvertapp.DummyPost')
90 '--post jupyter_nbconvert.tests.test_nbconvertapp.DummyPost')
91 self.assertIn('Dummy:notebook1.py', out)
91 self.assertIn('Dummy:notebook1.py', out)
92
92
93 @dec.onlyif_cmds_exist('pandoc')
93 @dec.onlyif_cmds_exist('pandoc')
94 def test_spurious_cr(self):
94 def test_spurious_cr(self):
95 """Check for extra CR characters"""
95 """Check for extra CR characters"""
96 with self.create_temp_cwd(['notebook2.ipynb']):
96 with self.create_temp_cwd(['notebook2.ipynb']):
97 self.call('nbconvert --log-level 0 --to latex notebook2')
97 self.nbconvert('--log-level 0 --to latex notebook2')
98 assert os.path.isfile('notebook2.tex')
98 assert os.path.isfile('notebook2.tex')
99 with open('notebook2.tex') as f:
99 with open('notebook2.tex') as f:
100 tex = f.read()
100 tex = f.read()
101 self.call('nbconvert --log-level 0 --to html notebook2')
101 self.nbconvert('--log-level 0 --to html notebook2')
102 assert os.path.isfile('notebook2.html')
102 assert os.path.isfile('notebook2.html')
103 with open('notebook2.html') as f:
103 with open('notebook2.html') as f:
104 html = f.read()
104 html = f.read()
105 self.assertEqual(tex.count('\r'), tex.count('\r\n'))
105 self.assertEqual(tex.count('\r'), tex.count('\r\n'))
106 self.assertEqual(html.count('\r'), html.count('\r\n'))
106 self.assertEqual(html.count('\r'), html.count('\r\n'))
107
107
108 @dec.onlyif_cmds_exist('pandoc')
108 @dec.onlyif_cmds_exist('pandoc')
109 def test_png_base64_html_ok(self):
109 def test_png_base64_html_ok(self):
110 """Is embedded png data well formed in HTML?"""
110 """Is embedded png data well formed in HTML?"""
111 with self.create_temp_cwd(['notebook2.ipynb']):
111 with self.create_temp_cwd(['notebook2.ipynb']):
112 self.call('nbconvert --log-level 0 --to HTML '
112 self.nbconvert('--log-level 0 --to HTML '
113 'notebook2.ipynb --template full')
113 'notebook2.ipynb --template full')
114 assert os.path.isfile('notebook2.html')
114 assert os.path.isfile('notebook2.html')
115 with open('notebook2.html') as f:
115 with open('notebook2.html') as f:
116 assert "data:image/png;base64,b'" not in f.read()
116 assert "data:image/png;base64,b'" not in f.read()
117
117
118 @dec.onlyif_cmds_exist('pandoc')
118 @dec.onlyif_cmds_exist('pandoc')
119 def test_template(self):
119 def test_template(self):
120 """
120 """
121 Do export templates work?
121 Do export templates work?
122 """
122 """
123 with self.create_temp_cwd(['notebook2.ipynb']):
123 with self.create_temp_cwd(['notebook2.ipynb']):
124 self.call('nbconvert --log-level 0 --to slides '
124 self.nbconvert('--log-level 0 --to slides '
125 'notebook2.ipynb')
125 'notebook2.ipynb')
126 assert os.path.isfile('notebook2.slides.html')
126 assert os.path.isfile('notebook2.slides.html')
127 with open('notebook2.slides.html') as f:
127 with open('notebook2.slides.html') as f:
128 assert '/reveal.css' in f.read()
128 assert '/reveal.css' in f.read()
129
129
130 def test_output_ext(self):
130 def test_output_ext(self):
131 """test --output=outputfile[.ext]"""
131 """test --output=outputfile[.ext]"""
132 with self.create_temp_cwd(['notebook1.ipynb']):
132 with self.create_temp_cwd(['notebook1.ipynb']):
133 self.call('nbconvert --log-level 0 --to python '
133 self.nbconvert('--log-level 0 --to python '
134 'notebook1.ipynb --output nb.py')
134 'notebook1.ipynb --output nb.py')
135 assert os.path.exists('nb.py')
135 assert os.path.exists('nb.py')
136
136
137 self.call('nbconvert --log-level 0 --to python '
137 self.nbconvert('--log-level 0 --to python '
138 'notebook1.ipynb --output nb2')
138 'notebook1.ipynb --output nb2')
139 assert os.path.exists('nb2.py')
139 assert os.path.exists('nb2.py')
140
140
141 def test_glob_explicit(self):
141 def test_glob_explicit(self):
142 """
142 """
143 Can a search pattern be used along with matching explicit notebook names?
143 Can a search pattern be used along with matching explicit notebook names?
144 """
144 """
145 with self.create_temp_cwd(['notebook*.ipynb']):
145 with self.create_temp_cwd(['notebook*.ipynb']):
146 self.call('nbconvert --log-level 0 --to python '
146 self.nbconvert('--log-level 0 --to python '
147 '*.ipynb notebook1.ipynb notebook2.ipynb')
147 '*.ipynb notebook1.ipynb notebook2.ipynb')
148 assert os.path.isfile('notebook1.py')
148 assert os.path.isfile('notebook1.py')
149 assert os.path.isfile('notebook2.py')
149 assert os.path.isfile('notebook2.py')
150
150
151
151
152 def test_explicit_glob(self):
152 def test_explicit_glob(self):
153 """
153 """
154 Can explicit notebook names be used and then a matching search pattern?
154 Can explicit notebook names be used and then a matching search pattern?
155 """
155 """
156 with self.create_temp_cwd(['notebook*.ipynb']):
156 with self.create_temp_cwd(['notebook*.ipynb']):
157 self.call('nbconvert --log-level 0 --to=python '
157 self.nbconvert('--log-level 0 --to=python '
158 'notebook1.ipynb notebook2.ipynb *.ipynb')
158 'notebook1.ipynb notebook2.ipynb *.ipynb')
159 assert os.path.isfile('notebook1.py')
159 assert os.path.isfile('notebook1.py')
160 assert os.path.isfile('notebook2.py')
160 assert os.path.isfile('notebook2.py')
161
161
162
162
163 def test_default_config(self):
163 def test_default_config(self):
164 """
164 """
165 Does the default config work?
165 Does the default config work?
166 """
166 """
167 with self.create_temp_cwd(['notebook*.ipynb', 'ipython_nbconvert_config.py']):
167 with self.create_temp_cwd(['notebook*.ipynb', 'ipython_nbconvert_config.py']):
168 self.call('nbconvert --log-level 0')
168 self.nbconvert('--log-level 0')
169 assert os.path.isfile('notebook1.py')
169 assert os.path.isfile('notebook1.py')
170 assert not os.path.isfile('notebook2.py')
170 assert not os.path.isfile('notebook2.py')
171
171
172
172
173 def test_override_config(self):
173 def test_override_config(self):
174 """
174 """
175 Can the default config be overriden?
175 Can the default config be overriden?
176 """
176 """
177 with self.create_temp_cwd(['notebook*.ipynb',
177 with self.create_temp_cwd(['notebook*.ipynb',
178 'ipython_nbconvert_config.py',
178 'ipython_nbconvert_config.py',
179 'override.py']):
179 'override.py']):
180 self.call('nbconvert --log-level 0 --config="override.py"')
180 self.nbconvert('--log-level 0 --config="override.py"')
181 assert not os.path.isfile('notebook1.py')
181 assert not os.path.isfile('notebook1.py')
182 assert os.path.isfile('notebook2.py')
182 assert os.path.isfile('notebook2.py')
183
183
184 def test_accents_in_filename(self):
184 def test_accents_in_filename(self):
185 """
185 """
186 Can notebook names include accents?
186 Can notebook names include accents?
187 """
187 """
188 with self.create_temp_cwd():
188 with self.create_temp_cwd():
189 self.create_empty_notebook(u'nb1_análisis.ipynb')
189 self.create_empty_notebook(u'nb1_análisis.ipynb')
190 self.call('nbconvert --log-level 0 --to python nb1_*')
190 self.nbconvert('--log-level 0 --to python nb1_*')
191 assert os.path.isfile(u'nb1_análisis.py')
191 assert os.path.isfile(u'nb1_análisis.py')
192
192
193 @dec.onlyif_cmds_exist('pdflatex', 'pandoc')
193 @dec.onlyif_cmds_exist('pdflatex', 'pandoc')
194 def test_filename_accent_pdf(self):
194 def test_filename_accent_pdf(self):
195 """
195 """
196 Generate PDFs if notebooks have an accent in their name?
196 Generate PDFs if notebooks have an accent in their name?
197 """
197 """
198 with self.create_temp_cwd():
198 with self.create_temp_cwd():
199 self.create_empty_notebook(u'nb1_análisis.ipynb')
199 self.create_empty_notebook(u'nb1_análisis.ipynb')
200 self.call('nbconvert --log-level 0 --to pdf "nb1_*"'
200 self.nbconvert('--log-level 0 --to pdf "nb1_*"'
201 ' --PDFExporter.latex_count=1'
201 ' --PDFExporter.latex_count=1'
202 ' --PDFExporter.verbose=True')
202 ' --PDFExporter.verbose=True')
203 assert os.path.isfile(u'nb1_análisis.pdf')
203 assert os.path.isfile(u'nb1_análisis.pdf')
204
204
205 def test_cwd_plugin(self):
205 def test_cwd_plugin(self):
206 """
206 """
207 Verify that an extension in the cwd can be imported.
207 Verify that an extension in the cwd can be imported.
208 """
208 """
209 with self.create_temp_cwd(['hello.py']):
209 with self.create_temp_cwd(['hello.py']):
210 self.create_empty_notebook(u'empty.ipynb')
210 self.create_empty_notebook(u'empty.ipynb')
211 self.call('nbconvert empty --to html --NbConvertApp.writer_class=\'hello.HelloWriter\'')
211 self.nbconvert('empty --to html --NbConvertApp.writer_class=\'hello.HelloWriter\'')
212 assert os.path.isfile(u'hello.txt')
212 assert os.path.isfile(u'hello.txt')
213
213
214 def test_output_suffix(self):
214 def test_output_suffix(self):
215 """
215 """
216 Verify that the output suffix is applied
216 Verify that the output suffix is applied
217 """
217 """
218 with self.create_temp_cwd():
218 with self.create_temp_cwd():
219 self.create_empty_notebook('empty.ipynb')
219 self.create_empty_notebook('empty.ipynb')
220 self.call('nbconvert empty.ipynb --to notebook')
220 self.nbconvert('empty.ipynb --to notebook')
221 assert os.path.isfile('empty.nbconvert.ipynb')
221 assert os.path.isfile('empty.nbconvert.ipynb')
222
222
223 def test_different_build_dir(self):
223 def test_different_build_dir(self):
224 """
224 """
225 Verify that the output suffix is not applied
225 Verify that the output suffix is not applied
226 """
226 """
227 with self.create_temp_cwd():
227 with self.create_temp_cwd():
228 self.create_empty_notebook('empty.ipynb')
228 self.create_empty_notebook('empty.ipynb')
229 os.mkdir('output')
229 os.mkdir('output')
230 self.call(
230 self.nbconvert(
231 'nbconvert empty.ipynb --to notebook '
231 'empty.ipynb --to notebook '
232 '--FilesWriter.build_directory=output')
232 '--FilesWriter.build_directory=output')
233 assert os.path.isfile('output/empty.ipynb')
233 assert os.path.isfile('output/empty.ipynb')
234
234
235 def test_inplace(self):
235 def test_inplace(self):
236 """
236 """
237 Verify that the notebook is converted in place
237 Verify that the notebook is converted in place
238 """
238 """
239 with self.create_temp_cwd():
239 with self.create_temp_cwd():
240 self.create_empty_notebook('empty.ipynb')
240 self.create_empty_notebook('empty.ipynb')
241 self.call('nbconvert empty.ipynb --to notebook --inplace')
241 self.nbconvert('empty.ipynb --to notebook --inplace')
242 assert os.path.isfile('empty.ipynb')
242 assert os.path.isfile('empty.ipynb')
243 assert not os.path.isfile('empty.nbconvert.ipynb')
243 assert not os.path.isfile('empty.nbconvert.ipynb')
@@ -1,27 +1,15 b''
1 """Test QtConsoleApp"""
1 """Test QtConsoleApp"""
2
2
3 #-----------------------------------------------------------------------------
3 # Copyright (c) Jupyter Development Team.
4 # Copyright (C) 2013 The IPython Development Team
4 # Distributed under the terms of the Modified BSD License.
5 #
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
5
14 import nose.tools as nt
6 import nose.tools as nt
15
7
16 import IPython.testing.tools as tt
8 from traitlets.tests.utils import check_help_all_output
17 from IPython.testing.decorators import skip_if_no_x11
9 from IPython.testing.decorators import skip_if_no_x11
18
10
19 #-----------------------------------------------------------------------------
20 # Test functions
21 #-----------------------------------------------------------------------------
22
23 @skip_if_no_x11
11 @skip_if_no_x11
24 def test_help_output():
12 def test_help_output():
25 """ipython qtconsole --help-all works"""
13 """jupyter qtconsole --help-all works"""
26 tt.help_all_output_test('qtconsole')
14 check_help_all_output('jupyter_qtconsole')
27
15
General Comments 0
You need to be logged in to leave comments. Login now