Skip to main content

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_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"
    )
    

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_sanity-0.2.0.dev1.tar.gz (21.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

python_sanity-0.2.0.dev1-py3-none-any.whl (25.1 kB view details)

Uploaded Python 3

File details

Details for the file python_sanity-0.2.0.dev1.tar.gz.

File metadata

  • Download URL: python_sanity-0.2.0.dev1.tar.gz
  • Upload date:
  • Size: 21.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.2

File hashes

Hashes for python_sanity-0.2.0.dev1.tar.gz
Algorithm Hash digest
SHA256 34e160d00738253d2407a8aa161dee627b517371e21ce16c4b6404949aa9a455
MD5 e3dbd4155c91e7a89fee67fb045d9bbb
BLAKE2b-256 c05bd30f550c812ebadf878690c00ab1ee29b2fb896da01518248aa465db4024

See more details on using hashes here.

File details

Details for the file python_sanity-0.2.0.dev1-py3-none-any.whl.

File metadata

File hashes

Hashes for python_sanity-0.2.0.dev1-py3-none-any.whl
Algorithm Hash digest
SHA256 9903e04a4875163ae4e86ff42e6f21c68fa0f2108bac08e4edfb36c56e0579d6
MD5 3c871436c696a1d67f7f64d58206f653
BLAKE2b-256 7cbd2b33d02dab1f6864e6f09b57ab0824a82520e71a68d6d4cf422ee246d21f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page