PocketBase Python SDK - A unofficial Python client library for PocketBase backend
Project description
PocketBase Python SDK
A unofficial Python client library for PocketBase, the open-source backend as a service.
Features
- ๐ Async/Await Support - Built on
asynciofor high-performance asynchronous operations - ๐ Authentication - Complete auth support including OAuth2, OTP, and password reset
- ๐ก Realtime - WebSocket connections for real-time subscriptions
- ๐๏ธ CRUD Operations - Full Create, Read, Update, Delete operations
- ๐ Batch Operations - Transactional batch requests
- ๐ฅ Health Checks - Monitor server health and status
- ๐ Logging - Access and manage server logs
- ๐ช Token Storage - Multiple auth store implementations (memory, local file, async)
- ๐ Type Hints - Full TypeScript-style type annotations
- ๐งช Test Coverage - Comprehensive test suite
Installation
pip install pocketbase_sdk
Quick Start
import asyncio
from pocketbase_sdk import Client, LocalAuthStore
async def main():
# Initialize client
client = Client("http://127.0.0.1:8090")
try:
# Check server health
health = await client.health.check()
print(f"Server status: {health}")
# Authenticate with email/password
auth_data = await client.collection("users").auth_with_password(
"user@example.com",
"password123"
)
print(f"Authenticated as: {auth_data.record.email}")
# Create a record
record = await client.collection("posts").create({
"title": "Hello PocketBase",
"content": "My first post"
})
print(f"Created record: {record.id}")
# Subscribe to real-time updates
def on_update(data):
print(f"Real-time update: {data.action} - {data.record.id}")
await client.collection("posts").subscribe("*", on_update)
# Keep running to receive updates
await asyncio.sleep(10)
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
asyncio.run(main())
API Overview
Client
The main Client class provides access to all services:
from pocketbase_sdk import Client
client = Client("http://127.0.0.1:8090")
Authentication
# Email/password authentication
auth_data = await client.collection("users").auth_with_password(
"user@example.com",
"password"
)
# OAuth2 authentication
auth_data = await client.collection("users").auth_with_oauth2_code(
"google",
"authorization_code",
"code_verifier",
"http://localhost/callback"
)
# Refresh token
auth_data = await client.collection("users").auth_refresh()
# Password reset
await client.collection("users").request_password_reset("user@example.com")
await client.collection("users").confirm_password_reset(
"reset_token",
"new_password",
"new_password"
)
CRUD Operations
# Create
record = await client.collection("posts").create({
"title": "New Post",
"content": "Post content"
})
# Read
record = await client.collection("posts").get_one(record.id)
# List
list_result = await client.collection("posts").get_list(
page=1,
per_page=30,
filter="created > '2023-01-01'"
)
# Full list
all_posts = await client.collection("posts").get_full_list(
batch=200
)
# Update
updated = await client.collection("posts").update(record.id, {
"title": "Updated Title"
})
# Delete
await client.collection("posts").delete(record.id)
Real-time Subscriptions
async def on_record_change(data):
if data.action == "create":
print(f"New record: {data.record}")
elif data.action == "update":
print(f"Updated record: {data.record}")
elif data.action == "delete":
print(f"Deleted record: {data.record}")
# Subscribe to all changes in a collection
unsubscribe = await client.collection("posts").subscribe("*", on_record_change)
# Subscribe to specific record changes
await client.collection("posts").subscribe(record.id, on_record_change)
# Unsubscribe
await unsubscribe() # or await client.collection("posts").unsubscribe()
Batch Operations
batch = client.create_batch()
# Add multiple operations
batch.collection("posts").create({"title": "Post 1"})
batch.collection("posts").update("post-id", {"title": "Updated Post"})
batch.collection("users").delete("user-id")
# Execute all operations in a single request
results = await batch.send()
Health Checks
# Basic health check
health = await client.health.check()
# Wait for server to be healthy
is_healthy = await client.health.wait_until_healthy(timeout=30)
# Get database stats
db_stats = await client.health.get_database_stats()
# Get cache stats
cache_stats = await client.health.get_cache_stats()
Logging
# Get recent logs
logs = await client.logs.get_list(page=1, per_page=50)
# Get error logs only
error_logs = await client.logs.get_error_logs()
# Get logs statistics
stats = await client.logs.get_stats()
# Delete old logs
await client.logs.delete_logs_older_than(days=30)
Filter Expressions
# Build filters with parameters
filter_expr = client.filter(
"title ~ {:title} && created >= {:date}",
{"title": "example", "date": "2023-01-01"}
)
# Use in queries
posts = await client.collection("posts").get_list(filter=filter_expr)
Advanced Usage
Custom Auth Store
from pocketbase_sdk import Client, BaseAuthStore
class CustomAuthStore(BaseAuthStore):
def __init__(self):
super().__init__()
# Custom initialization
def save(self, token, record=None):
# Custom save logic
super().save(token, record)
def clear(self):
# Custom clear logic
super().clear()
client = Client("http://127.0.0.1:8090", auth_store=CustomAuthStore())
Request Hooks
async def before_send(url, options):
print(f"Making request to: {url}")
# Modify request if needed
return {"url": url, "options": options}
async def after_send(response, data, options):
print(f"Response status: {response.status}")
# Modify response if needed
return data
client.before_send = before_send
client.after_send = after_send
File Uploads
from aiohttp import FormData
# Upload file with form data
form = FormData()
form.add_field('file', open('image.jpg', 'rb'), filename='image.jpg')
form.add_field('title', 'My Image')
record = await client.collection("images").create(form)
Error Handling
from pocketbase_sdk import Client, ClientResponseError
try:
await client.collection("users").auth_with_password("invalid", "credentials")
except ClientResponseError as e:
print(f"Authentication failed: {e.message}")
print(f"Status: {e.status}")
print(f"URL: {e.url}")
Configuration Options
Client Options
client = Client(
base_url="http://127.0.0.1:8090",
auth_store=LocalAuthStore(), # Default
lang="en-US" # Default
)
Request Options
All API methods accept optional request options:
from pocketbase_sdk import RecordOptions
await client.collection("posts").get_one(
"record-id",
RecordOptions(
fields="id,title,created",
expand="author,comments"
)
)
Development
Setup Development Environment
# Clone repository
git clone https://github.com/pocketbase/pocketbase-python-sdk
cd pocketbase-python-sdk
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=pocketbase
# Format code
black src tests
# Type checking
mypy src
Architecture Notes
The SDK uses lazy initialization to avoid circular dependencies between Client and Services. Services are created only when first accessed through properties:
client = Client("http://127.0.0.1:8090")
# Services are created on-demand
collections = client.collections # CollectionService created here
health = client.health # HealthService created here
logs = client.logs # LogService created here
realtime = client.realtime # RealtimeService created here
This approach:
- โ Eliminates circular dependency during initialization
- โ Improves memory usage (only used services are created)
- โ Maintains API compatibility
- โ Thread-safe for concurrent access
For details, see CIRCULAR_DEPENDENCY_FIX.md.
Project Structure
pocketbase-python-sdk/
โโโ src/
โ โโโ pocketbase_sdk/
โ โ โโโ __init__.py
โ โ โโโ client.py # Main client class
โ โ โโโ exceptions.py # Error handling
โ โ โโโ services/ # API services
โ โ โ โโโ __init__.py
โ โ โ โโโ base_service.py
โ โ โ โโโ collection_service.py
โ โ โ โโโ crud_service.py
โ โ โ โโโ health_service.py
โ โ โ โโโ log_service.py
โ โ โ โโโ record_service.py
โ โ โ โโโ realtime_service.py
โ โ โ โโโ batch_service.py
โ โ โโโ stores/ # Auth stores
โ โ โ โโโ __init__.py
โ โ โ โโโ base_auth_store.py
โ โ โ โโโ local_auth_store.py
โ โ โ โโโ async_auth_store.py
โ โ โโโ utils/ # Utilities
โ โ โโโ __init__.py
โ โ โโโ dtos.py
โ โ โโโ options.py
โ โ โโโ jwt.py
โ โ โโโ cookie.py
โโโ tests/ # Test suite
โโโ README.md
โโโ pyproject.toml
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Make your changes and add tests
- Run the test suite:
pytest - Submit a pull request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Related Projects
Support
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pocketbase_sdk-0.1.2.tar.gz.
File metadata
- Download URL: pocketbase_sdk-0.1.2.tar.gz
- Upload date:
- Size: 45.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
205e138139e77d9ca891fb476fb8f3547337691aaf83cd01066552c42e451677
|
|
| MD5 |
37ea61a285b2840ebe396fbc2e5b7ed3
|
|
| BLAKE2b-256 |
93db79db169fc7418650a8ee6965a5c2217b6e3b4e0b261609ad0a0d5fdcc391
|
File details
Details for the file pocketbase_sdk-0.1.2-py3-none-any.whl.
File metadata
- Download URL: pocketbase_sdk-0.1.2-py3-none-any.whl
- Upload date:
- Size: 40.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f29a36e84a8ca9142887e3f68d5ceb3c3401039c0c1ffb36cf0d05deffd8653f
|
|
| MD5 |
bc7cdc73e551144b78ce0f8fb05590ce
|
|
| BLAKE2b-256 |
3e05355ecd09ea6015dbaf3ab5e535a620f1b7d814e272631a34c5a4cef3d136
|