Skip to content

Commit

Permalink
feat: change score models, add legacy_only, update tests
Browse files Browse the repository at this point in the history
  • Loading branch information
NiceAesth committed Feb 29, 2024
1 parent 9b2429c commit 2a958b7
Show file tree
Hide file tree
Showing 61 changed files with 149 additions and 99 deletions.
2 changes: 1 addition & 1 deletion aiosu/models/beatmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ class BeatmapsetEvent(BaseModel):
type: BeatmapsetEventType
r"""Information on types: https://github.com/ppy/osu-web/blob/master/resources/js/interfaces/beatmapset-event-json.ts"""
created_at: datetime
user_id: int
user_id: Optional[int] = None
beatmapset: Optional[Beatmapset] = None
discussion: Optional[BeatmapsetDiscussion] = None
comment: Optional[dict] = None
Expand Down
1 change: 1 addition & 0 deletions aiosu/models/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"score_taiko",
"score_fruits",
"score_mania",
"legacy_match_score",
]
BeatmapScoreboardType = Literal["global", "country", "friend"]

Expand Down
39 changes: 27 additions & 12 deletions aiosu/models/lazer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .common import CurrentUserAttributes
from .common import ScoreType
from .gamemode import Gamemode
from .mods import Mods
from .score import ScoreWeight
from .user import User

Expand Down Expand Up @@ -128,32 +129,41 @@ class LazerReplayData(BaseModel):


class LazerScore(BaseModel):
id: int
accuracy: float
beatmap_id: int
ended_at: datetime
has_replay: bool = Field(validation_alias="replay")
is_perfect_combo: bool
legacy_perfect: bool
max_combo: int
maximum_statistics: LazerScoreStatistics
mods: list[LazerMod]
passed: bool
rank: str
ruleset_id: int
ended_at: datetime
statistics: LazerScoreStatistics
total_score: int
user_id: int
has_replay: bool
total_score: int = Field(alias="score")
type: ScoreType
current_user_attributes: CurrentUserAttributes
beatmap: Beatmap
beatmapset: Beatmapset
user: User
user_id: int
beatmap: Optional[Beatmap] = None
beatmapset: Optional[Beatmapset] = None
best_id: Optional[int] = None
build_id: Optional[int] = None
current_user_attributes: Optional[CurrentUserAttributes] = None
id: Optional[int] = None
match: Optional[MultiplayerMatch] = None
preserved: Optional[bool] = None
position: Optional[int] = None
ranked: Optional[bool] = None
rank_country: Optional[int] = None
rank_global: Optional[int] = None
legacy_score_id: Optional[int] = None
legacy_total_score: Optional[int] = None
started_at: Optional[datetime] = None
best_id: Optional[int] = None
legacy_perfect: Optional[bool] = None
playlist_item_id: Optional[int] = None
pp: Optional[float] = None
room_id: Optional[int] = None
started_at: Optional[datetime] = None
user: Optional[User] = None
weight: Optional[ScoreWeight] = None

@property
Expand Down Expand Up @@ -231,3 +241,8 @@ def _fail_rank(cls, values: dict[str, object]) -> dict[str, object]:
if not values["passed"]:
values["rank"] = "F"
return values


from .multiplayer import MultiplayerMatch

LazerScore.model_rebuild()
28 changes: 5 additions & 23 deletions aiosu/models/multiplayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
from .common import CursorModel
from .gamemode import Gamemode
from .lazer import LazerMod
from .lazer import LazerScoreStatistics
from .lazer import LazerScore
from .mods import Mods
from .score import Score
from .user import User

__all__ = (
Expand All @@ -37,7 +38,6 @@
"MultiplayerRoomGroupType",
"MultiplayerRoomMode",
"MultiplayerRoomsResponse",
"MultiplayerScore",
"MultiplayerScoreSortType",
"MultiplayerScoresAround",
"MultiplayerScoresResponse",
Expand Down Expand Up @@ -74,27 +74,9 @@ class MultiplayerScoresAround(BaseModel):
lower: MultiplayerScoresResponse


class MultiplayerScore(BaseModel):
user_id: int
rank: str
accuracy: float
max_combo: int
mods: list[Union[Mods, LazerMod]]
passed: bool
statistics: LazerScoreStatistics
id: Optional[int] = None
room_id: Optional[int] = None
user: Optional[User] = None
beatmap_id: Optional[int] = None
playlist_item_id: Optional[int] = None
position: Optional[int] = None
total_score: Optional[int] = None
scores_around: Optional[MultiplayerScoresAround] = None


class MultiplayerScoresResponse(CursorModel):
scores: list[MultiplayerScore]
user_score: Optional[MultiplayerScore] = None
scores: list[LazerScore]
user_score: Optional[LazerScore] = None
total: Optional[int] = None


Expand All @@ -113,7 +95,7 @@ class MultiplayerGame(BaseModel):
team_type: MultiplayerTeamType
mods: list[Union[Mods, LazerMod]]
beatmap_id: int
scores: list[MultiplayerScore]
scores: list[Score]
beatmap: Optional[Beatmap] = None
end_time: Optional[datetime] = None

Expand Down
42 changes: 35 additions & 7 deletions aiosu/v2/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,8 @@ async def __get_type_scores(
Optional, whether to include failed scores, defaults to ``False``
* *new_format* (``bool``) --
Optional, whether to use the new format, defaults to ``False``
* *legacy_only* (``bool``) --
Optional, whether to only get legacy scores, defaults to ``False``
:raises ValueError: If limit is not between 1 and 100
:raises ValueError: If type is invalid
Expand All @@ -908,6 +910,7 @@ async def __get_type_scores(
"offset": kwargs.pop("offset", 0),
}
add_param(params, kwargs, key="mode", converter=lambda x: str(Gamemode(x)))
add_param(params, kwargs, key="legacy_only", converter=int)
headers = {}
new_format = kwargs.pop("new_format", False)
if new_format:
Expand Down Expand Up @@ -1056,6 +1059,8 @@ async def get_user_beatmap_scores(
:Keyword Arguments:
* *mode* (``aiosu.models.gamemode.Gamemode``) --
Optional, gamemode to search for
* *legacy_only* (``bool``) --
Optional, whether to only get legacy scores, defaults to ``False``
:raises APIException: Contains status code and error message
:raises RefreshTokenExpiredError: If the client refresh token has expired
Expand All @@ -1065,6 +1070,7 @@ async def get_user_beatmap_scores(
url = f"{self.base_url}/api/v2/beatmaps/{beatmap_id}/scores/users/{user_id}/all"
params: dict[str, object] = {}
add_param(params, kwargs, key="mode", converter=lambda x: str(Gamemode(x)))
add_param(params, kwargs, key="legacy_only", converter=int)
json = await self._request("GET", url, params=params)
return from_list(Score.model_validate, json.get("scores", []))

Expand Down Expand Up @@ -1197,14 +1203,14 @@ async def get_beatmap_scores(self, beatmap_id: int, **kwargs: Any) -> list[Score
See below
:Keyword Arguments:
* *legacy_only* (``bool``) --
Optional, whether to only get legacy scores, defaults to ``False``
* *mode* (``aiosu.models.gamemode.Gamemode``) --
Optional, gamemode to search for
* *mods* (``aiosu.models.mods.Mods``) --
Optional, mods to search for
* *type* (``aiosu.models.common.BeatmapScoreboardType``) --
Optional, beatmap score ranking type
* *legacy_only* (``bool``) --
Optional, whether to only get legacy scores, defaults to ``False``
:raises APIException: Contains status code and error message
:raises RefreshTokenExpiredError: If the client refresh token has expired
Expand All @@ -1213,7 +1219,6 @@ async def get_beatmap_scores(self, beatmap_id: int, **kwargs: Any) -> list[Score
"""
url = f"{self.base_url}/api/v2/beatmaps/{beatmap_id}/scores"
params: dict[str, object] = {}
add_param(params, kwargs, key="legacy_only", converter=int)
add_param(params, kwargs, key="mode", converter=lambda x: str(Gamemode(x)))
add_param(
params,
Expand All @@ -1222,6 +1227,7 @@ async def get_beatmap_scores(self, beatmap_id: int, **kwargs: Any) -> list[Score
converter=lambda x: [str(y) for y in Mods(x)],
)
add_param(params, kwargs, key="type")
add_param(params, kwargs, key="legacy_only", converter=int)
json = await self._request("GET", url, params=params)
return from_list(Score.model_validate, json.get("scores", []))

Expand Down Expand Up @@ -1515,19 +1521,27 @@ async def get_beatmap_packs(self, **kwargs: Any) -> BeatmapPacksResponse:
@prepare_token
@check_token
@requires_scope(Scopes.PUBLIC)
async def get_beatmap_pack(self, pack_tag: str) -> BeatmapPack:
async def get_beatmap_pack(self, pack_tag: str, **kwargs: Any) -> BeatmapPack:
r"""Get beatmap pack.
:param pack_tag: The tag of the beatmap pack
:type pack_tag: str
:param \**kwargs:
See below
:Keyword Arguments:
* *legacy_only* (``bool``) --
Optional, whether or not to consider lazer scores for completion data, defaults to ``False``
:raises APIException: Contains status code and error message
:raises RefreshTokenExpiredError: If the client refresh token has expired
:return: Beatmap pack object
:rtype: aiosu.models.beatmap.BeatmapPack
"""
url = f"{self.base_url}/api/v2/beatmaps/packs/{pack_tag}"
json = await self._request("GET", url)
params: dict[str, object] = {}
add_param(params, kwargs, key="legacy_only", converter=int)
json = await self._request("GET", url, params=params)
return BeatmapPack.model_validate(json)

@prepare_token
Expand Down Expand Up @@ -1747,21 +1761,35 @@ async def get_score(
self,
score_id: int,
mode: Gamemode,
) -> Score:
**kwargs: Any,
) -> Union[Score, LazerScore]:
r"""Gets data about a score.
:param score_id: The ID of the score
:type score_id: int
:param mode: The gamemode to search for
:type mode: aiosu.models.gamemode.Gamemode
:param \**kwargs:
See below
:Keyword Arguments:
* *new_format* (``bool``) --
Optional, whether to use the new score format, defaults to ``False``
:raises APIException: Contains status code and error message
:raises RefreshTokenExpiredError: If the client refresh token has expired
:return: Score data object
:rtype: aiosu.models.score.Score
"""
url = f"{self.base_url}/api/v2/scores/{mode}/{score_id}"
json = await self._request("GET", url)
headers = {}
new_format = kwargs.pop("new_format", False)
if new_format:
headers = {"x-api-version": "20220705"}

json = await self._request("GET", url, headers=headers)
if new_format:
return LazerScore.model_validate(json)
return Score.model_validate(json)

@prepare_token
Expand Down
2 changes: 1 addition & 1 deletion tests/data/v1/get_beatmap_200.json

Large diffs are not rendered by default.

0 comments on commit 2a958b7

Please sign in to comment.