python-zendesk-sdk 0.4.0__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/PKG-INFO +58 -10
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/README.md +57 -9
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/examples/basic_usage.py +24 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/examples/enriched_tickets.py +24 -2
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/pyproject.toml +1 -1
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/__init__.py +11 -1
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/client.py +26 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/clients/__init__.py +2 -0
- python_zendesk_sdk-0.6.0/src/zendesk_sdk/clients/ticket_fields.py +101 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/clients/tickets.py +300 -26
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/models/__init__.py +12 -0
- python_zendesk_sdk-0.6.0/src/zendesk_sdk/models/enriched_ticket.py +142 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/models/search.py +18 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/pagination.py +120 -6
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/tests/test_clients.py +297 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/tests/test_models.py +127 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/tests/test_package_import.py +1 -1
- python_zendesk_sdk-0.4.0/src/zendesk_sdk/models/enriched_ticket.py +0 -63
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/.flake8 +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/.github/workflows/publish.yml +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/.gitignore +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/.python-version +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/LICENSE +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/examples/caching.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/examples/error_handling.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/examples/help_center.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/examples/pagination_example.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/examples/search.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/clients/attachments.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/clients/base.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/clients/help_center/__init__.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/clients/help_center/articles.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/clients/help_center/categories.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/clients/help_center/sections.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/clients/organizations.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/clients/search.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/clients/users.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/config.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/exceptions.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/http_client.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/models/base.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/models/comment.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/models/help_center.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/models/organization.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/models/ticket.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/src/zendesk_sdk/models/user.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/tests/__init__.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/tests/test_client.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/tests/test_config.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/tests/test_exceptions.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/tests/test_help_center_client.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/tests/test_http_client.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/tests/test_pagination.py +0 -0
- {python_zendesk_sdk-0.4.0 → python_zendesk_sdk-0.6.0}/tests/test_search_query_config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-zendesk-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Modern Python SDK for Zendesk API
|
|
5
5
|
Project-URL: Homepage, https://github.com/bormog/python-zendesk-sdk
|
|
6
6
|
Project-URL: Repository, https://github.com/bormog/python-zendesk-sdk
|
|
@@ -36,15 +36,15 @@ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
|
36
36
|
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
37
37
|
Description-Content-Type: text/markdown
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+

|
|
40
40
|
|
|
41
|
-
[](https://pypi.org/project/python-zendesk-sdk/)
|
|
42
|
-
[](https://pypi.org/project/python-zendesk-sdk/)
|
|
43
|
-
[](https://github.com/bormog/python-zendesk-sdk/blob/main/LICENSE)
|
|
45
|
-
[](https://pypi.org/project/python-zendesk-sdk/)
|
|
42
|
+
[](https://pypi.org/project/python-zendesk-sdk/)
|
|
43
|
+
[](https://pepy.tech/projects/python-zendesk-sdk)
|
|
44
|
+
[](https://github.com/bormog/python-zendesk-sdk/blob/main/LICENSE)
|
|
45
|
+
[](https://github.com/psf/black)
|
|
46
|
+
[](https://docs.pydantic.dev/)
|
|
47
|
+
[](https://docs.python.org/3/library/asyncio.html)
|
|
48
48
|
|
|
49
49
|
Modern Python SDK for Zendesk API, designed for automation and AI agents.
|
|
50
50
|
|
|
@@ -61,6 +61,7 @@ Modern Python SDK for Zendesk API, designed for automation and AI agents.
|
|
|
61
61
|
- [Tickets](#tickets)
|
|
62
62
|
- [Comments](#comments-nested-under-tickets)
|
|
63
63
|
- [Tags](#tags-nested-under-tickets)
|
|
64
|
+
- [Ticket Fields](#ticket-fields)
|
|
64
65
|
- [Enriched Tickets](#enriched-tickets)
|
|
65
66
|
- [Attachments](#attachments)
|
|
66
67
|
- [Search](#search)
|
|
@@ -194,10 +195,32 @@ paginator = client.organizations.list() # List organizations (paginator
|
|
|
194
195
|
|
|
195
196
|
### Tickets
|
|
196
197
|
```python
|
|
198
|
+
# Read
|
|
197
199
|
ticket = await client.tickets.get(ticket_id) # Get ticket by ID
|
|
198
200
|
paginator = client.tickets.list() # List tickets (paginator)
|
|
199
201
|
paginator = client.tickets.for_user(user_id) # User's tickets (paginator)
|
|
200
202
|
paginator = client.tickets.for_organization(org_id) # Org's tickets (paginator)
|
|
203
|
+
|
|
204
|
+
# Create
|
|
205
|
+
ticket = await client.tickets.create(
|
|
206
|
+
comment_body="Customer needs help with login",
|
|
207
|
+
subject="Login Issue",
|
|
208
|
+
priority="high", # low, normal, high, urgent
|
|
209
|
+
status="open", # new, open, pending, hold, solved
|
|
210
|
+
ticket_type="problem", # question, incident, problem, task
|
|
211
|
+
tags=["login", "urgent"],
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# Update
|
|
215
|
+
ticket = await client.tickets.update(
|
|
216
|
+
ticket_id,
|
|
217
|
+
status="solved",
|
|
218
|
+
priority="normal",
|
|
219
|
+
comment={"body": "Issue resolved!", "public": True},
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
# Delete (moves to trash, recoverable for 30 days)
|
|
223
|
+
await client.tickets.delete(ticket_id)
|
|
201
224
|
```
|
|
202
225
|
|
|
203
226
|
### Comments (nested under tickets)
|
|
@@ -216,9 +239,22 @@ tags = await client.tickets.tags.set(ticket_id, ["new"]) # Replace all tags
|
|
|
216
239
|
tags = await client.tickets.tags.remove(ticket_id, ["old"]) # Remove tags
|
|
217
240
|
```
|
|
218
241
|
|
|
242
|
+
### Ticket Fields
|
|
243
|
+
```python
|
|
244
|
+
# Get all ticket fields (system + custom)
|
|
245
|
+
async for field in client.ticket_fields.list():
|
|
246
|
+
print(f"{field.title}: {field.type}")
|
|
247
|
+
|
|
248
|
+
# Get specific field by ID (cached)
|
|
249
|
+
field = await client.ticket_fields.get(field_id)
|
|
250
|
+
|
|
251
|
+
# Find field by title (case-insensitive)
|
|
252
|
+
field = await client.ticket_fields.get_by_title("Subscription")
|
|
253
|
+
```
|
|
254
|
+
|
|
219
255
|
### Enriched Tickets
|
|
220
256
|
|
|
221
|
-
Load tickets with all related data (comments
|
|
257
|
+
Load tickets with all related data (comments, users, field definitions) in minimum API requests:
|
|
222
258
|
|
|
223
259
|
```python
|
|
224
260
|
from zendesk_sdk import SearchQueryConfig
|
|
@@ -234,6 +270,13 @@ for comment in enriched.comments:
|
|
|
234
270
|
author = enriched.get_comment_author(comment)
|
|
235
271
|
print(f"Comment by {author.name}: {comment.body[:50]}...")
|
|
236
272
|
|
|
273
|
+
# Access custom field values with human-readable names
|
|
274
|
+
field_values = enriched.get_field_values()
|
|
275
|
+
print(f"Subscription: {field_values.get('Subscription')}")
|
|
276
|
+
|
|
277
|
+
# Or get specific field value by ID
|
|
278
|
+
value = enriched.get_field_value(360001234)
|
|
279
|
+
|
|
237
280
|
# Search with all data loaded (using SearchQueryConfig)
|
|
238
281
|
config = SearchQueryConfig.tickets(
|
|
239
282
|
status=["open"],
|
|
@@ -455,6 +498,7 @@ The SDK provides specific exception classes for different error types:
|
|
|
455
498
|
from zendesk_sdk.exceptions import (
|
|
456
499
|
ZendeskAuthException,
|
|
457
500
|
ZendeskHTTPException,
|
|
501
|
+
ZendeskPaginationException,
|
|
458
502
|
ZendeskRateLimitException,
|
|
459
503
|
ZendeskTimeoutException,
|
|
460
504
|
ZendeskValidationException,
|
|
@@ -475,6 +519,9 @@ async with ZendeskClient(config) as client:
|
|
|
475
519
|
except ZendeskTimeoutException as e:
|
|
476
520
|
# Request timeout
|
|
477
521
|
print(f"Timeout: {e.message}")
|
|
522
|
+
except ZendeskPaginationException as e:
|
|
523
|
+
# Pagination errors (e.g., Zendesk 1000 result limit)
|
|
524
|
+
print(f"Pagination error: {e.message}")
|
|
478
525
|
```
|
|
479
526
|
|
|
480
527
|
### Automatic Retry
|
|
@@ -505,6 +552,7 @@ The SDK includes built-in caching for frequently accessed resources. Caching is
|
|
|
505
552
|
|----------|-----|----------|
|
|
506
553
|
| Users | 5 min | 1000 |
|
|
507
554
|
| Organizations | 10 min | 500 |
|
|
555
|
+
| Ticket Fields | 30 min | 200 |
|
|
508
556
|
| Articles | 15 min | 500 |
|
|
509
557
|
| Categories | 30 min | 200 |
|
|
510
558
|
| Sections | 30 min | 200 |
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+

|
|
2
2
|
|
|
3
|
-
[](https://pypi.org/project/python-zendesk-sdk/)
|
|
4
|
-
[](https://pypi.org/project/python-zendesk-sdk/)
|
|
5
|
-
[](https://github.com/bormog/python-zendesk-sdk/blob/main/LICENSE)
|
|
7
|
-
[](https://pypi.org/project/python-zendesk-sdk/)
|
|
4
|
+
[](https://pypi.org/project/python-zendesk-sdk/)
|
|
5
|
+
[](https://pepy.tech/projects/python-zendesk-sdk)
|
|
6
|
+
[](https://github.com/bormog/python-zendesk-sdk/blob/main/LICENSE)
|
|
7
|
+
[](https://github.com/psf/black)
|
|
8
|
+
[](https://docs.pydantic.dev/)
|
|
9
|
+
[](https://docs.python.org/3/library/asyncio.html)
|
|
10
10
|
|
|
11
11
|
Modern Python SDK for Zendesk API, designed for automation and AI agents.
|
|
12
12
|
|
|
@@ -23,6 +23,7 @@ Modern Python SDK for Zendesk API, designed for automation and AI agents.
|
|
|
23
23
|
- [Tickets](#tickets)
|
|
24
24
|
- [Comments](#comments-nested-under-tickets)
|
|
25
25
|
- [Tags](#tags-nested-under-tickets)
|
|
26
|
+
- [Ticket Fields](#ticket-fields)
|
|
26
27
|
- [Enriched Tickets](#enriched-tickets)
|
|
27
28
|
- [Attachments](#attachments)
|
|
28
29
|
- [Search](#search)
|
|
@@ -156,10 +157,32 @@ paginator = client.organizations.list() # List organizations (paginator
|
|
|
156
157
|
|
|
157
158
|
### Tickets
|
|
158
159
|
```python
|
|
160
|
+
# Read
|
|
159
161
|
ticket = await client.tickets.get(ticket_id) # Get ticket by ID
|
|
160
162
|
paginator = client.tickets.list() # List tickets (paginator)
|
|
161
163
|
paginator = client.tickets.for_user(user_id) # User's tickets (paginator)
|
|
162
164
|
paginator = client.tickets.for_organization(org_id) # Org's tickets (paginator)
|
|
165
|
+
|
|
166
|
+
# Create
|
|
167
|
+
ticket = await client.tickets.create(
|
|
168
|
+
comment_body="Customer needs help with login",
|
|
169
|
+
subject="Login Issue",
|
|
170
|
+
priority="high", # low, normal, high, urgent
|
|
171
|
+
status="open", # new, open, pending, hold, solved
|
|
172
|
+
ticket_type="problem", # question, incident, problem, task
|
|
173
|
+
tags=["login", "urgent"],
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Update
|
|
177
|
+
ticket = await client.tickets.update(
|
|
178
|
+
ticket_id,
|
|
179
|
+
status="solved",
|
|
180
|
+
priority="normal",
|
|
181
|
+
comment={"body": "Issue resolved!", "public": True},
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Delete (moves to trash, recoverable for 30 days)
|
|
185
|
+
await client.tickets.delete(ticket_id)
|
|
163
186
|
```
|
|
164
187
|
|
|
165
188
|
### Comments (nested under tickets)
|
|
@@ -178,9 +201,22 @@ tags = await client.tickets.tags.set(ticket_id, ["new"]) # Replace all tags
|
|
|
178
201
|
tags = await client.tickets.tags.remove(ticket_id, ["old"]) # Remove tags
|
|
179
202
|
```
|
|
180
203
|
|
|
204
|
+
### Ticket Fields
|
|
205
|
+
```python
|
|
206
|
+
# Get all ticket fields (system + custom)
|
|
207
|
+
async for field in client.ticket_fields.list():
|
|
208
|
+
print(f"{field.title}: {field.type}")
|
|
209
|
+
|
|
210
|
+
# Get specific field by ID (cached)
|
|
211
|
+
field = await client.ticket_fields.get(field_id)
|
|
212
|
+
|
|
213
|
+
# Find field by title (case-insensitive)
|
|
214
|
+
field = await client.ticket_fields.get_by_title("Subscription")
|
|
215
|
+
```
|
|
216
|
+
|
|
181
217
|
### Enriched Tickets
|
|
182
218
|
|
|
183
|
-
Load tickets with all related data (comments
|
|
219
|
+
Load tickets with all related data (comments, users, field definitions) in minimum API requests:
|
|
184
220
|
|
|
185
221
|
```python
|
|
186
222
|
from zendesk_sdk import SearchQueryConfig
|
|
@@ -196,6 +232,13 @@ for comment in enriched.comments:
|
|
|
196
232
|
author = enriched.get_comment_author(comment)
|
|
197
233
|
print(f"Comment by {author.name}: {comment.body[:50]}...")
|
|
198
234
|
|
|
235
|
+
# Access custom field values with human-readable names
|
|
236
|
+
field_values = enriched.get_field_values()
|
|
237
|
+
print(f"Subscription: {field_values.get('Subscription')}")
|
|
238
|
+
|
|
239
|
+
# Or get specific field value by ID
|
|
240
|
+
value = enriched.get_field_value(360001234)
|
|
241
|
+
|
|
199
242
|
# Search with all data loaded (using SearchQueryConfig)
|
|
200
243
|
config = SearchQueryConfig.tickets(
|
|
201
244
|
status=["open"],
|
|
@@ -417,6 +460,7 @@ The SDK provides specific exception classes for different error types:
|
|
|
417
460
|
from zendesk_sdk.exceptions import (
|
|
418
461
|
ZendeskAuthException,
|
|
419
462
|
ZendeskHTTPException,
|
|
463
|
+
ZendeskPaginationException,
|
|
420
464
|
ZendeskRateLimitException,
|
|
421
465
|
ZendeskTimeoutException,
|
|
422
466
|
ZendeskValidationException,
|
|
@@ -437,6 +481,9 @@ async with ZendeskClient(config) as client:
|
|
|
437
481
|
except ZendeskTimeoutException as e:
|
|
438
482
|
# Request timeout
|
|
439
483
|
print(f"Timeout: {e.message}")
|
|
484
|
+
except ZendeskPaginationException as e:
|
|
485
|
+
# Pagination errors (e.g., Zendesk 1000 result limit)
|
|
486
|
+
print(f"Pagination error: {e.message}")
|
|
440
487
|
```
|
|
441
488
|
|
|
442
489
|
### Automatic Retry
|
|
@@ -467,6 +514,7 @@ The SDK includes built-in caching for frequently accessed resources. Caching is
|
|
|
467
514
|
|----------|-----|----------|
|
|
468
515
|
| Users | 5 min | 1000 |
|
|
469
516
|
| Organizations | 10 min | 500 |
|
|
517
|
+
| Ticket Fields | 30 min | 200 |
|
|
470
518
|
| Articles | 15 min | 500 |
|
|
471
519
|
| Categories | 30 min | 200 |
|
|
472
520
|
| Sections | 30 min | 200 |
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
This example demonstrates:
|
|
4
4
|
- Configuration setup
|
|
5
5
|
- Basic API operations (get users, tickets, organizations)
|
|
6
|
+
- Ticket CRUD (create, update, delete)
|
|
6
7
|
- Pagination basics
|
|
7
8
|
- Search functionality
|
|
8
9
|
"""
|
|
@@ -42,6 +43,29 @@ async def main() -> None:
|
|
|
42
43
|
ticket = await client.tickets.get(12345)
|
|
43
44
|
print(f"Ticket: {ticket.subject} (status: {ticket.status})")
|
|
44
45
|
|
|
46
|
+
# Create a new ticket
|
|
47
|
+
new_ticket = await client.tickets.create(
|
|
48
|
+
comment_body="Customer cannot access their account",
|
|
49
|
+
subject="Account Access Issue",
|
|
50
|
+
priority="high",
|
|
51
|
+
ticket_type="incident",
|
|
52
|
+
tags=["account", "access"],
|
|
53
|
+
)
|
|
54
|
+
print(f"Created ticket: #{new_ticket.id} - {new_ticket.subject}")
|
|
55
|
+
|
|
56
|
+
# Update the ticket
|
|
57
|
+
updated_ticket = await client.tickets.update(
|
|
58
|
+
new_ticket.id,
|
|
59
|
+
status="open",
|
|
60
|
+
priority="normal",
|
|
61
|
+
comment={"body": "Working on this issue", "public": False},
|
|
62
|
+
)
|
|
63
|
+
print(f"Updated ticket status: {updated_ticket.status}")
|
|
64
|
+
|
|
65
|
+
# Delete the ticket (moves to trash)
|
|
66
|
+
await client.tickets.delete(new_ticket.id)
|
|
67
|
+
print(f"Deleted ticket: #{new_ticket.id}")
|
|
68
|
+
|
|
45
69
|
# Get ticket comments (returns paginator)
|
|
46
70
|
comments = await client.tickets.comments.list(12345, limit=10).collect()
|
|
47
71
|
print(f"Ticket has {len(comments)} comments (limited to 10)")
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"""Enriched tickets example for Zendesk SDK.
|
|
2
2
|
|
|
3
3
|
This example demonstrates:
|
|
4
|
-
- Loading tickets with all related data (comments
|
|
4
|
+
- Loading tickets with all related data (comments, users, field definitions)
|
|
5
5
|
- Using EnrichedTicket for efficient data access
|
|
6
|
+
- Accessing custom field values with human-readable names
|
|
6
7
|
- Minimizing API requests with batch loading
|
|
7
8
|
"""
|
|
8
9
|
|
|
@@ -22,7 +23,8 @@ async def main() -> None:
|
|
|
22
23
|
# ==================== Single enriched ticket ====================
|
|
23
24
|
|
|
24
25
|
# Get a single ticket with all related data
|
|
25
|
-
# This makes 2 API calls: ticket
|
|
26
|
+
# This makes 2 parallel API calls: ticket (with users) + fields
|
|
27
|
+
# Then fetches comments
|
|
26
28
|
enriched = await client.tickets.get_enriched(12345)
|
|
27
29
|
|
|
28
30
|
print(f"Ticket: {enriched.ticket.subject}")
|
|
@@ -40,6 +42,26 @@ async def main() -> None:
|
|
|
40
42
|
else:
|
|
41
43
|
print("Ticket is unassigned")
|
|
42
44
|
|
|
45
|
+
# ==================== Custom field values ====================
|
|
46
|
+
|
|
47
|
+
# Get all custom field values as dict with human-readable names
|
|
48
|
+
field_values = enriched.get_field_values()
|
|
49
|
+
print(f"\nCustom fields ({len(field_values)}):")
|
|
50
|
+
for name, value in field_values.items():
|
|
51
|
+
print(f" {name}: {value}")
|
|
52
|
+
|
|
53
|
+
# Or get specific field value by ID
|
|
54
|
+
subscription = enriched.get_field_value(360001234) # Replace with your field ID
|
|
55
|
+
if subscription:
|
|
56
|
+
print(f"\nSubscription level: {subscription}")
|
|
57
|
+
|
|
58
|
+
# Get field definition for more details
|
|
59
|
+
field = enriched.get_field(360001234)
|
|
60
|
+
if field:
|
|
61
|
+
print(f"Field type: {field.type}, Required: {field.required}")
|
|
62
|
+
|
|
63
|
+
# ==================== Comments with authors ====================
|
|
64
|
+
|
|
43
65
|
# Process comments with author information
|
|
44
66
|
print(f"\nComments ({len(enriched.comments)}):")
|
|
45
67
|
for comment in enriched.comments:
|
|
@@ -5,7 +5,7 @@ This package provides a clean, async-first interface to the Zendesk API
|
|
|
5
5
|
with full type safety and comprehensive error handling.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
__version__ = "0.
|
|
8
|
+
__version__ = "0.6.0"
|
|
9
9
|
|
|
10
10
|
from .client import ZendeskClient
|
|
11
11
|
from .clients import (
|
|
@@ -18,6 +18,7 @@ from .clients import (
|
|
|
18
18
|
SearchClient,
|
|
19
19
|
SectionsClient,
|
|
20
20
|
TagsClient,
|
|
21
|
+
TicketFieldsClient,
|
|
21
22
|
TicketsClient,
|
|
22
23
|
UsersClient,
|
|
23
24
|
)
|
|
@@ -38,9 +39,13 @@ from .models import (
|
|
|
38
39
|
Section,
|
|
39
40
|
SortOrder,
|
|
40
41
|
TicketChannel,
|
|
42
|
+
TicketField,
|
|
41
43
|
TicketPriority,
|
|
44
|
+
TicketPriorityInput,
|
|
42
45
|
TicketStatus,
|
|
46
|
+
TicketStatusInput,
|
|
43
47
|
TicketType,
|
|
48
|
+
TicketTypeInput,
|
|
44
49
|
UserRole,
|
|
45
50
|
)
|
|
46
51
|
|
|
@@ -53,6 +58,7 @@ __all__ = [
|
|
|
53
58
|
"UsersClient",
|
|
54
59
|
"OrganizationsClient",
|
|
55
60
|
"TicketsClient",
|
|
61
|
+
"TicketFieldsClient",
|
|
56
62
|
"CommentsClient",
|
|
57
63
|
"TagsClient",
|
|
58
64
|
"AttachmentsClient",
|
|
@@ -64,6 +70,7 @@ __all__ = [
|
|
|
64
70
|
"ArticlesClient",
|
|
65
71
|
# Models
|
|
66
72
|
"EnrichedTicket",
|
|
73
|
+
"TicketField",
|
|
67
74
|
"Category",
|
|
68
75
|
"Section",
|
|
69
76
|
"Article",
|
|
@@ -71,8 +78,11 @@ __all__ = [
|
|
|
71
78
|
"SearchQueryConfig",
|
|
72
79
|
"SearchType",
|
|
73
80
|
"TicketStatus",
|
|
81
|
+
"TicketStatusInput",
|
|
74
82
|
"TicketPriority",
|
|
83
|
+
"TicketPriorityInput",
|
|
75
84
|
"TicketType",
|
|
85
|
+
"TicketTypeInput",
|
|
76
86
|
"TicketChannel",
|
|
77
87
|
"UserRole",
|
|
78
88
|
"SortOrder",
|
|
@@ -12,6 +12,7 @@ if TYPE_CHECKING:
|
|
|
12
12
|
HelpCenterClient,
|
|
13
13
|
OrganizationsClient,
|
|
14
14
|
SearchClient,
|
|
15
|
+
TicketFieldsClient,
|
|
15
16
|
TicketsClient,
|
|
16
17
|
UsersClient,
|
|
17
18
|
)
|
|
@@ -131,6 +132,31 @@ class ZendeskClient:
|
|
|
131
132
|
|
|
132
133
|
return TicketsClient(self.http_client)
|
|
133
134
|
|
|
135
|
+
@cached_property
|
|
136
|
+
def ticket_fields(self) -> "TicketFieldsClient":
|
|
137
|
+
"""Access Ticket Fields API.
|
|
138
|
+
|
|
139
|
+
Provides access to ticket field definitions, including system
|
|
140
|
+
and custom fields. Essential for understanding ticket schema.
|
|
141
|
+
|
|
142
|
+
Example:
|
|
143
|
+
# List all ticket fields
|
|
144
|
+
async for field in client.ticket_fields.list():
|
|
145
|
+
print(f"{field.title}: {field.type}")
|
|
146
|
+
|
|
147
|
+
# Get specific field
|
|
148
|
+
field = await client.ticket_fields.get(12345)
|
|
149
|
+
|
|
150
|
+
# Get only custom fields
|
|
151
|
+
custom = await client.ticket_fields.list_custom()
|
|
152
|
+
|
|
153
|
+
# Get only active fields
|
|
154
|
+
active = await client.ticket_fields.list_active()
|
|
155
|
+
"""
|
|
156
|
+
from .clients import TicketFieldsClient
|
|
157
|
+
|
|
158
|
+
return TicketFieldsClient(self.http_client, self.config.cache)
|
|
159
|
+
|
|
134
160
|
@cached_property
|
|
135
161
|
def attachments(self) -> "AttachmentsClient":
|
|
136
162
|
"""Access Attachments API.
|
|
@@ -4,6 +4,7 @@ from .attachments import AttachmentsClient
|
|
|
4
4
|
from .help_center import ArticlesClient, CategoriesClient, HelpCenterClient, SectionsClient
|
|
5
5
|
from .organizations import OrganizationsClient
|
|
6
6
|
from .search import SearchClient
|
|
7
|
+
from .ticket_fields import TicketFieldsClient
|
|
7
8
|
from .tickets import CommentsClient, TagsClient, TicketsClient
|
|
8
9
|
from .users import UsersClient
|
|
9
10
|
|
|
@@ -12,6 +13,7 @@ __all__ = [
|
|
|
12
13
|
"UsersClient",
|
|
13
14
|
"OrganizationsClient",
|
|
14
15
|
"TicketsClient",
|
|
16
|
+
"TicketFieldsClient",
|
|
15
17
|
"AttachmentsClient",
|
|
16
18
|
"SearchClient",
|
|
17
19
|
# Ticket sub-clients
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Ticket Fields API client."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Callable, Optional
|
|
4
|
+
|
|
5
|
+
from ..models.ticket import TicketField
|
|
6
|
+
from ..pagination import ZendeskPaginator
|
|
7
|
+
from .base import BaseClient
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from ..config import CacheConfig
|
|
11
|
+
from ..http_client import HTTPClient
|
|
12
|
+
from ..pagination import Paginator
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TicketFieldsClient(BaseClient):
|
|
16
|
+
"""Client for Zendesk Ticket Fields API.
|
|
17
|
+
|
|
18
|
+
Provides access to ticket field definitions, including both system
|
|
19
|
+
fields and custom fields. Essential for understanding ticket schema.
|
|
20
|
+
|
|
21
|
+
Example:
|
|
22
|
+
async with ZendeskClient(config) as client:
|
|
23
|
+
# Get all ticket fields
|
|
24
|
+
async for field in client.ticket_fields.list():
|
|
25
|
+
print(f"{field.title}: {field.type}")
|
|
26
|
+
|
|
27
|
+
# Get a specific field by ID
|
|
28
|
+
field = await client.ticket_fields.get(12345)
|
|
29
|
+
|
|
30
|
+
# Find field by title
|
|
31
|
+
field = await client.ticket_fields.get_by_title("Subscription")
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
http_client: "HTTPClient",
|
|
37
|
+
cache_config: Optional["CacheConfig"] = None,
|
|
38
|
+
) -> None:
|
|
39
|
+
"""Initialize TicketFieldsClient with optional caching."""
|
|
40
|
+
super().__init__(http_client, cache_config)
|
|
41
|
+
# Ticket fields change infrequently, use longer TTL (30 minutes)
|
|
42
|
+
if cache_config:
|
|
43
|
+
maxsize = getattr(cache_config, "ticket_field_maxsize", 200)
|
|
44
|
+
ttl = getattr(cache_config, "ticket_field_ttl", 1800)
|
|
45
|
+
else:
|
|
46
|
+
maxsize = 200
|
|
47
|
+
ttl = 1800
|
|
48
|
+
self.get: Callable[[int], TicketField] = self._create_cached_method(
|
|
49
|
+
self._get_impl, maxsize=maxsize, ttl=ttl
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
async def _get_impl(self, field_id: int) -> TicketField:
|
|
53
|
+
"""Get a specific ticket field by ID.
|
|
54
|
+
|
|
55
|
+
Results are cached for 30 minutes by default.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
field_id: The ticket field's ID
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
TicketField object
|
|
62
|
+
"""
|
|
63
|
+
response = await self._get(f"ticket_fields/{field_id}.json")
|
|
64
|
+
return TicketField(**response["ticket_field"])
|
|
65
|
+
|
|
66
|
+
def list(self, per_page: int = 100, limit: Optional[int] = None) -> "Paginator[TicketField]":
|
|
67
|
+
"""Get paginated list of all ticket fields.
|
|
68
|
+
|
|
69
|
+
Returns both system fields and custom fields.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
per_page: Number of fields per page (max 100)
|
|
73
|
+
limit: Maximum number of items to return when iterating (None = no limit)
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Paginator for iterating through all ticket fields
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
# Iterate through all fields
|
|
80
|
+
async for field in client.ticket_fields.list():
|
|
81
|
+
print(f"{field.title} ({field.type})")
|
|
82
|
+
|
|
83
|
+
# Collect to list
|
|
84
|
+
fields = await client.ticket_fields.list().collect()
|
|
85
|
+
"""
|
|
86
|
+
return ZendeskPaginator.create_ticket_fields_paginator(self._http, per_page=per_page, limit=limit)
|
|
87
|
+
|
|
88
|
+
async def get_by_title(self, title: str) -> Optional[TicketField]:
|
|
89
|
+
"""Find a ticket field by its title.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
title: The title of the ticket field (case-insensitive)
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
TicketField if found, None otherwise
|
|
96
|
+
"""
|
|
97
|
+
title_lower = title.lower()
|
|
98
|
+
async for field in self.list():
|
|
99
|
+
if field.title.lower() == title_lower:
|
|
100
|
+
return field
|
|
101
|
+
return None
|