创建一个新的插件以扩展 CLI#

虽然 JupyterLite 应用程序的大部分行为可以通过扩展进行配置或修改,但这可能无法满足所有需求。也可以通过_插件_来扩展底层的jupyter lite CLI

自定义_插件_可以对已构建的 lite 应用程序的_输出文件夹_执行任何操作,以及修改其他_插件_(包括构成核心 API 的插件)的行为。

一些用例

  • 发布复杂的前端扩展

  • 可预测地修补已构建应用程序中的文件

  • 代码检查、测试、压缩或其他验证和优化技术

注意

选择_插件_是为了将这些组件与浏览器端的_插件_和前端的_扩展_区分开来,并且所有jupyter lite核心行为都作为_插件_实现。

CLI 架构#

在深入构建插件之前,值得了解它们在 CLI 整体结构中的位置。

为了从多个源下载、解压和更新静态文件和配置,CLI 使用了多层。

组件

示例

作用

应用

LiteBuildApp

加载配置并解析 CLI 参数

管理器

LiteManager

加载插件,运行doit

插件

StaticAddon

生成任务计划并实现操作

Hook

init

收集逻辑生命周期任务

Phase

pre_init

任务的细粒度排序

Task

init:static:unpack

具有任务和文件依赖关系的一组操作

Action

_unpack_stdlib

实际移动和更新文件

插件的结构#

最简单的插件以以下签名初始化

class MyAddon:
    __all__ = ["status"]

    def status(self, manager):
        yield dict(name="hello", actions=[lambda: print("world")])
  • __all__成员列出了插件实现的_钩子_

    • 钩子也可以带有pre_post_ _阶段_前缀

  • 如所宣传的钩子实现

值得注意的是

  • status阶段不应有副作用

  • init阶段主要保留给“黄金版”内容

  • build主要保留给用户创作内容

提示

请参阅此 JupyterLite 仓库中的现有示例,了解其他钩子实现。

生成任务#

每个钩子实现都应返回一个可迭代的doit 任务,其最小形式为

def post_build(manager):
    yield dict(
        name="a:unique:name", # will have the Addon, and maybe a prefix, prepended
        actions=[["things", "to", "do"]],
        file_dep=["a-file", Path("another-file")],
        targets=["an-output-file"],
    )

App 级别的任务已经根据它们的钩子父级配置了doit.create_after,这意味着任务可以_自信地_依赖其父级(由任何其他插件)已经存在的文件。

虽然不是_必需的_,但拥有准确的file_deptargets有助于确保已构建的应用程序始终处于一致状态,_而无需_大量返工。

BaseAddon#

一个便捷类,jupyterlite_core.addons.base.BaseAddon可以扩展以提供许多有用的功能。它扩展了traitlets.LoggingConfigurable,并将LiteManager设为_插件_的parent,从而允许它通过jupyter_lite_config.json按名称配置

{
  "LiteBuildConfig": {
    "ignore_sys_prefix": true
  },
  "MyAddon": {
    "enable_some_feature": true
  }
}

…或通过命令行。

jupyter lite build --MyAddon.enable_some_feature=True

短 CLI#

继承自BaseAddon(或以其他方式继承自traitlets.Configurable)的_插件_可以告知父应用程序它公开了额外的 CLI _别名_和_标志_,用于执行以及使用--help查询时。

提示

鼓励_插件_作者使用共同前缀对他们的别名和标志进行分组。

别名#

_别名_将 CLI 参数映射到单个特性。

from traitlets import Int

class MyFooAddon(BaseAddon):
    __all__ = ["status"]
    aliases = {
      "how-many-foos": "MyFooAddon.foo",
    }
    foo = Int(0, help="The number of foos").tag(config=True)
    # ...

警告

_插件_不得重载核心别名或先前加载的插件的别名。

标志#

_标志_将 CLI 参数映射到任意数量的traitlets.Configurable类上的任意数量的特性

from traitlets import Int, Bool

class MyFooBarAddon(BaseAddon):
    __all__ = ["status"]
    flags = {
      "foo-bar": (
        {"MyFooBarAddon": {"foo": 1, "bar": True}},
        "Foo once, and bar",
      )
    }
    foo = Int(0, help="The number of foos").tag(config=True)
    bar = Bar(False, help="Whether to bar").tag(config=True)
    # ...

注意

_插件_可以增强现有标志的行为,但不得覆盖先前注册的配置值。帮助文本将附加换行符。

打包#

_插件_通过entry_points进行广告,例如在pyproject.toml

[project.entry-points."jupyterlite.addon.v0"]
my-unique-addon = "my_module:MyAddon"

一般指南#

  • 值得研究BaseAddon及其子类如何处理某些任务

  • 记住可重现性,尽可能多地缓存,并利用file_depstargetsuptodate来保持构建速度