diff --git a/.gitignore b/.gitignore index 247d330..4986db0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ __pycache__/ *.pyc .DS_Store +.idea \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/csfloat_api.iml b/.idea/csfloat_api.iml deleted file mode 100644 index d0876a7..0000000 --- a/.idea/csfloat_api.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index a6218fe..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index ae8ddef..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 02b9112..310107b 100644 --- a/README.md +++ b/README.md @@ -73,20 +73,48 @@ Failing to close the session may result in warnings about unclosed client sessio ## Core Methods -* `get_exchange_rates()` – Retrieve current exchange rates. -* `get_all_listings(...)` – List items with optional filters (prices in cents). -* `get_specific_listing(listing_id)` – Get detailed info for a specific listing. -* `get_buy_orders(listing_id)` – Retrieve buy orders for a listing. -* `get_my_buy_orders(...)` – List your own buy orders. -* `get_me()` – Fetch authenticated user profile. -* `get_stall(user_id)` – Get a user's stall (listed items). -* `create_listing(asset_id, price, ...)` – Create a new listing (price in cents). -* `create_buy_order(market_hash_name, max_price, quantity)` – Place a buy order. -* `make_offer(listing_id, price)` – Make an offer on a listing. -* `buy_now(total_price, listing_id)` – Instantly buy one or more listings. -* `delete_buy_order(id)` – Cancel an existing buy order. - -For a full list of methods and parameters, refer to the library's source code. +### Meta +* `get_exchange_rates()` - Retrieve current exchange rates. +* `get_location()` - Get detected location metadata. + +### Account +* `get_me(raw_response=False)` - Fetch authenticated user profile. +* `get_account_standing()` - Retrieve account standing details. +* `get_transactions(page=0, limit=10)` - Get your transaction history. + +### Trades and Offers +* `get_pending_trades(limit=500, page=0)` - List pending trades. +* `get_trades(states, limit=500, page=0)` - List trades filtered by state. +* `get_trade_history(role="seller", limit=30, page=0)` - List completed, failed, or cancelled trades. +* `get_offers(limit=40)` - Fetch your offers timeline. +* `accept_sale(trade_ids)` - Accept one or more sales. + +### Listings (Browse) +* `get_all_listings(...)` - List items with optional filters (prices in cents). +* `get_specific_listing(listing_id, raw_response=False)` - Get detailed info for a specific listing. +* `get_similar(listing_id, raw_response=False)` - Find listings similar to a given listing. +* `get_sales(market_hash_name, paint_index=None)` - Retrieve historical sales for an item. +* `get_stall(user_id, limit=40, raw_response=False)` - Get a user's stall (listed items). + +### Inventory and Watchlist +* `get_inventory()` - Retrieve your inventory. +* `get_watchlist(limit=40)` - Retrieve your watchlist. +* `delete_watchlist(id)` - Remove a listing from your watchlist. + +### Listing Management +* `create_listing(asset_id, price, ...)` - Create a new listing (price in cents). +* `update_listing_price(listing_id, price)` - Update a listing price. +* `delete_listing(listing_id)` - Remove an existing listing. +* `make_offer(listing_id, price)` - Make an offer on a listing. +* `buy_now(total_price, listing_id)` - Instantly buy one or more listings. + +### Buy Orders +* `get_buy_orders(listing_id, limit=10, raw_response=False)` - Retrieve buy orders for a listing. +* `get_my_buy_orders(page=0, limit=10)` - List your own buy orders. +* `create_buy_order(market_hash_name, max_price, quantity)` - Place a buy order. +* `delete_buy_order(id)` - Cancel an existing buy order. + +For detailed parameters and return types, refer to `csfloat_client.py`. ## Proxy Support @@ -114,4 +142,4 @@ Contributions are welcome! Please submit issues and pull requests on the [GitHub ## License -This project is licensed under the [MIT License](https://opensource.org/licenses/MIT). \ No newline at end of file +This project is licensed under the [MIT License](https://opensource.org/licenses/MIT). diff --git a/csfloat_client.py b/csfloat_client.py index c1ba6bc..ccdaa88 100644 --- a/csfloat_client.py +++ b/csfloat_client.py @@ -1,7 +1,7 @@ import aiohttp import re from aiohttp_socks.connector import ProxyConnector -from typing import Iterable, Union, Optional, Dict, List +from typing import Iterable, Union, Optional, Dict, List, Sequence from .models.listing import Listing from .models.buy_orders import BuyOrders from .models.me import Me @@ -97,11 +97,13 @@ async def _request(self, method: str, parameters: str, json_data=None) -> Option return await response.json() - def _validate_category(self, category: int) -> None: + @staticmethod + def _validate_category(category: int) -> None: if category not in (0, 1, 2, 3): raise ValueError(f'Unknown category parameter "{category}"') - def _validate_sort_by(self, sort_by: str) -> None: + @staticmethod + def _validate_sort_by(sort_by: str) -> None: valid_sort_by = ( 'lowest_price', 'highest_price', 'most_recent', 'expires_soon', 'lowest_float', 'highest_float', 'best_deal', 'highest_discount', @@ -110,15 +112,32 @@ def _validate_sort_by(self, sort_by: str) -> None: if sort_by not in valid_sort_by: raise ValueError(f'Unknown sort_by parameter "{sort_by}"') - def _validate_type(self, type_: str) -> None: + @staticmethod + def _validate_type(type_: str) -> None: if type_ not in ('buy_now', 'auction'): raise ValueError(f'Unknown type parameter "{type_}"') - def _validate_role(self, role: str) -> None: + @staticmethod + def _validate_role(role: str) -> None: valid_roles = ("seller", "buyer") if role not in valid_roles: raise ValueError(f'Unknown role parameter: {role}') + @staticmethod + def _validate_trade_states(states: Sequence[str]) -> str: + allowed_states = {"queued", "pending", "verified", "failed", "cancelled"} + if isinstance(states, str) or not isinstance(states, Sequence): + raise ValueError("states must be a sequence of trade state strings.") + unique_states = [] + for state in states: + if state not in allowed_states: + raise ValueError(f'Unknown trade state "{state}"') + if state not in unique_states: + unique_states.append(state) + if not unique_states: + raise ValueError("states must include at least one trade state.") + return ",".join(unique_states) + async def get_exchange_rates(self) -> Optional[dict]: parameters = "/meta/exchange-rates" method = "GET" @@ -165,6 +184,16 @@ async def get_pending_trades( response = await self._request(method=method, parameters=parameters) return response + async def get_trades( + self, states: Sequence[str], limit: int = 500, page: int = 0 + ) -> Optional[dict]: + state_param = self._validate_trade_states(states) + parameters = f"/me/trades?state={state_param}&limit={limit}&page={page}" + method = "GET" + + response = await self._request(method=method, parameters=parameters) + return response + async def get_similar( self, *, listing_id: int, raw_response: bool = False ) -> Union[Iterable[Listing], dict]: diff --git a/models/item.py b/models/item.py index e0bee47..873556e 100644 --- a/models/item.py +++ b/models/item.py @@ -124,6 +124,7 @@ def low_rank(self) -> Optional[int]: def stickers(self) -> Optional[List[Sticker]]: if self._stickers is not None: return [Sticker(data=sticker) for sticker in self._stickers] + return None @property def tradable(self) -> Optional[bool]: diff --git a/models/stall.py b/models/stall.py index f336eed..32f5e4f 100644 --- a/models/stall.py +++ b/models/stall.py @@ -1,4 +1,4 @@ -from typing import List, Dict, Any, Optional +from typing import List, Dict, Any from .listing import Listing diff --git a/models/stickers.py b/models/stickers.py index bb88a2b..88f18c0 100644 --- a/models/stickers.py +++ b/models/stickers.py @@ -1,4 +1,5 @@ from typing import Dict, Any, Optional +from warnings import deprecated class StickerReference: @@ -28,7 +29,7 @@ def updated_at(self) -> Optional[str]: class Sticker: __slots__ = ( - "_stickerId", + "_sticker_id", "_slot", "_wear", "_offset_x", @@ -39,7 +40,7 @@ class Sticker: ) def __init__(self, *, data: Dict[str, Any]): - self._stickerId = data.get("stickerId") + self._sticker_id = data.get("stickerId") self._slot = data.get("slot") self._wear = data.get("wear") self._offset_x = data.get("offset_x") @@ -49,8 +50,13 @@ def __init__(self, *, data: Dict[str, Any]): self._reference = data.get("reference") @property + @deprecated("'stickerId' is deprecated; use 'sticker_id' instead.") def stickerId(self) -> Optional[int]: - return self._stickerId + return self.sticker_id + + @property + def sticker_id(self) -> Optional[int]: + return self._sticker_id @property def slot(self) -> Optional[int]: @@ -72,3 +78,4 @@ def name(self) -> Optional[str]: def reference(self) -> Optional[StickerReference]: if self._reference is not None: return StickerReference(data=self._reference) + return None