tywrap 0.2.1 → 0.3.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.
- package/README.md +65 -31
- package/dist/cli.js +49 -2
- package/dist/cli.js.map +1 -1
- package/dist/config/index.d.ts +11 -7
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +43 -7
- package/dist/config/index.js.map +1 -1
- package/dist/core/analyzer.d.ts +1 -0
- package/dist/core/analyzer.d.ts.map +1 -1
- package/dist/core/analyzer.js +47 -12
- package/dist/core/analyzer.js.map +1 -1
- package/dist/core/annotation-parser.d.ts +8 -0
- package/dist/core/annotation-parser.d.ts.map +1 -0
- package/dist/core/annotation-parser.js +409 -0
- package/dist/core/annotation-parser.js.map +1 -0
- package/dist/core/discovery.d.ts +1 -0
- package/dist/core/discovery.d.ts.map +1 -1
- package/dist/core/discovery.js +9 -9
- package/dist/core/discovery.js.map +1 -1
- package/dist/core/generator.d.ts +9 -1
- package/dist/core/generator.d.ts.map +1 -1
- package/dist/core/generator.js +738 -104
- package/dist/core/generator.js.map +1 -1
- package/dist/core/mapper.d.ts +9 -7
- package/dist/core/mapper.d.ts.map +1 -1
- package/dist/core/mapper.js +129 -44
- package/dist/core/mapper.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/runtime/bridge-core.d.ts +1 -0
- package/dist/runtime/bridge-core.d.ts.map +1 -1
- package/dist/runtime/bridge-core.js +52 -17
- package/dist/runtime/bridge-core.js.map +1 -1
- package/dist/runtime/bridge-protocol.d.ts +17 -0
- package/dist/runtime/bridge-protocol.d.ts.map +1 -1
- package/dist/runtime/bridge-protocol.js +97 -0
- package/dist/runtime/bridge-protocol.js.map +1 -1
- package/dist/runtime/errors.d.ts +10 -0
- package/dist/runtime/errors.d.ts.map +1 -1
- package/dist/runtime/errors.js +9 -0
- package/dist/runtime/errors.js.map +1 -1
- package/dist/runtime/http-io.d.ts.map +1 -1
- package/dist/runtime/http-io.js.map +1 -1
- package/dist/runtime/http.d.ts +1 -0
- package/dist/runtime/http.d.ts.map +1 -1
- package/dist/runtime/http.js +6 -0
- package/dist/runtime/http.js.map +1 -1
- package/dist/runtime/node.d.ts.map +1 -1
- package/dist/runtime/node.js +170 -32
- package/dist/runtime/node.js.map +1 -1
- package/dist/runtime/optimized-node.d.ts +1 -1
- package/dist/runtime/optimized-node.d.ts.map +1 -1
- package/dist/runtime/optimized-node.js +1 -1
- package/dist/runtime/optimized-node.js.map +1 -1
- package/dist/runtime/pooled-transport.d.ts +4 -0
- package/dist/runtime/pooled-transport.d.ts.map +1 -1
- package/dist/runtime/pooled-transport.js +2 -0
- package/dist/runtime/pooled-transport.js.map +1 -1
- package/dist/runtime/process-io.d.ts +5 -0
- package/dist/runtime/process-io.d.ts.map +1 -1
- package/dist/runtime/process-io.js +64 -30
- package/dist/runtime/process-io.js.map +1 -1
- package/dist/runtime/pyodide-io.d.ts +4 -5
- package/dist/runtime/pyodide-io.d.ts.map +1 -1
- package/dist/runtime/pyodide-io.js +99 -37
- package/dist/runtime/pyodide-io.js.map +1 -1
- package/dist/runtime/safe-codec.d.ts +25 -3
- package/dist/runtime/safe-codec.d.ts.map +1 -1
- package/dist/runtime/safe-codec.js +231 -57
- package/dist/runtime/safe-codec.js.map +1 -1
- package/dist/runtime/transport.d.ts +6 -1
- package/dist/runtime/transport.d.ts.map +1 -1
- package/dist/runtime/transport.js.map +1 -1
- package/dist/runtime/validators.d.ts +0 -11
- package/dist/runtime/validators.d.ts.map +1 -1
- package/dist/runtime/validators.js +13 -3
- package/dist/runtime/validators.js.map +1 -1
- package/dist/runtime/worker-pool.d.ts +12 -0
- package/dist/runtime/worker-pool.d.ts.map +1 -1
- package/dist/runtime/worker-pool.js +53 -5
- package/dist/runtime/worker-pool.js.map +1 -1
- package/dist/types/index.d.ts +51 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/tywrap.d.ts.map +1 -1
- package/dist/tywrap.js +227 -328
- package/dist/tywrap.js.map +1 -1
- package/dist/utils/cache.d.ts.map +1 -1
- package/dist/utils/cache.js +53 -5
- package/dist/utils/cache.js.map +1 -1
- package/dist/utils/codec.d.ts.map +1 -1
- package/dist/utils/codec.js +10 -16
- package/dist/utils/codec.js.map +1 -1
- package/dist/utils/ir-cache.d.ts +28 -0
- package/dist/utils/ir-cache.d.ts.map +1 -0
- package/dist/utils/ir-cache.js +29 -0
- package/dist/utils/ir-cache.js.map +1 -0
- package/dist/utils/parallel-processor.d.ts +1 -1
- package/dist/utils/parallel-processor.d.ts.map +1 -1
- package/dist/utils/parallel-processor.js +111 -40
- package/dist/utils/parallel-processor.js.map +1 -1
- package/dist/utils/runtime.d.ts +5 -1
- package/dist/utils/runtime.d.ts.map +1 -1
- package/dist/utils/runtime.js +112 -18
- package/dist/utils/runtime.js.map +1 -1
- package/package.json +40 -18
- package/runtime/python_bridge.py +78 -12
- package/src/cli.ts +61 -2
- package/src/config/index.ts +63 -17
- package/src/core/analyzer.ts +52 -15
- package/src/core/annotation-parser.ts +500 -0
- package/src/core/discovery.ts +26 -12
- package/src/core/generator.ts +956 -116
- package/src/core/mapper.ts +158 -51
- package/src/index.ts +34 -5
- package/src/runtime/bridge-core.ts +58 -18
- package/src/runtime/bridge-protocol.ts +164 -0
- package/src/runtime/errors.ts +14 -0
- package/src/runtime/http-io.ts +2 -1
- package/src/runtime/http.ts +7 -0
- package/src/runtime/node.ts +264 -44
- package/src/runtime/optimized-node.ts +4 -1
- package/src/runtime/pooled-transport.ts +12 -1
- package/src/runtime/process-io.ts +83 -55
- package/src/runtime/pyodide-io.ts +110 -44
- package/src/runtime/safe-codec.ts +290 -82
- package/src/runtime/transport.ts +6 -1
- package/src/runtime/validators.ts +14 -3
- package/src/runtime/worker-pool.ts +67 -6
- package/src/types/global.d.ts +11 -1
- package/src/types/index.ts +63 -0
- package/src/tywrap.ts +279 -358
- package/src/utils/cache.ts +59 -5
- package/src/utils/codec.ts +11 -15
- package/src/utils/ir-cache.ts +51 -0
- package/src/utils/parallel-processor.ts +119 -43
- package/src/utils/runtime.ts +129 -18
|
@@ -39,6 +39,13 @@ export interface WorkerPoolOptions {
|
|
|
39
39
|
* Use this for per-worker warmup (e.g., importing modules, running setup).
|
|
40
40
|
*/
|
|
41
41
|
onWorkerReady?: (worker: PooledWorker) => Promise<void>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Optional callback used only for background replacement workers after a
|
|
45
|
+
* fatal timeout/crash. This lets callers publish a replacement only after it
|
|
46
|
+
* is proven ready, without charging hidden work to normal request startup.
|
|
47
|
+
*/
|
|
48
|
+
onReplacementWorkerReady?: (worker: PooledWorker) => Promise<void>;
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
/**
|
|
@@ -99,8 +106,12 @@ interface QueuedWaiter {
|
|
|
99
106
|
* ```
|
|
100
107
|
*/
|
|
101
108
|
export class WorkerPool extends BoundedContext {
|
|
102
|
-
private readonly options: Omit<
|
|
109
|
+
private readonly options: Omit<
|
|
110
|
+
Required<WorkerPoolOptions>,
|
|
111
|
+
'onWorkerReady' | 'onReplacementWorkerReady'
|
|
112
|
+
> & {
|
|
103
113
|
onWorkerReady?: (worker: PooledWorker) => Promise<void>;
|
|
114
|
+
onReplacementWorkerReady?: (worker: PooledWorker) => Promise<void>;
|
|
104
115
|
};
|
|
105
116
|
private readonly workers: PooledWorker[] = [];
|
|
106
117
|
private readonly waitQueue: QueuedWaiter[] = [];
|
|
@@ -135,6 +146,7 @@ export class WorkerPool extends BoundedContext {
|
|
|
135
146
|
queueTimeoutMs: options.queueTimeoutMs ?? 30000,
|
|
136
147
|
maxConcurrentPerWorker: options.maxConcurrentPerWorker ?? 1,
|
|
137
148
|
onWorkerReady: options.onWorkerReady,
|
|
149
|
+
onReplacementWorkerReady: options.onReplacementWorkerReady,
|
|
138
150
|
};
|
|
139
151
|
}
|
|
140
152
|
|
|
@@ -319,8 +331,14 @@ export class WorkerPool extends BoundedContext {
|
|
|
319
331
|
* - Process exited unexpectedly
|
|
320
332
|
* - Pipe errors (EPIPE)
|
|
321
333
|
* - Connection reset errors (ECONNRESET)
|
|
334
|
+
* - Request timeouts (the worker may still be busy with an uncancellable request)
|
|
322
335
|
*/
|
|
323
336
|
private isFatalWorkerError(error: unknown): boolean {
|
|
337
|
+
// If a request times out, the underlying transport may still be executing it.
|
|
338
|
+
// Quarantine this worker so subsequent requests don't get stuck behind it.
|
|
339
|
+
if (error instanceof BridgeTimeoutError) {
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
324
342
|
if (error instanceof BridgeProtocolError) {
|
|
325
343
|
const msg = error.message.toLowerCase();
|
|
326
344
|
return (
|
|
@@ -347,6 +365,7 @@ export class WorkerPool extends BoundedContext {
|
|
|
347
365
|
worker.transport.dispose().catch(() => {
|
|
348
366
|
// Ignore disposal errors for dead workers
|
|
349
367
|
});
|
|
368
|
+
this.scheduleReplacementWorker();
|
|
350
369
|
}
|
|
351
370
|
}
|
|
352
371
|
|
|
@@ -386,13 +405,40 @@ export class WorkerPool extends BoundedContext {
|
|
|
386
405
|
return this.workers.find(w => w.inFlightCount < this.options.maxConcurrentPerWorker);
|
|
387
406
|
}
|
|
388
407
|
|
|
408
|
+
/**
|
|
409
|
+
* Replace a removed worker in the background so the next caller does not pay
|
|
410
|
+
* the full worker cold-start penalty after a timeout or crash.
|
|
411
|
+
*/
|
|
412
|
+
private scheduleReplacementWorker(): void {
|
|
413
|
+
if (this.state !== 'ready') {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (this.workers.length + this.pendingCreations >= this.options.maxWorkers) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
this.pendingCreations++;
|
|
421
|
+
const replacementReady = this.options.onReplacementWorkerReady ?? this.options.onWorkerReady;
|
|
422
|
+
this.createWorker(replacementReady)
|
|
423
|
+
.then(worker => {
|
|
424
|
+
// Reuse release() to wake queued callers if one is waiting.
|
|
425
|
+
this.release(worker);
|
|
426
|
+
})
|
|
427
|
+
.catch(() => {
|
|
428
|
+
// Ignore background replacement failures. A later acquire() can retry.
|
|
429
|
+
})
|
|
430
|
+
.finally(() => {
|
|
431
|
+
this.pendingCreations = Math.max(0, this.pendingCreations - 1);
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
389
435
|
/**
|
|
390
436
|
* Create a new worker and add it to the pool.
|
|
391
437
|
*
|
|
392
438
|
* If onWorkerReady is configured, calls it after the transport is initialized.
|
|
393
439
|
* This is useful for per-worker warmup (importing modules, running setup).
|
|
394
440
|
*/
|
|
395
|
-
private async createWorker(): Promise<PooledWorker> {
|
|
441
|
+
private async createWorker(onWorkerReady = this.options.onWorkerReady): Promise<PooledWorker> {
|
|
396
442
|
const transport = this.options.createTransport();
|
|
397
443
|
|
|
398
444
|
// Initialize the transport
|
|
@@ -403,13 +449,28 @@ export class WorkerPool extends BoundedContext {
|
|
|
403
449
|
inFlightCount: 0,
|
|
404
450
|
};
|
|
405
451
|
|
|
406
|
-
|
|
452
|
+
try {
|
|
453
|
+
// Call onWorkerReady callback if provided
|
|
454
|
+
if (onWorkerReady) {
|
|
455
|
+
await onWorkerReady(worker);
|
|
456
|
+
}
|
|
457
|
+
} catch (error) {
|
|
458
|
+
// Ensure partially initialized workers do not leak when warmup fails.
|
|
459
|
+
await transport.dispose().catch(() => {
|
|
460
|
+
// Ignore disposal failures during warmup failure handling.
|
|
461
|
+
});
|
|
462
|
+
throw error;
|
|
463
|
+
}
|
|
407
464
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
465
|
+
if (this.state === 'disposing' || this.state === 'disposed') {
|
|
466
|
+
await transport.dispose().catch(() => {
|
|
467
|
+
// Ignore disposal failures if the pool was torn down mid-creation.
|
|
468
|
+
});
|
|
469
|
+
throw new BridgeExecutionError('Pool disposed during worker creation');
|
|
411
470
|
}
|
|
412
471
|
|
|
472
|
+
this.workers.push(worker);
|
|
473
|
+
|
|
413
474
|
return worker;
|
|
414
475
|
}
|
|
415
476
|
|
package/src/types/global.d.ts
CHANGED
|
@@ -8,13 +8,20 @@ declare namespace DenoTypes {
|
|
|
8
8
|
deno: string;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
interface CommandOptions {
|
|
12
|
+
args?: string[];
|
|
13
|
+
cwd?: string;
|
|
14
|
+
env?: Record<string, string>;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
}
|
|
17
|
+
|
|
11
18
|
interface DenoGlobal {
|
|
12
19
|
version: Version;
|
|
13
20
|
readTextFile(path: string): Promise<string>;
|
|
14
21
|
writeTextFile(path: string, content: string): Promise<void>;
|
|
15
22
|
Command: new (
|
|
16
23
|
cmd: string,
|
|
17
|
-
options?:
|
|
24
|
+
options?: CommandOptions
|
|
18
25
|
) => {
|
|
19
26
|
output(): Promise<{ code: number; stdout: Uint8Array; stderr: Uint8Array }>;
|
|
20
27
|
};
|
|
@@ -37,12 +44,15 @@ declare namespace BunTypes {
|
|
|
37
44
|
options?: {
|
|
38
45
|
stdout?: string;
|
|
39
46
|
stderr?: string;
|
|
47
|
+
cwd?: string;
|
|
48
|
+
env?: Record<string, string>;
|
|
40
49
|
}
|
|
41
50
|
): {
|
|
42
51
|
stdout: ReadableStream;
|
|
43
52
|
stderr: ReadableStream;
|
|
44
53
|
exitCode?: number;
|
|
45
54
|
exited: Promise<void>;
|
|
55
|
+
kill(signal?: number | string): void;
|
|
46
56
|
};
|
|
47
57
|
}
|
|
48
58
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface PythonModule {
|
|
|
8
8
|
version?: string;
|
|
9
9
|
functions: PythonFunction[];
|
|
10
10
|
classes: PythonClass[];
|
|
11
|
+
typeAliases?: PythonTypeAlias[];
|
|
11
12
|
imports: PythonImport[];
|
|
12
13
|
exports: string[];
|
|
13
14
|
}
|
|
@@ -19,6 +20,7 @@ export interface PythonFunction {
|
|
|
19
20
|
decorators: string[];
|
|
20
21
|
isAsync: boolean;
|
|
21
22
|
isGenerator: boolean;
|
|
23
|
+
typeParameters?: PythonGenericParameter[];
|
|
22
24
|
returnType: PythonType;
|
|
23
25
|
parameters: Parameter[];
|
|
24
26
|
}
|
|
@@ -31,6 +33,23 @@ export interface PythonClass {
|
|
|
31
33
|
docstring?: string;
|
|
32
34
|
decorators: string[];
|
|
33
35
|
kind?: 'class' | 'protocol' | 'typed_dict' | 'namedtuple' | 'dataclass' | 'pydantic';
|
|
36
|
+
typeParameters?: PythonGenericParameter[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface PythonTypeAlias {
|
|
40
|
+
name: string;
|
|
41
|
+
type: PythonType;
|
|
42
|
+
typeParameters?: PythonGenericParameter[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type PythonGenericParameterKind = 'typevar' | 'paramspec' | 'typevartuple';
|
|
46
|
+
|
|
47
|
+
export interface PythonGenericParameter {
|
|
48
|
+
name: string;
|
|
49
|
+
kind: PythonGenericParameterKind;
|
|
50
|
+
bound?: PythonType;
|
|
51
|
+
constraints?: PythonType[];
|
|
52
|
+
variance?: 'covariant' | 'contravariant' | 'invariant';
|
|
34
53
|
}
|
|
35
54
|
|
|
36
55
|
export interface PythonImport {
|
|
@@ -47,12 +66,15 @@ export interface Parameter {
|
|
|
47
66
|
defaultValue?: unknown;
|
|
48
67
|
varArgs: boolean;
|
|
49
68
|
kwArgs: boolean;
|
|
69
|
+
positionalOnly?: boolean;
|
|
70
|
+
keywordOnly?: boolean;
|
|
50
71
|
}
|
|
51
72
|
|
|
52
73
|
export interface Property {
|
|
53
74
|
name: string;
|
|
54
75
|
type: PythonType;
|
|
55
76
|
readonly: boolean;
|
|
77
|
+
optional?: boolean;
|
|
56
78
|
setter?: boolean;
|
|
57
79
|
getter?: boolean;
|
|
58
80
|
}
|
|
@@ -76,6 +98,11 @@ export type PythonType =
|
|
|
76
98
|
| AnnotatedType
|
|
77
99
|
| CustomType
|
|
78
100
|
| TypeVarType
|
|
101
|
+
| ParamSpecType
|
|
102
|
+
| ParamSpecArgsType
|
|
103
|
+
| ParamSpecKwargsType
|
|
104
|
+
| TypeVarTupleType
|
|
105
|
+
| UnpackType
|
|
79
106
|
| FinalType
|
|
80
107
|
| ClassVarType;
|
|
81
108
|
|
|
@@ -103,6 +130,7 @@ export interface OptionalType {
|
|
|
103
130
|
export interface GenericType {
|
|
104
131
|
kind: 'generic';
|
|
105
132
|
name: string;
|
|
133
|
+
module?: string;
|
|
106
134
|
typeArgs: PythonType[];
|
|
107
135
|
}
|
|
108
136
|
|
|
@@ -115,6 +143,7 @@ export interface CustomType {
|
|
|
115
143
|
export interface CallableType {
|
|
116
144
|
kind: 'callable';
|
|
117
145
|
parameters: PythonType[];
|
|
146
|
+
parameterSpec?: ParamSpecType;
|
|
118
147
|
returnType: PythonType;
|
|
119
148
|
}
|
|
120
149
|
|
|
@@ -137,6 +166,31 @@ export interface TypeVarType {
|
|
|
137
166
|
variance?: 'covariant' | 'contravariant' | 'invariant';
|
|
138
167
|
}
|
|
139
168
|
|
|
169
|
+
export interface ParamSpecType {
|
|
170
|
+
kind: 'paramspec';
|
|
171
|
+
name: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface ParamSpecArgsType {
|
|
175
|
+
kind: 'paramspec_args';
|
|
176
|
+
name: string;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface ParamSpecKwargsType {
|
|
180
|
+
kind: 'paramspec_kwargs';
|
|
181
|
+
name: string;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface TypeVarTupleType {
|
|
185
|
+
kind: 'typevartuple';
|
|
186
|
+
name: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface UnpackType {
|
|
190
|
+
kind: 'unpack';
|
|
191
|
+
type: PythonType;
|
|
192
|
+
}
|
|
193
|
+
|
|
140
194
|
export interface FinalType {
|
|
141
195
|
kind: 'final';
|
|
142
196
|
type: PythonType;
|
|
@@ -242,6 +296,11 @@ export type RuntimeStrategy = 'pyodide' | 'node' | 'http' | 'auto';
|
|
|
242
296
|
|
|
243
297
|
export interface TywrapOptions {
|
|
244
298
|
pythonModules: Record<string, PythonModuleConfig>;
|
|
299
|
+
/**
|
|
300
|
+
* Additional Python import paths to prepend to PYTHONPATH during code generation
|
|
301
|
+
* and discovery (IR extraction). Useful for local modules not installed in site-packages.
|
|
302
|
+
*/
|
|
303
|
+
pythonImportPath?: string[];
|
|
245
304
|
output: OutputConfig;
|
|
246
305
|
runtime: RuntimeConfig;
|
|
247
306
|
performance: PerformanceConfig;
|
|
@@ -255,6 +314,10 @@ export interface PythonModuleConfig {
|
|
|
255
314
|
runtime: RuntimeStrategy;
|
|
256
315
|
functions?: string[];
|
|
257
316
|
classes?: string[];
|
|
317
|
+
/** Exclude specific exports by exact name. */
|
|
318
|
+
exclude?: string[];
|
|
319
|
+
/** Exclude exports matching one or more regex patterns (JavaScript RegExp source). */
|
|
320
|
+
excludePatterns?: string[];
|
|
258
321
|
alias?: string;
|
|
259
322
|
typeHints: 'strict' | 'loose' | 'ignore';
|
|
260
323
|
watch?: boolean;
|