an observable configuration object for the JupyterLite lifecycle

class jupyterlite.config.LiteBuildConfig(**kwargs)

the description of a JupyterLite build

This is most likely to be configured: - from environment variables - in a pyproject.toml - from the command line With direct instantiation a distant last place.

This is conceptually similar in scale to jupyter_server_config.json, and will piggy-back off of the {sys.prefix}/share/jupyter_{notebook,server}_config.d/ loader paths


Well-known (and otherwise) constants used by JupyterLite

jupyterlite.constants.ADDON_ENTRYPOINT = 'jupyterlite.addon.v0'

the extension point for addons, including core

jupyterlite.constants.ALL_APP_ARCHIVES = [PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/jupyterlite/checkouts/latest/py/jupyterlite/src/jupyterlite/jupyterlite-app-0.1.0-alpha.14.tgz')]

all of the archives

jupyterlite.constants.ALL_JSON = 'all.json'

commonly-used filename for response fixtures, e.g. settings

jupyterlite.constants.API_CONTENTS = 'api/contents'

the Jupyter API route for Contents API

jupyterlite.constants.C_LOCALE = 'C'

a locale for reproducible file sorting

jupyterlite.constants.DEFAULT_APP_ARCHIVE = PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/jupyterlite/checkouts/latest/py/jupyterlite/src/jupyterlite/jupyterlite-app-0.1.0-alpha.14.tgz')

our baseline archive.

jupyterlite.constants.DEFAULT_OUTPUT_DIR = '_output'

Needs a better canonical location

jupyterlite.constants.HOOKS = ['status', 'init', 'build', 'check', 'serve', 'archive']

our doit task-based plugin system

jupyterlite.constants.HOOK_PARENTS = {'archive': 'build', 'build': 'init', 'check': 'build', 'serve': 'build'}

the name of the previous hook

jupyterlite.constants.INDEX_HTML = 'index.html'

a predictably-serveable HTML file

jupyterlite.constants.JUPYTERLITE_APPS = ['lab', 'retro']

a set of apps we currently know _might_ be in an app archive

jupyterlite.constants.JUPYTERLITE_IPYNB = 'jupyter-lite.ipynb'

our configuration file

jupyterlite.constants.JUPYTERLITE_JSON = 'jupyter-lite.json'

our configuration file

jupyterlite.constants.JUPYTERLITE_SCHEMA = 'jupyterlite.schema.v0.json'

our schema

jupyterlite.constants.JUPYTER_CONFIG_DATA = 'jupyter-config-data'

a script DOM ID on most jupyter pages

jupyterlite.constants.NPM_SOURCE_DATE_EPOCH = 499162500

this is arrived at by inspection

jupyterlite.constants.OVERRIDES_JSON = 'overrides.json'

settings overrides. used JupyterLab build system, usually goes in $PREFIX/share/jupyter/lab/

jupyterlite.constants.PACKAGE_JSON = 'package.json'

the canonical location of labextension metadata

jupyterlite.constants.PHASES = ['pre_', '', 'post_']

the lifecycle stages inside a hook

jupyterlite.constants.REQUIREMENTS_TXT = 'requirements.txt'

the generally-used listing of pip requirements

jupyterlite.constants.SHA256SUMS = 'SHA256SUMS'

output equivalent to sha256sum * for providing a local bill-of-data

jupyterlite.constants.SHARE_LABEXTENSIONS = 'share/jupyter/labextensions'

the canonical location within an env (or archive) for labextensions

jupyterlite.constants.SOURCE_DATE_EPOCH = 'SOURCE_DATE_EPOCH'

a canonical environment variable for triggering reproducible builds

jupyterlite.constants.UTF8 = {'encoding': 'utf-8'}

the encoding for pretty much every file written and read by jupyterlite


the JupyterLite CLI App(s)

class jupyterlite.app.BaseLiteApp(**kwargs)

TODO: An undescribed app

property description

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.

class jupyterlite.app.LiteApp(**kwargs)

build ready-to-serve (or -publish) JupyterLite sites

class jupyterlite.app.LiteArchiveApp(**kwargs)

build a JupyterLite app archive, which can be used as a baseline

class jupyterlite.app.LiteBuildApp(**kwargs)

build a JupyterLite site, including user content

class jupyterlite.app.LiteCheckApp(**kwargs)

verify a JupyterLite site, using available schema and rules

class jupyterlite.app.LiteDoitApp(**kwargs)

Run the doit command


Start the whole thing

class jupyterlite.app.LiteInitApp(**kwargs)

initialize a JupyterLite site from an app archive baseline

class jupyterlite.app.LiteListApp(**kwargs)

describe a JupyterLite site

class jupyterlite.app.LiteRawDoitApp(**kwargs)

use the full doit CLI, see https://pydoit.org/contents.html

tell jupyter to not parse the arguments with –, e.g.

jupyter-lite doit – –help


Parse the command line arguments.

class jupyterlite.app.LiteServeApp(**kwargs)

serve a JupyterLite site, using best available HTTP server

class jupyterlite.app.LiteStatusApp(**kwargs)

report about what a JupyterLite build _might_ do

class jupyterlite.app.LiteTaskApp(**kwargs)

run a doit task, optionally with –force


Start the whole thing

class jupyterlite.app.ManagedApp(**kwargs)

An app with a LiteManager that can do some config fixing


Start the whole thing


Manager for JupyterLite

class jupyterlite.manager.LiteManager(**kwargs)

a manager for building jupyterlite sites

This primarily handles the business of mapping _addons_ to doit _tasks_, and then calling the doit API.

Packaging an Addon

An Addon is advertised via entry_points e.g. in pyproject.toml:

Structure of an Addon

An Addon is initialized with a signature like:

A convenience class, jupyterlite.addons.base.BaseAddon provides a number of useful features.

The __all__ member list hooks. Hooks may also be prefixed with pre_ and post_ phase which go in roughly logical order. Of note:

  • The init phase is mostly reserved for “gold master” content

  • The build is mostly reserved for user-authored content

  • A status method to give one-line reporting, and should have no side-effects

See the existing examples in this directory for other hook implementations.

The Task Generator

Each method is expected to return an iterable of doit tasks, of the minimal form:

The top-level tasks usually have doit.create_after configured based on their hook parent, which means a task can confidently rely on files from that parent (by any addons) would already exist.

doit_run(task, *args, raw=False)

run a subset of the doit command line


perform one-time inialization of the manager



a JupyterLite addon for generating app archives which can be used as input

class jupyterlite.addons.archive.ArchiveAddon(**kwargs)

Adds contents from the lite_dir to the output_dir, creates API output

If --source-date-epoch (SDE) is set, a number of features will be enabled to improve reproducibility of the final artifact. In addition to timestamps newer than SDE being “clamped” to SDE, this will also adjust some permissions inside the tarball


add all files created prior to pre_archive to an archive


apply best-effort entropy fixes to give more reproducible archives

log_archive(tarball, prefix='')

print some information about an archive

make_archive_stdlib(tarball, root, members)

actually build the archive.

  • this takes longer than any other hook
    • while this pure-python implementation needs to be maintained, a libarchive-based build might be preferrable for e.g. CI performance.

  • an npm-compatible .tgz is the only supported archive format, as this is compatible with the upstream webpack build and its native packaged format.


Context manager for changing the current locale


class jupyterlite.addons.base.BaseAddon(**kwargs)

A base class for addons to the JupyterLite build chain

Subclassing this is optional, but provides some useful utilities

copy_one(src, dest)

copy one Path (a file or folder)


update a federated_extension list in-place, ensuring unique names.


delete… something

fetch_one(url, dest)

fetch one file

TODO: enable other backends, auth, etc.

property log

A trait which allows any value.

merge_jupyter_config_data(config, in_config)

merge well-known jupyter-config-data fields

merge_one_jupyterlite(out_path, in_paths)

write the out_path with the merge content of in_paths, where all are valid jupyter-lite.* files.


adjust the timestamp to be –source-date-epoch for files newer than then

see https://reproducible-builds.org/specs/source-date-epoch


a JupyterLite addon for Jupyter Server-compatible contents

class jupyterlite.addons.contents.ContentsAddon(**kwargs)

Adds contents from the lite_dir to the output_dir, creates API output


perform the main user build of pre-populating /files/


verify that all Contents API is valid (sorta)

property file_src_dest

the pairs of contents that will be copied

these are processed in reverse order, such that only the last path wins

maybe_add_one_path(path, root=None)

add a file or folder’s contents (if not ignored)

one_contents_path(output_file_dir, api_path)

A lazy reuse of a jupyter_server Contents API generator

patch_listing_timestamps(listing, sde=None)

clamp a contents listing’s times to SOURCE_DATE_EPOCH


create a Contents API index for each subdirectory in /files/


yield some status information about the state of contents

class jupyterlite.addons.contents.DateTimeEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)

A custom date-aware JSON encoder


Implement this method in a subclass such that it returns a serializable object for o, or calls the base implementation (to raise a TypeError).

For example, to support arbitrary iterators, you could implement default like this:

def default(self, o):
        iterable = iter(o)
    except TypeError:
        return list(iterable)
    # Let the base class default method raise the TypeError
    return JSONEncoder.default(self, o)

a small helper to user Z for UTC ISO strings

Federated Extensions

a JupyterLite addon for supporting federated_extensions

class jupyterlite.addons.federated_extensions.FederatedExtensionAddon(**kwargs)

sync the as-installed federated_extensions and update jupyter-lite.json


yield a doit task to copy each local extension into the output_dir


copy the labextensions from a local conda package


copy one unpacked on-disk extension from sys.prefix into the output dir


copy one unpacked on-disk extension from anywhere into the output dir


copy one extension from the given path


copy the labextensions from a local wheel


a list of all federated extensions

extract_one_conda_extension(conda_pkg, pkg_json_info, all_infos)

extract one labextension from a conda package

extract_one_wheel_extension(wheel, pkg_json_info, all_infos)

extract one labextension from a wheel

property output_extensions

where labextensions will go in the output folder


add the federated_extensions to jupyter-lite.json


update the root jupyter-lite.json, and copy each output theme to each app


handle downloading of federated extensions


yield a doit task to copy each federated extension into the output_dir

resolve_one_extension(path_or_url, init)

try to resolve one URL or local folder/archive as a (set of) federated_extension(s)


a JupyterLite addon for jupyterlite-specific tasks

class jupyterlite.addons.lite.LiteAddon(**kwargs)

ensure jupyterlite files have been merged, and validate them


merge jupyter-lite.json into the output_dir


apply schema validation to all jupyter-lite.json in the output_dir

property lite_files

all the source jupyter-lite.* files


a JupyterLite addon for generating hashes

class jupyterlite.addons.report.ReportAddon(**kwargs)

update static listings of the site contents in various formats

having these in various formats down the line can be handy for various publishing tasks


generate a hash file of all files in the distribution.

As this is relatively expensive for hundreds of files, this is performed as late as possible, while still providing some useful publishing / QA features.

TODO: develop some contract with the frontend in relation to this file,

or a derivative, as it has precisely the right information for certain cache tasks.

property sha256sums

The location of the hashfile.


a JupyterLite addon for serving

class jupyterlite.addons.serve.ServeAddon(**kwargs)


a JupyterLite addon for supporting extension settings

class jupyterlite.addons.settings.SettingsAddon(**kwargs)

sync the as-installed overrides.json and update jupyter-lite.json

property output_extensions

where labextensions will go in the output folder

patch_one_overrides(jupyterlite_json, overrides_json)

update and normalize settingsOverrides


add settings from overrides.json per app where they exist


a JupyterLite addon for jupyterlab core

class jupyterlite.addons.static.StaticAddon(**kwargs)

Copy the core “gold master” artifacts into the output folder


unpack and copy the tarball files into the output_dir


remove static assets if the app is not installed


well before anything else, we need to ensure that the output_dir exists and is empty (if the baseline tarball has changed)