python-zendesk-sdk 0.2.0__tar.gz → 0.3.1__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 (54) hide show
  1. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/PKG-INFO +246 -21
  2. python_zendesk_sdk-0.3.1/README.md +524 -0
  3. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/examples/basic_usage.py +9 -6
  4. python_zendesk_sdk-0.3.1/examples/caching.py +135 -0
  5. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/examples/enriched_tickets.py +1 -6
  6. python_zendesk_sdk-0.3.1/examples/search.py +215 -0
  7. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/pyproject.toml +2 -1
  8. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/__init__.py +26 -3
  9. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/client.py +11 -10
  10. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/clients/base.py +45 -2
  11. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/clients/help_center/__init__.py +12 -5
  12. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/clients/help_center/articles.py +20 -2
  13. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/clients/help_center/categories.py +20 -2
  14. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/clients/help_center/sections.py +20 -2
  15. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/clients/organizations.py +21 -19
  16. python_zendesk_sdk-0.3.1/src/zendesk_sdk/clients/search.py +310 -0
  17. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/clients/tickets.py +66 -33
  18. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/clients/users.py +29 -20
  19. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/config.py +32 -0
  20. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/models/__init__.py +19 -0
  21. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/models/comment.py +6 -0
  22. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/models/enriched_ticket.py +6 -0
  23. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/models/organization.py +4 -0
  24. python_zendesk_sdk-0.3.1/src/zendesk_sdk/models/search.py +507 -0
  25. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/models/ticket.py +7 -0
  26. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/models/user.py +6 -0
  27. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/pagination.py +89 -0
  28. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/tests/test_clients.py +22 -94
  29. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/tests/test_models.py +20 -19
  30. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/tests/test_package_import.py +1 -1
  31. python_zendesk_sdk-0.3.1/tests/test_search_query_config.py +568 -0
  32. python_zendesk_sdk-0.2.0/README.md +0 -300
  33. python_zendesk_sdk-0.2.0/src/zendesk_sdk/clients/search.py +0 -82
  34. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/.flake8 +0 -0
  35. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/.github/workflows/publish.yml +0 -0
  36. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/.gitignore +0 -0
  37. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/.python-version +0 -0
  38. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/LICENSE +0 -0
  39. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/examples/error_handling.py +0 -0
  40. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/examples/help_center.py +0 -0
  41. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/examples/pagination_example.py +0 -0
  42. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/clients/__init__.py +0 -0
  43. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/clients/attachments.py +0 -0
  44. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/exceptions.py +0 -0
  45. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/http_client.py +0 -0
  46. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/models/base.py +0 -0
  47. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/src/zendesk_sdk/models/help_center.py +0 -0
  48. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/tests/__init__.py +0 -0
  49. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/tests/test_client.py +0 -0
  50. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/tests/test_config.py +0 -0
  51. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/tests/test_exceptions.py +0 -0
  52. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/tests/test_help_center_client.py +0 -0
  53. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/tests/test_http_client.py +0 -0
  54. {python_zendesk_sdk-0.2.0 → python_zendesk_sdk-0.3.1}/tests/test_pagination.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-zendesk-sdk
3
- Version: 0.2.0
3
+ Version: 0.3.1
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
@@ -22,6 +22,7 @@ Classifier: Programming Language :: Python :: 3.12
22
22
  Classifier: Topic :: Internet :: WWW/HTTP
23
23
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
24
  Requires-Python: >=3.8.1
25
+ Requires-Dist: async-lru>=2.0.0
25
26
  Requires-Dist: httpx>=0.25.0
26
27
  Requires-Dist: pydantic>=2.0.0
27
28
  Provides-Extra: dev
@@ -37,17 +38,69 @@ Description-Content-Type: text/markdown
37
38
 
38
39
  # Python Zendesk SDK
39
40
 
40
- Modern Python SDK for Zendesk API with async support, full type safety, and comprehensive error handling.
41
+ [![PyPI](https://img.shields.io/pypi/v/python-zendesk-sdk)](https://pypi.org/project/python-zendesk-sdk/)
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)
44
+ [![License](https://img.shields.io/github/license/bormog/python-zendesk-sdk)](https://github.com/bormog/python-zendesk-sdk/blob/main/LICENSE)
45
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
46
+ [![Pydantic v2](https://img.shields.io/badge/Pydantic-v2-blue)](https://docs.pydantic.dev/)
47
+ [![Async](https://img.shields.io/badge/async-first-blueviolet)](https://docs.python.org/3/library/asyncio.html)
48
+
49
+ Modern Python SDK for Zendesk API, designed for automation and AI agents.
50
+
51
+ ## Table of Contents
52
+
53
+ - [Why This SDK?](#why-this-sdk)
54
+ - [Features](#features)
55
+ - [Installation](#installation)
56
+ - [Quick Start](#quick-start)
57
+ - [Configuration](#configuration)
58
+ - [API Methods](#api-methods)
59
+ - [Users](#users)
60
+ - [Organizations](#organizations)
61
+ - [Tickets](#tickets)
62
+ - [Comments](#comments-nested-under-tickets)
63
+ - [Tags](#tags-nested-under-tickets)
64
+ - [Enriched Tickets](#enriched-tickets)
65
+ - [Attachments](#attachments)
66
+ - [Search](#search)
67
+ - [Help Center](#help-center)
68
+ - [Error Handling](#error-handling)
69
+ - [Caching](#caching)
70
+ - [Examples](#examples)
71
+
72
+ ## Why This SDK?
73
+
74
+ Zendesk has a powerful REST API, but using it directly is painful:
75
+ - Multiple API calls needed to get complete ticket context (ticket + comments + users)
76
+ - No type safety — just raw JSON dictionaries
77
+ - Manual pagination handling
78
+ - Boilerplate retry/rate-limit logic in every project
79
+
80
+ **This SDK solves these problems** with a clean, typed interface optimized for:
81
+
82
+ - **Support automation** — workflows, triggers, integrations
83
+ - **Internal tools** — dashboards, reports, bulk operations
84
+ - **LLM agents** — Claude Code, Codex, custom AI assistants that need structured Zendesk access
85
+
86
+ ### Developer Experience
87
+
88
+ - **Predictable structure** — typed Pydantic models instead of arbitrary dicts
89
+ - **Complete context in one call** — `get_enriched()` returns ticket + all comments + all users
90
+ - **No boilerplate** — pagination, caching, and object loading handled automatically
91
+ - **Minimal API calls** — built-in caching and batching reduce redundant requests
92
+ - **Clear namespaces** — `client.tickets.comments.add()` is self-documenting
41
93
 
42
94
  ## Features
43
95
 
44
- - **Async HTTP Client**: Built on httpx with retry logic, rate limiting, and exponential backoff
45
- - **Type Safety**: Full Pydantic v2 models for Users, Organizations, Tickets, Comments, and Help Center
46
- - **Namespace Pattern**: Clean API organization (`client.users`, `client.tickets`, `client.help_center`)
96
+ - **Type Safety**: Full Pydantic v2 models for all Zendesk entities
97
+ - **Namespace Pattern**: Clean API `client.users`, `client.tickets`, `client.help_center`
98
+ - **Search**: Raw queries + type-safe SearchQueryConfig, export methods for large datasets
99
+ - **Pagination**: Offset-based and cursor-based (export) with async iterators
100
+ - **Caching**: TTL-based caching for users, organizations, and Help Center
47
101
  - **Help Center**: Full CRUD for Categories, Sections, and Articles
48
- - **Pagination**: Both offset-based and cursor-based pagination support
49
- - **Search**: Zendesk search API support
50
- - **Configuration**: Flexible configuration with environment variable support
102
+ - **Async HTTP**: Built on httpx with retry logic, rate limiting, exponential backoff
103
+ - **Configuration**: Environment variables or direct instantiation
51
104
 
52
105
  ## Installation
53
106
 
@@ -80,9 +133,8 @@ async def main():
80
133
  ticket = await client.tickets.get(12345)
81
134
  print(f"Ticket: {ticket.subject}")
82
135
 
83
- # Search tickets
84
- results = await client.search.tickets("status:open priority:high")
85
- for ticket in results:
136
+ # Search tickets (async iterator with auto-pagination)
137
+ async for ticket in client.search.tickets("status:open priority:high", limit=10):
86
138
  print(f"High priority: {ticket.subject}")
87
139
 
88
140
  asyncio.run(main())
@@ -117,7 +169,6 @@ config = ZendeskConfig() # Will load from environment
117
169
  user = await client.users.get(user_id) # Get user by ID
118
170
  paginator = await client.users.list() # List users with pagination
119
171
  user = await client.users.by_email(email) # Get user by email
120
- users = await client.users.search(query) # Search users
121
172
  users = await client.users.get_many([id1, id2]) # Get multiple users
122
173
  ```
123
174
 
@@ -125,7 +176,6 @@ users = await client.users.get_many([id1, id2]) # Get multiple users
125
176
  ```python
126
177
  org = await client.organizations.get(org_id) # Get organization by ID
127
178
  paginator = await client.organizations.list() # List organizations
128
- orgs = await client.organizations.search(query) # Search organizations
129
179
  ```
130
180
 
131
181
  ### Tickets
@@ -134,7 +184,6 @@ ticket = await client.tickets.get(ticket_id) # Get ticket by ID
134
184
  paginator = await client.tickets.list() # List tickets
135
185
  tickets = await client.tickets.for_user(user_id) # Get user's tickets
136
186
  tickets = await client.tickets.for_organization(org_id) # Get org's tickets
137
- tickets = await client.tickets.search(query) # Search tickets
138
187
  ```
139
188
 
140
189
  ### Comments (nested under tickets)
@@ -158,6 +207,8 @@ tags = await client.tickets.tags.remove(ticket_id, ["old"]) # Remove tags
158
207
  Load tickets with all related data (comments + users) in minimum API requests:
159
208
 
160
209
  ```python
210
+ from zendesk_sdk import SearchQueryConfig
211
+
161
212
  # Get ticket with all related data
162
213
  enriched = await client.tickets.get_enriched(12345)
163
214
 
@@ -169,9 +220,15 @@ for comment in enriched.comments:
169
220
  author = enriched.get_comment_author(comment)
170
221
  print(f"Comment by {author.name}: {comment.body[:50]}...")
171
222
 
172
- # Search with all data loaded
173
- results = await client.tickets.search_enriched("status:open")
174
- for item in results:
223
+ # Search with all data loaded (using SearchQueryConfig)
224
+ config = SearchQueryConfig.tickets(
225
+ status=["open"],
226
+ priority=["high", "urgent"],
227
+ organization_id=12345,
228
+ )
229
+
230
+ # search_enriched returns async iterator
231
+ async for item in client.tickets.search_enriched(config, limit=10):
175
232
  print(f"{item.ticket.subject} - {len(item.comments)} comments")
176
233
  ```
177
234
 
@@ -185,13 +242,120 @@ await client.tickets.comments.add(ticket_id, "See attached", uploads=[token])
185
242
  ```
186
243
 
187
244
  ### Search
245
+
246
+ All search methods return **async iterators** with automatic pagination.
247
+
248
+ #### Raw Queries (Zendesk syntax)
249
+
250
+ Use the same query syntax as in Zendesk UI — it just works:
251
+
252
+ ```python
253
+ # Tickets
254
+ async for ticket in client.search.tickets("status:open priority:high"):
255
+ print(ticket.subject)
256
+
257
+ # Users
258
+ async for user in client.search.users("role:admin"):
259
+ print(user.name)
260
+
261
+ # Organizations
262
+ async for org in client.search.organizations("tags:enterprise"):
263
+ print(org.name)
264
+
265
+ # Collect to list
266
+ all_tickets = [t async for t in client.search.tickets("status:pending", limit=100)]
267
+
268
+ # Search with enrichment (loads comments + users)
269
+ async for item in client.tickets.search_enriched("status:open", limit=10):
270
+ print(f"{item.ticket.subject} - {len(item.comments)} comments")
271
+ ```
272
+
273
+ #### SearchQueryConfig (typed alternative)
274
+
275
+ Don't want to memorize Zendesk query syntax? Use `SearchQueryConfig` — your IDE will autocomplete available fields:
276
+
188
277
  ```python
189
- paginator = await client.search.all(query) # General search
190
- tickets = await client.search.tickets(query) # Search tickets
191
- users = await client.search.users(query) # Search users
192
- orgs = await client.search.organizations(query) # Search organizations
278
+ from zendesk_sdk import SearchQueryConfig
279
+
280
+ config = SearchQueryConfig.tickets(
281
+ status=["open", "pending"],
282
+ priority=["high", "urgent"],
283
+ organization_id=12345,
284
+ created_after=date(2024, 1, 1),
285
+ tags=["vip"],
286
+ exclude_tags=["spam"],
287
+ )
288
+ async for ticket in client.search.tickets(config):
289
+ print(ticket.subject)
290
+
291
+ config = SearchQueryConfig.users(
292
+ role=["admin", "agent"],
293
+ is_verified=True,
294
+ )
295
+ async for user in client.search.users(config):
296
+ print(user.name)
297
+
298
+ config = SearchQueryConfig.organizations(tags=["enterprise"])
299
+ async for org in client.search.organizations(config):
300
+ print(org.name)
193
301
  ```
194
302
 
303
+ <details>
304
+ <summary>Available SearchQueryConfig fields</summary>
305
+
306
+ | Field | Type | Description |
307
+ |-------|------|-------------|
308
+ | `type` | SearchType | TICKET (default), USER, ORGANIZATION |
309
+ | `status` | List[str] | new, open, pending, hold, solved, closed |
310
+ | `priority` | List[str] | low, normal, high, urgent |
311
+ | `ticket_type` | List[str] | question, incident, problem, task |
312
+ | `organization_id` | int | Filter by organization |
313
+ | `requester_id` | int\|"me"\|"none" | Filter by requester |
314
+ | `assignee_id` | int\|"me"\|"none" | Filter by assignee |
315
+ | `group_id` | int | Filter by group |
316
+ | `tags` | List[str] | Include items with tags (OR) |
317
+ | `exclude_tags` | List[str] | Exclude items with tags |
318
+ | `created_after` | date | Created after date |
319
+ | `created_before` | date | Created before date |
320
+ | `updated_after` | date | Updated after date |
321
+ | `updated_before` | date | Updated before date |
322
+ | `via` | List[str] | Channel: email, web, chat, api, phone |
323
+ | `custom_fields` | Dict[int, Any] | Custom field values |
324
+ | `order_by` | str | Sort field |
325
+ | `sort` | str | asc or desc |
326
+
327
+ </details>
328
+
329
+ #### Export Search (No Zendesk Limit)
330
+
331
+ Regular search is capped at 1000 results by Zendesk. Export endpoint has **no such limit**:
332
+
333
+ ```python
334
+ # Export fetches ALL matching entities (no 1000 limit)
335
+ async for ticket in client.search.export_tickets("status:open"):
336
+ print(ticket.subject) # Will iterate through ALL open tickets
337
+
338
+ async for user in client.search.export_users():
339
+ print(user.name) # ALL users
340
+
341
+ async for org in client.search.export_organizations():
342
+ print(org.name) # ALL organizations
343
+
344
+ # Works with SearchQueryConfig too
345
+ config = SearchQueryConfig.tickets(status=["open"], priority=["high"])
346
+ async for ticket in client.search.export_tickets(config):
347
+ print(ticket.subject)
348
+
349
+ # With limit if you don't need everything
350
+ async for ticket in client.search.export_tickets("priority:high", limit=500):
351
+ print(ticket.subject)
352
+ ```
353
+
354
+ | Method | Zendesk Limit | Pagination | Duplicates |
355
+ |--------|---------------|------------|------------|
356
+ | `search.tickets()` | 1000 max | Offset | Possible |
357
+ | `search.export_tickets()` | None | Cursor | None |
358
+
195
359
  ### Help Center
196
360
 
197
361
  Access Help Center (Guide) via `client.help_center` namespace:
@@ -317,20 +481,81 @@ config = ZendeskConfig(
317
481
  )
318
482
  ```
319
483
 
484
+ ## Caching
485
+
486
+ The SDK includes built-in caching for frequently accessed resources. Caching is enabled by default and can be configured or disabled.
487
+
488
+ ### Default Cache Settings
489
+
490
+ | Resource | TTL | Max Size |
491
+ |----------|-----|----------|
492
+ | Users | 5 min | 1000 |
493
+ | Organizations | 10 min | 500 |
494
+ | Articles | 15 min | 500 |
495
+ | Categories | 30 min | 200 |
496
+ | Sections | 30 min | 200 |
497
+
498
+ ### Custom Cache Configuration
499
+
500
+ ```python
501
+ from zendesk_sdk import CacheConfig, ZendeskClient, ZendeskConfig
502
+
503
+ config = ZendeskConfig(
504
+ subdomain="mycompany",
505
+ email="user@example.com",
506
+ token="api_token",
507
+ cache=CacheConfig(
508
+ enabled=True,
509
+ user_ttl=60, # 1 minute
510
+ user_maxsize=100,
511
+ org_ttl=300, # 5 minutes
512
+ article_ttl=600, # 10 minutes
513
+ )
514
+ )
515
+ ```
516
+
517
+ ### Disable Caching
518
+
519
+ ```python
520
+ config = ZendeskConfig(
521
+ subdomain="mycompany",
522
+ email="user@example.com",
523
+ token="api_token",
524
+ cache=CacheConfig(enabled=False)
525
+ )
526
+ ```
527
+
528
+ ### Cache Control
529
+
530
+ ```python
531
+ # Check cache statistics
532
+ info = client.users.get.cache_info()
533
+ print(f"Hits: {info.hits}, Misses: {info.misses}")
534
+
535
+ # Clear all cached users
536
+ client.users.get.cache_clear()
537
+
538
+ # Invalidate specific entry
539
+ client.users.get.cache_invalidate(user_id)
540
+ ```
541
+
320
542
  ## Examples
321
543
 
322
544
  See the `examples/` directory for complete usage examples:
323
545
  - `basic_usage.py` - Basic configuration and API operations
546
+ - `search.py` - Type-safe search with SearchQueryConfig
324
547
  - `pagination_example.py` - Working with paginated results
325
548
  - `error_handling.py` - Error handling patterns
326
549
  - `enriched_tickets.py` - Loading tickets with related data
327
550
  - `help_center.py` - Help Center categories, sections, and articles
551
+ - `caching.py` - Cache configuration and usage
328
552
 
329
553
  ## Requirements
330
554
 
331
555
  - Python 3.8+
332
556
  - httpx
333
557
  - pydantic >=2.0
558
+ - async-lru
334
559
 
335
560
  ## License
336
561