Skip to main content

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 with API 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 - SQLAlchemy AsyncEngine instance.
  • default_session_maker - Optional async session factory. If omitted, uses async_sessionmaker(engine).
  • auto_context_on_execute - If True, allows .execute() to run even without an active session by creating a temporary one.
  • auto_context_force_transaction - If True, .execute() always runs inside a transaction when auto context is used. If False, it uses .session() for read-only queries (like Select or CompoundSelect), and .transaction() for everything else, including Insert, Update, and raw SQL.

Session Methods:

  • session(...) -> AsyncIterator[AsyncSession] - Enter a new session context, or reuse an existing one if reuse_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. Raises NoSessionError if strict=True and no session exists.
  • execute(...) -> Result - Execute a SQLAlchemy Executable using the current or temporary context. Uses the current session if one is active. Otherwise, behavior depends on auto_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 (unless reuse_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 session explicitly.
  • 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(...) with self._session.execute(...) and db.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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sqlalchemy_tx_context-1.0.1.tar.gz (11.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sqlalchemy_tx_context-1.0.1-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

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

Hashes for sqlalchemy_tx_context-1.0.1.tar.gz
Algorithm Hash digest
SHA256 dc990efda9555035db5c9949823cf50e5b89a9de9a5355c046180d7de15c245b
MD5 430b947596232757a8a18c90d3758b99
BLAKE2b-256 7825ad45257d084012fe10127e9bc0cb56eb30230585bd8eaa638dbfd1916ba7

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sqlalchemy_tx_context-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for sqlalchemy_tx_context-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 13bcdec1fac24643ac0cbe30909c385dfaa9144809cc5e483c048cd36d72a8fc
MD5 7325a51a5813b18726b608a9d35d8729
BLAKE2b-256 7e6d0031d11d1e69c0573afdd79b7b65cc3a784d7a00b0dcf89c330cac735d32

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page