tywrap 0.6.1 → 0.8.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 +15 -5
- package/dist/core/annotation-parser.d.ts.map +1 -1
- package/dist/core/annotation-parser.js.map +1 -1
- package/dist/core/emit-call.d.ts.map +1 -1
- package/dist/core/emit-call.js +1 -1
- package/dist/core/emit-call.js.map +1 -1
- package/dist/core/generator.d.ts.map +1 -1
- package/dist/core/generator.js +40 -9
- package/dist/core/generator.js.map +1 -1
- package/dist/dev.d.ts.map +1 -1
- package/dist/dev.js +1 -3
- package/dist/dev.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/base-bridge.d.ts +57 -0
- package/dist/runtime/base-bridge.d.ts.map +1 -0
- package/dist/runtime/base-bridge.js +72 -0
- package/dist/runtime/base-bridge.js.map +1 -0
- package/dist/runtime/frame-codec.d.ts +111 -0
- package/dist/runtime/frame-codec.d.ts.map +1 -0
- package/dist/runtime/frame-codec.js +352 -0
- package/dist/runtime/frame-codec.js.map +1 -0
- package/dist/runtime/http-transport.d.ts +11 -1
- package/dist/runtime/http-transport.d.ts.map +1 -1
- package/dist/runtime/http-transport.js +19 -0
- package/dist/runtime/http-transport.js.map +1 -1
- package/dist/runtime/http.d.ts +5 -12
- package/dist/runtime/http.d.ts.map +1 -1
- package/dist/runtime/http.js +6 -29
- package/dist/runtime/http.js.map +1 -1
- package/dist/runtime/index.d.ts +2 -2
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/node.d.ts +25 -19
- package/dist/runtime/node.d.ts.map +1 -1
- package/dist/runtime/node.js +19 -34
- package/dist/runtime/node.js.map +1 -1
- package/dist/runtime/pooled-transport.d.ts +21 -2
- package/dist/runtime/pooled-transport.d.ts.map +1 -1
- package/dist/runtime/pooled-transport.js +16 -0
- package/dist/runtime/pooled-transport.js.map +1 -1
- package/dist/runtime/pyodide-bootstrap-core.generated.d.ts.map +1 -1
- package/dist/runtime/pyodide-bootstrap-core.generated.js +1 -1
- package/dist/runtime/pyodide-bootstrap-core.generated.js.map +1 -1
- package/dist/runtime/pyodide-transport.d.ts +12 -1
- package/dist/runtime/pyodide-transport.d.ts.map +1 -1
- package/dist/runtime/pyodide-transport.js +20 -0
- package/dist/runtime/pyodide-transport.js.map +1 -1
- package/dist/runtime/pyodide.d.ts +5 -12
- package/dist/runtime/pyodide.d.ts.map +1 -1
- package/dist/runtime/pyodide.js +6 -29
- package/dist/runtime/pyodide.js.map +1 -1
- package/dist/runtime/rpc-client.d.ts +14 -1
- package/dist/runtime/rpc-client.d.ts.map +1 -1
- package/dist/runtime/rpc-client.js +68 -6
- package/dist/runtime/rpc-client.js.map +1 -1
- package/dist/runtime/subprocess-transport.d.ts +177 -3
- package/dist/runtime/subprocess-transport.d.ts.map +1 -1
- package/dist/runtime/subprocess-transport.js +526 -26
- package/dist/runtime/subprocess-transport.js.map +1 -1
- package/dist/runtime/transport.d.ts +141 -0
- package/dist/runtime/transport.d.ts.map +1 -1
- package/dist/runtime/transport.js +21 -0
- package/dist/runtime/transport.js.map +1 -1
- package/dist/types/index.d.ts +59 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/tywrap.d.ts.map +1 -1
- package/dist/tywrap.js +204 -149
- package/dist/tywrap.js.map +1 -1
- package/dist/utils/codec.d.ts +2 -0
- package/dist/utils/codec.d.ts.map +1 -1
- package/dist/utils/codec.js +205 -6
- package/dist/utils/codec.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -1
- package/runtime/__pycache__/_tywrap_conformance_chunking_fixtures.cpython-311.pyc +0 -0
- package/runtime/__pycache__/_tywrap_member_fixtures.cpython-311.pyc +0 -0
- package/runtime/__pycache__/_tywrap_w4_chunking_fixture.cpython-311.pyc +0 -0
- package/runtime/__pycache__/_tywrap_w5_request_chunking_fixture.cpython-311.pyc +0 -0
- package/runtime/__pycache__/_tywrap_w6_pool_chunking_fixture.cpython-311.pyc +0 -0
- package/runtime/__pycache__/frame_codec.cpython-311.pyc +0 -0
- package/runtime/__pycache__/safe_codec.cpython-311.pyc +0 -0
- package/runtime/__pycache__/tywrap_bridge_core.cpython-311.pyc +0 -0
- package/runtime/frame_codec.py +424 -0
- package/runtime/python_bridge.py +241 -42
- package/runtime/tywrap_bridge_core.py +152 -13
- package/src/core/annotation-parser.ts +2 -1
- package/src/core/emit-call.ts +1 -7
- package/src/core/generator.ts +50 -11
- package/src/dev.ts +1 -3
- package/src/index.ts +1 -0
- package/src/runtime/base-bridge.ts +106 -0
- package/src/runtime/frame-codec.ts +469 -0
- package/src/runtime/http-transport.ts +21 -1
- package/src/runtime/http.ts +7 -51
- package/src/runtime/index.ts +2 -6
- package/src/runtime/node.ts +42 -53
- package/src/runtime/pooled-transport.ts +25 -2
- package/src/runtime/pyodide-bootstrap-core.generated.ts +1 -1
- package/src/runtime/pyodide-transport.ts +22 -0
- package/src/runtime/pyodide.ts +7 -52
- package/src/runtime/rpc-client.ts +91 -7
- package/src/runtime/subprocess-transport.ts +629 -30
- package/src/runtime/transport.ts +169 -0
- package/src/types/index.ts +62 -0
- package/src/tywrap.ts +265 -162
- package/src/utils/codec.ts +245 -7
- package/src/version.ts +1 -1
package/src/core/generator.ts
CHANGED
|
@@ -560,6 +560,7 @@ ${callPrelude}${guards} return getRuntimeBridge().call('${moduleId}', '${func.n
|
|
|
560
560
|
this.getTypeParameters(cls.typeParameters),
|
|
561
561
|
[
|
|
562
562
|
...cls.properties.map(property => property.type),
|
|
563
|
+
...(cls.accessors ?? []).map(accessor => accessor.type),
|
|
563
564
|
...cls.methods.flatMap(method => [
|
|
564
565
|
method.returnType,
|
|
565
566
|
...method.parameters.map(p => p.type),
|
|
@@ -604,6 +605,15 @@ ${callPrelude}${guards} return getRuntimeBridge().call('${moduleId}', '${func.n
|
|
|
604
605
|
`${this.escapeIdentifier(p.name)}: ${this.typeToTsFromPython(p.type, classGenericContext, 'value')};`
|
|
605
606
|
)
|
|
606
607
|
.join(' ');
|
|
608
|
+
// @property / cached_property members are bridge-accessed getters; mirror
|
|
609
|
+
// the concrete class's `get name(): Promise<T>` as readonly Promise props
|
|
610
|
+
// so protocol typings include them too (IR 0.3.0).
|
|
611
|
+
const accessors = (cls.accessors ?? [])
|
|
612
|
+
.map(
|
|
613
|
+
a =>
|
|
614
|
+
`readonly ${this.escapeIdentifier(a.name)}: Promise<${this.typeToTsFromPython(a.type, classGenericContext, 'return')}>;`
|
|
615
|
+
)
|
|
616
|
+
.join(' ');
|
|
607
617
|
const methods = cls.methods
|
|
608
618
|
.filter(m => m.name !== '__init__')
|
|
609
619
|
.map(m => {
|
|
@@ -628,7 +638,7 @@ ${callPrelude}${guards} return getRuntimeBridge().call('${moduleId}', '${func.n
|
|
|
628
638
|
return `${this.escapeIdentifier(m.name)}: ${methodTypeParamDecl}(${paramsDecl}) => ${returnType};`;
|
|
629
639
|
})
|
|
630
640
|
.join(' ');
|
|
631
|
-
return wrapAlias(`{ ${props} ${methods} }`);
|
|
641
|
+
return wrapAlias(`{ ${props} ${accessors} ${methods} }`);
|
|
632
642
|
}
|
|
633
643
|
|
|
634
644
|
if (cls.kind === 'dataclass' || cls.kind === 'pydantic') {
|
|
@@ -643,6 +653,7 @@ ${callPrelude}${guards} return getRuntimeBridge().call('${moduleId}', '${func.n
|
|
|
643
653
|
return wrapAlias(`{ ${props} }`);
|
|
644
654
|
}
|
|
645
655
|
|
|
656
|
+
const moduleId = moduleName ?? '__main__';
|
|
646
657
|
const sortedMethods = [...cls.methods].sort((a, b) => a.name.localeCompare(b.name));
|
|
647
658
|
const methodBodies: string[] = [];
|
|
648
659
|
const methodDeclarations: string[] = [];
|
|
@@ -650,6 +661,12 @@ ${callPrelude}${guards} return getRuntimeBridge().call('${moduleId}', '${func.n
|
|
|
650
661
|
sortedMethods
|
|
651
662
|
.filter(method => method.name !== '__init__')
|
|
652
663
|
.forEach(method => {
|
|
664
|
+
// @classmethod and @staticmethod become `static` members invoked through
|
|
665
|
+
// the class (`Class.method`), not the instance handle. Instance methods
|
|
666
|
+
// (the default, or an absent methodKind) keep the existing emission so
|
|
667
|
+
// their output stays byte-identical.
|
|
668
|
+
const isStatic = method.methodKind === 'class' || method.methodKind === 'static';
|
|
669
|
+
const staticPrefix = isStatic ? 'static ' : '';
|
|
653
670
|
const fparams = method.parameters.filter(p => p.name !== 'self' && p.name !== 'cls');
|
|
654
671
|
const methodOwnGenericContext = this.buildGenericRenderContext(
|
|
655
672
|
this.getTypeParameters(method.typeParameters),
|
|
@@ -737,11 +754,11 @@ ${callPrelude}${guards} return getRuntimeBridge().call('${moduleId}', '${func.n
|
|
|
737
754
|
}
|
|
738
755
|
rest.push(`kwargs: ${kwargsType}`);
|
|
739
756
|
overloads.push(
|
|
740
|
-
` ${mname}${methodTypeParamDecl}(${[...head, ...rest].join(', ')}): Promise<${returnType}>;`
|
|
757
|
+
` ${staticPrefix}${mname}${methodTypeParamDecl}(${[...head, ...rest].join(', ')}): Promise<${returnType}>;`
|
|
741
758
|
);
|
|
742
759
|
if (varArgsParam && needsVarArgsArray) {
|
|
743
760
|
overloads.push(
|
|
744
|
-
` ${mname}${methodTypeParamDecl}(${[...head, `kwargs: ${kwargsType}`].join(', ')}): Promise<${returnType}>;`
|
|
761
|
+
` ${staticPrefix}${mname}${methodTypeParamDecl}(${[...head, `kwargs: ${kwargsType}`].join(', ')}): Promise<${returnType}>;`
|
|
745
762
|
);
|
|
746
763
|
}
|
|
747
764
|
}
|
|
@@ -767,13 +784,18 @@ ${callPrelude}${guards} return getRuntimeBridge().call('${moduleId}', '${func.n
|
|
|
767
784
|
const guardLines = emitArgGuards(callDescriptor);
|
|
768
785
|
const guards = guardLines.length > 0 ? `${guardLines.join('\n')}\n` : '';
|
|
769
786
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
787
|
+
const callExpr = isStatic
|
|
788
|
+
? `getRuntimeBridge().call('${moduleId}', '${cls.name}.${method.name}', __args${
|
|
789
|
+
needsKwargsParam ? ', __kwargs' : ''
|
|
790
|
+
})`
|
|
791
|
+
: `getRuntimeBridge().callMethod(this.__handle, '${method.name}', __args${
|
|
792
|
+
needsKwargsParam ? ', __kwargs' : ''
|
|
793
|
+
})`;
|
|
794
|
+
methodBodies.push(`${overloadDecl} ${staticPrefix}async ${mname}${methodTypeParamDecl}(${paramsDecl}): Promise<${returnType}> {
|
|
795
|
+
${callPrelude}${guards} return ${callExpr};
|
|
774
796
|
}`);
|
|
775
797
|
methodDeclarations.push(
|
|
776
|
-
`${overloadDecl}${overloads.length > 0 ? '' : ` ${mname}${methodTypeParamDecl}(${paramsDecl}): Promise<${returnType}>;\n`}`
|
|
798
|
+
`${overloadDecl}${overloads.length > 0 ? '' : ` ${staticPrefix}${mname}${methodTypeParamDecl}(${paramsDecl}): Promise<${returnType}>;\n`}`
|
|
777
799
|
);
|
|
778
800
|
});
|
|
779
801
|
|
|
@@ -898,7 +920,24 @@ ${callPrelude}${guards} return getRuntimeBridge().callMethod(this.__handle, '
|
|
|
898
920
|
};
|
|
899
921
|
})();
|
|
900
922
|
|
|
901
|
-
|
|
923
|
+
// @property / functools.cached_property → TS getters returning Promise<T>.
|
|
924
|
+
// Reading the attribute fires the getter on the Python side; the bridge
|
|
925
|
+
// resolves it via callMethod with no args. Sorted for stable output.
|
|
926
|
+
const accessorBodies: string[] = [];
|
|
927
|
+
const accessorDeclarations: string[] = [];
|
|
928
|
+
const sortedAccessors = [...(cls.accessors ?? [])].sort((a, b) => a.name.localeCompare(b.name));
|
|
929
|
+
sortedAccessors.forEach(accessor => {
|
|
930
|
+
const aname = this.escapeIdentifier(accessor.name);
|
|
931
|
+
const accessorType = this.typeToTsFromPython(accessor.type, classGenericContext, 'return');
|
|
932
|
+
const jsdocAcc = this.generateJsDoc(accessor.docstring);
|
|
933
|
+
accessorBodies.push(
|
|
934
|
+
`${jsdocAcc} get ${aname}(): Promise<${accessorType}> { return getRuntimeBridge().callMethod(this.__handle, '${accessor.name}', []); }`
|
|
935
|
+
);
|
|
936
|
+
accessorDeclarations.push(`${jsdocAcc} get ${aname}(): Promise<${accessorType}>;\n`);
|
|
937
|
+
});
|
|
938
|
+
const accessorsImpl = accessorBodies.length > 0 ? `${accessorBodies.join('\n')}\n` : '';
|
|
939
|
+
const accessorsDecl = accessorDeclarations.length > 0 ? `${accessorDeclarations.join('')}` : '';
|
|
940
|
+
|
|
902
941
|
const methodsSection = methodBodies.length > 0 ? `\n${methodBodies.join('\n')}\n` : '\n';
|
|
903
942
|
const declarationMethodsSection =
|
|
904
943
|
methodDeclarations.length > 0 ? `\n${methodDeclarations.join('')}\n` : '\n';
|
|
@@ -913,14 +952,14 @@ ${ctorSpec.callPrelude}${ctorGuards} const handle = await getRuntimeBridge().
|
|
|
913
952
|
});
|
|
914
953
|
return ${newClassExpr};
|
|
915
954
|
}
|
|
916
|
-
static fromHandle${classTypeParamDecl}(handle: string): ${classSelfType} { return ${newClassExpr}; }${methodsSection} async disposeHandle(): Promise<void> { await getRuntimeBridge().disposeInstance(this.__handle); }
|
|
955
|
+
static fromHandle${classTypeParamDecl}(handle: string): ${classSelfType} { return ${newClassExpr}; }${methodsSection}${accessorsImpl} async disposeHandle(): Promise<void> { await getRuntimeBridge().disposeInstance(this.__handle); }
|
|
917
956
|
}
|
|
918
957
|
`;
|
|
919
958
|
|
|
920
959
|
const declaration = `${jsdoc}export class ${cname}${classTypeParamDecl} {
|
|
921
960
|
private readonly __handle: string;
|
|
922
961
|
private constructor(handle: string);
|
|
923
|
-
${ctorSpec.declaration} static fromHandle${classTypeParamDecl}(handle: string): ${classSelfType};${declarationMethodsSection} disposeHandle(): Promise<void>;
|
|
962
|
+
${ctorSpec.declaration} static fromHandle${classTypeParamDecl}(handle: string): ${classSelfType};${declarationMethodsSection}${accessorsDecl} disposeHandle(): Promise<void>;
|
|
924
963
|
}
|
|
925
964
|
`;
|
|
926
965
|
|
package/src/dev.ts
CHANGED
|
@@ -343,9 +343,7 @@ async function listChildDirectories(current: string): Promise<string[]> {
|
|
|
343
343
|
return [];
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
-
return entries
|
|
347
|
-
.filter(entry => entry.isDirectory())
|
|
348
|
-
.map(entry => join(current, entry.name));
|
|
346
|
+
return entries.filter(entry => entry.isDirectory()).map(entry => join(current, entry.name));
|
|
349
347
|
}
|
|
350
348
|
|
|
351
349
|
async function isWatchableDirectory(current: string, ignoredPaths: string[]): Promise<boolean> {
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BasePythonBridge - shared RPC delegation for the bridge facades.
|
|
3
|
+
*
|
|
4
|
+
* The three bridge facades (NodeBridge/HttpBridge/PyodideBridge) all extend
|
|
5
|
+
* DisposableBase (lifecycle/resources) and implement PythonRuntime by HOLDING
|
|
6
|
+
* an RpcClient. The PythonRuntime delegation was byte-identical across all
|
|
7
|
+
* three: each method does `await this.ensureReady()` then forwards to the held
|
|
8
|
+
* RpcClient. This base collapses that duplication onto a single
|
|
9
|
+
* `getRpcClient()` accessor while leaving each facade free to own its own
|
|
10
|
+
* RpcClient field (for constructor wiring, resource tracking, and — in
|
|
11
|
+
* NodeBridge's case — a caching override of call()).
|
|
12
|
+
*
|
|
13
|
+
* It carries no transport/codec/lifecycle specifics: doInit/doDispose remain
|
|
14
|
+
* abstract on DisposableBase and stay per-facade.
|
|
15
|
+
*
|
|
16
|
+
* @see https://github.com/bbopen/tywrap/issues/149
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { PythonRuntime, BridgeInfo } from '../types/index.js';
|
|
20
|
+
|
|
21
|
+
import { DisposableBase } from './bounded-context.js';
|
|
22
|
+
import type { RpcClient, GetBridgeInfoOptions } from './rpc-client.js';
|
|
23
|
+
import type { TransportCapabilities } from './transport.js';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Shared base for the bridge facades. Implements the PythonRuntime RPC
|
|
27
|
+
* delegation (plus getBridgeInfo) over a single held RpcClient, exposed by the
|
|
28
|
+
* abstract {@link getRpcClient} accessor. Lifecycle (doInit/doDispose) and the
|
|
29
|
+
* RpcClient's construction/ownership remain the subclass's responsibility.
|
|
30
|
+
*/
|
|
31
|
+
export abstract class BasePythonBridge extends DisposableBase implements PythonRuntime {
|
|
32
|
+
/**
|
|
33
|
+
* Return the held RpcClient that the shared delegating methods forward to.
|
|
34
|
+
* Subclasses construct, track, and own the RpcClient; this accessor lets the
|
|
35
|
+
* base reach it without dictating how it is stored.
|
|
36
|
+
*/
|
|
37
|
+
protected abstract getRpcClient(): RpcClient;
|
|
38
|
+
|
|
39
|
+
// ===========================================================================
|
|
40
|
+
// RPC METHODS (delegate to the held RpcClient)
|
|
41
|
+
// ===========================================================================
|
|
42
|
+
|
|
43
|
+
async call<T = unknown>(
|
|
44
|
+
module: string,
|
|
45
|
+
functionName: string,
|
|
46
|
+
args: unknown[],
|
|
47
|
+
kwargs?: Record<string, unknown>
|
|
48
|
+
): Promise<T> {
|
|
49
|
+
await this.ensureReady();
|
|
50
|
+
return this.getRpcClient().call<T>(module, functionName, args, kwargs);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async instantiate<T = unknown>(
|
|
54
|
+
module: string,
|
|
55
|
+
className: string,
|
|
56
|
+
args: unknown[],
|
|
57
|
+
kwargs?: Record<string, unknown>
|
|
58
|
+
): Promise<T> {
|
|
59
|
+
await this.ensureReady();
|
|
60
|
+
return this.getRpcClient().instantiate<T>(module, className, args, kwargs);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async callMethod<T = unknown>(
|
|
64
|
+
handle: string,
|
|
65
|
+
methodName: string,
|
|
66
|
+
args: unknown[],
|
|
67
|
+
kwargs?: Record<string, unknown>
|
|
68
|
+
): Promise<T> {
|
|
69
|
+
await this.ensureReady();
|
|
70
|
+
return this.getRpcClient().callMethod<T>(handle, methodName, args, kwargs);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async disposeInstance(handle: string): Promise<void> {
|
|
74
|
+
await this.ensureReady();
|
|
75
|
+
return this.getRpcClient().disposeInstance(handle);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Fetch bridge diagnostics and feature availability.
|
|
80
|
+
*/
|
|
81
|
+
async getBridgeInfo(options?: GetBridgeInfoOptions): Promise<BridgeInfo> {
|
|
82
|
+
await this.ensureReady();
|
|
83
|
+
return this.getRpcClient().getBridgeInfo(options);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Describe this backend's transport-level capabilities (Arrow/binary/chunking/
|
|
88
|
+
* streaming support, max frame size). The descriptor is static and does NOT
|
|
89
|
+
* depend on lifecycle state, so this intentionally does not `ensureReady()` —
|
|
90
|
+
* callers can query it before connecting to decide how to use the bridge.
|
|
91
|
+
*/
|
|
92
|
+
capabilities(): TransportCapabilities {
|
|
93
|
+
return this.getRpcClient().capabilities();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Ensure the facade is initialized before delegating an RPC. Replicates the
|
|
98
|
+
* auto-init that the bounded execute path provided pre-composition, so the
|
|
99
|
+
* facade's own doInit pre-work runs before any RPC.
|
|
100
|
+
*/
|
|
101
|
+
protected async ensureReady(): Promise<void> {
|
|
102
|
+
if (!this.isReady) {
|
|
103
|
+
await this.init();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|