| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- # Copyright (c) Jupyter Development Team.
- # Distributed under the terms of the Modified BSD License.
- import json
- from unittest.mock import Mock, patch
- import pytest
- from traitlets.config import Config, Configurable
- from jupyterlab.extensions import PyPIExtensionManager, ReadOnlyExtensionManager
- from jupyterlab.extensions.manager import ExtensionManager, ExtensionPackage, PluginManager
- from . import fake_client_factory
- @pytest.mark.parametrize(
- "version, expected",
- (
- ("1", "1"),
- ("1.0", "1.0"),
- ("1.0.0", "1.0.0"),
- ("1.0.0a52", "1.0.0-alpha.52"),
- ("1.0.0b3", "1.0.0-beta.3"),
- ("1.0.0rc22", "1.0.0-rc.22"),
- ("1.0.0rc23.post2", "1.0.0-rc.23"),
- ("1.0.0rc24.dev2", "1.0.0-rc.24"),
- ("1.0.0rc25.post4.dev2", "1.0.0-rc.25"),
- ),
- )
- def test_ExtensionManager_get_semver_version(version, expected):
- assert ExtensionManager.get_semver_version(version) == expected
- async def test_ExtensionManager_list_extensions_installed(monkeypatch):
- extension1 = ExtensionPackage("extension1", "Extension 1 description", "", "prebuilt")
- async def mock_installed(*args, **kwargs):
- return {"extension1": extension1}
- monkeypatch.setattr(ReadOnlyExtensionManager, "_get_installed_extensions", mock_installed)
- manager = ReadOnlyExtensionManager()
- extensions = await manager.list_extensions()
- assert extensions == ([extension1], 1)
- async def test_ExtensionManager_list_extensions_query(monkeypatch):
- extension1 = ExtensionPackage("extension1", "Extension 1 description", "", "prebuilt")
- extension2 = ExtensionPackage("extension2", "Extension 2 description", "", "prebuilt")
- async def mock_list(*args, **kwargs):
- return {"extension1": extension1, "extension2": extension2}, None
- monkeypatch.setattr(ReadOnlyExtensionManager, "list_packages", mock_list)
- manager = ReadOnlyExtensionManager()
- extensions = await manager.list_extensions("ext")
- assert extensions == ([extension1, extension2], 1)
- @patch("tornado.httpclient.AsyncHTTPClient", new_callable=fake_client_factory)
- async def test_ExtensionManager_list_extensions_query_allow(mock_client, monkeypatch):
- extension1 = ExtensionPackage("extension1", "Extension 1 description", "", "prebuilt")
- extension2 = ExtensionPackage("extension2", "Extension 2 description", "", "prebuilt")
- mock_client.body = json.dumps({"allowed_extensions": [{"name": "extension1"}]}).encode()
- async def mock_list(*args, **kwargs):
- return {"extension1": extension1, "extension2": extension2}, None
- monkeypatch.setattr(ReadOnlyExtensionManager, "list_packages", mock_list)
- manager = ReadOnlyExtensionManager(
- ext_options={"allowed_extensions_uris": {"http://dummy-allowed-extension"}},
- )
- extensions = await manager.list_extensions("ext")
- assert extensions == ([extension1], 1)
- @patch("tornado.httpclient.AsyncHTTPClient", new_callable=fake_client_factory)
- async def test_ExtensionManager_list_extensions_query_block(mock_client, monkeypatch):
- extension1 = ExtensionPackage("extension1", "Extension 1 description", "", "prebuilt")
- extension2 = ExtensionPackage("extension2", "Extension 2 description", "", "prebuilt")
- mock_client.body = json.dumps({"blocked_extensions": [{"name": "extension1"}]}).encode()
- async def mock_list(*args, **kwargs):
- return {"extension1": extension1, "extension2": extension2}, None
- monkeypatch.setattr(ReadOnlyExtensionManager, "list_packages", mock_list)
- manager = ReadOnlyExtensionManager(
- ext_options={"blocked_extensions_uris": {"http://dummy-blocked-extension"}}
- )
- extensions = await manager.list_extensions("ext")
- assert extensions == ([extension2], 1)
- @patch("tornado.httpclient.AsyncHTTPClient", new_callable=fake_client_factory)
- async def test_ExtensionManager_list_extensions_query_allow_block(mock_client, monkeypatch):
- extension1 = ExtensionPackage("extension1", "Extension 1 description", "", "prebuilt")
- extension2 = ExtensionPackage("extension2", "Extension 2 description", "", "prebuilt")
- mock_client.body = json.dumps(
- {
- "allowed_extensions": [{"name": "extension1"}],
- "blocked_extensions": [{"name": "extension1"}],
- }
- ).encode()
- async def mock_list(*args, **kwargs):
- return {"extension1": extension1, "extension2": extension2}, None
- monkeypatch.setattr(ReadOnlyExtensionManager, "list_packages", mock_list)
- manager = ReadOnlyExtensionManager(
- ext_options={
- "allowed_extensions_uris": {"http://dummy-allowed-extension"},
- "blocked_extensions_uris": {"http://dummy-blocked-extension"},
- }
- )
- extensions = await manager.list_extensions("ext")
- assert extensions == ([extension1], 1)
- async def test_ExtensionManager_install():
- manager = ReadOnlyExtensionManager()
- result = await manager.install("extension1")
- assert result.status == "error"
- assert result.message == "Extension installation not supported."
- async def test_ExtensionManager_uninstall():
- manager = ReadOnlyExtensionManager()
- result = await manager.uninstall("extension1")
- assert result.status == "error"
- assert result.message == "Extension removal not supported."
- @patch("jupyterlab.extensions.pypi.xmlrpc.client")
- async def test_ExtensionManager_list_extensions_query_sort(mocked_rpcclient):
- extension_data = [
- {
- "name": "jupyterlab-apod",
- "project_urls": {
- "Homepage": "https://github.com/jupyterlab/jupyterlab_apod",
- },
- },
- {
- "name": "jupyterlab-gitlab",
- "project_urls": {
- "Homepage": "https://github.com/jupyterlab-contrib/jupyterlab-gitlab/issues",
- },
- },
- {
- "name": "jupyterlab-git",
- "project_url": "https://github.com/jupyterlab/jupyterlab-git",
- },
- {
- "name": "jupyterlab-rainbow-brackets",
- "project_url": "https://github.com/krassowski/jupyterlab-rainbow-brackets",
- },
- {"name": "nbdime", "home_page": "https://github.com/jupyter/nbdime"},
- {
- "name": "rise",
- "project_urls": {
- "Source Code": "https://github.com/jupyterlab-contrib/rise",
- },
- },
- ]
- proxy = Mock(
- browse=Mock(return_value=[[extension["name"], "1.0.0"] for extension in extension_data]),
- )
- mocked_rpcclient.ServerProxy = Mock(return_value=proxy)
- manager = PyPIExtensionManager()
- extensions = {
- extension["name"]: {"version": "1.0.0", **extension} for extension in extension_data
- }
- async def mock_pkg_metadata(name, l, b): # noqa
- return extensions[name]
- manager._fetch_package_metadata = mock_pkg_metadata
- first_page, pages_count = await manager.list_extensions("", per_page=3)
- assert [extension.name for extension in first_page] == [
- # jupyter/jupyterlab
- "jupyterlab-git",
- "nbdime",
- # jupyterlab-contrib
- "jupyterlab-gitlab",
- ]
- assert pages_count == 2
- second_page, pages_count = await manager.list_extensions("", page=2, per_page=3)
- assert [extension.name for extension in second_page] == [
- # jupyterlab-contrib
- "rise",
- # other third-party
- "jupyterlab-rainbow-brackets",
- # example extensions
- "jupyterlab-apod",
- ]
- @patch("jupyterlab.extensions.pypi.xmlrpc.client")
- async def test_PyPiExtensionManager_list_extensions_query(mocked_rpcclient):
- extension1 = ExtensionPackage(
- name="jupyterlab-git",
- description="A JupyterLab extension for version control using git",
- homepage_url="https://github.com/jupyterlab/jupyterlab-git",
- pkg_type="prebuilt",
- latest_version="0.37.1",
- author="Jupyter Development Team",
- license="BSD-3-Clause",
- package_manager_url="https://pypi.org/project/jupyterlab-git/",
- )
- extension2 = ExtensionPackage(
- name="jupyterlab-github",
- description="JupyterLab viewer for GitHub repositories",
- homepage_url="https://github.com/jupyterlab/jupyterlab-github/blob/main/README.md",
- pkg_type="prebuilt",
- latest_version="3.0.1",
- author="Ian Rose",
- license="BSD-3-Clause",
- bug_tracker_url="https://github.com/jupyterlab/jupyterlab-github/issues",
- package_manager_url="https://pypi.org/project/jupyterlab-github/",
- repository_url="https://github.com/jupyterlab/jupyterlab-github",
- )
- proxy = Mock(
- browse=Mock(
- return_value=[
- ["jupyterlab-git", "0.33.0"],
- ["jupyterlab-git", "0.34.0"],
- ["jupyterlab-git", "0.34.1"],
- ["jupyterlab-git", "0.37.0"],
- ["jupyterlab-git", "0.37.1"],
- ["jupyterlab-github", "3.0.0"],
- ["jupyterlab-github", "3.0.1"],
- ]
- ),
- )
- mocked_rpcclient.ServerProxy = Mock(return_value=proxy)
- manager = PyPIExtensionManager()
- async def mock_pkg_metadata(n, l, b): # noqa
- return (
- {
- "name": "jupyterlab-git",
- "version": "0.37.1",
- "stable_version": None,
- "bugtrack_url": None,
- "package_url": "https://pypi.org/project/jupyterlab-git/",
- "release_url": "https://pypi.org/project/jupyterlab-git/0.37.1/",
- "docs_url": None,
- "home_page": "https://github.com/jupyterlab/jupyterlab-git",
- "download_url": "",
- "project_url": "",
- "project_urls": {},
- "author": "Jupyter Development Team",
- "author_email": "",
- "maintainer": "",
- "maintainer_email": "",
- "summary": "A JupyterLab extension for version control using git",
- "license": "BSD-3-Clause",
- "keywords": "Jupyter,JupyterLab,JupyterLab3,jupyterlab-extension,Git",
- "platform": "Linux",
- "classifiers": [
- "Framework :: Jupyter",
- "Framework :: Jupyter :: JupyterLab",
- "Framework :: Jupyter :: JupyterLab :: 3",
- "Framework :: Jupyter :: JupyterLab :: Extensions",
- "Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt",
- "Intended Audience :: Developers",
- "Intended Audience :: Science/Research",
- "License :: OSI Approved :: BSD License",
- "Programming Language :: Python",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.6",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- ],
- "requires": [],
- "requires_dist": [
- "jupyter-server",
- "nbdime (~=3.1)",
- "nbformat",
- "packaging",
- "pexpect",
- "coverage ; extra == 'dev'",
- "jupyterlab (~=3.0) ; extra == 'dev'",
- "pre-commit ; extra == 'dev'",
- "pytest ; extra == 'dev'",
- "pytest-asyncio ; extra == 'dev'",
- "pytest-cov ; extra == 'dev'",
- "pytest-tornasync ; extra == 'dev'",
- "coverage ; extra == 'tests'",
- "jupyterlab (~=3.0) ; extra == 'tests'",
- "pre-commit ; extra == 'tests'",
- "pytest ; extra == 'tests'",
- "pytest-asyncio ; extra == 'tests'",
- "pytest-cov ; extra == 'tests'",
- "pytest-tornasync ; extra == 'tests'",
- "hybridcontents ; extra == 'tests'",
- "jupytext ; extra == 'tests'",
- ],
- "provides": [],
- "provides_dist": [],
- "obsoletes": [],
- "obsoletes_dist": [],
- "requires_python": "<4,>=3.6",
- "requires_external": [],
- "_pypi_ordering": 55,
- "downloads": {"last_day": -1, "last_week": -1, "last_month": -1},
- "cheesecake_code_kwalitee_id": None,
- "cheesecake_documentation_id": None,
- "cheesecake_installability_id": None,
- }
- if n == "jupyterlab-git"
- else {
- "name": "jupyterlab-github",
- "version": "3.0.1",
- "stable_version": None,
- "bugtrack_url": None,
- "package_url": "https://pypi.org/project/jupyterlab-github/",
- "release_url": "https://pypi.org/project/jupyterlab-github/3.0.1/",
- "docs_url": None,
- "home_page": "",
- "download_url": "",
- "project_url": "",
- "project_urls": {
- "Homepage": "https://github.com/jupyterlab/jupyterlab-github/blob/main/README.md",
- "Bug Tracker": "https://github.com/jupyterlab/jupyterlab-github/issues",
- "Source Code": "https://github.com/jupyterlab/jupyterlab-github",
- },
- "author": "Ian Rose",
- "author_email": "jupyter@googlegroups.com",
- "maintainer": "",
- "maintainer_email": "",
- "summary": "JupyterLab viewer for GitHub repositories",
- "license": "BSD-3-Clause",
- "keywords": "Jupyter,JupyterLab,JupyterLab3",
- "platform": "Linux",
- "classifiers": [
- "Framework :: Jupyter",
- "Framework :: Jupyter :: JupyterLab",
- "Framework :: Jupyter :: JupyterLab :: 3",
- "Framework :: Jupyter :: JupyterLab :: Extensions",
- "Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt",
- "License :: OSI Approved :: BSD License",
- "Programming Language :: Python",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.6",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
- ],
- "requires": [],
- "requires_dist": ["jupyterlab (~=3.0)"],
- "provides": [],
- "provides_dist": [],
- "obsoletes": [],
- "obsoletes_dist": [],
- "requires_python": ">=3.6",
- "requires_external": [],
- "_pypi_ordering": 12,
- "downloads": {"last_day": -1, "last_week": -1, "last_month": -1},
- "cheesecake_code_kwalitee_id": None,
- "cheesecake_documentation_id": None,
- "cheesecake_installability_id": None,
- }
- )
- manager._fetch_package_metadata = mock_pkg_metadata
- extensions = await manager.list_extensions("git")
- assert extensions == ([extension1, extension2], 1)
- async def test_PyPiExtensionManager_custom_server_url():
- BASE_URL = "https://mylocal.pypi.server/pypi" # noqa
- parent = Configurable(config=Config({"PyPIExtensionManager": {"base_url": BASE_URL}}))
- manager = PyPIExtensionManager(parent=parent)
- assert manager.base_url == BASE_URL
- LEVELS = ["user", "sys_prefix", "system"]
- @pytest.mark.parametrize("level", LEVELS)
- async def test_PyPiExtensionManager_custom_level(level):
- parent = Configurable(config=Config({"PyPIExtensionManager": {"level": level}}))
- manager = PyPIExtensionManager(parent=parent)
- assert manager.level == level
- @pytest.mark.parametrize("level", LEVELS)
- async def test_PyPiExtensionManager_inherits_custom_level(level):
- parent = Configurable(config=Config({"PluginManager": {"level": level}}))
- manager = PyPIExtensionManager(parent=parent)
- assert manager.level == level
- @pytest.mark.parametrize("level", LEVELS)
- async def test_PluginManager_custom_level(level):
- parent = Configurable(config=Config({"PluginManager": {"level": level}}))
- manager = PluginManager(parent=parent)
- assert manager.level == level
- async def test_PluginManager_default_level():
- manager = PluginManager()
- assert manager.level == "sys_prefix"
|