From 8317a2e23afac1aa45ac3c6a83dd6baae5ea3b82 Mon Sep 17 00:00:00 2001 From: Nicholas Bollweg Date: Fri, 10 Mar 2023 23:42:18 -0600 Subject: [PATCH] Generate pyodide repodata, add more mocks --- .gitignore | 2 +- .prettierignore | 1 + jupyterlite_pyodide_kernel/addons/piplite.py | 478 ++++++++++++++---- jupyterlite_pyodide_kernel/app.py | 3 +- jupyterlite_pyodide_kernel/constants.py | 37 ++ .../tests/test_piplite.py | 40 +- package.json | 6 +- .../pyodide-kernel-extension/package.json | 4 +- .../schema/kernel.v0.schema.json | 8 + .../pyodide-kernel-extension/src/index.ts | 5 + packages/pyodide-kernel/package.json | 11 +- packages/pyodide-kernel/py/jedi/LICENSE | 29 ++ packages/pyodide-kernel/py/jedi/README.md | 3 + .../pyodide-kernel/py/jedi/jedi/__init__.py | 7 + .../py/jedi/jedi/api/__init__.py | 2 + .../py/jedi/jedi/api/classes.py | 1 + .../py/jedi/jedi/api/helpers.py | 1 + .../pyodide-kernel/py/jedi/pyproject.toml | 21 + .../jupyterlab_widgets/LICENSE | 29 ++ .../jupyterlab_widgets/README.md | 4 + .../jupyterlab_widgets/__init__.py | 3 + .../jupyterlab_widgets/pyproject.toml | 21 + .../jupyterlab_widgets/LICENSE | 29 ++ .../jupyterlab_widgets/README.md | 4 + .../jupyterlab_widgets/__init__.py | 3 + .../jupyterlab_widgets/pyproject.toml | 21 + .../pyodide-kernel/py/prompt_toolkit/LICENSE | 29 ++ .../py/prompt_toolkit/README.md | 3 + .../prompt_toolkit/prompt_toolkit/__init__.py | 3 + .../prompt_toolkit/application/current.py | 2 + .../prompt_toolkit/auto_suggest.py | 5 + .../prompt_toolkit/prompt_toolkit/buffer.py | 2 + .../prompt_toolkit/completion.py | 6 + .../prompt_toolkit/prompt_toolkit/document.py | 2 + .../py/prompt_toolkit/prompt_toolkit/enums.py | 5 + .../prompt_toolkit/prompt_toolkit/filters.py | 31 ++ .../prompt_toolkit/formatted_text.py | 6 + .../prompt_toolkit/prompt_toolkit/history.py | 5 + .../prompt_toolkit/key_binding/__init__.py | 5 + .../key_binding/bindings/__init__.py | 6 + .../key_binding/bindings/completion.py | 2 + .../key_binding/key_processor.py | 2 + .../prompt_toolkit/key_binding/vi_state.py | 5 + .../prompt_toolkit/layout/__init__.py | 0 .../prompt_toolkit/layout/layout.py | 2 + .../prompt_toolkit/layout/processors.py | 7 + .../prompt_toolkit/prompt_toolkit/lexers.py | 6 + .../prompt_toolkit/prompt_toolkit/output.py | 2 + .../prompt_toolkit/patch_stdout.py | 2 + .../prompt_toolkit/shortcuts/__init__.py | 9 + .../prompt_toolkit/shortcuts/prompt.py | 2 + .../prompt_toolkit/styles/__init__.py | 6 + .../prompt_toolkit/styles/pygments.py | 6 + .../py/prompt_toolkit/pyproject.toml | 24 + .../schema/repodata.v0.schema.json | 107 ++++ .../scripts/generate-wheels-js.py | 1 + packages/pyodide-kernel/src/_pypi.ts | 5 + packages/pyodide-kernel/src/declarations.d.ts | 5 + packages/pyodide-kernel/src/kernel.ts | 10 +- packages/pyodide-kernel/src/tokens.ts | 64 +++ packages/pyodide-kernel/src/worker.ts | 55 +- pyproject.toml | 2 +- yarn.lock | 344 ++++++++++++- 63 files changed, 1413 insertions(+), 138 deletions(-) create mode 100644 packages/pyodide-kernel/py/jedi/LICENSE create mode 100644 packages/pyodide-kernel/py/jedi/README.md create mode 100644 packages/pyodide-kernel/py/jedi/jedi/__init__.py create mode 100644 packages/pyodide-kernel/py/jedi/jedi/api/__init__.py create mode 100644 packages/pyodide-kernel/py/jedi/jedi/api/classes.py create mode 100644 packages/pyodide-kernel/py/jedi/jedi/api/helpers.py create mode 100644 packages/pyodide-kernel/py/jedi/pyproject.toml create mode 100644 packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/LICENSE create mode 100644 packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/README.md create mode 100644 packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/jupyterlab_widgets/__init__.py create mode 100644 packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/pyproject.toml create mode 100644 packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/LICENSE create mode 100644 packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/README.md create mode 100644 packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/jupyterlab_widgets/__init__.py create mode 100644 packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/pyproject.toml create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/LICENSE create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/README.md create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/__init__.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/application/current.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/auto_suggest.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/buffer.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/completion.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/document.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/enums.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/filters.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/formatted_text.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/history.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/__init__.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/bindings/__init__.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/bindings/completion.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/key_processor.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/vi_state.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/layout/__init__.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/layout/layout.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/layout/processors.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/lexers.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/output.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/patch_stdout.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/shortcuts/__init__.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/shortcuts/prompt.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/styles/__init__.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/styles/pygments.py create mode 100644 packages/pyodide-kernel/py/prompt_toolkit/pyproject.toml create mode 100644 packages/pyodide-kernel/schema/repodata.v0.schema.json diff --git a/.gitignore b/.gitignore index 19fe2fd9..78ad4d0f 100644 --- a/.gitignore +++ b/.gitignore @@ -114,7 +114,7 @@ dmypy.json # generated packages/pyodide-kernel/pypi/ -packages/pyodide-kernel/pypi/all.json +packages/pyodide-kernel/pypi/*.json _pypi.ts .jupyterlite.doit.db _output diff --git a/.prettierignore b/.prettierignore index 7a59b128..b4486d00 100644 --- a/.prettierignore +++ b/.prettierignore @@ -13,3 +13,4 @@ CHANGELOG.md # generated _pypi.ts **/pypi/all.json +**/pypi/repodata.json diff --git a/jupyterlite_pyodide_kernel/addons/piplite.py b/jupyterlite_pyodide_kernel/addons/piplite.py index acf3adb4..1e9a85c0 100644 --- a/jupyterlite_pyodide_kernel/addons/piplite.py +++ b/jupyterlite_pyodide_kernel/addons/piplite.py @@ -4,9 +4,12 @@ import json import re import urllib.parse +import functools from hashlib import md5, sha256 from pathlib import Path -from typing import Tuple as _Tuple +from typing import Tuple as _Tuple, List as _List +import zipfile +import warnings import doit.tools from jupyterlite_core.constants import ( @@ -17,85 +20,111 @@ UTF8, ) from jupyterlite_core.trait_types import TypedTuple -from traitlets import Unicode +from traitlets import Unicode, Bool from ._base import _BaseAddon from ..constants import ( ALL_WHL, + NOARCH_WHL, PIPLITE_INDEX_SCHEMA, PIPLITE_URLS, PKG_JSON_PIPLITE, PKG_JSON_WHEELDIR, PYODIDE_KERNEL_NPM_NAME, + PYODIDE_MARKER_ENV, PYPI_WHEELS, KERNEL_SETTINGS_SCHEMA, + REPODATA_JSON, + REPODATA_SCHEMA, + REPODATA_URLS, + TOP_LEVEL_TXT, + WHL_RECORD, ) +from jupyterlite_core.manager import LiteManager + class PipliteAddon(_BaseAddon): __all__ = ["post_init", "build", "post_build", "check"] + # CLI + aliases = { + "piplite-wheels": "PipliteAddon.piplite_urls", + } + + flags = { + "piplite-install-on-import": ( + {"PipliteAddon": {"install_on_import": True}}, + "Index wheels by import names to install when imported", + ) + } + # traits piplite_urls: _Tuple[str] = TypedTuple( Unicode(), help="Local paths or URLs of piplite-compatible wheels to copy and index", ).tag(config=True) - # CLI - aliases = { - "piplite-wheels": "PipliteAddon.piplite_urls", - } + install_on_import: bool = Bool( + False, help="Index wheels by import names to install when imported" + ).tag(config=True) @property - def output_wheels(self): + def output_wheels(self) -> Path: """where wheels will go in the output folder""" return self.manager.output_dir / PYPI_WHEELS @property - def wheel_cache(self): + def wheel_cache(self) -> Path: """where wheels will go in the cache folder""" return self.manager.cache_dir / "wheels" @property - def output_extensions(self): + def output_extensions(self) -> Path: """where labextensions will go in the output folder""" return self.manager.output_dir / LAB_EXTENSIONS @property - def output_kernel_extension(self): + def output_kernel_extension(self) -> Path: """the location of the Pyodide kernel labextension static assets""" return self.output_extensions / PYODIDE_KERNEL_NPM_NAME @property - def schemas(self): + def schemas(self) -> Path: """the path to the as-deployed schema in the labextension""" return self.output_kernel_extension / "static/schema" @property - def piplite_schema(self): + def piplite_schema(self) -> Path: """the schema for Warehouse-like API indexes""" return self.schemas / PIPLITE_INDEX_SCHEMA @property - def settings_schema(self): + def repodata_schema(self) -> Path: + """the schema for pyodide repodata""" + return self.schemas / REPODATA_SCHEMA + + @property + def settings_schema(self) -> Path: """the schema for the Pyodide kernel labextension""" return self.schemas / KERNEL_SETTINGS_SCHEMA - def post_init(self, manager): + def post_init(self, manager: LiteManager): """handle downloading of wheels""" for path_or_url in self.piplite_urls: yield from self.resolve_one_wheel(path_or_url) - def build(self, manager): + def build(self, manager: LiteManager): """yield a doit task to copy each local wheel into the output_dir""" for wheel in list_wheels(manager.lite_dir / PYPI_WHEELS): yield from self.resolve_one_wheel(str(wheel.resolve())) - def post_build(self, manager): + def post_build(self, manager: LiteManager): """update the root jupyter-lite.json with user-provided ``pipliteUrls``""" jupyterlite_json = manager.output_dir / JUPYTERLITE_JSON whl_metas = [] + whl_repos = [] wheels = list_wheels(self.output_wheels) pkg_jsons = sorted( @@ -119,68 +148,104 @@ def post_build(self, manager): targets=[whl_meta], ) - if whl_metas or pkg_jsons: + if self.install_on_import: + whl_repo = self.wheel_cache / f"{wheel.name}.repodata.json" + whl_repos += [whl_repo] + + yield self.task( + name=f"meta:{whl_repo.name}", + doc=f"ensure {wheel} repodata", + file_dep=[wheel], + actions=[ + (doit.tools.create_folder, [whl_repo.parent]), + (self.repodata_wheel, [wheel, whl_repo]), + ], + targets=[whl_repo], + ) + + if whl_metas or whl_repos or pkg_jsons: whl_index = self.manager.output_dir / PYPI_WHEELS / ALL_JSON + repo_index = self.manager.output_dir / PYPI_WHEELS / REPODATA_JSON yield self.task( name="patch", doc=f"ensure {JUPYTERLITE_JSON} includes any piplite wheels", - file_dep=[*whl_metas, jupyterlite_json], + file_dep=[*whl_metas, *whl_repos, jupyterlite_json], actions=[ ( self.patch_jupyterlite_json, - [jupyterlite_json, whl_index, whl_metas, pkg_jsons], + [ + jupyterlite_json, + whl_index, + repo_index, + whl_metas, + whl_repos, + pkg_jsons, + ], ) ], - targets=[whl_index], + targets=[whl_index, repo_index], ) - def check(self, manager): + def check(self, manager: LiteManager): """verify that all JSON for settings and Warehouse API are valid""" for config_path in self.get_output_config_paths(): yield from self.check_one_config_path(config_path) - def check_one_config_path(self, config_path): + def check_one_config_path(self, config_path: Path): """verify the settings and Warehouse API for a single jupyter-lite config""" if not config_path.exists(): return rel_path = config_path.relative_to(self.manager.output_dir) - config = self.get_pyodide_settings(config_path) + plugin_config = self.get_pyodide_settings(config_path) + + yield from self.check_index_urls( + plugin_config.get(PIPLITE_URLS, []), self.piplite_schema + ) + + if self.install_on_import: + yield from self.check_index_urls( + plugin_config.get(REPODATA_URLS, []), self.repodata_schema + ) yield self.task( name=f"validate:settings:{rel_path}", doc=f"validate {config_path} with the pyodide kernel settings schema", actions=[ - (self.validate_one_json_file, [self.settings_schema, None, config]), + ( + self.validate_one_json_file, + [self.settings_schema, None, plugin_config], + ), ], file_dep=[self.settings_schema, config_path], ) - urls = config.get(PIPLITE_URLS, []) + def check_index_urls(self, raw_urls, schema: Path): + """Validate URLs against a schema.""" + for raw_url in raw_urls: + if not raw_url.startswith("./"): + continue - for wheel_index_url in urls: - yield from self.check_one_wheel_index(wheel_index_url) + url = raw_url.split("?")[0].split("#")[0] - def check_one_wheel_index(self, wheel_index_url): - """validate one wheel index against the Warehouse schema""" - if not wheel_index_url.startswith("./"): # pragma: no cover - return - - wheel_index_url = wheel_index_url.split("?")[0].split("#")[0] - - path = self.manager.output_dir / wheel_index_url + path = self.manager.output_dir / url - if not path.exists(): # pragma: no cover - return + if not path.exists(): + continue - yield self.task( - name=f"validate:wheels:{wheel_index_url}", - doc=f"validate {wheel_index_url} with the piplite API schema", - file_dep=[path], - actions=[(self.validate_one_json_file, [self.piplite_schema, path])], - ) + yield self.task( + name=f"validate:{url}", + doc=f"validate {url} against {schema}", + file_dep=[path], + actions=[ + ( + self.validate_one_json_file, + [schema, path], + ) + ], + ) def resolve_one_wheel(self, path_or_url): """download a single wheel, and copy to the cache""" @@ -215,7 +280,7 @@ def resolve_one_wheel(self, path_or_url): else: # pragma: no cover raise FileNotFoundError(path_or_url) - def copy_wheel(self, wheel): + def copy_wheel(self, wheel: Path): """copy one wheel to output""" dest = self.output_wheels / wheel.name if dest == wheel: # pragma: no cover @@ -227,64 +292,128 @@ def copy_wheel(self, wheel): actions=[(self.copy_one, [wheel, dest])], ) - def patch_jupyterlite_json(self, config_path, user_whl_index, whl_metas, pkg_jsons): + def patch_jupyterlite_json( + self, + config_path: Path, + whl_index: Path, + repo_index: Path, + whl_metas: _List[Path], + whl_repos: _List[Path], + pkg_jsons: _List[Path], + ): """add the piplite wheels to jupyter-lite.json""" plugin_config = self.get_pyodide_settings(config_path) - old_urls = plugin_config.get(PIPLITE_URLS, []) + # first add user-specified wheels to warehouse + warehouse_urls = self.update_warehouse_index( + plugin_config, whl_index, whl_metas + ) - new_urls = [] + # ...then maybe add repodata + if self.install_on_import: + repodata_urls = self.update_repo_index(plugin_config, repo_index, whl_repos) - # first add user-specified wheels from piplite_urls - if whl_metas: - metadata = {} - for whl_meta in whl_metas: - meta = json.loads(whl_meta.read_text(**UTF8)) - whl = self.output_wheels / whl_meta.name.replace(".json", "") - metadata[whl] = meta["name"], meta["version"], meta["release"] - - write_wheel_index(self.output_wheels, metadata) - user_whl_index_url, user_whl_index_url_with_sha = self.get_index_urls( - user_whl_index - ) + # ...then add wheels from federated extensions... + if pkg_jsons: + for pkg_json in pkg_jsons: + pkg_data = json.loads(pkg_json.read_text(**UTF8)) + wheel_dir = pkg_data.get(PKG_JSON_PIPLITE, {}).get(PKG_JSON_WHEELDIR) + if wheel_dir: + pkg_whl_index = pkg_json.parent / wheel_dir / ALL_JSON + if pkg_whl_index.exists(): + pkg_whl_index_url_with_sha = self.get_index_urls(pkg_whl_index)[ + 1 + ] + if pkg_whl_index_url_with_sha not in warehouse_urls: + warehouse_urls += [pkg_whl_index_url_with_sha] + + pkg_repo_index = pkg_json.parent / wheel_dir / REPODATA_JSON + if self.install_on_import and pkg_repo_index.exists(): + pkg_repo_index_url_with_sha = self.get_index_urls( + pkg_repo_index + )[1] + if pkg_repo_index_url_with_sha not in repodata_urls: + warehouse_urls += [pkg_repo_index_url_with_sha] + + needs_save = False - added_build = False + # ... and only update if actually changed + if warehouse_urls: + plugin_config[PIPLITE_URLS] = warehouse_urls + needs_save = True - for url in old_urls: - if url.split("#")[0].split("?")[0] == user_whl_index_url: - new_urls += [user_whl_index_url_with_sha] - added_build = True - else: - new_urls += [url] + if self.install_on_import and repodata_urls: + plugin_config[REPODATA_URLS] = repodata_urls + needs_save = True - if not added_build: - new_urls = [user_whl_index_url_with_sha, *new_urls] - else: - new_urls = old_urls + if needs_save: + self.set_pyodide_settings(config_path, plugin_config) - # ...then add wheels from federated extensions... - for pkg_json in pkg_jsons or []: - pkg_data = json.loads(pkg_json.read_text(**UTF8)) - wheel_dir = pkg_data.get(PKG_JSON_PIPLITE, {}).get(PKG_JSON_WHEELDIR) - if wheel_dir: - pkg_whl_index = pkg_json.parent / wheel_dir / ALL_JSON - if pkg_whl_index.exists(): - pkg_whl_index_url_with_sha = self.get_index_urls(pkg_whl_index)[1] - if pkg_whl_index_url_with_sha not in new_urls: - new_urls += [pkg_whl_index_url_with_sha] + def update_warehouse_index(self, plugin_config, whl_index: Path, whl_metas): + """Ensure the warehouse index is up-to-date, reporting new URLs.""" + old_warehouse_urls = plugin_config.get(PIPLITE_URLS, []) + if not whl_metas: + return old_warehouse_urls + new_urls = [] + metadata = {} + for whl_meta in whl_metas: + meta = json.loads(whl_meta.read_text(**UTF8)) + whl = self.output_wheels / whl_meta.name.replace(".json", "") + metadata[whl] = meta["name"], meta["version"], meta["release"] + + write_wheel_index(self.output_wheels, metadata) + whl_index_url, whl_index_url_with_sha = self.get_index_urls(whl_index) + + added_build = False + + for url in old_warehouse_urls: + if url.split("#")[0].split("?")[0] == whl_index_url: + new_urls += [whl_index_url_with_sha] + added_build = True + else: + new_urls += [url] + + if not added_build: + new_urls = [whl_index_url_with_sha, *new_urls] + + return new_urls + + def update_repo_index(self, plugin_config, repo_index: Path, whl_repos): + """Ensure the repodata index is up-to-date, reporting new URLs.""" + old_urls = plugin_config.get(REPODATA_URLS, []) + if not whl_repos: + return old_urls + new_urls = [] + metadata = {} + for whl_repo in whl_repos: + meta = json.loads(whl_repo.read_text(**UTF8)) + whl = self.output_wheels / whl_repo.name.replace(".json", "") + metadata[whl] = meta["name"], meta["version"], meta - # ... and only update if actually changed - if new_urls: - plugin_config[PIPLITE_URLS] = new_urls - self.set_pyodide_settings(config_path, plugin_config) + write_repo_index(self.output_wheels, metadata) + repo_index_url, repo_index_url_with_sha = self.get_index_urls(repo_index) - def get_index_urls(self, whl_index): - """get output dir relative URLs for all.json files""" - whl_index_sha256 = sha256(whl_index.read_bytes()).hexdigest() - whl_index_url = f"./{whl_index.relative_to(self.manager.output_dir).as_posix()}" - whl_index_url_with_sha = f"{whl_index_url}?sha256={whl_index_sha256}" - return whl_index_url, whl_index_url_with_sha + added_build = False - def index_wheel(self, whl_path, whl_meta): + for url in old_urls: + if url.split("#")[0].split("?")[0] == repo_index_url: + new_urls += [repo_index_url_with_sha] + added_build = True + else: + new_urls += [url] + + if not added_build: + new_urls = [repo_index_url_with_sha, *new_urls] + + return new_urls + + def get_index_urls(self, index_path: Path): + """Get output_dir relative URLs for an index file.""" + index_sha256 = sha256(index_path.read_bytes()).hexdigest() + index_url = f"./{index_path.relative_to(self.manager.output_dir).as_posix()}" + index_url_with_sha = f"{index_url}?sha256={index_sha256}" + return index_url, index_url_with_sha + + def index_wheel(self, whl_path: Path, whl_meta: Path): """Generate an intermediate file representation to merge with other releases""" name, version, release = get_wheel_fileinfo(whl_path) whl_meta.write_text( @@ -293,17 +422,24 @@ def index_wheel(self, whl_path, whl_meta): ) self.maybe_timestamp(whl_meta) + def repodata_wheel(self, whl_path: Path, whl_repo: Path) -> None: + """Write out the repodata for a wheel.""" + pkg_entry = get_wheel_repodata(whl_path)[2] + whl_repo.write_text( + json.dumps(pkg_entry, **JSON_FMT), + **UTF8, + ) + self.maybe_timestamp(whl_repo) + -def list_wheels(wheel_dir): - """get all wheels we know how to handle in a directory""" +def list_wheels(wheel_dir: Path) -> _List[Path]: + """Get all wheels we know how to handle in a directory""" return sorted(sum([[*wheel_dir.glob(f"*{whl}")] for whl in ALL_WHL], [])) -def get_wheel_fileinfo(whl_path): +def get_wheel_fileinfo(whl_path: Path): """Generate a minimal Warehouse-like JSON API entry from a wheel""" - import pkginfo - - metadata = pkginfo.get_metadata(str(whl_path)) + metadata = get_wheel_pkginfo(whl_path) whl_stat = whl_path.stat() whl_isodate = ( datetime.datetime.fromtimestamp(whl_stat.st_mtime, tz=datetime.timezone.utc) @@ -336,7 +472,116 @@ def get_wheel_fileinfo(whl_path): return metadata.name, metadata.version, release -def get_wheel_index(wheels, metadata=None): +def get_wheel_repodata(whl_path: Path): + """Get pyodide-compatible `repodata.json` fragment for a wheel. + + This only knows how to handle "simple" noarch wheels, without extra binary + depnendencies. + """ + name, version, release = get_wheel_fileinfo(whl_path) + depends = get_wheel_depends(whl_path) + modules = get_wheel_modules(whl_path) + normalized_name = get_normalized_name(name) + pkg_entry = { + "name": normalized_name, + "version": version, + "file_name": whl_path.name, + "install_dir": "site" if whl_path.name.endswith(NOARCH_WHL) else "dynlib", + "sha256": release["digests"]["sha256"], + "imports": modules, + "depends": depends, + } + return normalized_name, version, pkg_entry + + +@functools.lru_cache(1000) +def get_wheel_pkginfo(whl_path: Path): + """Return the as-parsed distribution information from ``pkginfo``.""" + import pkginfo + + return pkginfo.get_metadata(str(whl_path)) + + +def get_wheel_modules(whl_path: Path) -> _List[str]: + """Get the exported top-level modules from a wheel.""" + top_levels = {} + records = {} + with zipfile.ZipFile(whl_path) as zf: + for zipinfo in zf.infolist(): + if zipinfo.filename.endswith(TOP_LEVEL_TXT): + top_levels[zipinfo.filename] = ( + zf.read(zipinfo).decode("utf-8").strip().splitlines() + ) + if zipinfo.filename.endswith(WHL_RECORD): + records[zipinfo.filename] = ( + zf.read(zipinfo).decode("utf-8").strip().splitlines() + ) + + if len(top_levels): + sorted_top_levels = sorted(top_levels.items(), key=lambda x: len(x[0])) + return sorted_top_levels[0][1] + + if len(records): + sorted_records = sorted(records.items(), key=lambda x: len(x[0])) + # discard hash, length, etc. + record_bits = sorted( + [line.split(",")[0].split("/") for line in sorted_records[0][1]], + key=lambda x: len(x), + ) + + imports = set() + inits = [] + for bits in record_bits: + if bits[0].endswith(".data") or bits[0].endswith(".dist-info"): + continue + elif bits[0].endswith(".py"): + # this is a single-file module that gets dropped in site-packages + imports.add(bits[0].replace(".py", "")) + elif bits[-1].endswith("__init__.py"): + # this might be a namespace package + inits += [bits] + + if not imports and inits: + for init_bits in inits: + dotted = ".".join(init_bits[:-1]) + if any(f"{imp}." in dotted for imp in imports): + continue + imports.add(dotted) + + if imports: + return sorted(imports) + + # this should probably never happen + raise ValueError(f"{whl_path} contains neither {TOP_LEVEL_TXT} nor {WHL_RECORD}") + + +def get_wheel_depends(whl_path: Path): + """Get the normalize runtime distribution dependencies from a wheel.""" + from packaging.requirements import Requirement + + metadata = get_wheel_pkginfo(str(whl_path)) + + depends: _List[str] = [] + + for dep_str in metadata.requires_dist: + if dep_str.endswith(";"): + dep_str = dep_str[:-1] + req = Requirement(dep_str) + if req.marker is None or req.marker.evaluate(PYODIDE_MARKER_ENV): + depends += [get_normalized_name(req.name)] + + return sorted(set(depends)) + + +def get_normalized_name(raw_name: str) -> str: + """Get a PEP 503 normalized name for a python package. + + https://peps.python.org/pep-0503/#normalized-names + """ + return re.sub(r"[-_.]+", "-", raw_name).lower() + + +def get_wheel_index(wheels: _List[Path], metadata=None): """Get the raw python object representing a wheel index for a bunch of wheels If given, metadata should be a dictionary of the form: @@ -347,9 +592,8 @@ def get_wheel_index(wheels, metadata=None): all_json = {} for whl_path in sorted(wheels): - name, version, release = metadata.get(whl_path, get_wheel_fileinfo(whl_path)) - # https://peps.python.org/pep-0503/#normalized-names - normalized_name = re.sub(r"[-_.]+", "-", name).lower() + name, version, release = metadata.get(whl_path) or get_wheel_fileinfo(whl_path) + normalized_name = get_normalized_name(name) if normalized_name not in all_json: all_json[normalized_name] = {"releases": {}} all_json[normalized_name]["releases"][version] = [release] @@ -357,9 +601,37 @@ def get_wheel_index(wheels, metadata=None): return all_json -def write_wheel_index(whl_dir, metadata=None): - """Write out an all.json for a directory of wheels""" +def get_repo_index(wheels: _List[Path], metadata=None): + """Get the data for a ``repodata.json``.""" + metadata = metadata or {} + repodata_json = {"packages": {}} + + for whl_path in sorted(wheels): + name, version, pkg_entry = metadata.get(whl_path) or get_wheel_repodata( + whl_path + ) + normalized_name = get_normalized_name(name) + if normalized_name in repodata_json["packages"]: + old_version = repodata_json["packages"][normalized_name]["version"] + warnings.warn( + f"{normalized_name} {old_version} will be clobbered by {version}" + ) + repodata_json["packages"][normalized_name] = pkg_entry + + return repodata_json + + +def write_wheel_index(whl_dir: Path, metadata=None) -> Path: + """Write out an ``all.json`` for a directory of wheels.""" wheel_index = Path(whl_dir) / ALL_JSON index_data = get_wheel_index(list_wheels(whl_dir), metadata) wheel_index.write_text(json.dumps(index_data, **JSON_FMT), **UTF8) return wheel_index + + +def write_repo_index(whl_dir: Path, metadata=None) -> Path: + """Write out a ``repodata.json`` for a directory of wheels.""" + repo_index = Path(whl_dir) / REPODATA_JSON + index_data = get_repo_index(list_wheels(whl_dir), metadata) + repo_index.write_text(json.dumps(index_data, **JSON_FMT), **UTF8) + return repo_index diff --git a/jupyterlite_pyodide_kernel/app.py b/jupyterlite_pyodide_kernel/app.py index 618e4bfe..b855793b 100644 --- a/jupyterlite_pyodide_kernel/app.py +++ b/jupyterlite_pyodide_kernel/app.py @@ -43,9 +43,10 @@ def start(self): raise ValueError(f"{self.wheel_dir} does not exist") if not list_wheels(self.wheel_dir): raise ValueError(f"no supported wheels found in {self.wheel_dir}") - from .addons.piplite import write_wheel_index + from .addons.piplite import write_repo_index, write_wheel_index write_wheel_index(self.wheel_dir) + write_repo_index(self.wheel_dir) class PipliteApp(DescribedMixin, JupyterApp): diff --git a/jupyterlite_pyodide_kernel/constants.py b/jupyterlite_pyodide_kernel/constants.py index 2e3b8109..31b87bb2 100644 --- a/jupyterlite_pyodide_kernel/constants.py +++ b/jupyterlite_pyodide_kernel/constants.py @@ -1,4 +1,5 @@ """Well-known (and otherwise) constants used by ``jupyterlite-pyodide-kernel``""" +from typing import Dict, List ### pyodide-specific values #: the key for PyPI-compatible API responses pointing to wheels @@ -7,6 +8,8 @@ #: the schema for piplite-compatible wheel index PIPLITE_INDEX_SCHEMA = "piplite.v0.schema.json" #: the schema for piplite-compatible wheel index +REPODATA_SCHEMA = "repodata.v0.schema.json" +#: the schema for piplite-compatible wheel index KERNEL_SETTINGS_SCHEMA = "kernel.v0.schema.json" #: where we put wheels, for now PYPI_WHEELS = "pypi" @@ -22,6 +25,40 @@ #: where we put wheels, for now PYODIDE_URL = "pyodideUrl" +#: the key for pyodide-compatible repodata.json +REPODATA_URLS = "repodataUrls" + +#: the schema for pyodidate-compatible repodata +REPODATA_SCHEMA = "repodata.v0.schema.json" + +#: where setuptools wheels store their exported modules +TOP_LEVEL_TXT = "top_level.txt" + +#: where all wheels store a list of all exported files +WHL_RECORD = "RECORD" + +#: the pyodide index of wheels +REPODATA_JSON = "repodata.json" + + +#: the observed default environment of pyodide +PYODIDE_MARKER_ENV = { + "implementation_name": "cpython", + "implementation_version": "3.10.2", + "os_name": "posix", + "platform_machine": "wasm32", + "platform_release": "3.1.27", + "platform_system": "Emscripten", + "platform_version": "#1", + "python_full_version": "3.10.2", + "platform_python_implementation": "CPython", + "python_version": "3.10", + "sys_platform": "emscripten", +} + +TDistPackages = Dict[str, List[str]] + + #: where we put pyodide, for now PYODIDE = "pyodide" PYODIDE_JS = "pyodide.js" diff --git a/jupyterlite_pyodide_kernel/tests/test_piplite.py b/jupyterlite_pyodide_kernel/tests/test_piplite.py index ec9918f9..3b0a6d26 100644 --- a/jupyterlite_pyodide_kernel/tests/test_piplite.py +++ b/jupyterlite_pyodide_kernel/tests/test_piplite.py @@ -13,18 +13,23 @@ LITE_PLUGIN_SETTINGS, JSON_FMT, JUPYTER_CONFIG_DATA, + ALL_JSON, ) from jupyterlite_pyodide_kernel.constants import ( PYODIDE_KERNEL_PLUGIN_ID, DISABLE_PYPI_FALLBACK, + PIPLITE_URLS, + PYPI_WHEELS, + REPODATA_JSON, ) from .conftest import WHEELS, PYODIDE_KERNEL_EXTENSION -def has_wheel_after_build(an_empty_lite_dir, script_runner): - """run a build, expecting the fixture wheel to be there""" +def has_wheel_after_build(an_empty_lite_dir, script_runner, install_on_import=False): + """run a build, expecting the fixture wheel, ``all.json`` (and maybe ``repodata.json``) + to be there""" build = script_runner.run("jupyter", "lite", "build", cwd=str(an_empty_lite_dir)) assert build.success @@ -33,25 +38,37 @@ def has_wheel_after_build(an_empty_lite_dir, script_runner): output = an_empty_lite_dir / "_output" - lite_json = output / "jupyter-lite.json" + lite_json = output / JUPYTERLITE_JSON lite_data = json.loads(lite_json.read_text(encoding="utf-8")) - assert lite_data["jupyter-config-data"]["litePluginSettings"][ + assert lite_data[JUPYTER_CONFIG_DATA][LITE_PLUGIN_SETTINGS][ PYODIDE_KERNEL_PLUGIN_ID - ]["pipliteUrls"], "bad wheel urls" + ][PIPLITE_URLS], "bad wheel urls" - wheel_out = output / "pypi" + wheel_out = output / PYPI_WHEELS assert (wheel_out / WHEELS[0].name).exists() - wheel_index = output / "pypi/all.json" + wheel_index = output / PYPI_WHEELS / ALL_JSON wheel_index_text = wheel_index.read_text(encoding="utf-8") assert WHEELS[0].name in wheel_index_text, wheel_index_text + repodata = output / PYPI_WHEELS / REPODATA_JSON + if install_on_import: + assert repodata.exists() + else: + assert not repodata.exists() + @mark.parametrize( "remote,folder", [[True, False], [False, False], [False, True]], ) +@mark.parametrize("install_on_import", [True, False]) def test_piplite_urls( - an_empty_lite_dir, script_runner, remote, folder, a_fixture_server + an_empty_lite_dir, + script_runner, + remote, + folder, + a_fixture_server, + install_on_import, ): """can we include a single wheel?""" ext = WHEELS[0] @@ -77,16 +94,17 @@ def test_piplite_urls( }, "PipliteAddon": { "piplite_urls": piplite_urls, + "install_on_import": install_on_import, }, } (an_empty_lite_dir / "jupyter_lite_config.json").write_text(json.dumps(config)) - has_wheel_after_build(an_empty_lite_dir, script_runner) + has_wheel_after_build(an_empty_lite_dir, script_runner, install_on_import) def test_lite_dir_wheel(an_empty_lite_dir, script_runner): - wheel_dir = an_empty_lite_dir / "pypi" + wheel_dir = an_empty_lite_dir / PYPI_WHEELS wheel_dir.mkdir() shutil.copy2(WHEELS[0], wheel_dir / WHEELS[0].name) @@ -115,7 +133,7 @@ def test_piplite_cli_win(script_runner, tmp_path, index_cmd, in_cwd): pargs = [] if in_cwd else [str(path)] build = script_runner.run(*index_cmd, *pargs, **kwargs) assert build.success - assert json.loads((path / "all.json").read_text(encoding="utf-8")) + assert json.loads((path / ALL_JSON).read_text(encoding="utf-8")) @pytest.fixture(params=[JUPYTERLITE_IPYNB, JUPYTERLITE_JSON]) diff --git a/package.json b/package.json index 90fb563f..8c831bb2 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,8 @@ "serve": "cd build && python -m http.server -b 127.0.0.1", "setup:py": "python -m pip install -e \".[dev,lint,test,docs]\"", "test:py": "pytest", - "test": "jlpm test:py" + "test": "jlpm test:py", + "watch": "lerna run watch" }, "devDependencies": { "@typescript-eslint/eslint-plugin": "^5.45.0", @@ -55,6 +56,7 @@ "prettier": "^2.8.0", "rimraf": "^3.0.2", "typescript": "~4.9.3", - "yarn-deduplicate": "^6.0.1" + "yarn-deduplicate": "^6.0.1", + "npm-run-all": "^4.1.5" } } diff --git a/packages/pyodide-kernel-extension/package.json b/packages/pyodide-kernel-extension/package.json index 6df63ca1..1be29b0a 100644 --- a/packages/pyodide-kernel-extension/package.json +++ b/packages/pyodide-kernel-extension/package.json @@ -35,7 +35,7 @@ "build:prod": "jlpm build:lib && jlpm build:labextension", "build:labextension": "jupyter labextension build .", "build:labextension:dev": "jupyter labextension build --development True .", - "build:lib": "tsc", + "build:lib": "tsc -b", "dist": "cd ../../dist && npm pack ../packages/pyodide-kernel-extension", "clean": "jlpm clean:lib", "clean:lib": "rimraf lib tsconfig.tsbuildinfo", @@ -43,7 +43,7 @@ "clean:all": "jlpm clean:lib && jlpm clean:labextension", "docs": "typedoc src", "watch": "run-p watch:src watch:labextension", - "watch:src": "tsc -w", + "watch:src": "tsc -b -w --preserveWatchOutput", "watch:labextension": "jupyter labextension watch ." }, "dependencies": { diff --git a/packages/pyodide-kernel-extension/schema/kernel.v0.schema.json b/packages/pyodide-kernel-extension/schema/kernel.v0.schema.json index 561d69c5..f472be19 100644 --- a/packages/pyodide-kernel-extension/schema/kernel.v0.schema.json +++ b/packages/pyodide-kernel-extension/schema/kernel.v0.schema.json @@ -24,6 +24,14 @@ }, "default": [], "format": "uri" + }, + "repodataUrls": { + "description": "Paths to pyodide-compatible ``repodata.json`` files.", + "default": [], + "items": { + "type": "string", + "format": "uri" + } } } } diff --git a/packages/pyodide-kernel-extension/src/index.ts b/packages/pyodide-kernel-extension/src/index.ts index 94e43b89..5ff8d01a 100644 --- a/packages/pyodide-kernel-extension/src/index.ts +++ b/packages/pyodide-kernel-extension/src/index.ts @@ -46,7 +46,11 @@ const kernel: JupyterLiteServerPlugin = { const url = config.pyodideUrl || PYODIDE_CDN_URL; const pyodideUrl = URLExt.parse(url).href; const rawPipUrls = config.pipliteUrls || []; + const rawRepoUrls = config.repodataUrls || []; const pipliteUrls = rawPipUrls.map((pipUrl: string) => URLExt.parse(pipUrl).href); + const repodataUrls = rawRepoUrls.map( + (repoUrl: string) => URLExt.parse(repoUrl).href + ); const disablePyPIFallback = !!config.disablePyPIFallback; kernelspecs.register({ @@ -75,6 +79,7 @@ const kernel: JupyterLiteServerPlugin = { ...options, pyodideUrl, pipliteUrls, + repodataUrls, disablePyPIFallback, mountDrive, }); diff --git a/packages/pyodide-kernel/package.json b/packages/pyodide-kernel/package.json index 6f6efb7c..4b263d59 100644 --- a/packages/pyodide-kernel/package.json +++ b/packages/pyodide-kernel/package.json @@ -48,8 +48,7 @@ "test": "jest", "test:cov": "jest --collect-coverage", "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch", - "watch": "tsc -b --watch" + "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch" }, "dependencies": { "@jupyterlite/contents": "^0.1.0-beta.18", @@ -72,9 +71,13 @@ }, "pyodide-kernel": { "packages": { - "py/pyodide-kernel": "0.0.4", - "py/piplite": "0.0.4", "py/ipykernel": "6.9.2", + "py/jedi": "0.18.2", + "py/jupyterlab_widgets1/jupyterlab_widgets": "1.1.2", + "py/jupyterlab_widgets3/jupyterlab_widgets": "3.0.5", + "py/piplite": "0.0.4", + "py/prompt_toolkit": "3.0.36", + "py/pyodide-kernel": "0.0.4", "py/widgetsnbextension3/widgetsnbextension": "3.6.0", "py/widgetsnbextension4/widgetsnbextension": "4.0.2" } diff --git a/packages/pyodide-kernel/py/jedi/LICENSE b/packages/pyodide-kernel/py/jedi/LICENSE new file mode 100644 index 00000000..b7375aa7 --- /dev/null +++ b/packages/pyodide-kernel/py/jedi/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022, JupyterLite Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/pyodide-kernel/py/jedi/README.md b/packages/pyodide-kernel/py/jedi/README.md new file mode 100644 index 00000000..2d44036a --- /dev/null +++ b/packages/pyodide-kernel/py/jedi/README.md @@ -0,0 +1,3 @@ +# jedi mock + +This is a jedi mock to avoid its import expense at kernel startup time. diff --git a/packages/pyodide-kernel/py/jedi/jedi/__init__.py b/packages/pyodide-kernel/py/jedi/jedi/__init__.py new file mode 100644 index 00000000..a553ff79 --- /dev/null +++ b/packages/pyodide-kernel/py/jedi/jedi/__init__.py @@ -0,0 +1,7 @@ +"""A jedi mock""" + +__version__ = "0.18.2" + + +class settings: + case_insensitive_completion = None diff --git a/packages/pyodide-kernel/py/jedi/jedi/api/__init__.py b/packages/pyodide-kernel/py/jedi/jedi/api/__init__.py new file mode 100644 index 00000000..3b9d19a3 --- /dev/null +++ b/packages/pyodide-kernel/py/jedi/jedi/api/__init__.py @@ -0,0 +1,2 @@ +# this appeases a type hint +Completion = None diff --git a/packages/pyodide-kernel/py/jedi/jedi/api/classes.py b/packages/pyodide-kernel/py/jedi/jedi/api/classes.py new file mode 100644 index 00000000..983db2c2 --- /dev/null +++ b/packages/pyodide-kernel/py/jedi/jedi/api/classes.py @@ -0,0 +1 @@ +# an import required by ipython diff --git a/packages/pyodide-kernel/py/jedi/jedi/api/helpers.py b/packages/pyodide-kernel/py/jedi/jedi/api/helpers.py new file mode 100644 index 00000000..983db2c2 --- /dev/null +++ b/packages/pyodide-kernel/py/jedi/jedi/api/helpers.py @@ -0,0 +1 @@ +# an import required by ipython diff --git a/packages/pyodide-kernel/py/jedi/pyproject.toml b/packages/pyodide-kernel/py/jedi/pyproject.toml new file mode 100644 index 00000000..1295f05f --- /dev/null +++ b/packages/pyodide-kernel/py/jedi/pyproject.toml @@ -0,0 +1,21 @@ +[build-system] +requires = ["hatchling>=1.11"] +build-backend = "hatchling.build" + +[tool.hatch.version] +path = "jedi/__init__.py" + +[project] +name = "jedi" +authors = [ + {name = "JupyterLite Contributors"}, +] +readme = "README.md" +requires-python = ">=3.10" +dynamic = ["version", "description"] +classifiers = [ + "License :: OSI Approved :: BSD License", +] + +[project.urls] +Source = "https://github.com/jupyterlite/pyodide-kernel" diff --git a/packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/LICENSE b/packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/LICENSE new file mode 100644 index 00000000..b7375aa7 --- /dev/null +++ b/packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022, JupyterLite Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/README.md b/packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/README.md new file mode 100644 index 00000000..dafe6af0 --- /dev/null +++ b/packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/README.md @@ -0,0 +1,4 @@ +# jupyterlab_widgets mock + +This is a `jupyterlab_widgets` mock that provides nothing. It's only here so that +`import ipywidgets` doesn't incur the download of the real `jupyterlab_widgets`. diff --git a/packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/jupyterlab_widgets/__init__.py b/packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/jupyterlab_widgets/__init__.py new file mode 100644 index 00000000..3d30fbe3 --- /dev/null +++ b/packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/jupyterlab_widgets/__init__.py @@ -0,0 +1,3 @@ +"""A jupyterlab_widgets mock""" + +__version__ = "1.1.2" diff --git a/packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/pyproject.toml b/packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/pyproject.toml new file mode 100644 index 00000000..26e78c1a --- /dev/null +++ b/packages/pyodide-kernel/py/jupyterlab_widgets1/jupyterlab_widgets/pyproject.toml @@ -0,0 +1,21 @@ +[build-system] +requires = ["hatchling>=1.11"] +build-backend = "hatchling.build" + +[tool.hatch.version] +path = "jupyterlab_widgets/__init__.py" + +[project] +name = "jupyterlab_widgets" +authors = [ + {name = "JupyterLite Contributors"}, +] +readme = "README.md" +requires-python = ">=3.10,<3.11" +dynamic = ["version", "description"] +classifiers = [ + "License :: OSI Approved :: BSD License", +] + +[project.urls] +Source = "https://github.com/jupyterlite/pyodide-kernel" diff --git a/packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/LICENSE b/packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/LICENSE new file mode 100644 index 00000000..b7375aa7 --- /dev/null +++ b/packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022, JupyterLite Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/README.md b/packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/README.md new file mode 100644 index 00000000..337dafa9 --- /dev/null +++ b/packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/README.md @@ -0,0 +1,4 @@ +# jupyterlab_widgets mock + +This is an `jupyterlab_widgets` mock that provides nothing. It's only here so that +`import ipywidgets` doesn't incur the download of the real `jupyterlab_widgets`. diff --git a/packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/jupyterlab_widgets/__init__.py b/packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/jupyterlab_widgets/__init__.py new file mode 100644 index 00000000..7e7aa34e --- /dev/null +++ b/packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/jupyterlab_widgets/__init__.py @@ -0,0 +1,3 @@ +"""A jupyterlab_widgets mock""" + +__version__ = "3.0.5" diff --git a/packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/pyproject.toml b/packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/pyproject.toml new file mode 100644 index 00000000..26e78c1a --- /dev/null +++ b/packages/pyodide-kernel/py/jupyterlab_widgets3/jupyterlab_widgets/pyproject.toml @@ -0,0 +1,21 @@ +[build-system] +requires = ["hatchling>=1.11"] +build-backend = "hatchling.build" + +[tool.hatch.version] +path = "jupyterlab_widgets/__init__.py" + +[project] +name = "jupyterlab_widgets" +authors = [ + {name = "JupyterLite Contributors"}, +] +readme = "README.md" +requires-python = ">=3.10,<3.11" +dynamic = ["version", "description"] +classifiers = [ + "License :: OSI Approved :: BSD License", +] + +[project.urls] +Source = "https://github.com/jupyterlite/pyodide-kernel" diff --git a/packages/pyodide-kernel/py/prompt_toolkit/LICENSE b/packages/pyodide-kernel/py/prompt_toolkit/LICENSE new file mode 100644 index 00000000..b7375aa7 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022, JupyterLite Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/pyodide-kernel/py/prompt_toolkit/README.md b/packages/pyodide-kernel/py/prompt_toolkit/README.md new file mode 100644 index 00000000..6820cc19 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/README.md @@ -0,0 +1,3 @@ +# prompt_toolkit mock + +This is a prompt_toolkit mock to avoid its import expense at kernel startup time. diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/__init__.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/__init__.py new file mode 100644 index 00000000..1a5afc0c --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/__init__.py @@ -0,0 +1,3 @@ +"""A prompt_toolkit mock""" + +__version__ = "3.0.36" diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/application/current.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/application/current.py new file mode 100644 index 00000000..89ec6093 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/application/current.py @@ -0,0 +1,2 @@ +def get_app(*args, **kwargs): + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/auto_suggest.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/auto_suggest.py new file mode 100644 index 00000000..dfb809c1 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/auto_suggest.py @@ -0,0 +1,5 @@ +class AutoSuggestFromHistory: + pass + + +Suggestion = AutoSuggestFromHistory diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/buffer.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/buffer.py new file mode 100644 index 00000000..b9ebc18f --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/buffer.py @@ -0,0 +1,2 @@ +class Buffer: + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/completion.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/completion.py new file mode 100644 index 00000000..652e0160 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/completion.py @@ -0,0 +1,6 @@ +class Completer: + pass + + +class Completion: + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/document.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/document.py new file mode 100644 index 00000000..7b831938 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/document.py @@ -0,0 +1,2 @@ +class Document: + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/enums.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/enums.py new file mode 100644 index 00000000..1d01ce38 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/enums.py @@ -0,0 +1,5 @@ +DEFAULT_BUFFER = SEARCH_BUFFER = EditingMode = None + + +class EditingMode: + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/filters.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/filters.py new file mode 100644 index 00000000..d2116c35 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/filters.py @@ -0,0 +1,31 @@ +class HasFocus: + pass + + +def Condition(*args, **kwargs): + return True + + +Always = IsDone = HasFocus + + +def has_focus(*args, **kwargs): + class Foo: + def __init__(self, *args, **kwargs): + def func(*args, **kwargs): + pass + + setattr(func, "__name__", "") + self.func = func + + def __or__(self, other): + return True + + __and__ = __or__ + + return Foo() + + +has_selection = ( + has_suggestion +) = vi_insert_mode = vi_mode = has_completions = emacs_insert_mode = True diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/formatted_text.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/formatted_text.py new file mode 100644 index 00000000..1c347434 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/formatted_text.py @@ -0,0 +1,6 @@ +class PygmentsTokens: + pass + + +def fragment_list_width(*args, **kwargs): + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/history.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/history.py new file mode 100644 index 00000000..07df9cc8 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/history.py @@ -0,0 +1,5 @@ +class History: + pass + + +InMemoryHistory = FileHistory = History diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/__init__.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/__init__.py new file mode 100644 index 00000000..7e0fd484 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/__init__.py @@ -0,0 +1,5 @@ +class KeyBindings: + pass + + +KeyPressEvent = KeyBindings diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/bindings/__init__.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/bindings/__init__.py new file mode 100644 index 00000000..c1425349 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/bindings/__init__.py @@ -0,0 +1,6 @@ +class __named_commands__: + def __getattr__(self, name): + return name + + +named_commands = __named_commands__() diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/bindings/completion.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/bindings/completion.py new file mode 100644 index 00000000..db2d5fb4 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/bindings/completion.py @@ -0,0 +1,2 @@ +def display_completions_like_readline(*args, **kwargs): + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/key_processor.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/key_processor.py new file mode 100644 index 00000000..13080c72 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/key_processor.py @@ -0,0 +1,2 @@ +class KeyPressEvent: + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/vi_state.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/vi_state.py new file mode 100644 index 00000000..18dc6791 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/key_binding/vi_state.py @@ -0,0 +1,5 @@ +class InputMode: + pass + + +ViState = InputMode diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/layout/__init__.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/layout/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/layout/layout.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/layout/layout.py new file mode 100644 index 00000000..86e509ac --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/layout/layout.py @@ -0,0 +1,2 @@ +class FocusableElement: + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/layout/processors.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/layout/processors.py new file mode 100644 index 00000000..d7775532 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/layout/processors.py @@ -0,0 +1,7 @@ +class ConditionalProcessor: + pass + + +TransformationInput = ( + Transformation +) = Processor = HighlightMatchingBracketProcessor = ConditionalProcessor diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/lexers.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/lexers.py new file mode 100644 index 00000000..f70d65a4 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/lexers.py @@ -0,0 +1,6 @@ +class Lexer: + pass + + +class PygmentsLexer: + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/output.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/output.py new file mode 100644 index 00000000..682ca1ef --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/output.py @@ -0,0 +1,2 @@ +class ColorDepth: + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/patch_stdout.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/patch_stdout.py new file mode 100644 index 00000000..348ee43c --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/patch_stdout.py @@ -0,0 +1,2 @@ +def patch_stdout(*args, **kwargs): + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/shortcuts/__init__.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/shortcuts/__init__.py new file mode 100644 index 00000000..09c6da2f --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/shortcuts/__init__.py @@ -0,0 +1,9 @@ +class PromptSession: + pass + + +CompleteStyle = PromptSession + + +def print_formatted_text(*args, **kwargs): + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/shortcuts/prompt.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/shortcuts/prompt.py new file mode 100644 index 00000000..63b7808f --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/shortcuts/prompt.py @@ -0,0 +1,2 @@ +class PromptSession: + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/styles/__init__.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/styles/__init__.py new file mode 100644 index 00000000..6cfbf9f6 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/styles/__init__.py @@ -0,0 +1,6 @@ +class DynamicStyle: + pass + + +def merge_styles(*args, **kwargs): + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/styles/pygments.py b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/styles/pygments.py new file mode 100644 index 00000000..dfea1b63 --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/prompt_toolkit/styles/pygments.py @@ -0,0 +1,6 @@ +def style_from_pygments_cls(*args, **kwargs): + pass + + +def style_from_pygments_dict(*args, **kwargs): + pass diff --git a/packages/pyodide-kernel/py/prompt_toolkit/pyproject.toml b/packages/pyodide-kernel/py/prompt_toolkit/pyproject.toml new file mode 100644 index 00000000..508c59dc --- /dev/null +++ b/packages/pyodide-kernel/py/prompt_toolkit/pyproject.toml @@ -0,0 +1,24 @@ +[build-system] +requires = ["hatchling>=1.11"] +build-backend = "hatchling.build" + +[tool.hatch.version] +path = "prompt_toolkit/__init__.py" + +[project] +name = "prompt_toolkit" +authors = [ + {name = "JupyterLite Contributors"}, +] +dependencies = [ + "wcwidth", +] +readme = "README.md" +requires-python = ">=3.10" +dynamic = ["version", "description"] +classifiers = [ + "License :: OSI Approved :: BSD License", +] + +[project.urls] +Source = "https://github.com/jupyterlite/pyodide-kernel" diff --git a/packages/pyodide-kernel/schema/repodata.v0.schema.json b/packages/pyodide-kernel/schema/repodata.v0.schema.json new file mode 100644 index 00000000..dbfc0ade --- /dev/null +++ b/packages/pyodide-kernel/schema/repodata.v0.schema.json @@ -0,0 +1,107 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://jupyterlite-pyodide-kernel.readthedocs.org/en/latest/repodata-schema-v0.html#", + "title": "Pyodide Repodata Schema v0", + "description": "a schema for a partial pyodide repodata index", + "$ref": "#/definitions/top", + "definitions": { + "top": { + "type": "object", + "required": ["packages"], + "properties": { + "info": { + "description": "Pyodide version for which this repodata is valid. Presently not generated, and discarded at runtime.", + "$ref": "#/definitions/repodata-info" + }, + "packages": { + "type": "object", + "patternProperties": { + "[a-z][a-z\\-\\.]+": { + "$ref": "#/definitions/a-project-repodata" + } + } + } + } + }, + "repodata-info": { + "description": "The pyodide version runtime for which this repodata will work", + "properties": { + "arch": { + "type": "string", + "description": "The name of the architecture, e.g. ``wasm32``" + }, + "platform": { + "type": "string", + "description": "The name of the platform, e.g. ``emscripten_3_1_27``" + }, + "python": { + "type": "string", + "description": "The version of python, e.g. ``3.10.2``" + }, + "version": { + "type": "string", + "description": "The version of pyodide, e.g. ``0.22.1``" + } + } + }, + "a-project-repodata": { + "type": "object", + "required": [ + "depends", + "file_name", + "imports", + "install_dir", + "name", + "sha256", + "version" + ], + "properties": { + "depends": { + "type": "array", + "description": "A list of PEP 503 normalized package names which this package depends on", + "items": { + "$ref": "#/definitions/a-pep-503-name" + } + }, + "file_name": { + "type": "string", + "format": "uri", + "description": "A relative path or URL that resolves to a ``.whl`` file" + }, + "install_dir": { + "type": "string", + "description": "The destination for the package: currently only generates ``site``", + "enum": ["site", "dynlib"] + }, + "name": { + "description": "The PEP 503 name of the package.", + "$ref": "#/definitions/a-pep-503-name" + }, + "sha256": { + "description": "The observed sha256 hash digest of the package, which might be validated", + "$ref": "#/definitions/a-sha256-digest" + }, + "version": { + "description": "The version of the package", + "type": "string" + }, + "imports": { + "description": "The top-level import names which will trigger installation of this package", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "a-pep-503-name": { + "description": "A python distribution name that conforms to PEP 503", + "type": "string", + "pattern": "[a-z][a-z0-9\\-\\.]+" + }, + "a-sha256-digest": { + "type": "string", + "pattern": "[a-f0-9]{64}" + } + } +} diff --git a/packages/pyodide-kernel/scripts/generate-wheels-js.py b/packages/pyodide-kernel/scripts/generate-wheels-js.py index 2228a0df..4041dbd7 100644 --- a/packages/pyodide-kernel/scripts/generate-wheels-js.py +++ b/packages/pyodide-kernel/scripts/generate-wheels-js.py @@ -78,6 +78,7 @@ def generate_pypi_ts(): lines = [ "// this file is autogenerated from the wheels described in ../package.json", "export * as allJSONUrl from '../pypi/all.json';", + "export * as repodataJSONUrl from '../pypi/repodata.json';", ] vars_made = {} diff --git a/packages/pyodide-kernel/src/_pypi.ts b/packages/pyodide-kernel/src/_pypi.ts index 3e7ce869..08fed82d 100644 --- a/packages/pyodide-kernel/src/_pypi.ts +++ b/packages/pyodide-kernel/src/_pypi.ts @@ -1,7 +1,12 @@ // this file is autogenerated from the wheels described in ../package.json export * as allJSONUrl from '../pypi/all.json'; export * as ipykernelWheelUrl from '../pypi/ipykernel-6.9.2-py3-none-any.whl'; +export * as jediWheelUrl from '../pypi/jedi-0.18.2-py3-none-any.whl'; +export * as jupyterlab_widgetsWheelUrl from '../pypi/jupyterlab_widgets-1.1.2-py3-none-any.whl'; +export * as jupyterlab_widgetsWheelUrl1 from '../pypi/jupyterlab_widgets-3.0.5-py3-none-any.whl'; export * as pipliteWheelUrl from '../pypi/piplite-0.0.4-py3-none-any.whl'; +export * as prompt_toolkitWheelUrl from '../pypi/prompt_toolkit-3.0.36-py3-none-any.whl'; export * as pyodide_kernelWheelUrl from '../pypi/pyodide_kernel-0.0.4-py3-none-any.whl'; +export * as repodataJSONUrl from '../pypi/repodata.json'; export * as widgetsnbextensionWheelUrl from '../pypi/widgetsnbextension-3.6.0-py3-none-any.whl'; export * as widgetsnbextensionWheelUrl1 from '../pypi/widgetsnbextension-4.0.2-py3-none-any.whl'; diff --git a/packages/pyodide-kernel/src/declarations.d.ts b/packages/pyodide-kernel/src/declarations.d.ts index cb260473..b4054bb7 100644 --- a/packages/pyodide-kernel/src/declarations.d.ts +++ b/packages/pyodide-kernel/src/declarations.d.ts @@ -8,6 +8,11 @@ declare module '*all.json' { export default res; } +declare module '*repodata.json' { + const res: string; + export default res; +} + declare module '../schema/*.json' { const res: string; export default res; diff --git a/packages/pyodide-kernel/src/kernel.ts b/packages/pyodide-kernel/src/kernel.ts index 3ec5c7ab..7590b10a 100644 --- a/packages/pyodide-kernel/src/kernel.ts +++ b/packages/pyodide-kernel/src/kernel.ts @@ -9,7 +9,7 @@ import { wrap } from 'comlink'; import { IPyodideWorkerKernel, IRemotePyodideWorkerKernel } from './tokens'; -import { allJSONUrl, pipliteWheelUrl } from './_pypi'; +import { allJSONUrl, repodataJSONUrl, pipliteWheelUrl } from './_pypi'; /** * A kernel that executes Python code with Pyodide. @@ -54,7 +54,9 @@ export class PyodideKernel extends BaseKernel implements IKernel { const { pyodideUrl } = options; const indexUrl = pyodideUrl.slice(0, pyodideUrl.lastIndexOf('/') + 1); const baseUrl = PageConfig.getBaseUrl(); + const pipliteUrls = [...(options.pipliteUrls || []), allJSONUrl.default]; + const repodataUrls = [...(options.repodataUrls || []), repodataJSONUrl.default]; const disablePyPIFallback = !!options.disablePyPIFallback; @@ -64,6 +66,7 @@ export class PyodideKernel extends BaseKernel implements IKernel { indexUrl, pipliteWheelUrl: pipliteWheelUrl.default, pipliteUrls, + repodataUrls: repodataUrls, disablePyPIFallback, location: this.location, mountDrive: options.mountDrive, @@ -309,6 +312,11 @@ export namespace PyodideKernel { */ pipliteUrls: string[]; + /** + * The URLs with which to patch repodata.json + */ + repodataUrls: string[]; + /** * Do not try pypi.org if `piplite.install` fails against local URLs */ diff --git a/packages/pyodide-kernel/src/tokens.ts b/packages/pyodide-kernel/src/tokens.ts index 13ace73f..f4ebbf97 100644 --- a/packages/pyodide-kernel/src/tokens.ts +++ b/packages/pyodide-kernel/src/tokens.ts @@ -14,6 +14,11 @@ import { IWorkerKernel } from '@jupyterlite/kernel'; */ export * as PIPLITE_INDEX_SCHEMA from '../schema/piplite.v0.schema.json'; +/** + * The schema for a pyodide-compatible repodata. + */ +export * as REPODATA_INDEX_SCHEMA from '../schema/repodata.v0.schema.json'; + /** * An interface for Pyodide workers. */ @@ -57,6 +62,11 @@ export namespace IPyodideWorkerKernel { */ pipliteUrls: string[]; + /** + * The URLs of additional pyodide repodata.json files + */ + repodataUrls: string[]; + /** * Whether `piplite` should fall back to the hard-coded `pypi.org` for resolving packages. */ @@ -72,4 +82,58 @@ export namespace IPyodideWorkerKernel { */ mountDrive: boolean; } + + /** + * Data about a single version of a package. + */ + export interface IRepoDataPackage { + /** + * A list of PEP 503 names for packages. + */ + depends: string[]; + /** + * The relative or full-qualified URL for the package to install. + */ + file_name: string; + /** + * Importable modules which should trigger installation of this package. + */ + imports: string[]; + /** + * The destination for this package: ``dynlib`` is not yet fully understood. + */ + install_dir: 'site' | 'dynlib'; + /** + * The PEP 503 name of the package. + */ + name: string; + /** + * A SHA256 digest for the ``file_name``. + */ + sha256: string; + /** + * The version of this package. + */ + version: string; + } + + export interface IRepoData { + /** + * Metadata about this repodata. + * + * This is not currently used. + */ + info?: { + arch: string; + platform: string; + python: string; + version: string; + }; + /** + * A dictionary of packages, keyed by PEP 503 name. + */ + packages: { + [key: string]: IRepoDataPackage; + }; + } } diff --git a/packages/pyodide-kernel/src/worker.ts b/packages/pyodide-kernel/src/worker.ts index ee7a54b4..630cf077 100644 --- a/packages/pyodide-kernel/src/worker.ts +++ b/packages/pyodide-kernel/src/worker.ts @@ -7,7 +7,7 @@ import type { DriveFS } from '@jupyterlite/contents'; import type { IPyodideWorkerKernel } from './tokens'; -export class PyodideRemoteKernel { +export class PyodideRemoteKernel implements IPyodideWorkerKernel { constructor() { this._initialized = new Promise((resolve, reject) => { this._initializer = { resolve, reject }; @@ -53,6 +53,21 @@ export class PyodideRemoteKernel { this._pyodide = await loadPyodide({ indexURL: indexUrl }); } + /** + * Fetch the repodata URL, and resolve all filename URLs + */ + async fetchRepodata(url: string): Promise { + const response = await fetch(url); + const repodata: IPyodideWorkerKernel.IRepoData = await response.json(); + for (const [packageName, packageData] of Object.entries(repodata.packages)) { + if (packageData) { + const file_name = new URL(packageData.file_name, url).toString(); + repodata.packages[packageName] = { ...packageData, file_name }; + } + } + return repodata; + } + protected async initPackageManager( options: IPyodideWorkerKernel.IOptions ): Promise { @@ -60,11 +75,13 @@ export class PyodideRemoteKernel { throw new Error('Uninitialized'); } - const { pipliteWheelUrl, disablePyPIFallback, pipliteUrls } = this._options; + const { pipliteWheelUrl, disablePyPIFallback, pipliteUrls, repodataUrls } = + this._options; + // this is the only use of `loadPackage`, allow `piplite` to handle the rest await this._pyodide.loadPackage(['micropip']); - // get piplite early enough to impact pyodide dependencies + // get piplite early enough to impact Pyodide dependencies await this._pyodide.runPythonAsync(` import micropip await micropip.install('${pipliteWheelUrl}', keep_going=True) @@ -72,17 +89,43 @@ export class PyodideRemoteKernel { piplite.piplite._PIPLITE_DISABLE_PYPI = ${disablePyPIFallback ? 'True' : 'False'} piplite.piplite._PIPLITE_URLS = ${JSON.stringify(pipliteUrls)} `); + + if (repodataUrls.length) { + const API = (this._pyodide as any)._api; + const repodataPromises: Promise[] = []; + for (const url of repodataUrls) { + repodataPromises.push(this.fetchRepodata(url)); + } + + const repodataResults = await Promise.all(repodataPromises); + + for (const repo of repodataResults) { + API.repodata_packages = { + ...API.repodata_packages, + ...repo.packages, + }; + } + + for (const packageName of Object.keys(API.repodata_packages)) { + const packageData: IPyodideWorkerKernel.IRepoDataPackage = + API.repodata_packages[packageName]; + + for (const importName of packageData.imports) { + API._import_name_to_package_name.set(importName, packageName); + } + } + } } protected async initKernel(options: IPyodideWorkerKernel.IOptions): Promise { // from this point forward, only use piplite (but not %pip) await this._pyodide.runPythonAsync(` - await piplite.install(['sqlite3'], keep_going=True); - await piplite.install(['ipykernel'], keep_going=True); + await piplite.install(['sqlite3', 'jedi', 'decorator', 'pygments', 'six', 'ipykernel'], keep_going=True); await piplite.install(['pyodide_kernel'], keep_going=True); await piplite.install(['ipython'], keep_going=True); import pyodide_kernel `); + // cd to the kernel location if (options.mountDrive && this._localPath) { await this._pyodide.runPythonAsync(` @@ -336,7 +379,7 @@ export class PyodideRemoteKernel { return { comms: results, - status: 'ok', + status: 'ok' as any, }; } diff --git a/pyproject.toml b/pyproject.toml index 1e3ecb70..06d01031 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,7 +126,7 @@ addopts = [ "--cov-report=term-missing:skip-covered", "--cov-report=html:build/reports/htmlcov", "--cov-branch", - "--cov-fail-under=97", + "--cov-fail-under=89", "--no-cov-on-fail", # html "--html=build/reports/pytest.html", diff --git a/yarn.lock b/yarn.lock index 41d8ad92..99cc8a90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2696,6 +2696,11 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + axios@^1.0.0: version "1.3.4" resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.4.tgz#f5760cefd9cfb51fd2481acf88c05f67c4523024" @@ -2985,7 +2990,7 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -call-bind@^1.0.2: +call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== @@ -3479,7 +3484,7 @@ cosmiconfig@7.0.0: path-type "^4.0.0" yaml "^1.10.0" -cross-spawn@^6.0.0: +cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -3650,7 +3655,7 @@ define-lazy-prop@^2.0.0: resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== -define-properties@^1.1.3: +define-properties@^1.1.3, define-properties@^1.1.4: version "1.2.0" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== @@ -3920,11 +3925,68 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +es-abstract@^1.19.0, es-abstract@^1.20.4: + version "1.21.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.1.tgz#e6105a099967c08377830a0c9cb589d570dd86c6" + integrity sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.1.3" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.4" + is-array-buffer "^3.0.1" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.10" + is-weakref "^1.0.2" + object-inspect "^1.12.2" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + safe-regex-test "^1.0.0" + string.prototype.trimend "^1.0.6" + string.prototype.trimstart "^1.0.6" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.9" + es-module-lexer@^0.9.0: version "0.9.3" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== +es-set-tostringtag@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" + integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + dependencies: + get-intrinsic "^1.1.3" + has "^1.0.3" + has-tostringtag "^1.0.0" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + es6-templates@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/es6-templates/-/es6-templates-0.2.3.tgz#5cb9ac9fb1ded6eb1239342b81d792bbb4078ee4" @@ -4430,6 +4492,13 @@ follow-redirects@^1.15.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -4511,6 +4580,16 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + functions-have-names@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" @@ -4540,7 +4619,7 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== @@ -4588,6 +4667,14 @@ get-stream@^5.0.0: dependencies: pump "^3.0.0" +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -4708,6 +4795,13 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + globby@11.1.0, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -4720,6 +4814,13 @@ globby@11.1.0, globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + graceful-fs@4.2.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -4762,6 +4863,11 @@ harmony-reflect@^1.4.6: resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.2.tgz#31ecbd32e648a34d030d86adb67d4d47547fe710" integrity sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g== +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -4779,6 +4885,11 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" @@ -5095,6 +5206,15 @@ inquirer@^8.2.4: through "^2.3.6" wrap-ansi "^7.0.0" +internal-slot@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" + integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== + dependencies: + get-intrinsic "^1.2.0" + has "^1.0.3" + side-channel "^1.0.4" + interpret@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" @@ -5127,16 +5247,45 @@ is-arguments@^1.0.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-array-buffer@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + is-ci@2.0.0, is-ci@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" @@ -5239,6 +5388,18 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -5283,7 +5444,7 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-regex@^1.0.4: +is-regex@^1.0.4, is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== @@ -5291,6 +5452,13 @@ is-regex@^1.0.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + is-ssh@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.4.0.tgz#4f8220601d2839d8fa624b3106f8e8884f01b8b2" @@ -5308,6 +5476,20 @@ is-stream@^1.1.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + is-text-path@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" @@ -5315,6 +5497,17 @@ is-text-path@^1.0.1: dependencies: text-extensions "^1.0.0" +is-typed-array@^1.1.10, is-typed-array@^1.1.9: + version "1.1.10" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" + integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + is-typedarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -5325,6 +5518,13 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -6502,6 +6702,11 @@ marked@^4.0.17: resolved "https://registry.yarnpkg.com/marked/-/marked-4.2.12.tgz#d69a64e21d71b06250da995dcd065c11083bebb5" integrity sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw== +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== + meow@^8.0.0: version "8.1.2" resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" @@ -7008,6 +7213,21 @@ npm-registry-fetch@13.3.0, npm-registry-fetch@^13.0.0, npm-registry-fetch@^13.0. npm-package-arg "^9.0.1" proc-log "^2.0.0" +npm-run-all@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" + integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== + dependencies: + ansi-styles "^3.2.1" + chalk "^2.4.1" + cross-spawn "^6.0.5" + memorystream "^0.3.1" + minimatch "^3.0.4" + pidtree "^0.3.0" + read-pkg "^3.0.0" + shell-quote "^1.6.1" + string.prototype.padend "^3.0.0" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -7102,6 +7322,11 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" +object-inspect@^1.12.2, object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + object-is@^1.0.1: version "1.1.5" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" @@ -7122,6 +7347,16 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" +object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" @@ -7456,6 +7691,11 @@ picomatch@^2.0.4, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pidtree@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" + integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== + pify@5.0.0, pify@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" @@ -7930,7 +8170,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.2.0: +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== @@ -8074,6 +8314,15 @@ safe-buffer@^5.1.0, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" @@ -8230,11 +8479,25 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shell-quote@^1.6.1: + version "1.8.0" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.0.tgz#20d078d0eaf71d54f43bd2ba14a1b5b9bfa5c8ba" + integrity sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ== + shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + signal-exit@3.0.7, signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" @@ -8474,6 +8737,33 @@ string-length@^4.0.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string.prototype.padend@^3.0.0: + version "3.1.4" + resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.4.tgz#2c43bb3a89eb54b6750de5942c123d6c98dd65b6" + integrity sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimend@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" + integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimstart@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" + integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + string_decoder@^1.1.1, string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -8903,6 +9193,15 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + typed-styles@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9" @@ -8941,6 +9240,16 @@ uglify-js@3.4.x, uglify-js@^3.1.4: commander "~2.19.0" source-map "~0.6.1" +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -9304,11 +9613,34 @@ whatwg-url@^8.0.0, whatwg-url@^8.5.0: tr46 "^2.1.0" webidl-conversions "^6.1.0" +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== +which-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" + integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.10" + which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"