Python client for Sanity.io CMS HTTP API
Project description
python-sanity
Python client for Sanity.io CMS HTTP API. Sanity is a hosted CMS solution for content management. This project is not affiliated with Sanity.io and is a third-party package.
ℹ️ Note: This package is an active fork of the original project at OmniPro-Group/sanity-python.
Install
Available on pypi as package python-sanity
Install with uv:
uv add python-sanity
Install with pip:
pip install python-sanity
Environment Variables
You can pass parameters to the client constructor directly, but it is recommended to use environment variables.
| Variable | Description | Required | Default Value |
|---|---|---|---|
| SANITY_PROJECT_ID | The project ID | Yes | |
| SANITY_DATASET | The dataset to use | No | production |
| SANITY_API_TOKEN | The API token | No (required for mutations) | |
| SANITY_LOG_LEVEL | Level of logging | No | INFO |
What's New in v0.2.0
- AsyncClient: Full async/await support for all operations
- Optional Logger: Logger parameter is now optional, uses built-in logger with
SANITY_LOG_LEVELsupport - httpx: Migrated from
requeststohttpxfor better async support and HTTP/2 - Automatic Retries: Configurable retry logic with exponential backoff
- Better Error Handling: Specific exception types (
SanityAuthError,SanityRateLimitError, etc.) - New API Parameters:
- Query:
perspective,result_source_map,tag,return_query - Mutation:
auto_generate_array_keys,skip_cross_dataset_references_validation,transaction_id
- Query:
- Context Managers: Both
ClientandAsyncClientsupport context managers - Updated API Version: Default API version updated to
2025-02-19
Quick Start
Synchronous Client
from sanity import Client
# Simple initialization (logger is now optional!)
client = Client() # Uses environment variables
# Or with explicit parameters
client = Client(
project_id="your-project-id",
dataset="production",
token="your-api-token", # Optional for read-only queries
use_cdn=True
)
# Query with GROQ
result = client.query(
groq="*[_type == 'post'] | order(publishedAt desc)[0...10]",
variables={"limit": 10}
)
# Mutations
transactions = [{
"createOrReplace": {
"_id": "post.123",
"_type": "post",
"title": "Hello World",
"publishedAt": "2025-01-15T00:00:00Z"
}
}]
result = client.mutate(
transactions=transactions,
return_documents=True
)
# Upload assets
result = client.assets(
file_path="https://example.com/image.png"
)
Async Client
from sanity import AsyncClient
import asyncio
async def main():
# Use async context manager
async with AsyncClient() as client:
# Async query
result = await client.query(
groq="*[_type == 'post']",
perspective="published"
)
# Async mutation
result = await client.mutate(
transactions=[{
"create": {
"_type": "post",
"title": "Async Post"
}
}]
)
# Async asset upload
result = await client.assets(
file_path="/path/to/image.png"
)
asyncio.run(main())
Advanced Configuration
from sanity import Client, TimeoutConfig, RetryConfig
# Custom timeouts and retries
client = Client(
timeout=TimeoutConfig(
connect=5.0,
read=30.0,
write=30.0,
pool=5.0
),
retry_config=RetryConfig(
max_retries=5,
backoff_factor=1.0
),
http2=True
)
Error Handling
from sanity import (
Client,
SanityAuthError,
SanityRateLimitError,
SanityValidationError
)
client = Client()
try:
result = client.query(groq="*[_type == 'post']")
except SanityAuthError as e:
print(f"Authentication failed: {e.message}")
except SanityRateLimitError as e:
print(f"Rate limited, retry after {e.retry_after}s")
except SanityValidationError as e:
print(f"Validation error: {e.response_body}")
Migration Guide from v0.1.x
Breaking Changes
None! v0.2.0 is fully backward compatible.
Optional Improvements
-
Logger is now optional:
# Old way (still works) import logging client = Client(logger=logging.getLogger(__name__)) # New way (simpler) client = Client() # Uses built-in logger with SANITY_LOG_LEVEL
-
Use context managers for cleanup:
# Recommended with Client() as client: result = client.query(groq="*[_type == 'post']")
-
Try async for better performance:
from sanity import AsyncClient async with AsyncClient() as client: result = await client.query(groq="*[_type == 'post']")
-
Use new parameters:
# Query with perspective result = client.query( groq="*[_type == 'post']", perspective="published", # drafts, published, raw tag="my-app" ) # Mutations with new options result = client.mutate( transactions=[...], auto_generate_array_keys=True, transaction_id="my-custom-id" )
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 python_sanity-0.2.0.dev2.tar.gz.
File metadata
- Download URL: python_sanity-0.2.0.dev2.tar.gz
- Upload date:
- Size: 20.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66ed95715e5b33e712d79b6e081e3f3be04fc320b2460de53c56c8adb86578b5
|
|
| MD5 |
ea871c66c5e3c7b2d0e1b68189ddea13
|
|
| BLAKE2b-256 |
b154a75ade9bb0d2c36cecbc8d905295f4582f601a3636694547c1196ea50536
|
File details
Details for the file python_sanity-0.2.0.dev2-py3-none-any.whl.
File metadata
- Download URL: python_sanity-0.2.0.dev2-py3-none-any.whl
- Upload date:
- Size: 25.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
daaac967b95334638b43abb1929a47ad825b4359136137e58cbec81137ab88d5
|
|
| MD5 |
9ed7281fc61424571f714400df92fb4a
|
|
| BLAKE2b-256 |
1fb274a414427aeb6bc361e4b7db60de693a99dfb36aad9ade939f93225d0330
|