Skip to content

Commit

Permalink
Implement level trait for plugin/extension managers (jupyterlab#15512)
Browse files Browse the repository at this point in the history
This matches the `level` CLI option for `labextension` command.

Also do not collect tests from `.ipynb_checkpoints`.
  • Loading branch information
krassowski authored Dec 12, 2023
1 parent 9be3e7a commit 77cc55e
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 4 deletions.
7 changes: 7 additions & 0 deletions docs/source/user/extensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,13 @@ running the ``jupyter labextension enable`` or ``jupyter labextension disable``
:class: jp-screenshot
:alt: An example search result in the plugin extension listing.


Plugins can be enabled/disabled on ``system``, ``sys-prefix`` (default) or
``user`` level, which influences where the ``page_config.json`` configuration
file is written to (see ``config` section in results of ``jupyter --paths``).
To change the level for the plugin manager and the default extension manager
use ``PluginManager.level`` trait (extension manager inherits from plugin manager).

.. _locking_plugins:

Locking and Unlocking Plugins
Expand Down
14 changes: 12 additions & 2 deletions jupyterlab/extensions/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import tornado
from jupyterlab_server.translation_utils import translator
from traitlets import Enum
from traitlets.config import Configurable, LoggingConfigurable

from jupyterlab.commands import (
Expand Down Expand Up @@ -192,13 +193,22 @@ class PluginManager(LoggingConfigurable):
options: Plugin manager options
"""

level = Enum(
values=["sys_prefix", "user", "system"],
default_value="sys_prefix",
help="Level at which to manage plugins: sys_prefix, user, system",
).tag(config=True)

def __init__(
self,
app_options: Optional[dict] = None,
ext_options: Optional[dict] = None,
parent: Optional[Configurable] = None,
) -> None:
super().__init__(parent=parent)
self.log.debug(
"Plugins in %s will managed on the %s level", self.__class__.__name__, self.level
)
self.app_options = _ensure_options(app_options)
plugin_options_field = {f.name for f in fields(PluginManagerOptions)}
plugin_options = {
Expand Down Expand Up @@ -255,7 +265,7 @@ async def disable(self, plugins: Union[str, List[str]]) -> ActionResult:
)
try:
for plugin in plugins:
disable_extension(plugin, app_options=self.app_options)
disable_extension(plugin, app_options=self.app_options, level=self.level)
return ActionResult(status="ok", needs_restart=["frontend"])
except Exception as err:
return ActionResult(status="error", message=repr(err))
Expand All @@ -281,7 +291,7 @@ async def enable(self, plugins: Union[str, List[str]]) -> ActionResult:
)
try:
for plugin in plugins:
enable_extension(plugin, app_options=self.app_options)
enable_extension(plugin, app_options=self.app_options, level=self.level)
return ActionResult(status="ok", needs_restart=["frontend"])
except Exception as err:
return ActionResult(status="error", message=repr(err))
Expand Down
1 change: 1 addition & 0 deletions jupyterlab/labapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,7 @@ def initialize_handlers(self): # noqa
"lock_rules": lock_rules,
"all_locked": self.lock_all_plugins,
},
parent=self,
)
},
)
Expand Down
31 changes: 30 additions & 1 deletion jupyterlab/tests/test_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from traitlets.config import Config, Configurable

from jupyterlab.extensions import PyPIExtensionManager, ReadOnlyExtensionManager
from jupyterlab.extensions.manager import ExtensionManager, ExtensionPackage
from jupyterlab.extensions.manager import ExtensionManager, ExtensionPackage, PluginManager

from . import fake_client_factory

Expand Down Expand Up @@ -340,3 +340,32 @@ async def test_PyPiExtensionManager_custom_server_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"
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ npm = ["node", "yarn.js"]

[tool.pytest.ini_options]
testpaths = "jupyterlab/tests"
norecursedirs = "node_modules .git _build"
norecursedirs = "node_modules .git _build .ipynb_checkpoints"
addopts = "--pdbcls=IPython.terminal.debugger:Pdb -v --junitxml=junit.xml"
ignore = "tests examples"

Expand Down

0 comments on commit 77cc55e

Please sign in to comment.