Skip to content

Commit

Permalink
feat(api): better impl
Browse files Browse the repository at this point in the history
  • Loading branch information
Caceresenzo committed Feb 29, 2024
1 parent a9a99ad commit 3ac1a1e
Show file tree
Hide file tree
Showing 38 changed files with 1,468 additions and 136 deletions.
2 changes: 2 additions & 0 deletions crunch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
your work to the crunchdao platform easily!
"""

from . import api

from .inline import load as load_notebook
from .runner import is_inside as is_inside_runner
from .orthogonalization import orthogonalize
3 changes: 2 additions & 1 deletion crunch/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .domain import *
from .models import *
from .client import Client
66 changes: 66 additions & 0 deletions crunch/api/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import abc
import typing


class Auth(metaclass=abc.ABCMeta):

@abc.abstractmethod
def apply(
self,
headers: dict,
params: dict,
data: typing.Optional[dict],
):
...


class NoneAuth(Auth):

def apply(
self,
headers: dict,
params: dict,
data: typing.Optional[dict],
):
pass


class ApiKeyAuth(Auth):

def __init__(
self,
key: str
):
super().__init__()

self._key = key

def apply(
self,
headers: dict,
params: dict,
data: typing.Optional[dict],
):
headers["Authorization"] = f"API-Key {self._key}"


class PushTokenAuth(Auth):

def __init__(
self,
token: str
):
super().__init__()

self._token = token

def apply(
self,
headers: dict,
params: dict,
data: typing.Optional[dict],
):
if data:
data["pushToken"] = self._token
else:
params["pushToken"] = self._token
32 changes: 32 additions & 0 deletions crunch/api/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import os

from .. import store, constants

from .auth import Auth, ApiKeyAuth, NoneAuth
from .endpoints import EndpointClient
from .models.competitions import CompetitionCollection


class Client:

def __init__(
self,
base_url: str,
auth: Auth
):
self.api = EndpointClient(base_url, auth)

@property
def competitions(self):
return CompetitionCollection(client=self)

def from_env():
store.load_from_env()

api_key = os.getenv(constants.API_KEY_ENV_VAR)
if api_key:
auth = ApiKeyAuth(api_key)
else:
auth = NoneAuth()

return Client(store.api_base_url, auth)
6 changes: 3 additions & 3 deletions crunch/api/client/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import inflection

from ... import store
from .. import domain
from .. import models


@dataclasses.dataclass(frozen=True)
Expand Down Expand Up @@ -71,8 +71,8 @@ def _find_error_class(
for suffix in ["Exception", "Error"]:
class_name = base_class_name + suffix

clazz = getattr(domain, class_name, None)
clazz = getattr(models, class_name, None)
if clazz is not None:
return clazz

return domain.ApiException
return models.ApiException
7 changes: 0 additions & 7 deletions crunch/api/domain/__init__.py

This file was deleted.

22 changes: 0 additions & 22 deletions crunch/api/domain/_common.py

This file was deleted.

5 changes: 0 additions & 5 deletions crunch/api/domain/_crunch.py

This file was deleted.

29 changes: 0 additions & 29 deletions crunch/api/domain/_prediction.py

This file was deleted.

5 changes: 0 additions & 5 deletions crunch/api/domain/_project.py

This file was deleted.

49 changes: 0 additions & 49 deletions crunch/api/domain/_score.py

This file was deleted.

5 changes: 0 additions & 5 deletions crunch/api/domain/_submission.py

This file was deleted.

1 change: 1 addition & 0 deletions crunch/api/endpoints/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .client import EndpointClient
12 changes: 12 additions & 0 deletions crunch/api/endpoints/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CheckEndpointMixin:

def list_checks(
self,
competition_identifier
):
return self._result(
self.get(
f"/v1/competitions/{competition_identifier}/checks"
),
json=True
)
89 changes: 89 additions & 0 deletions crunch/api/endpoints/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import urllib.parse

import requests

from ..auth import Auth
from ..errors import ApiException
from .check import CheckEndpointMixin
from .competition import CompetitionEndpointMixin
from .crunch import CrunchEndpointMixin
from .data_release import DataReleaseEndpointMixin
from .phase import PhaseEndpointMixin
from .prediction import PredictionEndpointMixin
from .project import ProjectEndpointMixin
from .round import RoundEndpointMixin
from .score import ScoreEndpointMixin


class EndpointClient(
requests.Session,
CheckEndpointMixin,
CompetitionEndpointMixin,
CrunchEndpointMixin,
DataReleaseEndpointMixin,
PhaseEndpointMixin,
PredictionEndpointMixin,
ProjectEndpointMixin,
RoundEndpointMixin,
ScoreEndpointMixin,
):

def __init__(
self,
base_url: str,
auth: Auth
):
super().__init__()

self.base_url = base_url
self.auth_ = auth

def request(self, method, url, *args, **kwargs):
headers = kwargs.pop("headers", {})
params = kwargs.pop("params", {})
data = kwargs.pop("data", None)

self.auth_.apply(headers, params, data)

return super().request(
method,
urllib.parse.urljoin(self.base_url, url),
*args,
headers=headers,
params=params,
data=data,
**kwargs,
)

def _raise_for_status(
self,
response: requests.Response,
):
try:
response.raise_for_status()
except requests.exceptions.HTTPError as error:
content = error.response.json()

code = content.pop("code", "")
message = content.pop("message", "")

raise ApiException(
f"{code}: {message}"
)

def _result(
self,
response: requests.Response,
json=False,
binary=False
):
assert not (json and binary)
self._raise_for_status(response)

if json:
return response.json()

if binary:
return response.content

return response.text
22 changes: 22 additions & 0 deletions crunch/api/endpoints/competition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class CompetitionEndpointMixin:

def list_competitions(
self
):
return self._result(
self.get(
"/v1/competitions"
),
json=True
)

def get_competition(
self,
identifier
):
return self._result(
self.get(
f"/v1/competitions/{identifier}"
),
json=True
)
Loading

0 comments on commit 3ac1a1e

Please sign in to comment.