Skip to content

Commit bc657e3

Browse files
Add support for sync clients (#78)
* Sync client test * Install grpc * Test sync unary stream * Test sync stream unary and stream stream * Make grpcio dependency optional * Fix workflow
1 parent 82bb95b commit bc657e3

File tree

4 files changed

+146
-5
lines changed

4 files changed

+146
-5
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ jobs:
5757

5858
- name: Install dependencies
5959
shell: bash
60-
run: poetry install -E grpc-async
60+
run: poetry install -E all
6161

6262
- name: Download compiled test files
6363
shell: bash
@@ -69,7 +69,7 @@ jobs:
6969

7070
- name: Install dependencies with the Rust codec
7171
shell: bash
72-
run: poetry install -E grpc-async -E rust-codec
72+
run: poetry install -E all -E rust-codec
7373

7474
- name: Execute test suite with the Rust codec
7575
shell: bash

poetry.lock

Lines changed: 67 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ Repository = "https://github.com/betterproto/python-betterproto2"
1818

1919
[project.optional-dependencies]
2020
rust-codec = ["betterproto2-rust-codec"]
21+
grpc-sync = ["grpcio"]
2122
grpc-async = ["grpclib"]
22-
all = ["betterproto2-rust-codec", "grpclib"]
23+
24+
# betterproto2-rust-codec is not included because still experimental
25+
all = ["grpclib", "grpcio"]
2326

2427
[tool.poetry]
2528
packages = [
@@ -28,6 +31,7 @@ packages = [
2831

2932
[tool.poetry.dependencies]
3033
grpclib = { version = "^0.4.1", optional = true }
34+
grpcio = { version = "^1.71.0", optional = true }
3135
python-dateutil = "^2.8"
3236
typing-extensions = "^4.7.1"
3337
betterproto2-rust-codec = { version = "^0.1.2", optional = true }

tests/test_sync_client.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import asyncio
2+
import threading
3+
from collections.abc import AsyncIterator
4+
5+
import grpc
6+
import pytest
7+
from grpclib.server import Server
8+
9+
from tests.output_betterproto.simple_service import (
10+
Request,
11+
Response,
12+
SimpleServiceBase,
13+
SimpleServiceSyncStub,
14+
)
15+
16+
17+
class SimpleService(SimpleServiceBase):
18+
async def get_unary_unary(self, message: "Request") -> "Response":
19+
return Response(message=f"Hello {message.value}")
20+
21+
async def get_unary_stream(self, message: "Request") -> "AsyncIterator[Response]":
22+
for i in range(5):
23+
yield Response(message=f"Hello {message.value} {i}")
24+
25+
async def get_stream_unary(self, messages: "AsyncIterator[Request]") -> "Response":
26+
s = 0
27+
async for m in messages:
28+
s += m.value
29+
return Response(message=f"Hello {s}")
30+
31+
async def get_stream_stream(self, messages: "AsyncIterator[Request]") -> "AsyncIterator[Response]":
32+
async for message in messages:
33+
yield Response(message=f"Hello {message.value}")
34+
35+
36+
@pytest.mark.asyncio
37+
async def test_sync_client():
38+
def start_server():
39+
async def run_server():
40+
server = Server([SimpleService()])
41+
await server.start("127.0.0.1", 1234)
42+
await asyncio.sleep(3) # Close the server after 3 seconds
43+
server.close()
44+
45+
loop = asyncio.new_event_loop()
46+
loop.run_until_complete(run_server())
47+
loop.close()
48+
49+
# We need to start the server in a new thread to avoid a deadlock
50+
server_thread = threading.Thread(target=start_server)
51+
server_thread.start()
52+
53+
# Create a sync client
54+
with grpc.insecure_channel("localhost:1234") as channel:
55+
client = SimpleServiceSyncStub(channel)
56+
57+
response = client.get_unary_unary(Request(value=42))
58+
assert response.message == "Hello 42"
59+
60+
response = client.get_unary_stream(Request(value=42))
61+
assert [r.message for r in response] == [f"Hello 42 {i}" for i in range(5)]
62+
63+
response = client.get_stream_unary([Request(value=i) for i in range(5)])
64+
assert response.message == "Hello 10"
65+
66+
response = client.get_stream_stream([Request(value=i) for i in range(5)])
67+
assert [r.message for r in response] == [f"Hello {i}" for i in range(5)]
68+
69+
# Create an async client
70+
# client = SimpleServiceStub(Channel(host="127.0.0.1", port=1234))
71+
# response = await client.get_unary_unary(Request(value=42))
72+
# assert response.message == "Hello 42"

0 commit comments

Comments
 (0)