python-zendesk-sdk 0.3.1__tar.gz → 0.4.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.
Files changed (53) hide show
  1. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/PKG-INFO +41 -27
  2. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/README.md +40 -26
  3. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/examples/basic_usage.py +7 -6
  4. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/examples/caching.py +3 -3
  5. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/examples/enriched_tickets.py +13 -19
  6. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/examples/error_handling.py +4 -3
  7. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/examples/help_center.py +22 -20
  8. python_zendesk_sdk-0.4.0/examples/pagination_example.py +106 -0
  9. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/examples/search.py +44 -9
  10. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/pyproject.toml +1 -1
  11. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/__init__.py +1 -1
  12. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/clients/attachments.py +1 -2
  13. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/clients/help_center/articles.py +30 -8
  14. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/clients/help_center/categories.py +12 -4
  15. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/clients/help_center/sections.py +20 -8
  16. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/clients/organizations.py +12 -6
  17. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/clients/search.py +121 -138
  18. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/clients/tickets.py +62 -92
  19. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/clients/users.py +12 -6
  20. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/models/ticket.py +14 -0
  21. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/pagination.py +224 -47
  22. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/tests/test_clients.py +35 -41
  23. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/tests/test_package_import.py +1 -1
  24. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/tests/test_pagination.py +23 -6
  25. python_zendesk_sdk-0.3.1/examples/pagination_example.py +0 -66
  26. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/.flake8 +0 -0
  27. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/.github/workflows/publish.yml +0 -0
  28. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/.gitignore +0 -0
  29. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/.python-version +0 -0
  30. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/LICENSE +0 -0
  31. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/client.py +0 -0
  32. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/clients/__init__.py +0 -0
  33. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/clients/base.py +0 -0
  34. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/clients/help_center/__init__.py +0 -0
  35. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/config.py +0 -0
  36. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/exceptions.py +0 -0
  37. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/http_client.py +0 -0
  38. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/models/__init__.py +0 -0
  39. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/models/base.py +0 -0
  40. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/models/comment.py +0 -0
  41. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/models/enriched_ticket.py +0 -0
  42. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/models/help_center.py +0 -0
  43. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/models/organization.py +0 -0
  44. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/models/search.py +0 -0
  45. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/src/zendesk_sdk/models/user.py +0 -0
  46. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/tests/__init__.py +0 -0
  47. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/tests/test_client.py +0 -0
  48. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/tests/test_config.py +0 -0
  49. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/tests/test_exceptions.py +0 -0
  50. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/tests/test_help_center_client.py +0 -0
  51. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/tests/test_http_client.py +0 -0
  52. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.0}/tests/test_models.py +0 -0
  53. {python_zendesk_sdk-0.3.1 → python_zendesk_sdk-0.4.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.1
3
+ Version: 0.4.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
@@ -40,7 +40,7 @@ Description-Content-Type: text/markdown
40
40
 
41
41
  [![PyPI](https://img.shields.io/pypi/v/python-zendesk-sdk)](https://pypi.org/project/python-zendesk-sdk/)
42
42
  [![Python](https://img.shields.io/pypi/pyversions/python-zendesk-sdk)](https://pypi.org/project/python-zendesk-sdk/)
43
- [![PyPI Downloads](https://static.pepy.tech/personalized-badge/python-zendesk-sdk?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/python-zendesk-sdk)
43
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/python-zendesk-sdk?period=total&units=INTERNATIONAL_SYSTEM&left_color=GREY&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/python-zendesk-sdk)
44
44
  [![License](https://img.shields.io/github/license/bormog/python-zendesk-sdk)](https://github.com/bormog/python-zendesk-sdk/blob/main/LICENSE)
45
45
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
46
46
  [![Pydantic v2](https://img.shields.io/badge/Pydantic-v2-blue)](https://docs.pydantic.dev/)
@@ -122,18 +122,15 @@ async def main():
122
122
  )
123
123
 
124
124
  async with ZendeskClient(config) as client:
125
- # Get users with pagination
126
- paginator = await client.users.list(per_page=10)
127
- users = await paginator.get_page()
128
-
129
- for user in users:
130
- print(f"User: {user['name']} ({user['email']})")
125
+ # Get a single user
126
+ user = await client.users.get(12345)
127
+ print(f"User: {user.name} ({user.email})")
131
128
 
132
129
  # Get specific ticket
133
130
  ticket = await client.tickets.get(12345)
134
131
  print(f"Ticket: {ticket.subject}")
135
132
 
136
- # Search tickets (async iterator with auto-pagination)
133
+ # Search tickets with pagination
137
134
  async for ticket in client.search.tickets("status:open priority:high", limit=10):
138
135
  print(f"High priority: {ticket.subject}")
139
136
 
@@ -164,31 +161,48 @@ config = ZendeskConfig() # Will load from environment
164
161
 
165
162
  ## API Methods
166
163
 
164
+ ### Pagination
165
+
166
+ All list methods return **Paginator** objects. Three ways to work with them:
167
+
168
+ ```python
169
+ # 1. Get specific page
170
+ paginator = client.users.list(per_page=20)
171
+ users = await paginator.get_page(2) # Get page 2
172
+
173
+ # 2. Iterate through all items
174
+ async for user in client.users.list():
175
+ print(user.name)
176
+
177
+ # 3. Collect to list
178
+ users = await client.users.list(limit=50).collect()
179
+ ```
180
+
167
181
  ### Users
168
182
  ```python
169
183
  user = await client.users.get(user_id) # Get user by ID
170
- paginator = await client.users.list() # List users with pagination
171
184
  user = await client.users.by_email(email) # Get user by email
172
185
  users = await client.users.get_many([id1, id2]) # Get multiple users
186
+ paginator = client.users.list() # List users (paginator)
173
187
  ```
174
188
 
175
189
  ### Organizations
176
190
  ```python
177
191
  org = await client.organizations.get(org_id) # Get organization by ID
178
- paginator = await client.organizations.list() # List organizations
192
+ paginator = client.organizations.list() # List organizations (paginator)
179
193
  ```
180
194
 
181
195
  ### Tickets
182
196
  ```python
183
197
  ticket = await client.tickets.get(ticket_id) # Get ticket by ID
184
- paginator = await client.tickets.list() # List tickets
185
- tickets = await client.tickets.for_user(user_id) # Get user's tickets
186
- tickets = await client.tickets.for_organization(org_id) # Get org's tickets
198
+ paginator = client.tickets.list() # List tickets (paginator)
199
+ paginator = client.tickets.for_user(user_id) # User's tickets (paginator)
200
+ paginator = client.tickets.for_organization(org_id) # Org's tickets (paginator)
187
201
  ```
188
202
 
189
203
  ### Comments (nested under tickets)
190
204
  ```python
191
- comments = await client.tickets.comments.list(ticket_id)
205
+ paginator = client.tickets.comments.list(ticket_id) # List comments (paginator)
192
206
  ticket = await client.tickets.comments.add(ticket_id, body, public=False)
193
207
  await client.tickets.comments.make_private(ticket_id, comment_id)
194
208
  comment = await client.tickets.comments.redact(ticket_id, comment_id, text)
@@ -243,14 +257,14 @@ await client.tickets.comments.add(ticket_id, "See attached", uploads=[token])
243
257
 
244
258
  ### Search
245
259
 
246
- All search methods return **async iterators** with automatic pagination.
260
+ All search methods return **Paginator** objects with the same interface as list methods.
247
261
 
248
262
  #### Raw Queries (Zendesk syntax)
249
263
 
250
264
  Use the same query syntax as in Zendesk UI — it just works:
251
265
 
252
266
  ```python
253
- # Tickets
267
+ # Tickets - iterate through results
254
268
  async for ticket in client.search.tickets("status:open priority:high"):
255
269
  print(ticket.subject)
256
270
 
@@ -262,8 +276,8 @@ async for user in client.search.users("role:admin"):
262
276
  async for org in client.search.organizations("tags:enterprise"):
263
277
  print(org.name)
264
278
 
265
- # Collect to list
266
- all_tickets = [t async for t in client.search.tickets("status:pending", limit=100)]
279
+ # Collect to list with limit
280
+ tickets = await client.search.tickets("status:pending", limit=100).collect()
267
281
 
268
282
  # Search with enrichment (loads comments + users)
269
283
  async for item in client.tickets.search_enriched("status:open", limit=10):
@@ -363,7 +377,7 @@ Access Help Center (Guide) via `client.help_center` namespace:
363
377
  #### Categories
364
378
  ```python
365
379
  cat = await client.help_center.categories.get(category_id)
366
- paginator = await client.help_center.categories.list()
380
+ paginator = client.help_center.categories.list() # Paginator
367
381
  cat = await client.help_center.categories.create(name, description)
368
382
  cat = await client.help_center.categories.update(category_id, name=new_name)
369
383
  await client.help_center.categories.delete(category_id, force=True)
@@ -372,8 +386,8 @@ await client.help_center.categories.delete(category_id, force=True)
372
386
  #### Sections
373
387
  ```python
374
388
  sec = await client.help_center.sections.get(section_id)
375
- paginator = await client.help_center.sections.list()
376
- paginator = await client.help_center.sections.for_category(category_id)
389
+ paginator = client.help_center.sections.list() # Paginator
390
+ paginator = client.help_center.sections.for_category(category_id)
377
391
  sec = await client.help_center.sections.create(category_id, name, description)
378
392
  sec = await client.help_center.sections.update(section_id, name=new_name)
379
393
  await client.help_center.sections.delete(section_id, force=True)
@@ -382,9 +396,9 @@ await client.help_center.sections.delete(section_id, force=True)
382
396
  #### Articles
383
397
  ```python
384
398
  art = await client.help_center.articles.get(article_id)
385
- paginator = await client.help_center.articles.list()
386
- paginator = await client.help_center.articles.for_section(section_id)
387
- paginator = await client.help_center.articles.for_category(category_id)
399
+ paginator = client.help_center.articles.list() # Paginator
400
+ paginator = client.help_center.articles.for_section(section_id)
401
+ paginator = client.help_center.articles.for_category(category_id)
388
402
  results = await client.help_center.articles.search(query)
389
403
  art = await client.help_center.articles.create(section_id, title, body=html)
390
404
  art = await client.help_center.articles.update(article_id, title=new_title)
@@ -397,8 +411,8 @@ async with ZendeskClient(config) as client:
397
411
  hc = client.help_center
398
412
 
399
413
  # Get permission_group_id from existing article (required for article creation)
400
- existing = await (await hc.articles.list(per_page=1)).get_page()
401
- article_details = await hc.articles.get(existing[0]["id"])
414
+ existing = await hc.articles.list(per_page=1).get_page()
415
+ article_details = await hc.articles.get(existing[0].id)
402
416
  permission_group_id = article_details.permission_group_id
403
417
 
404
418
  # Create category -> section -> article hierarchy
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![PyPI](https://img.shields.io/pypi/v/python-zendesk-sdk)](https://pypi.org/project/python-zendesk-sdk/)
4
4
  [![Python](https://img.shields.io/pypi/pyversions/python-zendesk-sdk)](https://pypi.org/project/python-zendesk-sdk/)
5
- [![PyPI Downloads](https://static.pepy.tech/personalized-badge/python-zendesk-sdk?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/python-zendesk-sdk)
5
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/python-zendesk-sdk?period=total&units=INTERNATIONAL_SYSTEM&left_color=GREY&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/python-zendesk-sdk)
6
6
  [![License](https://img.shields.io/github/license/bormog/python-zendesk-sdk)](https://github.com/bormog/python-zendesk-sdk/blob/main/LICENSE)
7
7
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
8
8
  [![Pydantic v2](https://img.shields.io/badge/Pydantic-v2-blue)](https://docs.pydantic.dev/)
@@ -84,18 +84,15 @@ async def main():
84
84
  )
85
85
 
86
86
  async with ZendeskClient(config) as client:
87
- # Get users with pagination
88
- paginator = await client.users.list(per_page=10)
89
- users = await paginator.get_page()
90
-
91
- for user in users:
92
- print(f"User: {user['name']} ({user['email']})")
87
+ # Get a single user
88
+ user = await client.users.get(12345)
89
+ print(f"User: {user.name} ({user.email})")
93
90
 
94
91
  # Get specific ticket
95
92
  ticket = await client.tickets.get(12345)
96
93
  print(f"Ticket: {ticket.subject}")
97
94
 
98
- # Search tickets (async iterator with auto-pagination)
95
+ # Search tickets with pagination
99
96
  async for ticket in client.search.tickets("status:open priority:high", limit=10):
100
97
  print(f"High priority: {ticket.subject}")
101
98
 
@@ -126,31 +123,48 @@ config = ZendeskConfig() # Will load from environment
126
123
 
127
124
  ## API Methods
128
125
 
126
+ ### Pagination
127
+
128
+ All list methods return **Paginator** objects. Three ways to work with them:
129
+
130
+ ```python
131
+ # 1. Get specific page
132
+ paginator = client.users.list(per_page=20)
133
+ users = await paginator.get_page(2) # Get page 2
134
+
135
+ # 2. Iterate through all items
136
+ async for user in client.users.list():
137
+ print(user.name)
138
+
139
+ # 3. Collect to list
140
+ users = await client.users.list(limit=50).collect()
141
+ ```
142
+
129
143
  ### Users
130
144
  ```python
131
145
  user = await client.users.get(user_id) # Get user by ID
132
- paginator = await client.users.list() # List users with pagination
133
146
  user = await client.users.by_email(email) # Get user by email
134
147
  users = await client.users.get_many([id1, id2]) # Get multiple users
148
+ paginator = client.users.list() # List users (paginator)
135
149
  ```
136
150
 
137
151
  ### Organizations
138
152
  ```python
139
153
  org = await client.organizations.get(org_id) # Get organization by ID
140
- paginator = await client.organizations.list() # List organizations
154
+ paginator = client.organizations.list() # List organizations (paginator)
141
155
  ```
142
156
 
143
157
  ### Tickets
144
158
  ```python
145
159
  ticket = await client.tickets.get(ticket_id) # Get ticket by ID
146
- paginator = await client.tickets.list() # List tickets
147
- tickets = await client.tickets.for_user(user_id) # Get user's tickets
148
- tickets = await client.tickets.for_organization(org_id) # Get org's tickets
160
+ paginator = client.tickets.list() # List tickets (paginator)
161
+ paginator = client.tickets.for_user(user_id) # User's tickets (paginator)
162
+ paginator = client.tickets.for_organization(org_id) # Org's tickets (paginator)
149
163
  ```
150
164
 
151
165
  ### Comments (nested under tickets)
152
166
  ```python
153
- comments = await client.tickets.comments.list(ticket_id)
167
+ paginator = client.tickets.comments.list(ticket_id) # List comments (paginator)
154
168
  ticket = await client.tickets.comments.add(ticket_id, body, public=False)
155
169
  await client.tickets.comments.make_private(ticket_id, comment_id)
156
170
  comment = await client.tickets.comments.redact(ticket_id, comment_id, text)
@@ -205,14 +219,14 @@ await client.tickets.comments.add(ticket_id, "See attached", uploads=[token])
205
219
 
206
220
  ### Search
207
221
 
208
- All search methods return **async iterators** with automatic pagination.
222
+ All search methods return **Paginator** objects with the same interface as list methods.
209
223
 
210
224
  #### Raw Queries (Zendesk syntax)
211
225
 
212
226
  Use the same query syntax as in Zendesk UI — it just works:
213
227
 
214
228
  ```python
215
- # Tickets
229
+ # Tickets - iterate through results
216
230
  async for ticket in client.search.tickets("status:open priority:high"):
217
231
  print(ticket.subject)
218
232
 
@@ -224,8 +238,8 @@ async for user in client.search.users("role:admin"):
224
238
  async for org in client.search.organizations("tags:enterprise"):
225
239
  print(org.name)
226
240
 
227
- # Collect to list
228
- all_tickets = [t async for t in client.search.tickets("status:pending", limit=100)]
241
+ # Collect to list with limit
242
+ tickets = await client.search.tickets("status:pending", limit=100).collect()
229
243
 
230
244
  # Search with enrichment (loads comments + users)
231
245
  async for item in client.tickets.search_enriched("status:open", limit=10):
@@ -325,7 +339,7 @@ Access Help Center (Guide) via `client.help_center` namespace:
325
339
  #### Categories
326
340
  ```python
327
341
  cat = await client.help_center.categories.get(category_id)
328
- paginator = await client.help_center.categories.list()
342
+ paginator = client.help_center.categories.list() # Paginator
329
343
  cat = await client.help_center.categories.create(name, description)
330
344
  cat = await client.help_center.categories.update(category_id, name=new_name)
331
345
  await client.help_center.categories.delete(category_id, force=True)
@@ -334,8 +348,8 @@ await client.help_center.categories.delete(category_id, force=True)
334
348
  #### Sections
335
349
  ```python
336
350
  sec = await client.help_center.sections.get(section_id)
337
- paginator = await client.help_center.sections.list()
338
- paginator = await client.help_center.sections.for_category(category_id)
351
+ paginator = client.help_center.sections.list() # Paginator
352
+ paginator = client.help_center.sections.for_category(category_id)
339
353
  sec = await client.help_center.sections.create(category_id, name, description)
340
354
  sec = await client.help_center.sections.update(section_id, name=new_name)
341
355
  await client.help_center.sections.delete(section_id, force=True)
@@ -344,9 +358,9 @@ await client.help_center.sections.delete(section_id, force=True)
344
358
  #### Articles
345
359
  ```python
346
360
  art = await client.help_center.articles.get(article_id)
347
- paginator = await client.help_center.articles.list()
348
- paginator = await client.help_center.articles.for_section(section_id)
349
- paginator = await client.help_center.articles.for_category(category_id)
361
+ paginator = client.help_center.articles.list() # Paginator
362
+ paginator = client.help_center.articles.for_section(section_id)
363
+ paginator = client.help_center.articles.for_category(category_id)
350
364
  results = await client.help_center.articles.search(query)
351
365
  art = await client.help_center.articles.create(section_id, title, body=html)
352
366
  art = await client.help_center.articles.update(article_id, title=new_title)
@@ -359,8 +373,8 @@ async with ZendeskClient(config) as client:
359
373
  hc = client.help_center
360
374
 
361
375
  # Get permission_group_id from existing article (required for article creation)
362
- existing = await (await hc.articles.list(per_page=1)).get_page()
363
- article_details = await hc.articles.get(existing[0]["id"])
376
+ existing = await hc.articles.list(per_page=1).get_page()
377
+ article_details = await hc.articles.get(existing[0].id)
364
378
  permission_group_id = article_details.permission_group_id
365
379
 
366
380
  # Create category -> section -> article hierarchy
@@ -3,6 +3,7 @@
3
3
  This example demonstrates:
4
4
  - Configuration setup
5
5
  - Basic API operations (get users, tickets, organizations)
6
+ - Pagination basics
6
7
  - Search functionality
7
8
  """
8
9
 
@@ -41,23 +42,23 @@ async def main() -> None:
41
42
  ticket = await client.tickets.get(12345)
42
43
  print(f"Ticket: {ticket.subject} (status: {ticket.status})")
43
44
 
44
- # Get ticket comments
45
- comments = await client.tickets.comments.list(12345)
46
- print(f"Ticket has {len(comments)} comments")
45
+ # Get ticket comments (returns paginator)
46
+ comments = await client.tickets.comments.list(12345, limit=10).collect()
47
+ print(f"Ticket has {len(comments)} comments (limited to 10)")
47
48
 
48
49
  # Get organization
49
50
  org = await client.organizations.get(123)
50
51
  print(f"Organization: {org.name}")
51
52
 
52
- # Search for tickets (returns async iterator)
53
+ # Search for tickets (paginator with async iteration)
53
54
  count = 0
54
55
  async for ticket in client.search.tickets("status:open", limit=10):
55
56
  count += 1
56
57
  print(f" Open ticket: {ticket.subject}")
57
58
  print(f"Found {count} open tickets (limited to 10)")
58
59
 
59
- # Search for users (returns async iterator)
60
- admins = [u async for u in client.search.users("role:admin", limit=5)]
60
+ # Collect search results to list
61
+ admins = await client.search.users("role:admin", limit=5).collect()
61
62
  print(f"Found {len(admins)} admin users (limited to 5)")
62
63
 
63
64
 
@@ -85,9 +85,9 @@ async def demo_disabled_cache() -> None:
85
85
  print(f"Cache enabled: {config.cache.enabled}")
86
86
 
87
87
  # Both calls hit the API
88
- user1 = await client.users.get(12345)
89
- user2 = await client.users.get(12345)
90
- print(f"Both calls hit API - no caching")
88
+ _ = await client.users.get(12345)
89
+ _ = await client.users.get(12345)
90
+ print("Both calls hit API - no caching")
91
91
 
92
92
  # cache_info not available when caching is disabled
93
93
  has_cache_info = hasattr(client.users.get, "cache_info")
@@ -19,6 +19,8 @@ async def main() -> None:
19
19
  )
20
20
 
21
21
  async with ZendeskClient(config) as client:
22
+ # ==================== Single enriched ticket ====================
23
+
22
24
  # Get a single ticket with all related data
23
25
  # This makes 2 API calls: ticket + comments (with sideloaded users)
24
26
  enriched = await client.tickets.get_enriched(12345)
@@ -48,6 +50,8 @@ async def main() -> None:
48
50
  else:
49
51
  print(f" - Unknown: {body_preview}")
50
52
 
53
+ # ==================== Search with enrichment ====================
54
+
51
55
  # Search for tickets and load all related data
52
56
  # This efficiently batch-loads users using show_many endpoint
53
57
  print("\n--- Searching tickets with enriched data ---")
@@ -57,25 +61,15 @@ async def main() -> None:
57
61
  print(f" Assignee: {item.assignee.name if item.assignee else 'Unassigned'}")
58
62
  print(f" Comments: {len(item.comments)}")
59
63
 
60
- # Get organization tickets with all related data
61
- print("\n--- Organization tickets ---")
62
- org_tickets = await client.tickets.for_organization_enriched(
63
- org_id=123,
64
- per_page=10,
65
- )
66
-
67
- for item in org_tickets:
68
- print(f"Ticket #{item.ticket.id}: {item.ticket.subject}")
69
-
70
- # Get user's tickets with all related data
71
- print("\n--- User tickets ---")
72
- user_tickets = await client.tickets.for_user_enriched(
73
- user_id=456,
74
- per_page=10,
75
- )
76
-
77
- for item in user_tickets:
78
- print(f"Ticket #{item.ticket.id}: {item.ticket.subject}")
64
+ # ==================== Collect enriched tickets ====================
65
+
66
+ # You can also collect enriched tickets to a list
67
+ print("\n--- Collecting enriched tickets ---")
68
+ enriched_tickets = [item async for item in client.tickets.search_enriched("status:pending", limit=5)]
69
+ print(f"Collected {len(enriched_tickets)} enriched tickets")
70
+
71
+ for item in enriched_tickets:
72
+ print(f" #{item.ticket.id}: {item.ticket.subject}")
79
73
 
80
74
 
81
75
  if __name__ == "__main__":
@@ -69,7 +69,7 @@ async def main() -> None:
69
69
 
70
70
  # Example: Handling specific HTTP status codes
71
71
  try:
72
- ticket = await client.tickets.get(123)
72
+ _ = await client.tickets.get(123)
73
73
  except ZendeskHTTPException as e:
74
74
  if e.status_code == 404:
75
75
  print("Ticket not found")
@@ -92,8 +92,9 @@ async def retry_with_backoff() -> None:
92
92
  max_attempts = 5
93
93
  for attempt in range(max_attempts):
94
94
  try:
95
- result = await client.search.tickets("status:open")
96
- print(f"Found {len(result)} tickets")
95
+ # Search returns paginator - iterate to get results
96
+ tickets = await client.search.tickets("status:open", limit=10).collect()
97
+ print(f"Found {len(tickets)} tickets")
97
98
  break
98
99
  except ZendeskRateLimitException as e:
99
100
  if attempt < max_attempts - 1:
@@ -26,34 +26,31 @@ async def main() -> None:
26
26
 
27
27
  # ==================== Reading Content ====================
28
28
 
29
- # List categories with pagination
29
+ # List categories with pagination (no await for list())
30
30
  print("--- Categories ---")
31
- categories_paginator = await hc.categories.list(per_page=10)
32
- categories = await categories_paginator.get_page()
31
+ categories = await hc.categories.list(per_page=10).get_page()
33
32
  for cat in categories[:5]:
34
- print(f"Category: {cat['name']} (ID: {cat['id']})")
33
+ print(f"Category: {cat.name} (ID: {cat.id})")
35
34
 
36
35
  # Get specific category
37
36
  if categories:
38
- category = await hc.categories.get(categories[0]["id"])
37
+ category = await hc.categories.get(categories[0].id)
39
38
  print(f"\nCategory details: {category.name}")
40
39
  print(f"Description: {category.description}")
41
40
 
42
41
  # List sections (all or by category)
43
42
  print("\n--- Sections ---")
44
- sections_paginator = await hc.sections.list(per_page=10)
45
- sections = await sections_paginator.get_page()
43
+ sections = await hc.sections.list(per_page=10).get_page()
46
44
  for sec in sections[:5]:
47
- print(f"Section: {sec['name']} (Category: {sec['category_id']})")
45
+ print(f"Section: {sec.name} (Category: {sec.category_id})")
48
46
 
49
47
  # List articles in a section
50
48
  if sections:
51
- section_id = sections[0]["id"]
52
- articles_paginator = await hc.articles.for_section(section_id, per_page=10)
53
- articles = await articles_paginator.get_page()
49
+ section_id = sections[0].id
50
+ articles = await hc.articles.for_section(section_id, per_page=10).get_page()
54
51
  print(f"\nArticles in section {section_id}:")
55
52
  for art in articles[:5]:
56
- print(f" - {art['title']}")
53
+ print(f" - {art.title}")
57
54
 
58
55
  # ==================== Search ====================
59
56
 
@@ -84,11 +81,11 @@ async def main() -> None:
84
81
  print(f"Created section: {new_section.name} (ID: {new_section.id})")
85
82
 
86
83
  # Get permission_group_id from an existing article (required for creation)
87
- existing_articles = await (await hc.articles.list(per_page=1)).get_page()
84
+ existing_articles = await hc.articles.list(per_page=1).get_page()
88
85
  if not existing_articles:
89
86
  print("No existing articles to get permission_group_id from")
90
87
  return
91
- existing = await hc.articles.get(existing_articles[0]["id"])
88
+ existing = await hc.articles.get(existing_articles[0].id)
92
89
  permission_group_id = existing.permission_group_id
93
90
 
94
91
  # Create an article in the section
@@ -129,20 +126,25 @@ async def main() -> None:
129
126
  await hc.categories.delete(new_category.id, force=True)
130
127
  print("Deleted category (cascade deleted section and article)")
131
128
 
132
- # ==================== Pagination ====================
129
+ # ==================== Pagination Examples ====================
133
130
 
134
- # Iterate through all articles with async for
135
- print("\n--- Pagination Example ---")
136
- all_articles_paginator = await hc.articles.list(per_page=10)
131
+ print("\n--- Pagination Examples ---")
132
+
133
+ # Iterate through all articles
137
134
  count = 0
138
- async for article_data in all_articles_paginator:
135
+ async for article in hc.articles.list(per_page=10):
139
136
  count += 1
140
137
  if count <= 3:
141
- print(f"Article {count}: {article_data['title'][:40]}...")
138
+ title = article.title[:40] if article.title else "Untitled"
139
+ print(f"Article {count}: {title}...")
142
140
  if count >= 10:
143
141
  print(f"... and more (stopped at {count})")
144
142
  break
145
143
 
144
+ # Collect articles to list
145
+ all_articles = await hc.articles.list(limit=50).collect()
146
+ print(f"Collected {len(all_articles)} articles")
147
+
146
148
 
147
149
  if __name__ == "__main__":
148
150
  asyncio.run(main())
@@ -0,0 +1,106 @@
1
+ """Pagination example for Zendesk SDK.
2
+
3
+ This example demonstrates three ways to work with paginators:
4
+ 1. Get specific page
5
+ 2. Iterate through all items
6
+ 3. Collect to list
7
+
8
+ All list() and search() methods return Paginator objects.
9
+ """
10
+
11
+ import asyncio
12
+
13
+ from zendesk_sdk import ZendeskClient, ZendeskConfig
14
+
15
+
16
+ async def main() -> None:
17
+ config = ZendeskConfig(
18
+ subdomain="your-subdomain",
19
+ email="your-email@example.com",
20
+ token="your-api-token",
21
+ )
22
+
23
+ async with ZendeskClient(config) as client:
24
+ # ==================== Method 1: Get specific page ====================
25
+
26
+ print("=== Method 1: Get specific page ===")
27
+
28
+ # Create paginator (no await needed)
29
+ paginator = client.users.list(per_page=20)
30
+
31
+ # Get first page
32
+ first_page = await paginator.get_page()
33
+ print(f"First page: {len(first_page)} users")
34
+
35
+ # Get specific page by number
36
+ second_page = await paginator.get_page(page=2)
37
+ print(f"Second page: {len(second_page)} users")
38
+
39
+ # Check pagination info after fetching
40
+ if paginator.pagination_info:
41
+ print(f"Total count: {paginator.pagination_info.count}")
42
+ print(f"Has more: {paginator.pagination_info.has_more}")
43
+
44
+ # ==================== Method 2: Iterate through all ====================
45
+
46
+ print("\n=== Method 2: Iterate through all items ===")
47
+
48
+ # Iterate through all users (handles pagination automatically)
49
+ count = 0
50
+ async for user in client.users.list(per_page=100):
51
+ count += 1
52
+ if count <= 3:
53
+ print(f" User: {user.name}")
54
+ if count >= 100:
55
+ print(f" ... stopping at {count} users")
56
+ break
57
+
58
+ print(f"Iterated through {count} users")
59
+
60
+ # ==================== Method 3: Collect to list ====================
61
+
62
+ print("\n=== Method 3: Collect to list ===")
63
+
64
+ # Collect with limit
65
+ users = await client.users.list(limit=50).collect()
66
+ print(f"Collected {len(users)} users (limit=50)")
67
+
68
+ # Collect all (be careful with large datasets!)
69
+ # all_users = await client.users.list().collect()
70
+
71
+ # ==================== Pagination with search ====================
72
+
73
+ print("\n=== Pagination with search ===")
74
+
75
+ # Search also returns paginator
76
+ paginator = client.search.tickets("status:open", per_page=50)
77
+
78
+ # Get first page
79
+ open_tickets = await paginator.get_page()
80
+ print(f"Found {len(open_tickets)} open tickets on first page")
81
+
82
+ # Or iterate
83
+ async for ticket in client.search.tickets("priority:high", limit=10):
84
+ print(f" High priority: {ticket.subject}")
85
+
86
+ # Or collect
87
+ urgent = await client.search.tickets("priority:urgent", limit=20).collect()
88
+ print(f"Collected {len(urgent)} urgent tickets")
89
+
90
+ # ==================== Pagination info ====================
91
+
92
+ print("\n=== Pagination info ===")
93
+
94
+ paginator = client.tickets.list(per_page=10)
95
+ await paginator.get_page()
96
+
97
+ info = paginator.pagination_info
98
+ if info:
99
+ print(f"Page: {info.page}")
100
+ print(f"Per page: {info.per_page}")
101
+ print(f"Total count: {info.count}")
102
+ print(f"Has more: {info.has_more}")
103
+
104
+
105
+ if __name__ == "__main__":
106
+ asyncio.run(main())