Sync Client
The package includes a synchronous client, SyncVClient, for use in applications that don't use async/await. It provides the same API surface as the async VClient — identical configuration options, service methods, and models — without requiring an event loop.
When to Use Sync vs Async
Use SyncVClient when your application is synchronous:
- Flask or Django views
- CLI tools and scripts
- Data pipelines
- Jupyter notebooks
- Any code that doesn't use
async/await
Use VClient (async) when your application already uses an event loop:
- FastAPI / Starlette endpoints
asyncio-based services- Applications using
async with/awaitpatterns
Creating the Client
SyncVClient accepts the same constructor options as VClient. See Configuration for the full options reference.
from vclient import SyncVClient
client = SyncVClient(
base_url="https://api.valentina-noir.com",
api_key="YOUR_API_KEY",
)
Environment variables work identically — see Environment Variables.
client = SyncVClient() # reads from VALENTINA_CLIENT_BASE_URL / VALENTINA_CLIENT_API_KEY
Context Manager
Use with instead of async with to ensure the HTTP client is closed when you're done:
from vclient import SyncVClient
with SyncVClient() as client:
companies = client.companies
all_companies = companies.list_all()
# HTTP client is automatically closed when exiting the context
Factory Functions
Every async factory function has a sync counterpart prefixed with sync_:
| Async | Sync |
|---|---|
companies_service() |
sync_companies_service() |
users_service() |
sync_users_service() |
campaigns_service() |
sync_campaigns_service() |
characters_service() |
sync_characters_service() |
character_traits_service() |
sync_character_traits_service() |
books_service() |
sync_books_service() |
chapters_service() |
sync_chapters_service() |
dicerolls_service() |
sync_dicerolls_service() |
dictionary_service() |
sync_dictionary_service() |
character_blueprint_service() |
sync_character_blueprint_service() |
options_service() |
sync_options_service() |
Factory functions work the same way — create a SyncVClient first, then call the factory from any module:
from vclient import SyncVClient, sync_companies_service
client = SyncVClient()
companies = sync_companies_service()
all_companies = companies.list_all()
Key Differences from Async
The sync client is auto-generated from the async source, so the API is nearly identical. The only differences are syntactic:
| Async | Sync |
|---|---|
async with VClient() as client: |
with SyncVClient() as client: |
await companies.list_all() |
companies.list_all() |
await companies.get("id") |
companies.get("id") |
async for c in companies.iter_all(): |
for c in companies.iter_all(): |
Returns AsyncIterator[T] |
Returns Iterator[T] |
Models, exceptions, and configuration are shared between both clients.
Complete Example
from vclient import SyncVClient, sync_companies_service, sync_campaigns_service
with SyncVClient(
base_url="https://api.valentina-noir.com",
api_key="YOUR_API_KEY",
default_company_id="COMPANY_ID",
) as client:
# List companies via factory function
companies = sync_companies_service()
for company in companies.list_all():
print(f"Company: {company.name} ({company.id})")
# Get campaigns for a user
campaigns = sync_campaigns_service(user_id="USER_ID")
for campaign in campaigns.list_all():
print(f"Campaign: {campaign.name}")
# Paginate through results
page = companies.get_page(limit=10, offset=0)
print(f"Page {page.current_page} of {page.total_pages}")
# Stream all items with iter_all()
for company in companies.iter_all():
print(company.name)