Skip to main content

sqlalchemy-session-proxy

A lightweight proxy for SQLAlchemy sessions that provides a unified interface over both synchronous (Session) and asynchronous (AsyncSession) usage.

This library allows you to write database-access code that works in both sync and async environments with minimal branching, while still respecting SQLAlchemy’s execution model.


Features

  • Unified API for Session and AsyncSession
  • Automatic async detection via is_async
  • Explicit dispatching to sync or async implementations
  • Async-compatible method signatures for mixed environments
  • Fully type-annotated for IDEs and static analysis
  • No hidden magic beyond SQLAlchemy’s own async design

Installation

pip install sqlalchemy-session-proxy

Basic Usage

from sqlalchemy.orm import Session
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy_session_proxy.session_proxy import SqlalchemySessionProxy

Synchronous Session

session = Session(...)
proxy = SqlalchemySessionProxy(session)

proxy.add(obj)
proxy.commit()

result = proxy.execute(statement)

Asynchronous Session

async def main():
    async_session = AsyncSession(...)
    proxy = SqlalchemySessionProxy(async_session)

    proxy.add(obj)          # NOT awaitable (by SQLAlchemy design)
    await proxy.commit()    # awaitable

    result = await proxy.execute(statement)

⚠️ Important

Some methods (such as add, add_all, expire) are synchronous by design even when used with AsyncSession. This behavior follows SQLAlchemy’s official API.


Unified Execution Pattern

The following methods automatically dispatch based on the session type:

result = await proxy.execute(stmt)
rows = await proxy.scalars(stmt)
value = await proxy.scalar(stmt)
obj = await proxy.get(User, user_id)
  • In sync mode, these methods do not require await
  • In async mode, they must be awaited

API Overview

Core Properties

  • SqlalchemySessionProxy(session)
  • .session — underlying Session or AsyncSession
  • .is_async — True if using AsyncSession

Method Compatibility Matrix

Method Sync Async Notes
add ✔️ ✔️ Not awaitable
add_all ✔️ ✔️ Not awaitable
commit ✔️ ✔️ Awaitable in async
rollback ✔️ ✔️ Awaitable in async
close ✔️ ✔️ Awaitable in async
flush ✔️ ✔️ Awaitable in async
merge ✔️ ✔️ Awaitable in async
delete ✔️ ✔️ Awaitable in async
get ✔️ ✔️ Awaitable in async
get_one ✔️ ✔️ Awaitable in async
execute ✔️ ✔️ Awaitable in async
scalars ✔️ ✔️ Awaitable in async
scalar ✔️ ✔️ Awaitable in async
refresh ✔️ ✔️ Awaitable in async
expire ✔️ ✔️ Not awaitable
expire_all ✔️ ✔️ Not awaitable
expunge ✔️ ✔️ Not awaitable
expunge_all ✔️ ✔️ Not awaitable
is_modified ✔️ ✔️ Not awaitable
in_transaction ✔️ ✔️ Not awaitable
in_nested_transaction ✔️ ✔️ Not awaitable
query ✔️ ❌ Sync-only (legacy API)
stream ❌ ✔️ Async-only
stream_scalars ❌ ✔️ Async-only
run_sync ❌ ✔️ Async-only

Notes on query()

  • query() is sync-only

  • Calling it on an AsyncSession proxy raises NotImplementedError

  • This mirrors SQLAlchemy’s own guidance:

    • Query is legacy
    • Prefer select() for new code

run_sync

def legacy_fn(session: Session, value: str) -> str:
    session.add(MyModel(name=value))
    session.flush()
    return "ok"

async def main():
    async with AsyncSession(engine) as session:
        proxy = SqlalchemySessionProxy(session)
        result = await proxy.run_sync(legacy_fn, "test")
  • Runs synchronous ORM logic inside async code
  • Uses SQLAlchemy’s greenlet bridge
  • Available only for AsyncSession

License

Apache-2.0


Author

Tercel (tercel.yi@gmail.com)


Links

Metadata

Release files for sqlalchemy-session-proxy 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sqlalchemy-session-proxy 0.3.0
File Size Uploaded
sqlalchemy_session_proxy-0.3.0.tar.gz 12.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sqlalchemy-session-proxy 0.3.0
File Interpreter ABI Platform
sqlalchemy_session_proxy-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 22.0 kB

Release files / sqlalchemy_session_proxy-0.3.0.tar.gz

Download URL sqlalchemy_session_proxy-0.3.0.tar.gz
Size 12.4 kB
Tags Source
SHA-256 checksum
How to use checksums
a8a7eb541d0841939d3484abe85e5422d22779e17bac5425851b1306042453c9
BLAKE2b-256 checksum
How to use checksums
f919924ab0b4bf7a176075667a9a71d1955ccb8f0cdc73ba7cc010752982b82d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.11

Release files / sqlalchemy_session_proxy-0.3.0-py3-none-any.whl

Download URL sqlalchemy_session_proxy-0.3.0-py3-none-any.whl
Size 9.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5b4e1bb106b81e6b81b5ea1df330bf0ca4fa6722ce4508af5afd384d06f421c4
BLAKE2b-256 checksum
How to use checksums
221835912c936a198ad7196dc77e06a1eb26dcade0c14d78967523647fb4ab95
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.11

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page