Skip to content

Commit 853fa9a

Browse files
authored
Update to jupyterlite-core 0.7.x, pyodide 0.28.1, micropip 0.10.1 (#203)
* start bumping to pyodide 0.28.0 * mostly fix piplite * linting * update piplite cli options * pyodide 0.28.1 * rework readme changes * commit yarn.lock * target jupyterlite-core 0.7.0a1 * also bump ui-tests versions * fix more pins * more lab bumps
1 parent 08ff569 commit 853fa9a

File tree

14 files changed

+974
-739
lines changed

14 files changed

+974
-739
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
| status | `jupyterlite-pyodide-kernel` | `jupyterlite-core` | `jupyterlab` | `notebook` | `retrolab` |
2525
| :----: | :--------------------------: | :----------------: | :------------: | :------------: | :----------: |
26+
| alpha | `0.7.*` | `>=0.6,<0.7` | `>=4.4.5,<4.5` | `>=7.4.5,<7.5` | - |
2627
| stable | `0.6.*` | `>=0.6,<0.7` | `>=4.4.3,<4.5` | `>=7.4.3,<7.5` | - |
2728
| stable | `0.5.*` | `>=0.5,<0.6` | `>=4.3.0,<4.4` | `>=7.3.0,<7.4` | - |
2829
| stable | `0.4.*` | `>=0.4,<0.5` | `>=4.2.0,<4.3` | `>=7.2.0,<7.3` | - |
@@ -46,6 +47,7 @@ yet work in a full, `jupyter_server`-hosted client such as JupyterLab or Noteboo
4647
| `>=0.4.7,<=0.5.0` | `0.27.*` | `3.12.*` | `3.1.58` |
4748
| `>=0.5.0,<=0.6.0` | `0.27.*` | `3.12.*` | `3.1.58` |
4849
| `>=0.6.0,<=0.7.0` | `0.27.*` | `3.12.*` | `3.1.58` |
50+
| `>=0.7.0,<=0.8.0` | `0.28.*` | `3.13.*` | `4.0.9` |
4951

5052
Note that the Emscripten version is strict down to the bugfix version.
5153

examples/jupyter-lite.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"@jupyterlite/pyodide-kernel-extension:kernel": {
77
"loadPyodideOptions": {
88
"packages": ["matplotlib", "micropip", "numpy", "sqlite3", "ssl"],
9-
"lockFileURL": "https://cdn.jsdelivr.net/pyodide/v0.27.6/full/pyodide-lock.json?from-lite-config=1"
9+
"lockFileURL": "https://cdn.jsdelivr.net/pyodide/v0.28.1/full/pyodide-lock.json?from-lite-config=1"
1010
}
1111
}
1212
}

jupyterlite_pyodide_kernel/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
PYODIDE_URL_ENV_VAR = "JUPYTERLITE_PYODIDE_URL"
3030

3131
#: probably only compatible with this version of pyodide
32-
PYODIDE_VERSION = "0.27.6"
32+
PYODIDE_VERSION = "0.28.1"
3333

3434
#: the only kind of noarch wheel piplite understands
3535
NOARCH_WHL = "py3-none-any.whl"

packages/pyodide-kernel-extension/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,17 @@
4747
"watch:labextension": "jupyter labextension watch ."
4848
},
4949
"dependencies": {
50-
"@jupyterlab/application": "^4.4.0",
51-
"@jupyterlab/coreutils": "^6.4.0",
52-
"@jupyterlab/logconsole": "^4.4.0",
53-
"@jupyterlite/contents": "^0.6.0",
54-
"@jupyterlite/kernel": "^0.6.0",
50+
"@jupyterlab/application": "^4.5.0-alpha.1",
51+
"@jupyterlab/coreutils": "^6.5.0-alpha.1",
52+
"@jupyterlab/logconsole": "^4.5.0-alpha.1",
53+
"@jupyterlite/contents": "^0.7.0-alpha.1",
54+
"@jupyterlite/kernel": "^0.7.0-alpha.1",
5555
"@jupyterlite/pyodide-kernel": "^0.6.1",
56-
"@jupyterlite/server": "^0.6.0"
56+
"@jupyterlite/server": "^0.7.0-alpha.1"
5757
},
5858
"devDependencies": {
59-
"@jupyterlab/builder": "~4.4.0",
60-
"rimraf": "^5.0.1",
59+
"@jupyterlab/builder": "^4.5.0-alpha.1",
60+
"rimraf": "^6.0.1",
6161
"typescript": "~5.2.2"
6262
},
6363
"publishConfig": {

packages/pyodide-kernel-extension/schema/kernel.v0.schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"pyodideUrl": {
99
"description": "The path to the main pyodide.js entry point",
1010
"type": "string",
11-
"default": "https://cdn.jsdelivr.net/pyodide/v0.27.6/full/pyodide.js",
11+
"default": "https://cdn.jsdelivr.net/pyodide/v0.28.1/full/pyodide.js",
1212
"format": "uri"
1313
},
1414
"disablePyPIFallback": {

packages/pyodide-kernel-extension/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const KERNEL_ICON_URL = `data:image/svg+xml;base64,${btoa(KERNEL_ICON_SVG_STR)}`
2020
/**
2121
* The default CDN fallback for Pyodide
2222
*/
23-
const PYODIDE_CDN_URL = 'https://cdn.jsdelivr.net/pyodide/v0.27.6/full/pyodide.js';
23+
const PYODIDE_CDN_URL = 'https://cdn.jsdelivr.net/pyodide/v0.28.1/full/pyodide.js';
2424

2525
/**
2626
* The id for the extension, and key in the litePlugins.

packages/pyodide-kernel/package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,18 @@
5050
"watch": "tsc -b --watch"
5151
},
5252
"dependencies": {
53-
"@jupyterlab/coreutils": "^6.4.0",
54-
"@jupyterlab/logconsole": "^4.4.0",
55-
"@jupyterlite/contents": "^0.6.0",
56-
"@jupyterlite/kernel": "^0.6.0",
53+
"@jupyterlab/coreutils": "^6.5.0-alpha.1",
54+
"@jupyterlab/logconsole": "^4.5.0-alpha.1",
55+
"@jupyterlite/contents": "^0.7.0-alpha.1",
56+
"@jupyterlite/kernel": "^0.7.0-alpha.1",
5757
"coincident": "^1.2.3",
5858
"comlink": "^4.4.2"
5959
},
6060
"devDependencies": {
6161
"@babel/core": "^7.22.17",
6262
"esbuild": "^0.19.2",
63-
"pyodide": "0.27.6",
64-
"rimraf": "^5.0.1",
63+
"pyodide": "0.28.1",
64+
"rimraf": "^6.0.1",
6565
"typescript": "~5.2.2"
6666
},
6767
"publishConfig": {

packages/pyodide-kernel/py/piplite/piplite/cli.py

Lines changed: 82 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,46 @@
22
33
As of the upstream:
44
5-
https://github.com/pyodide/micropip/blob/v0.2.0/micropip/_micropip.py#L468
5+
https://github.com/pyodide/micropip/blob/0.10.0/micropip/package_manager.py#L43-L55
66
77
.. code:
88
99
async def install(
1010
self,
11-
requirements: str | list[str], # -r and [packages]
11+
requirements: str | list[str], # -r and [PACKAGES]
1212
keep_going: bool = False, # --verbose
1313
deps: bool = True, # --no-deps
1414
credentials: str | None = None, # no CLI alias
1515
pre: bool = False, # --pre
1616
index_urls: list[str] | str | None = None, # no CLI alias
1717
*,
18-
verbose: bool | int | None = None,
19-
):
20-
```
18+
constraints: list[str] | None = None, # --constraints
19+
reinstall: bool = False, # no CLI alias
20+
verbose: bool | int | None = None, # --verbose
21+
) -> None:
2122
2223
As this is _not_ really a CLI, it doesn't bother with accurate return codes, and
2324
failures should not block execution.
2425
"""
2526

27+
from __future__ import annotations
28+
2629
import re
2730
import sys
28-
import typing
31+
from typing import Any, TYPE_CHECKING
2932
from argparse import ArgumentParser
3033
from pathlib import Path
3134

32-
REQ_FILE_PREFIX = r"^(-r|--requirements)\s*=?\s*(.*)\s*"
35+
if TYPE_CHECKING:
36+
from collections.abc import AsyncIterator
37+
38+
REQ_FILE_SPEC = r"^(?P<flag>-r|--requirements)\s*=?\s*(?P<path_ref>.+)$"
3339

3440
__all__ = ["get_transformed_code"]
3541

3642

37-
def warn(msg):
43+
def warn(msg: str) -> None:
44+
"""Print a warning to stderr."""
3845
print(msg, file=sys.stderr, flush=True)
3946

4047

@@ -44,7 +51,7 @@ def _get_parser() -> ArgumentParser:
4451
"piplite",
4552
exit_on_error=False,
4653
allow_abbrev=False,
47-
description="a pip-like wrapper for `piplite` and `micropip`",
54+
description="a ``pip``-like wrapper for ``piplite`` and ``micropip``",
4855
)
4956
parser.add_argument(
5057
"--verbose",
@@ -64,7 +71,19 @@ def _get_parser() -> ArgumentParser:
6471
"--requirements",
6572
"-r",
6673
nargs="*",
67-
help="paths to requirements files",
74+
help=(
75+
"path to a requirements file; each line should be a PEP 508 spec"
76+
" or -r to a relative path"
77+
),
78+
)
79+
parser.add_argument(
80+
"--constraints",
81+
"-c",
82+
nargs="*",
83+
help=(
84+
"path to a constraints file; each line should be a PEP 508 spec"
85+
" or -r to a relative path"
86+
),
6887
)
6988
parser.add_argument(
7089
"--no-deps",
@@ -76,6 +95,11 @@ def _get_parser() -> ArgumentParser:
7695
action="store_true",
7796
help="whether pre-release packages should be considered",
7897
)
98+
parser.add_argument(
99+
"--force-reinstall",
100+
action="store_true",
101+
help="reinstall all packages even if they are already installed",
102+
)
79103
parser.add_argument(
80104
"packages",
81105
nargs="*",
@@ -87,21 +111,25 @@ def _get_parser() -> ArgumentParser:
87111
return parser
88112

89113

90-
async def get_transformed_code(argv: list[str]) -> typing.Optional[str]:
114+
async def get_transformed_code(argv: list[str]) -> str | None:
91115
"""Return a string of code for use in in-kernel execution."""
92116
action, kwargs = await get_action_kwargs(argv)
117+
code_str: str = "\n"
93118

94119
if action == "help":
95120
pass
121+
96122
if action == "install":
97123
if kwargs["requirements"]:
98-
return f"""await __import__("piplite").install(**{kwargs})\n"""
124+
code_str = f"""await __import__("piplite").install(**{kwargs})\n"""
99125
else:
100126
warn("piplite needs at least one package to install")
101127

128+
return code_str
102129

103-
async def get_action_kwargs(argv: list[str]) -> tuple[typing.Optional[str], dict]:
104-
"""Get the arguments to `piplite` subcommands from CLI-like tokens."""
130+
131+
async def get_action_kwargs(argv: list[str]) -> tuple[str | None, dict[str, Any]]:
132+
"""Get the arguments to ``piplite`` subcommands from CLI-like tokens."""
105133

106134
parser = _get_parser()
107135

@@ -126,51 +154,54 @@ async def get_action_kwargs(argv: list[str]) -> tuple[typing.Optional[str], dict
126154
if args.verbose:
127155
kwargs["keep_going"] = True
128156

157+
if args.reinstall:
158+
kwargs["reinstall"] = True
159+
129160
for req_file in args.requirements or []:
130-
kwargs["requirements"] += await _packages_from_requirements_file(
131-
Path(req_file)
132-
)
161+
async for spec in _specs_from_requirements_file(Path(req_file)):
162+
kwargs["requirements"] += [spec]
133163

134-
return action, kwargs
164+
for const_file in args.constraints or []:
165+
async for spec in _specs_from_requirements_file(Path(const_file)):
166+
kwargs["constraints"] += [spec]
135167

168+
return action, kwargs
136169

137-
async def _packages_from_requirements_file(req_path: Path) -> list[str]:
138-
"""Extract (potentially nested) package requirements from a requirements file."""
139-
if not req_path.exists():
140-
warn(f"piplite could not find requirements file {req_path}")
141-
return []
142170

143-
requirements = []
171+
async def _specs_from_requirements_file(spec_path: Path) -> AsyncIterator[str]:
172+
"""Extract package specs from a ``requirements.txt``-style file."""
173+
if not spec_path.exists():
174+
warn(f"piplite could not find requirements file {spec_path}")
175+
return
144176

145-
for line_no, line in enumerate(req_path.read_text(encoding="utf").splitlines()):
146-
requirements += await _packages_from_requirements_line(
147-
req_path, line_no + 1, line
148-
)
177+
for line_no, line in enumerate(spec_path.read_text(encoding="utf").splitlines()):
178+
async for spec in _specs_from_requirements_line(spec_path, line_no + 1, line):
179+
yield spec
149180

150-
return requirements
151181

182+
async def _specs_from_requirements_line(
183+
spec_path: Path, line_no: int, line: str
184+
) -> AsyncIterator[str]:
185+
"""Get package specs from a line of a ``requirements.txt``-style file.
152186
153-
async def _packages_from_requirements_line(
154-
req_path: Path, line_no: int, line: str
155-
) -> list[str]:
156-
"""Extract (potentially nested) package requirements from line of a
157-
requirements file.
187+
``micropip`` has a sufficient pep508 implementation to handle most cases.
158188
159-
`micropip` has a sufficient pep508 implementation to handle most cases
189+
References to other, local files with ``-r`` are supported.
160190
"""
161-
req = line.strip().split("#")[0].strip()
162-
# is it another requirement file?
163-
req_file_match = re.match(REQ_FILE_PREFIX, req)
164-
if req_file_match:
165-
if req_file_match[2].startswith("/"):
166-
sub_req = Path(req)
167-
else:
168-
sub_req = req_path.parent / req_file_match[2]
169-
return await _packages_from_requirements_file(sub_req)
170-
171-
if req.startswith("-"):
172-
warn(f"{req_path}:{line_no}: unrecognized requirement: {req}")
173-
req = None
174-
if not req:
175-
return []
176-
return [req]
191+
raw = line.strip().split("#")[0].strip()
192+
# is it another spec file?
193+
file_match = re.match(REQ_FILE_SPEC, raw)
194+
195+
if file_match:
196+
ref = file_match.groupdict()["path_ref"]
197+
ref_path = Path(ref if ref.startswith("/") else spec_path.parent / ref)
198+
async for sub_spec in _specs_from_requirements_file(ref_path):
199+
yield sub_spec
200+
elif raw.startswith("-"):
201+
warn(f"{spec_path}:{line_no}: unrecognized spec: {raw}")
202+
return
203+
else:
204+
spec = raw
205+
206+
if spec:
207+
yield spec

0 commit comments

Comments
 (0)