Skip to content

Commit 023aefc

Browse files
committed
chore: Update docs for slightly better UX.
1 parent 13edc63 commit 023aefc

File tree

10 files changed

+103
-25
lines changed

10 files changed

+103
-25
lines changed

README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
[![Tests](https://github.com/sirstig/yokedcache/actions/workflows/test.yml/badge.svg)](https://github.com/sirstig/yokedcache/actions/workflows/test.yml)
77
[![Coverage](https://codecov.io/gh/sirstig/yokedcache/branch/main/graph/badge.svg)](https://codecov.io/gh/sirstig/yokedcache)
88

9-
Async-first caching with the **same API** across backends: in-process memory (default install), Redis, Memcached, disk, and SQLite. Tag and pattern invalidation, optional Starlette HTTP middleware, and production metrics—usable from FastAPI, Starlette, Django async code, workers, or plain `asyncio`.
9+
Async-first caching with the **same API** across backends: in-process memory (default install), Redis, Memcached, disk, and SQLite. Tag and pattern invalidation, optional Starlette HTTP middleware, and production metrics—use `await` in FastAPI, Starlette, Django async views, workers, or plain `asyncio`. **Sync code** is welcome too: `get_sync` / `set_sync` (and friends) or `@cached` on a normal `def`—same async-backed implementation, not a separate Redis client.
1010

1111
**[Documentation](https://sirstig.github.io/yokedcache/)** · **[Changelog](https://sirstig.github.io/yokedcache/changelog.html)** · **[PyPI](https://pypi.org/project/yokedcache/)** · **[Issues](https://github.com/sirstig/yokedcache/issues)**
1212

@@ -16,7 +16,7 @@ Async-first caching with the **same API** across backends: in-process memory (de
1616

1717
- **Invalidation** — Tags, patterns, and workflows that keep cache and writes aligned
1818
- **Backends** — Memory (no extra deps), Redis, Memcached, disk, SQLite; per-prefix routing
19-
- **Framework-agnostic core**`YokedCache` and decorators work in any asyncio context; FastAPI helpers are optional
19+
- **Framework-agnostic core**async API in any asyncio context; sync helpers for scripts and blocking functions; FastAPI helpers optional
2020
- **HTTP** — ETag / `Cache-Control` middleware (`yokedcache[web]` / Starlette)
2121
- **Resilience** — Circuit breaker, retries, stale-if-error style patterns
2222
- **Observability** — Prometheus, StatsD, OpenTelemetry (optional extras)
@@ -71,6 +71,22 @@ asyncio.run(main())
7171

7272
For Redis in production: `pip install "yokedcache[redis]"`, set `redis_url` (or env `YOKEDCACHE_REDIS_URL`), then `connect()` as usual.
7373

74+
### Sync code
75+
76+
Prefer `await` inside apps that already run an event loop. For scripts or blocking call stacks, connect once, then use `*_sync`:
77+
78+
```python
79+
import asyncio
80+
from yokedcache import YokedCache
81+
from yokedcache.config import CacheConfig
82+
83+
cache = YokedCache(CacheConfig())
84+
asyncio.run(cache.connect())
85+
cache.set_sync("user:1", {"name": "Ada"}, ttl=60)
86+
print(cache.get_sync("user:1"))
87+
asyncio.run(cache.disconnect())
88+
```
89+
7490
## FastAPI example
7591

7692
Install FastAPI in your app (`pip install fastapi` or use `yokedcache[full]`).

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ build-backend = "hatchling.build"
88
[project]
99
name = "yokedcache"
1010
dynamic = ["version"]
11-
description = "Async multi-backend cache (memory, Redis, Memcached, disk, SQLite) with tag invalidation, optional HTTP middleware, and production metrics"
11+
description = "Async-first multi-backend cache (memory, Redis, Memcached, disk, SQLite); sync helpers for scripts; tag invalidation, optional HTTP middleware, metrics"
1212
readme = "README.md"
1313
license = "MIT"
1414
requires-python = ">=3.10"
@@ -17,6 +17,7 @@ authors = [
1717
]
1818
keywords = [
1919
"async cache",
20+
"sync helpers",
2021
"cache invalidation",
2122
"multi-backend cache",
2223
"redis",

scripts/build_docs_site.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33

44
from __future__ import annotations
55

6+
import json
67
import os
78
import re
89
import shutil
910
import sys
1011
from pathlib import Path
1112
from urllib.parse import urlparse
13+
from urllib.request import Request, urlopen
1214

1315
import markdown
1416
from jinja2 import Environment, FileSystemLoader, select_autoescape
@@ -22,6 +24,8 @@
2224
OUT = ROOT / "site"
2325
INIT_PY = ROOT / "src" / "yokedcache" / "__init__.py"
2426

27+
PYPI_PACKAGE = "yokedcache"
28+
2529
SITE_URL = "https://sirstig.github.io/yokedcache"
2630
GITHUB_REPO = "https://github.com/sirstig/yokedcache"
2731

@@ -77,6 +81,22 @@ def read_version() -> str:
7781
return m.group(1) if m else "0.0.0"
7882

7983

84+
def fetch_pypi_latest_version(timeout: float = 4.0) -> str | None:
85+
url = f"https://pypi.org/pypi/{PYPI_PACKAGE}/json"
86+
req = Request(url, headers={"User-Agent": "yokedcache-docs-build/1"})
87+
try:
88+
with urlopen(req, timeout=timeout) as resp:
89+
data = json.load(resp)
90+
ver = data.get("info", {}).get("version")
91+
return ver if isinstance(ver, str) and ver else None
92+
except OSError:
93+
return None
94+
95+
96+
def resolve_public_version() -> str:
97+
return fetch_pypi_latest_version() or read_version()
98+
99+
80100
def md_to_html_path(md_rel: str) -> str:
81101
return Path(md_rel).with_suffix(".html").as_posix()
82102

@@ -206,7 +226,7 @@ def _skip_root_html(src: str, names: list[str]) -> set[str]:
206226
},
207227
)
208228

209-
version = read_version()
229+
version = resolve_public_version()
210230

211231
for _group_label, items in NAV:
212232
for _title, src in items:

site-src/assets/style.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,19 @@ tbody tr:hover td { background: var(--glass); }
520520
margin: 0 auto;
521521
}
522522

523+
.hero-meta {
524+
display: flex;
525+
align-items: center;
526+
justify-content: center;
527+
flex-wrap: wrap;
528+
gap: 0.6rem 1rem;
529+
margin-bottom: 1.5rem;
530+
}
531+
532+
.hero-meta .hero-eyebrow { margin-bottom: 0; }
533+
534+
.hero-version { text-transform: none; letter-spacing: 0.02em; }
535+
523536
.hero-eyebrow {
524537
display: inline-flex;
525538
align-items: center;

site-src/pages/core-concepts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ logging.getLogger("yokedcache").setLevel(logging.INFO)
367367

368368
- **Connection Pooling**: YokedCache maintains connection pools automatically
369369
- **Pool Sizing**: Configure `max_connections` based on concurrency needs
370-
- **Async Operations**: Use async/await consistently for best performance
370+
- **Async vs sync**: Prefer async/await in hot paths and inside frameworks; `*_sync` is fine for scripts and low-volume blocking code
371371

372372
### Batch Operations
373373

site-src/pages/getting-started.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
---
22
title: Getting Started with YokedCache
3-
description: Install YokedCache, choose a cache backend (memory or Redis), and use the same async API across FastAPI, Starlette, or plain asyncio.
4-
keywords: yokedcache, installation, async cache, redis, memcached, multi-backend
3+
description: Install YokedCache, pick a backend (memory or Redis), and use the async-first API—or sync helpers—in FastAPI, scripts, or asyncio.
4+
keywords: yokedcache, installation, async cache, sync helpers, redis, memcached, multi-backend
55
---
66

77
# Getting Started with YokedCache
88

9-
Install the package, pick a **backend** (in-process memory by default, or Redis for production), and use one async API everywhere. Invalidation, tags, and patterns work the same no matter which store you use.
9+
Install the package, pick a **backend** (in-process memory by default, or Redis for production). The main methods are async (`await cache.get(...)`). Invalidation, tags, and patterns work the same on every store. If you are in sync-only code, use `get_sync` / `set_sync` or `@cached` on a plain function—same implementation underneath.
1010

1111
## Installation
1212

@@ -105,6 +105,24 @@ With `yokedcache[redis]` and Redis running:
105105
yokedcache ping
106106
```
107107

108+
## Using from sync code
109+
110+
Prefer `await` when you already have an event loop (for example inside FastAPI). **`_sync` methods are for blocking contexts**—do not use them from inside a running loop; use `await cache.get(...)` there instead.
111+
112+
```python
113+
import asyncio
114+
from yokedcache import YokedCache
115+
from yokedcache.config import CacheConfig
116+
117+
cache = YokedCache(CacheConfig())
118+
asyncio.run(cache.connect())
119+
cache.set_sync("user:1", {"name": "Ada"}, ttl=60)
120+
print(cache.get_sync("user:1"))
121+
asyncio.run(cache.disconnect())
122+
```
123+
124+
You can also put `@cached` on a normal `def`; it will use the sync cache path automatically.
125+
108126
## Your First Cache
109127

110128
Let's start with a simple example that demonstrates core caching concepts.

site-src/pages/performance.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,8 @@
2525

2626
- Reuse a single `YokedCache` instance; avoid reconnecting per request.
2727
- Use pipeline where appropriate (handled internally for set/tag ops).
28+
29+
## Sync helpers
30+
31+
- `get_sync` / `set_sync` / `delete_sync` / `exists_sync` each run the async work via `asyncio.run`; reuse one cache instance, but avoid tight loops of many `*_sync` calls if throughput matters.
32+
- Prefer `await` inside apps that already have an event loop.

site-src/static/llms.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# yokedcache
22

3-
> MIT-licensed async Python cache: same API for in-process memory, Redis, Memcached, disk, and SQLite; tag/pattern invalidation; optional Starlette HTTP middleware and metrics.
3+
> MIT-licensed Python cache: async-first, same API for in-process memory, Redis, Memcached, disk, and SQLite; sync helpers (`*_sync`, `@cached` on plain functions); tag/pattern invalidation; optional Starlette HTTP middleware and metrics.
44

55
## Summary
66

77
- Package: yokedcache (PyPI). **Python 3.10+** (CI: 3.10–3.14). Plain `pip install yokedcache` uses **embedded memory** when `redis` is not installed (1.0.1+). Add `yokedcache[redis]` for Redis, `yokedcache[web]` for HTTP middleware, `yokedcache[full]` for the full optional stack.
8+
- **Async-first** (`await` for `get` / `set` / `connect`). **Sync-friendly**: `get_sync` / `set_sync` / `delete_sync` / `exists_sync` and `@cached` on a normal `def` use the same async-backed implementation—not a separate blocking Redis client.
89
- Docs: https://sirstig.github.io/yokedcache/
910
- API (HTML): https://sirstig.github.io/yokedcache/api/
1011
- Changelog: https://sirstig.github.io/yokedcache/changelog.html

site-src/templates/index.html.jinja2

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
<head>
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1">
6-
<title>YokedCache — Async multi-backend cache for Python</title>
7-
<meta name="description" content="Async Python cache with the same API across memory, Redis, Memcached, disk, and SQLite. Tag invalidation, optional Starlette HTTP caching, metrics, and FastAPI-friendly helpers. MIT licensed.">
6+
<title>YokedCache — Multi-backend Python cache (async-first)</title>
7+
<meta name="description" content="Async-first Python cache across memory, Redis, Memcached, disk, and SQLite. Sync helpers for scripts and plain functions. Tag invalidation, optional HTTP caching, metrics. MIT licensed.">
88
<meta name="keywords" content="python, async cache, redis, memcached, sqlalchemy, caching, cache invalidation, starlette, fastapi, prometheus, yokedcache, Joshua Kac, Project Yoked">
99
<meta name="author" content="Joshua Kac">
1010
<meta name="robots" content="index,follow">
@@ -15,15 +15,15 @@
1515
<meta property="og:type" content="website">
1616
<meta property="og:locale" content="en_US">
1717
<meta property="og:url" content="{{ home_canonical }}">
18-
<meta property="og:title" content="YokedCache — Async multi-backend cache for Python">
19-
<meta property="og:description" content="Async Python cache with the same API across memory, Redis, Memcached, disk, and SQLite. Tag invalidation, optional HTTP middleware, metrics. MIT licensed.">
18+
<meta property="og:title" content="YokedCache — Multi-backend Python cache (async-first)">
19+
<meta property="og:description" content="Async-first cache across memory, Redis, Memcached, disk, SQLite. Sync helpers when you need them. Invalidation, optional HTTP middleware, metrics. MIT licensed.">
2020
<meta property="og:image" content="{{ og_image_url }}">
2121
<meta property="og:image:width" content="1200">
2222
<meta property="og:image:height" content="630">
2323
<meta property="og:site_name" content="YokedCache">
2424
<meta name="twitter:card" content="summary_large_image">
25-
<meta name="twitter:title" content="YokedCache — Async multi-backend cache for Python">
26-
<meta name="twitter:description" content="Same async API for memory, Redis, Memcached, disk, and SQLite. Invalidation, optional HTTP caching, observability. MIT licensed.">
25+
<meta name="twitter:title" content="YokedCache — Multi-backend Python cache (async-first)">
26+
<meta name="twitter:description" content="Async-first; sync helpers for scripts. Same API across memory, Redis, Memcached, disk, SQLite. Invalidation, HTTP caching, observability. MIT licensed.">
2727
<meta name="twitter:image" content="{{ og_image_url }}">
2828
<link rel="preconnect" href="https://fonts.googleapis.com">
2929
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -41,7 +41,7 @@
4141
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
4242
"url": "{{ site_url }}",
4343
"downloadUrl": "https://pypi.org/project/yokedcache/",
44-
"description": "Async multi-backend Python cache: memory, Redis, Memcached, disk, SQLite; tag invalidation; optional Starlette HTTP caching.",
44+
"description": "Async-first multi-backend Python cache (memory, Redis, Memcached, disk, SQLite) with sync helpers; tag invalidation; optional Starlette HTTP caching.",
4545
"codeRepository": "{{ github_repo }}",
4646
"license": "https://opensource.org/licenses/MIT",
4747
"author": {
@@ -94,11 +94,14 @@
9494

9595
<div class="landing">
9696
<section class="hero">
97-
<div class="hero-eyebrow">Open source · MIT License</div>
98-
<h1>One async cache API,<br>your choice of backend</h1>
97+
<div class="hero-meta">
98+
<div class="hero-eyebrow">Open source · MIT License</div>
99+
<a class="header-badge hero-version" href="https://pypi.org/project/yokedcache/{{ version }}/" target="_blank" rel="noopener" title="Latest release on PyPI" aria-label="Latest release on PyPI, version {{ version }}">v{{ version }}</a>
100+
</div>
101+
<h1>One cache API,<br>your choice of backend</h1>
99102
<p class="hero-sub">
100-
Memory, Redis, Memcached, disk, or SQLite — same invalidation and patterns.
101-
Optional Starlette HTTP caching, FastAPI-ready decorators, metrics, and a small CLI.
103+
Async-first across memory, Redis, Memcached, disk, and SQLite — same invalidation and patterns.
104+
Sync helpers when you are not in an async app. Optional HTTP caching, FastAPI decorators, metrics, CLI.
102105
</p>
103106
<div class="install-pill">
104107
<span class="prompt">$</span>
@@ -134,8 +137,8 @@
134137
</div>
135138
<div class="feature-card">
136139
<div class="feature-icon">◇</div>
137-
<h3>Async everywhere</h3>
138-
<p>Use from FastAPI, Starlette, Django async views, workers, or plain <code>asyncio</code>. Optional dependency helpers for FastAPI.</p>
140+
<h3>Fits async and sync</h3>
141+
<p>Use <code>await</code> in FastAPI, Starlette, Django async, and workers. For blocking code, <code>get_sync</code> / <code>set_sync</code> or <code>@cached</code> on a normal function.</p>
139142
</div>
140143
<div class="feature-card">
141144
<div class="feature-icon">◇</div>

src/yokedcache/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"""
2-
YokedCache — async caching with pluggable backends and tag-based invalidation.
2+
YokedCache — async-first caching with pluggable backends and tag-based invalidation.
33
4-
Core installs use an in-memory store unless you add optional extras (e.g. ``redis``,
5-
``web`` for Starlette HTTP middleware, ``memcached``, ``full``).
4+
Use ``await`` in apps; ``get_sync`` / ``set_sync`` and ``@cached`` on plain functions
5+
for sync code. Core installs use in-memory storage unless you add extras (``redis``,
6+
``web``, ``memcached``, ``full``, etc.).
67
"""
78

89
__version__ = "1.0.1"

0 commit comments

Comments
 (0)