Skip to content

Commit 8c3cf4a

Browse files
Merge pull request #105 from pyscript/storage
Added a storage utility
2 parents a1b57c7 + 0b43495 commit 8c3cf4a

File tree

15 files changed

+122
-12
lines changed

15 files changed

+122
-12
lines changed

.eslintrc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
},
66
"extends": "eslint:recommended",
77
"parserOptions": {
8-
"ecmaVersion": 12,
8+
"ecmaVersion": "latest",
99
"sourceType": "module"
1010
},
1111
"ignorePatterns": ["__template.js", "xworker.js", "esm/python/*.js", "esm/3rd-party/*"],

docs/README.md

+21
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ The module is registered within the interpreter as *JS* module and it offers var
379379
| currentScript | `from polyscript import currentScript` | it's an explicit, always correct, reference to the current node running the generic script code. |
380380
| js_modules | `from polyscript import js_modules` | described in the [Extra config Features](#extra-config-features) part. |
381381
| lazy_py_modules | `from polyscript import lazy_py_modules` | allows, only in *Python* related interpreters, and without needing static config entries, to import lazily any available module.
382+
| storage | `from polyscript import storage` | a utility to instantiate a named [idb-map](https://github.com/WebReflection/idb-map/#readme) that can be consumed synchronously.
382383
383384
384385
#### lazy_py_modules
@@ -393,6 +394,26 @@ The module is registered within the interpreter as *JS* module and it offers var
393394
</script>
394395
```
395396
397+
#### storage
398+
399+
```html
400+
<script type="micropython" async>
401+
from polyscript import storage
402+
403+
# await its loading
404+
map = await storage("my-user-persistent-storage")
405+
406+
# just use it synchronously
407+
map.set("key", "value")
408+
print(map.get("key"))
409+
410+
# after set, delete, or clear
411+
# it is possible to sync operations
412+
await map.sync()
413+
</script>
414+
```
415+
416+
396417
397418
### Worker exports
398419

docs/index.js

+2-2
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/_python.js

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { dedent } from '../utils.js';
22
import { io } from './_io.js';
3+
import Storage from '../storage.js';
34

45
export const loader = new WeakMap();
56

@@ -11,6 +12,11 @@ export const registerJSModule = (interpreter, name, value) => {
1112
await loader.get(interpreter)(packages);
1213
return packages.map(name => interpreter.pyimport(name));
1314
};
15+
value.storage = async (name) => {
16+
const storage = new Storage(name);
17+
await storage.sync();
18+
return storage;
19+
};
1420
}
1521
interpreter.registerJsModule(name, value);
1622
};

esm/interpreter/micropython.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const mkdir = (FS, path) => {
2323

2424
export default {
2525
type,
26-
module: (version = '1.23.0') =>
26+
module: (version = '1.24.0-preview-44') =>
2727
`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${version}/micropython.mjs`,
2828
async engine({ loadMicroPython }, config, url, baseURL) {
2929
const { stderr, stdout, get } = stdio({

esm/storage.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import IDBMap from '@webreflection/idb-map';
2+
3+
export default class Storage extends Map {
4+
#map;
5+
#queue;
6+
constructor(name) {
7+
super();
8+
this.#map = new IDBMap(name);
9+
this.#queue = this.#map.entries().then(entries => {
10+
for (const [key, value] of entries)
11+
this.set(key, value);
12+
});
13+
}
14+
async sync() {
15+
await this.#queue;
16+
}
17+
clear() {
18+
this.#queue = this.#queue.then(() => this.#map.clear());
19+
return super.clear();
20+
}
21+
delete(key) {
22+
this.#queue = this.#queue.then(() => this.#map.delete(key));
23+
return super.delete(key);
24+
}
25+
set(key, value) {
26+
this.#queue = this.#queue.then(() => this.#map.set(key, value));
27+
return super.set(key, value);
28+
}
29+
}

node.importmap

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"imports": {
33
"http://pyodide": "./test/mocked/pyodide.mjs",
44
"https://cdn.jsdelivr.net/pyodide/v0.26.1/full/pyodide.mjs": "./test/mocked/pyodide.mjs",
5-
"https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@1.23.0/micropython.mjs": "./test/mocked/micropython.mjs",
5+
"https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@1.24.0-preview-44/micropython.mjs": "./test/mocked/micropython.mjs",
66
"./3rd-party/toml.js": "./test/mocked/toml.mjs"
77
}
88
}

package-lock.json

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

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "polyscript",
3-
"version": "0.12.15",
3+
"version": "0.13.1",
44
"description": "PyScript single core to rule them all",
55
"main": "./cjs/index.js",
66
"types": "./types/polyscript/esm/index.d.ts",
@@ -80,6 +80,7 @@
8080
"@ungap/structured-clone": "^1.2.0",
8181
"@ungap/with-resolvers": "^0.1.0",
8282
"@webreflection/fetch": "^0.1.5",
83+
"@webreflection/idb-map": "^0.2.0",
8384
"basic-devtools": "^0.1.6",
8485
"codedent": "^0.1.2",
8586
"coincident": "^1.2.3",
@@ -90,6 +91,6 @@
9091
"to-json-callback": "^0.1.1"
9192
},
9293
"worker": {
93-
"blob": "sha256-pWERQSHp3qDvCx7LVz9I3QMz9+k3IwDLVMixPMRxxI4="
94+
"blob": "sha256-QYGr9ma1eAghLgOKOxC9Tz8PvKkbO4gurbzJ1bac/xM="
9495
}
9596
}

test/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const patchFetch = (callback) => {
2929
const { parseHTML } = require("linkedom");
3030
const { document, window, CustomEvent } = parseHTML("...");
3131

32+
globalThis.indexedDB = { open: () => ({}) };
3233
globalThis.document = document;
3334
globalThis.Element = window.Element;
3435
globalThis.CustomEvent = CustomEvent;

test/integration.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<title>polyscript integration tests</title>
77
</head>
8-
<body><ul><li><strong>micropython</strong><ul><li><a href="/test/integration/interpreter/micropython/bootstrap.html">bootstrap</a></li><li><a href="/test/integration/interpreter/micropython/config-json.html">config-json</a></li><li><a href="/test/integration/interpreter/micropython/config-object.html">config-object</a></li><li><a href="/test/integration/interpreter/micropython/current-script.html">current-script</a></li><li><a href="/test/integration/interpreter/micropython/custom-hooks.html">custom-hooks</a></li><li><a href="/test/integration/interpreter/micropython/fetch.html">fetch</a></li><li><a href="/test/integration/interpreter/micropython/interpreter-local.html">interpreter-local</a></li><li><a href="/test/integration/interpreter/micropython/mip.html">mip</a></li><li><a href="/test/integration/interpreter/micropython/no-type.html">no-type</a></li><li><a href="/test/integration/interpreter/micropython/ready-done.html">ready-done</a></li><li><a href="/test/integration/interpreter/micropython/worker-attribute.html">worker-attribute</a></li><li><a href="/test/integration/interpreter/micropython/worker-bad.html">worker-bad</a></li><li><a href="/test/integration/interpreter/micropython/worker-empty-attribute.html">worker-empty-attribute</a></li><li><a href="/test/integration/interpreter/micropython/worker-error.html">worker-error</a></li><li><a href="/test/integration/interpreter/micropython/worker-lua.html">worker-lua</a></li><li><a href="/test/integration/interpreter/micropython/worker-tag.html">worker-tag</a></li><li><a href="/test/integration/interpreter/micropython/worker-window.html">worker-window</a></li><li><a href="/test/integration/interpreter/micropython/worker.html">worker</a></li></ul><li><strong>pyodide</strong><ul><li><a href="/test/integration/interpreter/pyodide/bootstrap.html">bootstrap</a></li><li><a href="/test/integration/interpreter/pyodide/button.html">button</a></li><li><a href="/test/integration/interpreter/pyodide/config-json.html">config-json</a></li><li><a href="/test/integration/interpreter/pyodide/fetch.html">fetch</a></li><li><a href="/test/integration/interpreter/pyodide/sync.html">sync</a></li><li><a href="/test/integration/interpreter/pyodide/worker-error.html">worker-error</a></li><li><a href="/test/integration/interpreter/pyodide/worker-transform.html">worker-transform</a></li><li><a href="/test/integration/interpreter/pyodide/worker.html">worker</a></li></ul><li><strong>ruby-wasm-wasi</strong><ul><li><a href="/test/integration/interpreter/ruby-wasm-wasi/bootstrap.html">bootstrap</a></li></ul><li><strong>wasmoon</strong><ul><li><a href="/test/integration/interpreter/wasmoon/bootstrap.html">bootstrap</a></li><li><a href="/test/integration/interpreter/wasmoon/worker.html">worker</a></li></ul><li><strong>webr</strong><ul><li><a href="/test/integration/interpreter/webr/just-click.html">just-click</a></li></ul></ul></body>
8+
<body><ul><li><strong>micropython</strong><ul><li><a href="/test/integration/interpreter/micropython/bootstrap.html">bootstrap</a></li><li><a href="/test/integration/interpreter/micropython/config-json.html">config-json</a></li><li><a href="/test/integration/interpreter/micropython/config-object.html">config-object</a></li><li><a href="/test/integration/interpreter/micropython/current-script.html">current-script</a></li><li><a href="/test/integration/interpreter/micropython/custom-hooks.html">custom-hooks</a></li><li><a href="/test/integration/interpreter/micropython/fetch.html">fetch</a></li><li><a href="/test/integration/interpreter/micropython/interpreter-local.html">interpreter-local</a></li><li><a href="/test/integration/interpreter/micropython/mip.html">mip</a></li><li><a href="/test/integration/interpreter/micropython/no-type.html">no-type</a></li><li><a href="/test/integration/interpreter/micropython/ready-done.html">ready-done</a></li><li><a href="/test/integration/interpreter/micropython/storage.html">storage</a></li><li><a href="/test/integration/interpreter/micropython/worker-attribute.html">worker-attribute</a></li><li><a href="/test/integration/interpreter/micropython/worker-bad.html">worker-bad</a></li><li><a href="/test/integration/interpreter/micropython/worker-empty-attribute.html">worker-empty-attribute</a></li><li><a href="/test/integration/interpreter/micropython/worker-error.html">worker-error</a></li><li><a href="/test/integration/interpreter/micropython/worker-lua.html">worker-lua</a></li><li><a href="/test/integration/interpreter/micropython/worker-tag.html">worker-tag</a></li><li><a href="/test/integration/interpreter/micropython/worker-window.html">worker-window</a></li><li><a href="/test/integration/interpreter/micropython/worker.html">worker</a></li></ul><li><strong>pyodide</strong><ul><li><a href="/test/integration/interpreter/pyodide/bootstrap.html">bootstrap</a></li><li><a href="/test/integration/interpreter/pyodide/button.html">button</a></li><li><a href="/test/integration/interpreter/pyodide/config-json.html">config-json</a></li><li><a href="/test/integration/interpreter/pyodide/fetch.html">fetch</a></li><li><a href="/test/integration/interpreter/pyodide/sync.html">sync</a></li><li><a href="/test/integration/interpreter/pyodide/worker-error.html">worker-error</a></li><li><a href="/test/integration/interpreter/pyodide/worker-transform.html">worker-transform</a></li><li><a href="/test/integration/interpreter/pyodide/worker.html">worker</a></li></ul><li><strong>ruby-wasm-wasi</strong><ul><li><a href="/test/integration/interpreter/ruby-wasm-wasi/bootstrap.html">bootstrap</a></li></ul><li><strong>wasmoon</strong><ul><li><a href="/test/integration/interpreter/wasmoon/bootstrap.html">bootstrap</a></li><li><a href="/test/integration/interpreter/wasmoon/worker.html">worker</a></li></ul><li><strong>webr</strong><ul><li><a href="/test/integration/interpreter/webr/just-click.html">just-click</a></li></ul></ul></body>
99
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<script type="module">
7+
import { init } from '../utils.js';
8+
init('micropython');
9+
</script>
10+
</head>
11+
<body>
12+
<script type="micropython" async>
13+
from polyscript import storage
14+
15+
store = await storage("@polyscript/storage")
16+
17+
# just a devtools console check
18+
# it is true on refresh
19+
print(store.get("main") == True, store.size)
20+
21+
store.set("main", True)
22+
23+
import js
24+
js.document.documentElement.classList.add(f"main")
25+
</script>
26+
<script type="micropython" worker async>
27+
from polyscript import xworker, storage
28+
29+
store = await storage("@polyscript/storage")
30+
31+
# just a devtools console check
32+
# it is true on refresh
33+
print(store.get("worker") == True, store.size)
34+
35+
store.set("worker", True)
36+
37+
xworker.window.document.documentElement.classList.add(f"worker")
38+
</script>
39+
</body>
40+
</html>

test/integration/micropython.js

+5
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,9 @@ module.exports = (playwright, baseURL) => {
5252
test('MicroPython local intepreter', python.localInterpreter(playwright, baseURL));
5353

5454
test('MicroPython mip', python.waitForDone(playwright, `${baseURL}/mip.html`));
55+
56+
test('MicroPython Storage', async ({ page }) => {
57+
await page.goto(`${baseURL}/storage.html`);
58+
await page.waitForSelector(`html.ready.main.worker`);
59+
});
5560
};

versions/micropython

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.23.0
1+
1.24.0-preview-44

0 commit comments

Comments
 (0)