##// END OF EJS Templates
Don't trap any copying errors - allow them to bubble up.
Jason Grout -
Show More
@@ -1,361 +1,358 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 # 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 from __future__ import print_function
7 from __future__ import print_function
8
8
9 import os
9 import os
10 import shutil
10 import shutil
11 import sys
11 import sys
12 import tarfile
12 import tarfile
13 import zipfile
13 import zipfile
14 import uuid
14 import uuid
15 from os.path import basename, join as pjoin
15 from os.path import basename, join as pjoin
16
16
17 # Deferred imports
17 # Deferred imports
18 try:
18 try:
19 from urllib.parse import urlparse # Py3
19 from urllib.parse import urlparse # Py3
20 from urllib.request import urlretrieve
20 from urllib.request import urlretrieve
21 except ImportError:
21 except ImportError:
22 from urlparse import urlparse
22 from urlparse import urlparse
23 from urllib import urlretrieve
23 from urllib import urlretrieve
24
24
25 from IPython.utils.path import get_ipython_dir, ensure_dir_exists
25 from IPython.utils.path import get_ipython_dir, ensure_dir_exists
26 from IPython.utils.py3compat import string_types, cast_unicode_py2
26 from IPython.utils.py3compat import string_types, cast_unicode_py2
27 from IPython.utils.tempdir import TemporaryDirectory
27 from IPython.utils.tempdir import TemporaryDirectory
28
28
29 class ArgumentConflict(ValueError):
29 class ArgumentConflict(ValueError):
30 pass
30 pass
31
31
32 # Packagers: modify the next block if you store system-installed nbextensions elsewhere (unlikely)
32 # Packagers: modify the next block if you store system-installed nbextensions elsewhere (unlikely)
33 SYSTEM_NBEXTENSIONS_DIRS = []
33 SYSTEM_NBEXTENSIONS_DIRS = []
34
34
35 if os.name == 'nt':
35 if os.name == 'nt':
36 programdata = os.environ.get('PROGRAMDATA', None)
36 programdata = os.environ.get('PROGRAMDATA', None)
37 if programdata: # PROGRAMDATA is not defined by default on XP.
37 if programdata: # PROGRAMDATA is not defined by default on XP.
38 SYSTEM_NBEXTENSIONS_DIRS = [pjoin(programdata, 'jupyter', 'nbextensions')]
38 SYSTEM_NBEXTENSIONS_DIRS = [pjoin(programdata, 'jupyter', 'nbextensions')]
39 prefixes = []
39 prefixes = []
40 else:
40 else:
41 prefixes = [os.path.sep + pjoin('usr', 'local'), os.path.sep + 'usr']
41 prefixes = [os.path.sep + pjoin('usr', 'local'), os.path.sep + 'usr']
42
42
43 # add sys.prefix at the front
43 # add sys.prefix at the front
44 if sys.prefix not in prefixes:
44 if sys.prefix not in prefixes:
45 prefixes.insert(0, sys.prefix)
45 prefixes.insert(0, sys.prefix)
46
46
47 for prefix in prefixes:
47 for prefix in prefixes:
48 nbext = pjoin(prefix, 'share', 'jupyter', 'nbextensions')
48 nbext = pjoin(prefix, 'share', 'jupyter', 'nbextensions')
49 if nbext not in SYSTEM_NBEXTENSIONS_DIRS:
49 if nbext not in SYSTEM_NBEXTENSIONS_DIRS:
50 SYSTEM_NBEXTENSIONS_DIRS.append(nbext)
50 SYSTEM_NBEXTENSIONS_DIRS.append(nbext)
51
51
52 if os.name == 'nt':
52 if os.name == 'nt':
53 # PROGRAMDATA
53 # PROGRAMDATA
54 SYSTEM_NBEXTENSIONS_INSTALL_DIR = SYSTEM_NBEXTENSIONS_DIRS[-1]
54 SYSTEM_NBEXTENSIONS_INSTALL_DIR = SYSTEM_NBEXTENSIONS_DIRS[-1]
55 else:
55 else:
56 # /usr/local
56 # /usr/local
57 SYSTEM_NBEXTENSIONS_INSTALL_DIR = SYSTEM_NBEXTENSIONS_DIRS[-2]
57 SYSTEM_NBEXTENSIONS_INSTALL_DIR = SYSTEM_NBEXTENSIONS_DIRS[-2]
58
58
59
59
60 def _should_copy(src, dest, verbose=1):
60 def _should_copy(src, dest, verbose=1):
61 """should a file be copied?"""
61 """should a file be copied?"""
62 if not os.path.exists(dest):
62 if not os.path.exists(dest):
63 return True
63 return True
64 if os.stat(src).st_mtime - os.stat(dest).st_mtime > 1e-6:
64 if os.stat(src).st_mtime - os.stat(dest).st_mtime > 1e-6:
65 # we add a fudge factor to work around a bug in python 2.x
65 # we add a fudge factor to work around a bug in python 2.x
66 # that was fixed in python 3.x: http://bugs.python.org/issue12904
66 # that was fixed in python 3.x: http://bugs.python.org/issue12904
67 if verbose >= 2:
67 if verbose >= 2:
68 print("%s is out of date" % dest)
68 print("%s is out of date" % dest)
69 return True
69 return True
70 if verbose >= 2:
70 if verbose >= 2:
71 print("%s is up to date" % dest)
71 print("%s is up to date" % dest)
72 return False
72 return False
73
73
74
74
75 def _maybe_copy(src, dest, verbose=1):
75 def _maybe_copy(src, dest, verbose=1):
76 """copy a file if it needs updating"""
76 """copy a file if it needs updating"""
77 if _should_copy(src, dest, verbose):
77 if _should_copy(src, dest, verbose):
78 if verbose >= 1:
78 if verbose >= 1:
79 print("copying %s -> %s" % (src, dest))
79 print("copying %s -> %s" % (src, dest))
80 try:
80 shutil.copy2(src, dest)
81 shutil.copy2(src, dest)
82 except IOError as e:
83 print(str(e), file=sys.stderr)
84
81
85 def _safe_is_tarfile(path):
82 def _safe_is_tarfile(path):
86 """safe version of is_tarfile, return False on IOError"""
83 """safe version of is_tarfile, return False on IOError"""
87 try:
84 try:
88 return tarfile.is_tarfile(path)
85 return tarfile.is_tarfile(path)
89 except IOError:
86 except IOError:
90 return False
87 return False
91
88
92
89
93 def _get_nbext_dir(nbextensions_dir=None, user=False, prefix=None):
90 def _get_nbext_dir(nbextensions_dir=None, user=False, prefix=None):
94 """Return the nbextension directory specified"""
91 """Return the nbextension directory specified"""
95 if sum(map(bool, [user, prefix, nbextensions_dir])) > 1:
92 if sum(map(bool, [user, prefix, nbextensions_dir])) > 1:
96 raise ArgumentConflict("Cannot specify more than one of user, prefix, or nbextensions_dir.")
93 raise ArgumentConflict("Cannot specify more than one of user, prefix, or nbextensions_dir.")
97 if user:
94 if user:
98 nbext = pjoin(get_ipython_dir(), u'nbextensions')
95 nbext = pjoin(get_ipython_dir(), u'nbextensions')
99 else:
96 else:
100 if prefix:
97 if prefix:
101 nbext = pjoin(prefix, 'share', 'jupyter', 'nbextensions')
98 nbext = pjoin(prefix, 'share', 'jupyter', 'nbextensions')
102 elif nbextensions_dir:
99 elif nbextensions_dir:
103 nbext = nbextensions_dir
100 nbext = nbextensions_dir
104 else:
101 else:
105 nbext = SYSTEM_NBEXTENSIONS_INSTALL_DIR
102 nbext = SYSTEM_NBEXTENSIONS_INSTALL_DIR
106 return nbext
103 return nbext
107
104
108
105
109 def check_nbextension(files, user=False, prefix=None, nbextensions_dir=None):
106 def check_nbextension(files, user=False, prefix=None, nbextensions_dir=None):
110 """Check whether nbextension files have been installed
107 """Check whether nbextension files have been installed
111
108
112 Returns True if all files are found, False if any are missing.
109 Returns True if all files are found, False if any are missing.
113
110
114 Parameters
111 Parameters
115 ----------
112 ----------
116
113
117 files : list(paths)
114 files : list(paths)
118 a list of relative paths within nbextensions.
115 a list of relative paths within nbextensions.
119 user : bool [default: False]
116 user : bool [default: False]
120 Whether to check the user's .ipython/nbextensions directory.
117 Whether to check the user's .ipython/nbextensions directory.
121 Otherwise check a system-wide install (e.g. /usr/local/share/jupyter/nbextensions).
118 Otherwise check a system-wide install (e.g. /usr/local/share/jupyter/nbextensions).
122 prefix : str [optional]
119 prefix : str [optional]
123 Specify install prefix, if it should differ from default (e.g. /usr/local).
120 Specify install prefix, if it should differ from default (e.g. /usr/local).
124 Will check prefix/share/jupyter/nbextensions
121 Will check prefix/share/jupyter/nbextensions
125 nbextensions_dir : str [optional]
122 nbextensions_dir : str [optional]
126 Specify absolute path of nbextensions directory explicitly.
123 Specify absolute path of nbextensions directory explicitly.
127 """
124 """
128 nbext = _get_nbext_dir(nbextensions_dir, user, prefix)
125 nbext = _get_nbext_dir(nbextensions_dir, user, prefix)
129 # make sure nbextensions dir exists
126 # make sure nbextensions dir exists
130 if not os.path.exists(nbext):
127 if not os.path.exists(nbext):
131 return False
128 return False
132
129
133 if isinstance(files, string_types):
130 if isinstance(files, string_types):
134 # one file given, turn it into a list
131 # one file given, turn it into a list
135 files = [files]
132 files = [files]
136
133
137 return all(os.path.exists(pjoin(nbext, f)) for f in files)
134 return all(os.path.exists(pjoin(nbext, f)) for f in files)
138
135
139
136
140 def install_nbextension(files, overwrite=False, symlink=False, user=False, prefix=None, nbextensions_dir=None, verbose=1):
137 def install_nbextension(files, overwrite=False, symlink=False, user=False, prefix=None, nbextensions_dir=None, verbose=1):
141 """Install a Javascript extension for the notebook
138 """Install a Javascript extension for the notebook
142
139
143 Stages files and/or directories into the nbextensions directory.
140 Stages files and/or directories into the nbextensions directory.
144 By default, this compares modification time, and only stages files that need updating.
141 By default, this compares modification time, and only stages files that need updating.
145 If `overwrite` is specified, matching files are purged before proceeding.
142 If `overwrite` is specified, matching files are purged before proceeding.
146
143
147 Parameters
144 Parameters
148 ----------
145 ----------
149
146
150 files : list(paths or URLs) or dict(install_name: path or URL)
147 files : list(paths or URLs) or dict(install_name: path or URL)
151 One or more paths or URLs to existing files directories to install.
148 One or more paths or URLs to existing files directories to install.
152 If given as a list, these will be installed with their base name, so '/path/to/foo'
149 If given as a list, these will be installed with their base name, so '/path/to/foo'
153 will install to 'nbextensions/foo'. If given as a dict, such as {'bar': '/path/to/foo'},
150 will install to 'nbextensions/foo'. If given as a dict, such as {'bar': '/path/to/foo'},
154 then '/path/to/foo' will install to 'nbextensions/bar'.
151 then '/path/to/foo' will install to 'nbextensions/bar'.
155 Archives (zip or tarballs) will be extracted into the nbextensions directory.
152 Archives (zip or tarballs) will be extracted into the nbextensions directory.
156 overwrite : bool [default: False]
153 overwrite : bool [default: False]
157 If True, always install the files, regardless of what may already be installed.
154 If True, always install the files, regardless of what may already be installed.
158 symlink : bool [default: False]
155 symlink : bool [default: False]
159 If True, create a symlink in nbextensions, rather than copying files.
156 If True, create a symlink in nbextensions, rather than copying files.
160 Not allowed with URLs or archives. Windows support for symlinks requires
157 Not allowed with URLs or archives. Windows support for symlinks requires
161 Vista or above, Python 3, and a permission bit which only admin users
158 Vista or above, Python 3, and a permission bit which only admin users
162 have by default, so don't rely on it.
159 have by default, so don't rely on it.
163 user : bool [default: False]
160 user : bool [default: False]
164 Whether to install to the user's .ipython/nbextensions directory.
161 Whether to install to the user's .ipython/nbextensions directory.
165 Otherwise do a system-wide install (e.g. /usr/local/share/jupyter/nbextensions).
162 Otherwise do a system-wide install (e.g. /usr/local/share/jupyter/nbextensions).
166 prefix : str [optional]
163 prefix : str [optional]
167 Specify install prefix, if it should differ from default (e.g. /usr/local).
164 Specify install prefix, if it should differ from default (e.g. /usr/local).
168 Will install to prefix/share/jupyter/nbextensions
165 Will install to prefix/share/jupyter/nbextensions
169 nbextensions_dir : str [optional]
166 nbextensions_dir : str [optional]
170 Specify absolute path of nbextensions directory explicitly.
167 Specify absolute path of nbextensions directory explicitly.
171 verbose : int [default: 1]
168 verbose : int [default: 1]
172 Set verbosity level. The default is 1, where file actions are printed.
169 Set verbosity level. The default is 1, where file actions are printed.
173 set verbose=2 for more output, or verbose=0 for silence.
170 set verbose=2 for more output, or verbose=0 for silence.
174 """
171 """
175 nbext = _get_nbext_dir(nbextensions_dir, user, prefix)
172 nbext = _get_nbext_dir(nbextensions_dir, user, prefix)
176 # make sure nbextensions dir exists
173 # make sure nbextensions dir exists
177 ensure_dir_exists(nbext)
174 ensure_dir_exists(nbext)
178
175
179 if isinstance(files, string_types):
176 if isinstance(files, string_types):
180 # one file given, turn it into a list
177 # one file given, turn it into a list
181 files = [files]
178 files = [files]
182 if isinstance(files, (list,tuple)):
179 if isinstance(files, (list,tuple)):
183 # list given, turn into dict
180 # list given, turn into dict
184 _files = {}
181 _files = {}
185 for path in map(cast_unicode_py2, files):
182 for path in map(cast_unicode_py2, files):
186 if path.startswith(('https://', 'http://')):
183 if path.startswith(('https://', 'http://')):
187 destination = urlparse(path).path.split('/')[-1]
184 destination = urlparse(path).path.split('/')[-1]
188 elif path.endswith('.zip') or _safe_is_tarfile(path):
185 elif path.endswith('.zip') or _safe_is_tarfile(path):
189 destination = str(uuid.uuid4()) # ignored for archives
186 destination = str(uuid.uuid4()) # ignored for archives
190 else:
187 else:
191 destination = basename(path)
188 destination = basename(path)
192 _files[destination] = path
189 _files[destination] = path
193 files = _files
190 files = _files
194
191
195 for dest_basename,path in (map(cast_unicode_py2, item) for item in files.items()):
192 for dest_basename,path in (map(cast_unicode_py2, item) for item in files.items()):
196
193
197 if path.startswith(('https://', 'http://')):
194 if path.startswith(('https://', 'http://')):
198 if symlink:
195 if symlink:
199 raise ValueError("Cannot symlink from URLs")
196 raise ValueError("Cannot symlink from URLs")
200 # Given a URL, download it
197 # Given a URL, download it
201 with TemporaryDirectory() as td:
198 with TemporaryDirectory() as td:
202 filename = urlparse(path).path.split('/')[-1]
199 filename = urlparse(path).path.split('/')[-1]
203 local_path = os.path.join(td, filename)
200 local_path = os.path.join(td, filename)
204 if verbose >= 1:
201 if verbose >= 1:
205 print("downloading %s to %s" % (path, local_path))
202 print("downloading %s to %s" % (path, local_path))
206 urlretrieve(path, local_path)
203 urlretrieve(path, local_path)
207 # now install from the local copy
204 # now install from the local copy
208 install_nbextension({dest_basename: local_path}, overwrite=overwrite, symlink=symlink, nbextensions_dir=nbext, verbose=verbose)
205 install_nbextension({dest_basename: local_path}, overwrite=overwrite, symlink=symlink, nbextensions_dir=nbext, verbose=verbose)
209 continue
206 continue
210
207
211 # handle archives
208 # handle archives
212 archive = None
209 archive = None
213 if path.endswith('.zip'):
210 if path.endswith('.zip'):
214 archive = zipfile.ZipFile(path)
211 archive = zipfile.ZipFile(path)
215 elif _safe_is_tarfile(path):
212 elif _safe_is_tarfile(path):
216 archive = tarfile.open(path)
213 archive = tarfile.open(path)
217
214
218 if archive:
215 if archive:
219 if symlink:
216 if symlink:
220 raise ValueError("Cannot symlink from archives")
217 raise ValueError("Cannot symlink from archives")
221 if verbose >= 1:
218 if verbose >= 1:
222 print("extracting %s to %s" % (path, nbext))
219 print("extracting %s to %s" % (path, nbext))
223 archive.extractall(nbext)
220 archive.extractall(nbext)
224 archive.close()
221 archive.close()
225 continue
222 continue
226
223
227 dest = pjoin(nbext, dest_basename)
224 dest = pjoin(nbext, dest_basename)
228 if overwrite and os.path.exists(dest):
225 if overwrite and os.path.exists(dest):
229 if verbose >= 1:
226 if verbose >= 1:
230 print("removing %s" % dest)
227 print("removing %s" % dest)
231 if os.path.isdir(dest) and not os.path.islink(dest):
228 if os.path.isdir(dest) and not os.path.islink(dest):
232 shutil.rmtree(dest)
229 shutil.rmtree(dest)
233 else:
230 else:
234 os.remove(dest)
231 os.remove(dest)
235
232
236 if symlink:
233 if symlink:
237 path = os.path.abspath(path)
234 path = os.path.abspath(path)
238 if not os.path.exists(dest):
235 if not os.path.exists(dest):
239 if verbose >= 1:
236 if verbose >= 1:
240 print("symlink %s -> %s" % (dest, path))
237 print("symlink %s -> %s" % (dest, path))
241 os.symlink(path, dest)
238 os.symlink(path, dest)
242 continue
239 continue
243
240
244 if os.path.isdir(path):
241 if os.path.isdir(path):
245 path = pjoin(os.path.abspath(path), '') # end in path separator
242 path = pjoin(os.path.abspath(path), '') # end in path separator
246 for parent, dirs, files in os.walk(path):
243 for parent, dirs, files in os.walk(path):
247 dest_dir = pjoin(dest, parent[len(path):])
244 dest_dir = pjoin(dest, parent[len(path):])
248 if not os.path.exists(dest_dir):
245 if not os.path.exists(dest_dir):
249 if verbose >= 2:
246 if verbose >= 2:
250 print("making directory %s" % dest_dir)
247 print("making directory %s" % dest_dir)
251 os.makedirs(dest_dir)
248 os.makedirs(dest_dir)
252 for file in files:
249 for file in files:
253 src = pjoin(parent, file)
250 src = pjoin(parent, file)
254 # print("%r, %r" % (dest_dir, file))
251 # print("%r, %r" % (dest_dir, file))
255 dest_file = pjoin(dest_dir, file)
252 dest_file = pjoin(dest_dir, file)
256 _maybe_copy(src, dest_file, verbose)
253 _maybe_copy(src, dest_file, verbose)
257 else:
254 else:
258 src = path
255 src = path
259 _maybe_copy(src, dest, verbose)
256 _maybe_copy(src, dest, verbose)
260
257
261 #----------------------------------------------------------------------
258 #----------------------------------------------------------------------
262 # install nbextension app
259 # install nbextension app
263 #----------------------------------------------------------------------
260 #----------------------------------------------------------------------
264
261
265 from IPython.utils.traitlets import Bool, Enum, Unicode, TraitError
262 from IPython.utils.traitlets import Bool, Enum, Unicode, TraitError
266 from IPython.core.application import BaseIPythonApplication
263 from IPython.core.application import BaseIPythonApplication
267
264
268 flags = {
265 flags = {
269 "overwrite" : ({
266 "overwrite" : ({
270 "NBExtensionApp" : {
267 "NBExtensionApp" : {
271 "overwrite" : True,
268 "overwrite" : True,
272 }}, "Force overwrite of existing files"
269 }}, "Force overwrite of existing files"
273 ),
270 ),
274 "debug" : ({
271 "debug" : ({
275 "NBExtensionApp" : {
272 "NBExtensionApp" : {
276 "verbose" : 2,
273 "verbose" : 2,
277 }}, "Extra output"
274 }}, "Extra output"
278 ),
275 ),
279 "quiet" : ({
276 "quiet" : ({
280 "NBExtensionApp" : {
277 "NBExtensionApp" : {
281 "verbose" : 0,
278 "verbose" : 0,
282 }}, "Minimal output"
279 }}, "Minimal output"
283 ),
280 ),
284 "symlink" : ({
281 "symlink" : ({
285 "NBExtensionApp" : {
282 "NBExtensionApp" : {
286 "symlink" : True,
283 "symlink" : True,
287 }}, "Create symlinks instead of copying files"
284 }}, "Create symlinks instead of copying files"
288 ),
285 ),
289 "user" : ({
286 "user" : ({
290 "NBExtensionApp" : {
287 "NBExtensionApp" : {
291 "user" : True,
288 "user" : True,
292 }}, "Install to the user's IPython directory"
289 }}, "Install to the user's IPython directory"
293 ),
290 ),
294 }
291 }
295 flags['s'] = flags['symlink']
292 flags['s'] = flags['symlink']
296
293
297 aliases = {
294 aliases = {
298 "ipython-dir" : "NBExtensionApp.ipython_dir",
295 "ipython-dir" : "NBExtensionApp.ipython_dir",
299 "prefix" : "NBExtensionApp.prefix",
296 "prefix" : "NBExtensionApp.prefix",
300 "nbextensions" : "NBExtensionApp.nbextensions_dir",
297 "nbextensions" : "NBExtensionApp.nbextensions_dir",
301 }
298 }
302
299
303 class NBExtensionApp(BaseIPythonApplication):
300 class NBExtensionApp(BaseIPythonApplication):
304 """Entry point for installing notebook extensions"""
301 """Entry point for installing notebook extensions"""
305
302
306 description = """Install IPython notebook extensions
303 description = """Install IPython notebook extensions
307
304
308 Usage
305 Usage
309
306
310 ipython install-nbextension file [more files, folders, archives or urls]
307 ipython install-nbextension file [more files, folders, archives or urls]
311
308
312 This copies files and/or folders into the IPython nbextensions directory.
309 This copies files and/or folders into the IPython nbextensions directory.
313 If a URL is given, it will be downloaded.
310 If a URL is given, it will be downloaded.
314 If an archive is given, it will be extracted into nbextensions.
311 If an archive is given, it will be extracted into nbextensions.
315 If the requested files are already up to date, no action is taken
312 If the requested files are already up to date, no action is taken
316 unless --overwrite is specified.
313 unless --overwrite is specified.
317 """
314 """
318
315
319 examples = """
316 examples = """
320 ipython install-nbextension /path/to/d3.js /path/to/myextension
317 ipython install-nbextension /path/to/d3.js /path/to/myextension
321 """
318 """
322 aliases = aliases
319 aliases = aliases
323 flags = flags
320 flags = flags
324
321
325 overwrite = Bool(False, config=True, help="Force overwrite of existing files")
322 overwrite = Bool(False, config=True, help="Force overwrite of existing files")
326 symlink = Bool(False, config=True, help="Create symlinks instead of copying files")
323 symlink = Bool(False, config=True, help="Create symlinks instead of copying files")
327 user = Bool(False, config=True, help="Whether to do a user install")
324 user = Bool(False, config=True, help="Whether to do a user install")
328 prefix = Unicode('', config=True, help="Installation prefix")
325 prefix = Unicode('', config=True, help="Installation prefix")
329 nbextensions_dir = Unicode('', config=True, help="Full path to nbextensions dir (probably use prefix or user)")
326 nbextensions_dir = Unicode('', config=True, help="Full path to nbextensions dir (probably use prefix or user)")
330 verbose = Enum((0,1,2), default_value=1, config=True,
327 verbose = Enum((0,1,2), default_value=1, config=True,
331 help="Verbosity level"
328 help="Verbosity level"
332 )
329 )
333
330
334 def install_extensions(self):
331 def install_extensions(self):
335 install_nbextension(self.extra_args,
332 install_nbextension(self.extra_args,
336 overwrite=self.overwrite,
333 overwrite=self.overwrite,
337 symlink=self.symlink,
334 symlink=self.symlink,
338 verbose=self.verbose,
335 verbose=self.verbose,
339 user=self.user,
336 user=self.user,
340 prefix=self.prefix,
337 prefix=self.prefix,
341 nbextensions_dir=self.nbextensions_dir,
338 nbextensions_dir=self.nbextensions_dir,
342 )
339 )
343
340
344 def start(self):
341 def start(self):
345 if not self.extra_args:
342 if not self.extra_args:
346 for nbext in [pjoin(self.ipython_dir, u'nbextensions')] + SYSTEM_NBEXTENSIONS_DIRS:
343 for nbext in [pjoin(self.ipython_dir, u'nbextensions')] + SYSTEM_NBEXTENSIONS_DIRS:
347 if os.path.exists(nbext):
344 if os.path.exists(nbext):
348 print("Notebook extensions in %s:" % nbext)
345 print("Notebook extensions in %s:" % nbext)
349 for ext in os.listdir(nbext):
346 for ext in os.listdir(nbext):
350 print(u" %s" % ext)
347 print(u" %s" % ext)
351 else:
348 else:
352 try:
349 try:
353 self.install_extensions()
350 self.install_extensions()
354 except ArgumentConflict as e:
351 except ArgumentConflict as e:
355 print(str(e), file=sys.stderr)
352 print(str(e), file=sys.stderr)
356 self.exit(1)
353 self.exit(1)
357
354
358
355
359 if __name__ == '__main__':
356 if __name__ == '__main__':
360 NBExtensionApp.launch_instance()
357 NBExtensionApp.launch_instance()
361
358
General Comments 0
You need to be logged in to leave comments. Login now