From 68d9360ad6225e7f86a79139078cd641b519273a Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 16:52:17 -0400 Subject: [PATCH 01/29] Update documentation with new attributes and more attribute tables --- .readthedocs.yaml | 35 ++++++ brawlstats/models.py | 3 + docs/api.rst | 275 ++++++++++++++++++++++++------------------- requirements-dev.txt | 1 + 4 files changed, 191 insertions(+), 123 deletions(-) create mode 100644 .readthedocs.yaml diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..c079acf --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,35 @@ +# Read the Docs configuration file for Sphinx projects +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.5" + # You can also specify other tool versions: + # nodejs: "20" + # rust: "1.70" + # golang: "1.20" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/conf.py + # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs + # builder: "dirhtml" + # Fail on all warnings to avoid broken references + # fail_on_warning: true + +# Optionally build your docs in additional formats such as PDF and ePub +# formats: +# - pdf +# - epub + +# Optional but recommended, declare the Python requirements required +# to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +# python: +# install: +# - requirements: docs/requirements.txt \ No newline at end of file diff --git a/brawlstats/models.py b/brawlstats/models.py index 4669ed6..e906c3c 100644 --- a/brawlstats/models.py +++ b/brawlstats/models.py @@ -62,6 +62,9 @@ def __str__(self): def get_members(self) -> Members: """Gets the members of a club. + Note: It is preferred to get the members + via Club.members since this method makes + an extra API call but returns the same data. Returns ------- diff --git a/docs/api.rst b/docs/api.rst index 75ad25b..7da026d 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -42,12 +42,11 @@ Player A full player object (all its statistics) - Attributes: -============================================ ============= +============================================ ====================== Name Type -============================================ ============= +============================================ ====================== ``tag`` str ``name`` str ``name_color`` str @@ -58,16 +57,16 @@ Name Type ``exp_level`` int ``exp_points`` int ``is_qualified_from_championship_challenge`` bool -``x3vs3_victories`` int -``team_victories`` int +``x3vs3_victories`` / ``team_victories`` int ``solo_victories`` int ``duo_victories`` int ``best_robo_rumble_time`` int ``best_time_as_big_brawler`` int +``brawlers`` List[`PlayerBrawler`_] ``club.tag`` str ``club.name`` str -``brawlers`` List[Brawler] -============================================ ============= +``icon.id`` int +============================================ ====================== Club ~~~~ @@ -75,26 +74,27 @@ Club A full club object to get a club's statistics. In order to get this, you must get it from the client or a player object. - Attributes: -===================== ============ +===================== =============== Name Type -===================== ============ +===================== =============== ``tag`` str ``name`` str ``description`` str ``type`` str ``trophies`` int ``required_trophies`` int -``members`` List[Member] -===================== ============ +``members`` List[`Member`_] +``badge_id`` int +===================== =============== -Members -~~~~~~~ +Member +~~~~~~ -Returns a list of club members. Get this by accessing -Club.members or Club.get_members() +Members is a list of club members. Get this by accessing +``Club.members`` or ``Club.get_members()``. +Each Member in the list has the following attributes: .. code:: py @@ -111,14 +111,16 @@ Name Type ``name_color`` str ``role`` str ``trophies`` int +``icon.id`` int ============== ==== Ranking ~~~~~~~ -Returns a list of top players, clubs, or brawlers. To access this, do ``ranking[index]`` +A list of top players, clubs, or brawlers. +Each item in the list has the following attributes: -Player/Brawler attributes: +Player/Brawler Ranking attributes: ============== ==== Name Type @@ -129,9 +131,10 @@ Name Type ``trophies`` int ``rank`` int ``club.name`` str +``icon.id`` int ============== ==== -Club attributes: +Club Ranking attributes: ================ ==== Name Type @@ -141,36 +144,41 @@ Name Type ``trophies`` int ``rank`` int ``member_count`` int +``badge_id`` int ================ ==== -Brawler -~~~~~~~ +PlayerBrawler +~~~~~~~~~~~~~ -Returns a brawler object with the following attributes. You can retrieve -a profile’s brawler info by getting ``Profile.brawlers`` +PlayerBrawlers is a list of brawler objects, each with the following attributes. +The brawlers are sorted in order of descending trophies. +Note: ``PlayerBrawler`` only represents a brawler that a player owns and +can only be accessed from ``Player.brawlers``. .. code:: py - brawlers = profile.brawlers - top_brawler = brawlers[0] # first index in list = highest trophies - print(top_brawler.name, top_brawler.trophies) # prints best brawler's name and trophies + brawlers = player.brawlers + top_brawler = brawlers[0] # first index in list = highest trophies + print(top_brawler.name, top_brawler.trophies) # prints best brawler's name and trophies Attributes: -==================== ======== +==================== ================== Name Type -==================== ======== +==================== ================== ``id`` int ``name`` str ``power`` int ``rank`` int ``trophies`` int ``highest_trophies`` int -``star_powers`` List[SP] -==================== ======== +``star_powers`` List[`StarPower`_] +``gadgets`` List[`Gadget`_] +``gears`` List[`Gear`_] +==================== ================== -Star Power -~~~~~~~~~~ +StarPower +~~~~~~~~~ Attributes: @@ -181,105 +189,126 @@ Name Type ``name`` str ======== ==== -Battle Logs -~~~~~~~~~~~ +Gadget +~~~~~~ + +Attributes: + +======== ==== +Name Type +======== ==== +``id`` int +``name`` str +======== ==== + +Gear +~~~~ + +Attributes: + +========= ==== +Name Type +========= ==== +``id`` int +``name`` str +``level`` int +========= ==== + +BattleLog +~~~~~~~~~ -Returns a list of objects with this structure: +A BattleLog contains a list of items, each with the following attributes: Attributes: -:: - - { - "battleTime":"20190706T151526.000Z", - "event":{ - "id":15000126, - "mode":"duoShowdown", - "map":"Royal Runway" - }, - "battle":{ - "mode":"duoShowdown", - "type":"ranked", - "rank":1, - "trophyChange":9, - "teams":[ - [ - { - "tag":"#Y2QPGG", - "name":"Lex_YouTube", - "brawler":{ - "id":16000005, - "name":"SPIKE", - "power":10, - "trophies":495 - } - }, - { - "tag":"#8Q229LJY", - "name":"Brandon", - "brawler":{ - "id":16000003, - "name":"BROCK", - "power":10, - "trophies":495 - } - }, - { - "tag":"#29RGL0QJ0", - "name":"smallwhitepeen1", - "brawler":{ - "id":16000007, - "name":"JESSIE", - "power":7, - "trophies":486 - } - } - ], - [ - { - "tag":"#CYLVL8LY", - "name":"TST|ROYER™", - "brawler":{ - "id":16000019, - "name":"PENNY", - "power":8, - "trophies":541 - } - }, - { - "tag":"#8P2URCR0", - "name":"ANOTHER", - "brawler":{ - "id":16000023, - "name":"LEON", - "power":8, - "trophies":559 - } - }, - { - "tag":"#8LRY92QP", - "name":"Marshmello", - "brawler":{ - "id":16000021, - "name":"GENE", - "power":7, - "trophies":448 - } - } - ] - ] - } - } +=============== =============== +Name Type +=============== =============== +``battle_time`` str +``event`` `Event`_ +``battle`` List[`Battle`_] +=============== =============== + +Event +~~~~~ + +An object containing information about an event. + +Attributes: + +======== ==== +Name Type +======== ==== +``id`` int +``mode`` str +``map`` str +======== ==== + +Battle +~~~~~~ + +Each Battle object contains information about a battle. +Note: The ``star_player`` attribute may not exist for certain modes +that do not have a star player (e.g. showdown, duoShowdown). + +Attributes: + +==================== =========================== +Name Type +==================== =========================== +``mode`` str +``type`` str +``result`` str +``duration`` int +``trophy_change`` int +``star_player`` `BattlePlayer`_ +``teams`` List[List[`BattlePlayer`_]] +==================== =========================== + +BattlePlayer +~~~~~~~~~~~~ + +Represents a player who played in a battle. + +=========== ================ +Name Type +=========== ================ +``tag`` str +``name`` str +``brawler`` `BattleBrawler`_ +=========== ================ + +BattleBrawler +~~~~~~~~~~~~ + +Represents a brawler that was played in a battle. +Note: ``BattlerBrawler`` only reprents brawlers that were played in a battle +and can only be accessed from ``BattlePlayer.brawler``. + +============ ==== +Name Type +============ ==== +``id`` int +``name`` str +``power`` int +``trophies`` int +============ ==== Brawlers ~~~~~~~~ -Returns list of available brawlers and information about them with this structure: +Returns list of all brawlers in the game and information, +with each item having the following attributes. +Note: ``Brawlers`` only represents the brawler objects returned +from ``Client.get_brawlers()``. Attributes: -:: - - [ - Brawler - ] \ No newline at end of file +==================== ================== +Name Type +==================== ================== +``id`` int +``name`` str +``star_powers`` List[`StarPower`_] +``gadgets`` List[`Gadget`_] +==================== ================== diff --git a/requirements-dev.txt b/requirements-dev.txt index 8c67d40..e650ad3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,4 +4,5 @@ pluggy>=0.12.0,<1.0.0 pytest pytest-asyncio python-dotenv +sphinx tox-travis \ No newline at end of file From de14d5fa9e1e67824b4aceb9e60faa696652a59f Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 16:52:45 -0400 Subject: [PATCH 02/29] Fix a bug where the session being passed in wasn't actually being used --- brawlstats/core.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/brawlstats/core.py b/brawlstats/core.py index 607cc25..6fe6b26 100644 --- a/brawlstats/core.py +++ b/brawlstats/core.py @@ -31,8 +31,12 @@ class Client: Setting this to ``True`` makes the client async, by default False loop: asyncio.window_events._WindowsSelectorEventLoop, optional The event loop to use for asynchronous operations, by default None + If you are passing in an aiohttp session, using this will not work. + You must set it when initializing the session. connector: aiohttp.TCPConnector, optional Pass a TCPConnector into the client (aiohttp), by default None + If you are passing in an aiohttp session, using this will not work. + You must set it when initializing the session. debug: bool, optional Whether or not to log info for debugging, by default False prevent_ratelimit: bool, optional @@ -53,7 +57,7 @@ def __init__(self, token, session=None, timeout=30, is_async=False, **options): self.cache = TTLCache(3200 * 3, 60 * 3) # 3200 requests per minute # Session and request options - self.session = options.get('session') or ( + self.session = session or ( aiohttp.ClientSession(loop=self.loop, connector=self.connector) if self.is_async else requests.Session() ) self.timeout = timeout @@ -71,12 +75,12 @@ def __init__(self, token, session=None, timeout=30, is_async=False, **options): # Load brawlers for get_rankings if self.is_async: - self.loop.create_task(self.__ainit__()) + self.loop.create_task(self._ainit()) else: brawlers_info = self.get_brawlers() self.api.set_brawlers(brawlers_info) - async def __ainit__(self): + async def _ainit(self): """Task created to run `get_brawlers` asynchronously""" self.api.set_brawlers(await self.get_brawlers()) @@ -282,7 +286,7 @@ def get_rankings(self, *, ranking: str, region: str=None, limit: int=200, brawle ranking : str The type of ranking. Must be "players", "clubs", "brawlers". region : str, optional - The region to retrieve from. Must be a 2 letter country code, by default None + The region to retrieve from. Must be a 2 letter country code, 'global', or None: by default None limit : int, optional The number of top players or clubs to fetch, by default 200 brawler : Union[str, int], optional From 5e1ba0a864247486097cba0688279e300745e501 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 16:53:10 -0400 Subject: [PATCH 03/29] Fix a bug where the text wasn't being shown in the message of UnexpectedError --- brawlstats/errors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/brawlstats/errors.py b/brawlstats/errors.py index 8b3a26d..341234e 100644 --- a/brawlstats/errors.py +++ b/brawlstats/errors.py @@ -49,7 +49,7 @@ class UnexpectedError(RequestError): def __init__(self, url, code, text): self.code = code self.url = url - self.message = 'An unexpected error has occured.\n{text}' + self.message = 'An unexpected error has occured.\n{}'.format(text) super().__init__(self.code, self.message) From a8f8125a839ca8aef5eaa34daace1b5205dbdf35 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 16:57:41 -0400 Subject: [PATCH 04/29] update readthedocs python version to 3.6 --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index c079acf..87ea169 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,7 +8,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.5" + python: "3.6" # You can also specify other tool versions: # nodejs: "20" # rust: "1.70" From e89c487f67c7017c25fa20983e1e1505facf6e25 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 17:11:01 -0400 Subject: [PATCH 05/29] try to fix .readthedocs.yaml --- .readthedocs.yaml | 6 +++--- docs/api.rst | 2 +- docs/requirements.txt | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 docs/requirements.txt diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 87ea169..b640052 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -30,6 +30,6 @@ sphinx: # Optional but recommended, declare the Python requirements required # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html -# python: -# install: -# - requirements: docs/requirements.txt \ No newline at end of file +python: + install: + - requirements: docs/requirements.txt \ No newline at end of file diff --git a/docs/api.rst b/docs/api.rst index 7da026d..06ac7b0 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -279,7 +279,7 @@ Name Type =========== ================ BattleBrawler -~~~~~~~~~~~~ +~~~~~~~~~~~~~ Represents a brawler that was played in a battle. Note: ``BattlerBrawler`` only reprents brawlers that were played in a battle diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..2b28a47 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,2 @@ +-e . +sphinx \ No newline at end of file From 59f4bf6e23b73206dd6c41412041cf69d823d643 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 17:15:10 -0400 Subject: [PATCH 06/29] some more doc updates to make shorter codeblocks --- docs/api.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 06ac7b0..d2fe399 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -94,12 +94,14 @@ Member Members is a list of club members. Get this by accessing ``Club.members`` or ``Club.get_members()``. +The club's members are sorted in order of descending trophies. Each Member in the list has the following attributes: .. code:: py members = club.members - print(members[0].name, members[0].role) # prints best player's name and role (sorted by trophies) + # Prints club's best player's name and role + print(members[0].name, members[0].role) Attributes: @@ -158,8 +160,10 @@ can only be accessed from ``Player.brawlers``. .. code:: py brawlers = player.brawlers - top_brawler = brawlers[0] # first index in list = highest trophies - print(top_brawler.name, top_brawler.trophies) # prints best brawler's name and trophies + # List is sorted by descending trophies + top_brawler = brawlers[0] + # print the player's best brawler's name and trophies + print(top_brawler.name, top_brawler.trophies) Attributes: From a65476a213cb31d45a6eef832fd8d03a2e68d36f Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 17:18:57 -0400 Subject: [PATCH 07/29] note that discord example is outdated --- examples/discord_cog.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/discord_cog.py b/examples/discord_cog.py index 0045c12..786285a 100644 --- a/examples/discord_cog.py +++ b/examples/discord_cog.py @@ -1,3 +1,5 @@ +# NOTE: This discord example is outdated as Discord's Bot API has changed + import discord from discord.ext import commands From 8edfa85bdd35a901671fa036bf535ac0e3b10fa0 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 19:54:18 -0400 Subject: [PATCH 08/29] Drop support for Python 3.5, 3.6, 3.7, 3.8 --- .readthedocs.yaml | 2 +- CHANGELOG.md | 8 ++++++++ README.rst | 19 +++++++++---------- requirements-dev.txt | 2 +- tox.ini | 8 ++++++-- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index b640052..c58a27c 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,7 +8,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.6" + python: "3.9" # You can also specify other tool versions: # nodejs: "20" # rust: "1.70" diff --git a/CHANGELOG.md b/CHANGELOG.md index d8563a5..8515af8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Change Log All notable changes to this project will be documented in this file. +## [development] - 10/6/24 +### Fixed +- Client actually uses session passed into parameters now instead of creating a new one anyways +- `UnexpectedError` now properly shows the returned text in the message +### Removed +- No longer uses `asyncio.Lock` when prevent_ratelimit=True and is_async=True as that just imitates sync behavior +- Dropped support for Python 3.5, 3.6, 3.7, and 3.8. + ## [4.1.1] - 10/31/21 ### Fixed - Installation dependency issue with aiohttp diff --git a/README.rst b/README.rst index 8bfe38f..98ed88f 100644 --- a/README.rst +++ b/README.rst @@ -20,8 +20,8 @@ Brawl Stats :target: https://github.com/SharpBit/brawlstats/blob/master/LICENSE :alt: MIT License -- This library is a sync and async wrapper for the Brawl Stars API. -- Python 3.5.3 or later is required. +- This library is a sync and async Python wrapper for the Brawl Stars API. +- Python 3.9 or later is required. Features ~~~~~~~~ @@ -72,11 +72,11 @@ Contributing ~~~~~~~~~~~~ Special thanks to this project's contributors ❤️ -- `4JR`_ +- `erickang21`_ +- `fourjr`_ - `golbu`_ -- `kawaii banana`_ - `kjkui`_ -- `Kyber`_ +- `kyb3r`_ - `Papiersnipper`_ - `Pollen`_ - `OrangutanGaming`_ @@ -86,17 +86,16 @@ If you want to contribute, whether it be a bug fix or new feature, make sure to This project is no longer actively maintained. No new features will be added, only bugfixes and security fixes will be accepted. .. _create an issue: https://github.com/SharpBit/brawlstats/issues -.. _Read the Docs: https://brawlstats.rtfd.io/ +.. _Read the Docs: https://brawlstats.readthedocs.io/en/stable/ .. _examples folder: https://github.com/SharpBit/brawlstats/tree/master/examples .. _discord.py: https://github.com/rapptz/discord.py .. _contributing guidelines: https://github.com/SharpBit/brawlstats/blob/master/CONTRIBUTING.md -.. _4JR: https://github.com/fourjr +.. _erickang21: https://github.com/erickang21 +.. _fourjr: https://github.com/fourjr .. _OrangutanGaming: https://github.com/OrangutanGaming .. _Stitch: https://github.com/Soumil07 .. _kjkui: https://github.com/kjkui -.. _Kyber: https://github.com/kyb3r +.. _kyb3r: https://github.com/kyb3r .. _Papiersnipper: https://github.com/robinmahieu -.. _Pollen: https://github.com/pollen5 -.. _kawaii banana: https://github.com/bananaboy21 .. _golbu: https://github.com/0dminnimda diff --git a/requirements-dev.txt b/requirements-dev.txt index e650ad3..70363e3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,7 +2,7 @@ asynctest flake8 pluggy>=0.12.0,<1.0.0 pytest -pytest-asyncio +pytest-asyncio~=0.21.0 python-dotenv sphinx tox-travis \ No newline at end of file diff --git a/tox.ini b/tox.ini index 4e40de0..abfa141 100644 --- a/tox.ini +++ b/tox.ini @@ -4,10 +4,14 @@ exclude = .tox,__init__.py ignore = E252,E302,E731,W605 [tox] -envlist = py35,py36,py37,py38 +envlist = py310 + +[pytest] +filterwarnings = + ignore:"@coroutine" decorator is deprecated since Python 3.8, use "async def" instead:DeprecationWarning [testenv] -deps = -r{toxinidir}/requirements-dev.txt +deps = -Ur{toxinidir}/requirements-dev.txt commands = flake8 tests pytest From 54f76c0e0536a63522f2d03e507939e4f64ea46a Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 19:55:00 -0400 Subject: [PATCH 09/29] Remove prevent_ratelimit option for the client --- brawlstats/core.py | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/brawlstats/core.py b/brawlstats/core.py index a2650e1..f6fd1d2 100644 --- a/brawlstats/core.py +++ b/brawlstats/core.py @@ -2,7 +2,6 @@ import json import logging import sys -import time from typing import Union import aiohttp @@ -29,18 +28,16 @@ class Client: How long to wait in seconds before shutting down requests, by default 30 is_async: bool, optional Setting this to ``True`` makes the client async, by default False - loop: asyncio.window_events._WindowsSelectorEventLoop, optional - The event loop to use for asynchronous operations, by default None - If you are passing in an aiohttp session, using this will not work. - You must set it when initializing the session. - connector: aiohttp.TCPConnector, optional - Pass a TCPConnector into the client (aiohttp), by default None - If you are passing in an aiohttp session, using this will not work. - You must set it when initializing the session. + loop: asyncio.AbstractEventLoop, optional + The event loop to use for asynchronous operations, by default None. + If you are passing in an aiohttp session, using this will not work: + you must set it when initializing the session. + connector: aiohttp.BaseConnector, optional + Pass a Connector into the client (aiohttp), by default None + If you are passing in an aiohttp session, using this will not work: + you must set it when initializing the session. debug: bool, optional Whether or not to log info for debugging, by default False - prevent_ratelimit: bool, optional - Whether or not to wait between requests to prevent being ratelimited, by default False base_url: str, optional Sets a different base URL to make request to, by default None """ @@ -87,6 +84,18 @@ async def _ainit(self): def __repr__(self): return ''.format(self.is_async, self.timeout, self.debug) + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.close() + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_value, traceback): + self.close() + def close(self): return self.session.close() @@ -175,13 +184,7 @@ def _request(self, url, use_cache=True): async def _aget_model(self, url, model, use_cache=True, key=None): """Method to turn the response data into a Model class for the async client.""" - if self.prevent_ratelimit: - # Use self.lock if prevent_ratelimit=True - async with self.lock: - data = await self._arequest(url, use_cache) - await asyncio.sleep(0.1) - else: - data = await self._arequest(url) + data = await self._arequest(url) if model == Constants: if key: @@ -199,8 +202,6 @@ def _get_model(self, url, model, use_cache=True, key=None): return self._aget_model(url, model=model, use_cache=use_cache, key=key) data = self._request(url, use_cache) - if self.prevent_ratelimit: - time.sleep(0.1) if model == Constants: if key: From b51e29d7fc268c80407841ae91c85cc0f9ff2bb7 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 19:55:39 -0400 Subject: [PATCH 10/29] Properly tearDown in async tests and match ordering in blocking tests --- tests/test_async.py | 13 ++++--------- tests/test_blocking.py | 7 +++---- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/tests/test_async.py b/tests/test_async.py index 5edcf5d..18298e5 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -1,6 +1,5 @@ import os -import aiohttp import asynctest import brawlstats import pytest @@ -11,21 +10,20 @@ class TestAsyncClient(asynctest.TestCase): - use_default_loop = True PLAYER_TAG = '#V2LQY9UY' CLUB_TAG = '#UL0GCC8' async def setUp(self): - session = aiohttp.ClientSession(loop=self.loop) - self.client = brawlstats.Client( os.getenv('token'), base_url=os.getenv('base_url'), - is_async=True, - session=session + is_async=True ) + async def tearDown(self): + await self.client.close() + async def test_get_player(self): player = await self.client.get_player(self.PLAYER_TAG) self.assertIsInstance(player, brawlstats.Player) @@ -117,9 +115,6 @@ async def test_get_brawlers(self): brawlers = await self.client.get_brawlers() self.assertIsInstance(brawlers, brawlstats.Brawlers) - async def asyncTearDown(self): - await self.client.close() - if __name__ == '__main__': asynctest.main() diff --git a/tests/test_blocking.py b/tests/test_blocking.py index 869a9d9..ad1101d 100644 --- a/tests/test_blocking.py +++ b/tests/test_blocking.py @@ -13,12 +13,14 @@ class TestBlockingClient(unittest.TestCase): CLUB_TAG = '#UL0GCC8' def setUp(self): - self.client = brawlstats.Client( os.getenv('token'), base_url=os.getenv('base_url') ) + def tearDown(self): + self.client.close() + def test_get_player(self): player = self.client.get_player(self.PLAYER_TAG) self.assertIsInstance(player, brawlstats.Player) @@ -95,9 +97,6 @@ def test_get_brawlers(self): brawlers = self.client.get_brawlers() self.assertIsInstance(brawlers, brawlstats.Brawlers) - def tearDown(self): - self.client.close() - if __name__ == '__main__': unittest.main() From 92ae917f279653199c4266ed718eb86470863a9d Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 20:33:17 -0400 Subject: [PATCH 11/29] Fix bug with use_cache and change most .format() to f-strings to drop support for python 3.5 --- CHANGELOG.md | 1 + brawlstats/core.py | 32 ++++++++++++++++---------------- brawlstats/errors.py | 4 ++-- brawlstats/models.py | 16 ++++++++-------- brawlstats/utils.py | 2 +- examples/discord_cog.py | 6 +++--- 6 files changed, 31 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8515af8..a0f2e9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ### Fixed - Client actually uses session passed into parameters now instead of creating a new one anyways - `UnexpectedError` now properly shows the returned text in the message +- The `use_cache` parameter now works for `get_constants`, `get_brawlers`, and the async client. ### Removed - No longer uses `asyncio.Lock` when prevent_ratelimit=True and is_async=True as that just imitates sync behavior - Dropped support for Python 3.5, 3.6, 3.7, and 3.8. diff --git a/brawlstats/core.py b/brawlstats/core.py index f6fd1d2..0f255da 100644 --- a/brawlstats/core.py +++ b/brawlstats/core.py @@ -65,8 +65,8 @@ def __init__(self, token, session=None, timeout=30, is_async=False, **options): # Request/response headers self.headers = { - 'Authorization': 'Bearer {}'.format(token), - 'User-Agent': 'brawlstats/{0} (Python {1[0]}.{1[1]})'.format(self.api.VERSION, sys.version_info), + 'Authorization': f'Bearer {token}', + 'User-Agent': f'brawlstats/{self.api.VERSION} (Python {sys.version_info[0]}.{sys.version_info[1]})', 'Accept-Encoding': 'gzip' } @@ -82,7 +82,7 @@ async def _ainit(self): self.api.set_brawlers(await self.get_brawlers()) def __repr__(self): - return ''.format(self.is_async, self.timeout, self.debug) + return f'' def __enter__(self): return self @@ -133,7 +133,7 @@ def _resolve_cache(self, url): if not data: return None if self.debug: - log.debug('GET {} got result from cache.'.format(url)) + log.debug(f'GET {url} got result from cache.') return data async def _arequest(self, url, use_cache=True): @@ -161,7 +161,7 @@ async def _arequest(self, url, use_cache=True): def _request(self, url, use_cache=True): """Sync method to request a url.""" if self.is_async: - return self._arequest(url, use_cache) + return self._arequest(url, use_cache=use_cache) # Try and retrieve from cache if use_cache: @@ -184,14 +184,14 @@ def _request(self, url, use_cache=True): async def _aget_model(self, url, model, use_cache=True, key=None): """Method to turn the response data into a Model class for the async client.""" - data = await self._arequest(url) + data = await self._arequest(url, use_cache=use_cache) if model == Constants: if key: if data.get(key): return model(self, data.get(key)) else: - raise KeyError('No such Constants key "{}"'.format(key)) + raise KeyError(f'No such Constants key "{key}"') return model(self, data) @@ -208,7 +208,7 @@ def _get_model(self, url, model, use_cache=True, key=None): if data.get(key): return model(self, data.get(key)) else: - raise KeyError('No such Constants key "{}"'.format(key)) + raise KeyError(f'No such Constants key "{key}"') return model(self, data) @@ -229,7 +229,7 @@ def get_player(self, tag: bstag, use_cache=True) -> Player: Player A player object with all of its attributes. """ - url = '{}/{}'.format(self.api.PROFILE, tag) + url = f'{self.api.PROFILE}/{tag}' return self._get_model(url, model=Player, use_cache=use_cache) get_profile = get_player @@ -251,7 +251,7 @@ def get_battle_logs(self, tag: bstag, use_cache=True) -> BattleLog: BattleLog A player battle object with all of its attributes. """ - url = '{}/{}/battlelog'.format(self.api.PROFILE, tag) + url = f'{self.api.PROFILE}/{tag}/battlelog' return self._get_model(url, model=BattleLog, use_cache=use_cache) @typecasted @@ -271,7 +271,7 @@ def get_club(self, tag: bstag, use_cache=True) -> Club: Club A club object with all of its attributes. """ - url = '{}/{}'.format(self.api.CLUB, tag) + url = f'{self.api.CLUB}/{tag}' return self._get_model(url, model=Club, use_cache=use_cache) @typecasted @@ -291,7 +291,7 @@ def get_club_members(self, tag: bstag, use_cache=True) -> Members: Members A list of the members in a club. """ - url = '{}/{}/members'.format(self.api.CLUB, tag) + url = f'{self.api.CLUB}/{tag}/members' return self._get_model(url, model=Members, use_cache=use_cache) def get_rankings( @@ -348,9 +348,9 @@ def get_rankings( raise ValueError('Make sure limit is between 1 and 200.') # Construct URL - url = '{}/{}/{}?limit={}'.format(self.api.RANKINGS, region, ranking, limit) + url = f'{self.api.RANKINGS}/{region}/{ranking}?limit={limit}' if ranking == 'brawlers': - url = '{}/{}/{}/{}?limit={}'.format(self.api.RANKINGS, region, ranking, brawler, limit) + url = f'{self.api.RANKINGS}/{region}/{ranking}/{brawler}?limit={limit}' return self._get_model(url, model=Ranking, use_cache=use_cache) @@ -369,7 +369,7 @@ def get_constants(self, key: str=None, use_cache=True) -> Constants: Constants Data containing some Brawl Stars constants. """ - return self._get_model(self.api.CONSTANTS, model=Constants, key=key) + return self._get_model(self.api.CONSTANTS, model=Constants, key=key, use_cache=use_cache) def get_brawlers(self, use_cache=True) -> Brawlers: """Gets available brawlers and information about them. @@ -384,4 +384,4 @@ def get_brawlers(self, use_cache=True) -> Brawlers: Brawlers A list of available brawlers and information about them. """ - return self._get_model(self.api.BRAWLERS, model=Brawlers) + return self._get_model(self.api.BRAWLERS, model=Brawlers, use_cache=use_cache) diff --git a/brawlstats/errors.py b/brawlstats/errors.py index 341234e..f6f79fd 100644 --- a/brawlstats/errors.py +++ b/brawlstats/errors.py @@ -27,7 +27,7 @@ def __init__(self, code, **kwargs): self.reason = kwargs.pop('reason', None) self.invalid_chars = kwargs.pop('invalid_chars', []) if self.reason: - self.message += '\nReason: {}'.format(self.reason) + self.message += f'\nReason: {self.reason}' elif self.invalid_chars: self.message += 'Invalid characters: {}'.format(', '.join(self.invalid_chars)) super().__init__(self.code, self.message) @@ -49,7 +49,7 @@ class UnexpectedError(RequestError): def __init__(self, url, code, text): self.code = code self.url = url - self.message = 'An unexpected error has occured.\n{}'.format(text) + self.message = f'An unexpected error has occured.\n{text}' super().__init__(self.code, self.message) diff --git a/brawlstats/models.py b/brawlstats/models.py index e906c3c..ca4836e 100644 --- a/brawlstats/models.py +++ b/brawlstats/models.py @@ -28,7 +28,7 @@ def __getitem__(self, item): try: return self._boxed_data[item] except IndexError: - raise IndexError('No such index: {}'.format(item)) + raise IndexError(f'No such index: {item}') class BaseBoxList(BaseBox): @@ -48,17 +48,17 @@ def __init__(self, client, data): super().__init__(client, data['items']) def __repr__(self): - return ''.format(len(self)) + return f'' class Club(BaseBox): """A club object with all of its attributes.""" def __repr__(self): - return "".format(self) + return f"" def __str__(self): - return '{0.name} ({0.tag})'.format(self) + return f'{self.name} ({self.tag})' def get_members(self) -> Members: """Gets the members of a club. @@ -71,7 +71,7 @@ def get_members(self) -> Members: Members A list of the members in a club. """ - url = '{}/{}/members'.format(self.client.api.CLUB, bstag(self.tag)) + url = f'{self.client.api.CLUB}/{bstag(self.tag)}/members' return self.client._get_model(url, model=Members) @@ -83,10 +83,10 @@ def __init__(self, *args, **kwargs): self.team_victories = self.x3vs3_victories def __repr__(self): - return "".format(self) + return f"" def __str__(self): - return '{0.name} ({0.tag})'.format(self) + return f'{self.name} ({self.tag})' def get_club(self) -> Club: """Gets the player's club. @@ -103,7 +103,7 @@ async def wrapper(): return wrapper() return None - url = '{}/{}'.format(self.client.api.CLUB, bstag(self.club.tag)) + url = f'{self.client.api.CLUB}/{bstag(self.club.tag)}' return self.client._get_model(url, model=Club) diff --git a/brawlstats/utils.py b/brawlstats/utils.py index 710b7b6..31d133b 100644 --- a/brawlstats/utils.py +++ b/brawlstats/utils.py @@ -10,7 +10,7 @@ class API: def __init__(self, base_url, version=1): - self.BASE = base_url or 'https://api.brawlstars.com/v{}'.format(version) + self.BASE = base_url or f'https://api.brawlstars.com/v{version}' self.PROFILE = self.BASE + '/players' self.CLUB = self.BASE + '/clubs' self.RANKINGS = self.BASE + '/rankings' diff --git a/examples/discord_cog.py b/examples/discord_cog.py index 786285a..18732c1 100644 --- a/examples/discord_cog.py +++ b/examples/discord_cog.py @@ -19,10 +19,10 @@ async def profile(self, ctx, tag: str): try: player = await self.client.get_profile(tag) except brawlstats.RequestError as e: # catches all exceptions - return await ctx.send('```\n{}: {}\n```'.format(e.code, e.message)) # sends code and error message - em = discord.Embed(title='{0.name} ({0.tag})'.format(player)) + return await ctx.send(f'```\n{e.code}: {e.message}\n```') # sends code and error message + em = discord.Embed(title=f'{player.name} ({player.tag})') - em.description = 'Trophies: {}'.format(player.trophies) # you could make this better by using embed fields + em.description = f'Trophies: {player.trophies}' # you could make this better by using embed fields await ctx.send(embed=em) From a084729f7a1a194b51836e543ea9440fdccb8b85 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 21:00:43 -0400 Subject: [PATCH 12/29] Update docs and fix tox.ini to properly run flake8 on the whole repo --- docs/index.rst | 8 ++++++-- docs/logging.rst | 2 +- tox.ini | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 26f7121..66a61df 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -9,12 +9,16 @@ Welcome to Brawl Stats' documentation! :target: https://travis-ci.com/SharpBit/brawlstats :alt: Travis-CI build +.. image:: https://img.shields.io/pypi/pyversions/brawlstats.svg + :target: https://pypi.org/project/brawlstats/ + :alt: Supported Versions + .. image:: https://img.shields.io/github/license/SharpBit/brawlstats.svg :target: https://github.com/SharpBit/brawlstats/blob/master/LICENSE :alt: MIT License -- This library is a sync and async wrapper for the Brawl Stars API. -- Python 3.5.3 or later is required. +- This library is a sync and async Python wrapper for the Brawl Stars API. +- Python 3.9 or later is required. Features ~~~~~~~~ diff --git a/docs/logging.rst b/docs/logging.rst index 1e51730..d3cf275 100644 --- a/docs/logging.rst +++ b/docs/logging.rst @@ -42,7 +42,7 @@ stdout of your program. Currently, the following things are logged: -- ``DEBUG``: API Requests +- ``DEBUG``: API Requests, Cache Hits diff --git a/tox.ini b/tox.ini index abfa141..e32949d 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ filterwarnings = [testenv] deps = -Ur{toxinidir}/requirements-dev.txt commands = - flake8 tests + flake8 . pytest passenv = token From 7574957a91ff317ff9cdf0ee034b3c1137d5ba58 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 21:04:17 -0400 Subject: [PATCH 13/29] update license year and setup.py python version --- LICENSE | 2 +- setup.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/LICENSE b/LICENSE index 20164b3..502a58a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018-2020 SharpBit +Copyright (c) 2018-2024 SharpBit Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/setup.py b/setup.py index f7b62c8..261fadd 100644 --- a/setup.py +++ b/setup.py @@ -25,21 +25,21 @@ keywords=['brawl stars, brawlstats, supercell'], packages=find_packages(), install_requires=requirements, - python_requires='>=3.5.3', + python_requires='>=3.9.0', project_urls={ 'Source Code': 'https://github.com/SharpBit/brawlstats', 'Issue Tracker': 'https://github.com/SharpBit/brawlstats/issues', - 'Documentation': 'https://brawlstats.readthedocs.io/', + 'Documentation': 'https://brawlstats.readthedocs.io/en/stable', }, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Topic :: Games/Entertainment :: Real Time Strategy', 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'Natural Language :: English' ] ) From b894839c90ffe6defa93b802c802139c6fd70a98 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 21:37:31 -0400 Subject: [PATCH 14/29] Add `Client.get_event_rotation()` #94 --- brawlstats/core.py | 17 ++++++++++++++++- brawlstats/models.py | 7 ++++++- brawlstats/utils.py | 1 + docs/api.rst | 22 +++++++++++++++++++++- tests/test_async.py | 4 ++++ tests/test_blocking.py | 4 ++++ 6 files changed, 52 insertions(+), 3 deletions(-) diff --git a/brawlstats/core.py b/brawlstats/core.py index 0f255da..418907e 100644 --- a/brawlstats/core.py +++ b/brawlstats/core.py @@ -9,7 +9,7 @@ from cachetools import TTLCache from .errors import Forbidden, NotFoundError, RateLimitError, ServerError, UnexpectedError -from .models import BattleLog, Brawlers, Club, Constants, Members, Player, Ranking +from .models import BattleLog, Brawlers, Club, Constants, EventRotation, Members, Player, Ranking from .utils import API, bstag, typecasted log = logging.getLogger(__name__) @@ -385,3 +385,18 @@ def get_brawlers(self, use_cache=True) -> Brawlers: A list of available brawlers and information about them. """ return self._get_model(self.api.BRAWLERS, model=Brawlers, use_cache=use_cache) + + def get_event_rotation(self, use_cache=True) -> EventRotation: + """Gets the current events in rotation. + + Parameters + ---------- + use_cache : bool, optional + Whether to use the internal 3 minutes cache, by default True + + Returns + ------- + Events + A list of the current events in rotation. + """ + return self._get_model(self.api.EVENT_ROTATION, model=EventRotation, use_cache=use_cache) diff --git a/brawlstats/models.py b/brawlstats/models.py index ca4836e..32addbd 100644 --- a/brawlstats/models.py +++ b/brawlstats/models.py @@ -2,7 +2,7 @@ from .utils import bstag -__all__ = ['Player', 'Club', 'Members', 'Ranking', 'BattleLog', 'Constants', 'Brawlers'] +__all__ = ['Player', 'Club', 'Members', 'Ranking', 'BattleLog', 'Constants', 'Brawlers', 'EventRotation'] class BaseBox: @@ -134,3 +134,8 @@ class Brawlers(BaseBoxList): def __init__(self, client, data): super().__init__(client, data['items']) + + +class EventRotation(BaseBoxList): + """A list of events in the current rotation.""" + pass diff --git a/brawlstats/utils.py b/brawlstats/utils.py index 31d133b..184b488 100644 --- a/brawlstats/utils.py +++ b/brawlstats/utils.py @@ -16,6 +16,7 @@ def __init__(self, base_url, version=1): self.RANKINGS = self.BASE + '/rankings' self.CONSTANTS = 'https://fourjr.herokuapp.com/bs/constants' self.BRAWLERS = self.BASE + '/brawlers' + self.EVENT_ROTATION = self.BASE + '/events/rotation' # Get package version from __init__.py path = os.path.dirname(__file__) diff --git a/docs/api.rst b/docs/api.rst index d2fe399..a61cd4a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -31,6 +31,9 @@ Data Models .. autoclass:: brawlstats.models.Brawlers :members: +.. autoclass:: brawlstats.models.EventRotation + :members: + Attributes of Data Models ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -301,7 +304,7 @@ Name Type Brawlers ~~~~~~~~ -Returns list of all brawlers in the game and information, +Represents a list of all brawlers in the game and information, with each item having the following attributes. Note: ``Brawlers`` only represents the brawler objects returned from ``Client.get_brawlers()``. @@ -316,3 +319,20 @@ Name Type ``star_powers`` List[`StarPower`_] ``gadgets`` List[`Gadget`_] ==================== ================== + +EventRotation +~~~~~~~~~~~~~ + +Represents a list of events in the current rotation, +each with the following attributes: + +Attributes: + +============== ======== +Name Type +============== ======== +``start_time`` str +``end_time`` str +``slot_id`` int +``event`` `Event`_ +============== ======== \ No newline at end of file diff --git a/tests/test_async.py b/tests/test_async.py index 18298e5..f46c175 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -115,6 +115,10 @@ async def test_get_brawlers(self): brawlers = await self.client.get_brawlers() self.assertIsInstance(brawlers, brawlstats.Brawlers) + async def test_get_event_rotation(self): + events = await self.client.get_event_rotation() + self.assertIsInstance(events, brawlstats.EventRotation) + if __name__ == '__main__': asynctest.main() diff --git a/tests/test_blocking.py b/tests/test_blocking.py index ad1101d..b272d6a 100644 --- a/tests/test_blocking.py +++ b/tests/test_blocking.py @@ -97,6 +97,10 @@ def test_get_brawlers(self): brawlers = self.client.get_brawlers() self.assertIsInstance(brawlers, brawlstats.Brawlers) + def test_get_event_rotation(self): + events = self.client.get_event_rotation() + self.assertIsInstance(events, brawlstats.EventRotation) + if __name__ == '__main__': unittest.main() From 1a1bf30f47805bff8c4f5637638c84074285518e Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 21:50:09 -0400 Subject: [PATCH 15/29] Add `Player.get_battle_logs` #93 --- CHANGELOG.md | 3 +++ brawlstats/models.py | 25 ++++++++++++++++++------- tests/test_async.py | 3 +++ tests/test_blocking.py | 3 +++ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0f2e9a..c98b186 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ All notable changes to this project will be documented in this file. ## [development] - 10/6/24 +### Added +- Implemented an endpoint with `Client.get_event_rotation` which gets the events in the current rotation. +- Added a method `Player.get_battle_logs` which directly gets the player's battle log. ### Fixed - Client actually uses session passed into parameters now instead of creating a new one anyways - `UnexpectedError` now properly shows the returned text in the message diff --git a/brawlstats/models.py b/brawlstats/models.py index 32addbd..74c97b6 100644 --- a/brawlstats/models.py +++ b/brawlstats/models.py @@ -51,6 +51,13 @@ def __repr__(self): return f'' +class BattleLog(BaseBoxList): + """A player battle object with all of its attributes.""" + + def __init__(self, client, data): + super().__init__(client, data['items']) + + class Club(BaseBox): """A club object with all of its attributes.""" @@ -106,6 +113,17 @@ async def wrapper(): url = f'{self.client.api.CLUB}/{bstag(self.club.tag)}' return self.client._get_model(url, model=Club) + def get_battle_logs(self) -> BattleLog: + """Gets the player's battle logs. + + Returns + ------- + BattleLog + The battle log containing the player's most recent battles. + """ + url = f'{self.client.api.PROFILE}/{bstag(self.tag)}/battlelog' + return self.client._get_model(url, model=BattleLog) + class Ranking(BaseBoxList): """A player or club ranking that contains a list of players or clubs.""" @@ -117,13 +135,6 @@ def __repr__(self): return ''.format(len(self)) -class BattleLog(BaseBoxList): - """A player battle object with all of its attributes.""" - - def __init__(self, client, data): - super().__init__(client, data['items']) - - class Constants(BaseBox): """Data containing some Brawl Stars constants.""" pass diff --git a/tests/test_async.py b/tests/test_async.py index f46c175..744d315 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -33,6 +33,9 @@ async def test_get_player(self): self.assertIsInstance(club, brawlstats.Club) self.assertEqual(club.tag, self.CLUB_TAG) + battle_logs = await player.get_battle_logs() + self.assertIsInstance(battle_logs, brawlstats.BattleLog) + with self.assertRaises(brawlstats.NotFoundError): await self.client.get_player('2PPPPPPP') diff --git a/tests/test_blocking.py b/tests/test_blocking.py index b272d6a..757b3c4 100644 --- a/tests/test_blocking.py +++ b/tests/test_blocking.py @@ -30,6 +30,9 @@ def test_get_player(self): self.assertIsInstance(club, brawlstats.Club) self.assertEqual(club.tag, self.CLUB_TAG) + battle_logs = player.get_battle_logs() + self.assertIsInstance(battle_logs, brawlstats.BattleLog) + self.assertRaises(brawlstats.NotFoundError, self.client.get_player, '2PPPPPPP') self.assertRaises(brawlstats.NotFoundError, self.client.get_player, 'P') self.assertRaises(brawlstats.NotFoundError, self.client.get_player, 'AAA') From 4b021a082e9d44bba4d681e5c300a4a8bc801205 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 22:18:02 -0400 Subject: [PATCH 16/29] remove `Client.get_constants` --- CHANGELOG.md | 7 ++++--- README.rst | 3 ++- brawlstats/core.py | 35 +---------------------------------- brawlstats/models.py | 7 +------ brawlstats/utils.py | 1 - docs/api.rst | 3 --- docs/index.rst | 4 ++-- tests/test_async.py | 9 --------- tests/test_blocking.py | 9 --------- 9 files changed, 10 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c98b186..bb7a8b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,11 @@ All notable changes to this project will be documented in this file. ### Fixed - Client actually uses session passed into parameters now instead of creating a new one anyways - `UnexpectedError` now properly shows the returned text in the message -- The `use_cache` parameter now works for `get_constants`, `get_brawlers`, and the async client. +- The `use_cache` parameter now works for `get_brawlers` and the async client ### Removed -- No longer uses `asyncio.Lock` when prevent_ratelimit=True and is_async=True as that just imitates sync behavior -- Dropped support for Python 3.5, 3.6, 3.7, and 3.8. +- Removed the prevent_ratelimit option for the Client +- Dropped support for Python 3.5, 3.6, 3.7, and 3.8 +- Removed `Client.get_constants` as the site that was hosting it is no longer running ## [4.1.1] - 10/31/21 ### Fixed diff --git a/README.rst b/README.rst index 98ed88f..6b20ccc 100644 --- a/README.rst +++ b/README.rst @@ -31,7 +31,8 @@ Features - Get a player profile and battlelog. - Get a club and its members. - Get the top 200 rankings for players, clubs, or a specific brawler. -- Get information about maps, brawlers, and more! +- Get information about all the brawlers in the game. +- Get information about the current event rotation! Installation ~~~~~~~~~~~~ diff --git a/brawlstats/core.py b/brawlstats/core.py index 418907e..3f756cc 100644 --- a/brawlstats/core.py +++ b/brawlstats/core.py @@ -9,7 +9,7 @@ from cachetools import TTLCache from .errors import Forbidden, NotFoundError, RateLimitError, ServerError, UnexpectedError -from .models import BattleLog, Brawlers, Club, Constants, EventRotation, Members, Player, Ranking +from .models import BattleLog, Brawlers, Club, EventRotation, Members, Player, Ranking from .utils import API, bstag, typecasted log = logging.getLogger(__name__) @@ -185,14 +185,6 @@ def _request(self, url, use_cache=True): async def _aget_model(self, url, model, use_cache=True, key=None): """Method to turn the response data into a Model class for the async client.""" data = await self._arequest(url, use_cache=use_cache) - - if model == Constants: - if key: - if data.get(key): - return model(self, data.get(key)) - else: - raise KeyError(f'No such Constants key "{key}"') - return model(self, data) def _get_model(self, url, model, use_cache=True, key=None): @@ -202,14 +194,6 @@ def _get_model(self, url, model, use_cache=True, key=None): return self._aget_model(url, model=model, use_cache=use_cache, key=key) data = self._request(url, use_cache) - - if model == Constants: - if key: - if data.get(key): - return model(self, data.get(key)) - else: - raise KeyError(f'No such Constants key "{key}"') - return model(self, data) @typecasted @@ -354,23 +338,6 @@ def get_rankings( return self._get_model(url, model=Ranking, use_cache=use_cache) - def get_constants(self, key: str=None, use_cache=True) -> Constants: - """Gets Brawl Stars constants extracted from the app. - - Parameters - ---------- - key : str, optional - Any key to get specific data, by default None - use_cache : bool, optional - Whether to use the internal 3 minutes cache, by default True - - Returns - ------- - Constants - Data containing some Brawl Stars constants. - """ - return self._get_model(self.api.CONSTANTS, model=Constants, key=key, use_cache=use_cache) - def get_brawlers(self, use_cache=True) -> Brawlers: """Gets available brawlers and information about them. diff --git a/brawlstats/models.py b/brawlstats/models.py index 74c97b6..b04d021 100644 --- a/brawlstats/models.py +++ b/brawlstats/models.py @@ -2,7 +2,7 @@ from .utils import bstag -__all__ = ['Player', 'Club', 'Members', 'Ranking', 'BattleLog', 'Constants', 'Brawlers', 'EventRotation'] +__all__ = ['Player', 'Club', 'Members', 'Ranking', 'BattleLog', 'Brawlers', 'EventRotation'] class BaseBox: @@ -135,11 +135,6 @@ def __repr__(self): return ''.format(len(self)) -class Constants(BaseBox): - """Data containing some Brawl Stars constants.""" - pass - - class Brawlers(BaseBoxList): """A list of available brawlers and information about them.""" diff --git a/brawlstats/utils.py b/brawlstats/utils.py index 184b488..e042941 100644 --- a/brawlstats/utils.py +++ b/brawlstats/utils.py @@ -14,7 +14,6 @@ def __init__(self, base_url, version=1): self.PROFILE = self.BASE + '/players' self.CLUB = self.BASE + '/clubs' self.RANKINGS = self.BASE + '/rankings' - self.CONSTANTS = 'https://fourjr.herokuapp.com/bs/constants' self.BRAWLERS = self.BASE + '/brawlers' self.EVENT_ROTATION = self.BASE + '/events/rotation' diff --git a/docs/api.rst b/docs/api.rst index a61cd4a..c9ecaf9 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -25,9 +25,6 @@ Data Models .. autoclass:: brawlstats.models.Members :members: -.. autoclass:: brawlstats.models.Constants - :members: - .. autoclass:: brawlstats.models.Brawlers :members: diff --git a/docs/index.rst b/docs/index.rst index 66a61df..16ddaa5 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -28,8 +28,8 @@ Features - Get a player profile and battlelog. - Get a club and its members. - Get the top 200 rankings for players, clubs, or a specific brawler. -- Get information about maps and more! -- Get information about current available brawlers. +- Get information about all the brawlers in the game. +- Get information about the current event rotation! Installation ~~~~~~~~~~~~ diff --git a/tests/test_async.py b/tests/test_async.py index 744d315..ece42ea 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -105,15 +105,6 @@ async def test_get_rankings(self): with self.assertRaises(ValueError): await self.client.get_rankings(ranking='brawlers', brawler='SharpBit') - async def test_get_constants(self): - constants = await self.client.get_constants() - self.assertIsInstance(constants, brawlstats.Constants) - - maps = await self.client.get_constants('maps') - self.assertIsInstance(maps, brawlstats.Constants) - - await self.assertAsyncRaises(KeyError, self.client.get_constants('invalid')) - async def test_get_brawlers(self): brawlers = await self.client.get_brawlers() self.assertIsInstance(brawlers, brawlstats.Brawlers) diff --git a/tests/test_blocking.py b/tests/test_blocking.py index 757b3c4..cc3d0c8 100644 --- a/tests/test_blocking.py +++ b/tests/test_blocking.py @@ -87,15 +87,6 @@ def test_get_rankings(self): self.assertIsInstance(us_brawler_ranking, brawlstats.Ranking) self.assertTrue(len(us_brawler_ranking) == 1) - def test_get_constants(self): - constants = self.client.get_constants() - self.assertIsInstance(constants, brawlstats.Constants) - - maps = self.client.get_constants('maps') - self.assertIsInstance(maps, brawlstats.Constants) - - self.assertRaises(KeyError, self.client.get_constants, 'invalid') - def test_get_brawlers(self): brawlers = self.client.get_brawlers() self.assertIsInstance(brawlers, brawlstats.Brawlers) From 8b7ee41da22a35cfca7062847558bfc8f35c540a Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 22:27:41 -0400 Subject: [PATCH 17/29] Python package workflow --- .github/workflows/python-package.yml | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/python-package.yml diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 0000000..fcef0b5 --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,37 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python package + +on: + push: + branches: [ "master", "development" ] + pull_request: + branches: [ "master", "development" ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements-dev.txt + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + - name: Test with pytest + run: | + pytest From 7d598f629b3b46f57a4ba177e668bb3b158a6220 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 22:29:25 -0400 Subject: [PATCH 18/29] Install the package in the ci workflow --- .github/workflows/python-package.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index fcef0b5..a129ea4 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -28,6 +28,7 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install -r requirements-dev.txt + python -m pip install . - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names From 50c478b1754b2a95401da4383086139e2fbcd813 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 22:55:54 -0400 Subject: [PATCH 19/29] delete github workflow --- .github/workflows/python-package.yml | 38 ---------------------------- 1 file changed, 38 deletions(-) delete mode 100644 .github/workflows/python-package.yml diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml deleted file mode 100644 index a129ea4..0000000 --- a/.github/workflows/python-package.yml +++ /dev/null @@ -1,38 +0,0 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python - -name: Python package - -on: - push: - branches: [ "master", "development" ] - pull_request: - branches: [ "master", "development" ] - -jobs: - build: - - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: ["3.9", "3.10", "3.11", "3.12"] - - steps: - - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install -r requirements-dev.txt - python -m pip install . - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - - name: Test with pytest - run: | - pytest From 8aee1f1c82265e00c8d5b3f9739e47f25c382893 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 23:04:54 -0400 Subject: [PATCH 20/29] update travis envs --- .travis.yml | 15 ++++++--------- tox.ini | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index a4bdfa6..efc147d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,16 @@ language: python python: -- '3.5' -- '3.6' -matrix: - include: - - python: 3.7 - dist: xenial - sudo: true +- '3.9' +- '3.10' +- '3.11' +- '3.12' install: - pip install -r requirements-dev.txt - pip install . -before_script: flake8 -script: tox +script: + - tox notifications: email: diff --git a/tox.ini b/tox.ini index e32949d..2399253 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ exclude = .tox,__init__.py ignore = E252,E302,E731,W605 [tox] -envlist = py310 +envlist = py39, py310, py311, py312 [pytest] filterwarnings = From 025d099c3c98b99f23b810b6df34cd2288c6c544 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Sun, 6 Oct 2024 23:10:06 -0400 Subject: [PATCH 21/29] try using xenial for travis --- .travis.yml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index efc147d..6be8232 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,19 @@ language: python -python: -- '3.9' -- '3.10' -- '3.11' -- '3.12' +matrix: + include: + - python: 3.9 + dist: xenial + sudo: true + - python: 3.10 + dist: xenial + sudo: true + - python: 3.11 + dist: xenial + sudo: true + - python: 3.12 + dist: xenial + sudo: true install: - pip install -r requirements-dev.txt From 5c2d2bf8c9d7d392d40532c2b400b5391c7dfb94 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Mon, 7 Oct 2024 00:15:55 -0400 Subject: [PATCH 22/29] try using focal dist for travis --- .travis.yml | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6be8232..dbe2009 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,12 @@ +os: linux +dist: focal language: python -matrix: - include: - - python: 3.9 - dist: xenial - sudo: true - - python: 3.10 - dist: xenial - sudo: true - - python: 3.11 - dist: xenial - sudo: true - - python: 3.12 - dist: xenial - sudo: true +python: + - "3.9" + - "3.10" + - "3.11" + - "3.12" install: - pip install -r requirements-dev.txt From 3a7ba8fbdbe0a352dec20a7872902bdd4723ea02 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Mon, 7 Oct 2024 02:13:32 -0400 Subject: [PATCH 23/29] remove asynctest as a dependency since asyncio.coroutine is deprecated --- requirements-dev.txt | 2 -- tests/test_async.py | 19 ++++++++++++------- tests/test_blocking.py | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 70363e3..b633f3d 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,8 +1,6 @@ -asynctest flake8 pluggy>=0.12.0,<1.0.0 pytest pytest-asyncio~=0.21.0 python-dotenv -sphinx tox-travis \ No newline at end of file diff --git a/tests/test_async.py b/tests/test_async.py index ece42ea..fad05aa 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -1,27 +1,31 @@ import os +import unittest -import asynctest +import aiohttp import brawlstats import pytest + from dotenv import load_dotenv pytestmark = pytest.mark.asyncio load_dotenv() -class TestAsyncClient(asynctest.TestCase): +class TestAsyncClient(unittest.IsolatedAsyncioTestCase): PLAYER_TAG = '#V2LQY9UY' CLUB_TAG = '#UL0GCC8' - async def setUp(self): + async def asyncSetUp(self): + session = aiohttp.ClientSession(trust_env=True) self.client = brawlstats.Client( - os.getenv('token'), + token=os.getenv('token'), + session=session, base_url=os.getenv('base_url'), is_async=True ) - async def tearDown(self): + async def asyncTearDown(self): await self.client.close() async def test_get_player(self): @@ -72,7 +76,8 @@ async def test_get_club_members(self): self.assertIsInstance(club_members, brawlstats.Members) self.assertIn(self.PLAYER_TAG, [x.tag for x in club_members]) - await self.assertAsyncRaises(brawlstats.NotFoundError, self.client.get_club_members('8GGGGGGG')) + with self.assertRaises(brawlstats.NotFoundError): + await self.client.get_club_members('8GGGGGGG') async def test_get_rankings(self): player_ranking = await self.client.get_rankings(ranking='players') @@ -115,4 +120,4 @@ async def test_get_event_rotation(self): if __name__ == '__main__': - asynctest.main() + unittest.main() diff --git a/tests/test_blocking.py b/tests/test_blocking.py index cc3d0c8..76cb8f9 100644 --- a/tests/test_blocking.py +++ b/tests/test_blocking.py @@ -14,7 +14,7 @@ class TestBlockingClient(unittest.TestCase): def setUp(self): self.client = brawlstats.Client( - os.getenv('token'), + token=os.getenv('token'), base_url=os.getenv('base_url') ) From cb011af9d33bdc29779cd0877623f54e3e1e3214 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:08:25 -0400 Subject: [PATCH 24/29] try github workflows again since travis-ci costs money now... --- .github/workflows/python-package.yml | 41 ++++++++++++++++++++++++++++ tests/test_async.py | 4 +-- tests/test_blocking.py | 4 +-- tox.ini | 8 ++---- 4 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/python-package.yml diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 0000000..7e5aedc --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,41 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python package + +on: + push: + branches: [ "master", "development" ] + pull_request: + branches: [ "master", "development" ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements-dev.txt + python -m pip install . + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + - name: Test with pytest + env: + TOKEN: ${{ secrets.TOKEN }} + BASE_URL: ${{ secrets.BASE_URL }} + run: | + pytest \ No newline at end of file diff --git a/tests/test_async.py b/tests/test_async.py index fad05aa..9519275 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -19,9 +19,9 @@ class TestAsyncClient(unittest.IsolatedAsyncioTestCase): async def asyncSetUp(self): session = aiohttp.ClientSession(trust_env=True) self.client = brawlstats.Client( - token=os.getenv('token'), + token=os.getenv('TOKEN'), session=session, - base_url=os.getenv('base_url'), + base_url=os.getenv('BASE_URL'), is_async=True ) diff --git a/tests/test_blocking.py b/tests/test_blocking.py index 76cb8f9..d5b16c1 100644 --- a/tests/test_blocking.py +++ b/tests/test_blocking.py @@ -14,8 +14,8 @@ class TestBlockingClient(unittest.TestCase): def setUp(self): self.client = brawlstats.Client( - token=os.getenv('token'), - base_url=os.getenv('base_url') + token=os.getenv('TOKEN'), + base_url=os.getenv('BASE_URL') ) def tearDown(self): diff --git a/tox.ini b/tox.ini index 2399253..a179fd4 100644 --- a/tox.ini +++ b/tox.ini @@ -6,15 +6,11 @@ ignore = E252,E302,E731,W605 [tox] envlist = py39, py310, py311, py312 -[pytest] -filterwarnings = - ignore:"@coroutine" decorator is deprecated since Python 3.8, use "async def" instead:DeprecationWarning - [testenv] deps = -Ur{toxinidir}/requirements-dev.txt commands = flake8 . pytest passenv = - token - base_url \ No newline at end of file + TOKEN + BASE_URL \ No newline at end of file From 9ccfc287b46379b90071aa077fa6519836194dff Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:17:30 -0400 Subject: [PATCH 25/29] farewell travis, you will not be missed --- .env.example | 4 ++-- .travis.yml | 19 ------------------- setup.py | 2 +- 3 files changed, 3 insertions(+), 22 deletions(-) delete mode 100644 .travis.yml diff --git a/.env.example b/.env.example index cc5c18a..9317121 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,2 @@ -token = # Replace this with your API token -base_url = # Proxy server to handle requests to API due to IP limitations \ No newline at end of file +TOKEN = # Replace this with your API token +BASE_URL = # Proxy server to handle requests to API due to IP limitations \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index dbe2009..0000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -os: linux -dist: focal -language: python - -python: - - "3.9" - - "3.10" - - "3.11" - - "3.12" - -install: - - pip install -r requirements-dev.txt - - pip install . -script: - - tox - -notifications: - email: - - sharpbit3618@gmail.com \ No newline at end of file diff --git a/setup.py b/setup.py index 261fadd..b678b1b 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name='brawlstats', version=version, - description='An easy-to-use wrapper for the Brawl Stars API', + description='BrawlStats is an easy-to-use Python API wrapper for the Brawl Stars API', long_description=long_description, long_description_content_type='text/x-rst', url='https://github.com/SharpBit/brawlstats', From 2c4992e57d07bfa3ac3bf9c3711b17967fc05c35 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:49:12 -0400 Subject: [PATCH 26/29] update some descriptions and tags --- .github/workflows/{python-package.yml => tests.yml} | 2 +- CHANGELOG.md | 2 +- README.rst | 3 +-- docs/index.rst | 2 +- setup.py | 8 ++++++-- 5 files changed, 10 insertions(+), 7 deletions(-) rename .github/workflows/{python-package.yml => tests.yml} (98%) diff --git a/.github/workflows/python-package.yml b/.github/workflows/tests.yml similarity index 98% rename from .github/workflows/python-package.yml rename to .github/workflows/tests.yml index 7e5aedc..567f67e 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/tests.yml @@ -1,7 +1,7 @@ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python -name: Python package +name: tests on: push: diff --git a/CHANGELOG.md b/CHANGELOG.md index bb7a8b7..2bc17b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Change Log All notable changes to this project will be documented in this file. -## [development] - 10/6/24 +## [4.2.0] - 10/7/24 ### Added - Implemented an endpoint with `Client.get_event_rotation` which gets the events in the current rotation. - Added a method `Player.get_battle_logs` which directly gets the player's battle log. diff --git a/README.rst b/README.rst index 6b20ccc..31880ba 100644 --- a/README.rst +++ b/README.rst @@ -20,7 +20,7 @@ Brawl Stats :target: https://github.com/SharpBit/brawlstats/blob/master/LICENSE :alt: MIT License -- This library is a sync and async Python wrapper for the Brawl Stars API. +- BrawlStats is a sync and async Python API wrapper to fetch statistics from the official Brawl Stars API. - Python 3.9 or later is required. Features @@ -79,7 +79,6 @@ Special thanks to this project's contributors ❤️ - `kjkui`_ - `kyb3r`_ - `Papiersnipper`_ -- `Pollen`_ - `OrangutanGaming`_ - `Stitch`_ diff --git a/docs/index.rst b/docs/index.rst index 16ddaa5..8439a8f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -17,7 +17,7 @@ Welcome to Brawl Stats' documentation! :target: https://github.com/SharpBit/brawlstats/blob/master/LICENSE :alt: MIT License -- This library is a sync and async Python wrapper for the Brawl Stars API. +- BrawlStats is a sync and async Python API wrapper to fetch statistics from the official Brawl Stars API. - Python 3.9 or later is required. Features diff --git a/setup.py b/setup.py index b678b1b..f29c87e 100644 --- a/setup.py +++ b/setup.py @@ -15,14 +15,18 @@ setup( name='brawlstats', version=version, - description='BrawlStats is an easy-to-use Python API wrapper for the Brawl Stars API', + description='BrawlStats is an easy-to-use sync and async Python API wrapper' + 'to fetch statistics from the official Brawl Stars API', long_description=long_description, long_description_content_type='text/x-rst', url='https://github.com/SharpBit/brawlstats', author='SharpBit', author_email='sharpbit3618@gmail.com', license='MIT', - keywords=['brawl stars, brawlstats, supercell'], + keywords=[ + 'brawl stars, brawl stats, brawlstats, supercell, python, sync, async, ' + 'python wrapper, api wrapper, python api wrapper, python 3.9, python 3.10, python 3.11, python 3.12' + ], packages=find_packages(), install_requires=requirements, python_requires='>=3.9.0', From 72b463e787ccc303f2810f0ed40ab3f557f829f9 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:56:22 -0400 Subject: [PATCH 27/29] Add some badges --- README.rst | 10 +++++++--- docs/index.rst | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 31880ba..2c88e9f 100644 --- a/README.rst +++ b/README.rst @@ -8,9 +8,9 @@ Brawl Stats :target: https://pypi.org/project/brawlstats/ :alt: PyPi -.. image:: https://travis-ci.com/SharpBit/brawlstats.svg?branch=master - :target: https://travis-ci.com/SharpBit/brawlstats - :alt: Travis-CI build +.. image:: https://github.com/SharpBit/brawlstats/actions/workflows/tests.yml/badge.svg + :target: https://github.com/SharpBit/brawlstats/actions/workflows/tests.yml/badge.svg + :alt: GitHub Actions Tests .. image:: https://img.shields.io/pypi/pyversions/brawlstats.svg :target: https://pypi.org/project/brawlstats/ @@ -20,6 +20,10 @@ Brawl Stats :target: https://github.com/SharpBit/brawlstats/blob/master/LICENSE :alt: MIT License +.. image:: https://readthedocs.org/projects/brawlstats/badge/?version=stable + :target: https://brawlstats.readthedocs.io/en/stable/?badge=stable + :alt: Documentation Status + - BrawlStats is a sync and async Python API wrapper to fetch statistics from the official Brawl Stars API. - Python 3.9 or later is required. diff --git a/docs/index.rst b/docs/index.rst index 8439a8f..3e88eab 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,9 +5,9 @@ Welcome to Brawl Stats' documentation! :target: https://pypi.org/project/brawlstats/ :alt: PyPi -.. image:: https://travis-ci.com/SharpBit/brawlstats.svg?branch=master - :target: https://travis-ci.com/SharpBit/brawlstats - :alt: Travis-CI build +.. image:: https://github.com/SharpBit/brawlstats/actions/workflows/tests.yml/badge.svg + :target: https://github.com/SharpBit/brawlstats/actions/workflows/tests.yml/badge.svg + :alt: GitHub Actions Tests .. image:: https://img.shields.io/pypi/pyversions/brawlstats.svg :target: https://pypi.org/project/brawlstats/ @@ -17,6 +17,10 @@ Welcome to Brawl Stats' documentation! :target: https://github.com/SharpBit/brawlstats/blob/master/LICENSE :alt: MIT License +.. image:: https://readthedocs.org/projects/brawlstats/badge/?version=stable + :target: https://brawlstats.readthedocs.io/en/stable/?badge=stable + :alt: Documentation Status + - BrawlStats is a sync and async Python API wrapper to fetch statistics from the official Brawl Stars API. - Python 3.9 or later is required. From 7f2052b28f0160aeb7117ba47ceee11e9b166314 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Tue, 8 Oct 2024 02:09:17 -0400 Subject: [PATCH 28/29] Update version to 4.2.0 and fix github actions badge url --- README.rst | 2 +- brawlstats/__init__.py | 2 +- docs/index.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 2c88e9f..163085c 100644 --- a/README.rst +++ b/README.rst @@ -9,7 +9,7 @@ Brawl Stats :alt: PyPi .. image:: https://github.com/SharpBit/brawlstats/actions/workflows/tests.yml/badge.svg - :target: https://github.com/SharpBit/brawlstats/actions/workflows/tests.yml/badge.svg + :target: https://github.com/SharpBit/brawlstats/actions/workflows/tests.yml :alt: GitHub Actions Tests .. image:: https://img.shields.io/pypi/pyversions/brawlstats.svg diff --git a/brawlstats/__init__.py b/brawlstats/__init__.py index 7bad5be..ea66010 100644 --- a/brawlstats/__init__.py +++ b/brawlstats/__init__.py @@ -7,7 +7,7 @@ ############ -__version__ = 'v4.1.1' +__version__ = 'v4.2.0' __title__ = 'brawlstats' __license__ = 'MIT' __author__ = 'SharpBit' diff --git a/docs/index.rst b/docs/index.rst index 3e88eab..5c837ff 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,7 +6,7 @@ Welcome to Brawl Stats' documentation! :alt: PyPi .. image:: https://github.com/SharpBit/brawlstats/actions/workflows/tests.yml/badge.svg - :target: https://github.com/SharpBit/brawlstats/actions/workflows/tests.yml/badge.svg + :target: https://github.com/SharpBit/brawlstats/actions/workflows/tests.yml :alt: GitHub Actions Tests .. image:: https://img.shields.io/pypi/pyversions/brawlstats.svg From c519cbe458847c16145ff310e9dd0ed97a7c0448 Mon Sep 17 00:00:00 2001 From: SharpBit <31069084+SharpBit@users.noreply.github.com> Date: Tue, 8 Oct 2024 02:35:03 -0400 Subject: [PATCH 29/29] Update 4.2.0 date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bc17b6..68d8458 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Change Log All notable changes to this project will be documented in this file. -## [4.2.0] - 10/7/24 +## [4.2.0] - 10/8/24 ### Added - Implemented an endpoint with `Client.get_event_rotation` which gets the events in the current rotation. - Added a method `Player.get_battle_logs` which directly gets the player's battle log.