Skip to content

Commit

Permalink
chore: created http client, serialiser (#1089)
Browse files Browse the repository at this point in the history
created request, response, client, http client for RC release which is required by auto generated code.
  • Loading branch information
sbansla authored Oct 3, 2024
1 parent 9515dce commit aeb9888
Show file tree
Hide file tree
Showing 19 changed files with 521 additions and 3 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/test-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
timeout-minutes: 20
strategy:
matrix:
python-version: [ '2.7', '3.5', '3.6', '3.7', '3.8', '3.9', '3.10', '3.11' ]
python-version: ['3.8', '3.9', '3.10', '3.11' ]
env:
DOCKER_LOGIN: ${{ secrets.DOCKER_USERNAME && secrets.DOCKER_AUTH_TOKEN }}
steps:
Expand All @@ -31,6 +31,11 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_AUTH_TOKEN }}

- name: Install Docker Compose
run: |
sudo apt-get update
sudo apt-get install -y docker-compose
- name: Build & Test
run: make test-docker version=${{ matrix.python-version }}

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ example.pdf
TODO.txt
twilio.env
prism*
**/.openapi-generator*
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (C) 2023, Twilio SendGrid, Inc. <[email protected]>
Copyright (C) 2024, Twilio SendGrid, Inc. <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
Expand Down
6 changes: 5 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
Flask==1.1.2
#Flask==1.1.2
requests>=2.31.0
#aiohttp>=3.9.4
#aiohttp-retry>=2.8.3

PyYAML>=4.2b1
python-http-client>=3.2.1
six==1.11.0
Expand Down
1 change: 1 addition & 0 deletions sendgrid/base/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# __init__.py
12 changes: 12 additions & 0 deletions sendgrid/base/auth_strategy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# 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.")
7 changes: 7 additions & 0 deletions sendgrid/base/client_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class ClientBase:

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

def request(self):
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

13 changes: 13 additions & 0 deletions sendgrid/base/values.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from typing import Dict

unset = object()


def of(d: Dict[str, object]) -> Dict[str, object]:
"""
Remove unset values from a dict.
:param d: A dict to strip.
:return A dict with unset values removed.
"""
return {k: v for k, v in d.items() if v != unset}
47 changes: 47 additions & 0 deletions sendgrid/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
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 = api_key
self.region = region
self.edge = edge
self.user_agent_extensions = user_agent_extensions or []
self.http_client: SendgridHttpClient = SendgridHttpClient()

def send(self, request: Request):
url = build_url(request.url, self.region)
response = self.http_client.request(
method=request.method,
url=url,
data=request.data,
headers=request.headers,
api_key=self.api_key,
)
return response
Empty file added sendgrid/converters/__init__.py
Empty file.
43 changes: 43 additions & 0 deletions sendgrid/converters/serialize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from enum import Enum

from enum import Enum


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
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 obj.to_dict()
elif isinstance(obj, Enum):
return obj.value
else:
return obj


def from_serializable(data, cls=None):
"""
Converts a dictionary or list into a class instance or a list of instances.
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
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
else:
return data # Return primitive types as is
15 changes: 15 additions & 0 deletions sendgrid/exceptions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import Any, Dict


class SendgridException(Exception):
pass


class ApiException(SendgridException):
def __init__(self, status_code: int, error: Any, headers: Dict[str, Any] = None):
self.status_code = status_code
self.error = error
self.headers = headers or {}

def __str__(self):
return f"ApiException(status_code={self.status_code}, error={self.error}, headers={self.headers})"
1 change: 1 addition & 0 deletions sendgrid/http/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Loading

0 comments on commit aeb9888

Please sign in to comment.