Skip to content

Commit 275624b

Browse files
committed
Add basic typing to Bracket endpoint
1 parent f1b9ba6 commit 275624b

File tree

9 files changed

+314
-82
lines changed

9 files changed

+314
-82
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ An async Python client for Sendou.ink
1111

1212
## Dependencies
1313
- aiohttp
14+
- [aiohttp-client-cache](https://pypi.org/project/aiohttp-client-cache/)
1415
- python-dateutil
1516

1617
## Installation
@@ -22,7 +23,7 @@ An async Python client for Sendou.ink
2223
- [x] Get Tournament Info
2324
- [x] Get Tournament Teams
2425
- [X] Get Tournament Brackets
25-
- [x] Get Tournament Match Info (*by ID not linked to bracket*)
26+
- [x] Get Tournament Match Info
2627

2728
## Usage
2829
```python

docs/index.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@ This library is maintained by [Inkling Performance Labs Productions](https://git
88

99
## Dependencies
1010
- aiohttp
11+
- [aiohttp-client-cache](https://pypi.org/project/aiohttp-client-cache/)
1112
- python-dateutil
1213

1314
## Installation
1415
`pip install sendou.py`
1516

1617
## Supported Endpoints
1718
- [x] Get user
19+
- [x] Get Calendar Entries
1820
- [x] Get Tournament Info
1921
- [x] Get Tournament Teams
2022
- [X] Get Tournament Brackets
21-
- [x] Get Tournament Match Info (*by ID not linked to bracket*)
23+
- [x] Get Tournament Match Info
2224

2325
## Usage
2426
```python

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "sendou-py"
3-
version = "1.0.0"
3+
version = "1.1.0"
44
description = "An async Python library for Sendou.ink"
55
authors = ["Vincent Lee <[email protected]>"]
66
license = "MIT"
@@ -12,7 +12,7 @@ documentation = "https://sendou.opensource.iplabs.work/"
1212
keywords = ["splatoon", "sendou.ink"]
1313
classifiers = [
1414
"Topic :: Software Development :: Libraries :: Python Modules",
15-
"Development Status :: 3 - Alpha"
15+
"Development Status :: 3 - Beta"
1616
]
1717

1818
[tool.poetry.dependencies]

sendou/models/tournament/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
from .tournament import TournamentTeamInfo as TournamentTeam
33
from .team import TournamentTeam, TeamMember
44
from .match import Match, MatchTeam, MapListSourceEnum, MapListMap
5-
from .bracket import Bracket
5+
from .bracket import Bracket

sendou/models/tournament/bracket.py

Lines changed: 0 additions & 58 deletions
This file was deleted.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .bracket import Bracket
2+
from .type import BracketType, RoundType, MatchResult
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
"""
2+
Tournament Bracket Model
3+
"""
4+
from sendou.models.baseModel import BaseModel
5+
from sendou.requests import RequestsClient
6+
7+
from typing import Any, Optional, List
8+
from datetime import datetime, timezone
9+
10+
from .type import BracketType, RoundType, MatchResult
11+
from sendou.models.tournament.match import Match
12+
13+
14+
class BracketMeta:
15+
"""
16+
Bracket Metadata
17+
18+
Attributes:
19+
teams_per_group (Optional[int]): Teams per Group
20+
group_count (Optional[int]): Group Count
21+
round_count (Optional[int]): Round Count
22+
"""
23+
teams_per_group: Optional[int]
24+
group_count: Optional[int]
25+
round_count: Optional[int]
26+
27+
def __init__(self, data: dict):
28+
self.teams_per_group = data.get("teamsPerGroup", None)
29+
self.group_count = data.get("groupCount", None)
30+
self.round_count = data.get("roundCount", None)
31+
32+
33+
class BracketStage:
34+
"""
35+
Bracket Stage
36+
37+
Attributes:
38+
id (int): Bracket Stage ID
39+
name (str): Bracket Stage Name
40+
number (int): Bracket Stage Number
41+
settings (Any): Bracket Stage Settings
42+
tournament_id (int): Tournament ID
43+
type (BracketType): Bracket Type
44+
created_at (datetime): Created At
45+
"""
46+
id: int
47+
name: str
48+
number: int
49+
settings: Any
50+
tournament_id: int
51+
type: BracketType
52+
created_at: datetime # Provided as unix timestamp
53+
54+
def __init__(self, data: dict):
55+
self.id = data.get("id", 0)
56+
self.name = data.get("name", "")
57+
self.number = data.get("number", 0)
58+
self.settings = data.get("settings", {})
59+
self.tournament_id = data.get("tournament_id", 0)
60+
self.type = BracketType(data.get("type", ""))
61+
self.created_at = datetime.fromtimestamp(data.get("createdAt", 0), tz=timezone.utc)
62+
63+
64+
class BracketGroup:
65+
"""
66+
Bracket Group
67+
68+
Attributes:
69+
id (int): Bracket Group ID
70+
number (int): Bracket Group Number
71+
stage_id (int): Bracket Stage ID
72+
"""
73+
id: int
74+
number: int
75+
stage_id: int
76+
77+
def __init__(self, data: dict):
78+
self.id = data.get("id", 0)
79+
self.numbers = data.get("number", 0)
80+
self.stage_id = data.get("stage_id", 0)
81+
82+
83+
class BracketRoundMap:
84+
"""
85+
Bracket Round Map
86+
87+
Attributes:
88+
count (int): Round Count
89+
type (RoundType): Round Type
90+
"""
91+
count: int
92+
type: RoundType
93+
94+
def __init__(self, data: dict):
95+
self.count = data.get("count", 0)
96+
self.type = RoundType(data.get("type", ""))
97+
98+
99+
class BracketRound:
100+
"""
101+
Bracket Round
102+
103+
Attributes:
104+
id (int): Bracket Round ID
105+
group_id (int): Bracket Group ID
106+
number (int): Bracket Round Number
107+
stage_id (int): Bracket Stage ID
108+
maps (BracketRoundMap): Bracket Round Map Metadata
109+
"""
110+
id: int
111+
group_id: int
112+
number: int
113+
stage_id: int
114+
maps: BracketRoundMap
115+
116+
def __init__(self, data: dict):
117+
self.id = data.get("id", 0)
118+
self.group_id = data.get("group_id", 0)
119+
self.number = data.get("number", 0)
120+
self.stage_id = data.get("stage_id", 0)
121+
self.maps = BracketRoundMap(data.get("maps", {}))
122+
123+
124+
class BracketMatchOpponent:
125+
"""
126+
Bracket Match Opponent
127+
128+
Attributes:
129+
id (int): Opponent ID
130+
position (int): Opponent Seed?
131+
score (int): Opponent Score
132+
result (MatchResult): Opponent Result
133+
totalPoints (int): Total Points (Swiss/RR)
134+
"""
135+
id: int
136+
position: Optional[int]
137+
score: Optional[int]
138+
result: Optional[MatchResult]
139+
totalPoints: Optional[int]
140+
141+
def __init__(self, data: dict):
142+
self.id = data.get("id", 0)
143+
if "position" in data:
144+
self.position = data.get("position", 0)
145+
if "score" in data:
146+
self.score = data.get("score", 0)
147+
if "result" in data:
148+
self.result = MatchResult(data.get("result", ""))
149+
if "totalPoints" in data:
150+
self.totalPoints = data.get("totalPoints", 0)
151+
152+
153+
class BracketMatch(BaseModel):
154+
"""
155+
Bracket Match
156+
157+
Attributes:
158+
id (int): Bracket Match ID
159+
group_id (int): Bracket Group ID
160+
number (int): Bracket Match Number
161+
opponent1 (BracketMatchOpponent): Opponent 1
162+
opponent2 (Optional[BracketMatchOpponent]): Opponent 2
163+
round_id (int): Bracket Round ID
164+
stage_id (int): Bracket Stage ID
165+
status (int): Bracket Match Status
166+
lastGameFinishedAt (datetime): Last Game Finished At
167+
createdAt (datetime): Created At
168+
"""
169+
id: int
170+
group_id: int
171+
number: int
172+
opponent1: BracketMatchOpponent
173+
opponent2: Optional[BracketMatchOpponent]
174+
round_id: int
175+
stage_id: int
176+
status: int
177+
lastGameFinishedAt: Optional[datetime] # Unix timestamp
178+
createdAt: Optional[datetime] # Unix timestamp
179+
180+
def __init__(self, data: dict, request_client: RequestsClient):
181+
super().__init__(data, request_client)
182+
self.id = data.get("id", 0)
183+
self.group_id = data.get("group_id", 0)
184+
self.number = data.get("number", 0)
185+
self.opponent1 = BracketMatchOpponent(data.get("opponent1", {}))
186+
if data.get("opponent2", {}):
187+
self.opponent2 = BracketMatchOpponent(data.get("opponent2", {}))
188+
self.round_id = data.get("round_id", 0)
189+
self.stage_id = data.get("stage_id", 0)
190+
self.status = data.get("status", 0)
191+
if data.get("lastGameFinishedAt", None):
192+
self.lastGameFinishedAt = datetime.fromtimestamp(data.get("lastGameFinishedAt", 0), tz=timezone.utc)
193+
if data.get("createdAt", None):
194+
self.createdAt = datetime.fromtimestamp(data.get("createdAt", 0), tz=timezone.utc)
195+
196+
async def get_match(self) -> Optional[Match]:
197+
"""
198+
Get the match data
199+
200+
Returns:
201+
(Match): Match Data
202+
"""
203+
path = Match.api_route(match_id=self.id)
204+
data = await self._request_client.get_response(path)
205+
if data:
206+
return Match(data, self._request_client)
207+
208+
209+
class BracketData(BaseModel):
210+
"""
211+
Bracket Data
212+
213+
Attributes:
214+
stage (BracketStage): Bracket Stage
215+
group (List[BracketGroup]): Bracket Groups
216+
round (List[BracketRound]): Bracket Rounds
217+
match (List[BracketMatch]): Bracket Matches
218+
"""
219+
stage: List[BracketStage]
220+
group: List[BracketGroup]
221+
round: List[BracketRound]
222+
match: List[BracketMatch]
223+
224+
def __init__(self, data: dict, request_client: RequestsClient):
225+
super().__init__(data, request_client)
226+
self.stage = [BracketStage(stage) for stage in data.get("stage", [])]
227+
self.group = [BracketGroup(group) for group in data.get("group", [])]
228+
self.round = [BracketRound(r) for r in data.get("round", [])]
229+
self.match = [BracketMatch(match, request_client) for match in data.get("match", [])]
230+
231+
232+
class Bracket(BaseModel):
233+
"""
234+
Sendou.ink Tournament Bracket Info
235+
236+
Attributes:
237+
data (Any): Bracket Data
238+
meta (BracketMeta): Bracket Metadata
239+
"""
240+
data: BracketData # https://github.com/Sendouc/sendou.ink/blob/rewrite/app/features/api-public/schema.ts#L232
241+
meta: BracketMeta
242+
243+
def __init__(self, data: dict, request_client: RequestsClient):
244+
super().__init__(data, request_client)
245+
self.data = BracketData(data.get("data", {}), request_client)
246+
self.meta = BracketMeta(data.get("meta", {}))
247+
248+
@staticmethod
249+
def api_route(**kwargs) -> str:
250+
"""
251+
Get the api route for the bracket
252+
253+
Args:
254+
tournament_id (str): Tournament ID
255+
bracket_index (int): Bracket Index
256+
257+
Returns:
258+
(str): API Route
259+
"""
260+
return f"api/tournament/{kwargs.get('tournament_id')}/brackets/{kwargs.get('bracket_index')}"

0 commit comments

Comments
 (0)