Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Objects implementing MutableMapping which are not dicts can't be searched for #886

Open
warownia1 opened this issue Apr 15, 2024 · 0 comments

Comments

@warownia1
Copy link

In my application, I use slotted classes implementing MutableMapping with mongo database for performance reasons. However, even though those objects can be stored in the database, mongomock is unable to perform searches on those object with a find() method.

Here is my MutableMapping implementation which maps keys to object attributes. It can be used like dict but it lacks the underlying dictionary

from collections.abc import MutableMapping
NOTHING = object()

class AttrsDict(MutableMapping):
  __slots__ = ()

  def __getitem__(self, key):
    try:
      return getattr(self, key)
    except AttributeError:
      raise KeyError(key)
    
  def __setitem__(self, key, value):
    try:
      setattr(self, key, value)
    except AttributeError:
      raise KeyError(key)
    
  def __delitem__(self, key):
    try:
      delattr(self, key)
    except AttributeError:
      raise KeyError(key)
    
  def __iter__(self):
    return (
      slot for slot in self.__slots__
      if hasattr(self, slot)
    )
  
  def __len__(self):
    return sum(1 for _ in self)

I tested it with both mongomock and real mongo database. Mongomock database is unable to find the stored object.

import mongomock
import pymongo
import pytest

class Example(AttrsDict):
  __slots__ = ('_id', 'name')

  def __init__(self, *, _id=NOTHING, name):
    if _id is not NOTHING:
      self._id = _id
    self.name = name

@pytest.fixture(params=[mongomock, pymongo])
def database(request):
  mongo = request.param.MongoClient()
  database = mongo.temp_testdb
  yield database
  mongo.drop_database(database)


def test_mongo_retrieve_object(database):
  collection = database['example']
  collection.insert_one(Example(name='foo'))
  cursor = collection.find({'name': 'foo'})
  assert next(cursor)

The test fails when using mongomock, but passes when using actual database.

def test_mongo_retrieve_dict(database):
  collection = database['example']
  collection.insert_one({'name': 'foo'})
  cursor = collection.find({'name': 'foo'})
  assert next(cursor)

Using dicts works both ways.

def test_mongo_retrieve_any_object(database):
  collection = database['example']
  collection.insert_one(Example(name='foo'))
  cursor = collection.find()
  assert next(cursor)

Fetching all objects without filtering works as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant