Skip to content
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,22 @@

All notable changes to the Sonetel Python Module are tracked in this file.

## [0.2.1] - 24-08-2024
## [0.3.0] - 28-03-2025

### Added
- HTTP Session Management with connection pooling for improved performance
- Automatic retry mechanism with exponential backoff for failed requests
- Configurable timeouts, retry settings, and connection pool parameters
- Proper resource cleanup on program exit
- Enhanced error handling and logging capabilities
- New `configure()` function to customize SDK behavior
- `delete()` method added to the VoiceApp class. Can be used to delete an existing voice app in the account.

### Changed
- Optimized API request handling for better performance
- Improved error reporting with more detailed messages
- Updated docstrings to follow Google style format

### Fixed
- `get()` method in the Recording class didn't apply the optional parameters correctly. Fixed now.

Expand Down
39 changes: 36 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
![GitHub](https://img.shields.io/github/license/sonetel/sonetel-python)   ![PyPI](https://img.shields.io/pypi/v/sonetel)   ![GitHub issues](https://img.shields.io/github/issues/sonetel/sonetel-python)   [![Documentation Status](https://readthedocs.org/projects/sonetel-python/badge/?version=latest)](https://sonetel-python.readthedocs.io/en/latest/?badge=latest)

## 1. Introduction

The Sonetel API is a REST based web-service that enables you to manage your Sonetel account from your own platform or service. You can manage your account, your phone numbers and make callback calls etc.

This Python package provides an easy-to-use interface to integrate Sonetel's APIs with your service. For more information about the API, please see the [documentation](https://docs.sonetel.com/).
Expand Down Expand Up @@ -48,6 +49,7 @@ To use the package, add the following line to the top of your Python program.
`import sonetel`

Here's a description of the various modules and the methods available with each.

#### 2.2.1 Auth

The Auth module is used to generate and manage access tokens.
Expand All @@ -73,7 +75,7 @@ s = sntl.Auth(username=user, password=pswd)
print(s.get_access_token())
```

##### Refresh access token
##### Refresh access token

When your access token has expired, you can use the `create_token()` method to get a new `access_token` & `refresh_token`.

Expand Down Expand Up @@ -124,7 +126,7 @@ It supports the following methods:
3. `get_balance()` - Returns the prepaid balance. Pass the parameter `currency` = `True` to include the currency with the returned value.
4. `get_accountid()` - Fetch the account ID.

##### Print your Sonetel account ID and the current prepaid balance.
##### Print your Sonetel account ID and the current prepaid balance

```python
import os
Expand Down Expand Up @@ -198,6 +200,37 @@ print(ph.get())

```

## SDK Configuration

The Sonetel SDK now supports customizable configuration options for HTTP connections, retries, and logging. You can configure these settings using the `configure()` function:

```python
import sonetel

# Configure the SDK with custom settings
sonetel.configure(
timeout=(5, 60), # (connect_timeout, read_timeout) in seconds
max_retries=5, # Maximum number of retries for failed requests
backoff_factor=0.5, # Exponential backoff factor
pool_connections=20, # Number of connection pools
pool_maxsize=20, # Maximum connections per pool
log_level="DEBUG" # Logging level (DEBUG, INFO, WARNING, ERROR)
)

# Then use the SDK as normal
user = os.environ.get('sonetelUsername')
pswd = os.environ.get('sonetelPassword')
auth = sonetel.Auth(username=user, password=pswd)
```

### Performance Improvements

The SDK now uses connection pooling and automatic retries to improve performance and reliability:

- **Connection Pooling**: Reuses HTTP connections to reduce latency and overhead
- **Automatic Retries**: Automatically retries failed requests with exponential backoff
- **Proper Resource Cleanup**: Automatically closes connections when your program exits

## Storing your credentials

Please keep your Sonetel login credentials safe to avoid any misuse of your account. Do not hard code them into scripts or save them in files that are saved in any form of version control.
Expand All @@ -220,6 +253,6 @@ print(s.get_access_token())

## Help

For help with the Sonetel API, have a look at the <a href="https://docs.sonetel.com">API documentation</a>.
For help with the Sonetel API, have a look at the [API documentation](https://docs.sonetel.com)</a>.

If you have an issue with the module, please [report an issue](https://github.com/Sonetel/sonetel-python/issues/issues) on GitHub.
29 changes: 29 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,32 @@ It allows you to quickly integrate Sonetel's communication services such as inte

- If you don't have an account, sign up from [sonetel.com](https://app.sonetel.com/register?tag=api-developer&simple=true)
- Install the `sonetel` package using pip.

## Performance Features

The Sonetel SDK includes several performance optimizations:

- **HTTP Session Management**: Uses connection pooling to reduce latency and overhead
- **Automatic Retries**: Retries failed requests with exponential backoff
- **Configurable Settings**: Customize timeouts, retry behavior, and connection pooling
- **Resource Management**: Automatically cleans up resources when your program exits

## Configuration

You can configure the SDK's behavior using the `configure()` function:

```python
import sonetel

# Configure the SDK with custom settings
sonetel.configure(
timeout=(5, 60), # (connect_timeout, read_timeout) in seconds
max_retries=5, # Maximum number of retries for failed requests
backoff_factor=0.5, # Exponential backoff factor
pool_connections=20, # Number of connection pools
pool_maxsize=20, # Maximum connections per pool
log_level="DEBUG" # Logging level (DEBUG, INFO, WARNING, ERROR)
)
```

All parameters are optional and have sensible defaults.
98 changes: 98 additions & 0 deletions docs/reference/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Configuration

The Sonetel SDK provides configuration options to customize its behavior, including HTTP connection settings, retry behavior, and logging.

## Configure Function

The `configure()` function allows you to customize the SDK's behavior:

```python
import sonetel

sonetel.configure(
timeout=(3.05, 60),
max_retries=3,
backoff_factor=0.3,
pool_connections=10,
pool_maxsize=10,
log_level="INFO"
)
```

### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `timeout` | `float` or `tuple(float, float)` | `(3.05, 60)` | Request timeout in seconds. Can be a single float or a tuple of (connect_timeout, read_timeout) |
| `max_retries` | `int` | `3` | Maximum number of retries for failed requests |
| `backoff_factor` | `float` | `0.3` | Backoff factor for retries (exponential backoff) |
| `pool_connections` | `int` | `10` | Number of connection pools to cache |
| `pool_maxsize` | `int` | `10` | Maximum number of connections to save in the pool |
| `log_level` | `str` | `None` | Logging level (DEBUG, INFO, WARNING, ERROR) |

## Session Management

The SDK uses connection pooling to improve performance by reusing HTTP connections. This reduces the overhead of establishing new connections for each request.

### Benefits

- **Reduced Latency**: Reusing connections eliminates the need for TCP handshakes and TLS negotiations for each request
- **Improved Throughput**: Connection pooling allows for more efficient use of resources
- **Automatic Retries**: Failed requests are automatically retried with exponential backoff
- **Resource Cleanup**: Connections are properly closed when your program exits

### Retry Behavior

The SDK automatically retries failed requests with the following characteristics:

- Retries are performed for server errors (HTTP 500, 502, 503, 504)
- Exponential backoff is used to avoid overwhelming the server
- The backoff formula is: `{backoff factor} * (2 ** ({number of total retries} - 1))`
- With the default backoff factor of 0.3, the retry delays would be:
- 1st retry: 0.3s
- 2nd retry: 0.6s
- 3rd retry: 1.2s

## Logging

The SDK uses Python's standard logging module. You can configure the log level using the `log_level` parameter in the `configure()` function.

```python
import sonetel

# Enable debug logging
sonetel.configure(log_level="DEBUG")
```

You can also configure logging manually:

```python
import logging

# Configure the root logger
logging.basicConfig(level=logging.INFO)

# Or configure just the sonetel logger
logging.getLogger('sonetel').setLevel(logging.DEBUG)
```

## Example Usage

```python
import sonetel
import logging

# Configure the SDK with custom settings
sonetel.configure(
timeout=(5, 60),
max_retries=5,
backoff_factor=0.5,
pool_connections=20,
pool_maxsize=20,
log_level="DEBUG"
)

# Then use the SDK as normal
user = os.environ.get('sonetelUsername')
pswd = os.environ.get('sonetelPassword')
auth = sonetel.Auth(username=user, password=pswd)
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ nav:
- Account: reference/account.md
- Auth: reference/auth.md
- Calls: reference/calls.md
- Configuration: reference/configuration.md
33 changes: 25 additions & 8 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
from setuptools import setup

setup(
name='sonetel',
version='0.2.1',
packages=['sonetel'],
url='https://github.com/Sonetel/sonetel-python',
license='MIT',
author='aashish',
author_email='dev.support@sonetel.com',
description='A simple python wrapper for using Sonetel\'s REST APIs'
name="sonetel",
version="0.3.0",
packages=["sonetel"],
url="https://github.com/Sonetel/sonetel-python",
license="MIT",
author="aashish",
author_email="dev.support@sonetel.com",
description="A simple python wrapper for using Sonetel's REST APIs",
install_requires=[
"requests>=2.25.0",
"PyJWT>=2.0.0",
],
python_requires=">=3.6",
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Topic :: Software Development :: Libraries :: Python Modules",
],
)
62 changes: 61 additions & 1 deletion sonetel/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,71 @@
"""
Sonetel
Sonetel Python SDK

A Python package for using Sonetel's REST API endpoints.
"""

import atexit
import logging
from typing import Optional, Tuple, Union

from .account import Account
from .auth import Auth
from .calls import Call
from .phonenumber import PhoneNumber
from .recording import Recording
from .users import User
from .utilities import get_session
from .voiceapps import VoiceApp

# Configure package-level logger
logger = logging.getLogger(__name__)

__version__ = "0.3.0"


def configure(
timeout: Union[float, Tuple[float, float]] = (3.05, 60),
max_retries: int = 3,
backoff_factor: float = 0.3,
pool_connections: int = 10,
pool_maxsize: int = 10,
log_level: Optional[str] = None,
):
"""
Configure the Sonetel SDK with custom parameters.

Args:
timeout: Request timeout in seconds. Can be a single float or a tuple of (connect_timeout, read_timeout)
max_retries: Maximum number of retries for failed requests
backoff_factor: Backoff factor for retries (exponential backoff)
pool_connections: Number of connection pools to cache
pool_maxsize: Maximum number of connections to save in the pool
log_level: Logging level (DEBUG, INFO, WARNING, ERROR)
"""
# Configure logging
if log_level:
logging.basicConfig(level=getattr(logging, log_level))
logger.setLevel(getattr(logging, log_level))

# Get session with custom parameters
get_session(
timeout=timeout,
max_retries=max_retries,
backoff_factor=backoff_factor,
pool_connections=pool_connections,
pool_maxsize=pool_maxsize,
)


# Register cleanup function for program exit
def _cleanup():
"""Close the session and release resources on program exit."""
try:
session = get_session()
session.close()
logger.debug("Sonetel SDK session closed")
except Exception as e:
logger.debug("Error during cleanup: %s", e)


atexit.register(_cleanup)
Loading