Skip to main content

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_LEVEL support
  • httpx: Migrated from requests to httpx for 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
  • Context Managers: Both Client and AsyncClient support 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

  1. 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
    
  2. Use context managers for cleanup:

    # Recommended
    with Client() as client:
        result = client.query(groq="*[_type == 'post']")
    
  3. Try async for better performance:

    from sanity import AsyncClient
    
    async with AsyncClient() as client:
        result = await client.query(groq="*[_type == 'post']")
    
  4. 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"
    )
    

Metadata

Release files for python-sanity 0.2.0.post1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for python-sanity 0.2.0.post1
File Size Uploaded
python_sanity-0.2.0.post1.tar.gz 20.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for python-sanity 0.2.0.post1
File Interpreter ABI Platform
python_sanity-0.2.0.post1-py3-none-any.whl Python 3 none any Details

Total release size: 46.0 kB

Release files / python_sanity-0.2.0.post1.tar.gz

Download URL python_sanity-0.2.0.post1.tar.gz
Size 20.9 kB
Tags Source
SHA-256 checksum
How to use checksums
3a24614b74a6eb24ea42a42bfafdb9e7ac9d37d0685d5a3b13cdaa8ac312e7d4
BLAKE2b-256 checksum
How to use checksums
8eeed6c0c2ee9c7a0013ca423a9e89d43400a3c70eb42dd49046e47f2801c164
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.2

Release files / python_sanity-0.2.0.post1-py3-none-any.whl

Download URL python_sanity-0.2.0.post1-py3-none-any.whl
Size 25.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c8a09b49fac1d12c2de49db7845b5f0ae7679cecf159153f429de89716b41e24
BLAKE2b-256 checksum
How to use checksums
905a94d9b85b5f0ac247ad2881659f789887bd9ab42e23940be75cf872adc11e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.2
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page