|
2 | 2 | from pathlib import Path
|
3 | 3 | from typing import Literal
|
4 | 4 |
|
5 |
| -from pydantic import BaseModel, Extra |
| 5 | +from pydantic import BaseModel, Extra, Field |
6 | 6 |
|
7 | 7 | from .utils import (
|
| 8 | + _add_required, |
8 | 9 | _generate_package_hash,
|
9 | 10 | _wheel_depends,
|
10 | 11 | parse_top_level_import_name,
|
11 | 12 | )
|
12 | 13 |
|
13 | 14 |
|
14 | 15 | class InfoSpec(BaseModel):
|
15 |
| - arch: Literal["wasm32", "wasm64"] = "wasm32" |
16 |
| - platform: str |
17 |
| - version: str |
18 |
| - python: str |
| 16 | + arch: Literal["wasm32", "wasm64"] = Field( |
| 17 | + default="wasm32", |
| 18 | + description=( |
| 19 | + "the short name for the compiled architecture, available in " |
| 20 | + "dependency markers as `platform_machine`" |
| 21 | + ), |
| 22 | + ) |
| 23 | + platform: str = Field( |
| 24 | + description=( |
| 25 | + "the emscripten virtual machine for which this distribution is " |
| 26 | + " compiled, not available directly in a dependency marker: use e.g. " |
| 27 | + """`plaform_system == "Emscripten" and platform_release == "3.1.45"`""" |
| 28 | + ), |
| 29 | + examples=["emscripten_3_1_32", "emscripten_3_1_45"], |
| 30 | + ) |
| 31 | + version: str = Field( |
| 32 | + description="the PEP 440 version of pyodide", |
| 33 | + examples=["0.24.1", "0.23.3"], |
| 34 | + ) |
| 35 | + python: str = Field( |
| 36 | + description=( |
| 37 | + "the version of python for which this lockfile is valid, available in " |
| 38 | + "version markers as `platform_machine`" |
| 39 | + ), |
| 40 | + examples=["3.11.2", "3.11.3"], |
| 41 | + ) |
19 | 42 |
|
20 | 43 | class Config:
|
21 | 44 | extra = Extra.forbid
|
22 | 45 |
|
| 46 | + schema_extra = _add_required( |
| 47 | + "arch", |
| 48 | + description=( |
| 49 | + "the execution environment in which the packages in this lockfile " |
| 50 | + "can be installed" |
| 51 | + ), |
| 52 | + ) |
| 53 | + |
23 | 54 |
|
24 | 55 | class PackageSpec(BaseModel):
|
25 |
| - name: str |
26 |
| - version: str |
27 |
| - file_name: str |
28 |
| - install_dir: str |
29 |
| - sha256: str = "" |
| 56 | + name: str = Field( |
| 57 | + description="the verbatim name as found in the package's metadata", |
| 58 | + examples=["pyodide-lock", "PyYAML", "ruamel.yaml"], |
| 59 | + ) |
| 60 | + version: str = Field( |
| 61 | + description="the reported version of the package", |
| 62 | + examples=["0.1.0", "1.0.0a0", "1.0.0a0.post1"], |
| 63 | + ) |
| 64 | + file_name: str = Field( |
| 65 | + format="uri-reference", |
| 66 | + description="the URL of the file", |
| 67 | + examples=[ |
| 68 | + "pyodide_lock-0.1.0-py3-none-any.whl", |
| 69 | + "https://files.pythonhosted.org/packages/py3/m/micropip/micropip-0.5.0-py3-none-any.whl", |
| 70 | + ], |
| 71 | + ) |
| 72 | + install_dir: str = Field( |
| 73 | + default="site", |
| 74 | + description="the file system destination for a package's data", |
| 75 | + examples=["dynlib", "stdlib"], |
| 76 | + ) |
| 77 | + sha256: str = Field(description="the SHA256 cryptographic hash of the file") |
30 | 78 | package_type: Literal[
|
31 | 79 | "package", "cpython_module", "shared_library", "static_library"
|
32 |
| - ] = "package" |
33 |
| - imports: list[str] = [] |
34 |
| - depends: list[str] = [] |
35 |
| - unvendored_tests: bool = False |
| 80 | + ] = Field( |
| 81 | + default="package", |
| 82 | + description="the top-level kind of content provided by this package", |
| 83 | + ) |
| 84 | + imports: list[str] = Field( |
| 85 | + default=[], |
| 86 | + description=( |
| 87 | + "the importable names provided by this package." |
| 88 | + "note that PEP 420 namespace packages will likely not be correctly found." |
| 89 | + ), |
| 90 | + ) |
| 91 | + depends: list[str] = Field( |
| 92 | + default=[], |
| 93 | + unique_items=True, |
| 94 | + description=( |
| 95 | + "package names that must be installed when this package in installed" |
| 96 | + ), |
| 97 | + ) |
| 98 | + unvendored_tests: bool = Field( |
| 99 | + default=False, |
| 100 | + description=( |
| 101 | + "whether the package's tests folder have been repackaged " |
| 102 | + "as a separate archive" |
| 103 | + ), |
| 104 | + ) |
36 | 105 | # This field is deprecated
|
37 |
| - shared_library: bool = False |
| 106 | + shared_library: bool = Field( |
| 107 | + default=False, |
| 108 | + deprecated=True, |
| 109 | + description=( |
| 110 | + "(deprecated) whether this package is a shared library. " |
| 111 | + "replaced with `package_type: shared_library`" |
| 112 | + ), |
| 113 | + ) |
38 | 114 |
|
39 | 115 | class Config:
|
40 | 116 | extra = Extra.forbid
|
| 117 | + schema_extra = _add_required( |
| 118 | + "depends", |
| 119 | + "imports", |
| 120 | + "install_dir", |
| 121 | + description="a single pyodide-compatible file", |
| 122 | + ) |
41 | 123 |
|
42 | 124 | @classmethod
|
43 | 125 | def from_wheel(
|
@@ -78,11 +160,27 @@ def update_sha256(self, path: Path) -> "PackageSpec":
|
78 | 160 | class PyodideLockSpec(BaseModel):
|
79 | 161 | """A specification for the pyodide-lock.json file."""
|
80 | 162 |
|
81 |
| - info: InfoSpec |
82 |
| - packages: dict[str, PackageSpec] |
| 163 | + info: InfoSpec = Field( |
| 164 | + description=( |
| 165 | + "the execution environment in which the packages in this lockfile " |
| 166 | + "can be installable" |
| 167 | + ) |
| 168 | + ) |
| 169 | + packages: dict[str, PackageSpec] = Field( |
| 170 | + default={}, |
| 171 | + description="a set of packages keyed by name", |
| 172 | + ) |
83 | 173 |
|
84 | 174 | class Config:
|
85 | 175 | extra = Extra.forbid
|
| 176 | + schema_extra = { |
| 177 | + "$schema": "https://json-schema.org/draft/2019-09/schema#", |
| 178 | + "$id": ("https://pyodide.org/schema/pyodide-lock/v0-lockfile.schema.json"), |
| 179 | + "description": ( |
| 180 | + "a description of a viable pyodide runtime environment, " |
| 181 | + "as defined by pyodide-lock" |
| 182 | + ), |
| 183 | + } |
86 | 184 |
|
87 | 185 | @classmethod
|
88 | 186 | def from_json(cls, path: Path) -> "PyodideLockSpec":
|
|
0 commit comments