Install & Compatibility
Where this runs
tested against v0.4.3 · 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
muslpy 3.10–3.920 runs
installs and imports cleanly · install 0.0s · import 1.067s · 42.7MB
glibcpy 3.10–3.920 runs
installs and imports cleanly · install 3.5s · import 0.963s · 41MB
45MB installed
● package 45MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
AlchemyMagicMock
✓ from alchemy_mock.mocking import AlchemyMagicMock
UnifiedAlchemyMagicMock
✓ from alchemy_mock.mocking import UnifiedAlchemyMagicMock
ExpressionMatcher
✓ from alchemy_mock.comparison import ExpressionMatcher
This quickstart demonstrates how to use `UnifiedAlchemyMagicMock` to mock a SQLAlchemy session. It includes an example of stubbing query results and asserting on method calls. It also highlights a common behavior where the mock session doesn't perform actual filtering on objects added to it, requiring different assertion strategies.
import unittest
from unittest import mock
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from alchemy_mock.mocking import UnifiedAlchemyMagicMock
# Define a simple SQLAlchemy model for demonstration
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String)
def __repr__(self):
return f"<User(id={self.id}, name='{self.name}', email='{self.email}')>"
# Example usage of UnifiedAlchemyMagicMock
def get_user_by_name(session, name):
return session.query(User).filter(User.name == name).first()
def add_user(session, name, email):
user = User(name=name, email=email)
session.add(user)
session.commit()
return user
class TestUserService(unittest.TestCase):
def test_get_user_by_name(self):
mock_session = UnifiedAlchemyMagicMock(
data=[([mock.call.query(User), mock.call.filter(User.name == 'Alice')], [User(id=1, name='Alice', email='alice@example.com')])]
)
user = get_user_by_name(mock_session, 'Alice')
self.assertIsNotNone(user)
self.assertEqual(user.name, 'Alice')
mock_session.filter.assert_called_once_with(User.name == 'Alice')
def test_add_user(self):
mock_session = UnifiedAlchemyMagicMock()
new_user = add_user(mock_session, 'Bob', 'bob@example.com')
# In alchemy-mock, the mock session doesn't apply filters to added models, so querying them directly might not work as expected.
# However, you can assert that the add and commit calls happened.
mock_session.add.assert_called_once()
mock_session.commit.assert_called_once()
# To retrieve added data, you typically would configure 'data' if querying after adding.
# Or, assert on the object passed to add.
self.assertEqual(new_user.name, 'Bob')
self.assertEqual(new_user.email, 'bob@example.com')
# To run the tests (example):
if __name__ == '__main__':
unittest.main()
Debug
Known issues
breakingThe `alchemy-mock` project appears to be abandoned, with no new releases since November 2019. For ongoing development and better Python version compatibility, consider migrating to the actively maintained fork `mock-alchemy` (PyPI: `mock-alchemy`, GitHub: `rajivsarvepalli/mock-alchemy`).fixFor new projects or if encountering issues with newer Python/SQLAlchemy versions, install `mock-alchemy` instead: `pip install mock-alchemy`. Update imports from `alchemy_mock` to `mock_alchemy`.
affects: <=0.4.3
gotchaWhen using `UnifiedAlchemyMagicMock`, `session.query(Model).filter(...)` will return all data provided in `UnifiedAlchemyMagicMock(data=...)` if you've also added models to the session, as the mock does not perform actual filtering on the added models.fixDesign your tests to assert on the `filter` calls themselves (e.g., `mock_session.filter.assert_called_once_with(...)`) rather than relying on the return value of subsequent filters on added data. For specific query results based on filters, pre-configure the `data` parameter of `UnifiedAlchemyMagicMock` with expected inputs and outputs.
affects: All versions
gotchaMocking `scalar()` has specific behaviors: querying on columns expects an indexable sequence from the mocked data, while querying on a table expects a non-indexable object. Misconfiguration can lead to unexpected `TypeError` or incorrect return values.fixEnsure your mocked data for `scalar()` calls matches the expected type: a sequence (e.g., `[value]`) for column queries and a single object for table queries (e.g., `[Model()]`).
affects: All versions
deprecatedThe original `alchemy-mock` repository has an open issue (#35) regarding 'Importing ABC directly from collections will be removed in Python 3.10', indicating potential compatibility issues with Python 3.10+.fixThis issue is addressed in the `mock-alchemy` fork. If you need to use `alchemy-mock` with Python 3.10+, you may encounter this. Consider upgrading to `mock-alchemy`.
affects: 0.4.3 (Python 3.10+)
Errors
Common errors & fixes
AttributeError: 'MagicMock' object has no attribute 'filter' (or '.all', '.first', etc.)
This typically occurs when a mock in a chained call is not configured with `return_value`, so an intermediate call returns a generic `MagicMock` instead of a mock configured to respond to the next method in the chain.
fixEnsure all parts of your SQLAlchemy query chain are correctly mocked with `return_value`. For example, instead of `session.query.filter.return_value = ...`, use `session.query.return_value.filter.return_value = ...` or use `UnifiedAlchemyMagicMock` which handles common chains.
TypeError: 'BinaryExpression' object is not callable
Attempting to pass a SQLAlchemy binary expression (e.g., `User.id == 1`) directly to `mock.call(...)` or `assert_called_with` when the underlying mock expects a comparable object, but the mock library doesn't know how to compare the SQLAlchemy expression type.
fixWrap SQLAlchemy expressions with `ExpressionMatcher` from `alchemy_mock.comparison` when asserting calls that involve such expressions. For example, `mock_session.filter.assert_called_once_with(ExpressionMatcher(User.name == 'Alice'))`.
TypeError: object of type 'MagicMock' has no len() (or 'is not subscriptable') when mocking scalar()
This indicates an incorrect return type for a `scalar()` mock. When querying a column with `scalar()`, the mock expects an indexable sequence (e.g., `[value]`). When querying a table and getting a single object, it expects a non-indexable single object.
fixAdjust the mocked data for `scalar()`: if it's a column query, provide data as `[value]`. If it's a table query returning a single object, provide data as `[obj]`, ensuring the mock returns `obj` directly for `scalar()`.
Upgrade
Version history
0.4.3latest on PyPI · released Nov 5, 2019
Audit
Dependencies
SQLAlchemyrequiredThis library mocks SQLAlchemy sessions; SQLAlchemy is a core dependency for its functionality.
mockrequiredRelies on Python's `mock` (or `unittest.mock` for Python 3.3+) for core mocking capabilities.