Registry / database / zope-sqlalchemy

zope-sqlalchemy

JSON →
library4.1pypypi✓ verified 68d ago

zope.sqlalchemy provides minimal integration between SQLAlchemy and Zope's transaction management system. It acts as a data manager, unifying various approaches to allow SQLAlchemy ORM sessions to participate in Zope transactions, often used in web frameworks like Pyramid. The library is currently at version 4.1, released in November 2025, and maintains an active release schedule.

pip install zope.sqlalchemy
INSTALL
IMPORT
SIG · ZOPE-SQLALCHEMY
Z
zope-sqlalchemy
databasepythonv4.1
Install
3.8s avg
Import
895ms
Disk
45MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v4.1 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.920 runs
installs and imports cleanly · install 0.0s · import 0.931s · 45.8MB
glibc
py 3.103.920 runs
installs and imports cleanly · install 3.8s · import 0.859s · 44MB
45MB installed
● package 45MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

register
from zope.sqlalchemy import register
This is the current and recommended way to integrate a SQLAlchemy session factory with Zope transactions.
ZopeTransactionExtension
from zope.sqlalchemy import ZopeTransactionEvents
from zope.sqlalchemy import ZopeTransactionExtension
In `zope.sqlalchemy` v1.2, `ZopeTransactionExtension` was renamed to `ZopeTransactionEvents`. The `register()` function is now the preferred way to integrate, replacing the `extension` argument in `sessionmaker`.

This quickstart demonstrates how to set up `zope.sqlalchemy` with a SQLAlchemy engine and a scoped session. It defines a simple `User` model, creates an in-memory SQLite database, registers the `DBSession` factory, and then uses a Zope transaction to add and retrieve data. Note the explicit `transaction.commit()` and `transaction.abort()`, and `DBSession.remove()` after each operation to properly manage the session lifecycle.

import os from sqlalchemy import create_engine, Column, Integer, String from sqlalchemy.orm import sessionmaker, scoped_session, declarative_base from zope.sqlalchemy import register import transaction # 1. Define a simple SQLAlchemy model Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(50), nullable=False) def __repr__(self): return f"<User(id={self.id}, name='{self.name}')>" # 2. Create an engine (using an in-memory SQLite for example) # Use an environment variable for a real database DSN, e.g., POSTGRES_DSN='postgresql://user:pass@host/db' database_url = os.environ.get('TEST_DSN', 'sqlite:///:memory:') engine = create_engine(database_url) # 3. Create tables (only if they don't exist) Base.metadata.create_all(engine) # 4. Create a SQLAlchemy session factory and scope it # Scoped sessions are important for web applications or multi-threaded environments Session = sessionmaker(bind=engine) DBSession = scoped_session(Session) # 5. Register the scoped session factory with zope.sqlalchemy # This integrates its commits/rollbacks with Zope transactions register(DBSession) # --- Usage Example --- # Get a session from the factory (it's thread-local/scoped) session = DBSession() try: # Add a new user new_user = User(name='Alice') session.add(new_user) # The transaction manager handles committing/rolling back the session transaction.commit() print(f"Added user: {new_user}") # After commit, the session might be closed/invalidated by default # Attempting to access new_user might raise DetachedInstanceError if not reloaded # print(new_user.name) # This might fail if session is closed. except Exception as e: transaction.abort() print(f"Transaction aborted due to error: {e}") finally: # Ensure the session is removed from the scope, especially in web requests DBSession.remove() # Start a new transaction for another operation session = DBSession() try: # Query users users = session.query(User).all() print(f"Current users: {users}") transaction.commit() except Exception as e: transaction.abort() print(f"Query transaction aborted: {e}") finally: DBSession.remove()
Debug
Known issues
breakingAs of `zope.sqlalchemy` v3.0, you can no longer call `session.commit()` directly within a manual nested database transaction (i.e., when using `session.begin_nested()`). You must commit the savepoint returned by `session.begin_nested()` or use it as a context manager.
fix
Instead of `with session.begin_nested(): session.commit()`, use `with session.begin_nested(): pass` or `savepoint = session.begin_nested(); savepoint.commit()`. The outer Zope transaction will manage the ultimate commit.
affects: 3.0+
breakingIn `zope.sqlalchemy` v1.2, `ZopeTransactionExtension` was renamed to `ZopeTransactionEvents`. The recommended integration pattern also shifted from passing an `extension` argument to `sessionmaker` to using the `register()` function on the session factory.
fix
Update imports from `from zope.sqlalchemy import ZopeTransactionExtension` to `from zope.sqlalchemy import register`. Change session factory creation from `scoped_session(sessionmaker(extension=ZopeTransactionExtension(), **options))` to `DBSession = scoped_session(sessionmaker(**options)); register(DBSession)`.
affects: 1.2+
gotchaBy default, `zope.sqlalchemy` often closes sessions after `transaction.commit()`. Accessing ORM-managed objects after a commit without reloading them can lead to `DetachedInstanceError`.
fix
If you need to access objects after a commit, either reload them (`session.query(MyObject).get(obj.id)`) or configure `zope.sqlalchemy.register` with `keep_session=True` for long-lasting sessions (though this can have other implications).
affects: All versions
gotchaWhen performing direct SQL write operations (not through the ORM), `zope.sqlalchemy` cannot automatically detect that the session has changed. This can lead to uncommitted changes if `transaction.commit()` is called without the session being marked as 'changed'.
fix
Manually mark the session as changed using `zope.sqlalchemy.mark_changed(session)` after direct SQL write operations.
affects: All versions
gotchaSQLAlchemy versions 2.0.32 through 2.0.35 are known to cause deadlocks when running tests on Python 3.11+. These versions are explicitly excluded from `zope.sqlalchemy`'s supported versions.
fix
Ensure you are using a version of SQLAlchemy outside this problematic range (e.g., <2.0.32 or >2.0.35) when working with Python 3.11+ and `zope.sqlalchemy`.
affects: 2.0.32 - 2.0.35 of SQLAlchemy with Python 3.11+
Errors
Common errors & fixes
sqlalchemy.orm.exc.DetachedInstanceError: Instance <User at 0x...> is not bound to a Session; attribute refresh operation cannot proceed (for example, due to a delete or rollback) or validation is pending
Attempting to access an ORM object after the session it was loaded from has been closed or invalidated, typically after a `transaction.commit()` or `transaction.abort()`.
fix
Reload the object within a new session context or configure `zope.sqlalchemy.register` with `keep_session=True` (use with caution in web contexts). Alternatively, only access object attributes that were loaded before the session was detached.
ImportError: cannot import name 'ZopeTransactionExtension' from 'zope.sqlalchemy'
`ZopeTransactionExtension` was renamed to `ZopeTransactionEvents` in `zope.sqlalchemy` v1.2, and direct use of `extension` in `sessionmaker` is deprecated in favor of `register()`.
fix
Update your code to use `from zope.sqlalchemy import register` and then call `register(DBSession)` after creating your `scoped_session` factory. If you *must* use the class directly for compatibility, import `ZopeTransactionEvents` instead.
Connection busy issue / The transaction is inactive due to a rollback in a subtransaction
Can occur in multi-threaded environments or complex transaction scenarios (e.g., with `Products.SQLAlchemyDA` or intricate nested transactions) where database connections or sessions are not properly isolated or released, leading to contention or premature invalidation.
fix
Ensure proper session scoping, especially `scoped_session` and `DBSession.remove()` at the end of each request/thread. Review transaction logic for any manual `session.commit()` calls within implicitly managed Zope transactions. Consider database pooling settings. For `session.merge()` issues, explicitly call `session.expire_all()` or configure `register(DBSession, initial_state='changed')` to ensure state is reloaded.
sqlalchemy.exc.IntegrityError: (IntegrityError) NOT NULL constraint failed: user.name [SQL: INSERT INTO user DEFAULT VALUES]
This is a standard SQLAlchemy integrity error, but sometimes in Zope/Pyramid contexts, the traceback or error handling can be obscured if the transaction manager isn't set up to propagate exceptions cleanly.
fix
Ensure your SQLAlchemy operations are wrapped in `try...except` blocks that catch `IntegrityError` (and other `sqlalchemy.exc` errors) and explicitly call `transaction.abort()` to roll back the Zope transaction. Verify the data being committed adheres to database constraints.
Upgrade
Version history
4.1latest on PyPI · released Nov 25, 2025
Audit
Dependencies
SQLAlchemyrequiredProvides the ORM and database connectivity; zope.sqlalchemy integrates its sessions with transactions. Requires SQLAlchemy >= 0.9, >= 1.1, and 2.0+ for recent versions.
transactionrequiredProvides the Zope transaction management API that zope.sqlalchemy integrates with.
Agent activity
45 hits · last 30 days
node
38
Amazon
1
Resources
zope-sqlalchemy — pip install zope-sqlalchemy · libregistry