ossapi 5.0.2__tar.gz → 5.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ossapi-5.0.2 → ossapi-5.1.0}/PKG-INFO +2 -2
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi/enums.py +5 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi/models.py +61 -11
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi/ossapiv2.py +38 -8
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi/ossapiv2_async.py +27 -4
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi.egg-info/PKG-INFO +2 -2
- {ossapi-5.0.2 → ossapi-5.1.0}/pyproject.toml +1 -1
- {ossapi-5.0.2 → ossapi-5.1.0}/tests/test_endpoints.py +21 -1
- {ossapi-5.0.2 → ossapi-5.1.0}/.gitignore +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/.nojekyll +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/LICENSE +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/Makefile +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/README.md +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/_static/custom.css +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/advanced.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/api-reference.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/async.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/beatmap packs.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/beatmaps.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/beatmapsets.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/changelog.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/chat.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/comments.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/conf.py +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/creating-a-client.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/domains.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/endpoints.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/events.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/expandable-models.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/foreign-keys.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/forums.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/friends.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/generate_docs.py +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/generate_readme_list.py +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/grants.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/home.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/index.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/matches.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/me.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/news.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/oauth.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/pagination.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/quickstart.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/rankings.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/rooms.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/scores.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/seasonal backgrounds.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/serializing-models.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/spotlights.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/users.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/docs/wiki.rst +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi/__init__.py +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi/encoder.py +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi/mod.py +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi/ossapi.py +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi/replay.py +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi/utils.py +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi.egg-info/SOURCES.txt +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi.egg-info/dependency_links.txt +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi.egg-info/requires.txt +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/ossapi.egg-info/top_level.txt +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/setup.cfg +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/tests/__init__.py +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/tests/test_cursor.py +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/tests/test_models.py +0 -0
- {ossapi-5.0.2 → ossapi-5.1.0}/tests/test_v1.py +0 -0
|
@@ -68,6 +68,7 @@ from ossapi.enums import (
|
|
|
68
68
|
BeatmapPackUserCompletionData,
|
|
69
69
|
RoomPlaylistItemStats,
|
|
70
70
|
RoomDifficultyRange,
|
|
71
|
+
BeatmapOwner,
|
|
71
72
|
)
|
|
72
73
|
from ossapi.utils import Datetime, Model, BaseModel, Field
|
|
73
74
|
|
|
@@ -292,6 +293,9 @@ class Beatmap(BeatmapCompact):
|
|
|
292
293
|
# This is optional as a workaround until
|
|
293
294
|
# https://github.com/ppy/osu-web/issues/9784 is resolved.
|
|
294
295
|
owner: Field(name="user", type=Optional[UserCompact])
|
|
296
|
+
# TODO does the new addition of this owners attribute deprecate the owner
|
|
297
|
+
# attribute?
|
|
298
|
+
owners: Optional[List[BeatmapOwner]]
|
|
295
299
|
|
|
296
300
|
# overridden fields
|
|
297
301
|
# -----------------
|
|
@@ -737,7 +741,11 @@ class BeatmapsetDiscussion(Model):
|
|
|
737
741
|
current_user_attributes: Any
|
|
738
742
|
updated_at: Datetime
|
|
739
743
|
deleted_at: Optional[Datetime]
|
|
740
|
-
|
|
744
|
+
# marked as required in the docs, but null in
|
|
745
|
+
# api.beatmapset_events(beatmapset_id=1112418)
|
|
746
|
+
# due to this post
|
|
747
|
+
# https://osu.ppy.sh/beatmapsets/1112418/discussion/-/generalAll#/1633002
|
|
748
|
+
last_post_at: Optional[Datetime]
|
|
741
749
|
kudosu_denied: bool
|
|
742
750
|
starting_post: Optional[BeatmapsetDiscussionPost]
|
|
743
751
|
posts: Optional[List[BeatmapsetDiscussionPost]]
|
|
@@ -942,7 +950,7 @@ class ChangelogListing(Model):
|
|
|
942
950
|
|
|
943
951
|
class MultiplayerScores(Model):
|
|
944
952
|
cursor_string: CursorStringT
|
|
945
|
-
params:
|
|
953
|
+
params: Any
|
|
946
954
|
scores: List[MultiplayerScore]
|
|
947
955
|
total: Optional[int]
|
|
948
956
|
user_score: Optional[MultiplayerScore]
|
|
@@ -954,7 +962,7 @@ class MultiplayerScore(Model):
|
|
|
954
962
|
room_id: int
|
|
955
963
|
playlist_item_id: int
|
|
956
964
|
beatmap_id: int
|
|
957
|
-
rank:
|
|
965
|
+
rank: Grade
|
|
958
966
|
total_score: int
|
|
959
967
|
max_combo: int
|
|
960
968
|
mods: List[Mod]
|
|
@@ -963,6 +971,28 @@ class MultiplayerScore(Model):
|
|
|
963
971
|
position: Optional[int]
|
|
964
972
|
scores_around: Optional[MultiplayerScoresAround]
|
|
965
973
|
user: User
|
|
974
|
+
solo_score_id: int
|
|
975
|
+
classic_total_score: int
|
|
976
|
+
preserve: bool
|
|
977
|
+
processed: bool
|
|
978
|
+
ranked: bool
|
|
979
|
+
maximum_statistics: Statistics
|
|
980
|
+
total_score_without_mods: int
|
|
981
|
+
best_id: Optional[int]
|
|
982
|
+
type: str
|
|
983
|
+
accuracy: float
|
|
984
|
+
build_id: int
|
|
985
|
+
ended_at: Datetime
|
|
986
|
+
is_perfect_combo: bool
|
|
987
|
+
replay: bool
|
|
988
|
+
pp: float
|
|
989
|
+
started_at: Datetime
|
|
990
|
+
ruleset_id: int
|
|
991
|
+
current_user_attributes: Any
|
|
992
|
+
has_replay: bool
|
|
993
|
+
legacy_perfect: bool
|
|
994
|
+
legacy_score_id: int
|
|
995
|
+
legacy_total_score: int
|
|
966
996
|
|
|
967
997
|
def beatmap(self):
|
|
968
998
|
return self._fk_beatmap(self.beatmap_id)
|
|
@@ -1070,6 +1100,12 @@ class BeatmapPack(Model):
|
|
|
1070
1100
|
user_completion_data: Optional[BeatmapPackUserCompletionData]
|
|
1071
1101
|
|
|
1072
1102
|
|
|
1103
|
+
class Scores(Model):
|
|
1104
|
+
cursor: CursorT
|
|
1105
|
+
cursor_string: CursorStringT
|
|
1106
|
+
scores: List[Score]
|
|
1107
|
+
|
|
1108
|
+
|
|
1073
1109
|
# ================
|
|
1074
1110
|
# Parameter Models
|
|
1075
1111
|
# ================
|
|
@@ -1145,12 +1181,12 @@ class BeatmapsetEventComment(Model):
|
|
|
1145
1181
|
|
|
1146
1182
|
class BeatmapsetEventCommentNoPost(Model):
|
|
1147
1183
|
beatmap_discussion_id: int
|
|
1148
|
-
beatmap_discussion_post_id: int
|
|
1184
|
+
beatmap_discussion_post_id: Optional[int]
|
|
1149
1185
|
|
|
1150
1186
|
|
|
1151
1187
|
class BeatmapsetEventCommentNone(Model):
|
|
1152
|
-
beatmap_discussion_id: int
|
|
1153
|
-
beatmap_discussion_post_id: int
|
|
1188
|
+
beatmap_discussion_id: Optional[int]
|
|
1189
|
+
beatmap_discussion_post_id: Optional[int]
|
|
1154
1190
|
|
|
1155
1191
|
|
|
1156
1192
|
class BeatmapsetEventCommentChange(Generic[S], BeatmapsetEventCommentNone):
|
|
@@ -1176,6 +1212,7 @@ class BeatmapsetEventCommentOwnerChange(BeatmapsetEventCommentNone):
|
|
|
1176
1212
|
beatmap_version: str
|
|
1177
1213
|
new_user_id: int
|
|
1178
1214
|
new_user_username: str
|
|
1215
|
+
new_users: List[int]
|
|
1179
1216
|
|
|
1180
1217
|
|
|
1181
1218
|
class BeatmapsetEventCommentNominate(Model):
|
|
@@ -1224,7 +1261,14 @@ class BeatmapsetEvent(Model):
|
|
|
1224
1261
|
BeatmapsetEventType.DISCUSSION_RESTORE: BeatmapsetEventCommentNoPost,
|
|
1225
1262
|
# same here
|
|
1226
1263
|
# BeatmapsetEventType.DISCUSSION_UNLOCK: BeatmapsetEventComment,
|
|
1227
|
-
|
|
1264
|
+
# Some events have a comment that is *just a string*.
|
|
1265
|
+
# api.beatmapset_events(beatmapset_id=724033)
|
|
1266
|
+
# I've only seen this for "type": "disqualify", but who knows where
|
|
1267
|
+
# else it could happen. I've preemptively marked NOMINATION_RESET as
|
|
1268
|
+
# taking a string also.
|
|
1269
|
+
BeatmapsetEventType.DISQUALIFY: Union[
|
|
1270
|
+
BeatmapsetEventCommentWithNominators, str
|
|
1271
|
+
],
|
|
1228
1272
|
# same here
|
|
1229
1273
|
# BeatmapsetEventType.DISQUALIFY_LEGACY: BeatmapsetEventComment
|
|
1230
1274
|
BeatmapsetEventType.GENRE_EDIT: BeatmapsetEventCommentChange[str],
|
|
@@ -1240,7 +1284,9 @@ class BeatmapsetEvent(Model):
|
|
|
1240
1284
|
BeatmapsetEventType.NOMINATE: BeatmapsetEventCommentNominate,
|
|
1241
1285
|
# same here
|
|
1242
1286
|
# BeatmapsetEventType.NOMINATE_MODES: BeatmapsetEventComment,
|
|
1243
|
-
BeatmapsetEventType.NOMINATION_RESET:
|
|
1287
|
+
BeatmapsetEventType.NOMINATION_RESET: Union[
|
|
1288
|
+
BeatmapsetEventCommentWithNominators, str
|
|
1289
|
+
],
|
|
1244
1290
|
BeatmapsetEventType.NOMINATION_RESET_RECEIVED: BeatmapsetEventCommentWithSourceUser,
|
|
1245
1291
|
BeatmapsetEventType.QUALIFY: type(None),
|
|
1246
1292
|
BeatmapsetEventType.RANK: type(None),
|
|
@@ -1248,7 +1294,11 @@ class BeatmapsetEvent(Model):
|
|
|
1248
1294
|
BeatmapsetEventType.NSFW_TOGGLE: BeatmapsetEventCommentChange[bool],
|
|
1249
1295
|
}
|
|
1250
1296
|
type_ = BeatmapsetEventType(data["type"])
|
|
1251
|
-
|
|
1297
|
+
# some events don't seem to have an associate comment, eg
|
|
1298
|
+
# api.beatmapset_events(beatmapset_id=692322)
|
|
1299
|
+
# I don't know under what circumstances this does or does not happen, so
|
|
1300
|
+
# I am marking all comments as optional.
|
|
1301
|
+
return {"comment": Optional[mapping[type_]]}
|
|
1252
1302
|
|
|
1253
1303
|
def user(self) -> Optional[User]:
|
|
1254
1304
|
return self._fk_user(self.user_id)
|
|
@@ -1402,7 +1452,7 @@ class _Room1(Model):
|
|
|
1402
1452
|
type: RoomType
|
|
1403
1453
|
user_id: int
|
|
1404
1454
|
starts_at: Datetime
|
|
1405
|
-
ends_at: Datetime
|
|
1455
|
+
ends_at: Optional[Datetime]
|
|
1406
1456
|
max_attempts: Optional[int]
|
|
1407
1457
|
participant_count: int
|
|
1408
1458
|
channel_id: int
|
|
@@ -1422,7 +1472,7 @@ class Room(Model):
|
|
|
1422
1472
|
type: RoomType
|
|
1423
1473
|
user_id: int
|
|
1424
1474
|
starts_at: Datetime
|
|
1425
|
-
ends_at: Datetime
|
|
1475
|
+
ends_at: Optional[Datetime]
|
|
1426
1476
|
max_attempts: Optional[int]
|
|
1427
1477
|
participant_count: int
|
|
1428
1478
|
channel_id: int
|
|
@@ -77,6 +77,7 @@ from ossapi.models import (
|
|
|
77
77
|
Events,
|
|
78
78
|
BeatmapPack,
|
|
79
79
|
BeatmapPacks,
|
|
80
|
+
Scores,
|
|
80
81
|
)
|
|
81
82
|
from ossapi.enums import (
|
|
82
83
|
GameMode,
|
|
@@ -898,12 +899,21 @@ class Ossapi:
|
|
|
898
899
|
# because if we got here that means we were passed a value for this
|
|
899
900
|
# attribute, so we know it's defined and not optional.
|
|
900
901
|
if is_optional(type_):
|
|
901
|
-
|
|
902
|
-
#
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
902
|
+
assert len(args) >= 2
|
|
903
|
+
# two args is the standard, for Optional[T] = Union[T, None].
|
|
904
|
+
# but we could also have Union[T, None, V] which passes is_optional
|
|
905
|
+
# but we want to unwrap differently to preserve the Union[T, V].
|
|
906
|
+
if len(args) == 2:
|
|
907
|
+
type_ = args[0]
|
|
908
|
+
origin = get_origin(type_)
|
|
909
|
+
args = get_args(type_)
|
|
910
|
+
else:
|
|
911
|
+
# should we be changing type_ here? it's not technically correct
|
|
912
|
+
# anymore, we'd have to remove None from the union. But I don't
|
|
913
|
+
# know if we rely on type_ instead of args anywhere, and I don't
|
|
914
|
+
# know how to create a new type instance.
|
|
915
|
+
origin = get_origin(type_)
|
|
916
|
+
args = tuple(t for t in get_args(type_) if t is not type(None))
|
|
907
917
|
|
|
908
918
|
# validate that the values we're receiving are the types we expect them
|
|
909
919
|
# to be
|
|
@@ -2423,8 +2433,6 @@ class Ossapi:
|
|
|
2423
2433
|
# /rooms
|
|
2424
2434
|
# ------
|
|
2425
2435
|
|
|
2426
|
-
# TODO add test for this once I figure out values for room_id and
|
|
2427
|
-
# playlist_id that actually produce a response lol
|
|
2428
2436
|
@request(Scope.PUBLIC, category="rooms")
|
|
2429
2437
|
def multiplayer_scores(
|
|
2430
2438
|
self,
|
|
@@ -2562,6 +2570,28 @@ class Ossapi:
|
|
|
2562
2570
|
"""
|
|
2563
2571
|
return self._get(Score, f"/scores/{score_id}")
|
|
2564
2572
|
|
|
2573
|
+
@request(Scope.PUBLIC, category="scores")
|
|
2574
|
+
def scores(
|
|
2575
|
+
self, mode: GameModeT, *, cursor_string: Optional[str] = None
|
|
2576
|
+
) -> Scores:
|
|
2577
|
+
"""
|
|
2578
|
+
Returns most recent 1000 passed scores across all users.
|
|
2579
|
+
|
|
2580
|
+
Parameters
|
|
2581
|
+
----------
|
|
2582
|
+
mode
|
|
2583
|
+
The mode to get scores for.
|
|
2584
|
+
cursor_string
|
|
2585
|
+
Cursor for pagination.
|
|
2586
|
+
|
|
2587
|
+
Notes
|
|
2588
|
+
-----
|
|
2589
|
+
Implements the `Get Scores
|
|
2590
|
+
<https://osu.ppy.sh/docs/index.html#get-scores94>`__ endpoint.
|
|
2591
|
+
"""
|
|
2592
|
+
params = {"mode": mode.value, "cursor_string": cursor_string}
|
|
2593
|
+
return self._get(Scores, "/scores", params)
|
|
2594
|
+
|
|
2565
2595
|
@request(Scope.PUBLIC, category="scores")
|
|
2566
2596
|
def score_mode(self, mode: GameModeT, score_id: int) -> Score:
|
|
2567
2597
|
"""
|
|
@@ -90,6 +90,7 @@ from ossapi.models import (
|
|
|
90
90
|
Events,
|
|
91
91
|
BeatmapPack,
|
|
92
92
|
BeatmapPacks,
|
|
93
|
+
Scores,
|
|
93
94
|
)
|
|
94
95
|
from ossapi.enums import (
|
|
95
96
|
GameMode,
|
|
@@ -2648,7 +2649,7 @@ class OssapiAsync:
|
|
|
2648
2649
|
# -------
|
|
2649
2650
|
|
|
2650
2651
|
@request(Scope.PUBLIC, category="scores")
|
|
2651
|
-
def score(self, score_id: int) -> Score:
|
|
2652
|
+
async def score(self, score_id: int) -> Score:
|
|
2652
2653
|
"""
|
|
2653
2654
|
Get a score. This corresponds to urls of the form https://osu.ppy.sh/scores/1312718771
|
|
2654
2655
|
("new id format").
|
|
@@ -2665,10 +2666,32 @@ class OssapiAsync:
|
|
|
2665
2666
|
Implements the `Get Score
|
|
2666
2667
|
<https://osu.ppy.sh/docs/index.html#scoresmodescore>`__ endpoint.
|
|
2667
2668
|
"""
|
|
2668
|
-
return self._get(Score, f"/scores/{score_id}")
|
|
2669
|
+
return await self._get(Score, f"/scores/{score_id}")
|
|
2669
2670
|
|
|
2670
2671
|
@request(Scope.PUBLIC, category="scores")
|
|
2671
|
-
def
|
|
2672
|
+
async def scores(
|
|
2673
|
+
self, mode: GameModeT, *, cursor_string: Optional[str] = None
|
|
2674
|
+
) -> Scores:
|
|
2675
|
+
"""
|
|
2676
|
+
Returns most recent 1000 passed scores across all users.
|
|
2677
|
+
|
|
2678
|
+
Parameters
|
|
2679
|
+
----------
|
|
2680
|
+
mode
|
|
2681
|
+
The mode to get scores for.
|
|
2682
|
+
cursor_string
|
|
2683
|
+
Cursor for pagination.
|
|
2684
|
+
|
|
2685
|
+
Notes
|
|
2686
|
+
-----
|
|
2687
|
+
Implements the `Get Scores
|
|
2688
|
+
<https://osu.ppy.sh/docs/index.html#get-scores94>`__ endpoint.
|
|
2689
|
+
"""
|
|
2690
|
+
params = {"mode": mode.value, "cursor_string": cursor_string}
|
|
2691
|
+
return await self._get(Scores, "/scores", params)
|
|
2692
|
+
|
|
2693
|
+
@request(Scope.PUBLIC, category="scores")
|
|
2694
|
+
async def score_mode(self, mode: GameModeT, score_id: int) -> Score:
|
|
2672
2695
|
"""
|
|
2673
2696
|
Get a score, where the score id is specific to the gamemode. This
|
|
2674
2697
|
corresponds to urls of the form https://osu.ppy.sh/scores/osu/4459998279
|
|
@@ -2688,7 +2711,7 @@ class OssapiAsync:
|
|
|
2688
2711
|
Implements the `Get Score
|
|
2689
2712
|
<https://osu.ppy.sh/docs/index.html#scoresmodescore>`__ endpoint.
|
|
2690
2713
|
"""
|
|
2691
|
-
return self._get(Score, f"/scores/{mode.value}/{score_id}")
|
|
2714
|
+
return await self._get(Score, f"/scores/{mode.value}/{score_id}")
|
|
2692
2715
|
|
|
2693
2716
|
async def _download_score(self, *, url, raw):
|
|
2694
2717
|
from aiohttp import ClientSession, ContentTypeError
|
|
@@ -56,8 +56,13 @@ class TestBeatmapScores(TestCase):
|
|
|
56
56
|
class TestBeatmap(TestCase):
|
|
57
57
|
def test_deserialize(self):
|
|
58
58
|
api.beatmap(beatmap_id=221777)
|
|
59
|
+
# beatmap with multiple owners (.owners)
|
|
60
|
+
bm = api.beatmap(beatmap_id=4060023)
|
|
61
|
+
# see https://discord.com/channels/188630481301012481/
|
|
62
|
+
# 188630616286167041/1315396179655262239
|
|
63
|
+
assert bm.owner is None
|
|
59
64
|
|
|
60
|
-
# beatmap with a diff owner
|
|
65
|
+
# beatmap with a diff owner (.owner)
|
|
61
66
|
bm = api.beatmap(beatmap_id=1604098)
|
|
62
67
|
# might need to be updated when
|
|
63
68
|
# https://github.com/ppy/osu-web/issues/9784 is addressed.
|
|
@@ -72,6 +77,10 @@ class TestBeatmapset(TestCase):
|
|
|
72
77
|
class TestBeatmapsetEvents(TestCase):
|
|
73
78
|
def test_deserialize(self):
|
|
74
79
|
api.beatmapset_events()
|
|
80
|
+
api.beatmapset_events(beatmapset_id=1339615)
|
|
81
|
+
api.beatmapset_events(beatmapset_id=692322)
|
|
82
|
+
api.beatmapset_events(beatmapset_id=724033)
|
|
83
|
+
api.beatmapset_events(beatmapset_id=1112418)
|
|
75
84
|
|
|
76
85
|
def test_all_types(self):
|
|
77
86
|
# beatmapset_events is a really complicated endpoint in terms of return
|
|
@@ -310,6 +319,17 @@ class TestBeatmapPack(TestCase):
|
|
|
310
319
|
api.beatmap_pack("A1")
|
|
311
320
|
|
|
312
321
|
|
|
322
|
+
class TestMultiplayerScores(TestCase):
|
|
323
|
+
def test_deserialize(self):
|
|
324
|
+
api.multiplayer_scores(1057998, 11773230)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
class TestScores(TestCase):
|
|
328
|
+
def test_deserialize(self):
|
|
329
|
+
scores = api.scores("osu")
|
|
330
|
+
api.scores("osu", cursor_string=scores.cursor_string)
|
|
331
|
+
|
|
332
|
+
|
|
313
333
|
# ======================
|
|
314
334
|
# api_full test cases
|
|
315
335
|
# ======================
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|