python-resource-management
wshobson/agents
Manage Python resources deterministically with context managers, cleanup patterns, and streaming.
What is python-resource-management?
Implements context managers and cleanup patterns for reliable resource management in Python. Use when managing database connections, file handles, network sockets, or building streaming responses where resources must be released even on exceptions.
- Implement class-based context managers with __enter__/__exit__ protocol
- Create async context managers with __aenter__/__aexit__ for async resources
- Use @contextmanager and @asynccontextmanager decorators for simple patterns
- Guarantee unconditional resource cleanup regardless of exceptions
- Handle nested resource cleanup and dynamic resource counts with ExitStack
- Build streaming responses with accumulated state and efficient cleanup
How to install python-resource-management
npx skills add https://github.com/wshobson/agents --skill python-resource-managementHow to use python-resource-management
- 1.Define a class implementing __enter__ and __exit__ methods, or use @contextmanager decorator
- 2.In __enter__, acquire the resource and return it (or self)
- 3.In __exit__, perform cleanup unconditionally in a finally block or after yield
- 4.Use the resource with a with statement to ensure automatic cleanup
- 5.For async resources, implement __aenter__/__aexit__ or use @asynccontextmanager
- 6.Return False from __exit__ to propagate exceptions, True only if intentionally suppressing
Use cases
- Managing database connections and connection pools with automatic cleanup
- Working with file handles and I/O streams that require guaranteed closure
- Implementing custom context managers for domain-specific resources
- Building streaming responses that accumulate state across requests
- Handling nested resource cleanup in complex workflows
- Backend developers managing database connections and pools
- Systems engineers working with file handles and network sockets
- Python developers implementing cleanup logic and resource lifecycle management
- Streaming API developers building responses with accumulated state
- Anyone building production systems requiring deterministic resource release
python-resource-management FAQ
Use @contextmanager for simple, straightforward resource patterns. Use class-based for complex resources with multiple methods, state tracking, or when you need to support both context manager and manual management patterns.
The __exit__ method always runs regardless of exceptions. You can inspect exc_type, exc_val, and exc_tb to handle exceptions. Return False (the default) to propagate the exception, or True to suppress it.
Nest multiple with statements or use contextlib.ExitStack to manage a dynamic number of resources. ExitStack is especially useful when the number of resources is determined at runtime.
Yes, use async context managers with __aenter__/__aexit__ or the @asynccontextmanager decorator. Use async with instead of with to properly await the async operations.
Return False (default) to propagate any exception that occurred. Return True only if you intentionally want to suppress the exception. Unintended suppression can hide bugs.
Full instructions (SKILL.md)
Source of truth, from wshobson/agents.
name: python-resource-management description: Python resource management with context managers, cleanup patterns, and streaming. Use when managing connections, file handles, implementing cleanup logic, or building streaming responses with accumulated state.
Python Resource Management
Manage resources deterministically using context managers. Resources like database connections, file handles, and network sockets should be released reliably, even when exceptions occur.
When to Use This Skill
- Managing database connections and connection pools
- Working with file handles and I/O
- Implementing custom context managers
- Building streaming responses with state
- Handling nested resource cleanup
- Creating async context managers
Core Concepts
1. Context Managers
The with statement ensures resources are released automatically, even on exceptions.
2. Protocol Methods
__enter__/__exit__ for sync, __aenter__/__aexit__ for async resource management.
3. Unconditional Cleanup
__exit__ always runs, regardless of whether an exception occurred.
4. Exception Handling
Return True from __exit__ to suppress exceptions, False to propagate them.
Quick Start
from contextlib import contextmanager
@contextmanager
def managed_resource():
resource = acquire_resource()
try:
yield resource
finally:
resource.cleanup()
with managed_resource() as r:
r.do_work()
Fundamental Patterns
Pattern 1: Class-Based Context Manager
Implement the context manager protocol for complex resources.
class DatabaseConnection:
"""Database connection with automatic cleanup."""
def __init__(self, dsn: str) -> None:
self._dsn = dsn
self._conn: Connection | None = None
def connect(self) -> None:
"""Establish database connection."""
self._conn = psycopg.connect(self._dsn)
def close(self) -> None:
"""Close connection if open."""
if self._conn is not None:
self._conn.close()
self._conn = None
def __enter__(self) -> "DatabaseConnection":
"""Enter context: connect and return self."""
self.connect()
return self
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None:
"""Exit context: always close connection."""
self.close()
# Usage with context manager (preferred)
with DatabaseConnection(dsn) as db:
result = db.execute(query)
# Manual management when needed
db = DatabaseConnection(dsn)
db.connect()
try:
result = db.execute(query)
finally:
db.close()
Pattern 2: Async Context Manager
For async resources, implement the async protocol.
class AsyncDatabasePool:
"""Async database connection pool."""
def __init__(self, dsn: str, min_size: int = 1, max_size: int = 10) -> None:
self._dsn = dsn
self._min_size = min_size
self._max_size = max_size
self._pool: asyncpg.Pool | None = None
async def __aenter__(self) -> "AsyncDatabasePool":
"""Create connection pool."""
self._pool = await asyncpg.create_pool(
self._dsn,
min_size=self._min_size,
max_size=self._max_size,
)
return self
async def __aexit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None:
"""Close all connections in pool."""
if self._pool is not None:
await self._pool.close()
async def execute(self, query: str, *args) -> list[dict]:
"""Execute query using pooled connection."""
async with self._pool.acquire() as conn:
return await conn.fetch(query, *args)
# Usage
async with AsyncDatabasePool(dsn) as pool:
users = await pool.execute("SELECT * FROM users WHERE active = $1", True)
Pattern 3: Using @contextmanager Decorator
Simplify context managers with the decorator for straightforward cases.
from contextlib import contextmanager, asynccontextmanager
import time
import structlog
logger = structlog.get_logger()
@contextmanager
def timed_block(name: str):
"""Time a block of code."""
start = time.perf_counter()
try:
yield
finally:
elapsed = time.perf_counter() - start
logger.info(f"{name} completed", duration_seconds=round(elapsed, 3))
# Usage
with timed_block("data_processing"):
process_large_dataset()
@asynccontextmanager
async def database_transaction(conn: AsyncConnection):
"""Manage database transaction."""
await conn.execute("BEGIN")
try:
yield conn
await conn.execute("COMMIT")
except Exception:
await conn.execute("ROLLBACK")
raise
# Usage
async with database_transaction(conn) as tx:
await tx.execute("INSERT INTO users ...")
await tx.execute("INSERT INTO audit_log ...")
Pattern 4: Unconditional Resource Release
Always clean up resources in __exit__, regardless of exceptions.
class FileProcessor:
"""Process file with guaranteed cleanup."""
def __init__(self, path: str) -> None:
self._path = path
self._file: IO | None = None
self._temp_files: list[Path] = []
def __enter__(self) -> "FileProcessor":
self._file = open(self._path, "r")
return self
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None:
"""Clean up all resources unconditionally."""
# Close main file
if self._file is not None:
self._file.close()
# Clean up any temporary files
for temp_file in self._temp_files:
try:
temp_file.unlink()
except OSError:
pass # Best effort cleanup
# Return None/False to propagate any exception
Detailed worked examples and patterns
Detailed sections (starting with ## Advanced Patterns) live in references/details.md. Read that file when the navigation summary above is insufficient.
Best Practices Summary
- Always use context managers - For any resource that needs cleanup
- Clean up unconditionally -
__exit__runs even on exception - Don't suppress unexpectedly - Return
Falseunless suppression is intentional - Use @contextmanager - For simple resource patterns
- Implement both protocols - Support
withand manual management - Use ExitStack - For dynamic numbers of resources
- Accumulate efficiently - List + join, not string concatenation
- Track metrics - Time-to-first-byte matters for streaming
- Document behavior - Especially exception suppression
- Test cleanup paths - Verify resources are released on errors
Related skills
More from wshobson/agents and the wider catalog.

python-testing-patterns
Implement comprehensive testing strategies with pytest, fixtures, mocking, and test-driven development.

python-type-safety
Add robust Python type hints, generics, and protocols with strict mypy/pyright checking guidance.

quantized-export
Export promoted fine-tuned models in the right deployment format—FP8, AWQ, GGUF, or LoRA-only.

rag-implementation
Build RAG systems with vector databases and semantic search to ground LLMs in external knowledge.

react-modernization
Upgrade React apps to latest versions, migrate class components to hooks, and adopt concurrent features.

react-native-architecture
Production React Native patterns with Expo, navigation, native modules, and offline-first architecture.