Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: artist tracks endpoint, array url param #233

Merged
merged 2 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions aiosu/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

__all__ = (
"add_param",
"add_range",
"append_param",
"from_list",
)
Expand Down Expand Up @@ -90,3 +91,31 @@ def add_param(

params[param_name or key] = value
return True


def add_range(
params: MutableMapping[str, Any],
kwargs: Mapping[str, object],
key: str,
param_name: Optional[str] = None,
) -> None:
r"""Adds a range parameter to a dictionary if it exists in kwargs.

:param params: Dictionary to add parameter to
:type params: Mapping[str, Any]
:param kwargs: Dictionary to get parameter from
:type kwargs: Mapping[str, Any]
:param key: Key to get parameter from
:type key: str
:param param_name: Name of parameter to add to dictionary, defaults to None
:type param_name: Optional[str]
"""
if key not in kwargs:
return

value = kwargs[key]
if not isinstance(value, (tuple, list)) or len(value) != 2:
raise ValueError("Range parameter must be a tuple of length 2.")

params[f"{param_name}[gte]"] = value[0]
params[f"{param_name}[lte]"] = value[1]
4 changes: 2 additions & 2 deletions aiosu/models/artist.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
"Artist",
"ArtistAlbum",
"ArtistLabel",
"ArtistResponse",
"ArtistSearch",
"ArtistSortType",
"ArtistTrack",
"ArtistTracksResponse",
)

ArtistSortType = Literal[
Expand Down Expand Up @@ -116,7 +116,7 @@ class ArtistTrack(BaseModel):
version: Optional[str] = None


class ArtistResponse(CursorModel):
class ArtistTracksResponse(CursorModel):
"""Artist response model."""

artist_tracks: list[ArtistTrack]
Expand Down
35 changes: 16 additions & 19 deletions aiosu/v2/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@
from ..exceptions import APIException
from ..exceptions import RefreshTokenExpiredError
from ..helpers import add_param
from ..helpers import add_range
from ..helpers import append_param
from ..helpers import from_list
from ..models import ArtistResponse
from ..models import ArtistTracksResponse
from ..models import Beatmap
from ..models import BeatmapDifficultyAttributes
from ..models import BeatmapPack
Expand Down Expand Up @@ -345,7 +346,6 @@ async def _request(
async with self._session.request(request_type, *args, **kwargs) as resp:
if resp.status == 204:
return

body = await resp.read()
content_type = get_content_type(resp.headers.get("content-type", ""))
if resp.status != 200:
Expand Down Expand Up @@ -408,24 +408,22 @@ async def _refresh(self) -> None:
)

@prepare_token
async def get_featured_artists(self, **kwargs: Any) -> ArtistResponse:
r"""Gets the current featured artists.
async def get_featured_tracks(self, **kwargs: Any) -> ArtistTracksResponse:
r"""Query tracks from featured artists.

:param \**kwargs:
See below

:Keyword Arguments:
* *limit* (``int``) --
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does not do anything

Optional, the number of featured artists to return.
* *album* (``str``) --
Optional, the album to filter by.
* *artist* (``str``) --
Optional, the artist to filter by.
* *genre* (``int``) --
Optional, the genre ID to filter by.
* *length* (``list[int]``) --
* *length* (``tuple[int, int]``) --
Optional, the length range to filter by.
* *bpm* (``list[int]``) --
* *bpm* (``tuple[int, int]``) --
Optional, The BPM range to filter by.
* *query* (``str``) --
Optional, the search query to filter by.
Expand All @@ -435,26 +433,25 @@ async def get_featured_artists(self, **kwargs: Any) -> ArtistResponse:
Optional, the sort to use.

:raises APIException: Contains status code and error message
:return: Featured artist response object
:rtype: aiosu.models.artist.ArtistResponse
:return: Featured artist tracks response object
:rtype: aiosu.models.artist.ArtistTracksResponse
"""
url = f"{self.base_url}/beatmaps/artists/tracks"
params: dict[str, object] = {}
add_param(params, kwargs, key="limit")
add_param(params, kwargs, key="album")
add_param(params, kwargs, key="artist")
add_param(params, kwargs, key="genre")
add_param(params, kwargs, key="length")
add_param(params, kwargs, key="bpm")
add_range(params, kwargs, key="length")
add_range(params, kwargs, key="bpm")
add_param(params, kwargs, key="query")
add_param(params, kwargs, key="is_default_sort", converter=to_lower_str)
add_param(params, kwargs, key="sort")
add_param(params, kwargs, key="cursor_string")
json = await self._request("GET", url)
resp = ArtistResponse.model_validate(json)
json = await self._request("GET", url, params=params)
resp = ArtistTracksResponse.model_validate(json)
if resp.cursor_string:
kwargs["cursor_string"] = resp.cursor_string
resp.next = partial(self.get_featured_artists, **kwargs)
resp.next = partial(self.get_featured_tracks, **kwargs)
return resp

@prepare_token
Expand Down Expand Up @@ -824,7 +821,7 @@ async def get_users(self, user_ids: list[int]) -> list[User]:
"""
url = f"{self.base_url}/api/v2/users"
params: dict[str, object] = {
"ids": user_ids,
"ids[]": user_ids,
}
json = await self._request("GET", url, params=params)
return from_list(User.model_validate, json.get("users", []))
Expand Down Expand Up @@ -1688,7 +1685,7 @@ async def get_beatmapset_discussion_posts(
add_param(params, kwargs, key="limit")
add_param(params, kwargs, key="page")
add_param(params, kwargs, key="sort")
add_param(params, kwargs, key="types")
add_param(params, kwargs, key="types[]")
add_param(params, kwargs, key="user", param_name="user_id")
add_param(params, kwargs, key="with_deleted", converter=to_lower_str)
add_param(params, kwargs, key="cursor_string")
Expand Down Expand Up @@ -2254,7 +2251,7 @@ async def create_chat_channel(
Required if type is ``ANNOUNCE``, the message to send in the PM
* *target_id* (``int``) --
Only used if if type is ``PM``, the ID of the user to send a PM to
* *target_ids* (``List[int]``) --
* *target_ids* (``list[int]``) --
Only used if type is ``ANNOUNCE``, the IDs of the users to send a PM to
* *channel_name* (``str``) --
Only used if type is ``ANNOUNCE``, the name of the channel
Expand Down
2 changes: 1 addition & 1 deletion tests/test_v2/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ async def test_generated(status_code, content_type, token, mocker):


tests = [
generate_test(aiosu.v2.Client.get_featured_artists, STATUS_CAN_200),
generate_test(aiosu.v2.Client.get_featured_tracks, STATUS_CAN_200),
generate_test(aiosu.v2.Client.get_seasonal_backgrounds, STATUS_CAN_200),
generate_test(aiosu.v2.Client.get_changelog_listing, STATUS_CAN_200),
generate_test(
Expand Down