Skip to content

Commit 0874cae

Browse files
Merge pull request #8 from Devotel/services-namespace-refactor
Fix formatting
2 parents 3133542 + 299c8cb commit 0874cae

File tree

6 files changed

+144
-56
lines changed

6 files changed

+144
-56
lines changed

examples/README.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -158,34 +158,34 @@ The following examples show the structure and planned functionality but are not
158158
The contact groups resource is fully implemented with all CRUD operations:
159159

160160
### 🔧 Available Functions
161-
1. **List Groups** - `client.contact_groups.list()`
161+
1. **List Groups** - `client.services.contact_groups.list()`
162162
- Uses GET `/api/v1/contacts-groups`
163163
- Pagination and search support
164164
- Field filtering capabilities
165165

166-
2. **Create Group** - `client.contact_groups.create()`
166+
2. **Create Group** - `client.services.contact_groups.create()`
167167
- Uses POST `/api/v1/contacts-groups`
168168
- Metadata and contact assignment
169169
- Validation and error handling
170170

171-
3. **Update Group** - `client.contact_groups.update()`
171+
3. **Update Group** - `client.services.contact_groups.update()`
172172
- Uses PUT `/api/v1/contacts-groups/{group_id}`
173173
- Partial updates with metadata
174174
- Flexible field modification
175175

176-
4. **Get Group** - `client.contact_groups.get_by_id()`
176+
4. **Get Group** - `client.services.contact_groups.get_by_id()`
177177
- Uses GET `/api/v1/contacts-groups/{group_id}`
178178
- Complete group information retrieval
179179

180-
5. **Delete Group** - `client.contact_groups.delete_by_id()`
180+
5. **Delete Group** - `client.services.contact_groups.delete_by_id()`
181181
- Uses DELETE `/api/v1/contacts-groups/{group_id}`
182182
- Individual group deletion with approval
183183

184-
6. **Bulk Delete** - `client.contact_groups.delete_bulk()`
184+
6. **Bulk Delete** - `client.services.contact_groups.delete_bulk()`
185185
- Uses DELETE `/api/v1/contacts-groups`
186186
- Multiple group deletion with contact transfer
187187

188-
7. **Search Groups** - `client.contact_groups.search()`
188+
7. **Search Groups** - `client.services.contact_groups.search()`
189189
- Uses GET `/api/v1/contacts-groups`
190190
- Advanced search with field filtering
191191

@@ -201,23 +201,26 @@ The contact groups resource is fully implemented with all CRUD operations:
201201
```python
202202
from devo_global_comms_python.models.contact_groups import CreateContactsGroupDto
203203

204-
# Create new contact group
204+
# Create new contact group (using new services namespace)
205205
group_data = CreateContactsGroupDto(
206206
name="VIP Customers",
207207
description="High-value customers",
208208
contact_ids=["contact1", "contact2"],
209209
metadata={"priority": "high"}
210210
)
211-
group = client.contact_groups.create(group_data)
211+
group = client.services.contact_groups.create(group_data)
212212

213213
# List with pagination
214-
groups = client.contact_groups.list(page=1, limit=10, search="VIP")
214+
groups = client.services.contact_groups.list(page=1, limit=10, search="VIP")
215215

216216
# Search groups
217-
search_results = client.contact_groups.search(
217+
search_results = client.services.contact_groups.search(
218218
query="priority",
219219
fields=["name", "description"]
220220
)
221+
222+
# Backward compatibility (deprecated - shows warning)
223+
# groups = client.contact_groups.list() # Still works but deprecated
221224
```
222225

223226
## 🔧 Configuration Notes

examples/basic_usage.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,23 @@ def main():
3737
resources.append(("💬 WhatsApp", "Placeholder", "whatsapp_example.py"))
3838
if hasattr(client, "contacts"):
3939
resources.append(("👥 Contacts", "Placeholder", "contacts_example.py"))
40-
if hasattr(client, "contact_groups"):
41-
resources.append(("🗂️ Contact Groups", "Implemented", "contact_groups_example.py"))
40+
if hasattr(client, "services") and hasattr(client.services, "contact_groups"):
41+
resources.append(("🗂️ Contact Groups", "Implemented (Services)", "contact_groups_example.py"))
4242
if hasattr(client, "rcs"):
4343
resources.append(("🎴 RCS", "Placeholder", "rcs_example.py"))
4444
if hasattr(client, "messages"):
4545
resources.append(("📬 Messages", "Implemented", "omni_channel_example.py"))
4646

4747
for resource, status, example_file in resources:
48-
print(f" {resource:<12} - {status:<12} -> {example_file}")
48+
print(f" {resource:<18} - {status:<20} -> {example_file}")
49+
50+
# Services namespace information
51+
if hasattr(client, "services"):
52+
print("\n🏢 Services Namespace:")
53+
print("-" * 30)
54+
print(" 🗂️ Contact Groups - client.services.contact_groups")
55+
print(" 👥 Contacts (Future) - client.services.contacts")
56+
print(" 📊 Analytics (Future) - client.services.analytics")
4957

5058
# Quick SMS test if available
5159
if hasattr(client, "sms"):

examples/contact_groups_example.py

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#!/usr/bin/env python3
21
import os
32
from datetime import datetime
43

@@ -11,13 +10,6 @@
1110

1211

1312
def main():
14-
"""
15-
Demonstrate contact groups management capabilities.
16-
17-
Shows how to create, read, update and delete contact groups
18-
using the Contact Groups API.
19-
"""
20-
2113
# Initialize the client
2214
api_key = os.getenv("DEVO_API_KEY")
2315
if not api_key:
@@ -28,11 +20,13 @@ def main():
2820

2921
print("🗂️ Devo Global Communications - Contact Groups Management Example")
3022
print("=" * 75)
23+
print("📋 Using services namespace: client.services.contact_groups")
24+
print()
3125

3226
# Example 1: List existing contact groups
3327
print("\n📋 Listing existing contact groups...")
3428
try:
35-
groups_list = client.contact_groups.list(page=1, limit=5)
29+
groups_list = client.services.contact_groups.list(page=1, limit=5)
3630
print(f"✅ Found {groups_list.total} total groups")
3731
print(f" Page: {groups_list.page}/{groups_list.total_pages}")
3832
print(f" Showing: {len(groups_list.groups)} groups")
@@ -63,7 +57,7 @@ def main():
6357
},
6458
)
6559

66-
new_group = client.contact_groups.create(new_group_data)
60+
new_group = client.services.contact_groups.create(new_group_data)
6761
print("✅ Contact group created successfully!")
6862
print(f" 📁 Name: {new_group.name}")
6963
print(f" 🆔 ID: {new_group.id}")
@@ -88,7 +82,7 @@ def main():
8882
metadata={"updated_by": "api_example", "updated_at": datetime.now().isoformat(), "version": "2.0"},
8983
)
9084

91-
updated_group = client.contact_groups.update(created_group_id, update_data)
85+
updated_group = client.services.contact_groups.update(created_group_id, update_data)
9286
print("✅ Contact group updated successfully!")
9387
print(f" 📁 New name: {updated_group.name}")
9488
print(f" 📝 New description: {updated_group.description}")
@@ -102,7 +96,7 @@ def main():
10296
if created_group_id:
10397
print(f"\n🔍 Retrieving specific group {created_group_id}...")
10498
try:
105-
specific_group = client.contact_groups.get_by_id(created_group_id)
99+
specific_group = client.services.contact_groups.get_by_id(created_group_id)
106100
print("✅ Group retrieved successfully!")
107101
print(f" 📁 Name: {specific_group.name}")
108102
print(f" 📝 Description: {specific_group.description}")
@@ -115,7 +109,9 @@ def main():
115109
# Example 5: Search contact groups
116110
print("\n🔎 Searching contact groups...")
117111
try:
118-
search_results = client.contact_groups.search(query="demo", fields=["name", "description"], page=1, limit=10)
112+
search_results = client.services.contact_groups.search(
113+
query="demo", fields=["name", "description"], page=1, limit=10
114+
)
119115
print(f"✅ Search completed! Found {search_results.total} matching groups")
120116

121117
for i, group in enumerate(search_results.groups, 1):
@@ -130,7 +126,7 @@ def main():
130126
# Example 6: Advanced listing with filters
131127
print("\n🔧 Advanced group listing with filters...")
132128
try:
133-
filtered_groups = client.contact_groups.list(
129+
filtered_groups = client.services.contact_groups.list(
134130
page=1, limit=3, search="demo", search_fields=["name", "description"]
135131
)
136132
print("✅ Filtered listing completed!")
@@ -157,7 +153,7 @@ def main():
157153
metadata={"bulk_demo": True, "group_number": i + 1},
158154
)
159155

160-
bulk_group = client.contact_groups.create(bulk_group_data)
156+
bulk_group = client.services.contact_groups.create(bulk_group_data)
161157
bulk_group_ids.append(bulk_group.id)
162158
print(f" ✅ Created bulk group {i+1}: {bulk_group.name}")
163159

@@ -170,7 +166,7 @@ def main():
170166
if created_group_id:
171167
print(f"\n🗑️ Deleting individual group {created_group_id}...")
172168
try:
173-
deleted_group = client.contact_groups.delete_by_id(created_group_id, approve="yes")
169+
deleted_group = client.services.contact_groups.delete_by_id(created_group_id, approve="yes")
174170
print("✅ Individual group deleted successfully!")
175171
print(f" 📁 Deleted group: {deleted_group.name}")
176172

@@ -185,17 +181,17 @@ def main():
185181
backup_group_data = CreateContactsGroupDto(
186182
name="Backup Group for Bulk Delete Demo", description="Temporary group to receive transferred contacts"
187183
)
188-
backup_group = client.contact_groups.create(backup_group_data)
184+
backup_group = client.services.contact_groups.create(backup_group_data)
189185

190186
# Perform bulk deletion
191187
bulk_delete_data = DeleteContactsGroupsDto(group_ids=bulk_group_ids, transfer_contacts_to=backup_group.id)
192188

193-
bulk_delete_result = client.contact_groups.delete_bulk(bulk_delete_data, approve="yes")
189+
bulk_delete_result = client.services.contact_groups.delete_bulk(bulk_delete_data, approve="yes")
194190
print("✅ Bulk deletion completed successfully!")
195191
print(f" 📊 Operation result: {bulk_delete_result.name}")
196192

197193
# Clean up backup group
198-
client.contact_groups.delete_by_id(backup_group.id, approve="yes")
194+
client.services.contact_groups.delete_by_id(backup_group.id, approve="yes")
199195
print(" 🧹 Cleaned up backup group")
200196

201197
except Exception as e:
@@ -205,7 +201,7 @@ def main():
205201
print("\n⚠️ Error handling demonstration...")
206202
try:
207203
# Try to get a non-existent group
208-
client.contact_groups.get_by_id("non_existent_group_id")
204+
client.services.contact_groups.get_by_id("non_existent_group_id")
209205

210206
except Exception as e:
211207
print(f"✅ Properly handled expected error: {type(e).__name__}")
@@ -277,7 +273,7 @@ def contact_group_management_workflow():
277273
name=group_type["name"], description=group_type["description"], metadata=group_type["metadata"]
278274
)
279275

280-
group = client.contact_groups.create(group_data)
276+
group = client.services.contact_groups.create(group_data)
281277
created_groups.append(group)
282278
print(f" ✅ Created: {group.name}")
283279

@@ -310,7 +306,7 @@ def contact_group_management_workflow():
310306
},
311307
)
312308

313-
client.contact_groups.update(vip_group.id, update_data)
309+
client.services.contact_groups.update(vip_group.id, update_data)
314310
print(" ✅ Updated VIP group with enhanced metadata")
315311

316312
except Exception as e:
@@ -326,16 +322,16 @@ def contact_group_management_workflow():
326322
temp_group_data = CreateContactsGroupDto(
327323
name="Temporary Archive", description="Temporary group for workflow cleanup"
328324
)
329-
temp_group = client.contact_groups.create(temp_group_data)
325+
temp_group = client.services.contact_groups.create(temp_group_data)
330326

331327
# Bulk delete with contact transfer
332328
delete_data = DeleteContactsGroupsDto(group_ids=group_ids, transfer_contacts_to=temp_group.id)
333329

334-
client.contact_groups.delete_bulk(delete_data, approve="yes")
330+
client.services.contact_groups.delete_bulk(delete_data, approve="yes")
335331
print(f" ✅ Bulk deleted {len(group_ids)} demonstration groups")
336332

337333
# Delete temporary group
338-
client.contact_groups.delete_by_id(temp_group.id, approve="yes")
334+
client.services.contact_groups.delete_by_id(temp_group.id, approve="yes")
339335
print(" ✅ Cleaned up temporary archive group")
340336

341337
except Exception as e:

src/devo_global_comms_python/client.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,46 @@
66

77
from .auth import APIKeyAuth
88
from .exceptions import DevoAPIException, DevoAuthenticationException, DevoException, DevoMissingAPIKeyException
9-
from .resources.contact_groups import ContactGroupsResource
109
from .resources.contacts import ContactsResource
1110
from .resources.email import EmailResource
1211
from .resources.messages import MessagesResource
1312
from .resources.rcs import RCSResource
1413
from .resources.sms import SMSResource
1514
from .resources.whatsapp import WhatsAppResource
15+
from .services import ServicesNamespace
1616

1717

1818
class DevoClient:
1919
"""
2020
Main client for interacting with the Devo Global Communications API.
2121
22-
This client follows a resource-based pattern,
23-
where each communication channel (SMS, Email, etc.) is accessed as a
24-
resource with its own methods.
22+
This client follows a resource-based pattern with two main namespaces:
23+
- Messaging resources: Direct access to communication channels (SMS, Email, etc.)
24+
- Services namespace: Organized access to data management services
2525
2626
Example:
2727
>>> client = DevoClient(api_key="your-api-key")
28-
>>> # Send SMS using new API
28+
>>>
29+
>>> # Messaging resources (direct access)
2930
>>> response = client.sms.send_sms(
3031
... recipient="+1234567890",
3132
... message="Hello, World!",
3233
... sender="+0987654321"
3334
... )
3435
>>> print(f"Message ID: {response.id}")
35-
>>> print(f"Status: {response.status}")
3636
>>>
37-
>>> # Get available senders
38-
>>> senders = client.sms.get_senders()
39-
>>> for sender in senders.senders:
40-
... print(f"Sender: {sender.phone_number}")
37+
>>> # Services namespace (organized access)
38+
>>> groups = client.services.contact_groups.list()
39+
>>> for group in groups.groups:
40+
... print(f"Group: {group.name}")
4141
>>>
42-
>>> # Get available numbers
43-
>>> numbers = client.sms.get_available_numbers(region="US", limit=5)
44-
>>> for number_info in numbers.numbers:
45-
... for feature in number_info.features:
46-
... print(f"Number: {feature.phone_number}")
42+
>>> # Omni-channel messaging
43+
>>> from devo_global_comms_python.models.messages import SendMessageDto
44+
>>> message = client.messages.send(SendMessageDto(
45+
... channel="sms",
46+
... to="+1234567890",
47+
... payload={"text": "Hello World"}
48+
... ))
4749
"""
4850

4951
DEFAULT_BASE_URL = "https://global-api-development.devotel.io/api/v1"
@@ -82,15 +84,17 @@ def __init__(
8284
# Set up session with retry strategy
8385
self.session = session or self._create_session(max_retries)
8486

85-
# Initialize resources
87+
# Initialize messaging resources
8688
self.sms = SMSResource(self)
8789
self.email = EmailResource(self)
8890
self.whatsapp = WhatsAppResource(self)
8991
self.rcs = RCSResource(self)
9092
self.contacts = ContactsResource(self)
91-
self.contact_groups = ContactGroupsResource(self)
9293
self.messages = MessagesResource(self)
9394

95+
# Initialize services namespace
96+
self.services = ServicesNamespace(self)
97+
9498
def _create_session(self, max_retries: int) -> requests.Session:
9599
"""Create a requests session with retry strategy."""
96100
session = requests.Session()

0 commit comments

Comments
 (0)