python-best-practices-async-context-manager
Create async context managers for resource management using @asynccontextmanager decorator. Use when managing async resources, database sessions, file handles, connections, or any resource requiring automatic cleanup. Works with Python async/await patterns. Analyzes .py files with async with statements, AsyncIterator type hints, and try/finally patterns.
What this skill does
# Implement Async Context Manager
## Purpose
Create async context managers for automatic resource lifecycle management (setup, use, cleanup) in async Python code using the `@asynccontextmanager` decorator pattern.
## When to Use This Skill
Use when managing async resources with "create context manager", "manage database session", "async with pattern", or "resource cleanup".
Do NOT use for synchronous resources (use regular context managers), simple try/finally (overkill), or testing (use pytest fixtures).
## When to Use
Use this skill when:
- Managing database sessions or connections (primary use case)
- Handling async file I/O operations requiring cleanup
- Managing network connections with automatic close
- Coordinating resource pools with acquire/release patterns
- Ensuring cleanup in async operations (preventing resource leaks)
- Converting synchronous context managers to async
- Implementing transaction management with automatic commit/rollback
## Quick Start
```python
from contextlib import asynccontextmanager
from collections.abc import AsyncIterator
@asynccontextmanager
async def session(database: str) -> AsyncIterator[Session]:
"""Create a database session with automatic cleanup."""
session = await create_session(database)
try:
yield session
finally:
await session.close()
# Usage
async with session("mydb") as s:
await s.query("SELECT 1")
```
## Table of Contents
### Core Sections
- [Purpose](#purpose) - Core purpose and when to use async context managers
- [Quick Start](#quick-start) - Minimal working example
- [Instructions](#instructions) - Complete implementation guide
- [Step 1: Identify Resource Management Needs](#step-1-identify-resource-management-needs) - When to use async context managers
- [Step 2: Choose Implementation Pattern](#step-2-choose-implementation-pattern) - @asynccontextmanager vs __aenter__/__aexit__
- [Step 3: Implement @asynccontextmanager Pattern](#step-3-implement-asynccontextmanager-pattern) - Primary implementation approach
- [Step 4: Handle Error Cases](#step-4-handle-error-cases) - Comprehensive error handling patterns
- [Step 5: Add Type Safety](#step-5-add-type-safety) - Type hints and generic patterns
- [Step 6: Test Async Context Managers](#step-6-test-async-context-managers) - Testing strategies
- [Examples](#examples) - Production-ready implementations
- [Example 1: Database Session Manager](#example-1-database-session-manager-primary-pattern) - Primary pattern from codebase
- [Example 2: Resource Pool Manager](#example-2-resource-pool-manager) - Connection pool handling
- [Example 3: Async File Manager](#example-3-async-file-manager) - File I/O with cleanup
- [Common Patterns](#common-patterns) - Reusable implementation patterns
- [Pattern 1: State Tracking](#pattern-1-state-tracking) - Prevent double-cleanup
- [Pattern 2: Statistics Tracking](#pattern-2-statistics-tracking) - Track active resources
- [Pattern 3: Nested Context Managers](#pattern-3-nested-context-managers) - Composing context managers
### Project Integration
- [Integration with Project Patterns](#integration-with-project-patterns) - Clean Architecture, ServiceResult, Fail-Fast
- [Red Flags](#red-flags) - Common mistakes and best practices
- [Requirements](#requirements) - Dependencies and knowledge needed
### Supporting Resources
- [references/reference.md](./references/reference.md) - Technical details and advanced usage
- [templates/context-manager-template.py](./templates/context-manager-template.py) - Reusable template
- [Production Example](../../src/project_watch_mcp/infrastructure/neo4j/database.py) - Real-world implementation (line 517)
### Utility Scripts
- [Convert Sync to Async](./scripts/convert_sync_to_async_cm.py) - Automatically convert synchronous context managers to async
- [Generate Async Context Manager](./scripts/generate_async_context_manager.py) - Generate properly structured async context managers from template
- [Validate Context Managers](./scripts/validate_context_managers.py) - Check codebase for common anti-patterns and missing best practices
## Instructions
### Step 1: Identify Resource Management Needs
Async context managers are needed when:
- Managing database sessions/connections
- Handling file I/O with async operations
- Managing network connections
- Coordinating resource pools
- Ensuring cleanup in async operations
**Evidence from codebase**: 38 occurrences of `async with` patterns indicate resource management needs.
### Step 2: Choose Implementation Pattern
**Option A: @asynccontextmanager (Recommended)**
- Use for simple resource management
- Cleaner syntax with single function
- Automatic `__aenter__`/`__aexit__` generation
- Better for one-off context managers
**Option B: __aenter__/__aexit__ methods**
- Use for complex classes with state
- More control over lifecycle
- Better for reusable context manager classes
### Step 3: Implement @asynccontextmanager Pattern
```python
from contextlib import asynccontextmanager
from collections.abc import AsyncIterator
from typing import TypeVar
T = TypeVar("T")
@asynccontextmanager
async def resource_manager(
config: Config,
resource_id: str
) -> AsyncIterator[Resource]:
"""Manage resource lifecycle with automatic cleanup.
Args:
config: Configuration for resource creation (required)
resource_id: Unique identifier for resource
Yields:
Resource: Active resource instance
Raises:
ValueError: If config is None
ResourceError: If resource creation fails
"""
if not config:
raise ValueError("Config is required")
resource = None
try:
# Setup phase
resource = await create_resource(config, resource_id)
await resource.initialize()
# Yield resource to caller
yield resource
finally:
# Cleanup phase (always runs)
if resource:
await resource.cleanup()
await resource.close()
```
### Step 4: Handle Error Cases
**Critical patterns**:
- Validate inputs before setup
- Track resource state (None check before cleanup)
- Use try/finally for guaranteed cleanup
- Handle cleanup errors gracefully
- Log cleanup failures but don't raise
```python
@asynccontextmanager
async def safe_resource_manager(
settings: Settings
) -> AsyncIterator[Resource]:
"""Resource manager with comprehensive error handling."""
if not settings:
raise ValueError("Settings is required")
resource = None
try:
resource = await create_resource(settings)
yield resource
except Exception as e:
logger.error(f"Resource operation failed: {e}")
raise
finally:
if resource:
try:
await resource.close()
except Exception as cleanup_error:
# Log but don't raise - cleanup errors shouldn't hide original error
logger.warning(f"Cleanup failed: {cleanup_error}")
```
### Step 5: Add Type Safety
**Required type hints**:
- Return type: `AsyncIterator[T]` where T is yielded type
- Parameter types: All parameters must be typed
- Generic types: Use TypeVar for reusable managers
```python
from collections.abc import AsyncIterator
from typing import TypeVar
T = TypeVar("T")
@asynccontextmanager
async def typed_manager(
config: Config,
factory: Callable[[Config], T]
) -> AsyncIterator[T]:
"""Generic resource manager with type safety."""
resource = factory(config)
try:
yield resource
finally:
if hasattr(resource, 'close'):
await resource.close()
```
### Step 6: Test Async Context Managers
```python
import pytest
@pytest.mark.asyncio
async def test_context_manager_cleanup():
"""Test cleanup happens even on error."""
cleanup_called = False
@asynccontextmanager
async def test_resource() -> AsyncIterator[str]:
nonlocal cleanup_called
try:
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.