Skip to content

Commit 2cd75f3

Browse files
committed
many: pass data directly to event handler & add more tests for subscribe object
1 parent 54adba6 commit 2cd75f3

File tree

2 files changed

+79
-19
lines changed

2 files changed

+79
-19
lines changed

tests/codec_test.py

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
from typing import Type, TypeVar, Any
55

66
import capnp
7+
import pytest
78
from google.protobuf.message import Message
89

910
from xconn.client import connect_anonymous
1011
from xconn import codec
11-
from xconn.types import Event
1212
from tests.schemas.profile_pb2 import ProfileCreate, ProfileGet
1313

1414

@@ -82,12 +82,63 @@ def test_pubsub_object():
8282
session = connect_anonymous("ws://localhost:8080/ws", "realm1")
8383
session.set_payload_codec(Base64Codec())
8484

85-
def event_handler(event: Event):
86-
assert event.args[0] == "hello"
85+
def event_handler(data: String):
86+
assert data == "hello"
8787

88-
session.subscribe_object("io.xconn.object", event_handler, String)
88+
session.subscribe_object("io.xconn.object", event_handler)
8989

90-
session.publish_object("io.xconn.object", String("hello"))
90+
session.publish_object("io.xconn.object", String("hello"), {"acknowledge": True})
91+
92+
session.leave()
93+
94+
95+
def test_subscribe_object_without_codec():
96+
session = connect_anonymous("ws://localhost:8080/ws", "realm1")
97+
98+
def event_handler(user: ProfileCreate):
99+
pass
100+
101+
with pytest.raises(ValueError, match="no payload codec set"):
102+
session.subscribe_object("io.xconn.object", event_handler)
103+
104+
session.leave()
105+
106+
107+
def test_subscribe_object_without_args():
108+
session = connect_anonymous("ws://localhost:8080/ws", "realm1")
109+
session.set_payload_codec(Base64Codec())
110+
111+
def event_handler():
112+
pass
113+
114+
with pytest.raises(ValueError, match="event handler must accept 1 argument"):
115+
session.subscribe_object("io.xconn.object", event_handler)
116+
117+
session.leave()
118+
119+
120+
def test_subscribe_object_with_multiple_args():
121+
session = connect_anonymous("ws://localhost:8080/ws", "realm1")
122+
session.set_payload_codec(ProtobufCodec())
123+
124+
def event_handler(user: ProfileCreate, a):
125+
pass
126+
127+
with pytest.raises(ValueError, match="event handler must accept 1 argument"):
128+
session.subscribe_object("io.xconn.object", event_handler)
129+
130+
session.leave()
131+
132+
133+
def test_subscribe_object_without_annotation():
134+
session = connect_anonymous("ws://localhost:8080/ws", "realm1")
135+
session.set_payload_codec(ProtobufCodec())
136+
137+
def event_handler(user):
138+
pass
139+
140+
with pytest.raises(TypeError, match="event handler parameter must have a type annotation"):
141+
session.subscribe_object("io.xconn.object", event_handler)
91142

92143
session.leave()
93144

@@ -96,16 +147,15 @@ def test_pubsub_protobuf():
96147
session = connect_anonymous("ws://localhost:8080/ws", "realm1")
97148
session.set_payload_codec(ProtobufCodec())
98149

99-
def event_handler(event: Event):
100-
user: ProfileCreate = event.args[0]
150+
def event_handler(user: ProfileCreate):
101151
assert user.username == "john"
102152
assert user.email == "[email protected]"
103153
assert user.age == 25
104154

105-
session.subscribe_object("io.xconn.object", event_handler, ProfileCreate)
155+
session.subscribe_object("io.xconn.object", event_handler)
106156

107157
create_msg = ProfileCreate(username="john", email="[email protected]", age=25)
108-
session.publish_object("io.xconn.object", create_msg)
158+
session.publish_object("io.xconn.object", create_msg, {"acknowledge": True})
109159

110160
session.leave()
111161

@@ -239,19 +289,18 @@ def test_pubsub_capnproto():
239289
session = connect_anonymous("ws://localhost:8080/ws", "realm1")
240290
session.set_payload_codec(CapnpProtoCodec())
241291

242-
def event_handler(event: Event):
243-
user: UserCreate = event.args[0]
292+
def event_handler(user: UserCreate):
244293
assert user.name == "alice"
245294
assert user.email == "[email protected]"
246295
assert user.age == 21
247296

248-
session.subscribe_object("io.xconn.object", event_handler, UserCreate)
297+
session.subscribe_object("io.xconn.object", event_handler)
249298

250299
new_user = UserCreate.new_message()
251300
new_user.name = "alice"
252301
new_user.email = "[email protected]"
253302
new_user.age = 21
254303

255-
session.publish_object("io.xconn.object", new_user)
304+
session.publish_object("io.xconn.object", new_user, {"acknowledge": True})
256305

257306
session.leave()

xconn/session.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,26 +217,37 @@ def call_object(self, procedure: str, request: TReq = None, return_type: Type[TR
217217

218218
return None
219219

220-
def subscribe_object(self, topic: str, event_handler: Callable[[types.Event], None], return_type: Type[TRes]):
220+
def subscribe_object(self, topic: str, event_handler: Callable[[TReq], None]):
221221
if self._payload_codec is None:
222222
raise ValueError("no payload codec set")
223223

224+
sig = inspect.signature(event_handler)
225+
226+
params = list(sig.parameters.values())
227+
if len(params) != 1:
228+
raise ValueError("event handler must accept 1 argument")
229+
230+
param_type = params[0].annotation
231+
if param_type is inspect._empty:
232+
raise TypeError("event handler parameter must have a type annotation")
233+
224234
def _event_handler(event: types.Event):
225-
if len(event.args) != 1:
235+
if len(event.args) != 1 or len(event.kwargs) != 0:
226236
raise ValueError("only one argument expected in event")
227237

228238
data = event.args[0]
229-
d = self._payload_codec.decode(data, return_type)
230-
event_handler(types.Event(args=[d], kwargs={}, details={}))
239+
request_obj = self._payload_codec.decode(data, param_type)
240+
event_handler(request_obj)
231241

232242
return self.subscribe(topic, _event_handler)
233243

234-
def publish_object(self, topic: str, request: TReq):
244+
def publish_object(self, topic: str, request: TReq, options: dict[str, Any] | None = None):
235245
if self._payload_codec is None:
236246
raise ValueError("no payload codec set")
237247

238248
encoded = self._payload_codec.encode(request)
239-
return self.publish(topic, [encoded])
249+
250+
return self.publish(topic, [encoded], options=options)
240251

241252
def register_object(
242253
self,

0 commit comments

Comments
 (0)