diff --git a/src/polymarket/clients/async_public.py b/src/polymarket/clients/async_public.py index 41f5165..ab4c770 100644 --- a/src/polymarket/clients/async_public.py +++ b/src/polymarket/clients/async_public.py @@ -138,6 +138,7 @@ def __init__( @property def environment(self) -> Environment: + """Environment this client sends requests to.""" return self._ctx.environment @overload @@ -182,6 +183,15 @@ async def subscribe( self, specs: PublicSubscription | Sequence[PublicSubscription], ) -> SubscriptionHandle[MarketEvent | SportsEvent | RtdsEvent]: + """Subscribe to one or more public realtime streams. + + Pass a single subscription spec for one stream or a sequence of specs to + receive events through one merged handle. + + Returns: + A subscription handle. Iterate over it to receive events and close it + when finished. + """ items = _normalize_specs(specs) # AsyncSubscriptionHandle is invariant in T, so per-channel handles # can't widen to the union type at the type level. Cast at the @@ -288,6 +298,7 @@ async def get_market( include_tag: bool | None = None, locale: str | None = None, ) -> Market: + """Get a market by id, slug, or Polymarket URL.""" return await async_dispatch( self._ctx, _gamma_actions.get_market_spec( @@ -296,6 +307,7 @@ async def get_market( ) 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)) async def get_event( @@ -309,6 +321,7 @@ async def get_event( include_template: bool | None = None, locale: str | None = None, ) -> Event: + """Get an event by id, slug, or Polymarket URL.""" return await async_dispatch( self._ctx, _gamma_actions.get_event_spec( @@ -323,6 +336,7 @@ async def get_event( ) async def get_event_tags(self, id: str) -> tuple[TagReference, ...]: + """Get an event's tags.""" return await async_dispatch(self._ctx, _gamma_actions.get_event_tags_spec(id)) async def get_series( @@ -332,6 +346,7 @@ async def get_series( include_chat: bool | None = None, locale: str | None = None, ) -> Series: + """Get a series.""" return await async_dispatch( self._ctx, _gamma_actions.get_series_spec(id, include_chat=include_chat, locale=locale), @@ -346,6 +361,7 @@ async def get_tag( include_template: bool | None = None, locale: str | None = None, ) -> Tag: + """Get a tag by id or slug.""" return await async_dispatch( self._ctx, _gamma_actions.get_tag_spec( @@ -365,6 +381,7 @@ async def get_related_tags( omit_empty: bool | None = None, status: str | None = None, ) -> tuple[RelatedTag, ...]: + """Get related tag relationships.""" return await async_dispatch( self._ctx, _gamma_actions.get_related_tags_spec( @@ -381,6 +398,7 @@ async def get_related_tag_resources( omit_empty: bool | None = None, status: str | None = None, ) -> tuple[Tag, ...]: + """Get tag resources linked from related tag relationships.""" return await async_dispatch( self._ctx, _gamma_actions.get_related_tag_resources_spec( @@ -389,12 +407,15 @@ async def get_related_tag_resources( ) async def get_sports(self) -> tuple[SportsMetadata, ...]: + """Get available sports metadata.""" return await async_dispatch(self._ctx, _gamma_actions.get_sports_spec()) async def get_sports_market_types(self) -> SportsMarketTypes: + """Get available sports market types.""" return await async_dispatch(self._ctx, _gamma_actions.get_sports_market_types_spec()) async def get_public_profile(self, address: str) -> PublicProfile | None: + """Get a public profile by wallet address. Returns None if no profile exists.""" try: return await async_dispatch(self._ctx, _gamma_actions.get_public_profile_spec(address)) except RequestRejectedError as error: @@ -405,17 +426,20 @@ async def get_public_profile(self, address: str) -> PublicProfile | None: async def get_comment_thread( self, id: str, *, get_positions: bool | None = None ) -> tuple[Comment, ...]: + """Get a comment thread by comment ID.""" return await async_dispatch( self._ctx, _gamma_actions.get_comment_thread_spec(id, get_positions=get_positions), ) async def get_event_live_volumes(self, *, id: str) -> tuple[LiveVolume, ...]: + """Get live volume entries for an event.""" return await async_dispatch(self._ctx, _data_actions.get_event_live_volumes_spec(id=id)) async def get_open_interests( self, *, market: Sequence[str] | None = None ) -> tuple[OpenInterest, ...]: + """Get open interest values, optionally filtered by market ids.""" return await async_dispatch(self._ctx, _data_actions.get_open_interests_spec(market=market)) async def get_market_holders( @@ -425,6 +449,7 @@ async def get_market_holders( limit: int | None = None, min_balance: int | None = None, ) -> tuple[MetaHolder, ...]: + """Get holder balances for one or more markets.""" return await async_dispatch( self._ctx, _data_actions.get_market_holders_spec( @@ -435,11 +460,13 @@ async def get_market_holders( async def get_portfolio_values( self, *, user: str, market: Sequence[str] | None = None ) -> tuple[PortfolioValue, ...]: + """Get portfolio value snapshots for a user.""" return await async_dispatch( self._ctx, _data_actions.get_portfolio_values_spec(user=user, market=market) ) async def get_traded_market_count(self, *, user: str) -> TradedMarketCount: + """Get the number of markets a user has traded.""" return await async_dispatch( self._ctx, _data_actions.get_traded_market_count_spec(user=user) ) @@ -447,6 +474,7 @@ async def get_traded_market_count(self, *, user: str) -> TradedMarketCount: async def get_builder_volumes( self, *, time_period: BuilderVolumeTimePeriod | None = None ) -> tuple[BuilderVolumeEntry, ...]: + """Get builder volume leaderboard entries.""" return await async_dispatch( self._ctx, _data_actions.get_builder_volumes_spec(time_period=time_period) ) @@ -461,6 +489,12 @@ def list_builder_trades( after: str | None = None, before: str | None = None, ) -> AsyncPaginator[BuilderTrade]: + """List builder-attributed trades. + + Returns: + An async paginator over matching builder-attributed trades. + """ + async def fetch(cursor: str | None) -> Page[BuilderTrade]: path, params = _builders_actions.build_list_builder_trades_request( builder_code=builder_code, @@ -490,6 +524,11 @@ def list_positions( title: str | None = None, page_size: int = 20, ) -> AsyncPaginator[Position]: + """List open positions for a user. + + Returns: + An async paginator over matching positions. + """ spec = _data_actions.list_positions_spec( user=user, market=market, @@ -514,6 +553,11 @@ def list_closed_positions( sort_direction: SortDirection | None = None, page_size: int = 20, ) -> AsyncPaginator[ClosedPosition]: + """List closed positions for a user. + + Returns: + An async paginator over matching closed positions. + """ spec = _data_actions.list_closed_positions_spec( user=user, market=market, @@ -534,6 +578,11 @@ def list_market_positions( sort_direction: SortDirection | None = None, page_size: int = 20, ) -> AsyncPaginator[MetaMarketPosition]: + """List positions in a market. + + Returns: + An async paginator over matching market positions. + """ spec = _data_actions.list_market_positions_spec( market=market, user=user, @@ -555,6 +604,11 @@ def list_trades( filter_amount: float | None = None, page_size: int = 20, ) -> AsyncPaginator[Trade]: + """List public trades. + + Returns: + An async paginator over matching trades. + """ spec = _data_actions.list_trades_spec( user=user, market=market, @@ -580,6 +634,11 @@ def list_activity( end: int | None = None, page_size: int = 20, ) -> AsyncPaginator[Activity]: + """List user activity. + + Returns: + An async paginator over matching activity entries. + """ spec = _data_actions.list_activity_spec( user=user, market=market, @@ -599,10 +658,16 @@ def list_builder_leaderboard( time_period: LeaderboardTimePeriod | None = None, page_size: int = 20, ) -> AsyncPaginator[LeaderboardEntry]: + """List builder leaderboard entries. + + Returns: + An async paginator over leaderboard rows. + """ spec = _data_actions.list_builder_leaderboard_spec(time_period=time_period) return async_paginate_offset(self._ctx, spec, page_size=page_size) async def download_accounting_snapshot(self, *, user: str) -> bytes: + """Download the accounting snapshot archive for a user.""" path, params = _data_actions.build_accounting_snapshot_request(user=user) return await self._ctx.data.get_bytes(path, params=params) @@ -616,6 +681,11 @@ def list_trader_leaderboard( user_name: str | None = None, page_size: int = 20, ) -> AsyncPaginator[TraderLeaderboardEntry]: + """List trader leaderboard entries. + + Returns: + An async paginator over leaderboard rows. + """ spec = _data_actions.list_trader_leaderboard_spec( category=category, time_period=time_period, @@ -668,6 +738,18 @@ def list_events( volume_min: float | None = None, page_size: int = 20, ) -> AsyncPaginator[Event]: + """List events. + + Returns: + An async paginator over matching events. + + Examples: + Iterate over every page:: + + async for page in client.list_events(page_size=10): + for event in page.items: + print(event.title) + """ spec = _gamma_actions.list_events_spec( ascending=ascending, closed=closed, @@ -744,6 +826,17 @@ def list_markets( volume_num_min: float | None = None, page_size: int = 20, ) -> AsyncPaginator[Market]: + """List markets. + + Returns: + An async paginator over matching markets. + + Examples: + Iterate over individual market items:: + + async for market in client.list_markets(closed=False).items(): + print(market.question) + """ spec = _gamma_actions.list_markets_spec( ascending=ascending, closed=closed, @@ -792,6 +885,11 @@ def list_series( slug: str | Sequence[str] | None = None, page_size: int = 20, ) -> AsyncPaginator[Series]: + """List series. + + Returns: + An async paginator over matching series. + """ spec = _gamma_actions.list_series_spec( ascending=ascending, categories_ids=categories_ids, @@ -817,6 +915,11 @@ def list_tags( order: str | None = None, page_size: int = 20, ) -> AsyncPaginator[Tag]: + """List tags. + + Returns: + An async paginator over matching tags. + """ spec = _gamma_actions.list_tags_spec( ascending=ascending, include_chat=include_chat, @@ -838,6 +941,11 @@ def list_teams( provider_ids: int | Sequence[int] | None = None, page_size: int = 20, ) -> AsyncPaginator[Team]: + """List teams. + + Returns: + An async paginator over matching teams. + """ spec = _gamma_actions.list_teams_spec( abbreviation=abbreviation, ascending=ascending, @@ -859,6 +967,11 @@ def list_comments( order: str | None = None, page_size: int = 20, ) -> AsyncPaginator[Comment]: + """List comments for a market or event. + + Returns: + An async paginator over matching comments. + """ spec = _gamma_actions.list_comments_spec( parent_entity_id=parent_entity_id, parent_entity_type=parent_entity_type, @@ -877,6 +990,11 @@ def list_comments_by_user_address( order: str | None = None, page_size: int = 20, ) -> AsyncPaginator[Comment]: + """List comments authored by a user address. + + Returns: + An async paginator over matching comments. + """ spec = _gamma_actions.list_comments_by_user_address_spec( address=address, ascending=ascending, @@ -902,6 +1020,11 @@ def search( sort: str | None = None, page_size: int = 10, ) -> AsyncPaginator[SearchResults]: + """Search Polymarket content. + + Returns: + An async paginator over search result pages. + """ spec = _gamma_actions.search_spec( q=q, ascending=ascending, @@ -920,40 +1043,49 @@ def search( return async_paginate_page_based(self._ctx, spec, page_size=page_size) async def get_midpoint(self, *, token_id: str) -> Decimal: + """Get the midpoint price for a token.""" path, params = _clob_actions.build_midpoint_request(token_id=token_id) return _clob_actions.parse_midpoint(await self._ctx.clob.get_json(path, params=params)) async def get_midpoints(self, *, token_ids: Sequence[str]) -> dict[str, Decimal]: + """Get midpoint prices for multiple tokens.""" path, body = _clob_actions.build_midpoints_request(token_ids=token_ids) return _clob_actions.parse_midpoints(await self._ctx.clob.post_json(path, json=body)) async def get_price(self, *, token_id: str, side: OrderSide) -> Decimal: + """Get the executable price for a token side.""" path, params = _clob_actions.build_price_request(token_id=token_id, side=side) return _clob_actions.parse_price(await self._ctx.clob.get_json(path, params=params)) async def get_prices( self, *, requests: Sequence[PriceRequest] ) -> dict[str, dict[OrderSide, Decimal]]: + """Get executable prices for multiple token-side requests.""" path, body = _clob_actions.build_prices_request(requests=requests) return _clob_actions.parse_prices(await self._ctx.clob.post_json(path, json=body)) async def get_order_book(self, *, token_id: str) -> OrderBook: + """Get the order book for a token.""" path, params = _clob_actions.build_order_book_request(token_id=token_id) return _clob_actions.parse_order_book(await self._ctx.clob.get_json(path, params=params)) async def get_order_books(self, *, token_ids: Sequence[str]) -> tuple[OrderBook, ...]: + """Get order books for multiple tokens.""" path, body = _clob_actions.build_order_books_request(token_ids=token_ids) return _clob_actions.parse_order_books(await self._ctx.clob.post_json(path, json=body)) async def get_spread(self, *, token_id: str) -> Decimal: + """Get the bid-ask spread for a token.""" path, params = _clob_actions.build_spread_request(token_id=token_id) return _clob_actions.parse_spread(await self._ctx.clob.get_json(path, params=params)) async def get_spreads(self, *, token_ids: Sequence[str]) -> dict[str, Decimal]: + """Get bid-ask spreads for multiple tokens.""" path, body = _clob_actions.build_spreads_request(token_ids=token_ids) return _clob_actions.parse_spreads(await self._ctx.clob.post_json(path, json=body)) async def get_last_trade_price(self, *, token_id: str) -> LastTradePrice: + """Get the most recent trade price for a token.""" path, params = _clob_actions.build_last_trade_price_request(token_id=token_id) return _clob_actions.parse_last_trade_price( await self._ctx.clob.get_json(path, params=params) @@ -962,6 +1094,7 @@ async def get_last_trade_price(self, *, token_id: str) -> LastTradePrice: async def get_last_trade_prices( self, *, token_ids: Sequence[str] ) -> tuple[LastTradePriceForToken, ...]: + """Get the most recent trade prices for multiple tokens.""" path, body = _clob_actions.build_last_trade_prices_request(token_ids=token_ids) return _clob_actions.parse_last_trade_prices( await self._ctx.clob.post_json(path, json=body) @@ -976,6 +1109,7 @@ async def get_price_history( fidelity: int | None = None, interval: PriceHistoryInterval | None = None, ) -> tuple[PriceHistoryPoint, ...]: + """Get historical price points for a token.""" path, params = _clob_actions.build_price_history_request( token_id=token_id, start_ts=start_ts, @@ -1012,6 +1146,11 @@ async def estimate_market_price( shares: Decimal | int | float | str | None = None, order_type: MarketOrderType = "FOK", ) -> Decimal: + """Estimate the average execution price for a market order. + + BUY orders use ``amount`` as the spend amount. SELL orders use ``shares`` + as the number of shares to sell. + """ return await _estimate_market_price( self._ctx, token_id=token_id, @@ -1024,6 +1163,12 @@ async def estimate_market_price( def list_current_rewards( self, *, sponsored: bool | None = None ) -> AsyncPaginator[CurrentReward]: + """List current rewards. + + Returns: + An async paginator over current reward configurations. + """ + async def fetch(cursor: str | None) -> Page[CurrentReward]: path, params = _rewards_actions.build_list_current_rewards_request( sponsored=sponsored, cursor=cursor @@ -1037,6 +1182,12 @@ async def fetch(cursor: str | None) -> Page[CurrentReward]: def list_market_rewards( self, *, condition_id: str, sponsored: bool | None = None ) -> AsyncPaginator[MarketReward]: + """List rewards for a market condition. + + Returns: + An async paginator over matching market reward configurations. + """ + async def fetch(cursor: str | None) -> Page[MarketReward]: path, params = _rewards_actions.build_list_market_rewards_request( condition_id=ConditionId(condition_id), sponsored=sponsored, cursor=cursor diff --git a/src/polymarket/clients/async_secure.py b/src/polymarket/clients/async_secure.py index cab369a..447ade1 100644 --- a/src/polymarket/clients/async_secure.py +++ b/src/polymarket/clients/async_secure.py @@ -210,6 +210,12 @@ class AsyncSecureClient: + """Async client for authenticated account, trading, wallet, and stream workflows. + + Create instances with :meth:`AsyncSecureClient.create` so the SDK can derive + or validate credentials before authenticated requests are made. + """ + def __init__( self, *, @@ -242,6 +248,43 @@ def _ctx(self, value: AsyncSecureClientContext) -> None: @classmethod async def create( + cls, + *, + private_key: str, + wallet: str | None = None, + environment: Environment = PRODUCTION, + credentials: ApiKeyCreds | None = None, + api_key: ApiKey | None = None, + nonce: int = 0, + logger: logging.Logger | None = None, + ) -> Self: + """Create an authenticated async client. + + Args: + private_key: EVM private key used for signing. + wallet: Wallet address to act for. Defaults to the signer's address. + credentials: Existing API credentials. When omitted, credentials are + derived during client creation. + api_key: Optional key for gasless wallet and relayed transaction workflows. + nonce: Credential derivation nonce. Cannot be combined with ``credentials``. + + Raises: + UserInputError: If key material, wallet, nonce, or credentials are invalid. + RequestRejectedError: If credential derivation or validation is rejected. + """ + return await cls._create( + private_key=private_key, + wallet=wallet, + environment=environment, + credentials=credentials, + api_key=api_key, + nonce=nonce, + validate_credentials=True, + logger=logger, + ) + + @classmethod + async def _create( cls, *, private_key: str, @@ -346,22 +389,27 @@ def _construct_for_wallet( @property def environment(self) -> Environment: + """Environment this client sends requests to.""" return self._ctx.environment @property def wallet(self) -> EvmAddress: + """Wallet address authenticated by this client.""" return self._ctx.wallet @property def signer(self) -> EvmAddress: + """Signer address used for signatures.""" return cast(EvmAddress, self._ctx.signer.address) @property def wallet_type(self) -> WalletType: + """Detected wallet type for the authenticated wallet.""" return self._ctx.wallet_type @property def credentials(self) -> ApiKeyCreds: + """API credentials used for authenticated requests.""" return self._ctx.credentials @overload @@ -410,6 +458,16 @@ async def subscribe( self, specs: SecureSubscription | Sequence[SecureSubscription], ) -> SubscriptionHandle[MarketEvent | SportsEvent | RtdsEvent | UserEvent]: + """Subscribe to one or more public or authenticated realtime streams. + + Pass a single subscription spec for one stream or a sequence of specs to + receive events through one merged handle. Authenticated user stream specs + are supported only by secure clients. + + Returns: + A subscription handle. Iterate over it to receive events and close it + when finished. + """ items = _normalize_specs(specs) handles: list[AsyncSubscriptionHandle[Any]] = [] try: @@ -502,6 +560,7 @@ async def __aexit__( await self.close() async def close(self) -> None: + """Close the underlying network transports and any open streams.""" ctx = self._ctx_inner try: if self._market_manager is not None: @@ -548,6 +607,7 @@ async def get_market( include_tag: bool | None = None, locale: str | None = None, ) -> Market: + """Get a market by id, slug, or Polymarket URL.""" return await async_dispatch( self._ctx, _gamma_actions.get_market_spec( @@ -556,6 +616,7 @@ async def get_market( ) 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)) async def get_event( @@ -569,6 +630,7 @@ async def get_event( include_template: bool | None = None, locale: str | None = None, ) -> Event: + """Get an event by id, slug, or Polymarket URL.""" return await async_dispatch( self._ctx, _gamma_actions.get_event_spec( @@ -583,6 +645,7 @@ async def get_event( ) async def get_event_tags(self, id: str) -> tuple[TagReference, ...]: + """Get an event's tags.""" return await async_dispatch(self._ctx, _gamma_actions.get_event_tags_spec(id)) async def get_series( @@ -592,6 +655,7 @@ async def get_series( include_chat: bool | None = None, locale: str | None = None, ) -> Series: + """Get a series.""" return await async_dispatch( self._ctx, _gamma_actions.get_series_spec(id, include_chat=include_chat, locale=locale), @@ -606,6 +670,7 @@ async def get_tag( include_template: bool | None = None, locale: str | None = None, ) -> Tag: + """Get a tag by id or slug.""" return await async_dispatch( self._ctx, _gamma_actions.get_tag_spec( @@ -625,6 +690,7 @@ async def get_related_tags( omit_empty: bool | None = None, status: str | None = None, ) -> tuple[RelatedTag, ...]: + """Get related tag relationships.""" return await async_dispatch( self._ctx, _gamma_actions.get_related_tags_spec( @@ -641,6 +707,7 @@ async def get_related_tag_resources( omit_empty: bool | None = None, status: str | None = None, ) -> tuple[Tag, ...]: + """Get tag resources linked from related tag relationships.""" return await async_dispatch( self._ctx, _gamma_actions.get_related_tag_resources_spec( @@ -649,12 +716,15 @@ async def get_related_tag_resources( ) async def get_sports(self) -> tuple[SportsMetadata, ...]: + """Get available sports metadata.""" return await async_dispatch(self._ctx, _gamma_actions.get_sports_spec()) async def get_sports_market_types(self) -> SportsMarketTypes: + """Get available sports market types.""" return await async_dispatch(self._ctx, _gamma_actions.get_sports_market_types_spec()) async def get_public_profile(self, address: str) -> PublicProfile | None: + """Get a public profile by wallet address. Returns None if no profile exists.""" try: return await async_dispatch(self._ctx, _gamma_actions.get_public_profile_spec(address)) except RequestRejectedError as error: @@ -665,17 +735,20 @@ async def get_public_profile(self, address: str) -> PublicProfile | None: async def get_comment_thread( self, id: str, *, get_positions: bool | None = None ) -> tuple[Comment, ...]: + """Get a comment thread by comment ID.""" return await async_dispatch( self._ctx, _gamma_actions.get_comment_thread_spec(id, get_positions=get_positions), ) async def get_event_live_volumes(self, *, id: str) -> tuple[LiveVolume, ...]: + """Get live volume entries for an event.""" return await async_dispatch(self._ctx, _data_actions.get_event_live_volumes_spec(id=id)) async def get_open_interests( self, *, market: Sequence[str] | None = None ) -> tuple[OpenInterest, ...]: + """Get open interest values, optionally filtered by market ids.""" return await async_dispatch(self._ctx, _data_actions.get_open_interests_spec(market=market)) async def get_market_holders( @@ -685,6 +758,7 @@ async def get_market_holders( limit: int | None = None, min_balance: int | None = None, ) -> tuple[MetaHolder, ...]: + """Get holder balances for one or more markets.""" return await async_dispatch( self._ctx, _data_actions.get_market_holders_spec( @@ -698,12 +772,14 @@ async def get_portfolio_values( user: str | None = None, market: Sequence[str] | None = None, ) -> tuple[PortfolioValue, ...]: + """Get portfolio value snapshots for a user or the authenticated wallet.""" return await async_dispatch( self._ctx, _data_actions.get_portfolio_values_spec(user=self._user_or_wallet(user), market=market), ) async def get_traded_market_count(self, *, user: str | None = None) -> TradedMarketCount: + """Get the number of markets traded by a user or the authenticated wallet.""" return await async_dispatch( self._ctx, _data_actions.get_traded_market_count_spec(user=self._user_or_wallet(user)), @@ -712,6 +788,7 @@ async def get_traded_market_count(self, *, user: str | None = None) -> TradedMar async def get_builder_volumes( self, *, time_period: BuilderVolumeTimePeriod | None = None ) -> tuple[BuilderVolumeEntry, ...]: + """Get builder volume leaderboard entries.""" return await async_dispatch( self._ctx, _data_actions.get_builder_volumes_spec(time_period=time_period) ) @@ -726,6 +803,12 @@ def list_builder_trades( after: str | None = None, before: str | None = None, ) -> AsyncPaginator[BuilderTrade]: + """List builder-attributed trades. + + Returns: + An async paginator over matching builder-attributed trades. + """ + async def fetch(cursor: str | None) -> Page[BuilderTrade]: path, params = _builders_actions.build_list_builder_trades_request( builder_code=builder_code, @@ -755,6 +838,11 @@ def list_positions( title: str | None = None, page_size: int = 20, ) -> AsyncPaginator[Position]: + """List open positions for a user or the authenticated wallet. + + Returns: + An async paginator over matching positions. + """ spec = _data_actions.list_positions_spec( user=self._user_or_wallet(user), market=market, @@ -779,6 +867,11 @@ def list_closed_positions( sort_direction: SortDirection | None = None, page_size: int = 20, ) -> AsyncPaginator[ClosedPosition]: + """List closed positions for a user or the authenticated wallet. + + Returns: + An async paginator over matching closed positions. + """ spec = _data_actions.list_closed_positions_spec( user=self._user_or_wallet(user), market=market, @@ -799,6 +892,11 @@ def list_market_positions( sort_direction: SortDirection | None = None, page_size: int = 20, ) -> AsyncPaginator[MetaMarketPosition]: + """List positions in a market. + + Returns: + An async paginator over matching market positions. + """ spec = _data_actions.list_market_positions_spec( market=market, user=user, @@ -820,6 +918,11 @@ def list_trades( filter_amount: float | None = None, page_size: int = 20, ) -> AsyncPaginator[Trade]: + """List trades for a user or the authenticated wallet. + + Returns: + An async paginator over matching trades. + """ spec = _data_actions.list_trades_spec( user=self._user_or_wallet(user), market=market, @@ -845,6 +948,11 @@ def list_activity( end: int | None = None, page_size: int = 20, ) -> AsyncPaginator[Activity]: + """List activity for a user or the authenticated wallet. + + Returns: + An async paginator over matching activity entries. + """ spec = _data_actions.list_activity_spec( user=self._user_or_wallet(user), market=market, @@ -864,10 +972,16 @@ def list_builder_leaderboard( time_period: LeaderboardTimePeriod | None = None, page_size: int = 20, ) -> AsyncPaginator[LeaderboardEntry]: + """List builder leaderboard entries. + + Returns: + An async paginator over leaderboard rows. + """ spec = _data_actions.list_builder_leaderboard_spec(time_period=time_period) return async_paginate_offset(self._ctx, spec, page_size=page_size) async def download_accounting_snapshot(self, *, user: str | None = None) -> bytes: + """Download the accounting snapshot archive for a user or the authenticated wallet.""" path, params = _data_actions.build_accounting_snapshot_request( user=self._user_or_wallet(user) ) @@ -883,6 +997,11 @@ def list_trader_leaderboard( user_name: str | None = None, page_size: int = 20, ) -> AsyncPaginator[TraderLeaderboardEntry]: + """List trader leaderboard entries. + + Returns: + An async paginator over leaderboard rows. + """ spec = _data_actions.list_trader_leaderboard_spec( category=category, time_period=time_period, @@ -935,6 +1054,11 @@ def list_events( volume_min: float | None = None, page_size: int = 20, ) -> AsyncPaginator[Event]: + """List events. + + Returns: + An async paginator over matching events. + """ spec = _gamma_actions.list_events_spec( ascending=ascending, closed=closed, @@ -1011,6 +1135,11 @@ def list_markets( volume_num_min: float | None = None, page_size: int = 20, ) -> AsyncPaginator[Market]: + """List markets. + + Returns: + An async paginator over matching markets. + """ spec = _gamma_actions.list_markets_spec( ascending=ascending, closed=closed, @@ -1059,6 +1188,11 @@ def list_series( slug: str | Sequence[str] | None = None, page_size: int = 20, ) -> AsyncPaginator[Series]: + """List series. + + Returns: + An async paginator over matching series. + """ spec = _gamma_actions.list_series_spec( ascending=ascending, categories_ids=categories_ids, @@ -1084,6 +1218,11 @@ def list_tags( order: str | None = None, page_size: int = 20, ) -> AsyncPaginator[Tag]: + """List tags. + + Returns: + An async paginator over matching tags. + """ spec = _gamma_actions.list_tags_spec( ascending=ascending, include_chat=include_chat, @@ -1105,6 +1244,11 @@ def list_teams( provider_ids: int | Sequence[int] | None = None, page_size: int = 20, ) -> AsyncPaginator[Team]: + """List teams. + + Returns: + An async paginator over matching teams. + """ spec = _gamma_actions.list_teams_spec( abbreviation=abbreviation, ascending=ascending, @@ -1126,6 +1270,11 @@ def list_comments( order: str | None = None, page_size: int = 20, ) -> AsyncPaginator[Comment]: + """List comments for a market or event. + + Returns: + An async paginator over matching comments. + """ spec = _gamma_actions.list_comments_spec( parent_entity_id=parent_entity_id, parent_entity_type=parent_entity_type, @@ -1144,6 +1293,11 @@ def list_comments_by_user_address( order: str | None = None, page_size: int = 20, ) -> AsyncPaginator[Comment]: + """List comments authored by a user address. + + Returns: + An async paginator over matching comments. + """ spec = _gamma_actions.list_comments_by_user_address_spec( address=address, ascending=ascending, @@ -1169,6 +1323,11 @@ def search( sort: str | None = None, page_size: int = 10, ) -> AsyncPaginator[SearchResults]: + """Search Polymarket content. + + Returns: + An async paginator over search result pages. + """ spec = _gamma_actions.search_spec( q=q, ascending=ascending, @@ -1187,40 +1346,49 @@ def search( return async_paginate_page_based(self._ctx, spec, page_size=page_size) async def get_midpoint(self, *, token_id: str) -> Decimal: + """Get the midpoint price for a token.""" path, params = _clob_actions.build_midpoint_request(token_id=token_id) return _clob_actions.parse_midpoint(await self._ctx.clob.get_json(path, params=params)) async def get_midpoints(self, *, token_ids: Sequence[str]) -> dict[str, Decimal]: + """Get midpoint prices for multiple tokens.""" path, body = _clob_actions.build_midpoints_request(token_ids=token_ids) return _clob_actions.parse_midpoints(await self._ctx.clob.post_json(path, json=body)) async def get_price(self, *, token_id: str, side: OrderSide) -> Decimal: + """Get the executable price for a token side.""" path, params = _clob_actions.build_price_request(token_id=token_id, side=side) return _clob_actions.parse_price(await self._ctx.clob.get_json(path, params=params)) async def get_prices( self, *, requests: Sequence[PriceRequest] ) -> dict[str, dict[OrderSide, Decimal]]: + """Get executable prices for multiple token-side requests.""" path, body = _clob_actions.build_prices_request(requests=requests) return _clob_actions.parse_prices(await self._ctx.clob.post_json(path, json=body)) async def get_order_book(self, *, token_id: str) -> OrderBook: + """Get the order book for a token.""" path, params = _clob_actions.build_order_book_request(token_id=token_id) return _clob_actions.parse_order_book(await self._ctx.clob.get_json(path, params=params)) async def get_order_books(self, *, token_ids: Sequence[str]) -> tuple[OrderBook, ...]: + """Get order books for multiple tokens.""" path, body = _clob_actions.build_order_books_request(token_ids=token_ids) return _clob_actions.parse_order_books(await self._ctx.clob.post_json(path, json=body)) async def get_spread(self, *, token_id: str) -> Decimal: + """Get the bid-ask spread for a token.""" path, params = _clob_actions.build_spread_request(token_id=token_id) return _clob_actions.parse_spread(await self._ctx.clob.get_json(path, params=params)) async def get_spreads(self, *, token_ids: Sequence[str]) -> dict[str, Decimal]: + """Get bid-ask spreads for multiple tokens.""" path, body = _clob_actions.build_spreads_request(token_ids=token_ids) return _clob_actions.parse_spreads(await self._ctx.clob.post_json(path, json=body)) async def get_last_trade_price(self, *, token_id: str) -> LastTradePrice: + """Get the most recent trade price for a token.""" path, params = _clob_actions.build_last_trade_price_request(token_id=token_id) return _clob_actions.parse_last_trade_price( await self._ctx.clob.get_json(path, params=params) @@ -1229,6 +1397,7 @@ async def get_last_trade_price(self, *, token_id: str) -> LastTradePrice: async def get_last_trade_prices( self, *, token_ids: Sequence[str] ) -> tuple[LastTradePriceForToken, ...]: + """Get the most recent trade prices for multiple tokens.""" path, body = _clob_actions.build_last_trade_prices_request(token_ids=token_ids) return _clob_actions.parse_last_trade_prices( await self._ctx.clob.post_json(path, json=body) @@ -1243,6 +1412,7 @@ async def get_price_history( fidelity: int | None = None, interval: PriceHistoryInterval | None = None, ) -> tuple[PriceHistoryPoint, ...]: + """Get historical price points for a token.""" path, params = _clob_actions.build_price_history_request( token_id=token_id, start_ts=start_ts, @@ -1253,12 +1423,15 @@ async def get_price_history( return _clob_actions.parse_price_history(await self._ctx.clob.get_json(path, params=params)) async def fetch_api_keys(self) -> tuple[str, ...]: + """Fetch API key identifiers for the authenticated account.""" return await _auth_actions.fetch_api_keys(self._ctx.secure_clob) async def delete_api_key(self) -> None: + """Delete the API key currently used by this client.""" await _auth_actions.delete_api_key(self._ctx.secure_clob) async def end_authentication(self) -> "AsyncPublicClient": + """Delete current credentials, close this client, and return an async public client.""" environment = self._ctx.environment try: await self.delete_api_key() @@ -1271,6 +1444,7 @@ async def end_authentication(self) -> "AsyncPublicClient": return AsyncPublicClient(environment=environment) async def get_closed_only_mode(self) -> bool: + """Return whether the authenticated account is in closed-only mode.""" path, params = _account_actions.build_closed_only_mode_request() return _account_actions.parse_closed_only_mode( await self._ctx.secure_clob.get_json(path, params=params) @@ -1283,6 +1457,12 @@ def list_open_orders( id: str | None = None, market: str | None = None, ) -> AsyncPaginator[OpenOrder]: + """List open orders for the authenticated account. + + Returns: + An async paginator over matching open orders. + """ + async def fetch(cursor: str | None) -> Page[OpenOrder]: path, params = _account_actions.build_list_open_orders_request( token_id=token_id, id=id, market=market, cursor=cursor @@ -1293,6 +1473,7 @@ async def fetch(cursor: str | None) -> Page[OpenOrder]: return AsyncPaginator(fetch=fetch) async def get_order(self, *, order_id: str) -> OpenOrder: + """Get one open order for the authenticated account.""" path, params = _account_actions.build_get_order_request(order_id=order_id) return _account_actions.parse_open_order( await self._ctx.secure_clob.get_json(path, params=params) @@ -1308,6 +1489,12 @@ def list_account_trades( after: str | None = None, before: str | None = None, ) -> AsyncPaginator[ClobTrade]: + """List trades for the authenticated account. + + Returns: + An async paginator over matching trades. + """ + async def fetch(cursor: str | None) -> Page[ClobTrade]: path, params = _account_actions.build_list_account_trades_request( token_id=token_id, @@ -1324,6 +1511,7 @@ async def fetch(cursor: str | None) -> Page[ClobTrade]: return AsyncPaginator(fetch=fetch) async def get_notifications(self) -> tuple[Notification, ...]: + """Get notifications for the authenticated account.""" path, params = _account_actions.build_notifications_request( signature_type=signature_type_for(self._ctx.wallet_type) ) @@ -1332,6 +1520,7 @@ async def get_notifications(self) -> tuple[Notification, ...]: ) async def drop_notifications(self, *, ids: Sequence[int | str]) -> None: + """Delete notifications for the authenticated account.""" path, params = _account_actions.build_drop_notifications_request( ids=ids, signature_type=signature_type_for(self._ctx.wallet_type) ) @@ -1340,6 +1529,7 @@ async def drop_notifications(self, *, ids: Sequence[int | str]) -> None: async def get_balance_allowance( self, *, asset_type: AssetType, token_id: str | None = None ) -> BalanceAllowance: + """Get balance and allowance information for an asset.""" path, params = _account_actions.build_balance_allowance_request( asset_type=asset_type, token_id=token_id, @@ -1376,6 +1566,11 @@ async def estimate_market_price( shares: Decimal | int | float | str | None = None, order_type: MarketOrderType = "FOK", ) -> Decimal: + """Estimate the average execution price for a market order. + + BUY orders use ``amount`` as the spend amount. SELL orders use ``shares`` + as the number of shares to sell. + """ return await _estimate_market_price( self._ctx, token_id=token_id, @@ -1396,6 +1591,11 @@ async def create_limit_order( expiration: int | None = None, builder_code: str | None = None, ) -> SignedOrder: + """Create and sign a limit order without posting it. + + Use :meth:`post_order` to submit the returned signed order, or + :meth:`place_limit_order` to create and post in one call. + """ params = validate_limit_order_params( token_id=token_id, price=price, @@ -1440,6 +1640,12 @@ async def create_market_order( order_type: MarketOrderType = "FAK", builder_code: str | None = None, ) -> SignedOrder: + """Create and sign a market order without posting it. + + BUY orders use ``amount`` as the spend amount and may include + ``max_spend``. SELL orders use ``shares`` as the number of shares to + sell. + """ return await self._prepare_and_sign_market_order( token_id=token_id, side=side, @@ -1484,6 +1690,7 @@ async def place_limit_order( expiration: int | None = None, builder_code: str | None = None, ) -> OrderResponse: + """Create, sign, and post a limit order.""" signed = await self.create_limit_order( token_id=token_id, price=price, @@ -1527,6 +1734,12 @@ async def place_market_order( order_type: MarketOrderType = "FAK", builder_code: str | None = None, ) -> OrderResponse: + """Create, sign, and post a market order. + + BUY orders use ``amount`` as the spend amount and may include + ``max_spend``. SELL orders use ``shares`` as the number of shares to + sell. + """ signed = await self._prepare_and_sign_market_order( token_id=token_id, side=side, @@ -1539,6 +1752,7 @@ async def place_market_order( return await post_order_with_allowance_recovery(self, signed) async def get_builder_fee_rates(self, builder_code: str) -> BuilderFeeRates: + """Get fee rates for a builder code.""" from polymarket._internal.actions.orders.market_data import fetch_builder_fee_rates return await fetch_builder_fee_rates(self._ctx, builder_code=builder_code) @@ -1551,6 +1765,14 @@ async def approve_erc20( amount: int | Literal["max"], metadata: str | None = None, ) -> TransactionHandle: + """Submit an ERC-20 approval transaction. + + Args: + amount: Base-units amount to approve, or ``"max"`` for the maximum value. + + Returns: + A transaction handle. Await ``wait()`` to wait for a terminal outcome. + """ try: token = cast(EvmAddress, to_checksum_address(token_address)) except ValueError as error: @@ -1574,6 +1796,11 @@ async def approve_erc1155_for_all( approved: bool = True, metadata: str | None = None, ) -> TransactionHandle: + """Approve or revoke an ERC-1155 operator for all tokens. + + Returns: + A transaction handle. Await ``wait()`` to wait for a terminal outcome. + """ try: token = cast(EvmAddress, to_checksum_address(token_address)) except ValueError as error: @@ -1597,6 +1824,14 @@ async def transfer_erc20( amount: int, metadata: str | None = None, ) -> TransactionHandle: + """Submit an ERC-20 transfer transaction. + + Args: + amount: Base-units amount to transfer. + + Returns: + A transaction handle. Await ``wait()`` to wait for a terminal outcome. + """ try: token = cast(EvmAddress, to_checksum_address(token_address)) except ValueError as error: @@ -1612,6 +1847,15 @@ async def transfer_erc20( return await self._dispatch_single_call(call, metadata=resolved_metadata) async def setup_trading_approvals(self) -> TransactionHandle: + """Approve the standard set of trading allowances for the wallet. + + EOA wallets submit approvals directly. Gasless wallets submit a relayed + transaction. The returned handle represents the final transaction in the + setup workflow. + + Returns: + A transaction handle. Await ``wait()`` to wait for a terminal outcome. + """ env = self._ctx.environment collateral = cast(EvmAddress, env.collateral_token) conditional = cast(EvmAddress, env.conditional_tokens) @@ -1682,6 +1926,15 @@ async def setup_trading_approvals(self) -> TransactionHandle: ) async def setup_gasless_wallet(self) -> Self: + """Create or reuse the gasless wallet for the signer. + + Returns: + A new async secure client scoped to the gasless wallet. + + Raises: + UserInputError: If the client was not created with an API key that + can authorize gasless wallet workflows. + """ ctx = self._ctx if ctx.api_key is None: raise UserInputError( @@ -1721,6 +1974,7 @@ async def setup_gasless_wallet(self) -> Self: ) async def is_gasless_ready(self) -> bool: + """Return whether the signer has a deployed gasless wallet ready to use.""" ctx = self._ctx if ctx.wallet_type != "EOA": type_param = ( @@ -1759,6 +2013,14 @@ async def split_position( amount: int, metadata: str | None = None, ) -> TransactionHandle: + """Split collateral into outcome positions for a condition. + + Args: + amount: Base-units collateral amount to split. + + Returns: + A transaction handle. Await ``wait()`` to wait for a terminal outcome. + """ env = self._ctx.environment neg_risk = await self._resolve_market_neg_risk(condition_id) call = split_position_call( @@ -1781,6 +2043,15 @@ async def merge_positions( amount: int | Literal["max"], metadata: str | None = None, ) -> TransactionHandle: + """Merge outcome positions back into collateral. + + Args: + amount: Base-units position amount to merge, or ``"max"`` to merge + the largest available balanced amount. + + Returns: + A transaction handle. Await ``wait()`` to wait for a terminal outcome. + """ env = self._ctx.environment binary = await self._fetch_binary_positions(condition_id) neg_risk = expect_negative_risk_flag(binary) @@ -1805,6 +2076,16 @@ async def redeem_positions( market_id: str | None = None, metadata: str | None = None, ) -> TransactionHandle: + """Redeem resolved positions for a condition or market. + + Provide exactly one of ``condition_id`` or ``market_id``. + + Returns: + A transaction handle. Await ``wait()`` to wait for a terminal outcome. + + Raises: + UserInputError: If both identifiers or neither identifier is provided. + """ if (condition_id is None) == (market_id is None): raise UserInputError("Provide exactly one of condition_id or market_id") env = self._ctx.environment @@ -1853,6 +2134,7 @@ async def _fetch_binary_positions(self, market_id_or_condition_id: str): # type return expect_binary_positions(page.items) async def post_order(self, signed_order: SignedOrder) -> OrderResponse: + """Post a signed order for the authenticated account.""" path, payload = _post_actions.build_post_order_request( signed_order, owner_api_key=self._ctx.credentials.key ) @@ -1861,6 +2143,7 @@ async def post_order(self, signed_order: SignedOrder) -> OrderResponse: ) async def post_orders(self, signed_orders: Sequence[SignedOrder]) -> tuple[OrderResponse, ...]: + """Post multiple signed orders for the authenticated account.""" path, payload = _post_actions.build_post_orders_request( signed_orders, owner_api_key=self._ctx.credentials.key ) @@ -1869,18 +2152,21 @@ async def post_orders(self, signed_orders: Sequence[SignedOrder]) -> tuple[Order ) async def cancel_order(self, *, order_id: str) -> CancelOrdersResponse: + """Cancel one open order for the authenticated account.""" path, body = _cancel_actions.build_cancel_order_request(order_id=order_id) return _cancel_actions.parse_cancel_orders_response( await self._ctx.secure_clob.delete_json(path, json=body) ) async def cancel_orders(self, *, order_ids: Sequence[str]) -> CancelOrdersResponse: + """Cancel multiple open orders for the authenticated account.""" path, body = _cancel_actions.build_cancel_orders_request(order_ids=order_ids) return _cancel_actions.parse_cancel_orders_response( await self._ctx.secure_clob.delete_json(path, json=body) ) async def cancel_all(self) -> CancelOrdersResponse: + """Cancel all open orders for the authenticated account.""" path, body = _cancel_actions.build_cancel_all_request() return _cancel_actions.parse_cancel_orders_response( await self._ctx.secure_clob.delete_json(path, json=body) @@ -1889,6 +2175,7 @@ async def cancel_all(self) -> CancelOrdersResponse: async def cancel_market_orders( self, *, market: str | None = None, token_id: str | None = None ) -> CancelOrdersResponse: + """Cancel open orders matching a market or token filter.""" path, body = _cancel_actions.build_cancel_market_orders_request( market=market, token_id=token_id ) @@ -1913,6 +2200,12 @@ async def _sign_order(self, draft: OrderDraft, *, post_only: bool) -> SignedOrde def list_current_rewards( self, *, sponsored: bool | None = None ) -> AsyncPaginator[CurrentReward]: + """List current rewards. + + Returns: + An async paginator over current reward configurations. + """ + async def fetch(cursor: str | None) -> Page[CurrentReward]: path, params = _rewards_actions.build_list_current_rewards_request( sponsored=sponsored, cursor=cursor @@ -1926,6 +2219,12 @@ async def fetch(cursor: str | None) -> Page[CurrentReward]: def list_market_rewards( self, *, condition_id: str, sponsored: bool | None = None ) -> AsyncPaginator[MarketReward]: + """List rewards for a market condition. + + Returns: + An async paginator over matching market reward configurations. + """ + async def fetch(cursor: str | None) -> Page[MarketReward]: path, params = _rewards_actions.build_list_market_rewards_request( condition_id=ConditionId(condition_id), sponsored=sponsored, cursor=cursor @@ -1937,18 +2236,26 @@ async def fetch(cursor: str | None) -> Page[MarketReward]: return AsyncPaginator(fetch=fetch) async def get_order_scoring(self, *, order_id: str) -> bool: + """Return whether an order is currently scoring rewards.""" path, params = _rewards_actions.build_get_order_scoring_request(order_id=order_id) return _rewards_actions.parse_order_scoring( await self._ctx.secure_clob.get_json(path, params=params) ) async def get_orders_scoring(self, *, order_ids: Sequence[str]) -> dict[str, bool]: + """Return reward-scoring status for multiple orders.""" path, body = _rewards_actions.build_get_orders_scoring_request(order_ids=order_ids) return _rewards_actions.parse_orders_scoring( await self._ctx.secure_clob.post_json(path, json=body) ) def list_user_earnings_for_day(self, *, date: str) -> AsyncPaginator[UserEarning]: + """List reward earnings for the authenticated user on a date. + + Returns: + An async paginator over matching earning entries. + """ + async def fetch(cursor: str | None) -> Page[UserEarning]: path, params = _rewards_actions.build_list_user_earnings_for_day_request( date=date, @@ -1964,6 +2271,7 @@ async def fetch(cursor: str | None) -> Page[UserEarning]: async def get_total_earnings_for_user_for_day( self, *, date: str ) -> tuple[TotalUserEarning, ...]: + """Get total reward earnings for the authenticated user on a date.""" path, params = _rewards_actions.build_total_user_earnings_for_day_request( date=date, signature_type=signature_type_for(self._ctx.wallet_type) ) @@ -1980,6 +2288,12 @@ def list_user_earnings_and_markets_config( position: str | None = None, page_size: int | None = None, ) -> AsyncPaginator[UserRewardsEarning]: + """List reward earnings with market configuration for the authenticated user. + + Returns: + An async paginator over matching reward earning entries. + """ + async def fetch(cursor: str | None) -> Page[UserRewardsEarning]: path, params = _rewards_actions.build_list_user_earnings_and_markets_config_request( date=date, @@ -1997,6 +2311,7 @@ async def fetch(cursor: str | None) -> Page[UserRewardsEarning]: return AsyncPaginator(fetch=fetch) async def get_reward_percentages(self) -> RewardsPercentages: + """Get current reward percentage allocations for the authenticated account.""" path, params = _rewards_actions.build_get_reward_percentages_request( signature_type=signature_type_for(self._ctx.wallet_type) ) diff --git a/src/polymarket/clients/public.py b/src/polymarket/clients/public.py index 8625aab..25afd71 100644 --- a/src/polymarket/clients/public.py +++ b/src/polymarket/clients/public.py @@ -110,6 +110,7 @@ def __init__( @property def environment(self) -> Environment: + """Environment this client sends requests to.""" return self._ctx.environment def __enter__(self) -> Self: @@ -277,11 +278,13 @@ def get_comment_thread( ) def get_event_live_volumes(self, *, id: str) -> tuple[LiveVolume, ...]: + """Get live volume entries for an event.""" return sync_dispatch(self._ctx, _data_actions.get_event_live_volumes_spec(id=id)) def get_open_interests( self, *, market: Sequence[str] | None = None ) -> tuple[OpenInterest, ...]: + """Get open interest values, optionally filtered by market ids.""" return sync_dispatch(self._ctx, _data_actions.get_open_interests_spec(market=market)) def get_market_holders( @@ -291,6 +294,7 @@ def get_market_holders( limit: int | None = None, min_balance: int | None = None, ) -> tuple[MetaHolder, ...]: + """Get holder balances for one or more markets.""" return sync_dispatch( self._ctx, _data_actions.get_market_holders_spec( @@ -301,16 +305,19 @@ def get_market_holders( def get_portfolio_values( self, *, user: str, market: Sequence[str] | None = None ) -> tuple[PortfolioValue, ...]: + """Get portfolio value snapshots for a user.""" return sync_dispatch( self._ctx, _data_actions.get_portfolio_values_spec(user=user, market=market) ) def get_traded_market_count(self, *, user: str) -> TradedMarketCount: + """Get the number of markets a user has traded.""" return sync_dispatch(self._ctx, _data_actions.get_traded_market_count_spec(user=user)) def get_builder_volumes( self, *, time_period: BuilderVolumeTimePeriod | None = None ) -> tuple[BuilderVolumeEntry, ...]: + """Get builder volume leaderboard entries.""" return sync_dispatch( self._ctx, _data_actions.get_builder_volumes_spec(time_period=time_period) ) @@ -325,6 +332,13 @@ def list_builder_trades( after: str | None = None, before: str | None = None, ) -> Paginator[BuilderTrade]: + """List builder-attributed trades. + + Returns: + A paginator. Use ``first_page()``, iterate over pages, or call ``items()`` + to stream individual trades. + """ + def fetch(cursor: str | None) -> Page[BuilderTrade]: path, params = _builders_actions.build_list_builder_trades_request( builder_code=builder_code, @@ -354,6 +368,11 @@ def list_positions( title: str | None = None, page_size: int = 20, ) -> Paginator[Position]: + """List open positions for a user. + + Returns: + A paginator over matching positions. + """ spec = _data_actions.list_positions_spec( user=user, market=market, @@ -378,6 +397,11 @@ def list_closed_positions( sort_direction: SortDirection | None = None, page_size: int = 20, ) -> Paginator[ClosedPosition]: + """List closed positions for a user. + + Returns: + A paginator over matching closed positions. + """ spec = _data_actions.list_closed_positions_spec( user=user, market=market, @@ -398,6 +422,11 @@ def list_market_positions( sort_direction: SortDirection | None = None, page_size: int = 20, ) -> Paginator[MetaMarketPosition]: + """List positions in a market. + + Returns: + A paginator over matching market positions. + """ spec = _data_actions.list_market_positions_spec( market=market, user=user, @@ -419,6 +448,11 @@ def list_trades( filter_amount: float | None = None, page_size: int = 20, ) -> Paginator[Trade]: + """List public trades. + + Returns: + A paginator over matching trades. + """ spec = _data_actions.list_trades_spec( user=user, market=market, @@ -444,6 +478,11 @@ def list_activity( end: int | None = None, page_size: int = 20, ) -> Paginator[Activity]: + """List user activity. + + Returns: + A paginator over matching activity entries. + """ spec = _data_actions.list_activity_spec( user=user, market=market, @@ -463,10 +502,16 @@ def list_builder_leaderboard( time_period: LeaderboardTimePeriod | None = None, page_size: int = 20, ) -> Paginator[LeaderboardEntry]: + """List builder leaderboard entries. + + Returns: + A paginator over leaderboard rows. + """ spec = _data_actions.list_builder_leaderboard_spec(time_period=time_period) return sync_paginate_offset(self._ctx, spec, page_size=page_size) def download_accounting_snapshot(self, *, user: str) -> bytes: + """Download the accounting snapshot archive for a user.""" path, params = _data_actions.build_accounting_snapshot_request(user=user) return self._ctx.data.get_bytes(path, params=params) @@ -480,6 +525,11 @@ def list_trader_leaderboard( user_name: str | None = None, page_size: int = 20, ) -> Paginator[TraderLeaderboardEntry]: + """List trader leaderboard entries. + + Returns: + A paginator over leaderboard rows. + """ spec = _data_actions.list_trader_leaderboard_spec( category=category, time_period=time_period, @@ -532,6 +582,23 @@ def list_events( volume_min: float | None = None, page_size: int = 20, ) -> Paginator[Event]: + """List events. + + Returns: + A paginator over matching events. + + Examples: + Fetch the first page:: + + paginator = client.list_events(page_size=10) + first_page = paginator.first_page() + + Iterate over all pages:: + + for page in client.list_events(page_size=10): + for event in page.items: + print(event.title) + """ spec = _gamma_actions.list_events_spec( ascending=ascending, closed=closed, @@ -608,6 +675,22 @@ def list_markets( volume_num_min: float | None = None, page_size: int = 20, ) -> Paginator[Market]: + """List markets. + + Returns: + A paginator over matching markets. + + Examples: + Fetch the first page:: + + paginator = client.list_markets(closed=False, page_size=10) + first_page = paginator.first_page() + + Iterate over every market item:: + + for market in client.list_markets(closed=False).items(): + print(market.question) + """ spec = _gamma_actions.list_markets_spec( ascending=ascending, closed=closed, @@ -656,6 +739,11 @@ def list_series( slug: str | Sequence[str] | None = None, page_size: int = 20, ) -> Paginator[Series]: + """List series. + + Returns: + A paginator over matching series. + """ spec = _gamma_actions.list_series_spec( ascending=ascending, categories_ids=categories_ids, @@ -681,6 +769,11 @@ def list_tags( order: str | None = None, page_size: int = 20, ) -> Paginator[Tag]: + """List tags. + + Returns: + A paginator over matching tags. + """ spec = _gamma_actions.list_tags_spec( ascending=ascending, include_chat=include_chat, @@ -702,6 +795,11 @@ def list_teams( provider_ids: int | Sequence[int] | None = None, page_size: int = 20, ) -> Paginator[Team]: + """List teams. + + Returns: + A paginator over matching teams. + """ spec = _gamma_actions.list_teams_spec( abbreviation=abbreviation, ascending=ascending, @@ -723,6 +821,11 @@ def list_comments( order: str | None = None, page_size: int = 20, ) -> Paginator[Comment]: + """List comments for a market or event. + + Returns: + A paginator over matching comments. + """ spec = _gamma_actions.list_comments_spec( parent_entity_id=parent_entity_id, parent_entity_type=parent_entity_type, @@ -741,6 +844,11 @@ def list_comments_by_user_address( order: str | None = None, page_size: int = 20, ) -> Paginator[Comment]: + """List comments authored by a user address. + + Returns: + A paginator over matching comments. + """ spec = _gamma_actions.list_comments_by_user_address_spec( address=address, ascending=ascending, @@ -766,6 +874,17 @@ def search( sort: str | None = None, page_size: int = 10, ) -> Paginator[SearchResults]: + """Search Polymarket content. + + Returns: + A paginator over search result pages. + + Examples: + Search markets and events:: + + for result in client.search(q="election").items(): + print(result) + """ spec = _gamma_actions.search_spec( q=q, ascending=ascending, @@ -784,46 +903,56 @@ def search( return sync_paginate_page_based(self._ctx, spec, page_size=page_size) def get_midpoint(self, *, token_id: str) -> Decimal: + """Get the midpoint price for a token.""" path, params = _clob_actions.build_midpoint_request(token_id=token_id) return _clob_actions.parse_midpoint(self._ctx.clob.get_json(path, params=params)) def get_midpoints(self, *, token_ids: Sequence[str]) -> dict[str, Decimal]: + """Get midpoint prices for multiple tokens.""" path, body = _clob_actions.build_midpoints_request(token_ids=token_ids) return _clob_actions.parse_midpoints(self._ctx.clob.post_json(path, json=body)) def get_price(self, *, token_id: str, side: OrderSide) -> Decimal: + """Get the executable price for a token side.""" path, params = _clob_actions.build_price_request(token_id=token_id, side=side) return _clob_actions.parse_price(self._ctx.clob.get_json(path, params=params)) def get_prices( self, *, requests: Sequence[PriceRequest] ) -> dict[str, dict[OrderSide, Decimal]]: + """Get executable prices for multiple token-side requests.""" path, body = _clob_actions.build_prices_request(requests=requests) return _clob_actions.parse_prices(self._ctx.clob.post_json(path, json=body)) def get_order_book(self, *, token_id: str) -> OrderBook: + """Get the order book for a token.""" path, params = _clob_actions.build_order_book_request(token_id=token_id) return _clob_actions.parse_order_book(self._ctx.clob.get_json(path, params=params)) def get_order_books(self, *, token_ids: Sequence[str]) -> tuple[OrderBook, ...]: + """Get order books for multiple tokens.""" path, body = _clob_actions.build_order_books_request(token_ids=token_ids) return _clob_actions.parse_order_books(self._ctx.clob.post_json(path, json=body)) def get_spread(self, *, token_id: str) -> Decimal: + """Get the bid-ask spread for a token.""" path, params = _clob_actions.build_spread_request(token_id=token_id) return _clob_actions.parse_spread(self._ctx.clob.get_json(path, params=params)) def get_spreads(self, *, token_ids: Sequence[str]) -> dict[str, Decimal]: + """Get bid-ask spreads for multiple tokens.""" path, body = _clob_actions.build_spreads_request(token_ids=token_ids) return _clob_actions.parse_spreads(self._ctx.clob.post_json(path, json=body)) def get_last_trade_price(self, *, token_id: str) -> LastTradePrice: + """Get the most recent trade price for a token.""" path, params = _clob_actions.build_last_trade_price_request(token_id=token_id) return _clob_actions.parse_last_trade_price(self._ctx.clob.get_json(path, params=params)) def get_last_trade_prices( self, *, token_ids: Sequence[str] ) -> tuple[LastTradePriceForToken, ...]: + """Get the most recent trade prices for multiple tokens.""" path, body = _clob_actions.build_last_trade_prices_request(token_ids=token_ids) return _clob_actions.parse_last_trade_prices(self._ctx.clob.post_json(path, json=body)) @@ -836,6 +965,7 @@ def get_price_history( fidelity: int | None = None, interval: PriceHistoryInterval | None = None, ) -> tuple[PriceHistoryPoint, ...]: + """Get historical price points for a token.""" path, params = _clob_actions.build_price_history_request( token_id=token_id, start_ts=start_ts, @@ -872,6 +1002,15 @@ def estimate_market_price( shares: Decimal | int | float | str | None = None, order_type: MarketOrderType = "FOK", ) -> Decimal: + """Estimate the average execution price for a market order. + + BUY orders use ``amount`` as the spend amount. SELL orders use ``shares`` + as the number of shares to sell. + + Raises: + UserInputError: If the side-specific amount is missing or invalid. + InsufficientLiquidityError: If available liquidity cannot fill the order. + """ return _estimate_market_price_sync( self._ctx, token_id=token_id, @@ -882,6 +1021,12 @@ def estimate_market_price( ) def list_current_rewards(self, *, sponsored: bool | None = None) -> Paginator[CurrentReward]: + """List current rewards. + + Returns: + A paginator over current reward configurations. + """ + def fetch(cursor: str | None) -> Page[CurrentReward]: path, params = _rewards_actions.build_list_current_rewards_request( sponsored=sponsored, cursor=cursor @@ -895,6 +1040,12 @@ def fetch(cursor: str | None) -> Page[CurrentReward]: def list_market_rewards( self, *, condition_id: str, sponsored: bool | None = None ) -> Paginator[MarketReward]: + """List rewards for a market condition. + + Returns: + A paginator over matching market reward configurations. + """ + def fetch(cursor: str | None) -> Page[MarketReward]: path, params = _rewards_actions.build_list_market_rewards_request( condition_id=ConditionId(condition_id), sponsored=sponsored, cursor=cursor diff --git a/src/polymarket/clients/secure.py b/src/polymarket/clients/secure.py index db7e9d4..8ab9aac 100644 --- a/src/polymarket/clients/secure.py +++ b/src/polymarket/clients/secure.py @@ -188,6 +188,12 @@ def _validate_nonce(nonce: object) -> None: class SecureClient: + """Synchronous client for authenticated account, trading, and wallet workflows. + + Create instances with :meth:`SecureClient.create` so the SDK can derive or + validate credentials before authenticated requests are made. + """ + def __init__( self, *, @@ -216,6 +222,43 @@ def _ctx(self, value: SyncSecureClientContext) -> None: @classmethod def create( + cls, + *, + private_key: str, + wallet: str | None = None, + environment: Environment = PRODUCTION, + credentials: ApiKeyCreds | None = None, + api_key: ApiKey | None = None, + nonce: int = 0, + logger: logging.Logger | None = None, + ) -> Self: + """Create an authenticated synchronous client. + + Args: + private_key: EVM private key used for signing. + wallet: Wallet address to act for. Defaults to the signer's address. + credentials: Existing API credentials. When omitted, credentials are + derived during client creation. + api_key: Optional key for gasless wallet and relayed transaction workflows. + nonce: Credential derivation nonce. Cannot be combined with ``credentials``. + + Raises: + UserInputError: If key material, wallet, nonce, or credentials are invalid. + RequestRejectedError: If credential derivation or validation is rejected. + """ + return cls._create( + private_key=private_key, + wallet=wallet, + environment=environment, + credentials=credentials, + api_key=api_key, + nonce=nonce, + validate_credentials=True, + logger=logger, + ) + + @classmethod + def _create( cls, *, private_key: str, @@ -328,22 +371,27 @@ def _construct_for_wallet( @property def environment(self) -> Environment: + """Environment this client sends requests to.""" return self._ctx.environment @property def wallet(self) -> EvmAddress: + """Wallet address authenticated by this client.""" return self._ctx.wallet @property def signer(self) -> EvmAddress: + """Signer address used for signatures.""" return cast(EvmAddress, self._ctx.signer.address) @property def wallet_type(self) -> WalletType: + """Detected wallet type for the authenticated wallet.""" return self._ctx.wallet_type @property def credentials(self) -> ApiKeyCreds: + """API credentials used for authenticated requests.""" return self._ctx.credentials def __enter__(self) -> Self: @@ -389,6 +437,7 @@ def get_market( include_tag: bool | None = None, locale: str | None = None, ) -> Market: + """Get a market by id, slug, or Polymarket URL.""" return sync_dispatch( self._ctx, _gamma_actions.get_market_spec( @@ -397,6 +446,7 @@ def get_market( ) 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)) def get_event( @@ -410,6 +460,7 @@ def get_event( include_template: bool | None = None, locale: str | None = None, ) -> Event: + """Get an event by id, slug, or Polymarket URL.""" return sync_dispatch( self._ctx, _gamma_actions.get_event_spec( @@ -424,6 +475,7 @@ def get_event( ) def get_event_tags(self, id: str) -> tuple[TagReference, ...]: + """Get an event's tags.""" return sync_dispatch(self._ctx, _gamma_actions.get_event_tags_spec(id)) def get_series( @@ -433,6 +485,7 @@ def get_series( include_chat: bool | None = None, locale: str | None = None, ) -> Series: + """Get a series.""" return sync_dispatch( self._ctx, _gamma_actions.get_series_spec(id, include_chat=include_chat, locale=locale), @@ -447,6 +500,7 @@ def get_tag( include_template: bool | None = None, locale: str | None = None, ) -> Tag: + """Get a tag by id or slug.""" return sync_dispatch( self._ctx, _gamma_actions.get_tag_spec( @@ -466,6 +520,7 @@ def get_related_tags( omit_empty: bool | None = None, status: str | None = None, ) -> tuple[RelatedTag, ...]: + """Get related tag relationships.""" return sync_dispatch( self._ctx, _gamma_actions.get_related_tags_spec( @@ -482,6 +537,7 @@ def get_related_tag_resources( omit_empty: bool | None = None, status: str | None = None, ) -> tuple[Tag, ...]: + """Get tag resources linked from related tag relationships.""" return sync_dispatch( self._ctx, _gamma_actions.get_related_tag_resources_spec( @@ -490,12 +546,15 @@ def get_related_tag_resources( ) def get_sports(self) -> tuple[SportsMetadata, ...]: + """Get available sports metadata.""" return sync_dispatch(self._ctx, _gamma_actions.get_sports_spec()) def get_sports_market_types(self) -> SportsMarketTypes: + """Get available sports market types.""" return sync_dispatch(self._ctx, _gamma_actions.get_sports_market_types_spec()) def get_public_profile(self, address: str) -> PublicProfile | None: + """Get a public profile by wallet address. Returns None if no profile exists.""" try: return sync_dispatch(self._ctx, _gamma_actions.get_public_profile_spec(address)) except RequestRejectedError as error: @@ -506,17 +565,20 @@ def get_public_profile(self, address: str) -> PublicProfile | None: def get_comment_thread( self, id: str, *, get_positions: bool | None = None ) -> tuple[Comment, ...]: + """Get a comment thread by comment ID.""" return sync_dispatch( self._ctx, _gamma_actions.get_comment_thread_spec(id, get_positions=get_positions), ) def get_event_live_volumes(self, *, id: str) -> tuple[LiveVolume, ...]: + """Get live volume entries for an event.""" return sync_dispatch(self._ctx, _data_actions.get_event_live_volumes_spec(id=id)) def get_open_interests( self, *, market: Sequence[str] | None = None ) -> tuple[OpenInterest, ...]: + """Get open interest values, optionally filtered by market ids.""" return sync_dispatch(self._ctx, _data_actions.get_open_interests_spec(market=market)) def get_market_holders( @@ -526,6 +588,7 @@ def get_market_holders( limit: int | None = None, min_balance: int | None = None, ) -> tuple[MetaHolder, ...]: + """Get holder balances for one or more markets.""" return sync_dispatch( self._ctx, _data_actions.get_market_holders_spec( @@ -539,12 +602,14 @@ def get_portfolio_values( user: str | None = None, market: Sequence[str] | None = None, ) -> tuple[PortfolioValue, ...]: + """Get portfolio value snapshots for a user or the authenticated wallet.""" return sync_dispatch( self._ctx, _data_actions.get_portfolio_values_spec(user=self._user_or_wallet(user), market=market), ) def get_traded_market_count(self, *, user: str | None = None) -> TradedMarketCount: + """Get the number of markets traded by a user or the authenticated wallet.""" return sync_dispatch( self._ctx, _data_actions.get_traded_market_count_spec(user=self._user_or_wallet(user)), @@ -553,6 +618,7 @@ def get_traded_market_count(self, *, user: str | None = None) -> TradedMarketCou def get_builder_volumes( self, *, time_period: BuilderVolumeTimePeriod | None = None ) -> tuple[BuilderVolumeEntry, ...]: + """Get builder volume leaderboard entries.""" return sync_dispatch( self._ctx, _data_actions.get_builder_volumes_spec(time_period=time_period) ) @@ -567,6 +633,12 @@ def list_builder_trades( after: str | None = None, before: str | None = None, ) -> Paginator[BuilderTrade]: + """List builder-attributed trades. + + Returns: + A paginator over matching builder-attributed trades. + """ + def fetch(cursor: str | None) -> Page[BuilderTrade]: path, params = _builders_actions.build_list_builder_trades_request( builder_code=builder_code, @@ -596,6 +668,11 @@ def list_positions( title: str | None = None, page_size: int = 20, ) -> Paginator[Position]: + """List open positions for a user or the authenticated wallet. + + Returns: + A paginator over matching positions. + """ spec = _data_actions.list_positions_spec( user=self._user_or_wallet(user), market=market, @@ -620,6 +697,11 @@ def list_closed_positions( sort_direction: SortDirection | None = None, page_size: int = 20, ) -> Paginator[ClosedPosition]: + """List closed positions for a user or the authenticated wallet. + + Returns: + A paginator over matching closed positions. + """ spec = _data_actions.list_closed_positions_spec( user=self._user_or_wallet(user), market=market, @@ -640,6 +722,11 @@ def list_market_positions( sort_direction: SortDirection | None = None, page_size: int = 20, ) -> Paginator[MetaMarketPosition]: + """List positions in a market. + + Returns: + A paginator over matching market positions. + """ spec = _data_actions.list_market_positions_spec( market=market, user=user, @@ -661,6 +748,11 @@ def list_trades( filter_amount: float | None = None, page_size: int = 20, ) -> Paginator[Trade]: + """List trades for a user or the authenticated wallet. + + Returns: + A paginator over matching trades. + """ spec = _data_actions.list_trades_spec( user=self._user_or_wallet(user), market=market, @@ -686,6 +778,11 @@ def list_activity( end: int | None = None, page_size: int = 20, ) -> Paginator[Activity]: + """List activity for a user or the authenticated wallet. + + Returns: + A paginator over matching activity entries. + """ spec = _data_actions.list_activity_spec( user=self._user_or_wallet(user), market=market, @@ -705,10 +802,16 @@ def list_builder_leaderboard( time_period: LeaderboardTimePeriod | None = None, page_size: int = 20, ) -> Paginator[LeaderboardEntry]: + """List builder leaderboard entries. + + Returns: + A paginator over leaderboard rows. + """ spec = _data_actions.list_builder_leaderboard_spec(time_period=time_period) return sync_paginate_offset(self._ctx, spec, page_size=page_size) def download_accounting_snapshot(self, *, user: str | None = None) -> bytes: + """Download the accounting snapshot archive for a user or the authenticated wallet.""" path, params = _data_actions.build_accounting_snapshot_request( user=self._user_or_wallet(user) ) @@ -724,6 +827,11 @@ def list_trader_leaderboard( user_name: str | None = None, page_size: int = 20, ) -> Paginator[TraderLeaderboardEntry]: + """List trader leaderboard entries. + + Returns: + A paginator over leaderboard rows. + """ spec = _data_actions.list_trader_leaderboard_spec( category=category, time_period=time_period, @@ -776,6 +884,11 @@ def list_events( volume_min: float | None = None, page_size: int = 20, ) -> Paginator[Event]: + """List events. + + Returns: + A paginator over matching events. + """ spec = _gamma_actions.list_events_spec( ascending=ascending, closed=closed, @@ -852,6 +965,11 @@ def list_markets( volume_num_min: float | None = None, page_size: int = 20, ) -> Paginator[Market]: + """List markets. + + Returns: + A paginator over matching markets. + """ spec = _gamma_actions.list_markets_spec( ascending=ascending, closed=closed, @@ -900,6 +1018,11 @@ def list_series( slug: str | Sequence[str] | None = None, page_size: int = 20, ) -> Paginator[Series]: + """List series. + + Returns: + A paginator over matching series. + """ spec = _gamma_actions.list_series_spec( ascending=ascending, categories_ids=categories_ids, @@ -925,6 +1048,11 @@ def list_tags( order: str | None = None, page_size: int = 20, ) -> Paginator[Tag]: + """List tags. + + Returns: + A paginator over matching tags. + """ spec = _gamma_actions.list_tags_spec( ascending=ascending, include_chat=include_chat, @@ -946,6 +1074,11 @@ def list_teams( provider_ids: int | Sequence[int] | None = None, page_size: int = 20, ) -> Paginator[Team]: + """List teams. + + Returns: + A paginator over matching teams. + """ spec = _gamma_actions.list_teams_spec( abbreviation=abbreviation, ascending=ascending, @@ -967,6 +1100,11 @@ def list_comments( order: str | None = None, page_size: int = 20, ) -> Paginator[Comment]: + """List comments for a market or event. + + Returns: + A paginator over matching comments. + """ spec = _gamma_actions.list_comments_spec( parent_entity_id=parent_entity_id, parent_entity_type=parent_entity_type, @@ -985,6 +1123,11 @@ def list_comments_by_user_address( order: str | None = None, page_size: int = 20, ) -> Paginator[Comment]: + """List comments authored by a user address. + + Returns: + A paginator over matching comments. + """ spec = _gamma_actions.list_comments_by_user_address_spec( address=address, ascending=ascending, @@ -1010,6 +1153,11 @@ def search( sort: str | None = None, page_size: int = 10, ) -> Paginator[SearchResults]: + """Search Polymarket content. + + Returns: + A paginator over search result pages. + """ spec = _gamma_actions.search_spec( q=q, ascending=ascending, @@ -1028,46 +1176,56 @@ def search( return sync_paginate_page_based(self._ctx, spec, page_size=page_size) def get_midpoint(self, *, token_id: str) -> Decimal: + """Get the midpoint price for a token.""" path, params = _clob_actions.build_midpoint_request(token_id=token_id) return _clob_actions.parse_midpoint(self._ctx.clob.get_json(path, params=params)) def get_midpoints(self, *, token_ids: Sequence[str]) -> dict[str, Decimal]: + """Get midpoint prices for multiple tokens.""" path, body = _clob_actions.build_midpoints_request(token_ids=token_ids) return _clob_actions.parse_midpoints(self._ctx.clob.post_json(path, json=body)) def get_price(self, *, token_id: str, side: OrderSide) -> Decimal: + """Get the executable price for a token side.""" path, params = _clob_actions.build_price_request(token_id=token_id, side=side) return _clob_actions.parse_price(self._ctx.clob.get_json(path, params=params)) def get_prices( self, *, requests: Sequence[PriceRequest] ) -> dict[str, dict[OrderSide, Decimal]]: + """Get executable prices for multiple token-side requests.""" path, body = _clob_actions.build_prices_request(requests=requests) return _clob_actions.parse_prices(self._ctx.clob.post_json(path, json=body)) def get_order_book(self, *, token_id: str) -> OrderBook: + """Get the order book for a token.""" path, params = _clob_actions.build_order_book_request(token_id=token_id) return _clob_actions.parse_order_book(self._ctx.clob.get_json(path, params=params)) def get_order_books(self, *, token_ids: Sequence[str]) -> tuple[OrderBook, ...]: + """Get order books for multiple tokens.""" path, body = _clob_actions.build_order_books_request(token_ids=token_ids) return _clob_actions.parse_order_books(self._ctx.clob.post_json(path, json=body)) def get_spread(self, *, token_id: str) -> Decimal: + """Get the bid-ask spread for a token.""" path, params = _clob_actions.build_spread_request(token_id=token_id) return _clob_actions.parse_spread(self._ctx.clob.get_json(path, params=params)) def get_spreads(self, *, token_ids: Sequence[str]) -> dict[str, Decimal]: + """Get bid-ask spreads for multiple tokens.""" path, body = _clob_actions.build_spreads_request(token_ids=token_ids) return _clob_actions.parse_spreads(self._ctx.clob.post_json(path, json=body)) def get_last_trade_price(self, *, token_id: str) -> LastTradePrice: + """Get the most recent trade price for a token.""" path, params = _clob_actions.build_last_trade_price_request(token_id=token_id) return _clob_actions.parse_last_trade_price(self._ctx.clob.get_json(path, params=params)) def get_last_trade_prices( self, *, token_ids: Sequence[str] ) -> tuple[LastTradePriceForToken, ...]: + """Get the most recent trade prices for multiple tokens.""" path, body = _clob_actions.build_last_trade_prices_request(token_ids=token_ids) return _clob_actions.parse_last_trade_prices(self._ctx.clob.post_json(path, json=body)) @@ -1080,6 +1238,7 @@ def get_price_history( fidelity: int | None = None, interval: PriceHistoryInterval | None = None, ) -> tuple[PriceHistoryPoint, ...]: + """Get historical price points for a token.""" path, params = _clob_actions.build_price_history_request( token_id=token_id, start_ts=start_ts, @@ -1116,6 +1275,11 @@ def estimate_market_price( shares: Decimal | int | float | str | None = None, order_type: MarketOrderType = "FOK", ) -> Decimal: + """Estimate the average execution price for a market order. + + BUY orders use ``amount`` as the spend amount. SELL orders use ``shares`` + as the number of shares to sell. + """ return _estimate_market_price_sync( self._ctx, token_id=token_id, @@ -1126,6 +1290,12 @@ def estimate_market_price( ) def list_current_rewards(self, *, sponsored: bool | None = None) -> Paginator[CurrentReward]: + """List current rewards. + + Returns: + A paginator over current reward configurations. + """ + def fetch(cursor: str | None) -> Page[CurrentReward]: path, params = _rewards_actions.build_list_current_rewards_request( sponsored=sponsored, cursor=cursor @@ -1139,6 +1309,12 @@ def fetch(cursor: str | None) -> Page[CurrentReward]: def list_market_rewards( self, *, condition_id: str, sponsored: bool | None = None ) -> Paginator[MarketReward]: + """List rewards for a market condition. + + Returns: + A paginator over matching market reward configurations. + """ + def fetch(cursor: str | None) -> Page[MarketReward]: path, params = _rewards_actions.build_list_market_rewards_request( condition_id=ConditionId(condition_id), sponsored=sponsored, cursor=cursor @@ -1150,12 +1326,15 @@ def fetch(cursor: str | None) -> Page[MarketReward]: return Paginator(fetch=fetch) def fetch_api_keys(self) -> tuple[str, ...]: + """Fetch API key identifiers for the authenticated account.""" return _auth_actions.fetch_api_keys_sync(self._ctx.secure_clob) def delete_api_key(self) -> None: + """Delete the API key currently used by this client.""" _auth_actions.delete_api_key_sync(self._ctx.secure_clob) def end_authentication(self) -> "PublicClient": + """Delete current credentials, close this client, and return a public client.""" from polymarket.clients.public import PublicClient environment = self._ctx.environment @@ -1170,6 +1349,7 @@ def end_authentication(self) -> "PublicClient": return PublicClient(environment=environment) def get_closed_only_mode(self) -> bool: + """Return whether the authenticated account is in closed-only mode.""" path, params = _account_actions.build_closed_only_mode_request() return _account_actions.parse_closed_only_mode( self._ctx.secure_clob.get_json(path, params=params) @@ -1182,6 +1362,12 @@ def list_open_orders( id: str | None = None, market: str | None = None, ) -> Paginator[OpenOrder]: + """List open orders for the authenticated account. + + Returns: + A paginator over matching open orders. + """ + def fetch(cursor: str | None) -> Page[OpenOrder]: path, params = _account_actions.build_list_open_orders_request( token_id=token_id, id=id, market=market, cursor=cursor @@ -1192,6 +1378,7 @@ def fetch(cursor: str | None) -> Page[OpenOrder]: return Paginator(fetch=fetch) def get_order(self, *, order_id: str) -> OpenOrder: + """Get one open order for the authenticated account.""" path, params = _account_actions.build_get_order_request(order_id=order_id) return _account_actions.parse_open_order( self._ctx.secure_clob.get_json(path, params=params) @@ -1207,6 +1394,12 @@ def list_account_trades( after: str | None = None, before: str | None = None, ) -> Paginator[ClobTrade]: + """List trades for the authenticated account. + + Returns: + A paginator over matching trades. + """ + def fetch(cursor: str | None) -> Page[ClobTrade]: path, params = _account_actions.build_list_account_trades_request( token_id=token_id, @@ -1223,6 +1416,7 @@ def fetch(cursor: str | None) -> Page[ClobTrade]: return Paginator(fetch=fetch) def get_notifications(self) -> tuple[Notification, ...]: + """Get notifications for the authenticated account.""" path, params = _account_actions.build_notifications_request( signature_type=signature_type_for(self._ctx.wallet_type) ) @@ -1231,6 +1425,7 @@ def get_notifications(self) -> tuple[Notification, ...]: ) def drop_notifications(self, *, ids: Sequence[int | str]) -> None: + """Delete notifications for the authenticated account.""" path, params = _account_actions.build_drop_notifications_request( ids=ids, signature_type=signature_type_for(self._ctx.wallet_type) ) @@ -1239,6 +1434,7 @@ def drop_notifications(self, *, ids: Sequence[int | str]) -> None: def get_balance_allowance( self, *, asset_type: AssetType, token_id: str | None = None ) -> BalanceAllowance: + """Get balance and allowance information for an asset.""" path, params = _account_actions.build_balance_allowance_request( asset_type=asset_type, token_id=token_id, @@ -1259,6 +1455,15 @@ def create_limit_order( expiration: int | None = None, builder_code: str | None = None, ) -> SignedOrder: + """Create and sign a limit order without posting it. + + Use :meth:`post_order` to submit the returned signed order, or + :meth:`place_limit_order` to create and post in one call. + + Raises: + UserInputError: If order parameters are invalid. + SigningError: If the order cannot be signed. + """ return self._prepare_and_sign_limit_order( token_id=token_id, price=price, @@ -1301,6 +1506,17 @@ def create_market_order( order_type: MarketOrderType = "FAK", builder_code: str | None = None, ) -> SignedOrder: + """Create and sign a market order without posting it. + + BUY orders use ``amount`` as the spend amount and may include + ``max_spend``. SELL orders use ``shares`` as the number of shares to + sell. + + Raises: + UserInputError: If side-specific order parameters are invalid. + InsufficientLiquidityError: If available liquidity cannot fill the order. + SigningError: If the order cannot be signed. + """ return self._prepare_and_sign_market_order( token_id=token_id, side=side, @@ -1322,6 +1538,14 @@ def place_limit_order( expiration: int | None = None, builder_code: str | None = None, ) -> OrderResponse: + """Create, sign, and post a limit order. + + Raises: + UserInputError: If order parameters are invalid. + InsufficientAllowanceError: If required allowance cannot be recovered. + SigningError: If the order cannot be signed. + RequestRejectedError: If posting the order is rejected. + """ signed = self._prepare_and_sign_limit_order( token_id=token_id, price=price, @@ -1365,6 +1589,19 @@ def place_market_order( order_type: MarketOrderType = "FAK", builder_code: str | None = None, ) -> OrderResponse: + """Create, sign, and post a market order. + + BUY orders use ``amount`` as the spend amount and may include + ``max_spend``. SELL orders use ``shares`` as the number of shares to + sell. + + Raises: + UserInputError: If side-specific order parameters are invalid. + InsufficientLiquidityError: If available liquidity cannot fill the order. + InsufficientAllowanceError: If required allowance cannot be recovered. + SigningError: If the order cannot be signed. + RequestRejectedError: If posting the order is rejected. + """ signed = self._prepare_and_sign_market_order( token_id=token_id, side=side, @@ -1377,11 +1614,13 @@ def place_market_order( return post_order_with_allowance_recovery_sync(self, signed) def get_builder_fee_rates(self, builder_code: str) -> BuilderFeeRates: + """Get fee rates for a builder code.""" from polymarket._internal.actions.orders.market_data import fetch_builder_fee_rates_sync return fetch_builder_fee_rates_sync(self._ctx, builder_code=builder_code) def post_order(self, signed_order: SignedOrder) -> OrderResponse: + """Post a signed order for the authenticated account.""" path, payload = _post_actions.build_post_order_request( signed_order, owner_api_key=self._ctx.credentials.key ) @@ -1390,6 +1629,7 @@ def post_order(self, signed_order: SignedOrder) -> OrderResponse: ) def post_orders(self, signed_orders: Sequence[SignedOrder]) -> tuple[OrderResponse, ...]: + """Post multiple signed orders for the authenticated account.""" path, payload = _post_actions.build_post_orders_request( signed_orders, owner_api_key=self._ctx.credentials.key ) @@ -1398,18 +1638,21 @@ def post_orders(self, signed_orders: Sequence[SignedOrder]) -> tuple[OrderRespon ) def cancel_order(self, *, order_id: str) -> CancelOrdersResponse: + """Cancel one open order for the authenticated account.""" path, body = _cancel_actions.build_cancel_order_request(order_id=order_id) return _cancel_actions.parse_cancel_orders_response( self._ctx.secure_clob.delete_json(path, json=body) ) def cancel_orders(self, *, order_ids: Sequence[str]) -> CancelOrdersResponse: + """Cancel multiple open orders for the authenticated account.""" path, body = _cancel_actions.build_cancel_orders_request(order_ids=order_ids) return _cancel_actions.parse_cancel_orders_response( self._ctx.secure_clob.delete_json(path, json=body) ) def cancel_all(self) -> CancelOrdersResponse: + """Cancel all open orders for the authenticated account.""" path, body = _cancel_actions.build_cancel_all_request() return _cancel_actions.parse_cancel_orders_response( self._ctx.secure_clob.delete_json(path, json=body) @@ -1418,6 +1661,7 @@ def cancel_all(self) -> CancelOrdersResponse: def cancel_market_orders( self, *, market: str | None = None, token_id: str | None = None ) -> CancelOrdersResponse: + """Cancel open orders matching a market or token filter.""" path, body = _cancel_actions.build_cancel_market_orders_request( market=market, token_id=token_id ) @@ -1486,18 +1730,26 @@ def _sign_order(self, draft: OrderDraft, *, post_only: bool) -> SignedOrder: return create_signed_order(unsigned, final_signature, post_only=post_only) def get_order_scoring(self, *, order_id: str) -> bool: + """Return whether an order is currently scoring rewards.""" path, params = _rewards_actions.build_get_order_scoring_request(order_id=order_id) return _rewards_actions.parse_order_scoring( self._ctx.secure_clob.get_json(path, params=params) ) def get_orders_scoring(self, *, order_ids: Sequence[str]) -> dict[str, bool]: + """Return reward-scoring status for multiple orders.""" path, body = _rewards_actions.build_get_orders_scoring_request(order_ids=order_ids) return _rewards_actions.parse_orders_scoring( self._ctx.secure_clob.post_json(path, json=body) ) def list_user_earnings_for_day(self, *, date: str) -> Paginator[UserEarning]: + """List reward earnings for the authenticated user on a date. + + Returns: + A paginator over matching earning entries. + """ + def fetch(cursor: str | None) -> Page[UserEarning]: path, params = _rewards_actions.build_list_user_earnings_for_day_request( date=date, @@ -1511,6 +1763,7 @@ def fetch(cursor: str | None) -> Page[UserEarning]: return Paginator(fetch=fetch) def get_total_earnings_for_user_for_day(self, *, date: str) -> tuple[TotalUserEarning, ...]: + """Get total reward earnings for the authenticated user on a date.""" path, params = _rewards_actions.build_total_user_earnings_for_day_request( date=date, signature_type=signature_type_for(self._ctx.wallet_type) ) @@ -1527,6 +1780,12 @@ def list_user_earnings_and_markets_config( position: str | None = None, page_size: int | None = None, ) -> Paginator[UserRewardsEarning]: + """List reward earnings with market configuration for the authenticated user. + + Returns: + A paginator over matching reward earning entries. + """ + def fetch(cursor: str | None) -> Page[UserRewardsEarning]: path, params = _rewards_actions.build_list_user_earnings_and_markets_config_request( date=date, @@ -1544,6 +1803,7 @@ def fetch(cursor: str | None) -> Page[UserRewardsEarning]: return Paginator(fetch=fetch) def get_reward_percentages(self) -> RewardsPercentages: + """Get current reward percentage allocations for the authenticated account.""" path, params = _rewards_actions.build_get_reward_percentages_request( signature_type=signature_type_for(self._ctx.wallet_type) ) @@ -1559,6 +1819,14 @@ def approve_erc20( amount: int | Literal["max"], metadata: str | None = None, ) -> SyncTransactionHandle: + """Submit an ERC-20 approval transaction. + + Args: + amount: Base-units amount to approve, or ``"max"`` for the maximum value. + + Returns: + A transaction handle. Call ``wait()`` to wait for a terminal outcome. + """ try: token = cast(EvmAddress, to_checksum_address(token_address)) except ValueError as error: @@ -1582,6 +1850,11 @@ def approve_erc1155_for_all( approved: bool = True, metadata: str | None = None, ) -> SyncTransactionHandle: + """Approve or revoke an ERC-1155 operator for all tokens. + + Returns: + A transaction handle. Call ``wait()`` to wait for a terminal outcome. + """ try: token = cast(EvmAddress, to_checksum_address(token_address)) except ValueError as error: @@ -1605,6 +1878,14 @@ def transfer_erc20( amount: int, metadata: str | None = None, ) -> SyncTransactionHandle: + """Submit an ERC-20 transfer transaction. + + Args: + amount: Base-units amount to transfer. + + Returns: + A transaction handle. Call ``wait()`` to wait for a terminal outcome. + """ try: token = cast(EvmAddress, to_checksum_address(token_address)) except ValueError as error: @@ -1620,6 +1901,15 @@ def transfer_erc20( return self._dispatch_single_call(call, metadata=resolved_metadata) def setup_trading_approvals(self) -> SyncTransactionHandle: + """Approve the standard set of trading allowances for the wallet. + + EOA wallets submit approvals directly. Gasless wallets submit a relayed + transaction. The returned handle represents the final transaction in the + setup workflow. + + Returns: + A transaction handle. Call ``wait()`` to wait for a terminal outcome. + """ env = self._ctx.environment collateral = cast(EvmAddress, env.collateral_token) conditional = cast(EvmAddress, env.conditional_tokens) @@ -1690,6 +1980,15 @@ def setup_trading_approvals(self) -> SyncTransactionHandle: ) def setup_gasless_wallet(self) -> Self: + """Create or reuse the gasless wallet for the signer. + + Returns: + A new secure client scoped to the gasless wallet. + + Raises: + UserInputError: If the client was not created with an API key that + can authorize gasless wallet workflows. + """ ctx = self._ctx if ctx.api_key is None: raise UserInputError( @@ -1729,6 +2028,7 @@ def setup_gasless_wallet(self) -> Self: ) def is_gasless_ready(self) -> bool: + """Return whether the signer has a deployed gasless wallet ready to use.""" ctx = self._ctx if ctx.wallet_type != "EOA": type_param = ( @@ -1749,6 +2049,14 @@ def split_position( amount: int, metadata: str | None = None, ) -> SyncTransactionHandle: + """Split collateral into outcome positions for a condition. + + Args: + amount: Base-units collateral amount to split. + + Returns: + A transaction handle. Call ``wait()`` to wait for a terminal outcome. + """ env = self._ctx.environment neg_risk = self._resolve_market_neg_risk(condition_id) call = split_position_call( @@ -1771,6 +2079,15 @@ def merge_positions( amount: int | Literal["max"], metadata: str | None = None, ) -> SyncTransactionHandle: + """Merge outcome positions back into collateral. + + Args: + amount: Base-units position amount to merge, or ``"max"`` to merge + the largest available balanced amount. + + Returns: + A transaction handle. Call ``wait()`` to wait for a terminal outcome. + """ env = self._ctx.environment binary = self._fetch_binary_positions(condition_id) neg_risk = expect_negative_risk_flag(binary) @@ -1795,6 +2112,16 @@ def redeem_positions( market_id: str | None = None, metadata: str | None = None, ) -> SyncTransactionHandle: + """Redeem resolved positions for a condition or market. + + Provide exactly one of ``condition_id`` or ``market_id``. + + Returns: + A transaction handle. Call ``wait()`` to wait for a terminal outcome. + + Raises: + UserInputError: If both identifiers or neither identifier is provided. + """ if (condition_id is None) == (market_id is None): raise UserInputError("Provide exactly one of condition_id or market_id") env = self._ctx.environment diff --git a/src/polymarket/models/clob/account.py b/src/polymarket/models/clob/account.py index d6f2ac6..deb96ef 100644 --- a/src/polymarket/models/clob/account.py +++ b/src/polymarket/models/clob/account.py @@ -52,6 +52,8 @@ def _parse_optional_epoch(value: object) -> datetime | None: class OpenOrder(BaseModel): + """Open order owned by an account.""" + id: str market: str token_id: TokenId = Field(validation_alias="asset_id") @@ -80,6 +82,8 @@ def _parse_expires_at(cls, value: object) -> datetime | None: class MakerOrder(BaseModel): + """Maker-side fill information attached to a trade.""" + order_id: str = Field(validation_alias="order_id") token_id: TokenId = Field(validation_alias="asset_id") maker_address: str = Field(validation_alias="maker_address") @@ -97,6 +101,8 @@ def _empty_to_none(cls, value: object) -> object: class ClobTrade(BaseModel): + """Executed trade for an account or market.""" + id: str market: str token_id: TokenId = Field(validation_alias="asset_id") @@ -123,6 +129,8 @@ def _parse_epoch_field(cls, value: object) -> datetime: class Notification(BaseModel): + """Account notification.""" + id: int owner: str type: int @@ -151,6 +159,8 @@ def _parse_timestamp(cls, value: object) -> datetime: class BalanceAllowance(BaseModel): + """Balance and allowance values for an asset in base units.""" + balance: int allowances: dict[str, int] diff --git a/src/polymarket/models/data/portfolio.py b/src/polymarket/models/data/portfolio.py index 2acaf0b..16437f6 100644 --- a/src/polymarket/models/data/portfolio.py +++ b/src/polymarket/models/data/portfolio.py @@ -16,6 +16,8 @@ class PortfolioValue(BaseModel): + """Current portfolio value for a user.""" + user: EvmAddress | None = None value: Decimal | None = None @@ -26,11 +28,15 @@ def _parse_value(cls, value: object) -> Decimal | None: class TradedMarketCount(BaseModel): + """Number of markets traded by a user.""" + user: EvmAddress | None = None traded: int | None = None class Position(BaseModel): + """Open market position held by a wallet.""" + condition_id: ConditionId = Field(validation_alias="conditionId") wallet: EvmAddress | None = Field(default=None, validation_alias="proxyWallet") token_id: TokenId | None = Field(default=None, validation_alias="asset") @@ -80,6 +86,8 @@ def _parse_end_date(cls, value: object) -> date | None: class ClosedPosition(BaseModel): + """Closed market position for a wallet.""" + wallet: EvmAddress | None = Field(default=None, validation_alias="proxyWallet") token_id: TokenId | None = Field(default=None, validation_alias="asset") condition_id: ConditionId | None = Field(default=None, validation_alias="conditionId") diff --git a/src/polymarket/models/gamma/market.py b/src/polymarket/models/gamma/market.py index 3112acc..fc1fe34 100644 --- a/src/polymarket/models/gamma/market.py +++ b/src/polymarket/models/gamma/market.py @@ -34,6 +34,8 @@ class UmaResolutionStatus(StrEnum): + """Resolution lifecycle state for a market.""" + DISPUTED = "disputed" PROPOSED = "proposed" REQUESTED = "requested" @@ -42,6 +44,8 @@ class UmaResolutionStatus(StrEnum): class MarketState(BaseModel): + """Operational state and timing for a market.""" + active: bool | None = None closed: bool | None = None archived: bool | None = None @@ -77,6 +81,8 @@ def _parse_datetime(cls, value: object) -> datetime | None: class MarketOutcome(BaseModel): + """One tradable outcome in a binary market.""" + label: str token_id: TokenId | None = Field( default=None, @@ -91,11 +97,15 @@ def _parse_price(cls, value: object) -> Decimal | None: class MarketOutcomes(BaseModel): + """Binary market outcomes.""" + yes: MarketOutcome no: MarketOutcome class MarketMetrics(BaseModel): + """Volume and liquidity metrics for a market.""" + volume: Decimal | None = None volume_num: Decimal | None = Field( default=None, @@ -142,6 +152,8 @@ def _parse_metric(cls, value: object) -> Decimal | None: class MarketPrices(BaseModel): + """Current price and price-change data for a market.""" + best_bid: Decimal | None = Field( default=None, validation_alias="bestBid", @@ -183,6 +195,8 @@ def _parse_price(cls, value: object) -> Decimal | None: class FeeSchedule(BaseModel): + """Fee schedule applied to market trading.""" + exponent: int | float rate: Decimal taker_only: bool = Field(validation_alias="takerOnly") @@ -195,6 +209,8 @@ def _parse_decimal(cls, value: object) -> Decimal: class MarketTrading(BaseModel): + """Trading configuration and constraints for a market.""" + minimum_order_size: Decimal | None = Field( default=None, validation_alias="minimumOrderSize", @@ -227,6 +243,8 @@ def _parse_optional_decimal(cls, value: object) -> Decimal | None: class MarketResolution(BaseModel): + """Resolution metadata for a market.""" + question_id: QuestionId | None = Field( default=None, validation_alias="questionId", @@ -257,6 +275,8 @@ def _parse_uma_status(cls, value: object) -> object | None: class ClobReward(BaseModel): + """Reward configuration attached to a market condition.""" + id: ClobRewardId condition_id: ConditionId = Field(validation_alias="conditionId") asset_address: str = Field(validation_alias="assetAddress") @@ -275,6 +295,8 @@ def _parse_decimal(cls, value: object) -> Decimal: class MarketRewards(BaseModel): + """Reward settings for a market.""" + clob_rewards: tuple[ClobReward, ...] | None = Field( default=None, validation_alias="clobRewards", @@ -299,6 +321,8 @@ def _parse_optional_decimal(cls, value: object) -> Decimal | None: class MarketSportsMetadata(BaseModel): + """Sports-specific metadata for a market.""" + sports_market_type: str | None = Field( default=None, validation_alias="sportsMarketType", @@ -320,6 +344,8 @@ def _parse_datetime(cls, value: object) -> datetime | None: class MarketEvent(BaseModel): + """Event reference attached to a market.""" + id: EventId slug: str | None = None title: str | None = None @@ -331,6 +357,8 @@ def _coerce_id(cls, value: object) -> object: class MarketTag(BaseModel): + """Tag reference attached to a market.""" + id: TagId slug: str | None = None label: str | None = None diff --git a/src/polymarket/pagination.py b/src/polymarket/pagination.py index 59b1a51..b3002ac 100644 --- a/src/polymarket/pagination.py +++ b/src/polymarket/pagination.py @@ -11,13 +11,25 @@ @dataclass(frozen=True, slots=True) class Page(Generic[T]): + """One page of paginated SDK results.""" + items: tuple[T, ...] + """Items returned on this page.""" has_more: bool + """Whether another page is available.""" next_cursor: str | None = None + """Cursor to pass to ``from_cursor()`` for the next page, when available.""" total_count: int | None = None + """Total matching item count when the API provides it.""" class Paginator(Generic[T]): + """Synchronous paginator returned by list-style client methods. + + Iterate over the paginator to fetch pages lazily, or call ``items()`` to + iterate over individual items across pages. + """ + def __init__( self, fetch: Callable[[str | None], Page[T]], @@ -27,9 +39,14 @@ def __init__( self._initial_cursor = initial_cursor def first_page(self) -> Page[T]: + """Fetch the first page for this paginator.""" return self._fetch(self._initial_cursor) def from_cursor(self, cursor: str | None) -> Paginator[T]: + """Create a paginator that starts from ``cursor``. + + Passing ``None`` returns an empty paginator because no next page exists. + """ if cursor is None: return cast(Paginator[T], _EmptyPaginator()) return Paginator(self._fetch, initial_cursor=cursor) @@ -38,6 +55,7 @@ def __iter__(self) -> Iterator[Page[T]]: return self._iter_pages() def items(self) -> Iterator[T]: + """Iterate over individual items across all fetched pages.""" for page in self._iter_pages(): yield from page.items @@ -56,6 +74,12 @@ def _iter_pages(self) -> Iterator[Page[T]]: class AsyncPaginator(Generic[T]): + """Async paginator returned by async list-style client methods. + + Use ``async for`` over the paginator to fetch pages lazily, or call + ``items()`` to iterate over individual items across pages. + """ + def __init__( self, fetch: Callable[[str | None], Awaitable[Page[T]]], @@ -65,9 +89,14 @@ def __init__( self._initial_cursor = initial_cursor async def first_page(self) -> Page[T]: + """Fetch the first page for this paginator.""" return await self._fetch(self._initial_cursor) def from_cursor(self, cursor: str | None) -> AsyncPaginator[T]: + """Create an async paginator that starts from ``cursor``. + + Passing ``None`` returns an empty paginator because no next page exists. + """ if cursor is None: return cast(AsyncPaginator[T], _EmptyAsyncPaginator()) return AsyncPaginator(self._fetch, initial_cursor=cursor) @@ -76,6 +105,7 @@ def __aiter__(self) -> AsyncIterator[Page[T]]: return self._iter_pages() def items(self) -> AsyncIterator[T]: + """Iterate over individual items across all fetched pages.""" return self._iter_items() async def _iter_pages(self) -> AsyncIterator[Page[T]]: diff --git a/src/polymarket/streams/_specs.py b/src/polymarket/streams/_specs.py index faeb9ed..b1a8392 100644 --- a/src/polymarket/streams/_specs.py +++ b/src/polymarket/streams/_specs.py @@ -25,7 +25,7 @@ @dataclass(frozen=True, slots=True, kw_only=True) class MarketSpec: - """Subscription for the CLOB market stream.""" + """Subscribe to realtime market updates for one or more token ids.""" token_ids: Sequence[str] custom_feature_enabled: bool = False @@ -61,6 +61,12 @@ class SportsSpec: @dataclass(frozen=True, slots=True, kw_only=True) class CommentsSpec: + """Subscribe to realtime comment and reaction events. + + Filters are optional. When provided, ``types`` limits event kinds and the + parent entity fields limit events to a specific market or event. + """ + types: Sequence[CommentsEventType] | None = None parent_entity_id: int | None = None parent_entity_type: ParentEntityType | None = None @@ -93,6 +99,12 @@ def __post_init__(self) -> None: @dataclass(frozen=True, slots=True, kw_only=True) class CryptoPricesSpec: + """Subscribe to realtime crypto price updates for a topic. + + When ``symbols`` is omitted, the subscription receives all symbols for the + selected topic. + """ + topic: CryptoPricesTopic symbols: Sequence[str] | None = None @@ -118,6 +130,8 @@ def __post_init__(self) -> None: @dataclass(frozen=True, slots=True, kw_only=True) class EquityPricesSpec: + """Subscribe to realtime equity price updates for one symbol.""" + symbol: str types: Sequence[EquityPricesEventType] | None = None topic: Literal["prices.equity.pyth"] = field(default="prices.equity.pyth", init=False) @@ -140,6 +154,12 @@ def __post_init__(self) -> None: @dataclass(frozen=True, slots=True, kw_only=True) class UserSpec: + """Subscribe to authenticated user order and trade events. + + When ``markets`` is omitted, the subscription receives user events for all + markets available to the authenticated account. + """ + markets: Sequence[str] | None = None topic: Literal["user"] = field(default="user", init=False) diff --git a/src/polymarket/transactions.py b/src/polymarket/transactions.py index aeee513..2efae1d 100644 --- a/src/polymarket/transactions.py +++ b/src/polymarket/transactions.py @@ -12,6 +12,8 @@ @dataclass(frozen=True, slots=True) class GaslessTransactionHandle: + """Async handle for a relayed gasless transaction.""" + transaction_id: str transaction_hash: str | None _relayer: AsyncTransport = field(repr=False) @@ -19,6 +21,7 @@ class GaslessTransactionHandle: _poll_delay_s: float async def wait(self) -> TransactionOutcome: + """Wait until the transaction reaches a terminal outcome.""" from polymarket._internal.actions.relayer.poll import poll_until_terminal return await poll_until_terminal( @@ -32,6 +35,8 @@ async def wait(self) -> TransactionOutcome: @dataclass(frozen=True, slots=True) class EoaTransactionHandle: + """Async handle for a directly broadcast EOA transaction.""" + transaction_hash: str _rpc: JsonRpcClient = field(repr=False) _max_polls: int @@ -39,9 +44,11 @@ class EoaTransactionHandle: @property def transaction_id(self) -> None: + """Return None because EOA transactions do not have relayer ids.""" return None async def wait(self) -> TransactionOutcome: + """Wait until the transaction reaches a terminal outcome.""" from polymarket._internal.eoa.broadcast import wait_for_receipt return await wait_for_receipt( @@ -54,6 +61,8 @@ async def wait(self) -> TransactionOutcome: @dataclass(frozen=True, slots=True) class SyncGaslessTransactionHandle: + """Synchronous handle for a relayed gasless transaction.""" + transaction_id: str transaction_hash: str | None _relayer: SyncTransport = field(repr=False) @@ -61,6 +70,7 @@ class SyncGaslessTransactionHandle: _poll_delay_s: float def wait(self) -> TransactionOutcome: + """Wait until the transaction reaches a terminal outcome.""" from polymarket._internal.actions.relayer.poll import poll_until_terminal_sync return poll_until_terminal_sync( @@ -74,6 +84,8 @@ def wait(self) -> TransactionOutcome: @dataclass(frozen=True, slots=True) class SyncEoaTransactionHandle: + """Synchronous handle for a directly broadcast EOA transaction.""" + transaction_hash: str _rpc: SyncJsonRpcClient = field(repr=False) _max_polls: int @@ -81,9 +93,11 @@ class SyncEoaTransactionHandle: @property def transaction_id(self) -> None: + """Return None because EOA transactions do not have relayer ids.""" return None def wait(self) -> TransactionOutcome: + """Wait until the transaction reaches a terminal outcome.""" from polymarket._internal.eoa.broadcast import wait_for_receipt_sync return wait_for_receipt_sync( @@ -95,7 +109,10 @@ def wait(self) -> TransactionOutcome: TransactionHandle: TypeAlias = GaslessTransactionHandle | EoaTransactionHandle +"""Async transaction handle returned by async wallet methods.""" + SyncTransactionHandle: TypeAlias = SyncGaslessTransactionHandle | SyncEoaTransactionHandle +"""Synchronous transaction handle returned by sync wallet methods.""" __all__ = [ diff --git a/tests/integration/test_clob_reads.py b/tests/integration/test_clob_reads.py index 4e5a24b..f4615d0 100644 --- a/tests/integration/test_clob_reads.py +++ b/tests/integration/test_clob_reads.py @@ -1,3 +1,4 @@ +# pyright: reportPrivateUsage=false import asyncio from decimal import Decimal @@ -40,7 +41,7 @@ def test_async_secure_get_midpoint_returns_decimal_in_unit_range( active_clob_token: TokenId, ) -> None: async def run() -> Decimal: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/_relayer_helpers.py b/tests/unit/_relayer_helpers.py index fc86bdb..82afb9e 100644 --- a/tests/unit/_relayer_helpers.py +++ b/tests/unit/_relayer_helpers.py @@ -31,7 +31,7 @@ async def make_deposit_client() -> AsyncSecureClient: signer = Account.from_key(PK_DEPLOY_WALLET) wallet = derive_uups_deposit_wallet_address(signer.address, PRODUCTION.wallet_derivation) - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PK_DEPLOY_WALLET, wallet=wallet, credentials=FAKE_CREDS, @@ -48,7 +48,7 @@ async def make_proxy_client() -> AsyncSecureClient: signer = Account.from_key(PK_PROXY_WALLET) wallet = derive_proxy_wallet_address(signer.address, PRODUCTION.wallet_derivation) - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PK_PROXY_WALLET, wallet=wallet, credentials=FAKE_CREDS, @@ -61,7 +61,7 @@ async def make_eoa_client(*, with_api_key: bool = True) -> AsyncSecureClient: from eth_account import Account signer = Account.from_key(PK_DEPLOY_WALLET) - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PK_DEPLOY_WALLET, wallet=signer.address, credentials=FAKE_CREDS, @@ -80,7 +80,7 @@ async def make_eoa_client_with_rpc( env = dataclasses.replace(PRODUCTION, rpc_url="https://rpc.test") signer = Account.from_key(PK_DEPLOY_WALLET) - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PK_DEPLOY_WALLET, wallet=signer.address, credentials=FAKE_CREDS, @@ -153,7 +153,7 @@ async def make_safe_client() -> AsyncSecureClient: signer = Account.from_key(PK_SAFE_WALLET) wallet = derive_safe_wallet_address(signer.address, PRODUCTION.wallet_derivation) - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PK_SAFE_WALLET, wallet=wallet, credentials=FAKE_CREDS, @@ -226,7 +226,7 @@ def make_sync_eoa_client(*, with_api_key: bool = True) -> SecureClient: from eth_account import Account signer = Account.from_key(PK_DEPLOY_WALLET) - return SecureClient.create( + return SecureClient._create( private_key=PK_DEPLOY_WALLET, wallet=signer.address, credentials=FAKE_CREDS, @@ -243,7 +243,7 @@ def make_sync_deposit_client() -> SecureClient: signer = Account.from_key(PK_DEPLOY_WALLET) wallet = derive_uups_deposit_wallet_address(signer.address, PRODUCTION.wallet_derivation) - return SecureClient.create( + return SecureClient._create( private_key=PK_DEPLOY_WALLET, wallet=wallet, credentials=FAKE_CREDS, @@ -260,7 +260,7 @@ def make_sync_proxy_client() -> SecureClient: signer = Account.from_key(PK_PROXY_WALLET) wallet = derive_proxy_wallet_address(signer.address, PRODUCTION.wallet_derivation) - return SecureClient.create( + return SecureClient._create( private_key=PK_PROXY_WALLET, wallet=wallet, credentials=FAKE_CREDS, @@ -277,7 +277,7 @@ def make_sync_safe_client() -> SecureClient: signer = Account.from_key(PK_SAFE_WALLET) wallet = derive_safe_wallet_address(signer.address, PRODUCTION.wallet_derivation) - return SecureClient.create( + return SecureClient._create( private_key=PK_SAFE_WALLET, wallet=wallet, credentials=FAKE_CREDS, diff --git a/tests/unit/test_account_transport.py b/tests/unit/test_account_transport.py index 7b176b8..9442122 100644 --- a/tests/unit/test_account_transport.py +++ b/tests/unit/test_account_transport.py @@ -96,7 +96,7 @@ def _assert_l2_headers(request: httpx.Request) -> None: def _make_client() -> AsyncSecureClient: return asyncio.run( - AsyncSecureClient.create( + AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -109,7 +109,7 @@ def test_get_closed_only_mode_returns_bool_and_uses_l2_headers() -> None: captured: list[httpx.Request] = [] async def run() -> bool: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -147,7 +147,7 @@ def handler(request: httpx.Request) -> httpx.Response: return httpx.Response(200, json=next(responses), request=request) async def run() -> list[str]: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -177,7 +177,7 @@ def test_get_order_targets_data_order_path() -> None: captured: list[httpx.Request] = [] async def run() -> str: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -209,7 +209,7 @@ def handler(request: httpx.Request) -> httpx.Response: return httpx.Response(200, json=next(responses), request=request) async def run() -> list[str]: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -239,7 +239,7 @@ def test_get_notifications_includes_signature_type_for_eoa_wallet() -> None: captured: list[httpx.Request] = [] async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -263,7 +263,7 @@ def test_drop_notifications_uses_delete_with_comma_separated_ids() -> None: captured: list[httpx.Request] = [] async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -286,7 +286,7 @@ async def run() -> None: def test_drop_notifications_rejects_empty_id_list() -> None: async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -305,7 +305,7 @@ def test_get_balance_allowance_for_collateral_omits_token_id() -> None: captured: list[httpx.Request] = [] async def run() -> int: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -334,7 +334,7 @@ def test_get_balance_allowance_for_conditional_includes_token_id() -> None: captured: list[httpx.Request] = [] async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -366,7 +366,7 @@ def test_secure_client_classifies_eoa_when_wallet_equals_signer() -> None: def test_secure_client_normalizes_wallet_to_checksum() -> None: async def run() -> str: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS.lower(), credentials=FAKE_CREDS, @@ -382,7 +382,7 @@ async def run() -> str: def test_secure_client_rejects_invalid_wallet_address() -> None: async def run() -> None: - await AsyncSecureClient.create( + await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet="not-an-address", credentials=FAKE_CREDS, @@ -400,7 +400,7 @@ def test_secure_client_defaults_wallet_to_signer_address() -> None: expected = to_checksum_address(Account.from_key(PRIVATE_KEY).address) async def run() -> str: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, credentials=FAKE_CREDS, validate_credentials=False, @@ -416,7 +416,7 @@ async def run() -> str: def test_secure_client_rejects_unrelated_wallet_address() -> None: async def run() -> None: - await AsyncSecureClient.create( + await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet="0x0000000000000000000000000000000000000002", credentials=FAKE_CREDS, diff --git a/tests/unit/test_auth_transport.py b/tests/unit/test_auth_transport.py index b357685..8af7c1b 100644 --- a/tests/unit/test_auth_transport.py +++ b/tests/unit/test_auth_transport.py @@ -126,7 +126,7 @@ async def run() -> ApiKeyCreds: def test_async_secure_create_with_credentials_skips_auth_flow() -> None: async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -144,7 +144,7 @@ def test_fetch_api_keys_sends_l2_headers() -> None: captured: list[httpx.Request] = [] async def run() -> tuple[str, ...]: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -173,7 +173,7 @@ def test_delete_api_key_succeeds_on_ok_response() -> None: captured: list[httpx.Request] = [] async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -193,7 +193,7 @@ async def run() -> None: def test_delete_api_key_raises_unexpected_response_on_non_ok_payload() -> None: async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -211,7 +211,7 @@ async def run() -> None: def test_fetch_api_keys_propagates_401_as_request_rejected() -> None: async def run() -> tuple[str, ...]: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -232,7 +232,7 @@ def test_async_secure_create_rejects_credentials_with_nonzero_nonce() -> None: from polymarket.errors import UserInputError async def run() -> None: - await AsyncSecureClient.create( + await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, nonce=1 ) @@ -244,7 +244,11 @@ def test_async_secure_create_rejects_negative_nonce() -> None: from polymarket.errors import UserInputError async def run() -> None: - await AsyncSecureClient.create(private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, nonce=-1) + await AsyncSecureClient._create( + private_key=PRIVATE_KEY, + wallet=SIGNER_ADDRESS, + nonce=-1, + ) with pytest.raises(UserInputError, match="non-negative integer"): asyncio.run(run()) @@ -254,7 +258,11 @@ def test_async_secure_create_rejects_bool_nonce() -> None: from polymarket.errors import UserInputError async def run() -> None: - await AsyncSecureClient.create(private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, nonce=True) # type: ignore[arg-type] + await AsyncSecureClient._create( + private_key=PRIVATE_KEY, + wallet=SIGNER_ADDRESS, + nonce=True, # type: ignore[arg-type] + ) with pytest.raises(UserInputError, match="non-negative integer"): asyncio.run(run()) @@ -298,7 +306,7 @@ def test_l2_signature_includes_canonical_body_for_authenticated_post() -> None: captured: list[httpx.Request] = [] async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_builder_attribution.py b/tests/unit/test_builder_attribution.py index ef54e3f..f48f9e2 100644 --- a/tests/unit/test_builder_attribution.py +++ b/tests/unit/test_builder_attribution.py @@ -190,7 +190,7 @@ def _install_secure_clob(client: AsyncSecureClient, handler: httpx.MockTransport async def _make_client() -> AsyncSecureClient: - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=_PRIVATE_KEY, wallet=_SIGNER_ADDRESS, credentials=_FAKE_CREDS, diff --git a/tests/unit/test_builder_trades.py b/tests/unit/test_builder_trades.py index 36e7fb6..52b1bc1 100644 --- a/tests/unit/test_builder_trades.py +++ b/tests/unit/test_builder_trades.py @@ -342,7 +342,7 @@ def handler(request: httpx.Request) -> httpx.Response: ) async def run() -> BuilderTrade: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=_PRIVATE_KEY, wallet=_SIGNER, credentials=_FAKE_CREDS, diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 8d537af..5d34152 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -1,4 +1,6 @@ +# pyright: reportPrivateUsage=false import asyncio +import inspect from typing import cast import pytest @@ -45,7 +47,7 @@ async def run() -> None: def test_secure_client_factory_uses_production_by_default() -> None: - client = SecureClient.create( + client = SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -57,6 +59,11 @@ def test_secure_client_factory_uses_production_by_default() -> None: client.close() +def test_secure_client_factory_signature_hides_test_validation_switch() -> None: + assert "validate_credentials" not in inspect.signature(SecureClient.create).parameters + assert "validate_credentials" not in inspect.signature(AsyncSecureClient.create).parameters + + def test_secure_client_requires_factory() -> None: from polymarket._internal.context import SyncSecureClientContext @@ -65,7 +72,7 @@ def test_secure_client_requires_factory() -> None: def test_secure_client_supports_context_manager() -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -76,7 +83,7 @@ def test_secure_client_supports_context_manager() -> None: def test_async_secure_client_factory_uses_production_by_default() -> None: async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -97,7 +104,7 @@ def test_async_secure_client_requires_factory() -> None: def test_async_secure_client_supports_context_manager() -> None: async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -110,7 +117,7 @@ async def run() -> None: def test_secure_client_exposes_signer_wallet() -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -121,7 +128,7 @@ def test_secure_client_exposes_signer_wallet() -> None: def test_async_secure_client_exposes_signer_wallet() -> None: async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -146,7 +153,7 @@ def test_secure_client_wallet_defaults_to_signer_when_omitted() -> None: expected = to_checksum_address(Account.from_key(PRIVATE_KEY).address) - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, credentials=FAKE_CREDS, validate_credentials=False, @@ -170,7 +177,7 @@ def test_async_secure_client_wallet_defaults_to_signer_when_omitted() -> None: expected = to_checksum_address(Account.from_key(PRIVATE_KEY).address) async def run() -> str: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, validate_credentials=False, ) diff --git a/tests/unit/test_client_request_params.py b/tests/unit/test_client_request_params.py index 3b2401c..0174460 100644 --- a/tests/unit/test_client_request_params.py +++ b/tests/unit/test_client_request_params.py @@ -116,7 +116,7 @@ async def run() -> None: def test_secure_list_trades_passes_event_id() -> None: captured: list[httpx.Request] = [] - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -134,7 +134,7 @@ def test_async_secure_list_trades_passes_event_id() -> None: captured: list[httpx.Request] = [] async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -178,7 +178,7 @@ async def run() -> None: def test_secure_list_activity_passes_event_id() -> None: captured: list[httpx.Request] = [] - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -196,7 +196,7 @@ def test_async_secure_list_activity_passes_event_id() -> None: captured: list[httpx.Request] = [] async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -228,7 +228,7 @@ def test_public_list_positions_passes_event_id() -> None: def test_secure_list_positions_passes_event_id() -> None: captured: list[httpx.Request] = [] - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -259,7 +259,7 @@ def test_secure_list_trades_rejects_market_and_event_id_together() -> None: from polymarket.errors import UserInputError with ( - SecureClient.create( + SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_clob_transport.py b/tests/unit/test_clob_transport.py index 64b9658..6c5f75e 100644 --- a/tests/unit/test_clob_transport.py +++ b/tests/unit/test_clob_transport.py @@ -73,7 +73,7 @@ def test_async_secure_get_midpoint_uses_same_clob_endpoint() -> None: captured: list[httpx.Request] = [] async def run() -> Decimal: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_clob_transport_sync.py b/tests/unit/test_clob_transport_sync.py index f44cd4e..7498df0 100644 --- a/tests/unit/test_clob_transport_sync.py +++ b/tests/unit/test_clob_transport_sync.py @@ -61,7 +61,7 @@ def _body(request: httpx.Request) -> object: def _secure_client() -> SecureClient: - return SecureClient.create( + return SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_end_authentication.py b/tests/unit/test_end_authentication.py index 22e62cf..072ab8d 100644 --- a/tests/unit/test_end_authentication.py +++ b/tests/unit/test_end_authentication.py @@ -35,7 +35,7 @@ def _install_secure_clob(client: AsyncSecureClient, handler: httpx.MockTransport async def _build_client() -> AsyncSecureClient: - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_market_order_overloads.py b/tests/unit/test_market_order_overloads.py index a5b937b..89e1b31 100644 --- a/tests/unit/test_market_order_overloads.py +++ b/tests/unit/test_market_order_overloads.py @@ -19,7 +19,7 @@ def _make_client() -> AsyncSecureClient: return asyncio.run( - AsyncSecureClient.create( + AsyncSecureClient._create( private_key=_PRIVATE_KEY, wallet=_SIGNER, credentials=_FAKE_CREDS, diff --git a/tests/unit/test_order_allowance.py b/tests/unit/test_order_allowance.py index 399516d..54aaa40 100644 --- a/tests/unit/test_order_allowance.py +++ b/tests/unit/test_order_allowance.py @@ -32,7 +32,7 @@ def handler(request: httpx.Request) -> httpx.Response: async def _make_client() -> AsyncSecureClient: - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_order_client.py b/tests/unit/test_order_client.py index fa07db6..d7a6d74 100644 --- a/tests/unit/test_order_client.py +++ b/tests/unit/test_order_client.py @@ -104,7 +104,7 @@ def _install_secure_clob(client: AsyncSecureClient, handler: httpx.MockTransport async def _make_client() -> AsyncSecureClient: - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_order_estimate.py b/tests/unit/test_order_estimate.py index 29a02a9..9b73b4a 100644 --- a/tests/unit/test_order_estimate.py +++ b/tests/unit/test_order_estimate.py @@ -49,7 +49,7 @@ def handler(request: httpx.Request) -> httpx.Response: async def _make_client() -> AsyncSecureClient: - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_order_limit.py b/tests/unit/test_order_limit.py index da4bf0f..570d119 100644 --- a/tests/unit/test_order_limit.py +++ b/tests/unit/test_order_limit.py @@ -43,7 +43,7 @@ def _install_public_clob(client: AsyncSecureClient, handler: httpx.MockTransport async def _make_client() -> AsyncSecureClient: - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_order_market.py b/tests/unit/test_order_market.py index 34ae025..c8c9b8c 100644 --- a/tests/unit/test_order_market.py +++ b/tests/unit/test_order_market.py @@ -57,7 +57,7 @@ def _install_public_clob(client: AsyncSecureClient, handler: httpx.MockTransport async def _make_client() -> AsyncSecureClient: - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_order_market_data.py b/tests/unit/test_order_market_data.py index 096c82a..ead755f 100644 --- a/tests/unit/test_order_market_data.py +++ b/tests/unit/test_order_market_data.py @@ -41,7 +41,7 @@ def _install_public_clob(client: AsyncSecureClient, handler: httpx.MockTransport async def _make_client() -> AsyncSecureClient: - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_place_order_recovery.py b/tests/unit/test_place_order_recovery.py index 170db60..db388d2 100644 --- a/tests/unit/test_place_order_recovery.py +++ b/tests/unit/test_place_order_recovery.py @@ -33,7 +33,7 @@ async def _make_deposit_client() -> AsyncSecureClient: signer = Account.from_key(_PRIVATE_KEY) wallet = derive_uups_deposit_wallet_address(signer.address, PRODUCTION.wallet_derivation) - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=_PRIVATE_KEY, wallet=wallet, credentials=_CREDS, diff --git a/tests/unit/test_relayer_approve_erc20.py b/tests/unit/test_relayer_approve_erc20.py index d89ee94..d9e2e6a 100644 --- a/tests/unit/test_relayer_approve_erc20.py +++ b/tests/unit/test_relayer_approve_erc20.py @@ -35,7 +35,7 @@ def test_approve_erc20_rejects_when_no_api_key() -> None: async def run() -> None: signer = Account.from_key(PK_DEPLOY_WALLET) wallet = derive_uups_deposit_wallet_address(signer.address, PRODUCTION.wallet_derivation) - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PK_DEPLOY_WALLET, wallet=wallet, credentials=FAKE_CREDS, @@ -425,7 +425,7 @@ def test_approve_erc20_works_with_relayer_api_key() -> None: async def run() -> None: signer = Account.from_key(PK_DEPLOY_WALLET) wallet = derive_uups_deposit_wallet_address(signer.address, PRODUCTION.wallet_derivation) - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PK_DEPLOY_WALLET, wallet=wallet, credentials=FAKE_CREDS, diff --git a/tests/unit/test_relayer_is_gasless_ready.py b/tests/unit/test_relayer_is_gasless_ready.py index 95d55d4..7a5af0f 100644 --- a/tests/unit/test_relayer_is_gasless_ready.py +++ b/tests/unit/test_relayer_is_gasless_ready.py @@ -27,7 +27,7 @@ async def _make_eoa_secure_client() -> AsyncSecureClient: from eth_account import Account signer = Account.from_key(PK_DEPLOY_WALLET) - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PK_DEPLOY_WALLET, wallet=signer.address, credentials=FAKE_CREDS, diff --git a/tests/unit/test_rewards_transport.py b/tests/unit/test_rewards_transport.py index a34331e..72afee3 100644 --- a/tests/unit/test_rewards_transport.py +++ b/tests/unit/test_rewards_transport.py @@ -65,7 +65,7 @@ def _install_secure_public_clob(client: AsyncSecureClient, handler: httpx.MockTr async def _make_secure_client() -> AsyncSecureClient: - return await AsyncSecureClient.create( + return await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_rewards_transport_sync.py b/tests/unit/test_rewards_transport_sync.py index 56b358b..1441faf 100644 --- a/tests/unit/test_rewards_transport_sync.py +++ b/tests/unit/test_rewards_transport_sync.py @@ -106,7 +106,7 @@ def test_public_passes_sponsored_filter(self) -> None: def test_secure_uses_unsigned_clob_not_secure_clob(self) -> None: captured: list[httpx.Request] = [] - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -143,7 +143,7 @@ def test_public_routes_with_condition_id_in_path(self) -> None: def test_secure_uses_unsigned_clob_not_secure_clob(self) -> None: captured: list[httpx.Request] = [] - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_secure_account_sync.py b/tests/unit/test_secure_account_sync.py index a42157a..7f7c717 100644 --- a/tests/unit/test_secure_account_sync.py +++ b/tests/unit/test_secure_account_sync.py @@ -94,7 +94,7 @@ def _assert_l2_headers(request: httpx.Request) -> None: def _make_client() -> SecureClient: - return SecureClient.create( + return SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_secure_api_keys_sync.py b/tests/unit/test_secure_api_keys_sync.py index 95fcaad..b3eb92a 100644 --- a/tests/unit/test_secure_api_keys_sync.py +++ b/tests/unit/test_secure_api_keys_sync.py @@ -34,7 +34,7 @@ def _install_secure_clob(client: SecureClient, handler: httpx.MockTransport) -> def _make_client() -> SecureClient: - return SecureClient.create( + return SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_secure_auth_sync.py b/tests/unit/test_secure_auth_sync.py index 8991ed8..40c25c9 100644 --- a/tests/unit/test_secure_auth_sync.py +++ b/tests/unit/test_secure_auth_sync.py @@ -26,7 +26,7 @@ def handler(request: httpx.Request) -> httpx.Response: def _make_client() -> SecureClient: - return SecureClient.create( + return SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -107,7 +107,7 @@ def handler(request: httpx.Request) -> httpx.Response: def test_create_with_credentials_skips_auth_flow_when_validation_disabled() -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -147,7 +147,7 @@ def handler(request: httpx.Request) -> httpx.Response: def test_create_rejects_credentials_with_nonzero_nonce() -> None: with pytest.raises(UserInputError, match="nonce cannot be combined"): - SecureClient.create( + SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -157,12 +157,12 @@ def test_create_rejects_credentials_with_nonzero_nonce() -> None: def test_create_rejects_negative_nonce() -> None: with pytest.raises(UserInputError, match="non-negative integer"): - SecureClient.create(private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, nonce=-1) + SecureClient._create(private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, nonce=-1) def test_create_rejects_bool_nonce() -> None: with pytest.raises(UserInputError, match="non-negative integer"): - SecureClient.create( + SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, nonce=cast(int, True), @@ -170,7 +170,7 @@ def test_create_rejects_bool_nonce() -> None: def test_create_defaults_wallet_to_signer_when_omitted() -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, credentials=FAKE_CREDS, validate_credentials=False, @@ -181,7 +181,7 @@ def test_create_defaults_wallet_to_signer_when_omitted() -> None: def test_create_rejects_invalid_wallet_address() -> None: with pytest.raises(UserInputError, match="Invalid wallet address"): - SecureClient.create( + SecureClient._create( private_key=PRIVATE_KEY, wallet="not-an-address", credentials=FAKE_CREDS, @@ -196,7 +196,7 @@ def test_create_classifies_eoa_when_wallet_equals_signer() -> None: def test_create_normalizes_wallet_to_checksum() -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS.lower(), credentials=FAKE_CREDS, diff --git a/tests/unit/test_secure_orders_sync.py b/tests/unit/test_secure_orders_sync.py index 16a2654..c7d7c63 100644 --- a/tests/unit/test_secure_orders_sync.py +++ b/tests/unit/test_secure_orders_sync.py @@ -98,7 +98,7 @@ def _install_secure_clob(client: SecureClient, handler: httpx.MockTransport) -> def _make_client() -> SecureClient: - return SecureClient.create( + return SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_secure_rewards_sync.py b/tests/unit/test_secure_rewards_sync.py index 444724d..adeb4fa 100644 --- a/tests/unit/test_secure_rewards_sync.py +++ b/tests/unit/test_secure_rewards_sync.py @@ -32,7 +32,7 @@ def _install_secure_clob(client: SecureClient, handler: httpx.MockTransport) -> def _make_client() -> SecureClient: - return SecureClient.create( + return SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, diff --git a/tests/unit/test_secure_signer_defaults.py b/tests/unit/test_secure_signer_defaults.py index 289e4e8..01ff4bc 100644 --- a/tests/unit/test_secure_signer_defaults.py +++ b/tests/unit/test_secure_signer_defaults.py @@ -53,7 +53,7 @@ def _captured() -> list[httpx.Request]: def test_secure_get_portfolio_values_defaults_to_signer(captured: list[httpx.Request]) -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -68,7 +68,7 @@ def test_secure_get_portfolio_values_defaults_to_signer(captured: list[httpx.Req def test_secure_get_portfolio_values_respects_explicit_user( captured: list[httpx.Request], ) -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -86,7 +86,7 @@ def test_secure_get_portfolio_values_respects_explicit_user( def test_secure_get_traded_market_count_defaults_to_signer( captured: list[httpx.Request], ) -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -103,7 +103,7 @@ def test_secure_get_traded_market_count_defaults_to_signer( def test_secure_get_traded_market_count_respects_explicit_user( captured: list[httpx.Request], ) -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -127,7 +127,7 @@ def handler(request: httpx.Request) -> httpx.Response: captured.append(request) return httpx.Response(200, content=b"PK\x03\x04", request=request) - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -146,7 +146,7 @@ def handler(request: httpx.Request) -> httpx.Response: captured.append(request) return httpx.Response(200, content=b"PK\x03\x04", request=request) - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -162,7 +162,7 @@ def handler(request: httpx.Request) -> httpx.Response: def test_secure_list_positions_defaults_to_signer(captured: list[httpx.Request]) -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -175,7 +175,7 @@ def test_secure_list_positions_defaults_to_signer(captured: list[httpx.Request]) def test_secure_list_positions_respects_explicit_user(captured: list[httpx.Request]) -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -191,7 +191,7 @@ def test_secure_list_positions_respects_explicit_user(captured: list[httpx.Reque def test_secure_list_closed_positions_defaults_to_signer(captured: list[httpx.Request]) -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -207,7 +207,7 @@ def test_secure_list_closed_positions_defaults_to_signer(captured: list[httpx.Re def test_secure_list_trades_defaults_to_signer(captured: list[httpx.Request]) -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -223,7 +223,7 @@ def test_secure_list_trades_defaults_to_signer(captured: list[httpx.Request]) -> def test_secure_list_activity_defaults_to_signer(captured: list[httpx.Request]) -> None: - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -242,7 +242,7 @@ def test_async_secure_list_positions_defaults_to_signer() -> None: captured: list[httpx.Request] = [] async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -262,7 +262,7 @@ def test_async_secure_list_positions_respects_explicit_user() -> None: captured: list[httpx.Request] = [] async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -286,7 +286,7 @@ def test_async_secure_list_positions_defaults_to_wallet_when_proxy() -> None: captured: list[httpx.Request] = [] async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=proxy_wallet, credentials=FAKE_CREDS, @@ -311,7 +311,7 @@ def handler(request: httpx.Request) -> httpx.Response: return httpx.Response(200, content=b"PK\x03\x04", request=request) async def run() -> None: - client = await AsyncSecureClient.create( + client = await AsyncSecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -335,7 +335,7 @@ def test_secure_list_positions_rejects_explicit_empty_user( ) -> None: from polymarket.errors import UserInputError - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS, @@ -351,7 +351,7 @@ def test_secure_get_portfolio_values_rejects_explicit_empty_user( ) -> None: from polymarket.errors import UserInputError - with SecureClient.create( + with SecureClient._create( private_key=PRIVATE_KEY, wallet=SIGNER_ADDRESS, credentials=FAKE_CREDS,