Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DEVEXP-758: SinchClient Configuration #49

Merged
merged 2 commits into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 35 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,47 +33,64 @@ For more information on the Sinch APIs on which this SDK is based, refer to the
You can install this package by typing:
`pip install sinch`

## Products

The Sinch client provides access to the following Sinch products:
- Numbers API
- SMS API
- Verification API
- Voice API
- Conversation API (beta release)


## Getting started


### Client initialization


To initialize communication with Sinch backed, credentials obtained from Sinch portal have to be provided to the main client class of this SDK.
It's highly advised to not hardcode those credentials, but to fetch them from environment variables:
To establish a connection with the Sinch backend, you must provide the appropriate credentials based on the API
you intend to use. For security best practices, avoid hardcoding credentials.
Instead, retrieve them from environment variables.

#### Verification and Voice APIs

To initialize the client for the **Verification** and **Voice** APIs, use the following credentials:

```python
from sinch import SinchClient

sinch_client = SinchClient(
key_id="key_id",
key_secret="key_secret",
project_id="some_project",
application_key="application_key",
application_secret="application_secret"
)
```

#### SMS API
For the SMS API in **Australia (AU)**, **Brazil (BR)**, **Canada (CA)**, **the United States (US)**,
and **the European Union (EU)**, provide the following parameters:

```python
import os
from sinch import SinchClient

sinch_client = SinchClient(
key_id=os.getenv("KEY_ID"),
key_secret=os.getenv("KEY_SECRET"),
project_id=os.getenv("PROJECT_ID"),
application_key=os.getenv("APPLICATION_KEY"),
application_secret=os.getenv("APPLICATION_SECRET")
service_plan_id="service_plan_id",
sms_api_token="api_token"
)
```

## Products
#### All Other Sinch APIs
For all other Sinch APIs, including SMS in US and EU regions, use the following parameters:

Sinch client provides access to the following Sinch products:
- Numbers
- SMS
- Verification
- Voice API
- Conversation API (beta release)
```python
from sinch import SinchClient

sinch_client = SinchClient(
project_id="project_id",
key_id="key_id",
key_secret="key_secret"
)
```

## Logging

Expand Down
60 changes: 23 additions & 37 deletions tests/unit/test_client.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,30 @@
import pytest
from sinch import SinchClient, SinchClientAsync
from sinch.core.clients.sinch_client_configuration import Configuration


def test_sinch_client_initialization():
sinch_client_sync = SinchClient(
key_id="test",
key_secret="test_secret",
project_id="test_project_id"
)
assert sinch_client_sync


def test_sinch_client_async_initialization():
sinch_client_async = SinchClientAsync(
@pytest.mark.parametrize("client", [SinchClient, SinchClientAsync])
def test_sinch_client_initialization(client):
""" Test that SinchClient and SinchClientAsync can be initialized with or without parameters """
sinch_client = client(
key_id="test",
key_secret="test_secret",
project_id="test_project_id"
)
assert sinch_client_async


def test_sinch_client_has_all_business_domains(sinch_client_sync):
assert hasattr(sinch_client_sync, "authentication")
assert hasattr(sinch_client_sync, "sms")
assert hasattr(sinch_client_sync, "conversation")
assert hasattr(sinch_client_sync, "numbers")


def test_sinch_client_async_has_all_business_domains(sinch_client_async):
assert hasattr(sinch_client_async, "authentication")
assert hasattr(sinch_client_async, "sms")
assert hasattr(sinch_client_async, "conversation")
assert hasattr(sinch_client_async, "numbers")


def test_sinch_client_has_configuration_object(sinch_client_sync):
assert hasattr(sinch_client_sync, "configuration")
assert isinstance(sinch_client_sync.configuration, Configuration)


def test_sinch_client_async_has_configuration_object(sinch_client_async):
assert hasattr(sinch_client_async, "configuration")
assert isinstance(sinch_client_async.configuration, Configuration)
assert sinch_client

sinch_client_empty = client()
assert sinch_client_empty


@pytest.mark.parametrize("client", ["sinch_client_sync", "sinch_client_async"])
def test_sinch_client_expects_all_attributes(request, client):
""" Test that SinchClient and SinchClientAsync have all attributes"""
client_instance = request.getfixturevalue(client)
assert hasattr(client_instance, "authentication")
assert hasattr(client_instance, "sms")
assert hasattr(client_instance, "conversation")
assert hasattr(client_instance, "numbers")
assert hasattr(client_instance, "verification")
assert hasattr(client_instance, "voice")
assert hasattr(client_instance, "configuration")
assert isinstance(client_instance.configuration, Configuration)
53 changes: 40 additions & 13 deletions tests/unit/test_configuration.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,48 @@
import pytest
from logging import Logger, getLogger
from sinch.core.clients.sinch_client_configuration import Configuration
from sinch.core.adapters.requests_http_transport import HTTPTransportRequests
from sinch.core.token_manager import TokenManager
from sinch.core.adapters.httpx_adapter import HTTPXTransport
from sinch.core.token_manager import TokenManager, TokenManagerAsync


@pytest.mark.parametrize(
"transport_class, token_manager_class, client_fixture",
[
(HTTPTransportRequests, TokenManager, "sinch_client_sync"),
(HTTPXTransport, TokenManagerAsync, "sinch_client_async")
]
)
def test_configuration_happy_capy_expects_initialization(
request, transport_class, token_manager_class, client_fixture
):
""" Test that Configuration can be initialized with all parameters """
sinch_client = request.getfixturevalue(client_fixture)


def test_configuration_initialization_happy_path(sinch_client_sync):
client_configuration = Configuration(
key_id="Rodney",
key_secret="Mullen",
project_id="Is the King!",
transport=HTTPTransportRequests(sinch_client_sync),
token_manager=TokenManager(sinch_client_sync)
key_id="CapyKey",
key_secret="CapybaraWhisper",
project_id="CapybaraProjectX",
logger=getLogger("CapyTrace"),
connection_timeout=10,
application_key="AppybaraKey",
application_secret="SecretHabitatEntry",
service_plan_id="CappyPremiumPlan",
sms_api_token="HappyCappyToken",
transport=transport_class(sinch_client),
token_manager=token_manager_class(sinch_client)
)
assert client_configuration.key_id == "Rodney"
assert client_configuration.key_secret == "Mullen"
assert client_configuration.project_id == "Is the King!"
assert isinstance(client_configuration.transport, HTTPTransportRequests)
assert isinstance(client_configuration.token_manager, TokenManager)

assert client_configuration.key_id == "CapyKey"
assert client_configuration.key_secret == "CapybaraWhisper"
assert client_configuration.project_id == "CapybaraProjectX"
assert isinstance(client_configuration.logger, Logger)
assert client_configuration.application_key == "AppybaraKey"
assert client_configuration.application_secret == "SecretHabitatEntry"
assert client_configuration.service_plan_id == "CappyPremiumPlan"
assert client_configuration.sms_api_token == "HappyCappyToken"
assert isinstance(client_configuration.transport, transport_class)
assert isinstance(client_configuration.token_manager, token_manager_class)


def test_set_sms_region_property_and_check_that_sms_origin_was_updated(sinch_client_sync):
Expand Down