Skip to content

Commit

Permalink
RELEASE: V1.1 (#39)
Browse files Browse the repository at this point in the history
* DEVEXP-340/DEVEXP-471 - automated CI/CD release to PyPI and async library replacement (#29)

* DEVEXP-464 update verification API with backwards compat (#36)

* fix: recursion error (#38)

* [SMS] service plan id version of the API (#17)

* relese: bump the package version
  • Loading branch information
650elx authored Dec 19, 2024
1 parent be6b973 commit 3d24434
Show file tree
Hide file tree
Showing 69 changed files with 1,148 additions and 344 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/release-sdk.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Release Python SDK

on:
release:
types: [published]

env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v2
- name: Install packaging tools
run: |
python -m pip install --upgrade pip
pip install twine
pip install poetry
- name: Build package
run: |
poetry build
- name: Verify package
run: |
twine check dist/*
- name: Release package
run: |
twine upload dist/*
2 changes: 2 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ env:
PROJECT_ID: ${{ secrets.PROJECT_ID }}
NUMBERS_ORIGIN: ${{ secrets.NUMBERS_ORIGIN }}
SMS_ORIGIN: ${{ secrets.SMS_ORIGIN }}
SERVICE_PLAN_ID: ${{ secrets.SERVICE_PLAN_ID }}
SMS_API_TOKEN: ${{ secrets.SMS_API_TOKEN }}
CONVERSATION_ORIGIN: ${{ secrets.CONVERSATION_ORIGIN }}
AUTH_ORIGIN: ${{ secrets.AUTH_ORIGIN }}
DISABLE_SSL: ${{ secrets.DISABLE_SSL }}
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tool.poetry]
name = "sinch"
description = "Sinch SDK for Python programming language"
version = "1.0.0"
version = "1.1.0"
license = "Apache 2.0"
readme = "README.md"
authors = [
Expand All @@ -27,7 +27,7 @@ keywords = ["sinch", "sdk"]
[tool.poetry.dependencies]
python = ">=3.9"
requests = "*"
aiohttp = "*"
httpx = "*"

[build-system]
requires = ["poetry-core"]
Expand Down
2 changes: 1 addition & 1 deletion sinch/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
""" Sinch Python SDK
To access Sinch resources, use the Sync or Async version of the Sinch Client.
"""
__version__ = "1.0.0"
__version__ = "1.1.0"

from sinch.core.clients.sinch_client_sync import SinchClient
from sinch.core.clients.sinch_client_async import SinchClientAsync
Expand Down
53 changes: 0 additions & 53 deletions sinch/core/adapters/asyncio_http_adapter.py

This file was deleted.

62 changes: 62 additions & 0 deletions sinch/core/adapters/httpx_adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import httpx
from sinch.core.ports.http_transport import AsyncHTTPTransport, HttpRequest
from sinch.core.endpoint import HTTPEndpoint
from sinch.core.models.http_response import HTTPResponse


class HTTPXTransport(AsyncHTTPTransport):
def __init__(self, sinch):
super().__init__(sinch)
self.http_session = None

async def request(self, endpoint: HTTPEndpoint) -> HTTPResponse:
request_data: HttpRequest = self.prepare_request(endpoint)
request_data: HttpRequest = await self.authenticate(endpoint, request_data)

if not self.http_session:
self.http_session = httpx.AsyncClient()

self.sinch.configuration.logger.debug(
f"Async HTTP {request_data.http_method} call with headers:"
f" {request_data.headers} and body: {request_data.request_body} to URL: {request_data.url}"
)

if isinstance(request_data.request_body, str):
response = await self.http_session.request(
method=request_data.http_method,
headers=request_data.headers,
url=request_data.url,
content=request_data.request_body,
auth=request_data.auth,
params=request_data.query_params,
timeout=self.sinch.configuration.connection_timeout
)
else:
response = await self.http_session.request(
method=request_data.http_method,
headers=request_data.headers,
url=request_data.url,
data=request_data.request_body,
auth=request_data.auth,
params=request_data.query_params,
timeout=self.sinch.configuration.connection_timeout,
)

response_body = self.deserialize_json_response(response)

self.sinch.configuration.logger.debug(
f"Async HTTP {response.status_code} response with headers: {response.headers}"
f"and body: {response_body} from URL: {request_data.url}"
)

return await self.handle_response(
endpoint=endpoint,
http_response=HTTPResponse(
status_code=response.status_code,
body=response_body,
headers=response.headers
)
)

async def close_session(self):
await self.http_session.aclose()
5 changes: 1 addition & 4 deletions sinch/core/adapters/requests_http_transport.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import requests
import json
from sinch.core.ports.http_transport import HTTPTransport, HttpRequest
from sinch.core.endpoint import HTTPEndpoint
from sinch.core.models.http_response import HTTPResponse
Expand Down Expand Up @@ -29,9 +28,7 @@ def request(self, endpoint: HTTPEndpoint) -> HTTPResponse:
params=request_data.query_params
)

response_body = response.content
if response_body:
response_body = json.loads(response_body)
response_body = self.deserialize_json_response(response)

self.sinch.configuration.logger.debug(
f"Sync HTTP {response.status_code} response with headers: {response.headers}"
Expand Down
12 changes: 8 additions & 4 deletions sinch/core/clients/sinch_client_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from sinch.core.clients.sinch_client_base import SinchClientBase
from sinch.core.clients.sinch_client_configuration import Configuration
from sinch.core.token_manager import TokenManagerAsync
from sinch.core.adapters.asyncio_http_adapter import HTTPTransportAioHTTP
from sinch.core.adapters.httpx_adapter import HTTPXTransport
from sinch.domains.authentication import AuthenticationAsync
from sinch.domains.numbers import NumbersAsync
from sinch.domains.conversation import ConversationAsync
Expand All @@ -25,18 +25,22 @@ def __init__(
logger_name: str = None,
logger: Logger = None,
application_key: str = None,
application_secret: str = None
application_secret: str = None,
service_plan_id: str = None,
sms_api_token: str = None
):
self.configuration = Configuration(
key_id=key_id,
key_secret=key_secret,
project_id=project_id,
logger_name=logger_name,
logger=logger,
transport=HTTPTransportAioHTTP(self),
transport=HTTPXTransport(self),
token_manager=TokenManagerAsync(self),
application_secret=application_secret,
application_key=application_key
application_key=application_key,
service_plan_id=service_plan_id,
sms_api_token=sms_api_token
)

self.authentication = AuthenticationAsync(self)
Expand Down
4 changes: 3 additions & 1 deletion sinch/core/clients/sinch_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ def __init__(
logger_name: str = None,
logger: Logger = None,
application_key: str = None,
application_secret: str = None
application_secret: str = None,
service_plan_id: str = None,
sms_api_token: str = None
):
pass

Expand Down
72 changes: 56 additions & 16 deletions sinch/core/clients/sinch_client_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from sinch.core.ports.http_transport import HTTPTransport
from sinch.core.token_manager import TokenManager, TokenManagerAsync
from sinch.core.enums import HTTPAuthentication


class Configuration:
Expand All @@ -22,14 +23,18 @@ def __init__(
disable_https=False,
connection_timeout=10,
application_key: str = None,
application_secret: str = None
application_secret: str = None,
service_plan_id: str = None,
sms_api_token: str = None
):
self.key_id = key_id
self.key_secret = key_secret
self.project_id = project_id
self.application_key = application_key
self.application_secret = application_secret
self.connection_timeout = connection_timeout
self.sms_api_token = sms_api_token
self.service_plan_id = service_plan_id
self.auth_origin = "auth.sinch.com"
self.numbers_origin = "numbers.api.sinch.com"
self.verification_origin = "verification.api.sinch.com"
Expand All @@ -39,7 +44,10 @@ def __init__(
self._conversation_region = "eu"
self._conversation_domain = ".conversation.api.sinch.com"
self._sms_region = "us"
self._sms_region_with_service_plan_id = "us"
self._sms_domain = "zt.{}.sms.api.sinch.com"
self._sms_domain_with_service_plan_id = "{}.sms.api.sinch.com"
self._sms_authentication = HTTPAuthentication.OAUTH.value
self._templates_region = "eu"
self._templates_domain = ".template.api.sinch.com"
self.token_manager = token_manager
Expand All @@ -48,6 +56,7 @@ def __init__(

self._set_conversation_origin()
self._set_sms_origin()
self._set_sms_origin_with_service_plan_id()
self._set_templates_origin()
self._set_voice_origin()

Expand All @@ -58,23 +67,35 @@ def __init__(
else:
self.logger = logging.getLogger("Sinch")

def _set_voice_origin(self):
if not self._voice_region:
self.voice_origin = self._voice_domain.format("calling")
else:
self.voice_origin = self._voice_domain.format("calling-" + self._voice_region)
def _set_sms_origin_with_service_plan_id(self):
self.sms_origin_with_service_plan_id = self._sms_domain_with_service_plan_id.format(
self._sms_region_with_service_plan_id
)

def _set_voice_region(self, region):
self._voice_region = region
self._set_voice_origin()
def _set_sms_region_with_service_plan_id(self, region):
self._sms_region_with_service_plan_id = region
self._set_sms_origin_with_service_plan_id()

def _get_voice_region(self):
return self._voice_region
def _get_sms_region_with_service_plan_id(self):
return self._sms_region_with_service_plan_id

voice_region = property(
_get_voice_region,
_set_voice_region,
doc="Voice Region"
sms_region_with_service_plan_id = property(
_get_sms_region_with_service_plan_id,
_set_sms_region_with_service_plan_id,
doc="SMS Region for service plan id version of the SMS API"
)

def _set_sms_domain_with_service_plan_id(self, domain):
self._sms_domain_with_service_plan_id = domain
self._set_sms_origin_with_service_plan_id()

def _get_sms_domain_with_service_plan_id(self):
return self._sms_domain_with_service_plan_id

sms_domain_with_service_plan_id = property(
_get_sms_domain_with_service_plan_id,
_set_sms_domain_with_service_plan_id,
doc="SMS Domain for service plan id version of the SMS API"
)

def _set_sms_origin(self):
Expand All @@ -98,7 +119,7 @@ def _set_sms_domain(self, domain):
self._set_sms_origin()

def _get_sms_domain(self):
return self.sms_domain
return self._sms_domain

sms_domain = property(
_get_sms_domain,
Expand Down Expand Up @@ -163,3 +184,22 @@ def _get_templates_domain(self):
_set_templates_domain,
doc="Conversation API Templates Domain"
)

def _set_voice_origin(self):
if not self._voice_region:
self.voice_origin = self._voice_domain.format("calling")
else:
self.voice_origin = self._voice_domain.format("calling-" + self._voice_region)

def _set_voice_region(self, region):
self._voice_region = region
self._set_voice_origin()

def _get_voice_region(self):
return self._voice_region

voice_region = property(
_get_voice_region,
_set_voice_region,
doc="Voice Region"
)
8 changes: 6 additions & 2 deletions sinch/core/clients/sinch_client_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ def __init__(
logger_name: str = None,
logger: Logger = None,
application_key: str = None,
application_secret: str = None
application_secret: str = None,
service_plan_id: str = None,
sms_api_token: str = None
):
self.configuration = Configuration(
key_id=key_id,
Expand All @@ -36,7 +38,9 @@ def __init__(
transport=HTTPTransportRequests(self),
token_manager=TokenManager(self),
application_key=application_key,
application_secret=application_secret
application_secret=application_secret,
service_plan_id=service_plan_id,
sms_api_token=sms_api_token
)

self.authentication = Authentication(self)
Expand Down
Loading

0 comments on commit 3d24434

Please sign in to comment.