diff --git a/.env.example b/.env.example
index 969477a9..ff24da67 100644
--- a/.env.example
+++ b/.env.example
@@ -17,7 +17,7 @@ USE_API_CACHE_IN_APP=false
EXPIRED_CACHE_REFRESH_LIMIT=3600
HEROES_PATH_CACHE_TIMEOUT=86400
HERO_PATH_CACHE_TIMEOUT=86400
-HOME_PATH_CACHE_TIMEOUT=86400
+CSV_CACHE_TIMEOUT=86400
CAREER_PATH_CACHE_TIMEOUT=7200
SEARCH_ACCOUNT_PATH_CACHE_TIMEOUT=3600
NAMECARDS_TIMEOUT=7200
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a3ce9e32..d3532057 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -5,6 +5,7 @@ This guide aims to help you in contributing in OverFast API. The first step for
As of now, only some specific stuff can easily be updated by anyone, even without any knowledge in Python or FastAPI framework. If I take too much time to update them, don't hesitate to make a PR if you need up-to-date data :
- The CSV file containing basic heroes data : name, role, and some statistics like health, armor and shields
+- The CSV file containing the list of gamemodes of the game
- The CSV file containing the list of maps of the game
## 🦸 Heroes data
@@ -16,6 +17,12 @@ The CSV file containing heroes statistics data is located in `app/data/heroes.cs
- `armor` : Armor of the hero, mainly possessed by tanks
- `shields` : Shields of the hero
+## 🎲 Gamemodes list
+The CSV file containing gamemodes list is located in `app/data/gamemodes.csv`. Data is divided into 3 columns :
+- `key` : Key of the gamemode, used in URLs of the API, and for the name of the corresponding screenshot and icon files
+- `name` : Name of the gamemode (in english)
+- `description` : Description of the gamemode (in english)
+
## 🗺️ Maps list
The CSV file containing maps list is located in `app/data/maps.csv`. Data is divided into 5 columns :
- `key` : Key of the map, used in URLs of the API, and for the name of the corresponding screenshot file
diff --git a/app/commands/check_and_update_cache.py b/app/commands/check_and_update_cache.py
index 5622c42a..eb178425 100644
--- a/app/commands/check_and_update_cache.py
+++ b/app/commands/check_and_update_cache.py
@@ -10,8 +10,8 @@
from app.common.helpers import overfast_internal_error
from app.common.logging import logger
from app.config import settings
-from app.parsers.abstract_parser import AbstractParser
from app.parsers.gamemodes_parser import GamemodesParser
+from app.parsers.generics.abstract_parser import AbstractParser
from app.parsers.hero_parser import HeroParser
from app.parsers.heroes_parser import HeroesParser
from app.parsers.heroes_stats_parser import HeroesStatsParser
diff --git a/app/common/enums.py b/app/common/enums.py
index 67abcb33..72c9041a 100644
--- a/app/common/enums.py
+++ b/app/common/enums.py
@@ -132,16 +132,13 @@ class Locale(StrEnum):
CHINESE_TAIWAN = "zh-tw"
-class MapGamemode(StrEnum):
- """Maps gamemodes keys"""
-
- ASSAULT = "assault"
- CAPTURE_THE_FLAG = "capture-the-flag"
- CONTROL = "control"
- DEATHMATCH = "deathmatch"
- ELIMINATION = "elimination"
- ESCORT = "escort"
- FLASHPOINT = "flashpoint"
- HYBRID = "hybrid"
- PUSH = "push"
- TEAM_DEATHMATCH = "team-deathmatch"
+# Dynamically create the MapGamemode enum by using the CSV File
+gamemodes_data = read_csv_data_file("gamemodes.csv")
+MapGamemode = StrEnum(
+ "MapGamemode",
+ {
+ gamemode["key"].upper().replace("-", "_"): gamemode["key"]
+ for gamemode in gamemodes_data
+ },
+)
+MapGamemode.__doc__ = "Maps gamemodes keys"
diff --git a/app/config.py b/app/config.py
index 3b88f07d..a9dd53d9 100644
--- a/app/config.py
+++ b/app/config.py
@@ -88,8 +88,8 @@ class Settings(BaseSettings):
# Cache TTL for specific hero data (seconds)
hero_path_cache_timeout: int = 86400
- # Cache TTL for Blizzard homepage data : gamemodes and roles (seconds)
- home_path_cache_timeout: int = 86400
+ # Cache TTL for local CSV-based data : heroes stats, gamemodes and maps
+ csv_cache_timeout: int = 86400
# Cache TTL for career pages data (seconds)
career_path_cache_timeout: int = 7200
diff --git a/app/data/gamemodes.csv b/app/data/gamemodes.csv
new file mode 100644
index 00000000..41d05439
--- /dev/null
+++ b/app/data/gamemodes.csv
@@ -0,0 +1,11 @@
+key,name,description
+assault,Assault,"Teams fight to capture or defend two successive points against the enemy team. It's an inactive Overwatch 1 gamemode, also called 2CP."
+capture-the-flag,Capture the Flag,Teams compete to capture the enemy team’s flag while defending their own.
+control,Control,Teams fight to hold a single objective. The first team to win two rounds wins the map.
+deathmatch,Deathmatch,Race to reach 20 points first by racking up kills in a free-for-all format.
+elimination,Elimination,"Dispatch all enemies to win the round. Win three rounds to claim victory. Available with teams of one, three, or six."
+escort,Escort,"One team escorts a payload to its delivery point, while the other races to stop them."
+flashpoint,Flashpoint,"Teams fight for control of key positions across the map, aiming to capture three of them before their opponents do."
+hybrid,Hybrid,"Attackers capture a payload, then escort it to its destination; defenders try to hold them back."
+push,Push,Teams battle to take control of a robot and push it toward the enemy base.
+team-deathmatch,Team Deathmatch,Team up and triumph over your enemies by scoring the most kills.
diff --git a/app/handlers/list_gamemodes_request_handler.py b/app/handlers/list_gamemodes_request_handler.py
index 4da2a417..7c5c7532 100644
--- a/app/handlers/list_gamemodes_request_handler.py
+++ b/app/handlers/list_gamemodes_request_handler.py
@@ -13,4 +13,4 @@ class ListGamemodesRequestHandler(APIRequestHandler):
"""
parser_classes: ClassVar[list] = [GamemodesParser]
- timeout = settings.home_path_cache_timeout
+ timeout = settings.csv_cache_timeout
diff --git a/app/handlers/list_maps_request_handler.py b/app/handlers/list_maps_request_handler.py
index 9f54a0cb..3ba6493a 100644
--- a/app/handlers/list_maps_request_handler.py
+++ b/app/handlers/list_maps_request_handler.py
@@ -13,4 +13,4 @@ class ListMapsRequestHandler(APIRequestHandler):
"""
parser_classes: ClassVar[list] = [MapsParser]
- timeout = settings.home_path_cache_timeout
+ timeout = settings.csv_cache_timeout
diff --git a/app/parsers/gamemodes_parser.py b/app/parsers/gamemodes_parser.py
index d2f224aa..2d4ef6f7 100644
--- a/app/parsers/gamemodes_parser.py
+++ b/app/parsers/gamemodes_parser.py
@@ -1,47 +1,27 @@
"""Gamemodes Parser module"""
-from app.config import settings
-from .api_parser import APIParser
+from .generics.csv_parser import CSVParser
-class GamemodesParser(APIParser):
+class GamemodesParser(CSVParser):
"""Overwatch map gamemodes list page Parser class"""
- root_path = settings.home_path
- timeout = settings.home_path_cache_timeout
+ filename = "gamemodes"
def parse_data(self) -> list[dict]:
- gamemodes_container = (
- self.root_tag.find("div", class_="maps", recursive=False)
- .find("blz-carousel-section", recursive=False)
- .find("blz-carousel", recursive=False)
- )
-
- gamemodes_extras = [
- {
- "key": feature_div["label"],
- "description": (
- feature_div.find("blz-header")
- .find("div", slot="description")
- .get_text()
- .strip()
- ),
- "screenshot": feature_div.find("blz-image")["src:min-plus"],
- }
- for feature_div in gamemodes_container.find_all("blz-feature")
- ]
-
return [
{
- "key": gamemodes_extras[gamemode_index]["key"],
- "name": gamemode_div.get_text(),
- "icon": gamemode_div.find("blz-image")["src:min-plus"],
- "description": gamemodes_extras[gamemode_index]["description"],
- "screenshot": gamemodes_extras[gamemode_index]["screenshot"],
- }
- for gamemode_index, gamemode_div in enumerate(
- gamemodes_container.find("blz-tab-controls").find_all(
- "blz-tab-control",
+ "key": gamemode["key"],
+ "name": gamemode["name"],
+ "icon": self.get_static_url(
+ f"{gamemode['key']}-icon",
+ extension="svg",
),
- )
+ "description": gamemode["description"],
+ "screenshot": self.get_static_url(
+ gamemode["key"],
+ extension="avif",
+ ),
+ }
+ for gamemode in self.csv_data
]
diff --git a/app/parsers/generics/__init__.py b/app/parsers/generics/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/app/parsers/abstract_parser.py b/app/parsers/generics/abstract_parser.py
similarity index 100%
rename from app/parsers/abstract_parser.py
rename to app/parsers/generics/abstract_parser.py
diff --git a/app/parsers/api_parser.py b/app/parsers/generics/api_parser.py
similarity index 100%
rename from app/parsers/api_parser.py
rename to app/parsers/generics/api_parser.py
diff --git a/app/parsers/generics/csv_parser.py b/app/parsers/generics/csv_parser.py
new file mode 100644
index 00000000..7419df04
--- /dev/null
+++ b/app/parsers/generics/csv_parser.py
@@ -0,0 +1,45 @@
+"""Abstract API Parser module"""
+from abc import abstractmethod
+
+from app.common.helpers import read_csv_data_file
+from app.config import settings
+
+from .abstract_parser import AbstractParser
+
+
+class CSVParser(AbstractParser):
+ """CSV Parser class used to define generic behavior for parsers used
+ to extract data from local CSV files.
+ """
+
+ # Timeout to use for every CSV-based data
+ timeout = settings.csv_cache_timeout
+
+ # Name of CSV file to retrieve (without extension), also
+ # used as a sub-folder name for storing related static files
+ filename: str
+
+ async def retrieve_and_parse_data(self) -> None:
+ """Method used to retrieve data from CSV file and storing
+ it into self.data attribute
+ """
+
+ # Read the CSV file
+ self.csv_data = read_csv_data_file(f"{self.filename}.csv")
+
+ # Parse the data
+ self.data = self.parse_data()
+
+ # Update the Parser Cache
+ self.cache_manager.update_parser_cache(self.cache_key, self.data, self.timeout)
+
+ @abstractmethod
+ def parse_data(self) -> dict | list[dict]:
+ """Main submethod of the parser, mainly doing the parsing of CSV data and
+ returning a dict, which will be cached and used by the API. Can
+ raise an error if there is an issue when parsing the data.
+ """
+
+ def get_static_url(self, key: str, extension: str = "jpg") -> str:
+ """Method used to retrieve the URL of a local static file"""
+ return f"{settings.app_base_url}/static/{self.filename}/{key}.{extension}"
diff --git a/app/parsers/hero_parser.py b/app/parsers/hero_parser.py
index da7d95ea..3d1b689f 100644
--- a/app/parsers/hero_parser.py
+++ b/app/parsers/hero_parser.py
@@ -8,7 +8,7 @@
from app.common.exceptions import ParserBlizzardError
from app.config import settings
-from .api_parser import APIParser
+from .generics.api_parser import APIParser
from .helpers import get_full_url, get_role_from_icon_url
diff --git a/app/parsers/heroes_parser.py b/app/parsers/heroes_parser.py
index 5a6d7e54..db6b5678 100644
--- a/app/parsers/heroes_parser.py
+++ b/app/parsers/heroes_parser.py
@@ -1,7 +1,7 @@
"""Heroes page Parser module"""
from app.config import settings
-from .api_parser import APIParser
+from .generics.api_parser import APIParser
class HeroesParser(APIParser):
diff --git a/app/parsers/heroes_stats_parser.py b/app/parsers/heroes_stats_parser.py
index 6c062320..82f9c5f5 100644
--- a/app/parsers/heroes_stats_parser.py
+++ b/app/parsers/heroes_stats_parser.py
@@ -1,29 +1,21 @@
"""Heroes Stats Parser module"""
from typing import ClassVar
-from app.common.helpers import read_csv_data_file
-from app.config import settings
+from .generics.csv_parser import CSVParser
-from .abstract_parser import AbstractParser
-
-class HeroesStatsParser(AbstractParser):
+class HeroesStatsParser(CSVParser):
"""Heroes stats (health, armor, shields) Parser class"""
- timeout = settings.hero_path_cache_timeout
+ filename = "heroes"
hitpoints_keys: ClassVar[set] = {"health", "armor", "shields"}
- async def retrieve_and_parse_data(self) -> None:
- heroes_stats_data = read_csv_data_file("heroes.csv")
-
- self.data = {
+ def parse_data(self) -> dict:
+ return {
hero_stats["key"]: {"hitpoints": self.__get_hitpoints(hero_stats)}
- for hero_stats in heroes_stats_data
+ for hero_stats in self.csv_data
}
- # Update the Parser Cache
- self.cache_manager.update_parser_cache(self.cache_key, self.data, self.timeout)
-
def __get_hitpoints(self, hero_stats: dict) -> dict:
hitpoints = {hp_key: int(hero_stats[hp_key]) for hp_key in self.hitpoints_keys}
hitpoints["total"] = sum(hitpoints.values())
diff --git a/app/parsers/maps_parser.py b/app/parsers/maps_parser.py
index 8a1b3283..92da0dab 100644
--- a/app/parsers/maps_parser.py
+++ b/app/parsers/maps_parser.py
@@ -1,32 +1,25 @@
"""Maps Parser module"""
-from app.common.helpers import read_csv_data_file
-from app.config import settings
-from .abstract_parser import AbstractParser
+from .generics.csv_parser import CSVParser
-class MapsParser(AbstractParser):
+class MapsParser(CSVParser):
"""Overwatch maps list page Parser class"""
- timeout = settings.home_path_cache_timeout
+ filename = "maps"
- async def retrieve_and_parse_data(self) -> None:
- maps_data = read_csv_data_file("maps.csv")
-
- self.data = [
+ def parse_data(self) -> list[dict]:
+ return [
{
"name": map_dict["name"],
- "screenshot": self.get_screenshot_url(map_dict["key"]),
+ "screenshot": self.get_static_url(map_dict["key"]),
"gamemodes": map_dict["gamemodes"].split(","),
"location": map_dict["location"],
- "country_code": map_dict["country_code"] or None,
+ "country_code": map_dict.get("country_code") or None,
}
- for map_dict in maps_data
+ for map_dict in self.csv_data
]
- # Update the Parser Cache
- self.cache_manager.update_parser_cache(self.cache_key, self.data, self.timeout)
-
def filter_request_using_query(self, **kwargs) -> list:
gamemode = kwargs.get("gamemode")
return (
@@ -36,6 +29,3 @@ def filter_request_using_query(self, **kwargs) -> list:
map_dict for map_dict in self.data if gamemode in map_dict["gamemodes"]
]
)
-
- def get_screenshot_url(self, map_key: str) -> str:
- return f"{settings.app_base_url}/static/maps/{map_key}.jpg"
diff --git a/app/parsers/namecard_parser.py b/app/parsers/namecard_parser.py
index cd016c59..8eab655a 100644
--- a/app/parsers/namecard_parser.py
+++ b/app/parsers/namecard_parser.py
@@ -5,7 +5,7 @@
from app.common.logging import logger
from app.config import settings
-from .api_parser import APIParser
+from .generics.api_parser import APIParser
class NamecardParser(APIParser):
diff --git a/app/parsers/player_parser.py b/app/parsers/player_parser.py
index d01a798f..91181040 100644
--- a/app/parsers/player_parser.py
+++ b/app/parsers/player_parser.py
@@ -14,7 +14,7 @@
from app.common.exceptions import ParserBlizzardError
from app.config import settings
-from .api_parser import APIParser
+from .generics.api_parser import APIParser
from .helpers import (
get_computed_stat_value,
get_division_from_rank_icon,
diff --git a/app/parsers/roles_parser.py b/app/parsers/roles_parser.py
index d47bbd2c..e2438aad 100644
--- a/app/parsers/roles_parser.py
+++ b/app/parsers/roles_parser.py
@@ -1,7 +1,7 @@
"""Roles Parser module"""
from app.config import settings
-from .api_parser import APIParser
+from .generics.api_parser import APIParser
from .helpers import get_role_from_icon_url
diff --git a/app/routers/gamemodes.py b/app/routers/gamemodes.py
index c151ce96..337bfa69 100644
--- a/app/routers/gamemodes.py
+++ b/app/routers/gamemodes.py
@@ -1,8 +1,8 @@
"""Gamemodes endpoints router : gamemodes list, etc."""
-from fastapi import APIRouter, Query, Request
+from fastapi import APIRouter, Request
from app.common.decorators import validation_error_handler
-from app.common.enums import Locale, RouteTag
+from app.common.enums import RouteTag
from app.common.helpers import routes_responses
from app.handlers.list_gamemodes_request_handler import ListGamemodesRequestHandler
from app.models.gamemodes import GamemodeDetails
@@ -16,14 +16,11 @@
tags=[RouteTag.GAMEMODES],
summary="Get a list of gamemodes",
description=(
- "Get a list of Overwatch gamemodes : Assault, Escort, Hybrid, etc."
+ "Get a list of Overwatch gamemodes : Assault, Escort, Flashpoint, Hybrid, etc."
" **Cache TTL : 1 day.**"
),
operation_id="list_map_gamemodes",
)
@validation_error_handler(response_model=GamemodeDetails)
-async def list_map_gamemodes(
- request: Request,
- locale: Locale = Query(Locale.ENGLISH_US, title="Locale to be displayed"),
-) -> list[GamemodeDetails]:
- return await ListGamemodesRequestHandler(request).process_request(locale=locale)
+async def list_map_gamemodes(request: Request) -> list[GamemodeDetails]:
+ return await ListGamemodesRequestHandler(request).process_request()
diff --git a/pyproject.toml b/pyproject.toml
index 80a4ecc0..a9dd403a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "overfast-api"
-version = "2.19.3"
+version = "2.19.4"
description = "Overwatch API giving data about heroes, maps, and players statistics."
license = "MIT"
authors = ["TeKrop "]
@@ -12,14 +12,14 @@ documentation = "https://overfast-api.tekrop.fr/"
[tool.poetry.dependencies]
python = "^3.11"
beautifulsoup4 = "^4.12.2"
-fastapi = "^0.101.0"
+fastapi = "^0.103.0"
httpx = {extras = ["http2"], version = "^0.24.1"}
loguru = "^0.7.0"
lxml = "^4.9.3"
-redis = "^4.6.0"
+redis = "^5.0.0"
uvicorn = {extras = ["standard"], version = "^0.23.2"}
-pydantic = "^2.1.1"
-pydantic-settings = "^2.0.2"
+pydantic = "^2.3.0"
+pydantic-settings = "^2.0.3"
[tool.poetry.group.dev.dependencies]
black = "^23.7.0"
diff --git a/static/gamemodes/assault-icon.svg b/static/gamemodes/assault-icon.svg
new file mode 100644
index 00000000..adef9256
--- /dev/null
+++ b/static/gamemodes/assault-icon.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/static/gamemodes/assault.avif b/static/gamemodes/assault.avif
new file mode 100644
index 00000000..f1371d7f
Binary files /dev/null and b/static/gamemodes/assault.avif differ
diff --git a/static/gamemodes/capture-the-flag-icon.svg b/static/gamemodes/capture-the-flag-icon.svg
new file mode 100644
index 00000000..e48b47f7
--- /dev/null
+++ b/static/gamemodes/capture-the-flag-icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/static/gamemodes/capture-the-flag.avif b/static/gamemodes/capture-the-flag.avif
new file mode 100644
index 00000000..e4bef676
Binary files /dev/null and b/static/gamemodes/capture-the-flag.avif differ
diff --git a/static/gamemodes/control-icon.svg b/static/gamemodes/control-icon.svg
new file mode 100644
index 00000000..8d766328
--- /dev/null
+++ b/static/gamemodes/control-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/static/gamemodes/control.avif b/static/gamemodes/control.avif
new file mode 100644
index 00000000..81fe12d5
Binary files /dev/null and b/static/gamemodes/control.avif differ
diff --git a/static/gamemodes/deathmatch-icon.svg b/static/gamemodes/deathmatch-icon.svg
new file mode 100644
index 00000000..6caafb28
--- /dev/null
+++ b/static/gamemodes/deathmatch-icon.svg
@@ -0,0 +1,6 @@
+
diff --git a/static/gamemodes/deathmatch.avif b/static/gamemodes/deathmatch.avif
new file mode 100644
index 00000000..64460347
Binary files /dev/null and b/static/gamemodes/deathmatch.avif differ
diff --git a/static/gamemodes/elimination-icon.svg b/static/gamemodes/elimination-icon.svg
new file mode 100644
index 00000000..d54ff094
--- /dev/null
+++ b/static/gamemodes/elimination-icon.svg
@@ -0,0 +1,7 @@
+
diff --git a/static/gamemodes/elimination.avif b/static/gamemodes/elimination.avif
new file mode 100644
index 00000000..84ffa855
Binary files /dev/null and b/static/gamemodes/elimination.avif differ
diff --git a/static/gamemodes/escort-icon.svg b/static/gamemodes/escort-icon.svg
new file mode 100644
index 00000000..4fa16869
--- /dev/null
+++ b/static/gamemodes/escort-icon.svg
@@ -0,0 +1,7 @@
+
diff --git a/static/gamemodes/escort.avif b/static/gamemodes/escort.avif
new file mode 100644
index 00000000..e12c785a
Binary files /dev/null and b/static/gamemodes/escort.avif differ
diff --git a/static/gamemodes/flashpoint-icon.svg b/static/gamemodes/flashpoint-icon.svg
new file mode 100644
index 00000000..38842187
--- /dev/null
+++ b/static/gamemodes/flashpoint-icon.svg
@@ -0,0 +1,7 @@
+
+
+
diff --git a/static/gamemodes/flashpoint.avif b/static/gamemodes/flashpoint.avif
new file mode 100644
index 00000000..f2509125
Binary files /dev/null and b/static/gamemodes/flashpoint.avif differ
diff --git a/static/gamemodes/hybrid-icon.svg b/static/gamemodes/hybrid-icon.svg
new file mode 100644
index 00000000..fa713606
--- /dev/null
+++ b/static/gamemodes/hybrid-icon.svg
@@ -0,0 +1,8 @@
+
diff --git a/static/gamemodes/hybrid.avif b/static/gamemodes/hybrid.avif
new file mode 100644
index 00000000..9a130bbd
Binary files /dev/null and b/static/gamemodes/hybrid.avif differ
diff --git a/static/gamemodes/push-icon.svg b/static/gamemodes/push-icon.svg
new file mode 100644
index 00000000..730c2890
--- /dev/null
+++ b/static/gamemodes/push-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/static/gamemodes/push.avif b/static/gamemodes/push.avif
new file mode 100644
index 00000000..b022f00c
Binary files /dev/null and b/static/gamemodes/push.avif differ
diff --git a/static/gamemodes/team-deathmatch-icon.svg b/static/gamemodes/team-deathmatch-icon.svg
new file mode 100644
index 00000000..81c12c1b
--- /dev/null
+++ b/static/gamemodes/team-deathmatch-icon.svg
@@ -0,0 +1,6 @@
+
diff --git a/static/gamemodes/team-deathmatch.avif b/static/gamemodes/team-deathmatch.avif
new file mode 100644
index 00000000..ef023f18
Binary files /dev/null and b/static/gamemodes/team-deathmatch.avif differ
diff --git a/tests/commands/test_check_and_update_cache.py b/tests/commands/test_check_and_update_cache.py
index 93dea234..8a5110a0 100644
--- a/tests/commands/test_check_and_update_cache.py
+++ b/tests/commands/test_check_and_update_cache.py
@@ -39,9 +39,7 @@ def test_check_and_update_gamemodes_cache_to_update(
home_html_data: list,
gamemodes_json_data: dict,
):
- gamemodes_cache_key = (
- f"GamemodesParser-{settings.blizzard_host}/{locale}{settings.home_path}"
- )
+ gamemodes_cache_key = "GamemodesParser"
# Add some data (to update and not to update)
cache_manager.update_parser_cache(
@@ -167,7 +165,7 @@ def test_check_and_update_cache_no_update(cache_manager: CacheManager, locale: s
settings.expired_cache_refresh_limit + 5,
)
cache_manager.update_parser_cache(
- f"GamemodesParser-{settings.blizzard_host}/{locale}{settings.home_path}",
+ "GamemodesParser",
[],
settings.expired_cache_refresh_limit + 10,
)
@@ -206,7 +204,7 @@ def test_check_and_update_specific_player_to_update(
settings.expired_cache_refresh_limit + 5,
)
cache_manager.update_parser_cache(
- f"GamemodesParser-{settings.blizzard_host}/{locale}{settings.home_path}",
+ "GamemodesParser",
[],
settings.expired_cache_refresh_limit + 10,
)
@@ -256,7 +254,7 @@ def test_check_and_update_player_stats_summary_to_update(
settings.expired_cache_refresh_limit + 5,
)
cache_manager.update_parser_cache(
- f"GamemodesParser-{settings.blizzard_host}/{locale}{settings.home_path}",
+ "GamemodesParser",
[],
settings.expired_cache_refresh_limit + 10,
)
@@ -403,14 +401,11 @@ def test_check_parser_init_error(
def test_check_and_update_several_to_update(
cache_manager: CacheManager,
- locale: str,
home_html_data: list,
gamemodes_json_data: dict,
maps_json_data: dict,
):
- gamemodes_cache_key = (
- f"GamemodesParser-{settings.blizzard_host}/{locale}{settings.home_path}"
- )
+ gamemodes_cache_key = "GamemodesParser"
maps_cache_key = "MapsParser"
# Add some data to update
@@ -468,7 +463,7 @@ def test_check_and_update_namecard_to_update(
settings.expired_cache_refresh_limit + 5,
)
cache_manager.update_parser_cache(
- f"GamemodesParser-{settings.blizzard_host}/{locale}{settings.home_path}",
+ "GamemodesParser",
[],
settings.expired_cache_refresh_limit + 10,
)
diff --git a/tests/fixtures/json/gamemodes.json b/tests/fixtures/json/gamemodes.json
index b807ed53..8e70a553 100644
--- a/tests/fixtures/json/gamemodes.json
+++ b/tests/fixtures/json/gamemodes.json
@@ -1 +1,72 @@
-[{"key":"push","name":"Push","icon":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blt054b513cd6e95acf/62fd5b4a8972f93d1e325243/Push.svg","description":"Teams battle to take control of a robot and push it toward the enemy base.","screenshot":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blt93eefb6e91347639/62fc2d9eda42240856c1459c/Toronto_Push.jpg"},{"key":"control","name":"Control","icon":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blt5ea0d3baf0e2d03f/62fc2d8bda42240856c14598/Control.svg","description":"Teams fight to hold a single objective. The first team to win two rounds wins the map.","screenshot":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blta3f8e647a52bb9e9/62fc312456388515882767ed/Oasis_Control.jpg"},{"key":"escort","name":"Escort","icon":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/bltba08041a1eb32c43/62fc2d8bc317e303559ab5b1/Escort.svg","description":"One team escorts a payload to its delivery point, while the other races to stop them.","screenshot":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blt7d04bb6ad434cafa/62fc332a7ea1d970140fa139/Monte_Carlo_Escort.jpg"},{"key":"hybrid","name":"Hybrid","icon":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/bltd55839866311dd1e/62fc2d8bd62b1d3a8d1e5318/Hybrid.svg","description":"Attackers capture a payload, then escort it to its destination; defenders try to hold them back.","screenshot":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blt253b3f05c32db72b/62fc2d9e947fcf14cd224b18/Rio_de_Janeiro_Hybrid.jpg"},{"key":"capture-the-flag","name":"Capture the Flag","icon":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blt81ca1f07a1cf5a6e/62fc2d8bc8d34f7f53197dc6/Capture_the_Flag.svg","description":"Teams compete to capture the enemy team’s flag while defending their own.","screenshot":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blt42d587e346415db3/62fc2d9e8282cd7f515e855b/Lijang_Tower_Capture_the_Flag.jpg"},{"key":"elimination","name":"Elimination","icon":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blt4a8d26b9e2ae0739/62fc2d8b7198180857a9e75d/Elimination.svg","description":"Dispatch all enemies to win the round. Win three rounds to claim victory. Available with teams of one, three, or six.","screenshot":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blt4ccc6acd0dbed78a/62fc2d9eb60eb7158600e04c/Black_Forest_Elimination.jpg"},{"key":"deathmatch","name":"Deathmatch","icon":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blt9b57125d24705a16/62fc2d8b8972f93d1e32520e/Deathmatch.svg","description":"Race to reach 20 points first by racking up kills in a free-for-all format.","screenshot":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blt88ad6ddb9de11b3e/62fc2d9e26d7fa3ee92d03e2/Eichenwalde_Deathmatch.png"},{"key":"team-deathmatch","name":"Team Deathmatch","icon":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blta97d85f157469bd5/62fc2d8b3a2b8b6d5939b85a/Team_Deathmatch.svg","description":"Team up and triumph over your enemies by scoring the most kills.","screenshot":"https://blz-contentstack-images.akamaized.net/v3/assets/blt9c12f249ac15c7ec/blt63df614431a3f554/62fc2d9ead1dcd16f35de8e9/Kanezaka_Team_Deathmatch.jpg"}]
\ No newline at end of file
+[
+ {
+ "key": "assault",
+ "name": "Assault",
+ "icon": "https://overfast-api.tekrop.fr/static/gamemodes/assault-icon.svg",
+ "description": "Teams fight to capture or defend two successive points against the enemy team. It's an inactive Overwatch 1 gamemode, also called 2CP.",
+ "screenshot": "https://overfast-api.tekrop.fr/static/gamemodes/assault.avif"
+ },
+ {
+ "key": "capture-the-flag",
+ "name": "Capture the Flag",
+ "icon": "https://overfast-api.tekrop.fr/static/gamemodes/capture-the-flag-icon.svg",
+ "description": "Teams compete to capture the enemy team’s flag while defending their own.",
+ "screenshot": "https://overfast-api.tekrop.fr/static/gamemodes/capture-the-flag.avif"
+ },
+ {
+ "key": "control",
+ "name": "Control",
+ "icon": "https://overfast-api.tekrop.fr/static/gamemodes/control-icon.svg",
+ "description": "Teams fight to hold a single objective. The first team to win two rounds wins the map.",
+ "screenshot": "https://overfast-api.tekrop.fr/static/gamemodes/control.avif"
+ },
+ {
+ "key": "deathmatch",
+ "name": "Deathmatch",
+ "icon": "https://overfast-api.tekrop.fr/static/gamemodes/deathmatch-icon.svg",
+ "description": "Race to reach 20 points first by racking up kills in a free-for-all format.",
+ "screenshot": "https://overfast-api.tekrop.fr/static/gamemodes/deathmatch.avif"
+ },
+ {
+ "key": "elimination",
+ "name": "Elimination",
+ "icon": "https://overfast-api.tekrop.fr/static/gamemodes/elimination-icon.svg",
+ "description": "Dispatch all enemies to win the round. Win three rounds to claim victory. Available with teams of one, three, or six.",
+ "screenshot": "https://overfast-api.tekrop.fr/static/gamemodes/elimination.avif"
+ },
+ {
+ "key": "escort",
+ "name": "Escort",
+ "icon": "https://overfast-api.tekrop.fr/static/gamemodes/escort-icon.svg",
+ "description": "One team escorts a payload to its delivery point, while the other races to stop them.",
+ "screenshot": "https://overfast-api.tekrop.fr/static/gamemodes/escort.avif"
+ },
+ {
+ "key": "flashpoint",
+ "name": "Flashpoint",
+ "icon": "https://overfast-api.tekrop.fr/static/gamemodes/flashpoint-icon.svg",
+ "description": "Teams fight for control of key positions across the map, aiming to capture three of them before their opponents do.",
+ "screenshot": "https://overfast-api.tekrop.fr/static/gamemodes/flashpoint.avif"
+ },
+ {
+ "key": "hybrid",
+ "name": "Hybrid",
+ "icon": "https://overfast-api.tekrop.fr/static/gamemodes/hybrid-icon.svg",
+ "description": "Attackers capture a payload, then escort it to its destination; defenders try to hold them back.",
+ "screenshot": "https://overfast-api.tekrop.fr/static/gamemodes/hybrid.avif"
+ },
+ {
+ "key": "push",
+ "name": "Push",
+ "icon": "https://overfast-api.tekrop.fr/static/gamemodes/push-icon.svg",
+ "description": "Teams battle to take control of a robot and push it toward the enemy base.",
+ "screenshot": "https://overfast-api.tekrop.fr/static/gamemodes/push.avif"
+ },
+ {
+ "key": "team-deathmatch",
+ "name": "Team Deathmatch",
+ "icon": "https://overfast-api.tekrop.fr/static/gamemodes/team-deathmatch-icon.svg",
+ "description": "Team up and triumph over your enemies by scoring the most kills.",
+ "screenshot": "https://overfast-api.tekrop.fr/static/gamemodes/team-deathmatch.avif"
+ }
+]
\ No newline at end of file
diff --git a/tests/views/test_gamemodes_route.py b/tests/views/test_gamemodes_route.py
index fd1623ec..e1daf8f4 100644
--- a/tests/views/test_gamemodes_route.py
+++ b/tests/views/test_gamemodes_route.py
@@ -26,32 +26,6 @@ def test_get_gamemodes(gamemodes_json_data: list):
assert response.json() == gamemodes_json_data
-def test_get_gamemodes_after_get_roles(gamemodes_json_data: list):
- # Used to check we don't have any conflict between parsers
- # using the same Blizzard URL and associated Parser caches
- client.get("/heroes/roles")
- response = client.get("/gamemodes")
- assert response.status_code == status.HTTP_200_OK
- assert response.json() == gamemodes_json_data
-
-
-def test_get_gamemodes_blizzard_error():
- with patch.object(
- overfast_client,
- "get",
- return_value=Mock(
- status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
- text="Service Unavailable",
- ),
- ):
- response = client.get("/gamemodes")
-
- assert response.status_code == status.HTTP_504_GATEWAY_TIMEOUT
- assert response.json() == {
- "error": "Couldn't get Blizzard page (HTTP 503 error) : Service Unavailable",
- }
-
-
def test_get_gamemodes_internal_error():
with patch(
"app.handlers.list_gamemodes_request_handler."
diff --git a/tests/views/test_hero_routes.py b/tests/views/test_hero_routes.py
index 1d19deb3..f0a7c0ac 100644
--- a/tests/views/test_hero_routes.py
+++ b/tests/views/test_hero_routes.py
@@ -145,7 +145,7 @@ def test_get_hero_no_hitpoints(
Mock(status_code=status.HTTP_200_OK, text=heroes_html_data),
],
), patch(
- "app.parsers.heroes_stats_parser.read_csv_data_file",
+ "app.parsers.generics.csv_parser.read_csv_data_file",
return_value=heroes_stats,
):
response = client.get(f"/heroes/{hero_name}")