| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 |
- """Jupyter LabExtension Entry Points."""
- # Copyright (c) Jupyter Development Team.
- # Distributed under the terms of the Modified BSD License.
- import os
- import sys
- from copy import copy
- from jupyter_core.application import JupyterApp, base_aliases, base_flags
- from traitlets import Bool, Instance, List, Unicode, default
- from jupyterlab.coreconfig import CoreConfig
- from jupyterlab.debuglog import DebugLogFileMixin
- from .commands import (
- HERE,
- AppOptions,
- build,
- check_extension,
- disable_extension,
- enable_extension,
- get_app_version,
- install_extension,
- link_package,
- list_extensions,
- lock_extension,
- uninstall_extension,
- unlink_package,
- unlock_extension,
- update_extension,
- )
- from .federated_labextensions import build_labextension, develop_labextension_py, watch_labextension
- from .labapp import LabApp
- flags = dict(base_flags)
- flags["no-build"] = (
- {"BaseExtensionApp": {"should_build": False}},
- "Defer building the app after the action.",
- )
- flags["dev-build"] = (
- {"BaseExtensionApp": {"dev_build": True}},
- "Build in development mode.",
- )
- flags["no-minimize"] = (
- {"BaseExtensionApp": {"minimize": False}},
- "Do not minimize a production build.",
- )
- flags["clean"] = (
- {"BaseExtensionApp": {"should_clean": True}},
- "Cleanup intermediate files after the action.",
- )
- flags["splice-source"] = (
- {"BaseExtensionApp": {"splice_source": True}},
- "Splice source packages into app directory.",
- )
- check_flags = copy(flags)
- check_flags["installed"] = (
- {"CheckLabExtensionsApp": {"should_check_installed_only": True}},
- "Check only if the extension is installed.",
- )
- develop_flags = copy(flags)
- develop_flags["overwrite"] = (
- {"DevelopLabExtensionApp": {"overwrite": True}},
- "Overwrite files",
- )
- update_flags = copy(flags)
- update_flags["all"] = (
- {"UpdateLabExtensionApp": {"all": True}},
- "Update all extensions",
- )
- uninstall_flags = copy(flags)
- uninstall_flags["all"] = (
- {"UninstallLabExtensionApp": {"all": True}},
- "Uninstall all extensions",
- )
- list_flags = copy(flags)
- list_flags["verbose"] = (
- {"ListLabExtensionsApp": {"verbose": True}},
- "Increase verbosity level",
- )
- aliases = dict(base_aliases)
- aliases["app-dir"] = "BaseExtensionApp.app_dir"
- aliases["dev-build"] = "BaseExtensionApp.dev_build"
- aliases["minimize"] = "BaseExtensionApp.minimize"
- aliases["debug-log-path"] = "DebugLogFileMixin.debug_log_path"
- install_aliases = copy(aliases)
- install_aliases["pin-version-as"] = "InstallLabExtensionApp.pin"
- enable_aliases = copy(aliases)
- enable_aliases["level"] = "EnableLabExtensionsApp.level"
- disable_aliases = copy(aliases)
- disable_aliases["level"] = "DisableLabExtensionsApp.level"
- lock_aliases = copy(aliases)
- lock_aliases["level"] = "LockLabExtensionsApp.level"
- unlock_aliases = copy(aliases)
- unlock_aliases["level"] = "UnlockLabExtensionsApp.level"
- VERSION = get_app_version()
- LABEXTENSION_COMMAND_WARNING = "Users should manage prebuilt extensions with package managers like pip and conda, and extension authors are encouraged to distribute their extensions as prebuilt packages"
- class BaseExtensionApp(JupyterApp, DebugLogFileMixin):
- version = VERSION
- flags = flags
- aliases = aliases
- name = "lab"
- # Not configurable!
- core_config = Instance(CoreConfig, allow_none=True)
- app_dir = Unicode("", config=True, help="The app directory to target")
- should_build = Bool(True, config=True, help="Whether to build the app after the action")
- dev_build = Bool(
- None,
- allow_none=True,
- config=True,
- help="Whether to build in dev mode. Defaults to True (dev mode) if there are any locally linked extensions, else defaults to False (production mode).",
- )
- minimize = Bool(
- True,
- config=True,
- help="Whether to minimize a production build (defaults to True).",
- )
- should_clean = Bool(
- False,
- config=True,
- help="Whether temporary files should be cleaned up after building jupyterlab",
- )
- splice_source = Bool(False, config=True, help="Splice source packages into app directory.")
- labextensions_path = List(
- Unicode(),
- help="The standard paths to look in for prebuilt JupyterLab extensions",
- )
- @default("labextensions_path")
- def _default_labextensions_path(self):
- lab = LabApp()
- lab.load_config_file()
- return lab.labextensions_path + lab.extra_labextensions_path
- @default("splice_source")
- def _default_splice_source(self):
- version = get_app_version(AppOptions(app_dir=self.app_dir))
- return version.endswith("-spliced")
- def start(self):
- if self.app_dir and self.app_dir.startswith(HERE):
- msg = "Cannot run lab extension commands in core app"
- raise ValueError(msg)
- with self.debug_logging():
- ans = self.run_task()
- if ans and self.should_build:
- production = None if self.dev_build is None else not self.dev_build
- app_options = AppOptions(
- app_dir=self.app_dir,
- logger=self.log,
- core_config=self.core_config,
- splice_source=self.splice_source,
- )
- build(
- clean_staging=self.should_clean,
- production=production,
- minimize=self.minimize,
- app_options=app_options,
- )
- def run_task(self):
- pass
- def deprecation_warning(self, msg):
- return self.log.warning(
- f"\033[33m(Deprecated) {msg}\n\n{LABEXTENSION_COMMAND_WARNING} \033[0m"
- )
- def _log_format_default(self):
- """A default format for messages"""
- return "%(message)s"
- class InstallLabExtensionApp(BaseExtensionApp):
- description = """Install labextension(s)
- Usage
- jupyter labextension install [--pin-version-as <alias,...>] <package...>
- This installs JupyterLab extensions similar to yarn add or npm install.
- Pass a list of comma separate names to the --pin-version-as flag
- to use as aliases for the packages providers. This is useful to
- install multiple versions of the same extension.
- These can be uninstalled with the alias you provided
- to the flag, similar to the "alias" feature of yarn add.
- """
- aliases = install_aliases
- pin = Unicode("", config=True, help="Pin this version with a certain alias")
- def run_task(self):
- self.deprecation_warning(
- "Installing extensions with the jupyter labextension install command is now deprecated and will be removed in a future major version of JupyterLab."
- )
- pinned_versions = self.pin.split(",")
- self.extra_args = self.extra_args or [os.getcwd()]
- return any(
- install_extension(
- arg,
- # Pass in pinned alias if we have it
- pin=pinned_versions[i] if i < len(pinned_versions) else None,
- app_options=AppOptions(
- app_dir=self.app_dir,
- logger=self.log,
- core_config=self.core_config,
- labextensions_path=self.labextensions_path,
- ),
- )
- for i, arg in enumerate(self.extra_args)
- )
- class DevelopLabExtensionApp(BaseExtensionApp):
- description = "(developer) Develop labextension"
- flags = develop_flags
- user = Bool(False, config=True, help="Whether to do a user install")
- sys_prefix = Bool(True, config=True, help="Use the sys.prefix as the prefix")
- overwrite = Bool(False, config=True, help="Whether to overwrite files")
- symlink = Bool(True, config=False, help="Whether to use a symlink")
- labextensions_dir = Unicode(
- "",
- config=True,
- help="Full path to labextensions dir (probably use prefix or user)",
- )
- def run_task(self):
- """Add config for this labextension"""
- self.extra_args = self.extra_args or [os.getcwd()]
- for arg in self.extra_args:
- develop_labextension_py(
- arg,
- user=self.user,
- sys_prefix=self.sys_prefix,
- labextensions_dir=self.labextensions_dir,
- logger=self.log,
- overwrite=self.overwrite,
- symlink=self.symlink,
- )
- class BuildLabExtensionApp(BaseExtensionApp):
- description = "(developer) Build labextension"
- static_url = Unicode("", config=True, help="Sets the url for static assets when building")
- development = Bool(False, config=True, help="Build in development mode")
- source_map = Bool(False, config=True, help="Generate source maps")
- core_path = Unicode(
- os.path.join(HERE, "staging"),
- config=True,
- help="Directory containing core application package.json file",
- )
- aliases = {
- "static-url": "BuildLabExtensionApp.static_url",
- "development": "BuildLabExtensionApp.development",
- "source-map": "BuildLabExtensionApp.source_map",
- "core-path": "BuildLabExtensionApp.core_path",
- }
- def run_task(self):
- self.extra_args = self.extra_args or [os.getcwd()]
- build_labextension(
- self.extra_args[0],
- logger=self.log,
- development=self.development,
- static_url=self.static_url or None,
- source_map=self.source_map,
- core_path=self.core_path or None,
- )
- class WatchLabExtensionApp(BaseExtensionApp):
- description = "(developer) Watch labextension"
- development = Bool(True, config=True, help="Build in development mode")
- source_map = Bool(False, config=True, help="Generate source maps")
- core_path = Unicode(
- os.path.join(HERE, "staging"),
- config=True,
- help="Directory containing core application package.json file",
- )
- aliases = {
- "core-path": "WatchLabExtensionApp.core_path",
- "development": "WatchLabExtensionApp.development",
- "source-map": "WatchLabExtensionApp.source_map",
- }
- def run_task(self):
- self.extra_args = self.extra_args or [os.getcwd()]
- labextensions_path = self.labextensions_path
- watch_labextension(
- self.extra_args[0],
- labextensions_path,
- logger=self.log,
- development=self.development,
- source_map=self.source_map,
- core_path=self.core_path or None,
- )
- class UpdateLabExtensionApp(BaseExtensionApp):
- description = "Update labextension(s)"
- flags = update_flags
- all = Bool(False, config=True, help="Whether to update all extensions")
- def run_task(self):
- self.deprecation_warning(
- "Updating extensions with the jupyter labextension update command is now deprecated and will be removed in a future major version of JupyterLab."
- )
- if not self.all and not self.extra_args:
- self.log.warning(
- "Specify an extension to update, or use --all to update all extensions"
- )
- return False
- app_options = AppOptions(
- app_dir=self.app_dir,
- logger=self.log,
- core_config=self.core_config,
- labextensions_path=self.labextensions_path,
- )
- if self.all:
- return update_extension(all_=True, app_options=app_options)
- return any(update_extension(name=arg, app_options=app_options) for arg in self.extra_args)
- class LinkLabExtensionApp(BaseExtensionApp):
- description = """
- Link local npm packages that are not lab extensions.
- Links a package to the JupyterLab build process. A linked
- package is manually re-installed from its source location when
- `jupyter lab build` is run.
- """
- should_build = Bool(True, config=True, help="Whether to build the app after the action")
- def run_task(self):
- self.extra_args = self.extra_args or [os.getcwd()]
- options = AppOptions(
- app_dir=self.app_dir,
- logger=self.log,
- labextensions_path=self.labextensions_path,
- core_config=self.core_config,
- )
- return any(link_package(arg, app_options=options) for arg in self.extra_args)
- class UnlinkLabExtensionApp(BaseExtensionApp):
- description = "Unlink packages by name or path"
- def run_task(self):
- self.extra_args = self.extra_args or [os.getcwd()]
- options = AppOptions(
- app_dir=self.app_dir,
- logger=self.log,
- labextensions_path=self.labextensions_path,
- core_config=self.core_config,
- )
- return any(unlink_package(arg, app_options=options) for arg in self.extra_args)
- class UninstallLabExtensionApp(BaseExtensionApp):
- description = "Uninstall labextension(s) by name"
- flags = uninstall_flags
- all = Bool(False, config=True, help="Whether to uninstall all extensions")
- def run_task(self):
- self.deprecation_warning(
- "Uninstalling extensions with the jupyter labextension uninstall command is now deprecated and will be removed in a future major version of JupyterLab."
- )
- self.extra_args = self.extra_args or [os.getcwd()]
- options = AppOptions(
- app_dir=self.app_dir,
- logger=self.log,
- labextensions_path=self.labextensions_path,
- core_config=self.core_config,
- )
- return any(
- uninstall_extension(arg, all_=self.all, app_options=options) for arg in self.extra_args
- )
- class ListLabExtensionsApp(BaseExtensionApp):
- description = "List the installed labextensions"
- verbose = Bool(False, help="Increase verbosity level.").tag(config=True)
- flags = list_flags
- def run_task(self):
- list_extensions(
- app_options=AppOptions(
- app_dir=self.app_dir,
- logger=self.log,
- core_config=self.core_config,
- labextensions_path=self.labextensions_path,
- verbose=self.verbose,
- )
- )
- class EnableLabExtensionsApp(BaseExtensionApp):
- description = "Enable labextension(s) by name"
- aliases = enable_aliases
- level = Unicode("sys_prefix", help="Level at which to enable: sys_prefix, user, system").tag(
- config=True
- )
- def run_task(self):
- app_options = AppOptions(
- app_dir=self.app_dir,
- logger=self.log,
- core_config=self.core_config,
- labextensions_path=self.labextensions_path,
- )
- [
- enable_extension(arg, app_options=app_options, level=self.level)
- for arg in self.extra_args
- ]
- class DisableLabExtensionsApp(BaseExtensionApp):
- description = "Disable labextension(s) by name"
- aliases = disable_aliases
- level = Unicode("sys_prefix", help="Level at which to disable: sys_prefix, user, system").tag(
- config=True
- )
- def run_task(self):
- app_options = AppOptions(
- app_dir=self.app_dir,
- logger=self.log,
- core_config=self.core_config,
- labextensions_path=self.labextensions_path,
- )
- [
- disable_extension(arg, app_options=app_options, level=self.level)
- for arg in self.extra_args
- ]
- self.log.info(
- "Starting with JupyterLab 4.1 individual plugins can be re-enabled"
- " in the user interface. While all plugins which were previously"
- " disabled have been locked, you need to explicitly lock any newly"
- " disabled plugins by using `jupyter labextension lock` command."
- )
- class LockLabExtensionsApp(BaseExtensionApp):
- description = "Lock labextension(s) by name"
- aliases = lock_aliases
- level = Unicode("sys_prefix", help="Level at which to lock: sys_prefix, user, system").tag(
- config=True
- )
- def run_task(self):
- app_options = AppOptions(
- app_dir=self.app_dir,
- logger=self.log,
- core_config=self.core_config,
- labextensions_path=self.labextensions_path,
- )
- [lock_extension(arg, app_options=app_options, level=self.level) for arg in self.extra_args]
- class UnlockLabExtensionsApp(BaseExtensionApp):
- description = "Unlock labextension(s) by name"
- aliases = unlock_aliases
- level = Unicode("sys_prefix", help="Level at which to unlock: sys_prefix, user, system").tag(
- config=True
- )
- def run_task(self):
- app_options = AppOptions(
- app_dir=self.app_dir,
- logger=self.log,
- core_config=self.core_config,
- labextensions_path=self.labextensions_path,
- )
- [
- unlock_extension(arg, app_options=app_options, level=self.level)
- for arg in self.extra_args
- ]
- class CheckLabExtensionsApp(BaseExtensionApp):
- description = "Check labextension(s) by name"
- flags = check_flags
- should_check_installed_only = Bool(
- False,
- config=True,
- help="Whether it should check only if the extensions is installed",
- )
- def run_task(self):
- app_options = AppOptions(
- app_dir=self.app_dir,
- logger=self.log,
- core_config=self.core_config,
- labextensions_path=self.labextensions_path,
- )
- all_enabled = all(
- check_extension(
- arg, installed=self.should_check_installed_only, app_options=app_options
- )
- for arg in self.extra_args
- )
- if not all_enabled:
- self.exit(1)
- _EXAMPLES = """
- jupyter labextension list # list all configured labextensions
- jupyter labextension install <extension name> # install a labextension
- jupyter labextension uninstall <extension name> # uninstall a labextension
- jupyter labextension develop # (developer) develop a prebuilt labextension
- jupyter labextension build # (developer) build a prebuilt labextension
- jupyter labextension watch # (developer) watch a prebuilt labextension
- """
- class LabExtensionApp(JupyterApp):
- """Base jupyter labextension command entry point"""
- name = "jupyter labextension"
- version = VERSION
- description = "Work with JupyterLab extensions"
- examples = _EXAMPLES
- subcommands = {
- "install": (InstallLabExtensionApp, "Install labextension(s)"),
- "update": (UpdateLabExtensionApp, "Update labextension(s)"),
- "uninstall": (UninstallLabExtensionApp, "Uninstall labextension(s)"),
- "list": (ListLabExtensionsApp, "List labextensions"),
- "link": (LinkLabExtensionApp, "Link labextension(s)"),
- "unlink": (UnlinkLabExtensionApp, "Unlink labextension(s)"),
- "enable": (EnableLabExtensionsApp, "Enable labextension(s)"),
- "disable": (DisableLabExtensionsApp, "Disable labextension(s)"),
- "lock": (LockLabExtensionsApp, "Lock labextension(s)"),
- "unlock": (UnlockLabExtensionsApp, "Unlock labextension(s)"),
- "check": (CheckLabExtensionsApp, "Check labextension(s)"),
- "develop": (DevelopLabExtensionApp, "(developer) Develop labextension(s)"),
- "build": (BuildLabExtensionApp, "(developer) Build labextension"),
- "watch": (WatchLabExtensionApp, "(developer) Watch labextension"),
- }
- def start(self):
- """Perform the App's functions as configured"""
- super().start()
- # The above should have called a subcommand and raised NoStart; if we
- # get here, it didn't, so we should self.log.info a message.
- subcmds = ", ".join(sorted(self.subcommands))
- self.exit(f"Please supply at least one subcommand: {subcmds}")
- main = LabExtensionApp.launch_instance
- if __name__ == "__main__":
- sys.exit(main())
|