Skip to content

Commit f0f191b

Browse files
Merge pull request #13 from Devotel/fix/pydantic-consistency
Fix: Standardize Pydantic model parsing and minor fixes
2 parents b949cfb + b17d917 commit f0f191b

File tree

9 files changed

+35
-250
lines changed

9 files changed

+35
-250
lines changed

src/devo_global_comms_python/client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from requests.adapters import HTTPAdapter
55
from urllib3.util.retry import Retry
66

7+
from . import __version__
78
from .auth import APIKeyAuth
89
from .exceptions import DevoAPIException, DevoAuthenticationException, DevoException, DevoMissingAPIKeyException
910
from .resources.contacts import ContactsResource
@@ -143,7 +144,7 @@ def request(
143144

144145
# Prepare headers
145146
request_headers = {
146-
"User-Agent": f"devo-python/{self.__class__.__module__.split('.')[0]}",
147+
"User-Agent": f"devo-python-sdk/{__version__}",
147148
"Accept": "application/json",
148149
}
149150
if headers:

src/devo_global_comms_python/models/sms.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ def __init__(self, data: List[Dict] = None, **kwargs):
212212
"""Custom constructor to handle direct array response."""
213213
if data is not None and isinstance(data, list):
214214
# Convert list of dicts to list of AvailableNumber objects
215-
numbers = [AvailableNumber.parse_obj(item) for item in data]
215+
numbers = [AvailableNumber.model_validate(item) for item in data]
216216
super().__init__(numbers=numbers, **kwargs)
217217
else:
218218
super().__init__(**kwargs)
@@ -222,7 +222,7 @@ def __init__(self, data: List[Dict] = None, **kwargs):
222222
@classmethod
223223
def parse_from_list(cls, data: List[Dict]) -> "AvailableNumbersResponse":
224224
"""Parse from direct array response."""
225-
numbers = [AvailableNumber.parse_obj(item) for item in data]
225+
numbers = [AvailableNumber.model_validate(item) for item in data]
226226
return cls(numbers=numbers)
227227

228228

src/devo_global_comms_python/resources/contacts.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def list(
9797

9898
from ..models.contacts import GetContactsSerializer
9999

100-
return GetContactsSerializer.parse_obj(response.json())
100+
return GetContactsSerializer.model_validate(response.json())
101101

102102
def create(self, contact_data: "CreateContactDto") -> "ContactSerializer":
103103
"""
@@ -113,7 +113,7 @@ def create(self, contact_data: "CreateContactDto") -> "ContactSerializer":
113113

114114
from ..models.contacts import ContactSerializer
115115

116-
return ContactSerializer.parse_obj(response.json())
116+
return ContactSerializer.model_validate(response.json())
117117

118118
def update(self, contact_id: str, contact_data: "UpdateContactDto") -> "ContactSerializer":
119119
"""
@@ -132,7 +132,7 @@ def update(self, contact_id: str, contact_data: "UpdateContactDto") -> "ContactS
132132

133133
from ..models.contacts import ContactSerializer
134134

135-
return ContactSerializer.parse_obj(response.json())
135+
return ContactSerializer.model_validate(response.json())
136136

137137
def delete_bulk(self, delete_data: "DeleteContactsDto", approve: Optional[str] = None) -> "ContactSerializer":
138138
"""
@@ -153,7 +153,7 @@ def delete_bulk(self, delete_data: "DeleteContactsDto", approve: Optional[str] =
153153

154154
from ..models.contacts import ContactSerializer
155155

156-
return ContactSerializer.parse_obj(response.json())
156+
return ContactSerializer.model_validate(response.json())
157157

158158
# Contact Group Management
159159

@@ -198,7 +198,7 @@ def import_from_csv(
198198

199199
from ..models.contacts import CreateContactsFromCsvRespDto
200200

201-
return CreateContactsFromCsvRespDto.parse_obj(response.json())
201+
return CreateContactsFromCsvRespDto.model_validate(response.json())
202202

203203
# Custom Fields Management
204204

@@ -232,7 +232,7 @@ def list_custom_fields(
232232

233233
from ..models.contacts import GetCustomFieldsSerializer
234234

235-
return GetCustomFieldsSerializer.parse_obj(response.json())
235+
return GetCustomFieldsSerializer.model_validate(response.json())
236236

237237
def create_custom_field(self, field_data: "CreateCustomFieldDto") -> "CustomFieldSerializer":
238238
"""
@@ -248,7 +248,7 @@ def create_custom_field(self, field_data: "CreateCustomFieldDto") -> "CustomFiel
248248

249249
from ..models.contacts import CustomFieldSerializer
250250

251-
return CustomFieldSerializer.parse_obj(response.json())
251+
return CustomFieldSerializer.model_validate(response.json())
252252

253253
def update_custom_field(self, field_id: str, field_data: "UpdateCustomFieldDto") -> None:
254254
"""
Lines changed: 2 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
from typing import TYPE_CHECKING, Any, Dict, List, Optional
1+
from typing import TYPE_CHECKING
22

33
from ..utils import validate_email, validate_required_string
44
from .base import BaseResource
55

66
if TYPE_CHECKING:
7-
from ..models.email import EmailMessage, EmailSendResponse
7+
from ..models.email import EmailSendResponse
88

99

1010
class EmailResource(BaseResource):
@@ -60,151 +60,3 @@ def send_email(
6060
from ..models.email import EmailSendResponse
6161

6262
return EmailSendResponse.model_validate(response.json())
63-
64-
def send(
65-
self,
66-
to: str,
67-
subject: str,
68-
body: str,
69-
from_: Optional[str] = None,
70-
html_body: Optional[str] = None,
71-
cc: Optional[List[str]] = None,
72-
bcc: Optional[List[str]] = None,
73-
attachments: Optional[List[Dict[str, Any]]] = None,
74-
reply_to: Optional[str] = None,
75-
callback_url: Optional[str] = None,
76-
metadata: Optional[Dict[str, Any]] = None,
77-
) -> "EmailMessage":
78-
"""
79-
Send an email message.
80-
81-
Args:
82-
to: The recipient's email address
83-
subject: The email subject
84-
body: The plain text email body
85-
from_: The sender's email address (optional, uses account default)
86-
html_body: The HTML email body (optional)
87-
cc: List of CC email addresses (optional)
88-
bcc: List of BCC email addresses (optional)
89-
attachments: List of attachment objects (optional)
90-
reply_to: Reply-to email address (optional)
91-
callback_url: Webhook URL for delivery status (optional)
92-
metadata: Custom metadata dictionary (optional)
93-
94-
Returns:
95-
EmailMessage: The sent message details
96-
"""
97-
# Validate inputs
98-
to = validate_email(to)
99-
subject = validate_required_string(subject, "subject")
100-
body = validate_required_string(body, "body")
101-
102-
if from_:
103-
from_ = validate_email(from_)
104-
if reply_to:
105-
reply_to = validate_email(reply_to)
106-
if cc:
107-
cc = [validate_email(email) for email in cc]
108-
if bcc:
109-
bcc = [validate_email(email) for email in bcc]
110-
111-
# Prepare request data
112-
data = {
113-
"to": to,
114-
"subject": subject,
115-
"body": body,
116-
}
117-
118-
if from_:
119-
data["from"] = from_
120-
if html_body:
121-
data["html_body"] = html_body
122-
if cc:
123-
data["cc"] = cc
124-
if bcc:
125-
data["bcc"] = bcc
126-
if attachments:
127-
data["attachments"] = attachments
128-
if reply_to:
129-
data["reply_to"] = reply_to
130-
if callback_url:
131-
data["callback_url"] = callback_url
132-
if metadata:
133-
data["metadata"] = metadata
134-
135-
# Send request
136-
response = self.client.post("email/messages", json=data)
137-
138-
from ..models.email import EmailMessage
139-
140-
return EmailMessage.parse_obj(response.json())
141-
142-
def get(self, message_id: str) -> "EmailMessage":
143-
"""
144-
Retrieve an email message by ID.
145-
146-
Args:
147-
message_id: The message ID
148-
149-
Returns:
150-
EmailMessage: The message details
151-
"""
152-
message_id = validate_required_string(message_id, "message_id")
153-
154-
response = self.client.get(f"email/messages/{message_id}")
155-
156-
from ..models.email import EmailMessage
157-
158-
return EmailMessage.parse_obj(response.json())
159-
160-
def list(
161-
self,
162-
to: Optional[str] = None,
163-
from_: Optional[str] = None,
164-
subject: Optional[str] = None,
165-
date_sent_after: Optional[str] = None,
166-
date_sent_before: Optional[str] = None,
167-
status: Optional[str] = None,
168-
limit: int = 50,
169-
offset: int = 0,
170-
) -> List["EmailMessage"]:
171-
"""
172-
List email messages with optional filtering.
173-
174-
Args:
175-
to: Filter by recipient email address
176-
from_: Filter by sender email address
177-
subject: Filter by subject (partial match)
178-
date_sent_after: Filter messages sent after this date
179-
date_sent_before: Filter messages sent before this date
180-
status: Filter by message status
181-
limit: Maximum number of messages to return (default: 50)
182-
offset: Number of messages to skip (default: 0)
183-
184-
Returns:
185-
List[EmailMessage]: List of messages
186-
"""
187-
params = {
188-
"limit": limit,
189-
"offset": offset,
190-
}
191-
192-
if to:
193-
params["to"] = validate_email(to)
194-
if from_:
195-
params["from"] = validate_email(from_)
196-
if subject:
197-
params["subject"] = subject
198-
if date_sent_after:
199-
params["date_sent_after"] = date_sent_after
200-
if date_sent_before:
201-
params["date_sent_before"] = date_sent_before
202-
if status:
203-
params["status"] = status
204-
205-
response = self.client.get("email/messages", params=params)
206-
data = response.json()
207-
208-
from ..models.email import EmailMessage
209-
210-
return [EmailMessage.parse_obj(item) for item in data.get("messages", [])]

src/devo_global_comms_python/resources/messages.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def get(self, message_id: str) -> "Message":
9393

9494
from ..models.messages import Message
9595

96-
return Message.parse_obj(response.json())
96+
return Message.model_validate(response.json())
9797

9898
def list(
9999
self,
@@ -142,7 +142,7 @@ def list(
142142

143143
from ..models.messages import Message
144144

145-
return [Message.parse_obj(item) for item in data.get("messages", [])]
145+
return [Message.model_validate(item) for item in data.get("messages", [])]
146146

147147
def get_delivery_status(self, message_id: str) -> Dict[str, Any]:
148148
"""
@@ -173,4 +173,4 @@ def resend(self, message_id: str) -> "Message":
173173

174174
from ..models.messages import Message
175175

176-
return Message.parse_obj(response.json())
176+
return Message.model_validate(response.json())

src/devo_global_comms_python/resources/rcs.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def create_account(self, account_data: Dict[str, Any]) -> "RcsAccountSerializer"
1717

1818
from ..models.rcs import RcsAccountSerializer
1919

20-
return RcsAccountSerializer.parse_obj(response.json())
20+
return RcsAccountSerializer.model_validate(response.json())
2121

2222
def get_accounts(
2323
self,
@@ -65,7 +65,7 @@ def verify_account(self, verification_data: Dict[str, Any]) -> "SuccessSerialize
6565

6666
from ..models.rcs import SuccessSerializer
6767

68-
return SuccessSerializer.parse_obj(response.json())
68+
return SuccessSerializer.model_validate(response.json())
6969

7070
def update_account(self, account_id: str, account_data: Dict[str, Any]) -> Dict[str, Any]:
7171
"""Update RCS Account."""
@@ -86,7 +86,7 @@ def send_message(self, message_data: Dict[str, Any]) -> "RcsSendMessageSerialize
8686

8787
from ..models.rcs import RcsSendMessageSerializer
8888

89-
return RcsSendMessageSerializer.parse_obj(response.json())
89+
return RcsSendMessageSerializer.model_validate(response.json())
9090

9191
def list_messages(
9292
self,
@@ -113,7 +113,7 @@ def list_messages(
113113

114114
from ..models.rcs import RcsSendMessageSerializer
115115

116-
return [RcsSendMessageSerializer.parse_obj(message) for message in response.json()]
116+
return [RcsSendMessageSerializer.model_validate(message) for message in response.json()]
117117

118118
# Template Management Endpoints
119119
def create_template(self, template_data: Dict[str, Any]) -> Dict[str, Any]:
@@ -238,7 +238,7 @@ def send_text(
238238

239239
from ..models.rcs import RCSMessage
240240

241-
return RCSMessage.parse_obj(response.json())
241+
return RCSMessage.model_validate(response.json())
242242

243243
def send_rich_card(
244244
self,
@@ -277,7 +277,7 @@ def send_rich_card(
277277

278278
from ..models.rcs import RCSMessage
279279

280-
return RCSMessage.parse_obj(response.json())
280+
return RCSMessage.model_validate(response.json())
281281

282282
def get(self, message_id: str) -> "RCSMessage":
283283
"""Retrieve an RCS message by ID."""
@@ -286,4 +286,4 @@ def get(self, message_id: str) -> "RCSMessage":
286286

287287
from ..models.rcs import RCSMessage
288288

289-
return RCSMessage.parse_obj(response.json())
289+
return RCSMessage.model_validate(response.json())

0 commit comments

Comments
 (0)