Skip to content

Commit

Permalink
chore: fixed serialiser for enums, added url builder
Browse files Browse the repository at this point in the history
  • Loading branch information
sbansla committed Sep 28, 2024
1 parent 550250b commit 9614eae
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 109 deletions.
3 changes: 1 addition & 2 deletions sendgrid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from .helpers.endpoints import * # noqa
from .helpers.mail import * # noqa
from .helpers.stats import * # noqa
from .helpers.eventwebhook import * # noqa
from .helpers.eventwebhook import * # noqa
from .sendgrid import SendGridAPIClient # noqa
from .twilio_email import TwilioEmailAPIClient # noqa
from .version import __version__
4 changes: 0 additions & 4 deletions sendgrid/base/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
import os
import platform

# __init__.py

10 changes: 4 additions & 6 deletions sendgrid/base/auth_strategy.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@


# Handle different of authentications, Currently sendgrid authenticate using apikey.
# Handle different of authentications, Currently sendgrid authenticate using apikey.
# class AuthStrategy:
# def authenticate(self):
# print('Not yet implemented')
#
#
#
#
# class ApiKeyAuthStrategy(AuthStrategy):
# def __init__(self, api_key):
# self.api_key = api_key
# print('init ApiKeyAuthStrategy')
# def authenticate(self, api_key):
# print(f"Authenticating {api_key} using Token Authentication.")
# print(f"Authenticating {api_key} using Token Authentication.")
6 changes: 2 additions & 4 deletions sendgrid/base/client_base.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
class ClientBase:

def __init__(self):
print('Creating ClientBase class')
print("Creating ClientBase class")

def request(self):
print('Making request')


print("Making request")
16 changes: 16 additions & 0 deletions sendgrid/base/url_builder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
def build_url(url: str, region: str) -> str:
base_url = "https://api.sendgrid.com"

if region and isinstance(region, str):
new_url = f"https://api.{region}.sendgrid.com"
else:
new_url = base_url

# Ensure that there's a '/' before appending the url
if not new_url.endswith('/'):
new_url += '/'

new_url += url.lstrip('/')

return new_url

39 changes: 20 additions & 19 deletions sendgrid/client.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,33 @@
import os
import platform
from typing import Dict, List, MutableMapping, Optional, Tuple
from urllib.parse import urlparse, urlunparse
import json
from typing import List, Optional
from sendgrid.http.http_client import SendgridHttpClient, HttpClient
from sendgrid.http.request import Request


from sendgrid.base.url_builder import build_url

# class AuthStrategy:
# def authenticate(self):
# pass
#
#
#
#
# class ApiKeyAuthStrategy(AuthStrategy):
# def __init__(self, api_key):
# self.api_key = api_key
#
#
# def authenticate(
# self,
# headers: Optional[Dict[str, str]] = None
# ):
# headers["Authorization"] = f"Bearer {self.api_key}"
#
#


class Client:
def __init__(
self,
api_key: str,
region: Optional[str] = None,
edge: Optional[str] = None,
http_client: Optional[HttpClient] = None,
user_agent_extensions: Optional[List[str]] = None
self,
api_key: str,
region: Optional[str] = None,
edge: Optional[str] = None,
http_client: Optional[HttpClient] = None,
user_agent_extensions: Optional[List[str]] = None,
):
self.api_key = api_key
self.region = region
Expand All @@ -40,7 +36,12 @@ def __init__(
self.http_client: SendgridHttpClient = SendgridHttpClient()

def send(self, request: Request):
url = build_url(request.url, self.region)
response = self.http_client.request(
method='POST', url=request.url, data=request.data, headers=request.headers, api_key=self.api_key
method=request.method,
url=url,
data=request.data,
headers=request.headers,
api_key=self.api_key,
)
return response
return response
23 changes: 16 additions & 7 deletions sendgrid/converters/serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@

def to_serializable(obj):
if isinstance(obj, list):
return [to_serializable(item) for item in obj if item is not None] # Remove None from lists
return [
to_serializable(item) for item in obj if item is not None
] # Remove None from lists
elif isinstance(obj, dict):
return {key: to_serializable(value) for key, value in obj.items() if
value is not None} # Remove None from dicts
elif hasattr(obj, 'to_dict'):
return {
key: to_serializable(value)
for key, value in obj.items()
if value is not None
} # Remove None from dicts
elif hasattr(obj, "to_dict"):
return obj.to_dict()
elif isinstance(obj, Enum):
return obj.name
return obj.value
else:
return obj

Expand All @@ -23,12 +28,16 @@ def from_serializable(data, cls=None):
If `cls` is provided, it will instantiate the class using the dictionary values.
"""
if isinstance(data, list):
return [from_serializable(item, cls) for item in data] # Recursively handle lists
return [
from_serializable(item, cls) for item in data
] # Recursively handle lists
elif isinstance(data, dict):
if cls:
# If a class is provided, instantiate it using the dictionary
return cls(**{key: from_serializable(value) for key, value in data.items()})
else:
return {key: from_serializable(value) for key, value in data.items()} # Recursively handle dicts
return {
key: from_serializable(value) for key, value in data.items()
} # Recursively handle dicts
else:
return data # Return primitive types as is
4 changes: 0 additions & 4 deletions sendgrid/http/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@

from logging import Logger
from typing import Any, Dict, Optional, Tuple
from urllib.parse import urlencode

78 changes: 40 additions & 38 deletions sendgrid/http/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ def __init__(self, logger: Logger, is_async: bool, timeout: Optional[float] = No
"""

def request(
self,
method: str,
uri: str,
params: Optional[Dict[str, object]] = None,
data: Optional[Dict[str, object]] = None,
headers: Optional[Dict[str, str]] = None,
auth: Optional[Tuple[str, str]] = None,
timeout: Optional[float] = None,
allow_redirects: bool = False,
self,
method: str,
uri: str,
params: Optional[Dict[str, object]] = None,
data: Optional[Dict[str, object]] = None,
headers: Optional[Dict[str, str]] = None,
auth: Optional[Tuple[str, str]] = None,
timeout: Optional[float] = None,
allow_redirects: bool = False,
) -> Response:
"""
Make an HTTP request.
Expand Down Expand Up @@ -84,15 +84,15 @@ class AsyncHttpClient(HttpClient):
"""

async def request(
self,
method: str,
uri: str,
params: Optional[Dict[str, object]] = None,
data: Optional[Dict[str, object]] = None,
headers: Optional[Dict[str, str]] = None,
auth: Optional[Tuple[str, str]] = None,
timeout: Optional[float] = None,
allow_redirects: bool = False,
self,
method: str,
uri: str,
params: Optional[Dict[str, object]] = None,
data: Optional[Dict[str, object]] = None,
headers: Optional[Dict[str, str]] = None,
auth: Optional[Tuple[str, str]] = None,
timeout: Optional[float] = None,
allow_redirects: bool = False,
) -> Response:
"""
Make an asynchronous HTTP request.
Expand All @@ -106,13 +106,13 @@ class SendgridHttpClient(HttpClient):
"""

def __init__(
self,
pool_connections: bool = True,
request_hooks: Optional[Dict[str, object]] = None,
timeout: Optional[float] = None,
logger: logging.Logger = _logger,
proxy: Optional[Dict[str, str]] = None,
max_retries: Optional[int] = None,
self,
pool_connections: bool = True,
request_hooks: Optional[Dict[str, object]] = None,
timeout: Optional[float] = None,
logger: logging.Logger = _logger,
proxy: Optional[Dict[str, str]] = None,
max_retries: Optional[int] = None,
):
"""
Constructor for the TwilioHttpClient
Expand All @@ -136,20 +136,20 @@ def __init__(
self.proxy = proxy if proxy else {}

def request(
self,
method: str,
url: str,
api_key: str = None,
params: Optional[Dict[str, object]] = None,
data: Optional[Dict[str, object]] = None,
headers: Optional[Dict[str, str]] = None,
timeout: Optional[float] = None,
allow_redirects: bool = False,
self,
method: str,
url: str,
api_key: str = None,
params: Optional[Dict[str, object]] = None,
data: Optional[Dict[str, object]] = None,
headers: Optional[Dict[str, str]] = None,
timeout: Optional[float] = None,
allow_redirects: bool = False,
) -> Response:
"""
Make an HTTP Request with parameters provided.
:param api_key:
:param api_key:
:param method: The HTTP method to use
:param url: The URL to request
:param params: Query parameters to append to the URL
Expand All @@ -167,7 +167,9 @@ def request(
raise ValueError(timeout)

headers["Authorization"] = f"Bearer {api_key}"
#auth.authenticate()
# Currently supporting 'application/json' content type
headers["Content-Type"] = "application/json"
# auth.authenticate()
kwargs = {
"method": method.upper(),
"url": url,
Expand All @@ -185,7 +187,7 @@ def request(
session = self.session or Session()
request = Request(**kwargs)
self._test_only_last_request = Request(**kwargs)

prepped_request = session.prepare_request(request)

settings = session.merge_environment_settings(
Expand All @@ -196,7 +198,7 @@ def request(
prepped_request,
allow_redirects=allow_redirects,
timeout=timeout,
**settings
**settings,
)
print(response)
print(response.status_code)
Expand Down
28 changes: 14 additions & 14 deletions sendgrid/http/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ class Match(Enum):

class Request(object):
def __init__(
self,
method: Union[str, Match] = Match.ANY,
url: Union[str, Match] = Match.ANY,
auth: Union[Tuple[str, str], Match] = Match.ANY,
params: Union[Dict[str, str], Match] = Match.ANY,
data: Union[Dict[str, str], Match] = Match.ANY,
headers: Union[Dict[str, str], Match] = Match.ANY,
**kwargs: Any
self,
method: Union[str, Match] = Match.ANY,
url: Union[str, Match] = Match.ANY,
auth: Union[Tuple[str, str], Match] = Match.ANY,
params: Union[Dict[str, str], Match] = Match.ANY,
data: Union[Dict[str, str], Match] = Match.ANY,
headers: Union[Dict[str, str], Match] = Match.ANY,
**kwargs: Any
):
self.method = method
if method and method is not Match.ANY:
Expand All @@ -43,12 +43,12 @@ def __eq__(self, other) -> bool:
return False

return (
self.attribute_equal(self.method, other.method)
and self.attribute_equal(self.url, other.url)
and self.attribute_equal(self.auth, other.auth)
and self.attribute_equal(self.params, other.params)
and self.attribute_equal(self.data, other.data)
and self.attribute_equal(self.headers, other.headers)
self.attribute_equal(self.method, other.method)
and self.attribute_equal(self.url, other.url)
and self.attribute_equal(self.auth, other.auth)
and self.attribute_equal(self.params, other.params)
and self.attribute_equal(self.data, other.data)
and self.attribute_equal(self.headers, other.headers)
)

def __str__(self) -> str:
Expand Down
15 changes: 5 additions & 10 deletions sendgrid/http/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ class HTTPStatus:

class Response(object):
def __init__(
self,
status_code: int,
text: str,
headers: Optional[Any] = None,
self,
status_code: int,
text: str,
headers: Optional[Any] = None,
):
self.content = text
self.headers = headers
Expand All @@ -32,12 +32,7 @@ def __str__(self) -> str:


class ApiResponse(object):
def __init__(
self,
status_code,
model,
headers
):
def __init__(self, status_code, model, headers):
self.status_code = status_code
self.model = model
self.headers = headers
Expand Down
1 change: 0 additions & 1 deletion sendgrid/utility/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,3 @@ def parse_response(self, response: Response) -> Any:
raise self.exception(response, "Unable to create record")

return json.loads(response.text)

0 comments on commit 9614eae

Please sign in to comment.