ProvenPin Install

Beanie ODM documents tested against mongomock-motor offline: working versions (tested 2026-10-15)

Define Beanie documents with a unique index and a link, then query them fully offline on mongomock-motor, patching a motor-only call and resolving links by hand.

passed6 passed · 0 failed2026-10-15 18:09 UTC
Status
passed
Last passed
2026-10-15 18:09 UTC
Tests
6 / 6
Language
Python
Runtime
Python 3.13.16
pinned versions3
beanie@2.2.0mongomock-motor@0.0.36pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt
.venv/bin/python -m pytest -q
test environment
Python 3.13.16
linux 6.17.0-1022-azure
x64
runner: github-actions 38783276983

The code

Exactly the files that passed. Your agent can pull them with get_recipe("beanie-mongomock-odm") (install), or see them on GitHub.

requirements.txt
beanie==2.2.0
mongomock-motor==0.0.36
pytest==9.1.1
documents.py
import asyncio
import contextlib
from collections.abc import AsyncIterator, Callable

from beanie import Document, Indexed, Link, init_beanie
from mongomock.database import Database as MongoMockDatabase
from mongomock_motor import AsyncMongoMockClient

_original_list_collection_names = MongoMockDatabase.list_collection_names


def _list_collection_names(self, *args, **kwargs):
    kwargs.pop("authorizedCollections", None)
    kwargs.pop("nameOnly", None)
    return _original_list_collection_names(self, *args, **kwargs)


MongoMockDatabase.list_collection_names = _list_collection_names


class Author(Document):
    name: str

    class Settings:
        name = "authors"


class Book(Document):
    title: str
    year: int = 0
    isbn: Indexed(str, unique=True)
    author: Link[Author] | None = None

    class Settings:
        name = "books"


@contextlib.asynccontextmanager
async def memory_db() -> AsyncIterator[object]:
    client = AsyncMongoMockClient()
    await init_beanie(database=client["test"], document_models=[Author, Book])
    try:
        yield client["test"]
    finally:
        client.close()


def async_test(fn: Callable) -> Callable:
    def wrapper(*args, **kwargs):
        return asyncio.run(fn(*args, **kwargs))

    return wrapper
tests/test_documents.py
import pytest
from beanie import Link, PydanticObjectId
from pymongo.errors import DuplicateKeyError

from documents import Author, Book, async_test, memory_db


@async_test
async def test_insert_and_get_roundtrip():
    async with memory_db() as db:
        book = Book(title="Dune", year=1965, isbn="9780441013593")
        await book.insert()
        assert isinstance(book.id, PydanticObjectId)
        fetched = await Book.get(book.id)
        assert fetched is not None and fetched.title == "Dune"
        assert await db["books"].count_documents({}) == 1


@async_test
async def test_query_operators_and_sort():
    async with memory_db() as db:
        await Book(title="A", year=1999, isbn="1").insert()
        await Book(title="B", year=2020, isbn="2").insert()
        await Book(title="C", year=2024, isbn="3").insert()
        recent = await Book.find(Book.year >= 2000).sort(-Book.year).to_list()
        assert [b.title for b in recent] == ["C", "B"]


@async_test
async def test_unique_index_is_enforced():
    async with memory_db() as db:
        await Book(title="A", isbn="dup").insert()
        with pytest.raises(DuplicateKeyError):
            await Book(title="B", isbn="dup").insert()


@async_test
async def test_save_and_bulk_update():
    async with memory_db() as db:
        book = Book(title="Old", year=2001, isbn="x")
        await book.insert()
        book.title = "New"
        await book.save()
        assert (await Book.get(book.id)).title == "New"
        result = await Book.find(Book.year >= 2000).update({"$set": {"year": 2002}})
        assert result.modified_count == 1


@async_test
async def test_links_need_manual_resolution():
    async with memory_db() as db:
        author = Author(name="Frank")
        await author.insert()
        book = Book(title="Dune", isbn="978", author=author)
        await book.insert()
        stored = await Book.get(book.id)
        assert isinstance(stored.author, Link)
        resolved = await Author.get(stored.author.ref.id)
        assert resolved.name == "Frank"


@async_test
async def test_delete_and_count():
    async with memory_db() as db:
        books = [Book(title=f"t{i}", isbn=str(i)) for i in range(3)]
        for b in books:
            await b.insert()
        await books[0].delete()
        assert await Book.count() == 2
pytest.ini
[pytest]
pythonpath = .

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.