Error Handling⚓︎
PokeLance raises a small, predictable exception hierarchy so you can catch broadly (any library error) or narrowly (a specific HTTP status) depending on what your application needs.
The hierarchy⚓︎
flowchart TD
A[PokeLanceException] --> B[HTTPException]
B --> C[BadRequest - 400]
B --> D[Unauthorized - 401]
B --> E[Forbidden - 403]
B --> F[NotFound - 404]
F --> G[ResourceNotFound]
B --> H[MethodNotAllowed - 405]
B --> I[UnknownError - any other status]
F --> J[ImageNotFound]
F --> K[AudioNotFound]
Every exception carries the Route that caused it, so
str(exc) always tells you exactly which endpoint failed:
import asyncio
from pokelance import PokeLance
from pokelance.exceptions import ResourceNotFound
client = PokeLance()
async def main() -> str:
await client.wait_until_ready()
try:
await client.pokemon.fetch_pokemon("not-a-real-pokemon")
except ResourceNotFound as exc:
return str(exc)
finally:
await client.close()
return "unreachable"
print(asyncio.run(main()))
Resource not found. Suggestions: inteleon | <Route endpoint=/pokemon/not-a-real-pokemon method=GET> | 404
ResourceNotFound: typo suggestions⚓︎
ResourceNotFound is raised by
_validate_resource (used internally by every get_*/fetch_* method) before any
network request is made, as soon as a name/id isn't found in the pre-loaded endpoint
registry. It carries a suggestions: Optional[List[str]] attribute, computed with
difflib.get_close_matches against every known name and id in that category:
import asyncio
from pokelance import PokeLance
from pokelance.exceptions import ResourceNotFound
client = PokeLance()
async def main() -> str:
await client.wait_until_ready()
try:
await client.berry.fetch_berry("chery") # typo for "cheri"
except ResourceNotFound as exc:
print(f"Failed to fetch {exc.route}: {', '.join(exc.suggestions or [])}")
finally:
await client.close()
asyncio.run(main())
Failed to fetch <Route endpoint=/berry/chery method=GET>: cheri, yache, chople, chesto, charti
Requires the endpoint registry to be populated
Suggestions (and the pre-flight validation itself) only work when the relevant
category's endpoint registry has been loaded, i.e. cache_endpoints=True
(the default) and, ideally, after await client.wait_until_ready(). See
Configuration.
HTTP status mapping⚓︎
Anything that does reach the network and comes back with a non-2xx status is converted
by HTTPException.create() into the matching
subclass, via get_exception:
from pokelance.exceptions import CODES, UnknownError
for status, cls in sorted(CODES.items()):
print(f"{status} -> {cls.__name__}")
print(f"(anything else) -> {UnknownError.__name__}")
400 -> BadRequest
401 -> Unauthorized
403 -> Forbidden
404 -> ResourceNotFound
405 -> MethodNotAllowed
(anything else) -> UnknownError
| Status | Exception |
|---|---|
| 400 | BadRequest |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | ResourceNotFound |
| 405 | MethodNotAllowed |
| other | UnknownError |
Media-specific exceptions⚓︎
get_image_async and
get_audio_async validate the response's
Content-Type in addition to its status code, and raise
ImageNotFound /
AudioNotFound respectively if either the request
failed or the URL didn't actually point at image/audio content. See
Media for the accepted content types.
Recommended patterns⚓︎
In a FastAPI handler, for instance, you may want an unhandled ResourceNotFound to
naturally become a 404, see the FastAPI recipe for a
complete example with an exception handler registered at the app level.