| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809 |
- """Test installation of JupyterLab extensions"""
- # Copyright (c) Jupyter Development Team.
- # Distributed under the terms of the Modified BSD License.
- import glob
- import json
- import logging
- import os
- import platform
- import shutil
- import subprocess
- import sys
- from os.path import join as pjoin
- from pathlib import Path
- from tempfile import TemporaryDirectory
- from unittest import TestCase
- from unittest.mock import patch
- import pytest
- from jupyter_core import paths
- from jupyterlab import commands
- from jupyterlab.commands import (
- DEV_DIR,
- AppOptions,
- _compare_ranges,
- _test_overlap,
- build,
- build_check,
- check_extension,
- disable_extension,
- enable_extension,
- get_app_info,
- get_app_version,
- install_extension,
- link_package,
- list_extensions,
- lock_extension,
- uninstall_extension,
- unlink_package,
- unlock_extension,
- update_extension,
- )
- from jupyterlab.coreconfig import CoreConfig, _get_default_core_data
- here = os.path.dirname(os.path.abspath(__file__))
- def touch(file, mtime=None):
- """ensure a file exists, and set its modification time
- returns the modification time of the file
- """
- dirname = os.path.dirname(file)
- if not os.path.exists(dirname):
- os.makedirs(dirname)
- 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
- # @pytest.fixture()
- # def resource():
- # print("setup")
- # yield "resource"
- # print("teardown")
- class AppHandlerTest(TestCase):
- def tempdir(self):
- td = TemporaryDirectory()
- self.tempdirs.append(td)
- return td.name
- def setUp(self):
- # Any TemporaryDirectory objects appended to this list will be cleaned
- # up at the end of the test run.
- self.tempdirs = []
- self.devnull = open(os.devnull, "w") # noqa
- @self.addCleanup
- def cleanup_tempdirs():
- for d in self.tempdirs:
- d.cleanup()
- self.test_dir = self.tempdir()
- self.data_dir = pjoin(self.test_dir, "data")
- self.config_dir = pjoin(self.test_dir, "config")
- self.pkg_names = {}
- # Copy in the mock packages.
- for name in ["extension", "incompat", "package", "mimeextension"]:
- src = pjoin(here, "mock_packages", name)
- def ignore(dname, files):
- if "node_modules" in dname:
- files = []
- if "node_modules" in files:
- files.remove("node_modules")
- return dname, files
- dest = pjoin(self.test_dir, name)
- shutil.copytree(src, dest, ignore=ignore)
- # Make a node modules folder so npm install is not called.
- if not os.path.exists(pjoin(dest, "node_modules")):
- os.makedirs(pjoin(dest, "node_modules"))
- setattr(self, "mock_" + name, dest)
- with open(pjoin(dest, "package.json")) as fid:
- data = json.load(fid)
- self.pkg_names[name] = data["name"]
- self.patches = []
- p = patch.dict(
- "os.environ",
- {
- "JUPYTER_CONFIG_DIR": self.config_dir,
- "JUPYTER_DATA_DIR": self.data_dir,
- "JUPYTERLAB_DIR": pjoin(self.data_dir, "lab"),
- },
- )
- self.patches.append(p)
- for mod in [paths]:
- if hasattr(mod, "ENV_JUPYTER_PATH"):
- p = patch.object(mod, "ENV_JUPYTER_PATH", [self.data_dir])
- self.patches.append(p)
- if hasattr(mod, "ENV_CONFIG_PATH"):
- p = patch.object(mod, "ENV_CONFIG_PATH", [self.config_dir])
- self.patches.append(p)
- if hasattr(mod, "CONFIG_PATH"):
- p = patch.object(mod, "CONFIG_PATH", self.config_dir)
- self.patches.append(p)
- if hasattr(mod, "BUILD_PATH"):
- p = patch.object(mod, "BUILD_PATH", self.data_dir)
- self.patches.append(p)
- for p in self.patches:
- p.start()
- self.addCleanup(p.stop)
- # verify our patches
- self.assertEqual(paths.ENV_CONFIG_PATH, [self.config_dir])
- self.assertEqual(paths.ENV_JUPYTER_PATH, [self.data_dir])
- self.assertEqual(
- Path(commands.get_app_dir()).resolve(), (Path(self.data_dir) / "lab").resolve()
- )
- self.app_dir = commands.get_app_dir()
- # Set pinned extension names
- self.pinned_packages = ["jupyterlab-test-extension@1.0", "jupyterlab-test-extension@2.0"]
- class TestExtension(AppHandlerTest):
- def test_install_extension(self):
- assert install_extension(self.mock_extension) is True
- path = pjoin(self.app_dir, "extensions", "*.tgz")
- assert glob.glob(path)
- extensions = get_app_info()["extensions"]
- name = self.pkg_names["extension"]
- assert name in extensions
- assert check_extension(name)
- def test_install_twice(self):
- assert install_extension(self.mock_extension) is True
- path = pjoin(self.app_dir, "extensions", "*.tgz")
- assert install_extension(self.mock_extension) is True
- assert glob.glob(path)
- extensions = get_app_info()["extensions"]
- name = self.pkg_names["extension"]
- assert name in extensions
- assert check_extension(name)
- def test_install_mime_renderer(self):
- install_extension(self.mock_mimeextension)
- name = self.pkg_names["mimeextension"]
- assert name in get_app_info()["extensions"]
- assert check_extension(name)
- assert uninstall_extension(name) is True
- assert name not in get_app_info()["extensions"]
- assert not check_extension(name)
- def test_install_incompatible(self):
- with pytest.raises(ValueError) as excinfo:
- install_extension(self.mock_incompat)
- assert "Conflicting Dependencies" in str(excinfo.value)
- assert not check_extension(self.pkg_names["incompat"])
- def test_install_failed(self):
- path = self.mock_package
- with pytest.raises(ValueError):
- install_extension(path)
- with open(pjoin(path, "package.json")) as fid:
- data = json.load(fid)
- extensions = get_app_info()["extensions"]
- name = data["name"]
- assert name not in extensions
- assert not check_extension(name)
- def test_validation(self):
- path = self.mock_extension
- os.remove(pjoin(path, "index.js"))
- with pytest.raises(ValueError):
- install_extension(path)
- assert not check_extension(self.pkg_names["extension"])
- path = self.mock_mimeextension
- os.remove(pjoin(path, "index.js"))
- with pytest.raises(ValueError):
- install_extension(path)
- assert not check_extension(self.pkg_names["mimeextension"])
- def test_uninstall_extension(self):
- assert install_extension(self.mock_extension) is True
- name = self.pkg_names["extension"]
- assert check_extension(name)
- assert uninstall_extension(self.pkg_names["extension"]) is True
- path = pjoin(self.app_dir, "extensions", "*.tgz")
- assert not glob.glob(path)
- extensions = get_app_info()["extensions"]
- assert name not in extensions
- assert not check_extension(name)
- def test_uninstall_all_extensions(self):
- install_extension(self.mock_extension)
- install_extension(self.mock_mimeextension)
- ext_name = self.pkg_names["extension"]
- mime_ext_name = self.pkg_names["mimeextension"]
- assert check_extension(ext_name) is True
- assert check_extension(mime_ext_name) is True
- assert uninstall_extension(all_=True) is True
- extensions = get_app_info()["extensions"]
- assert ext_name not in extensions
- assert mime_ext_name not in extensions
- @pytest.mark.slow
- def test_uninstall_core_extension(self):
- assert uninstall_extension("@jupyterlab/console-extension") is True
- app_dir = self.app_dir
- build()
- with open(pjoin(app_dir, "staging", "package.json")) as fid:
- data = json.load(fid)
- extensions = data["jupyterlab"]["extensions"]
- assert "@jupyterlab/console-extension" not in extensions
- assert not check_extension("@jupyterlab/console-extension")
- assert install_extension("@jupyterlab/console-extension") is True
- build()
- with open(pjoin(app_dir, "staging", "package.json")) as fid:
- data = json.load(fid)
- extensions = data["jupyterlab"]["extensions"]
- assert "@jupyterlab/console-extension" in extensions
- assert check_extension("@jupyterlab/console-extension")
- def test_install_and_uninstall_pinned(self):
- """
- You should be able to install different versions of the same extension with different
- pinned names and uninstall them with those names.
- """
- NAMES = ["test-1", "test-2"] # noqa
- assert install_extension(self.pinned_packages[0], pin=NAMES[0])
- assert install_extension(self.pinned_packages[1], pin=NAMES[1])
- extensions = get_app_info()["extensions"]
- assert NAMES[0] in extensions
- assert NAMES[1] in extensions
- assert check_extension(NAMES[0])
- assert check_extension(NAMES[1])
- # Uninstall
- assert uninstall_extension(NAMES[0])
- assert uninstall_extension(NAMES[1])
- extensions = get_app_info()["extensions"]
- assert NAMES[0] not in extensions
- assert NAMES[1] not in extensions
- assert not check_extension(NAMES[0])
- assert not check_extension(NAMES[1])
- @pytest.mark.skipif(
- platform.system() == "Windows", reason="running npm pack fails on windows CI"
- )
- def test_install_and_uninstall_pinned_folder(self):
- """
- Same as above test, but installs from a local folder instead of from npm.
- """
- # Download each version of the package from NPM:
- base_dir = Path(self.tempdir())
- # The archive file names are printed to stdout when run `npm pack`
- packages = [
- subprocess.run( # noqa S603
- ["npm", "pack", name], # noqa S607
- stdout=subprocess.PIPE,
- text=True,
- check=True,
- cwd=str(base_dir),
- ).stdout.strip()
- for name in self.pinned_packages
- ]
- shutil.unpack_archive(str(base_dir / packages[0]), str(base_dir / "1"))
- shutil.unpack_archive(str(base_dir / packages[1]), str(base_dir / "2"))
- # Change pinned packages to be these directories now, so we install from these folders
- self.pinned_packages = [str(base_dir / "1" / "package"), str(base_dir / "2" / "package")]
- self.test_install_and_uninstall_pinned()
- def test_link_extension(self):
- path = self.mock_extension
- name = self.pkg_names["extension"]
- link_package(path)
- linked = get_app_info()["linked_packages"]
- assert name not in linked
- assert name in get_app_info()["extensions"]
- assert check_extension(name)
- assert unlink_package(path) is True
- linked = get_app_info()["linked_packages"]
- assert name not in linked
- assert name not in get_app_info()["extensions"]
- assert not check_extension(name)
- def test_link_package(self):
- path = self.mock_package
- name = self.pkg_names["package"]
- assert link_package(path) is True
- linked = get_app_info()["linked_packages"]
- assert name in linked
- assert name not in get_app_info()["extensions"]
- assert check_extension(name)
- assert unlink_package(path)
- linked = get_app_info()["linked_packages"]
- assert name not in linked
- assert not check_extension(name)
- def test_unlink_package(self):
- target = self.mock_package
- assert link_package(target) is True
- assert unlink_package(target) is True
- linked = get_app_info()["linked_packages"]
- name = self.pkg_names["package"]
- assert name not in linked
- assert not check_extension(name)
- def test_list_extensions(self):
- assert install_extension(self.mock_extension) is True
- list_extensions()
- def test_app_dir(self):
- app_dir = self.tempdir()
- options = AppOptions(app_dir=app_dir)
- assert install_extension(self.mock_extension, app_options=options) is True
- path = pjoin(app_dir, "extensions", "*.tgz")
- assert glob.glob(path)
- extensions = get_app_info(app_options=options)["extensions"]
- ext_name = self.pkg_names["extension"]
- assert ext_name in extensions
- assert check_extension(ext_name, app_options=options)
- assert uninstall_extension(self.pkg_names["extension"], app_options=options) is True
- path = pjoin(app_dir, "extensions", "*.tgz")
- assert not glob.glob(path)
- extensions = get_app_info(app_options=options)["extensions"]
- assert ext_name not in extensions
- assert not check_extension(ext_name, app_options=options)
- assert link_package(self.mock_package, app_options=options) is True
- linked = get_app_info(app_options=options)["linked_packages"]
- pkg_name = self.pkg_names["package"]
- assert pkg_name in linked
- assert check_extension(pkg_name, app_options=options)
- assert unlink_package(self.mock_package, app_options=options) is True
- linked = get_app_info(app_options=options)["linked_packages"]
- assert pkg_name not in linked
- assert not check_extension(pkg_name, app_options=options)
- def test_app_dir_use_sys_prefix(self):
- app_dir = self.tempdir()
- options = AppOptions(app_dir=app_dir)
- if os.path.exists(self.app_dir):
- os.removedirs(self.app_dir)
- assert install_extension(self.mock_extension) is True
- path = pjoin(app_dir, "extensions", "*.tgz")
- assert not glob.glob(path)
- extensions = get_app_info(app_options=options)["extensions"]
- ext_name = self.pkg_names["extension"]
- assert ext_name in extensions
- assert check_extension(ext_name, app_options=options)
- def test_app_dir_disable_sys_prefix(self):
- app_dir = self.tempdir()
- options = AppOptions(app_dir=app_dir, use_sys_dir=False)
- if os.path.exists(self.app_dir):
- os.removedirs(self.app_dir)
- assert install_extension(self.mock_extension) is True
- path = pjoin(app_dir, "extensions", "*.tgz")
- assert not glob.glob(path)
- extensions = get_app_info(app_options=options)["extensions"]
- ext_name = self.pkg_names["extension"]
- assert ext_name not in extensions
- assert not check_extension(ext_name, app_options=options)
- def test_app_dir_shadowing(self):
- app_dir = self.tempdir()
- sys_dir = self.app_dir
- app_options = AppOptions(app_dir=app_dir)
- if os.path.exists(sys_dir):
- os.removedirs(sys_dir)
- assert install_extension(self.mock_extension) is True
- sys_path = pjoin(sys_dir, "extensions", "*.tgz")
- assert glob.glob(sys_path)
- app_path = pjoin(app_dir, "extensions", "*.tgz")
- assert not glob.glob(app_path)
- extensions = get_app_info(app_options=app_options)["extensions"]
- ext_name = self.pkg_names["extension"]
- assert ext_name in extensions
- assert check_extension(ext_name, app_options=app_options)
- assert install_extension(self.mock_extension, app_options=app_options) is True
- assert glob.glob(app_path)
- extensions = get_app_info(app_options=app_options)["extensions"]
- assert ext_name in extensions
- assert check_extension(ext_name, app_options=app_options)
- assert uninstall_extension(self.pkg_names["extension"], app_options=app_options) is True
- assert not glob.glob(app_path)
- assert glob.glob(sys_path)
- extensions = get_app_info(app_options=app_options)["extensions"]
- assert ext_name in extensions
- assert check_extension(ext_name, app_options=app_options)
- assert uninstall_extension(self.pkg_names["extension"], app_options=app_options) is True
- assert not glob.glob(app_path)
- assert not glob.glob(sys_path)
- extensions = get_app_info(app_options=app_options)["extensions"]
- assert ext_name not in extensions
- assert not check_extension(ext_name, app_options=app_options)
- @pytest.mark.slow
- def test_build(self):
- assert install_extension(self.mock_extension) is True
- build()
- # check staging directory.
- entry = pjoin(self.app_dir, "staging", "build", "index.out.js")
- with open(entry) as fid:
- data = fid.read()
- assert self.pkg_names["extension"] in data
- # check static directory.
- entry = pjoin(self.app_dir, "static", "index.out.js")
- with open(entry) as fid:
- data = fid.read()
- assert self.pkg_names["extension"] in data
- @pytest.mark.slow
- @pytest.mark.skipif(not os.path.exists(DEV_DIR), reason="Not in git checkout")
- def test_build_splice_packages(self):
- app_options = AppOptions(splice_source=True)
- assert install_extension(self.mock_extension) is True
- build(app_options=app_options)
- assert "-spliced" in get_app_version(app_options)
- # check staging directory.
- entry = pjoin(self.app_dir, "staging", "build", "index.out.js")
- with open(entry) as fid:
- data = fid.read()
- assert self.pkg_names["extension"] in data
- # check static directory.
- entry = pjoin(self.app_dir, "static", "index.out.js")
- with open(entry) as fid:
- data = fid.read()
- assert self.pkg_names["extension"] in data
- @pytest.mark.slow
- def test_build_custom(self):
- assert install_extension(self.mock_extension) is True
- build(name="foo", version="1.0", static_url="bar")
- # check static directory.
- entry = pjoin(self.app_dir, "static", "index.out.js")
- with open(entry) as fid:
- data = fid.read()
- assert self.pkg_names["extension"] in data
- pkg = pjoin(self.app_dir, "static", "package.json")
- with open(pkg) as fid:
- data = json.load(fid)
- assert data["jupyterlab"]["name"] == "foo"
- assert data["jupyterlab"]["version"] == "1.0"
- assert data["jupyterlab"]["staticUrl"] == "bar"
- @pytest.mark.slow
- def test_build_custom_minimal_core_config(self):
- default_config = CoreConfig()
- core_config = CoreConfig()
- core_config.clear_packages()
- logger = logging.getLogger("jupyterlab_test_logger")
- logger.setLevel("DEBUG")
- app_dir = self.tempdir()
- options = AppOptions(
- app_dir=app_dir,
- core_config=core_config,
- logger=logger,
- use_sys_dir=False,
- )
- extensions = (
- "@jupyterlab/application-extension",
- "@jupyterlab/apputils-extension",
- )
- singletons = (
- "@jupyterlab/application",
- "@jupyterlab/apputils",
- "@jupyterlab/coreutils",
- "@jupyterlab/services",
- )
- for name in extensions:
- semver = default_config.extensions[name]
- core_config.add(name, semver, extension=True)
- for name in singletons:
- semver = default_config.singletons[name]
- core_config.add(name, semver)
- assert install_extension(self.mock_extension, app_options=options) is True
- build(app_options=options)
- # check static directory.
- entry = pjoin(app_dir, "static", "index.out.js")
- with open(entry) as fid:
- data = fid.read()
- assert self.pkg_names["extension"] in data
- pkg = pjoin(app_dir, "static", "package.json")
- with open(pkg) as fid:
- data = json.load(fid)
- assert sorted(data["jupyterlab"]["extensions"].keys()) == [
- "@jupyterlab/application-extension",
- "@jupyterlab/apputils-extension",
- "@jupyterlab/mock-extension",
- ]
- assert data["jupyterlab"]["mimeExtensions"] == {}
- for pkg in data["jupyterlab"]["singletonPackages"]:
- if pkg.startswith("@jupyterlab/"):
- assert pkg in singletons
- def test_disable_extension(self):
- options = AppOptions(app_dir=self.tempdir())
- assert install_extension(self.mock_extension, app_options=options) is True
- assert disable_extension(self.pkg_names["extension"], app_options=options) is True
- info = get_app_info(app_options=options)
- name = self.pkg_names["extension"]
- assert info["disabled"].get(name) is True
- assert not check_extension(name, app_options=options)
- assert check_extension(name, installed=True, app_options=options)
- assert disable_extension("@jupyterlab/notebook-extension", app_options=options) is True
- info = get_app_info(app_options=options)
- assert info["disabled"].get("@jupyterlab/notebook-extension") is True
- assert not check_extension("@jupyterlab/notebook-extension", app_options=options)
- assert check_extension(
- "@jupyterlab/notebook-extension", installed=True, app_options=options
- )
- assert info["disabled"].get(name) is True
- assert not check_extension(name, app_options=options)
- assert check_extension(name, installed=True, app_options=options)
- def test_enable_extension(self):
- options = AppOptions(app_dir=self.tempdir())
- assert install_extension(self.mock_extension, app_options=options) is True
- assert disable_extension(self.pkg_names["extension"], app_options=options) is True
- assert enable_extension(self.pkg_names["extension"], app_options=options) is True
- info = get_app_info(app_options=options)
- assert "@jupyterlab/notebook-extension" not in info["disabled"]
- name = self.pkg_names["extension"]
- assert info["disabled"].get(name, False) is False
- assert check_extension(name, app_options=options)
- assert disable_extension("@jupyterlab/notebook-extension", app_options=options) is True
- assert check_extension(name, app_options=options)
- assert not check_extension("@jupyterlab/notebook-extension", app_options=options)
- def test_lock_unlock_extension(self):
- options = AppOptions(app_dir=self.tempdir())
- assert install_extension(self.mock_extension, app_options=options) is True
- name = self.pkg_names["extension"]
- info = get_app_info(app_options=options)
- assert info["locked"].get(name, False) is False
- lock_extension(self.pkg_names["extension"], app_options=options)
- info = get_app_info(app_options=options)
- assert info["locked"].get(name, False) is True
- unlock_extension(self.pkg_names["extension"], app_options=options)
- info = get_app_info(app_options=options)
- assert info["locked"].get(name, False) is False
- @pytest.mark.slow
- def test_build_check(self):
- # Do the initial build.
- assert build_check()
- assert install_extension(self.mock_extension) is True
- assert link_package(self.mock_package) is True
- build()
- assert not build_check()
- # Check installed extensions.
- assert install_extension(self.mock_mimeextension) is True
- assert build_check()
- assert uninstall_extension(self.pkg_names["mimeextension"]) is True
- assert not build_check()
- # Check local extensions.
- pkg_path = pjoin(self.mock_extension, "package.json")
- with open(pkg_path) as fid:
- data = json.load(fid)
- with open(pkg_path, "rb") as fid:
- orig = fid.read()
- data["foo"] = "bar"
- with open(pkg_path, "w") as fid:
- json.dump(data, fid)
- assert build_check()
- assert build_check()
- with open(pkg_path, "wb") as fid:
- fid.write(orig)
- assert not build_check()
- # Check linked packages.
- pkg_path = pjoin(self.mock_package, "index.js")
- with open(pkg_path, "rb") as fid:
- orig = fid.read()
- with open(pkg_path, "wb") as fid:
- fid.write(orig + b'\nconsole.log("hello");')
- assert build_check()
- assert build_check()
- with open(pkg_path, "wb") as fid:
- fid.write(orig)
- assert not build_check()
- def test_compatibility(self):
- assert _test_overlap("^0.6.0", "^0.6.1")
- assert _test_overlap(">0.1", "0.6")
- assert _test_overlap("~0.5.0", "~0.5.2")
- assert _test_overlap("0.5.2", "^0.5.0")
- assert not _test_overlap("^0.5.0", "^0.6.0")
- assert not _test_overlap("~1.5.0", "^1.6.0")
- assert _test_overlap("*", "0.6") is None
- assert _test_overlap("<0.6", "0.1") is None
- assert _test_overlap("^1 || ^2", "^1")
- assert _test_overlap("^1 || ^2", "^2")
- assert _test_overlap("^1", "^1 || ^2")
- assert _test_overlap("^2", "^1 || ^2")
- assert _test_overlap("^1 || ^2", "^2 || ^3")
- assert not _test_overlap("^1 || ^2", "^3 || ^4")
- assert not _test_overlap("^2", "^1 || ^3")
- def test_compare_ranges(self):
- assert _compare_ranges("^1 || ^2", "^1") == 0
- assert _compare_ranges("^1 || ^2", "^2 || ^3") == 0
- assert _compare_ranges("^1 || ^2", "^3 || ^4") == 1
- assert _compare_ranges("^3 || ^4", "^1 || ^2") == -1
- assert _compare_ranges("^2 || ^3", "^1 || ^4") is None
- def test_install_compatible(self):
- core_data = _get_default_core_data()
- current_app_dep = core_data["dependencies"]["@jupyterlab/application"]
- def _gen_dep(ver):
- return {"dependencies": {"@jupyterlab/application": ver}}
- def _mock_metadata(registry, name, logger):
- assert name == "mockextension"
- return {
- "name": name,
- "versions": {
- "0.9.0": _gen_dep(current_app_dep),
- "1.0.0": _gen_dep(current_app_dep),
- "1.1.0": _gen_dep(current_app_dep),
- "2.0.0": _gen_dep("^2000.0.0"),
- "2.0.0-b0": _gen_dep(current_app_dep),
- "2.1.0-b0": _gen_dep("^2000.0.0"),
- "2.1.0": _gen_dep("^2000.0.0"),
- },
- }
- def _mock_extract(self, source, tempdir, *args, **kwargs):
- data = {
- "name": source,
- "version": "2.1.0",
- "jupyterlab": {"extension": True},
- "jupyterlab_extracted_files": ["index.js"],
- }
- data.update(_gen_dep("^2000.0.0"))
- info = {
- "source": source,
- "is_dir": False,
- "data": data,
- "name": source,
- "version": data["version"],
- "filename": "mockextension.tgz",
- "path": pjoin(tempdir, "mockextension.tgz"),
- }
- return info
- class Success(Exception): # noqa
- pass
- def _mock_install(self, name, *args, **kwargs):
- assert name in ("mockextension", "mockextension@1.1.0")
- if name == "mockextension@1.1.0":
- raise Success()
- return orig_install(self, name, *args, **kwargs)
- p1 = patch.object(commands, "_fetch_package_metadata", _mock_metadata)
- p2 = patch.object(commands._AppHandler, "_extract_package", _mock_extract)
- p3 = patch.object(commands._AppHandler, "_install_extension", _mock_install)
- with p1, p2:
- orig_install = commands._AppHandler._install_extension
- with p3, pytest.raises(Success):
- assert install_extension("mockextension") is True
- def test_update_single(self):
- installed = []
- def _mock_install(self, name, *args, **kwargs):
- installed.append(name[0] + name[1:].split("@")[0])
- return {"name": name, "is_dir": False, "path": "foo/bar/" + name}
- def _mock_latest(self, name):
- return "10000.0.0"
- p1 = patch.object(commands._AppHandler, "_install_extension", _mock_install)
- p2 = patch.object(commands._AppHandler, "_latest_compatible_package_version", _mock_latest)
- assert install_extension(self.mock_extension) is True
- assert install_extension(self.mock_mimeextension) is True
- with p1, p2:
- assert update_extension(self.pkg_names["extension"]) is True
- assert installed == [self.pkg_names["extension"]]
- def test_update_missing_extension(self):
- assert update_extension("foo") is False
- def test_update_multiple(self):
- installed = []
- def _mock_install(self, name, *args, **kwargs):
- installed.append(name[0] + name[1:].split("@")[0])
- return {"name": name, "is_dir": False, "path": "foo/bar/" + name}
- def _mock_latest(self, name):
- return "10000.0.0"
- p1 = patch.object(commands._AppHandler, "_install_extension", _mock_install)
- p2 = patch.object(commands._AppHandler, "_latest_compatible_package_version", _mock_latest)
- install_extension(self.mock_extension)
- install_extension(self.mock_mimeextension)
- with p1, p2:
- assert update_extension(self.pkg_names["extension"]) is True
- assert update_extension(self.pkg_names["mimeextension"]) is True
- assert installed == [self.pkg_names["extension"], self.pkg_names["mimeextension"]]
- def test_update_all(self):
- updated = []
- def _mock_update(self, name, *args, **kwargs):
- updated.append(name[0] + name[1:].split("@")[0])
- return True
- original_app_info = commands._AppHandler._get_app_info
- def _mock_app_info(self):
- info = original_app_info(self)
- info["local_extensions"] = []
- return info
- assert install_extension(self.mock_extension) is True
- assert install_extension(self.mock_mimeextension) is True
- p1 = patch.object(commands._AppHandler, "_update_extension", _mock_update)
- # local packages are not updated, so mock them as non-local:
- p2 = patch.object(commands._AppHandler, "_get_app_info", _mock_app_info)
- with p1, p2:
- assert update_extension(None, all_=True) is True
- assert sorted(updated) == [self.pkg_names["extension"], self.pkg_names["mimeextension"]]
- def test_load_extension(jp_serverapp, make_lab_app):
- app = make_lab_app()
- stderr = sys.stderr
- # sys.stderr = self.devnull
- app._link_jupyter_server_extension(jp_serverapp)
- app.initialize()
- sys.stderr = stderr
|