Skip to content

Commit 6df90d7

Browse files
committed
Using Pyodide lockFileURL + packages when a cache exists
1 parent f8ffc38 commit 6df90d7

File tree

6 files changed

+131
-87
lines changed

6 files changed

+131
-87
lines changed

docs/index.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/index.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

esm/interpreter/pyodide.js

+42-8
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import { create } from 'gc-hook';
33
import { RUNNING_IN_WORKER, createProgress, writeFile } from './_utils.js';
44
import { getFormat, loader, loadProgress, registerJSModule, run, runAsync, runEvent } from './_python.js';
55
import { stdio } from './_io.js';
6-
import { isArray } from '../utils.js';
6+
import { IDBMapSync, isArray } from '../utils.js';
77

88
const type = 'pyodide';
99
const toJsOptions = { dict_converter: Object.fromEntries };
1010

11+
const { stringify } = JSON;
12+
13+
// REQUIRES INTEGRATION TEST
1114
/* c8 ignore start */
1215
let overrideFunction = false;
1316
const overrideMethod = method => (...args) => {
@@ -75,10 +78,7 @@ const applyOverride = () => {
7578
};
7679

7780
const progress = createProgress('py');
78-
/* c8 ignore stop */
7981

80-
// REQUIRES INTEGRATION TEST
81-
/* c8 ignore start */
8282
export default {
8383
type,
8484
module: (version = '0.26.2') =>
@@ -88,15 +88,45 @@ export default {
8888
if (!RUNNING_IN_WORKER && config.experimental_create_proxy === 'auto')
8989
applyOverride();
9090
progress('Loading Pyodide');
91-
const { stderr, stdout, get } = stdio();
91+
let { packages } = config;
92+
progress('Loading Storage');
9293
const indexURL = url.slice(0, url.lastIndexOf('/'));
94+
// each pyodide version shares its own cache
95+
const storage = new IDBMapSync(indexURL);
96+
const options = { indexURL };
97+
const save = config.packages_cache !== 'never';
98+
await storage.sync();
99+
// packages_cache = 'never' means: erase the whole DB
100+
if (!save) storage.clear();
101+
// otherwise check if cache is known
102+
else if (packages) {
103+
packages = packages.slice(0).sort();
104+
// packages are uniquely stored as JSON key
105+
const key = stringify(packages);
106+
if (storage.has(key)) {
107+
const blob = new Blob(
108+
[storage.get(key)],
109+
{ type: 'application/json' },
110+
);
111+
// this should be used to bootstrap loadPyodide
112+
options.lockFileURL = URL.createObjectURL(blob);
113+
// no need to use micropip manually here
114+
options.packages = packages;
115+
packages = null;
116+
}
117+
}
118+
progress('Loaded Storage');
119+
const { stderr, stdout, get } = stdio();
93120
const interpreter = await get(
94-
loadPyodide({ stderr, stdout, indexURL }),
121+
loadPyodide({ stderr, stdout, ...options }),
95122
);
96123
const py_imports = importPackages.bind(interpreter);
97124
loader.set(interpreter, py_imports);
98125
await loadProgress(this, progress, interpreter, config, baseURL);
99-
if (config.packages) await py_imports(config.packages);
126+
// if cache wasn't know, import and freeze it for the next time
127+
if (packages) await py_imports(packages, storage, save);
128+
await storage.close();
129+
if (options.lockFileURL) URL.revokeObjectURL(options.lockFileURL);
100130
progress('Loaded Pyodide');
101131
return interpreter;
102132
},
@@ -130,7 +160,7 @@ function transform(value) {
130160
}
131161

132162
// exposed utility to import packages via polyscript.lazy_py_modules
133-
async function importPackages(packages) {
163+
async function importPackages(packages, storage, save = false) {
134164
// temporary patch/fix console.log which is used
135165
// not only by Pyodide but by micropip too and there's
136166
// no way to intercept those calls otherwise
@@ -146,6 +176,10 @@ async function importPackages(packages) {
146176
const micropip = this.pyimport('micropip');
147177
await micropip.install(packages, { keep_going: true });
148178
console.log = log;
179+
if (save && (storage instanceof IDBMapSync)) {
180+
const frozen = micropip.freeze();
181+
storage.set(stringify(packages), frozen);
182+
}
149183
micropip.destroy();
150184
}
151185
/* c8 ignore stop */

package-lock.json

+72-72
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)