Context-local session manager for SQLAlchemy AsyncSession
Project description
SQLAlchemy Transaction Context
Minimalistic context-local session and transaction controller for SQLAlchemy AsyncSession.
sqlalchemy-tx-context provides context-aware session and transaction management using Python’s contextvars,
eliminating the need to pass AsyncSession objects explicitly. Especially useful in code where database access should
be decoupled from explicit session passing - such as service layers or background jobs.
Features
- Context-local session management via
contextvars, without relying on thread-locals or global session objects. - Clean
async withAPI for managing session and transaction scopes. - Supports safe nesting of transactions.
.execute(...)automatically creates a session or transaction if none is active (optional fallback).- Explicit control over how sessions are scoped and reused.
Installation
pip install sqlalchemy-tx-context
Quick Example
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy_tx_context import SQLAlchemyTransactionContext
engine = create_async_engine("postgresql+asyncpg://user:pass@host/db")
db = SQLAlchemyTransactionContext(engine)
async def create_user():
async with db.transaction():
await db.execute(insert(User).values(name="John"))
async def get_users():
async with db.session():
result = await db.execute(select(User))
return result.scalars().all()
API Reference
Constructor
SQLAlchemyTransactionContext(
engine: AsyncEngine,
*,
default_session_maker: Optional[async_sessionmaker[AsyncSession]] = None,
auto_context_on_execute: bool = False,
auto_context_force_transaction: bool = False,
)
Parameters:
engine- SQLAlchemyAsyncEngineinstance.default_session_maker- Optional async session factory. If omitted, usesasync_sessionmaker(engine).auto_context_on_execute- IfTrue, allows.execute()to run even without an active session by creating a temporary one.auto_context_force_transaction- IfTrue,.execute()always runs inside a transaction when auto context is used. IfFalse, it uses.session()for read-only queries (likeSelectorCompoundSelect), and.transaction()for everything else, includingInsert,Update, and raw SQL.
Session Methods:
session(...) -> AsyncIterator[AsyncSession]- Enter a new session context, or reuse an existing one ifreuse_if_exists=True.transaction(...) -> AsyncIterator[AsyncSession]- Enter a transactional context. Will nest if a transaction is already active.new_session(...) -> AsyncIterator[AsyncSession]- Create a new isolated session, even if another is already active. Overrides the context for the duration.new_transaction(...) -> AsyncIterator[AsyncSession]- Create a new transaction in an isolated session.get_session(strict: bool = True) -> AsyncSession | None- Return the current session from context. RaisesNoSessionErrorifstrict=Trueand no session exists.execute(...) -> Result- Execute a SQLAlchemyExecutableusing the current or temporary context. Uses the current session if one is active. Otherwise, behavior depends onauto_context_on_execute- a new session or transaction context may be created automatically.
Auto-context Example
# Opens a temporary session or transaction depending on statement type
db = SQLAlchemyTransactionContext(engine, auto_context_on_execute=True)
await db.execute(insert(User).values(name="Alice"))
await db.execute(select(User))
Full Example
For a complete working example using PostgreSQL, see
example/.
It demonstrates table creation, data insertion, transactional rollback, and querying.
Exceptions
This library defines a few custom exceptions to help catch context-related mistakes:
NoSessionError: Raised when attempting to access or use a session when none is active and fallback is disabled.SessionAlreadyActiveError: Raised when entering.session()while a session is already active (unlessreuse_if_exists=True).TransactionAlreadyActiveError: Raised when entering.transaction()while a transaction is already active and nesting is disabled.
Motivation
SQLAlchemy does not provide an out-of-the-box solution for context-local session tracking when working with
AsyncSession. Passing sessions around explicitly can make service-layer code verbose and harder to maintain.
The library introduces a lightweight and predictable abstraction that:
- Stores current session in a
ContextVar. - Provides safe transactional/session boundaries.
- Exposes a unified
execute(...)interface. - Integrates with standard SQLAlchemy models, statements, and engines.
When should you use this?
- You're writing service-layer logic and want to avoid passing
sessionexplicitly. - You need nested transactional logic with clean context boundaries.
- You prefer explicit context management over dependency-injected sessions.
- You work with context-local transaction boundaries in background tasks or microservices.
- You need precise control over session lifecycle and scope.
This library is best suited for functional or script-style code where sessions are not injected via DI frameworks.
Best Practices
- Use
.transaction()or.session()explicitly in your service-layer or job code to clearly define execution boundaries. .execute(...)is ideal for small projects, functional-style code, or early-stage prototypes - it avoids boilerplate and makes code fast to write.- As your project grows, you can gradually migrate to DI-based session and transaction management:
just replace
db.execute(...)withself._session.execute(...)anddb.transaction()with your own context (e.g.,UnitOfWork,session.begin()) - the query logic remains the same. - This makes the library especially useful for bootstrapping or background scripts, where a full-blown DI setup would be overkill.
Tests
pytest --cov=sqlalchemy_tx_context --cov-report=term-missing
Compatibility
Tested on Python 3.9 - 3.12.
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sqlalchemy_tx_context-1.0.1.tar.gz.
File metadata
- Download URL: sqlalchemy_tx_context-1.0.1.tar.gz
- Upload date:
- Size: 11.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc990efda9555035db5c9949823cf50e5b89a9de9a5355c046180d7de15c245b
|
|
| MD5 |
430b947596232757a8a18c90d3758b99
|
|
| BLAKE2b-256 |
7825ad45257d084012fe10127e9bc0cb56eb30230585bd8eaa638dbfd1916ba7
|
Provenance
The following attestation bundles were made for sqlalchemy_tx_context-1.0.1.tar.gz:
Publisher:
python-publish.yml on QuisEgoSum/sqlalchemy-tx-context
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sqlalchemy_tx_context-1.0.1.tar.gz -
Subject digest:
dc990efda9555035db5c9949823cf50e5b89a9de9a5355c046180d7de15c245b - Sigstore transparency entry: 241020394
- Sigstore integration time:
-
Permalink:
QuisEgoSum/sqlalchemy-tx-context@b1974077df6f24a87facbce89789ffc3e543509e -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/QuisEgoSum
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@b1974077df6f24a87facbce89789ffc3e543509e -
Trigger Event:
release
-
Statement type:
File details
Details for the file sqlalchemy_tx_context-1.0.1-py3-none-any.whl.
File metadata
- Download URL: sqlalchemy_tx_context-1.0.1-py3-none-any.whl
- Upload date:
- Size: 9.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13bcdec1fac24643ac0cbe30909c385dfaa9144809cc5e483c048cd36d72a8fc
|
|
| MD5 |
7325a51a5813b18726b608a9d35d8729
|
|
| BLAKE2b-256 |
7e6d0031d11d1e69c0573afdd79b7b65cc3a784d7a00b0dcf89c330cac735d32
|
Provenance
The following attestation bundles were made for sqlalchemy_tx_context-1.0.1-py3-none-any.whl:
Publisher:
python-publish.yml on QuisEgoSum/sqlalchemy-tx-context
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sqlalchemy_tx_context-1.0.1-py3-none-any.whl -
Subject digest:
13bcdec1fac24643ac0cbe30909c385dfaa9144809cc5e483c048cd36d72a8fc - Sigstore transparency entry: 241020398
- Sigstore integration time:
-
Permalink:
QuisEgoSum/sqlalchemy-tx-context@b1974077df6f24a87facbce89789ffc3e543509e -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/QuisEgoSum
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@b1974077df6f24a87facbce89789ffc3e543509e -
Trigger Event:
release
-
Statement type: