Skip to content

Commit

Permalink
Initial commit of a handling preview client's 429 Too Many Requests e…
Browse files Browse the repository at this point in the history
…rror.
  • Loading branch information
fkdosilovic committed Nov 29, 2024
1 parent c055e17 commit 25b0740
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/judge0/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ def _get_implicit_client(flavor: Flavor) -> Client:
CE = Flavor.CE
EXTRA_CE = Flavor.EXTRA_CE

# TODO: Let's use getattr and setattr for this language ALIASES and raise an
# exception if a value already exists.
PYTHON = LanguageAlias.PYTHON
CPP = LanguageAlias.CPP
JAVA = LanguageAlias.JAVA
Expand Down
13 changes: 12 additions & 1 deletion src/judge0/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .data import LANGUAGE_TO_LANGUAGE_ID
from .retry import RetryStrategy
from .submission import Submission, Submissions
from .utils import handle_too_many_requests_error_for_preview_client


class Client:
Expand All @@ -22,6 +23,7 @@ def __init__(
self.auth_headers = auth_headers
self.retry_strategy = retry_strategy

# TODO: Should be handled differently.
try:
self.languages = tuple(Language(**lang) for lang in self.get_languages())
self.config = Config(**self.get_config_info())
Expand All @@ -30,6 +32,7 @@ def __init__(
f"Authentication failed. Visit {self.HOME_URL} to get or review your authentication credentials."
) from e

@handle_too_many_requests_error_for_preview_client
def get_about(self) -> dict:
r = requests.get(
f"{self.endpoint}/about",
Expand All @@ -38,6 +41,7 @@ def get_about(self) -> dict:
r.raise_for_status()
return r.json()

@handle_too_many_requests_error_for_preview_client
def get_config_info(self) -> dict:
r = requests.get(
f"{self.endpoint}/config_info",
Expand All @@ -46,18 +50,21 @@ def get_config_info(self) -> dict:
r.raise_for_status()
return r.json()

@handle_too_many_requests_error_for_preview_client
def get_language(self, language_id) -> dict:
request_url = f"{self.endpoint}/languages/{language_id}"
r = requests.get(request_url, headers=self.auth_headers)
r.raise_for_status()
return r.json()

@handle_too_many_requests_error_for_preview_client
def get_languages(self) -> list[dict]:
request_url = f"{self.endpoint}/languages"
r = requests.get(request_url, headers=self.auth_headers)
r.raise_for_status()
return r.json()

@handle_too_many_requests_error_for_preview_client
def get_statuses(self) -> list[dict]:
r = requests.get(
f"{self.endpoint}/statuses",
Expand All @@ -74,7 +81,7 @@ def version(self):
return self._version

def get_language_id(self, language: Union[LanguageAlias, int]) -> int:
"""Get language id for the corresponding language alias for the client."""
"""Get language id corresponding to the language alias for the client."""
if isinstance(language, LanguageAlias):
supported_language_ids = LANGUAGE_TO_LANGUAGE_ID[self.version]
language = supported_language_ids.get(language, -1)
Expand All @@ -85,6 +92,7 @@ def is_language_supported(self, language: Union[LanguageAlias, int]) -> bool:
language_id = self.get_language_id(language)
return any(language_id == lang.id for lang in self.languages)

@handle_too_many_requests_error_for_preview_client
def create_submission(self, submission: Submission) -> Submission:
# Check if the client supports the language specified in the submission.
if not self.is_language_supported(language=submission.language):
Expand Down Expand Up @@ -112,6 +120,7 @@ def create_submission(self, submission: Submission) -> Submission:

return submission

@handle_too_many_requests_error_for_preview_client
def get_submission(
self,
submission: Submission,
Expand Down Expand Up @@ -143,6 +152,7 @@ def get_submission(

return submission

@handle_too_many_requests_error_for_preview_client
def create_submissions(self, submissions: Submissions) -> Submissions:
# Check if all submissions contain supported language.
for submission in submissions:
Expand All @@ -167,6 +177,7 @@ def create_submissions(self, submissions: Submissions) -> Submissions:

return submissions

@handle_too_many_requests_error_for_preview_client
def get_submissions(
self,
submissions: Submissions,
Expand Down
47 changes: 47 additions & 0 deletions src/judge0/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Module containing different utility functions for Judge0 Python SDK."""

from functools import wraps
from http import HTTPStatus

from requests import HTTPError


def is_http_too_many_requests_error(exception: Exception) -> bool:
return (
isinstance(exception, HTTPError)
and exception.response is not None
and exception.response.status_code == HTTPStatus.TOO_MANY_REQUESTS
)


def handle_too_many_requests_error_for_preview_client(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except HTTPError as err:
if is_http_too_many_requests_error(exception=err):
# If the raised exception is inside the one of the Sulu clients
# let's check if we are dealing with the implicit client.
if args:
instance = args[0]
class_name = instance.__class__.__name__
# Check if we are using a preview version of the client.
if (
class_name in ("SuluJudge0CE", "SuluJudge0ExtraCE")
and instance.api_key is None
):
raise RuntimeError(
"You are using a preview version of the Sulu "
"clients and you've hit a rate limit on the preview "
f"clients. Visit {instance.HOME_URL} to get or "
"review your authentication credentials."
) from err
else:
raise err from None
else:
raise err from None
except Exception as err:
raise err from None

return wrapper

0 comments on commit 25b0740

Please sign in to comment.