@volter/browser-python 0.1.0

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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +14 -0
  3. package/dist/asgi-bridge.d.ts +3 -0
  4. package/dist/asgi-bridge.d.ts.map +1 -0
  5. package/dist/asgi-bridge.js +307 -0
  6. package/dist/asgi-bridge.js.map +1 -0
  7. package/dist/command.d.ts +20 -0
  8. package/dist/command.d.ts.map +1 -0
  9. package/dist/command.js +154 -0
  10. package/dist/command.js.map +1 -0
  11. package/dist/filesystem.d.ts +9 -0
  12. package/dist/filesystem.d.ts.map +1 -0
  13. package/dist/filesystem.js +96 -0
  14. package/dist/filesystem.js.map +1 -0
  15. package/dist/index.d.ts +4 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +3 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/package-manager.d.ts +8 -0
  20. package/dist/package-manager.d.ts.map +1 -0
  21. package/dist/package-manager.js +103 -0
  22. package/dist/package-manager.js.map +1 -0
  23. package/dist/process-host.d.ts +27 -0
  24. package/dist/process-host.d.ts.map +1 -0
  25. package/dist/process-host.js +326 -0
  26. package/dist/process-host.js.map +1 -0
  27. package/dist/protocol.d.ts +169 -0
  28. package/dist/protocol.d.ts.map +1 -0
  29. package/dist/protocol.js +2 -0
  30. package/dist/protocol.js.map +1 -0
  31. package/dist/pyodide-runtime.d.ts +37 -0
  32. package/dist/pyodide-runtime.d.ts.map +1 -0
  33. package/dist/pyodide-runtime.js +13 -0
  34. package/dist/pyodide-runtime.js.map +1 -0
  35. package/dist/server-host.d.ts +21 -0
  36. package/dist/server-host.d.ts.map +1 -0
  37. package/dist/server-host.js +526 -0
  38. package/dist/server-host.js.map +1 -0
  39. package/dist/sqlite-coherence.d.ts +19 -0
  40. package/dist/sqlite-coherence.d.ts.map +1 -0
  41. package/dist/sqlite-coherence.js +167 -0
  42. package/dist/sqlite-coherence.js.map +1 -0
  43. package/dist/subprocess-bridge.d.ts +12 -0
  44. package/dist/subprocess-bridge.d.ts.map +1 -0
  45. package/dist/subprocess-bridge.js +407 -0
  46. package/dist/subprocess-bridge.js.map +1 -0
  47. package/dist/worker.d.ts +2 -0
  48. package/dist/worker.d.ts.map +1 -0
  49. package/dist/worker.js +251 -0
  50. package/dist/worker.js.map +1 -0
  51. package/dist/wsgi-bridge.d.ts +21 -0
  52. package/dist/wsgi-bridge.d.ts.map +1 -0
  53. package/dist/wsgi-bridge.js +268 -0
  54. package/dist/wsgi-bridge.js.map +1 -0
  55. package/package.json +23 -0
@@ -0,0 +1,167 @@
1
+ import { BrowserFileCoherenceClient, coherentFileFamily, } from "@volter/browser-runtime/browser-file-coherence.js";
2
+ import { BrowserFileLockClient } from "@volter/browser-runtime/browser-file-locks.js";
3
+ /** Serializes unchanged CPython sqlite connections with every browser lane. */
4
+ export class PythonSqliteCoherence {
5
+ filesystem;
6
+ locks;
7
+ coherence;
8
+ counts = new Map();
9
+ owner;
10
+ constructor(filesystem, locks, coherence, ownerPrefix) {
11
+ this.filesystem = filesystem;
12
+ this.locks = locks;
13
+ this.coherence = coherence;
14
+ this.owner = `${ownerPrefix}:sqlite`;
15
+ }
16
+ install(pyodide) {
17
+ pyodide.globals.set("_browser_runtime_sqlite_acquire", (path) => this.acquire(path));
18
+ pyodide.globals.set("_browser_runtime_sqlite_release", (path) => this.release(path));
19
+ return pyodide.runPythonAsync(PYTHON_SQLITE_BOOTSTRAP);
20
+ }
21
+ releaseAll() {
22
+ for (const path of [...this.counts.keys()]) {
23
+ this.counts.set(path, 1);
24
+ this.release(path);
25
+ }
26
+ }
27
+ acquire(path) {
28
+ if (!path.startsWith("/") || path.includes("\0"))
29
+ throw new Error("Invalid SQLite path.");
30
+ const count = this.counts.get(path) ?? 0;
31
+ if (count > 0) {
32
+ this.counts.set(path, count + 1);
33
+ return;
34
+ }
35
+ const response = this.locks.request({
36
+ operation: "set",
37
+ owner: this.owner,
38
+ namespace: "posix",
39
+ path,
40
+ range: { start: 0 },
41
+ mode: "write",
42
+ pid: 1,
43
+ blocking: true,
44
+ });
45
+ if (response.result < 0)
46
+ throw new Error(`SQLite lock acquisition failed with ${response.result}.`);
47
+ try {
48
+ for (const member of coherentFileFamily(path))
49
+ this.writeLocal(member, this.coherence.pull(member));
50
+ this.counts.set(path, 1);
51
+ }
52
+ catch (error) {
53
+ this.locks.request({
54
+ operation: "unlock",
55
+ owner: this.owner,
56
+ namespace: "posix",
57
+ path,
58
+ range: { start: 0 },
59
+ });
60
+ throw error;
61
+ }
62
+ }
63
+ release(path) {
64
+ const count = this.counts.get(path) ?? 0;
65
+ if (count > 1) {
66
+ this.counts.set(path, count - 1);
67
+ return;
68
+ }
69
+ if (count === 0)
70
+ return;
71
+ for (const member of coherentFileFamily(path))
72
+ this.coherence.push(member, this.readLocal(member));
73
+ const response = this.locks.request({
74
+ operation: "unlock",
75
+ owner: this.owner,
76
+ namespace: "posix",
77
+ path,
78
+ range: { start: 0 },
79
+ });
80
+ if (response.result < 0)
81
+ throw new Error(`SQLite lock release failed with ${response.result}.`);
82
+ this.counts.delete(path);
83
+ }
84
+ readLocal(path) {
85
+ if (!this.filesystem.analyzePath(path).exists)
86
+ return;
87
+ const stat = this.filesystem.stat(path);
88
+ if ((stat.mode & 0o170000) === 0o040000)
89
+ return;
90
+ const mtimeMs = stat.mtime instanceof Date ? stat.mtime.getTime() : stat.mtime;
91
+ return {
92
+ bytes: this.filesystem.readFile(path),
93
+ mode: stat.mode & 0o7777,
94
+ ...(typeof mtimeMs === "number" && Number.isFinite(mtimeMs) ? { mtimeMs } : {}),
95
+ };
96
+ }
97
+ writeLocal(path, file) {
98
+ if (!file) {
99
+ if (this.filesystem.analyzePath(path).exists
100
+ && (this.filesystem.stat(path).mode & 0o170000) !== 0o040000)
101
+ this.filesystem.unlink(path);
102
+ return;
103
+ }
104
+ const parent = path.slice(0, path.lastIndexOf("/")) || "/";
105
+ if (!this.filesystem.analyzePath(parent).exists)
106
+ this.filesystem.mkdirTree(parent);
107
+ this.filesystem.writeFile(path, file.bytes);
108
+ if (file.mode !== undefined)
109
+ this.filesystem.chmod(path, file.mode);
110
+ if (file.mtimeMs !== undefined)
111
+ this.filesystem.utime(path, file.mtimeMs, file.mtimeMs);
112
+ }
113
+ }
114
+ const PYTHON_SQLITE_BOOTSTRAP = String.raw `
115
+ import os as _browser_runtime_sqlite_os, sqlite3 as _browser_runtime_sqlite
116
+
117
+ _browser_runtime_sqlite_connect_original = _browser_runtime_sqlite.connect
118
+
119
+ def _browser_runtime_sqlite_path(database, uri=False):
120
+ try:
121
+ value = _browser_runtime_sqlite_os.fspath(database)
122
+ except TypeError:
123
+ return None
124
+ if isinstance(value, bytes):
125
+ value = _browser_runtime_sqlite_os.fsdecode(value)
126
+ if value == ":memory:" or value.startswith("file::memory:"):
127
+ return None
128
+ if uri and value.startswith("file:"):
129
+ value = value[5:].split("?", 1)[0]
130
+ return _browser_runtime_sqlite_os.path.abspath(value)
131
+
132
+ class _BrowserRuntimeSqliteConnection(_browser_runtime_sqlite.Connection):
133
+ def __init__(self, *args, **kwargs):
134
+ database = args[0] if args else kwargs.get("database")
135
+ self._browser_runtime_path = _browser_runtime_sqlite_path(database, bool(kwargs.get("uri", False)))
136
+ self._browser_runtime_released = False
137
+ if self._browser_runtime_path:
138
+ _browser_runtime_sqlite_acquire(self._browser_runtime_path)
139
+ try:
140
+ super().__init__(*args, **kwargs)
141
+ except BaseException:
142
+ if self._browser_runtime_path:
143
+ _browser_runtime_sqlite_release(self._browser_runtime_path)
144
+ self._browser_runtime_released = True
145
+ raise
146
+
147
+ def close(self):
148
+ if self._browser_runtime_released:
149
+ return super().close()
150
+ try:
151
+ return super().close()
152
+ finally:
153
+ if self._browser_runtime_path:
154
+ _browser_runtime_sqlite_release(self._browser_runtime_path)
155
+ self._browser_runtime_released = True
156
+
157
+ def _browser_runtime_sqlite_connect(database, *args, **kwargs):
158
+ factory = kwargs.get("factory")
159
+ if factory is not None and factory is not _browser_runtime_sqlite.Connection:
160
+ raise NotImplementedError("custom sqlite connection factories are not yet supported by browser coherence")
161
+ kwargs["factory"] = _BrowserRuntimeSqliteConnection
162
+ return _browser_runtime_sqlite_connect_original(database, *args, **kwargs)
163
+
164
+ _browser_runtime_sqlite.connect = _browser_runtime_sqlite_connect
165
+ _browser_runtime_sqlite.dbapi2.connect = _browser_runtime_sqlite_connect
166
+ `;
167
+ //# sourceMappingURL=sqlite-coherence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-coherence.js","sourceRoot":"","sources":["../src/sqlite-coherence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { PyodideRuntime } from "./pyodide-runtime.js";
2
+ /** Synchronous CPython subprocess calls backed by the page's shared process host. */
3
+ export declare class PythonProcessClient {
4
+ private readonly pyodide;
5
+ private readonly port;
6
+ private nextRequestId;
7
+ constructor(pyodide: PyodideRuntime, port: MessagePort);
8
+ private run;
9
+ private exchange;
10
+ }
11
+ export declare const PYTHON_SUBPROCESS_BOOTSTRAP: string;
12
+ //# sourceMappingURL=subprocess-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subprocess-bridge.d.ts","sourceRoot":"","sources":["../src/subprocess-bridge.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAO3D,qFAAqF;AACrF,qBAAa,mBAAmB;IAI5B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJvB,OAAO,CAAC,aAAa,CAAK;gBAGP,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,WAAW;IAMpC,OAAO,CAAC,GAAG;IA0CX,OAAO,CAAC,QAAQ;CA8BjB;AAED,eAAO,MAAM,2BAA2B,QAuUvC,CAAC"}
@@ -0,0 +1,407 @@
1
+ import { restorePythonSnapshot } from "./filesystem.js";
2
+ const RESPONSE_BYTES = 16 * 1024 * 1024;
3
+ const TIMEOUT_MS = 30_000;
4
+ const POPEN_TIMEOUT_MS = 5 * 60_000;
5
+ /** Synchronous CPython subprocess calls backed by the page's shared process host. */
6
+ export class PythonProcessClient {
7
+ pyodide;
8
+ port;
9
+ nextRequestId = 1;
10
+ constructor(pyodide, port) {
11
+ this.pyodide = pyodide;
12
+ this.port = port;
13
+ pyodide.globals.set("__browser_runtime_run_process", (payload) => this.run(payload));
14
+ pyodide.globals.set("__browser_runtime_process_exchange", (payload) => this.exchange(payload));
15
+ }
16
+ run(payload) {
17
+ const request = JSON.parse(payload);
18
+ const controlBuffer = new SharedArrayBuffer(2 * Int32Array.BYTES_PER_ELEMENT);
19
+ const responseBuffer = new SharedArrayBuffer(RESPONSE_BYTES);
20
+ const control = new Int32Array(controlBuffer);
21
+ const requestId = this.nextRequestId++;
22
+ this.port.postMessage({
23
+ type: "process-run",
24
+ requestId,
25
+ ...request,
26
+ control: controlBuffer,
27
+ response: responseBuffer,
28
+ });
29
+ const result = Atomics.wait(control, 0, 0, TIMEOUT_MS);
30
+ if (result === "timed-out" || Atomics.load(control, 0) !== 1) {
31
+ this.port.postMessage({ type: "process-cancel", requestId });
32
+ throw new Error("Python subprocess timed out after 30 seconds.");
33
+ }
34
+ const length = Atomics.load(control, 1);
35
+ if (!Number.isSafeInteger(length) || length < 0 || length > responseBuffer.byteLength) {
36
+ throw new Error("Invalid Python subprocess response.");
37
+ }
38
+ // TextDecoder deliberately rejects SAB-backed views. Copy out of shared
39
+ // memory once the host has published the completion state.
40
+ const responseBytes = new Uint8Array(length);
41
+ responseBytes.set(new Uint8Array(responseBuffer, 0, length));
42
+ const response = JSON.parse(new TextDecoder().decode(responseBytes));
43
+ if (response.error)
44
+ throw new Error(response.error);
45
+ if (!response.result || !response.filesystem)
46
+ throw new Error("Incomplete Python subprocess response.");
47
+ restorePythonSnapshot(this.pyodide.FS, response.filesystem);
48
+ return JSON.stringify(response.result);
49
+ }
50
+ exchange(payload) {
51
+ const request = JSON.parse(payload);
52
+ const controlBuffer = new SharedArrayBuffer(2 * Int32Array.BYTES_PER_ELEMENT);
53
+ const responseBuffer = new SharedArrayBuffer(RESPONSE_BYTES);
54
+ const control = new Int32Array(controlBuffer);
55
+ this.port.postMessage({
56
+ ...request,
57
+ requestId: this.nextRequestId++,
58
+ control: controlBuffer,
59
+ response: responseBuffer,
60
+ });
61
+ const result = Atomics.wait(control, 0, 0, POPEN_TIMEOUT_MS);
62
+ if (result === "timed-out" || Atomics.load(control, 0) !== 1) {
63
+ throw new Error("Python Popen operation timed out after 5 minutes.");
64
+ }
65
+ const length = Atomics.load(control, 1);
66
+ if (!Number.isSafeInteger(length) || length < 0 || length > responseBuffer.byteLength) {
67
+ throw new Error("Invalid Python Popen response.");
68
+ }
69
+ const responseBytes = new Uint8Array(length);
70
+ responseBytes.set(new Uint8Array(responseBuffer, 0, length));
71
+ const response = JSON.parse(new TextDecoder().decode(responseBytes));
72
+ if (response.filesystem)
73
+ restorePythonSnapshot(this.pyodide.FS, response.filesystem);
74
+ if (response.error)
75
+ throw new Error(response.error);
76
+ return JSON.stringify(response);
77
+ }
78
+ }
79
+ export const PYTHON_SUBPROCESS_BOOTSTRAP = String.raw `
80
+ import base64 as __browser_runtime_base64
81
+ import codecs as _browser_runtime_codecs
82
+ import json as __browser_runtime_json
83
+ import os
84
+ import shlex as __browser_runtime_shlex
85
+ import subprocess as __browser_runtime_subprocess
86
+ import sys
87
+
88
+ def __browser_runtime_subprocess_run(args, *, stdin=None, input=None, stdout=None, stderr=None,
89
+ capture_output=False, shell=False, cwd=None, timeout=None,
90
+ check=False, encoding=None, errors=None, text=False, env=None, **kwargs):
91
+ if timeout is not None:
92
+ raise NotImplementedError("browser subprocess timeout is fixed at 30 seconds")
93
+ if kwargs:
94
+ raise NotImplementedError("unsupported browser subprocess options: " + ", ".join(kwargs.keys()))
95
+ if capture_output:
96
+ if stdout is not None or stderr is not None:
97
+ raise ValueError("stdout and stderr arguments may not be used with capture_output")
98
+ stdout = stderr = __browser_runtime_subprocess.PIPE
99
+ if stdin not in (None, __browser_runtime_subprocess.PIPE, __browser_runtime_subprocess.DEVNULL):
100
+ raise NotImplementedError("browser subprocess stdin must be PIPE, DEVNULL, or None")
101
+ if stdout not in (None, __browser_runtime_subprocess.PIPE, __browser_runtime_subprocess.DEVNULL):
102
+ raise NotImplementedError("browser subprocess stdout must be PIPE, DEVNULL, or None")
103
+ if stderr not in (None, __browser_runtime_subprocess.PIPE, __browser_runtime_subprocess.DEVNULL, __browser_runtime_subprocess.STDOUT):
104
+ raise NotImplementedError("browser subprocess stderr must be PIPE, DEVNULL, STDOUT, or None")
105
+ if input is not None and stdin not in (None, __browser_runtime_subprocess.PIPE):
106
+ raise ValueError("stdin argument may not be used with input")
107
+ if isinstance(args, str):
108
+ command = args if shell else __browser_runtime_shlex.join([args])
109
+ else:
110
+ command = __browser_runtime_shlex.join([str(value) for value in args])
111
+ if input is None:
112
+ input_bytes = b""
113
+ elif isinstance(input, str):
114
+ input_bytes = input.encode(encoding or "utf-8", errors or "strict")
115
+ else:
116
+ input_bytes = bytes(input)
117
+ payload = __browser_runtime_json.dumps({
118
+ "command": command,
119
+ "cwd": os.path.abspath(cwd or os.getcwd()),
120
+ "env": {str(key): str(value) for key, value in (env or os.environ).items()},
121
+ "stdinBase64": __browser_runtime_base64.b64encode(input_bytes).decode("ascii"),
122
+ })
123
+ result = __browser_runtime_json.loads(__browser_runtime_run_process(payload))
124
+ use_text = text or encoding is not None or errors is not None
125
+ out_text, err_text = result["stdout"], result["stderr"]
126
+ if stderr == __browser_runtime_subprocess.STDOUT:
127
+ out_text += err_text
128
+ err_text = ""
129
+ if stdout != __browser_runtime_subprocess.PIPE:
130
+ if stdout != __browser_runtime_subprocess.DEVNULL and out_text:
131
+ sys.stdout.write(out_text)
132
+ completed_stdout = None
133
+ else:
134
+ completed_stdout = out_text if use_text else out_text.encode(encoding or "utf-8", errors or "strict")
135
+ if stderr not in (__browser_runtime_subprocess.PIPE, __browser_runtime_subprocess.STDOUT):
136
+ if stderr != __browser_runtime_subprocess.DEVNULL and err_text:
137
+ sys.stderr.write(err_text)
138
+ completed_stderr = None
139
+ else:
140
+ completed_stderr = None if stderr == __browser_runtime_subprocess.STDOUT else (err_text if use_text else err_text.encode(encoding or "utf-8", errors or "strict"))
141
+ completed = __browser_runtime_subprocess.CompletedProcess(args, int(result["exitCode"]), completed_stdout, completed_stderr)
142
+ if check:
143
+ completed.check_returncode()
144
+ return completed
145
+
146
+ def __browser_runtime_subprocess_call(*popenargs, timeout=None, **kwargs):
147
+ return __browser_runtime_subprocess_run(*popenargs, timeout=timeout, **kwargs).returncode
148
+
149
+ def __browser_runtime_subprocess_check_call(*popenargs, **kwargs):
150
+ result = __browser_runtime_subprocess_run(*popenargs, **kwargs)
151
+ result.check_returncode()
152
+ return 0
153
+
154
+ def __browser_runtime_process_command(args, shell):
155
+ if isinstance(args, str):
156
+ return args if shell else __browser_runtime_shlex.join([args])
157
+ return __browser_runtime_shlex.join([str(value) for value in args])
158
+
159
+ def __browser_runtime_process_action(payload):
160
+ return __browser_runtime_json.loads(__browser_runtime_process_exchange(__browser_runtime_json.dumps(payload)))
161
+
162
+ _browser_runtime_base64 = __browser_runtime_base64
163
+ _browser_runtime_process_action = __browser_runtime_process_action
164
+ _browser_runtime_process_command = __browser_runtime_process_command
165
+ _browser_runtime_subprocess = __browser_runtime_subprocess
166
+
167
+ class __browser_runtime_BrowserPipe:
168
+ def __init__(self, process, stream, writable=False):
169
+ self.process = process
170
+ self.stream = stream
171
+ self.writable = writable
172
+ self.closed = False
173
+ self._buffer = "" if self.process.text_mode else bytearray()
174
+ self._decoder = _browser_runtime_codecs.getincrementaldecoder(self.process.encoding)(self.process.errors) if self.process.text_mode else None
175
+ self._eof = False
176
+
177
+ def write(self, value):
178
+ if not self.writable or self.closed:
179
+ raise ValueError("write to closed or read-only browser subprocess pipe")
180
+ raw = value.encode(self.process.encoding, self.process.errors) if isinstance(value, str) else bytes(value)
181
+ result = self.process._action("write", stdinBase64=_browser_runtime_base64.b64encode(raw).decode("ascii"))
182
+ return len(value) if isinstance(value, str) else int(result.get("written", len(raw)))
183
+
184
+ def flush(self):
185
+ if self.closed:
186
+ raise ValueError("flush of closed browser subprocess pipe")
187
+
188
+ def close(self):
189
+ if self.closed:
190
+ return
191
+ self.closed = True
192
+ if self.writable:
193
+ self.process._action("close")
194
+
195
+ def _pull(self, maximum=65536):
196
+ if self.writable or self.closed:
197
+ raise ValueError("read from closed or write-only browser subprocess pipe")
198
+ if self._eof:
199
+ return
200
+ result = self.process._action("read", stream=self.stream, maximum=maximum)
201
+ raw = _browser_runtime_base64.b64decode(result.get("dataBase64", ""))
202
+ self._eof = bool(result.get("eof", False))
203
+ if self.process.text_mode:
204
+ self._buffer += self._decoder.decode(raw, final=self._eof)
205
+ elif raw:
206
+ self._buffer.extend(raw)
207
+
208
+ def read(self, size=-1):
209
+ if size is None or size < 0:
210
+ while not self._eof:
211
+ self._pull()
212
+ value = self._buffer if self.process.text_mode else bytes(self._buffer)
213
+ self._buffer = "" if self.process.text_mode else bytearray()
214
+ return value
215
+ if size == 0:
216
+ return "" if self.process.text_mode else b""
217
+ while not self._buffer and not self._eof:
218
+ self._pull(min(max(size, 1), 1048576))
219
+ count = min(size, len(self._buffer))
220
+ value = self._buffer[:count] if self.process.text_mode else bytes(self._buffer[:count])
221
+ if self.process.text_mode:
222
+ self._buffer = self._buffer[count:]
223
+ else:
224
+ del self._buffer[:count]
225
+ return value
226
+
227
+ def readline(self, size=-1):
228
+ limit = None if size is None or size < 0 else size
229
+ newline_value = "\n" if self.process.text_mode else b"\n"
230
+ while not self._eof and newline_value not in self._buffer and (limit is None or len(self._buffer) < limit):
231
+ self._pull()
232
+ newline = self._buffer.find(newline_value)
233
+ count = len(self._buffer) if newline < 0 else newline + 1
234
+ if limit is not None:
235
+ count = min(count, limit)
236
+ value = self._buffer[:count] if self.process.text_mode else bytes(self._buffer[:count])
237
+ if self.process.text_mode:
238
+ self._buffer = self._buffer[count:]
239
+ else:
240
+ del self._buffer[:count]
241
+ return value
242
+
243
+ def readlines(self, hint=-1):
244
+ lines = []
245
+ total = 0
246
+ while True:
247
+ line = self.readline()
248
+ if not line:
249
+ break
250
+ lines.append(line)
251
+ total += len(line)
252
+ if hint is not None and hint >= 0 and total >= hint:
253
+ break
254
+ return lines
255
+
256
+ def __iter__(self):
257
+ return self
258
+
259
+ def __next__(self):
260
+ line = self.readline()
261
+ if not line:
262
+ raise StopIteration
263
+ return line
264
+
265
+ def __enter__(self):
266
+ return self
267
+
268
+ def __exit__(self, exc_type, value, traceback):
269
+ self.close()
270
+
271
+ _browser_runtime_BrowserPipe = __browser_runtime_BrowserPipe
272
+
273
+ class __browser_runtime_BrowserPopen:
274
+ def __init__(self, args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None,
275
+ preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None,
276
+ universal_newlines=None, startupinfo=None, creationflags=0,
277
+ restore_signals=True, start_new_session=False, pass_fds=(), *, user=None,
278
+ group=None, extra_groups=None, encoding=None, errors=None, text=None,
279
+ umask=-1, pipesize=-1, process_group=None):
280
+ unsupported = {
281
+ "executable": executable, "preexec_fn": preexec_fn, "startupinfo": startupinfo,
282
+ "creationflags": creationflags or None, "start_new_session": start_new_session or None,
283
+ "pass_fds": pass_fds or None, "user": user, "group": group,
284
+ "extra_groups": extra_groups, "umask": None if umask == -1 else umask,
285
+ "pipesize": None if pipesize == -1 else pipesize, "process_group": process_group,
286
+ }
287
+ rejected = [name for name, value in unsupported.items() if value is not None]
288
+ if rejected:
289
+ raise NotImplementedError("unsupported browser Popen options: " + ", ".join(rejected))
290
+ if stdin not in (None, _browser_runtime_subprocess.PIPE, _browser_runtime_subprocess.DEVNULL):
291
+ raise NotImplementedError("browser Popen stdin must be PIPE, DEVNULL, or None")
292
+ if stdout not in (None, _browser_runtime_subprocess.PIPE, _browser_runtime_subprocess.DEVNULL):
293
+ raise NotImplementedError("browser Popen stdout must be PIPE, DEVNULL, or None")
294
+ if stderr not in (None, _browser_runtime_subprocess.PIPE, _browser_runtime_subprocess.DEVNULL, _browser_runtime_subprocess.STDOUT):
295
+ raise NotImplementedError("browser Popen stderr must be PIPE, DEVNULL, STDOUT, or None")
296
+ self.args = args
297
+ self.returncode = None
298
+ self.encoding = encoding or "utf-8"
299
+ self.errors = errors or "strict"
300
+ self.text_mode = bool(text or universal_newlines or encoding is not None or errors is not None)
301
+ self._stdout_mode = stdout
302
+ self._stderr_mode = stderr
303
+ self._stdout = "" if self.text_mode else b""
304
+ self._stderr = "" if self.text_mode else b""
305
+ self._completion = None
306
+ result = _browser_runtime_process_action({
307
+ "type": "process-start",
308
+ "command": _browser_runtime_process_command(args, shell),
309
+ "cwd": os.path.abspath(cwd or os.getcwd()),
310
+ "env": {str(key): str(value) for key, value in (env or os.environ).items()},
311
+ "stdinPipe": stdin == _browser_runtime_subprocess.PIPE,
312
+ "stdoutPipe": stdout == _browser_runtime_subprocess.PIPE,
313
+ "stderrPipe": stderr == _browser_runtime_subprocess.PIPE,
314
+ "stderrToStdout": stderr == _browser_runtime_subprocess.STDOUT,
315
+ })
316
+ self.pid = int(result["childId"])
317
+ self.stdin = _browser_runtime_BrowserPipe(self, "stdin", True) if stdin == _browser_runtime_subprocess.PIPE else None
318
+ self.stdout = _browser_runtime_BrowserPipe(self, "stdout") if stdout == _browser_runtime_subprocess.PIPE else None
319
+ self.stderr = _browser_runtime_BrowserPipe(self, "stderr") if stderr == _browser_runtime_subprocess.PIPE else None
320
+
321
+ def _action(self, action, **values):
322
+ return _browser_runtime_process_action({"type": "process-action", "childId": self.pid, "action": action, **values})
323
+
324
+ def _wait_result(self, input_value=None, close_stdin=False):
325
+ if self._completion is not None:
326
+ return self._completion
327
+ raw_input = b""
328
+ if input_value is not None:
329
+ if self.stdin is None:
330
+ raise ValueError("Cannot send input after starting communication without stdin=PIPE")
331
+ raw_input = input_value.encode(self.encoding, self.errors) if isinstance(input_value, str) else bytes(input_value)
332
+ result = self._action(
333
+ "wait",
334
+ stdinBase64=_browser_runtime_base64.b64encode(raw_input).decode("ascii"),
335
+ closeStdin=close_stdin,
336
+ )
337
+ completed = result["result"]
338
+ self.returncode = int(completed["exitCode"])
339
+ out_text, err_text = completed["stdout"], completed["stderr"]
340
+ if self._stdout_mode == _browser_runtime_subprocess.PIPE:
341
+ self._stdout = ("" if self.text_mode else b"") if self.stdout.closed else self.stdout.read()
342
+ out_text = ""
343
+ else:
344
+ self._stdout = "" if self.text_mode else b""
345
+ if self._stderr_mode == _browser_runtime_subprocess.PIPE:
346
+ self._stderr = ("" if self.text_mode else b"") if self.stderr.closed else self.stderr.read()
347
+ err_text = ""
348
+ else:
349
+ self._stderr = "" if self.text_mode else b""
350
+ if self._stderr_mode == _browser_runtime_subprocess.STDOUT and self._stdout_mode != _browser_runtime_subprocess.PIPE:
351
+ out_text += err_text
352
+ err_text = ""
353
+ if self._stdout_mode not in (_browser_runtime_subprocess.PIPE, _browser_runtime_subprocess.DEVNULL) and out_text:
354
+ sys.stdout.write(out_text)
355
+ if self._stderr_mode not in (_browser_runtime_subprocess.PIPE, _browser_runtime_subprocess.DEVNULL, _browser_runtime_subprocess.STDOUT) and err_text:
356
+ sys.stderr.write(err_text)
357
+ self._completion = completed
358
+ self._action("release")
359
+ return completed
360
+
361
+ def poll(self):
362
+ if self.returncode is None:
363
+ value = self._action("poll").get("returncode")
364
+ if value is not None:
365
+ self.returncode = int(value)
366
+ return self.returncode
367
+
368
+ def wait(self, timeout=None):
369
+ if timeout is not None:
370
+ raise NotImplementedError("browser Popen wait timeout is fixed at five minutes")
371
+ self._wait_result()
372
+ return self.returncode
373
+
374
+ def communicate(self, input=None, timeout=None):
375
+ if timeout is not None:
376
+ raise NotImplementedError("browser Popen communicate timeout is fixed at five minutes")
377
+ self._wait_result(input, self.stdin is not None)
378
+ if self.stdin is not None:
379
+ self.stdin.closed = True
380
+ return (
381
+ self._stdout if self._stdout_mode == _browser_runtime_subprocess.PIPE else None,
382
+ self._stderr if self._stderr_mode == _browser_runtime_subprocess.PIPE else None,
383
+ )
384
+
385
+ def terminate(self):
386
+ if self.returncode is None:
387
+ self._action("terminate")
388
+
389
+ kill = terminate
390
+
391
+ def send_signal(self, sig):
392
+ self.terminate()
393
+
394
+ def __enter__(self):
395
+ return self
396
+
397
+ def __exit__(self, exc_type, value, traceback):
398
+ if self.stdin is not None and not self.stdin.closed:
399
+ self.stdin.close()
400
+ self.wait()
401
+
402
+ __browser_runtime_subprocess.run = __browser_runtime_subprocess_run
403
+ __browser_runtime_subprocess.call = __browser_runtime_subprocess_call
404
+ __browser_runtime_subprocess.check_call = __browser_runtime_subprocess_check_call
405
+ __browser_runtime_subprocess.Popen = __browser_runtime_BrowserPopen
406
+ `;
407
+ //# sourceMappingURL=subprocess-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subprocess-bridge.js","sourceRoot":"","sources":["../src/subprocess-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":""}