Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions sdks/python/pmxt/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1746,13 +1746,22 @@ def fetch_balance(self, address: Optional[str] = None) -> List[Balance]:
raise self._parse_api_exception(e) from None

def unwatch_order_book(self, outcome_id: Union[str, "MarketOutcome"] = _UNSET, **_compat_kwargs) -> None:
outcome_id = _compat_id(outcome_id, _compat_kwargs)
resolved = _resolve_outcome_id(outcome_id)
self._unwatch_required_via_ws(
"unwatch_order_book",
"unwatchOrderBook",
[resolved],
)
try:
outcome_id = _compat_id(outcome_id, _compat_kwargs)
body: dict = {"args": [_resolve_outcome_id(outcome_id)]}
creds = self._get_credentials_dict()
if creds:
body["credentials"] = creds
url = f"{self._resolve_sidecar_host()}/api/{self.exchange_name}/unwatchOrderBook"
headers = {"Content-Type": "application/json", "Accept": "application/json"}
headers.update(self._get_auth_headers())
response = self._fetch_with_retry(
lambda: self._api_client.call_api(method="POST", url=url, body=body, header_params=headers)
)
response.read()
self._handle_response(json.loads(response.data))
except ApiException as e:
raise self._parse_api_exception(e) from None

def unwatch_address(self, address: str) -> None:
try:
Expand Down
56 changes: 22 additions & 34 deletions sdks/python/tests/test_streaming_ws_transport.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import json
import threading

import pytest

Expand Down Expand Up @@ -37,7 +36,6 @@ def _raw_trade() -> dict:
("watch_order_book", ("outcome-1",), "watch_order_book() requires WebSocket transport"),
("watch_order_books", (["outcome-1"],), "watch_order_books() requires WebSocket transport"),
("watch_trades", ("outcome-1",), "watch_trades() requires WebSocket transport"),
("unwatch_order_book", ("outcome-1",), "unwatch_order_book() requires WebSocket transport"),
],
)
def test_streaming_methods_require_websocket_transport(monkeypatch, method_name, args, message):
Expand Down Expand Up @@ -179,46 +177,36 @@ def test_watch_trades_uses_websocket_transport(monkeypatch):
assert trades[0].id == "trade-1"


def test_unwatch_order_book_sends_websocket_unsubscribe(monkeypatch):
def test_unwatch_order_book_uses_http_sidecar_transport(monkeypatch):
exchange = _exchange()
calls = []

class FakeSocket:
def __init__(self):
self.sent = []

def send(self, raw):
self.sent.append(json.loads(raw))

class FakeWs:
connected = True
class FakeResponse:
data = json.dumps({"success": True, "data": None}).encode()

def __init__(self):
self._lock = threading.Lock()
self._ws = FakeSocket()
self._active_subs = {"watchOrderBook:outcome-1": "req-existing"}
self._subscriptions = {"req-existing": object()}
self._data_queues = {"req-existing": [_raw_order_book()]}
self._data_store = {"req-existing": _raw_order_book()}
def read(self):
return self.data

def _ensure_connected(self):
return None
def fake_call_api(**kwargs):
calls.append(kwargs)
return FakeResponse()

fake_ws = FakeWs()
monkeypatch.setattr(exchange, "_get_or_create_ws", lambda: fake_ws)
monkeypatch.setattr(exchange._api_client, "call_api", fake_call_api)
monkeypatch.setattr(
exchange,
"_fetch_with_retry",
lambda _fn: pytest.fail("unwatch_order_book attempted HTTP fallback"),
"_get_or_create_ws",
lambda: pytest.fail("unwatch_order_book attempted WebSocket transport"),
)

exchange.unwatch_order_book("outcome-1")

assert fake_ws._ws.sent[0]["action"] == "unsubscribe"
assert fake_ws._ws.sent[0]["id"] == "req-existing"
assert fake_ws._ws.sent[0]["exchange"] == "mock"
assert fake_ws._ws.sent[0]["method"] == "unwatchOrderBook"
assert fake_ws._ws.sent[0]["args"] == ["outcome-1"]
assert "watchOrderBook:outcome-1" not in fake_ws._active_subs
assert "req-existing" not in fake_ws._subscriptions
assert "req-existing" not in fake_ws._data_queues
assert "req-existing" not in fake_ws._data_store
assert calls == [
{
"method": "POST",
"url": "http://127.0.0.1:9/api/mock/unwatchOrderBook",
"body": {"args": ["outcome-1"]},
"header_params": calls[0]["header_params"],
}
]
assert calls[0]["header_params"]["Content-Type"] == "application/json"
assert calls[0]["header_params"]["Accept"] == "application/json"
Loading