From 4de4b2c3c5eecfc5155af904758519168c527f2b Mon Sep 17 00:00:00 2001 From: SomeSpecialOne Date: Wed, 26 Jan 2022 00:33:13 +0300 Subject: [PATCH] =?UTF-8?q?Code=20style=20now=20is=20`Black`=20=E2=9C=A8.?= =?UTF-8?q?=20Fix=20test=20data=20for=20`steam.Client`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + pyproject.toml | 5 + steam_tradeoffer_manager/_monkey_patch.py | 4 +- steam_tradeoffer_manager/base/abc.py | 42 +++++--- steam_tradeoffer_manager/base/bot.py | 49 ++++----- steam_tradeoffer_manager/base/enums.py | 12 +-- steam_tradeoffer_manager/base/mixins.py | 21 ++-- steam_tradeoffer_manager/base/pool.py | 3 +- steam_tradeoffer_manager/bot.py | 112 ++++++++++----------- steam_tradeoffer_manager/inventory.py | 4 +- steam_tradeoffer_manager/item.py | 1 + steam_tradeoffer_manager/manager.py | 116 +++++++++++----------- steam_tradeoffer_manager/mixins.py | 99 ++++++++++++------ steam_tradeoffer_manager/trades.py | 2 + steam_tradeoffer_manager/utils.py | 9 +- tests/conftest.py | 3 +- tests/data.py | 20 ++-- tests/mocks.py | 16 +-- tests/test_bot_exceptions.py | 17 ++-- tests/test_constraints_mixin.py | 3 +- tests/test_manager.py | 20 ++-- 21 files changed, 314 insertions(+), 245 deletions(-) diff --git a/README.md b/README.md index 1a10bdc..b973cd1 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ [![codecov](https://codecov.io/gh/somespecialone/python-steam-tradeoffer-manager/branch/master/graph/badge.svg?token=H3JL81SL7P)](https://codecov.io/gh/somespecialone/python-steam-tradeoffer-manager) [![CodeFactor](https://www.codefactor.io/repository/github/somespecialone/python-steam-tradeoffer-manager/badge)](https://www.codefactor.io/repository/github/somespecialone/python-steam-tradeoffer-manager) [![versions](https://img.shields.io/pypi/pyversions/steam-tradeoffer-manager)](https://pypi.org/project/steam-tradeoffer-manager) +[![black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![steam](https://shields.io/badge/steam-1b2838?logo=steam)](https://store.steampowered.com/) ## Installation diff --git a/pyproject.toml b/pyproject.toml index bb3fdb2..acfcb48 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,11 @@ pytest-cov = "^3.0.0" mkdocs = "^1.2.3" mkdocs-material = "^8.1.6" mkdocs-git-revision-date-localized-plugin = "^0.11.1" +black = "^21.12b0" + +[tool.black] +line-length = 120 +target-version = ['py310'] [tool.pytest.ini_options] testpaths = ["tests"] diff --git a/steam_tradeoffer_manager/_monkey_patch.py b/steam_tradeoffer_manager/_monkey_patch.py index b41a4a4..9b5bd15 100644 --- a/steam_tradeoffer_manager/_monkey_patch.py +++ b/steam_tradeoffer_manager/_monkey_patch.py @@ -49,8 +49,8 @@ async def poll_trades_patched(self: state.ConnectionState) -> None: async def get_api_key_patched(self: http.HTTPClient) -> str | None: resp = await self.get(models.URL.COMMUNITY / "dev/apikey") if ( - "

Access Denied

" in resp - or "You must have a validated email address to create a Steam Web API key" in resp + "

Access Denied

" in resp + or "You must have a validated email address to create a Steam Web API key" in resp ): return diff --git a/steam_tradeoffer_manager/base/abc.py b/steam_tradeoffer_manager/base/abc.py index bee7a25..8f91869 100644 --- a/steam_tradeoffer_manager/base/abc.py +++ b/steam_tradeoffer_manager/base/abc.py @@ -7,46 +7,60 @@ class AbstractBasePool(metaclass=ABCMeta): """Abstract base class for pool""" @abstractmethod - def add(self, *args, **kwargs): ... + def add(self, *args, **kwargs): + ... @abstractmethod - def remove(self, *args, **kwargs): ... + def remove(self, *args, **kwargs): + ... @abstractmethod - def startup(self): ... + def startup(self): + ... @abstractmethod - def shutdown(self): ... + def shutdown(self): + ... @abstractmethod - def get(self, k): ... + def get(self, k): + ... @abstractmethod - def pop(self, k): ... + def pop(self, k): + ... @abstractmethod - def _bind(self, *args): ... + def _bind(self, *args): + ... @abstractmethod - def _unbind(self, *args): ... + def _unbind(self, *args): + ... @abstractmethod - def __contains__(self, item): ... + def __contains__(self, item): + ... @abstractmethod - def __len__(self): ... + def __len__(self): + ... @abstractmethod - def __iter__(self): ... + def __iter__(self): + ... @abstractmethod - def __getitem__(self, item): ... + def __getitem__(self, item): + ... # @abstractmethod # def __setitem__(self, key, value): ... @abstractmethod - def __delitem__(self, key): ... + def __delitem__(self, key): + ... @abstractmethod - def __bool__(self): ... + def __bool__(self): + ... diff --git a/steam_tradeoffer_manager/base/bot.py b/steam_tradeoffer_manager/base/bot.py index c15d9f9..237aa46 100644 --- a/steam_tradeoffer_manager/base/bot.py +++ b/steam_tradeoffer_manager/base/bot.py @@ -8,10 +8,10 @@ from .enums import BotState from .mixins import PoolBotMixin -__all__ = ('SteamBot',) +__all__ = ("SteamBot",) _log = logging.getLogger(__name__) -_P = TypeVar("_P", bound='pool.SteamBotPool') +_P = TypeVar("_P", bound="pool.SteamBotPool") _I = TypeVar("_I", bound=int) @@ -21,25 +21,25 @@ class SteamBot(steam.Client, PoolBotMixin[_I, _P]): `id` attr must be steam id64 """ - constraints = ('username',) - dimension = 'steam' + constraints = ("username",) + dimension = "steam" def __init__( - self, - username: str, - password: str, - shared_secret: str, - identity_secret: str, - *, - id: _I = None, - whitelist: set[int] | None = None, - user_agent: str | None = None, - proxy: str | None = None, - proxy_auth: BasicAuth | None = None, - connector: BaseConnector | None = None, - randomizer: Callable[[], int] | None = None, - domain: str | None = None, - **options: Any, + self, + username: str, + password: str, + shared_secret: str, + identity_secret: str, + *, + id: _I = None, + whitelist: set[int] | None = None, + user_agent: str | None = None, + proxy: str | None = None, + proxy_auth: BasicAuth | None = None, + connector: BaseConnector | None = None, + randomizer: Callable[[], int] | None = None, + domain: str | None = None, + **options: Any, ) -> None: self._id = id @@ -167,7 +167,8 @@ def randomizer(self, value: Callable[[], int]): async def on_ready(self) -> None: self._state = BotState.Active - if not self.id: setattr(self, "_id", self.user.id64) # id will be automatically set when client is ready + if not self.id: + setattr(self, "_id", self.user.id64) # id will be automatically set when client is ready _log.info(f"Bot {self.user} is ready") @@ -198,10 +199,12 @@ def __del__(self): if not self.is_closed(): import warnings - warnings.warn(f'Unstopped bot {self}!', ResourceWarning, source=self) - if self._refresh_task: self._refresh_task.cancel() + warnings.warn(f"Unstopped bot {self}!", ResourceWarning, source=self) + if self._refresh_task: + self._refresh_task.cancel() # maybe asyncio.call_exception_handler needed - if self.pool: del self.pool[self.id] + if self.pool: + del self.pool[self.id] super().__del__() def __str__(self) -> str: diff --git a/steam_tradeoffer_manager/base/enums.py b/steam_tradeoffer_manager/base/enums.py index 68ad924..e5546da 100644 --- a/steam_tradeoffer_manager/base/enums.py +++ b/steam_tradeoffer_manager/base/enums.py @@ -2,15 +2,15 @@ from random import randint, random from typing import Callable -__all__ = ('BotState', 'ONCE_EVERY') +__all__ = ("BotState", "ONCE_EVERY") class BotState(enum.Enum): - Active = 'active' # working fine - Waiting = 'waiting' # waiting until ready - InvalidCredentials = 'invalid credentials' - UnknownError = 'unknown exception' # stopped by error - Stopped = 'stopped' # just stopped + Active = "active" # working fine + Waiting = "waiting" # waiting until ready + InvalidCredentials = "invalid credentials" + UnknownError = "unknown exception" # stopped by error + Stopped = "stopped" # just stopped class Timings: diff --git a/steam_tradeoffer_manager/base/mixins.py b/steam_tradeoffer_manager/base/mixins.py index 638124d..dc2ce10 100644 --- a/steam_tradeoffer_manager/base/mixins.py +++ b/steam_tradeoffer_manager/base/mixins.py @@ -6,11 +6,11 @@ from .exceptions import ConstraintException from ..utils import join_multiple_in_string -__all__ = ('PoolBotMixin', 'ConstraintsMixin') +__all__ = ("PoolBotMixin", "ConstraintsMixin") _log = logging.getLogger(__name__) _P = TypeVar("_P", bound=AbstractBasePool) -_I = TypeVar('_I') +_I = TypeVar("_I") class ConstraintsMixin: @@ -20,6 +20,7 @@ class ConstraintsMixin: but always must be passed like arguments to `__init__` and be `hashable`. Implement `__del__` method to clean up hashes in storage while garbage collecting, """ + __storage__: Final[dict[str, set[int]]] = {} constraints: Sequence[str | Sequence[str]] = () @@ -27,13 +28,16 @@ class ConstraintsMixin: def __init_subclass__(cls, dimension: str = None, **kwargs): super().__init_subclass__(**kwargs) - subclass_dimension = getattr(cls, 'dimension', None) + subclass_dimension = getattr(cls, "dimension", None) arg_dimension = dimension if subclass_dimension and arg_dimension: import warnings - warnings.warn('Subclass overrides `dimension` and `dimension` arg has been passed to subclass init. ' - f'Used [{subclass_dimension}] by default.', stacklevel=len(inspect.stack()) + 1) + warnings.warn( + "Subclass overrides `dimension` and `dimension` arg has been passed to subclass init. " + f"Used [{subclass_dimension}] by default.", + stacklevel=len(inspect.stack()) + 1, + ) if subclass_dimension: cls.dimension = subclass_dimension @@ -78,7 +82,7 @@ def _check_constraints(self): if h in self.__storage__[self.dimension]: f = join_multiple_in_string(self.constraints) # would be great if I write violated constraints here - raise ConstraintException(f'Instance with unique values({f}) already created.') + raise ConstraintException(f"Instance with unique values({f}) already created.") self.__storage__[self.dimension].update(self._hashes) @@ -88,6 +92,7 @@ def __del__(self) -> None: class _MappingPoolBotMixin(ConstraintsMixin, Generic[_I, _P]): # pragma: no cover """Mixin for bot. Contains required methods to interact with pool""" + # maps to ids and pool __ids__: Final[dict[str, _I]] = {} __pools__: Final[dict[str, _P]] = {} @@ -118,11 +123,11 @@ class _PropertyPoolBotMixin(ConstraintsMixin, Generic[_I, _P]): # pure properties @property def id(self) -> _I | None: - return getattr(self, '_id', None) + return getattr(self, "_id", None) @property def pool(self) -> _P | None: - return getattr(self, '_pool', None) + return getattr(self, "_pool", None) def __repr__(self) -> str: return f"<{self.__class__.__name__} id={self.id}>" diff --git a/steam_tradeoffer_manager/base/pool.py b/steam_tradeoffer_manager/base/pool.py index a2256e4..6272bb5 100644 --- a/steam_tradeoffer_manager/base/pool.py +++ b/steam_tradeoffer_manager/base/pool.py @@ -44,6 +44,7 @@ def add(self, bot: _B, raise_=True) -> None: if bot.pool: import warnings import inspect + msg = f"Bot with id {bot.id} already in pool" if raise_: @@ -76,7 +77,7 @@ def _unbind(self, bot: _B) -> None: def _bind(self, bot: _B) -> None: if not bot.id: raise ValueError(f"Bot id is {bot.id}") - setattr(bot, '_pool', self) + setattr(bot, "_pool", self) self._store[bot.id] = bot # container methods https://docs.python.org/3/reference/datamodel.html#emulating-container-types diff --git a/steam_tradeoffer_manager/bot.py b/steam_tradeoffer_manager/bot.py index 1423e30..290d176 100644 --- a/steam_tradeoffer_manager/bot.py +++ b/steam_tradeoffer_manager/bot.py @@ -51,41 +51,43 @@ class ManagerBot(SteamBot[_I, _M]): """ @overload - def __init__(self, - username: str, - password: str, - shared_secret: str, - identity_secret: str, - *, - id: int = None, - whitelist: set[int] | None = None, - user_agent: str | None = None, - proxy: str | None = None, - proxy_auth: BasicAuth | None = None, - connector: BaseConnector | None = None, - randomizer: Callable[[], int] | None = None, - domain: str | None = None, - offer_cancel_delay: timedelta | None = None, - prefetch_games: tuple[SteamGame] = (), - max_messages: int | None = ..., - game: steam.Game | None = ..., - games: list[steam.Game] = ..., - state: steam.PersonaState | None = ..., - ui_mode: steam.UIMode | None = ..., - flags: steam.PersonaStateFlag | None = ..., - force_kick: bool = ..., - ): ... + def __init__( + self, + username: str, + password: str, + shared_secret: str, + identity_secret: str, + *, + id: int = None, + whitelist: set[int] | None = None, + user_agent: str | None = None, + proxy: str | None = None, + proxy_auth: BasicAuth | None = None, + connector: BaseConnector | None = None, + randomizer: Callable[[], int] | None = None, + domain: str | None = None, + offer_cancel_delay: timedelta | None = None, + prefetch_games: tuple[SteamGame] = (), + max_messages: int | None = ..., + game: steam.Game | None = ..., + games: list[steam.Game] = ..., + state: steam.PersonaState | None = ..., + ui_mode: steam.UIMode | None = ..., + flags: steam.PersonaStateFlag | None = ..., + force_kick: bool = ..., + ): + ... def __init__( - self, - username: str, - password: str, - shared_secret: str, - identity_secret: str, - *, - offer_cancel_delay: timedelta | None = None, - prefetch_games: tuple[SteamGame] = (), - **kwargs + self, + username: str, + password: str, + shared_secret: str, + identity_secret: str, + *, + offer_cancel_delay: timedelta | None = None, + prefetch_games: tuple[SteamGame] = (), + **kwargs, ): super().__init__(username, password, shared_secret, identity_secret, **kwargs) @@ -143,12 +145,12 @@ def get_all_items(self) -> list[BotItem]: @ready_required def create_offer( - self, - partner: steam.User, - token: str | None = None, - message: str | None = None, - send_items: list[steam.Item] | None = None, - receive_items: list[steam.Item] | None = None, + self, + partner: steam.User, + token: str | None = None, + message: str | None = None, + send_items: list[steam.Item] | None = None, + receive_items: list[steam.Item] | None = None, ) -> ManagerTradeOffer["ManagerBot"]: """ Create trade offer model, but not send it. @@ -161,21 +163,19 @@ def create_offer( """ return ManagerTradeOffer( _steam_offer=steam.TradeOffer( - message=message, - token=token, - items_to_send=send_items, - items_to_receive=receive_items), + message=message, token=token, items_to_send=send_items, items_to_receive=receive_items + ), owner=self, - partner=copy_user(self, partner) if partner.id64 not in self._connection._users else partner + partner=copy_user(self, partner) if partner.id64 not in self._connection._users else partner, ) @ready_required async def create_offer_from_trade_url( - self, - trade_url: str, - message: str | None = None, - send_items: list[steam.Item] | None = None, - receive_items: list[steam.Item] | None = None, + self, + trade_url: str, + message: str | None = None, + send_items: list[steam.Item] | None = None, + receive_items: list[steam.Item] | None = None, ) -> ManagerTradeOffer["ManagerBot"]: """ Create trade offer model using trade url, but not send it. @@ -189,13 +189,7 @@ async def create_offer_from_trade_url( partner_id32, token = parse_trade_url(trade_url) partner = self.get_user(partner_id32) or await self.fetch_user(partner_id32) - return self.create_offer( - partner, - token, - message, - send_items, - receive_items - ) + return self.create_offer(partner, token, message, send_items, receive_items) @ready_required def get_trade(self, id: int): @@ -222,7 +216,8 @@ async def send_offer(self, offer: ManagerTradeOffer) -> None: if offer.owner is self: await offer.partner.send(trade=offer._steam_offer) self.manager_trades.add(offer) - if offer.cancel_delay is not None: offer._set_cancel_timeout() + if offer.cancel_delay is not None: + offer._set_cancel_timeout() # TODO: check if this is necessary self.loop.create_task(self.ws._connection.poll_trades(), name=f"{self.user} poll trades task") @@ -277,7 +272,8 @@ async def on_ready(self) -> None: trade_url = await super().trade_url() _, self._trade_url_token = parse_trade_url(trade_url) - for game in self.prefetch_games: await self.inventory.fetch_game_inventory(game) # fetch inventories + for game in self.prefetch_games: + await self.inventory.fetch_game_inventory(game) # fetch inventories def dispatch(self, event: str, *args: Any, **kwargs: Any) -> None: super().dispatch(event, *args, **kwargs) diff --git a/steam_tradeoffer_manager/inventory.py b/steam_tradeoffer_manager/inventory.py index 8aa347c..ebd418f 100644 --- a/steam_tradeoffer_manager/inventory.py +++ b/steam_tradeoffer_manager/inventory.py @@ -8,7 +8,7 @@ __all__ = ("GamesInventory",) -_B = TypeVar("_B", bound='bot.ManagerBot') +_B = TypeVar("_B", bound="bot.ManagerBot") _D = TypeVar("_D") SteamGame: TypeAlias = "Game | StatefulGame" BotInventory: TypeAlias = "BaseInventory[BotItem[_B]]" @@ -18,7 +18,7 @@ class GamesInventory(MutableMapping[AssetId, BotItem[_B]], Generic[_B]): """Container class created to store fetched inventories""" - __slots__ = ('_items_storage', 'owner', "_inventories_storage") + __slots__ = ("_items_storage", "owner", "_inventories_storage") def __init__(self, owner: _B): self._inventories_storage: dict[int, BotInventory] = {} # default inventories with refs to items diff --git a/steam_tradeoffer_manager/item.py b/steam_tradeoffer_manager/item.py index 15be4f3..d59e0f4 100644 --- a/steam_tradeoffer_manager/item.py +++ b/steam_tradeoffer_manager/item.py @@ -9,6 +9,7 @@ class BotItem(Item, Generic[_O]): """Almost `steam.Item` except one thing - `owner is `ManagerBot``""" + owner: _O def __init__(self, item: Item, owner: _O): diff --git a/steam_tradeoffer_manager/manager.py b/steam_tradeoffer_manager/manager.py index 054b380..d7f0248 100644 --- a/steam_tradeoffer_manager/manager.py +++ b/steam_tradeoffer_manager/manager.py @@ -22,6 +22,7 @@ class TradeOfferManager(SteamBotPool[_I, _B], ManagerDispatchMixin): """Manager class...""" + randomizer = ONCE_EVERY.SIX_HOURS offer_cancel_delay: timedelta | None = timedelta(minutes=5) prefetch_games: tuple[Game] = () @@ -39,33 +40,30 @@ def get_offer(self, id: int) -> ManagerTradeOffer[_B] | None: return self.trades.get(id) def _create_offer( - self, - bot: _B, - partner: User, - token: str | None, - message: str | None, - send_items: list[BotItem] | None, - receive_items: list[Item] | None, + self, + bot: _B, + partner: User, + token: str | None, + message: str | None, + send_items: list[BotItem] | None, + receive_items: list[Item] | None, ) -> ManagerTradeOffer[_B]: - if bot not in self: raise ValueError(f"Bot {bot.user} not bounded to this manager") + if bot not in self: + raise ValueError(f"Bot {bot.user} not bounded to this manager") return bot.create_offer( - partner=partner, - token=token, - message=message, - send_items=send_items, - receive_items=receive_items + partner=partner, token=token, message=message, send_items=send_items, receive_items=receive_items ) def _create_offers( - self, - owners: set[_B], - partner: User, - token: str | None, - message: str | None, - send_items: list[BotItem] | None, - receive_items: list[Item] | None, - msg_in_all_offers: bool + self, + owners: set[_B], + partner: User, + token: str | None, + message: str | None, + send_items: list[BotItem] | None, + receive_items: list[Item] | None, + msg_in_all_offers: bool, ) -> list[ManagerTradeOffer[_B]]: trades: list[ManagerTradeOffer[_B]] = [] @@ -79,7 +77,7 @@ def _create_offers( token=token, message=message if (not message_flag or msg_in_all_offers) else None, send_items=[item for item in send_items if item.owner is bot], - receive_items=receive_items if not receive_items_flag else None + receive_items=receive_items if not receive_items_flag else None, ) ) receive_items_flag = True @@ -88,12 +86,12 @@ def _create_offers( return trades def create_offer( - self, - partner: User, - token: str | None = None, - message: str | None = None, - send_items: list[BotItem] | None = None, - receive_items: list[Item] | None = None, + self, + partner: User, + token: str | None = None, + message: str | None = None, + send_items: list[BotItem] | None = None, + receive_items: list[Item] | None = None, ) -> ManagerTradeOffer[_B]: """ Create `ManagerTradeOffer`. Consider that items must be owned by one bot. @@ -108,7 +106,8 @@ def create_offer( """ owner = {item.owner for item in send_items} f = join_multiple_in_string(tuple(owner)) - if len(owner) > 1: raise ValueError(f"Items to send owns by few or more manager bots {f}") + if len(owner) > 1: + raise ValueError(f"Items to send owns by few or more manager bots {f}") return self._create_offer( bot=owner.pop(), @@ -116,15 +115,15 @@ def create_offer( token=token, message=message, send_items=send_items, - receive_items=receive_items + receive_items=receive_items, ) async def create_offer_from_url( - self, - trade_url: str, - message: str | None = None, - send_items: list[BotItem] | None = None, - receive_items: list[Item] | None = None, + self, + trade_url: str, + message: str | None = None, + send_items: list[BotItem] | None = None, + receive_items: list[Item] | None = None, ) -> ManagerTradeOffer[_B]: """ Create `ManagerTradeOffer` from trade url. Requires fetching user model. @@ -138,30 +137,26 @@ async def create_offer_from_url( """ owner = {item.owner for item in send_items} f = join_multiple_in_string(tuple(owner)) - if len(owner) > 1: raise ValueError(f"Items to send owns by few or more manager bots {f}") + if len(owner) > 1: + raise ValueError(f"Items to send owns by few or more manager bots {f}") bot: _B = owner.pop() partner_id32, token = parse_trade_url(trade_url) partner = bot.get_user(partner_id32) or await bot.fetch_user(partner_id32) return self._create_offer( - bot=bot, - partner=partner, - token=token, - message=message, - send_items=send_items, - receive_items=receive_items + bot=bot, partner=partner, token=token, message=message, send_items=send_items, receive_items=receive_items ) def create_offers( - self, - partner: User, - token: str | None = None, - message: str | None = None, - send_items: list[BotItem] | None = None, - receive_items: list[Item] | None = None, - *, - msg_in_all_offers: bool = False + self, + partner: User, + token: str | None = None, + message: str | None = None, + send_items: list[BotItem] | None = None, + receive_items: list[Item] | None = None, + *, + msg_in_all_offers: bool = False, ) -> list[ManagerTradeOffer[_B]]: """ Creates different trade offers if items placed in different bots inventories. @@ -184,17 +179,17 @@ def create_offers( message=message, send_items=send_items, receive_items=receive_items, - msg_in_all_offers=msg_in_all_offers + msg_in_all_offers=msg_in_all_offers, ) async def create_offers_from_url( - self, - trade_url: str, - message: str | None = None, - send_items: list[BotItem] | None = None, - receive_items: list[Item] | None = None, - *, - msg_in_all_offers: bool = False + self, + trade_url: str, + message: str | None = None, + send_items: list[BotItem] | None = None, + receive_items: list[Item] | None = None, + *, + msg_in_all_offers: bool = False, ) -> list[ManagerTradeOffer[_B]]: """ Creates different trade offers from trade url if items placed in different bots inventories. @@ -222,11 +217,12 @@ async def create_offers_from_url( message=message, send_items=send_items, receive_items=receive_items, - msg_in_all_offers=msg_in_all_offers + msg_in_all_offers=msg_in_all_offers, ) async def on_inventory_update(self, bot: _B, inventory: BotInventory) -> None: - for item in inventory: self.items.add(item) + for item in inventory: + self.items.add(item) async def on_manager_trade_send(self, bot: _B, trade: ManagerTradeOffer) -> None: self.trades.add(trade) diff --git a/steam_tradeoffer_manager/mixins.py b/steam_tradeoffer_manager/mixins.py index d4e4416..0b5c892 100644 --- a/steam_tradeoffer_manager/mixins.py +++ b/steam_tradeoffer_manager/mixins.py @@ -84,68 +84,101 @@ async def on_inventory_update(self, bot, inventory: BotInventory) -> None: """ # steamio events - async def on_connect(self, bot) -> None: ... + async def on_connect(self, bot) -> None: + ... - async def on_disconnect(self, bot) -> None: ... + async def on_disconnect(self, bot) -> None: + ... - async def on_ready(self, bot) -> None: ... + async def on_ready(self, bot) -> None: + ... - async def on_login(self, bot) -> None: ... + async def on_login(self, bot) -> None: + ... - async def on_logout(self, bot) -> None: ... + async def on_logout(self, bot) -> None: + ... - async def on_message(self, bot, message: steam.Message) -> None: ... + async def on_message(self, bot, message: steam.Message) -> None: + ... - async def on_typing(self, bot, user: steam.User, when: datetime.datetime) -> None: ... + async def on_typing(self, bot, user: steam.User, when: datetime.datetime) -> None: + ... - async def on_trade_receive(self, bot, trade: steam.TradeOffer) -> None: ... + async def on_trade_receive(self, bot, trade: steam.TradeOffer) -> None: + ... - async def on_trade_send(self, bot, trade: steam.TradeOffer) -> None: ... + async def on_trade_send(self, bot, trade: steam.TradeOffer) -> None: + ... - async def on_trade_accept(self, bot, trade: steam.TradeOffer) -> None: ... + async def on_trade_accept(self, bot, trade: steam.TradeOffer) -> None: + ... - async def on_trade_decline(self, bot, trade: steam.TradeOffer) -> None: ... + async def on_trade_decline(self, bot, trade: steam.TradeOffer) -> None: + ... - async def on_trade_cancel(self, bot, trade: steam.TradeOffer) -> None: ... + async def on_trade_cancel(self, bot, trade: steam.TradeOffer) -> None: + ... - async def on_trade_expire(self, bot, trade: steam.TradeOffer) -> None: ... + async def on_trade_expire(self, bot, trade: steam.TradeOffer) -> None: + ... - async def on_trade_counter(self, bot, trade: steam.TradeOffer) -> None: ... + async def on_trade_counter(self, bot, trade: steam.TradeOffer) -> None: + ... - async def on_comment(self, bot, comment: steam.Comment) -> None: ... + async def on_comment(self, bot, comment: steam.Comment) -> None: + ... - async def on_user_invite(self, bot, invite: steam.UserInvite) -> None: ... + async def on_user_invite(self, bot, invite: steam.UserInvite) -> None: + ... - async def on_user_invite_accept(self, bot, invite: steam.UserInvite) -> None: ... + async def on_user_invite_accept(self, bot, invite: steam.UserInvite) -> None: + ... - async def on_user_invite_decline(self, bot, invite: steam.UserInvite) -> None: ... + async def on_user_invite_decline(self, bot, invite: steam.UserInvite) -> None: + ... - async def on_user_update(self, bot, before: steam.User, after: steam.User) -> None: ... + async def on_user_update(self, bot, before: steam.User, after: steam.User) -> None: + ... - async def on_user_remove(self, bot, user: steam.User) -> None: ... + async def on_user_remove(self, bot, user: steam.User) -> None: + ... - async def on_clan_invite(self, bot, invite: steam.ClanInvite) -> None: ... + async def on_clan_invite(self, bot, invite: steam.ClanInvite) -> None: + ... - async def on_clan_invite_accept(self, bot, invite: steam.ClanInvite) -> None: ... + async def on_clan_invite_accept(self, bot, invite: steam.ClanInvite) -> None: + ... - async def on_clan_invite_decline(self, bot, invite: steam.ClanInvite) -> None: ... + async def on_clan_invite_decline(self, bot, invite: steam.ClanInvite) -> None: + ... - async def on_clan_join(self, bot, clan: steam.Clan) -> None: ... + async def on_clan_join(self, bot, clan: steam.Clan) -> None: + ... - async def on_clan_update(self, bot, before: steam.Clan, after: steam.Clan) -> None: ... + async def on_clan_update(self, bot, before: steam.Clan, after: steam.Clan) -> None: + ... - async def on_clan_leave(self, bot, clan: steam.Clan) -> None: ... + async def on_clan_leave(self, bot, clan: steam.Clan) -> None: + ... - async def on_group_join(self, bot, group: steam.Group) -> None: ... + async def on_group_join(self, bot, group: steam.Group) -> None: + ... - async def on_group_update(self, bot, before: steam.Group, after: steam.Group) -> None: ... + async def on_group_update(self, bot, before: steam.Group, after: steam.Group) -> None: + ... - async def on_group_leave(self, bot, group: steam.Group) -> None: ... + async def on_group_leave(self, bot, group: steam.Group) -> None: + ... - async def on_event_create(self, bot, event: steam.Event) -> None: ... + async def on_event_create(self, bot, event: steam.Event) -> None: + ... - async def on_announcement_create(self, bot, announcement: steam.Announcement) -> None: ... + async def on_announcement_create(self, bot, announcement: steam.Announcement) -> None: + ... - async def on_socket_receive(self, bot, msg: Msg | MsgProto) -> None: ... + async def on_socket_receive(self, bot, msg: Msg | MsgProto) -> None: + ... - async def on_socket_send(self, bot, msg: Msg | MsgProto) -> None: ... + async def on_socket_send(self, bot, msg: Msg | MsgProto) -> None: + ... diff --git a/steam_tradeoffer_manager/trades.py b/steam_tradeoffer_manager/trades.py index 3344fe4..36235ac 100644 --- a/steam_tradeoffer_manager/trades.py +++ b/steam_tradeoffer_manager/trades.py @@ -20,6 +20,7 @@ class ManagerBotTrades(MutableMapping[TradeOfferId, ManagerTradeOffer[_B]], Gene """ ManagerTradeOffer's storage for ManagerBot. """ + __slots__ = ("owner", "_storage") def __init__(self, owner: _B): @@ -32,6 +33,7 @@ def add(self, offer: ManagerTradeOffer): if offer.id in self: import warnings + warnings.warn(f"Trade offer {offer.id} already in storage!") self[offer.id] = offer diff --git a/steam_tradeoffer_manager/utils.py b/steam_tradeoffer_manager/utils.py index 028a019..cf812d6 100644 --- a/steam_tradeoffer_manager/utils.py +++ b/steam_tradeoffer_manager/utils.py @@ -6,11 +6,12 @@ from .base import ReadyRequired -__all__ = ('ready_required', "parse_trade_url", "join_multiple_in_string") +__all__ = ("ready_required", "parse_trade_url", "join_multiple_in_string", "copy_user") class _HasIsReadyProtocol(Protocol): - def is_ready(self) -> bool: ... + def is_ready(self) -> bool: + ... def ready_required(func): @@ -20,6 +21,7 @@ def wrapper(self: _HasIsReadyProtocol, *args, **kwargs): return func(self, *args, **kwargs) else: raise ReadyRequired("Client is not ready or bot is closed/stopped!") + return wrapper @@ -35,9 +37,10 @@ def wrapper(self: _HasIsReadyProtocol, *args, **kwargs): # # return inner + def parse_trade_url(trade_url: str) -> tuple[int, str]: qs = urllib.parse.parse_qs(urllib.parse.urlparse(trade_url).query) - return int(qs['partner'][0]), qs['token'][0] + return int(qs["partner"][0]), qs["token"][0] def join_multiple_in_string(fs: Sequence) -> str: diff --git a/tests/conftest.py b/tests/conftest.py index 69779e9..517c7fe 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -26,6 +26,7 @@ async def bot(event_loop): yield bot_instance - if not bot_instance.is_closed(): await bot_instance.close() + if not bot_instance.is_closed(): + await bot_instance.close() bot_instance.__del__() diff --git a/tests/data.py b/tests/data.py index b474bc5..a284ba2 100644 --- a/tests/data.py +++ b/tests/data.py @@ -27,7 +27,7 @@ def bot_data(): "password": BOT_PASSWORD, "shared_secret": SHARED_SECRET, "identity_secret": IDENTITY_SECRET, - "id": BOT_ID + "id": BOT_ID, } @@ -57,10 +57,10 @@ def user_dict(): "loccityid": 123, "gameid": "730", # game app id "gameextrainfo": "str", # game name - "timecreated": 123, - "lastlogoff": 123, - "last_logon": 123, - "last_seen_online": 123, + "timecreated": time() - 3600 * 24 * 12, + "lastlogoff": time() - 3600 * 24 * 2, + "last_logon": time() - 3600 * 12, + "last_seen_online": time() - 3600 * 1.5, } @@ -87,10 +87,10 @@ def client_user_dict(): "loccityid": 123, "gameid": "730", # game app id "gameextrainfo": "str", # game name - "timecreated": 123, - "lastlogoff": 123, - "last_logon": 123, - "last_seen_online": 123, + "timecreated": time() - 3600 * 24 * 12, + "lastlogoff": time() - 3600 * 24 * 2, + "last_logon": time() - 3600 * 12, + "last_seen_online": time() - 3600 * 1.5, } @@ -118,7 +118,7 @@ def trade_data(): "items_to_receive": [], "is_our_offer": True, "from_real_time_trade": False, - "confirmation_method": 1 # 2 is mobile 1 might be email? not a clue what other values are + "confirmation_method": 1, # 2 is mobile 1 might be email? not a clue what other values are } diff --git a/tests/mocks.py b/tests/mocks.py index 58b44a2..b451c69 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -11,11 +11,11 @@ async def send( - self: steam.User, - content=None, - *, - trade: steam.TradeOffer | None = None, - image: steam.Image | None = None, + self: steam.User, + content=None, + *, + trade: steam.TradeOffer | None = None, + image: steam.Image | None = None, ): trade._update_from_send(self._state, trade_data(), self, active=True) trade.state = steam.TradeOfferState.Active @@ -36,9 +36,11 @@ class WsMock: def __init__(self, state): self._connection = state - async def change_presence(self, *args, **kwargs): pass + async def change_presence(self, *args, **kwargs): + pass - async def handle_close(self): pass + async def handle_close(self): + pass async def login(self: steam.Client, username: str, password: str, *, shared_secret: str | None = None): diff --git a/tests/test_bot_exceptions.py b/tests/test_bot_exceptions.py index 8a7079e..cf2d24b 100644 --- a/tests/test_bot_exceptions.py +++ b/tests/test_bot_exceptions.py @@ -12,17 +12,20 @@ class TestBotExceptions: @pytest.fixture async def bot(self, event_loop): - bot_instance = ManagerBot(**{ - "username": BOT_USERNAME, - "password": BOT_PASSWORD, - "shared_secret": SHARED_SECRET, - "identity_secret": IDENTITY_SECRET, - }) + bot_instance = ManagerBot( + **{ + "username": BOT_USERNAME, + "password": BOT_PASSWORD, + "shared_secret": SHARED_SECRET, + "identity_secret": IDENTITY_SECRET, + } + ) bot_instance.loop = event_loop yield bot_instance - if not bot_instance.is_closed(): await bot_instance.close() + if not bot_instance.is_closed(): + await bot_instance.close() bot_instance.__del__() @pytest.mark.asyncio diff --git a/tests/test_constraints_mixin.py b/tests/test_constraints_mixin.py index 9bd8ebd..7071f65 100644 --- a/tests/test_constraints_mixin.py +++ b/tests/test_constraints_mixin.py @@ -10,7 +10,8 @@ class ConstraintsSubclass(ConstraintsMixin): constraints = ("arg1", ("arg2", "arg3")) dimension = "test_dimension" - def __init__(self, arg1, arg2, arg3): ... + def __init__(self, arg1, arg2, arg3): + ... return ConstraintsSubclass diff --git a/tests/test_manager.py b/tests/test_manager.py index 3c52a6d..9520291 100644 --- a/tests/test_manager.py +++ b/tests/test_manager.py @@ -10,13 +10,15 @@ class TestManager: @staticmethod def get_bot(index: int) -> ManagerBot: - return ManagerBot(**{ - "username": BOT_USERNAME + str(index), - "password": BOT_PASSWORD, - "shared_secret": SHARED_SECRET, - "identity_secret": IDENTITY_SECRET, - "id": BOT_ID + index - }) + return ManagerBot( + **{ + "username": BOT_USERNAME + str(index), + "password": BOT_PASSWORD, + "shared_secret": SHARED_SECRET, + "identity_secret": IDENTITY_SECRET, + "id": BOT_ID + index, + } + ) @pytest.fixture(scope="class") async def manager(self, event_loop): @@ -68,7 +70,7 @@ async def test_offer_create(self, manager): [item], ) await offer.send() - await asyncio.sleep(.01) # wait for dispatch to manager and add offer to trades + await asyncio.sleep(0.01) # wait for dispatch to manager and add offer to trades assert len(manager.trades) == 1 @@ -82,7 +84,7 @@ async def test_offer_create_from_url(self, manager): [item], ) await offer.send() - await asyncio.sleep(.01) # wait for dispatch to manager and add offer to trades + await asyncio.sleep(0.01) # wait for dispatch to manager and add offer to trades assert offer in manager.trades