Skip to content

Commit

Permalink
Merge branch 'main' into snyk-fix-445944dcea8926350b116120651ec59c
Browse files Browse the repository at this point in the history
  • Loading branch information
manisha1997 authored Jan 28, 2025
2 parents 246a237 + 513743f commit 5b24530
Show file tree
Hide file tree
Showing 532 changed files with 21,507 additions and 5,614 deletions.
69 changes: 69 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Bug report
description: Report a bug with the twilio-python helper library.
title: "[BUG] Describe the issue briefly"
labels: "type: bug"
body:
- type: markdown
attributes:
value: |
Thank you for reporting a bug in the twilio-python helper library. Please provide the details below to help us investigate and resolve the issue.
- type: textarea
attributes:
label: Describe the bug
description: Provide a clear and concise description of the issue.
placeholder: A clear and concise description of the bug.
validations:
required: true

- type: textarea
attributes:
label: Code snippet
description: Provide the code snippet that reproduces the issue.
placeholder: "```\n// Code snippet here\n```"
validations:
required: true

- type: textarea
attributes:
label: Actual behavior
description: Describe what actually happened.
placeholder: A description of the actual behavior.
validations:
required: true

- type: textarea
attributes:
label: Expected behavior
description: Describe what you expected to happen.
placeholder: A description of the expected outcome.
validations:
required: true

- type: input
attributes:
label: twilio-python version
description: Specify the version of the twilio-python helper library you are using.
placeholder: e.g., 9.4.1
validations:
required: true

- type: input
attributes:
label: Python version
description: Specify the version of Python you are using.
placeholder: e.g., 3.9.1
validations:
required: true

- type: textarea
attributes:
label: Logs or error messages
description: Provide relevant logs or error messages (if any).
placeholder: "Error: Something went wrong..."

- type: textarea
attributes:
label: Additional context
description: Add any other context about the problem here.
placeholder: Any additional
2 changes: 1 addition & 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: [ '3.7', '3.8', '3.9', '3.10', '3.11', '3.12' ]
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ]
steps:
- name: Checkout twilio-python
uses: actions/checkout@v3
Expand Down
61 changes: 61 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,67 @@ twilio-python Changelog

Here you can see the full list of changes between each twilio-python release.

[2025-01-13] Version 9.4.3
--------------------------
**Messaging**
- Adds validity period Default value in service resource documentation


[2025-01-09] Version 9.4.2
--------------------------
**Library - Chore**
- [PR #832](https://github.com/twilio/twilio-python/pull/832): remove test for 3.7. Thanks to [@tiwarishubham635](https://github.com/tiwarishubham635)!

**Numbers**
- Change beta feature flag to use v2/BulkHostedNumberOrders


[2024-12-13] Version 9.4.1
--------------------------
**Library - Fix**
- [PR #827](https://github.com/twilio/twilio-python/pull/827): Fixing init file for preview iam domain. Thanks to [@AsabuHere](https://github.com/AsabuHere)!

**Library - Chore**
- [PR #826](https://github.com/twilio/twilio-python/pull/826): fix orgs api changes. Thanks to [@tiwarishubham635](https://github.com/tiwarishubham635)!


[2024-12-12] Version 9.4.0
--------------------------
**Library - Feature**
- [PR #825](https://github.com/twilio/twilio-python/pull/825): Docs update and examples for organization api uptake and public oauth. Thanks to [@AsabuHere](https://github.com/AsabuHere)!
- [PR #815](https://github.com/twilio/twilio-python/pull/815): Organizations Api uptake for twilio-python. Thanks to [@AsabuHere](https://github.com/AsabuHere)!


[2024-12-05] Version 9.3.8
--------------------------
**Api**
- Add optional parameter `intelligence_service` to `transcription`
- Updated `phone_number_sid` to be populated for sip trunking terminating calls.

**Numbers**
- Add Update Hosted Number Order V2 API endpoint
- Update Port in docs

**Twiml**
- Add optional parameter `intelligence_service` to `<Transcription>`
- Add support for new `<ConversationRelay>` and `<Assistant>` noun
- Add `events` attribute to `<Dial>` verb


[2024-11-15] Version 9.3.7
--------------------------
**Library - Chore**
- [PR #819](https://github.com/twilio/twilio-python/pull/819): use older verison of aiohttp_retry. Thanks to [@sbansla](https://github.com/sbansla)!

**Api**
- Added `ivr-virtual-agent-custom-voices` and `ivr-virtual-agent-genai` to `usage_record` API.
- Add open-api file tag to realtime_transcriptions

**Taskrouter**
- Add `api-tag` property to workers reservation
- Add `api-tag` property to task reservation


[2024-10-25] Version 9.3.6
--------------------------
**Library - Chore**
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ After a brief delay, you will receive the text message on your phone.
> **Warning**
> It's okay to hardcode your credentials when testing locally, but you should use environment variables to keep them secret before committing any code or deploying to production. Check out [How to Set Environment Variables](https://www.twilio.com/blog/2017/01/how-to-set-environment-variables.html) for more information.
## OAuth Feature for Twilio APIs
We are introducing Client Credentials Flow-based OAuth 2.0 authentication. This feature is currently in beta and its implementation is subject to change.

API examples [here](https://github.com/twilio/twilio-python/blob/main/examples/public_oauth.py)

Organisation API examples [here](https://github.com/twilio/twilio-python/blob/main/examples/organization_api.py)

## Use the helper library

### API Credentials
Expand Down
32 changes: 32 additions & 0 deletions examples/organization_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import os

from twilio.rest import Client
from twilio.credential.orgs_credential_provider import OrgsCredentialProvider

ACCOUNT_SID = os.environ.get("TWILIO_ACCOUNT_SID")
API_KEY = os.environ.get("TWILIO_API_KEY")
API_SECRET = os.environ.get("TWILIO_API_SECRET")

CLIENT_ID = os.environ.get("TWILIO_CLIENT_ID")
CLIENT_SECRET = os.environ.get("CLIENT_SECRET")
ORGS_SID = os.environ.get("ORGS_SID")


def example():
"""
Some example usage of using organization resources
"""
self.client = Client(
account_sid=ACCOUNT_SID,
credential_provider=OrgsCredentialProvider(CLIENT_ID, CLIENT_SECRET),
)

accounts = self.client.preview_iam.organization(
organization_sid=ORGS_SID
).accounts.stream()
for record in accounts:
print(record)


if __name__ == "__main__":
example()
31 changes: 31 additions & 0 deletions examples/public_oauth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import os

from twilio.rest import Client
from twilio.credential.client_credential_provider import ClientCredentialProvider

ACCOUNT_SID = os.environ.get("TWILIO_ACCOUNT_SID")
API_KEY = os.environ.get("TWILIO_API_KEY")
API_SECRET = os.environ.get("TWILIO_API_SECRET")
FROM_NUMBER = os.environ.get("TWILIO_FROM_NUMBER")
TO_NUMBER = os.environ.get("TWILIO_TO_NUMBER")

CLIENT_ID = os.environ.get("TWILIO_CLIENT_ID")
CLIENT_SECRET = os.environ.get("CLIENT_SECRET")


def example():
"""
Some example usage of message resources.
"""
self.client = Client(
account_sid=ACCOUNT_SID,
credential_provider=ClientCredentialProvider(CLIENT_ID, CLIENT_SECRET),
)

msg = self.client.messages.create(
to=self.to_number, from_=self.from_number, body="hello world"
)


if __name__ == "__main__":
example()
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

setup(
name="twilio",
version="9.3.6",
version="9.4.3",
description="Twilio API client and TwiML generator",
author="Twilio",
help_center="https://www.twilio.com/help/contact",
Expand All @@ -24,7 +24,7 @@
"requests >= 2.0.0",
"PyJWT >= 2.0.0, < 3.0.0",
"aiohttp>=3.8.4",
"aiohttp-retry==2.8.3",
"aiohttp-retry>=2.8.3",
],
packages=find_packages(exclude=["tests", "tests.*"]),
include_package_data=True,
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/http/test_async_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ class MockResponse(object):
A mock of the aiohttp.ClientResponse class
"""

def __init__(self, text, status):
def __init__(self, text, status, method="GET"):
self._text = text
self.status = status
self.headers = {}
self.method = method

async def text(self):
return self._text
Expand Down
2 changes: 1 addition & 1 deletion twilio/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version_info__ = ("9", "3", "6")
__version_info__ = ("9", "4", "3")
__version__ = ".".join(__version_info__)
Empty file.
19 changes: 19 additions & 0 deletions twilio/auth_strategy/auth_strategy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from twilio.auth_strategy.auth_type import AuthType
from abc import abstractmethod


class AuthStrategy(object):
def __init__(self, auth_type: AuthType):
self._auth_type = auth_type

@property
def auth_type(self) -> AuthType:
return self._auth_type

@abstractmethod
def get_auth_string(self) -> str:
"""Return the authentication string."""

@abstractmethod
def requires_authentication(self) -> bool:
"""Return True if authentication is required, else False."""
12 changes: 12 additions & 0 deletions twilio/auth_strategy/auth_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from enum import Enum


class AuthType(Enum):
ORGS_TOKEN = "orgs_stoken"
NO_AUTH = "noauth"
BASIC = "basic"
API_KEY = "api_key"
CLIENT_CREDENTIALS = "client_credentials"

def __str__(self):
return self.value
13 changes: 13 additions & 0 deletions twilio/auth_strategy/no_auth_strategy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from auth_type import AuthType
from twilio.auth_strategy.auth_strategy import AuthStrategy


class NoAuthStrategy(AuthStrategy):
def __init__(self):
super().__init__(AuthType.NO_AUTH)

def get_auth_string(self) -> str:
return ""

def requires_authentication(self) -> bool:
return False
53 changes: 53 additions & 0 deletions twilio/auth_strategy/token_auth_strategy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import jwt
import threading
import logging
from datetime import datetime

from twilio.auth_strategy.auth_type import AuthType
from twilio.auth_strategy.auth_strategy import AuthStrategy
from twilio.http.token_manager import TokenManager


class TokenAuthStrategy(AuthStrategy):
def __init__(self, token_manager: TokenManager):
super().__init__(AuthType.ORGS_TOKEN)
self.token_manager = token_manager
self.token = None
self.lock = threading.Lock()
logging.basicConfig(level=logging.INFO)
self.logger = logging.getLogger(__name__)

def get_auth_string(self) -> str:
self.fetch_token()
return f"Bearer {self.token}"

def requires_authentication(self) -> bool:
return True

def fetch_token(self):
if self.token is None or self.token == "" or self.is_token_expired(self.token):
with self.lock:
if (
self.token is None
or self.token == ""
or self.is_token_expired(self.token)
):
self.logger.info("New token fetched for accessing organization API")
self.token = self.token_manager.fetch_access_token()

def is_token_expired(self, token):
try:
decoded = jwt.decode(token, options={"verify_signature": False})
exp = decoded.get("exp")

if exp is None:
return True # No expiration time present, consider it expired

# Check if the expiration time has passed
return datetime.fromtimestamp(exp) < datetime.utcnow()

except jwt.DecodeError:
return True # Token is invalid
except Exception as e:
print(f"An error occurred: {e}")
return True
Loading

0 comments on commit 5b24530

Please sign in to comment.