blackbull.grpc.registry¶
blackbull.grpc.registry
¶
gRPC service registry — maps /package.Service/Method to a handler.
This is the gRPC analogue of :class:blackbull.router.Router: it holds the
table of method paths and the coroutine that serves each one.
A unary handler is::
async def handler(request: bytes, context: GrpcContext) -> bytes
A server-streaming handler is an async generator that yields zero or more response messages::
async def handler(request: bytes, context: GrpcContext):
yield b'...'
yield b'...'
In both cases request is the (already de-framed) request message body and
the yielded / returned value is a response message body. Protobuf
(de)serialisation is the handler's responsibility — the framework stays
dependency-free. Handlers signal a non-OK result by raising
:class:GrpcError or calling context.abort(...).
A client-streaming or bidirectional handler takes an async iterator of
request messages instead of a single request::
async def handler(request_iter, context) -> bytes: # client-streaming
async for message in request_iter:
...
async def handler(request_iter, context): # bidirectional
async for message in request_iter:
yield ...
Response-streaming is detected automatically at registration via
:func:inspect.isasyncgenfunction; request-streaming is detected from the first
parameter name (request_iter / requests / request_iterator /
request_stream). Pass streaming= / client_streaming= explicitly to
override when a decorator hides the handler's nature.
GrpcMethod
¶
Bases: NamedTuple
A registered method: its handler and the two streaming axes.
streaming is the response axis (the handler is an async generator that
yields response messages); client_streaming is the request axis (the
handler takes an async iterator of request messages instead of a single
request: bytes). The four combinations are unary, server-streaming,
client-streaming, and bidirectional.
handler is annotated as a bare :class:~collections.abc.Callable rather
than :data:GrpcHandler: a response-streaming handler is an async generator
function (its call returns an async iterator, not an Awaitable), and a
plain Callable is the one form that stays runtime-isinstanceable for the
NamedTuple field check (see memory beartype-namedtuple-callable-alias).
GrpcServiceRegistry
¶
Holds the path -> GrpcMethod table for gRPC methods.
add_method(path, handler, *, streaming=None, client_streaming=None)
¶
Register handler for the fully-qualified method path
(/package.Service/Method or package.Service/Method).
streaming is the response axis — server-streaming (the handler is
an async generator that yields response messages). When None (the
default) it is auto-detected with :func:inspect.isasyncgenfunction;
pass True to force it for a handler whose async-generator nature is
hidden behind a wrapper, or False to force a single response.
Forcing False on an async-generator function is a contradiction and
raises ValueError.
client_streaming is the request axis — the handler takes an async
iterator of request messages (first parameter request_iter /
requests / request_iterator / request_stream) instead of a
single request: bytes. When None it is auto-detected from that
first parameter name; pass an explicit bool to override.
add_service(service, methods)
¶
Register every method_name -> handler in methods under the
fully-qualified service name (e.g. "helloworld.Greeter").
Each handler's streaming-ness is auto-detected individually.
lookup(path)
¶
Return the handler for path, or None if unregistered.
Backwards-compatible accessor (returns just the callable); use
:meth:lookup_method when the streaming flag is needed.
lookup_method(path)
¶
Return the :class:GrpcMethod for path, or None if
unregistered.
method(path, *, streaming=None, client_streaming=None)
¶
Decorator form of :meth:add_method.
methods()
¶
Return all registered method paths, in registration order.