overfast-client 0.1.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.
@@ -0,0 +1,160 @@
1
+ Metadata-Version: 2.4
2
+ Name: overfast-client
3
+ Version: 0.1.0
4
+ Summary: Async Python client for the OverFast API (Overwatch data).
5
+ Project-URL: Homepage, https://github.com/Leo890728/overwatch_py
6
+ Project-URL: Repository, https://github.com/Leo890728/overwatch_py
7
+ Project-URL: Issues, https://github.com/Leo890728/overwatch_py/issues
8
+ Project-URL: Changelog, https://github.com/Leo890728/overwatch_py/blob/main/CHANGELOG.md
9
+ Author-email: Leo890728 <Leo890728@users.noreply.github.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: api,async,httpx,overfast,overwatch,pydantic
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Framework :: AsyncIO
15
+ Classifier: Framework :: Pydantic :: 2
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Games/Entertainment
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.10
28
+ Requires-Dist: hishel<0.2,>=0.0.30
29
+ Requires-Dist: httpx-retries>=0.3
30
+ Requires-Dist: httpx>=0.27
31
+ Requires-Dist: pydantic>=2.5
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
34
+ Requires-Dist: pytest>=8.0; extra == 'dev'
35
+ Requires-Dist: respx>=0.21; extra == 'dev'
36
+ Description-Content-Type: text/markdown
37
+
38
+ # overfast-client
39
+
40
+ Async Python client for the [OverFast API](https://overfast-api.tekrop.fr) — comprehensive Overwatch data (heroes, maps, gamemodes, player stats) via a typed, pydantic-backed interface.
41
+
42
+ ## Install
43
+
44
+ ```bash
45
+ pip install overfast-client
46
+ ```
47
+
48
+ > The PyPI distribution is `overfast-client`; the import name is `overwatch_py`.
49
+
50
+ Or from source (editable):
51
+
52
+ ```bash
53
+ pip install -e .
54
+ ```
55
+
56
+ ## Quick start
57
+
58
+ ```python
59
+ import asyncio
60
+ from overwatch_py import Client
61
+ from overwatch_py.enums import Hero, Locale, Role, HeroGamemode, PlayerGamemode, Platform
62
+
63
+ async def main():
64
+ client = Client()
65
+
66
+ # List heroes
67
+ heroes = await client.get_heroes(role=Role.SUPPORT, locale=Locale.EN_US)
68
+ for h in heroes:
69
+ print(h.key, h.name)
70
+
71
+ # Full hero data (abilities, story, hitpoints, ...)
72
+ ana = await client.get_hero_data(Hero.ANA)
73
+ print(ana.hitpoints, len(ana.abilities))
74
+
75
+ # Maps & gamemodes
76
+ maps = await client.get_maps()
77
+ gamemodes = await client.get_gamemode_details()
78
+
79
+ # Hero usage stats (pickrate / winrate)
80
+ stats = await client.get_heroes_stats(
81
+ platform=Platform.PC,
82
+ gamemode=PlayerGamemode.COMPETITIVE,
83
+ )
84
+
85
+ # Players
86
+ result = await client.search_players("TeKrop", limit=10)
87
+ player = await client.get_player(result.results[0].player_id)
88
+ summary = await client.get_player_summary("TeKrop-2217")
89
+ stats_summary = await client.get_player_stats("TeKrop-2217", gamemode=PlayerGamemode.COMPETITIVE)
90
+
91
+ asyncio.run(main())
92
+ ```
93
+
94
+ ## Configuration
95
+
96
+ ```python
97
+ from overwatch_py import Client
98
+ from overwatch_py.config import Config
99
+ from overwatch_py.session import HTTPSession
100
+
101
+ config = Config(
102
+ timeout=10, # seconds
103
+ retries=3, # retries on 5xx
104
+ cache=True, # HTTP-level cache (hishel), respects server Cache-Control
105
+ cache_backend="sqlite", # "memory" | "sqlite" | "file"
106
+ )
107
+ client = Client(HTTPSession(config))
108
+ ```
109
+
110
+ ### Caching
111
+
112
+ Caching is disabled by default. When enabled, [hishel](https://hishel.com) sits in the httpx transport stack and honors each endpoint's `Cache-Control` / `Age` headers (e.g. `/heroes` is cached ~1 day, `/heroes/stats` ~1 hour by the upstream API).
113
+
114
+ ## Exceptions
115
+
116
+ All non-2xx responses map to subclasses of `APIError`:
117
+
118
+ | Status | Exception |
119
+ |--------|-----------|
120
+ | 400 | `BadRequestError` |
121
+ | 404 | `NotFoundError` |
122
+ | 422 | `ValidationError` |
123
+ | 429 | `APIRateLimitError` |
124
+ | 500 | `InternalServerError` |
125
+ | 503 | `BlizzardRateLimitError` |
126
+ | 504 | `BlizzardServerError` |
127
+
128
+ ```python
129
+ from overwatch_py.exceptions import NotFoundError, APIRateLimitError
130
+
131
+ try:
132
+ await client.get_player_summary("does-not-exist-1234")
133
+ except NotFoundError:
134
+ ...
135
+ except APIRateLimitError as e:
136
+ print("rate limited:", e.response.headers.get("retry-after"))
137
+ ```
138
+
139
+ ## API surface
140
+
141
+ Exposed on `Client`:
142
+
143
+ - **Heroes** — `get_heroes`, `get_hero_data`, `get_heroes_stats`
144
+ - **Maps / Gamemodes** — `get_maps`, `get_gamemode_details`
145
+ - **Players** — `search_players`, `get_player`, `get_player_summary`, `get_player_stats`, `get_player_career_stats`, `get_player_career_stats_with_labels`, `get_player_full_stats`
146
+
147
+ The underlying services (`client.heros`, `client.maps`, `client.players`) are also available if you prefer service-level access.
148
+
149
+ ## Development
150
+
151
+ ```bash
152
+ pip install -e ".[dev]"
153
+ pytest # unit + mocked HTTP tests
154
+ pytest -m live # hits the real API (rate-limited)
155
+ pytest -m 'live or not live' # run everything
156
+ ```
157
+
158
+ ## License
159
+
160
+ MIT.
@@ -0,0 +1,34 @@
1
+ overwatch_py/__init__.py,sha256=h8jkjJd_ZWwpwwRJ5zMXBF-8oV3xKQdpYYIp-G5UOws,85
2
+ overwatch_py/client.py,sha256=Svn_fsXl6Gk22KCFBuxi0-s79EgMrXxcCnzsUj0yEIs,4902
3
+ overwatch_py/config.py,sha256=v21ZAqzGpuBkiwpSkh8yPJLQUz_Q-UJBZoI2i4PR2ts,284
4
+ overwatch_py/exceptions.py,sha256=SDiXFwMGTX34fOR4uaRjOWySUVQMYDlpxObAU8XQlhQ,714
5
+ overwatch_py/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ overwatch_py/session.py,sha256=acnkIDmvBV668hB48kGvcI26j5ED80FO9WiZmEgK-KM,2148
7
+ overwatch_py/enums/__init__.py,sha256=qUKvvqaxRInTkIzAepfVMNl4WsmgzB8vHH16ikqixgk,652
8
+ overwatch_py/enums/background_image_size.py,sha256=rHJL6s4YAbUAUU4gred2nWFbfJQHaeemG1Ync-KWN7k,154
9
+ overwatch_py/enums/career_stat_category.py,sha256=s1h4olzLj4r0ZfjhoFskH2_5lKPfiLbMHFSwNOMALUc,272
10
+ overwatch_py/enums/gamemode.py,sha256=YbNU4nI9azUkN2pfd12pgo5n8zGhTWhwHdffLkYTt9I,348
11
+ overwatch_py/enums/hero.py,sha256=-8ZVCuBUpXazr4N_SCF-AhyJwbB_cLagO5VhYekVQGc,1225
12
+ overwatch_py/enums/locale.py,sha256=7cESDJy_LYkvdfr-zVB-S8f4FTKvvIkdVF-0NTVv4VM,308
13
+ overwatch_py/enums/map.py,sha256=3Hkm4zBs1flqWUpwwOaXe-BQBYpyB3gQnjBayK9W18c,1825
14
+ overwatch_py/enums/map_gamemode.py,sha256=ny9h0NtrtBvmpXutZfioQOxwv3MLBjhXoD6XIyAy3Rg,455
15
+ overwatch_py/enums/platform.py,sha256=U__Ga6Ma_JlvfQ3tlR14R2t5OTJQ03ILFJhb2WtRu20,88
16
+ overwatch_py/enums/rank.py,sha256=vZoyW9XcyPg1lSmOLTdfB6vGdXsTYKfUdmYLKoXO4Kk,556
17
+ overwatch_py/enums/region.py,sha256=eiVnirCz3DiaQmAlHNXEjlFoKi8pC2OxQuSLWQnSRSk,115
18
+ overwatch_py/enums/role.py,sha256=6KrifIbH6BW9D_BsyFTxT6s46B025YEfyGZr7Pj4EM8,110
19
+ overwatch_py/models/__init__.py,sha256=x3Hg2J-UnEYTL7RS559E_HLLTgUfLSa9E72SiMptC5Q,1382
20
+ overwatch_py/models/gamemode_details.py,sha256=Pd-mujYqsKsOpRhCsZUu5jTyr_reUHMwXt69SiucqQ0,206
21
+ overwatch_py/models/hero.py,sha256=l7EqTbpdHQJCtoXEGFieVUobRCkBdtceoyQYbSkEcsY,1269
22
+ overwatch_py/models/hero_short.py,sha256=e7Yi6lrRHbzkEGVmNCNDhX9Y9nuandznjF61yHFGER8,215
23
+ overwatch_py/models/hero_stats.py,sha256=tbQVxSwPnUIbxi-7nnwN0bIrvjFviBJuTwUAY4TvY0k,140
24
+ overwatch_py/models/map_details.py,sha256=I5wTkKFO3xAq6-6yizqKg7wRnLPpcqQaXRtpvad9MX8,270
25
+ overwatch_py/models/player.py,sha256=7uZ9eG_GmHqTqonFc7hKNVof5rJN_DnNfD7aIcxvZw8,1608
26
+ overwatch_py/models/player_stats.py,sha256=lPPe47O_oDPaMUnnXXUPT-hhX3eJopnB-feq5AdNSuU,3247
27
+ overwatch_py/services/__init__.py,sha256=a2drwxI_bz_a9eRjLlQaEgLvnE5iDqHbbZgHlVxSPUE,159
28
+ overwatch_py/services/heros.py,sha256=sAZNu1VOxkf_UFdrwGvfJDAHzp-o4VPxWmWKNvm9588,4660
29
+ overwatch_py/services/maps.py,sha256=B6n-Ao2yP99UE42ngxfAnSbwdfAzd8ieX2Al4ZDCNqI,892
30
+ overwatch_py/services/players.py,sha256=5J8jG0NPB6x_zPNvV75XxgknNyZsgQRKfvQyRRRC-Ag,4759
31
+ overfast_client-0.1.0.dist-info/METADATA,sha256=KQaMBQZgU_BeGN1nlBU8owUbwN7Brk5FM979DgMa77M,5106
32
+ overfast_client-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
33
+ overfast_client-0.1.0.dist-info/licenses/LICENSE,sha256=1OjTzFo2zh8donxQs_QiBTv6e4fp9NqYLvRKooqWyWk,1065
34
+ overfast_client-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Leo890728
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,4 @@
1
+ from .client import Client
2
+
3
+ __version__ = "0.1.0"
4
+ __all__ = ["Client", "__version__"]
overwatch_py/client.py ADDED
@@ -0,0 +1,96 @@
1
+ from typing import Optional
2
+
3
+ from .services import HerosService, MapsService, PlayersService
4
+ from .services.players import HeroFilter
5
+ from .session import HTTPSession
6
+ from .models import (
7
+ GamemodeDetails,
8
+ HeroData,
9
+ HeroPlayerCareerStats,
10
+ HeroShort,
11
+ HeroStats,
12
+ MapDetails,
13
+ Player,
14
+ PlayerSearchResult,
15
+ PlayerStats,
16
+ PlayerStatsSummary,
17
+ PlayerSummary,
18
+ )
19
+ from .enums import (
20
+ CompetitiveDivisionFilter,
21
+ Hero,
22
+ HeroGamemode,
23
+ Locale,
24
+ Map,
25
+ MapGamemode,
26
+ Platform,
27
+ PlayerGamemode,
28
+ Region,
29
+ Role,
30
+ )
31
+
32
+
33
+ class Client:
34
+ def __init__(self, session: HTTPSession = None):
35
+ self.session = session or HTTPSession()
36
+ self.heros = HerosService(self.session)
37
+ self.maps = MapsService(self.session)
38
+ self.players = PlayersService(self.session)
39
+
40
+ async def get_heroes(self, role: Role = None, locale: Locale = Locale.EN_US, gamemode: Optional[HeroGamemode] = None) -> list[HeroShort]:
41
+ """Get a list of Overwatch heroes, which can be filtered using roles or gamemodes."""
42
+ return await self.heros.get_heroes(role, locale, gamemode)
43
+
44
+ async def get_hero_data(self, hero: Hero, locale: Locale = Locale.EN_US) -> HeroData:
45
+ """Get data about an Overwatch hero : description, abilities, stadium powers, story, etc."""
46
+ return await self.heros.get_hero_data(hero, locale)
47
+
48
+ async def get_maps(self, map_gamemode: Optional[MapGamemode] = None) -> list[MapDetails]:
49
+ """Get a list of Overwatch maps : Hanamura, King's Row, Dorado, etc."""
50
+ return await self.maps.get_maps(map_gamemode)
51
+
52
+ async def get_gamemode_details(self) -> list[GamemodeDetails]:
53
+ """Get a list of Overwatch gamemodes : Assault, Escort, Flashpoint, Hybrid, etc."""
54
+ return await self.maps.get_gamemode_details()
55
+
56
+ async def get_heroes_stats(self, platform: Platform = Platform.PC, gamemode: PlayerGamemode = PlayerGamemode.COMPETITIVE,
57
+ region: Region = Region.ASIA, role: Optional[Role] = None, map: Optional[Map] = None,
58
+ competitive_division: Optional[CompetitiveDivisionFilter] = None, order_by: Optional[str] = "hero:asc") -> list[HeroStats]:
59
+ """Get hero statistics usage, filtered by platform, region, role, etc. Only Role Queue gamemodes are concerned."""
60
+ return await self.heros.get_heroes_stats(platform, gamemode, region, role, map, competitive_division, order_by)
61
+
62
+ async def search_players(self, name: str, order_by: Optional[str] = None,
63
+ offset: Optional[int] = None, limit: Optional[int] = None) -> PlayerSearchResult:
64
+ """Search for players by BattleTag name."""
65
+ return await self.players.search_players(name, order_by, offset, limit)
66
+
67
+ async def get_player(self, player_id: str, gamemode: Optional[PlayerGamemode] = None,
68
+ platform: Optional[Platform] = None) -> Player:
69
+ """Get all player data: summary and statistics."""
70
+ return await self.players.get_player(player_id, gamemode, platform)
71
+
72
+ async def get_player_summary(self, player_id: str) -> PlayerSummary:
73
+ """Get player summary: name, avatar, endorsement, competitive ranks."""
74
+ return await self.players.get_player_summary(player_id)
75
+
76
+ async def get_player_stats(self, player_id: str, gamemode: Optional[PlayerGamemode] = None,
77
+ platform: Optional[Platform] = None) -> PlayerStatsSummary:
78
+ """Get player stats summary (general / roles / heroes)."""
79
+ return await self.players.get_player_stats(player_id, gamemode, platform)
80
+
81
+ async def get_player_career_stats(self, player_id: str, gamemode: PlayerGamemode,
82
+ platform: Optional[Platform] = None,
83
+ hero: Optional[HeroFilter] = None) -> dict[str, Optional[HeroPlayerCareerStats]]:
84
+ """Get player career stats as flat {label: value} maps per hero."""
85
+ return await self.players.get_player_career_stats(player_id, gamemode, platform, hero)
86
+
87
+ async def get_player_career_stats_with_labels(self, player_id: str, gamemode: PlayerGamemode,
88
+ platform: Optional[Platform] = None,
89
+ hero: Optional[HeroFilter] = None):
90
+ """Get player career stats with labels and categories per hero."""
91
+ return await self.players.get_player_career_stats_with_labels(player_id, gamemode, platform, hero)
92
+
93
+ async def get_player_full_stats(self, player_id: str, gamemode: Optional[PlayerGamemode] = None,
94
+ platform: Optional[Platform] = None) -> PlayerStats:
95
+ """Get a player's full per-platform stats (pc/console)."""
96
+ return await self.players.get_player_full_stats(player_id, gamemode, platform)
overwatch_py/config.py ADDED
@@ -0,0 +1,11 @@
1
+ from typing import Literal
2
+
3
+ from pydantic import BaseModel, HttpUrl
4
+
5
+
6
+ class Config(BaseModel):
7
+ base_url: HttpUrl = "https://overfast-api.tekrop.fr"
8
+ timeout: int = 10
9
+ retries: int = 3
10
+ cache: bool = False
11
+ cache_backend: Literal["memory", "sqlite", "file"] = "memory"
@@ -0,0 +1,28 @@
1
+ from .background_image_size import BackgroundImageSize
2
+ from .career_stat_category import CareerStatCategory
3
+ from .map_gamemode import MapGamemode
4
+ from .hero import Hero
5
+ from .locale import Locale
6
+ from .platform import Platform
7
+ from .region import Region
8
+ from .role import Role
9
+ from .map import Map
10
+ from .gamemode import HeroGamemode, PlayerGamemode
11
+ from .rank import Rank, CompetitiveDivisionFilter
12
+
13
+
14
+ __all__ = [
15
+ "BackgroundImageSize",
16
+ "CareerStatCategory",
17
+ "CompetitiveDivisionFilter",
18
+ "Hero",
19
+ "HeroGamemode",
20
+ "Locale",
21
+ "Map",
22
+ "MapGamemode",
23
+ "Platform",
24
+ "PlayerGamemode",
25
+ "Rank",
26
+ "Region",
27
+ "Role",
28
+ ]
@@ -0,0 +1,10 @@
1
+ from enum import Enum
2
+
3
+
4
+ class BackgroundImageSize(str, Enum):
5
+ MIN = "min"
6
+ XS = "xs"
7
+ SM = "sm"
8
+ MD = "md"
9
+ LG = "lg"
10
+ XL_PLUS = "xl+"
@@ -0,0 +1,12 @@
1
+ from enum import Enum
2
+
3
+
4
+ class CareerStatCategory(str, Enum):
5
+ ASSISTS = "assists"
6
+ AVERAGE = "average"
7
+ BEST = "best"
8
+ COMBAT = "combat"
9
+ GAME = "game"
10
+ HERO_SPECIFIC = "hero_specific"
11
+ MATCH_AWARDS = "match_awards"
12
+ MISCELLANEOUS = "miscellaneous"
@@ -0,0 +1,13 @@
1
+ from enum import Enum
2
+
3
+
4
+ class HeroGamemode(str, Enum):
5
+ """Gamemodes a hero can be played in (used by /heroes filter and HeroShort.gamemodes)."""
6
+ QUICKPLAY = "quickplay"
7
+ STADIUM = "stadium"
8
+
9
+
10
+ class PlayerGamemode(str, Enum):
11
+ """Gamemodes used by player-stats endpoints."""
12
+ QUICKPLAY = "quickplay"
13
+ COMPETITIVE = "competitive"
@@ -0,0 +1,55 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Hero(str, Enum):
5
+ ANA = "ana"
6
+ ANRAN = "anran"
7
+ ASHE = "ashe"
8
+ BAPTISTE = "baptiste"
9
+ BASTION = "bastion"
10
+ BRIGITTE = "brigitte"
11
+ CASSIDY = "cassidy"
12
+ DVA = "dva"
13
+ DOMINA = "domina"
14
+ DOOMFIST = "doomfist"
15
+ ECHO = "echo"
16
+ EMRE = "emre"
17
+ FREJA = "freja"
18
+ GENJI = "genji"
19
+ HAZARD = "hazard"
20
+ HANZO = "hanzo"
21
+ ILLARI = "illari"
22
+ JETPACK_CAT = "jetpack-cat"
23
+ JUNKER_QUEEN = "junker-queen"
24
+ JUNKRAT = "junkrat"
25
+ JUNO = "juno"
26
+ KIRIKO = "kiriko"
27
+ LIFEWEAVER = "lifeweaver"
28
+ LUCIO = "lucio"
29
+ MAUGA = "mauga"
30
+ MEI = "mei"
31
+ MERCY = "mercy"
32
+ MIZUKI = "mizuki"
33
+ MOIRA = "moira"
34
+ ORISA = "orisa"
35
+ PHARAH = "pharah"
36
+ RAMATTRA = "ramattra"
37
+ REAPER = "reaper"
38
+ REINHARDT = "reinhardt"
39
+ ROADHOG = "roadhog"
40
+ SIGMA = "sigma"
41
+ SIERRA = "sierra"
42
+ SOJOURN = "sojourn"
43
+ SOLDIER_76 = "soldier-76"
44
+ SOMBRA = "sombra"
45
+ SYMMETRA = "symmetra"
46
+ TORBJORN = "torbjorn"
47
+ TRACER = "tracer"
48
+ VENDETTA = "vendetta"
49
+ VENTURE = "venture"
50
+ WIDOWMAKER = "widowmaker"
51
+ WINSTON = "winston"
52
+ WRECKING_BALL = "wrecking-ball"
53
+ WUYANG = "wuyang"
54
+ ZARYA = "zarya"
55
+ ZENYATTA = "zenyatta"
@@ -0,0 +1,17 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Locale(str, Enum):
5
+ DE_DE = "de-de"
6
+ EN_GB = "en-gb"
7
+ EN_US = "en-us"
8
+ ES_ES = "es-es"
9
+ ES_MX = "es-mx"
10
+ FR_FR = "fr-fr"
11
+ IT_IT = "it-it"
12
+ JA_JP = "ja-jp"
13
+ KO_KR = "ko-kr"
14
+ PL_PL = "pl-pl"
15
+ PT_BR = "pt-br"
16
+ RU_RU = "ru-ru"
17
+ ZH_TW = "zh-tw"
@@ -0,0 +1,61 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Map(str, Enum):
5
+ AATLIS = "aatlis"
6
+ ANTARCTIC_PENINSULA = "antarctic-peninsula"
7
+ ANUBIS = "anubis"
8
+ ARENA_VICTORIAE = "arena-victoriae"
9
+ AYUTTHAYA = "ayutthaya"
10
+ BLACK_FOREST = "black-forest"
11
+ BLIZZARD_WORLD = "blizzard-world"
12
+ BUSAN = "busan"
13
+ CASTILLO = "castillo"
14
+ CHATEAU_GUILLARD = "chateau-guillard"
15
+ CIRCUIT_ROYAL = "circuit-royal"
16
+ COLOSSEO = "colosseo"
17
+ DORADO = "dorado"
18
+ ECOPOINT_ANTARCTICA = "ecopoint-antarctica"
19
+ EICHENWALDE = "eichenwalde"
20
+ ESPERANCA = "esperanca"
21
+ GOGADORO = "gogadoro"
22
+ HANAMURA = "hanamura"
23
+ HANAOKA = "hanaoka"
24
+ HAVANA = "havana"
25
+ HOLLYWOOD = "hollywood"
26
+ HORIZON = "horizon"
27
+ ILIOS = "ilios"
28
+ JUNKERTOWN = "junkertown"
29
+ LIJIANG_TOWER = "lijiang-tower"
30
+ KANEZAKA = "kanezaka"
31
+ KINGS_ROW = "kings-row"
32
+ MALEVENTO = "malevento"
33
+ MIDTOWN = "midtown"
34
+ NECROPOLIS = "necropolis"
35
+ NEPAL = "nepal"
36
+ NEW_JUNK_CITY = "new-junk-city"
37
+ NEW_QUEEN_STREET = "new-queen-street"
38
+ NUMBANI = "numbani"
39
+ OASIS = "oasis"
40
+ PARAISO = "paraiso"
41
+ PARIS = "paris"
42
+ PETRA = "petra"
43
+ PLACE_LACROIX = "place-lacroix"
44
+ POWDER_KEG_MINE = "powder-keg-mine"
45
+ PRACTICE_RANGE = "practice-range"
46
+ REDWOOD_DAM = "redwood-dam"
47
+ RIALTO = "rialto"
48
+ ROUTE_66 = "route-66"
49
+ RUNASAPI = "runasapi"
50
+ SAMOA = "samoa"
51
+ SHAMBALI_MONASTERY = "shambali-monastery"
52
+ SURAVASA = "suravasa"
53
+ THAMES_DISTRICT = "thames-district"
54
+ THRONE_OF_ANUBIS = "throne-of-anubis"
55
+ VOLSKAYA = "volskaya"
56
+ WATCHPOINT_GIBRALTAR = "watchpoint-gibraltar"
57
+ WORKSHOP_CHAMBER = "workshop-chamber"
58
+ WORKSHOP_EXPANSE = "workshop-expanse"
59
+ WORKSHOP_GREEN_SCREEN = "workshop-green-screen"
60
+ WORKSHOP_ISLAND = "workshop-island"
61
+ WUXING_UNIVERSITY = "wuxing-university"
@@ -0,0 +1,18 @@
1
+ from enum import Enum
2
+
3
+
4
+ class MapGamemode(str, Enum):
5
+ ASSAULT = "assault"
6
+ CAPTURE_THE_FLAG = "capture-the-flag"
7
+ CLASH = "clash"
8
+ CONTROL = "control"
9
+ DEATHMATCH = "deathmatch"
10
+ ELIMINATION = "elimination"
11
+ ESCORT = "escort"
12
+ FLASHPOINT = "flashpoint"
13
+ HYBRID = "hybrid"
14
+ PAYLOAD_RACE = "payload-race"
15
+ PRACTICE_RANGE = "practice-range"
16
+ PUSH = "push"
17
+ TEAM_DEATHMATCH = "team-deathmatch"
18
+ WORKSHOP = "workshop"
@@ -0,0 +1,6 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Platform(str, Enum):
5
+ PC = "pc"
6
+ CONSOLE = "console"
@@ -0,0 +1,23 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Rank(str, Enum):
5
+ BRONZE = "bronze"
6
+ SILVER = "silver"
7
+ GOLD = "gold"
8
+ PLATINUM = "platinum"
9
+ DIAMOND = "diamond"
10
+ MASTER = "master"
11
+ GRANDMASTER = "grandmaster"
12
+ ULTIMATE = "ultimate"
13
+
14
+
15
+ class CompetitiveDivisionFilter(str, Enum):
16
+ """Same as Rank, but without ULTIMATE — accepted by /heroes/stats `competitive_division` query."""
17
+ BRONZE = "bronze"
18
+ SILVER = "silver"
19
+ GOLD = "gold"
20
+ PLATINUM = "platinum"
21
+ DIAMOND = "diamond"
22
+ MASTER = "master"
23
+ GRANDMASTER = "grandmaster"
@@ -0,0 +1,7 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Region(str, Enum):
5
+ EUROPE = "europe"
6
+ AMERICAS = "americas"
7
+ ASIA = "asia"
@@ -0,0 +1,7 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Role(str, Enum):
5
+ TANK = "tank"
6
+ DAMAGE = "damage"
7
+ SUPPORT = "support"
@@ -0,0 +1,33 @@
1
+ class APIError(Exception):
2
+ def __init__(self, message: str, status_code: int, response=None):
3
+ super().__init__(message)
4
+ self.status_code = status_code
5
+ self.response = response
6
+
7
+
8
+ class BadRequestError(APIError):
9
+ """400 Bad Request Error"""
10
+
11
+
12
+ class NotFoundError(APIError):
13
+ """404 Not Found (hero or player)"""
14
+
15
+
16
+ class ValidationError(APIError):
17
+ """422 Validation Error"""
18
+
19
+
20
+ class APIRateLimitError(APIError):
21
+ """429 API Rate Limit Error"""
22
+
23
+
24
+ class InternalServerError(APIError):
25
+ """500 Internal Server Error"""
26
+
27
+
28
+ class BlizzardRateLimitError(APIError):
29
+ """503 Blizzard Rate Limit Error"""
30
+
31
+
32
+ class BlizzardServerError(APIError):
33
+ """504 Blizzard Server Error"""