##// END OF EJS Templates
support URLs and zip/tarballs in install_extension
MinRK -
Show More
@@ -1,176 +1,224 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Utilities for installing Javascript extensions for the notebook"""
2 """Utilities for installing Javascript extensions for the notebook"""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2014 The IPython Development Team
5 # Copyright (C) 2014 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 from __future__ import print_function
11 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):
22 """should a file be copied?"""
33 """should a file be copied?"""
23 if not os.path.exists(dest):
34 if not os.path.exists(dest):
24 return True
35 return True
25 if os.stat(dest).st_mtime < os.stat(src).st_mtime:
36 if os.stat(dest).st_mtime < os.stat(src).st_mtime:
26 if verbose >= 2:
37 if verbose >= 2:
27 print("%s is out of date" % dest)
38 print("%s is out of date" % dest)
28 return True
39 return True
29 if verbose >= 2:
40 if verbose >= 2:
30 print("%s is up to date" % dest)
41 print("%s is up to date" % dest)
31 return False
42 return False
32
43
33
44
34 def _maybe_copy(src, dest, verbose=1):
45 def _maybe_copy(src, dest, verbose=1):
35 """copy a file if it needs updating"""
46 """copy a file if it needs updating"""
36 if _should_copy(src, dest, verbose):
47 if _should_copy(src, dest, verbose):
37 if verbose >= 1:
48 if verbose >= 1:
38 print("copying %s -> %s" % (src, dest))
49 print("copying %s -> %s" % (src, dest))
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]
59 The path to an IPython directory, if the default value is not desired.
79 The path to an IPython directory, if the default value is not desired.
60 get_ipython_dir() is used by default.
80 get_ipython_dir() is used by default.
61 verbose : int [default: 1]
81 verbose : int [default: 1]
62 Set verbosity level. The default is 1, where file actions are printed.
82 Set verbosity level. The default is 1, where file actions are printed.
63 set verbose=2 for more output, or verbose=0 for silence.
83 set verbose=2 for more output, or verbose=0 for silence.
64 """
84 """
65
85
66 ipython_dir = ipython_dir or get_ipython_dir()
86 ipython_dir = ipython_dir or get_ipython_dir()
67 nbext = pjoin(ipython_dir, u'nbextensions')
87 nbext = pjoin(ipython_dir, u'nbextensions')
68 # make sure nbextensions dir exists
88 # make sure nbextensions dir exists
69 if not os.path.exists(nbext):
89 if not os.path.exists(nbext):
70 os.makedirs(nbext)
90 os.makedirs(nbext)
71
91
72 if isinstance(files, string_types):
92 if isinstance(files, string_types):
73 # one file given, turn it into a list
93 # one file given, turn it into a list
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:
80 print("removing %s" % dest)
127 print("removing %s" % dest)
81 if os.path.isdir(dest):
128 if os.path.isdir(dest):
82 shutil.rmtree(dest)
129 shutil.rmtree(dest)
83 else:
130 else:
84 os.remove(dest)
131 os.remove(dest)
85
132
86 if os.path.isdir(path):
133 if os.path.isdir(path):
87 strip_prefix_len = len(path) - len(basename(path))
134 strip_prefix_len = len(path) - len(basename(path))
88 for parent, dirs, files in os.walk(path):
135 for parent, dirs, files in os.walk(path):
89 dest_dir = pjoin(nbext, parent[strip_prefix_len:])
136 dest_dir = pjoin(nbext, parent[strip_prefix_len:])
90 if not os.path.exists(dest_dir):
137 if not os.path.exists(dest_dir):
91 if verbose >= 2:
138 if verbose >= 2:
92 print("making directory %s" % dest_dir)
139 print("making directory %s" % dest_dir)
93 os.makedirs(dest_dir)
140 os.makedirs(dest_dir)
94 for file in files:
141 for file in files:
95 src = pjoin(parent, file)
142 src = pjoin(parent, file)
96 # print("%r, %r" % (dest_dir, file))
143 # print("%r, %r" % (dest_dir, file))
97 dest = pjoin(dest_dir, file)
144 dest = pjoin(dest_dir, file)
98 _maybe_copy(src, dest, verbose)
145 _maybe_copy(src, dest, verbose)
99 else:
146 else:
100 src = path
147 src = path
101 _maybe_copy(src, dest, verbose)
148 _maybe_copy(src, dest, verbose)
102
149
103 #----------------------------------------------------------------------
150 #----------------------------------------------------------------------
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
111 flags = {
157 flags = {
112 "overwrite" : ({
158 "overwrite" : ({
113 "NBExtensionApp" : {
159 "NBExtensionApp" : {
114 "overwrite" : True,
160 "overwrite" : True,
115 }}, "Force overwrite of existing files"
161 }}, "Force overwrite of existing files"
116 ),
162 ),
117 "debug" : ({
163 "debug" : ({
118 "NBExtensionApp" : {
164 "NBExtensionApp" : {
119 "verbose" : 2,
165 "verbose" : 2,
120 }}, "Extra output"
166 }}, "Extra output"
121 ),
167 ),
122 "quiet" : ({
168 "quiet" : ({
123 "NBExtensionApp" : {
169 "NBExtensionApp" : {
124 "verbose" : 0,
170 "verbose" : 0,
125 }}, "Minimal output"
171 }}, "Minimal output"
126 ),
172 ),
127 }
173 }
128 aliases = {
174 aliases = {
129 "ipython-dir" : "NBExtensionApp.ipython_dir"
175 "ipython-dir" : "NBExtensionApp.ipython_dir"
130 }
176 }
131
177
132 class NBExtensionApp(BaseIPythonApplication):
178 class NBExtensionApp(BaseIPythonApplication):
133 """Entry point for installing notebook extensions"""
179 """Entry point for installing notebook extensions"""
134
180
135 description = """Install IPython notebook extensions
181 description = """Install IPython notebook extensions
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 """
145
193
146 examples = """
194 examples = """
147 ipython install-nbextension /path/to/d3.js /path/to/myextension
195 ipython install-nbextension /path/to/d3.js /path/to/myextension
148 """
196 """
149 aliases = aliases
197 aliases = aliases
150 flags = flags
198 flags = flags
151
199
152 overwrite = Bool(False, config=True, help="Force overwrite of existing files")
200 overwrite = Bool(False, config=True, help="Force overwrite of existing files")
153 verbose = Enum((0,1,2), default_value=1, config=True,
201 verbose = Enum((0,1,2), default_value=1, config=True,
154 help="Verbosity level"
202 help="Verbosity level"
155 )
203 )
156
204
157 def install_extensions(self):
205 def install_extensions(self):
158 install_nbextension(self.extra_args,
206 install_nbextension(self.extra_args,
159 overwrite=self.overwrite,
207 overwrite=self.overwrite,
160 verbose=self.verbose,
208 verbose=self.verbose,
161 ipython_dir=self.ipython_dir,
209 ipython_dir=self.ipython_dir,
162 )
210 )
163
211
164 def start(self):
212 def start(self):
165 if not self.extra_args:
213 if not self.extra_args:
166 nbext = pjoin(self.ipython_dir, u'nbextensions')
214 nbext = pjoin(self.ipython_dir, u'nbextensions')
167 print("Notebook extensions in %s:" % nbext)
215 print("Notebook extensions in %s:" % nbext)
168 for ext in os.listdir(nbext):
216 for ext in os.listdir(nbext):
169 print(u" %s" % ext)
217 print(u" %s" % ext)
170 else:
218 else:
171 self.install_extensions()
219 self.install_extensions()
172
220
173
221
174 if __name__ == '__main__':
222 if __name__ == '__main__':
175 NBExtensionApp.launch_instance()
223 NBExtensionApp.launch_instance()
176 No newline at end of file
224
@@ -1,201 +1,234 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) 2014 The IPython Development Team
4 # Copyright (C) 2014 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
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
31 from IPython.html.nbextensions import install_nbextension
27 from IPython.html.nbextensions import install_nbextension
32
28
33 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
34 # Test functions
30 # Test functions
35 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
36
32
37 def touch(file, mtime=None):
33 def touch(file, mtime=None):
38 """ensure a file exists, and set its modification time
34 """ensure a file exists, and set its modification time
39
35
40 returns the modification time of the file
36 returns the modification time of the file
41 """
37 """
42 open(file, 'a').close()
38 open(file, 'a').close()
43 # set explicit mtime
39 # set explicit mtime
44 if mtime:
40 if mtime:
45 atime = os.stat(file).st_atime
41 atime = os.stat(file).st_atime
46 os.utime(file, (atime, mtime))
42 os.utime(file, (atime, mtime))
47 return os.stat(file).st_mtime
43 return os.stat(file).st_mtime
48
44
49
45
50 class TestInstallNBExtension(TestCase):
46 class TestInstallNBExtension(TestCase):
51
47
52 def tempdir(self):
48 def tempdir(self):
53 td = TemporaryDirectory()
49 td = TemporaryDirectory()
54 self.tempdirs.append(td)
50 self.tempdirs.append(td)
55 return py3compat.cast_unicode(td.name)
51 return py3compat.cast_unicode(td.name)
56
52
57 def setUp(self):
53 def setUp(self):
58 self.tempdirs = []
54 self.tempdirs = []
59 src = self.src = self.tempdir()
55 src = self.src = self.tempdir()
60 self.files = files = [
56 self.files = files = [
61 pjoin(u'Ζ’ile'),
57 pjoin(u'Ζ’ile'),
62 pjoin(u'βˆ‚ir', u'Ζ’ile1'),
58 pjoin(u'βˆ‚ir', u'Ζ’ile1'),
63 pjoin(u'βˆ‚ir', u'βˆ‚ir2', u'Ζ’ile2'),
59 pjoin(u'βˆ‚ir', u'βˆ‚ir2', u'Ζ’ile2'),
64 ]
60 ]
65 for file in files:
61 for file in files:
66 fullpath = os.path.join(self.src, file)
62 fullpath = os.path.join(self.src, file)
67 parent = os.path.dirname(fullpath)
63 parent = os.path.dirname(fullpath)
68 if not os.path.exists(parent):
64 if not os.path.exists(parent):
69 os.makedirs(parent)
65 os.makedirs(parent)
70 touch(fullpath)
66 touch(fullpath)
71
67
72 self.ipdir = self.tempdir()
68 self.ipdir = self.tempdir()
73 self.save_get_ipython_dir = nbextensions.get_ipython_dir
69 self.save_get_ipython_dir = nbextensions.get_ipython_dir
74 nbextensions.get_ipython_dir = lambda : self.ipdir
70 nbextensions.get_ipython_dir = lambda : self.ipdir
75
71
76 def tearDown(self):
72 def tearDown(self):
77 for td in self.tempdirs:
73 for td in self.tempdirs:
78 td.cleanup()
74 td.cleanup()
79 nbextensions.get_ipython_dir = self.save_get_ipython_dir
75 nbextensions.get_ipython_dir = self.save_get_ipython_dir
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):
87 self.fail(u"%s should not exist" % path)
84 self.fail(u"%s should not exist" % path)
88
85
89 def assert_installed(self, relative_path, ipdir=None):
86 def assert_installed(self, relative_path, ipdir=None):
90 self.assert_path_exists(
87 self.assert_path_exists(
91 pjoin(ipdir or self.ipdir, u'nbextensions', relative_path)
88 pjoin(ipdir or self.ipdir, u'nbextensions', relative_path)
92 )
89 )
93
90
94 def assert_not_installed(self, relative_path, ipdir=None):
91 def assert_not_installed(self, relative_path, ipdir=None):
95 self.assert_not_path_exists(
92 self.assert_not_path_exists(
96 pjoin(ipdir or self.ipdir, u'nbextensions', relative_path)
93 pjoin(ipdir or self.ipdir, u'nbextensions', relative_path)
97 )
94 )
98
95
99 def test_create_ipython_dir(self):
96 def test_create_ipython_dir(self):
100 """install_nbextension when ipython_dir doesn't exist"""
97 """install_nbextension when ipython_dir doesn't exist"""
101 with TemporaryDirectory() as td:
98 with TemporaryDirectory() as td:
102 ipdir = pjoin(td, u'ipython')
99 ipdir = pjoin(td, u'ipython')
103 install_nbextension(self.src, ipython_dir=ipdir)
100 install_nbextension(self.src, ipython_dir=ipdir)
104 self.assert_path_exists(ipdir)
101 self.assert_path_exists(ipdir)
105 for file in self.files:
102 for file in self.files:
106 self.assert_installed(
103 self.assert_installed(
107 pjoin(basename(self.src), file),
104 pjoin(basename(self.src), file),
108 ipdir
105 ipdir
109 )
106 )
110
107
111 def test_create_nbextensions(self):
108 def test_create_nbextensions(self):
112 with TemporaryDirectory() as ipdir:
109 with TemporaryDirectory() as ipdir:
113 install_nbextension(self.src, ipython_dir=ipdir)
110 install_nbextension(self.src, ipython_dir=ipdir)
114 self.assert_installed(
111 self.assert_installed(
115 pjoin(basename(self.src), u'Ζ’ile'),
112 pjoin(basename(self.src), u'Ζ’ile'),
116 ipdir
113 ipdir
117 )
114 )
118
115
119 def test_single_file(self):
116 def test_single_file(self):
120 file = self.files[0]
117 file = self.files[0]
121 install_nbextension(pjoin(self.src, file))
118 install_nbextension(pjoin(self.src, file))
122 self.assert_installed(file)
119 self.assert_installed(file)
123
120
124 def test_single_dir(self):
121 def test_single_dir(self):
125 d = u'βˆ‚ir'
122 d = u'βˆ‚ir'
126 install_nbextension(pjoin(self.src, d))
123 install_nbextension(pjoin(self.src, d))
127 self.assert_installed(self.files[-1])
124 self.assert_installed(self.files[-1])
128
125
129 def test_install_nbextension(self):
126 def test_install_nbextension(self):
130 install_nbextension(glob.glob(pjoin(self.src, '*')))
127 install_nbextension(glob.glob(pjoin(self.src, '*')))
131 for file in self.files:
128 for file in self.files:
132 self.assert_installed(file)
129 self.assert_installed(file)
133
130
134 def test_overwrite_file(self):
131 def test_overwrite_file(self):
135 with TemporaryDirectory() as d:
132 with TemporaryDirectory() as d:
136 fname = u'Ζ’.js'
133 fname = u'Ζ’.js'
137 src = pjoin(d, fname)
134 src = pjoin(d, fname)
138 with open(src, 'w') as f:
135 with open(src, 'w') as f:
139 f.write('first')
136 f.write('first')
140 mtime = touch(src)
137 mtime = touch(src)
141 dest = pjoin(self.ipdir, u'nbextensions', fname)
138 dest = pjoin(self.ipdir, u'nbextensions', fname)
142 install_nbextension(src)
139 install_nbextension(src)
143 with open(src, 'w') as f:
140 with open(src, 'w') as f:
144 f.write('overwrite')
141 f.write('overwrite')
145 mtime = touch(src, mtime - 100)
142 mtime = touch(src, mtime - 100)
146 install_nbextension(src, overwrite=True)
143 install_nbextension(src, overwrite=True)
147 with open(dest) as f:
144 with open(dest) as f:
148 self.assertEqual(f.read(), 'overwrite')
145 self.assertEqual(f.read(), 'overwrite')
149
146
150 def test_overwrite_dir(self):
147 def test_overwrite_dir(self):
151 with TemporaryDirectory() as src:
148 with TemporaryDirectory() as src:
152 # src = py3compat.cast_unicode_py2(src)
149 # src = py3compat.cast_unicode_py2(src)
153 base = basename(src)
150 base = basename(src)
154 fname = u'Ζ’.js'
151 fname = u'Ζ’.js'
155 touch(pjoin(src, fname))
152 touch(pjoin(src, fname))
156 install_nbextension(src)
153 install_nbextension(src)
157 self.assert_installed(pjoin(base, fname))
154 self.assert_installed(pjoin(base, fname))
158 os.remove(pjoin(src, fname))
155 os.remove(pjoin(src, fname))
159 fname2 = u'βˆ‚.js'
156 fname2 = u'βˆ‚.js'
160 touch(pjoin(src, fname2))
157 touch(pjoin(src, fname2))
161 install_nbextension(src, overwrite=True)
158 install_nbextension(src, overwrite=True)
162 self.assert_installed(pjoin(base, fname2))
159 self.assert_installed(pjoin(base, fname2))
163 self.assert_not_installed(pjoin(base, fname))
160 self.assert_not_installed(pjoin(base, fname))
164
161
165 def test_update_file(self):
162 def test_update_file(self):
166 with TemporaryDirectory() as d:
163 with TemporaryDirectory() as d:
167 fname = u'Ζ’.js'
164 fname = u'Ζ’.js'
168 src = pjoin(d, fname)
165 src = pjoin(d, fname)
169 with open(src, 'w') as f:
166 with open(src, 'w') as f:
170 f.write('first')
167 f.write('first')
171 mtime = touch(src)
168 mtime = touch(src)
172 install_nbextension(src)
169 install_nbextension(src)
173 self.assert_installed(fname)
170 self.assert_installed(fname)
174 dest = pjoin(self.ipdir, u'nbextensions', fname)
171 dest = pjoin(self.ipdir, u'nbextensions', fname)
175 old_mtime = os.stat(dest).st_mtime
172 old_mtime = os.stat(dest).st_mtime
176 with open(src, 'w') as f:
173 with open(src, 'w') as f:
177 f.write('overwrite')
174 f.write('overwrite')
178 touch(src, mtime + 10)
175 touch(src, mtime + 10)
179 install_nbextension(src)
176 install_nbextension(src)
180 with open(dest) as f:
177 with open(dest) as f:
181 self.assertEqual(f.read(), 'overwrite')
178 self.assertEqual(f.read(), 'overwrite')
182
179
183 def test_skip_old_file(self):
180 def test_skip_old_file(self):
184 with TemporaryDirectory() as d:
181 with TemporaryDirectory() as d:
185 fname = u'Ζ’.js'
182 fname = u'Ζ’.js'
186 src = pjoin(d, fname)
183 src = pjoin(d, fname)
187 mtime = touch(src)
184 mtime = touch(src)
188 install_nbextension(src)
185 install_nbextension(src)
189 self.assert_installed(fname)
186 self.assert_installed(fname)
190 dest = pjoin(self.ipdir, u'nbextensions', fname)
187 dest = pjoin(self.ipdir, u'nbextensions', fname)
191 old_mtime = os.stat(dest).st_mtime
188 old_mtime = os.stat(dest).st_mtime
192
189
193 mtime = touch(src, mtime - 100)
190 mtime = touch(src, mtime - 100)
194 install_nbextension(src)
191 install_nbextension(src)
195 new_mtime = os.stat(dest).st_mtime
192 new_mtime = os.stat(dest).st_mtime
196 self.assertEqual(new_mtime, old_mtime)
193 self.assertEqual(new_mtime, old_mtime)
197
194
198 def test_quiet(self):
195 def test_quiet(self):
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