From cbcf844496729d7f9dd861a1e236c2bf95c0781b Mon Sep 17 00:00:00 2001 From: Tidelight Mirror Bot Date: Fri, 16 Oct 2026 02:11:36 +0000 Subject: [PATCH] chore(sync): mirror python from 8b8e01c2fc176b8c362acfc351502478f5d28d06 --- README.md | 2 +- src/tidelight/client.py | 6 +++++- tests/test_client.py | 12 ++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 20965fa..d9676d3 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ import os from tidelight import Client client = Client(os.environ["TIDELIGHT_API_KEY"]) -page = client.list_tokenized_equities(limit=20) +page = client.list_tokenized_equities(limit=20, underlying_ticker="AAPL") for instrument in page.data: print(instrument.symbol, instrument.underlying_ticker) diff --git a/src/tidelight/client.py b/src/tidelight/client.py index 45608a1..798da46 100644 --- a/src/tidelight/client.py +++ b/src/tidelight/client.py @@ -78,14 +78,18 @@ def __init__(self, api_key: str, *, base_url: str = "https://api.tidelight.app/v self._opener = opener self._sleeper = sleeper - def list_tokenized_equities(self, *, limit: int = 20, cursor: str | None = None) -> InstrumentPage: + def list_tokenized_equities(self, *, limit: int = 20, cursor: str | None = None, underlying_ticker: str | None = None) -> InstrumentPage: if not isinstance(limit, int) or not 1 <= limit <= 100: raise ValueError("limit must be 1 to 100.") if cursor is not None and not re.fullmatch(r"[A-Z0-9]{2,32}", cursor): raise ValueError("Invalid instrument cursor.") + if underlying_ticker is not None and not re.fullmatch(r"[A-Z][A-Z0-9.]{0,9}", underlying_ticker.upper()): + raise ValueError("Invalid underlying_ticker.") params = {"kind": "rtoken", "limit": str(limit)} if cursor is not None: params["cursor"] = cursor + if underlying_ticker is not None: + params["underlying_ticker"] = underlying_ticker.upper() url = f"{self._base_url}/market/instruments?{urlencode(params)}" request = Request(url, headers={"Authorization": f"Bearer {self._api_key}", "Accept": "application/json"}) for attempt in range(self._max_retries + 1): diff --git a/tests/test_client.py b/tests/test_client.py index 176ab8f..db78d88 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -89,6 +89,18 @@ def test_input_validation(self): client.list_tokenized_equities(limit=101) with self.assertRaises(ValueError): client.list_tokenized_equities(cursor="../../etc") + with self.assertRaises(ValueError): + client.list_tokenized_equities(underlying_ticker="AAPL?") + + def test_underlying_ticker_is_normalized_and_sent_before_pagination(self): + calls = [] + + def opener(request, timeout): + calls.append(parse_qs(urlparse(request.full_url).query)) + return FakeResponse({"data": [INSTRUMENT], "next_cursor": None, "generated_at": 1, "request_id": "filter"}) + + Client(KEY, opener=opener).list_tokenized_equities(limit=1, underlying_ticker="aapl") + self.assertEqual(calls[0]["underlying_ticker"], ["AAPL"]) def test_webhook_management_and_delivery_history(self): endpoint_id = "01234567-89ab-4cde-8fab-0123456789ab"