Configuration
Single database configuration
You can initialise the manager providing an instance of SQLAlchemyConfig
from sqlalchemy_bind_manager import SQLAlchemyConfig, SQLAlchemyBindManager
config = SQLAlchemyConfig(
engine_url="sqlite:///./sqlite.db",
engine_options=dict(connect_args={"check_same_thread": False}, echo=True),
session_options=dict(expire_on_commit=False),
)
sa_manager = SQLAlchemyBindManager(config)
The engine_url and engine_options dictionaries accept the same parameters as SQLAlchemy create_engine()
The session_options dictionary accepts the same parameters as SQLALchemy sessionmaker()
Once the bind manager is initialised we can retrieve and use the SQLAlchemyBind using the method get_bind()
The SQLAlchemyBind class has the following attributes:
engine: The initialised SQLALchemyEnginedeclarative_base: A base class that can be used to create declarative modelsregistry_mapper: Theregistryassociated with theengine. It can be used with Alembic or to setup imperative mappingsession_class: The class built by sessionmaker(), eitherSessionorAsyncSession
The SQLAlchemyBindManager provides some helper methods to quickly access some of the bind properties without using the SQLAlchemyBind:
get_session: returns a Session objectget_mapper: returns the mapper associated with the bind
Multiple databases configuration
SQLAlchemyBindManager accepts also multiple databases configuration, provided as a dictionary.
The dictionary keys are used as a reference name for each bind.
from sqlalchemy_bind_manager import SQLAlchemyConfig, SQLAlchemyBindManager
config = {
"default": SQLAlchemyConfig(
engine_url="sqlite:///./sqlite.db",
engine_options=dict(connect_args={"check_same_thread": False}, echo=True),
session_options=dict(expire_on_commit=False),
),
"secondary": SQLAlchemyConfig(
engine_url="sqlite:///./secondary.db",
engine_options=dict(connect_args={"check_same_thread": False}, echo=True),
session_options=dict(expire_on_commit=False),
),
}
sa_manager = SQLAlchemyBindManager(config)
All the SQLAlchemyBindManager helper methods accept the bind_name optional parameter:
get_session(bind_name="default")get_mapper(bind_name="default")
Asynchronous database engines
Is it possible to supply configurations for asyncio supported engines using the async_engine config property.
from sqlalchemy_bind_manager import SQLAlchemyConfig, SQLAlchemyBindManager
config = SQLAlchemyConfig(
engine_url="postgresql+asyncpg://scott:tiger@localhost/test",
async_engine=True,
)
sa_manager = SQLAlchemyBindManager(config)
This will make sure we initialise a SQLAlchemyAsyncBind object, containing AsyncEngine and AsyncSession.
The interfaces are exactly the same, however you'll need to await the relevant functions in SQLAlchemy. E.g.:
async with sa_manager.get_session() as session:
session.add(o)
await session.commit()
Note that async implementation has several differences from the sync one, make sure to check SQLAlchemy asyncio documentation
Bind engines lifecycle
Engine disposal is handled automatically by SQLAlchemyBindManager. Engines are disposed when:
- The manager instance is garbage collected
- The Python interpreter shuts down (via an
atexithandler)
In some scenarios, such as automated tests, you may need to manually dispose engines to release database connections between tests. The dispose_engines() method is available for this purpose:
sa_manager = SQLAlchemyBindManager(config)
# ... use the manager ...
# Manually dispose all engines
sa_manager.dispose_engines()
This method disposes all engines synchronously, including async engines (using their underlying sync engine).