Skip to content

Commit

Permalink
Reviewed the docs, update docstrings fixed issues.
Browse files Browse the repository at this point in the history
  • Loading branch information
hassaanfarooq01 committed Jan 26, 2024
1 parent bc7b6a1 commit 745a084
Show file tree
Hide file tree
Showing 14 changed files with 333 additions and 252 deletions.
89 changes: 61 additions & 28 deletions hub_sdk/base/api_client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Ultralytics HUB-SDK 🚀, AGPL-3.0 License

from typing import Optional
from typing import Dict, Optional
import requests

from hub_sdk.config import HUB_EXCEPTIONS
Expand All @@ -9,7 +9,22 @@


class APIClientError(Exception):
def __init__(self, message: str, status_code: int = None):
"""
Custom exception class for API client errors.
Attributes:
message (str): A human-readable error message.
status_code (int): The HTTP status code associated with the error, if available.
"""

def __init__(self, message: str, status_code: Optional[int] = None):
"""
Initialize the APIClientError instance.
Args:
message (str): A human-readable error message.
status_code (int, optional): The HTTP status code associated with the error, if available.
"""
super().__init__(message)
self.status_code = status_code
self.message = message
Expand All @@ -19,39 +34,50 @@ def __str__(self) -> str:


class APIClient:
def __init__(self, base_url: str, headers: dict = None):
"""
Represents an API client for making requests to a specified base URL.
Attributes:
base_url (str): The base URL for the API.
headers (dict, None): Headers to be included in each request.
logger (logging.Logger): An instance of the logger for logging purposes.
"""

def __init__(self, base_url: str, headers: Optional[Dict] = None):
"""
Initialize an instance of the APIClient class.
Args:
base_url (str): The base URL for the API.
headers (dict, optional): Headers to be included in each request. Defaults to None.
headers (dict, optional): Headers to be included in each request.
"""
self.base_url = base_url
self.headers = headers
self.logger = logger

def _make_request(
self, method: str, endpoint: str, data: dict = None, json=None, params=None, files=None, stream: bool = False
self, method: str, endpoint: str, data: Optional[Dict] = None, json: Optional[Dict] = None,
params: Optional[Dict] = None, files: Optional[Dict] = None, stream: bool = False
) -> Optional[requests.Response]:
"""
Make an HTTP request to the API.
Args:
method (str): The HTTP method to use for the request (e.g., "GET", "POST").
endpoint (str): The endpoint to append to the base URL for the request.
data (dict, optional): Data to be sent in the request's body. Defaults to None.
json_data (dict, optional): JSON data to be sent in the request's body. Defaults to None.
params (dict, optional): Query parameters for the request. Defaults to None.
files (dict, optional): Files to be sent as part of the form data. Defaults to None.
stream (bool, optional): Whether to stream the response content. Defaults to False.
data (dict, optional): Data to be sent in the request's body.
json (dict, optional): JSON data to be sent in the request's body.
params (dict, optional): Query parameters for the request.
files (dict, optional): Files to be sent as part of the form data.
stream (bool, optional): Whether to stream the response content.
Returns:
(Optional[requests.Response]): The response object from the HTTP request, None if it fails and HUB_EXCEPTIONS off.
(Optional[requests.Response]): The response object from the HTTP request, None if it fails and
HUB_EXCEPTIONS off.
Raises:
(APIClientError): If an error occurs during the request, this exception is raised with an appropriate message
based on the HTTP status code.
(APIClientError): If an error occurs during the request, this exception is raised with an appropriate
message based on the HTTP status code.
"""
# Overwrite the base url if a http url is submitted
url = endpoint if endpoint.startswith("http") else self.base_url + endpoint
Expand Down Expand Up @@ -79,68 +105,75 @@ def _make_request(
self.logger.error(error_msg)

if not HUB_EXCEPTIONS:
raise APIClientError(error_msg, status_code=response.status_code) from e
raise APIClientError(error_msg, status_code=status_code) from e

def get(self, endpoint: str, params=None) -> Optional(requests.Response):
def get(self, endpoint: str, params=None) -> Optional[requests.Response]:
"""
Make a GET request to the API.
Args:
endpoint (str): The endpoint to append to the base URL for the request.
params (dict, optional): Query parameters for the request. Defaults to None.
params (dict, optional): Query parameters for the request.
Returns:
(Optional[requests.Response]): The response object from the HTTP GET request, None if it fails.
"""
return self._make_request("GET", endpoint, params=params)

def post(self, endpoint: str, data: dict = None, json=None, files=None, stream=False) -> Optional(
requests.Response
):
def post(self, endpoint: str, data: Optional[Dict] = None, json: Optional[Dict] = None,
files: Optional[Dict] = None, stream=False) -> Optional[requests.Response]:
"""
Make a POST request to the API.
Args:
endpoint (str): The endpoint to append to the base URL for the request.
data (dict, optional): Data to be sent in the request's body. Defaults to None.
data (dict, optional): Data to be sent in the request's body.
json (dict, optional): JSON data to be sent in the request's body.
files (dict, optional): Files to be included in the request, if any.
stream (bool, optional): If True, the response content will be streamed.
Returns:
(Optional(requests.Response)): The response object from the HTTP POST request.
(Optional[requests.Response]): The response object from the HTTP POST request.
"""
return self._make_request("POST", endpoint, data=data, json=json, files=files, stream=stream)

def put(self, endpoint: str, data=None, json=None) -> Optional(requests.Response):
def put(self, endpoint: str, data: Optional[Dict] = None, json: Optional[Dict] = None) -> \
Optional[requests.Response]:
"""
Make a PUT request to the API.
Args:
endpoint (str): The endpoint to append to the base URL for the request.
data (dict, optional): Data to be sent in the request's body. Defaults to None.
data (Optional[Dict], optional): Data to be sent in the request's body.
json (Optional[Dict], optional): JSON data to be sent in the request's body
Returns:
(Optional(requests.Response)): The response object from the HTTP PUT request.
(Optional[requests.Response]): The response object from the HTTP PUT request.
"""
return self._make_request("PUT", endpoint, data=data, json=json)

def delete(self, endpoint: str, params=None) -> Optional(requests.Response):
def delete(self, endpoint: str, params: Optional[Dict] = None) -> Optional[requests.Response]:
"""
Make a DELETE request to the API.
Args:
endpoint (str): The endpoint to append to the base URL for the request.
params (dict, optional): Parameters to include in the request.
Returns:
(Optional(requests.Response)): The response object from the HTTP DELETE request, or None if it fails.
(Optional[requests.Response]): The response object from the HTTP DELETE request, or None if it fails.
"""
return self._make_request("DELETE", endpoint, params=params)

def patch(self, endpoint: str, data=None, json=None) -> requests.Response:
def patch(self, endpoint: str, data: Optional[Dict] = None, json: Optional[Dict] = None) -> \
Optional[requests.Response]:
"""
Make a PATCH request to the API.
Args:
endpoint (str): The endpoint to append to the base URL for the request.
data (dict, optional): Data to be sent in the request's body. Defaults to None.
data (dict, optional): Data to be sent in the request's body.
json (dict, optional): JSON data to be sent in the request's body.
Returns:
(Optional[requests.Response]): The response object from the HTTP PATCH request, or None if it fails.
Expand Down
14 changes: 11 additions & 3 deletions hub_sdk/base/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,16 @@


class Auth:
"""
Represents an authentication manager.
Attributes:
api_key (str, None): The API key used for authentication.
id_token (str, None): The authentication token.
"""
def __init__(self):
self.get_auth_header = None
self.api_key = None
self.id_token = None

def authenticate(self) -> bool:
"""
Expand Down Expand Up @@ -45,12 +53,12 @@ def authenticate(self) -> bool:
self.id_token = self.api_key = False # reset invalid
return False

def get_auth_header(self) -> Optional(dict):
def get_auth_header(self) -> Optional[dict]:
"""
Get the authentication header for making API requests.
Returns:
(Optional(dict)): The authentication header if id_token or API key is set, None otherwise.
(Optional[dict]): The authentication header if id_token or API key is set, None otherwise.
"""
if self.id_token:
return {"authorization": f"Bearer {self.id_token}"}
Expand Down
16 changes: 11 additions & 5 deletions hub_sdk/base/crud_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@


class CRUDClient(APIClient):
"""
Represents a CRUD (Create, Read, Update, Delete) client for interacting with a specific resource.
Attributes:
name (str): The name associated with the CRUD operations (e.g., "User").
logger (logging.Logger): An instance of the logger for logging purposes.
"""
def __init__(self, base_endpoint, name, headers):
"""
Initialize a CRUDClient instance.
Expand Down Expand Up @@ -51,7 +58,7 @@ def read(self, id: str) -> Optional[Response]:
except Exception as e:
self.logger.error(f"Failed to read {self.name}({id}): %s", e)

def update(self, id: str, data: dict) -> dict:
def update(self, id: str, data: dict) -> Optional[Response]:
"""
Update an existing entity using the API.
Expand All @@ -74,13 +81,12 @@ def delete(self, id: str, hard: bool = False) -> Optional[Response]:
Args:
id (str): The unique identifier of the entity to delete.
hard (bool, optional): If True, perform a hard delete. If False, perform a soft delete.
Default is False.
Returns:
(Optional[Response]): Response object from the delete request, or None if delete fails.
"""
try:
return super().delete(f"/{id}", hard)
return super().delete(f"/{id}", {"hard": hard})
except Exception as e:
self.logger.error(f"Failed to delete {self.name}({id}): %s", e)

Expand All @@ -89,8 +95,8 @@ def list(self, page: int = 0, limit: int = 10) -> Optional[Response]:
List entities using the API.
Args:
page (int, optional): The page number to retrieve. Default is 0.
limit (int, optional): The maximum number of entities per page. Default is 10.
page (int, optional): The page number to retrieve.
limit (int, optional): The maximum number of entities per page.
Returns:
(Optional[Response]): Response object from the list request, or None if it fails.
Expand Down
18 changes: 9 additions & 9 deletions hub_sdk/base/paginated_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ def __init__(self, base_endpoint, name, page_size=None, headers=None):
Args:
base_endpoint (str): The base API endpoint for the paginated resource.
name (str): A descriptive name for the paginated resource.
page_size (int, optional): The number of items per page. Defaults to None.
headers (dict, optional): Additional headers to include in API requests. Defaults to None.
page_size (int, optional): The number of items per page.
headers (dict, optional): Additional headers to include in API requests.
"""
super().__init__(f"{HUB_FUNCTIONS_ROOT}/v1/{base_endpoint}", headers)
self.name = name
Expand All @@ -30,7 +30,7 @@ def _get(self, query=None):
Retrieve data for the current page.
Args:
query (dict, optional): Additional query parameters for the API request. Defaults to None.
query (dict, optional): Additional query parameters for the API request.
"""
try:
last_record = self.pages[self.current_page]
Expand Down Expand Up @@ -62,19 +62,19 @@ def next(self) -> None:
except Exception as e:
self.logger.error("Failed to get next page: %s", e)

def __update_data(self, resp) -> None:
def __update_data(self, resp: Response) -> None:
"""
Update the internal data with the response from the API.
Args:
resp (dict): API response data.
resp (Response): API response data.
"""
resp_data = resp.json().get("data", {})
self.results = resp_data.get("results", {})
self.total_pages = resp_data.get("total") // self.page_size
last_record_id = resp_data.get("lastRecordId")
if last_record_id is None:
self.pages[self.current_page + 1 :] = [None] * (len(self.pages) - self.current_page - 1)
self.pages[self.current_page + 1:] = [None] * (len(self.pages) - self.current_page - 1)

elif len(self.pages) <= self.current_page + 1:
self.pages.append(last_record_id)
Expand All @@ -86,9 +86,9 @@ def list(self, page_size: int = 10, last_record=None, query=None) -> Optional[Re
Retrieve a list of items from the API.
Args:
page_size (int, optional): The number of items per page. Defaults to 10.
last_record (str, optional): ID of the last record from the previous page. Defaults to None.
query (dict, optional): Additional query parameters for the API request. Defaults to None.
page_size (int, optional): The number of items per page.
last_record (str, optional): ID of the last record from the previous page.
query (dict, optional): Additional query parameters for the API request.
Returns:
(Optional[Response]): Response object from the list request, or None if it fails.
Expand Down
Loading

0 comments on commit 745a084

Please sign in to comment.