##// END OF EJS Templates
Fix error when overwriting a bad symbolic link installing an nbextension...
Jason Grout -
Show More
@@ -1,350 +1,350 b''
1 1 # coding: utf-8
2 2 """Utilities for installing Javascript extensions for the notebook"""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from __future__ import print_function
8 8
9 9 import os
10 10 import shutil
11 11 import sys
12 12 import tarfile
13 13 import zipfile
14 14 import uuid
15 15 from os.path import basename, join as pjoin
16 16
17 17 # Deferred imports
18 18 try:
19 19 from urllib.parse import urlparse # Py3
20 20 from urllib.request import urlretrieve
21 21 except ImportError:
22 22 from urlparse import urlparse
23 23 from urllib import urlretrieve
24 24
25 25 from IPython.utils.path import get_ipython_dir, ensure_dir_exists
26 26 from IPython.utils.py3compat import string_types, cast_unicode_py2
27 27 from IPython.utils.tempdir import TemporaryDirectory
28 28
29 29 class ArgumentConflict(ValueError):
30 30 pass
31 31
32 32 # Packagers: modify the next block if you store system-installed nbextensions elsewhere (unlikely)
33 33 SYSTEM_NBEXTENSIONS_DIRS = []
34 34
35 35 if os.name == 'nt':
36 36 programdata = os.environ.get('PROGRAMDATA', None)
37 37 if programdata: # PROGRAMDATA is not defined by default on XP.
38 38 SYSTEM_NBEXTENSIONS_DIRS = [pjoin(programdata, 'jupyter', 'nbextensions')]
39 39 prefixes = []
40 40 else:
41 41 prefixes = [os.path.sep + pjoin('usr', 'local'), os.path.sep + 'usr']
42 42
43 43 # add sys.prefix at the front
44 44 if sys.prefix not in prefixes:
45 45 prefixes.insert(0, sys.prefix)
46 46
47 47 for prefix in prefixes:
48 48 nbext = pjoin(prefix, 'share', 'jupyter', 'nbextensions')
49 49 if nbext not in SYSTEM_NBEXTENSIONS_DIRS:
50 50 SYSTEM_NBEXTENSIONS_DIRS.append(nbext)
51 51
52 52 if os.name == 'nt':
53 53 # PROGRAMDATA
54 54 SYSTEM_NBEXTENSIONS_INSTALL_DIR = SYSTEM_NBEXTENSIONS_DIRS[-1]
55 55 else:
56 56 # /usr/local
57 57 SYSTEM_NBEXTENSIONS_INSTALL_DIR = SYSTEM_NBEXTENSIONS_DIRS[-2]
58 58
59 59
60 60 def _should_copy(src, dest, verbose=1):
61 61 """should a file be copied?"""
62 62 if not os.path.exists(dest):
63 63 return True
64 64 if os.stat(src).st_mtime - os.stat(dest).st_mtime > 1e-6:
65 65 # we add a fudge factor to work around a bug in python 2.x
66 66 # that was fixed in python 3.x: http://bugs.python.org/issue12904
67 67 if verbose >= 2:
68 68 print("%s is out of date" % dest)
69 69 return True
70 70 if verbose >= 2:
71 71 print("%s is up to date" % dest)
72 72 return False
73 73
74 74
75 75 def _maybe_copy(src, dest, verbose=1):
76 76 """copy a file if it needs updating"""
77 77 if _should_copy(src, dest, verbose):
78 78 if verbose >= 1:
79 79 print("copying %s -> %s" % (src, dest))
80 80 shutil.copy2(src, dest)
81 81
82 82 def _safe_is_tarfile(path):
83 83 """safe version of is_tarfile, return False on IOError"""
84 84 try:
85 85 return tarfile.is_tarfile(path)
86 86 except IOError:
87 87 return False
88 88
89 89
90 90 def _get_nbext_dir(nbextensions_dir=None, user=False, prefix=None):
91 91 """Return the nbextension directory specified"""
92 92 if sum(map(bool, [user, prefix, nbextensions_dir])) > 1:
93 93 raise ArgumentConflict("Cannot specify more than one of user, prefix, or nbextensions_dir.")
94 94 if user:
95 95 nbext = pjoin(get_ipython_dir(), u'nbextensions')
96 96 else:
97 97 if prefix:
98 98 nbext = pjoin(prefix, 'share', 'jupyter', 'nbextensions')
99 99 elif nbextensions_dir:
100 100 nbext = nbextensions_dir
101 101 else:
102 102 nbext = SYSTEM_NBEXTENSIONS_INSTALL_DIR
103 103 return nbext
104 104
105 105
106 106 def check_nbextension(files, user=False, prefix=None, nbextensions_dir=None):
107 107 """Check whether nbextension files have been installed
108 108
109 109 Returns True if all files are found, False if any are missing.
110 110
111 111 Parameters
112 112 ----------
113 113
114 114 files : list(paths)
115 115 a list of relative paths within nbextensions.
116 116 user : bool [default: False]
117 117 Whether to check the user's .ipython/nbextensions directory.
118 118 Otherwise check a system-wide install (e.g. /usr/local/share/jupyter/nbextensions).
119 119 prefix : str [optional]
120 120 Specify install prefix, if it should differ from default (e.g. /usr/local).
121 121 Will check prefix/share/jupyter/nbextensions
122 122 nbextensions_dir : str [optional]
123 123 Specify absolute path of nbextensions directory explicitly.
124 124 """
125 125 nbext = _get_nbext_dir(nbextensions_dir, user, prefix)
126 126 # make sure nbextensions dir exists
127 127 if not os.path.exists(nbext):
128 128 return False
129 129
130 130 if isinstance(files, string_types):
131 131 # one file given, turn it into a list
132 132 files = [files]
133 133
134 134 return all(os.path.exists(pjoin(nbext, f)) for f in files)
135 135
136 136
137 137 def install_nbextension(path, overwrite=False, symlink=False, user=False, prefix=None, nbextensions_dir=None, destination=None, verbose=1):
138 138 """Install a Javascript extension for the notebook
139 139
140 140 Stages files and/or directories into the nbextensions directory.
141 141 By default, this compares modification time, and only stages files that need updating.
142 142 If `overwrite` is specified, matching files are purged before proceeding.
143 143
144 144 Parameters
145 145 ----------
146 146
147 147 path : path to file, directory, zip or tarball archive, or URL to install
148 148 By default, the file will be installed with its base name, so '/path/to/foo'
149 149 will install to 'nbextensions/foo'. See the destination argument below to change this.
150 150 Archives (zip or tarballs) will be extracted into the nbextensions directory.
151 151 overwrite : bool [default: False]
152 152 If True, always install the files, regardless of what may already be installed.
153 153 symlink : bool [default: False]
154 154 If True, create a symlink in nbextensions, rather than copying files.
155 155 Not allowed with URLs or archives. Windows support for symlinks requires
156 156 Vista or above, Python 3, and a permission bit which only admin users
157 157 have by default, so don't rely on it.
158 158 user : bool [default: False]
159 159 Whether to install to the user's .ipython/nbextensions directory.
160 160 Otherwise do a system-wide install (e.g. /usr/local/share/jupyter/nbextensions).
161 161 prefix : str [optional]
162 162 Specify install prefix, if it should differ from default (e.g. /usr/local).
163 163 Will install to prefix/share/jupyter/nbextensions
164 164 nbextensions_dir : str [optional]
165 165 Specify absolute path of nbextensions directory explicitly.
166 166 destination : str [optional]
167 167 name the nbextension is installed to. For example, if destination is 'foo', then
168 168 the source file will be installed to 'nbextensions/foo', regardless of the source name.
169 169 This cannot be specified if an archive is given as the source.
170 170 verbose : int [default: 1]
171 171 Set verbosity level. The default is 1, where file actions are printed.
172 172 set verbose=2 for more output, or verbose=0 for silence.
173 173 """
174 174 nbext = _get_nbext_dir(nbextensions_dir, user, prefix)
175 175 # make sure nbextensions dir exists
176 176 ensure_dir_exists(nbext)
177 177
178 178 if isinstance(path, (list, tuple)):
179 179 raise TypeError("path must be a string pointing to a single extension to install; call this function multiple times to install multiple extensions")
180 180
181 181 path = cast_unicode_py2(path)
182 182
183 183 if path.startswith(('https://', 'http://')):
184 184 if symlink:
185 185 raise ValueError("Cannot symlink from URLs")
186 186 # Given a URL, download it
187 187 with TemporaryDirectory() as td:
188 188 filename = urlparse(path).path.split('/')[-1]
189 189 local_path = os.path.join(td, filename)
190 190 if verbose >= 1:
191 191 print("downloading %s to %s" % (path, local_path))
192 192 urlretrieve(path, local_path)
193 193 # now install from the local copy
194 194 install_nbextension(local_path, overwrite=overwrite, symlink=symlink, nbextensions_dir=nbext, destination=destination, verbose=verbose)
195 195 elif path.endswith('.zip') or _safe_is_tarfile(path):
196 196 if symlink:
197 197 raise ValueError("Cannot symlink from archives")
198 198 if destination:
199 199 raise ValueError("Cannot give destination for archives")
200 200 if verbose >= 1:
201 201 print("extracting %s to %s" % (path, nbext))
202 202
203 203 if path.endswith('.zip'):
204 204 archive = zipfile.ZipFile(path)
205 205 elif _safe_is_tarfile(path):
206 206 archive = tarfile.open(path)
207 207 archive.extractall(nbext)
208 208 archive.close()
209 209 else:
210 210 if not destination:
211 211 destination = basename(path)
212 212 destination = cast_unicode_py2(destination)
213 213 full_dest = pjoin(nbext, destination)
214 if overwrite and os.path.exists(full_dest):
214 if overwrite and os.path.lexists(full_dest):
215 215 if verbose >= 1:
216 216 print("removing %s" % full_dest)
217 217 if os.path.isdir(full_dest) and not os.path.islink(full_dest):
218 218 shutil.rmtree(full_dest)
219 219 else:
220 220 os.remove(full_dest)
221 221
222 222 if symlink:
223 223 path = os.path.abspath(path)
224 224 if not os.path.exists(full_dest):
225 225 if verbose >= 1:
226 226 print("symlink %s -> %s" % (full_dest, path))
227 227 os.symlink(path, full_dest)
228 228 elif os.path.isdir(path):
229 229 path = pjoin(os.path.abspath(path), '') # end in path separator
230 230 for parent, dirs, files in os.walk(path):
231 231 dest_dir = pjoin(full_dest, parent[len(path):])
232 232 if not os.path.exists(dest_dir):
233 233 if verbose >= 2:
234 234 print("making directory %s" % dest_dir)
235 235 os.makedirs(dest_dir)
236 236 for file in files:
237 237 src = pjoin(parent, file)
238 238 # print("%r, %r" % (dest_dir, file))
239 239 dest_file = pjoin(dest_dir, file)
240 240 _maybe_copy(src, dest_file, verbose)
241 241 else:
242 242 src = path
243 243 _maybe_copy(src, full_dest, verbose)
244 244
245 245 #----------------------------------------------------------------------
246 246 # install nbextension app
247 247 #----------------------------------------------------------------------
248 248
249 249 from IPython.utils.traitlets import Bool, Enum, Unicode, TraitError
250 250 from IPython.core.application import BaseIPythonApplication
251 251
252 252 flags = {
253 253 "overwrite" : ({
254 254 "NBExtensionApp" : {
255 255 "overwrite" : True,
256 256 }}, "Force overwrite of existing files"
257 257 ),
258 258 "debug" : ({
259 259 "NBExtensionApp" : {
260 260 "verbose" : 2,
261 261 }}, "Extra output"
262 262 ),
263 263 "quiet" : ({
264 264 "NBExtensionApp" : {
265 265 "verbose" : 0,
266 266 }}, "Minimal output"
267 267 ),
268 268 "symlink" : ({
269 269 "NBExtensionApp" : {
270 270 "symlink" : True,
271 271 }}, "Create symlink instead of copying files"
272 272 ),
273 273 "user" : ({
274 274 "NBExtensionApp" : {
275 275 "user" : True,
276 276 }}, "Install to the user's IPython directory"
277 277 ),
278 278 }
279 279 flags['s'] = flags['symlink']
280 280
281 281 aliases = {
282 282 "ipython-dir" : "NBExtensionApp.ipython_dir",
283 283 "prefix" : "NBExtensionApp.prefix",
284 284 "nbextensions" : "NBExtensionApp.nbextensions_dir",
285 285 "destination" : "NBExtensionApp.destination",
286 286 }
287 287
288 288 class NBExtensionApp(BaseIPythonApplication):
289 289 """Entry point for installing notebook extensions"""
290 290
291 291 description = """Install IPython notebook extensions
292 292
293 293 Usage
294 294
295 295 ipython install-nbextension path/url
296 296
297 297 This copies a file or a folder into the IPython nbextensions directory.
298 298 If a URL is given, it will be downloaded.
299 299 If an archive is given, it will be extracted into nbextensions.
300 300 If the requested files are already up to date, no action is taken
301 301 unless --overwrite is specified.
302 302 """
303 303
304 304 examples = """
305 305 ipython install-nbextension /path/to/myextension
306 306 """
307 307 aliases = aliases
308 308 flags = flags
309 309
310 310 overwrite = Bool(False, config=True, help="Force overwrite of existing files")
311 311 symlink = Bool(False, config=True, help="Create symlinks instead of copying files")
312 312 user = Bool(False, config=True, help="Whether to do a user install")
313 313 prefix = Unicode('', config=True, help="Installation prefix")
314 314 nbextensions_dir = Unicode('', config=True, help="Full path to nbextensions dir (probably use prefix or user)")
315 315 destination = Unicode('', config=True, help="Destination for the copy or symlink")
316 316 verbose = Enum((0,1,2), default_value=1, config=True,
317 317 help="Verbosity level"
318 318 )
319 319
320 320 def install_extensions(self):
321 321 if len(self.extra_args)>1:
322 322 raise ValueError("only one nbextension allowed at a time. Call multiple times to install multiple extensions.")
323 323 install_nbextension(self.extra_args[0],
324 324 overwrite=self.overwrite,
325 325 symlink=self.symlink,
326 326 verbose=self.verbose,
327 327 user=self.user,
328 328 prefix=self.prefix,
329 329 destination=self.destination,
330 330 nbextensions_dir=self.nbextensions_dir,
331 331 )
332 332
333 333 def start(self):
334 334 if not self.extra_args:
335 335 for nbext in [pjoin(self.ipython_dir, u'nbextensions')] + SYSTEM_NBEXTENSIONS_DIRS:
336 336 if os.path.exists(nbext):
337 337 print("Notebook extensions in %s:" % nbext)
338 338 for ext in os.listdir(nbext):
339 339 print(u" %s" % ext)
340 340 else:
341 341 try:
342 342 self.install_extensions()
343 343 except ArgumentConflict as e:
344 344 print(str(e), file=sys.stderr)
345 345 self.exit(1)
346 346
347 347
348 348 if __name__ == '__main__':
349 349 NBExtensionApp.launch_instance()
350 350
@@ -1,316 +1,332 b''
1 1 # coding: utf-8
2 2 """Test installation of notebook extensions"""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 import glob
8 8 import os
9 9 import re
10 10 import tarfile
11 11 import zipfile
12 12 from io import BytesIO
13 13 from os.path import basename, join as pjoin
14 14 from unittest import TestCase
15 15
16 16 import IPython.testing.tools as tt
17 17 import IPython.testing.decorators as dec
18 18 from IPython.utils import py3compat
19 19 from IPython.utils.tempdir import TemporaryDirectory
20 20 from IPython.html import nbextensions
21 21 from IPython.html.nbextensions import install_nbextension, check_nbextension
22 22
23 23
24 24 def touch(file, mtime=None):
25 25 """ensure a file exists, and set its modification time
26 26
27 27 returns the modification time of the file
28 28 """
29 29 open(file, 'a').close()
30 30 # set explicit mtime
31 31 if mtime:
32 32 atime = os.stat(file).st_atime
33 33 os.utime(file, (atime, mtime))
34 34 return os.stat(file).st_mtime
35 35
36 36 class TestInstallNBExtension(TestCase):
37 37
38 38 def tempdir(self):
39 39 td = TemporaryDirectory()
40 40 self.tempdirs.append(td)
41 41 return py3compat.cast_unicode(td.name)
42 42
43 43 def setUp(self):
44 44 self.tempdirs = []
45 45 src = self.src = self.tempdir()
46 46 self.files = files = [
47 47 pjoin(u'ƒile'),
48 48 pjoin(u'∂ir', u'ƒile1'),
49 49 pjoin(u'∂ir', u'∂ir2', u'ƒile2'),
50 50 ]
51 51 for file in files:
52 52 fullpath = os.path.join(self.src, file)
53 53 parent = os.path.dirname(fullpath)
54 54 if not os.path.exists(parent):
55 55 os.makedirs(parent)
56 56 touch(fullpath)
57 57
58 58 self.ipdir = self.tempdir()
59 59 self.save_get_ipython_dir = nbextensions.get_ipython_dir
60 60 nbextensions.get_ipython_dir = lambda : self.ipdir
61 61 self.save_system_dir = nbextensions.SYSTEM_NBEXTENSIONS_INSTALL_DIR
62 62 nbextensions.SYSTEM_NBEXTENSIONS_INSTALL_DIR = self.system_nbext = self.tempdir()
63 63
64 64 def tearDown(self):
65 65 nbextensions.get_ipython_dir = self.save_get_ipython_dir
66 66 nbextensions.SYSTEM_NBEXTENSIONS_INSTALL_DIR = self.save_system_dir
67 67 for td in self.tempdirs:
68 68 td.cleanup()
69 69
70 70 def assert_dir_exists(self, path):
71 71 if not os.path.exists(path):
72 72 do_exist = os.listdir(os.path.dirname(path))
73 73 self.fail(u"%s should exist (found %s)" % (path, do_exist))
74 74
75 75 def assert_not_dir_exists(self, path):
76 76 if os.path.exists(path):
77 77 self.fail(u"%s should not exist" % path)
78 78
79 79 def assert_installed(self, relative_path, user=False):
80 80 if user:
81 81 nbext = pjoin(self.ipdir, u'nbextensions')
82 82 else:
83 83 nbext = self.system_nbext
84 84 self.assert_dir_exists(
85 85 pjoin(nbext, relative_path)
86 86 )
87 87
88 88 def assert_not_installed(self, relative_path, user=False):
89 89 if user:
90 90 nbext = pjoin(self.ipdir, u'nbextensions')
91 91 else:
92 92 nbext = self.system_nbext
93 93 self.assert_not_dir_exists(
94 94 pjoin(nbext, relative_path)
95 95 )
96 96
97 97 def test_create_ipython_dir(self):
98 98 """install_nbextension when ipython_dir doesn't exist"""
99 99 with TemporaryDirectory() as td:
100 100 self.ipdir = ipdir = pjoin(td, u'ipython')
101 101 install_nbextension(self.src, user=True)
102 102 self.assert_dir_exists(ipdir)
103 103 for file in self.files:
104 104 self.assert_installed(
105 105 pjoin(basename(self.src), file),
106 106 user=bool(ipdir)
107 107 )
108 108
109 109 def test_create_nbextensions_user(self):
110 110 with TemporaryDirectory() as td:
111 111 self.ipdir = ipdir = pjoin(td, u'ipython')
112 112 install_nbextension(self.src, user=True)
113 113 self.assert_installed(
114 114 pjoin(basename(self.src), u'ƒile'),
115 115 user=True
116 116 )
117 117
118 118 def test_create_nbextensions_system(self):
119 119 with TemporaryDirectory() as td:
120 120 nbextensions.SYSTEM_NBEXTENSIONS_INSTALL_DIR = self.system_nbext = pjoin(td, u'nbextensions')
121 121 install_nbextension(self.src, user=False)
122 122 self.assert_installed(
123 123 pjoin(basename(self.src), u'ƒile'),
124 124 user=False
125 125 )
126 126
127 127 def test_single_file(self):
128 128 file = self.files[0]
129 129 install_nbextension(pjoin(self.src, file))
130 130 self.assert_installed(file)
131 131
132 132 def test_single_dir(self):
133 133 d = u'∂ir'
134 134 install_nbextension(pjoin(self.src, d))
135 135 self.assert_installed(self.files[-1])
136 136
137 137
138 138 def test_destination_file(self):
139 139 file = self.files[0]
140 140 install_nbextension(pjoin(self.src, file), destination = u'ƒiledest')
141 141 self.assert_installed(u'ƒiledest')
142 142
143 143 def test_destination_dir(self):
144 144 d = u'∂ir'
145 145 install_nbextension(pjoin(self.src, d), destination = u'ƒiledest2')
146 146 self.assert_installed(pjoin(u'ƒiledest2', u'∂ir2', u'ƒile2'))
147 147
148 148 def test_install_nbextension(self):
149 149 with self.assertRaises(TypeError):
150 150 install_nbextension(glob.glob(pjoin(self.src, '*')))
151 151
152 152 def test_overwrite_file(self):
153 153 with TemporaryDirectory() as d:
154 154 fname = u'ƒ.js'
155 155 src = pjoin(d, fname)
156 156 with open(src, 'w') as f:
157 157 f.write('first')
158 158 mtime = touch(src)
159 159 dest = pjoin(self.system_nbext, fname)
160 160 install_nbextension(src)
161 161 with open(src, 'w') as f:
162 162 f.write('overwrite')
163 163 mtime = touch(src, mtime - 100)
164 164 install_nbextension(src, overwrite=True)
165 165 with open(dest) as f:
166 166 self.assertEqual(f.read(), 'overwrite')
167 167
168 168 def test_overwrite_dir(self):
169 169 with TemporaryDirectory() as src:
170 170 base = basename(src)
171 171 fname = u'ƒ.js'
172 172 touch(pjoin(src, fname))
173 173 install_nbextension(src)
174 174 self.assert_installed(pjoin(base, fname))
175 175 os.remove(pjoin(src, fname))
176 176 fname2 = u'∂.js'
177 177 touch(pjoin(src, fname2))
178 178 install_nbextension(src, overwrite=True)
179 179 self.assert_installed(pjoin(base, fname2))
180 180 self.assert_not_installed(pjoin(base, fname))
181 181
182 182 def test_update_file(self):
183 183 with TemporaryDirectory() as d:
184 184 fname = u'ƒ.js'
185 185 src = pjoin(d, fname)
186 186 with open(src, 'w') as f:
187 187 f.write('first')
188 188 mtime = touch(src)
189 189 install_nbextension(src)
190 190 self.assert_installed(fname)
191 191 dest = pjoin(self.system_nbext, fname)
192 192 old_mtime = os.stat(dest).st_mtime
193 193 with open(src, 'w') as f:
194 194 f.write('overwrite')
195 195 touch(src, mtime + 10)
196 196 install_nbextension(src)
197 197 with open(dest) as f:
198 198 self.assertEqual(f.read(), 'overwrite')
199 199
200 200 def test_skip_old_file(self):
201 201 with TemporaryDirectory() as d:
202 202 fname = u'ƒ.js'
203 203 src = pjoin(d, fname)
204 204 mtime = touch(src)
205 205 install_nbextension(src)
206 206 self.assert_installed(fname)
207 207 dest = pjoin(self.system_nbext, fname)
208 208 old_mtime = os.stat(dest).st_mtime
209 209
210 210 mtime = touch(src, mtime - 100)
211 211 install_nbextension(src)
212 212 new_mtime = os.stat(dest).st_mtime
213 213 self.assertEqual(new_mtime, old_mtime)
214 214
215 215 def test_quiet(self):
216 216 with tt.AssertNotPrints(re.compile(r'.+')):
217 217 install_nbextension(self.src, verbose=0)
218 218
219 219 def test_install_zip(self):
220 220 path = pjoin(self.src, "myjsext.zip")
221 221 with zipfile.ZipFile(path, 'w') as f:
222 222 f.writestr("a.js", b"b();")
223 223 f.writestr("foo/a.js", b"foo();")
224 224 install_nbextension(path)
225 225 self.assert_installed("a.js")
226 226 self.assert_installed(pjoin("foo", "a.js"))
227 227
228 228 def test_install_tar(self):
229 229 def _add_file(f, fname, buf):
230 230 info = tarfile.TarInfo(fname)
231 231 info.size = len(buf)
232 232 f.addfile(info, BytesIO(buf))
233 233
234 234 for i,ext in enumerate((".tar.gz", ".tgz", ".tar.bz2")):
235 235 path = pjoin(self.src, "myjsext" + ext)
236 236 with tarfile.open(path, 'w') as f:
237 237 _add_file(f, "b%i.js" % i, b"b();")
238 238 _add_file(f, "foo/b%i.js" % i, b"foo();")
239 239 install_nbextension(path)
240 240 self.assert_installed("b%i.js" % i)
241 241 self.assert_installed(pjoin("foo", "b%i.js" % i))
242 242
243 243 def test_install_url(self):
244 244 def fake_urlretrieve(url, dest):
245 245 touch(dest)
246 246 save_urlretrieve = nbextensions.urlretrieve
247 247 nbextensions.urlretrieve = fake_urlretrieve
248 248 try:
249 249 install_nbextension("http://example.com/path/to/foo.js")
250 250 self.assert_installed("foo.js")
251 251 install_nbextension("https://example.com/path/to/another/bar.js")
252 252 self.assert_installed("bar.js")
253 253 install_nbextension("https://example.com/path/to/another/bar.js",
254 254 destination = 'foobar.js')
255 255 self.assert_installed("foobar.js")
256 256 finally:
257 257 nbextensions.urlretrieve = save_urlretrieve
258 258
259 259 def test_check_nbextension(self):
260 260 with TemporaryDirectory() as d:
261 261 f = u'ƒ.js'
262 262 src = pjoin(d, f)
263 263 touch(src)
264 264 install_nbextension(src, user=True)
265 265
266 266 assert check_nbextension(f, user=True)
267 267 assert check_nbextension([f], user=True)
268 268 assert not check_nbextension([f, pjoin('dne', f)], user=True)
269 269
270 270 @dec.skip_win32
271 271 def test_install_symlink(self):
272 272 with TemporaryDirectory() as d:
273 273 f = u'ƒ.js'
274 274 src = pjoin(d, f)
275 275 touch(src)
276 276 install_nbextension(src, symlink=True)
277 277 dest = pjoin(self.system_nbext, f)
278 278 assert os.path.islink(dest)
279 279 link = os.readlink(dest)
280 280 self.assertEqual(link, src)
281 281
282 282 @dec.skip_win32
283 def test_overwrite_broken_symlink(self):
284 with TemporaryDirectory() as d:
285 f = u'ƒ.js'
286 f2 = u'ƒ2.js'
287 src = pjoin(d, f)
288 src2 = pjoin(d, f2)
289 touch(src)
290 install_nbextension(src, symlink=True)
291 os.rename(src, src2)
292 install_nbextension(src2, symlink=True, overwrite=True, destination=f)
293 dest = pjoin(self.system_nbext, f)
294 assert os.path.islink(dest)
295 link = os.readlink(dest)
296 self.assertEqual(link, src2)
297
298 @dec.skip_win32
283 299 def test_install_symlink_destination(self):
284 300 with TemporaryDirectory() as d:
285 301 f = u'ƒ.js'
286 302 flink = u'ƒlink.js'
287 303 src = pjoin(d, f)
288 304 touch(src)
289 305 install_nbextension(src, symlink=True, destination=flink)
290 306 dest = pjoin(self.system_nbext, flink)
291 307 assert os.path.islink(dest)
292 308 link = os.readlink(dest)
293 309 self.assertEqual(link, src)
294 310
295 311 def test_install_symlink_bad(self):
296 312 with self.assertRaises(ValueError):
297 313 install_nbextension("http://example.com/foo.js", symlink=True)
298 314
299 315 with TemporaryDirectory() as d:
300 316 zf = u'ƒ.zip'
301 317 zsrc = pjoin(d, zf)
302 318 with zipfile.ZipFile(zsrc, 'w') as z:
303 319 z.writestr("a.js", b"b();")
304 320
305 321 with self.assertRaises(ValueError):
306 322 install_nbextension(zsrc, symlink=True)
307 323
308 324 def test_install_destination_bad(self):
309 325 with TemporaryDirectory() as d:
310 326 zf = u'ƒ.zip'
311 327 zsrc = pjoin(d, zf)
312 328 with zipfile.ZipFile(zsrc, 'w') as z:
313 329 z.writestr("a.js", b"b();")
314 330
315 331 with self.assertRaises(ValueError):
316 332 install_nbextension(zsrc, destination='foo')
General Comments 0
You need to be logged in to leave comments. Login now