universal-wasm-loader 2.0.1__tar.gz → 2.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/PKG-INFO +1 -1
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/pyproject.toml +1 -1
- universal_wasm_loader-2.0.2/tests/test_github_release.py +164 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/.gitignore +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/LICENSE +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/README.md +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/src/universal_wasm_loader/__init__.py +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/src/universal_wasm_loader/_abi.py +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/src/universal_wasm_loader/_loader.py +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/src/universal_wasm_loader/_wit_parser.py +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/__init__.py +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/conftest.py +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/booleans_50.wasm +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/booleans_50.wit +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/fixtures.json +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/imports_50.wasm +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/imports_50.wit +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/init_check.wasm +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/init_check.wat +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/math_50.wasm +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/math_50.wit +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/strings_50.wasm +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/strings_50.wit +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/wasi_io_50.wasm +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/fixtures/wasi_io_50.wit +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/py_fixtures/versioned.wat +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/test_fixtures.py +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/test_loader.py +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/test_pypi_files.py +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/test_refusals.py +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/test_release_script.py +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/tests/test_wit_parser.py +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/LICENSE +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/README.md +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/booleans_50.wasm +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/booleans_50.wit +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/fixtures.json +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/imports_50.wasm +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/imports_50.wit +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/init_check.wasm +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/init_check.wat +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/loader.test.js +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/math_50.wasm +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/math_50.wit +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/strings_50.wasm +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/strings_50.wit +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/wasi_io_50.wasm +0 -0
- {universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/tests/wasi_io_50.wit +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: universal-wasm-loader
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: Universal WASM loader for Python
|
|
5
5
|
Project-URL: Homepage, https://github.com/synapticforge1/universalWasmLoader-py
|
|
6
6
|
Project-URL: Repository, https://github.com/synapticforge1/universalWasmLoader-py
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""scripts/github_release.py against an in-process mock of GitHub's REST API (no network)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import importlib.util
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
import threading
|
|
8
|
+
from collections.abc import Iterator
|
|
9
|
+
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from types import ModuleType
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
import pytest
|
|
15
|
+
|
|
16
|
+
SCRIPT = Path(__file__).parent.parent / "scripts" / "github_release.py"
|
|
17
|
+
REPO, TAG, SHA, OTHER = "o/r", "v2.0.2", "a" * 40, "b" * 40
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _load() -> ModuleType:
|
|
21
|
+
spec = importlib.util.spec_from_file_location("github_release", SCRIPT)
|
|
22
|
+
assert spec is not None and spec.loader is not None
|
|
23
|
+
mod = importlib.util.module_from_spec(spec)
|
|
24
|
+
sys.modules["github_release"] = mod
|
|
25
|
+
spec.loader.exec_module(mod)
|
|
26
|
+
return mod
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
gr = _load()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Mock:
|
|
33
|
+
"""GitHub state + a log of (method, path, auth, body)."""
|
|
34
|
+
|
|
35
|
+
def __init__(self) -> None:
|
|
36
|
+
self.tags: dict[str, dict[str, str]] = {} # tag -> ref object
|
|
37
|
+
self.tag_objects: dict[str, dict[str, str]] = {} # annotated tag sha -> object
|
|
38
|
+
self.releases: dict[str, dict[str, Any]] = {}
|
|
39
|
+
self.log: list[tuple[str, str, str | None, Any]] = []
|
|
40
|
+
self.post_status = 201
|
|
41
|
+
|
|
42
|
+
def writes(self) -> list[tuple[str, str, str | None, Any]]:
|
|
43
|
+
return [e for e in self.log if e[0] != "GET"]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@pytest.fixture
|
|
47
|
+
def mock() -> Iterator[tuple[Mock, str]]:
|
|
48
|
+
state = Mock()
|
|
49
|
+
|
|
50
|
+
class Handler(BaseHTTPRequestHandler):
|
|
51
|
+
def log_message(self, *_: Any) -> None:
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
def _send(self, code: int, doc: Any = None) -> None:
|
|
55
|
+
raw = b"" if doc is None else json.dumps(doc).encode()
|
|
56
|
+
self.send_response(code)
|
|
57
|
+
self.send_header("Content-Type", "application/json")
|
|
58
|
+
self.send_header("Content-Length", str(len(raw)))
|
|
59
|
+
self.end_headers()
|
|
60
|
+
self.wfile.write(raw)
|
|
61
|
+
|
|
62
|
+
def do_GET(self) -> None: # noqa: N802
|
|
63
|
+
state.log.append(("GET", self.path, self.headers.get("Authorization"), None))
|
|
64
|
+
p = self.path
|
|
65
|
+
if p.startswith(f"/repos/{REPO}/git/ref/tags/"):
|
|
66
|
+
obj = state.tags.get(p.rsplit("/", 1)[1])
|
|
67
|
+
return self._send(200, {"object": obj}) if obj else self._send(404)
|
|
68
|
+
if p.startswith(f"/repos/{REPO}/git/tags/"):
|
|
69
|
+
obj = state.tag_objects.get(p.rsplit("/", 1)[1])
|
|
70
|
+
return self._send(200, {"object": obj}) if obj else self._send(404)
|
|
71
|
+
if p.startswith(f"/repos/{REPO}/releases/tags/"):
|
|
72
|
+
rel = state.releases.get(p.rsplit("/", 1)[1])
|
|
73
|
+
return self._send(200, rel) if rel else self._send(404)
|
|
74
|
+
self._send(404)
|
|
75
|
+
|
|
76
|
+
def do_POST(self) -> None: # noqa: N802
|
|
77
|
+
body = json.loads(self.rfile.read(int(self.headers["Content-Length"])))
|
|
78
|
+
state.log.append(("POST", self.path, self.headers.get("Authorization"), body))
|
|
79
|
+
if self.path != f"/repos/{REPO}/releases" or state.post_status != 201:
|
|
80
|
+
return self._send(state.post_status, {"message": "nope"})
|
|
81
|
+
rel = {"id": 7, "tag_name": body["tag_name"], "draft": False,
|
|
82
|
+
"html_url": f"https://example.invalid/{body['tag_name']}"}
|
|
83
|
+
state.releases[body["tag_name"]] = rel
|
|
84
|
+
self._send(201, rel)
|
|
85
|
+
|
|
86
|
+
server = HTTPServer(("127.0.0.1", 0), Handler)
|
|
87
|
+
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
|
88
|
+
thread.start()
|
|
89
|
+
try:
|
|
90
|
+
yield state, f"http://127.0.0.1:{server.server_port}"
|
|
91
|
+
finally:
|
|
92
|
+
server.shutdown()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _run(base: str, token: str | None = "t0k", dry: bool = False, tag: str = TAG) -> int:
|
|
96
|
+
return int(gr.run(REPO, tag, SHA, dry, gr.Api(base, token)))
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_creates_the_release_then_reads_it_back(mock: tuple[Mock, str]) -> None:
|
|
100
|
+
state, base = mock
|
|
101
|
+
state.tags[TAG] = {"type": "commit", "sha": SHA}
|
|
102
|
+
assert _run(base) == 0
|
|
103
|
+
(method, path, auth, body), = state.writes()
|
|
104
|
+
assert (method, path, auth) == ("POST", f"/repos/{REPO}/releases", "Bearer t0k")
|
|
105
|
+
assert body["tag_name"] == TAG and body["generate_release_notes"] is True
|
|
106
|
+
assert "target_commitish" not in body # the tag already exists; nothing to target
|
|
107
|
+
assert "pypi.org/project/universal-wasm-loader/2.0.2/" in body["body"]
|
|
108
|
+
assert state.log[-2][1].endswith(f"/releases/tags/{TAG}") # read back after the POST
|
|
109
|
+
assert state.log[-1][1].endswith(f"/git/ref/tags/{TAG}") # tag re-checked last
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_rerun_is_safe_existing_release_means_done(mock: tuple[Mock, str]) -> None:
|
|
113
|
+
state, base = mock
|
|
114
|
+
state.tags[TAG] = {"type": "commit", "sha": SHA}
|
|
115
|
+
state.releases[TAG] = {"tag_name": TAG, "draft": False, "html_url": "x"}
|
|
116
|
+
assert _run(base) == 0
|
|
117
|
+
assert state.writes() == []
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_annotated_tag_is_peeled(mock: tuple[Mock, str]) -> None:
|
|
121
|
+
state, base = mock
|
|
122
|
+
state.tags[TAG] = {"type": "tag", "sha": "c" * 40}
|
|
123
|
+
state.tag_objects["c" * 40] = {"type": "commit", "sha": SHA}
|
|
124
|
+
assert _run(base) == 0
|
|
125
|
+
assert len(state.writes()) == 1
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@pytest.mark.parametrize("case", ["missing tag", "moved tag", "annotated tag moved"])
|
|
129
|
+
def test_refuses_with_no_write(mock: tuple[Mock, str], case: str) -> None:
|
|
130
|
+
state, base = mock
|
|
131
|
+
if case == "moved tag":
|
|
132
|
+
state.tags[TAG] = {"type": "commit", "sha": OTHER}
|
|
133
|
+
elif case == "annotated tag moved":
|
|
134
|
+
state.tags[TAG] = {"type": "tag", "sha": "c" * 40}
|
|
135
|
+
state.tag_objects["c" * 40] = {"type": "commit", "sha": OTHER}
|
|
136
|
+
assert _run(base) == 1
|
|
137
|
+
assert state.writes() == []
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def test_dry_run_and_no_token_send_no_write(mock: tuple[Mock, str]) -> None:
|
|
141
|
+
state, base = mock
|
|
142
|
+
state.tags[TAG] = {"type": "commit", "sha": SHA}
|
|
143
|
+
assert _run(base, dry=True) == 0
|
|
144
|
+
assert _run(base, token=None) == 1
|
|
145
|
+
assert state.writes() == []
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def test_a_failed_post_is_a_failure(
|
|
149
|
+
mock: tuple[Mock, str], monkeypatch: pytest.MonkeyPatch
|
|
150
|
+
) -> None:
|
|
151
|
+
state, base = mock
|
|
152
|
+
state.tags[TAG] = {"type": "commit", "sha": SHA}
|
|
153
|
+
state.post_status = 422
|
|
154
|
+
with pytest.raises(gr.ApiError, match="HTTP 422"):
|
|
155
|
+
_run(base)
|
|
156
|
+
monkeypatch.setenv("GITHUB_API_URL", base) # main() must hit the mock, never GitHub
|
|
157
|
+
monkeypatch.setenv("GITHUB_TOKEN", "t0k")
|
|
158
|
+
assert gr.main(["--repo", REPO, "--tag", TAG, "--sha", SHA]) == 1 # ApiError -> exit 1
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def test_malformed_tag_sends_no_request(mock: tuple[Mock, str]) -> None:
|
|
162
|
+
state, base = mock
|
|
163
|
+
assert _run(base, tag="main") == 1
|
|
164
|
+
assert state.log == []
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/src/universal_wasm_loader/__init__.py
RENAMED
|
File without changes
|
{universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/src/universal_wasm_loader/_abi.py
RENAMED
|
File without changes
|
{universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/src/universal_wasm_loader/_loader.py
RENAMED
|
File without changes
|
{universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/src/universal_wasm_loader/_wit_parser.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{universal_wasm_loader-2.0.1 → universal_wasm_loader-2.0.2}/upstream/universalwasmloader-js/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|