Source code for tibiapy.kill_statistics

"""Models related to the kill statistics section in Tibia.com."""
from typing import Dict, List

from tibiapy import abc
from tibiapy.errors import InvalidContent
from tibiapy.utils import get_tibia_url, parse_form_data, parse_tibiacom_content

__all__ = (
    "KillStatistics",
    "RaceEntry",
)


[docs]class KillStatistics(abc.Serializable): """Represents the kill statistics of a world. Attributes ---------- world: :class:`str` The world the statistics belong to. entries: :class:`dict` A dictionary of kills entries of every race, where the key is the name of the race. total: :class:`RaceEntry` The kill statistics totals. available_worlds: :class:`list` of :class:`str` The list of worlds available for selection. """ __slots__ = ( "world", "total", "entries", "available_worlds", ) def __init__(self, world, entries=None, total=None, available_worlds=None): self.world: str = world self.entries: Dict[str, RaceEntry] = entries or {} self.total: RaceEntry = total or RaceEntry() self.available_worlds: List[str] = available_worlds or [] @property def url(self): """:class:`str`: The URL to the kill statistics page on Tibia.com containing the results.""" return self.get_url(self.world) @property def players(self): """:class:`RaceEntry`: The kill statistics for players.""" return self.entries.get("players", RaceEntry())
[docs] @classmethod def get_url(cls, world): """Get the Tibia.com URL of the kill statistics of a world. Parameters ---------- world: :class:`str` The game world of the desired kill statistics. Returns ------- The URL to the Tibia.com kill statistics for this world. """ return get_tibia_url("community", "killstatistics", world=world)
[docs] @classmethod def from_content(cls, content): """Create an instance of the class from the HTML content of the kill statistics' page. Parameters ----------- content: :class:`str` The HTML content of the page. Returns ---------- :class:`KillStatistics` The kill statistics contained in the page or None if it doesn't exist. Raises ------ InvalidContent If content is not the HTML of a kill statistics' page. """ try: parsed_content = parse_tibiacom_content(content) entries_table = parsed_content.find('table', attrs={'border': '0', 'cellpadding': '3'}) form = parsed_content.find("form") data = parse_form_data(form, include_options=True) world = data["world"] available_worlds = list(data["__options__"]["world"].values()) if not entries_table: entries_table = parsed_content.find("table", {"class": "Table3"}) # If the entries table doesn't exist, it means that this belongs to an nonexistent or unselected world. if entries_table is None: return None header, subheader, *rows = entries_table.find_all('tr') entries = {} total = None for i, row in enumerate(rows): columns_raw = row.find_all('td') columns = [c.text.replace('\xa0', ' ').strip() for c in columns_raw] if not columns[2].isnumeric(): continue entry = RaceEntry(last_day_players_killed=int(columns[1]), last_day_killed=int(columns[2]), last_week_players_killed=int(columns[3]), last_week_killed=int(columns[4])) if i == len(rows) - 1: total = entry else: entries[columns[0]] = entry return cls(world, entries, total, available_worlds=available_worlds) except (AttributeError, KeyError) as e: raise InvalidContent("content does not belong to a Tibia.com kill statistics page.", e)
[docs]class RaceEntry(abc.Serializable): """Represents the statistics of a race. Attributes ---------- last_day_killed: :class:`int` Number of creatures of this race killed in the last day. last_day_players_killed: :class:`int` Number of players killed by this race in the last day. last_week_killed: :class:`int` Number of creatures of this race killed in the last week. last_week_players_killed: :class:`int` Number of players killed by this race in the last week. """ __slots__ = ( "last_day_killed", "last_day_players_killed", "last_week_killed", "last_week_players_killed", ) def __init__(self, last_day_killed=0, last_day_players_killed=0, last_week_killed=0, last_week_players_killed=0): self.last_day_killed: int = last_day_killed self.last_day_players_killed: int = last_day_players_killed self.last_week_killed: int = last_week_killed self.last_week_players_killed: int = last_week_players_killed def __repr__(self): return "<{0.__class__.__name__} last_day_killed={0.last_day_killed}" \ " last_day_players_killed={0.last_day_players_killed} last_week_killed={0.last_week_killed}" \ " last_week_players_killed={0.last_week_players_killed}>" \ .format(self) def __eq__(self, other): return isinstance(other, self.__class__) and \ self.last_day_killed == other.last_day_killed and \ self.last_day_players_killed == other.last_day_players_killed and \ self.last_week_killed == other.last_week_killed and \ self.last_week_players_killed == other.last_week_players_killed