Skip to main content

A lightweight proxy for SQLAlchemy sessions that seamlessly supports both synchronous (`Session`) and asynchronous (`AsyncSession`) usage. This library provides a unified interface to interact with SQLAlchemy sessions, making it easy to write code that works in both sync and async environments.

Project description

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_asyncTrue 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

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_session_proxy-0.3.0.tar.gz (12.4 kB view details)

Uploaded Source

Built Distribution

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

sqlalchemy_session_proxy-0.3.0-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

Details for the file sqlalchemy_session_proxy-0.3.0.tar.gz.

File metadata

  • Download URL: sqlalchemy_session_proxy-0.3.0.tar.gz
  • Upload date:
  • Size: 12.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for sqlalchemy_session_proxy-0.3.0.tar.gz
Algorithm Hash digest
SHA256 a8a7eb541d0841939d3484abe85e5422d22779e17bac5425851b1306042453c9
MD5 a21f139d1ca6eaca025c6a30443026b9
BLAKE2b-256 f919924ab0b4bf7a176075667a9a71d1955ccb8f0cdc73ba7cc010752982b82d

See more details on using hashes here.

File details

Details for the file sqlalchemy_session_proxy-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for sqlalchemy_session_proxy-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5b4e1bb106b81e6b81b5ea1df330bf0ca4fa6722ce4508af5afd384d06f421c4
MD5 9f02d82700a479f8e4034f98cb578e0a
BLAKE2b-256 221835912c936a198ad7196dc77e06a1eb26dcade0c14d78967523647fb4ab95

See more details on using hashes here.

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