From 382064657a627a6cb4ebc1415e0e2cd25b9c7704 Mon Sep 17 00:00:00 2001 From: frissyn <62220201+frissyn@users.noreply.github.com> Date: Wed, 9 Mar 2022 02:33:57 +0000 Subject: [PATCH 01/12] :package:: add sub-packages to package list (critical fix) --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 749514c..41385d6 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ python_requires=">=3.8.0", zip_safe=False, - packages=["valorant"], + packages=["valorant", "valorant/local", "valorant/objects"], classifiers=[ "License :: OSI Approved :: MIT License", From f1c4838f45db56cb56a45c29f89ecc28cf9f21f3 Mon Sep 17 00:00:00 2001 From: frissyn <62220201+frissyn@users.noreply.github.com> Date: Thu, 10 Mar 2022 13:41:29 +0000 Subject: [PATCH 02/12] :sparkles:: add page iteration functionality to Client.get_leaderboard --- valorant/client.py | 13 +++++++++++-- valorant/objects/__init__.py | 3 ++- valorant/objects/ranked.py | 33 +++++++++++++++++++++++++++++---- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/valorant/client.py b/valorant/client.py index c2882c1..54c980a 100644 --- a/valorant/client.py +++ b/valorant/client.py @@ -13,6 +13,7 @@ ContentDTO, ContentItemDTO, LeaderboardDTO, + LeaderboardIterator, PlatformDataDTO, ) @@ -204,9 +205,17 @@ def get_game_modes(self) -> t.List[ContentItemDTO]: return self._content_if_cache().gameModes def get_leaderboard( - self, size: int = 100, page: int = 0, actID: t.Text = "" - ) -> LeaderboardDTO: + self, + size: int = 100, + page: int = 0, + pages: t.Optional[int] = None, + actID: t.Text = "", + ) -> t.Union[LeaderboardDTO, LeaderboardIterator]: actID = self.get_current_act().id if not actID else actID + + if pages: + return LeaderboardIterator(self.handle, pages=pages, size=size, actID=actID) + params = {"size": size, "startIndex": size * page} r = self.handle.call("GET", "leaderboard", params=params, actID=actID) diff --git a/valorant/objects/__init__.py b/valorant/objects/__init__.py index b433eaf..9796265 100644 --- a/valorant/objects/__init__.py +++ b/valorant/objects/__init__.py @@ -30,7 +30,7 @@ PlayerStatsDTO, ) -from .ranked import LeaderboardPlayerDTO, LeaderboardDTO +from .ranked import LeaderboardPlayerDTO, LeaderboardDTO, LeaderboardIterator __all__ = [ @@ -49,6 +49,7 @@ "KillDTO", "LeaderboardDTO", "LeaderboardPlayerDTO", + "LeaderboardIterator", "LocationDTO", "MatchDTO", "MatchInfoDTO", diff --git a/valorant/objects/ranked.py b/valorant/objects/ranked.py index 69a97f5..fd06255 100644 --- a/valorant/objects/ranked.py +++ b/valorant/objects/ranked.py @@ -1,8 +1,11 @@ +import json import typing as t from .content import ContentList from .dto import DTO +from ..caller import WebCaller + class LeaderboardPlayerDTO(DTO): puuid: str @@ -24,8 +27,30 @@ def __init__(self, obj): self.players = ContentList(LeaderboardPlayerDTO(p) for p in obj["players"]) - # self.players = ContentList() - # for p in obj["players"]: - # if obj.get("gameName"): - # self.players.append(LeaderboardPlayerDTO(p)) +class LeaderboardIterator: + def __init__(self, caller: WebCaller, pages: int = 1, **params): + self.handle = caller + self.kwargs = params + self.index, self.pages = 0, pages + + def __iter__(self): + return self + + def __next__(self) -> LeaderboardDTO: + if self.index >= self.pages: + raise StopIteration + else: + self.index += 1 + + payload = { + "actID": self.kwargs["actID"], + "params": { + "size": self.kwargs["size"], + "startIndex": (self.index - 1) * self.kwargs["size"], + }, + } + + data = self.handle.call("GET", "leaderboard", **payload) + + return LeaderboardDTO(data) From 624a93be420e429e86d62582982ab5deda45203b Mon Sep 17 00:00:00 2001 From: frissyn <62220201+frissyn@users.noreply.github.com> Date: Thu, 10 Mar 2022 16:44:44 +0000 Subject: [PATCH 03/12] :adhesive_bandage:: allow LeaderboardPlayerDTO to be anonymous (#32) --- valorant/objects/ranked.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/valorant/objects/ranked.py b/valorant/objects/ranked.py index fd06255..f147c40 100644 --- a/valorant/objects/ranked.py +++ b/valorant/objects/ranked.py @@ -1,4 +1,3 @@ -import json import typing as t from .content import ContentList @@ -8,13 +7,20 @@ class LeaderboardPlayerDTO(DTO): - puuid: str - gameName: str - tagLine: str + puuid: t.Optional[str] + gameName: t.Optional[str] + tagLine: t.Optional[str] leaderboardRank: int rankedRating: int numberOfWins: int + def __init__(self, obj): + super().__init__(obj) + + for name in ["gameName", "tagLine", "puuid"]: + if not obj.get(name): + self.__setattr__(name, None) + class LeaderboardDTO(DTO): shard: str From 344cb9acbd5e10b5ea1865e88e73fdc2f0688f63 Mon Sep 17 00:00:00 2001 From: frissyn <62220201+frissyn@users.noreply.github.com> Date: Fri, 11 Mar 2022 22:45:15 +0000 Subject: [PATCH 04/12] :adhesive_bandage:: build account req URL with route, not region (#34) --- valorant/caller.py | 5 ----- valorant/client.py | 6 +++--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/valorant/caller.py b/valorant/caller.py index 1312aa5..13852ab 100644 --- a/valorant/caller.py +++ b/valorant/caller.py @@ -45,11 +45,6 @@ def call( route: t.Optional[t.Text] = False, **kw, ) -> t.Mapping[str, t.Any]: - if ep not in list(self.eps.keys()): - raise ValueError - else: - pass - prefix = self.base.format(root=self.route if route else self.region) url = prefix + self.eps[ep].format(**kw) diff --git a/valorant/client.py b/valorant/client.py index 54c980a..fa579c1 100644 --- a/valorant/client.py +++ b/valorant/client.py @@ -293,9 +293,9 @@ def get_user(self, puuid: t.Text) -> t.Optional[AccountDTO]: """ try: - r = self.handle.call("GET", "puuid", puuid=puuid) + r = self.handle.call("GET", "puuid", route=True, puuid=puuid) except requests.exceptions.HTTPError as e: - if e.response.status_code == 400: + if e.response.status_code in [400, 404]: return None else: e.response.raise_for_status() @@ -303,7 +303,7 @@ def get_user(self, puuid: t.Text) -> t.Optional[AccountDTO]: return AccountDTO(r, self.handle) def get_user_by_name(self, name: t.Text) -> t.Optional[AccountDTO]: - """Gets a Riot Account by thier game name and tag line. Returns ``None`` if + """Gets a Riot Account by their game name and tag line. Returns ``None`` if user could not be found. :param name: From d89ca63166380fe778f085b066a3c4adc70666e6 Mon Sep 17 00:00:00 2001 From: frissyn <62220201+frissyn@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:27:23 +0000 Subject: [PATCH 05/12] :open_book:: updates to docstrings (spelling, links, etc.) --- valorant/client.py | 37 ++++++++++++++++++++++--------------- valorant/local/client.py | 12 +++++++++--- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/valorant/client.py b/valorant/client.py index fa579c1..54fe0e1 100644 --- a/valorant/client.py +++ b/valorant/client.py @@ -30,23 +30,27 @@ class Client(object): :type key: str :param locale: The region locale to use when making requests. This defaults to the system's - locale as determined by Python. (i.e ``locale.getdefaultlocale()``) If set to - ``None``, `localizedNames` will be included in response objects. + locale as determined by Python. + (i.e `locale.getdefaultlocale() `_) + If set to ``None``, :attr:`ContentItemDTO.localizedNames` will be included in + the response. :type locale: Optional[str] :param region: - The region to use when making requests. This defaults to `na`. Valid - regions include `na`, `eu`, `latam`, etc. + The region to use when making requests. This defaults to `na`. Valid regions + include `na`, `eu`, `latam`, etc. See :data:`Lex.REGIONS` for a complete list + of valid regions. :type region: Optional[str] :param route: - The region route to user when making requests. This defaults to `americas`. - Valid routes are `americas`, `asia`, and `europe`. + The region route to use when making requests for Riot Accounts. This defaults + to `americas`. Valid routes are `americas`, `asia`, `europe`, and `esports`. + See :data:`Lex.ROUTES` for a complete list of valid routes. :type route: Optional[str] :param load_content: - Whether to load and cache content data from VALORANT. Defaults to `True`. + Whether to load and cache content data from VALORANT upon initialization. + Defaults to `True`. :type load_content: bool - .. versionchanged: 1.0 - Renamed *reload* parameter to *load_content* + *Changed in version 1.0:* Renamed *reload* parameter to *load_content*. """ def __init__( @@ -79,12 +83,15 @@ def _content_if_cache(self) -> ContentDTO: def __getattribute__(self, name): return super(Client, self).__getattribute__(name) - def asset(self, **attributes: t.Mapping[t.Text, t.Any]) -> t.Optional[DTO]: + def asset( + self, **attributes: t.Mapping[t.Text, t.Any] + ) -> t.Optional[t.Union[ActDTO, ContentItemDTO]]: """Find an item in VALORANT content data matching all given attributes. - Returns ``None`` if item is not found. + Returns ``None`` if item is not found. This works because there are no + semantic distinctions between Content Items. For example, ``client.asset(name="Viper")`` would return a - :class:`ContentItemDTO ` denoting content data for Viper. + :class:`ContentItemDTO` denoting content data for Viper. .. note:: If content data is not cached, this function will make a request @@ -93,7 +100,7 @@ def asset(self, **attributes: t.Mapping[t.Text, t.Any]) -> t.Optional[DTO]: :param attributes: A mapping of keyword arguments to match for. :type attributes: Mapping[str, Any] - :rtype: Optional[DTO] + :rtype: Optional[Union[ActDTO, ContentItemDTO]] """ content = self._content_if_cache() @@ -106,7 +113,7 @@ def asset(self, **attributes: t.Mapping[t.Text, t.Any]) -> t.Optional[DTO]: return None def get_acts(self) -> t.List[ActDTO]: - """Get a :class:`ContentList` of :class:`ActDTO` objects from VALORANt. + """Get a :class:`ContentList` of :class:`ActDTO` objects from VALORANT. :rtype: ContentList[ActDTO] """ @@ -162,7 +169,7 @@ def get_content(self, cache: bool = True) -> ContentDTO: :param cache: If set to ``True``, the Client will cache the response data, and subsequent calls wills return the cache. Update this cache by calling - ``.get_content`` again with cache set to ``True``. + :func:`Client.get_content` again with cache set to ``True``. .. note:: The cache provided is stored in memory and will not persist across program diff --git a/valorant/local/client.py b/valorant/local/client.py index 5fc6155..5b72d3f 100644 --- a/valorant/local/client.py +++ b/valorant/local/client.py @@ -1,7 +1,6 @@ import os import ssl import json -import base64 import requests from ..lexicon import Lex @@ -9,8 +8,15 @@ class LocalClient(object): """Client for interacting with the local instance of the VALORANT application. - The game must be running for this class to function properly. Currently unstable, - support is coming soon. + This is called the `RCS API`. The game must be running for this class to function + properly. Currently unstable, complete support is coming soon. + + .. warning:: + While interacting with the RCS API is not + `explicitly disallowed `_, + please have some common sense. ``valorant.py`` is not liable for any punishment + you may recieve if you break Riot's Terms of Service. (`i.e. creating an Auto + Agent Selector`) :param region: The region to instance the client with. If this doesn't match the game's From 5a1a23d0a01356fccbf18f1d863f1a273d757d8d Mon Sep 17 00:00:00 2001 From: frissyn <62220201+frissyn@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:32:03 +0000 Subject: [PATCH 06/12] :wastebasket:: deprecate ClientCaller class (#35) --- valorant/caller.py | 15 --------------- valorant/lexicon.py | 8 -------- valorant/local/client.py | 4 ++-- 3 files changed, 2 insertions(+), 25 deletions(-) diff --git a/valorant/caller.py b/valorant/caller.py index 13852ab..04ae211 100644 --- a/valorant/caller.py +++ b/valorant/caller.py @@ -52,18 +52,3 @@ def call( r.raise_for_status() return r.json() - - -class ClientCaller(object): - def __init__(self, token: t.Text): - self.base = "https://pd.{code}.a.pvp.net/" - self.token = token - - self.sess = requests.Session() - self.sess.headers.update( - { - "Authorization": f"Bearer {token}", - "Content-Type": "application/json", - "X-Riot-Entitlements-JWT": "riot_entitlement", - } - ) diff --git a/valorant/lexicon.py b/valorant/lexicon.py index 05974d2..8cd284e 100644 --- a/valorant/lexicon.py +++ b/valorant/lexicon.py @@ -83,9 +83,6 @@ def __init__(self): """List of content data attribute names.""" ENDPOINTS = { - "client": { - "mmr": "mmr/v1/players/{playerID}/competitiveupdates", - }, "web": { "content": "val/content/v1/contents", "game-name": "riot/account/v1/accounts/by-riot-id/{name}/{tag}", @@ -101,11 +98,6 @@ def __init__(self): HEADERS = { "web": {"Accept-Charset": "application/x-www-form-urlencoded; charset=UTF-8"}, - "client": { - "Authorization": "Bearer {token}", - "Content-Type": "application/json", - "X-Riot-Entitlements-JWT": "riot_entitlement", - }, } """Default headers for the client and web API.""" diff --git a/valorant/local/client.py b/valorant/local/client.py index 5b72d3f..685d379 100644 --- a/valorant/local/client.py +++ b/valorant/local/client.py @@ -13,9 +13,9 @@ class LocalClient(object): .. warning:: While interacting with the RCS API is not - `explicitly disallowed `_, + `explicitly disallowed `_, please have some common sense. ``valorant.py`` is not liable for any punishment - you may recieve if you break Riot's Terms of Service. (`i.e. creating an Auto + you may recieve if you break Riot's Terms of Service. (`i.e. creating an Auto Agent Selector`) :param region: From 6fed0117f55c0b76ef1af64eedac2565d7379b04 Mon Sep 17 00:00:00 2001 From: frissyn <62220201+frissyn@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:38:10 +0000 Subject: [PATCH 07/12] :checkered_flag:: minor code optimizations (thanks to @IanMGF) --- valorant/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/valorant/client.py b/valorant/client.py index 54fe0e1..391e9f9 100644 --- a/valorant/client.py +++ b/valorant/client.py @@ -302,7 +302,7 @@ def get_user(self, puuid: t.Text) -> t.Optional[AccountDTO]: try: r = self.handle.call("GET", "puuid", route=True, puuid=puuid) except requests.exceptions.HTTPError as e: - if e.response.status_code in [400, 404]: + if e.response.status_code in (400, 404): return None else: e.response.raise_for_status() @@ -327,7 +327,7 @@ def get_user_by_name(self, name: t.Text) -> t.Optional[AccountDTO]: "GET", "game-name", route=True, name=vals[0], tag=vals[1] ) except requests.exceptions.HTTPError as e: - if e.response.status_code in [400, 404]: + if e.response.status_code in (400, 404): return None else: e.response.raise_for_status() From 2d32d7467a03f61e68eac28d22918e830909d7f7 Mon Sep 17 00:00:00 2001 From: frissyn <62220201+frissyn@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:50:53 +0000 Subject: [PATCH 08/12] :sparkles:: allow specification of account route --- valorant/client.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/valorant/client.py b/valorant/client.py index 391e9f9..1759e69 100644 --- a/valorant/client.py +++ b/valorant/client.py @@ -290,12 +290,18 @@ def get_sprays(self) -> t.List[ContentItemDTO]: """ return self._content_if_cache().sprays - def get_user(self, puuid: t.Text) -> t.Optional[AccountDTO]: + def get_user( + self, puuid: t.Text, route: t.Text = "americas" + ) -> t.Optional[AccountDTO]: """Get a Riot Account by their PUUID. Returns ``None`` if user could not be found. :param puuid: The PUUID of the account to retrieve. :type puuid: str + :param route: + Geographical route to get the account from. See :data:`Lex.ROUTES` for + a list of valid routes. Defaults `americas`. + :type route: str :rtype: Optional[AccountDTO] """ @@ -309,7 +315,9 @@ def get_user(self, puuid: t.Text) -> t.Optional[AccountDTO]: return AccountDTO(r, self.handle) - def get_user_by_name(self, name: t.Text) -> t.Optional[AccountDTO]: + def get_user_by_name( + self, name: t.Text, route: t.Text = "americas" + ) -> t.Optional[AccountDTO]: """Gets a Riot Account by their game name and tag line. Returns ``None`` if user could not be found. @@ -317,6 +325,10 @@ def get_user_by_name(self, name: t.Text) -> t.Optional[AccountDTO]: The account's full game name and tag line, split by a hastag. (i.e `frissyn#6969`) :type name: str + :param route: + Geographical route to get the account from. See :data:`Lex.ROUTES` for + a list of valid routes. Defaults `americas`. + :type route: str :rtype: Optional[AccountDTO] """ vals = name.split("#") From 2f0e55ec6e90ee3c6c587dc8e3e3bcfa23fef1b3 Mon Sep 17 00:00:00 2001 From: frissyn <62220201+frissyn@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:53:41 +0000 Subject: [PATCH 09/12] :wrench:: add custom assertion method --- tests/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/__init__.py b/tests/__init__.py index 3d11185..95a07e5 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -8,10 +8,16 @@ def setUp(self): KEY = os.environ["VALPY-KEY"] self.access_key = KEY - self.client = valorant.Client(KEY) + self.client = valorant.Client(KEY, locale=None, load_content=False) def tearDown(self): self.client.handle.sess.close() + def assertHasAttr(self, obj: object, attr: str): + exp = hasattr(obj, attr) + + if not exp: + self.fail(f"{obj.__class__} has no attribute '{attr}'.") + from .client import * From 82372a8583bc2dead3e202a4f545bea9f21d1e9d Mon Sep 17 00:00:00 2001 From: frissyn <62220201+frissyn@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:54:27 +0000 Subject: [PATCH 10/12] :wrench:: increase verbosity of test output --- tests/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/__main__.py b/tests/__main__.py index 93e33e9..6dfa3d1 100644 --- a/tests/__main__.py +++ b/tests/__main__.py @@ -1,4 +1,4 @@ import unittest if __name__ == "__main__": - unittest.main("tests", exit=False, warnings=None) + unittest.main("tests", exit=False, warnings=None, verbosity=5) From 8e58cb66ac9f930854873c030d9d3f87f201b448 Mon Sep 17 00:00:00 2001 From: frissyn <62220201+frissyn@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:55:20 +0000 Subject: [PATCH 11/12] :alembic:: create leaderboard tests, update test methods --- tests/client/__init__.py | 1 + tests/client/test_account.py | 18 +++++---------- tests/client/test_content.py | 29 +++++++++++------------- tests/client/test_ranked.py | 43 ++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 29 deletions(-) create mode 100644 tests/client/test_ranked.py diff --git a/tests/client/__init__.py b/tests/client/__init__.py index 6d798cc..34f43eb 100644 --- a/tests/client/__init__.py +++ b/tests/client/__init__.py @@ -1,2 +1,3 @@ from .test_account import TestAccount from .test_content import TestContent +from .test_ranked import TestRanked diff --git a/tests/client/test_account.py b/tests/client/test_account.py index 5086ea7..8a002cc 100644 --- a/tests/client/test_account.py +++ b/tests/client/test_account.py @@ -6,24 +6,16 @@ class TestAccount(BaseTest): def test_account(self): acc = self.client.get_user( - "B-_urbbPjxhSekDzdIS7fznZ6w82fss8PBd1OnOIiJ_7wNdRyj4cljexSBoGCESzJglohUbAM4H5kw" + "B-" + "_urbbPjxhSekDzdIS7fznZ6w82fss8PBd1OnOIiJ" + "_7wNdRyj4cljexSBoGCESzJglohUbAM4H5kw" ) - self.assertEqual(acc.gameName, "frissyn") + self.assertEqual(getattr(acc, "gameName", None), "frissyn") self.assertIsInstance(acc, valorant.AccountDTO) def test_account_by_name(self): acc = self.client.get_user_by_name("frissyn#6969") - self.assertEqual(acc.gameName, "frissyn") + self.assertEqual(getattr(acc, "gameName", None), "frissyn") self.assertIsInstance(acc, valorant.AccountDTO) - - def test_account_missing(self): - acc = self.client.get_user(".") - - self.assertIsNone(acc) - - def test_account_missing_by_name(self): - acc = self.client.get_user_by_name("missing#0000") - - self.assertIsNone(acc) diff --git a/tests/client/test_content.py b/tests/client/test_content.py index 60cabf4..ec954d4 100644 --- a/tests/client/test_content.py +++ b/tests/client/test_content.py @@ -4,24 +4,21 @@ class TestContent(BaseTest): - def test_content(self): - content = self.client.get_content(cache=True) + def setUp(self): + super().setUp() - self.assertIsInstance(content, valorant.ContentDTO) - self.assertEqual(content, self.client.content) + self.content = self.client.get_content(cache=True) - def test_asset(self): - assets = { - "gamemode": self.client.asset(assetName="BombGameMode"), - "agent": self.client.asset(name="Viper"), - "map": self.client.asset(id="7EAECC1B-4337-BBF6-6AB9-04B8F06B3319"), - } + def test_asset_1(self): + asset = self.client.asset(name="Neon") - self.assertEqual(assets["gamemode"].name, "Standard") - self.assertEqual(assets["agent"].name, "Viper") - self.assertEqual(assets["map"].name, "Ascent") + self.assertEqual(asset.name, "Neon") - def test_leaderboard(self): - lb = self.client.get_leaderboard(100) + def test_asset_2(self): + asset = self.client.asset(id="7EAECC1B-4337-BBF6-6AB9-04B8F06B3319") - self.assertIsInstance(lb, valorant.LeaderboardDTO) + self.assertEqual(asset.name, "Ascent") + + def test_content_attributes(self): + for name in valorant.Lex.CONTENT_NAMES: + self.assertHasAttr(self.content, name) diff --git a/tests/client/test_ranked.py b/tests/client/test_ranked.py new file mode 100644 index 0000000..e1ab3ed --- /dev/null +++ b/tests/client/test_ranked.py @@ -0,0 +1,43 @@ +import valorant + +from tests import BaseTest + + +class TestRanked(BaseTest): + def setUp(self): + super().setUp() + + self.lb = self.client.get_leaderboard(10) + self.iterator = self.client.get_leaderboard(pages=3, size=10) + + def test_leaderboard_attributes(self): + for name in [ + "actId", + "players", + "totalPlayers", + "startIndex", + "query", + "shard", + ]: + self.assertHasAttr(self.lb, name) + + def test_leaderboard_players(self): + lb = self.client.get_leaderboard(10) + + for player in lb.players: + for name in [ + "gameName", + "leaderboardRank", + "numberOfWins", + "puuid", + "rankedRating", + "tagLine", + ]: + self.assertHasAttr(player, name) + + def test_leaderboard_iteration(self): + for i in range(self.iterator.pages): + next(self.iterator) + + with self.assertRaises(StopIteration): + next(self.iterator) From 7f74895248be5071ce185f4804aa3856e594c64f Mon Sep 17 00:00:00 2001 From: frissyn <62220201+frissyn@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:58:58 +0000 Subject: [PATCH 12/12] :pushpin:: working version, 1.0.2-dev --- valorant/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/valorant/__init__.py b/valorant/__init__.py index 254d553..0cc88d9 100644 --- a/valorant/__init__.py +++ b/valorant/__init__.py @@ -19,7 +19,7 @@ class Version(t.NamedTuple): release: t.Literal["alpha", "beta", "dev"] -version_info = Version(major=1, minor=0, micro=1, release="") +version_info = Version(major=1, minor=0, micro=2, release="dev") if not version_info.release: tag = ""