Skip to content

Commit e9eaa72

Browse files
committed
Organization api uptake changes
1 parent 76fecab commit e9eaa72

File tree

23 files changed

+1906
-601
lines changed

23 files changed

+1906
-601
lines changed

twilio/auth_strategy/auth_strategy.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from twilio.auth_strategy.auth_type import AuthType
2-
from enum import Enum
32
from abc import abstractmethod
43

54

@@ -14,9 +13,7 @@ def auth_type(self) -> AuthType:
1413
@abstractmethod
1514
def get_auth_string(self) -> str:
1615
"""Return the authentication string."""
17-
pass
1816

1917
@abstractmethod
2018
def requires_authentication(self) -> bool:
2119
"""Return True if authentication is required, else False."""
22-
pass

twilio/auth_strategy/auth_type.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from enum import Enum
22

3+
34
class AuthType(Enum):
4-
ORGS_TOKEN = 'orgs_stoken'
5-
NO_AUTH = 'noauth'
6-
BASIC = 'basic'
7-
API_KEY = 'api_key'
8-
CLIENT_CREDENTIALS = 'client_credentials'
5+
ORGS_TOKEN = "orgs_stoken"
6+
NO_AUTH = "noauth"
7+
BASIC = "basic"
8+
API_KEY = "api_key"
9+
CLIENT_CREDENTIALS = "client_credentials"
910

1011
def __str__(self):
11-
return self.value
12+
return self.value
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from auth_type import AuthType
22

3+
34
class NoAuthStrategy(AuthStrategy):
45
def __init__(self):
56
super().__init__(AuthType.NO_AUTH)
@@ -8,4 +9,4 @@ def get_auth_string(self) -> str:
89
return ""
910

1011
def requires_authentication(self) -> bool:
11-
return False
12+
return False

twilio/auth_strategy/token_auth_strategy.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import jwt
22
import threading
33
import logging
4-
from datetime import datetime, timedelta
4+
from datetime import datetime
55

66
from twilio.auth_strategy.auth_type import AuthType
77
from twilio.auth_strategy.auth_strategy import AuthStrategy
@@ -25,16 +25,16 @@ def requires_authentication(self) -> bool:
2525
return True
2626

2727
def fetch_token(self):
28-
self.logger.info("New token fetched for accessing organization API")
2928
if self.token is None or self.token == "" or self.is_token_expired(self.token):
30-
with self.lock:
29+
# with self.lock:
3130
if self.token is None or self.token == "" or self.is_token_expired(self.token):
31+
self.logger.info("New token fetched for accessing organization API")
3232
self.token = self.token_manager.fetch_access_token()
3333

3434
def is_token_expired(self, token):
3535
try:
3636
decoded = jwt.decode(token, options={"verify_signature": False})
37-
exp = decoded.get('exp')
37+
exp = decoded.get("exp")
3838

3939
if exp is None:
4040
return True # No expiration time present, consider it expired
@@ -46,4 +46,4 @@ def is_token_expired(self, token):
4646
return True # Token is invalid
4747
except Exception as e:
4848
print(f"An error occurred: {e}")
49-
return True
49+
return True

twilio/base/client_base.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from twilio.http import HttpClient
88
from twilio.http.http_client import TwilioHttpClient
99
from twilio.http.response import Response
10-
from twilio.auth_strategy.auth_type import AuthType
1110
from twilio.credential.credential_provider import CredentialProvider
1211

1312

@@ -88,27 +87,26 @@ def request(
8887
8988
:returns: Response from the Twilio API
9089
"""
91-
9290
headers = self.get_headers(method, headers)
9391

9492
##If credential provider is provided by user, get the associated auth strategy
9593
##Using the auth strategy, fetch the auth string and set it to authorization header
9694
if self.credential_provider:
95+
9796
auth_strategy = self.credential_provider.to_auth_strategy()
9897
headers["Authorization"] = auth_strategy.get_auth_string()
9998
elif self.username is not None and self.password is not None:
10099
auth = self.get_auth(auth)
101100
else:
102101
auth = None
103102

104-
105103
uri = self.get_hostname(uri)
106-
104+
filtered_data = self.copy_non_none_values(data)
107105
return self.http_client.request(
108106
method,
109107
uri,
110108
params=params,
111-
data=data,
109+
data=filtered_data,
112110
headers=headers,
113111
auth=auth,
114112
timeout=timeout,
@@ -147,7 +145,6 @@ async def request_async(
147145
"http_client must be asynchronous to support async API requests"
148146
)
149147

150-
151148
headers = self.get_headers(method, headers)
152149

153150
##If credential provider is provided by user, get the associated auth strategy
@@ -162,18 +159,25 @@ async def request_async(
162159
auth = None
163160

164161
uri = self.get_hostname(uri)
165-
162+
filtered_data = self.copy_non_none_values(data)
166163
return await self.http_client.request(
167164
method,
168165
uri,
169166
params=params,
170-
data=data,
167+
data=filtered_data,
171168
headers=headers,
172169
auth=auth,
173170
timeout=timeout,
174171
allow_redirects=allow_redirects,
175172
)
176173

174+
def copy_non_none_values(self, data):
175+
if isinstance(data, dict):
176+
return {k: self.copy_non_none_values(v) for k, v in data.items() if v is not None}
177+
elif isinstance(data, list):
178+
return [self.copy_non_none_values(item) for item in data if item is not None]
179+
return data
180+
177181
def get_auth(self, auth: Optional[Tuple[str, str]]) -> Tuple[str, str]:
178182
"""
179183
Get the request authentication object
@@ -252,6 +256,20 @@ def get_hostname(self, uri: str) -> str:
252256
)
253257
return str(urlunparse(parsed_url))
254258

259+
def remove_nulls(self, data):
260+
res = {}
261+
for key, sub_dict in data.items():
262+
temp_dict = {}
263+
if type(sub_dict) != str and sub_dict is not None:
264+
for sub_key, sub_value in sub_dict.items():
265+
if sub_value is not None:
266+
temp_dict[sub_key] = sub_value
267+
if type(sub_dict) == str:
268+
temp_dict = sub_dict
269+
if temp_dict:
270+
res[key] = temp_dict
271+
return res
272+
255273
def __repr__(self) -> str:
256274
"""
257275
Provide a friendly representation

twilio/base/page.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ def load_page(self, payload: Dict[str, Any]):
7777
key = keys - self.META_KEYS
7878
if len(key) == 1:
7979
return payload[key.pop()]
80+
if "Resources" in payload:
81+
return payload["Resources"]
8082

8183
raise TwilioException("Page Records can not be deserialized")
8284

twilio/base/version.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ async def fetch_async(
164164
timeout=timeout,
165165
allow_redirects=allow_redirects,
166166
)
167+
print('response')
168+
print(response)
169+
170+
167171

168172
return self._parse_fetch(method, uri, response)
169173

twilio/credential/credential_provider.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from twilio.auth_strategy.auth_type import AuthType
22

3+
34
class CredentialProvider:
45
def __init__(self, auth_type: AuthType):
56
self._auth_type = auth_type

twilio/credential/orgs_credential_provider.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
2-
31
from twilio.http.orgs_token_manager import OrgTokenManager
42
from twilio.base.exceptions import TwilioException
53
from twilio.credential.credential_provider import CredentialProvider
@@ -22,7 +20,9 @@ def __init__(self, client_id: str, client_secret: str, token_manager=None):
2220

2321
def to_auth_strategy(self):
2422
if self.token_manager is None:
25-
self.token_manager = OrgTokenManager(self.grant_type, self.client_id, self.client_secret)
23+
self.token_manager = OrgTokenManager(
24+
self.grant_type, self.client_id, self.client_secret
25+
)
2626
if self.auth_strategy is None:
2727
self.auth_strategy = TokenAuthStrategy(self.token_manager)
2828
return self.auth_strategy

twilio/http/http_client.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@ def request(
8888
}
8989
if headers and headers.get("Content-Type") == "application/json":
9090
kwargs["json"] = data
91+
elif headers and headers.get("Content-Type") == "application/scim+json":
92+
kwargs["json"] = data
9193
else:
9294
kwargs["data"] = data
9395
self.log_request(kwargs)
94-
print(f'args : {kwargs}')
96+
print(f"\nargs : {kwargs}")
9597
self._test_only_last_response = None
9698
session = self.session or Session()
9799
request = Request(**kwargs)
@@ -106,9 +108,12 @@ def request(
106108
prepped_request,
107109
allow_redirects=allow_redirects,
108110
timeout=timeout,
109-
**settings
111+
**settings,
110112
)
111113

114+
print(f"\nresponse : {response.text}")
115+
print(f"\nresponse code : {response}")
116+
112117
self.log_response(response.status_code, response)
113118

114119
self._test_only_last_response = Response(

0 commit comments

Comments
 (0)