pyke
pyke
pyke is a production-ready Riot API wrapper with intelligent rate limiting and robust error handling, specifically designed for League of Legends.
Key Features
- Smart Rate Limiting - Dynamic request throttling based on API headers to maximize throughput while preventing 429 errors
- Resilient Retry Logic - Retry strategies for rate limits and server errors with intelligent exponential backoff
- Type-Safe - Full Pydantic model support with comprehensive type hints for autocompletion and validation
- Pythonic API - Clean, intuitive interface that mirrors Riot's API structure exactly
- Production Logging - Standard Python logging integration with configurable levels
- Highly Configurable - Customize timeouts, retry limits, rate limiting behavior, and more
Installation
Install the latest version directly from PyPI:
pip install pyke-lol
Note: You need Python 3.9+ to use pyke.
Quickstart
from pyke import Continent, Pyke, exceptions
# Initialize the API
api = Pyke("RGAPI-...")
# Every pyke method follows the same convention as the Riot API
# For example account/v1/accounts/by-riot-id/{gameName}/{tagLine} becomes:
account = api.account.by_riot_id(Continent.EUROPE, "saves", "000")
# Every response is a Pydantic model with dot notation access
print(f"Riot ID: {account.game_name}#{account.tag_line}")
print(f"PUUID: {account.puuid}")
# Pydantic models provide convenient serialization
print(account.model_dump_json()) # JSON string
print(account.model_dump()) # Python dictionary
# pyke throws typed exceptions matching Riot API error codes
try:
region = api.account.region_by_puuid(Continent.EUROPE, account.puuid)
except exceptions.DataNotFound as e:
print(e) # Output: Data not found (Error Code: 404)
quit()
print(f"PUUID: {region.puuid}")
print(f"Game: {region.game}")
print(f"Region: {region.region}")
Configuration
pyke offers extensive configuration options for production use:
from pyke import Pyke
api = Pyke(
api_key="RGAPI-...",
smart_rate_limiting=True, # Enable intelligent rate limiting (default: True)
timeout=60, # Request timeout in seconds (default: 60)
max_rate_limit_retries=5, # Max retries for 429 errors (default: 5)
max_server_error_retries=3, # Max retries for 502/503/504 (default: 3)
)
Smart Rate Limiting
pyke's rate limiting algorithm analyzes response headers to:
- Calculate optimal wait times between requests
- Maximize throughput without hitting rate limits
- Automatically respect
Retry-Afterheaders on 429 responses
Result: Zero rate limit violations while maintaining maximum request speed.
Intelligent Retry Logic
pyke uses separate retry strategies for different error types:
Rate Limit Errors (429):
- Independent retry counter (default: 5 attempts)
- Respects
Retry-Afterheader from API - Logs retry progress:
Rate limit retries: 2/5
Server Errors (502/503/504):
- Separate retry counter (default: 3 attempts)
- Error-specific exponential backoff:
- 504 Gateway Timeout: 10s base (10s → 20s → 40s) - longer recovery for backend timeouts
- 502/503 Server Errors: 5s base (5s → 10s → 20s) - faster recovery for transient issues
- Prevents infinite retry loops while maintaining resilience
Logging
pyke uses Python's standard logging module for comprehensive diagnostics:
import logging
from pyke import Pyke
# Configure logging before creating Pyke instance
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
datefmt="%H:%M:%S",
)
api = Pyke("RGAPI-...")
Log Levels
- DEBUG: Detailed diagnostic information
- INFO: Request URLs with rate limit tracking:
(45/100) - https://na1.api.riotgames.com/... - WARNING: Retries, rate limiting, malformed API responses
- ERROR: Critical failures
Common Configurations
# Production (quiet) - only warnings and errors
logging.basicConfig(level=logging.WARNING)
# Development (verbose) - see all requests
logging.basicConfig(level=logging.INFO)
# Debugging - maximum verbosity
logging.basicConfig(level=logging.DEBUG)
# Completely silent
logging.getLogger('pyke').setLevel(logging.CRITICAL)
# Log to file
logging.basicConfig(
level=logging.INFO,
filename="api_requests.log",
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s"
)
Advanced Features
Type Safety with Pydantic Models
All API responses are Pydantic models with full type hints:
from pyke import Pyke, Region
api = Pyke("RGAPI-...")
account = api.account.by_riot_id(Continent.EUROPE, "saves", "000")
summoner = api.summoner.by_puuid(Region.EUW, account.puuid)
# Dot notation access with autocomplete
print(summoner.puuid) # Type: str
print(summoner.summoner_level) # Type: int
print(summoner.profile_icon_id) # Type: int
# JSON serialization
json_str = summoner.model_dump_json()
dict_data = summoner.model_dump()
Custom Exception Handling
pyke provides typed exceptions for all HTTP status codes:
from pyke import exceptions
try:
summoner = api.summoner.by_puuid(Region.EUW, "NonExistentPuuid")
except exceptions.DataNotFound as e:
print(f"Not found: {e}") # Data not found (Error Code: 404)
except exceptions.RateLimitExceeded as e:
print(f"Rate limited: {e}") # Rate limit exceeded after 5 retries (Error Code: 429)
except exceptions.InternalServerError as e:
print(f"Server error: {e}") # Internal server error (Error Code: 500)
Available exceptions:
BadRequest (400), Unauthorized (401), Forbidden (403), DataNotFound (404), MethodNotAllowed (405), UnsupportedMediaType (415), RateLimitExceeded (429), InternalServerError (500), BadGateway (502), ServiceUnavailable (503), GatewayTimeout (504)
Continental vs Regional Routing
pyke automatically handles Riot's routing requirements:
from pyke import Continent, Region
# Continental routing (Account-V1, Match-V5)
account = api.account.by_riot_id(Continent.EUROPE, "saves", "000")
# Regional routing (Summoner-V4, League-V4, etc.)
summoner = api.summoner.by_puuid(Region.EUW, account.puuid)
Continental Routing:
AMERICAS: NA, BR, LAN, LASASIA: KR, JPEUROPE: EUNE, EUW, ME1, TR, RUSEA: OCE, SG2, TW2, VN2
Complete Feature List
- Smart Rate Limiting - Dynamic throttling based on API headers
- Dual Retry Strategies - Separate 429 and 50x retry logic with exponential backoff
- Type-Safe Models - 97 Pydantic models with full type hints
- Production Logging - Standard Python logging with configurable levels
- Custom Exceptions - 11 typed exception classes for precise error handling
- Continental Routing - Automatic routing for Account/Match endpoints
- Configurable Timeouts - Adjust request timeouts for slow endpoints
- Mirror API Design - Intuitive mapping to Riot's API structure
- Pythonic Interface - Clean, idiomatic Python code
- 94% Test Coverage - Comprehensive integration test suite
- Python 3.9-3.14 - Tested across 6 Python versions
Documentation & Resources
- API Documentation - Complete API reference with examples
- Examples Directory - 15+ working examples covering all features
- PyPI Package - Official package distribution
- GitHub Repository - Source code and issue tracking
Contributing & Support
Found a bug or have a feature request? Open an issue on GitHub.
For questions or help, reach out on Discord: .irm
License
MIT License - see LICENSE.txt for details.
Made with ❤️ for the League of Legends developer community
1"""# pyke 2 3[](https://pypi.org/project/pyke-lol/) 4[](https://diodemusic.github.io/pyke/) 5[](https://pypi.org/project/pyke-lol/) 6 7[](https://github.com/diodemusic/pyke/blob/main/LICENCE.txt) 8 9**pyke** is a production-ready Riot API wrapper with intelligent rate limiting and robust error handling, specifically designed for League of Legends. 10 11## Key Features 12 13- **Smart Rate Limiting** - Dynamic request throttling based on API headers to maximize throughput while preventing 429 errors 14- **Resilient Retry Logic** - Retry strategies for rate limits and server errors with intelligent exponential backoff 15- **Type-Safe** - Full Pydantic model support with comprehensive type hints for autocompletion and validation 16- **Pythonic API** - Clean, intuitive interface that mirrors Riot's API structure exactly 17- **Production Logging** - Standard Python logging integration with configurable levels 18- **Highly Configurable** - Customize timeouts, retry limits, rate limiting behavior, and more 19 20--- 21 22## Installation 23 24Install the latest version directly from PyPI: 25 26```bash 27pip install pyke-lol 28``` 29 30> **Note:** You need Python 3.9+ to use pyke. 31 32--- 33 34## Quickstart 35 36```py 37from pyke import Continent, Pyke, exceptions 38 39# Initialize the API 40api = Pyke("RGAPI-...") 41 42# Every pyke method follows the same convention as the Riot API 43# For example account/v1/accounts/by-riot-id/{gameName}/{tagLine} becomes: 44account = api.account.by_riot_id(Continent.EUROPE, "saves", "000") 45 46# Every response is a Pydantic model with dot notation access 47print(f"Riot ID: {account.game_name}#{account.tag_line}") 48print(f"PUUID: {account.puuid}") 49 50# Pydantic models provide convenient serialization 51print(account.model_dump_json()) # JSON string 52print(account.model_dump()) # Python dictionary 53 54# pyke throws typed exceptions matching Riot API error codes 55try: 56 region = api.account.region_by_puuid(Continent.EUROPE, account.puuid) 57except exceptions.DataNotFound as e: 58 print(e) # Output: Data not found (Error Code: 404) 59 quit() 60 61print(f"PUUID: {region.puuid}") 62print(f"Game: {region.game}") 63print(f"Region: {region.region}") 64``` 65 66--- 67 68## Configuration 69 70pyke offers extensive configuration options for production use: 71 72```py 73from pyke import Pyke 74 75api = Pyke( 76 api_key="RGAPI-...", 77 smart_rate_limiting=True, # Enable intelligent rate limiting (default: True) 78 timeout=60, # Request timeout in seconds (default: 60) 79 max_rate_limit_retries=5, # Max retries for 429 errors (default: 5) 80 max_server_error_retries=3, # Max retries for 502/503/504 (default: 3) 81) 82``` 83 84### Smart Rate Limiting 85 86pyke's rate limiting algorithm analyzes response headers to: 87 88- Calculate optimal wait times between requests 89- Maximize throughput without hitting rate limits 90- Automatically respect `Retry-After` headers on 429 responses 91 92**Result:** Zero rate limit violations while maintaining maximum request speed. 93 94### Intelligent Retry Logic 95 96pyke uses **separate retry strategies** for different error types: 97 98**Rate Limit Errors (429):** 99 100- Independent retry counter (default: 5 attempts) 101- Respects `Retry-After` header from API 102- Logs retry progress: `Rate limit retries: 2/5` 103 104**Server Errors (502/503/504):** 105 106- Separate retry counter (default: 3 attempts) 107- Error-specific exponential backoff: 108 - **504 Gateway Timeout:** 10s base (10s → 20s → 40s) - longer recovery for backend timeouts 109 - **502/503 Server Errors:** 5s base (5s → 10s → 20s) - faster recovery for transient issues 110- Prevents infinite retry loops while maintaining resilience 111 112--- 113 114## Logging 115 116pyke uses Python's standard `logging` module for comprehensive diagnostics: 117 118```py 119import logging 120from pyke import Pyke 121 122# Configure logging before creating Pyke instance 123logging.basicConfig( 124 level=logging.INFO, 125 format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", 126 datefmt="%H:%M:%S", 127) 128 129api = Pyke("RGAPI-...") 130``` 131 132### Log Levels 133 134- **DEBUG:** Detailed diagnostic information 135- **INFO:** Request URLs with rate limit tracking: `(45/100) - https://na1.api.riotgames.com/...` 136- **WARNING:** Retries, rate limiting, malformed API responses 137- **ERROR:** Critical failures 138 139### Common Configurations 140 141```py 142# Production (quiet) - only warnings and errors 143logging.basicConfig(level=logging.WARNING) 144 145# Development (verbose) - see all requests 146logging.basicConfig(level=logging.INFO) 147 148# Debugging - maximum verbosity 149logging.basicConfig(level=logging.DEBUG) 150 151# Completely silent 152logging.getLogger('pyke').setLevel(logging.CRITICAL) 153 154# Log to file 155logging.basicConfig( 156 level=logging.INFO, 157 filename="api_requests.log", 158 format="%(asctime)s [%(levelname)s] %(name)s: %(message)s" 159) 160``` 161 162--- 163 164## Advanced Features 165 166### Type Safety with Pydantic Models 167 168All API responses are Pydantic models with full type hints: 169 170```py 171from pyke import Pyke, Region 172 173api = Pyke("RGAPI-...") 174 175account = api.account.by_riot_id(Continent.EUROPE, "saves", "000") 176summoner = api.summoner.by_puuid(Region.EUW, account.puuid) 177 178# Dot notation access with autocomplete 179print(summoner.puuid) # Type: str 180print(summoner.summoner_level) # Type: int 181print(summoner.profile_icon_id) # Type: int 182 183# JSON serialization 184json_str = summoner.model_dump_json() 185dict_data = summoner.model_dump() 186``` 187 188### Custom Exception Handling 189 190pyke provides typed exceptions for all HTTP status codes: 191 192```py 193from pyke import exceptions 194 195try: 196 summoner = api.summoner.by_puuid(Region.EUW, "NonExistentPuuid") 197except exceptions.DataNotFound as e: 198 print(f"Not found: {e}") # Data not found (Error Code: 404) 199except exceptions.RateLimitExceeded as e: 200 print(f"Rate limited: {e}") # Rate limit exceeded after 5 retries (Error Code: 429) 201except exceptions.InternalServerError as e: 202 print(f"Server error: {e}") # Internal server error (Error Code: 500) 203``` 204 205**Available exceptions:** 206`BadRequest` (400), `Unauthorized` (401), `Forbidden` (403), `DataNotFound` (404), `MethodNotAllowed` (405), `UnsupportedMediaType` (415), `RateLimitExceeded` (429), `InternalServerError` (500), `BadGateway` (502), `ServiceUnavailable` (503), `GatewayTimeout` (504) 207 208### Continental vs Regional Routing 209 210pyke automatically handles Riot's routing requirements: 211 212```py 213from pyke import Continent, Region 214 215# Continental routing (Account-V1, Match-V5) 216account = api.account.by_riot_id(Continent.EUROPE, "saves", "000") 217 218# Regional routing (Summoner-V4, League-V4, etc.) 219summoner = api.summoner.by_puuid(Region.EUW, account.puuid) 220``` 221 222**Continental Routing:** 223 224- `AMERICAS`: NA, BR, LAN, LAS 225- `ASIA`: KR, JP 226- `EUROPE`: EUNE, EUW, ME1, TR, RU 227- `SEA`: OCE, SG2, TW2, VN2 228 229--- 230 231## Complete Feature List 232 233- **Smart Rate Limiting** - Dynamic throttling based on API headers 234- **Dual Retry Strategies** - Separate 429 and 50x retry logic with exponential backoff 235- **Type-Safe Models** - 97 Pydantic models with full type hints 236- **Production Logging** - Standard Python logging with configurable levels 237- **Custom Exceptions** - 11 typed exception classes for precise error handling 238- **Continental Routing** - Automatic routing for Account/Match endpoints 239- **Configurable Timeouts** - Adjust request timeouts for slow endpoints 240- **Mirror API Design** - Intuitive mapping to Riot's API structure 241- **Pythonic Interface** - Clean, idiomatic Python code 242- **94% Test Coverage** - Comprehensive integration test suite 243- **Python 3.9-3.14** - Tested across 6 Python versions 244 245--- 246 247## Documentation & Resources 248 249- **[API Documentation](https://diodemusic.github.io/pyke/pyke.html)** - Complete API reference with examples 250- **[Examples Directory](https://github.com/diodemusic/pyke/tree/master/examples)** - 15+ working examples covering all features 251- **[PyPI Package](https://pypi.org/project/pyke-lol/)** - Official package distribution 252- **[GitHub Repository](https://github.com/diodemusic/pyke)** - Source code and issue tracking 253 254--- 255 256## Contributing & Support 257 258Found a bug or have a feature request? Open an issue on [GitHub](https://github.com/diodemusic/pyke/issues). 259 260For questions or help, reach out on Discord: `.irm` 261 262--- 263 264## License 265 266MIT License - see [LICENSE.txt](https://github.com/diodemusic/pyke/blob/main/LICENCE.txt) for details. 267 268--- 269 270**Made with ❤️ for the League of Legends developer community** 271""" 272 273from . import ddragon, endpoints, enums, exceptions, models 274from .__version__ import __author__, __title__, __version__ 275from .enums.continent import Continent 276from .enums.division import Division 277from .enums.level import Level 278from .enums.queue import Queue 279from .enums.region import Region 280from .enums.tier import Tier 281from .enums.type import Type 282from .main import DataDragon, Pyke 283 284__all__ = [ 285 "ddragon", 286 "exceptions", 287 "Continent", 288 "Division", 289 "Level", 290 "Queue", 291 "Region", 292 "Tier", 293 "Type", 294 "DataDragon", 295 "Pyke", 296 "__author__", 297 "__title__", 298 "__version__", 299 "endpoints", 300 "enums", 301 "models", 302]
5class Continent(Enum): 6 """# Continent to execute against""" 7 8 AMERICAS = "americas" 9 ASIA = "asia" 10 EUROPE = "europe" 11 SEA = "sea"
Continent to execute against
5class Division(Enum): 6 """# Ranked division""" 7 8 I = "I" # noqa: E741 9 II = "II" 10 III = "III" 11 IV = "IV"
Ranked division
5class Level(Enum): 6 """# Challenge level""" 7 8 NONE = "NONE" 9 IRON = "IRON" 10 BRONZE = "BRONZE" 11 SILVER = "SILVER" 12 GOLD = "GOLD" 13 PLATINUM = "PLATINUM" 14 EMERALD = "EMERALD" 15 DIAMOND = "DIAMOND" 16 MASTER = "MASTER" 17 GRANDMASTER = "GRANDMASTER" 18 CHALLENGER = "CHALLENGER" 19 HIGHEST_NOT_LEADERBOARD_ONLY = "HIGHEST_NOT_LEADERBOARD_ONLY" 20 HIGHEST = "HIGHEST" 21 LOWEST = "LOWEST"
Challenge level
5class Queue(Enum): 6 """# Ranked queue type""" 7 8 SOLO_DUO = "RANKED_SOLO_5x5" 9 FLEX = "RANKED_FLEX_SR"
Ranked queue type
5class Region(Enum): 6 """# Region to execute against""" 7 8 BR = "br1" 9 EUNE = "eun1" 10 EUW = "euw1" 11 JP = "jp1" 12 KR = "kr" 13 LAN = "la1" 14 LAS = "la2" 15 ME = "me1" 16 NA = "na1" 17 OCE = "oc1" 18 RU = "ru" 19 TR = "tr1" 20 PH = "sg2" 21 SG = "sg2" 22 TH = "sg2" 23 TW = "tw2" 24 VN = "vn2"
Region to execute against
5class Tier(Enum): 6 """# Ranked tier""" 7 8 IRON = "IRON" 9 BRONZE = "BRONZE" 10 SILVER = "SILVER" 11 GOLD = "GOLD" 12 PLATINUM = "PLATINUM" 13 EMERALD = "EMERALD" 14 DIAMOND = "DIAMOND" 15 MASTER = "MASTER" 16 GRANDMASTER = "GRANDMASTER" 17 CHALLENGER = "CHALLENGER"
Ranked tier
5class Type(Enum): 6 """# Type of match""" 7 8 RANKED = "ranked" 9 NORMAL = "normal" 10 TOURNEY = "tourney" 11 TUTORIAL = "tutorial"
Type of match
82class DataDragon: 83 def __init__(self, version: str | None = None, timeout: int = 10) -> None: 84 self._client = _BaseDataDragonClient(version, timeout) 85 86 # self.versions = VersionsData(self._client) 87 self.spellbuffs = SpellbuffsData(self._client) 88 self.item = ItemData(self._client) 89 self.runes_reforged = RunesReforgedData(self._client) 90 self.language = LanguageData(self._client) 91 self.feats = FeatsData(self._client) 92 self.champion_full = ChampionFullData(self._client) 93 self.summoner = SummonerData(self._client) 94 self.champion = ChampionData(self._client) 95 self.challenges = ChallengesData(self._client) 96 self.sticker = StickerData(self._client) 97 self.profileicon = ProfileiconData(self._client) 98 self.map = MapData(self._client)
83 def __init__(self, version: str | None = None, timeout: int = 10) -> None: 84 self._client = _BaseDataDragonClient(version, timeout) 85 86 # self.versions = VersionsData(self._client) 87 self.spellbuffs = SpellbuffsData(self._client) 88 self.item = ItemData(self._client) 89 self.runes_reforged = RunesReforgedData(self._client) 90 self.language = LanguageData(self._client) 91 self.feats = FeatsData(self._client) 92 self.champion_full = ChampionFullData(self._client) 93 self.summoner = SummonerData(self._client) 94 self.champion = ChampionData(self._client) 95 self.challenges = ChallengesData(self._client) 96 self.sticker = StickerData(self._client) 97 self.profileicon = ProfileiconData(self._client) 98 self.map = MapData(self._client)
39class Pyke: 40 """# Main entrypoint for interacting with the Riot API 41 42 **Example:** 43 `api = Pyke("API_KEY")` 44 45 **Args:** 46 `api_key (str | None)` Your Riot API key. 47 `smart_rate_limiting (bool, optional)` Automatically throttle requests to stay under rate limits. Defaults to True. 48 `timeout (int, optional)` Request timeout in seconds. Defaults to 60. 49 `max_rate_limit_retries (int, optional)` Maximum retry attempts for 429 rate limit errors. Defaults to 5. 50 `max_server_error_retries (int, optional)` Maximum retry attempts for 502/503/504 server errors. Defaults to 3. 51 """ # fmt: skip 52 53 def __init__( 54 self, 55 api_key: str | None, 56 smart_rate_limiting: bool = True, 57 timeout: int = 60, 58 max_rate_limit_retries: int = 5, 59 max_server_error_retries: int = 3, 60 ) -> None: 61 self._client = _BaseApiClient( 62 api_key, 63 smart_rate_limiting, 64 timeout, 65 max_rate_limit_retries, 66 max_server_error_retries, 67 ) 68 69 self.account = AccountEndpoint(self._client) 70 self.champion_mastery = ChampionMasteryEndpoint(self._client) 71 self.champion = ChampionEndpoint(self._client) 72 self.clash = ClashEndpoint(self._client) 73 self.league_exp = LeagueExpEndpoint(self._client) 74 self.league = LeagueEndpoint(self._client) 75 self.lol_challenges = ChallengesEndpoint(self._client) 76 self.lol_status = StatusEndpoint(self._client) 77 self.match = MatchEndpoint(self._client) 78 self.spectator = SpectatorEndpoint(self._client) 79 self.summoner = SummonerEndpoint(self._client)
Main entrypoint for interacting with the Riot API
Example:
api = Pyke("API_KEY")
Args:
api_key (str | None) Your Riot API key.
smart_rate_limiting (bool, optional) Automatically throttle requests to stay under rate limits. Defaults to True.
timeout (int, optional) Request timeout in seconds. Defaults to 60.
max_rate_limit_retries (int, optional) Maximum retry attempts for 429 rate limit errors. Defaults to 5.
max_server_error_retries (int, optional) Maximum retry attempts for 502/503/504 server errors. Defaults to 3.
53 def __init__( 54 self, 55 api_key: str | None, 56 smart_rate_limiting: bool = True, 57 timeout: int = 60, 58 max_rate_limit_retries: int = 5, 59 max_server_error_retries: int = 3, 60 ) -> None: 61 self._client = _BaseApiClient( 62 api_key, 63 smart_rate_limiting, 64 timeout, 65 max_rate_limit_retries, 66 max_server_error_retries, 67 ) 68 69 self.account = AccountEndpoint(self._client) 70 self.champion_mastery = ChampionMasteryEndpoint(self._client) 71 self.champion = ChampionEndpoint(self._client) 72 self.clash = ClashEndpoint(self._client) 73 self.league_exp = LeagueExpEndpoint(self._client) 74 self.league = LeagueEndpoint(self._client) 75 self.lol_challenges = ChallengesEndpoint(self._client) 76 self.lol_status = StatusEndpoint(self._client) 77 self.match = MatchEndpoint(self._client) 78 self.spectator = SpectatorEndpoint(self._client) 79 self.summoner = SummonerEndpoint(self._client)