stash-graphql-client and using it the way it’s meant to be used: through the EntityStore. The store is what turns this library from “a typed GraphQL client” into an ORM-like layer — an identity map so the same entity ID is always the same Python object, read-through caching, selective field loading, Django-style filtering, and batched saves that figure out create-before-update ordering for you.
You can always drop down to raw client calls (covered near the end), but reach for the store first.
Prerequisites
- Python 3.12 or higher
- Stash server v0.30.0 or later (appSchema 75+). Newer features are gated via introspection; currently tracking v0.31.x.
- Poetry (optional, for development)
Installation
Option 1: Install from PyPI (Recommended)
Option 2: Install with Poetry
Option 3: Install from Source
Verify Installation
Configuration
Create a connection dictionary with your Stash server details:ApiKey above.
Your First Script
StashContext is an async context manager. Entering it yields a ready-to-use StashClient, and the context exposes a single store singleton (context.store) wired to the identity map. This is the pattern you’ll use most:
Keep a reference to the
context (don’t write async with StashContext(...) as client: if you need the store) — context.store is the identity-map-wired singleton, and it’s only initialized once the context is entered.Working with the EntityStore
The store is the recommended entry point for everything: reads, searches, and writes.Identity Map + Caching
store.get() checks the cache first and fetches on a miss. Because of the identity map, the same entity ID always returns the same object reference, so a change made anywhere is visible everywhere:
Django-Style Filtering
store.find() accepts familiar field__lookup filters instead of hand-built GraphQL filter objects:
Selective Field Loading
Entities may arrive as “stubs” with only base fields.store.populate() fetches only the fields you actually need (it tracks what’s already present), and supports nested field__subfield specs:
Saving Changes
Modify entities in place, then persist.store.save() saves one entity; store.save_all() flushes every dirty or new entity the store is tracking in a single batched request (handling create-before-update ordering automatically):
Lazy Iteration Over Large Sets
For large result sets,store.find_iter() yields entities as it pages through them, so you never hold the whole set in memory:
Get or Create
store.get_or_create() finds an entity by search criteria or builds a new one from those same criteria. New entities are not auto-saved — persist them with store.save():
Core Workflows
These are the same workflows you’ll reach for daily — expressed store-first.Workflow 1: Find and Update
Workflow 2: Create and Link Entities
Build several entities, link them, and letsave_all() persist everything in one batch with correct ordering (new tags get server IDs before the scene that references them):
Workflow 3: Bulk Processing with Progress
Understanding UNSET
The UNSET pattern is how the library does precise partial updates: a field is either set to a value, explicitlyNone, or UNSET (never touched, so it’s excluded from mutations).
Working with Relationships
Relationships may be UNSET until populated. Usestore.populate() to load them, and is_set() before accessing:
Lower-Level: Using the Client Directly
The store is built on top ofStashClient, and you can use the client directly when you don’t need caching, the identity map, or batching — for example a one-off lookup or a quick script. Entities save against the client with entity.save(client):
Error Handling
Best Practices
1. Use the store singleton
Access the store viacontext.store so every part of your code shares one identity map and cache:
2. Batch your writes
Make all your edits, then flush once:3. Populate only what you need
4. Check for UNSET before accessing
5. Handle None responses
Common Patterns
Pattern: Get or Create
Pattern: Batch Processing with the Store
Next Steps
Now that you’ve completed the getting started guide, explore these topics:- Usage Patterns - Common recipes and best practices
- UNSET Pattern Guide - Deep dive on partial updates
- Overview - Architecture and core concepts
- Entity Store API - Complete store method reference
Troubleshooting
Connection Issues
Problem:ConnectError: Cannot connect to server
Solution:
- Verify Stash is running
- Check host and port in connection config
- Try accessing Stash web interface manually
Import Errors
Problem:ModuleNotFoundError: No module named 'stash_graphql_client'
Solution:
Type Errors
Problem: IDE shows type errors for entity fields Solution:- Ensure Python 3.12+ is being used
- Check that Pydantic v2 is installed
- May need to restart IDE/language server
Getting Help
- Documentation: https://jakan-kink.github.io/stash-graphql-client/
- GitHub Issues: https://github.com/Jakan-Kink/stash-graphql-client/issues
- Stash Community: https://discord.gg/stash