##// 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 import os
13 import os
14 import shutil
14 import shutil
15 import tarfile
16 import zipfile
15 from os.path import basename, join as pjoin
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 from IPython.utils.path import get_ipython_dir
27 from IPython.utils.path import get_ipython_dir
18 from IPython.utils.py3compat import string_types, cast_unicode_py2
28 from IPython.utils.py3compat import string_types, cast_unicode_py2
29 from IPython.utils.tempdir import TemporaryDirectory
19
30
20
31
21 def _should_copy(src, dest, verbose=1):
32 def _should_copy(src, dest, verbose=1):
@@ -39,20 +50,29 b' def _maybe_copy(src, dest, verbose=1):'
39 shutil.copy2(src, dest)
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 def install_nbextension(files, overwrite=False, ipython_dir=None, verbose=1):
61 def install_nbextension(files, overwrite=False, ipython_dir=None, verbose=1):
43 """Install a Javascript extension for the notebook
62 """Install a Javascript extension for the notebook
44
63
45 Stages files and/or directories into IPYTHONDIR/nbextensions.
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 If `overwrite` is specified, matching files are purged before proceeding.
66 If `overwrite` is specified, matching files are purged before proceeding.
48
67
49 Parameters
68 Parameters
50 ----------
69 ----------
51
70
52 files : list(paths)
71 files : list(paths or URLs)
53 One or more paths to existing files or directories to install.
72 One or more paths or URLs to existing files directories to install.
54 These will be installed with their base name, so '/path/to/foo'
73 These will be installed with their base name, so '/path/to/foo'
55 will install to 'nbextensions/foo'.
74 will install to 'nbextensions/foo'.
75 Archives (zip or tarballs) will be extracted into the nbextensions directory.
56 overwrite : bool [default: False]
76 overwrite : bool [default: False]
57 If True, always install the files, regardless of what may already be installed.
77 If True, always install the files, regardless of what may already be installed.
58 ipython_dir : str [optional]
78 ipython_dir : str [optional]
@@ -74,6 +94,33 b' def install_nbextension(files, overwrite=False, ipython_dir=None, verbose=1):'
74 files = [files]
94 files = [files]
75
95
76 for path in map(cast_unicode_py2, files):
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 dest = pjoin(nbext, basename(path))
124 dest = pjoin(nbext, basename(path))
78 if overwrite and os.path.exists(dest):
125 if overwrite and os.path.exists(dest):
79 if verbose >= 1:
126 if verbose >= 1:
@@ -104,7 +151,6 b' def install_nbextension(files, overwrite=False, ipython_dir=None, verbose=1):'
104 # install nbextension app
151 # install nbextension app
105 #----------------------------------------------------------------------
152 #----------------------------------------------------------------------
106
153
107 import logging
108 from IPython.utils.traitlets import Bool, Enum
154 from IPython.utils.traitlets import Bool, Enum
109 from IPython.core.application import BaseIPythonApplication
155 from IPython.core.application import BaseIPythonApplication
110
156
@@ -136,9 +182,11 b' class NBExtensionApp(BaseIPythonApplication):'
136
182
137 Usage
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 This copies files and/or folders into the IPython nbextensions directory.
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 If the requested files are already up to date, no action is taken
190 If the requested files are already up to date, no action is taken
143 unless --overwrite is specified.
191 unless --overwrite is specified.
144 """
192 """
@@ -14,17 +14,13 b''
14 import glob
14 import glob
15 import os
15 import os
16 import re
16 import re
17 import time
17 import tarfile
18 from contextlib import contextmanager
18 import zipfile
19 from io import BytesIO
19 from os.path import basename, join as pjoin
20 from os.path import basename, join as pjoin
20 from unittest import TestCase
21 from unittest import TestCase
21
22
22 import nose.tools as nt
23
24 from IPython.external.decorator import decorator
25
26 import IPython.testing.tools as tt
23 import IPython.testing.tools as tt
27 import IPython.utils.path
28 from IPython.utils import py3compat
24 from IPython.utils import py3compat
29 from IPython.utils.tempdir import TemporaryDirectory
25 from IPython.utils.tempdir import TemporaryDirectory
30 from IPython.html import nbextensions
26 from IPython.html import nbextensions
@@ -80,7 +76,8 b' class TestInstallNBExtension(TestCase):'
80
76
81 def assert_path_exists(self, path):
77 def assert_path_exists(self, path):
82 if not os.path.exists(path):
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 def assert_not_path_exists(self, path):
82 def assert_not_path_exists(self, path):
86 if os.path.exists(path):
83 if os.path.exists(path):
@@ -199,3 +196,39 b' class TestInstallNBExtension(TestCase):'
199 with tt.AssertNotPrints(re.compile(r'.+')):
196 with tt.AssertNotPrints(re.compile(r'.+')):
200 install_nbextension(self.src, verbose=0)
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