Skip to content

Commit

Permalink
added version parsing to schema and appropriate tests
Browse files Browse the repository at this point in the history
  • Loading branch information
cesaregarza committed Nov 4, 2022
1 parent b5bfa2d commit b0c4b90
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 20 deletions.
12 changes: 7 additions & 5 deletions squidalytics/data/scrape_leanny.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ def enumerate_versions(return_soup: bool = False) -> list[str] | ResultSet:
@cache
def get_version_url(version: str | None = None) -> str:
"""Get the URL for the specified version of the datamine. If no version is
specified, get the latest version.
specified, get the latest version. If the version is not found, return the
previous version.
Args:
version (str | None): The version to get the URL for. If None, get the
Expand All @@ -50,14 +51,15 @@ def get_version_url(version: str | None = None) -> str:
"""
versions = enumerate_versions(return_soup=True)
versions_text = [(version.text, i) for i, version in enumerate(versions)]
versions_text.sort(key=lambda x: x[0])
if version is None:
versions_text.sort(key=lambda x: x[0])
selected_version_idx = versions_text[-1][1]
else:
version = version.replace("v", "").replace(".", "")
selected_version_idx = [x[1] for x in versions_text if x[0] == version][
0
]
# Leanny's datamine does not include changes that do not affect gameplay
# such as bug fixes, so we get the highest version that is less than or
# equal to the specified version.
selected_version_idx = [i for v, i in versions_text if v <= version][-1]
selected_version_soup = versions[selected_version_idx]
out_url: str = RAW_URL + selected_version_soup["href"]
out_url = out_url.replace("/tree", "")
Expand Down
70 changes: 55 additions & 15 deletions squidalytics/schemas/battle.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from dataclasses import dataclass
from datetime import datetime
from functools import cached_property
from typing import Any

import numpy as np
Expand Down Expand Up @@ -183,9 +185,13 @@ class playerFullSchema(playerSchema):
weapon: weaponSchema
result: resultSchema = None

def summary(self) -> dict:
def summary(self, version: str | None = None) -> dict:
"""Return a summary of the player's battle stats.
Args:
version (str | None, optional): The version of the game to use for
the weapon details. Defaults to None.
Returns:
dict: A dictionary of the player's stats.
"""
Expand All @@ -197,7 +203,7 @@ def summary(self) -> dict:
"species": self.species,
"paint": self.paint,
}
out["weapon_details"] = self.weapon_details
out["weapon_details"] = self.weapon_details(version=version)
if self.result:
append = {
"elimination": self.result.kill,
Expand All @@ -217,9 +223,10 @@ def summary(self) -> dict:
out.update(append)
return out

@property
def weapon_details(self) -> dict:
return WEAPON_MAP.versus_weapons[self.weapon.name]
def weapon_details(self, version: str | None = None) -> dict:
if version is None:
return WEAPON_MAP.versus_weapons[self.weapon.name]
return WEAPON_MAP[version].versus_weapons[self.weapon.name]


@dataclass(repr=False)
Expand Down Expand Up @@ -255,19 +262,23 @@ def score(self) -> int | float:
else:
return 0

def player_summary(self, detailed: bool = False) -> list[dict[str, Any]]:
def player_summary(
self, detailed: bool = False, version: str | None = None
) -> list[dict[str, Any]]:
"""Get a summary of the team's players.
Args:
detailed (bool): Whether to include detailed information about the
player. Defaults to False.
version (str | None, optional): The version of the game to use for
the weapon details. Defaults to None.
Returns:
list[dict]: A list of dictionaries containing the player's stats.
"""
out: list[dict[str, Any]] = []
for player in self.players:
out.append(player.summary())
out.append(player.summary(version=version))
if not detailed:
return out
# Add additional information if detailed is True.
Expand All @@ -288,7 +299,10 @@ def ratio(key: str) -> float:
return out

def team_summary(
self, player_summaries: list[dict] | None = None, detailed: bool = False
self,
player_summaries: list[dict] | None = None,
detailed: bool = False,
version: str | None = None,
) -> dict:
"""Get an overall summary of the team.
Expand All @@ -299,12 +313,16 @@ def team_summary(
Defaults to None.
detailed (bool): Whether to include detailed information about the
team. Defaults to False.
version (str | None, optional): The version of the game to use for
the weapon details. Defaults to None.
Returns:
dict: A dictionary of team statistics.
"""
if player_summaries is None:
player_summaries = [player.summary() for player in self.players]
player_summaries = [
player.summary(version=version) for player in self.players
]
team_total = {
"kill": sum(player["kill"] for player in player_summaries),
"death": sum(player["death"] for player in player_summaries),
Expand Down Expand Up @@ -384,7 +402,9 @@ def my_stats(self, detailed: bool = False) -> dict:
Returns:
dict: A dictionary of the user's team's stats.
"""
players_summary = self.myTeam.player_summary(detailed=detailed)
players_summary = self.myTeam.player_summary(
detailed=detailed, version=self.version
)
for player in players_summary:
if player["name"] == self.player.full_name:
return player
Expand All @@ -409,19 +429,39 @@ def summary(self, detailed: bool = False) -> dict:
"knockout": self.knockout,
"duration": self.duration,
"played_time": self.playedTime,
"version": self.version,
"my_stats": self.my_stats(),
"my_team": self.myTeam.player_summary(detailed=True),
"my_team": self.myTeam.player_summary(
detailed=True, version=self.version
),
"other_teams": [
team.player_summary(detailed=True) for team in self.otherTeams
team.player_summary(detailed=True, version=self.version)
for team in self.otherTeams
],
"awards": self.count_awards(),
"my_team_stats": self.myTeam.team_summary(detailed=detailed),
"my_team_stats": self.myTeam.team_summary(
detailed=detailed, version=self.version
),
"other_team_stats": [
team.team_summary(detailed=detailed) for team in self.otherTeams
team.team_summary(detailed=detailed, version=self.version)
for team in self.otherTeams
],
}
return out

@cached_property
def version(self) -> str:
return map_date_to_version(self.played_time_dt)

@cached_property
def played_time_dt(self) -> datetime:
"""Get the time the match was played as a datetime object.
Returns:
datetime: The time the match was played.
"""
return datetime.strptime(self.playedTime, "%Y-%m-%dT%H:%M:%SZ")


@dataclass(repr=False)
class battleDataSchema(JSONDataClass):
Expand Down Expand Up @@ -507,7 +547,7 @@ def to_pandas(self, detailed: bool = False) -> pd.DataFrame:
df["played_time"] = pd.to_datetime(df["played_time"])
df["duration"] = pd.to_timedelta(df["duration"], "s")
df["end_time"] = df["played_time"] + df["duration"]
df["version"] = df["played_time"].map(map_date_to_version)
# df["version"] = df["played_time"].map(map_date_to_version)
return df

def winrate_heatmap(
Expand Down
1 change: 1 addition & 0 deletions tests/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ class TestAnarchySchema:
"knockout": "NEITHER",
"duration": 300,
"played_time": "2022-10-04T06:30:14Z",
"version": "1.1.2",
"weapon": "Splatterscope",
"paint": 1073,
"elimination": 8,
Expand Down

0 comments on commit b0c4b90

Please sign in to comment.