Core RPC¶
The core module provides the server, connection, transport interface, error types, and convenience functions for defining and running RPC services.
Typical Usage¶
Most users only need serve_pipe (testing) or connect (subprocess):
from vgi_rpc import serve_pipe, connect
# In-process (tests)
with serve_pipe(MyService, MyServiceImpl()) as proxy:
proxy.my_method(arg=42)
# Subprocess
with connect(MyService, ["python", "worker.py"]) as proxy:
proxy.my_method(arg=42)
For more control, use RpcServer and RpcConnection directly.
API Reference¶
RpcServer¶
RpcServer
¶
RpcServer(
protocol: type,
implementation: object,
*,
extra_protocols: Sequence[tuple[type, object]] = (),
identity: object | None = None,
external_location: ExternalLocationConfig | None = None,
server_id: str | None = None,
server_version: str = "",
enable_describe: bool = False,
ipc_validation: IpcValidation | None = None,
include_tracebacks: bool = True,
grant_keys: GrantKeys | Literal["env"] | None = "env"
)
Dispatches RPC requests to an implementation over IO-stream transports.
Initialize with a protocol type and its implementation.
| PARAMETER | DESCRIPTION |
|---|---|
protocol
|
The Protocol class defining the RPC interface. If the
class declares a
TYPE:
|
implementation
|
Object implementing all methods from protocol.
TYPE:
|
extra_protocols
|
Additional protocol stays the primary: it is what
TYPE:
|
identity
|
An :class:
TYPE:
|
external_location
|
Optional ExternalLocation configuration.
TYPE:
|
server_id
|
Optional server identifier; auto-generated if
TYPE:
|
server_version
|
Build version string included in access log entries.
TYPE:
|
enable_describe
|
When
TYPE:
|
ipc_validation
|
Validation level for incoming IPC batches.
TYPE:
|
include_tracebacks
|
Whether EXCEPTION batches carry the remote
traceback (
TYPE:
|
grant_keys
|
Sealed-grant configuration (WIRE_PROTOCOL.md §16).
TYPE:
|
Source code in vgi_rpc/rpc/_server.py
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 | |
methods
property
¶
methods: Mapping[str, RpcMethodInfo]
Return method metadata for this server's protocol.
bindings
property
¶
The protocols this server hosts, keyed by wire name, primary first.
Framework-internal: dispatch, state-type resolution and telemetry read
it. Ordinary callers want methods or implementation_for.
Read-only. The hosted set is sealed at construction -- earlier than the "before serving starts" WIRE_PROTOCOL.md §3.1 requires -- and there is no registration API afterwards, so a protocol cannot appear on one transport and not another, or change what reflection already reported.
external_config
property
¶
external_config: ExternalLocationConfig | None
The ExternalLocation configuration, if any.
protocol_name
property
¶
Wire name of the primary protocol.
The declared protocol_name ClassVar when there is one, otherwise the
class name — so this is the routing key, not a Python identifier that
merely resembles it. A server hosting several protocols reports the
primary here; per-call labelling reads RpcMethodInfo.protocol_name.
server_version
property
¶
Version string passed at construction (empty if not set).
protocol_version
property
¶
Application protocol surface version declared by the Protocol class.
Read from vars(protocol).get("protocol_version") at construction
(a ClassVar[str] in canonical semver MAJOR.MINOR.PATCH form, or
None when the Protocol opts out). When set, the server enforces
an exact major+minor match on every dispatched request via
_check_protocol_version.
identity
property
¶
The hosted vgi_rpc.Identity.v1 implementation, when there is one.
grant_keys
property
¶
The sealed-grant configuration, when grants are on.
include_tracebacks
property
¶
Whether EXCEPTION batches carry the remote traceback, on every transport.
On by default everywhere. An earlier draft omitted it on HTTP and TCP; that hid chained causes from the DuckDB extension, which puts the remote traceback into the user-visible error. The setting stays so an operator who does not want stack traces leaving the process can turn them off for the whole server.
ctx_methods
property
¶
Method names whose implementations accept a ctx parameter.
describe_enabled
property
¶
Whether this server hosts the reflection protocol.
Named for the enable_describe constructor argument it reports, and
kept because the HTTP factory gates its human-readable describe page on
it.
transport_kind
property
¶
transport_kind: TransportKind | None
Coarse identifier of the bound transport, or None before serving begins.
Set by the framework right before the first request is dispatched
(lazy on HTTP for fork-safety). Workers may read this directly,
or rely on the on_serve_start lifecycle hook for one-shot
startup work.
transport_capabilities
property
¶
Capabilities advertised by the bound transport.
Currently includes "shm" when a :class:ShmPipeTransport is
bound. Empty before a transport is bound and for kinds without
special capabilities.
implementation_for
¶
implementation_for(info: RpcMethodInfo) -> object
Return the implementation that owns info's method.
implementation keeps returning the primary, because ~9 call sites
read it and silently changing its meaning is worse than either leaving
it or replacing it. Dispatch and stream rehydration use this instead, so
a second protocol's state is never rehydrated against the first
protocol's object.
Source code in vgi_rpc/rpc/_server.py
wants_ctx
¶
wants_ctx(info: RpcMethodInfo) -> bool
Whether info's owning implementation declares a ctx parameter.
Resolved against the binding that owns the method rather than against
the primary's set. ctx_methods is per binding precisely because
two protocols may define the same method name and only one may want a
:class:CallContext -- but every dispatch path read the primary's
set, so a secondary protocol whose methods all take ctx got none of
them. vgi_rpc.Identity.v1 is exactly that shape: both its methods
need the caller's :class:AuthContext to apply their guards, and
neither could be called at all until this looked at the right binding.
Source code in vgi_rpc/rpc/_server.py
protocol_hash_for
¶
protocol_hash_for(info: RpcMethodInfo | None) -> str
Return the canonical hash of the protocol that owns info's method.
Pairs with the protocol field, which is already per-binding. The
hash was not, and the two disagreeing is worse than either being wrong
alone: access-log-spec.md makes protocol_hash the registry key
for decoding archived records, so a record naming one protocol and
carrying another's digest is decoded against the wrong description --
and nothing about it looks wrong.
Falls back to the primary for a framework endpoint that belongs to no protocol, which is what the spec prescribes for those -- and for an unresolved method, where there is no owner to name.
Source code in vgi_rpc/rpc/_server.py
check_protocol_agreement
¶
check_protocol_agreement(info: RpcMethodInfo) -> None
Require the request's routing metadata to agree with info.
On HTTP the protocol rides twice: in vgi_rpc.protocol and as a path
segment. The metadata field is canonical -- it is the only carrier on
the stdio, unix and named-pipe transports -- and the path segment is a
required faithful projection, present so an edge device can act on the
protocol without an Arrow parser.
Left unchecked, the two may disagree, and then edge policy is applied
to one protocol while the worker runs another: the
Content-Length/Transfer-Encoding shape. Mirrors the vgi_rpc.method
check the HTTP dispatchers already make.
Absent is an error, not an exemption. The rationale that once stood here -- "the single-carrier case: the caller resolved from that key to begin with" -- is true on stdio, unix and named pipes and false here, because on HTTP the caller resolved from the path. Accepting a request with no routing key therefore means routing on the projection alone, which is exactly the case the canonical/projection split exists to catch: an intermediary that rewrites the path cannot touch the metadata, so a rewrite is detectable only while both carriers are required to be present and to agree.
| PARAMETER | DESCRIPTION |
|---|---|
info
|
The method resolved from the path segment. Its
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ProtocolNotSpecifiedError
|
The request carried no routing key. |
ProtocolNotSupportedError
|
The two carriers name different protocols. |
Source code in vgi_rpc/rpc/_server.py
gate_version
¶
gate_version(info: RpcMethodInfo) -> None
Enforce the declared protocol_version of the binding info belongs to.
A server hosting several protocols has a version per binding, so the gate has to read the resolved method's, not the primary's. Silently gating a secondary protocol against the primary's version is the shape of bug that produces a confusing mismatch message pointing at the wrong protocol.
No-op when the binding's Protocol declares no protocol_version, and
for a binding marked version-exempt (reflection): that is the
diagnostic path a mismatched client uses to find out what mismatched,
so gating it would deny the client its own diagnosis.
| PARAMETER | DESCRIPTION |
|---|---|
info
|
The resolved method. Its
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ProtocolVersionError
|
On a major or minor mismatch, with a directional message naming which side to upgrade. |
Source code in vgi_rpc/rpc/_server.py
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 | |
serve
¶
serve(
transport: RpcTransport,
*,
auth: AuthContext | None = None,
peer_evidence: PeerEvidenceSet | None = None,
transport_metadata: Mapping[str, Any] | None = None
) -> None
Serve requests until close, optionally under one connection identity.
HTTP installs request-scoped identity in middleware and therefore uses
the defaults. Stateful raw transports resolve once after accept and
pass an immutable connection snapshot here; every unary call, stream
turn, and cancellation hook on that connection then sees the same
AuthContext and PeerEvidenceSet.
Source code in vgi_rpc/rpc/_server.py
1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 | |
serve_one
¶
serve_one(
transport: RpcTransport,
*,
shm_cache: _ConnectionShm | None = None
) -> None
Handle a single RPC call (any method type) over the given transport.
Protocol-level errors (VersionError, RpcError from missing
metadata) are caught, written back as error responses, and the
method returns normally so the serve loop can continue.
| PARAMETER | DESCRIPTION |
|---|---|
transport
|
The transport to read the request from and write the response to.
TYPE:
|
shm_cache
|
Per-connection SHM segment cache supplied by
:meth:
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ArrowInvalid
|
If the incoming data is not valid Arrow IPC.
An error response is written to transport before raising so
the client can read a structured |
Source code in vgi_rpc/rpc/_server.py
1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 | |
RpcConnection¶
RpcConnection
¶
RpcConnection(
protocol: type[P],
transport: RpcTransport,
on_log: Callable[[Message], None] | None = None,
*,
external_location: ExternalLocationConfig | None = None,
ipc_validation: IpcValidation = FULL
)
Context manager that provides a typed RPC proxy over a transport.
The type parameter P is the Protocol class, enabling IDE
autocompletion for all methods defined on the protocol::
with RpcConnection(MyProtocol, transport) as svc:
result = svc.add(a=1, b=2) # IDE sees MyProtocol methods
Initialize with a protocol type and transport.
Source code in vgi_rpc/rpc/_client.py
__enter__
¶
Enter the context and return a typed proxy.
Source code in vgi_rpc/rpc/_client.py
__exit__
¶
__exit__(
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None
Close the transport.
Source code in vgi_rpc/rpc/_client.py
RpcTransport¶
RpcTransport
¶
Bases: Protocol
Bidirectional byte stream transport.
RpcMethodInfo¶
RpcMethodInfo
dataclass
¶
RpcMethodInfo(
name: str,
params_schema: Schema,
result_schema: Schema,
result_type: object,
method_type: MethodType,
has_return: bool,
doc: str | None,
param_defaults: dict[str, object] = dict(),
param_types: dict[str, object] = dict(),
param_docs: dict[str, str] = dict(),
header_type: (
type[ArrowSerializableDataclass] | None
) = None,
is_exchange: bool | None = None,
protocol_name: str = "",
)
Metadata for a single RPC method, derived from Protocol type hints.
Produced by :func:rpc_methods when introspecting a Protocol class.
Each instance describes one method's wire-protocol details: its Arrow
schemas, parameter types and defaults, and the original docstring.
| ATTRIBUTE | DESCRIPTION |
|---|---|
name |
Method name as it appears on the Protocol.
TYPE:
|
params_schema |
Arrow schema for the serialized request parameters.
TYPE:
|
result_schema |
Arrow schema for the serialized response (unary only; empty schema for stream methods).
TYPE:
|
result_type |
The raw Python return-type annotation (e.g.
TYPE:
|
method_type |
Whether this is a
TYPE:
|
has_return |
TYPE:
|
doc |
The method's docstring from the Protocol class, or
TYPE:
|
param_defaults |
Mapping of parameter name to default value for parameters that have defaults in the Protocol signature.
TYPE:
|
param_types |
Mapping of parameter name to its Python type annotation
(excludes
TYPE:
|
param_docs |
Mapping of parameter name to its documented description,
parsed from the Protocol method's docstring
TYPE:
|
header_type |
For stream methods with a header, the concrete
TYPE:
|
is_exchange |
For stream methods,
TYPE:
|
protocol_name |
Name of the Protocol this method belongs to. Makes an
TYPE:
|
MethodType¶
MethodType
¶
Bases: Enum
Classification of RPC method patterns.
Errors¶
RpcError
¶
RpcError(
error_type: str,
error_message: str,
remote_traceback: str,
*,
request_id: str = "",
error_code: str = "",
error_kind: str = "",
error_details: list[dict[str, Any]] | None = None
)
Bases: Exception
Raised on the client side when the server reports an error.
Carries the three layers of the error model (WIRE_PROTOCOL.md §8):
- :attr:
error_code-- the canonical code's name ("UNAVAILABLE"), or""when the server sent none (a server older than the model). :attr:codereads it as a :class:~vgi_rpc.errors.Code. - :attr:
error_kind-- the reason a client branches on, or"". - :attr:
error_details-- the detail objects as received, unknown types included. The typed accessors (:meth:retry_info, :meth:bad_request, ...) return the catalog entry of that type, ignoring the rest.
:meth:is_retryable classifies; nothing here retries. Automatic retry is
opt-in because a method may not be idempotent.
Initialize with error details from the remote side.
| PARAMETER | DESCRIPTION |
|---|---|
error_type
|
The remote exception's class name.
TYPE:
|
error_message
|
The remote message.
TYPE:
|
remote_traceback
|
The remote traceback, or
TYPE:
|
request_id
|
The request correlation ID, when known.
TYPE:
|
error_code
|
The
TYPE:
|
error_kind
|
The
TYPE:
|
error_details
|
The decoded
TYPE:
|
Source code in vgi_rpc/rpc/_common.py
is_retryable
¶
Whether retrying this call is warranted, by the rule in WIRE_PROTOCOL.md §8.
UNAVAILABLE always; RESOURCE_EXHAUSTED only with RetryInfo.
When :meth:retry_info is present a retry waits at least that long.
Source code in vgi_rpc/rpc/_common.py
details
¶
Return the details this client understands, in wire order; unknown types skipped.
error_info
¶
retry_info
¶
bad_request
¶
precondition_failure
¶
quota_failure
¶
resource_info
¶
help
¶
localized_message
¶
VersionError
¶
Bases: Exception
Raised when a request has a missing or incompatible protocol version.
ProtocolVersionError
¶
ProtocolVersionError(
message: str = "",
*,
protocol: str = "",
client_version: str = "",
server_version: str = ""
)
Bases: VersionError
Raised when the client's declared protocol_version is incompatible with the server's.
Subclass of VersionError so existing catch sites in serve_one
(and the HTTP unary/stream wrappers) write a typed error stream and
continue. Carries a directional message that tells whoever reads it
which side to upgrade.
Build the error, keeping the two versions for the precondition detail.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
The directional, human-readable explanation.
TYPE:
|
protocol
|
The protocol whose version gate refused the call.
TYPE:
|
client_version
|
What the client declared, or
TYPE:
|
server_version
|
What the server's binding declares.
TYPE:
|
Source code in vgi_rpc/rpc/_common.py
error_details
property
¶
One protocol_version violation naming the protocol, when known.
ProtocolVersionError (a VersionError subclass) is raised at the dispatch
boundary when the client's vgi_rpc.protocol_version differs from the
server's on the major+minor components (patch is ignored). It is only active
when the Protocol class declares a protocol_version; otherwise the check is
disabled. __describe__ is exempt so a mismatched client can still introspect
to discover the server's version.
Typed marker errors¶
These exception classes carry a stable error_kind class attribute that
the wire serializer surfaces as the vgi_rpc.error_kind metadata key on
the EXCEPTION-level batch. Clients can pattern-match the kind instead of
substring-searching the error message.
MethodNotImplementedError
¶
Bases: AttributeError
Raised server-side when no handler is registered for the requested RPC method.
Subclass of AttributeError so existing except AttributeError callers
keep working. Carries a stable error_kind class attribute that the
wire serializer surfaces as a top-level vgi_rpc.error_kind metadata
key on the EXCEPTION-level error batch, so clients can pattern-match on
the kind rather than substring-searching the message text.
Used by callers that want to detect "old server doesn't know this method" cleanly (e.g. capability detection + fallback to a legacy RPC method).
SessionLostError
¶
Bases: Exception
Raised server-side when a sticky session token cannot be honoured.
Surfaced over the wire with error_kind="session_lost" so clients can
pattern-match the kind without substring-searching the message. Causes
include: token presented to a different worker than the one that minted
it (server_id mismatch), the registry entry aged out via TTL eviction,
AAD mismatch (cross-principal replay), or any other validation failure.
Sticky session machinery is HTTP-only; this error never originates from pipe/unix transports.
ServerDrainingError
¶
Bases: Exception
Raised server-side when a sticky-enabled worker is draining and refuses new sessions.
Surfaced over the wire with error_kind="server_draining". Existing
sessions continue to serve through TTL or explicit close; only new
ctx.open_session calls are rejected. Operators trigger drain via
RpcServer.drain() (typically from a SIGTERM handler) ahead of
deploy-time worker rotation.
Build the error.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Human-readable explanation.
TYPE:
|
retry_after
|
Seconds before a retry -- which a load balancer will usually route to a worker that is not draining.
TYPE:
|
Source code in vgi_rpc/rpc/_common.py
See also IPCError in the Serialization module.
CallStatistics¶
CallStatistics
dataclass
¶
CallStatistics(
input_batches: int = 0,
output_batches: int = 0,
input_rows: int = 0,
output_rows: int = 0,
input_bytes: int = 0,
output_bytes: int = 0,
)
Mutable accumulator of per-call I/O counters for usage accounting.
Created at dispatch start and populated as batches flow through the server. Surfaced through the access log and OTel dispatch hook.
Byte measurement: uses pa.RecordBatch.get_total_buffer_size()
which reports logical Arrow buffer sizes (O(columns), negligible cost).
This is an approximation — it does not include IPC framing
overhead (padding, schema messages, EOS markers).
| ATTRIBUTE | DESCRIPTION |
|---|---|
input_batches |
Number of input batches read by the server.
TYPE:
|
output_batches |
Number of output batches written by the server.
TYPE:
|
input_rows |
Total rows across all input batches.
TYPE:
|
output_rows |
Total rows across all output batches.
TYPE:
|
input_bytes |
Approximate logical bytes across all input batches.
TYPE:
|
output_bytes |
Approximate logical bytes across all output batches.
TYPE:
|
Convenience Functions¶
run_server
¶
run_server(
protocol_or_server: type | RpcServer,
implementation: object | None = None,
) -> None
Serve RPC requests, defaulting to stdin/stdout pipe transport.
This is the recommended entry point for subprocess workers. Accepts
either a (protocol, implementation) pair or a pre-built RpcServer.
The function parses sys.argv and supports the following CLI flags:
--http— Serve over HTTP instead of stdin/stdout (requiresvgi-rpc[http]).--unix PATH— Serve raw framing over a Unix domain socket.--tcp [HOST:]PORT— Serve raw framing over a TCP socket. Host defaults to127.0.0.1(loopback only);PORTmay be0to auto-select. No auth/TLS — use--httpfor untrusted networks.--host HOST— HTTP bind address (default127.0.0.1).--port PORT— HTTP port (default0, auto-select).--describe— Enable the__describe__introspection method.--access-log PATH— Append JSONL access log records toPATH. The cross-language conformance contract requires every worker to accept this flag; seedocs/access-log-spec.md.--max-response-bytes N— HTTP-only. Cap the outgoing HTTP body of every method response atNbytes (including IPC framing). For producer streams, controls when the framework mints a continuation token to split the response across multiple HTTP turns. Default: no body cap. Env:VGI_RPC_MAX_RESPONSE_BYTES.--max-externalized-response-bytes N— HTTP-only. Cap the total bytes uploaded to external storage during one HTTP response. Default: unbounded. Env:VGI_RPC_MAX_EXTERNALIZED_RESPONSE_BYTES.--max-stream-response-bytes N— Deprecated; alias for--max-response-bytes.
Without --http the server runs over stdin/stdout pipes (the
default, suitable for SubprocessTransport).
| PARAMETER | DESCRIPTION |
|---|---|
protocol_or_server
|
A Protocol class (requires implementation) or
an already-constructed
TYPE:
|
implementation
|
The implementation object. Required when
protocol_or_server is a Protocol class; must be
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
TypeError
|
On invalid argument combinations. |
Source code in vgi_rpc/rpc/__init__.py
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 | |
connect
¶
connect(
protocol: type[P],
cmd: list[str],
*,
on_log: Callable[[Message], None] | None = None,
external_location: ExternalLocationConfig | None = None,
stderr: StderrMode = INHERIT,
stderr_logger: Logger | None = None,
ipc_validation: IpcValidation = FULL
) -> Iterator[P]
Connect to a subprocess RPC server.
Context manager that spawns a subprocess, yields a typed proxy, and cleans up on exit.
| PARAMETER | DESCRIPTION |
|---|---|
protocol
|
The Protocol class defining the RPC interface.
TYPE:
|
cmd
|
Command to spawn the subprocess worker.
TYPE:
|
on_log
|
Optional callback for log messages from the server.
TYPE:
|
external_location
|
Optional ExternalLocation configuration for resolving and producing externalized batches.
TYPE:
|
stderr
|
How to handle the child's stderr stream (see :class:
TYPE:
|
stderr_logger
|
Logger for
TYPE:
|
ipc_validation
|
Validation level for incoming IPC batches.
TYPE:
|
| YIELDS | DESCRIPTION |
|---|---|
P
|
A typed RPC proxy supporting all methods defined on protocol. |
Source code in vgi_rpc/rpc/__init__.py
serve_pipe
¶
serve_pipe(
protocol: type[P],
implementation: object,
*,
on_log: Callable[[Message], None] | None = None,
external_location: ExternalLocationConfig | None = None,
ipc_validation: IpcValidation | None = None
) -> Iterator[P]
Start an in-process pipe server and yield a typed client proxy.
Useful for tests and demos — no subprocess needed. A background thread
runs RpcServer.serve() on the server side of a pipe pair.
| PARAMETER | DESCRIPTION |
|---|---|
protocol
|
The Protocol class defining the RPC interface.
TYPE:
|
implementation
|
The implementation object.
TYPE:
|
on_log
|
Optional callback for log messages from the server.
TYPE:
|
external_location
|
Optional ExternalLocation configuration for resolving and producing externalized batches.
TYPE:
|
ipc_validation
|
Validation level for incoming IPC batches.
When
TYPE:
|
| YIELDS | DESCRIPTION |
|---|---|
P
|
A typed RPC proxy supporting all methods defined on protocol. |
Source code in vgi_rpc/rpc/__init__.py
describe_rpc
¶
describe_rpc(
protocol: type,
*,
methods: Mapping[str, RpcMethodInfo] | None = None
) -> str
Return a human-readable description of an RPC protocol's methods.