elo-system 1.0.0__py3-none-any.whl
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.
- elo_system/__init__.py +0 -0
- elo_system/_vendor/__init__.py +1 -0
- elo_system/_vendor/fantraxapi/LICENSE +21 -0
- elo_system/_vendor/fantraxapi/__init__.py +25 -0
- elo_system/_vendor/fantraxapi/api.py +135 -0
- elo_system/_vendor/fantraxapi/exceptions.py +39 -0
- elo_system/_vendor/fantraxapi/objs/__init__.py +36 -0
- elo_system/_vendor/fantraxapi/objs/_parse.py +85 -0
- elo_system/_vendor/fantraxapi/objs/base.py +13 -0
- elo_system/_vendor/fantraxapi/objs/game.py +67 -0
- elo_system/_vendor/fantraxapi/objs/league.py +372 -0
- elo_system/_vendor/fantraxapi/objs/player.py +93 -0
- elo_system/_vendor/fantraxapi/objs/position.py +58 -0
- elo_system/_vendor/fantraxapi/objs/roster.py +102 -0
- elo_system/_vendor/fantraxapi/objs/scoring_period.py +301 -0
- elo_system/_vendor/fantraxapi/objs/standings.py +83 -0
- elo_system/_vendor/fantraxapi/objs/status.py +37 -0
- elo_system/_vendor/fantraxapi/objs/team.py +100 -0
- elo_system/_vendor/fantraxapi/objs/trade.py +113 -0
- elo_system/_vendor/fantraxapi/objs/trade_block.py +47 -0
- elo_system/_vendor/fantraxapi/objs/transaction.py +62 -0
- elo_system/elo_system.py +201 -0
- elo_system/tools/__init__.py +2 -0
- elo_system/tools/basics/__init__.py +19 -0
- elo_system/tools/basics/common_classes.py +116 -0
- elo_system/tools/basics/common_funcs.py +109 -0
- elo_system/tools/basics/constants.py +6 -0
- elo_system/tools/elo_data.py +92 -0
- elo_system/tools/elo_league.py +302 -0
- elo_system/tools/helpers/__init__.py +5 -0
- elo_system/tools/helpers/calculator.py +105 -0
- elo_system/tools/helpers/formatter.py +50 -0
- elo_system/tools/helpers/frame_manager.py +190 -0
- elo_system/tools/helpers/helper_funcs.py +92 -0
- elo_system/tools/helpers/league.py +151 -0
- elo_system/tools/helpers/scraper.py +109 -0
- elo_system-1.0.0.dist-info/METADATA +79 -0
- elo_system-1.0.0.dist-info/RECORD +41 -0
- elo_system-1.0.0.dist-info/WHEEL +5 -0
- elo_system-1.0.0.dist-info/licenses/LICENSE +21 -0
- elo_system-1.0.0.dist-info/top_level.txt +1 -0
elo_system/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Vendored third-party packages bundled with elo_system."""
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 meisnate12
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# NOTE: Vendored copy of riders994/FantraxAPI (fork of meisnate12/FantraxAPI).
|
|
2
|
+
# Pinned to commit ee81bea250024cba670cd0a5a1a1849150dbb38c (@stable, v1.0.1).
|
|
3
|
+
# Absolute ``fantraxapi`` imports were rewritten to relative imports so the
|
|
4
|
+
# package works under ``elo_system._vendor.fantraxapi``. See ./LICENSE (MIT).
|
|
5
|
+
from .exceptions import FantraxException, NotLoggedIn, NotMemberOfLeague, NotTeamInLeague
|
|
6
|
+
from .objs import League
|
|
7
|
+
from .objs import League as FantraxAPI
|
|
8
|
+
|
|
9
|
+
__version__ = "1.0.1"
|
|
10
|
+
__author__ = "Nathan Taggart"
|
|
11
|
+
__credits__ = "meisnate12"
|
|
12
|
+
__package_name__ = "fantraxapi"
|
|
13
|
+
__project_name__ = "FantraxAPI"
|
|
14
|
+
__description__ = "A lightweight Python library for The Fantrax API."
|
|
15
|
+
__url__ = "https://github.com/meisnate12/FantraxAPI"
|
|
16
|
+
__email__ = "meisnate12@gmail.com"
|
|
17
|
+
__license__ = "MIT License"
|
|
18
|
+
__all__ = [
|
|
19
|
+
"FantraxAPI",
|
|
20
|
+
"FantraxException",
|
|
21
|
+
"NotLoggedIn",
|
|
22
|
+
"NotMemberOfLeague",
|
|
23
|
+
"NotTeamInLeague",
|
|
24
|
+
"League",
|
|
25
|
+
]
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
from datetime import date
|
|
2
|
+
from json.decoder import JSONDecodeError
|
|
3
|
+
from typing import TYPE_CHECKING, ParamSpec
|
|
4
|
+
|
|
5
|
+
from requests import Session
|
|
6
|
+
|
|
7
|
+
from .exceptions import FantraxException, NotLoggedIn, NotMemberOfLeague
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from .objs import League
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
Param: ParamSpec = ParamSpec("Param")
|
|
14
|
+
default_session: Session = Session()
|
|
15
|
+
|
|
16
|
+
debug: bool = False
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Method:
|
|
20
|
+
def __init__(self, name: str, **kwargs: Param.kwargs) -> None:
|
|
21
|
+
self.name: str = name
|
|
22
|
+
self.kwargs: dict = kwargs
|
|
23
|
+
self.response: dict | None = None
|
|
24
|
+
|
|
25
|
+
def msg_block(self, league_id: str) -> dict[str, str]:
|
|
26
|
+
output_data = {"leagueId": league_id}
|
|
27
|
+
for key, value in self.kwargs.items():
|
|
28
|
+
if value is not None:
|
|
29
|
+
if isinstance(value, date):
|
|
30
|
+
output_data[key] = value.strftime("%Y-%m-%d")
|
|
31
|
+
else:
|
|
32
|
+
output_data[key] = str(value)
|
|
33
|
+
return {"method": self.name, "data": output_data}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def request(league: "League", methods: list[Method] | Method) -> dict:
|
|
37
|
+
return _request(league.league_id, methods, session=league.session)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _request(league_id: str, methods: list[Method] | Method, session: Session | None = None) -> list[dict] | dict:
|
|
41
|
+
if not isinstance(methods, list):
|
|
42
|
+
methods = [methods]
|
|
43
|
+
json_data = {"msgs": [m.msg_block(league_id) for m in methods]}
|
|
44
|
+
if session is None:
|
|
45
|
+
session = default_session
|
|
46
|
+
if debug:
|
|
47
|
+
print(f"{'_' * 100} Request JSON {'_' * 100}")
|
|
48
|
+
print(json_data)
|
|
49
|
+
response = session.post("https://www.fantrax.com/fxpa/req", params={"leagueId": league_id}, json=json_data)
|
|
50
|
+
try:
|
|
51
|
+
response_json = response.json()
|
|
52
|
+
except JSONDecodeError as e:
|
|
53
|
+
raise FantraxException(f"Invalid JSON Response to {methods}: {e}\nData: {json_data}")
|
|
54
|
+
if debug:
|
|
55
|
+
print(f"{'-' * 100} Response JSON {'-' * 100}")
|
|
56
|
+
print("-" * 100)
|
|
57
|
+
print(response_json)
|
|
58
|
+
print("^" * 215)
|
|
59
|
+
if response.status_code >= 400:
|
|
60
|
+
raise FantraxException(f"({response.status_code} [{response.reason}]) {response_json}")
|
|
61
|
+
if "pageError" in response_json:
|
|
62
|
+
if "code" in response_json["pageError"]:
|
|
63
|
+
match response_json["pageError"]["code"]:
|
|
64
|
+
case "WARNING_NOT_LOGGED_IN":
|
|
65
|
+
raise NotLoggedIn("Not Logged in")
|
|
66
|
+
case "NOT_MEMBER_OF_LEAGUE":
|
|
67
|
+
raise NotMemberOfLeague("Not Member of League")
|
|
68
|
+
case "UNEXPECTED_ERROR":
|
|
69
|
+
raise FantraxException(f"{response_json['pageError']['title']}")
|
|
70
|
+
case _:
|
|
71
|
+
raise FantraxException(f"{response_json}")
|
|
72
|
+
|
|
73
|
+
return response_json["responses"][0]["data"] if len(methods) == 1 else [r["data"] for r in response_json["responses"]]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def get_init_info(league: "League") -> dict:
|
|
77
|
+
return request(
|
|
78
|
+
league,
|
|
79
|
+
[
|
|
80
|
+
Method("getFantasyLeagueInfo"),
|
|
81
|
+
Method("getRefObject", type="FantasyItemStatus"),
|
|
82
|
+
Method("getLiveScoringStats", newView=True),
|
|
83
|
+
Method("getTeamRosterInfo", view="GAMES_PER_POS"),
|
|
84
|
+
Method("getTeamRosterInfo", view="STATS"),
|
|
85
|
+
],
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def get_pending_transactions(league: "League") -> dict:
|
|
90
|
+
return request(league, Method("getPendingTransactions"))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_standings(league: "League", views: list[str] | str | None = None, **kwargs: Param.kwargs) -> dict:
|
|
94
|
+
if "view" in kwargs and views is None:
|
|
95
|
+
views = kwargs.pop("view")
|
|
96
|
+
if "view" in kwargs:
|
|
97
|
+
del kwargs["view"]
|
|
98
|
+
if not isinstance(views, list):
|
|
99
|
+
views = [views]
|
|
100
|
+
response = request(league, [Method("getStandings", view=v, **kwargs) for v in views])
|
|
101
|
+
responses = response if isinstance(response, list) else [response]
|
|
102
|
+
for res in responses:
|
|
103
|
+
if "fantasyTeamInfo" in res:
|
|
104
|
+
league._update_teams(res["fantasyTeamInfo"])
|
|
105
|
+
return response
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def get_trade_blocks(league: "League") -> dict:
|
|
109
|
+
return request(league, Method("getTradeBlocks"))["tradeBlocks"]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def get_team_roster_position_counts(league: "League", team_id: str, scoring_period_number: int | None = None) -> dict:
|
|
113
|
+
response = request(league, Method("getTeamRosterInfo", teamId=team_id, scoringPeriod=scoring_period_number, view="GAMES_PER_POS"))
|
|
114
|
+
league._update_teams(response["fantasyTeams"])
|
|
115
|
+
return response
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def get_team_roster_info(league: "League", team_id: str, period_number: int | None = None) -> dict:
|
|
119
|
+
responses = request(
|
|
120
|
+
league,
|
|
121
|
+
[
|
|
122
|
+
Method("getTeamRosterInfo", teamId=team_id, period=period_number, view="STATS"),
|
|
123
|
+
Method("getTeamRosterInfo", teamId=team_id, period=period_number, view="SCHEDULE_FULL"),
|
|
124
|
+
],
|
|
125
|
+
)
|
|
126
|
+
league._update_teams(responses[0]["fantasyTeams"])
|
|
127
|
+
return responses
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def get_transaction_history(league: "League", per_page_results: int = 100) -> dict:
|
|
131
|
+
return request(league, Method("getTransactionDetailsHistory", maxResultsPerPage=str(per_page_results)))
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def get_live_scoring_stats(league: "League", scoring_date: date | None = None) -> dict:
|
|
135
|
+
return request(league, Method("getLiveScoringStats", date=scoring_date, newView=True, period="1", playerViewType="1", sppId="-1", viewType="1"))
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from datetime import date, datetime
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class FantraxException(Exception):
|
|
5
|
+
"""Base class for all FantraxAPI exceptions."""
|
|
6
|
+
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DateNotInSeason(FantraxException):
|
|
11
|
+
"""Exception thrown when trying to query with a date not in the Season"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, error_date: str | date | datetime) -> None:
|
|
14
|
+
super().__init__(f"Date: {error_date if isinstance(error_date, str) else error_date.strftime('%Y-%m-%d')} not in the Season.")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class NotLoggedIn(FantraxException):
|
|
18
|
+
"""Exception thrown when accessing a private endpoint without being Logged In"""
|
|
19
|
+
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class NotMemberOfLeague(FantraxException):
|
|
24
|
+
"""Exception thrown when accessing an endpoint without being part of that League"""
|
|
25
|
+
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class NotTeamInLeague(FantraxException):
|
|
30
|
+
"""Exception thrown when trying to query for a Team not part of that League"""
|
|
31
|
+
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class PeriodNotInSeason(FantraxException):
|
|
36
|
+
"""Exception thrown when trying to query with a period not in the Season"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, error_date: str | int) -> None:
|
|
39
|
+
super().__init__(f"Period: {error_date} not in the Season.")
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from .game import Game
|
|
2
|
+
from .league import League
|
|
3
|
+
from .player import LivePlayer, Player
|
|
4
|
+
from .position import Position, PositionCount
|
|
5
|
+
from .roster import Roster, RosterRow
|
|
6
|
+
from .scoring_period import Matchup, ScoringPeriod, ScoringPeriodResult
|
|
7
|
+
from .standings import Record, Standings
|
|
8
|
+
from .status import Status
|
|
9
|
+
from .team import Team
|
|
10
|
+
from .trade import Trade, TradeDraftPick, TradePlayer
|
|
11
|
+
from .trade_block import TradeBlock
|
|
12
|
+
from .transaction import Transaction, TransactionPlayer
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"TradeDraftPick",
|
|
16
|
+
"Game",
|
|
17
|
+
"League",
|
|
18
|
+
"LivePlayer",
|
|
19
|
+
"Matchup",
|
|
20
|
+
"Player",
|
|
21
|
+
"Position",
|
|
22
|
+
"PositionCount",
|
|
23
|
+
"Record",
|
|
24
|
+
"Roster",
|
|
25
|
+
"RosterRow",
|
|
26
|
+
"ScoringPeriod",
|
|
27
|
+
"ScoringPeriodResult",
|
|
28
|
+
"Standings",
|
|
29
|
+
"Status",
|
|
30
|
+
"Team",
|
|
31
|
+
"Trade",
|
|
32
|
+
"TradeBlock",
|
|
33
|
+
"TradePlayer",
|
|
34
|
+
"Transaction",
|
|
35
|
+
"TransactionPlayer",
|
|
36
|
+
]
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Small parsing helpers shared across the data-model classes.
|
|
2
|
+
|
|
3
|
+
These centralise the brittle string/number parsing that Fantrax responses
|
|
4
|
+
require (comma thousands separators, bracketed date ranges, trailing period
|
|
5
|
+
numbers) so the same idioms aren't repeated, and so malformed data raises a
|
|
6
|
+
clear :class:`~fantraxapi.exceptions.FantraxException` instead of an opaque
|
|
7
|
+
``AttributeError``/``IndexError``.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
from datetime import date, datetime
|
|
12
|
+
from decimal import Decimal, InvalidOperation
|
|
13
|
+
|
|
14
|
+
from ..exceptions import FantraxException
|
|
15
|
+
|
|
16
|
+
# Characters that wrap a date range caption, e.g. "(Oct 12/24 - Oct 18/24)".
|
|
17
|
+
_RANGE_WRAPPERS = "()[] "
|
|
18
|
+
_PERIOD_SUFFIX = re.compile(r"(\d+)$")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def parse_float(value: object, default: float = 0.0) -> float:
|
|
22
|
+
"""Parse a float from a Fantrax cell value.
|
|
23
|
+
|
|
24
|
+
Handles ``None``, blank/``"-"`` placeholders and comma thousands
|
|
25
|
+
separators, falling back to ``default`` when the value can't be parsed.
|
|
26
|
+
"""
|
|
27
|
+
if value is None:
|
|
28
|
+
return default
|
|
29
|
+
text = str(value).strip().replace(",", "")
|
|
30
|
+
if not text or text == "-":
|
|
31
|
+
return default
|
|
32
|
+
try:
|
|
33
|
+
return float(text)
|
|
34
|
+
except ValueError:
|
|
35
|
+
return default
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def parse_decimal(value: object, default: Decimal = Decimal("0")) -> Decimal:
|
|
39
|
+
"""Parse a :class:`~decimal.Decimal` from a Fantrax cell value.
|
|
40
|
+
|
|
41
|
+
Like :func:`parse_float` but preserves exact decimal scores.
|
|
42
|
+
"""
|
|
43
|
+
if value is None:
|
|
44
|
+
return default
|
|
45
|
+
text = str(value).strip().replace(",", "")
|
|
46
|
+
if not text or text == "-":
|
|
47
|
+
return default
|
|
48
|
+
try:
|
|
49
|
+
return Decimal(text)
|
|
50
|
+
except InvalidOperation:
|
|
51
|
+
return default
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def parse_date_range(caption: str, fmt: str) -> tuple[date, date]:
|
|
55
|
+
"""Parse a ``"(<start> - <end>)"`` caption into ``(start, end)`` dates.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
caption: Bracketed caption such as ``"(Oct 12/24 - Oct 18/24)"``.
|
|
59
|
+
fmt: ``datetime.strptime`` format for each side of the range.
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
FantraxException: When the caption doesn't contain a parseable range.
|
|
63
|
+
"""
|
|
64
|
+
parts = caption.strip(_RANGE_WRAPPERS).split(" - ")
|
|
65
|
+
if len(parts) != 2:
|
|
66
|
+
raise FantraxException(f"Could not parse date range from caption: {caption!r}")
|
|
67
|
+
try:
|
|
68
|
+
return (
|
|
69
|
+
datetime.strptime(parts[0], fmt).date(),
|
|
70
|
+
datetime.strptime(parts[1], fmt).date(),
|
|
71
|
+
)
|
|
72
|
+
except ValueError as e:
|
|
73
|
+
raise FantraxException(f"Could not parse date range from caption: {caption!r}: {e}")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def period_number(caption: str) -> int:
|
|
77
|
+
"""Extract the trailing period number from a caption.
|
|
78
|
+
|
|
79
|
+
Raises:
|
|
80
|
+
FantraxException: When the caption has no trailing number.
|
|
81
|
+
"""
|
|
82
|
+
match = _PERIOD_SUFFIX.search(caption)
|
|
83
|
+
if match is None:
|
|
84
|
+
raise FantraxException(f"Could not find a period number in caption: {caption!r}")
|
|
85
|
+
return int(match.group(1))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from .league import League
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FantraxBaseObject:
|
|
8
|
+
def __init__(self, league: "League", data: dict | list[dict]) -> None:
|
|
9
|
+
self.league: "League" = league
|
|
10
|
+
self._data: dict | list[dict] = data
|
|
11
|
+
|
|
12
|
+
def __repr__(self) -> str:
|
|
13
|
+
return self.__str__()
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from datetime import date, datetime, time
|
|
2
|
+
from typing import TYPE_CHECKING, Self
|
|
3
|
+
|
|
4
|
+
from ..exceptions import DateNotInSeason
|
|
5
|
+
from .base import FantraxBaseObject
|
|
6
|
+
from .player import Player
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from .league import League
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Game(FantraxBaseObject):
|
|
13
|
+
"""Represents a single Game.
|
|
14
|
+
|
|
15
|
+
Attributes:
|
|
16
|
+
league (League): The League instance this object belongs to.
|
|
17
|
+
id (str): Game ID.
|
|
18
|
+
player (Player): Player to view this game from.
|
|
19
|
+
date (date): The date this game is played.
|
|
20
|
+
opponent (str): NHL Short Name of the opponent.
|
|
21
|
+
time (time): Time of the game start if it hasn't been played yet.
|
|
22
|
+
home (bool): Is Player Home?
|
|
23
|
+
away (bool): Is Player Away?
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, league: "League", player: Player, game_date: str, data: dict) -> None:
|
|
28
|
+
super().__init__(league, data)
|
|
29
|
+
self.id: str = self._data["eventId"]
|
|
30
|
+
self.player: Player = player
|
|
31
|
+
start = datetime.strptime(f"{game_date} {self.league.start_date.year}", "%a %m/%d %Y").date()
|
|
32
|
+
end = datetime.strptime(f"{game_date} {self.league.end_date.year}", "%a %m/%d %Y").date()
|
|
33
|
+
league_start = self.league.start_date.date()
|
|
34
|
+
league_end = self.league.end_date.date()
|
|
35
|
+
if league_end >= start >= league_start:
|
|
36
|
+
self.date: date = start
|
|
37
|
+
elif league_end >= end >= league_start:
|
|
38
|
+
self.date: date = end
|
|
39
|
+
else:
|
|
40
|
+
raise DateNotInSeason(game_date)
|
|
41
|
+
|
|
42
|
+
self.time: time | None = None
|
|
43
|
+
parts = data["content"].removesuffix(" F").split("\u003cbr/\u003e")
|
|
44
|
+
if ":" in parts[1]:
|
|
45
|
+
self.opponent: str = parts[0]
|
|
46
|
+
if self.opponent.startswith("@"):
|
|
47
|
+
self.opponent = self.opponent[1:]
|
|
48
|
+
home = self.player.team_short_name
|
|
49
|
+
else:
|
|
50
|
+
home = self.opponent
|
|
51
|
+
|
|
52
|
+
self.time = datetime.strptime(parts[1].split(" ")[1], "%I:%M%p").time()
|
|
53
|
+
else:
|
|
54
|
+
home = "".join(i for i in parts[0] if not i.isdigit() and i not in [" ", "@"])
|
|
55
|
+
away = "".join(i for i in parts[1] if not i.isdigit() and i not in [" ", "@"])
|
|
56
|
+
self.opponent = away if home == self.player.team_short_name else home
|
|
57
|
+
self.home: bool = home == self.player.team_short_name
|
|
58
|
+
self.away: bool = home != self.player.team_short_name
|
|
59
|
+
|
|
60
|
+
def __eq__(self, other: Self) -> bool:
|
|
61
|
+
return self.id == other.id
|
|
62
|
+
|
|
63
|
+
def __hash__(self) -> int:
|
|
64
|
+
return hash(("Game", self.id))
|
|
65
|
+
|
|
66
|
+
def __str__(self) -> str:
|
|
67
|
+
return f"[{self.id}:{f'{self.opponent} @{self.player.team_short_name}' if self.home else f'{self.player.team_short_name} @{self.opponent}'}{f' {self.time}' if self.time else ''}]"
|