Skip to content

Commit

Permalink
masquerade and more async methods (#2)
Browse files Browse the repository at this point in the history
* feat: added `masquerade_class` decorator; added tests using beanie; added `create_indexes` and `index_information` to collections async methods

* style: prefer single quotes

* style: fixed linting from Makefile and tyle issues

* docs: added badge with pypi version

* feat: added `*args, **kwargs` to AsyncMongoMockClients __init__
  • Loading branch information
michaelkryukov committed Nov 17, 2021
1 parent 9a458cd commit 2a3c9d8
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 31 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog

# v0.0.1
## v0.0.2

- Initial version with basic functionality loosely based on [this repository](https://github.com/gonzaloverussa/pytest-async-mongodb).
- Updated mock clasess to be treated as native motor's clasess.
- Added `create_indexes` and `index_information` to collection's async methods.

## v0.0.1

- Initial version with basic functionality loosely based on
[this repository](https://github.com/gonzaloverussa/pytest-async-mongodb).
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -5,7 +5,7 @@ all: lint test
lint:
python3 -c "import flake8" || python3 -m pip install flake8 flake8-quotes
flake8 mongomock_motor/ --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 mongomock_motor/ --count --max-complexity=10 --max-line-length=127 --statistics
flake8 mongomock_motor/ --count --max-complexity=10 --max-line-length=127 --statistics

test:
python3 -c "import pytest" || python3 -m pip install pytest
Expand Down
5 changes: 4 additions & 1 deletion README.md
@@ -1,6 +1,9 @@
# mongomock-motor

Mock for [AsyncIOMotorClient](https://motor.readthedocs.io/en/stable/api-asyncio/asyncio_motor_client.html) (Database, Collection, e.t.c) built on top of [mongomock](https://github.com/mongomock/mongomock) library.
[![PyPI version](https://badge.fury.io/py/mongomock-motor.svg)](https://badge.fury.io/py/mongomock-motor)

Best effort mock for [AsyncIOMotorClient](https://motor.readthedocs.io/en/stable/api-asyncio/asyncio_motor_client.html)
(Database, Collection, e.t.c) built on top of [mongomock](https://github.com/mongomock/mongomock) library.

## Example / Showcase

Expand Down
68 changes: 47 additions & 21 deletions mongomock_motor/__init__.py
@@ -1,6 +1,27 @@
from functools import wraps
import importlib
from mongomock import MongoClient


def masquerade_class(name):
module_name, target_name = name.rsplit('.', 1)

try:
target = getattr(importlib.import_module(module_name), target_name)
except Exception:
return lambda cls: cls

def decorator(cls):
@wraps(target, updated=())
class Wrapper(cls):
@property
def __class__(self):
return target
return Wrapper
return decorator


@masquerade_class('motor.motor_asyncio.AsyncIOMotorCursor')
class AsyncCursor():
def __init__(self, cursor):
self.__cursor = cursor
Expand All @@ -18,28 +39,31 @@ async def to_list(self, *args, **kwargs):
return list(self.__cursor)


@masquerade_class('motor.motor_asyncio.AsyncIOMotorCollection')
class AsyncMongoMockCollection():
ASYNC_METHODS = [
"find_one",
"find_one_and_delete",
"find_one_and_replace",
"find_one_and_update",
"find_and_modify",
"save",
"delete_one",
"delete_many",
"count",
"insert_one",
"insert_many",
"update_one",
"update_many",
"replace_one",
"count_documents",
"estimated_document_count",
"drop",
"create_index",
"ensure_index",
"map_reduce",
'count_documents',
'count',
'create_index',
'create_indexes',
'delete_many',
'delete_one',
'drop',
'ensure_index',
'estimated_document_count',
'find_and_modify',
'find_one_and_delete',
'find_one_and_replace',
'find_one_and_update',
'find_one',
'index_information',
'insert_many',
'insert_one',
'map_reduce',
'replace_one',
'save',
'update_many',
'update_one',
]

def __init__(self, collection):
Expand All @@ -57,6 +81,7 @@ def find(self, *args, **kwargs) -> AsyncCursor:
return AsyncCursor(self.__collection.find(*args, **kwargs))


@masquerade_class('motor.motor_asyncio.AsyncIOMotorDatabase')
class AsyncMongoMockDatabase():
def __init__(self, database):
self.__database = database
Expand All @@ -71,8 +96,9 @@ def __getattr__(self, name):
return self.__collections[name]


@masquerade_class('motor.motor_asyncio.AsyncIOMotorClient')
class AsyncMongoMockClient():
def __init__(self):
def __init__(self, *args, **kwargs):
self.__client = MongoClient()
self.__databases = {}

Expand Down
7 changes: 4 additions & 3 deletions requirements.txt
@@ -1,6 +1,7 @@
mongomock>=3.23.0,<4.0.0

# Development requirements
flake8
flake8-quotes
pytest
beanie>=1.7.2,<2.0.0
flake8-quotes>=3.3.1,<4.0.0
flake8>=4.0.1,<5.0.0
pytest>=6.2.5,<7.0.0
2 changes: 0 additions & 2 deletions setup.cfg

This file was deleted.

2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -8,7 +8,7 @@
import setuptools


VERSION = "0.0.1"
VERSION = "0.0.2"


with open("README.md", "r") as fh:
Expand Down
37 changes: 37 additions & 0 deletions tests/test_beanie.py
@@ -0,0 +1,37 @@
from typing import Optional
from beanie import Document, Indexed, init_beanie
from pydantic import BaseModel
from mongomock_motor import AsyncMongoMockClient


class Category(BaseModel):
name: str
description: str


class Product(Document):
name: str
description: Optional[str] = None
price: Indexed(float)
category: Category


async def test_beanie():
client = AsyncMongoMockClient('mongodb://user:pass@host:27017', connectTimeoutMS=250)

await init_beanie(database=client.beanie_test, document_models=[Product])

chocolate = Category(name='Chocolate', description='A preparation of roasted and ground cacao seeds.')
tonybar = Product(name="Tony's", price=5.95, category=chocolate)
await tonybar.insert()

find_many = Product.find_many(Product.category == chocolate)
assert find_many.motor_cursor
assert await find_many.count() == 1

product = await Product.find_one(Product.price < 10)
await product.set({Product.name: 'Gold bar'})

product = await Product.find_one(Product.category.name == 'Chocolade')
assert product.name == 'Gold bar'
assert product.category.description == chocolate.description

0 comments on commit 2a3c9d8

Please sign in to comment.