浏览代码

Add ability to enable and disable extensions

Steven Silvester 8 年之前
父节点
当前提交
8dd7d935f6
共有 4 个文件被更改,包括 168 次插入13 次删除
  1. 132 6
      jupyterlab/commands.py
  2. 11 2
      jupyterlab/index.js
  3. 1 0
      jupyterlab/labapp.py
  4. 24 5
      jupyterlab/labextensions.py

+ 132 - 6
jupyterlab/commands.py

@@ -16,6 +16,7 @@ import shutil
 import sys
 import tarfile
 from jupyter_core.paths import ENV_JUPYTER_PATH
+from notebook.extensions import GREEN_ENABLED, RED_DISABLED
 
 from ._version import __version__
 
@@ -28,6 +29,7 @@ else:
 
 
 here = osp.dirname(osp.abspath(__file__))
+sys_path = pjoin(ENV_JUPYTER_PATH[0], 'lab', 'extensions')
 
 
 def get_app_dir(app_dir=None):
@@ -153,6 +155,18 @@ def unlink_package(package, app_dir=None):
     return True
 
 
+def enable_extension(extension, app_dir=None):
+    """Enable a JupyterLab extension.
+    """
+    _toggle_extension(extension, True, app_dir)
+
+
+def disable_extension(extension, app_dir=None):
+    """Disable a JupyterLab package.
+    """
+    _toggle_extension(extension, False, app_dir)
+
+
 def should_build(app_dir=None):
     """Determine whether JupyterLab should be built.
 
@@ -213,6 +227,36 @@ def _get_build_config(app_dir):
             return json.load(fid)
 
 
+def _get_page_config(app_dir):
+    """Get the page config data for the given app dir
+    """
+    target = pjoin(app_dir, 'settings', 'page_config.json')
+    if not os.path.exists(target):
+        return {}
+    else:
+        with open(target) as fid:
+            return json.load(fid)
+
+
+def _toggle_extension(extension, value, app_dir=None):
+    """Enable or disable a lab extension.
+    """
+    app_dir = get_app_dir(app_dir)
+    config = _get_page_config(app_dir)
+    extensions = _get_extensions(app_dir)
+    if extension not in extensions:
+        raise ValueError('Extension %s is not installed' % extension)
+    disabled = config.get('disabled_extensions', dict())
+    disabled[extension] = value
+
+    # Prune extensions that are not installed.
+    for key in list(disabled):
+        if (key not in extensions):
+            del disabled[key]
+    config['disabled_extensions'] = disabled
+    _write_page_config(config)
+
+
 def _write_build_config(config, app_dir):
     """Write the build config to the app dir.
     """
@@ -222,6 +266,15 @@ def _write_build_config(config, app_dir):
         json.dump(config, fid, indent=4)
 
 
+def _write_page_config(config, app_dir):
+    """Write the build config to the app dir.
+    """
+    _ensure_package(app_dir)
+    target = pjoin(app_dir, 'settings', 'page_config.json')
+    with open(target, 'w') as fid:
+        json.dump(config, fid, indent=4)
+
+
 def uninstall_extension(name, app_dir=None):
     """Uninstall an extension by name.
     """
@@ -253,10 +306,70 @@ def uninstall_extension(name, app_dir=None):
 
 
 def list_extensions(app_dir=None):
-    """List installed extensions.
+    """List the extensions.
     """
     app_dir = get_app_dir(app_dir)
-    return sorted(_get_extensions(app_dir).keys())
+    extensions = _get_extensions(app_dir)
+    disabled = _get_disabled(app_dir)
+    linked = _get_linked_packages(app_dir)
+    app = []
+    sys = []
+    linked = []
+
+    # We want to organize by dir.
+    for (key, value) in extensions.items():
+        if key in linked:
+            linked.append(key)
+        if value['path'] == sys_path and sys_path != app_dir:
+            sys.append(key)
+            continue
+        app.append(key)
+
+    print('Known labextensions:')
+    if app:
+        print('   app dir: %s' % app_dir)
+        for item in sorted(app):
+            extra = ''
+            if item in linked:
+                extra += '*'
+            if disabled.get(item, False):
+                extra += ' %s' % RED_DISABLED
+            else:
+                extra += ' %s' % GREEN_ENABLED
+            print('        %s%s' % (item, extra))
+
+    if sys:
+        print('   sys dir: %s' % sys_path)
+        for item in sorted(sys):
+            extra = ''
+            if item in linked:
+                extra += '*'
+            if disabled.get(item, False):
+                extra += ' %s' % RED_DISABLED
+            else:
+                extra += ' %s' % GREEN_ENABLED
+            print('        %s%s' % (item, extra))
+
+    if linked:
+        print('* Denotes linked packages')
+
+    # Handle uninstalled and disabled core packages
+    uninstalled_core = _get_uinstalled_core_extensions(app_dir)
+    if uninstalled_core:
+        print('\nUninstalled core extensiosn:')
+        [print(item) for item in sorted(uninstalled_core)]
+
+    with open(pjoin(here, 'package.app.json')) as fid:
+        core_extensions = json.load(fid)['jupyterlab']['extensions']
+
+    disabled_core = []
+    for key in core_extensions:
+        if disabled.get(key, False):
+            disabled_core.append(key)
+
+    if disabled_core:
+        print('\nDisabled core extensions:')
+        [print(item) for item in sorted(disabled_core)]
 
 
 def clean(app_dir=None):
@@ -343,8 +456,7 @@ def _ensure_package(app_dir, name=None, version=None):
         data['dependencies'][key] = value['path']
         data['jupyterlab']['extensions'].append(key)
 
-    config = _get_build_config(app_dir)
-    for item in config.get('uninstalled_core_extensions', []):
+    for item in _get_uinstalled_core_extensions(app_dir):
         data['jupyterlab']['extensions'].remove(item)
 
     data['jupyterlab']['name'] = name or 'JupyterLab'
@@ -368,6 +480,13 @@ def _is_extension(data):
     return data['jupyterlab'].get('extension', False)
 
 
+def _get_uinstalled_core_extensions(app_dir):
+    """Get the uninstalled core extensions.
+    """
+    config = _get_build_config(app_dir)
+    return config.get('uninstalled_core_extensions', [])
+
+
 def _validate_package(data, extension):
     """Validate package.json data.
     """
@@ -376,18 +495,25 @@ def _validate_package(data, extension):
         raise ValueError(msg)
 
 
+def _get_disabled(app_dir):
+    """Get the disabled extensions.
+    """
+    config = _get_page_config(app_dir)
+    return config.get('disabled_extensions', dict())
+
+
 def _get_extensions(app_dir):
     """Get the extensions in a given app dir.
     """
     extensions = dict()
 
-    # Look in sys_prefix and app_dir if different
-    sys_path = pjoin(ENV_JUPYTER_PATH[0], 'lab', 'extensions')
+    # Get system level packages
     for target in glob.glob(pjoin(sys_path, '*.tgz')):
         data = _read_package(target)
         extensions[data['name']] = dict(path=os.path.realpath(target),
                                         version=data['version'])
 
+    # Look in app_dir if different
     app_path = pjoin(app_dir, 'extensions')
     if app_path == sys_path or not os.path.exists(app_path):
         return extensions

+ 11 - 2
jupyterlab/index.js

@@ -21,6 +21,13 @@ function main() {
     if (version[0] === 'v') {
         version = version.slice(1);
     }
+    var disabled = Object.create(null);
+    try {
+        var option = PageConfig.getOption('disabledExtensions');
+        disabled = JSON.parse(option);
+    } catch (e) {
+        // No-op
+    }
 
     lab = new app({
         namespace: namespace,
@@ -32,7 +39,9 @@ function main() {
     });
     {{#each jupyterlab_extensions}}
     try {
-        lab.registerPluginModule(require('{{this}}'));
+        if (String(disabled['{{this}}']) !== 'true') {
+            lab.registerPluginModule(require('{{this}}'));
+        }
     } catch (e) {
         console.error(e);
     }
@@ -42,7 +51,7 @@ function main() {
         var option = PageConfig.getOption('ignorePlugins');
         ignorePlugins = JSON.parse(option);
     } catch (e) {
-        console.error("Invalid ignorePlugins config:", option);
+        // No-op
     }
     lab.start({ "ignorePlugins": ignorePlugins });
 }

+ 1 - 0
jupyterlab/labapp.py

@@ -90,6 +90,7 @@ lab_flags['dev-mode'] = (
     "Start the app in dev mode for running from source."
 )
 
+
 class LabApp(NotebookApp):
     version = __version__
 

+ 24 - 5
jupyterlab/labextensions.py

@@ -15,6 +15,7 @@ from traitlets import Bool, Unicode
 from ._version import __version__
 from .commands import (
     install_extension, uninstall_extension, list_extensions,
+    enable_extension, disable_extension,    
     link_package, unlink_package, build, _get_linked_packages
 )
 
@@ -37,12 +38,13 @@ class BaseExtensionApp(JupyterApp):
     app_dir = Unicode('', config=True,
         help="The app directory to target")
 
-    should_build = Bool(True, config=True,
+    should_build = Bool(False, config=True,
         help="Whether to build the app after the action")
 
 
 class InstallLabExtensionApp(BaseExtensionApp):
     description = "Install labextension(s)"
+    should_build = True
 
     def start(self):
         self.extra_args = self.extra_args or [os.getcwd()]
@@ -60,6 +62,7 @@ class LinkLabExtensionApp(BaseExtensionApp):
     package is manually re-installed from its source location when
     `jupyter lab build` is run.
     """
+    should_build = True
 
     def start(self):
         self.extra_args = self.extra_args or [os.getcwd()]
@@ -70,6 +73,7 @@ class LinkLabExtensionApp(BaseExtensionApp):
 
 class UnlinkLabExtensionApp(BaseExtensionApp):
     description = "Unlink labextension(s) or packages by name or path"
+    should_build = True
 
     def start(self):
         self.extra_args = self.extra_args or [os.getcwd()]
@@ -81,6 +85,7 @@ class UnlinkLabExtensionApp(BaseExtensionApp):
 
 class UninstallLabExtensionApp(BaseExtensionApp):
     description = "Uninstall labextension(s) by name"
+    should_build = True
 
     def start(self):
         self.extra_args = self.extra_args or [os.getcwd()]
@@ -92,21 +97,33 @@ class UninstallLabExtensionApp(BaseExtensionApp):
 
 class ListLabExtensionsApp(BaseExtensionApp):
     description = "List the installed labextensions"
-    should_build = False
 
     def start(self):
-        [print(ext) for ext in list_extensions(self.app_dir)]
+        list_extensions(self.app_dir)
 
 
 class ListLinkedLabExtensionsApp(BaseExtensionApp):
     description = "List the linked packages"
-    should_build = False
 
     def start(self):
         for path in _get_linked_packages(self.app_dir).values():
             print(path)
 
 
+class EnableLabExtensionsApp(BaseExtensionApp):
+    description = "Enable labextension(s) by name"
+
+    def start(self):
+        [enable_extension(arg, self.app_dir) for arg in self.extra_args]
+
+
+class DisableLabExtensionsApp(BaseExtensionApp):
+    description = "Disable labextension(s) by name"
+
+    def start(self):
+        [disable_extension(arg, self.app_dir) for arg in self.extra_args]
+
+
 _examples = """
 jupyter labextension list                        # list all configured labextensions
 jupyter labextension install <extension name>    # install a labextension
@@ -127,7 +144,9 @@ class LabExtensionApp(JupyterApp):
         list=(ListLabExtensionsApp, "List labextensions"),
         link=(LinkLabExtensionApp, "Link labextension(s)"),
         unlink=(UnlinkLabExtensionApp, "Unlink labextension(s)"),
-        listlinked=(ListLinkedLabExtensionsApp, "List linked extensions")
+        listlinked=(ListLinkedLabExtensionsApp, "List linked extensions"),
+        enable=(EnableLabExtensionsApp, "Enable labextension(s)"),
+        disable=(DisableLabExtensionsApp, "Disable labextensions(s)")
     )
 
     def start(self):