jupyterlite-pyodide-lock#

Addons#

PyodideLockAddon#

A JupyterLite addon for patching pyodide-lock.json files.

class jupyterlite_pyodide_lock.addons.lock.PyodideLockAddon(**kwargs: Any)[source]#

Bases: _BaseAddon

Patches a pyodide to include pyodide-kernel and custom packages.

Can handle PEP508 specs, wheels, and their dependencies.

Special pyodide-specific .zip packages are not supported.

Create a configurable given a config config.

Parameters#

configConfig

If this is empty, default values are used. If config is a Config instance, it will be used to configure the instance.

parentConfigurable instance, optional

The parent Configurable instance of this object.

Notes#

Subclasses of Configurable must call the __init__() method of Configurable before doing anything else and using super():

class MyConfigurable(Configurable):
    def __init__(self, config=None):
        super(MyConfigurable, self).__init__(config=config)
        # Then any other code you need to finish initialization.

This ensures that instances will be configured properly.

aliases: ClassVar = {'pyodide-lock-date-epoch': 'PyodideLockAddon.lock_date_epoch'}#
bootstrap_wheels c.PyodideLockAddon.bootstrap_wheels = TypedTuple()#

packages names from the lockfile to ensure before attempting a lock

copy_wheel(wheel) TTaskGenerator[source]#

Copy one wheel to {output_dir}.

Parameters:

wheel (Path)

Return type:

Generator[None, None, dict[str, Any]]

enabled c.PyodideLockAddon.enabled = Bool(False)#

whether experimental ‘pyodide-lock’ integration is enabled

extra_preload_packages c.PyodideLockAddon.extra_preload_packages = TypedTuple()#

extra packages to add to PyodideAddon.loadPyodideOptions.packages: these will be downloaded and installed, but _not_ imported to sys.modules

property federated_wheel_dirs: list[Path]#

The locations of wheels referenced by federated labextensions.

flags c.PyodideLockAddon.extra_preload_packages = TypedTuple()#
get_packages() dict[str, Path][source]#

Find all file-based packages to install with micropip.

Return type:

dict[str, Path]

lock(packages, specs, lockfile) bool[source]#

Generate the lockfile.

Parameters:
Return type:

bool

lock_date_epoch c.PyodideLockAddon.lock_date_epoch = CInt(0)#

Trigger reproducible locks, clamping available package timestamps to this value

property lock_output_dir: Path#

The folder where the pyodide-lock.json and packages will be stored.

locker c.PyodideLockAddon.locker = Enum('BrowserLocker')#

approach to use for running ‘pyodide’ and solving the lock: these will have further configuration options under the same-namedconfigurable

property locker_config: Any#

A preview of the locker config.

property lockfile: Path#

The pyodide-lock.json file in the {output_dir}.

property package_cache: Path#

The root of the pyodide-lock cache.

packages c.PyodideLockAddon.packages = TypedTuple()#

URLs of packages, or local (folders of) packages for pyodide depdendencies

patch_config(jupyterlite_json) None[source]#

Update the runtime jupyter-lite-config.json.

Parameters:

jupyterlite_json (Path)

Return type:

None

post_build(manager) Generator[None, None, dict[str, Any]][source]#

Collect all the packages and generate a pyodide-lock.json file.

This includes those provided by federated labextensions (such as jupyterlite-pyodide-kernel iteself), copied during build:federated_extensions.

Parameters:

manager (LiteManager)

Return type:

Generator[None, None, dict[str, Any]]

post_init(manager) Generator[None, None, dict[str, Any]][source]#

Handle downloading of packages to the package cache.

Parameters:

manager (LiteManager)

Return type:

Generator[None, None, dict[str, Any]]

pre_status(manager) Generator[None, None, dict[str, Any]][source]#

Patch configuration of PyodideAddon if needed.

Parameters:

manager (LiteManager)

Return type:

Generator[None, None, dict[str, Any]]

preload_packages c.PyodideLockAddon.preload_packages = TypedTuple()#

pyodide_kernel dependencies to add to PyodideAddon.loadPyodideOptions.packages: these will be downloaded and installed, but _not_ imported to sys.modules

property pyodide_addon: PyodideAddon#

The manager’s pyodide addon, which will be reconfigured if needed.

pyodide_cdn_url Unicode('https://cdn.jsdelivr.net/pyodide/v0.26.1/full')#

the URL prefix for all packages not managed by pyodide-lock

pyodide_url Unicode('https://github.com/pyodide/pyodide/releases/download/0.26.1/pyodide-core-0.26.1.tar.bz2')#

a URL, folder, or path to a pyodide distribution, patched into PyodideAddon.pyodide_url

resolve_one_file_requirement(path_or_url, cache_root) Generator[None, None, dict[str, Any]][source]#

Download a wheel, and copy to the cache.

Parameters:
Return type:

Generator[None, None, dict[str, Any]]

specs c.PyodideLockAddon.specs = TypedTuple()#

raw pep508 requirements for pyodide dependencies

status(manager) Generator[None, None, dict[str, Any]][source]#

Report on the status of pyodide-lock.

Parameters:

manager (LiteManager)

Return type:

Generator[None, None, dict[str, Any]]

property well_known_packages: Path#

The location of .whl in the {lite_dir} to pick up.

jupyterlite_pyodide_lock.addons.lock.list_packages(package_dir) list[Path][source]#

Get all wheels we know how to handle in a directory.

Parameters:

package_dir (Path)

Return type:

list[Path]

Lockers#

BrowserLocker#

Solve pyodide-lock with the browser manged as a naive subprocess.

jupyterlite_pyodide_lock.lockers.browser.BROWSERS = {'chrome': {'headless': ['--headless=new'], 'launch': ['google-chrome', '--new-window'], 'private_mode': ['--incognito'], 'profile': ['--user-data-dir={PROFILE_DIR}']}, 'chromium': {'headless': ['--headless=new'], 'launch': ['chromium-browser', '--new-window'], 'private_mode': ['--incognito'], 'profile': ['--user-data-dir={PROFILE_DIR}']}, 'firefox': {'headless': ['--headless'], 'launch': ['firefox'], 'private_mode': ['--private-window'], 'profile': ['--new-instance', '--profile', '{PROFILE_DIR}']}}#

browser CLI args, keyed by configurable

jupyterlite_pyodide_lock.lockers.browser.BROWSER_CHROMIUM_BASE = {'headless': ['--headless=new'], 'private_mode': ['--incognito'], 'profile': ['--user-data-dir={PROFILE_DIR}']}#

chromium base args

class jupyterlite_pyodide_lock.lockers.browser.BrowserLocker(**kwargs) None[source]#

Bases: TornadoLocker

Use a web server and browser subprocess to build a pyodide-lock.json.

See tornado.TornadoLocker for server details.

Parameters:

kwargs (Any)

Create a configurable given a config config.

Parameters#

configConfig

If this is empty, default values are used. If config is a Config instance, it will be used to configure the instance.

parentConfigurable instance, optional

The parent Configurable instance of this object.

Notes#

Subclasses of Configurable must call the __init__() method of Configurable before doing anything else and using super():

class MyConfigurable(Configurable):
    def __init__(self, config=None):
        super(MyConfigurable, self).__init__(config=config)
        # Then any other code you need to finish initialization.

This ensures that instances will be configured properly.

param kwargs:

type kwargs:

Any

browser c.BrowserLocker.browser = Unicode('')#

an alias for a pre-configured browser

browser_argv c.BrowserLocker.browser_argv = TypedTuple()#

the non-URL arguments for the browser process: if configured, ignore ‘browser’, ‘headless’, ‘private_mode’, ‘temp_profile’, and ‘profile’

browser_cli_arg(browser, trait_name) list[str][source]#

Find the CLI args for specific browser by trait name.

Parameters:
  • browser (str)

  • trait_name (str)

Return type:

list[str]

cleanup() None[source]#

Clean up the browser process and profile directory.

Return type:

None

ensure_temp_profile(baseline=None) str[source]#

Create a temporary browser profile.

Parameters:

baseline (Path | None, default: None)

Return type:

str

extra_micropip_args c.BrowserLocker.extra_micropip_args = Dict()#

options for ‘micropip.install’

async fetch() None[source]#

Open the browser to the lock page, and wait for it to finish.

Return type:

None

headless c.BrowserLocker.headless = Bool(True)#

run the browser in headless mode

host c.BrowserLocker.host = Unicode('127.0.0.1')#

the host on which to bind

port c.BrowserLocker.port = Int(0)#

the port on which to listen

private_mode c.BrowserLocker.private_mode = Bool(True)#

run the browser in private mode

profile c.BrowserLocker.profile = Unicode(None)#

run the browser with a copy of the given profile directory

protocol c.BrowserLocker.protocol = Unicode('http')#

the protocol to serve

pyodide_cdn_url c.BrowserLocker.pyodide_cdn_url = Unicode('https://cdn.jsdelivr.net/pyodide/v0.26.1/full')#

remote URL for the version of a full pyodide distribution

pypi_api_url c.BrowserLocker.pypi_api_url = Unicode('https://pypi.org/pypi')#

remote URL for a Warehouse-compatible JSON API

temp_profile c.BrowserLocker.temp_profile = Bool(False)#

run the browser with a temporary profile: incompatible with profile

timeout c.BrowserLocker.timeout = Int(0)#

seconds to wait for a solve

tornado_settings c.BrowserLocker.tornado_settings = Dict()#

override settings used by the tornado server

Locker Bases#

BaseLocker#

class jupyterlite_pyodide_lock.lockers._base.BaseLocker(**kwargs) None[source]#

Bases: LoggingConfigurable

Common traits and methods for ‘pyodide-lock.json’ resolving strategies.

Parameters:

kwargs (Any)

Create a configurable given a config config.

Parameters#

configConfig

If this is empty, default values are used. If config is a Config instance, it will be used to configure the instance.

parentConfigurable instance, optional

The parent Configurable instance of this object.

Notes#

Subclasses of Configurable must call the __init__() method of Configurable before doing anything else and using super():

class MyConfigurable(Configurable):
    def __init__(self, config=None):
        super(MyConfigurable, self).__init__(config=config)
        # Then any other code you need to finish initialization.

This ensures that instances will be configured properly.

param kwargs:

type kwargs:

Any

extra_micropip_args c.BaseLocker.extra_micropip_args = Dict()#

options for ‘micropip.install’

lockfile Instance()#
micropip_args Dict()#
packages List()#
parent Instance()#
pyodide_cdn_url c.BaseLocker.pyodide_cdn_url = Unicode('https://cdn.jsdelivr.net/pyodide/v0.26.1/full')#

remote URL for the version of a full pyodide distribution

pypi_api_url c.BaseLocker.pypi_api_url = Unicode('https://pypi.org/pypi')#

remote URL for a Warehouse-compatible JSON API

pythonhosted_cdn_url Unicode('https://files.pythonhosted.org')#

remote URL for python packages (third-party not supported)

async resolve() bool | None[source]#

Asynchronous solve.

An async locker should overload this.

Return type:

bool | None

async resolve_async() bool | None[source]#

Asynchronous solve that handles timeout.

An async locker should _not_ overload this unless it has some other means of timing out.

Return type:

bool | None

resolve_sync() bool | None[source]#

Provide a sync facade for doing async solves, called by PyodideLockAddon.

If a locker is entirely synchronous, it can overload this.

Return type:

bool | None

specs List()#
timeout c.BaseLocker.timeout = Int(0)#

seconds to wait for a solve

TornadoLocker#

Host a tornado web application to solve``pyodide-lock.json`` .

jupyterlite_pyodide_lock.lockers.tornado.THandler#

a type for tornado rules

alias of tuple[str, type, dict[str, Any]]

class jupyterlite_pyodide_lock.lockers.tornado.TornadoLocker(**kwargs) None[source]#

Bases: BaseLocker

Start a web server and a browser (somehow) to build a pyodide-lock.json.

For an example strategy, see browser.BrowserLocker.

The server serves a number of mostly-static files, with a fallback to any files in the output_dir.

GET of the page the client loads:

  • /lock.html

POST/GET of the initial baseline lockfile, to be updated with the lock solution:

  • /pyodide-lock.json

POST of log messages:

  • /log

GET of a Warehhouse/pythonhosted CDN proxied to configured remote URLs:

  • /_proxy/pypi

  • /_proxy/pythonhosted

If an {output_dir}/static/pyodide distribution is found, these will also be proxied from the configured URL.

Parameters:

kwargs (Any)

Create a configurable given a config config.

Parameters#

configConfig

If this is empty, default values are used. If config is a Config instance, it will be used to configure the instance.

parentConfigurable instance, optional

The parent Configurable instance of this object.

Notes#

Subclasses of Configurable must call the __init__() method of Configurable before doing anything else and using super():

class MyConfigurable(Configurable):
    def __init__(self, config=None):
        super(MyConfigurable, self).__init__(config=config)
        # Then any other code you need to finish initialization.

This ensures that instances will be configured properly.

param kwargs:

type kwargs:

Any

property base_url: str#

The effective base URL.

property cache_dir: Path#

The location of cached files discovered during the solve.

cleanup() None[source]#

Handle any cleanup tasks, as needed by specific implementations.

Return type:

None

collect() dict[str, Path][source]#

Copy all packages in the cached lockfile to output_dir, and fix lock.

Return type:

dict[str, Path]

collect_one_package(package) dict[str, Path][source]#

Find a package in the cache.

Parameters:

package (dict[str, Any])

Return type:

dict[str, Path]

extra_micropip_args c.TornadoLocker.extra_micropip_args = Dict()#

options for ‘micropip.install’

async fetch() None[source]#

Actually perform the solve.

Return type:

None

fix_lock(found) None[source]#

Fill in missing metadata from the micropip.freeze output.

Parameters:

found (dict[str, Path])

Return type:

None

fix_one_package(root_posix, lock_dir, package, found_path) None[source]#

Update a pyodide-lock URL for deployment.

Parameters:
Return type:

None

host c.TornadoLocker.host = Unicode('127.0.0.1')#

the host on which to bind

property lock_html_url: str#

The as-served URL for the lock HTML page.

property lockfile_cache: Path#

The location of the updated lockfile.

port c.TornadoLocker.port = Int(0)#

the port on which to listen

preflight() None[source]#

Prepare the cache.

The PyPI cache is removed before each build, as the JSON cache is invalidated by both references to the temporary files.pythonhosted.org proxy and a potential change to lock_date_epoch.

Return type:

None

protocol c.TornadoLocker.protocol = Unicode('http')#

the protocol to serve

pyodide_cdn_url c.TornadoLocker.pyodide_cdn_url = Unicode('https://cdn.jsdelivr.net/pyodide/v0.26.1/full')#

remote URL for the version of a full pyodide distribution

pypi_api_url c.TornadoLocker.pypi_api_url = Unicode('https://pypi.org/pypi')#

remote URL for a Warehouse-compatible JSON API

async resolve() bool | None[source]#

Launch a web application, then delegate to actually run the solve.

Return type:

bool | None

timeout c.TornadoLocker.timeout = Int(0)#

seconds to wait for a solve

tornado_settings c.TornadoLocker.tornado_settings = Dict()#

override settings used by the tornado server