Skip to content

Commit 8c4266b

Browse files
committed
fix: replane client
1 parent 7af9a36 commit 8c4266b

4 files changed

Lines changed: 62 additions & 14 deletions

File tree

replane/_async.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,14 @@ def unsubscribe() -> None:
305305

306306
return unsubscribe
307307

308+
def is_initialized(self) -> bool:
309+
"""Check if the client has finished initialization.
310+
311+
Returns:
312+
True if the client has received initial configs from the server.
313+
"""
314+
return self._initialized.is_set()
315+
308316
async def close(self) -> None:
309317
"""Close the client and stop the SSE connection."""
310318
logger.debug("close() called")
@@ -424,13 +432,19 @@ async def _process_stream(self, response: httpx.Response) -> None:
424432

425433
async def _handle_event(self, event: Any) -> None:
426434
"""Handle a parsed SSE event."""
427-
logger.debug("SSE event received: type=%s", event.event)
428-
if event.event == "init":
435+
# Event type can be in SSE 'event:' field or in data.type
436+
event_type = event.event
437+
if event_type is None and isinstance(event.data, dict):
438+
event_type = event.data.get("type")
439+
440+
logger.debug("SSE event received: type=%s", event_type)
441+
442+
if event_type == "init":
429443
await self._handle_init(event.data)
430-
elif event.event == "config_change":
444+
elif event_type == "config_change":
431445
await self._handle_config_change(event.data)
432446
else:
433-
logger.debug("Unknown event type: %s, data=%s", event.event, event.data)
447+
logger.debug("Unknown event type: %s, data=%s", event_type, event.data)
434448

435449
async def _handle_init(self, data: dict[str, Any]) -> None:
436450
"""Handle the init event with all configs."""

replane/_sync.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,14 @@ def unsubscribe() -> None:
288288

289289
return unsubscribe
290290

291+
def is_initialized(self) -> bool:
292+
"""Check if the client has finished initialization.
293+
294+
Returns:
295+
True if the client has received initial configs from the server.
296+
"""
297+
return self._initialized.is_set()
298+
291299
def close(self) -> None:
292300
"""Close the client and stop the SSE connection."""
293301
logger.debug("close() called")
@@ -425,13 +433,22 @@ def _process_stream(self, response: http.client.HTTPResponse) -> None:
425433

426434
while not self._stop_event.is_set():
427435
try:
428-
chunk = response.read(buffer_size)
436+
# Use read1() to get available data without blocking for full buffer.
437+
# This is essential for SSE where data arrives in small chunks.
438+
# read1() returns data as soon as it's available from the socket.
439+
if hasattr(response.fp, "read1"):
440+
chunk = response.fp.read1(buffer_size) # type: ignore[union-attr]
441+
else:
442+
# Fallback for environments where read1 isn't available
443+
chunk = response.read(buffer_size)
444+
429445
if not chunk:
430446
logger.debug("SSE stream ended")
431447
break
432448

433449
last_event_time = time.monotonic()
434450
text = chunk.decode("utf-8", errors="replace")
451+
logger.debug("Received chunk: %d bytes", len(chunk))
435452

436453
for event in parser.feed(text):
437454
self._handle_event(event)
@@ -449,13 +466,19 @@ def _process_stream(self, response: http.client.HTTPResponse) -> None:
449466

450467
def _handle_event(self, event: Any) -> None:
451468
"""Handle a parsed SSE event."""
452-
logger.debug("SSE event received: type=%s", event.event)
453-
if event.event == "init":
469+
# Event type can be in SSE 'event:' field or in data.type
470+
event_type = event.event
471+
if event_type is None and isinstance(event.data, dict):
472+
event_type = event.data.get("type")
473+
474+
logger.debug("SSE event received: type=%s", event_type)
475+
476+
if event_type == "init":
454477
self._handle_init(event.data)
455-
elif event.event == "config_change":
478+
elif event_type == "config_change":
456479
self._handle_config_change(event.data)
457480
else:
458-
logger.debug("Unknown event type: %s, data=%s", event.event, event.data)
481+
logger.debug("Unknown event type: %s, data=%s", event_type, event.data)
459482

460483
def _handle_init(self, data: dict[str, Any]) -> None:
461484
"""Handle the init event with all configs."""

replane/testing.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,17 @@ def close(self) -> None:
237237
"""Close the client."""
238238
self._closed = True
239239

240+
def is_initialized(self) -> bool:
241+
"""Check if the client has finished initialization.
242+
243+
For the in-memory client, this always returns True since
244+
configs are available immediately.
245+
246+
Returns:
247+
True (always, for in-memory client).
248+
"""
249+
return True
250+
240251
def __enter__(self) -> InMemoryReplaneClient:
241252
return self
242253

replane/types.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,31 +152,31 @@ def parse_condition(data: dict[str, Any]) -> Condition:
152152
return PropertyCondition(
153153
operator=operator,
154154
property=data["property"],
155-
expected=data["expected"],
155+
expected=data.get("expected", data.get("value")),
156156
)
157157
elif operator == "less_than":
158158
return PropertyCondition(
159159
operator="lt",
160160
property=data["property"],
161-
expected=data["expected"],
161+
expected=data.get("expected", data.get("value")),
162162
)
163163
elif operator == "less_than_or_equal":
164164
return PropertyCondition(
165165
operator="lte",
166166
property=data["property"],
167-
expected=data["expected"],
167+
expected=data.get("expected", data.get("value")),
168168
)
169169
elif operator == "greater_than":
170170
return PropertyCondition(
171171
operator="gt",
172172
property=data["property"],
173-
expected=data["expected"],
173+
expected=data.get("expected", data.get("value")),
174174
)
175175
elif operator == "greater_than_or_equal":
176176
return PropertyCondition(
177177
operator="gte",
178178
property=data["property"],
179-
expected=data["expected"],
179+
expected=data.get("expected", data.get("value")),
180180
)
181181
else:
182182
raise ValueError(f"Unknown condition operator: {operator}")

0 commit comments

Comments
 (0)