From 0c6866847a402adf1d331172c4ca7694163fe5b3 Mon Sep 17 00:00:00 2001 From: Duc Trung LE Date: Tue, 15 Oct 2024 12:05:50 +0200 Subject: [PATCH] Add XeusAddon.package_url_factory config --- jupyterlite_xeus/add_on.py | 13 +++- src/index.ts | 126 ++++++++++++++++++++----------------- src/tokens.ts | 4 +- src/web_worker_kernel.ts | 13 +++- src/worker.ts | 7 +-- 5 files changed, 94 insertions(+), 69 deletions(-) diff --git a/jupyterlite_xeus/add_on.py b/jupyterlite_xeus/add_on.py index 39f77da..b315fb9 100644 --- a/jupyterlite_xeus/add_on.py +++ b/jupyterlite_xeus/add_on.py @@ -1,4 +1,5 @@ """a JupyterLite addon for creating the env for xeus kernels""" + import json import os from pathlib import Path @@ -18,7 +19,7 @@ SHARE_LABEXTENSIONS, UTF8, ) -from traitlets import Bool, List, Unicode +from traitlets import Bool, Callable, List, Unicode from .create_conda_env import ( create_conda_env_from_env_file, @@ -102,6 +103,13 @@ class XeusAddon(FederatedExtensionAddon): description="A comma-separated list of mount points, in the form : to mount in the wasm prefix", ) + package_url_factory = Callable( + None, + allow_none=True, + config=True, + description="Factory to generate package download URL from package metadata. This is used to load python packages from external host", + ) + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.xeus_output_dir = Path(self.manager.output_dir) / "xeus" @@ -290,6 +298,7 @@ def pack_prefix(self, kernel_dir): relocate_prefix="/", outdir=out_path, use_cache=False, + package_url_factory=self.package_url_factory, **pack_kwargs, ) @@ -430,4 +439,4 @@ def dedupe_federated_extensions(self, config): if os.path.exists(self.output_extensions / ext["name"] / ext["load"]): named[ext["name"]] = ext - config[FEDERATED_EXTENSIONS] = sorted(named.values(), key=lambda x: x["name"]) + config[FEDERATED_EXTENSIONS] = sorted(named.values(), key=lambda x: x["name"]) \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 682c1c8..fefd46b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,78 +30,86 @@ try { throw err; } -const plugins = kernel_list.map((kernel): JupyterLiteServerPlugin => { - return { - id: `@jupyterlite/xeus-${kernel}:register`, - autoStart: true, - requires: [IKernelSpecs], - optional: [IServiceWorkerManager, IBroadcastChannelWrapper, IEmpackEnvMetaFile], - activate: ( - app: JupyterLiteServer, - kernelspecs: IKernelSpecs, - serviceWorker?: IServiceWorkerManager, - broadcastChannel?: IBroadcastChannelWrapper, - empackEnvMetaFile?: IEmpackEnvMetaFile - ) => { - // Fetch kernel spec - const kernelspec = getJson('xeus/kernels/' + kernel + '/kernel.json'); - kernelspec.name = kernel; - kernelspec.dir = kernel; - for (const [key, value] of Object.entries(kernelspec.resources)) { - kernelspec.resources[key] = URLExt.join( - PageConfig.getBaseUrl(), - value as string - ); - } - - const contentsManager = app.serviceManager.contents; - kernelspecs.register({ - spec: kernelspec, - create: async (options: IKernel.IOptions): Promise => { - const mountDrive = !!( - (serviceWorker?.enabled && broadcastChannel?.enabled) || - crossOriginIsolated +const plugins = kernel_list.map( + (kernel): JupyterLiteServerPlugin => { + return { + id: `@jupyterlite/xeus-${kernel}:register`, + autoStart: true, + requires: [IKernelSpecs], + optional: [ + IServiceWorkerManager, + IBroadcastChannelWrapper, + IEmpackEnvMetaFile + ], + activate: ( + app: JupyterLiteServer, + kernelspecs: IKernelSpecs, + serviceWorker?: IServiceWorkerManager, + broadcastChannel?: IBroadcastChannelWrapper, + empackEnvMetaFile?: IEmpackEnvMetaFile + ) => { + // Fetch kernel spec + const kernelspec = getJson('xeus/kernels/' + kernel + '/kernel.json'); + kernelspec.name = kernel; + kernelspec.dir = kernel; + for (const [key, value] of Object.entries(kernelspec.resources)) { + kernelspec.resources[key] = URLExt.join( + PageConfig.getBaseUrl(), + value as string ); + } - if (mountDrive) { - console.info( - `${kernelspec.name} contents will be synced with Jupyter Contents` + const contentsManager = app.serviceManager.contents; + kernelspecs.register({ + spec: kernelspec, + create: async (options: IKernel.IOptions): Promise => { + const mountDrive = !!( + (serviceWorker?.enabled && broadcastChannel?.enabled) || + crossOriginIsolated ); - } else { - console.warn( - `${kernelspec.name} contents will NOT be synced with Jupyter Contents` - ); - } - const link = empackEnvMetaFile ? await empackEnvMetaFile.getLink(kernelspec.dir): ''; - return new WebWorkerKernel({ - ...options, - contentsManager, - mountDrive, - kernelSpec: kernelspec, - empackEnvMetaLink: link - }); - } - }); - } - }; -}); + if (mountDrive) { + console.info( + `${kernelspec.name} contents will be synced with Jupyter Contents` + ); + } else { + console.warn( + `${kernelspec.name} contents will NOT be synced with Jupyter Contents` + ); + } + const link = empackEnvMetaFile + ? await empackEnvMetaFile.getLink(kernelspec.dir) + : ''; + + return new WebWorkerKernel({ + ...options, + contentsManager, + mountDrive, + kernelSpec: kernelspec, + empackEnvMetaLink: link + }); + } + }); + } + }; + } +); const empackEnvMetaPlugin: JupyterLiteServerPlugin = { - id: `@jupyterlite/xeus-python:empack-env-meta`, + id: '@jupyterlite/xeus-python:empack-env-meta', autoStart: true, provides: IEmpackEnvMetaFile, activate: (): IEmpackEnvMetaFile => { return { getLink: async (kernel?: string) => { - const kernel_root_url = URLExt.join( - PageConfig.getBaseUrl(), - `xeus/kernels/${kernel}` - ); - return `${kernel_root_url}`; + const kernel_root_url = URLExt.join( + PageConfig.getBaseUrl(), + `xeus/kernels/${kernel}` + ); + return `${kernel_root_url}`; } }; - }, + } }; plugins.push(empackEnvMetaPlugin); diff --git a/src/tokens.ts b/src/tokens.ts index 3743470..ae0370d 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -97,4 +97,6 @@ export interface IEmpackEnvMetaFile { getLink: (kernel?: string) => Promise; } -export const IEmpackEnvMetaFile = new Token('@jupyterlite/xeus-python:IEmpackEnvMetaFile'); +export const IEmpackEnvMetaFile = new Token( + '@jupyterlite/xeus-python:IEmpackEnvMetaFile' +); diff --git a/src/web_worker_kernel.ts b/src/web_worker_kernel.ts index 94dc86c..719af94 100644 --- a/src/web_worker_kernel.ts +++ b/src/web_worker_kernel.ts @@ -29,8 +29,15 @@ export class WebWorkerKernel implements IKernel { * @param options The instantiation options for a new WebWorkerKernel */ constructor(options: WebWorkerKernel.IOptions) { - const { id, name, sendMessage, location, kernelSpec, contentsManager, empackEnvMetaLink } = - options; + const { + id, + name, + sendMessage, + location, + kernelSpec, + contentsManager, + empackEnvMetaLink + } = options; this._id = id; this._name = name; this._location = location; @@ -105,7 +112,7 @@ export class WebWorkerKernel implements IKernel { kernelSpec: this._kernelSpec, baseUrl: PageConfig.getBaseUrl(), mountDrive: options.mountDrive, - empackEnvMetaLink: this._empackEnvMetaLink, + empackEnvMetaLink: this._empackEnvMetaLink }) .then(this._ready.resolve.bind(this._ready)); diff --git a/src/worker.ts b/src/worker.ts index 1e25b50..4d47d06 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -125,10 +125,9 @@ export class XeusRemoteKernel { // This function is usually implemented in the pre/post.js // in the emscripten build of that kernel if (globalThis.Module['async_init'] !== undefined) { - const kernel_root_url = empackEnvMetaLink ? empackEnvMetaLink : URLExt.join( - baseUrl, - `xeus/kernels/${kernelSpec.dir}` - ); + const kernel_root_url = empackEnvMetaLink + ? empackEnvMetaLink + : URLExt.join(baseUrl, `xeus/kernels/${kernelSpec.dir}`); const pkg_root_url = URLExt.join(baseUrl, 'xeus/kernel_packages'); const verbose = true; await globalThis.Module['async_init'](