grapec
Declare plain Python classes, call gRPC and thrift services with them.
import grapec
@grapec.struct(package="connectrpc.eliza.v1")
class SayRequest:
sentence: str
@grapec.struct(package="connectrpc.eliza.v1")
class SayResponse:
sentence: str
class ElizaService(grapec.Client, package="connectrpc.eliza.v1"):
@grapec.name("Say")
def say(self, request: SayRequest) -> SayResponse: ...
eliza = ElizaService("grpcs://demo.connectrpc.com")
reply = eliza.say(SayRequest(sentence="I feel tired today"))
print(reply.sentence)
That talks to the public ELIZA demo at demo.connectrpc.com, paste it into a file and run it.
The type hints are the schema. @grapec.struct turns a class into a keyword only dataclass that encodes and decodes itself with the protobuf wire format or the thrift binary protocol, and grapec.Client subclasses call methods on a standard gRPC or thrift server. There are no .proto or .thrift files to write and no generated code to check in. The only dependency is h2.
Pronounced /ɡreɪ.peɪk/, like "gray-pay-k".
Install
Requires Python 3.12+.
pip install grapec
# or
uv add grapec
Example
import enum
from datetime import datetime
import grapec
class Priority(enum.IntEnum):
UNSPECIFIED = 0
LOW = 1
HIGH = 2
@grapec.struct(package="example.hello.v1")
class Tag:
key: str
value: str
@grapec.struct(package="example.hello.v1")
class HelloRequest:
name: str
priority: Priority = Priority.LOW
tags: list[Tag] # repeated Tag
sent_at: datetime | None # optional google.protobuf.Timestamp
@grapec.struct(package="example.hello.v1")
class HelloReply:
message: str
class Greeter(grapec.Client, package="example.hello.v1"):
@grapec.name("SayHello")
def say_hello(self, request: HelloRequest) -> HelloReply: ...
greeter = Greeter("grpc://localhost:50051", timeout=5)
reply = greeter.say_hello(HelloRequest(name="grapec", tags=[Tag(key="lang", value="python")]))
data = bytes(reply) # protobuf wire format
HelloReply.from_bytes(data)
reply.to_json() # proto3 JSON mapping
print(grapec.export_proto(Greeter)) # the .proto for the other side
Field numbers follow declaration order, Annotated[int, grapec.Id(7)] pins one. The URL scheme picks the transport, grpc://, grpcs://, thrift:// or thrifts://. Connections are pooled per client, calls accept timeout=, metadata= and compression=. For asyncio, subclass grapec.AsyncClient and declare the methods with async def.
The same structs work with thrift. Methods may take several parameters, return scalars and declare the exceptions they throw:
from typing import Annotated
import grapec
@grapec.struct(package="store")
class NotFound(Exception):
key: str
@grapec.struct(package="store")
class Item:
key: str
count: Annotated[int, grapec.I32]
class Store(grapec.Client, package="store"):
@grapec.raises(NotFound)
def get(self, key: str) -> Item: ...
def put(self, item: Item) -> None: ...
store = Store("thrift://localhost:9090")
try:
item = store.get("answer")
except NotFound as exc:
print("no such key", exc.key)
More
- docs/reference.md covers struct rules, type mapping, sessions and pooling, dict and JSON views,
.protoexport and the thrift details. - examples/eliza.py and examples/grpcbin.py call public gRPC services, no setup needed. examples/grpc and examples/thrift run a local grpcio or thriftpy2 server and walk through every feature.
Current scope is struct serialization and unary calls. Streaming is not implemented yet.
Development
uv sync
uv run pytest
Serialization is tested against the protobuf and thriftpy2 implementations, the clients against real grpcio and thrift servers.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file grapec-0.3.0.tar.gz.
File metadata
- Download URL: grapec-0.3.0.tar.gz
- Upload date:
- Size: 93.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67cc5f051f9bce008d1624b9242fa8c9d050daf2a3d3be1e1db745ec1aadb0fd
|
|
| MD5 |
f873ff69cff33bed6e1e7f2629e97242
|
|
| BLAKE2b-256 |
3cb87ff5db44f59deb6930a26d65f1b3b849eba792042e2fe6d9977a88fbeb39
|
Provenance
The following attestation bundles were made for grapec-0.3.0.tar.gz:
Publisher:
release.yml on aisk/grapec
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
grapec-0.3.0.tar.gz -
Subject digest:
67cc5f051f9bce008d1624b9242fa8c9d050daf2a3d3be1e1db745ec1aadb0fd - Sigstore transparency entry: 2561449072
- Sigstore integration time:
-
Permalink:
aisk/grapec@e7ca14200f1e6564730256d737b397cc33b8312a -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/aisk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e7ca14200f1e6564730256d737b397cc33b8312a -
Trigger Event:
push
-
Statement type:
File details
Details for the file grapec-0.3.0-py3-none-any.whl.
File metadata
- Download URL: grapec-0.3.0-py3-none-any.whl
- Upload date:
- Size: 46.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd79e60d91c946d4d382c5b71939cfb500bc6dd954656eab2711cda6c04c3ce1
|
|
| MD5 |
6affec5d856f9131e54c2efdf21ee7b3
|
|
| BLAKE2b-256 |
2e0ebc575e851813ebf000111d93552dab7edbf573ad9cf80977c69fe5146d01
|
Provenance
The following attestation bundles were made for grapec-0.3.0-py3-none-any.whl:
Publisher:
release.yml on aisk/grapec
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
grapec-0.3.0-py3-none-any.whl -
Subject digest:
dd79e60d91c946d4d382c5b71939cfb500bc6dd954656eab2711cda6c04c3ce1 - Sigstore transparency entry: 2561449449
- Sigstore integration time:
-
Permalink:
aisk/grapec@e7ca14200f1e6564730256d737b397cc33b8312a -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/aisk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e7ca14200f1e6564730256d737b397cc33b8312a -
Trigger Event:
push
-
Statement type: