Skip to main content

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

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.

Metadata

Release files for grapec 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for grapec 0.3.0
File Size Uploaded
grapec-0.3.0.tar.gz 93.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for grapec 0.3.0
File Interpreter ABI Platform
grapec-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 140.2 kB

Release files / grapec-0.3.0.tar.gz

Download URL grapec-0.3.0.tar.gz
Size 93.9 kB
Tags Source
SHA-256 checksum
How to use checksums
67cc5f051f9bce008d1624b9242fa8c9d050daf2a3d3be1e1db745ec1aadb0fd
BLAKE2b-256 checksum
How to use checksums
3cb87ff5db44f59deb6930a26d65f1b3b849eba792042e2fe6d9977a88fbeb39
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 22, 2026.

Transparency log

Release files / grapec-0.3.0-py3-none-any.whl

Download URL grapec-0.3.0-py3-none-any.whl
Size 46.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dd79e60d91c946d4d382c5b71939cfb500bc6dd954656eab2711cda6c04c3ce1
BLAKE2b-256 checksum
How to use checksums
2e0ebc575e851813ebf000111d93552dab7edbf573ad9cf80977c69fe5146d01
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 22, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page