Files
py-wikijs/docs/async_usage.md
Claude 59cdf5ee01 refactor: Rename package from wikijs-python-sdk to py-wikijs and migrate to GitHub
Complete package renaming and platform migration:

Package Name Changes:
- Rename package from 'wikijs-python-sdk' to 'py-wikijs'
- Update setup.py package name
- Update pyproject.toml package name
- Users can now install with: pip install py-wikijs

URL Migration (Gitea → GitHub):
- Replace all Gitea URLs with GitHub URLs
- Update repository: github.com/l3ocho/py-wikijs
- Update issue tracker: github.com/l3ocho/py-wikijs/issues
- Update documentation links
- Fix URL path format (/src/branch/main/ → /blob/main/)

Documentation Updates:
- Update README.md badges (PyPI, GitHub)
- Update installation instructions (pip install py-wikijs)
- Update all doc references to new package name
- Update all examples with GitHub URLs
- Update DEPLOYMENT_READY.md with new package name
- Update deployment.md with new package name

Testing:
- Successfully built py_wikijs-0.1.0.tar.gz (138 KB)
- Successfully built py_wikijs-0.1.0-py3-none-any.whl (66 KB)
- Package installs correctly: pip install py-wikijs
- Imports work: from wikijs import WikiJSClient
- Package metadata correct (Home-page: github.com/l3ocho/py-wikijs)

Breaking Changes:
- Package name changed from wikijs-python-sdk to py-wikijs
- Repository migrated from Gitea to GitHub
- All URLs updated to GitHub

Users should now:
pip install py-wikijs  # Instead of wikijs-python-sdk

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-23 20:23:50 +00:00

419 lines
9.8 KiB
Markdown

# Async/Await Support
The Wiki.js Python SDK provides full async/await support for high-performance concurrent operations using `aiohttp`.
## Installation
```bash
pip install py-wikijs[async]
```
## Quick Start
```python
import asyncio
from wikijs.aio import AsyncWikiJSClient
async def main():
# Use async context manager for automatic cleanup
async with AsyncWikiJSClient(
base_url="https://wiki.example.com",
auth="your-api-key"
) as client:
# All operations are now async
pages = await client.pages.list()
page = await client.pages.get(123)
print(f"Found {len(pages)} pages")
print(f"Page title: {page.title}")
# Run the async function
asyncio.run(main())
```
## Why Async?
Async operations provide significant performance benefits for concurrent requests:
- **Sequential (Sync)**: Requests happen one-by-one
- 100 requests @ 100ms each = 10 seconds
- **Concurrent (Async)**: Requests happen simultaneously
- 100 requests @ 100ms each = ~100ms total
- **>3x faster** for typical workloads!
## Basic Operations
### Connection Testing
```python
async with AsyncWikiJSClient(url, auth) as client:
connected = await client.test_connection()
print(f"Connected: {connected}")
```
### Listing Pages
```python
# List all pages
pages = await client.pages.list()
# List with filtering
pages = await client.pages.list(
limit=10,
offset=0,
search="documentation",
locale="en",
order_by="title",
order_direction="ASC"
)
```
### Getting Pages
```python
# Get by ID
page = await client.pages.get(123)
# Get by path
page = await client.pages.get_by_path("getting-started")
```
### Creating Pages
```python
from wikijs.models.page import PageCreate
new_page = PageCreate(
title="New Page",
path="new-page",
content="# New Page\n\nContent here.",
description="A new page",
tags=["new", "example"]
)
created_page = await client.pages.create(new_page)
print(f"Created page with ID: {created_page.id}")
```
### Updating Pages
```python
from wikijs.models.page import PageUpdate
updates = PageUpdate(
title="Updated Title",
content="# Updated\n\nNew content.",
tags=["updated"]
)
updated_page = await client.pages.update(123, updates)
```
### Deleting Pages
```python
success = await client.pages.delete(123)
print(f"Deleted: {success}")
```
### Searching Pages
```python
results = await client.pages.search("api documentation", limit=10)
for page in results:
print(f"- {page.title}")
```
## Concurrent Operations
The real power of async is running multiple operations concurrently:
### Fetch Multiple Pages
```python
import asyncio
# Sequential (slow)
pages = []
for page_id in [1, 2, 3, 4, 5]:
page = await client.pages.get(page_id)
pages.append(page)
# Concurrent (fast!)
tasks = [client.pages.get(page_id) for page_id in [1, 2, 3, 4, 5]]
pages = await asyncio.gather(*tasks)
```
### Bulk Create Operations
```python
# Create multiple pages concurrently
pages_to_create = [
PageCreate(title=f"Page {i}", path=f"page-{i}", content=f"Content {i}")
for i in range(1, 11)
]
tasks = [client.pages.create(page) for page in pages_to_create]
created_pages = await asyncio.gather(*tasks, return_exceptions=True)
# Filter out any errors
successful = [p for p in created_pages if isinstance(p, Page)]
print(f"Created {len(successful)} pages")
```
### Parallel Search Operations
```python
# Search multiple terms concurrently
search_terms = ["api", "guide", "tutorial", "reference"]
tasks = [client.pages.search(term) for term in search_terms]
results = await asyncio.gather(*tasks)
for term, pages in zip(search_terms, results):
print(f"{term}: {len(pages)} pages found")
```
## Error Handling
Handle errors gracefully with try/except:
```python
from wikijs.exceptions import (
AuthenticationError,
NotFoundError,
APIError
)
async with AsyncWikiJSClient(url, auth) as client:
try:
page = await client.pages.get(999)
except NotFoundError:
print("Page not found")
except AuthenticationError:
print("Invalid API key")
except APIError as e:
print(f"API error: {e}")
```
### Handle Errors in Concurrent Operations
```python
# Use return_exceptions=True to continue on errors
tasks = [client.pages.get(page_id) for page_id in [1, 2, 999, 4, 5]]
results = await asyncio.gather(*tasks, return_exceptions=True)
# Process results
for i, result in enumerate(results):
if isinstance(result, Exception):
print(f"Page {i}: Error - {result}")
else:
print(f"Page {i}: {result.title}")
```
## Resource Management
### Automatic Cleanup with Context Manager
```python
# Recommended: Use async context manager
async with AsyncWikiJSClient(url, auth) as client:
# Session automatically closed when block exits
pages = await client.pages.list()
```
### Manual Resource Management
```python
# If you need manual control
client = AsyncWikiJSClient(url, auth)
try:
pages = await client.pages.list()
finally:
await client.close() # Important: close the session
```
## Advanced Configuration
### Custom Connection Pool
```python
import aiohttp
# Create custom connector for fine-tuned control
connector = aiohttp.TCPConnector(
limit=200, # Max connections
limit_per_host=50, # Max per host
ttl_dns_cache=600, # DNS cache TTL
)
async with AsyncWikiJSClient(
url,
auth,
connector=connector
) as client:
# Use client with custom connector
pages = await client.pages.list()
```
### Custom Timeout
```python
# Set custom timeout (in seconds)
async with AsyncWikiJSClient(
url,
auth,
timeout=60 # 60 second timeout
) as client:
pages = await client.pages.list()
```
### Disable SSL Verification (Development Only)
```python
async with AsyncWikiJSClient(
url,
auth,
verify_ssl=False # NOT recommended for production!
) as client:
pages = await client.pages.list()
```
## Performance Best Practices
### 1. Use Connection Pooling
The async client automatically uses connection pooling. Keep a single client instance for your application:
```python
# Good: Reuse client
client = AsyncWikiJSClient(url, auth)
for i in range(100):
await client.pages.get(i)
await client.close()
# Bad: Create new client each time
for i in range(100):
async with AsyncWikiJSClient(url, auth) as client:
await client.pages.get(i) # New connection each time!
```
### 2. Batch Concurrent Operations
Use `asyncio.gather()` for concurrent operations:
```python
# Fetch 100 pages concurrently (fast!)
tasks = [client.pages.get(i) for i in range(1, 101)]
pages = await asyncio.gather(*tasks, return_exceptions=True)
```
### 3. Use Semaphores to Control Concurrency
Limit concurrent connections to avoid overwhelming the server:
```python
import asyncio
async def fetch_page_with_semaphore(client, page_id, sem):
async with sem: # Limit concurrent operations
return await client.pages.get(page_id)
# Limit to 10 concurrent requests
sem = asyncio.Semaphore(10)
tasks = [
fetch_page_with_semaphore(client, i, sem)
for i in range(1, 101)
]
pages = await asyncio.gather(*tasks)
```
## Comparison: Sync vs Async
| Feature | Sync Client | Async Client |
|---------|-------------|--------------|
| Import | `from wikijs import WikiJSClient` | `from wikijs.aio import AsyncWikiJSClient` |
| Usage | `client.pages.get(123)` | `await client.pages.get(123)` |
| Context Manager | `with WikiJSClient(...) as client:` | `async with AsyncWikiJSClient(...) as client:` |
| Concurrency | Sequential only | Concurrent with `asyncio.gather()` |
| Performance | Good for single requests | Excellent for multiple requests |
| Dependencies | `requests` | `aiohttp` |
| Best For | Simple scripts, sequential operations | Web apps, high-throughput, concurrent ops |
## When to Use Async
**Use Async When:**
- Making multiple concurrent API calls
- Building async web applications (FastAPI, aiohttp)
- Need maximum throughput
- Working with other async libraries
**Use Sync When:**
- Simple scripts or automation
- Sequential operations only
- Don't need concurrency
- Simpler code is preferred
## Complete Example
```python
import asyncio
from wikijs.aio import AsyncWikiJSClient
from wikijs.models.page import PageCreate, PageUpdate
async def main():
async with AsyncWikiJSClient(
base_url="https://wiki.example.com",
auth="your-api-key"
) as client:
# Test connection
print("Testing connection...")
connected = await client.test_connection()
print(f"Connected: {connected}")
# Create page
print("\nCreating page...")
new_page = PageCreate(
title="Test Page",
path="test-page",
content="# Test\n\nContent here.",
tags=["test"]
)
page = await client.pages.create(new_page)
print(f"Created page {page.id}: {page.title}")
# Update page
print("\nUpdating page...")
updates = PageUpdate(title="Updated Test Page")
page = await client.pages.update(page.id, updates)
print(f"Updated: {page.title}")
# List pages concurrently
print("\nFetching multiple pages...")
tasks = [
client.pages.list(limit=5),
client.pages.search("test"),
client.pages.get_by_tags(["test"])
]
list_results, search_results, tag_results = await asyncio.gather(*tasks)
print(f"Listed: {len(list_results)}")
print(f"Searched: {len(search_results)}")
print(f"By tags: {len(tag_results)}")
# Clean up
print("\nDeleting test page...")
await client.pages.delete(page.id)
print("Done!")
if __name__ == "__main__":
asyncio.run(main())
```
## See Also
- [Basic Usage Guide](../README.md#usage)
- [API Reference](api/)
- [Examples](../examples/)
- [Performance Benchmarks](benchmarks.md)