Skip to content

Commit

Permalink
fix: fixed age and birthday support for all locales (#111)
Browse files Browse the repository at this point in the history
  • Loading branch information
TeKrop authored Apr 17, 2024
1 parent d373566 commit 87673db
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 18 deletions.
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ else
endif

# Run OverFastAPI application (production mode)
up: down
up:
@echo "Building OverFastAPI (production mode)..."
docker compose build
@echo "Stopping OverFastAPI and cleaning containers..."
docker compose down -v --remove-orphans
@echo "Launching OverFastAPI (production mode)..."
docker compose up -d

Expand Down
30 changes: 26 additions & 4 deletions app/parsers/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import unicodedata
from functools import cache

from app.common.enums import CompetitiveDivision, CompetitiveRole, HeroKey, Role
from app.common.enums import CompetitiveDivision, CompetitiveRole, HeroKey, Locale, Role
from app.common.helpers import read_csv_data_file
from app.config import settings

Expand Down Expand Up @@ -308,13 +308,35 @@ def get_plural_stat_key(stat_key: str) -> str:
return stat_keys_mapping.get(stat_key, stat_key)


def get_birthday_and_age(birthday_age_text: str) -> tuple[str | None, int | None]:
def get_birthday_and_age(text: str, locale: Locale) -> tuple[str | None, int | None]:
"""Get birthday and age from text for a given hero"""
result = re.match(r"^(.*) \(Age: (\d+)\)$", birthday_age_text)

# Regex matching the birthday for every known locale
birthday_regex = r"^(.*) [\((].*[::] ?(\d+).*[\))]$"

result = re.match(birthday_regex, text)
if not result:
return None, None

birthday = result[1] if result[1] != "Unknown" else None
# Text corresponding to "Unknown" in the locale of the page
unknown_texts = {
Locale.GERMAN: "Unbekannt",
Locale.ENGLISH_EU: "Unknown",
Locale.ENGLISH_US: "Unknown",
Locale.SPANISH_EU: "Desconocido",
Locale.SPANISH_LATIN: "Desconocido",
Locale.FRENCH: "Inconnu",
Locale.ITALIANO: "Sconosciuto",
Locale.JAPANESE: "不明",
Locale.KOREAN: "알 수 없음",
Locale.POLISH: "Nieznane",
Locale.PORTUGUESE_BRAZIL: "Desconhecido",
Locale.RUSSIAN: "Неизвестно",
Locale.CHINESE_TAIWAN: "未知",
}
unknown_text = unknown_texts.get(locale, "Unknown")

birthday = result[1] if result[1] != unknown_text else None
age = int(result[2]) if result[2] else None

return birthday, age
13 changes: 9 additions & 4 deletions app/parsers/hero_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from bs4 import Tag
from fastapi import status

from app.common.enums import MediaType
from app.common.enums import Locale, MediaType
from app.common.exceptions import ParserBlizzardError
from app.config import settings

Expand All @@ -23,6 +23,10 @@ class HeroParser(APIParser):
404, # Hero Not Found response, we want to handle it here
]

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.locale = kwargs.get("locale") or Locale.ENGLISH_US

def get_blizzard_url(self, **kwargs) -> str:
return f"{super().get_blizzard_url(**kwargs)}/{kwargs.get('hero_key')}"

Expand All @@ -49,11 +53,12 @@ def parse_data(self) -> dict:
"story": self.__get_story(lore_section),
}

@staticmethod
def __get_summary(overview_section: Tag) -> dict:
def __get_summary(self, overview_section: Tag) -> dict:
header_section = overview_section.find("blz-header")
extra_list_items = overview_section.find("blz-list").find_all("blz-list-item")
birthday, age = get_birthday_and_age(extra_list_items[2].get_text())
birthday, age = get_birthday_and_age(
text=extra_list_items[2].get_text(), locale=self.locale
)

return {
"name": header_section.find("h2").get_text(),
Expand Down
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "overfast-api"
version = "2.28.0"
version = "2.28.1"
description = "Overwatch API giving data about heroes, maps, and players statistics."
license = "MIT"
authors = ["Valentin PORCHET <[email protected]>"]
Expand Down Expand Up @@ -116,6 +116,8 @@ ignore = [
"Q003", # avoidable escape quote
"W191" # tab indentation detected instead of spaces
]
# Allow some confusable UTF8 chars (used in regexp)
allowed-confusables = ["", "", ""]

[tool.ruff.lint.isort]
# Consider app as first-party for imports in tests
Expand Down
33 changes: 25 additions & 8 deletions tests/parsers/test_helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from app.common.enums import CompetitiveDivision, CompetitiveRole, HeroKey
from app.common.enums import CompetitiveDivision, CompetitiveRole, HeroKey, Locale
from app.config import settings
from app.parsers import helpers

Expand Down Expand Up @@ -254,17 +254,34 @@ def test_get_hero_role(hero_key: HeroKey):


@pytest.mark.parametrize(
("input_str", "result"),
("input_str", "locale", "result"),
[
# Classic cases
("Aug 19 (Age: 37)", ("Aug 19", 37)),
("May 9 (Age: 1)", ("May 9", 1)),
("Aug 19 (Age: 37)", Locale.ENGLISH_US, ("Aug 19", 37)),
("May 9 (Age: 1)", Locale.ENGLISH_US, ("May 9", 1)),
# Specific unknown case (bastion)
("Unknown (Age: 32)", (None, 32)),
("Unknown (Age: 32)", Locale.ENGLISH_US, (None, 32)),
# Specific venture case (not the same spacing)
("Aug 6 (Age : 26)", Locale.ENGLISH_US, ("Aug 6", 26)),
("Aug 6 (Age : 26)", Locale.ENGLISH_EU, ("Aug 6", 26)),
# Other languages than english
("6. Aug. (Alter: 26)", Locale.GERMAN, ("6. Aug.", 26)),
("6 ago (Edad: 26)", Locale.SPANISH_EU, ("6 ago", 26)),
("6 ago (Edad: 26)", Locale.SPANISH_LATIN, ("6 ago", 26)),
("6 août (Âge : 26 ans)", Locale.FRENCH, ("6 août", 26)),
("6 ago (Età: 26)", Locale.ITALIANO, ("6 ago", 26)),
("8月6日 (年齢: 26)", Locale.JAPANESE, ("8月6日", 26)),
("8월 6일 (나이: 26세)", Locale.KOREAN, ("8월 6일", 26)),
("6 sie (Wiek: 26 lat)", Locale.POLISH, ("6 sie", 26)),
("6 de ago. (Idade: 26)", Locale.PORTUGUESE_BRAZIL, ("6 de ago.", 26)),
("6 авг. (Возраст: 26)", Locale.RUSSIAN, ("6 авг.", 26)),
("8月6日 (年齡:26)", Locale.CHINESE_TAIWAN, ("8月6日", 26)),
# Invalid case
("Unknown", (None, None)),
("Unknown", Locale.ENGLISH_US, (None, None)),
],
)
def test_get_birthday_and_age(input_str: str, result: tuple[str | None, int | None]):
def test_get_birthday_and_age(
input_str: str, locale: Locale, result: tuple[str | None, int | None]
):
"""Get birthday and age from text for a given hero"""
assert helpers.get_birthday_and_age(input_str) == result
assert helpers.get_birthday_and_age(input_str, locale) == result

0 comments on commit 87673db

Please sign in to comment.