chub-dev 0.1.0 → 0.1.2-beta.0

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 (139) hide show
  1. package/README.md +55 -0
  2. package/bin/chub-mcp +2 -0
  3. package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
  4. package/dist/airtable/docs/database/python/DOC.md +1735 -0
  5. package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
  6. package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
  7. package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
  8. package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
  9. package/dist/asana/docs/tasks/DOC.md +1396 -0
  10. package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
  11. package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
  12. package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
  13. package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
  14. package/dist/auth0/docs/identity/python/DOC.md +1199 -0
  15. package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
  16. package/dist/aws/docs/s3/python/DOC.md +1807 -0
  17. package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
  18. package/dist/binance/docs/trading/python/DOC.md +1454 -0
  19. package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
  20. package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
  21. package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
  22. package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
  23. package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
  24. package/dist/clerk/docs/auth/python/DOC.md +274 -0
  25. package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
  26. package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
  27. package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
  28. package/dist/cohere/docs/llm/DOC.md +1335 -0
  29. package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
  30. package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
  31. package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
  32. package/dist/deepgram/docs/speech/python/DOC.md +685 -0
  33. package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
  34. package/dist/deepl/docs/translation/python/DOC.md +944 -0
  35. package/dist/deepseek/docs/llm/DOC.md +1220 -0
  36. package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
  37. package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
  38. package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
  39. package/dist/discord/docs/bot/python/DOC.md +1130 -0
  40. package/dist/elasticsearch/docs/search/DOC.md +1634 -0
  41. package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
  42. package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
  43. package/dist/firebase/docs/auth/DOC.md +1015 -0
  44. package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
  45. package/dist/gemini/docs/genai/python/DOC.md +555 -0
  46. package/dist/github/docs/octokit/DOC.md +1560 -0
  47. package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
  48. package/dist/google/docs/bigquery/python/DOC.md +1503 -0
  49. package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
  50. package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
  51. package/dist/huggingface/docs/transformers/DOC.md +948 -0
  52. package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
  53. package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
  54. package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
  55. package/dist/jira/docs/issues/python/DOC.md +1492 -0
  56. package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
  57. package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
  58. package/dist/landingai-ade/docs/api/DOC.md +620 -0
  59. package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
  60. package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
  61. package/dist/landingai-ade/skills/SKILL.md +489 -0
  62. package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
  63. package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
  64. package/dist/linear/docs/tracker/DOC.md +1554 -0
  65. package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
  66. package/dist/livekit/docs/realtime/python/DOC.md +163 -0
  67. package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
  68. package/dist/meilisearch/docs/search/DOC.md +1241 -0
  69. package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
  70. package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
  71. package/dist/mongodb/docs/atlas/DOC.md +2041 -0
  72. package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
  73. package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
  74. package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
  75. package/dist/okta/docs/identity/python/DOC.md +1401 -0
  76. package/dist/openai/docs/chat/javascript/DOC.md +407 -0
  77. package/dist/openai/docs/chat/python/DOC.md +568 -0
  78. package/dist/paypal/docs/checkout/DOC.md +278 -0
  79. package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
  80. package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
  81. package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
  82. package/dist/plaid/docs/banking/python/DOC.md +1203 -0
  83. package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
  84. package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
  85. package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
  86. package/dist/prisma/docs/orm/python/DOC.md +1317 -0
  87. package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
  88. package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
  89. package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
  90. package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
  91. package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
  92. package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
  93. package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
  94. package/dist/redis/docs/key-value/python/DOC.md +2054 -0
  95. package/dist/registry.json +2817 -0
  96. package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
  97. package/dist/resend/docs/email/DOC.md +1271 -0
  98. package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
  99. package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
  100. package/dist/search-index.json +1 -0
  101. package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
  102. package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
  103. package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
  104. package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
  105. package/dist/shopify/docs/storefront/DOC.md +457 -0
  106. package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
  107. package/dist/slack/docs/workspace/python/DOC.md +271 -0
  108. package/dist/square/docs/payments/javascript/DOC.md +1855 -0
  109. package/dist/square/docs/payments/python/DOC.md +1728 -0
  110. package/dist/stripe/docs/api/DOC.md +1727 -0
  111. package/dist/stripe/docs/payments/DOC.md +1726 -0
  112. package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
  113. package/dist/stytch/docs/auth/python/DOC.md +1962 -0
  114. package/dist/supabase/docs/client/DOC.md +1606 -0
  115. package/dist/twilio/docs/messaging/python/DOC.md +469 -0
  116. package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
  117. package/dist/vercel/docs/platform/DOC.md +1940 -0
  118. package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
  119. package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
  120. package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
  121. package/dist/zendesk/docs/support/python/DOC.md +2297 -0
  122. package/package.json +22 -6
  123. package/skills/get-api-docs/SKILL.md +84 -0
  124. package/src/commands/annotate.js +83 -0
  125. package/src/commands/build.js +12 -1
  126. package/src/commands/feedback.js +150 -0
  127. package/src/commands/get.js +83 -42
  128. package/src/commands/search.js +7 -0
  129. package/src/index.js +43 -17
  130. package/src/lib/analytics.js +90 -0
  131. package/src/lib/annotations.js +57 -0
  132. package/src/lib/bm25.js +170 -0
  133. package/src/lib/cache.js +69 -6
  134. package/src/lib/config.js +8 -3
  135. package/src/lib/identity.js +99 -0
  136. package/src/lib/registry.js +103 -20
  137. package/src/lib/telemetry.js +86 -0
  138. package/src/mcp/server.js +177 -0
  139. package/src/mcp/tools.js +251 -0
@@ -0,0 +1,1276 @@
1
+ ---
2
+ name: headless-cms
3
+ description: "Directus Python SDK coding guidelines for interacting with Directus projects using the py-directus library"
4
+ metadata:
5
+ languages: "python"
6
+ versions: "0.0.30"
7
+ updated-on: "2026-03-02"
8
+ source: maintainer
9
+ tags: "directus,headless-cms,api,content,backend"
10
+ ---
11
+
12
+ # Directus Python SDK Coding Guidelines
13
+
14
+ You are a Directus Python SDK coding expert. Help me with writing code using the Directus Python SDK calling the official libraries.
15
+
16
+ You can find the official SDK documentation and code samples here:
17
+ https://panos-stavrianos.github.io/py-directus/
18
+
19
+ ## Golden Rule: Use the Correct and Current SDK
20
+
21
+ Always use the py-directus library to interact with Directus projects in Python. This is a community-maintained async Python wrapper for the Directus API. Do not use outdated or unmaintained libraries.
22
+
23
+ - **Library Name:** py-directus
24
+ - **PyPI Package:** `py-directus`
25
+ - **Alternative Libraries:** `directus-sdk-py`, `pydirectus-sdk` (less maintained)
26
+
27
+ **Installation:**
28
+
29
+ - **Correct:** `pip install py-directus`
30
+ - **Incorrect:** `pip install directus`
31
+ - **Incorrect:** `pip install directus-python`
32
+
33
+ **APIs and Usage:**
34
+
35
+ - **Correct:** `from py_directus import Directus`
36
+ - **Correct:** `directus = await Directus(url, email, password)`
37
+ - **Correct:** `await directus.collection("articles").read()`
38
+ - **Incorrect:** `DirectusClient` or `DirectusAPI`
39
+ - **Incorrect:** Synchronous API calls without `await`
40
+
41
+ ## Installation
42
+
43
+ Install py-directus using pip:
44
+
45
+ ```bash
46
+ pip install py-directus
47
+ ```
48
+
49
+ ## Initialization and Authentication
50
+
51
+ The `py-directus` library is fully asynchronous and requires using `async`/`await` syntax. The library requires creating a Directus instance with authentication.
52
+
53
+ ### Authentication with Email and Password
54
+
55
+ ```python
56
+ from py_directus import Directus
57
+
58
+ async def main():
59
+ directus = await Directus(
60
+ url="https://your-directus-instance.com",
61
+ email="user@example.com",
62
+ password="your-password"
63
+ )
64
+
65
+ # Use directus client
66
+ # ...
67
+
68
+ # Run the async function
69
+ import asyncio
70
+ asyncio.run(main())
71
+ ```
72
+
73
+ ### Authentication with Static Token
74
+
75
+ ```python
76
+ from py_directus import Directus
77
+
78
+ async def main():
79
+ directus = await Directus(
80
+ url="https://your-directus-instance.com",
81
+ token="your-static-token"
82
+ )
83
+
84
+ # Use directus client
85
+
86
+ import asyncio
87
+ asyncio.run(main())
88
+ ```
89
+
90
+ ### Using Context Manager
91
+
92
+ ```python
93
+ from py_directus import Directus
94
+
95
+ async def main():
96
+ async with await Directus(
97
+ url="https://your-directus-instance.com",
98
+ email="user@example.com",
99
+ password="your-password"
100
+ ) as directus:
101
+ # Use directus client
102
+ users = await directus.collection("directus_users").read()
103
+
104
+ import asyncio
105
+ asyncio.run(main())
106
+ ```
107
+
108
+ ### With Environment Variables
109
+
110
+ ```python
111
+ import os
112
+ from py_directus import Directus
113
+
114
+ async def main():
115
+ directus = await Directus(
116
+ url=os.getenv("DIRECTUS_URL"),
117
+ token=os.getenv("DIRECTUS_TOKEN")
118
+ )
119
+
120
+ # Use directus client
121
+
122
+ import asyncio
123
+ asyncio.run(main())
124
+ ```
125
+
126
+ ## Reading Items from Collections
127
+
128
+ ### Read All Items
129
+
130
+ ```python
131
+ from py_directus import Directus
132
+
133
+ async def main():
134
+ directus = await Directus(
135
+ url="https://your-directus-instance.com",
136
+ token="your-token"
137
+ )
138
+
139
+ # Read all items from a collection
140
+ response = await directus.collection("articles").read()
141
+ articles = response.items
142
+
143
+ for article in articles:
144
+ print(article)
145
+
146
+ import asyncio
147
+ asyncio.run(main())
148
+ ```
149
+
150
+ ### Read Single Item
151
+
152
+ ```python
153
+ from py_directus import Directus
154
+
155
+ async def main():
156
+ directus = await Directus(
157
+ url="https://your-directus-instance.com",
158
+ token="your-token"
159
+ )
160
+
161
+ # Read single item by ID
162
+ response = await directus.collection("articles").read(id="1")
163
+ article = response.item
164
+
165
+ print(article)
166
+
167
+ import asyncio
168
+ asyncio.run(main())
169
+ ```
170
+
171
+ ### Read with Field Selection
172
+
173
+ ```python
174
+ from py_directus import Directus
175
+
176
+ async def main():
177
+ directus = await Directus(
178
+ url="https://your-directus-instance.com",
179
+ token="your-token"
180
+ )
181
+
182
+ # Select specific fields
183
+ response = await directus.collection("articles").fields("id", "title", "author.name").read()
184
+ articles = response.items
185
+
186
+ import asyncio
187
+ asyncio.run(main())
188
+ ```
189
+
190
+ ### Read with Limit and Offset
191
+
192
+ ```python
193
+ from py_directus import Directus
194
+
195
+ async def main():
196
+ directus = await Directus(
197
+ url="https://your-directus-instance.com",
198
+ token="your-token"
199
+ )
200
+
201
+ # Pagination
202
+ response = await directus.collection("articles").limit(10).offset(20).read()
203
+ articles = response.items
204
+
205
+ import asyncio
206
+ asyncio.run(main())
207
+ ```
208
+
209
+ ## Filtering Items
210
+
211
+ ### Simple Filter
212
+
213
+ ```python
214
+ from py_directus import Directus
215
+
216
+ async def main():
217
+ directus = await Directus(
218
+ url="https://your-directus-instance.com",
219
+ token="your-token"
220
+ )
221
+
222
+ # Filter by field value
223
+ response = await directus.collection("articles").filter(status="published").read()
224
+ articles = response.items
225
+
226
+ import asyncio
227
+ asyncio.run(main())
228
+ ```
229
+
230
+ ### Multiple Filters (AND)
231
+
232
+ ```python
233
+ from py_directus import Directus
234
+
235
+ async def main():
236
+ directus = await Directus(
237
+ url="https://your-directus-instance.com",
238
+ token="your-token"
239
+ )
240
+
241
+ # Multiple filters are combined with AND
242
+ response = await (
243
+ directus.collection("articles")
244
+ .filter(status="published")
245
+ .filter(views__gte=1000)
246
+ .read()
247
+ )
248
+ articles = response.items
249
+
250
+ import asyncio
251
+ asyncio.run(main())
252
+ ```
253
+
254
+ ### Complex Filters with F Object
255
+
256
+ ```python
257
+ from py_directus import Directus, F
258
+
259
+ async def main():
260
+ directus = await Directus(
261
+ url="https://your-directus-instance.com",
262
+ token="your-token"
263
+ )
264
+
265
+ # OR conditions
266
+ response = await (
267
+ directus.collection("users")
268
+ .filter(F(first_name="John") | F(first_name="Jane"))
269
+ .read()
270
+ )
271
+
272
+ # Complex nested conditions
273
+ response = await (
274
+ directus.collection("articles")
275
+ .filter(
276
+ (F(status="published") | F(status="archived"))
277
+ & F(views__gte=100)
278
+ )
279
+ .read()
280
+ )
281
+ articles = response.items
282
+
283
+ import asyncio
284
+ asyncio.run(main())
285
+ ```
286
+
287
+ ### Filter Operators
288
+
289
+ ```python
290
+ from py_directus import Directus
291
+
292
+ async def main():
293
+ directus = await Directus(
294
+ url="https://your-directus-instance.com",
295
+ token="your-token"
296
+ )
297
+
298
+ # Greater than
299
+ response = await directus.collection("articles").filter(views__gt=1000).read()
300
+
301
+ # Greater than or equal
302
+ response = await directus.collection("articles").filter(views__gte=1000).read()
303
+
304
+ # Less than
305
+ response = await directus.collection("articles").filter(views__lt=1000).read()
306
+
307
+ # Less than or equal
308
+ response = await directus.collection("articles").filter(views__lte=1000).read()
309
+
310
+ # Not equal
311
+ response = await directus.collection("articles").filter(status__neq="draft").read()
312
+
313
+ # Contains
314
+ response = await directus.collection("articles").filter(title__contains="directus").read()
315
+
316
+ # In list
317
+ response = await directus.collection("articles").filter(status__in=["published", "archived"]).read()
318
+
319
+ # Not in list
320
+ response = await directus.collection("articles").filter(status__nin=["draft", "deleted"]).read()
321
+
322
+ # Is null
323
+ response = await directus.collection("articles").filter(author__null=True).read()
324
+
325
+ # Is not null
326
+ response = await directus.collection("articles").filter(author__nnull=True).read()
327
+
328
+ import asyncio
329
+ asyncio.run(main())
330
+ ```
331
+
332
+ ## Sorting Items
333
+
334
+ ### Single Sort
335
+
336
+ ```python
337
+ from py_directus import Directus
338
+
339
+ async def main():
340
+ directus = await Directus(
341
+ url="https://your-directus-instance.com",
342
+ token="your-token"
343
+ )
344
+
345
+ # Sort ascending
346
+ response = await directus.collection("articles").sort("title").read()
347
+
348
+ # Sort descending
349
+ response = await directus.collection("articles").sort("-publish_date").read()
350
+
351
+ import asyncio
352
+ asyncio.run(main())
353
+ ```
354
+
355
+ ### Multiple Sorts
356
+
357
+ ```python
358
+ from py_directus import Directus
359
+
360
+ async def main():
361
+ directus = await Directus(
362
+ url="https://your-directus-instance.com",
363
+ token="your-token"
364
+ )
365
+
366
+ # Multiple sort fields
367
+ response = await directus.collection("articles").sort("-publish_date", "title").read()
368
+
369
+ import asyncio
370
+ asyncio.run(main())
371
+ ```
372
+
373
+ ## Searching Items
374
+
375
+ ```python
376
+ from py_directus import Directus
377
+
378
+ async def main():
379
+ directus = await Directus(
380
+ url="https://your-directus-instance.com",
381
+ token="your-token"
382
+ )
383
+
384
+ # Full-text search
385
+ response = await directus.collection("articles").search("directus cms").read()
386
+ articles = response.items
387
+
388
+ import asyncio
389
+ asyncio.run(main())
390
+ ```
391
+
392
+ ## Creating Items
393
+
394
+ ### Create Single Item
395
+
396
+ ```python
397
+ from py_directus import Directus
398
+
399
+ async def main():
400
+ directus = await Directus(
401
+ url="https://your-directus-instance.com",
402
+ token="your-token"
403
+ )
404
+
405
+ # Create a new item
406
+ new_article = {
407
+ "title": "New Article",
408
+ "content": "Article content here",
409
+ "status": "draft"
410
+ }
411
+
412
+ response = await directus.collection("articles").create(new_article)
413
+ created_article = response.item
414
+
415
+ print(f"Created article with ID: {created_article['id']}")
416
+
417
+ import asyncio
418
+ asyncio.run(main())
419
+ ```
420
+
421
+ ### Create Multiple Items
422
+
423
+ ```python
424
+ from py_directus import Directus
425
+
426
+ async def main():
427
+ directus = await Directus(
428
+ url="https://your-directus-instance.com",
429
+ token="your-token"
430
+ )
431
+
432
+ # Create multiple items
433
+ new_articles = [
434
+ {"title": "Article 1", "status": "draft"},
435
+ {"title": "Article 2", "status": "draft"},
436
+ {"title": "Article 3", "status": "published"}
437
+ ]
438
+
439
+ response = await directus.collection("articles").create(new_articles)
440
+ created_articles = response.items
441
+
442
+ import asyncio
443
+ asyncio.run(main())
444
+ ```
445
+
446
+ ## Updating Items
447
+
448
+ ### Update Single Item
449
+
450
+ ```python
451
+ from py_directus import Directus
452
+
453
+ async def main():
454
+ directus = await Directus(
455
+ url="https://your-directus-instance.com",
456
+ token="your-token"
457
+ )
458
+
459
+ # Update an item by ID
460
+ updated_data = {
461
+ "status": "published",
462
+ "publish_date": "2024-01-15"
463
+ }
464
+
465
+ response = await directus.collection("articles").update("1", updated_data)
466
+ updated_article = response.item
467
+
468
+ import asyncio
469
+ asyncio.run(main())
470
+ ```
471
+
472
+ ### Update Multiple Items
473
+
474
+ ```python
475
+ from py_directus import Directus
476
+
477
+ async def main():
478
+ directus = await Directus(
479
+ url="https://your-directus-instance.com",
480
+ token="your-token"
481
+ )
482
+
483
+ # Update multiple items by IDs
484
+ item_ids = ["1", "2", "3"]
485
+ updated_data = {"status": "published"}
486
+
487
+ response = await directus.collection("articles").update(item_ids, updated_data)
488
+ updated_articles = response.items
489
+
490
+ import asyncio
491
+ asyncio.run(main())
492
+ ```
493
+
494
+ ## Deleting Items
495
+
496
+ ### Delete Single Item
497
+
498
+ ```python
499
+ from py_directus import Directus
500
+
501
+ async def main():
502
+ directus = await Directus(
503
+ url="https://your-directus-instance.com",
504
+ token="your-token"
505
+ )
506
+
507
+ # Delete an item by ID
508
+ await directus.collection("articles").delete("1")
509
+
510
+ import asyncio
511
+ asyncio.run(main())
512
+ ```
513
+
514
+ ### Delete Multiple Items
515
+
516
+ ```python
517
+ from py_directus import Directus
518
+
519
+ async def main():
520
+ directus = await Directus(
521
+ url="https://your-directus-instance.com",
522
+ token="your-token"
523
+ )
524
+
525
+ # Delete multiple items by IDs
526
+ await directus.collection("articles").delete(["1", "2", "3"])
527
+
528
+ import asyncio
529
+ asyncio.run(main())
530
+ ```
531
+
532
+ ## Aggregation
533
+
534
+ ### Count Items
535
+
536
+ ```python
537
+ from py_directus import Directus
538
+
539
+ async def main():
540
+ directus = await Directus(
541
+ url="https://your-directus-instance.com",
542
+ token="your-token"
543
+ )
544
+
545
+ # Count all items
546
+ response = await directus.collection("articles").aggregate(count="id").read()
547
+ total_count = response.items[0]["count"]["id"]
548
+
549
+ print(f"Total articles: {total_count}")
550
+
551
+ import asyncio
552
+ asyncio.run(main())
553
+ ```
554
+
555
+ ### Count Distinct
556
+
557
+ ```python
558
+ from py_directus import Directus
559
+
560
+ async def main():
561
+ directus = await Directus(
562
+ url="https://your-directus-instance.com",
563
+ token="your-token"
564
+ )
565
+
566
+ # Count distinct values
567
+ response = await directus.collection("articles").aggregate(countDistinct="author").read()
568
+
569
+ import asyncio
570
+ asyncio.run(main())
571
+ ```
572
+
573
+ ### Sum, Average, Min, Max
574
+
575
+ ```python
576
+ from py_directus import Directus
577
+
578
+ async def main():
579
+ directus = await Directus(
580
+ url="https://your-directus-instance.com",
581
+ token="your-token"
582
+ )
583
+
584
+ # Sum
585
+ response = await directus.collection("articles").aggregate(sum="views").read()
586
+ total_views = response.items[0]["sum"]["views"]
587
+
588
+ # Average
589
+ response = await directus.collection("articles").aggregate(avg="views").read()
590
+ avg_views = response.items[0]["avg"]["views"]
591
+
592
+ # Min
593
+ response = await directus.collection("articles").aggregate(min="views").read()
594
+ min_views = response.items[0]["min"]["views"]
595
+
596
+ # Max
597
+ response = await directus.collection("articles").aggregate(max="views").read()
598
+ max_views = response.items[0]["max"]["views"]
599
+
600
+ import asyncio
601
+ asyncio.run(main())
602
+ ```
603
+
604
+ ### Multiple Aggregations
605
+
606
+ ```python
607
+ from py_directus import Directus
608
+
609
+ async def main():
610
+ directus = await Directus(
611
+ url="https://your-directus-instance.com",
612
+ token="your-token"
613
+ )
614
+
615
+ # Chain multiple aggregations
616
+ response = await (
617
+ directus.collection("articles")
618
+ .aggregate(count="id")
619
+ .aggregate(sum="views")
620
+ .aggregate(avg="views")
621
+ .read()
622
+ )
623
+
624
+ result = response.items[0]
625
+ print(f"Count: {result['count']['id']}")
626
+ print(f"Total views: {result['sum']['views']}")
627
+ print(f"Average views: {result['avg']['views']}")
628
+
629
+ import asyncio
630
+ asyncio.run(main())
631
+ ```
632
+
633
+ ### Aggregation with Agg Class
634
+
635
+ ```python
636
+ from py_directus import Directus, Agg, AggregationOperators
637
+
638
+ async def main():
639
+ directus = await Directus(
640
+ url="https://your-directus-instance.com",
641
+ token="your-token"
642
+ )
643
+
644
+ # Using Agg class for aggregations
645
+ sum_agg = Agg(operator=AggregationOperators.Sum, fields="amount")
646
+ avg_agg = Agg(operator=AggregationOperators.Avg, fields="amount")
647
+
648
+ response = await (
649
+ directus.collection("transactions")
650
+ .aggregate(sum_agg)
651
+ .aggregate(avg_agg)
652
+ .read()
653
+ )
654
+
655
+ import asyncio
656
+ asyncio.run(main())
657
+ ```
658
+
659
+ ### Group By
660
+
661
+ ```python
662
+ from py_directus import Directus
663
+
664
+ async def main():
665
+ directus = await Directus(
666
+ url="https://your-directus-instance.com",
667
+ token="your-token"
668
+ )
669
+
670
+ # Group by single field
671
+ response = await (
672
+ directus.collection("articles")
673
+ .aggregate(count="id")
674
+ .groupby("status")
675
+ .read()
676
+ )
677
+
678
+ # Group by multiple fields
679
+ response = await (
680
+ directus.collection("articles")
681
+ .aggregate(count="id")
682
+ .aggregate(avg="views")
683
+ .groupby("status", "author")
684
+ .read()
685
+ )
686
+
687
+ import asyncio
688
+ asyncio.run(main())
689
+ ```
690
+
691
+ ## Working with Pydantic Models
692
+
693
+ ### Using Built-in Models
694
+
695
+ ```python
696
+ from py_directus import Directus, DirectusUser
697
+
698
+ async def main():
699
+ directus = await Directus(
700
+ url="https://your-directus-instance.com",
701
+ token="your-token"
702
+ )
703
+
704
+ # Using DirectusUser model
705
+ response = await (
706
+ directus.collection(DirectusUser)
707
+ .filter(first_name="John")
708
+ .read()
709
+ )
710
+
711
+ # Response items are typed as DirectusUser objects
712
+ user = response.item
713
+ print(user.email)
714
+ print(user.first_name)
715
+ print(user.last_name)
716
+
717
+ import asyncio
718
+ asyncio.run(main())
719
+ ```
720
+
721
+ ### Creating Custom Pydantic Models
722
+
723
+ ```python
724
+ from py_directus import Directus
725
+ from pydantic import BaseModel
726
+ from typing import Optional
727
+
728
+ class Article(BaseModel):
729
+ id: Optional[str] = None
730
+ title: str
731
+ content: str
732
+ status: str
733
+ author: Optional[str] = None
734
+ views: int = 0
735
+
736
+ async def main():
737
+ directus = await Directus(
738
+ url="https://your-directus-instance.com",
739
+ token="your-token"
740
+ )
741
+
742
+ # Using custom model - collection name inferred from class name
743
+ response = await directus.collection(Article).read()
744
+ articles = response.items
745
+
746
+ # Type-safe access
747
+ for article in articles:
748
+ print(article.title)
749
+ print(article.status)
750
+
751
+ import asyncio
752
+ asyncio.run(main())
753
+ ```
754
+
755
+ ## File Management
756
+
757
+ ### Upload File
758
+
759
+ ```python
760
+ from py_directus import Directus
761
+ import aiofiles
762
+
763
+ async def main():
764
+ directus = await Directus(
765
+ url="https://your-directus-instance.com",
766
+ token="your-token"
767
+ )
768
+
769
+ # Upload a file
770
+ async with aiofiles.open("image.jpg", "rb") as f:
771
+ file_data = await f.read()
772
+
773
+ response = await directus.upload_file(
774
+ data=file_data,
775
+ filename="image.jpg",
776
+ title="My Image",
777
+ folder="folder-uuid"
778
+ )
779
+
780
+ uploaded_file = response.item
781
+ print(f"Uploaded file ID: {uploaded_file['id']}")
782
+
783
+ import asyncio
784
+ asyncio.run(main())
785
+ ```
786
+
787
+ ### Read Files
788
+
789
+ ```python
790
+ from py_directus import Directus
791
+
792
+ async def main():
793
+ directus = await Directus(
794
+ url="https://your-directus-instance.com",
795
+ token="your-token"
796
+ )
797
+
798
+ # Read all files
799
+ response = await directus.collection("directus_files").read()
800
+ files = response.items
801
+
802
+ # Filter image files
803
+ response = await (
804
+ directus.collection("directus_files")
805
+ .filter(type__starts_with="image/")
806
+ .read()
807
+ )
808
+
809
+ import asyncio
810
+ asyncio.run(main())
811
+ ```
812
+
813
+ ### Get File URL
814
+
815
+ ```python
816
+ from py_directus import Directus
817
+
818
+ async def main():
819
+ directus = await Directus(
820
+ url="https://your-directus-instance.com",
821
+ token="your-token"
822
+ )
823
+
824
+ file_id = "file-uuid"
825
+
826
+ # Construct file URL
827
+ file_url = f"{directus.url}/assets/{file_id}"
828
+
829
+ # With transformations (for images)
830
+ thumbnail_url = f"{directus.url}/assets/{file_id}?width=300&height=300&fit=cover"
831
+
832
+ import asyncio
833
+ asyncio.run(main())
834
+ ```
835
+
836
+ ## User Management
837
+
838
+ ### Read Users
839
+
840
+ ```python
841
+ from py_directus import Directus, DirectusUser
842
+
843
+ async def main():
844
+ directus = await Directus(
845
+ url="https://your-directus-instance.com",
846
+ token="your-token"
847
+ )
848
+
849
+ # Read all users
850
+ response = await directus.collection(DirectusUser).read()
851
+ users = response.items
852
+
853
+ # Filter active users
854
+ response = await (
855
+ directus.collection(DirectusUser)
856
+ .filter(status="active")
857
+ .read()
858
+ )
859
+
860
+ import asyncio
861
+ asyncio.run(main())
862
+ ```
863
+
864
+ ### Get Current User
865
+
866
+ ```python
867
+ from py_directus import Directus
868
+
869
+ async def main():
870
+ directus = await Directus(
871
+ url="https://your-directus-instance.com",
872
+ email="user@example.com",
873
+ password="password"
874
+ )
875
+
876
+ # Get current authenticated user
877
+ response = await directus.collection("directus_users").read(id="me")
878
+ current_user = response.item
879
+
880
+ print(f"Logged in as: {current_user['email']}")
881
+
882
+ import asyncio
883
+ asyncio.run(main())
884
+ ```
885
+
886
+ ### Create User
887
+
888
+ ```python
889
+ from py_directus import Directus
890
+
891
+ async def main():
892
+ directus = await Directus(
893
+ url="https://your-directus-instance.com",
894
+ token="your-token"
895
+ )
896
+
897
+ # Create a new user
898
+ new_user = {
899
+ "email": "newuser@example.com",
900
+ "password": "secure-password",
901
+ "role": "role-uuid",
902
+ "first_name": "John",
903
+ "last_name": "Doe",
904
+ "status": "active"
905
+ }
906
+
907
+ response = await directus.collection("directus_users").create(new_user)
908
+ created_user = response.item
909
+
910
+ import asyncio
911
+ asyncio.run(main())
912
+ ```
913
+
914
+ ### Update User
915
+
916
+ ```python
917
+ from py_directus import Directus
918
+
919
+ async def main():
920
+ directus = await Directus(
921
+ url="https://your-directus-instance.com",
922
+ token="your-token"
923
+ )
924
+
925
+ # Update a user
926
+ updated_data = {
927
+ "first_name": "Jane",
928
+ "status": "active"
929
+ }
930
+
931
+ response = await directus.collection("directus_users").update("user-uuid", updated_data)
932
+
933
+ import asyncio
934
+ asyncio.run(main())
935
+ ```
936
+
937
+ ## Roles and Permissions
938
+
939
+ ### Read Roles
940
+
941
+ ```python
942
+ from py_directus import Directus
943
+
944
+ async def main():
945
+ directus = await Directus(
946
+ url="https://your-directus-instance.com",
947
+ token="your-token"
948
+ )
949
+
950
+ # Read all roles
951
+ response = await directus.collection("directus_roles").read()
952
+ roles = response.items
953
+
954
+ import asyncio
955
+ asyncio.run(main())
956
+ ```
957
+
958
+ ### Read Permissions
959
+
960
+ ```python
961
+ from py_directus import Directus
962
+
963
+ async def main():
964
+ directus = await Directus(
965
+ url="https://your-directus-instance.com",
966
+ token="your-token"
967
+ )
968
+
969
+ # Read permissions for a specific role
970
+ response = await (
971
+ directus.collection("directus_permissions")
972
+ .filter(role="role-uuid")
973
+ .read()
974
+ )
975
+ permissions = response.items
976
+
977
+ import asyncio
978
+ asyncio.run(main())
979
+ ```
980
+
981
+ ## Collections and Fields
982
+
983
+ ### Read Collections
984
+
985
+ ```python
986
+ from py_directus import Directus
987
+
988
+ async def main():
989
+ directus = await Directus(
990
+ url="https://your-directus-instance.com",
991
+ token="your-token"
992
+ )
993
+
994
+ # Get all collections
995
+ response = await directus.collection("directus_collections").read()
996
+ collections = response.items
997
+
998
+ import asyncio
999
+ asyncio.run(main())
1000
+ ```
1001
+
1002
+ ### Read Fields
1003
+
1004
+ ```python
1005
+ from py_directus import Directus
1006
+
1007
+ async def main():
1008
+ directus = await Directus(
1009
+ url="https://your-directus-instance.com",
1010
+ token="your-token"
1011
+ )
1012
+
1013
+ # Get all fields for a collection
1014
+ response = await (
1015
+ directus.collection("directus_fields")
1016
+ .filter(collection="articles")
1017
+ .read()
1018
+ )
1019
+ fields = response.items
1020
+
1021
+ import asyncio
1022
+ asyncio.run(main())
1023
+ ```
1024
+
1025
+ ## Real-time with WebSockets
1026
+
1027
+ ### Subscribe to Collection
1028
+
1029
+ ```python
1030
+ from py_directus import Directus
1031
+
1032
+ async def main():
1033
+ directus = await Directus(
1034
+ url="https://your-directus-instance.com",
1035
+ token="your-token"
1036
+ )
1037
+
1038
+ # Subscribe to realtime updates
1039
+ async for message in directus.subscribe("articles"):
1040
+ print(f"Received update: {message}")
1041
+
1042
+ import asyncio
1043
+ asyncio.run(main())
1044
+ ```
1045
+
1046
+ ### Subscribe with Authentication
1047
+
1048
+ ```python
1049
+ from py_directus import Directus
1050
+
1051
+ async def main():
1052
+ directus = await Directus(
1053
+ url="https://your-directus-instance.com",
1054
+ email="user@example.com",
1055
+ password="password"
1056
+ )
1057
+
1058
+ # Subscribe to updates for authenticated user
1059
+ async for message in directus.subscribe("articles", uid=True):
1060
+ event_type = message.get("event")
1061
+ data = message.get("data")
1062
+
1063
+ if event_type == "create":
1064
+ print(f"New article created: {data}")
1065
+ elif event_type == "update":
1066
+ print(f"Article updated: {data}")
1067
+ elif event_type == "delete":
1068
+ print(f"Article deleted: {data}")
1069
+
1070
+ import asyncio
1071
+ asyncio.run(main())
1072
+ ```
1073
+
1074
+ ## Advanced Query Building
1075
+
1076
+ ### Chaining Methods
1077
+
1078
+ ```python
1079
+ from py_directus import Directus
1080
+
1081
+ async def main():
1082
+ directus = await Directus(
1083
+ url="https://your-directus-instance.com",
1084
+ token="your-token"
1085
+ )
1086
+
1087
+ # Chain multiple query methods
1088
+ response = await (
1089
+ directus.collection("articles")
1090
+ .fields("id", "title", "author.name", "publish_date")
1091
+ .filter(status="published")
1092
+ .filter(views__gte=1000)
1093
+ .sort("-publish_date")
1094
+ .limit(10)
1095
+ .offset(0)
1096
+ .search("directus")
1097
+ .read()
1098
+ )
1099
+
1100
+ articles = response.items
1101
+
1102
+ import asyncio
1103
+ asyncio.run(main())
1104
+ ```
1105
+
1106
+ ### Deep Filtering on Relations
1107
+
1108
+ ```python
1109
+ from py_directus import Directus
1110
+
1111
+ async def main():
1112
+ directus = await Directus(
1113
+ url="https://your-directus-instance.com",
1114
+ token="your-token"
1115
+ )
1116
+
1117
+ # Filter based on related collection
1118
+ response = await (
1119
+ directus.collection("articles")
1120
+ .filter(author__status="active")
1121
+ .filter(author__verified=True)
1122
+ .read()
1123
+ )
1124
+
1125
+ import asyncio
1126
+ asyncio.run(main())
1127
+ ```
1128
+
1129
+ ## Error Handling
1130
+
1131
+ ```python
1132
+ from py_directus import Directus
1133
+ import httpx
1134
+
1135
+ async def main():
1136
+ try:
1137
+ directus = await Directus(
1138
+ url="https://your-directus-instance.com",
1139
+ token="your-token"
1140
+ )
1141
+
1142
+ response = await directus.collection("articles").read()
1143
+ articles = response.items
1144
+
1145
+ except httpx.HTTPError as e:
1146
+ print(f"HTTP error occurred: {e}")
1147
+ except Exception as e:
1148
+ print(f"An error occurred: {e}")
1149
+
1150
+ import asyncio
1151
+ asyncio.run(main())
1152
+ ```
1153
+
1154
+ Handle authentication errors:
1155
+
1156
+ ```python
1157
+ from py_directus import Directus
1158
+
1159
+ async def main():
1160
+ try:
1161
+ directus = await Directus(
1162
+ url="https://your-directus-instance.com",
1163
+ email="user@example.com",
1164
+ password="wrong-password"
1165
+ )
1166
+ except Exception as e:
1167
+ print(f"Authentication failed: {e}")
1168
+
1169
+ import asyncio
1170
+ asyncio.run(main())
1171
+ ```
1172
+
1173
+ ## Request Metadata
1174
+
1175
+ ### Access Response Metadata
1176
+
1177
+ ```python
1178
+ from py_directus import Directus
1179
+
1180
+ async def main():
1181
+ directus = await Directus(
1182
+ url="https://your-directus-instance.com",
1183
+ token="your-token"
1184
+ )
1185
+
1186
+ response = await directus.collection("articles").read()
1187
+
1188
+ # Access items
1189
+ articles = response.items
1190
+
1191
+ # Access single item (when reading by ID)
1192
+ # article = response.item
1193
+
1194
+ # Check if request was successful
1195
+ print(f"Total items: {len(articles)}")
1196
+
1197
+ import asyncio
1198
+ asyncio.run(main())
1199
+ ```
1200
+
1201
+ ## Complete Example
1202
+
1203
+ ```python
1204
+ import os
1205
+ import asyncio
1206
+ from py_directus import Directus, F
1207
+
1208
+ async def main():
1209
+ # Initialize client
1210
+ directus = await Directus(
1211
+ url=os.getenv("DIRECTUS_URL"),
1212
+ token=os.getenv("DIRECTUS_TOKEN")
1213
+ )
1214
+
1215
+ # Create a new article
1216
+ new_article = {
1217
+ "title": "Getting Started with Directus",
1218
+ "content": "Directus is a powerful headless CMS...",
1219
+ "status": "draft",
1220
+ "author": "author-uuid"
1221
+ }
1222
+
1223
+ create_response = await directus.collection("articles").create(new_article)
1224
+ article_id = create_response.item["id"]
1225
+ print(f"Created article: {article_id}")
1226
+
1227
+ # Read articles with filters
1228
+ read_response = await (
1229
+ directus.collection("articles")
1230
+ .fields("id", "title", "status", "author.name")
1231
+ .filter(status="published")
1232
+ .filter(views__gte=100)
1233
+ .sort("-publish_date")
1234
+ .limit(10)
1235
+ .read()
1236
+ )
1237
+
1238
+ articles = read_response.items
1239
+ print(f"Found {len(articles)} published articles")
1240
+
1241
+ # Update the article
1242
+ update_data = {"status": "published"}
1243
+ await directus.collection("articles").update(article_id, update_data)
1244
+ print(f"Published article: {article_id}")
1245
+
1246
+ # Get statistics
1247
+ stats_response = await (
1248
+ directus.collection("articles")
1249
+ .aggregate(count="id")
1250
+ .aggregate(sum="views")
1251
+ .aggregate(avg="views")
1252
+ .groupby("status")
1253
+ .read()
1254
+ )
1255
+
1256
+ for stat in stats_response.items:
1257
+ print(f"Status: {stat['status']}")
1258
+ print(f"Count: {stat['count']['id']}")
1259
+ print(f"Total views: {stat['sum']['views']}")
1260
+ print(f"Avg views: {stat['avg']['views']}")
1261
+
1262
+ # Clean up - delete the article
1263
+ await directus.collection("articles").delete(article_id)
1264
+ print(f"Deleted article: {article_id}")
1265
+
1266
+ if __name__ == "__main__":
1267
+ asyncio.run(main())
1268
+ ```
1269
+
1270
+ ## Useful Links
1271
+
1272
+ - Documentation: https://panos-stavrianos.github.io/py-directus/
1273
+ - GitHub Repository: https://github.com/panos-stavrianos/py-directus
1274
+ - PyPI Package: https://pypi.org/project/py-directus/
1275
+ - Directus Official Docs: https://docs.directus.io/
1276
+ - Directus REST API Reference: https://docs.directus.io/reference/introduction