overfast-client 0.1.0__tar.gz

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.
Files changed (47) hide show
  1. overfast_client-0.1.0/.github/workflows/publish.yml +58 -0
  2. overfast_client-0.1.0/.github/workflows/test.yml +33 -0
  3. overfast_client-0.1.0/.gitignore +83 -0
  4. overfast_client-0.1.0/CHANGELOG.md +24 -0
  5. overfast_client-0.1.0/LICENSE +21 -0
  6. overfast_client-0.1.0/PKG-INFO +160 -0
  7. overfast_client-0.1.0/README.md +123 -0
  8. overfast_client-0.1.0/overwatch_py/__init__.py +4 -0
  9. overfast_client-0.1.0/overwatch_py/client.py +96 -0
  10. overfast_client-0.1.0/overwatch_py/config.py +11 -0
  11. overfast_client-0.1.0/overwatch_py/enums/__init__.py +28 -0
  12. overfast_client-0.1.0/overwatch_py/enums/background_image_size.py +10 -0
  13. overfast_client-0.1.0/overwatch_py/enums/career_stat_category.py +12 -0
  14. overfast_client-0.1.0/overwatch_py/enums/gamemode.py +13 -0
  15. overfast_client-0.1.0/overwatch_py/enums/hero.py +55 -0
  16. overfast_client-0.1.0/overwatch_py/enums/locale.py +17 -0
  17. overfast_client-0.1.0/overwatch_py/enums/map.py +61 -0
  18. overfast_client-0.1.0/overwatch_py/enums/map_gamemode.py +18 -0
  19. overfast_client-0.1.0/overwatch_py/enums/platform.py +6 -0
  20. overfast_client-0.1.0/overwatch_py/enums/rank.py +23 -0
  21. overfast_client-0.1.0/overwatch_py/enums/region.py +7 -0
  22. overfast_client-0.1.0/overwatch_py/enums/role.py +7 -0
  23. overfast_client-0.1.0/overwatch_py/exceptions.py +33 -0
  24. overfast_client-0.1.0/overwatch_py/models/__init__.py +61 -0
  25. overfast_client-0.1.0/overwatch_py/models/gamemode_details.py +11 -0
  26. overfast_client-0.1.0/overwatch_py/models/hero.py +72 -0
  27. overfast_client-0.1.0/overwatch_py/models/hero_short.py +11 -0
  28. overfast_client-0.1.0/overwatch_py/models/hero_stats.py +9 -0
  29. overfast_client-0.1.0/overwatch_py/models/map_details.py +13 -0
  30. overfast_client-0.1.0/overwatch_py/models/player.py +64 -0
  31. overfast_client-0.1.0/overwatch_py/models/player_stats.py +115 -0
  32. overfast_client-0.1.0/overwatch_py/py.typed +0 -0
  33. overfast_client-0.1.0/overwatch_py/services/__init__.py +6 -0
  34. overfast_client-0.1.0/overwatch_py/services/heros.py +110 -0
  35. overfast_client-0.1.0/overwatch_py/services/maps.py +21 -0
  36. overfast_client-0.1.0/overwatch_py/services/players.py +135 -0
  37. overfast_client-0.1.0/overwatch_py/session.py +64 -0
  38. overfast_client-0.1.0/pyproject.toml +62 -0
  39. overfast_client-0.1.0/tests/__init__.py +0 -0
  40. overfast_client-0.1.0/tests/conftest.py +31 -0
  41. overfast_client-0.1.0/tests/fixtures/openapi.json +1 -0
  42. overfast_client-0.1.0/tests/test_enums.py +55 -0
  43. overfast_client-0.1.0/tests/test_exceptions.py +48 -0
  44. overfast_client-0.1.0/tests/test_heros_service.py +71 -0
  45. overfast_client-0.1.0/tests/test_maps_service.py +46 -0
  46. overfast_client-0.1.0/tests/test_players_service.py +81 -0
  47. overfast_client-0.1.0/tests/test_smoke.py +24 -0
@@ -0,0 +1,58 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ # Allow manual runs (e.g. re-publishing the same tag after a build-only fix).
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ build:
12
+ name: Build sdist + wheel
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Set up Python
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.12"
22
+
23
+ - name: Install build
24
+ run: |
25
+ python -m pip install --upgrade pip
26
+ pip install build
27
+
28
+ - name: Build
29
+ run: python -m build
30
+
31
+ - name: Upload artifacts
32
+ uses: actions/upload-artifact@v4
33
+ with:
34
+ name: dist
35
+ path: dist/
36
+
37
+ publish:
38
+ name: Publish to PyPI (Trusted Publishing)
39
+ needs: build
40
+ runs-on: ubuntu-latest
41
+ # The environment name must match what you configure on PyPI under
42
+ # "Manage → Publishing → Trusted publishers".
43
+ environment:
44
+ name: pypi
45
+ url: https://pypi.org/project/overfast-client/
46
+ permissions:
47
+ # Required for OIDC token exchange with PyPI.
48
+ id-token: write
49
+
50
+ steps:
51
+ - name: Download artifacts
52
+ uses: actions/download-artifact@v4
53
+ with:
54
+ name: dist
55
+ path: dist/
56
+
57
+ - name: Publish to PyPI
58
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,33 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ${{ matrix.os }}
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ubuntu-latest, windows-latest, macos-latest]
16
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - name: Set up Python ${{ matrix.python-version }}
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+ cache: pip
26
+
27
+ - name: Install package and dev deps
28
+ run: |
29
+ python -m pip install --upgrade pip
30
+ pip install -e ".[dev]"
31
+
32
+ - name: Run tests
33
+ run: pytest -v
@@ -0,0 +1,83 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+
7
+ # Distribution / packaging
8
+ .Python
9
+ build/
10
+ develop-eggs/
11
+ dist/
12
+ downloads/
13
+ eggs/
14
+ .eggs/
15
+ lib/
16
+ lib64/
17
+ parts/
18
+ sdist/
19
+ var/
20
+ wheels/
21
+ share/python-wheels/
22
+ *.egg-info/
23
+ .installed.cfg
24
+ *.egg
25
+ MANIFEST
26
+
27
+ # PyInstaller
28
+ *.manifest
29
+ *.spec
30
+
31
+ # Installer logs
32
+ pip-log.txt
33
+ pip-delete-this-directory.txt
34
+
35
+ # Unit test / coverage reports
36
+ htmlcov/
37
+ .tox/
38
+ .nox/
39
+ .coverage
40
+ .coverage.*
41
+ .cache
42
+ nosetests.xml
43
+ coverage.xml
44
+ *.cover
45
+ *.py,cover
46
+ .hypothesis/
47
+ .pytest_cache/
48
+ cover/
49
+
50
+ # Environments
51
+ .env
52
+ .env.*
53
+ .venv
54
+ env/
55
+ venv/
56
+ ENV/
57
+ env.bak/
58
+ venv.bak/
59
+
60
+ # IDEs / editors
61
+ .idea/
62
+ .vscode/
63
+ *.swp
64
+ *.swo
65
+ *~
66
+ .DS_Store
67
+ Thumbs.db
68
+
69
+ # mypy / ruff / pyright
70
+ .mypy_cache/
71
+ .dmypy.json
72
+ dmypy.json
73
+ .pyre/
74
+ .pytype/
75
+ .ruff_cache/
76
+ .pyright/
77
+
78
+ # Jupyter
79
+ .ipynb_checkpoints
80
+
81
+ # Project-local scratch
82
+ openapi_tmp.json
83
+ *.zip
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-04-14
11
+
12
+ ### Added
13
+ - Initial release.
14
+ - Async client for the [OverFast API](https://overfast-api.tekrop.fr/) built on `httpx`.
15
+ - Services: `HeroesService`, `MapsService`, `GamemodesService`, `RolesService`, `PlayersService`.
16
+ - Pydantic v2 models for heroes, maps, gamemodes, roles, and player data (summary, stats, career, search).
17
+ - Enums synchronized with the OverFast API schema: `Hero`, `Role`, `Region`, `Platform`, `Rank`, `CompetitiveDivisionFilter`, `HeroGamemode`, `PlayerGamemode`, `Privacy`, `BackgroundImageSize`, `CareerStatCategory`.
18
+ - HTTP-layer caching via [hishel](https://hishel.com) (memory / sqlite / file backends), opt-in through `ClientConfig.cache`.
19
+ - Automatic retries for transient failures via `httpx-retries`.
20
+ - Typed exceptions mapped to OverFast API responses: `BadRequestError` (400), `NotFoundError` (404), `ValidationError` (422), `RateLimitError` (429), `InternalServerError` (500), `ServiceUnavailableError` (503), `ParserBlizzardError` (504).
21
+ - `py.typed` marker for PEP 561 type-checker support.
22
+
23
+ [Unreleased]: https://github.com/Leo890728/overwatch_py/compare/v0.1.0...HEAD
24
+ [0.1.0]: https://github.com/Leo890728/overwatch_py/releases/tag/v0.1.0
@@ -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,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,123 @@
1
+ # overfast-client
2
+
3
+ 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.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install overfast-client
9
+ ```
10
+
11
+ > The PyPI distribution is `overfast-client`; the import name is `overwatch_py`.
12
+
13
+ Or from source (editable):
14
+
15
+ ```bash
16
+ pip install -e .
17
+ ```
18
+
19
+ ## Quick start
20
+
21
+ ```python
22
+ import asyncio
23
+ from overwatch_py import Client
24
+ from overwatch_py.enums import Hero, Locale, Role, HeroGamemode, PlayerGamemode, Platform
25
+
26
+ async def main():
27
+ client = Client()
28
+
29
+ # List heroes
30
+ heroes = await client.get_heroes(role=Role.SUPPORT, locale=Locale.EN_US)
31
+ for h in heroes:
32
+ print(h.key, h.name)
33
+
34
+ # Full hero data (abilities, story, hitpoints, ...)
35
+ ana = await client.get_hero_data(Hero.ANA)
36
+ print(ana.hitpoints, len(ana.abilities))
37
+
38
+ # Maps & gamemodes
39
+ maps = await client.get_maps()
40
+ gamemodes = await client.get_gamemode_details()
41
+
42
+ # Hero usage stats (pickrate / winrate)
43
+ stats = await client.get_heroes_stats(
44
+ platform=Platform.PC,
45
+ gamemode=PlayerGamemode.COMPETITIVE,
46
+ )
47
+
48
+ # Players
49
+ result = await client.search_players("TeKrop", limit=10)
50
+ player = await client.get_player(result.results[0].player_id)
51
+ summary = await client.get_player_summary("TeKrop-2217")
52
+ stats_summary = await client.get_player_stats("TeKrop-2217", gamemode=PlayerGamemode.COMPETITIVE)
53
+
54
+ asyncio.run(main())
55
+ ```
56
+
57
+ ## Configuration
58
+
59
+ ```python
60
+ from overwatch_py import Client
61
+ from overwatch_py.config import Config
62
+ from overwatch_py.session import HTTPSession
63
+
64
+ config = Config(
65
+ timeout=10, # seconds
66
+ retries=3, # retries on 5xx
67
+ cache=True, # HTTP-level cache (hishel), respects server Cache-Control
68
+ cache_backend="sqlite", # "memory" | "sqlite" | "file"
69
+ )
70
+ client = Client(HTTPSession(config))
71
+ ```
72
+
73
+ ### Caching
74
+
75
+ 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).
76
+
77
+ ## Exceptions
78
+
79
+ All non-2xx responses map to subclasses of `APIError`:
80
+
81
+ | Status | Exception |
82
+ |--------|-----------|
83
+ | 400 | `BadRequestError` |
84
+ | 404 | `NotFoundError` |
85
+ | 422 | `ValidationError` |
86
+ | 429 | `APIRateLimitError` |
87
+ | 500 | `InternalServerError` |
88
+ | 503 | `BlizzardRateLimitError` |
89
+ | 504 | `BlizzardServerError` |
90
+
91
+ ```python
92
+ from overwatch_py.exceptions import NotFoundError, APIRateLimitError
93
+
94
+ try:
95
+ await client.get_player_summary("does-not-exist-1234")
96
+ except NotFoundError:
97
+ ...
98
+ except APIRateLimitError as e:
99
+ print("rate limited:", e.response.headers.get("retry-after"))
100
+ ```
101
+
102
+ ## API surface
103
+
104
+ Exposed on `Client`:
105
+
106
+ - **Heroes** — `get_heroes`, `get_hero_data`, `get_heroes_stats`
107
+ - **Maps / Gamemodes** — `get_maps`, `get_gamemode_details`
108
+ - **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`
109
+
110
+ The underlying services (`client.heros`, `client.maps`, `client.players`) are also available if you prefer service-level access.
111
+
112
+ ## Development
113
+
114
+ ```bash
115
+ pip install -e ".[dev]"
116
+ pytest # unit + mocked HTTP tests
117
+ pytest -m live # hits the real API (rate-limited)
118
+ pytest -m 'live or not live' # run everything
119
+ ```
120
+
121
+ ## License
122
+
123
+ MIT.
@@ -0,0 +1,4 @@
1
+ from .client import Client
2
+
3
+ __version__ = "0.1.0"
4
+ __all__ = ["Client", "__version__"]
@@ -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)
@@ -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"