for installing files into IPYTHONDIR/nbextensionspull/37/head
parent
47abe842b2
commit
704b349302
@ -0,0 +1,101 @@
|
||||
# coding: utf-8
|
||||
"""Utilities for installing Javascript extensions for the notebook"""
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (C) 2014 The IPython Development Team
|
||||
#
|
||||
# Distributed under the terms of the BSD License. The full license is in
|
||||
# the file COPYING, distributed as part of this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from os.path import basename, join as pjoin
|
||||
|
||||
from IPython.utils.path import get_ipython_dir
|
||||
from IPython.utils.py3compat import string_types, cast_unicode_py2
|
||||
|
||||
|
||||
def _should_copy(src, dest, verbose=1):
|
||||
"""should a file be copied?"""
|
||||
if not os.path.exists(dest):
|
||||
return True
|
||||
if os.stat(dest).st_mtime < os.stat(src).st_mtime:
|
||||
if verbose >= 2:
|
||||
print("%s is out of date" % dest)
|
||||
return True
|
||||
if verbose >= 2:
|
||||
print("%s is up to date" % dest)
|
||||
return False
|
||||
|
||||
|
||||
def _maybe_copy(src, dest, verbose=1):
|
||||
"""copy a file if it needs updating"""
|
||||
if _should_copy(src, dest, verbose):
|
||||
if verbose >= 1:
|
||||
print("copying %s -> %s" % (src, dest))
|
||||
shutil.copy2(src, dest)
|
||||
|
||||
|
||||
def install_nbextension(files, overwrite=False, ipython_dir=None, verbose=1):
|
||||
"""Install a Javascript extension for the notebook
|
||||
|
||||
Stages files and/or directories into IPYTHONDIR/nbextensions.
|
||||
By default, this comparse modification time, and only stages files that need updating.
|
||||
If `overwrite` is specified, matching files are purged before proceeding.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
files : list(paths)
|
||||
One or more paths to existing files or directories to install.
|
||||
These will be installed with their base name, so '/path/to/foo'
|
||||
will install to 'nbextensions/foo'.
|
||||
overwrite : bool [default: False]
|
||||
If True, always install the files, regardless of what may already be installed.
|
||||
ipython_dir : str [optional]
|
||||
The path to an IPython directory, if the default value is not desired.
|
||||
get_ipython_dir() is used by default.
|
||||
verbose : int [default: 1]
|
||||
Set verbosity level. The default is 1, where file actions are printed.
|
||||
set verbose=2 for more output, or verbose=0 for silence.
|
||||
"""
|
||||
|
||||
ipython_dir = ipython_dir or get_ipython_dir()
|
||||
nbext = pjoin(ipython_dir, u'nbextensions')
|
||||
# make sure nbextensions dir exists
|
||||
if not os.path.exists(nbext):
|
||||
os.makedirs(nbext)
|
||||
|
||||
if isinstance(files, string_types):
|
||||
# one file given, turn it into a list
|
||||
files = [files]
|
||||
|
||||
for path in map(cast_unicode_py2, files):
|
||||
dest = pjoin(nbext, basename(path))
|
||||
if overwrite and os.path.exists(dest):
|
||||
if verbose >= 1:
|
||||
print("removing %s" % dest)
|
||||
if os.path.isdir(dest):
|
||||
shutil.rmtree(dest)
|
||||
else:
|
||||
os.remove(dest)
|
||||
|
||||
if os.path.isdir(path):
|
||||
strip_prefix_len = len(path) - len(basename(path))
|
||||
for parent, dirs, files in os.walk(path):
|
||||
dest_dir = pjoin(nbext, parent[strip_prefix_len:])
|
||||
if not os.path.exists(dest_dir):
|
||||
if verbose >= 2:
|
||||
print("making directory %s" % dest_dir)
|
||||
os.makedirs(dest_dir)
|
||||
for file in files:
|
||||
src = pjoin(parent, file)
|
||||
# print("%r, %r" % (dest_dir, file))
|
||||
dest = pjoin(dest_dir, file)
|
||||
_maybe_copy(src, dest, verbose)
|
||||
else:
|
||||
src = path
|
||||
_maybe_copy(src, dest, verbose)
|
||||
@ -0,0 +1,201 @@
|
||||
# coding: utf-8
|
||||
"""Test installation of notebook extensions"""
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (C) 2014 The IPython Development Team
|
||||
#
|
||||
# Distributed under the terms of the BSD License. The full license is in
|
||||
# the file COPYING, distributed as part of this software.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Imports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from contextlib import contextmanager
|
||||
from os.path import basename, join as pjoin
|
||||
from unittest import TestCase
|
||||
|
||||
import nose.tools as nt
|
||||
|
||||
from IPython.external.decorator import decorator
|
||||
|
||||
import IPython.testing.tools as tt
|
||||
import IPython.utils.path
|
||||
from IPython.utils import py3compat
|
||||
from IPython.utils.tempdir import TemporaryDirectory
|
||||
from IPython.html import nbextensions
|
||||
from IPython.html.nbextensions import install_nbextension
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Test functions
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def touch(file, mtime=None):
|
||||
"""ensure a file exists, and set its modification time
|
||||
|
||||
returns the modification time of the file
|
||||
"""
|
||||
open(file, 'a').close()
|
||||
# set explicit mtime
|
||||
if mtime:
|
||||
atime = os.stat(file).st_atime
|
||||
os.utime(file, (atime, mtime))
|
||||
return os.stat(file).st_mtime
|
||||
|
||||
|
||||
class TestInstallNBExtension(TestCase):
|
||||
|
||||
def tempdir(self):
|
||||
td = TemporaryDirectory()
|
||||
self.tempdirs.append(td)
|
||||
return py3compat.cast_unicode(td.name)
|
||||
|
||||
def setUp(self):
|
||||
self.tempdirs = []
|
||||
src = self.src = self.tempdir()
|
||||
self.files = files = [
|
||||
pjoin(u'ƒile'),
|
||||
pjoin(u'∂ir', u'ƒile1'),
|
||||
pjoin(u'∂ir', u'∂ir2', u'ƒile2'),
|
||||
]
|
||||
for file in files:
|
||||
fullpath = os.path.join(self.src, file)
|
||||
parent = os.path.dirname(fullpath)
|
||||
if not os.path.exists(parent):
|
||||
os.makedirs(parent)
|
||||
touch(fullpath)
|
||||
|
||||
self.ipdir = self.tempdir()
|
||||
self.save_get_ipython_dir = nbextensions.get_ipython_dir
|
||||
nbextensions.get_ipython_dir = lambda : self.ipdir
|
||||
|
||||
def tearDown(self):
|
||||
for td in self.tempdirs:
|
||||
td.cleanup()
|
||||
nbextensions.get_ipython_dir = self.save_get_ipython_dir
|
||||
|
||||
def assert_path_exists(self, path):
|
||||
if not os.path.exists(path):
|
||||
self.fail(u"%s should exist" % path)
|
||||
|
||||
def assert_not_path_exists(self, path):
|
||||
if os.path.exists(path):
|
||||
self.fail(u"%s should not exist" % path)
|
||||
|
||||
def assert_installed(self, relative_path, ipdir=None):
|
||||
self.assert_path_exists(
|
||||
pjoin(ipdir or self.ipdir, u'nbextensions', relative_path)
|
||||
)
|
||||
|
||||
def assert_not_installed(self, relative_path, ipdir=None):
|
||||
self.assert_not_path_exists(
|
||||
pjoin(ipdir or self.ipdir, u'nbextensions', relative_path)
|
||||
)
|
||||
|
||||
def test_create_ipython_dir(self):
|
||||
"""install_nbextension when ipython_dir doesn't exist"""
|
||||
with TemporaryDirectory() as td:
|
||||
ipdir = pjoin(td, u'ipython')
|
||||
install_nbextension(self.src, ipython_dir=ipdir)
|
||||
self.assert_path_exists(ipdir)
|
||||
for file in self.files:
|
||||
self.assert_installed(
|
||||
pjoin(basename(self.src), file),
|
||||
ipdir
|
||||
)
|
||||
|
||||
def test_create_nbextensions(self):
|
||||
with TemporaryDirectory() as ipdir:
|
||||
install_nbextension(self.src, ipython_dir=ipdir)
|
||||
self.assert_installed(
|
||||
pjoin(basename(self.src), u'ƒile'),
|
||||
ipdir
|
||||
)
|
||||
|
||||
def test_single_file(self):
|
||||
file = self.files[0]
|
||||
install_nbextension(pjoin(self.src, file))
|
||||
self.assert_installed(file)
|
||||
|
||||
def test_single_dir(self):
|
||||
d = u'∂ir'
|
||||
install_nbextension(pjoin(self.src, d))
|
||||
self.assert_installed(self.files[-1])
|
||||
|
||||
def test_install_nbextension(self):
|
||||
install_nbextension(glob.glob(pjoin(self.src, '*')))
|
||||
for file in self.files:
|
||||
self.assert_installed(file)
|
||||
|
||||
def test_overwrite_file(self):
|
||||
with TemporaryDirectory() as d:
|
||||
fname = u'ƒ.js'
|
||||
src = pjoin(d, fname)
|
||||
with open(src, 'w') as f:
|
||||
f.write('first')
|
||||
mtime = touch(src)
|
||||
dest = pjoin(self.ipdir, u'nbextensions', fname)
|
||||
install_nbextension(src)
|
||||
with open(src, 'w') as f:
|
||||
f.write('overwrite')
|
||||
mtime = touch(src, mtime - 100)
|
||||
install_nbextension(src, overwrite=True)
|
||||
with open(dest) as f:
|
||||
self.assertEqual(f.read(), 'overwrite')
|
||||
|
||||
def test_overwrite_dir(self):
|
||||
with TemporaryDirectory() as src:
|
||||
# src = py3compat.cast_unicode_py2(src)
|
||||
base = basename(src)
|
||||
fname = u'ƒ.js'
|
||||
touch(pjoin(src, fname))
|
||||
install_nbextension(src)
|
||||
self.assert_installed(pjoin(base, fname))
|
||||
os.remove(pjoin(src, fname))
|
||||
fname2 = u'∂.js'
|
||||
touch(pjoin(src, fname2))
|
||||
install_nbextension(src, overwrite=True)
|
||||
self.assert_installed(pjoin(base, fname2))
|
||||
self.assert_not_installed(pjoin(base, fname))
|
||||
|
||||
def test_update_file(self):
|
||||
with TemporaryDirectory() as d:
|
||||
fname = u'ƒ.js'
|
||||
src = pjoin(d, fname)
|
||||
with open(src, 'w') as f:
|
||||
f.write('first')
|
||||
mtime = touch(src)
|
||||
install_nbextension(src)
|
||||
self.assert_installed(fname)
|
||||
dest = pjoin(self.ipdir, u'nbextensions', fname)
|
||||
old_mtime = os.stat(dest).st_mtime
|
||||
with open(src, 'w') as f:
|
||||
f.write('overwrite')
|
||||
touch(src, mtime + 10)
|
||||
install_nbextension(src)
|
||||
with open(dest) as f:
|
||||
self.assertEqual(f.read(), 'overwrite')
|
||||
|
||||
def test_skip_old_file(self):
|
||||
with TemporaryDirectory() as d:
|
||||
fname = u'ƒ.js'
|
||||
src = pjoin(d, fname)
|
||||
mtime = touch(src)
|
||||
install_nbextension(src)
|
||||
self.assert_installed(fname)
|
||||
dest = pjoin(self.ipdir, u'nbextensions', fname)
|
||||
old_mtime = os.stat(dest).st_mtime
|
||||
|
||||
mtime = touch(src, mtime - 100)
|
||||
install_nbextension(src)
|
||||
new_mtime = os.stat(dest).st_mtime
|
||||
self.assertEqual(new_mtime, old_mtime)
|
||||
|
||||
def test_quiet(self):
|
||||
with tt.AssertNotPrints(re.compile(r'.+')):
|
||||
install_nbextension(self.src, verbose=0)
|
||||
|
||||
Loading…
Reference in new issue