bateau84/skills

python-async

Asynchronous Python with asyncio and async/await — coroutines, tasks, TaskGroup, gather, cancellation, timeouts, async context managers, concurrency limits with Semaphore, the httpx.AsyncClient, and not blocking the event loop.

Voir la source

Mode d’emploi

  1. Copiez la commande et examinez le paquet avant de l’installer dans votre environnement agent.
  2. Consultez le document original pour les outils, identifiants et environnements requis.
  3. Décrivez les entrées et le livrable souhaité ; comparez la sortie aux sources.
npx skills add https://github.com/bateau84/skills --skill python-async

Avant de commencer

  • L’installation n’inclut ni abonnement au modèle, ni quota API, ni accès aux fichiers.
  • Étoiles et installations reflètent l’activité, pas un test indépendant de qualité ou de sécurité.
Document Skill original

Rendu depuis le dépôt source en conservant titres, exemples, code, tableaux, liens et images.

Pair with python-common-practice for shared verification guidance.

Persona: You are a Python async engineer. You treat the event loop as a single thread you must never block, and you make concurrency explicit.

Asynchronous Python

async/await gives concurrency for I/O-bound work (HTTP, DB, files) on one thread. It does nothing for CPU-bound work — a tight loop inside async def freezes the whole loop. Reach for async when you wait on the network, not when you crunch numbers.

The cardinal rule: never block the loop

A single synchronous call inside a coroutine stalls every other task. Diagnose these with ruff's ASYNC rules (→ See python-lint).

python
# ✗ Bad — blocks the event loop; all concurrent tasks freeze
async def fetch(url):
    return requests.get(url).json()          # sync I/O
    time.sleep(5)                            # sync sleep

# ✓ Good — yields control while waiting
async def fetch(client: httpx.AsyncClient, url):
    resp = await client.get(url)
    return resp.json()
    # await asyncio.sleep(5)  for delays

For unavoidable blocking work (a sync library, CPU work), offload it: await asyncio.to_thread(blocking_fn, arg). This keeps the loop responsive.

Run things concurrently — explicitly

awaiting calls one after another is sequential. To overlap, create tasks. Prefer asyncio.TaskGroup (3.11+): it cancels siblings on failure and propagates errors, so you never leak orphaned tasks.

python
async def fetch_all(client, ids):
    async with asyncio.TaskGroup() as tg:        # structured concurrency
        tasks = [tg.create_task(fetch(client, i)) for i in ids]
    return [t.result() for t in tasks]           # all done, errors already raised

asyncio.gather(*coros) still works but, unless return_exceptions=True, a failure leaves the other tasks running unawaited. Prefer TaskGroup for new code.

Bound concurrency — don't DoS the upstream

Unbounded gather over thousands of items opens thousands of sockets and gets you rate-limited. Cap it with a Semaphore.

python
async def fetch_bounded(client, ids, limit=10):
    sem = asyncio.Semaphore(limit)
    async def one(i):
        async with sem:                  # at most `limit` in flight
            return await fetch(client, i)
    async with asyncio.TaskGroup() as tg:
        tasks = [tg.create_task(one(i)) for i in ids]
    return [t.result() for t in tasks]

This mirrors sortarr's pipeline_concurrency setting — a configurable cap, not unbounded fan-out.

Timeouts and cancellation

Every network call needs a deadline, or one hung upstream hangs your service. Use asyncio.timeout (3.11+) as a context manager; it cancels the body on expiry.

python
async with asyncio.timeout(30):
    data = await fetch(client, url)

Cancellation arrives as asyncio.CancelledError. Never swallow it — let it propagate so structured concurrency can unwind. If you must clean up, re-raise:

python
try:
    await long_op()
except asyncio.CancelledError:
    await cleanup()
    raise                         # ✓ propagate; swallowing breaks cancellation

httpx — reuse one client

Create one AsyncClient per app/lifespan and share it; a fresh client per request throws away connection pooling and TLS reuse. Always close it (or use it as a context manager).

python
async with httpx.AsyncClient(timeout=30) as client:
    ...        # reuse across many requests

Background scheduling (APScheduler)

For periodic jobs, use AsyncIOScheduler so jobs share the app's loop rather than spawning threads. Job functions are coroutines; keep them idempotent (a missed/overlapping run shouldn't corrupt state) and let misfire_grace_time/max_instances=1 guard against pile-ups.

Common mistakes

MistakeFix
requests/time.sleep/sync DB inside async defUse async equivalents or asyncio.to_thread; ruff ASYNC flags these.
Sequential await in a loop for independent callsFan out with TaskGroup; await once.
Unbounded gather over a large listBound with asyncio.Semaphore.
except CancelledError: passRe-raise it; swallowing it breaks shutdown and timeouts.
New httpx.AsyncClient per callOne shared client per lifespan; reuse the pool.
asyncio.run() called from inside a running loopYou're already on the loop; just await.
Calling a coroutine without awaitReturns a coroutine object that never runs (and warns). Await it or make it a task.

Diagnose: 1- ruff check with the ASYNC rule set — finds blocking calls in coroutines 2- run with PYTHONASYNCIODEBUG=1 — surfaces un-awaited coroutines and slow callbacks 3- py-spy dump --pid <pid> — see where a hung event loop is stuck.

References

Tâches connexes

du même dépôt

Autres Skills

Tous les Skills
bateau84
Communauté

behavioral-spec

Derive bounded, implementation-independent requirements from agreed product intent through goal refinement, coverage lenses, obstacle analysis, provenance tracking, and counterexample checks. Use to select, author, and reconcile Behavioral Requirements (BR), Quality Scenarios (QS), and Obligation Contracts (OC) without expanding scope. Not for concrete API/schema/protocol realization (use architectural-spec) or human-centered stories and scenarios (use user-stories-and-scenarios).

Installations / 1h
1
GitHub Stars
0
Mis à jour
18 oct.
bateau84
Communauté

desktop-ui-design

Desktop GUI design for native and hybrid applications: platform conventions (macOS HIG, Windows Fluent, GNOME HIG), menus, keyboard shortcuts, window management, session persistence, native vs Electron/Tauri trade-offs, and accessibility APIs. Use for Swift/AppKit, C/WinUI, GTK+, or Electron/Tauri/Flutter desktop design. Add web-ui-design for a web app shipped as a desktop wrapper. Not for browser-only interfaces, terminal applications (use tui-design), or command-line tools (use cli-design).

Installations / 1h
1
GitHub Stars
0
Mis à jour
18 oct.
bateau84
Communauté

git-commit-discipline

Small coherent commits, explanatory messages, shared-working-tree discipline, and safe undo/recovery. Use when asked to commit, when a diff mixes concerns, when agents share a working tree, or when undoing or recovering Git changes. Not for content conflicts (use git-conflicts).

Installations / 1h
1
GitHub Stars
0
Mis à jour
18 oct.
bateau84
Communauté

golang-dependency-injection

google/wire, uber-go/dig, uber-go/fx, samber/do, manual constructor injection, and service containers in Go. Use when designing service architecture, setting up dependency injection, refactoring tightly coupled code, or managing singletons and service factories.

Installations / 1h
1
GitHub Stars
0
Mis à jour
18 oct.