Skip to content

Commit

Permalink
Replace requests w/ httpx so I/O no longer blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
claui committed Oct 28, 2024
1 parent 1907097 commit b3924c5
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 24 deletions.
8 changes: 7 additions & 1 deletion kickerde_api_client/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from typing import Any

import datetype
import httpx

from .mapping.league_list import league_list_home_to_dict
from .mapping.league_season_info import league_season_info_to_dict
Expand All @@ -29,11 +30,16 @@
class Api:
"""The primary API client and entry point for all requests."""

_provider: ResponseProvider

def __init__(
self,
http_client: httpx.AsyncClient | None = None,
provider: ResponseProvider | None = None,
) -> None:
self._provider = provider or DefaultResponseProvider()
self._provider = provider or DefaultResponseProvider(
http_client=http_client
)

async def leagues(self) -> dict[LeagueId, League]:
"""Returns all leagues and tournaments known to the system.
Expand Down
42 changes: 37 additions & 5 deletions kickerde_api_client/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

from abc import ABC, abstractmethod

import requests
import httpx

from .settings import DEFAULT_ENDPOINT_URL, REQUEST_TIMEOUT_SEC
from .settings import DEFAULT_ENDPOINT_URL


class ResponseProvider(ABC): # pylint: disable=too-few-public-methods
Expand All @@ -25,18 +25,50 @@ async def get(self, path: str) -> str:
class DefaultResponseProvider(ResponseProvider): # pylint: disable=too-few-public-methods
"""The default provider, which issues actual HTTP requests."""

def __init__(self, base_url: str = DEFAULT_ENDPOINT_URL):
# Internally re-use a single HTTP client for all object instances
# who do not bring their own
_internal_client: httpx.AsyncClient | None = None

_httpx_client: httpx.AsyncClient

def __init__(
self,
http_client: httpx.AsyncClient | None = None,
base_url: str = DEFAULT_ENDPOINT_URL,
):
"""
:param http_client:
An optional HTTP client to re-use.
The default value is `None`, which means that an internal
HTTP client will be used.
:param base_url:
The Kicker API endpoint to connect to.
The default value is the public production endpoint.
"""
self._base_url = base_url

if (
http_client is None
and DefaultResponseProvider._internal_client is None
):
DefaultResponseProvider._internal_client = (
httpx.AsyncClient()
)
existing_client = (
http_client or DefaultResponseProvider._internal_client
)
assert existing_client is not None
self._httpx_client = existing_client

async def get(self, path: str) -> str:
response = requests.get(
response = await self._httpx_client.get(
f'{self._base_url}/{path}',
timeout=REQUEST_TIMEOUT_SEC,
follow_redirects=False,
headers={
'Accept': 'application/xml',
'Cache-Control': 'no-cache',
},
)
response.raise_for_status()
return response.text
1 change: 0 additions & 1 deletion kickerde_api_client/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,5 @@
DEFAULT_ENDPOINT_URL = (
'https://ovsyndication.kicker.de/API/universal/3.0'
)
REQUEST_TIMEOUT_SEC = 30

debugMode = bool(os.getenv('KICKERDE_API_CLIENT_DEBUG'))
104 changes: 89 additions & 15 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ repository = "https://github.com/claui/kickerde-api-client"
[tool.poetry.dependencies]
python = ">=3.12"
datetype = "*"
requests = "^2.32.3"
httpx = "^0.27.2"
xmltodict = "^0.14.2"

[tool.poetry.group.dev.dependencies]
Expand All @@ -50,7 +50,6 @@ poethepoet = ">=0.24"
pylint = ">=3.0"
pytest = "*"
pytest-asyncio = "*"
types-requests = "*"
types-xmltodict = "*"

[tool.poetry.group.doc.dependencies]
Expand Down

0 comments on commit b3924c5

Please sign in to comment.