From eb22ddfbd1f08479bd151bdbac3e95cb0074b359 Mon Sep 17 00:00:00 2001 From: "Naruto11.eth" <269052135+naruto11eth@users.noreply.github.com> Date: Fri, 26 Jun 2026 19:34:18 -0500 Subject: [PATCH 1/3] feat(clients): add typed overloads for market/event/tag lookups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add keyword-only `@overload` stubs so "exactly one of id/slug/url" (id/slug for tags) is visible to the type checker on `get_market`/`get_event`/`get_tag`, across the sync and async public and secure clients. `get_tag`'s `include_template` is offered only on the id overload, mirroring the runtime guard. Impl bodies and the runtime "exactly one" validation are unchanged — overloads are typing-only guidance. --- src/polymarket/clients/async_public.py | 48 ++++++++++++++++++++++++++ src/polymarket/clients/async_secure.py | 48 ++++++++++++++++++++++++++ src/polymarket/clients/public.py | 48 ++++++++++++++++++++++++++ src/polymarket/clients/secure.py | 48 ++++++++++++++++++++++++++ 4 files changed, 192 insertions(+) diff --git a/src/polymarket/clients/async_public.py b/src/polymarket/clients/async_public.py index b726372..801e4a5 100644 --- a/src/polymarket/clients/async_public.py +++ b/src/polymarket/clients/async_public.py @@ -297,6 +297,18 @@ async def close(self) -> None: finally: await self._ctx.clob.close() + @overload + async def get_market( + self, *, id: str, include_tag: bool | None = None, locale: str | None = None + ) -> Market: ... + @overload + async def get_market( + self, *, slug: str, include_tag: bool | None = None, locale: str | None = None + ) -> Market: ... + @overload + async def get_market( + self, *, url: str, include_tag: bool | None = None, locale: str | None = None + ) -> Market: ... async def get_market( self, *, @@ -322,6 +334,36 @@ async def get_market_tags(self, id: str) -> tuple[TagReference, ...]: """Get a market's tags.""" return await async_dispatch(self._ctx, _gamma_actions.get_market_tags_spec(id)) + @overload + async def get_event( + self, + *, + id: str, + include_best_lines: bool | None = None, + include_chat: bool | None = None, + include_template: bool | None = None, + locale: str | None = None, + ) -> Event: ... + @overload + async def get_event( + self, + *, + slug: str, + include_best_lines: bool | None = None, + include_chat: bool | None = None, + include_template: bool | None = None, + locale: str | None = None, + ) -> Event: ... + @overload + async def get_event( + self, + *, + url: str, + include_best_lines: bool | None = None, + include_chat: bool | None = None, + include_template: bool | None = None, + locale: str | None = None, + ) -> Event: ... async def get_event( self, *, @@ -363,6 +405,12 @@ async def get_series( _gamma_actions.get_series_spec(id, locale=locale), ) + @overload + async def get_tag( + self, *, id: str, include_template: bool | None = None, locale: str | None = None + ) -> Tag: ... + @overload + async def get_tag(self, *, slug: str, locale: str | None = None) -> Tag: ... async def get_tag( self, *, diff --git a/src/polymarket/clients/async_secure.py b/src/polymarket/clients/async_secure.py index 7bcfe77..b6ec639 100644 --- a/src/polymarket/clients/async_secure.py +++ b/src/polymarket/clients/async_secure.py @@ -731,6 +731,18 @@ async def _close_rfq_session(self) -> None: def _user_or_wallet(self, user: str | None) -> str: return self._ctx.wallet if user is None else user + @overload + async def get_market( + self, *, id: str, include_tag: bool | None = None, locale: str | None = None + ) -> Market: ... + @overload + async def get_market( + self, *, slug: str, include_tag: bool | None = None, locale: str | None = None + ) -> Market: ... + @overload + async def get_market( + self, *, url: str, include_tag: bool | None = None, locale: str | None = None + ) -> Market: ... async def get_market( self, *, @@ -756,6 +768,36 @@ async def get_market_tags(self, id: str) -> tuple[TagReference, ...]: """Get a market's tags.""" return await async_dispatch(self._ctx, _gamma_actions.get_market_tags_spec(id)) + @overload + async def get_event( + self, + *, + id: str, + include_best_lines: bool | None = None, + include_chat: bool | None = None, + include_template: bool | None = None, + locale: str | None = None, + ) -> Event: ... + @overload + async def get_event( + self, + *, + slug: str, + include_best_lines: bool | None = None, + include_chat: bool | None = None, + include_template: bool | None = None, + locale: str | None = None, + ) -> Event: ... + @overload + async def get_event( + self, + *, + url: str, + include_best_lines: bool | None = None, + include_chat: bool | None = None, + include_template: bool | None = None, + locale: str | None = None, + ) -> Event: ... async def get_event( self, *, @@ -797,6 +839,12 @@ async def get_series( _gamma_actions.get_series_spec(id, locale=locale), ) + @overload + async def get_tag( + self, *, id: str, include_template: bool | None = None, locale: str | None = None + ) -> Tag: ... + @overload + async def get_tag(self, *, slug: str, locale: str | None = None) -> Tag: ... async def get_tag( self, *, diff --git a/src/polymarket/clients/public.py b/src/polymarket/clients/public.py index e18f3dc..43fa091 100644 --- a/src/polymarket/clients/public.py +++ b/src/polymarket/clients/public.py @@ -142,6 +142,18 @@ def close(self) -> None: finally: self._ctx.clob.close() + @overload + def get_market( + self, *, id: str, include_tag: bool | None = None, locale: str | None = None + ) -> Market: ... + @overload + def get_market( + self, *, slug: str, include_tag: bool | None = None, locale: str | None = None + ) -> Market: ... + @overload + def get_market( + self, *, url: str, include_tag: bool | None = None, locale: str | None = None + ) -> Market: ... def get_market( self, *, @@ -167,6 +179,36 @@ def get_market_tags(self, id: str) -> tuple[TagReference, ...]: """Get a market's tags.""" return sync_dispatch(self._ctx, _gamma_actions.get_market_tags_spec(id)) + @overload + def get_event( + self, + *, + id: str, + include_best_lines: bool | None = None, + include_chat: bool | None = None, + include_template: bool | None = None, + locale: str | None = None, + ) -> Event: ... + @overload + def get_event( + self, + *, + slug: str, + include_best_lines: bool | None = None, + include_chat: bool | None = None, + include_template: bool | None = None, + locale: str | None = None, + ) -> Event: ... + @overload + def get_event( + self, + *, + url: str, + include_best_lines: bool | None = None, + include_chat: bool | None = None, + include_template: bool | None = None, + locale: str | None = None, + ) -> Event: ... def get_event( self, *, @@ -208,6 +250,12 @@ def get_series( _gamma_actions.get_series_spec(id, locale=locale), ) + @overload + def get_tag( + self, *, id: str, include_template: bool | None = None, locale: str | None = None + ) -> Tag: ... + @overload + def get_tag(self, *, slug: str, locale: str | None = None) -> Tag: ... def get_tag( self, *, diff --git a/src/polymarket/clients/secure.py b/src/polymarket/clients/secure.py index 32c0808..8dd88d2 100644 --- a/src/polymarket/clients/secure.py +++ b/src/polymarket/clients/secure.py @@ -464,6 +464,18 @@ def close(self) -> None: def _user_or_wallet(self, user: str | None) -> str: return self._ctx.wallet if user is None else user + @overload + def get_market( + self, *, id: str, include_tag: bool | None = None, locale: str | None = None + ) -> Market: ... + @overload + def get_market( + self, *, slug: str, include_tag: bool | None = None, locale: str | None = None + ) -> Market: ... + @overload + def get_market( + self, *, url: str, include_tag: bool | None = None, locale: str | None = None + ) -> Market: ... def get_market( self, *, @@ -489,6 +501,36 @@ def get_market_tags(self, id: str) -> tuple[TagReference, ...]: """Get a market's tags.""" return sync_dispatch(self._ctx, _gamma_actions.get_market_tags_spec(id)) + @overload + def get_event( + self, + *, + id: str, + include_best_lines: bool | None = None, + include_chat: bool | None = None, + include_template: bool | None = None, + locale: str | None = None, + ) -> Event: ... + @overload + def get_event( + self, + *, + slug: str, + include_best_lines: bool | None = None, + include_chat: bool | None = None, + include_template: bool | None = None, + locale: str | None = None, + ) -> Event: ... + @overload + def get_event( + self, + *, + url: str, + include_best_lines: bool | None = None, + include_chat: bool | None = None, + include_template: bool | None = None, + locale: str | None = None, + ) -> Event: ... def get_event( self, *, @@ -530,6 +572,12 @@ def get_series( _gamma_actions.get_series_spec(id, locale=locale), ) + @overload + def get_tag( + self, *, id: str, include_template: bool | None = None, locale: str | None = None + ) -> Tag: ... + @overload + def get_tag(self, *, slug: str, locale: str | None = None) -> Tag: ... def get_tag( self, *, From 6f0846f9411a89a966893472e52234d996b7baa9 Mon Sep 17 00:00:00 2001 From: "Naruto11.eth" <269052135+naruto11eth@users.noreply.github.com> Date: Fri, 26 Jun 2026 20:02:41 -0500 Subject: [PATCH 2/3] feat(clients): add typed overloads for redeem_positions Add keyword-only `@overload` stubs so "exactly one of condition_id/market_id/position_id" is visible to the type checker on `SecureClient.redeem_positions` and its async twin. Impl body and the runtime sum-check are unchanged. --- src/polymarket/clients/async_secure.py | 12 ++++++++++++ src/polymarket/clients/secure.py | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/polymarket/clients/async_secure.py b/src/polymarket/clients/async_secure.py index b6ec639..6066bec 100644 --- a/src/polymarket/clients/async_secure.py +++ b/src/polymarket/clients/async_secure.py @@ -2330,6 +2330,18 @@ async def merge_positions( ) return await self._dispatch_single_call(call, metadata=resolved_metadata) + @overload + async def redeem_positions( + self, *, condition_id: str, metadata: str | None = None + ) -> TransactionHandle: ... + @overload + async def redeem_positions( + self, *, market_id: str, metadata: str | None = None + ) -> TransactionHandle: ... + @overload + async def redeem_positions( + self, *, position_id: str, metadata: str | None = None + ) -> TransactionHandle: ... async def redeem_positions( self, *, diff --git a/src/polymarket/clients/secure.py b/src/polymarket/clients/secure.py index 8dd88d2..a27bfc8 100644 --- a/src/polymarket/clients/secure.py +++ b/src/polymarket/clients/secure.py @@ -2224,6 +2224,18 @@ def merge_positions( ) return self._dispatch_single_call(call, metadata=resolved_metadata) + @overload + def redeem_positions( + self, *, condition_id: str, metadata: str | None = None + ) -> SyncTransactionHandle: ... + @overload + def redeem_positions( + self, *, market_id: str, metadata: str | None = None + ) -> SyncTransactionHandle: ... + @overload + def redeem_positions( + self, *, position_id: str, metadata: str | None = None + ) -> SyncTransactionHandle: ... def redeem_positions( self, *, From c9465b8f2646ba53cdd2627ac5a7446e9dd0c257 Mon Sep 17 00:00:00 2001 From: "Naruto11.eth" <269052135+naruto11eth@users.noreply.github.com> Date: Fri, 26 Jun 2026 20:48:33 -0500 Subject: [PATCH 3/3] test(clients): mark intentional invalid redeem_positions calls for pyright The new `redeem_positions` overloads correctly make the deliberate two-selector and zero-selector calls (which exercise the runtime "exactly one" guard) static type errors. Add a narrow `# pyright: ignore[reportCallIssue]` on each so the static-checks gate passes while the runtime-validation tests stay. --- tests/unit/test_relayer_redeem_positions.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_relayer_redeem_positions.py b/tests/unit/test_relayer_redeem_positions.py index 7e32223..bacb6de 100644 --- a/tests/unit/test_relayer_redeem_positions.py +++ b/tests/unit/test_relayer_redeem_positions.py @@ -99,7 +99,10 @@ async def run() -> None: client = await make_deposit_client() try: with pytest.raises(UserInputError, match="exactly one"): - await client.redeem_positions(condition_id=_CONDITION_ID, market_id="123") + # Two selectors is intentionally invalid — exercises the runtime guard. + await client.redeem_positions( # pyright: ignore[reportCallIssue] + condition_id=_CONDITION_ID, market_id="123" + ) finally: await client.close() @@ -111,7 +114,8 @@ async def run() -> None: client = await make_deposit_client() try: with pytest.raises(UserInputError, match="exactly one"): - await client.redeem_positions() + # Zero selectors is intentionally invalid — exercises the runtime guard. + await client.redeem_positions() # pyright: ignore[reportCallIssue] finally: await client.close()