Skip to content

Commit bc85a9d

Browse files
committed
WiP
1 parent a070660 commit bc85a9d

36 files changed

Lines changed: 1858 additions & 343 deletions

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,7 @@ cython_debug/
129129
.idea/
130130

131131
# Poetry
132-
poetry.lock
132+
poetry.lock
133+
134+
# DS-Store files
135+
.DS_Store

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ keywords = ["sinch", "sdk"]
2828
python = ">=3.9"
2929
requests = "*"
3030
httpx = "*"
31+
pydantic = ">=2.0.0"
3132

3233
[build-system]
3334
requires = ["poetry-core"]

requirements-dev.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
# Testing
22
pytest
33
pytest-asyncio
4+
pytest-mock
45
coverage
56

67
# Code Quality
78
flake8
89

910
# HTTP Libraries
1011
httpx
11-
requests
12+
requests
13+
14+
# Data Validation
15+
pydantic >= 2.0.0

sinch/core/models/base_model.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import json
2+
from datetime import datetime
23
from dataclasses import asdict, dataclass
4+
from pydantic import BaseModel, ConfigDict
35

46

57
@dataclass
@@ -15,3 +17,23 @@ def as_json(self):
1517
class SinchRequestBaseModel(SinchBaseModel):
1618
def as_dict(self):
1719
return {k: v for k, v in asdict(self).items() if v is not None}
20+
21+
22+
class BaseModelConfig(BaseModel):
23+
"""
24+
A base model that allows extra fields and converts camelCase to snake_case,
25+
and serializes datetime fields to ISO format.
26+
"""
27+
28+
def datetime_encoder(v: datetime) -> str:
29+
# Converts a datetime object to a string in ISO 8601 format
30+
return v.strftime("%Y-%m-%dT%H:%M:%S.%fZ")[:-3] + "Z"
31+
32+
model_config = ConfigDict(
33+
# Allows using both alias (camelCase) and field name (snake_case)
34+
populate_by_name=True,
35+
# Allows extra values in input
36+
extra="allow",
37+
# Custom datetime serialization
38+
ser_json_typed={datetime: datetime_encoder}
39+
)

sinch/domains/numbers/__init__.py

Lines changed: 1 addition & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
from sinch.core.pagination import TokenBasedPaginator, AsyncTokenBasedPaginator
2-
from sinch.domains.numbers.endpoints.available.search_for_number import SearchForNumberEndpoint
3-
from sinch.domains.numbers.endpoints.available.list_available_numbers import AvailableNumbersEndpoint
4-
from sinch.domains.numbers.endpoints.available.activate_number import ActivateNumberEndpoint
5-
from sinch.domains.numbers.endpoints.available.rent_any_number import RentAnyNumberEndpoint
2+
from sinch.domains.numbers.available_numbers import AvailableNumbers
63
from sinch.domains.numbers.endpoints.callbacks.get_configuration import GetNumbersCallbackConfigurationEndpoint
74
from sinch.domains.numbers.endpoints.callbacks.update_configuration import UpdateNumbersCallbackConfigurationEndpoint
8-
95
from sinch.domains.numbers.endpoints.active.list_active_numbers_for_project import ListActiveNumbersEndpoint
106
from sinch.domains.numbers.endpoints.active.update_number_configuration import UpdateNumberConfigurationEndpoint
117
from sinch.domains.numbers.endpoints.active.get_number_configuration import GetNumberConfigurationEndpoint
@@ -17,15 +13,7 @@
1713
ListActiveNumbersRequest, GetNumberConfigurationRequest,
1814
UpdateNumberConfigurationRequest, ReleaseNumberFromProjectRequest
1915
)
20-
from sinch.domains.numbers.models.available.requests import (
21-
ListAvailableNumbersRequest, ActivateNumberRequest,
22-
CheckNumberAvailabilityRequest, RentAnyNumberRequest
23-
)
2416
from sinch.domains.numbers.models.regions.responses import ListAvailableRegionsResponse
25-
from sinch.domains.numbers.models.available.responses import (
26-
ListAvailableNumbersResponse, ActivateNumberResponse,
27-
CheckNumberAvailabilityResponse
28-
)
2917
from sinch.domains.numbers.models.active.responses import (
3018
ListActiveNumbersResponse, UpdateNumberConfigurationResponse,
3119
GetNumberConfigurationResponse, ReleaseNumberFromProjectResponse
@@ -39,98 +27,6 @@
3927
)
4028

4129

42-
class AvailableNumbers:
43-
def __init__(self, sinch):
44-
self._sinch = sinch
45-
46-
def list(
47-
self,
48-
region_code: str,
49-
number_type: str,
50-
number_pattern: str = None,
51-
number_search_pattern: str = None,
52-
capabilities: list = None,
53-
page_size: int = None
54-
) -> ListAvailableNumbersResponse:
55-
"""
56-
Search for available virtual numbers using a variety of parameters to filter results.
57-
For additional documentation, see https://www.sinch.com and visit our developer portal.
58-
"""
59-
return self._sinch.configuration.transport.request(
60-
AvailableNumbersEndpoint(
61-
project_id=self._sinch.configuration.project_id,
62-
request_data=ListAvailableNumbersRequest(
63-
region_code=region_code,
64-
number_type=number_type,
65-
page_size=page_size,
66-
capabilities=capabilities,
67-
number_search_pattern=number_search_pattern,
68-
number_pattern=number_pattern
69-
)
70-
)
71-
)
72-
73-
def activate(
74-
self,
75-
phone_number: str,
76-
sms_configuration: dict = None,
77-
voice_configuration: dict = None
78-
) -> ActivateNumberResponse:
79-
"""
80-
Activate a virtual number to use with SMS products, Voice products, or both.
81-
For additional documentation, see https://www.sinch.com and visit our developer portal.
82-
"""
83-
return self._sinch.configuration.transport.request(
84-
ActivateNumberEndpoint(
85-
project_id=self._sinch.configuration.project_id,
86-
request_data=ActivateNumberRequest(
87-
phone_number=phone_number,
88-
sms_configuration=sms_configuration,
89-
voice_configuration=voice_configuration
90-
)
91-
)
92-
)
93-
94-
def rent_any(
95-
self,
96-
region_code: str,
97-
type_: str,
98-
number_pattern: str = None,
99-
capabilities: list = None,
100-
sms_configuration: dict = None,
101-
voice_configuration: dict = None,
102-
callback_url: str = None
103-
) -> RentAnyNumberRequest:
104-
return self._sinch.configuration.transport.request(
105-
RentAnyNumberEndpoint(
106-
project_id=self._sinch.configuration.project_id,
107-
request_data=RentAnyNumberRequest(
108-
region_code=region_code,
109-
type_=type_,
110-
number_pattern=number_pattern,
111-
capabilities=capabilities,
112-
sms_configuration=sms_configuration,
113-
voice_configuration=voice_configuration,
114-
callback_url=callback_url
115-
)
116-
)
117-
)
118-
119-
def check_availability(self, phone_number: str) -> CheckNumberAvailabilityResponse:
120-
"""
121-
Enter a specific phone number to check availability.
122-
For additional documentation, see https://www.sinch.com and visit our developer portal.
123-
"""
124-
return self._sinch.configuration.transport.request(
125-
SearchForNumberEndpoint(
126-
project_id=self._sinch.configuration.project_id,
127-
request_data=CheckNumberAvailabilityRequest(
128-
phone_number=phone_number
129-
)
130-
)
131-
)
132-
133-
13430
class ActiveNumbers:
13531
def __init__(self, sinch):
13632
self._sinch = sinch
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
from typing import Optional
2+
from pydantic import conlist, StrictInt, StrictStr
3+
from sinch.domains.numbers.endpoints.available.search_for_number import SearchForNumberEndpoint
4+
from sinch.domains.numbers.endpoints.available.list_available_numbers import AvailableNumbersEndpoint
5+
from sinch.domains.numbers.endpoints.available.activate_number import ActivateNumberEndpoint
6+
from sinch.domains.numbers.endpoints.available.rent_any_number import RentAnyNumberEndpoint
7+
from sinch.domains.numbers.models.available.list_available_numbers_request import ListAvailableNumbersRequest
8+
from sinch.domains.numbers.models.available.activate_number_request import ActivateNumberRequest
9+
from sinch.domains.numbers.models.available.rent_any_number_request import RentAnyNumberRequest
10+
from sinch.domains.numbers.models.available.check_number_availability_request import CheckNumberAvailabilityRequest
11+
12+
from sinch.domains.numbers.models.available.list_available_numbers_response import ListAvailableNumbersResponse
13+
from sinch.domains.numbers.models.available.activate_number_response import ActivateNumberResponse
14+
from sinch.domains.numbers.models.available.rent_any_number_response import RentAnyNumberResponse
15+
from sinch.domains.numbers.models.available.check_number_availability_response import CheckNumberAvailabilityResponse
16+
17+
18+
class AvailableNumbers:
19+
def __init__(self, sinch):
20+
self._sinch = sinch
21+
22+
def _request(self, endpoint_class, request_data):
23+
"""
24+
A helper method to make requests to endpoints.
25+
26+
Args:
27+
endpoint_class: The endpoint class to call.
28+
request_data: The request data to pass to the endpoint.
29+
30+
Returns:
31+
The response from the Sinch transport request.
32+
"""
33+
return self._sinch.configuration.transport.request(
34+
endpoint_class(
35+
project_id=self._sinch.configuration.project_id,
36+
request_data=request_data,
37+
)
38+
)
39+
40+
def list(
41+
self,
42+
region_code: StrictStr,
43+
number_type: StrictStr,
44+
number_pattern: Optional[StrictStr] = None,
45+
number_search_pattern: Optional[StrictStr] = None,
46+
capabilities: Optional[conlist] = None,
47+
page_size: Optional[StrictInt] = None,
48+
**kwargs
49+
) -> ListAvailableNumbersResponse:
50+
"""
51+
Search for available virtual numbers for you to activate using a variety of parameters to filter results.
52+
53+
Args:
54+
region_code (str): ISO 3166-1 alpha-2 country code of the phone number.
55+
number_type (str): Type of number (MOBILE, LOCAL, TOLL_FREE).
56+
number_pattern (str): Specific sequence of digits to search for.
57+
number_search_pattern (str): Pattern to apply (START, CONTAIN, END).
58+
capabilities (list): Capabilities (SMS, VOICE) required for the number.
59+
page_size (int): Maximum number of items to return.
60+
**kwargs: Additional filters for the request.
61+
62+
Returns:
63+
ListAvailableNumbersResponse: A response object with available numbers and their details.
64+
65+
For detailed documentation, visit https://developers.sinch.com
66+
"""
67+
request_data = ListAvailableNumbersRequest(
68+
region_code=region_code,
69+
number_type=number_type,
70+
page_size=page_size,
71+
capabilities=capabilities,
72+
number_search_pattern=number_search_pattern,
73+
number_pattern=number_pattern,
74+
**kwargs
75+
)
76+
return self._request(AvailableNumbersEndpoint, request_data)
77+
78+
def activate(
79+
self,
80+
phone_number: StrictStr,
81+
sms_configuration: Optional[dict] = None,
82+
voice_configuration: Optional[dict] = None,
83+
**kwargs
84+
) -> ActivateNumberResponse:
85+
"""
86+
Activate a virtual number to use with SMS products, Voice products, or both.
87+
88+
Args:
89+
phone_number (str): The phone number in E.164 format with leading +.
90+
sms_configuration (dict): Configuration for SMS activation.
91+
voice_configuration (dict): Configuration for Voice activation.
92+
**kwargs: Additional parameters for the request.
93+
94+
Returns:
95+
ActivateNumberResponse: A response object with the activated number and its details.
96+
97+
For detailed documentation, visit https://developers.sinch.com
98+
"""
99+
request_data = ActivateNumberRequest(
100+
phone_number=phone_number,
101+
sms_configuration=sms_configuration,
102+
voice_configuration=voice_configuration,
103+
**kwargs
104+
)
105+
return self._request(ActivateNumberEndpoint, request_data)
106+
107+
def rent_any(
108+
self,
109+
region_code: StrictStr,
110+
type_: StrictStr,
111+
number_pattern: Optional[StrictStr] = None,
112+
capabilities: Optional[conlist] = None,
113+
sms_configuration: Optional[dict] = None,
114+
voice_configuration: Optional[dict] = None,
115+
callback_url: Optional[StrictStr] = None,
116+
**kwargs
117+
) -> RentAnyNumberResponse:
118+
"""
119+
Search for and activate an available Sinch virtual number all in one API call.
120+
Currently, the rentAny operation works only for US 10DLC numbers
121+
122+
Args:
123+
region_code (str): ISO 3166-1 alpha-2 country code of the phone number.
124+
type_ (str): Type of number (MOBILE, LOCAL, TOLL_FREE).
125+
number_pattern (str): Specific sequence of digits to search for.
126+
capabilities (list): Capabilities (SMS, VOICE) required for the number.
127+
sms_configuration (dict): Configuration for SMS activation.
128+
voice_configuration (dict): Configuration for Voice activation.
129+
callback_url (str): The callback URL to receive notifications.
130+
**kwargs: Additional parameters for the request.
131+
132+
Returns:
133+
RentAnyNumberRequest: A response object with the activated number and its details.
134+
135+
For detailed documentation, visit https://developers.sinch.com
136+
"""
137+
request_data = RentAnyNumberRequest(
138+
region_code=region_code,
139+
type_=type_,
140+
number_pattern=number_pattern,
141+
capabilities=capabilities,
142+
sms_configuration=sms_configuration,
143+
voice_configuration=voice_configuration,
144+
callback_url=callback_url,
145+
**kwargs
146+
)
147+
return self._request(RentAnyNumberEndpoint, request_data)
148+
149+
def check_availability(self, phone_number: StrictStr, **kwargs) -> CheckNumberAvailabilityResponse:
150+
"""
151+
Enter a specific phone number to check availability.
152+
153+
Args:
154+
phone_number (str): The phone number in E.164 format with leading +.
155+
**kwargs: Additional parameters for the request.
156+
157+
Returns:
158+
CheckNumberAvailabilityResponse: A response object with the availability status of the number.
159+
160+
For detailed documentation, visit https://developers.sinch.com
161+
"""
162+
request_data = CheckNumberAvailabilityRequest(phone_number=phone_number, **kwargs)
163+
return self._request(SearchForNumberEndpoint, request_data)

0 commit comments

Comments
 (0)