##// END OF EJS Templates
support URLs and zip/tarballs in install_extension
MinRK -
Show More
@@ -12,10 +12,21 b' from __future__ import print_function'
12 12
13 13 import os
14 14 import shutil
15 import tarfile
16 import zipfile
15 17 from os.path import basename, join as pjoin
16 18
19 # Deferred imports
20 try:
21 from urllib.parse import urlparse # Py3
22 from urllib.request import urlretrieve
23 except ImportError:
24 from urlparse import urlparse
25 from urllib import urlretrieve
26
17 27 from IPython.utils.path import get_ipython_dir
18 28 from IPython.utils.py3compat import string_types, cast_unicode_py2
29 from IPython.utils.tempdir import TemporaryDirectory
19 30
20 31
21 32 def _should_copy(src, dest, verbose=1):
@@ -39,20 +50,29 b' def _maybe_copy(src, dest, verbose=1):'
39 50 shutil.copy2(src, dest)
40 51
41 52
53 def _safe_is_tarfile(path):
54 """safe version of is_tarfile, return False on IOError"""
55 try:
56 return tarfile.is_tarfile(path)
57 except IOError:
58 return False
59
60
42 61 def install_nbextension(files, overwrite=False, ipython_dir=None, verbose=1):
43 62 """Install a Javascript extension for the notebook
44 63
45 64 Stages files and/or directories into IPYTHONDIR/nbextensions.
46 By default, this comparse modification time, and only stages files that need updating.
65 By default, this compares modification time, and only stages files that need updating.
47 66 If `overwrite` is specified, matching files are purged before proceeding.
48 67
49 68 Parameters
50 69 ----------
51 70
52 files : list(paths)
53 One or more paths to existing files or directories to install.
71 files : list(paths or URLs)
72 One or more paths or URLs to existing files directories to install.
54 73 These will be installed with their base name, so '/path/to/foo'
55 74 will install to 'nbextensions/foo'.
75 Archives (zip or tarballs) will be extracted into the nbextensions directory.
56 76 overwrite : bool [default: False]
57 77 If True, always install the files, regardless of what may already be installed.
58 78 ipython_dir : str [optional]
@@ -74,6 +94,33 b' def install_nbextension(files, overwrite=False, ipython_dir=None, verbose=1):'
74 94 files = [files]
75 95
76 96 for path in map(cast_unicode_py2, files):
97
98 if path.startswith(('https://', 'http://')):
99 # Given a URL, download it
100 with TemporaryDirectory() as td:
101 filename = urlparse(path).path.split('/')[-1]
102 local_path = os.path.join(td, filename)
103 if verbose >= 1:
104 print("downloading %s to %s" % (path, local_path))
105 urlretrieve(path, local_path)
106 # now install from the local copy
107 install_nbextension(local_path, overwrite, ipython_dir, verbose)
108 continue
109
110 # handle archives
111 archive = None
112 if path.endswith('.zip'):
113 archive = zipfile.ZipFile(path)
114 elif _safe_is_tarfile(path):
115 archive = tarfile.open(path)
116
117 if archive:
118 if verbose >= 1:
119 print("extracting %s to %s" % (path, nbext))
120 archive.extractall(nbext)
121 archive.close()
122 continue
123
77 124 dest = pjoin(nbext, basename(path))
78 125 if overwrite and os.path.exists(dest):
79 126 if verbose >= 1:
@@ -104,7 +151,6 b' def install_nbextension(files, overwrite=False, ipython_dir=None, verbose=1):'
104 151 # install nbextension app
105 152 #----------------------------------------------------------------------
106 153
107 import logging
108 154 from IPython.utils.traitlets import Bool, Enum
109 155 from IPython.core.application import BaseIPythonApplication
110 156
@@ -136,9 +182,11 b' class NBExtensionApp(BaseIPythonApplication):'
136 182
137 183 Usage
138 184
139 ipython install-nbextension file [more files or folders]
185 ipython install-nbextension file [more files, folders, archives or urls]
140 186
141 187 This copies files and/or folders into the IPython nbextensions directory.
188 If a URL is given, it will be downloaded.
189 If an archive is given, it will be extracted into nbextensions.
142 190 If the requested files are already up to date, no action is taken
143 191 unless --overwrite is specified.
144 192 """
@@ -14,17 +14,13 b''
14 14 import glob
15 15 import os
16 16 import re
17 import time
18 from contextlib import contextmanager
17 import tarfile
18 import zipfile
19 from io import BytesIO
19 20 from os.path import basename, join as pjoin
20 21 from unittest import TestCase
21 22
22 import nose.tools as nt
23
24 from IPython.external.decorator import decorator
25
26 23 import IPython.testing.tools as tt
27 import IPython.utils.path
28 24 from IPython.utils import py3compat
29 25 from IPython.utils.tempdir import TemporaryDirectory
30 26 from IPython.html import nbextensions
@@ -80,7 +76,8 b' class TestInstallNBExtension(TestCase):'
80 76
81 77 def assert_path_exists(self, path):
82 78 if not os.path.exists(path):
83 self.fail(u"%s should exist" % path)
79 do_exist = os.listdir(os.path.dirname(path))
80 self.fail(u"%s should exist (found %s)" % (path, do_exist))
84 81
85 82 def assert_not_path_exists(self, path):
86 83 if os.path.exists(path):
@@ -199,3 +196,39 b' class TestInstallNBExtension(TestCase):'
199 196 with tt.AssertNotPrints(re.compile(r'.+')):
200 197 install_nbextension(self.src, verbose=0)
201 198
199 def test_install_zip(self):
200 path = pjoin(self.src, "myjsext.zip")
201 with zipfile.ZipFile(path, 'w') as f:
202 f.writestr("a.js", b"b();")
203 f.writestr("foo/a.js", b"foo();")
204 install_nbextension(path)
205 self.assert_installed("a.js")
206 self.assert_installed(pjoin("foo", "a.js"))
207
208 def test_install_tar(self):
209 def _add_file(f, fname, buf):
210 info = tarfile.TarInfo(fname)
211 info.size = len(buf)
212 f.addfile(info, BytesIO(buf))
213
214 for i,ext in enumerate((".tar.gz", ".tgz", ".tar.bz2")):
215 path = pjoin(self.src, "myjsext" + ext)
216 with tarfile.open(path, 'w') as f:
217 _add_file(f, "b%i.js" % i, b"b();")
218 _add_file(f, "foo/b%i.js" % i, b"foo();")
219 install_nbextension(path)
220 self.assert_installed("b%i.js" % i)
221 self.assert_installed(pjoin("foo", "b%i.js" % i))
222
223 def test_install_url(self):
224 def fake_urlretrieve(url, dest):
225 touch(dest)
226 save_urlretrieve = nbextensions.urlretrieve
227 nbextensions.urlretrieve = fake_urlretrieve
228 try:
229 install_nbextension("http://example.com/path/to/foo.js")
230 self.assert_installed("foo.js")
231 install_nbextension("https://example.com/path/to/another/bar.js")
232 self.assert_installed("bar.js")
233 finally:
234 nbextensions.urlretrieve = save_urlretrieve
General Comments 0
You need to be logged in to leave comments. Login now