mongomock icon indicating copy to clipboard operation
mongomock copied to clipboard

TypeError: CodecOptions got an unexpected keyword argument

Open plaan opened this issue 2 years ago • 5 comments

The following exception is raised when using pymongo 4.3.2 but it worked for pymongo 4.2:

TypeError: __new__() got an unexpected keyword argument 'datetime_conversion'

With the following code snippet (pymongo 4.3.2, mongomock 4.1.2):

import mongomock
from bson import CodecOptions

client = mongomock.MongoClient()
database = client.get_database("db").get_collection("c").with_options(codec_options=CodecOptions(tz_aware=True))
database

plaan avatar Oct 19 '22 10:10 plaan

Having same issue. pymongo added an extra parameter to their CodecOptions (see release notes https://pymongo.readthedocs.io/en/stable/changelog.html#changes-in-version-4-3-4-3-2). mongomock will need to update their CodecOptions class to match.

What I did as a workaround was actually patch my import of CodecOptions to use mongomock's CodecOptions for my tests.

So something like:

    # TEMP - hack/workaround for https://github.com/mongomock/mongomock/issues/810
    from mongomock.codec_options import CodecOptions as MockCodecOptions

    mocker.patch("my.module_i_am_testing.CodecOptions", MockCodecOptions)

That way mongomock is happy so long as we don't use the new CodecOptions in pymongo.

tkutcher avatar Oct 27 '22 19:10 tkutcher

@tkutcher , could you please share example of a code, how do you mock mongomock?

arturmkr avatar Dec 06 '22 18:12 arturmkr

@arturmkr Sure - here is a bit more context:

Let's say in my_lib/my_module.py I have something like:

import pymongo
from bson.codec_options import CodecOptions


def get_mongo_client(db_uri):
    return pymongo.MongoClient(db_uri)

def get_collection(mongo, name):
    return mongo["main"].get_collection(name, codec_options=CodecOptions(tz_aware=True))

Then, in my root conftest.py file:

@pytest.fixture(autouse=True)
def _mock_mongo_client(mocker) -> None:
    # Don't make any real connections to mongo, instead use mongomock.MongoClient.
    mocker.patch("my_lib.my_module.pymongo.MongoClient", mongomock.MongoClient)

    # Mock the CodecOptions import to be the ones mongomock is expecting.
    from mongomock.codec_options import CodecOptions as MockCodecOptions
    mocker.patch("my_lib.my_module.CodecOptions", MockCodecOptions)

So, in a test:

from my_lib.my_module import get_mongo_client, get_collection

def test_foo():
    mongo = get_mongo_client("foo")    # gets a mongomock.MongoClient instead of pymongo.MongoClient
    collection = mongo.get_collection(mongo, "blah")   # uses mongomock CodecOptions instead of bson.codec_options.

And the exact same code outside of the testing environment uses the real connections with pymongo.

tkutcher avatar Dec 06 '22 18:12 tkutcher

@tkutcher , Thank you so much!

arturmkr avatar Dec 06 '22 21:12 arturmkr

I also encountered this but resolved it the opposite way - by patching mongomock to use the real CodecOptions type, instead of patching my code. Not sure it's better, but it might also help someone.

This pytest fixture should do it:

from unittest import patch

import mongomock.codec_options
from bson import CodecOptions

@pytest.fixture
def patch_mongomock_codecopts(self):
    with patch.object(mongomock.codec_options, "CodecOptions", CodecOptions):
        yield

avivrosenberg avatar Apr 11 '23 13:04 avivrosenberg